diff --git a/README.md b/README.md index 0c371ea..6fc059a 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,8 @@ The idea is to provide a "kit" of components which can either be used "as-is", f What's currently included? -------------------------- * Raw RTF Parser - parses RTF, sends events representing content to a listener. Performs minimal processing - you get the RTF commands and data exactly as they appear in the file. -* Standard RTF Parser - parses RTF, sends events representing content to a listener. Handles character encoding, Unicode and so on, so you don't have to. This is probably the parser you want to use. +* Standard RTF Parser - parses RTF, sends events representing content to a listener. Handles character encoding, Unicode and so on, so you don't have to. +* Document Builder RTF Parser - parses RTF and constructs a document object model via an implementation of the Document interface. You can either use the provided DefaultDocument implementation, or provide your own. This is probably the parser you want to use. * Text Converter - demonstrates very simple text extraction from an RTF file * RTF Dump - another demonstration, this time writing the RTF file contents as XML diff --git a/RTF Parser Kit/.settings/org.eclipse.core.resources.prefs b/RTF Parser Kit/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 0000000..99f26c0 --- /dev/null +++ b/RTF Parser Kit/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1 +encoding/=UTF-8 diff --git a/RTF Parser Kit/src/com/rtfparserkit/document/Annotation.java b/RTF Parser Kit/src/com/rtfparserkit/document/Annotation.java new file mode 100644 index 0000000..69c43cf --- /dev/null +++ b/RTF Parser Kit/src/com/rtfparserkit/document/Annotation.java @@ -0,0 +1,41 @@ +/* + * Copyright 2015 Stephan Aßmus + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.rtfparserkit.document; + +import java.util.Date; + +/** + * Interface for annotation elements. The annotation contents are accessible + * via the DocumentPart functionality. Note that this would mean support for + * nested annotations. + */ +public interface Annotation extends DocumentPart +{ + + public void setId(String id); + + public String getId(); + + public void setAuthor(String author); + + public String getAuthor(); + + public void setDate(Date date); + + public Date getDate(); + +} diff --git a/RTF Parser Kit/src/com/rtfparserkit/document/CharacterStyle.java b/RTF Parser Kit/src/com/rtfparserkit/document/CharacterStyle.java new file mode 100644 index 0000000..f924a17 --- /dev/null +++ b/RTF Parser Kit/src/com/rtfparserkit/document/CharacterStyle.java @@ -0,0 +1,71 @@ +/* + * Copyright 2015 Stephan Aßmus + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.rtfparserkit.document; + +/** + * Interface for storing paragraph style parameters. + */ +public interface CharacterStyle extends Style +{ + public enum UnderlineStyle + { + NONE, SINGLE, DOUBLE, WORD, DOTTED, DASHED, DASH_DOTTED, DASH_DOT_DOTTED, LONG_DASHED, THICK, THICK_DOTTED, THICK_DASHED, THICK_DASH_DOTTED, THICK_DASH_DOT_DOTTED, THICK_LONG_DASHED, WAVE, HEAVY_WAVE, DOUBLE_WAVE + } + + public CharacterStyle createDerivedStyle(); + + public CharacterStyle createFlattenedStyle(); + + @Override + public CharacterStyle getParent(); + + public void setFont(Font font); + + public Font getFont(); + + public void setFontSize(float value); + + public float getFontSize(); + + public void setBold(boolean bold); + + public boolean getBold(); + + public void setItalic(boolean italic); + + public boolean getItalic(); + + public void setCaps(boolean caps); + + public boolean getCaps(); + + public void setStrikeOut(boolean strikeOut); + + public boolean getStrikeOut(); + + public void setUnderlined(UnderlineStyle style); + + public UnderlineStyle getUnderlined(); + + public void setBackgroundColor(Color color); + + public Color getBackgroundColor(); + + public void setForegroundColor(Color color); + + public Color getForegroundColor(); +} diff --git a/RTF Parser Kit/src/com/rtfparserkit/document/CharacterStyleTable.java b/RTF Parser Kit/src/com/rtfparserkit/document/CharacterStyleTable.java new file mode 100644 index 0000000..2113f6b --- /dev/null +++ b/RTF Parser Kit/src/com/rtfparserkit/document/CharacterStyleTable.java @@ -0,0 +1,34 @@ +/* + * Copyright 2015 Stephan Aßmus + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.rtfparserkit.document; + +/** + * Interface for style table in which character styles can be + * retrieved by their ID. + */ +public interface CharacterStyleTable extends Iterable +{ + + public CharacterStyle createStyle(); + + public void addStyle(int id, CharacterStyle style); + + public CharacterStyle styleFor(int id); + + public int countStyles(); + +} diff --git a/RTF Parser Kit/src/com/rtfparserkit/document/Chunk.java b/RTF Parser Kit/src/com/rtfparserkit/document/Chunk.java new file mode 100644 index 0000000..36c7604 --- /dev/null +++ b/RTF Parser Kit/src/com/rtfparserkit/document/Chunk.java @@ -0,0 +1,30 @@ +/* + * Copyright 2015 Stephan Aßmus + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.rtfparserkit.document; + +/** + * A chunk of text with a certain style. + */ +public interface Chunk extends Element +{ + + public String getText(); + + public CharacterStyle getStyle(); + + public void append(String string); +} diff --git a/RTF Parser Kit/src/com/rtfparserkit/document/Color.java b/RTF Parser Kit/src/com/rtfparserkit/document/Color.java new file mode 100644 index 0000000..162db98 --- /dev/null +++ b/RTF Parser Kit/src/com/rtfparserkit/document/Color.java @@ -0,0 +1,31 @@ +/* + * Copyright 2015 Stephan Aßmus + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.rtfparserkit.document; + +/** + * Represents a color that can be placed in the ColorTable. + */ +public interface Color +{ + + public int getRed(); + + public int getGreen(); + + public int getBlue(); + +} diff --git a/RTF Parser Kit/src/com/rtfparserkit/document/ColorTable.java b/RTF Parser Kit/src/com/rtfparserkit/document/ColorTable.java new file mode 100644 index 0000000..13cdcad --- /dev/null +++ b/RTF Parser Kit/src/com/rtfparserkit/document/ColorTable.java @@ -0,0 +1,31 @@ +/* + * Copyright 2015 Stephan Aßmus + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.rtfparserkit.document; + +/** + * Interface for adding a color to the global color table and retrieving + * a Color instance at a specific index. + */ +public interface ColorTable +{ + + public void addColor(int red, int green, int blue); + + public int countColors(); + + public Color colorAt(int index); +} diff --git a/RTF Parser Kit/src/com/rtfparserkit/document/Document.java b/RTF Parser Kit/src/com/rtfparserkit/document/Document.java new file mode 100644 index 0000000..546b23f --- /dev/null +++ b/RTF Parser Kit/src/com/rtfparserkit/document/Document.java @@ -0,0 +1,40 @@ +/* + * Copyright 2015 Stephan Aßmus + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.rtfparserkit.document; + +/** + * Interface for getting to all relevant parts of the document model. + */ +public interface Document extends DocumentPart +{ + + public FontTable getFontTable(); + + public ColorTable getColorTable(); + + public StyleSheet getStyleSheet(); + + public DocumentSettings getDocumentSettings(); + + public int countSections(); + + public Section sectionAt(int index); + + public void nextSection(); + + public Section getLastSection(); +} diff --git a/RTF Parser Kit/src/com/rtfparserkit/document/DocumentPart.java b/RTF Parser Kit/src/com/rtfparserkit/document/DocumentPart.java new file mode 100644 index 0000000..82baf8c --- /dev/null +++ b/RTF Parser Kit/src/com/rtfparserkit/document/DocumentPart.java @@ -0,0 +1,40 @@ +/* + * Copyright 2015 Stephan Aßmus + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.rtfparserkit.document; + +/** + * Interface for appending styled text and handling paragraphs. A flattened + * String representation of all contained text can be obtained via the Text + * functionality. + */ +public interface DocumentPart extends Text +{ + + public int countParagraphs(); + + public Paragraph paragraphAt(int index); + + public void append(String text, CharacterStyle style); + + public void nextParagraph(CharacterStyle lastStyle); + + public void nextLine(); + + public Annotation appendAnnotation(); + + public ParagraphStyle createDefaultStyle(); +} diff --git a/RTF Parser Kit/src/com/rtfparserkit/document/DocumentSettings.java b/RTF Parser Kit/src/com/rtfparserkit/document/DocumentSettings.java new file mode 100644 index 0000000..46b3c31 --- /dev/null +++ b/RTF Parser Kit/src/com/rtfparserkit/document/DocumentSettings.java @@ -0,0 +1,25 @@ +/* + * Copyright 2015 Stephan Aßmus + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.rtfparserkit.document; + +/** + * Interface for controlling global settings of the document. + */ +public interface DocumentSettings +{ + public PageSettings getPageSettings(); +} diff --git a/RTF Parser Kit/src/com/rtfparserkit/document/Element.java b/RTF Parser Kit/src/com/rtfparserkit/document/Element.java new file mode 100644 index 0000000..8a1bda3 --- /dev/null +++ b/RTF Parser Kit/src/com/rtfparserkit/document/Element.java @@ -0,0 +1,25 @@ +/* + * Copyright 2015 Stephan Aßmus + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.rtfparserkit.document; + +/** + * Base type for various possible children of a Paragraph. + */ +public interface Element +{ + +} diff --git a/RTF Parser Kit/src/com/rtfparserkit/document/Font.java b/RTF Parser Kit/src/com/rtfparserkit/document/Font.java new file mode 100644 index 0000000..3ebb181 --- /dev/null +++ b/RTF Parser Kit/src/com/rtfparserkit/document/Font.java @@ -0,0 +1,29 @@ +/* + * Copyright 2015 Stephan Aßmus + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.rtfparserkit.document; + +/** + * Simple interface for storing font information. + */ +public interface Font +{ + public void setName(String name); + + public String getName(); + + public boolean equals(Font other); +} diff --git a/RTF Parser Kit/src/com/rtfparserkit/document/FontTable.java b/RTF Parser Kit/src/com/rtfparserkit/document/FontTable.java new file mode 100644 index 0000000..cd1aa2a --- /dev/null +++ b/RTF Parser Kit/src/com/rtfparserkit/document/FontTable.java @@ -0,0 +1,36 @@ +/* + * Copyright 2015 Stephan Aßmus + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.rtfparserkit.document; + +/** + * Interface for adding a font definition to the global font table and + * retrieving the font information at a specific index. + */ +public interface FontTable extends Iterable +{ + + public enum FontFamily + { + DEFAULT, ROMAN, SWISS, MODERN, SCRIPT, DECOR, TECH, BIDI + } + + public void addFont(int id, String name, String alternativeName, String fileName, FontFamily fontFamily); + + public int countFonts(); + + public Font fontFor(int id); +} diff --git a/RTF Parser Kit/src/com/rtfparserkit/document/Footer.java b/RTF Parser Kit/src/com/rtfparserkit/document/Footer.java new file mode 100644 index 0000000..d8e1a5f --- /dev/null +++ b/RTF Parser Kit/src/com/rtfparserkit/document/Footer.java @@ -0,0 +1,25 @@ +/* + * Copyright 2015 Stephan Aßmus + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.rtfparserkit.document; + +/** + * Special type of a DocumentPart representing a page footer. + */ +public interface Footer extends DocumentPart +{ + +} diff --git a/RTF Parser Kit/src/com/rtfparserkit/document/Header.java b/RTF Parser Kit/src/com/rtfparserkit/document/Header.java new file mode 100644 index 0000000..aebc18e --- /dev/null +++ b/RTF Parser Kit/src/com/rtfparserkit/document/Header.java @@ -0,0 +1,25 @@ +/* + * Copyright 2015 Stephan Aßmus + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.rtfparserkit.document; + +/** + * Special type of a DocumentPart representing a page header. + */ +public interface Header extends DocumentPart +{ + +} diff --git a/RTF Parser Kit/src/com/rtfparserkit/document/PageSettings.java b/RTF Parser Kit/src/com/rtfparserkit/document/PageSettings.java new file mode 100644 index 0000000..c62d494 --- /dev/null +++ b/RTF Parser Kit/src/com/rtfparserkit/document/PageSettings.java @@ -0,0 +1,35 @@ +/* + * Copyright 2015 Stephan Aßmus + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.rtfparserkit.document; + +/** + * Interface for controlling page settings + */ +public interface PageSettings +{ + public void setPageMarginLeft(int value); + + public void setPageMarginRight(int value); + + public void setPageMarginTop(int value); + + public void setPageMarginBottom(int value); + + public void setPageWidth(int value); + + public void setPageHeight(int value); +} diff --git a/RTF Parser Kit/src/com/rtfparserkit/document/Paragraph.java b/RTF Parser Kit/src/com/rtfparserkit/document/Paragraph.java new file mode 100644 index 0000000..0cef010 --- /dev/null +++ b/RTF Parser Kit/src/com/rtfparserkit/document/Paragraph.java @@ -0,0 +1,30 @@ +/* + * Copyright 2015 Stephan Aßmus + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.rtfparserkit.document; + +/** + * Interface for paragraph functionality. A Paragraph contains Elements + * which currently may be of type Chunk and Annotation. + */ +public interface Paragraph extends Iterable, Text +{ + public int countElements(); + + public Element elementAt(int index); + + public ParagraphStyle getStyle(); +} diff --git a/RTF Parser Kit/src/com/rtfparserkit/document/ParagraphStyle.java b/RTF Parser Kit/src/com/rtfparserkit/document/ParagraphStyle.java new file mode 100644 index 0000000..aabc3a6 --- /dev/null +++ b/RTF Parser Kit/src/com/rtfparserkit/document/ParagraphStyle.java @@ -0,0 +1,74 @@ +/* + * Copyright 2015 Stephan Aßmus + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.rtfparserkit.document; + +/** + * Interface for storing paragraph style parameters. + */ +public interface ParagraphStyle extends CharacterStyle +{ + public enum Alignment + { + LEFT, RIGHT, CENTER, JUSTIFIED, DISTRIBUTED, + } + + public enum TabAlignment + { + LEFT, CENTER, RIGHT, DECIMAL, + } + + @Override + public ParagraphStyle createDerivedStyle(); + + public CharacterStyle createDerivedCharacterStyle(); + + @Override + public ParagraphStyle createFlattenedStyle(); + + @Override + public ParagraphStyle getParent(); + + public void setAlignment(Alignment alignment); + + public Alignment getAlignment(); + + public void setSpacingTop(float value); + + public float getSpacingTop(); + + public void setSpacingBottom(float value); + + public float getSpacingBottom(); + + public void setFirstLineIndent(float value); + + public float getFirstLineIndent(); + + public void setLeftIndent(float value); + + public float getLeftIndent(); + + public void setRightIndent(float value); + + public float getRightIndent(); + + public void setLineSpacing(float value); + + public float getLineSpacing(); + + public void addTab(float position, TabAlignment aligment); +} diff --git a/RTF Parser Kit/src/com/rtfparserkit/document/ParagraphStyleTable.java b/RTF Parser Kit/src/com/rtfparserkit/document/ParagraphStyleTable.java new file mode 100644 index 0000000..11abfce --- /dev/null +++ b/RTF Parser Kit/src/com/rtfparserkit/document/ParagraphStyleTable.java @@ -0,0 +1,34 @@ +/* + * Copyright 2015 Stephan Aßmus + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.rtfparserkit.document; + +/** + * Interface for style table in which paragraph styles can be + * retrieved by their ID. + */ +public interface ParagraphStyleTable extends Iterable +{ + + public ParagraphStyle createStyle(); + + public void addStyle(int id, ParagraphStyle style); + + public ParagraphStyle styleFor(int id); + + public int countStyles(); + +} diff --git a/RTF Parser Kit/src/com/rtfparserkit/document/Section.java b/RTF Parser Kit/src/com/rtfparserkit/document/Section.java new file mode 100644 index 0000000..fd80187 --- /dev/null +++ b/RTF Parser Kit/src/com/rtfparserkit/document/Section.java @@ -0,0 +1,35 @@ +/* + * Copyright 2015 Stephan Aßmus + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.rtfparserkit.document; + +/** + * Interface for starting a new section in a document. A section can have + * its own paper settings (for example orientation and margins). + */ +public interface Section extends DocumentPart, Iterable +{ + + public Header createHeader(); + + public Footer createFooter(); + + public Header getHeader(); + + public Footer getFooter(); + + public PageSettings getPageSettings(); +} diff --git a/RTF Parser Kit/src/com/rtfparserkit/document/Style.java b/RTF Parser Kit/src/com/rtfparserkit/document/Style.java new file mode 100644 index 0000000..0263e4c --- /dev/null +++ b/RTF Parser Kit/src/com/rtfparserkit/document/Style.java @@ -0,0 +1,44 @@ +/* + * Copyright 2015 Stephan Aßmus + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.rtfparserkit.document; + +import java.util.EnumSet; + +/** + * Interface style base class. Also defines a bunch of properties. + */ +public interface Style +{ + public enum Property + { + ALIGNMENT, SPACING_TOP, SPACING_BOTTOM, FIRST_LINE_INDENT, LEFT_INDENT, RIGHT_INDENT, LINE_SPACING, TABS, FONT, FONT_SIZE, BOLD, ITALIC, UNDERLINED, STRIKE_OUT, CAPS, BACKGROUND_COLOR, FOREGROUND_COLOR + } + + public void setName(String name); + + public String getName(); + + public Style getParent(); + + public EnumSet getOverriddenProperties(); + + public void resetToDefaults(); + + public boolean equals(Style other); + + public void setTo(Style other); +} diff --git a/RTF Parser Kit/src/com/rtfparserkit/document/StyleSheet.java b/RTF Parser Kit/src/com/rtfparserkit/document/StyleSheet.java new file mode 100644 index 0000000..4e70cc1 --- /dev/null +++ b/RTF Parser Kit/src/com/rtfparserkit/document/StyleSheet.java @@ -0,0 +1,33 @@ +/* + * Copyright 2015 Stephan Aßmus + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.rtfparserkit.document; + +/** + * Interface for adding a style definition to a global style sheet. The style + * sheet contains four style tables: Paragraph styles, character styles, + * section styles and table styles. Each have their own index name space. + */ +public interface StyleSheet +{ + + public ParagraphStyleTable getParagraphStyleTable(); + + public CharacterStyleTable getCharacterStyleTable(); + + // TODO: Section style table + // TODO: Table style table +} diff --git a/RTF Parser Kit/src/com/rtfparserkit/document/Text.java b/RTF Parser Kit/src/com/rtfparserkit/document/Text.java new file mode 100644 index 0000000..44b821f --- /dev/null +++ b/RTF Parser Kit/src/com/rtfparserkit/document/Text.java @@ -0,0 +1,27 @@ +/* + * Copyright 2015 Stephan Aßmus + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.rtfparserkit.document; + +/** + * Base type for Elements which can return a flattened String for their text + * contents. + */ +public interface Text extends Element +{ + + public String getText(); +} diff --git a/RTF Parser Kit/src/com/rtfparserkit/document/impl/DefaultAnnotation.java b/RTF Parser Kit/src/com/rtfparserkit/document/impl/DefaultAnnotation.java new file mode 100644 index 0000000..329221a --- /dev/null +++ b/RTF Parser Kit/src/com/rtfparserkit/document/impl/DefaultAnnotation.java @@ -0,0 +1,72 @@ +/* + * Copyright 2015 Stephan Aßmus + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.rtfparserkit.document.impl; + +import java.util.Calendar; +import java.util.Date; + +import com.rtfparserkit.document.Annotation; + +/** + * Default implementation for Annotation. + */ +public class DefaultAnnotation extends ParagraphList implements Annotation +{ + private String id = ""; + private String author = ""; + private long date = Calendar.getInstance().getTimeInMillis(); + + public DefaultAnnotation() + { + } + + @Override + public void setId(String id) + { + this.id = id; + } + + @Override + public String getId() + { + return id; + } + + @Override + public void setAuthor(String author) + { + this.author = author; + } + + @Override + public String getAuthor() + { + return author; + } + + @Override + public void setDate(Date date) + { + this.date = date.getTime(); + } + + @Override + public Date getDate() + { + return new Date(date); + } +} diff --git a/RTF Parser Kit/src/com/rtfparserkit/document/impl/DefaultCharacterStyle.java b/RTF Parser Kit/src/com/rtfparserkit/document/impl/DefaultCharacterStyle.java new file mode 100644 index 0000000..22808fc --- /dev/null +++ b/RTF Parser Kit/src/com/rtfparserkit/document/impl/DefaultCharacterStyle.java @@ -0,0 +1,300 @@ +/* + * Copyright 2015 Stephan Aßmus + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.rtfparserkit.document.impl; + +import java.util.EnumSet; + +import com.rtfparserkit.document.CharacterStyle; +import com.rtfparserkit.document.Color; +import com.rtfparserkit.document.Font; +import com.rtfparserkit.document.Style; + +/** + * Default CharacterStyle implementation + */ +public class DefaultCharacterStyle extends DefaultStyle implements CharacterStyle +{ + private CharacterStyle parent; + + private Font font; + private float fontSize; + private boolean bold; + private boolean italic; + private UnderlineStyle underlineStyle; + private boolean strikeOut; + private boolean caps; + private Color backgroundColor; + private Color foregroundColor; + // TODO: Support more RTF properties + + static private final EnumSet CHARACTER_STYLE_PROPERTIES = EnumSet.of(Property.FONT, Property.FONT_SIZE, Property.BOLD, Property.ITALIC, Property.UNDERLINED, Property.STRIKE_OUT, Property.CAPS, Property.BACKGROUND_COLOR, Property.FOREGROUND_COLOR); + + public DefaultCharacterStyle() + { + parent = null; + resetToDefaults(); + } + + public DefaultCharacterStyle(CharacterStyle other) + { + parent = other; + } + + @Override + public CharacterStyle getParent() + { + return parent; + } + + @Override + public void resetToDefaults() + { + // TODO: Mechanics should probably be changed. Instead of having a + // method resetFontToDefaults() here, the StyleSheet should have methods + // to set and get the default style. And Style should have a method + // to set(Style other) to copy the values from the parameter. + // Then \plain can be handled by copying the default style. The problem + // is that there are RTF commands which define the default style values. + font = new DefaultFont("default"); + fontSize = 12.0f; + bold = false; + italic = false; + underlineStyle = UnderlineStyle.NONE; + strikeOut = false; + caps = false; + backgroundColor = DefaultColor.WHITE; + foregroundColor = DefaultColor.BLACK; + + overriddenProperties.addAll(CHARACTER_STYLE_PROPERTIES); + } + + @Override + public CharacterStyle createDerivedStyle() + { + return new DefaultCharacterStyle(this); + } + + @Override + public CharacterStyle createFlattenedStyle() + { + DefaultCharacterStyle style = new DefaultCharacterStyle(); + style.copyFrom(this); + return style; + } + + protected void copyFrom(CharacterStyle style) + { + font = style.getFont(); + fontSize = style.getFontSize(); + bold = style.getBold(); + italic = style.getItalic(); + underlineStyle = style.getUnderlined(); + strikeOut = style.getStrikeOut(); + caps = style.getCaps(); + backgroundColor = style.getBackgroundColor(); + foregroundColor = style.getForegroundColor(); + + overriddenProperties.addAll(CHARACTER_STYLE_PROPERTIES); + } + + @Override + public boolean equals(Style object) + { + if (object == this) + return true; + if (object == null || !(object instanceof DefaultCharacterStyle)) + return false; + if (!super.equals(object)) + return false; + + DefaultCharacterStyle other = (DefaultCharacterStyle) object; + return parent == other.parent && (font != null ? font.equals(other.font) : other.font == null) && fontSize == other.fontSize && bold == other.bold && italic == other.italic && underlineStyle == other.underlineStyle && strikeOut == other.strikeOut && caps == other.caps && backgroundColor == other.backgroundColor && foregroundColor == other.foregroundColor; + } + + @Override + public void setTo(Style other) + { + if (other == this) + return; + if (other == null) + throw new IllegalArgumentException("Style must not be null"); + if (!(other instanceof CharacterStyle)) + throw new IllegalArgumentException("Incompatible type of Style"); + + CharacterStyle style = (CharacterStyle) other; + + copyFrom(style); + parent = style.getParent(); + overriddenProperties = style.getOverriddenProperties(); + } + + @Override + public void setFont(Font font) + { + this.font = font; + overriddenProperties.add(Property.FONT); + } + + @Override + public Font getFont() + { + if (overriddenProperties.contains(Property.BOLD)) + return font; + else + return parent.getFont(); + } + + @Override + public void setFontSize(float value) + { + this.fontSize = value; + overriddenProperties.add(Property.FONT_SIZE); + } + + @Override + public float getFontSize() + { + if (overriddenProperties.contains(Property.FONT_SIZE)) + return fontSize; + else + return parent.getFontSize(); + } + + @Override + public void setBold(boolean bold) + { + this.bold = bold; + overriddenProperties.add(Property.BOLD); + } + + @Override + public boolean getBold() + { + if (overriddenProperties.contains(Property.BOLD)) + return bold; + else + return parent.getBold(); + } + + @Override + public void setItalic(boolean italic) + { + this.italic = italic; + overriddenProperties.add(Property.ITALIC); + } + + @Override + public boolean getItalic() + { + if (overriddenProperties.contains(Property.ITALIC)) + return italic; + else + return parent.getItalic(); + } + + @Override + public void setUnderlined(UnderlineStyle style) + { + this.underlineStyle = style; + overriddenProperties.add(Property.UNDERLINED); + } + + @Override + public UnderlineStyle getUnderlined() + { + if (overriddenProperties.contains(Property.UNDERLINED)) + return underlineStyle; + else + return parent.getUnderlined(); + } + + @Override + public void setStrikeOut(boolean strikeOut) + { + this.strikeOut = strikeOut; + overriddenProperties.add(Property.STRIKE_OUT); + } + + @Override + public boolean getStrikeOut() + { + if (overriddenProperties.contains(Property.STRIKE_OUT)) + return strikeOut; + else + return parent.getStrikeOut(); + } + + @Override + public void setCaps(boolean caps) + { + this.caps = caps; + overriddenProperties.add(Property.CAPS); + } + + @Override + public boolean getCaps() + { + if (overriddenProperties.contains(Property.CAPS)) + return caps; + else + return parent.getCaps(); + } + + @Override + public void setBackgroundColor(Color color) + { + if (color instanceof DefaultColor) + { + backgroundColor = (DefaultColor) color; + overriddenProperties.add(Property.BACKGROUND_COLOR); + } + } + + @Override + public Color getBackgroundColor() + { + if (overriddenProperties.contains(Property.BACKGROUND_COLOR)) + return backgroundColor; + else + return parent.getBackgroundColor(); + } + + @Override + public void setForegroundColor(Color color) + { + if (color instanceof DefaultColor) + { + foregroundColor = (DefaultColor) color; + overriddenProperties.add(Property.FOREGROUND_COLOR); + } + } + + @Override + public Color getForegroundColor() + { + if (overriddenProperties.contains(Property.FOREGROUND_COLOR)) + return foregroundColor; + else + return parent.getForegroundColor(); + } + + @Override + public String toString() + { + return "DefaultCharacterStyle(" + (font != null ? font.getName() : "") + "@" + fontSize + ", " + (bold ? "bold, " : "") + (italic ? "italic, " : "") + (underlineStyle != UnderlineStyle.NONE ? ("underline: " + underlineStyle.name() + ", ") : "") + "fg: " + foregroundColor + ", " + "bg: " + backgroundColor + ")"; + } +} diff --git a/RTF Parser Kit/src/com/rtfparserkit/document/impl/DefaultCharacterStyleTable.java b/RTF Parser Kit/src/com/rtfparserkit/document/impl/DefaultCharacterStyleTable.java new file mode 100644 index 0000000..3f418fc --- /dev/null +++ b/RTF Parser Kit/src/com/rtfparserkit/document/impl/DefaultCharacterStyleTable.java @@ -0,0 +1,32 @@ +/* + * Copyright 2015 Stephan Aßmus + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.rtfparserkit.document.impl; + +import com.rtfparserkit.document.CharacterStyle; +import com.rtfparserkit.document.CharacterStyleTable; + +/** + * Default CharacterStyleTable implementation. + */ +public class DefaultCharacterStyleTable extends StyleTableimplements CharacterStyleTable +{ + @Override + public CharacterStyle createStyle() + { + return new DefaultCharacterStyle(); + } +} diff --git a/RTF Parser Kit/src/com/rtfparserkit/document/impl/DefaultChunk.java b/RTF Parser Kit/src/com/rtfparserkit/document/impl/DefaultChunk.java new file mode 100644 index 0000000..3a7a4d1 --- /dev/null +++ b/RTF Parser Kit/src/com/rtfparserkit/document/impl/DefaultChunk.java @@ -0,0 +1,53 @@ +/* + * Copyright 2015 Stephan Aßmus + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.rtfparserkit.document.impl; + +import com.rtfparserkit.document.CharacterStyle; +import com.rtfparserkit.document.Chunk; + +/** + * Default Chunk implementation. + */ +public class DefaultChunk implements Chunk +{ + private final StringBuilder stringBuilder; + private final CharacterStyle style; + + public DefaultChunk(CharacterStyle style) + { + stringBuilder = new StringBuilder(); + this.style = style; + } + + @Override + public String getText() + { + return stringBuilder.toString(); + } + + @Override + public CharacterStyle getStyle() + { + return style; + } + + @Override + public void append(String string) + { + stringBuilder.append(string); + } +} diff --git a/RTF Parser Kit/src/com/rtfparserkit/document/impl/DefaultColor.java b/RTF Parser Kit/src/com/rtfparserkit/document/impl/DefaultColor.java new file mode 100644 index 0000000..bba44ef --- /dev/null +++ b/RTF Parser Kit/src/com/rtfparserkit/document/impl/DefaultColor.java @@ -0,0 +1,71 @@ +/* + * Copyright 2015 Stephan Aßmus + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.rtfparserkit.document.impl; + +import com.rtfparserkit.document.Color; + +/** + * Default Color implementation. After creation, DefaultColor is not mutable. + */ +public class DefaultColor implements Color +{ + + private final int red; + private final int green; + private final int blue; + + static final DefaultColor BLACK = new DefaultColor(0, 0, 0); + static final DefaultColor WHITE = new DefaultColor(255, 255, 255); + + public DefaultColor(int red, int green, int blue) + { + this.red = red; + this.green = green; + this.blue = blue; + } + + public DefaultColor(Color other) + { + this.red = other.getRed(); + this.green = other.getGreen(); + this.blue = other.getBlue(); + } + + @Override + public int getRed() + { + return red; + } + + @Override + public int getGreen() + { + return green; + } + + @Override + public int getBlue() + { + return blue; + } + + @Override + public String toString() + { + return "(r" + red + "g" + green + "b" + blue + ")"; + } +} diff --git a/RTF Parser Kit/src/com/rtfparserkit/document/impl/DefaultColorTable.java b/RTF Parser Kit/src/com/rtfparserkit/document/impl/DefaultColorTable.java new file mode 100644 index 0000000..62139b0 --- /dev/null +++ b/RTF Parser Kit/src/com/rtfparserkit/document/impl/DefaultColorTable.java @@ -0,0 +1,55 @@ +/* + * Copyright 2015 Stephan Aßmus + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.rtfparserkit.document.impl; + +import java.util.ArrayList; +import java.util.List; + +import com.rtfparserkit.document.Color; +import com.rtfparserkit.document.ColorTable; + +/** + * Default implementation of ColorTable. + */ +public class DefaultColorTable implements ColorTable +{ + + private final List colors; + + public DefaultColorTable() + { + colors = new ArrayList(); + } + + @Override + public void addColor(int red, int green, int blue) + { + colors.add(new DefaultColor(red, green, blue)); + } + + @Override + public int countColors() + { + return colors.size(); + } + + @Override + public Color colorAt(int index) + { + return colors.get(index); + } +} diff --git a/RTF Parser Kit/src/com/rtfparserkit/document/impl/DefaultDocument.java b/RTF Parser Kit/src/com/rtfparserkit/document/impl/DefaultDocument.java new file mode 100644 index 0000000..e13163e --- /dev/null +++ b/RTF Parser Kit/src/com/rtfparserkit/document/impl/DefaultDocument.java @@ -0,0 +1,208 @@ +/* + * Copyright 2015 Stephan Aßmus + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.rtfparserkit.document.impl; + +import com.rtfparserkit.document.Annotation; +import com.rtfparserkit.document.CharacterStyle; +import com.rtfparserkit.document.Document; +import com.rtfparserkit.document.DocumentSettings; +import com.rtfparserkit.document.PageSettings; +import com.rtfparserkit.document.Paragraph; +import com.rtfparserkit.document.ParagraphStyle; +import com.rtfparserkit.document.Section; + +/** + * Default implementation of Document. Note that Document itself is also + * a DocumentPart. It implements relevant functionality by forwarding to the + * last Section. + */ +public class DefaultDocument extends SectionList implements Document +{ + + private final DefaultColorTable colors = new DefaultColorTable(); + private final DefaultFontTable fonts = new DefaultFontTable(); + private final DefaultStyleSheet styles = new DefaultStyleSheet(); + + private final PageMargins pageMargins = new PageMargins(); + private final PageSize pageSize = new PageSize(); + + @Override + public DefaultFontTable getFontTable() + { + return fonts; + } + + @Override + public DefaultColorTable getColorTable() + { + return colors; + } + + @Override + public DefaultStyleSheet getStyleSheet() + { + return styles; + } + + public PageMargins getPageMargins() + { + return pageMargins; + } + + public PageSize getPageSize() + { + return pageSize; + } + + @Override + public DocumentSettings getDocumentSettings() + { + return new DocumentSettings() + { + + @Override + public PageSettings getPageSettings() + { + return new PageSettings() + { + @Override + public void setPageMarginLeft(int value) + { + pageMargins.left = value; + } + + @Override + public void setPageMarginRight(int value) + { + pageMargins.right = value; + } + + @Override + public void setPageMarginTop(int value) + { + pageMargins.top = value; + } + + @Override + public void setPageMarginBottom(int value) + { + pageMargins.bottom = value; + } + + @Override + public void setPageWidth(int value) + { + pageSize.width = value; + } + + @Override + public void setPageHeight(int value) + { + pageSize.height = value; + } + }; + } + }; + } + + /** + * Appends a string of text to the last Section. + * + * @param text The string to append + * @param style The Style in which the appended string is to appear. + */ + @Override + public void append(String text, CharacterStyle style) + { + getLastSection().append(text, style); + } + + /** + * Starts a new Paragraph at the last Section and sets the Style of the + * previous last Paragraph. + * + * @param lastStyle The Style to be set on the previous paragraph. + */ + @Override + public void nextParagraph(CharacterStyle lastStyle) + { + getLastSection().nextParagraph(lastStyle); + } + + /** + * Creates a new line at the last Section. + */ + @Override + public void nextLine() + { + getLastSection().nextLine(); + } + + /** + * @return The default Style created by the last Section. + */ + @Override + public ParagraphStyle createDefaultStyle() + { + return getLastSection().createDefaultStyle(); + } + + /** + * @return The total count of all paragraphs contained in all Sections. + */ + @Override + public int countParagraphs() + { + int count = 0; + for (Section section : this) + count += section.countParagraphs(); + return count; + } + + /** + * @param index The index of the paragraph relative to the total paragraph + * count of all Sections. + */ + @Override + public Paragraph paragraphAt(int index) + { + int originalIndex = index; + for (Section section : this) + { + int paragrapgsInSection = section.countParagraphs(); + if (index > paragrapgsInSection) + { + index -= paragrapgsInSection; + continue; + } + return section.paragraphAt(index); + } + + throw new IndexOutOfBoundsException("paragraphs in section: " + countParagraphs() + ", requested index: " + originalIndex); + } + + /** + * Creates a new Annotation instance and appends it to the last Section. + * + * @return The appended annotation + */ + @Override + public Annotation appendAnnotation() + { + return getLastSection().appendAnnotation(); + } +} diff --git a/RTF Parser Kit/src/com/rtfparserkit/document/impl/DefaultFont.java b/RTF Parser Kit/src/com/rtfparserkit/document/impl/DefaultFont.java new file mode 100644 index 0000000..b7b6e34 --- /dev/null +++ b/RTF Parser Kit/src/com/rtfparserkit/document/impl/DefaultFont.java @@ -0,0 +1,58 @@ +/* + * Copyright 2015 Stephan Aßmus + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.rtfparserkit.document.impl; + +import com.rtfparserkit.document.Font; + +/** + * Default Font implementation + */ +public class DefaultFont implements Font +{ + private String name; + + public DefaultFont(String fontName) + { + name = fontName; + } + + @Override + public void setName(String name) + { + this.name = name; + } + + @Override + public String getName() + { + return name; + } + + @Override + public boolean equals(Font object) + { + if (object == this) + return true; + if (object == null || object.getClass() != DefaultFont.class) + return false; + DefaultFont other = (DefaultFont) object; + return name.equals(other.name); + } + + // TODO: Hold all necessary data. + +} diff --git a/RTF Parser Kit/src/com/rtfparserkit/document/impl/DefaultFontTable.java b/RTF Parser Kit/src/com/rtfparserkit/document/impl/DefaultFontTable.java new file mode 100644 index 0000000..686c29d --- /dev/null +++ b/RTF Parser Kit/src/com/rtfparserkit/document/impl/DefaultFontTable.java @@ -0,0 +1,42 @@ + +package com.rtfparserkit.document.impl; + +import java.util.HashMap; +import java.util.Iterator; + +import com.rtfparserkit.document.Font; +import com.rtfparserkit.document.FontTable; + +public class DefaultFontTable implements FontTable +{ + private final HashMap fonts; + + public DefaultFontTable() + { + fonts = new HashMap(); + } + + @Override + public void addFont(int id, String name, String alternativeName, String fileName, FontFamily fontFamily) + { + fonts.put(id, new DefaultFont(name)); + } + + @Override + public int countFonts() + { + return fonts.size(); + } + + @Override + public Font fontFor(int id) + { + return fonts.get(id); + } + + @Override + public Iterator iterator() + { + return fonts.values().iterator(); + } +} diff --git a/RTF Parser Kit/src/com/rtfparserkit/document/impl/DefaultFooter.java b/RTF Parser Kit/src/com/rtfparserkit/document/impl/DefaultFooter.java new file mode 100644 index 0000000..8aef754 --- /dev/null +++ b/RTF Parser Kit/src/com/rtfparserkit/document/impl/DefaultFooter.java @@ -0,0 +1,27 @@ +/* + * Copyright 2015 Stephan Aßmus + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.rtfparserkit.document.impl; + +import com.rtfparserkit.document.Footer; + +/** + * Default Footer implementation. + */ +public class DefaultFooter extends ParagraphList implements Footer +{ + +} diff --git a/RTF Parser Kit/src/com/rtfparserkit/document/impl/DefaultHeader.java b/RTF Parser Kit/src/com/rtfparserkit/document/impl/DefaultHeader.java new file mode 100644 index 0000000..36ed356 --- /dev/null +++ b/RTF Parser Kit/src/com/rtfparserkit/document/impl/DefaultHeader.java @@ -0,0 +1,27 @@ +/* + * Copyright 2015 Stephan Aßmus + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.rtfparserkit.document.impl; + +import com.rtfparserkit.document.Header; + +/** + * Default Header implementation + */ +public class DefaultHeader extends ParagraphList implements Header +{ + +} diff --git a/RTF Parser Kit/src/com/rtfparserkit/document/impl/DefaultParagraph.java b/RTF Parser Kit/src/com/rtfparserkit/document/impl/DefaultParagraph.java new file mode 100644 index 0000000..b0f7087 --- /dev/null +++ b/RTF Parser Kit/src/com/rtfparserkit/document/impl/DefaultParagraph.java @@ -0,0 +1,202 @@ +/* + * Copyright 2015 Stephan Aßmus + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.rtfparserkit.document.impl; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import com.rtfparserkit.document.CharacterStyle; +import com.rtfparserkit.document.Chunk; +import com.rtfparserkit.document.Element; +import com.rtfparserkit.document.Paragraph; +import com.rtfparserkit.document.ParagraphStyle; + +/** + * Default Paragraph implementation + */ +public class DefaultParagraph implements Iterable, Paragraph +{ + private final List chunks; + private ParagraphStyle style; + + public DefaultParagraph() + { + this(new DefaultParagraphStyle()); + } + + public DefaultParagraph(ParagraphStyle style) + { + chunks = new ArrayList(); + this.style = style; + } + + @Override + public Iterator iterator() + { + return chunks.iterator(); + } + + @Override + public String getText() + { + StringBuilder builder = new StringBuilder(); + for (Element element : chunks) + { + if (element instanceof Chunk) + builder.append(((Chunk) element).getText()); + } + return builder.toString(); + } + + @Override + public int countElements() + { + return chunks.size(); + } + + @Override + public Element elementAt(int index) + { + return chunks.get(index); + } + + @Override + public ParagraphStyle getStyle() + { + return style; + } + + public void append(Element element) + { + if (element == null) + throw new IllegalArgumentException("Element may not be null"); + chunks.add(element); + } + + /** + * Appends the string to the Paragraph. If the last Element of the Paragraph + * is a Chunk, the string will be appended to the Chunk. Otherwise a new + * Chunk will be created to hold the String. If the Paragraph already + * contains any Chunks, the Style of the last Chunk is used for the string. + * The paragraph may not already be delimited (end with '\n'). The appended + * string may contain a delimiter ('\n'), but it must be at the end of the + * string. + * + * @param string The string to append + */ + public void append(String string) + { + append(string, getLastStyle()); + } + + /** + * Appends the string to the Paragraph. If the last Element of the Paragraph + * is a Chunk, the string will be appended to that Chunk if the Style + * matches the Style of the last Chunk. Otherwise a new Chunk with the given + * Style will be created to hold the String. + * The paragraph may not already be delimited (end with '\n'). The appended + * string may contain a delimiter ('\n'), but it must be at the end of the + * string. + * + * @param string The string to append + * @param style The Style in which the string is to appear + */ + public void append(String string, CharacterStyle style) + { + if (string == null) + throw new IllegalArgumentException("String may not be null!"); + if (style == null) + throw new IllegalArgumentException("Style may not be null!"); + int firstLineBreak = string.indexOf('\n'); + if (firstLineBreak >= 0 && firstLineBreak != string.length() - 1) + { + throw new IllegalArgumentException("String must not contain a " + "line-break (\\n) unless right at the end."); + } + assertNotDelimited(); + appendString(string, style); + } + + public void end() + { + end(getLastStyle()); + } + + public void end(CharacterStyle lastStyle) + { + append("\n", lastStyle); + } + + public CharacterStyle getLastStyle() + { + // Try to use the last used Style instead of the default style + Chunk lastChunk = findLastChunk(); + if (lastChunk != null) + return lastChunk.getStyle(); + + return style; + } + + /** + * Makes sure that the paragraph doesn't already end with '\n'. + */ + private void assertNotDelimited() + { + for (int i = chunks.size() - 1; i >= 0; i--) + { + Element element = chunks.get(i); + if (element instanceof Chunk) + { + Chunk chunk = (Chunk) element; + if (chunk.getText().endsWith("\n")) + { + throw new IllegalArgumentException("Paragraph is already delimited."); + } + break; + } + } + } + + private void appendString(String string, CharacterStyle style) + { + Chunk chunk = null; + if (chunks.size() > 0) + { + Element last = chunks.get(chunks.size() - 1); + if (last instanceof Chunk) + chunk = (Chunk) last; + } + if (chunk == null || !chunk.getStyle().equals(style)) + { + chunk = new DefaultChunk(style); + append(chunk); + } + chunk.append(string); + } + + private Chunk findLastChunk() + { + for (int i = chunks.size() - 1; i >= 0; i--) + { + Element element = chunks.get(i); + if (element instanceof Chunk) + return (Chunk) element; + } + + return null; + } +} diff --git a/RTF Parser Kit/src/com/rtfparserkit/document/impl/DefaultParagraphStyle.java b/RTF Parser Kit/src/com/rtfparserkit/document/impl/DefaultParagraphStyle.java new file mode 100644 index 0000000..df1740f --- /dev/null +++ b/RTF Parser Kit/src/com/rtfparserkit/document/impl/DefaultParagraphStyle.java @@ -0,0 +1,264 @@ +/* + * Copyright 2015 Stephan Aßmus + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.rtfparserkit.document.impl; + +import java.util.EnumSet; + +import com.rtfparserkit.document.CharacterStyle; +import com.rtfparserkit.document.ParagraphStyle; +import com.rtfparserkit.document.Style; + +/** + * Default ParagraphStyle implementation + */ +public class DefaultParagraphStyle extends DefaultCharacterStyle implements ParagraphStyle +{ + private ParagraphStyle parent; + + private Alignment alignment; + private float spacingTop; + private float spacingBottom; + private float firstLineIndent; + private float leftIndent; + private float rightIndent; + private float lineSpacing; + // TODO: Support more RTF properties + + public DefaultParagraphStyle() + { + parent = null; + resetToDefaults(); + } + + public DefaultParagraphStyle(ParagraphStyle other) + { + super(other); + parent = other; + } + + @Override + public ParagraphStyle getParent() + { + return parent; + } + + @Override + public void resetToDefaults() + { + super.resetToDefaults(); + + alignment = Alignment.LEFT; + spacingTop = 0; + spacingBottom = 0; + firstLineIndent = 0; + leftIndent = 0; + rightIndent = 0; + lineSpacing = 0; + + overriddenProperties = EnumSet.allOf(Property.class); + } + + @Override + public ParagraphStyle createDerivedStyle() + { + return new DefaultParagraphStyle(this); + } + + @Override + public CharacterStyle createDerivedCharacterStyle() + { + return new DefaultCharacterStyle(this); + } + + @Override + public ParagraphStyle createFlattenedStyle() + { + DefaultParagraphStyle style = new DefaultParagraphStyle(); + style.copyFrom(this); + return style; + } + + protected void copyFrom(ParagraphStyle style) + { + super.copyFrom(style); + + alignment = style.getAlignment(); + spacingTop = style.getSpacingTop(); + spacingBottom = style.getSpacingBottom(); + firstLineIndent = style.getFirstLineIndent(); + leftIndent = style.getLeftIndent(); + rightIndent = style.getRightIndent(); + lineSpacing = style.getLineSpacing(); + + overriddenProperties = EnumSet.allOf(Property.class); + } + + @Override + public boolean equals(Style object) + { + if (object == this) + return true; + if (object == null || !(object instanceof DefaultParagraphStyle)) + return false; + if (!super.equals(object)) + return false; + + DefaultParagraphStyle other = (DefaultParagraphStyle) object; + return parent == other.parent && alignment == other.alignment && spacingTop == other.spacingTop && spacingBottom == other.spacingBottom && firstLineIndent == other.firstLineIndent && leftIndent == other.leftIndent && rightIndent == other.rightIndent && lineSpacing == other.lineSpacing; + } + + @Override + public void setTo(Style other) + { + if (other == this) + return; + if (other == null) + throw new IllegalArgumentException("Style must not be null"); + if (!(other instanceof CharacterStyle)) + throw new IllegalArgumentException("Incompatible type of Style"); + + ParagraphStyle style = (ParagraphStyle) other; + + copyFrom(style); + parent = style.getParent(); + overriddenProperties = style.getOverriddenProperties(); + } + + @Override + public void setAlignment(Alignment alignment) + { + this.alignment = alignment; + overriddenProperties.add(Property.ALIGNMENT); + } + + @Override + public Alignment getAlignment() + { + if (overriddenProperties.contains(Property.ALIGNMENT)) + return alignment; + else + return parent.getAlignment(); + } + + @Override + public void setSpacingTop(float value) + { + spacingTop = value; + overriddenProperties.add(Property.SPACING_TOP); + } + + @Override + public float getSpacingTop() + { + if (overriddenProperties.contains(Property.SPACING_TOP)) + return spacingTop; + else + return parent.getSpacingTop(); + } + + @Override + public void setSpacingBottom(float value) + { + spacingBottom = value; + overriddenProperties.add(Property.SPACING_BOTTOM); + } + + @Override + public float getSpacingBottom() + { + if (overriddenProperties.contains(Property.SPACING_BOTTOM)) + return spacingBottom; + else + return parent.getSpacingBottom(); + } + + @Override + public void setFirstLineIndent(float value) + { + firstLineIndent = value; + overriddenProperties.add(Property.FIRST_LINE_INDENT); + } + + @Override + public float getFirstLineIndent() + { + if (overriddenProperties.contains(Property.FIRST_LINE_INDENT)) + return firstLineIndent; + else + return parent.getFirstLineIndent(); + } + + @Override + public void setLeftIndent(float value) + { + leftIndent = value; + overriddenProperties.add(Property.LEFT_INDENT); + } + + @Override + public float getLeftIndent() + { + if (overriddenProperties.contains(Property.LEFT_INDENT)) + return leftIndent; + else + return parent.getLeftIndent(); + } + + @Override + public void setRightIndent(float value) + { + rightIndent = value; + overriddenProperties.add(Property.RIGHT_INDENT); + } + + @Override + public float getRightIndent() + { + if (overriddenProperties.contains(Property.RIGHT_INDENT)) + return rightIndent; + else + return parent.getRightIndent(); + } + + @Override + public void setLineSpacing(float value) + { + lineSpacing = value; + overriddenProperties.add(Property.LINE_SPACING); + } + + @Override + public float getLineSpacing() + { + if (overriddenProperties.contains(Property.LINE_SPACING)) + return lineSpacing; + else + return parent.getLineSpacing(); + } + + @Override + public void addTab(float position, TabAlignment aligment) + { + // TODO Auto-generated method stub + } + + @Override + public String toString() + { + return "ParagraphStyle(" + alignment.name() + ", " + (getFont() != null ? getFont().getName() : "") + "@" + getFontSize() + ", " + (getBold() ? "bold, " : "") + (getItalic() ? "italic, " : "") + (getUnderlined() != UnderlineStyle.NONE ? ("underline: " + getUnderlined().name() + ", ") : "") + "fg: " + getForegroundColor() + ", " + "bg: " + getBackgroundColor() + ")"; + } +} diff --git a/RTF Parser Kit/src/com/rtfparserkit/document/impl/DefaultParagraphStyleTable.java b/RTF Parser Kit/src/com/rtfparserkit/document/impl/DefaultParagraphStyleTable.java new file mode 100644 index 0000000..4fc22da --- /dev/null +++ b/RTF Parser Kit/src/com/rtfparserkit/document/impl/DefaultParagraphStyleTable.java @@ -0,0 +1,34 @@ +/* + * Copyright 2015 Stephan Aßmus + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.rtfparserkit.document.impl; + +import com.rtfparserkit.document.ParagraphStyle; +import com.rtfparserkit.document.ParagraphStyleTable; + +/** + * Default ParagraphStyleTable implementation. + */ +public class DefaultParagraphStyleTable extends StyleTableimplements ParagraphStyleTable +{ + + @Override + public ParagraphStyle createStyle() + { + return new DefaultParagraphStyle(); + } + +} diff --git a/RTF Parser Kit/src/com/rtfparserkit/document/impl/DefaultSection.java b/RTF Parser Kit/src/com/rtfparserkit/document/impl/DefaultSection.java new file mode 100644 index 0000000..4b8c20f --- /dev/null +++ b/RTF Parser Kit/src/com/rtfparserkit/document/impl/DefaultSection.java @@ -0,0 +1,117 @@ +/* + * Copyright 2015 Stephan Aßmus + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.rtfparserkit.document.impl; + +import com.rtfparserkit.document.Footer; +import com.rtfparserkit.document.Header; +import com.rtfparserkit.document.PageSettings; +import com.rtfparserkit.document.Section; + +/** + * Default Section implementation + */ +public class DefaultSection extends ParagraphList implements Section +{ + + private DefaultHeader header; + private DefaultFooter footer; + private final PageMargins pageMargins = new PageMargins(); + private final PageSize pageSize = new PageSize(); + + @Override + public Header createHeader() + { + if (header == null) + header = new DefaultHeader(); + return header; + } + + @Override + public Header getHeader() + { + return header; + } + + @Override + public Footer createFooter() + { + if (footer == null) + footer = new DefaultFooter(); + return footer; + } + + @Override + public Footer getFooter() + { + return footer; + } + + public PageMargins getPageMargins() + { + return pageMargins; + } + + public PageSize getPageSize() + { + return pageSize; + } + + @Override + public PageSettings getPageSettings() + { + return new PageSettings() + { + + @Override + public void setPageMarginLeft(int value) + { + pageMargins.left = value; + } + + @Override + public void setPageMarginRight(int value) + { + pageMargins.right = value; + } + + @Override + public void setPageMarginTop(int value) + { + pageMargins.top = value; + } + + @Override + public void setPageMarginBottom(int value) + { + pageMargins.bottom = value; + } + + @Override + public void setPageWidth(int value) + { + pageSize.width = value; + } + + @Override + public void setPageHeight(int value) + { + pageSize.height = value; + } + }; + } + +} diff --git a/RTF Parser Kit/src/com/rtfparserkit/document/impl/DefaultStyle.java b/RTF Parser Kit/src/com/rtfparserkit/document/impl/DefaultStyle.java new file mode 100644 index 0000000..c5ca84f --- /dev/null +++ b/RTF Parser Kit/src/com/rtfparserkit/document/impl/DefaultStyle.java @@ -0,0 +1,66 @@ +/* + * Copyright 2015 Stephan Aßmus + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.rtfparserkit.document.impl; + +import java.util.EnumSet; + +import com.rtfparserkit.document.Style; + +/** + * Default Style implementation + */ +abstract class DefaultStyle implements Style +{ + + private String name; + protected EnumSet overriddenProperties; + + protected DefaultStyle() + { + overriddenProperties = EnumSet.noneOf(Property.class); + } + + @Override + public void setName(String name) + { + this.name = name; + } + + @Override + public String getName() + { + return name; + } + + @Override + public EnumSet getOverriddenProperties() + { + return overriddenProperties; + } + + @Override + public boolean equals(Style object) + { + if (object == this) + return true; + if (object == null || !(object instanceof DefaultStyle)) + return false; + + DefaultStyle other = (DefaultStyle) object; + return (name != null ? name.equals(other.name) : other.name == null) && overriddenProperties.equals(other.overriddenProperties); + } +} diff --git a/RTF Parser Kit/src/com/rtfparserkit/document/impl/DefaultStyleSheet.java b/RTF Parser Kit/src/com/rtfparserkit/document/impl/DefaultStyleSheet.java new file mode 100644 index 0000000..8a4201c --- /dev/null +++ b/RTF Parser Kit/src/com/rtfparserkit/document/impl/DefaultStyleSheet.java @@ -0,0 +1,46 @@ +/* + * Copyright 2015 Stephan Aßmus + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.rtfparserkit.document.impl; + +import com.rtfparserkit.document.CharacterStyleTable; +import com.rtfparserkit.document.ParagraphStyleTable; +import com.rtfparserkit.document.StyleSheet; + +class DefaultStyleSheet implements StyleSheet +{ + + private final ParagraphStyleTable paragraphStyleTable; + private final CharacterStyleTable characterStyleTable; + + DefaultStyleSheet() + { + paragraphStyleTable = new DefaultParagraphStyleTable(); + characterStyleTable = new DefaultCharacterStyleTable(); + } + + @Override + public ParagraphStyleTable getParagraphStyleTable() + { + return paragraphStyleTable; + } + + @Override + public CharacterStyleTable getCharacterStyleTable() + { + return characterStyleTable; + } +} diff --git a/RTF Parser Kit/src/com/rtfparserkit/document/impl/PageMargins.java b/RTF Parser Kit/src/com/rtfparserkit/document/impl/PageMargins.java new file mode 100644 index 0000000..d229d17 --- /dev/null +++ b/RTF Parser Kit/src/com/rtfparserkit/document/impl/PageMargins.java @@ -0,0 +1,28 @@ +/* + * Copyright 2015 Stephan Aßmus + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.rtfparserkit.document.impl; + +/** + * Simple parameter storage for page margins. + */ +public class PageMargins +{ + public int left; + public int right; + public int top; + public int bottom; +} diff --git a/RTF Parser Kit/src/com/rtfparserkit/document/impl/PageSize.java b/RTF Parser Kit/src/com/rtfparserkit/document/impl/PageSize.java new file mode 100644 index 0000000..283405b --- /dev/null +++ b/RTF Parser Kit/src/com/rtfparserkit/document/impl/PageSize.java @@ -0,0 +1,26 @@ +/* + * Copyright 2015 Stephan Aßmus + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.rtfparserkit.document.impl; + +/** + * Simple parameter storage for page size. + */ +public class PageSize +{ + public int width; + public int height; +} diff --git a/RTF Parser Kit/src/com/rtfparserkit/document/impl/ParagraphList.java b/RTF Parser Kit/src/com/rtfparserkit/document/impl/ParagraphList.java new file mode 100644 index 0000000..7df785d --- /dev/null +++ b/RTF Parser Kit/src/com/rtfparserkit/document/impl/ParagraphList.java @@ -0,0 +1,216 @@ +/* + * Copyright 2015 Stephan Aßmus + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.rtfparserkit.document.impl; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import com.rtfparserkit.document.Annotation; +import com.rtfparserkit.document.CharacterStyle; +import com.rtfparserkit.document.DocumentPart; +import com.rtfparserkit.document.Paragraph; +import com.rtfparserkit.document.ParagraphStyle; + +/** + * A list of Paragraph objects. There is always at least one, empty paragraph + * in the list. + */ +public class ParagraphList implements Iterable, DocumentPart +{ + private final List paragraphs; + + /** + * Creates a new instance which already contains an empty initial paragraph + * by calling clear(). + */ + public ParagraphList() + { + paragraphs = new ArrayList(); + clear(); + } + + /** + * Returns and iterator over the Paragraphs contained in this list. + */ + @Override + public Iterator iterator() + { + return new ParagraphIterator(paragraphs.iterator()); + } + + /** + * Finalizes the current paragraph by appending a line-break character '\n'. + * Starts the next paragraph by appending a new empty Paragraph to the list. + */ + @Override + public void nextParagraph(CharacterStyle lastStyle) + { + if (countParagraphs() > 0) + getLastParagraph().end(lastStyle); + paragraphs.add(new DefaultParagraph()); + } + + /** + * Implements nextLine() by appending the Unicode character "Line Separator" + * to the current paragraph. + */ + @Override + public void nextLine() + { + getLastParagraph().append("\u2028"); + } + + /** + * @return The concatenated text of all contained Paragraphs. + */ + @Override + public String getText() + { + StringBuilder builder = new StringBuilder(); + for (Paragraph paragraph : paragraphs) + builder.append(paragraph.getText()); + return builder.toString(); + } + + @Override + public ParagraphStyle createDefaultStyle() + { + return new DefaultParagraphStyle(); + } + + /** + * Implements handleText() by separating the given text at line-breaks + * (calling nextParagraph() at '\n') and appending the chunks between + * line-breaks to the currently last Paragraph. This makes sure that all + * paragraphs in this list are normalized in that the last paragraph never + * contains a line-break, while all preceding paragraphs contain exactly + * one line-break which is at the very end of the paragraph. + * + * @param text The string to append. + * + * @see #nextParagraph() + */ + @Override + public void append(String text, CharacterStyle style) + { + int offset = 0; + while (offset < text.length()) + { + int nextLineBreak = text.indexOf('\n', offset); + if (nextLineBreak == offset) + { + nextParagraph(style); + offset++; + continue; + } + + int end = nextLineBreak > offset ? nextLineBreak : text.length(); + String subString = text.substring(offset, end); + getLastParagraph().append(subString, style); + + offset = end; + } + } + + public void append(String string) + { + CharacterStyle style = getLastParagraph().getLastStyle(); + append(string, style); + } + + @Override + public Annotation appendAnnotation() + { + Annotation annotation = new DefaultAnnotation(); + getLastParagraph().append(annotation); + return annotation; + } + + /** + * Removes all Paragraphs that are currently in the list and adds a new + * empty Paragraph as the initial Paragraph by calling nextParagraph() + */ + public void clear() + { + paragraphs.clear(); + // Add the initial empty paragraph + nextParagraph(new DefaultParagraphStyle()); + } + + /** + * @return The last Paragraph of the list. There is always at least + * one paragraph in the list. + */ + public DefaultParagraph getLastParagraph() + { + return paragraphs.get(paragraphs.size() - 1); + } + + /** + * @return The number of paragraphs in this list. + */ + @Override + public int countParagraphs() + { + return paragraphs.size(); + } + + /** + * Return the Paragraph at the specified index. + * + * @param index The index of the desired paragraph. The index must be + * >= 0 and < countParagraphs(). + * @return The paragraph at the given index. Throws an + * IndexOutOfBoundsExpception if index is out of bounds. + */ + @Override + public Paragraph paragraphAt(int index) + { + return paragraphs.get(index); + } + + private static class ParagraphIterator implements Iterator + { + + private final Iterator internalIterator; + + ParagraphIterator(Iterator iterator) + { + internalIterator = iterator; + } + + @Override + public boolean hasNext() + { + return internalIterator.hasNext(); + } + + @Override + public Paragraph next() + { + return internalIterator.next(); + } + + @Override + public void remove() + { + internalIterator.remove(); + } + + } +} diff --git a/RTF Parser Kit/src/com/rtfparserkit/document/impl/SectionList.java b/RTF Parser Kit/src/com/rtfparserkit/document/impl/SectionList.java new file mode 100644 index 0000000..52b6b1a --- /dev/null +++ b/RTF Parser Kit/src/com/rtfparserkit/document/impl/SectionList.java @@ -0,0 +1,110 @@ +/* + * Copyright 2015 Stephan Aßmus + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.rtfparserkit.document.impl; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +/** + * A list of Section objects. There is always at least one, empty section + * in the list. + */ +public class SectionList implements Iterable +{ + private final List sections; + + /** + * Creates a new instance which already contains an empty initial section + * by calling clear(). + */ + public SectionList() + { + sections = new ArrayList(); + clear(); + } + + /** + * Returns and iterator over the Sections contained in this list. + */ + @Override + public Iterator iterator() + { + return sections.iterator(); + } + + /** + * Starts the next Section by appending a new empty Section to the list. + */ + public void nextSection() + { + DefaultSection next = new DefaultSection(); + sections.add(next); + } + + /** + * Removes all Sections that are currently in the list and adds a new + * empty Section as the initial Section by calling nextSection() + */ + public void clear() + { + sections.clear(); + // Add the initial empty section + nextSection(); + } + + /** + * @return The last Paragraph of the list. There is always at least + * one paragraph in the list. + */ + public DefaultSection getLastSection() + { + return sections.get(sections.size() - 1); + } + + /** + * @return The number of paragraphs in this list. + */ + public int countSections() + { + return sections.size(); + } + + /** + * Return the Section at the specified index. + * + * @param index The index of the desired section. The index must be + * >= 0 and < countSections(). + * @return The Section at the given index. Throws an + * IndexOutOfBoundsExpception if index is out of bounds. + */ + public DefaultSection sectionAt(int index) + { + return sections.get(index); + } + + /** + * @return The concatenated text of all contained Sections. + */ + public String getText() + { + StringBuilder builder = new StringBuilder(); + for (DefaultSection section : sections) + builder.append(section.getText()); + return builder.toString(); + } +} diff --git a/RTF Parser Kit/src/com/rtfparserkit/document/impl/StyleTable.java b/RTF Parser Kit/src/com/rtfparserkit/document/impl/StyleTable.java new file mode 100644 index 0000000..342df97 --- /dev/null +++ b/RTF Parser Kit/src/com/rtfparserkit/document/impl/StyleTable.java @@ -0,0 +1,56 @@ +/* + * Copyright 2015 Stephan Aßmus + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.rtfparserkit.document.impl; + +import java.util.HashMap; +import java.util.Iterator; + +import com.rtfparserkit.document.Style; + +/** + * A table of Style objects. Styles can be added and retrieved by ID. + */ +class StyleTable implements Iterable +{ + private final HashMap styles; + + StyleTable() + { + styles = new HashMap(); + } + + @Override + public Iterator iterator() + { + return styles.values().iterator(); + } + + public void addStyle(int id, E style) + { + styles.put(id, style); + } + + public int countStyles() + { + return styles.size(); + } + + public E styleFor(int id) + { + return styles.get(id); + } +} diff --git a/RTF Parser Kit/src/com/rtfparserkit/parser/builder/AbstractRtfContext.java b/RTF Parser Kit/src/com/rtfparserkit/parser/builder/AbstractRtfContext.java new file mode 100644 index 0000000..d5c2e76 --- /dev/null +++ b/RTF Parser Kit/src/com/rtfparserkit/parser/builder/AbstractRtfContext.java @@ -0,0 +1,94 @@ +/* + * Copyright 2015 Stephan Aßmus + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.rtfparserkit.parser.builder; + +import com.rtfparserkit.rtf.Command; + +/** + * An implementation of all methods defined by RtfContext. All methods + * throw an IllegalStateException, unless the object is configured not to + * throw exception at construction time. The idea is that derived classes + * implement exactly the needed functionality and RTF events resulting in + * calling methods which have not been overridden means something is wrong. + * The only method which is supposed to be used by sub-classes is + * processGroupEnd(), which pops the context from the provided RtfContextStack. + */ +abstract class AbstractRtfContext implements RtfContext +{ + + private final boolean throwExceptions; + + protected AbstractRtfContext() + { + this(true); + } + + protected AbstractRtfContext(boolean throwExceptions) + { + this.throwExceptions = throwExceptions; + } + + @Override + public void processGroupStart(RtfContextStack stack) + { + handleUnexpectedEvent("Unexpected anonymous group start"); + stack.pushContext(this); + } + + @Override + public void processGroupStart(RtfContextStack stack, Command command, int parameter, boolean hasParameter, boolean optional) + { + handleUnexpectedEvent("Unexpected destination group start"); + stack.pushContext(this); + } + + @Override + public void processGroupEnd(RtfContextStack stack) + { + stack.popContext(); + } + + @Override + public void processCharacterBytes(byte[] data) + { + handleUnexpectedEvent("Unexpected character bytes"); + } + + @Override + public void processBinaryBytes(byte[] data) + { + handleUnexpectedEvent("Unexpected binary bytes"); + } + + @Override + public void processString(String string) + { + handleUnexpectedEvent("Unexpected string '" + string + "'"); + } + + @Override + public void processCommand(RtfContextStack stack, Command command, int parameter, boolean hasParameter, boolean optional) + { + handleUnexpectedEvent("Unexpected command '" + command + "'"); + } + + private void handleUnexpectedEvent(String eventInfo) + { + if (throwExceptions) + throw new IllegalStateException(eventInfo); + } +} diff --git a/RTF Parser Kit/src/com/rtfparserkit/parser/builder/AnnotationContext.java b/RTF Parser Kit/src/com/rtfparserkit/parser/builder/AnnotationContext.java new file mode 100644 index 0000000..8543719 --- /dev/null +++ b/RTF Parser Kit/src/com/rtfparserkit/parser/builder/AnnotationContext.java @@ -0,0 +1,123 @@ +/* + * Copyright 2015 Stephan Aßmus + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.rtfparserkit.parser.builder; + +import java.util.Date; + +import com.rtfparserkit.document.Annotation; +import com.rtfparserkit.parser.builder.TimeContext.DateListener; +import com.rtfparserkit.rtf.Command; + +/** + * Parses the body of an Annotation. + */ +class AnnotationContext extends DocumentPartContext +{ + + private final Annotation annotation; + private final DocumentPartContext parent; + + AnnotationContext(Annotation annotation, DocumentPartContext parent) + { + super(annotation, parent.document); + this.annotation = annotation; + this.parent = parent; + } + + @Override + public void processGroupStart(RtfContextStack stack, Command command, int parameter, boolean hasParameter, boolean optional) + { + switch (command) + { + case atntime: + case atndate: + stack.pushContext(new TimeContext(new DateListener() + { + @Override + public void setDate(Date date) + { + annotation.setDate(date); + } + })); + break; + case atnref: + // TODO: Handle annotation references. The reference is in + // the parameter. + stack.pushContext(new AnnotationReferenceContext()); + break; + case atnparent: + stack.pushContext(new AnnotationParentContext()); + break; + case atrfstart: + stack.pushContext(new BookmarkStartContext()); + break; + case atrfend: + stack.pushContext(new BookmarkEndContext()); + break; + default: + super.processGroupStart(stack, command, parameter, hasParameter, optional); + } + } + + @Override + public void processGroupEnd(RtfContextStack stack) + { + // Inform the parent context that parsing the annotation body has + // finished. + parent.annotationFinished(); + super.processGroupEnd(stack); + } + + private class AnnotationParentContext extends AbstractRtfContext + { + @Override + public void processGroupStart(RtfContextStack stack, Command command, int parameter, boolean hasParameter, boolean optional) + { + switch (command) + { + case atnid: + stack.pushContext(new AnnotationIdContext()); + break; + default: + super.processGroupStart(stack, command, parameter, hasParameter, optional); + } + } + } + + private class AnnotationIdContext extends AbstractRtfContext + { + @Override + public void processString(String string) + { + // TODO: The string is the ID of a parent Annotation. Do something + // with it. + } + } + + private class AnnotationReferenceContext extends AbstractRtfContext + { + } + + private class BookmarkStartContext extends AbstractRtfContext + { + } + + private class BookmarkEndContext extends AbstractRtfContext + { + } + +} diff --git a/RTF Parser Kit/src/com/rtfparserkit/parser/builder/CharacterStyleContext.java b/RTF Parser Kit/src/com/rtfparserkit/parser/builder/CharacterStyleContext.java new file mode 100644 index 0000000..8faa2b2 --- /dev/null +++ b/RTF Parser Kit/src/com/rtfparserkit/parser/builder/CharacterStyleContext.java @@ -0,0 +1,64 @@ +/* + * Copyright 2015 Stephan Aßmus + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.rtfparserkit.parser.builder; + +import com.rtfparserkit.document.CharacterStyle; +import com.rtfparserkit.rtf.Command; + +/** + * RtfContext for parsing a style definition group located in the style sheet + * section of an RTF document. + */ +class CharacterStyleContext extends AbstractRtfContext +{ + + private final CharacterStyle style; + + CharacterStyleContext(CharacterStyle style) + { + this.style = style; + } + + @Override + public void processGroupStart(RtfContextStack stack) + { + // TODO: Implement + stack.pushContext(new NullContext()); + } + + @Override + public void processGroupStart(RtfContextStack stack, Command command, int parameter, boolean hasParameter, boolean optional) + { + // TODO: Implement + stack.pushContext(new NullContext()); + } + + @Override + public void processString(String string) + { + int semicolon = string.indexOf(';'); + int end = semicolon >= 0 ? semicolon : string.length(); + string = string.substring(0, end); + style.setName(string); + } + + @Override + public void processCommand(RtfContextStack stack, Command command, int parameter, boolean hasParameter, boolean optional) + { + // TODO: Implement + } +} diff --git a/RTF Parser Kit/src/com/rtfparserkit/parser/builder/ColorTableContext.java b/RTF Parser Kit/src/com/rtfparserkit/parser/builder/ColorTableContext.java new file mode 100644 index 0000000..6e3e7a5 --- /dev/null +++ b/RTF Parser Kit/src/com/rtfparserkit/parser/builder/ColorTableContext.java @@ -0,0 +1,73 @@ +/* + * Copyright 2015 Stephan Aßmus + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.rtfparserkit.parser.builder; + +import com.rtfparserkit.document.ColorTable; +import com.rtfparserkit.rtf.Command; + +/** + * Processes RTF events that may be encountered in the color table section of + * the file. Whenever a color entry is closed with ';' a new color entry is + * added to the ColorTable instance which is passed on construction. + */ +class ColorTableContext extends AbstractRtfContext +{ + + private final ColorTable table; + + private int red; + private int green; + private int blue; + + ColorTableContext(ColorTable table) + { + this.table = table; + } + + @Override + public void processString(String string) + { + if (";".equals(string)) + { + table.addColor(red, green, blue); + } + else + { + throw new IllegalStateException("Unexpected string in color table"); + } + } + + @Override + public void processCommand(RtfContextStack stack, Command command, int parameter, boolean hasParameter, boolean optional) + { + switch (command) + { + case red: + red = parameter; + break; + case green: + green = parameter; + break; + case blue: + blue = parameter; + break; + default: + throw new IllegalStateException("Unexpected command in color table"); + } + } + +} diff --git a/RTF Parser Kit/src/com/rtfparserkit/parser/builder/DocumentBuilder.java b/RTF Parser Kit/src/com/rtfparserkit/parser/builder/DocumentBuilder.java new file mode 100644 index 0000000..593b58b --- /dev/null +++ b/RTF Parser Kit/src/com/rtfparserkit/parser/builder/DocumentBuilder.java @@ -0,0 +1,182 @@ +/* + * Copyright 2015 Stephan Aßmus + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.rtfparserkit.parser.builder; + +import com.rtfparserkit.document.Document; +import com.rtfparserkit.parser.IRtfListener; +import com.rtfparserkit.rtf.Command; +import com.rtfparserkit.rtf.CommandType; + +/** + * The main class used for building a Document model from parsing RTF events. + * The intended use is to construct an instance of DocumentBuilder with an + * instance of a Document, then pass the DocumentBuilder to + * StandardParser.parse(RtfSource, RtfListener) as the RtfListener. + * + * @author stippi + */ +public class DocumentBuilder implements IRtfListener +{ + + private int level = 0; + private boolean atGroupStart = false; + private boolean debugEvents = false; + + private final RtfContextStack stack; + + public DocumentBuilder(Document document) + { + stack = new RtfContextStack(new RootContext(document)); + } + + public void setDebugEvents(boolean debug) + { + debugEvents = debug; + } + + @Override + public void processDocumentStart() + { + } + + @Override + public void processDocumentEnd() + { + } + + @Override + public void processGroupStart() + { + atGroupStart = true; + } + + @Override + public void processGroupEnd() + { + handleDelayedGroupStart(); + if (debugEvents) + System.out.println(getIndentation() + "processGroupEnd()"); + stack.getContext().processGroupEnd(stack); + level--; + atGroupStart = false; + } + + @Override + public void processCharacterBytes(byte[] data) + { + handleDelayedGroupStart(); + if (debugEvents) + System.out.println(getIndentation() + "processCharacterBytes()"); + stack.getContext().processCharacterBytes(data); + } + + @Override + public void processBinaryBytes(byte[] data) + { + handleDelayedGroupStart(); + if (debugEvents) + System.out.println(getIndentation() + "processBinaryBytes()"); + stack.getContext().processBinaryBytes(data); + } + + @Override + public void processString(String string) + { + handleDelayedGroupStart(); + if (debugEvents) + System.out.println(getIndentation() + "processString(" + string + ")"); + stack.getContext().processString(string); + } + + @Override + public void processCommand(Command command, int parameter, boolean hasParameter, boolean optional) + { + if (atGroupStart) + { + // Handle delayed group start. + if (command == Command.optionalcommand) + { + // Optional group with an unknown command, completely ignore + // this. + if (debugEvents) + { + System.out.println(getIndentation() + "processGroupStart(" + command + ")"); + } + level++; + stack.pushContext(new NullContext()); + // Do not handle this command as processCommand() a second time. + groupStarted(); + return; + } + if (command.getCommandType() == CommandType.Destination) + { + if (debugEvents) + { + System.out.println(getIndentation() + "processGroupStart(" + command + ")"); + } + level++; + stack.getContext().processGroupStart(stack, command, parameter, hasParameter, optional); + // Do not handle this command as processCommand() a second time. + groupStarted(); + return; + } + else + { + handleDelayedGroupStart(); + } + } + + if (debugEvents) + { + System.out.print(getIndentation() + "processCommand() " + command); + if (hasParameter) + System.out.print(", parameter: " + parameter); + if (optional) + System.out.print(" (optional)"); + System.out.println(); + } + + stack.getContext().processCommand(stack, command, parameter, hasParameter, optional); + } + + private String getIndentation() + { + StringBuilder builder = new StringBuilder(); + for (int i = 0; i < level; i++) + builder.append(" "); + builder.append(stack.getContext().getClass().getSimpleName()); + builder.append('.'); + return builder.toString(); + } + + private void handleDelayedGroupStart() + { + if (atGroupStart) + { + if (debugEvents) + System.out.println(getIndentation() + "processGroupStart()"); + level++; + stack.getContext().processGroupStart(stack); + groupStarted(); + } + } + + private void groupStarted() + { + atGroupStart = false; + } +} diff --git a/RTF Parser Kit/src/com/rtfparserkit/parser/builder/DocumentContext.java b/RTF Parser Kit/src/com/rtfparserkit/parser/builder/DocumentContext.java new file mode 100644 index 0000000..6db0040 --- /dev/null +++ b/RTF Parser Kit/src/com/rtfparserkit/parser/builder/DocumentContext.java @@ -0,0 +1,98 @@ +/* + * Copyright 2015 Stephan Aßmus + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.rtfparserkit.parser.builder; + +import com.rtfparserkit.document.Document; +import com.rtfparserkit.rtf.Command; + +/** + * RtfContext for handling the {\rtf group. + */ +class DocumentContext extends DocumentPartContext +{ + + private final Document document; + + DocumentContext(Document document) + { + super(document, document); + this.document = document; + } + + @Override + public void processGroupStart(RtfContextStack stack, Command command, int parameter, boolean hasParameter, boolean optional) + { + switch (command) + { + case header: + stack.pushContext(new DocumentPartContext(document.getLastSection().createHeader(), document)); + break; + case footer: + stack.pushContext(new DocumentPartContext(document.getLastSection().createFooter(), document)); + break; + case colortbl: + stack.pushContext(new ColorTableContext(document.getColorTable())); + break; + case fonttbl: + stack.pushContext(new FontTableContext(document.getFontTable())); + break; + case stylesheet: + stack.pushContext(new StyleSheetContext(document.getStyleSheet())); + break; + + default: + // Unknown destinations should be ignored. + stack.pushContext(new NullContext()); + break; + } + } + + @Override + public void processGroupStart(RtfContextStack stack) + { + stack.pushContext(new DocumentPartContext(document, document)); + } + + @Override + public void processCommand(RtfContextStack stack, Command command, int parameter, boolean hasParameter, boolean optional) + { + switch (command) + { + case margl: + document.getDocumentSettings().getPageSettings().setPageMarginLeft(parameter); + break; + case margr: + document.getDocumentSettings().getPageSettings().setPageMarginRight(parameter); + break; + case margt: + document.getDocumentSettings().getPageSettings().setPageMarginTop(parameter); + break; + case margb: + document.getDocumentSettings().getPageSettings().setPageMarginBottom(parameter); + break; + case paperw: + document.getDocumentSettings().getPageSettings().setPageWidth(parameter); + break; + case paperh: + document.getDocumentSettings().getPageSettings().setPageHeight(parameter); + break; + + default: + super.processCommand(stack, command, parameter, hasParameter, optional); + } + } +} diff --git a/RTF Parser Kit/src/com/rtfparserkit/parser/builder/DocumentPartContext.java b/RTF Parser Kit/src/com/rtfparserkit/parser/builder/DocumentPartContext.java new file mode 100644 index 0000000..65b1043 --- /dev/null +++ b/RTF Parser Kit/src/com/rtfparserkit/parser/builder/DocumentPartContext.java @@ -0,0 +1,322 @@ +/* + * Copyright 2015 Stephan Aßmus + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.rtfparserkit.parser.builder; + +import com.rtfparserkit.document.Annotation; +import com.rtfparserkit.document.CharacterStyle.UnderlineStyle; +import com.rtfparserkit.document.Document; +import com.rtfparserkit.document.DocumentPart; +import com.rtfparserkit.document.ParagraphStyle; +import com.rtfparserkit.document.ParagraphStyle.Alignment; +import com.rtfparserkit.rtf.Command; + +/** + * RtfContext for processing RTF events which have a main styled text + * destination. + */ +class DocumentPartContext extends AbstractRtfContext +{ + private final DocumentPart documentPart; + protected final Document document; + private final ParagraphStyle style; + + private Annotation currentAnnotation; + + DocumentPartContext(DocumentPart part, Document document) + { + documentPart = part; + this.document = document; + style = part.createDefaultStyle(); + } + + DocumentPartContext(DocumentPartContext parent) + { + documentPart = parent.documentPart; + document = parent.document; + style = parent.style.createDerivedStyle(); + } + + @Override + public void processGroupStart(RtfContextStack stack) + { + stack.pushContext(new DocumentPartContext(this)); + } + + @Override + public void processGroupStart(RtfContextStack stack, Command command, int parameter, boolean hasParameter, boolean optional) + { + switch (command) + { + case atnid: + // A new Annotation started + if (currentAnnotation != null) + { + stack.handleError("An annotation has already started, but encountered another annotation ID."); + } + currentAnnotation = documentPart.appendAnnotation(); + stack.pushContext(new AnnotationIdContext()); + break; + case atnauthor: + stack.pushContext(new AnnotationAuthorContext()); + break; + case annotation: + stack.pushContext(new AnnotationContext(currentAnnotation, this)); + break; + default: + // Ignore groups with unknown command + stack.pushContext(new NullContext()); + } + } + + @Override + public void processCharacterBytes(byte[] data) + { + // Ignore + } + + @Override + public void processBinaryBytes(byte[] data) + { + // Ignore + } + + @Override + public void processString(String string) + { + documentPart.append(string, style.createFlattenedStyle()); + } + + @Override + public void processCommand(RtfContextStack stack, Command command, int parameter, boolean hasParameter, boolean optional) + { + switch (command) + { + // Paragraph control + case par: + documentPart.nextParagraph(style.createFlattenedStyle()); + break; + case line: + documentPart.nextLine(); + break; + + // Special characters + case chatn: + // This denotes a special character that is associated with an + // annotation. In most text processing applications, the text + // cursor can be "before" and "after" an annotation within the text. + // deleting this text position deletes the annotation. + // Before \chatn, there should have been an annotation started by + // \atnid and we have already appended an Annotation object to + // the DocumentPart. At the latest, this will happen with the + // next \annotation group. + break; + + // Text styles + case plain: + style.resetToDefaults(); + break; + case f: + style.setFont(document.getFontTable().fontFor(parameter)); + break; + case fs: + style.setFontSize(fromHalfPoints(parameter)); + break; + case b: + if (!hasParameter) + style.setBold(true); + else + style.setBold(parameter != 0); + break; + case i: + if (!hasParameter) + style.setItalic(true); + else + style.setItalic(parameter != 0); + break; + case caps: + if (!hasParameter) + style.setCaps(true); + else + style.setCaps(parameter != 0); + break; + case strike: + case striked: + if (!hasParameter) + style.setStrikeOut(true); + else + style.setStrikeOut(parameter != 0); + break; + case ul: + setUnderlined(UnderlineStyle.SINGLE, hasParameter, parameter); + break; + case uld: + setUnderlined(UnderlineStyle.DOTTED, hasParameter, parameter); + break; + case uldash: + setUnderlined(UnderlineStyle.DASHED, hasParameter, parameter); + break; + case uldashd: + setUnderlined(UnderlineStyle.DASH_DOTTED, hasParameter, parameter); + break; + case uldashdd: + setUnderlined(UnderlineStyle.DASH_DOT_DOTTED, hasParameter, parameter); + break; + case uldb: + setUnderlined(UnderlineStyle.DOUBLE, hasParameter, parameter); + break; + case ulhwave: + setUnderlined(UnderlineStyle.HEAVY_WAVE, hasParameter, parameter); + break; + case ulldash: + setUnderlined(UnderlineStyle.LONG_DASHED, hasParameter, parameter); + break; + case ulnone: + style.setUnderlined(UnderlineStyle.NONE); + break; + case ulth: + setUnderlined(UnderlineStyle.THICK, hasParameter, parameter); + break; + case ulthd: + setUnderlined(UnderlineStyle.THICK_DOTTED, hasParameter, parameter); + break; + case ulthdash: + setUnderlined(UnderlineStyle.THICK_DASHED, hasParameter, parameter); + break; + case ulthdashd: + setUnderlined(UnderlineStyle.THICK_DASH_DOTTED, hasParameter, parameter); + break; + case ulthdashdd: + setUnderlined(UnderlineStyle.THICK_DASH_DOT_DOTTED, hasParameter, parameter); + break; + case ulthldash: + setUnderlined(UnderlineStyle.THICK_LONG_DASHED, hasParameter, parameter); + break; + case ululdbwave: + setUnderlined(UnderlineStyle.DOUBLE_WAVE, hasParameter, parameter); + break; + case ulw: + setUnderlined(UnderlineStyle.WORD, hasParameter, parameter); + break; + case ulwave: + setUnderlined(UnderlineStyle.WAVE, hasParameter, parameter); + break; + case cb: + style.setBackgroundColor(document.getColorTable().colorAt(parameter)); + break; + case cf: + style.setForegroundColor(document.getColorTable().colorAt(parameter)); + break; + + // Alignment + case qc: + style.setAlignment(Alignment.CENTER); + break; + case qj: + style.setAlignment(Alignment.JUSTIFIED); + break; + case ql: + style.setAlignment(Alignment.LEFT); + break; + case qr: + style.setAlignment(Alignment.RIGHT); + break; + case qd: + style.setAlignment(Alignment.DISTRIBUTED); + break; + + // Indents + case fi: + style.setFirstLineIndent(fromTwips(parameter)); + break; + case li: + style.setLeftIndent(fromTwips(parameter)); + break; + case ri: + style.setRightIndent(fromTwips(parameter)); + break; + + // spacing + case sb: + style.setSpacingTop(fromTwips(parameter)); + break; + case sa: + style.setSpacingBottom(fromTwips(parameter)); + break; + case sl: + style.setLineSpacing(fromTwips(parameter)); + break; + + default: + // System.out.println("DocumentPartContext.processCommand(" + // + command + ") not handled!"); + break; + } + } + + private void setUnderlined(UnderlineStyle underline, boolean hasParamter, int parameter) + { + if (!hasParamter || parameter != 0) + style.setUnderlined(underline); + else + style.setUnderlined(UnderlineStyle.NONE); + } + + private static float fromTwips(int value) + { + return (float) value / 20.0f; + } + + private static float fromHalfPoints(int value) + { + return (float) value / 2.0f; + } + + private String append(String string, String toAppend) + { + return string != null ? string + toAppend : toAppend; + } + + void annotationFinished() + { + currentAnnotation = null; + } + + private class AnnotationAuthorContext extends AbstractRtfContext + { + @Override + public void processString(String string) + { + if (currentAnnotation != null) + { + currentAnnotation.setAuthor(append(currentAnnotation.getAuthor(), string)); + } + } + } + + private class AnnotationIdContext extends AbstractRtfContext + { + @Override + public void processString(String string) + { + if (currentAnnotation != null) + { + currentAnnotation.setId(append(currentAnnotation.getId(), string)); + } + } + } + +} diff --git a/RTF Parser Kit/src/com/rtfparserkit/parser/builder/DocumentSettingsContext.java b/RTF Parser Kit/src/com/rtfparserkit/parser/builder/DocumentSettingsContext.java new file mode 100644 index 0000000..6fd6148 --- /dev/null +++ b/RTF Parser Kit/src/com/rtfparserkit/parser/builder/DocumentSettingsContext.java @@ -0,0 +1,65 @@ +/* + * Copyright 2015 Stephan Aßmus + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.rtfparserkit.parser.builder; + +import com.rtfparserkit.document.DocumentSettings; +import com.rtfparserkit.rtf.Command; + +/** + * RtfContext implementing the storing of global settings to the document. + */ +class DocumentSettingsContext extends AbstractRtfContext +{ + + private final DocumentSettings settings; + + DocumentSettingsContext(DocumentSettings settings) + { + this.settings = settings; + } + + @Override + public void processCommand(RtfContextStack stack, Command command, int parameter, boolean hasParameter, boolean optional) + { + switch (command) + { + case margl: + settings.getPageSettings().setPageMarginLeft(parameter); + break; + case margr: + settings.getPageSettings().setPageMarginRight(parameter); + break; + case margt: + settings.getPageSettings().setPageMarginTop(parameter); + break; + case margb: + settings.getPageSettings().setPageMarginBottom(parameter); + break; + case paperw: + settings.getPageSettings().setPageWidth(parameter); + break; + case paperh: + settings.getPageSettings().setPageHeight(parameter); + break; + // TODO: More commands... + default: + super.processCommand(stack, command, parameter, hasParameter, optional); + break; + } + } + +} diff --git a/RTF Parser Kit/src/com/rtfparserkit/parser/builder/FontContext.java b/RTF Parser Kit/src/com/rtfparserkit/parser/builder/FontContext.java new file mode 100644 index 0000000..915b74e --- /dev/null +++ b/RTF Parser Kit/src/com/rtfparserkit/parser/builder/FontContext.java @@ -0,0 +1,147 @@ +/* + * Copyright 2015 Stephan Aßmus + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.rtfparserkit.parser.builder; + +import com.rtfparserkit.document.FontTable; +import com.rtfparserkit.document.FontTable.FontFamily; +import com.rtfparserkit.rtf.Command; + +/** + * RtfContext implementation which handles RTF events inside a group inside + * of the font table section. + */ +class FontContext extends AbstractRtfContext +{ + + protected final FontTable fontTable; + + private int id = 0; + private String fontName = ""; + private String alternativeName = ""; + private String fileName = ""; + private FontFamily fontFamily = FontFamily.DEFAULT; + + private enum ExpectedName + { + DEFAULT, ALTERNATIVE, FILE + } + + private ExpectedName expectedName = ExpectedName.DEFAULT; + + FontContext(FontTable fontTable) + { + this.fontTable = fontTable; + } + + FontContext(int id, FontTable fontTable) + { + this(fontTable); + this.id = id; + } + + @Override + public void processGroupEnd(RtfContextStack stack) + { + super.processGroupEnd(stack); + } + + @Override + public void processString(String string) + { + int offset = 0; + while (offset < string.length()) + { + // Chop off anything after and including the first semicolon + int semicolon = string.indexOf(';', offset); + + if (semicolon == offset) + { + fontTable.addFont(id, fontName, alternativeName, fileName, fontFamily); + offset = semicolon + 1; + continue; + } + + int end = semicolon >= 0 ? semicolon : string.length(); + + String name = string.substring(offset, end); + + switch (expectedName) + { + case DEFAULT: + fontName = name; + break; + case ALTERNATIVE: + alternativeName = name; + break; + case FILE: + fileName = name; + break; + } + + offset = end; + } + } + + @Override + public void processCommand(RtfContextStack stack, Command command, int parameter, boolean hasParameter, boolean optional) + { + switch (command) + { + case f: + id = parameter; + break; + + case fname: + expectedName = ExpectedName.DEFAULT; + break; + case falt: + expectedName = ExpectedName.ALTERNATIVE; + break; + case fontfile: + expectedName = ExpectedName.FILE; + break; + + case fnil: + fontFamily = FontFamily.DEFAULT; + break; + case froman: + fontFamily = FontFamily.ROMAN; + break; + case fswiss: + fontFamily = FontFamily.SWISS; + break; + case fmodern: + fontFamily = FontFamily.MODERN; + break; + case fscript: + fontFamily = FontFamily.SCRIPT; + break; + case fdecor: + fontFamily = FontFamily.DECOR; + break; + case ftech: + fontFamily = FontFamily.TECH; + break; + case fbidi: + fontFamily = FontFamily.BIDI; + break; + + default: + break; + } + } +} diff --git a/RTF Parser Kit/src/com/rtfparserkit/parser/builder/FontTableContext.java b/RTF Parser Kit/src/com/rtfparserkit/parser/builder/FontTableContext.java new file mode 100644 index 0000000..30b0ab6 --- /dev/null +++ b/RTF Parser Kit/src/com/rtfparserkit/parser/builder/FontTableContext.java @@ -0,0 +1,57 @@ +/* + * Copyright 2015 Stephan Aßmus + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.rtfparserkit.parser.builder; + +import com.rtfparserkit.document.FontTable; +import com.rtfparserkit.rtf.Command; + +/** + * Processes RTF events that may be encountered in the font table section of + * the file. Whenever a new group is started, a new FontContext is created to + * handle the events within the group which specify the font parameters. + * Note that FontTableContext inherits from FontContext, since RTF files may + * or may not have the \font elements within a group. + */ +class FontTableContext extends FontContext +{ + + FontTableContext(FontTable table) + { + super(table); + } + + @Override + public void processGroupStart(RtfContextStack stack) + { + stack.pushContext(new FontContext(fontTable)); + } + + @Override + public void processGroupStart(RtfContextStack stack, Command command, int parameter, boolean hasParameter, boolean optional) + { + switch (command) + { + case f: + stack.pushContext(new FontContext(parameter, fontTable)); + break; + default: + super.processGroupStart(stack, command, parameter, hasParameter, optional); + break; + } + } + +} diff --git a/RTF Parser Kit/src/com/rtfparserkit/parser/builder/NullContext.java b/RTF Parser Kit/src/com/rtfparserkit/parser/builder/NullContext.java new file mode 100644 index 0000000..aed2e57 --- /dev/null +++ b/RTF Parser Kit/src/com/rtfparserkit/parser/builder/NullContext.java @@ -0,0 +1,71 @@ +/* + * Copyright 2015 Stephan Aßmus + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.rtfparserkit.parser.builder; + +import com.rtfparserkit.rtf.Command; + +/** + * RtfContext ignoring all events. Used when text and other comments should not + * end up in a known destination. Groups within a null destination will also + * be completely ignored. + */ +class NullContext implements RtfContext +{ + + @Override + public void processGroupStart(RtfContextStack stack) + { + stack.pushContext(new NullContext()); + } + + @Override + public void processGroupStart(RtfContextStack stack, Command command, int parameter, boolean hasParameter, boolean optional) + { + processGroupStart(stack); + } + + @Override + public void processGroupEnd(RtfContextStack stack) + { + stack.popContext(); + } + + @Override + public void processCharacterBytes(byte[] data) + { + // Ignore + } + + @Override + public void processBinaryBytes(byte[] data) + { + // Ignore + } + + @Override + public void processString(String string) + { + // Ignore + } + + @Override + public void processCommand(RtfContextStack stack, Command command, int parameter, boolean hasParameter, boolean optional) + { + // Ignore + } + +} \ No newline at end of file diff --git a/RTF Parser Kit/src/com/rtfparserkit/parser/builder/ParagraphStyleContext.java b/RTF Parser Kit/src/com/rtfparserkit/parser/builder/ParagraphStyleContext.java new file mode 100644 index 0000000..35bd3c8 --- /dev/null +++ b/RTF Parser Kit/src/com/rtfparserkit/parser/builder/ParagraphStyleContext.java @@ -0,0 +1,64 @@ +/* + * Copyright 2015 Stephan Aßmus + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.rtfparserkit.parser.builder; + +import com.rtfparserkit.document.ParagraphStyle; +import com.rtfparserkit.rtf.Command; + +/** + * RtfContext for parsing a style definition group located in the style sheet + * section of an RTF document. + */ +class ParagraphStyleContext extends AbstractRtfContext +{ + + private final ParagraphStyle style; + + ParagraphStyleContext(ParagraphStyle style) + { + this.style = style; + } + + @Override + public void processGroupStart(RtfContextStack stack) + { + // TODO: Implement + stack.pushContext(new NullContext()); + } + + @Override + public void processGroupStart(RtfContextStack stack, Command command, int parameter, boolean hasParameter, boolean optional) + { + // TODO: Implement + stack.pushContext(new NullContext()); + } + + @Override + public void processString(String string) + { + int semicolon = string.indexOf(';'); + int end = semicolon >= 0 ? semicolon : string.length(); + string = string.substring(0, end); + style.setName(string); + } + + @Override + public void processCommand(RtfContextStack stack, Command command, int parameter, boolean hasParameter, boolean optional) + { + // TODO: Implement + } +} diff --git a/RTF Parser Kit/src/com/rtfparserkit/parser/builder/RootContext.java b/RTF Parser Kit/src/com/rtfparserkit/parser/builder/RootContext.java new file mode 100644 index 0000000..68d4560 --- /dev/null +++ b/RTF Parser Kit/src/com/rtfparserkit/parser/builder/RootContext.java @@ -0,0 +1,58 @@ +/* + * Copyright 2015 Stephan Aßmus + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.rtfparserkit.parser.builder; + +import com.rtfparserkit.document.Document; +import com.rtfparserkit.rtf.Command; + +/** + * Initial RtfContext. Pushes a DocumentContext upon encountering a group + * starting with \rtf. + */ +class RootContext extends AbstractRtfContext +{ + + private final Document document; + + RootContext(Document document) + { + this.document = document; + } + + @Override + public void processGroupStart(RtfContextStack stack, Command command, int parameter, boolean hasParameter, boolean optional) + { + switch (command) + { + case rtf: + stack.pushContext(new DocumentContext(document)); + break; + + default: + // Unknown destinations should be ignored. + stack.pushContext(new NullContext()); + break; + } + } + + @Override + public void processGroupStart(RtfContextStack stack) + { + // Unknown groups should be ignored. + stack.pushContext(new NullContext()); + } +} diff --git a/RTF Parser Kit/src/com/rtfparserkit/parser/builder/RtfContext.java b/RTF Parser Kit/src/com/rtfparserkit/parser/builder/RtfContext.java new file mode 100644 index 0000000..bdff5c3 --- /dev/null +++ b/RTF Parser Kit/src/com/rtfparserkit/parser/builder/RtfContext.java @@ -0,0 +1,43 @@ +/* + * Copyright 2015 Stephan Aßmus + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.rtfparserkit.parser.builder; + +import com.rtfparserkit.rtf.Command; + +/** + * Interface for delegating the handling of RTF Parser events to an object which + * knows how to handle the events based on the current "context" (location in + * the file and group hierarchy). + */ +interface RtfContext +{ + + public void processGroupStart(RtfContextStack stack); + + public void processGroupStart(RtfContextStack stack, Command command, int parameter, boolean hasParameter, boolean optional); + + public void processGroupEnd(RtfContextStack stack); + + public void processCharacterBytes(byte[] data); + + public void processBinaryBytes(byte[] data); + + public void processString(String string); + + public void processCommand(RtfContextStack stack, Command command, int parameter, boolean hasParameter, boolean optional); + +} diff --git a/RTF Parser Kit/src/com/rtfparserkit/parser/builder/RtfContextStack.java b/RTF Parser Kit/src/com/rtfparserkit/parser/builder/RtfContextStack.java new file mode 100644 index 0000000..84302ee --- /dev/null +++ b/RTF Parser Kit/src/com/rtfparserkit/parser/builder/RtfContextStack.java @@ -0,0 +1,68 @@ +/* + * Copyright 2015 Stephan Aßmus + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.rtfparserkit.parser.builder; + +import java.util.Stack; + +/** + * RtfContextStack manages a stack of RtfContext instances and has the notion + * of the current RtfContext (not part of the stack storage). + */ +class RtfContextStack +{ + + private final Stack stack; + private RtfContext currentContext; + + RtfContextStack(RtfContext initialContext) + { + if (initialContext == null) + { + throw new IllegalArgumentException("Initial RTF context cannot be null."); + } + stack = new Stack(); + currentContext = initialContext; + } + + RtfContext getContext() + { + return currentContext; + } + + void pushContext(RtfContext context) + { + stack.push(currentContext); + currentContext = context; + } + + void popContext() + { + if (stack.isEmpty()) + { + handleError("RTF context stack is empty"); + return; + } + currentContext = stack.pop(); + } + + void handleError(String error) + { + // TODO: Allow setting an error handler + throw new IllegalStateException(error); + //System.out.println(error); + } +} diff --git a/RTF Parser Kit/src/com/rtfparserkit/parser/builder/StyleSheetContext.java b/RTF Parser Kit/src/com/rtfparserkit/parser/builder/StyleSheetContext.java new file mode 100644 index 0000000..a31e06e --- /dev/null +++ b/RTF Parser Kit/src/com/rtfparserkit/parser/builder/StyleSheetContext.java @@ -0,0 +1,74 @@ +/* + * Copyright 2015 Stephan Aßmus + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.rtfparserkit.parser.builder; + +import com.rtfparserkit.document.CharacterStyle; +import com.rtfparserkit.document.ParagraphStyle; +import com.rtfparserkit.document.StyleSheet; +import com.rtfparserkit.rtf.Command; + +/** + * Processes RTF events that may be encountered in the style sheet section of + * the file. + */ +class StyleSheetContext extends NullContext +{ + + private final StyleSheet styleSheet; + + StyleSheetContext(StyleSheet styleSheet) + { + this.styleSheet = styleSheet; + } + + @Override + public void processGroupStart(RtfContextStack stack, Command command, int parameter, boolean hasParameter, boolean optional) + { + // The Style Sheet should only contain style definition groups. These + // can start with one of these commands, + switch (command) + { + case s: + { + // Paragraph style + ParagraphStyle style = styleSheet.getParagraphStyleTable().createStyle(); + styleSheet.getParagraphStyleTable().addStyle(parameter, style); + stack.pushContext(new ParagraphStyleContext(style)); + break; + } + case cs: + { + // Character style + CharacterStyle style = styleSheet.getCharacterStyleTable().createStyle(); + styleSheet.getCharacterStyleTable().addStyle(parameter, style); + stack.pushContext(new CharacterStyleContext(style)); + break; + } + case ds: + // TODO: Section style + stack.pushContext(new NullContext()); + break; + case ts: + // TODO: Table style + stack.pushContext(new NullContext()); + break; + default: + stack.pushContext(new NullContext()); + break; + } + } +} diff --git a/RTF Parser Kit/src/com/rtfparserkit/parser/builder/TimeContext.java b/RTF Parser Kit/src/com/rtfparserkit/parser/builder/TimeContext.java new file mode 100644 index 0000000..31b5044 --- /dev/null +++ b/RTF Parser Kit/src/com/rtfparserkit/parser/builder/TimeContext.java @@ -0,0 +1,95 @@ +/* + * Copyright 2015 Stephan Aßmus + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.rtfparserkit.parser.builder; + +import java.util.Calendar; +import java.util.Date; + +import com.rtfparserkit.rtf.Command; + +/** + * Context for parsing a time. When the current group is ended, it informs + * a DateListener provided at construction time about the Date that has been + * parsed. + */ +class TimeContext extends AbstractRtfContext +{ + + public interface DateListener + { + public void setDate(Date date); + } + + private Calendar calendar = Calendar.getInstance(); + + private final DateListener dateListener; + + TimeContext(DateListener listener) + { + dateListener = listener; + } + + @Override + public void processGroupEnd(RtfContextStack stack) + { + dateListener.setDate(calendar.getTime()); + super.processGroupEnd(stack); + } + + @Override + public void processString(String string) + { + try + { + long time = Long.parseLong(string); + calendar.setTimeInMillis(time * 1000); + } + catch (Exception e) + { + // Ignore + } + } + + @Override + public void processCommand(RtfContextStack stack, Command command, int parameter, boolean hasParameter, boolean optional) + { + switch (command) + { + case yr: + calendar.set(Calendar.YEAR, parameter); + break; + case mo: + calendar.set(Calendar.MONTH, parameter); + break; + case dy: + calendar.set(Calendar.DAY_OF_MONTH, parameter); + break; + case hr: + calendar.set(Calendar.HOUR, parameter); + break; + case min: + calendar.set(Calendar.MINUTE, parameter); + break; + case sec: + calendar.set(Calendar.SECOND, parameter); + break; + + default: + super.processCommand(stack, command, parameter, hasParameter, optional); + } + } +} diff --git a/RTF Parser Kit/test/com/rtfparserkit/document/ParagraphListTest.java b/RTF Parser Kit/test/com/rtfparserkit/document/ParagraphListTest.java new file mode 100644 index 0000000..e02f145 --- /dev/null +++ b/RTF Parser Kit/test/com/rtfparserkit/document/ParagraphListTest.java @@ -0,0 +1,64 @@ +/** + * Copyright 2015 DramaQueen GmbH. All rights reserved. + */ + +package com.rtfparserkit.document; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +import com.rtfparserkit.document.impl.ParagraphList; + +/** + * + * @author stippi + */ +public class ParagraphListTest +{ + + @Test + public void testEmptyParagraphList() + { + ParagraphList list = new ParagraphList(); + assertEquals(1, list.countParagraphs()); + assertEquals("", list.getText()); + } + + @Test + public void testAppend() + { + ParagraphList list = new ParagraphList(); + list.append("test1"); + list.append("test2"); + list.append("test3"); + assertEquals(1, list.countParagraphs()); + assertEquals("test1test2test3", list.getText()); + } + + @Test + public void testDelimiter() + { + ParagraphList list = new ParagraphList(); + list.append("\n"); + assertEquals(2, list.countParagraphs()); + assertEquals("\n", list.getText()); + assertEquals("\n", list.paragraphAt(0).getText()); + assertEquals("", list.paragraphAt(1).getText()); + + list.append("\n\n"); + assertEquals(4, list.countParagraphs()); + assertEquals("\n\n\n", list.getText()); + assertEquals("\n", list.paragraphAt(2).getText()); + assertEquals("", list.paragraphAt(3).getText()); + + list = new ParagraphList(); + list.append("test1"); + list.append("test2\ntest3\n"); + assertEquals(3, list.countParagraphs()); + assertEquals("test1test2\ntest3\n", list.getText()); + assertEquals("test1test2\n", list.paragraphAt(0).getText()); + assertEquals("test3\n", list.paragraphAt(1).getText()); + assertEquals("", list.paragraphAt(2).getText()); + } +} diff --git a/RTF Parser Kit/test/com/rtfparserkit/document/ParagraphTest.java b/RTF Parser Kit/test/com/rtfparserkit/document/ParagraphTest.java new file mode 100644 index 0000000..58e0cc1 --- /dev/null +++ b/RTF Parser Kit/test/com/rtfparserkit/document/ParagraphTest.java @@ -0,0 +1,123 @@ +/** + * Copyright 2015 DramaQueen GmbH. All rights reserved. + */ + +package com.rtfparserkit.document; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +import com.rtfparserkit.document.impl.DefaultAnnotation; +import com.rtfparserkit.document.impl.DefaultParagraph; + +/** + * + * @author stippi + */ +public class ParagraphTest +{ + + @Test + public void testEmptyParagraph() + { + DefaultParagraph p = new DefaultParagraph(); + assertEquals("", p.getText()); + } + + @Test + public void testAppend() + { + DefaultParagraph p = new DefaultParagraph(); + p.append("test1"); + p.append("test2"); + p.append("test3"); + assertEquals("test1test2test3", p.getText()); + } + + @Test + public void testDelimiter() + { + DefaultParagraph p = new DefaultParagraph(); + p.end(); + assertEquals("\n", p.getText()); + + p = new DefaultParagraph(); + p.append("test"); + assertEquals("test", p.getText()); + + p.end(); + assertEquals("test\n", p.getText()); + } + + @Test + public void testOnlyOneDelimiter() + { + DefaultParagraph p = new DefaultParagraph(); + p.end(); + expectException(p, "\n", true); + assertEquals("\n", p.getText()); + + p = new DefaultParagraph(); + p.append("test"); + expectException(p, "\n", false); + // Paragraph already delimited + expectException(p, "\n", true); + // Paragraph must not have changed + assertEquals("test\n", p.getText()); + + p = new DefaultParagraph(); + p.append("test"); + // Appended text may end with a delimiter + expectException(p, "test\n", false); + assertEquals("testtest\n", p.getText()); + // Paragraph already delimited, various cases of the text containing + // a delimiter should all raise an exception + expectException(p, "test\n", true); + expectException(p, "\n", true); + expectException(p, "\ntest", true); + expectException(p, "test\ntest", true); + // Paragraph must not have changed + assertEquals("testtest\n", p.getText()); + + p = new DefaultParagraph(); + p.append("test"); + // Appended text may only /end/ with a delimiter + expectException(p, "test\ntest", true); + expectException(p, "\ntest", true); + // Paragraph must not have changed + assertEquals("test", p.getText()); + } + + @Test + public void testAnnotation() + { + DefaultParagraph p = new DefaultParagraph(); + p.append("test"); + p.append(new DefaultAnnotation()); + p.append("test"); + + assertEquals(3, p.countElements()); + + p = new DefaultParagraph(); + p.append("test"); + p.append(new DefaultAnnotation()); + p.end(); + + assertEquals(3, p.countElements()); + } + + private void expectException(DefaultParagraph defaultParagraph, String toAppend, boolean exceptionExpected) + { + boolean exceptionRaised = false; + try + { + defaultParagraph.append(toAppend); + } + catch (Exception e) + { + exceptionRaised = true; + } + assertEquals(exceptionExpected, exceptionRaised); + } +} diff --git a/RTF Parser Kit/test/com/rtfparserkit/parser/builder/BuilderParseTest.java b/RTF Parser Kit/test/com/rtfparserkit/parser/builder/BuilderParseTest.java new file mode 100644 index 0000000..90dc3d8 --- /dev/null +++ b/RTF Parser Kit/test/com/rtfparserkit/parser/builder/BuilderParseTest.java @@ -0,0 +1,258 @@ + +package com.rtfparserkit.parser.builder; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.io.IOException; +import java.io.InputStream; + +import org.junit.Test; + +import com.rtfparserkit.document.Annotation; +import com.rtfparserkit.document.CharacterStyle.UnderlineStyle; +import com.rtfparserkit.document.Chunk; +import com.rtfparserkit.document.Document; +import com.rtfparserkit.document.Element; +import com.rtfparserkit.document.Paragraph; +import com.rtfparserkit.document.Section; +import com.rtfparserkit.document.impl.DefaultDocument; +import com.rtfparserkit.parser.RtfStreamSource; +import com.rtfparserkit.parser.standard.StandardRtfParser; + +public class BuilderParseTest +{ + + @Test + public void testParagraphContentsIText() + { + DefaultDocument document = new DefaultDocument(); + parseStream("lineSeparator", document, false); + + Section section = document.getLastSection(); + + int paragraphCount = section.countParagraphs(); + assertEquals(5, paragraphCount); + + assertEquals("INNEN. KÜCHE - TAG\n", section.paragraphAt(0).getText()); + assertEquals("Ein Absatz mit Line-Separator:\u2028Der geht hier auf einer neuen Zeile weiter.\n", section.paragraphAt(1).getText()); + assertEquals("INNEN. KÜCHE - TAG\n", section.paragraphAt(2).getText()); + assertEquals("Hier ist die zweite Szene.\n", section.paragraphAt(3).getText()); + assertEquals("", section.paragraphAt(4).getText()); + + assertEquals(12242, document.getPageSize().width); + assertEquals(15842, document.getPageSize().height); + + assertEquals(1425, document.getPageMargins().left); + assertEquals(360, document.getPageMargins().right); + assertEquals(950, document.getPageMargins().top); + assertEquals(1425, document.getPageMargins().bottom); + + assertEquals(2, document.getColorTable().countColors()); + } + + @Test + public void testParagraphContentsLibreOffice() + { + DefaultDocument document = new DefaultDocument(); + parseStream("annotationLibreOffice", document, true); + + Section section = document.getLastSection(); + + int paragraphCount = section.countParagraphs(); + assertEquals(2, paragraphCount); + + assertEquals("This word is commented.\n", section.paragraphAt(0).getText()); + } + + @Test + public void testAnnotations() + { + DefaultDocument document = new DefaultDocument(); + parseStream("annotationSpec", document, false); + + Section section = document.sectionAt(0); + + assertEquals(1, section.countParagraphs()); + + Paragraph paragraph = section.paragraphAt(0); + + assertEquals(3, paragraph.countElements()); + + Element element = paragraph.elementAt(0); + assertTrue(element instanceof Chunk); + Chunk chunk = (Chunk) element; + assertEquals("An example of a paradigm might be Darwinian biology.", chunk.getText()); + + element = paragraph.elementAt(1); + assertTrue(element instanceof Annotation); + Annotation annotation = (Annotation) element; + assertEquals("How about some examples that deal with social science? That is what this paper is about.", annotation.getText()); + assertEquals("JD", annotation.getId()); + assertEquals("John Doe", annotation.getAuthor()); + + element = paragraph.elementAt(2); + assertTrue(element instanceof Chunk); + chunk = (Chunk) element; + assertEquals(" ", chunk.getText()); + } + + @Test + public void testStyles() + { + // NOTE: Pages did not write the foreground/background colors + String[] files = {"variousStyles", /*"variousStylesPages",*/ "variousStylesGrouped",}; + + for (String file : files) + { + System.out.println("################################"); + + DefaultDocument document = new DefaultDocument(); + parseStream(file, document, false); + + assertEquals(1, document.countSections()); + Section section = document.sectionAt(0); + assertStyles(section); + } + } + + private void assertStyles(Section section) + { + int paragraphCount = section.countParagraphs(); + assertEquals(8, paragraphCount); + + for (int i = 0; i < paragraphCount; i++) + { + Paragraph paragraph = section.paragraphAt(i); + + switch (i) + { + case 0: + assertNormalBoldItalic(paragraph); + break; + case 1: + assertFontSizesAndColors(paragraph); + break; + default: + String text = paragraph.getText(); + System.out.print("[" + i + "]: " + text); + if (!text.endsWith("\n")) + System.out.println(); + for (Element element : paragraph) + { + if (element instanceof Chunk) + { + Chunk chunk = (Chunk) element; + System.out.println(" '" + chunk.getText().replaceAll("\n", "") + "' " + chunk.getStyle()); + } + } + } + } + } + + private void assertNormalBoldItalic(Paragraph paragraph) + { + int chunks = paragraph.countElements(); + assertEquals(5, chunks); + + Chunk chunk = (Chunk) paragraph.elementAt(0); + assertEquals("Normal ", chunk.getText()); + assertFalse(chunk.getStyle().getBold()); + assertFalse(chunk.getStyle().getItalic()); + + chunk = (Chunk) paragraph.elementAt(1); + assertEquals("Bold ", chunk.getText()); + assertTrue(chunk.getStyle().getBold()); + assertFalse(chunk.getStyle().getItalic()); + + chunk = (Chunk) paragraph.elementAt(2); + assertEquals("Bold/Italic", chunk.getText()); + assertTrue(chunk.getStyle().getBold()); + assertTrue(chunk.getStyle().getItalic()); + + chunk = (Chunk) paragraph.elementAt(3); + assertEquals(" Italic", chunk.getText()); + assertFalse(chunk.getStyle().getBold()); + assertTrue(chunk.getStyle().getItalic()); + + chunk = (Chunk) paragraph.elementAt(4); + assertEquals(" Normal.\n", chunk.getText()); + assertFalse(chunk.getStyle().getBold()); + assertFalse(chunk.getStyle().getItalic()); + } + + private void assertFontSizesAndColors(Paragraph paragraph) + { + int chunks = paragraph.countElements(); + assertEquals(5, chunks); + + Chunk chunk = (Chunk) paragraph.elementAt(0); + assertEquals("Bigger Font (18). ", chunk.getText()); + assertEquals(18.0f, chunk.getStyle().getFontSize(), 0.0f); + assertEquals("Helvetica", chunk.getStyle().getFont().getName()); + assertEquals(UnderlineStyle.NONE, chunk.getStyle().getUnderlined()); + + chunk = (Chunk) paragraph.elementAt(1); + assertEquals("Underlined", chunk.getText()); + assertEquals(18.0f, chunk.getStyle().getFontSize(), 0.0f); + assertEquals(UnderlineStyle.SINGLE, chunk.getStyle().getUnderlined()); + + chunk = (Chunk) paragraph.elementAt(2); + assertEquals(" Normal size. ", chunk.getText()); + assertEquals(12.0f, chunk.getStyle().getFontSize(), 0.0f); + assertEquals(UnderlineStyle.NONE, chunk.getStyle().getUnderlined()); + assertEquals(0, chunk.getStyle().getForegroundColor().getRed()); + assertEquals(0, chunk.getStyle().getForegroundColor().getGreen()); + assertEquals(0, chunk.getStyle().getForegroundColor().getBlue()); + + chunk = (Chunk) paragraph.elementAt(3); + assertEquals("Red text. ", chunk.getText()); + assertEquals(217, chunk.getStyle().getForegroundColor().getRed()); + assertEquals(11, chunk.getStyle().getForegroundColor().getGreen()); + assertEquals(0, chunk.getStyle().getForegroundColor().getBlue()); + assertEquals(255, chunk.getStyle().getBackgroundColor().getRed()); + assertEquals(255, chunk.getStyle().getBackgroundColor().getGreen()); + assertEquals(255, chunk.getStyle().getBackgroundColor().getBlue()); + + chunk = (Chunk) paragraph.elementAt(4); + assertEquals("On yellow background.\n", chunk.getText()); + assertEquals(217, chunk.getStyle().getForegroundColor().getRed()); + assertEquals(11, chunk.getStyle().getForegroundColor().getGreen()); + assertEquals(0, chunk.getStyle().getForegroundColor().getBlue()); + assertEquals(255, chunk.getStyle().getBackgroundColor().getRed()); + assertEquals(249, chunk.getStyle().getBackgroundColor().getGreen()); + assertEquals(89, chunk.getStyle().getBackgroundColor().getBlue()); + } + + private void parseStream(String fileName, Document document, boolean debug) + { + InputStream is = null; + try + { + is = BuilderParseTest.class.getResourceAsStream("data/" + fileName + ".rtf"); + StandardRtfParser parser = new StandardRtfParser(); + DocumentBuilder builder = new DocumentBuilder(document); + builder.setDebugEvents(debug); + parser.parse(new RtfStreamSource(is), builder); + } + catch (IOException e) + { + e.printStackTrace(); + } + finally + { + if (is != null) + { + try + { + is.close(); + } + catch (Exception e) + { + // Ignore + } + } + } + } +} diff --git a/RTF Parser Kit/test/com/rtfparserkit/parser/builder/data/annotationLibreOffice.rtf b/RTF Parser Kit/test/com/rtfparserkit/parser/builder/data/annotationLibreOffice.rtf new file mode 100644 index 0000000..a173ff5 --- /dev/null +++ b/RTF Parser Kit/test/com/rtfparserkit/parser/builder/data/annotationLibreOffice.rtf @@ -0,0 +1,19 @@ +{\rtf1\ansi\deff3\adeflang1025 +{\fonttbl{\f0\froman\fprq2\fcharset0 Times New Roman;}{\f1\froman\fprq2\fcharset2 Symbol;}{\f2\fswiss\fprq2\fcharset0 Arial;}{\f3\froman\fprq2\fcharset0 Times New Roman;}{\f4\fswiss\fprq2\fcharset0 Arial;}{\f5\fnil\fprq2\fcharset0 Arial Unicode MS;}} +{\colortbl;\red0\green0\blue0;\red128\green128\blue128;} +{\stylesheet{\s0\snext0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af5\langfe2052\dbch\af5\afs24\alang1081\loch\f3\fs24\lang1031 Standard;} +{\s15\sbasedon0\snext16\sb240\sa120\keepn\dbch\af5\dbch\af5\afs28\loch\f4\fs28 \u220\'dcberschrift;} +{\s16\sbasedon0\snext16\sb0\sa120 Textk\u246\'f6rper;} +{\s17\sbasedon16\snext17\sb0\sa120 Liste;} +{\s18\sbasedon0\snext18\sb120\sa120\noline\i\afs24\ai\fs24 Beschriftung;} +{\s19\sbasedon0\snext19\noline Verzeichnis;} +}{\info{\creatim\yr0\mo0\dy0\hr0\min0}{\revtim\yr0\mo0\dy0\hr0\min0}{\printim\yr0\mo0\dy0\hr0\min0}{\comment LibreOffice}{\vern3600}}\deftab720 +\viewscale100 +{\*\pgdsctbl +{\pgdsc0\pgdscuse195\pgwsxn12240\pghsxn15840\marglsxn1440\margrsxn1440\margtsxn1440\margbsxn1440\pgdscnxt0 Standard;}} +\formshade{\*\pgdscno0}\paperh15840\paperw12240\margl1440\margr1440\margt1440\margb1440\sectd\sbknone\sectunlocked1\pgndec\pgwsxn12240\pghsxn15840\marglsxn1440\margrsxn1440\margtsxn1440\margbsxn1440\ftnbj\ftnstart1\ftnrstcont\ftnnar\aenddoc\aftnrstcont\aftnstart1\aftnnrlc +\pgndec\pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af5\langfe2052\dbch\af5\afs24\alang1081\loch\f3\fs24\lang1031\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803{\rtlch \ltrch\loch +This }{\rtlch \ltrch\loch +{\*\atnid Unbekannter Autor}{\*\atnauthor Unbekannter Autor}\chatn{\*\annotation{\*\atndate -2026238962}These are the comment contents.}}{\rtlch \ltrch\loch +word is commented.} +\par } \ No newline at end of file diff --git a/RTF Parser Kit/test/com/rtfparserkit/parser/builder/data/annotationSpec.rtf b/RTF Parser Kit/test/com/rtfparserkit/parser/builder/data/annotationSpec.rtf new file mode 100644 index 0000000..104d529 --- /dev/null +++ b/RTF Parser Kit/test/com/rtfparserkit/parser/builder/data/annotationSpec.rtf @@ -0,0 +1,9 @@ +{\rtf1\ansi\ansicpg1252\cocoartf1348\cocoasubrtf170 +{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;\red217\green11\blue0;\red255\green249\blue89;} +\margl1440\margr1440\vieww10800\viewh8400\viewkind0 +\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardirnatural + +{\insrsid8729657 An example of a paradigm might be Darwinian biology.} +{\cs15\v\fs16\insrsid8729657 {\*\atnid JD}{\*\atnauthor John Doe}\chatn {\*\annotation{\*\atndate 1180187342}\pard\plain \s16\ql \li0\ri0\widctlpar\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs15\fs16\insrsid8729657 \chatn }{\insrsid9244585 How about some examples that deal with social science? That is what this paper is about.}}} +} \ No newline at end of file diff --git a/RTF Parser Kit/test/com/rtfparserkit/parser/builder/data/lineSeparator.rtf b/RTF Parser Kit/test/com/rtfparserkit/parser/builder/data/lineSeparator.rtf new file mode 100644 index 0000000..3dccc6f --- /dev/null +++ b/RTF Parser Kit/test/com/rtfparserkit/parser/builder/data/lineSeparator.rtf @@ -0,0 +1 @@ +{\rtf1\ansi\ansicpg1252\deff0{\fonttbl{\f0\froman\fcharset0 Times New Roman;}{\f1\froman\fcharset0 Arial;}{\f2\froman\fcharset0 Courier;}}{\colortbl\red0\green0\blue0;\red255\green255\blue255;}{\stylesheet {\style\s0 \ql\fi0\li0\ri0\f1\fs24\cf0 Normal;}{\style\s3 \ql\fi0\li0\ri0\f1\fs26\b\cf0 heading 3;}{\style\s2 \ql\fi0\li0\ri0\f1\fs28\b\i\cf0 heading 2;}{\style\s1 \ql\fi0\li0\ri0\f1\fs32\b\cf0 heading 1;}}{\*\listtable}{\*\listoverridetable}{\*\generator iText 2.1.7 by 1T3XT}{\info}\paperw12242\paperh15842\margl1425\margr360\margt950\margb1425{\header \pard\plain\s0\qr\fi0\li0\ri0\sl320\plain\f0{\field{\*\fldinst PAGE}{\fldrslt }}\f2\fs24 . \line \par}\pgwsxn12242\pghsxn15842\marglsxn1425\margrsxn360\margtsxn950\margbsxn1425\pard\plain\s0\ql\fi-734\li734\ri0\sb480\sa240\sl240\plain\tx720\tqr\tx9580\tx9720{\f2\fs24\cf0\chcbpat1 \tab }{\f2\fs24\cf0\chcbpat1 INNEN. K\u220?CHE - TAG}\par\pard\plain\s0\qj\fi0\li734\ri864\sb240\sa240\sl240\plain\tx1920\tx3840\tx5760\tx7680\tx9600{\f2\fs24\cf0\chcbpat1 Ein Absatz mit Line-Separator:\line Der geht hier auf einer neuen Zeile weiter.}\par\pard\plain\s0\ql\fi-734\li734\ri0\sb480\sa240\sl240\plain\tx720\tqr\tx9580\tx9720{\f2\fs24\cf0\chcbpat1 \tab }{\f2\fs24\cf0\chcbpat1 INNEN. K\u220?CHE - TAG}\par\pard\plain\s0\qj\fi0\li734\ri864\sb240\sl240\plain\tx1920\tx3840\tx5760\tx7680\tx9600{\f2\fs24\cf0\chcbpat1 Hier ist die zweite Szene.}\par} \ No newline at end of file diff --git a/RTF Parser Kit/test/com/rtfparserkit/parser/builder/data/variousStyles.rtf b/RTF Parser Kit/test/com/rtfparserkit/parser/builder/data/variousStyles.rtf new file mode 100644 index 0000000..18fb1e4 --- /dev/null +++ b/RTF Parser Kit/test/com/rtfparserkit/parser/builder/data/variousStyles.rtf @@ -0,0 +1,26 @@ +{\rtf1\ansi\ansicpg1252\cocoartf1348\cocoasubrtf170 +{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;\red217\green11\blue0;\red255\green249\blue89;} +\margl1440\margr1440\vieww10800\viewh8400\viewkind0 +\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardirnatural + +\f0\fs24 \cf0 Normal +\b Bold +\i Bold/Italic +\b0 Italic +\i0 Normal.\ + +\fs36 Bigger Font (18). \ul Underlined +\fs24 \ulnone Normal size. \cf2 Red text. \cb3 On yellow background.\ +\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardirnatural\qc +\cf0 \cb1 Centered.\ +\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardirnatural\qr +\cf0 Right.\ +\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardirnatural\qj +\cf0 Justified.\ +\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\sl480\slmult1\pardirnatural\qj +\cf0 With bigger line spacing. +\fs36 \ +\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardirnatural +\cf0 \ +} \ No newline at end of file diff --git a/RTF Parser Kit/test/com/rtfparserkit/parser/builder/data/variousStylesGrouped.rtf b/RTF Parser Kit/test/com/rtfparserkit/parser/builder/data/variousStylesGrouped.rtf new file mode 100644 index 0000000..cda1463 --- /dev/null +++ b/RTF Parser Kit/test/com/rtfparserkit/parser/builder/data/variousStylesGrouped.rtf @@ -0,0 +1,26 @@ +{\rtf1\ansi\ansicpg1252\cocoartf1348\cocoasubrtf170 +{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;\red217\green11\blue0;\red255\green249\blue89;} +\margl1440\margr1440\vieww10800\viewh8400\viewkind0 +\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardirnatural + +\f0\fs24 \cf0 Normal +{\b Bold +{\i Bold/Italic +\b0 Italic} +} Normal.\ + +\fs36 Bigger Font (18). \ul Underlined +\fs24 \ulnone Normal size. \cf2 Red text. \cb3 On yellow background.\ +\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardirnatural\qc +\cf0 \cb1 Centered.\ +\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardirnatural\qr +\cf0 Right.\ +\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardirnatural\qj +\cf0 Justified.\ +\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\sl480\slmult1\pardirnatural\qj +\cf0 With bigger line spacing. +\fs36 \ +\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardirnatural +\cf0 \ +} \ No newline at end of file diff --git a/RTF Parser Kit/test/com/rtfparserkit/parser/builder/data/variousStylesPages.rtf b/RTF Parser Kit/test/com/rtfparserkit/parser/builder/data/variousStylesPages.rtf new file mode 100644 index 0000000..fee6f91 --- /dev/null +++ b/RTF Parser Kit/test/com/rtfparserkit/parser/builder/data/variousStylesPages.rtf @@ -0,0 +1,43 @@ +{\rtf1\ansi\ansicpg1252\cocoartf1348\cocoasubrtf170 +\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;\red217\green11\blue0;} +\margl1440\margr1440\margb1800\margt1800 +\deftab720 +\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardeftab720\pardirnatural + +\f0\fs24 \cf0 \expnd0\expndtw0\kerning0 +\up0 \nosupersub \ulnone \outl0\strokewidth0 \strokec0 Normal +\b \expnd0\expndtw0\kerning0 +Bold +\i \expnd0\expndtw0\kerning0 +Bold/Italic +\b0 \expnd0\expndtw0\kerning0 + Italic +\i0 \expnd0\expndtw0\kerning0 + Normal.\ +\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardeftab720\pardirnatural + +\fs36 \expnd0\expndtw0\kerning0 +Bigger Font (18). \expnd0\expndtw0\kerning0 +\ul Underlined +\fs24 \expnd0\expndtw0\kerning0 +\ulnone Normal size. \cf2 \expnd0\expndtw0\kerning0 +\strokec2 Red text. On yellow background.\ +\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardeftab720\pardirnatural\qc +\cf0 \expnd0\expndtw0\kerning0 +\strokec0 Centered.\ +\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardeftab720\pardirnatural\qr +\expnd0\expndtw0\kerning0 +Right.\ +\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardeftab720\pardirnatural\qj +\expnd0\expndtw0\kerning0 +Justified.\ +\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardeftab720\sl480\slmult1\pardirnatural\qj +\expnd0\expndtw0\kerning0 +With bigger line spacing. +\fs36 \expnd0\expndtw0\kerning0 +\ +\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardeftab720\pardirnatural +\expnd0\expndtw0\kerning0 +\ +} \ No newline at end of file