summaryrefslogtreecommitdiff
path: root/ooxml/source
diff options
context:
space:
mode:
Diffstat (limited to 'ooxml/source')
-rw-r--r--ooxml/source/framework/JavaOOXMLParser/.classpath6
-rw-r--r--ooxml/source/framework/JavaOOXMLParser/.project17
-rw-r--r--ooxml/source/framework/JavaOOXMLParser/.settings/org.eclipse.jdt.core.prefs11
-rw-r--r--ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/AcceptingStateTable.java69
-rw-r--r--ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/ElementContext.java88
-rw-r--r--ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/Log.java130
-rw-r--r--ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/NameMap.java113
-rw-r--r--ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/NamespaceMap.java91
-rw-r--r--ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/OOXMLParser.java223
-rw-r--r--ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/ParseException.java42
-rw-r--r--ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/ParseTableReader.java100
-rw-r--r--ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/Parser.java249
-rw-r--r--ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/SkipStateTable.java70
-rw-r--r--ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/StateMachine.java330
-rw-r--r--ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/Transition.java77
-rw-r--r--ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/TransitionTable.java85
-rw-r--r--ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/action/ActionDescriptor.java114
-rw-r--r--ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/action/ActionIterator.java118
-rw-r--r--ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/action/ActionManager.java165
-rw-r--r--ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/action/ActionTrigger.java31
-rw-r--r--ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/action/IAction.java53
-rw-r--r--ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/attribute/AttributeDescriptor.java130
-rw-r--r--ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/attribute/AttributeManager.java273
-rw-r--r--ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/attribute/AttributeProvider.java99
-rw-r--r--ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/attribute/AttributeValues.java91
-rw-r--r--ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/type/BlobParser.java102
-rw-r--r--ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/type/DateTimeParser.java42
-rw-r--r--ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/type/ISimpleTypeParser.java31
-rw-r--r--ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/type/ListParser.java53
-rw-r--r--ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/type/NumberParser.java270
-rw-r--r--ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/type/SimpleTypeManager.java118
-rw-r--r--ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/type/StringParser.java122
-rw-r--r--ooxml/source/framework/JavaPartManager/.classpath7
-rw-r--r--ooxml/source/framework/JavaPartManager/.project17
-rw-r--r--ooxml/source/framework/JavaPartManager/.settings/org.eclipse.jdt.core.prefs11
-rw-r--r--ooxml/source/framework/JavaPartManager/src/org/apache/openoffice/ooxml/framework/part/ContentType.java77
-rw-r--r--ooxml/source/framework/JavaPartManager/src/org/apache/openoffice/ooxml/framework/part/ContentTypes.java150
-rw-r--r--ooxml/source/framework/JavaPartManager/src/org/apache/openoffice/ooxml/framework/part/IReferenceProvider.java6
-rw-r--r--ooxml/source/framework/JavaPartManager/src/org/apache/openoffice/ooxml/framework/part/OOXMLPackage.java56
-rw-r--r--ooxml/source/framework/JavaPartManager/src/org/apache/openoffice/ooxml/framework/part/Package.java158
-rw-r--r--ooxml/source/framework/JavaPartManager/src/org/apache/openoffice/ooxml/framework/part/Part.java89
-rw-r--r--ooxml/source/framework/JavaPartManager/src/org/apache/openoffice/ooxml/framework/part/PartManager.java145
-rw-r--r--ooxml/source/framework/JavaPartManager/src/org/apache/openoffice/ooxml/framework/part/PartManagerPrototype.java33
-rw-r--r--ooxml/source/framework/JavaPartManager/src/org/apache/openoffice/ooxml/framework/part/PartName.java130
-rw-r--r--ooxml/source/framework/JavaPartManager/src/org/apache/openoffice/ooxml/framework/part/RelatedParts.java131
-rw-r--r--ooxml/source/framework/JavaPartManager/src/org/apache/openoffice/ooxml/framework/part/RelationshipType.java112
-rw-r--r--ooxml/source/framework/JavaPartManager/src/org/apache/openoffice/ooxml/framework/part/parser/ContentTypesParser.java30
-rw-r--r--ooxml/source/framework/JavaPartManager/src/org/apache/openoffice/ooxml/framework/part/parser/ParserFactory.java46
-rw-r--r--ooxml/source/framework/JavaPartManager/src/org/apache/openoffice/ooxml/framework/part/parser/RelationshipParser.java30
-rwxr-xr-xooxml/source/framework/OOXMLViewer/.classpath8
-rwxr-xr-xooxml/source/framework/OOXMLViewer/.project17
-rwxr-xr-xooxml/source/framework/OOXMLViewer/.settings/org.eclipse.jdt.core.prefs11
-rwxr-xr-xooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/DetailViewManager.java131
-rwxr-xr-xooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/ImageView.java75
-rwxr-xr-xooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/KeyListener.java50
-rwxr-xr-xooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/OOXMLViewer.java208
-rwxr-xr-xooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/PartsView.java137
-rwxr-xr-xooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/StreamView.java266
-rwxr-xr-xooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/content/ContentView.java77
-rwxr-xr-xooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/content/PresentationImporter.java81
-rwxr-xr-xooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/content/PresentationModel.java43
-rwxr-xr-xooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/content/Slide.java56
-rwxr-xr-xooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/content/SlideManager.java77
-rwxr-xr-xooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/content/SlideParser.java80
-rwxr-xr-xooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/tokenview/DocumentFactory.java127
-rwxr-xr-xooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/tokenview/FormatState.java61
-rwxr-xr-xooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/tokenview/Formatter.java93
-rwxr-xr-xooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/tokenview/Line.java239
-rwxr-xr-xooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/tokenview/LineContainer.java194
-rwxr-xr-xooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/tokenview/Run.java249
-rwxr-xr-xooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/tokenview/RunRange.java87
-rwxr-xr-xooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/tokenview/Style.java109
-rwxr-xr-xooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/tokenview/TokenView.java406
-rwxr-xr-xooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/xml/DocumentTokenFormatter.java399
-rwxr-xr-xooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/xml/Token.java51
-rwxr-xr-xooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/xml/TokenType.java41
-rwxr-xr-xooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/xml/XMLScanner.java438
-rwxr-xr-xooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/xml/XMLTokenViewFactory.java106
-rwxr-xr-xooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/xmltokenview/XMLViewFactory.java143
-rw-r--r--ooxml/source/framework/SchemaParser/.classpath6
-rw-r--r--ooxml/source/framework/SchemaParser/.project17
-rw-r--r--ooxml/source/framework/SchemaParser/.settings/org.eclipse.jdt.core.prefs11
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/SchemaReader.java510
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/Test.java81
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/CreatorBase.java124
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/DFACreator.java280
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/EpsilonTransition.java70
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/FiniteAutomaton.java169
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/FiniteAutomatonContainer.java166
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/HopcroftMinimizer.java380
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/NonValidatingCreator.java212
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/SkipData.java54
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/State.java263
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/StateContainer.java73
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/StateContext.java269
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/StateSet.java245
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/Transition.java97
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/ValidatingCreator.java793
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/generator/LogGenerator.java313
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/generator/ParserTablesGenerator.java555
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/generator/html/HtmlGenerator.java623
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/generator/html/code.js442
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/generator/html/display.css57
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/generator/html/linking-template.html22
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/generator/html/template.html24
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/iterator/AttributeIterator.java109
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/iterator/AttributeNodeIterator.java112
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/iterator/DereferencingNodeIterator.java111
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/iterator/NodeIterator.java68
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/iterator/PermutationIterator.java137
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/misc/Log.java126
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/attribute/Attribute.java91
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/attribute/AttributeBase.java117
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/attribute/AttributeGroup.java65
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/attribute/AttributeGroupReference.java110
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/attribute/AttributeReference.java115
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/base/INode.java39
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/base/INodeReference.java32
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/base/INodeVisitor.java85
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/base/Location.java69
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/base/Node.java172
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/base/NodeType.java53
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/base/NodeVisitorAdapter.java203
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/base/QualifiedName.java149
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/All.java96
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/Any.java112
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/Choice.java68
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/ComplexContent.java65
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/ComplexType.java72
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/ComplexTypeReference.java100
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/Element.java109
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/ElementReference.java106
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/Extension.java160
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/Group.java70
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/GroupReference.java109
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/OccurrenceIndicator.java152
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/Sequence.java73
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/optimize/CopyVisitor.java112
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/optimize/RequestVisitor.java128
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/optimize/SchemaOptimizer.java140
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/schema/NamespaceMap.java178
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/schema/Schema.java107
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/schema/SchemaBase.java121
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/schema/TypeContainer.java100
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/simple/BuiltIn.java103
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/simple/BuiltInType.java109
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/simple/List.java84
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/simple/Restriction.java337
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/simple/SimpleContent.java65
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/simple/SimpleType.java102
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/simple/SimpleTypeReference.java107
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/simple/Union.java68
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/parser/FormDefault.java31
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/parser/SchemaParser.java1211
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/parser/XmlNamespace.java69
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/parser/XsdNamespace.java29
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/simple/BlobNode.java131
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/simple/DateTimeNode.java92
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/simple/EnumerationNode.java27
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/simple/ISimpleTypeNode.java48
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/simple/ISimpleTypeNodeVisitor.java31
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/simple/NumberNode.java310
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/simple/SimpleTypeContainer.java102
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/simple/SimpleTypeDescriptor.java86
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/simple/SimpleTypeDescriptorFactory.java307
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/simple/SimpleTypeNodeVisitorAdapter.java60
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/simple/StringNode.java269
-rw-r--r--ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/simple/UnionNode.java151
168 files changed, 22727 insertions, 0 deletions
diff --git a/ooxml/source/framework/JavaOOXMLParser/.classpath b/ooxml/source/framework/JavaOOXMLParser/.classpath
new file mode 100644
index 000000000000..fb565a588d8a
--- /dev/null
+++ b/ooxml/source/framework/JavaOOXMLParser/.classpath
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/ooxml/source/framework/JavaOOXMLParser/.project b/ooxml/source/framework/JavaOOXMLParser/.project
new file mode 100644
index 000000000000..409d549457ee
--- /dev/null
+++ b/ooxml/source/framework/JavaOOXMLParser/.project
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>JavaOOXMLParser</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
diff --git a/ooxml/source/framework/JavaOOXMLParser/.settings/org.eclipse.jdt.core.prefs b/ooxml/source/framework/JavaOOXMLParser/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 000000000000..7341ab1683c4
--- /dev/null
+++ b/ooxml/source/framework/JavaOOXMLParser/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,11 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.7
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.7
diff --git a/ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/AcceptingStateTable.java b/ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/AcceptingStateTable.java
new file mode 100644
index 000000000000..c11ea4405fe6
--- /dev/null
+++ b/ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/AcceptingStateTable.java
@@ -0,0 +1,69 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.parser;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/** List of all accepting states.
+ *
+ * The accepting status of states is important when a closing tag is seen.
+ * It denotes the end of the input stream for the state machine of the currently
+ * processed element. It is an error when the current state is not accepting
+ * when a closing tag is processed.
+ */
+public class AcceptingStateTable
+{
+ public AcceptingStateTable (final Iterable<String[]> aData)
+ {
+ maAcceptingStates = new HashSet<>();
+
+ for (final String[] aLine : aData)
+ {
+ // Create new transition.
+ final int nStateId = Integer.parseInt(aLine[1]);
+
+ maAcceptingStates.add(nStateId);
+ }
+ }
+
+
+
+
+ public boolean Contains (final int nStateId)
+ {
+ return maAcceptingStates.contains(nStateId);
+ }
+
+
+
+
+ public int GetAcceptingStateCount ()
+ {
+ return maAcceptingStates.size();
+ }
+
+
+
+
+ private final Set<Integer> maAcceptingStates;
+}
diff --git a/ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/ElementContext.java b/ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/ElementContext.java
new file mode 100644
index 000000000000..2114dd75af4e
--- /dev/null
+++ b/ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/ElementContext.java
@@ -0,0 +1,88 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.parser;
+
+import org.apache.openoffice.ooxml.parser.attribute.AttributeValues;
+
+/** Context that has the same life time (by default) as the element it represents.
+ * Gives access to the attribute values and the parent context.
+ */
+public class ElementContext
+{
+ ElementContext (
+ final String sElementName,
+ final String sTypeName,
+ final boolean bIsSkipping,
+ final AttributeValues aValues,
+ final ElementContext aParentContext)
+ {
+ msElementName = sElementName;
+ msTypeName = sTypeName;
+ mbIsSkipping = bIsSkipping;
+ maAttributeValues = aValues;
+ maParentContext = aParentContext;
+ }
+
+
+
+
+ public String GetElementName ()
+ {
+ return msElementName;
+ }
+
+
+
+
+ public String GetTypeName ()
+ {
+ return msTypeName;
+ }
+
+
+
+
+ public AttributeValues GetAttributes ()
+ {
+ return maAttributeValues;
+ }
+
+
+
+
+ /** Return the context of the parent element.
+ * Can be null when there is no parent element.
+ */
+ public ElementContext GetParentContext ()
+ {
+ return maParentContext;
+ }
+
+
+
+
+ private final String msElementName;
+ private final String msTypeName;
+ private final boolean mbIsSkipping;
+ private final AttributeValues maAttributeValues;
+ private final ElementContext maParentContext;
+}
diff --git a/ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/Log.java b/ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/Log.java
new file mode 100644
index 000000000000..cefdd513f8b4
--- /dev/null
+++ b/ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/Log.java
@@ -0,0 +1,130 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.parser;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+public class Log
+{
+ public static Log Std = new Log(System.out);
+ public static Log Err = new Log(System.err);
+ public static Log Dbg = Std;
+
+
+ public Log (final OutputStream aOut)
+ {
+ maOut = aOut;
+ msIndentation = "";
+ }
+
+
+
+
+ public Log (final String sFilename)
+ {
+ this(CreateFileOutputStream(sFilename));
+ }
+
+
+
+
+ public Log (final File aFile)
+ {
+ this(CreateFileOutputStream(aFile));
+ }
+
+
+
+
+ private static OutputStream CreateFileOutputStream (final File aFile)
+ {
+ try
+ {
+ return new FileOutputStream(aFile);
+ }
+ catch (final Exception aException)
+ {
+ aException.printStackTrace();
+ return null;
+ }
+ }
+
+
+
+
+ public void printf (final String sFormat, final Object ... aArgumentList)
+ {
+ try
+ {
+ maOut.write(msIndentation.getBytes());
+ maOut.write(String.format(sFormat, aArgumentList).getBytes());
+ }
+ catch (IOException e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+
+
+
+ public void IncreaseIndentation ()
+ {
+ msIndentation += " ";
+ }
+
+
+
+
+ public void DecreaseIndentation ()
+ {
+ msIndentation = msIndentation.substring(4);
+ }
+
+
+
+
+ private static OutputStream CreateFileOutputStream (final String sFilename)
+ {
+ OutputStream aOut;
+ try
+ {
+ aOut = new FileOutputStream(sFilename);
+ return aOut;
+ }
+ catch (FileNotFoundException e)
+ {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+
+
+
+ private final OutputStream maOut;
+ private String msIndentation;
+}
diff --git a/ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/NameMap.java b/ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/NameMap.java
new file mode 100644
index 000000000000..a8af8f93ce51
--- /dev/null
+++ b/ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/NameMap.java
@@ -0,0 +1,113 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.parser;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Vector;
+
+public class NameMap
+{
+ NameMap (final Vector<String[]> aData)
+ {
+ maNameToIdMap = new HashMap<>();
+ maIdToNameMap = new Vector<>();
+
+ for (final String[] aLine : aData)
+ {
+ final int nId = Integer.parseInt(aLine[1]);
+
+ maNameToIdMap.put(aLine[2], nId);
+
+ if (maIdToNameMap.size() <= nId)
+ maIdToNameMap.setSize(nId+1);
+ maIdToNameMap.set(nId, aLine[2]);
+ }
+ }
+
+
+
+
+ public int GetIdForName (
+ final String sName)
+ {
+ if ( ! maNameToIdMap.containsKey(sName))
+ throw new RuntimeException("token '"+sName+"' is not known");
+
+ return maNameToIdMap.get(sName);
+ }
+
+
+
+
+ public int GetIdForOptionalName (
+ final String sName)
+ {
+ final Integer aId = maNameToIdMap.get(sName);
+ if (aId == null)
+ return -1;
+ else
+ return aId;
+ }
+
+
+
+
+ public String GetNameForId (final int nId)
+ {
+ if (nId == -1)
+ return "<none>";
+ else
+ return maIdToNameMap.get(nId);
+ }
+
+
+
+
+ public int GetNameCount ()
+ {
+ return maIdToNameMap.size();
+ }
+
+
+
+
+ /** Return the ids of all states whose names match the given pattern.
+ */
+ public Vector<Integer> GetMatchingStateIds (final String sPattern)
+ {
+ final Vector<Integer> aStateIds = new Vector<>();
+ for (final Entry<String,Integer> aEntry : maNameToIdMap.entrySet())
+ {
+ if (aEntry.getKey().matches(sPattern))
+ aStateIds.add(aEntry.getValue());
+ }
+ return aStateIds;
+ }
+
+
+
+
+ private final Map<String,Integer> maNameToIdMap;
+ private final Vector<String> maIdToNameMap;
+}
diff --git a/ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/NamespaceMap.java b/ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/NamespaceMap.java
new file mode 100644
index 000000000000..d5a2af818c53
--- /dev/null
+++ b/ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/NamespaceMap.java
@@ -0,0 +1,91 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.parser;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Vector;
+
+public class NamespaceMap
+{
+ public class NamespaceDescriptor
+ {
+ NamespaceDescriptor (final String sPrefix, final int nId)
+ {
+ Prefix = sPrefix;
+ Id = nId;
+ }
+ public final String Prefix;
+ public final int Id;
+ }
+ NamespaceMap (final Vector<String[]> aData)
+ {
+ maUriToDescriptorMap = new HashMap<>();
+ maIdToDescriptorMap = new HashMap<>();
+
+ for (final String[] aLine : aData)
+ {
+ final int nId = Integer.parseInt(aLine[2]);
+ final NamespaceDescriptor aDescriptor = new NamespaceDescriptor(aLine[1], nId);
+ maUriToDescriptorMap.put(
+ aLine[3],
+ aDescriptor);
+ maIdToDescriptorMap.put(
+ nId,
+ aDescriptor);
+ }
+ }
+
+
+
+
+ public NamespaceDescriptor GetDescriptorForURI (final String sURI)
+ {
+ if (sURI == null)
+ throw new RuntimeException("namespace is null");
+ if ( ! maUriToDescriptorMap.containsKey(sURI))
+ throw new RuntimeException("namespace '"+sURI+"' is not known");
+ return maUriToDescriptorMap.get(sURI);
+ }
+
+
+
+
+ public NamespaceDescriptor GetDescriptorForId (final int nId)
+ {
+ return maIdToDescriptorMap.get(nId);
+ }
+
+
+
+
+ public int GetNamespaceCount ()
+ {
+ return maUriToDescriptorMap.size();
+ }
+
+
+
+
+ private final Map<String,NamespaceDescriptor> maUriToDescriptorMap;
+ private final Map<Integer,NamespaceDescriptor> maIdToDescriptorMap;
+}
diff --git a/ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/OOXMLParser.java b/ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/OOXMLParser.java
new file mode 100644
index 000000000000..369f5c3daf42
--- /dev/null
+++ b/ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/OOXMLParser.java
@@ -0,0 +1,223 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.parser;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.TreeMap;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+
+import javax.xml.stream.Location;
+
+import org.apache.openoffice.ooxml.parser.action.ActionManager;
+import org.apache.openoffice.ooxml.parser.action.ActionTrigger;
+import org.apache.openoffice.ooxml.parser.action.IAction;
+
+/** This OOXML parser is based on the output of the schema parser.
+ * It exists to debug the schema parser and as illustration and preparation of
+ * the C++ parse (yet to come.)
+ * Because of this, the parser data (set of states and transitions) are
+ * read at runtime while a real parser would do that at compile time.
+ */
+public class OOXMLParser
+{
+ class ActionContext
+ {
+ public Map<String,Integer> TypeCounts = new TreeMap<>();
+ }
+ /** The parser is called with two arguments:
+ * - A path to where the parser tables with the states and transitions can
+ * be found.
+ * - The XML input file or Zip stream to parse.
+ * The syntax for a Zip stream contains a '#' that separates the filename
+ * to its left from the entry name to its right.
+ */
+ public static void main (final String ... aArgumentList)
+ {
+ if (aArgumentList.length<2 ||aArgumentList.length>3)
+ throw new RuntimeException("usage: OOXMLParser <parser-tables-path> <XML-input-file> <log-file>?");
+
+ if (aArgumentList.length == 3)
+ {
+ final File aLogFile = new File(aArgumentList[2]);
+ Log.Dbg = new Log(aLogFile);
+ System.out.printf("writing log data to %s\n", aLogFile.toString());
+ }
+ else
+ {
+ Log.Dbg = null;
+ System.out.printf("writing no log data\n");
+ }
+
+ new OOXMLParser(aArgumentList[0], aArgumentList[1]);
+ }
+
+
+
+ private OOXMLParser (
+ final String sParseTableFilename,
+ final String sInputFilename)
+ {
+ long nStartTime = System.currentTimeMillis();
+ final StateMachine aMachine = new StateMachine(new File(sParseTableFilename), null);
+ final InputStream aIn = GetInputStream(sInputFilename);
+ long nEndTime = System.currentTimeMillis();
+
+ final ActionContext aActionContext = new ActionContext();
+ AddSomeActions(aMachine.GetActionManager(), aActionContext);
+
+ System.out.printf("initialzed parser in %fs\n", (nEndTime-nStartTime)/1000.0);
+
+ try
+ {
+ nStartTime = System.currentTimeMillis();
+ final Parser aParser = new Parser(aMachine, aIn);
+ aParser.Parse();
+ final int nElementCount = aParser.GetElementCount();
+ nEndTime = System.currentTimeMillis();
+ System.out.printf("parsed %d elements in %fs\n",
+ nElementCount,
+ (nEndTime-nStartTime)/1000.0);
+
+ System.out.printf("%d different elements found:\n", aActionContext.TypeCounts.size());
+ for (final Entry<String, Integer> aEntry : aActionContext.TypeCounts.entrySet())
+ {
+ System.out.printf("%-32s : %6d\n", aEntry.getKey(), aEntry.getValue());
+ }
+ }
+ catch (final Exception aException)
+ {
+ aException.printStackTrace();
+ }
+ }
+
+
+
+
+ private static void AddSomeActions (
+ final ActionManager aActionManager,
+ final ActionContext aActionContext)
+ {
+ aActionManager.AddElementStartAction(
+ "*",
+ new IAction()
+ {
+ @Override public void Run(
+ final ActionTrigger eTrigger,
+ final ElementContext aContext,
+ final String sText,
+ final Location aStartLocation,
+ final Location aEndLocation)
+ {
+ Integer nValue = aActionContext.TypeCounts.get(aContext.GetTypeName());
+ if (nValue == null)
+ nValue = 1;
+ else
+ ++nValue;
+ aActionContext.TypeCounts.put(aContext.GetTypeName(), nValue);
+ }
+ }
+ );
+ aActionManager.AddElementStartAction(
+ ".*CT_Shd",
+ new IAction()
+ {
+ @Override public void Run(
+ final ActionTrigger eTrigger,
+ final ElementContext aContext,
+ final String sText,
+ final Location aStartLocation,
+ final Location aEndLocation)
+ {
+ System.out.printf("processing %s of element %s at position %d\n",
+ eTrigger,
+ aContext.GetElementName(),
+ aStartLocation.getCharacterOffset());
+
+ if (aContext.GetAttributes().GetAttributeCount() == 0)
+ System.out.printf(" no attributes\n");
+ else
+ for (final Entry<String,String> aAttribute : aContext.GetAttributes().GetAttributes())
+ System.out.printf(" %s -> %s\n", aAttribute.getKey(), aAttribute.getValue());
+ }
+ }
+ );
+ aActionManager.AddTextAction(
+ ".*CT_Text",
+ new IAction()
+ {
+ @Override public void Run(
+ final ActionTrigger eTrigger,
+ final ElementContext aContext,
+ final String sText,
+ final Location aStartLocation,
+ final Location aEndLocation)
+ {
+// System.out.printf("%s text \"%s\"\n", aContext.GetTypeName(), sText.replace("\n", "\\n"));
+ }
+ }
+ );
+ }
+
+
+
+
+ private static InputStream GetInputStream (final String sInputName)
+ {
+ final InputStream aIn;
+ try
+ {
+ final int nSeparator = sInputName.indexOf('#');
+ if (nSeparator >= 0)
+ {
+ // Split the input name into the file name of the archive and the
+ // name of a zip entry.
+ final String sArchiveName = sInputName.substring(0, nSeparator);
+ String sEntryName = sInputName.substring(nSeparator+1);
+
+ // Normalize and cleanup the entry name.
+ sEntryName = sEntryName.replace('\\', '/');
+ if (sEntryName.startsWith("/"))
+ sEntryName = sEntryName.substring(1);
+
+ final ZipFile aZipFile = new ZipFile(new File(sArchiveName));
+ final ZipEntry aZipEntry = aZipFile.getEntry(sEntryName);
+ aIn = aZipFile.getInputStream(aZipEntry);
+ }
+ else
+ {
+ // The input name points to a plain XML file.
+ aIn = new FileInputStream(sInputName);
+ }
+ }
+ catch (final Exception aException)
+ {
+ aException.printStackTrace();
+ return null;
+ }
+ return aIn;
+ }
+}
diff --git a/ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/ParseException.java b/ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/ParseException.java
new file mode 100644
index 000000000000..ae07f9ca1fec
--- /dev/null
+++ b/ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/ParseException.java
@@ -0,0 +1,42 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.parser;
+
+import javax.xml.stream.Location;
+
+@SuppressWarnings("serial")
+public class ParseException
+ extends RuntimeException
+{
+ public ParseException (
+ final Exception aException,
+ final Location aLocation)
+ {
+ super(aException);
+ Location = aLocation;
+ }
+
+
+
+
+ public final Location Location;
+}
diff --git a/ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/ParseTableReader.java b/ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/ParseTableReader.java
new file mode 100644
index 000000000000..0288886c5342
--- /dev/null
+++ b/ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/ParseTableReader.java
@@ -0,0 +1,100 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.parser;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Vector;
+
+/** A simple reader for the parse table data that allows simple filtering on the
+ * first word in each line.
+ *
+ * Lines that only contain comments or whitespace are ignored.
+ *
+ */
+public class ParseTableReader
+{
+ public ParseTableReader (final File aFile)
+ {
+ maSections = new HashMap<>();
+
+ try
+ {
+ final BufferedReader aReader = new BufferedReader(new FileReader(aFile));
+
+ while (true)
+ {
+ final String sLine = aReader.readLine();
+ if (sLine == null)
+ break;
+ else if (sLine.startsWith("#"))
+ continue;
+ else if (sLine.isEmpty())
+ continue;
+
+ final String[] aLineParts = sLine.split("\\s+");
+ for (int nIndex=0; nIndex<aLineParts.length; ++nIndex)
+ {
+ final String sPart = aLineParts[nIndex];
+ if (sPart.isEmpty())
+ {
+ throw new RuntimeException();
+ }
+ else if (sPart.charAt(0) == '"')
+ {
+ // Remove leading and trailing quotes, unquote spaces.
+ aLineParts[nIndex] = sPart.substring(1, sPart.length()-1).replace("%20", " ").replace("&quot;", "\"");
+ }
+ }
+ GetSection(aLineParts[0]).add(aLineParts);
+ }
+
+ aReader.close();
+ }
+ catch (final Exception aException)
+ {
+ throw new RuntimeException(aException);
+ }
+ }
+
+
+
+
+ public Vector<String[]> GetSection (final String sSectionName)
+ {
+ Vector<String[]> aSection = maSections.get(sSectionName);
+ if (aSection == null)
+ {
+ aSection = new Vector<>();
+ maSections.put(sSectionName, aSection);
+ }
+ return aSection;
+ }
+
+
+
+
+ private final Map<String,Vector<String[]>> maSections;
+}
diff --git a/ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/Parser.java b/ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/Parser.java
new file mode 100644
index 000000000000..cd51087f3c3d
--- /dev/null
+++ b/ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/Parser.java
@@ -0,0 +1,249 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.parser;
+
+import java.io.InputStream;
+import java.util.Vector;
+
+import javax.xml.stream.Location;
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
+
+import org.apache.openoffice.ooxml.parser.action.ActionManager;
+import org.apache.openoffice.ooxml.parser.attribute.AttributeProvider;
+
+/** This is the actual parser (where OOXMLParser is the front end that handles
+ * parameters given to the main method).
+ */
+public class Parser
+{
+ public Parser (
+ final StateMachine aMachine,
+ final InputStream aIn)
+ {
+ maMachine = aMachine;
+ maReader = GetStreamReader(aIn, "input");
+ mnElementCount = 0;
+ }
+
+
+
+
+ public void Parse ()
+ {
+ Location aLocation = null;
+ try
+ {
+ final AttributeProvider aAttributeProvider = new AttributeProvider(maReader);
+ while (maReader.hasNext())
+ {
+ aLocation = maReader.getLocation();
+ final int nCode = maReader.next();
+ switch(nCode)
+ {
+ case XMLStreamReader.START_ELEMENT:
+ ++mnElementCount;
+ if (maMachine.IsInSkipState())
+ {
+ if (Log.Dbg != null)
+ Log.Dbg.printf("is skip state -> starting to skip\n");
+ Skip();
+ }
+ else if ( ! maMachine.ProcessStartElement(
+ maReader.getNamespaceURI(),
+ maReader.getLocalName(),
+ aLocation,
+ maReader.getLocation(),
+ aAttributeProvider))
+ {
+ if (Log.Dbg != null)
+ Log.Dbg.printf("starting to skip to recover from error\n");
+ Skip();
+ }
+ break;
+
+ case XMLStreamReader.END_ELEMENT:
+ maMachine.ProcessEndElement(
+ maReader.getNamespaceURI(),
+ maReader.getLocalName(),
+ aLocation,
+ maReader.getLocation());
+ break;
+
+ case XMLStreamReader.CHARACTERS:
+ maMachine.ProcessCharacters(
+ maReader.getText(),
+ aLocation,
+ maReader.getLocation());
+ break;
+
+ case XMLStreamReader.END_DOCUMENT:
+ break;
+
+ default:
+ Log.Err.printf("can't handle XML event of type %d\n", nCode);
+ }
+ }
+
+ maReader.close();
+ }
+ catch (final XMLStreamException aException)
+ {
+ aException.printStackTrace();
+ }
+ catch (final Exception aException)
+ {
+ throw new ParseException(
+ aException,
+ aLocation);
+ }
+ }
+
+
+
+
+
+
+ public int GetElementCount ()
+ {
+ return mnElementCount;
+ }
+
+
+
+
+ private void Skip ()
+ {
+ if (Log.Dbg != null)
+ {
+ Log.Dbg.printf("starting to skip on %s at L%dC%d\n",
+ maReader.getLocalName(),
+ maReader.getLocation().getLineNumber(),
+ maReader.getLocation().getColumnNumber());
+ Log.Dbg.IncreaseIndentation();
+ }
+
+ // We are called when processing a start element. This means that we are
+ // already at relative depth 1.
+ int nRelativeDepth = 1;
+ try
+ {
+ while (maReader.hasNext())
+ {
+ final int nCode = maReader.next();
+ switch (nCode)
+ {
+ case XMLStreamReader.START_ELEMENT:
+ ++nRelativeDepth;
+ ++mnElementCount;
+ if (Log.Dbg != null)
+ {
+ Log.Dbg.printf("skipping start element %s\n", maReader.getLocalName());
+ Log.Dbg.IncreaseIndentation();
+ }
+ break;
+
+ case XMLStreamReader.END_ELEMENT:
+ --nRelativeDepth;
+ if (Log.Dbg != null)
+ Log.Dbg.DecreaseIndentation();
+ if (nRelativeDepth <= 0)
+ {
+ if (Log.Dbg != null)
+ Log.Dbg.printf("leaving skip mode on %s\n", maReader.getLocalName());
+ return;
+ }
+ break;
+
+ case XMLStreamReader.END_DOCUMENT:
+ throw new RuntimeException("saw end of document while skipping elements\n");
+
+ case XMLStreamReader.CHARACTERS:
+ SkipText(maReader.getText());
+ break;
+
+ default:
+ if (Log.Dbg != null)
+ Log.Dbg.printf("%s\n", nCode);
+ break;
+ }
+ }
+ }
+ catch (final XMLStreamException aException)
+ {
+ aException.printStackTrace();
+ }
+ }
+
+
+
+
+ private void SkipText (final String sText)
+ {
+ if (Log.Dbg != null)
+ Log.Dbg.printf("skipping text [%s]\n", sText.replace("\n", "\\n"));
+ }
+
+
+
+
+ private XMLStreamReader GetStreamReader (
+ final InputStream aIn,
+ final String sDescription)
+ {
+ if (aIn == null)
+ return null;
+
+ try
+ {
+ final XMLInputFactory aFactory = (XMLInputFactory)XMLInputFactory.newInstance();
+ aFactory.setProperty(XMLInputFactory.IS_REPLACING_ENTITY_REFERENCES, false);
+ aFactory.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, false);
+ aFactory.setProperty(XMLInputFactory.IS_COALESCING, false);
+
+ return (XMLStreamReader)aFactory.createXMLStreamReader(
+ sDescription,
+ aIn);
+ }
+ catch (final Exception aException)
+ {
+ aException.printStackTrace();
+ return null;
+ }
+ }
+
+
+
+
+ public ActionManager GetActionManager()
+ {
+ return maMachine.GetActionManager();
+ }
+
+
+
+
+ private final XMLStreamReader maReader;
+ private final StateMachine maMachine;
+ private int mnElementCount;
+}
diff --git a/ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/SkipStateTable.java b/ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/SkipStateTable.java
new file mode 100644
index 000000000000..0171b743a811
--- /dev/null
+++ b/ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/SkipStateTable.java
@@ -0,0 +1,70 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.parser;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/** Table of all skip states.
+ *
+ * A skip state corresponds to the 'any' element in the schemas.
+ * It means that the content of the element is specified by an extension of the
+ * schema which may or may not be known at parse time.
+ * At the moment the whole element is skipped, i.e. ignored.
+ *
+ */
+public class SkipStateTable
+{
+ public SkipStateTable (final Iterable<String[]> aData)
+ {
+ maSkipStates = new HashSet<>();
+
+ for (final String[] aLine : aData)
+ {
+ // Create new transition.
+ final int nStateId = Integer.parseInt(aLine[1]);
+
+ maSkipStates.add(nStateId);
+ }
+ }
+
+
+
+
+ public boolean Contains (final int nStateId)
+ {
+ return maSkipStates.contains(nStateId);
+ }
+
+
+
+
+ public int GetSkipStateCount ()
+ {
+ return maSkipStates.size();
+ }
+
+
+
+
+ private final Set<Integer> maSkipStates;
+}
diff --git a/ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/StateMachine.java b/ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/StateMachine.java
new file mode 100644
index 000000000000..39ff4dfd8137
--- /dev/null
+++ b/ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/StateMachine.java
@@ -0,0 +1,330 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.parser;
+
+import java.io.File;
+import java.util.Stack;
+import java.util.Vector;
+
+import javax.xml.stream.Location;
+
+import org.apache.openoffice.ooxml.parser.action.ActionManager;
+import org.apache.openoffice.ooxml.parser.action.ActionTrigger;
+import org.apache.openoffice.ooxml.parser.action.IAction;
+import org.apache.openoffice.ooxml.parser.attribute.AttributeManager;
+import org.apache.openoffice.ooxml.parser.attribute.AttributeProvider;
+import org.apache.openoffice.ooxml.parser.attribute.AttributeValues;
+import org.apache.openoffice.ooxml.parser.type.SimpleTypeManager;
+
+/** The state machine is initialized at creation from the data tables
+ * created previously by a stack automaton.
+ */
+public class StateMachine
+{
+ public StateMachine (
+ final File aParseTableFile,
+ final Vector<String> aErrorsAndWarnings)
+ {
+ if (Log.Dbg != null)
+ Log.Dbg.printf("reading parse tables from %s\n", aParseTableFile.toString());
+
+ final ParseTableReader aReader = new ParseTableReader(aParseTableFile);
+ maNamespaceMap = new NamespaceMap(aReader.GetSection("namespace"));
+ maNameMap = new NameMap(aReader.GetSection("name"));
+ maStateNameMap = new NameMap(aReader.GetSection("state-name"));
+ maTransitions = new TransitionTable(aReader.GetSection("transition"));
+ maSkipStates = new SkipStateTable(aReader.GetSection("skip"));
+ maAttributeValueMap = new NameMap(aReader.GetSection("attribute-value"));
+ maAcceptingStates = new AcceptingStateTable(aReader.GetSection("accepting-state"));
+ maSimpleTypeManager = new SimpleTypeManager(
+ aReader.GetSection("simple-type"),
+ maAttributeValueMap);
+ maAttributeManager = new AttributeManager(
+ aReader.GetSection("attribute"),
+ maNamespaceMap,
+ maNameMap,
+ maStateNameMap,
+ maSimpleTypeManager,
+ aErrorsAndWarnings);
+ mnStartStateId = Integer.parseInt(aReader.GetSection("start-state").firstElement()[1]);
+ mnEndStateId = Integer.parseInt(aReader.GetSection("end-state").firstElement()[1]);
+
+ mnCurrentStateId = mnStartStateId;
+ maStateStack = new Stack<>();
+ maElementContextStack = new Stack<>();
+ maActionManager = new ActionManager(maStateNameMap);
+ maErrorsAndWarnings = aErrorsAndWarnings;
+
+ if (Log.Dbg != null)
+ {
+ Log.Dbg.printf("read %d namespace, %d names, %d states (%d skip, %d accept), %d transitions and %d attributes\n",
+ maNamespaceMap.GetNamespaceCount(),
+ maNameMap.GetNameCount(),
+ maStateNameMap.GetNameCount(),
+ maSkipStates.GetSkipStateCount(),
+ maAcceptingStates.GetAcceptingStateCount(),
+ maTransitions.GetTransitionCount(),
+ maAttributeManager.GetAttributeCount());
+ Log.Dbg.printf("starting in state _start_ (%d)\n", mnCurrentStateId);
+ }
+ }
+
+
+
+
+ public boolean ProcessStartElement (
+ final String sNamespaceURI,
+ final String sElementName,
+ final Location aStartLocation,
+ final Location aEndLocation,
+ final AttributeProvider aAttributes)
+ {
+ boolean bResult = false;
+
+ try
+ {
+ final NamespaceMap.NamespaceDescriptor aNamespaceDescriptor = maNamespaceMap.GetDescriptorForURI(sNamespaceURI);
+ final int nElementNameId = maNameMap.GetIdForName(sElementName);
+ if (Log.Dbg != null)
+ Log.Dbg.printf("%s:%s(%d:%d) L%dC%d\n",
+ aNamespaceDescriptor.Prefix,
+ sElementName,
+ aNamespaceDescriptor.Id,
+ nElementNameId,
+ aStartLocation.getLineNumber(),
+ aStartLocation.getColumnNumber());
+
+ final Transition aTransition = maTransitions.GetTransition(
+ mnCurrentStateId,
+ aNamespaceDescriptor.Id,
+ nElementNameId);
+ if (aTransition == null)
+ {
+ final String sText = String.format(
+ "can not find transition for state %s(%d) and element %s:%s(%d:%d) at L%dC%d\n",
+ maStateNameMap.GetNameForId(mnCurrentStateId),
+ mnCurrentStateId,
+ aNamespaceDescriptor.Prefix,
+ maNameMap.GetNameForId(nElementNameId),
+ aNamespaceDescriptor.Id,
+ nElementNameId,
+ aStartLocation.getLineNumber(),
+ aStartLocation.getColumnNumber());
+ Log.Err.printf(sText);
+ if (Log.Dbg != null)
+ Log.Dbg.printf(sText);
+ }
+ else
+ {
+ if (Log.Dbg != null)
+ {
+ Log.Dbg.printf(" %s(%d) -> %s(%d) via %s(%d)",
+ maStateNameMap.GetNameForId(mnCurrentStateId),
+ mnCurrentStateId,
+ maStateNameMap.GetNameForId(aTransition.GetEndStateId()),
+ aTransition.GetEndStateId(),
+ maStateNameMap.GetNameForId(aTransition.GetActionId()),
+ aTransition.GetActionId());
+ Log.Dbg.printf("\n");
+ }
+
+ // Follow the transition to its end state but first process its
+ // content. We do that by
+
+ if (Log.Dbg != null)
+ Log.Dbg.IncreaseIndentation();
+
+ // a) pushing the end state to the state stack so that on the
+ // end tag that corresponds to the current start tag it will become the current state.
+ maStateStack.push(aTransition.GetEndStateId());
+
+ // b) entering the state that corresponds to start tag that
+ // we are currently processing.
+ mnCurrentStateId = aTransition.GetActionId();
+
+ // c) Prepare the attributes and store them in the new element context.
+ final AttributeValues aAttributeValues = maAttributeManager.ParseAttributes(
+ mnCurrentStateId,
+ aAttributes);
+
+ // d) creating a new ElementContext for the element that just starts.
+ maElementContextStack.push(maCurrentElementContext);
+ final ElementContext aPreviousElementContext = maCurrentElementContext;
+ maCurrentElementContext = new ElementContext(
+ sElementName,
+ maStateNameMap.GetNameForId(aTransition.GetActionId()),
+ false,
+ aAttributeValues,
+ aPreviousElementContext);
+
+ // e) and run all actions that are bound to the the current start tag.
+ ExecuteActions(
+ mnCurrentStateId,
+ maCurrentElementContext,
+ ActionTrigger.ElementStart,
+ null,
+ aStartLocation,
+ aEndLocation);
+
+ bResult = true;
+ }
+ }
+ catch (RuntimeException aException)
+ {
+ Log.Err.printf("error at line %d and column %d\n",
+ aStartLocation.getLineNumber(),
+ aStartLocation.getColumnNumber());
+ throw aException;
+ }
+ return bResult;
+ }
+
+
+
+
+ public void ProcessEndElement (
+ final String sNamespaceURI,
+ final String sElementName,
+ final Location aStartLocation,
+ final Location aEndLocation)
+ {
+ if ( ! maAcceptingStates.Contains(mnCurrentStateId)
+ && mnCurrentStateId!=-1)
+ {
+ if (Log.Dbg != null)
+ Log.Dbg.printf("current state %s(%d) is not an accepting state\n",
+ maStateNameMap.GetNameForId(mnCurrentStateId),
+ mnCurrentStateId);
+ throw new RuntimeException("not expecting end element "+sElementName);
+ }
+
+ final NamespaceMap.NamespaceDescriptor aDescriptor = maNamespaceMap.GetDescriptorForURI(sNamespaceURI);
+
+ // Leave the current element.
+
+ final int nPreviousStateId = mnCurrentStateId;
+ mnCurrentStateId = maStateStack.pop();
+ if (mnCurrentStateId == mnEndStateId)
+ mnCurrentStateId = mnStartStateId;
+
+ final ElementContext aPreviousElementContext = maCurrentElementContext;
+ maCurrentElementContext = maElementContextStack.pop();
+
+ ExecuteActions(
+ nPreviousStateId,
+ aPreviousElementContext,
+ ActionTrigger.ElementEnd,
+ null,
+ aStartLocation,
+ aEndLocation);
+
+ if (Log.Dbg != null)
+ {
+ Log.Dbg.DecreaseIndentation();
+ Log.Dbg.printf("/%s:%s L%d%d\n",
+ aDescriptor.Prefix,
+ sElementName,
+ aStartLocation.getLineNumber(),
+ aStartLocation.getColumnNumber());
+ Log.Dbg.printf(" %s(%d) <- %s(%d)\n",
+ maStateNameMap.GetNameForId(nPreviousStateId),
+ nPreviousStateId,
+ maStateNameMap.GetNameForId(mnCurrentStateId),
+ mnCurrentStateId);
+ }
+ }
+
+
+
+
+ public void ProcessCharacters (
+ final String sText,
+ final Location aStartLocation,
+ final Location aEndLocation)
+ {
+ if (Log.Dbg != null)
+ Log.Dbg.printf("text [%s]\n", sText.replace("\n", "\\n"));
+
+ ExecuteActions(
+ mnCurrentStateId,
+ maCurrentElementContext,
+ ActionTrigger.Text,
+ sText,
+ aStartLocation,
+ aEndLocation);
+
+ }
+
+
+
+
+ public boolean IsInSkipState ()
+ {
+ return maSkipStates.Contains(mnCurrentStateId);
+ }
+
+
+
+
+ public ActionManager GetActionManager ()
+ {
+ return maActionManager;
+ }
+
+
+
+
+ private void ExecuteActions (
+ final int nStateId,
+ final ElementContext aElementContext,
+ final ActionTrigger eTrigger,
+ final String sText,
+ final Location aStartLocation,
+ final Location aEndLocation)
+ {
+ final Iterable<IAction> aActions = maActionManager.GetActions(nStateId, eTrigger);
+ if (aActions != null)
+ for (final IAction aAction : aActions)
+ aAction.Run(eTrigger, aElementContext, sText, aStartLocation, aEndLocation);
+ }
+
+
+
+
+ private final NamespaceMap maNamespaceMap;
+ private final NameMap maNameMap;
+ private final NameMap maStateNameMap;
+ private final TransitionTable maTransitions;
+ private final SimpleTypeManager maSimpleTypeManager;
+ private final AttributeManager maAttributeManager;
+ private final NameMap maAttributeValueMap;
+ private int mnCurrentStateId;
+ private Stack<Integer> maStateStack;
+ private ElementContext maCurrentElementContext;
+ private Stack<ElementContext> maElementContextStack;
+ private final int mnStartStateId;
+ private final int mnEndStateId;
+ private SkipStateTable maSkipStates;
+ private AcceptingStateTable maAcceptingStates;
+ private final ActionManager maActionManager;
+ private final Vector<String> maErrorsAndWarnings;
+}
diff --git a/ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/Transition.java b/ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/Transition.java
new file mode 100644
index 000000000000..c5c956116b28
--- /dev/null
+++ b/ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/Transition.java
@@ -0,0 +1,77 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.parser;
+
+class Transition
+{
+ Transition (
+ final int nStartStateId,
+ final int nEndStateId,
+ final int nElementId,
+ final int nActionStateId)
+ {
+ mnStartStateId = nStartStateId;
+ mnEndStateId = nEndStateId;
+ mnElementId = nElementId;
+ mnActionStateId = nActionStateId;
+ }
+
+
+
+
+ public int GetStartStateId ()
+ {
+ return mnStartStateId;
+ }
+
+
+
+
+ public int GetEndStateId ()
+ {
+ return mnEndStateId;
+ }
+
+
+
+
+ public int GetElementId ()
+ {
+ return mnElementId;
+ }
+
+
+
+
+ public int GetActionId ()
+ {
+ return mnActionStateId;
+ }
+
+
+
+
+ private final int mnStartStateId;
+ private final int mnEndStateId;
+ private final int mnElementId;
+ private final int mnActionStateId;
+}
diff --git a/ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/TransitionTable.java b/ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/TransitionTable.java
new file mode 100644
index 000000000000..32326daa5a9f
--- /dev/null
+++ b/ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/TransitionTable.java
@@ -0,0 +1,85 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.parser;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Vector;
+
+public class TransitionTable
+{
+ public TransitionTable (final Vector<String[]> aData)
+ {
+ maTransitions = new HashMap<>();
+
+ for (final String[] aLine : aData)
+ {
+ // Create new transition.
+ final int nStartStateId = Integer.parseInt(aLine[1]);
+ final int nEndStateId = Integer.parseInt(aLine[2]);
+ final int nElementPrefixId = Integer.parseInt(aLine[3]);
+ final int nElementLocalId = Integer.parseInt(aLine[4]);
+ final int nElementStateId = Integer.parseInt(aLine[5]);
+ final Transition aTransition = new Transition(
+ nStartStateId,
+ nEndStateId,
+ (nElementPrefixId<<16) | nElementLocalId,
+ nElementStateId);
+
+ Map<Integer,Transition> aPerElementTransitions = maTransitions.get(aTransition.GetStartStateId());
+ if (aPerElementTransitions == null)
+ {
+ aPerElementTransitions = new HashMap<>();
+ maTransitions.put(aTransition.GetStartStateId(), aPerElementTransitions);
+ }
+ aPerElementTransitions.put(aTransition.GetElementId(), aTransition);
+ }
+ }
+
+
+
+
+ public Transition GetTransition (
+ final int nStateId,
+ final int nPrefixId,
+ final int nLocalId)
+ {
+ Map<Integer,Transition> aPerElementTransitions = maTransitions.get(nStateId);
+ if (aPerElementTransitions == null)
+ return null;
+ else
+ return aPerElementTransitions.get((nPrefixId<<16) | nLocalId);
+ }
+
+
+
+
+ public int GetTransitionCount ()
+ {
+ return maTransitions.size();
+ }
+
+
+
+
+ private final Map<Integer,Map<Integer,Transition>> maTransitions;
+}
diff --git a/ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/action/ActionDescriptor.java b/ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/action/ActionDescriptor.java
new file mode 100644
index 000000000000..27ce9d4b8f90
--- /dev/null
+++ b/ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/action/ActionDescriptor.java
@@ -0,0 +1,114 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.parser.action;
+
+import java.util.Vector;
+
+/** Container of all actions that are associated with a single state.
+ */
+public class ActionDescriptor
+{
+ public ActionDescriptor (
+ final int nStateId,
+ final String sName)
+ {
+ msStateName = sName;
+
+ maElementStartActions = null;
+ maElementEndActions = null;
+ maTextActions = null;
+ }
+
+
+
+
+ public void AddAction (
+ final IAction aAction,
+ final ActionTrigger eTrigger)
+ {
+ GetActionsForTrigger(eTrigger, true).add(aAction);
+ }
+
+
+
+
+ public Iterable<IAction> GetActions (
+ final ActionTrigger eTrigger)
+ {
+ return GetActionsForTrigger(eTrigger, false);
+ }
+
+
+
+
+ @Override
+ public String toString ()
+ {
+ return "actions for state "+msStateName;
+ }
+
+
+
+
+ private Vector<IAction> GetActionsForTrigger (
+ final ActionTrigger eTrigger,
+ final boolean bCreateWhenMissing)
+ {
+ Vector<IAction> aActions = null;
+ switch(eTrigger)
+ {
+ case ElementStart:
+ aActions = maElementStartActions;
+ if (bCreateWhenMissing && aActions==null)
+ {
+ aActions = new Vector<>();
+ maElementStartActions = aActions;
+ }
+ break;
+ case ElementEnd:
+ aActions = maElementEndActions;
+ if (bCreateWhenMissing && aActions==null)
+ {
+ aActions = new Vector<>();
+ maElementEndActions = aActions;
+ }
+ break;
+ case Text:
+ aActions = maTextActions;
+ if (bCreateWhenMissing && aActions==null)
+ {
+ aActions = new Vector<>();
+ maTextActions = aActions;
+ }
+ break;
+ }
+ return aActions;
+ }
+
+
+
+
+ private final String msStateName;
+ private Vector<IAction> maElementStartActions;
+ private Vector<IAction> maElementEndActions;
+ private Vector<IAction> maTextActions;
+}
diff --git a/ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/action/ActionIterator.java b/ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/action/ActionIterator.java
new file mode 100644
index 000000000000..0ca176ad51bb
--- /dev/null
+++ b/ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/action/ActionIterator.java
@@ -0,0 +1,118 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.parser.action;
+
+import java.util.Iterator;
+
+/** Iterate over two sources of actions, both given as an Iterable<IAction>
+ * object that can be null.
+*/
+public class ActionIterator implements Iterable<IAction>
+{
+ public ActionIterator (
+ final Iterable<IAction> aOneStateActions,
+ final Iterable<IAction> aAllStateActions)
+ {
+ maOneStateActions = aOneStateActions;
+ maAllStateActions = aAllStateActions;
+ }
+
+
+
+
+ @Override public Iterator<IAction> iterator()
+ {
+ return new Iterator<IAction>()
+ {
+ Iterator<IAction> maIterator = null;
+ int mnPhase = 0;
+
+ @Override
+ public boolean hasNext()
+ {
+ while(true)
+ {
+ if (mnPhase == 2)
+ return false;
+ else if (mnPhase == 0)
+ {
+ if (maIterator == null)
+ if (maOneStateActions == null)
+ {
+ mnPhase = 1;
+ continue;
+ }
+ else
+ maIterator = maOneStateActions.iterator();
+ if (maIterator.hasNext())
+ return true;
+ else
+ {
+ maIterator = null;
+ mnPhase = 1;
+ }
+ }
+ else if (mnPhase == 1)
+ {
+ if (maIterator == null)
+ if (maAllStateActions == null)
+ {
+ mnPhase = 2;
+ return false;
+ }
+ else
+ maIterator = maAllStateActions.iterator();
+ if (maIterator.hasNext())
+ return true;
+ else
+ {
+ mnPhase = 2;
+ }
+ }
+ }
+ }
+
+
+
+
+ @Override
+ public IAction next()
+ {
+ return maIterator.next();
+ }
+
+
+
+
+ @Override
+ public void remove()
+ {
+ }
+ };
+ }
+
+
+
+
+ private final Iterable<IAction> maOneStateActions;
+ private final Iterable<IAction> maAllStateActions;
+}
diff --git a/ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/action/ActionManager.java b/ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/action/ActionManager.java
new file mode 100644
index 000000000000..48d78a03977b
--- /dev/null
+++ b/ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/action/ActionManager.java
@@ -0,0 +1,165 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.parser.action;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.openoffice.ooxml.parser.NameMap;
+
+/** Manage actions that are bound to states and XML events.
+ */
+public class ActionManager
+{
+ public ActionManager (
+ final NameMap aStateNameToIdMap)
+ {
+ maStateNameToIdMap = aStateNameToIdMap;
+ maAllStatesActions = new ActionDescriptor(0,"*");
+ maStateToActionsMap = new HashMap<>();
+ }
+
+
+
+
+ /** Add an action for an element start.
+ * @param sStateSelector
+ * The element is specified via a state name. This allows one element
+ * that leads to different complex types to have different actions,
+ * depending on the complex type.
+ * The selector value can be a full state name (including the namespace
+ * prefix and CT prefix, e.g. w06_CT_Table) or a regular expression
+ * (e.g. .*_CT_Table to match w06_CT_Table and w12_CT_Table).
+ * The action is bound to all matching states.
+ * @param aAction
+ * The action to call on entering any of the states that match the
+ * selector.
+ */
+ public void AddElementStartAction (
+ final String sStateSelector,
+ final IAction aAction)
+ {
+ AddAction(sStateSelector, aAction, ActionTrigger.ElementStart);
+ }
+
+
+
+
+ /** Add an action for an element end.
+ * @see AddElementStartAction.
+ */
+ public void AddElementEndAction (
+ final String sStateSelector,
+ final IAction aAction)
+ {
+ AddAction(sStateSelector, aAction, ActionTrigger.ElementEnd);
+ }
+
+
+
+
+ /** Add an action for XML text events.
+ * @see AddElementStartAction.
+ */
+ public void AddTextAction (
+ final String sStateSelector,
+ final IAction aAction)
+ {
+ AddAction(sStateSelector, aAction, ActionTrigger.Text);
+ }
+
+
+
+
+ /** Return an iterable object that gives access to all actions
+ * bound to the given state and trigger.
+ * Return value can be null when there are no actions bound to the state
+ * and trigger.
+ */
+ public Iterable<IAction> GetActions (
+ final int nStateId,
+ final ActionTrigger eTrigger)
+ {
+ final ActionDescriptor aOneStateActionsDescriptor = maStateToActionsMap.get(nStateId);
+ final Iterable<IAction> aOneStateActions = aOneStateActionsDescriptor!=null
+ ? aOneStateActionsDescriptor.GetActions(eTrigger)
+ : null;
+ final Iterable<IAction> aAllStateActions = maAllStatesActions.GetActions(eTrigger);
+
+ if (aOneStateActions == null)
+ return aAllStateActions;
+ else if (aAllStateActions == null)
+ return aOneStateActions;
+ else
+ return new ActionIterator(aOneStateActions, aAllStateActions);
+ }
+
+
+
+
+ private void AddAction (
+ final String sStateSelector,
+ final IAction aAction,
+ final ActionTrigger eTrigger)
+ {
+ if (sStateSelector.equals("*"))
+ {
+ // Simple optimization when an action is defined for all states.
+ maAllStatesActions.AddAction(aAction, eTrigger);
+ }
+ else if (sStateSelector.contains("*") || sStateSelector.contains("?"))
+ {
+ // The state selector contains wildcards. We have to iterate over
+ // all state names to find the matching ones.
+ for (final int nStateId : maStateNameToIdMap.GetMatchingStateIds(sStateSelector))
+ {
+ GetActionDescriptor(nStateId).AddAction(aAction, eTrigger);
+ }
+ }
+ else
+ {
+ final int nStateId = maStateNameToIdMap.GetIdForName(sStateSelector);
+ GetActionDescriptor(nStateId).AddAction(aAction, eTrigger);
+ }
+ }
+
+
+
+
+ private ActionDescriptor GetActionDescriptor (final int nStateId)
+ {
+ ActionDescriptor aDescriptor = maStateToActionsMap.get(nStateId);
+ if (aDescriptor == null)
+ {
+ aDescriptor = new ActionDescriptor(nStateId, maStateNameToIdMap.GetNameForId(nStateId));
+ maStateToActionsMap.put(nStateId, aDescriptor);
+ }
+ return aDescriptor;
+ }
+
+
+
+
+ private final NameMap maStateNameToIdMap;
+ private final ActionDescriptor maAllStatesActions;
+ private final Map<Integer,ActionDescriptor> maStateToActionsMap;
+}
diff --git a/ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/action/ActionTrigger.java b/ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/action/ActionTrigger.java
new file mode 100644
index 000000000000..33b781a0b1a6
--- /dev/null
+++ b/ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/action/ActionTrigger.java
@@ -0,0 +1,31 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.parser.action;
+
+/** An enumeration of all supported action triggers.
+ */
+public enum ActionTrigger
+{
+ ElementStart,
+ ElementEnd,
+ Text
+} \ No newline at end of file
diff --git a/ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/action/IAction.java b/ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/action/IAction.java
new file mode 100644
index 000000000000..e784ed7c5537
--- /dev/null
+++ b/ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/action/IAction.java
@@ -0,0 +1,53 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.parser.action;
+
+import javax.xml.stream.Location;
+
+import org.apache.openoffice.ooxml.parser.ElementContext;
+
+/** Interface for actions that are bound to states and triggered by XML events.
+ */
+public interface IAction
+{
+ /** Callback for a single XML event.
+ * @param eTrigger
+ * Equivalent to the XML event type.
+ * @param aContext
+ * The context of the element that was just entered (element start),
+ * is about to be left (element end) or is currently active (all other
+ * events).
+ * @param sText
+ * Contains text for ActionTrigger.Text. Is null for all other
+ * triggers.
+ * @param aStartLocation
+ * The location in the source file where the triggering element starts.
+ * @param aEndLocation
+ * The location in the source file where the triggering element ends.
+ */
+ void Run (
+ final ActionTrigger eTrigger,
+ final ElementContext aContext,
+ final String sText,
+ final Location aStartLocation,
+ final Location aEndLocation);
+}
diff --git a/ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/attribute/AttributeDescriptor.java b/ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/attribute/AttributeDescriptor.java
new file mode 100644
index 000000000000..a51aa54f184f
--- /dev/null
+++ b/ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/attribute/AttributeDescriptor.java
@@ -0,0 +1,130 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.parser.attribute;
+
+/** Store information about a single attribute (per state) that was read
+ * from the parse table.
+ *
+ * Note that an attribute that is defined for more than one state has one
+ * AttributeDescriptor object per state.
+ *
+ */
+public class AttributeDescriptor
+{
+ public AttributeDescriptor (
+ final int nPrefixId,
+ final int nAttributeId,
+ final boolean bCanBeUnqualified,
+ final boolean bIsOptional,
+ final String sDefaultValue,
+ final String sAttributeName,
+ final int nAttributeTypeId)
+ {
+ mnNamespaceId = nPrefixId;
+ mnAttributeId = nAttributeId;
+ mbCanBeUnqualified = bCanBeUnqualified;
+ mbIsOptional = bIsOptional;
+ msDefaultValue = sDefaultValue;
+ msAttributeName = sAttributeName;
+ mnAttributeTypeId = nAttributeTypeId;
+ }
+
+
+
+
+ public int GetTypeId()
+ {
+ return mnAttributeTypeId;
+ }
+
+
+
+
+ public int GetNamespaceId ()
+ {
+ return mnNamespaceId;
+ }
+
+
+
+
+ public int GetNameId ()
+ {
+ return mnAttributeId;
+ }
+
+
+
+
+ public boolean CanBeUnqualified ()
+ {
+ return mbCanBeUnqualified;
+ }
+
+
+
+
+ public boolean IsOptional ()
+ {
+ return mbIsOptional;
+ }
+
+
+
+
+ public String GetDefaultValue ()
+ {
+ return msDefaultValue;
+ }
+
+
+
+
+ public String GetName ()
+ {
+ return msAttributeName;
+ }
+
+
+
+
+ @Override
+ public String toString ()
+ {
+ return String.format(
+ "attribute %s(%d) of type %d",
+ msAttributeName,
+ mnAttributeId,
+ mnAttributeTypeId);
+ }
+
+
+
+
+ private final int mnNamespaceId;
+ private final int mnAttributeId;
+ private final boolean mbCanBeUnqualified;
+ private final boolean mbIsOptional;
+ private final String msDefaultValue;
+ private final String msAttributeName;
+ private final int mnAttributeTypeId;
+}
diff --git a/ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/attribute/AttributeManager.java b/ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/attribute/AttributeManager.java
new file mode 100644
index 000000000000..55b1df9f1f5e
--- /dev/null
+++ b/ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/attribute/AttributeManager.java
@@ -0,0 +1,273 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.parser.attribute;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.Vector;
+
+import org.apache.openoffice.ooxml.parser.Log;
+import org.apache.openoffice.ooxml.parser.NameMap;
+import org.apache.openoffice.ooxml.parser.NamespaceMap;
+import org.apache.openoffice.ooxml.parser.type.SimpleTypeManager;
+
+
+/** Match a set of attributes from the document with the attribute
+ * specifications of a state.
+ *
+ */
+public class AttributeManager
+{
+ /** Create a new AttributeManager for the attribute specifications that
+ * are given in the parse table.
+ */
+ public AttributeManager (
+ final Vector<String[]> aData,
+ final NamespaceMap aNamespaceMap,
+ final NameMap aNameMap,
+ final NameMap aStateNameMap,
+ final SimpleTypeManager aSimpleTypeManager,
+ final Vector<String> aErrorsAndWarnings)
+ {
+ maStateIdToAttributesMap = new HashMap<>();
+ maNamespaceMap = aNamespaceMap;
+ maNameMap = aNameMap;
+ maStateNameMap = aStateNameMap;
+ maSimpleTypeManager = aSimpleTypeManager;
+ maErrorsAndWarnings = aErrorsAndWarnings;
+ ParseData(aData);
+ }
+
+
+
+
+ private void ParseData (final Vector<String[]> aData)
+ {
+ for (final String[] aLine : aData)
+ {
+ final int nStateId = Integer.parseInt(aLine[1]);
+ final int nPrefixId = Integer.parseInt(aLine[2]);
+ final boolean bCanBeUnqualified = aLine[3].startsWith("u");
+ final int nAttributeId = Integer.parseInt(aLine[4]);
+ final int nAttributeTypeId = aLine[5].equals("null") ? -1 : Integer.parseInt(aLine[5]);
+ final boolean bIsOptional = aLine[6].startsWith("o");
+ final String sDefault = aLine[7];
+ // State name.
+ final String sAttributeName = aLine[9];
+ // Attribute type name.
+
+ Map<Integer,AttributeDescriptor> aAttributesPerState = maStateIdToAttributesMap.get(nStateId);
+ if (aAttributesPerState == null)
+ {
+ aAttributesPerState = new HashMap<>();
+ maStateIdToAttributesMap.put(nStateId, aAttributesPerState);
+ }
+
+ final AttributeDescriptor aAttributeDescriptor = new AttributeDescriptor(
+ nPrefixId,
+ nAttributeId,
+ bCanBeUnqualified,
+ bIsOptional,
+ sDefault,
+ sAttributeName,
+ nAttributeTypeId);
+
+ aAttributesPerState.put(
+ (nPrefixId<<16)|nAttributeId,
+ aAttributeDescriptor);
+ if (bCanBeUnqualified)
+ aAttributesPerState.put(
+ nAttributeId,
+ aAttributeDescriptor);
+ }
+ }
+
+
+
+
+ /** For the state with id nStateId, match the attributes from the document
+ * with the attribute specifications of that state.
+ */
+ public AttributeValues ParseAttributes (
+ final int nStateId,
+ final AttributeProvider aDocumentAttributes)
+ {
+ final AttributeValues aValues = new AttributeValues();
+
+ final Map<Integer,AttributeDescriptor> aAttributesPerState = maStateIdToAttributesMap.get(nStateId);
+ if (aAttributesPerState == null)
+ {
+ if (aDocumentAttributes.HasAttributes())
+ {
+ Log.Std.printf("state has not attributes defined but document provides %d attributes\n",
+ aDocumentAttributes.GetAttributeCount());
+ for (final String[] aEntry : aDocumentAttributes)
+ {
+ Log.Dbg.printf(" %s -> %s\n", aEntry[0], aEntry[1]);
+ }
+ throw new RuntimeException();
+ }
+ }
+ else
+ {
+ final Set<AttributeDescriptor> aUsedAttributes = new HashSet<>();
+
+ // Process all attributes from the document.
+ for (final String[] aEntry : aDocumentAttributes)
+ {
+ final String sRawValue = aEntry[2];
+ final AttributeDescriptor aAttributeDescriptor = ProcessAttribute(
+ aEntry[0],
+ aEntry[1],
+ sRawValue,
+ aAttributesPerState);
+ aUsedAttributes.add(aAttributeDescriptor);
+ final Object aProcessedValue = maSimpleTypeManager.PreprocessValue(
+ sRawValue,
+ aAttributeDescriptor);
+ if (aProcessedValue == null)
+ {
+ maSimpleTypeManager.PreprocessValue(
+ sRawValue,
+ aAttributeDescriptor);
+ throw new RuntimeException(
+ String.format("value '%s' of attribute '%s' is not recognized",
+ sRawValue,
+ aAttributeDescriptor.GetName()));
+ }
+ aValues.AddAttribute(
+ aAttributeDescriptor,
+ sRawValue,
+ aProcessedValue);
+
+ if (Log.Dbg != null)
+ {
+ if (aAttributeDescriptor == null)
+ Log.Dbg.printf("attribute %s%s is not known\n",
+ aEntry[0]==null ? "" : ":"+aEntry[0],
+ aEntry[1]);
+ else
+ Log.Dbg.printf("attribute %s:%s(%d:%d) has type %s(%d) and value %s('%s')\n",
+ maNamespaceMap.GetDescriptorForId(aAttributeDescriptor.GetNamespaceId()).Prefix,
+ maNameMap.GetNameForId(aAttributeDescriptor.GetNameId()),
+ aAttributeDescriptor.GetNamespaceId(),
+ aAttributeDescriptor.GetNameId(),
+ maStateNameMap.GetNameForId(aAttributeDescriptor.GetTypeId()),
+ aAttributeDescriptor.GetTypeId(),
+ aProcessedValue,
+ sRawValue);
+ }
+ }
+
+ // Check if all required attributes where given.
+ for (final AttributeDescriptor aAttribute : aAttributesPerState.values())
+ {
+ if ( ! aUsedAttributes.contains(aAttribute))
+ {
+ if ( ! aAttribute.IsOptional())
+ {
+ final String sMessage = String.format("attribute '"+aAttribute.GetName()+"' is not present but also not optional");
+ if (maErrorsAndWarnings != null)
+ maErrorsAndWarnings.add(sMessage);
+ else
+ throw new RuntimeException(sMessage);
+ }
+ else
+ {
+ // Add an entry that gives access to the default value.
+ aValues.AddAttribute(aAttribute, null, null);
+ }
+ }
+ }
+ }
+
+ return aValues;
+ }
+
+
+
+
+ private AttributeDescriptor ProcessAttribute (
+ final String sNamespace,
+ final String sAttributeName,
+ final String sAttributeValue,
+ final Map<Integer,AttributeDescriptor> aAttributesPerState)
+ {
+ final AttributeDescriptor aAttributeDescriptor;
+ if (sNamespace == null)
+ {
+ // Attribute name has no namespace.
+ final int nAttributeNameId = maNameMap.GetIdForName(sAttributeName);
+ aAttributeDescriptor = aAttributesPerState.get(nAttributeNameId);
+ }
+ else
+ {
+ // Attribute name has explicit namespace.
+ final NamespaceMap.NamespaceDescriptor aDescriptor = maNamespaceMap.GetDescriptorForURI(sNamespace);
+ final int nAttributeNameId = maNameMap.GetIdForName(sAttributeName);
+ aAttributeDescriptor = aAttributesPerState.get((aDescriptor.Id<<16) | nAttributeNameId);
+ }
+ return aAttributeDescriptor;
+ }
+
+
+
+
+ /** Remove the quotes around the given string.
+ * If it has the special value null (without quotes) then the null reference
+ * is returned.
+ */
+ private String UnquoteString (final String sValue)
+ {
+ if (sValue.equals("null"))
+ return null;
+ else
+ {
+ assert(sValue.startsWith("\""));
+ assert(sValue.endsWith("\""));
+ return sValue.substring(1, sValue.length()-1);
+ }
+ }
+
+
+
+
+ public int GetAttributeCount ()
+ {
+ int nCount = 0;
+ for (final Map<Integer,AttributeDescriptor> aMap : maStateIdToAttributesMap.values())
+ nCount += aMap.size();
+ return nCount;
+ }
+
+
+
+
+ private final Map<Integer,Map<Integer,AttributeDescriptor>> maStateIdToAttributesMap;
+ private final NamespaceMap maNamespaceMap;
+ private final NameMap maNameMap;
+ private final NameMap maStateNameMap;
+ private final SimpleTypeManager maSimpleTypeManager;
+ private final Vector<String> maErrorsAndWarnings;
+}
diff --git a/ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/attribute/AttributeProvider.java b/ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/attribute/AttributeProvider.java
new file mode 100644
index 000000000000..ab9e28550bc2
--- /dev/null
+++ b/ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/attribute/AttributeProvider.java
@@ -0,0 +1,99 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.parser.attribute;
+
+import java.util.Iterator;
+
+import javax.xml.stream.XMLStreamReader;
+
+/** Give access to the attributes that are read from an OOXML stream.
+ */
+public class AttributeProvider
+ implements Iterable<String[]>
+{
+ public AttributeProvider (final XMLStreamReader aReader)
+ {
+ maReader = aReader;
+ }
+
+
+
+ public boolean HasAttributes ()
+ {
+ return maReader.getAttributeCount() > 0;
+ }
+
+
+
+
+ public String GetValue (final String sKey)
+ {
+ return maReader.getAttributeValue(null, sKey);
+ }
+
+
+
+ @Override
+ public Iterator<String[]> iterator ()
+ {
+ return new Iterator<String[]> ()
+ {
+ int nIndex = 0;
+ final int nCount = maReader.getAttributeCount();
+
+ @Override public boolean hasNext()
+ {
+ return nIndex < nCount;
+ }
+
+ @Override public String[] next()
+ {
+ final String[] aResult = new String[]
+ {
+ maReader.getAttributeNamespace(nIndex),
+ maReader.getAttributeLocalName(nIndex),
+ maReader.getAttributeValue(nIndex)
+ };
+ ++nIndex;
+ return aResult;
+ }
+
+ @Override public void remove()
+ {
+ }
+
+ };
+ }
+
+
+
+
+ public Integer GetAttributeCount ()
+ {
+ return maReader.getAttributeCount();
+ }
+
+
+
+
+ private final XMLStreamReader maReader;
+}
diff --git a/ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/attribute/AttributeValues.java b/ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/attribute/AttributeValues.java
new file mode 100644
index 000000000000..a419abbec0ec
--- /dev/null
+++ b/ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/attribute/AttributeValues.java
@@ -0,0 +1,91 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.parser.attribute;
+
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.TreeMap;
+
+/** Container of attribute values of an opening tag.
+ */
+public class AttributeValues
+{
+ AttributeValues ()
+ {
+ maRawAttributeValues = new TreeMap<>();
+ maProcessedAttributeValues = new TreeMap<>();
+ }
+
+
+
+
+ public void AddAttribute (
+ final AttributeDescriptor aAttributeDescriptor,
+ final String sRawValue,
+ final Object aProcessedValue)
+ {
+ maRawAttributeValues.put(
+ aAttributeDescriptor.GetName(),
+ sRawValue);
+ maProcessedAttributeValues.put(
+ aAttributeDescriptor.GetName(),
+ aProcessedValue);
+ }
+
+
+
+
+ public Iterable<Entry<String,String>> GetAttributes ()
+ {
+ return maRawAttributeValues.entrySet();
+ }
+
+
+
+
+ public String GetRawAttributeValue (final String sName)
+ {
+ return maRawAttributeValues.get(sName);
+ }
+
+
+
+
+ public Object GetProcessedAttributeValue (final String sName)
+ {
+ return maProcessedAttributeValues.get(sName);
+ }
+
+
+
+
+ public int GetAttributeCount ()
+ {
+ return maRawAttributeValues.size();
+ }
+
+
+
+
+ private Map<String,String> maRawAttributeValues;
+ private Map<String,Object> maProcessedAttributeValues;
+}
diff --git a/ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/type/BlobParser.java b/ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/type/BlobParser.java
new file mode 100644
index 000000000000..7edafaeb0b24
--- /dev/null
+++ b/ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/type/BlobParser.java
@@ -0,0 +1,102 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.parser.type;
+
+import org.apache.openoffice.ooxml.parser.NameMap;
+
+public class BlobParser implements ISimpleTypeParser
+{
+ public BlobParser(final String[] aLine)
+ {
+ switch(aLine[5])
+ {
+ case "B":
+ meType = Type.Base64Binary;
+ break;
+ case "H":
+ meType = Type.HexBinary;
+ break;
+ default:
+ throw new RuntimeException();
+ }
+ switch(aLine[6])
+ {
+ case "L":
+ mnLengthRestriction = Integer.parseInt(aLine[7]);
+ break;
+ case "N":
+ mnLengthRestriction = null;
+ break;
+ default:
+ throw new RuntimeException();
+ }
+ }
+
+
+
+
+ @Override
+ public Object Parse (
+ final String sRawValue,
+ final NameMap aAttributeValueMap)
+ {
+ if (mnLengthRestriction != null)
+ if (sRawValue.length()/2 != mnLengthRestriction)
+ return null;
+ /*
+ throw new RuntimeException(
+ String.format(
+ "length restriction (=%d) is violated, actual length is %d",
+ mnLengthRestriction,
+ sRawValue.length()));
+ */
+ switch(meType)
+ {
+ case Base64Binary:
+ throw new RuntimeException("not yet implemented");
+
+ case HexBinary:
+ try
+ {
+ return Integer.parseInt(sRawValue, 16);
+ }
+ catch (NumberFormatException aException)
+ {
+ return null;
+ }
+
+ default:
+ throw new RuntimeException();
+ }
+ }
+
+
+
+
+ enum Type
+ {
+ Base64Binary,
+ HexBinary
+ };
+ private final Type meType;
+ private final Integer mnLengthRestriction;
+}
diff --git a/ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/type/DateTimeParser.java b/ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/type/DateTimeParser.java
new file mode 100644
index 000000000000..979d4051b6e5
--- /dev/null
+++ b/ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/type/DateTimeParser.java
@@ -0,0 +1,42 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.parser.type;
+
+import org.apache.openoffice.ooxml.parser.NameMap;
+
+public class DateTimeParser implements ISimpleTypeParser
+{
+
+ public DateTimeParser(String[] aLine)
+ {
+ // TODO Auto-generated constructor stub
+ }
+
+ @Override
+ public Object Parse(
+ final String sRawValue,
+ final NameMap aAttributeValueMap)
+ {
+ throw new RuntimeException();
+ }
+
+}
diff --git a/ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/type/ISimpleTypeParser.java b/ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/type/ISimpleTypeParser.java
new file mode 100644
index 000000000000..aaa234009767
--- /dev/null
+++ b/ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/type/ISimpleTypeParser.java
@@ -0,0 +1,31 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.parser.type;
+
+import org.apache.openoffice.ooxml.parser.NameMap;
+
+public interface ISimpleTypeParser
+{
+ Object Parse (
+ final String sRawValue,
+ final NameMap aAttributeValueMap);
+}
diff --git a/ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/type/ListParser.java b/ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/type/ListParser.java
new file mode 100644
index 000000000000..94feeb04e3b2
--- /dev/null
+++ b/ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/type/ListParser.java
@@ -0,0 +1,53 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.parser.type;
+
+import org.apache.openoffice.ooxml.parser.NameMap;
+
+public class ListParser implements ISimpleTypeParser
+{
+
+ public ListParser (final ISimpleTypeParser aItemParser)
+ {
+ maItemParser = aItemParser;
+ }
+
+
+
+
+ @Override
+ public Object Parse(
+ final String sRawValue,
+ final NameMap aAttributeValueMap)
+ {
+ final String[] aParts = sRawValue.split("\\s+");
+ final Object[] aValues = new Object[aParts.length];
+ for (int nIndex=0; nIndex<aParts.length; ++nIndex)
+ aValues[nIndex] = maItemParser.Parse(aParts[nIndex], aAttributeValueMap);
+ return aValues;
+ }
+
+
+
+
+ private final ISimpleTypeParser maItemParser;
+}
diff --git a/ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/type/NumberParser.java b/ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/type/NumberParser.java
new file mode 100644
index 000000000000..19fc833867cf
--- /dev/null
+++ b/ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/type/NumberParser.java
@@ -0,0 +1,270 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.parser.type;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.openoffice.ooxml.parser.NameMap;
+
+public class NumberParser implements ISimpleTypeParser
+{
+ public NumberParser (final String[] aLine)
+ {
+ switch(aLine[5])
+ {
+ case "u1":
+ meNumberType = NumberType.Boolean;
+ meJavaNumberType = JavaNumberType.Boolean;
+ break;
+ case "s8":
+ meNumberType = NumberType.Byte;
+ meJavaNumberType = JavaNumberType.Byte;
+ break;
+ case "u8":
+ meNumberType = NumberType.UnsignedByte;
+ meJavaNumberType = JavaNumberType.Short;
+ break;
+ case "s16":
+ meNumberType = NumberType.Short;
+ meJavaNumberType = JavaNumberType.Short;
+ break;
+ case "u16":
+ meNumberType = NumberType.UnsignedShort;
+ meJavaNumberType = JavaNumberType.Integer;
+ break;
+ case "s32":
+ meNumberType = NumberType.Int;
+ meJavaNumberType = JavaNumberType.Integer;
+ break;
+ case "u32":
+ meNumberType = NumberType.UnsignedInt;
+ meJavaNumberType = JavaNumberType.Long;
+ break;
+ case "s64":
+ meNumberType = NumberType.Long;
+ meJavaNumberType = JavaNumberType.Long;
+ break;
+ case "u64":
+ meNumberType = NumberType.UnsignedLong;
+ meJavaNumberType = JavaNumberType.Long;
+ break;
+ case "s*":
+ meNumberType = NumberType.Integer;
+ meJavaNumberType = JavaNumberType.Long;
+ break;
+ case "f":
+ meNumberType = NumberType.Float;
+ meJavaNumberType = JavaNumberType.Float;
+ break;
+ case "d":
+ meNumberType = NumberType.Double;
+ meJavaNumberType = JavaNumberType.Double;
+ break;
+ default:
+ throw new RuntimeException("unsupported numerical type "+aLine[5]);
+ }
+
+ switch(aLine[6])
+ {
+ case "E":
+ meRestrictionType = RestrictionType.Enumeration;
+ maEnumeration = new HashSet<>();
+ for (int nIndex=7; nIndex<aLine.length; ++nIndex)
+ maEnumeration.add(ParseNumber(aLine[nIndex]));
+ break;
+
+ case "S":
+ meRestrictionType = RestrictionType.Size;
+ for (int nIndex=7; nIndex<=9; nIndex+=2)
+ if (nIndex<aLine.length)
+ switch (aLine[nIndex])
+ {
+ case "<=":
+ maMaximumValue = ParseNumber(aLine[nIndex+1]);
+ mbIsMaximumInclusive = true;
+ break;
+ case "<":
+ maMaximumValue = ParseNumber(aLine[nIndex+1]);
+ mbIsMaximumInclusive = false;
+ break;
+ case ">=":
+ maMinimumValue = ParseNumber(aLine[nIndex+1]);
+ mbIsMinimumInclusive = true;
+ break;
+ case ">":
+ maMinimumValue = ParseNumber(aLine[nIndex+1]);
+ mbIsMinimumInclusive = false;
+ break;
+ }
+ break;
+
+ case "N":
+ meRestrictionType = RestrictionType.None;
+ break;
+
+ default:
+ throw new RuntimeException("unsupported numerical restriction "+aLine[6]);
+ }
+ }
+
+
+
+
+ @Override
+ public Object Parse(
+ final String sRawValue,
+ final NameMap aAttributeValueMap)
+ {
+ final Object aNumber = ParseNumber(sRawValue);
+ switch(meRestrictionType)
+ {
+ case Enumeration:
+ if (maEnumeration.contains(aNumber))
+ return aNumber;
+ else
+ return null;
+
+ case Size:
+ if (maMinimumValue != null)
+ if (mbIsMinimumInclusive)
+ {
+ if (CompareTo(aNumber, maMinimumValue, meJavaNumberType) < 0)
+ return null;
+ }
+ else
+ {
+ if (CompareTo(aNumber, maMinimumValue, meJavaNumberType) <= 0)
+ return null;
+ }
+ if (maMaximumValue != null)
+ if (mbIsMaximumInclusive)
+ {
+ if (CompareTo(aNumber, maMaximumValue, meJavaNumberType) > 0)
+ return null;
+ }
+ else
+ {
+ if (CompareTo(aNumber, maMaximumValue, meJavaNumberType) >= 0)
+ return null;
+ }
+ return aNumber;
+
+ case None:
+ return aNumber;
+
+ default:
+ throw new RuntimeException();
+ }
+ }
+
+
+
+
+ Object ParseNumber (final String sNumber)
+ {
+ switch(meJavaNumberType)
+ {
+ case Boolean: return Boolean.parseBoolean(sNumber);
+ case Byte: return Byte.parseByte(sNumber);
+ case Short: return Short.parseShort(sNumber);
+ case Integer: return Integer.parseInt(sNumber);
+ case Long: return Long.parseLong(sNumber);
+ case Float: return Float.parseFloat(sNumber);
+ case Double: return Double.parseDouble(sNumber);
+ default:
+ throw new RuntimeException();
+ }
+ }
+
+
+
+
+ private static int CompareTo (
+ final Object aLeft,
+ final Object aRight,
+ final JavaNumberType eType)
+ {
+ switch(eType)
+ {
+ case Boolean:
+ return ((Boolean)aLeft).compareTo((Boolean)aRight);
+ case Byte:
+ return ((Byte)aLeft).compareTo((Byte)aRight);
+ case Short:
+ return ((Short)aLeft).compareTo((Short)aRight);
+ case Integer:
+ return ((Integer)aLeft).compareTo((Integer)aRight);
+ case Long:
+ return ((Long)aLeft).compareTo((Long)aRight);
+ case Float:
+ return ((Float)aLeft).compareTo((Float)aRight);
+ case Double:
+ return ((Double)aLeft).compareTo((Double)aRight);
+ default:
+ throw new RuntimeException();
+ }
+ }
+
+
+
+
+ enum NumberType
+ {
+ Boolean,
+ Byte,
+ UnsignedByte,
+ Short,
+ UnsignedShort,
+ Int,
+ UnsignedInt,
+ Long,
+ UnsignedLong,
+ Integer,
+ Float,
+ Double
+ }
+ enum JavaNumberType
+ {
+ Boolean,
+ Byte,
+ Short,
+ Integer,
+ Long,
+ Float,
+ Double
+ }
+ enum RestrictionType
+ {
+ Enumeration,
+ Size,
+ None
+ }
+ private final NumberType meNumberType;
+ private final JavaNumberType meJavaNumberType;
+ private final RestrictionType meRestrictionType;
+ private Set<Object> maEnumeration;
+ private Object maMinimumValue;
+ private boolean mbIsMinimumInclusive;
+ private Object maMaximumValue;
+ private boolean mbIsMaximumInclusive;
+}
diff --git a/ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/type/SimpleTypeManager.java b/ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/type/SimpleTypeManager.java
new file mode 100644
index 000000000000..abeb529ddc52
--- /dev/null
+++ b/ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/type/SimpleTypeManager.java
@@ -0,0 +1,118 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.parser.type;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Vector;
+
+import org.apache.openoffice.ooxml.parser.NameMap;
+import org.apache.openoffice.ooxml.parser.attribute.AttributeDescriptor;
+
+public class SimpleTypeManager
+{
+ public SimpleTypeManager(
+ final Vector<String[]> aData,
+ final NameMap aAttributeValueMap)
+ {
+ maAttributeValueMap = aAttributeValueMap;
+ maSimpleTypeToParsersMap = new HashMap<>();
+ ParseData(aData);
+ }
+
+
+
+
+ private void ParseData (final Vector<String[]> aData)
+ {
+ for (final String[] aLine : aData)
+ {
+ final int nSimpleTypeId = Integer.parseInt(aLine[1]);
+// final int nVariant = Integer.parseInt(aLine[2]);
+ final boolean bIsList = aLine[3].equals("L");
+ final ISimpleTypeParser aVariantParser;
+ switch (aLine[4])
+ {
+ case "S":
+ aVariantParser = new StringParser(aLine);
+ break;
+ case "N":
+ aVariantParser = new NumberParser(aLine);
+ break;
+ case "D":
+ aVariantParser = new DateTimeParser(aLine);
+ break;
+ case "B":
+ aVariantParser = new BlobParser(aLine);
+ break;
+ default:
+ throw new RuntimeException("unexpected parser type: "+aLine[4]);
+ }
+
+ Vector<ISimpleTypeParser> aVariants = maSimpleTypeToParsersMap.get(nSimpleTypeId);
+ if (aVariants == null)
+ {
+ aVariants = new Vector<>();
+ maSimpleTypeToParsersMap.put(nSimpleTypeId, aVariants);
+ }
+ if (bIsList)
+ aVariants.add(new ListParser(aVariantParser));
+ else
+ aVariants.add(aVariantParser);
+ }
+ }
+
+
+
+
+ public Object PreprocessValue (
+ final String sRawValue,
+ final AttributeDescriptor aAttributeDescriptor)
+ {
+ final Vector<ISimpleTypeParser> aTypeParsers = maSimpleTypeToParsersMap.get(aAttributeDescriptor.GetTypeId());
+ if (aTypeParsers == null)
+ throw new RuntimeException("type "+aAttributeDescriptor.GetTypeId()+" is not supported");
+
+ for (final ISimpleTypeParser aParser : aTypeParsers)
+ {
+ try
+ {
+ final Object aProcessedValue = aParser.Parse(
+ sRawValue,
+ maAttributeValueMap);
+ if (aProcessedValue != null)
+ return aProcessedValue;
+ }
+ catch(final Exception aException)
+ {
+ return "error";
+ }
+ }
+ return null;
+ }
+
+
+
+
+ private final NameMap maAttributeValueMap;
+ private Map<Integer,Vector<ISimpleTypeParser>> maSimpleTypeToParsersMap;
+}
diff --git a/ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/type/StringParser.java b/ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/type/StringParser.java
new file mode 100644
index 000000000000..c3b22bf5fba0
--- /dev/null
+++ b/ooxml/source/framework/JavaOOXMLParser/src/org/apache/openoffice/ooxml/parser/type/StringParser.java
@@ -0,0 +1,122 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.parser.type;
+
+import java.util.HashSet;
+import java.util.Set;
+import java.util.regex.Pattern;
+
+import org.apache.openoffice.ooxml.parser.NameMap;
+
+public class StringParser
+ implements ISimpleTypeParser
+{
+
+ public StringParser (final String[] aLine)
+ {
+ switch(aLine[5])
+ {
+ case "E":
+ meRestrictionType = RestrictionType.Enumeration;
+ maEnumeration = new HashSet<>();
+ for (int nIndex=6; nIndex<aLine.length; ++nIndex)
+ maEnumeration.add(Integer.parseInt(aLine[nIndex]));
+ break;
+
+ case "P":
+ meRestrictionType = RestrictionType.Pattern;
+ maPattern = Pattern.compile(aLine[6].replace("\\p{Is", "\\p{In"));
+ break;
+
+ case "L":
+ meRestrictionType = RestrictionType.Length;
+ mnMinimumLength = Integer.parseInt(aLine[6]);
+ mnMaximumLength = Integer.parseInt(aLine[7]);
+ break;
+
+ case "N":
+ meRestrictionType = RestrictionType.None;
+ break;
+
+ default:
+ throw new RuntimeException();
+ }
+ }
+
+
+
+
+ @Override
+ public Object Parse (
+ final String sRawValue,
+ final NameMap aAttributeValueMap)
+ {
+ switch(meRestrictionType)
+ {
+ case Enumeration:
+ final int nId = aAttributeValueMap.GetIdForOptionalName(sRawValue);
+ if ( ! maEnumeration.contains(nId))
+ return null;//throw new RuntimeException("value is not part of enumeration");
+ else
+ return nId;
+
+ case Pattern:
+ if ( ! maPattern.matcher(sRawValue).matches())
+ return null;//throw new RuntimeException("value does not match pattern");
+ else
+ return sRawValue;
+
+ case Length:
+ if (sRawValue.length()<mnMinimumLength || sRawValue.length()>mnMaximumLength)
+ return null;/*throw new RuntimeException(
+ String.format("value violates string length restriction: %s is not inside [%d,%d]",
+ sRawValue.length(),
+ mnMinimumLength,
+ mnMaximumLength));
+ */
+ else
+ return sRawValue;
+
+ case None:
+ return sRawValue;
+
+ default:
+ throw new RuntimeException();
+ }
+ }
+
+
+
+
+ enum RestrictionType
+ {
+ Enumeration,
+ Pattern,
+ Length,
+ None
+ }
+ private final RestrictionType meRestrictionType;
+ private Set<Integer> maEnumeration;
+ private Pattern maPattern;
+ private int mnMinimumLength;
+ private int mnMaximumLength;
+}
diff --git a/ooxml/source/framework/JavaPartManager/.classpath b/ooxml/source/framework/JavaPartManager/.classpath
new file mode 100644
index 000000000000..5ec76483b264
--- /dev/null
+++ b/ooxml/source/framework/JavaPartManager/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7"/>
+ <classpathentry combineaccessrules="false" kind="src" path="/JavaOOXMLParser"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/ooxml/source/framework/JavaPartManager/.project b/ooxml/source/framework/JavaPartManager/.project
new file mode 100644
index 000000000000..08a7d0d1b383
--- /dev/null
+++ b/ooxml/source/framework/JavaPartManager/.project
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>JavaPartManager</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
diff --git a/ooxml/source/framework/JavaPartManager/.settings/org.eclipse.jdt.core.prefs b/ooxml/source/framework/JavaPartManager/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 000000000000..7341ab1683c4
--- /dev/null
+++ b/ooxml/source/framework/JavaPartManager/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,11 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.7
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.7
diff --git a/ooxml/source/framework/JavaPartManager/src/org/apache/openoffice/ooxml/framework/part/ContentType.java b/ooxml/source/framework/JavaPartManager/src/org/apache/openoffice/ooxml/framework/part/ContentType.java
new file mode 100644
index 000000000000..fc147cbd5cd4
--- /dev/null
+++ b/ooxml/source/framework/JavaPartManager/src/org/apache/openoffice/ooxml/framework/part/ContentType.java
@@ -0,0 +1,77 @@
+package org.apache.openoffice.ooxml.framework.part;
+
+public enum ContentType
+{
+ ApplicationDrawing ("application/vnd.openxmlformats-officedocument.vmlDrawing"),
+ ApplicationExcel ("application/vnd.ms-excel"),
+ ApplicationXML ("application/xml"),
+ Chart ("application/vnd.openxmlformats-officedocument.drawingml.chart+xml"),
+ ContentTypes (""),
+ CoreProperties ("application/vnd.openxmlformats-package.core-properties+xml"),
+ CustomXMLProperties ("application/vnd.openxmlformats-officedocument.customXmlProperties+xml"),
+ ExtendedProperties ("application/vnd.openxmlformats-officedocument.extended-properties+xml"),
+ ImageGIF ("image/gif"),
+ ImageJPG ("image/png"),
+ ImagePNG ("image/jpeg"),
+ OleObject ("application/vnd.openxmlformats-officedocument.oleObject"),
+ PmlDocument ("application/vnd.openxmlformats-officedocument.presentationml.presentation.main+xml"),
+ PmlHandoutMaster ("application/vnd.openxmlformats-officedocument.presentationml.handoutMaster+xml"),
+ PmlNotesMaster ("application/vnd.openxmlformats-officedocument.presentationml.notesMaster+xml"),
+ PmlNotesSlide ("application/vnd.openxmlformats-officedocument.presentationml.notesSlide+xml"),
+ PmlProperties ("application/vnd.openxmlformats-officedocument.presentationml.presProps+xml"),
+ PmlSlide ("application/vnd.openxmlformats-officedocument.presentationml.slide+xml"),
+ PmlSlideLayout ("application/vnd.openxmlformats-officedocument.presentationml.slideLayout+xml"),
+ PmlSlideMaster ("application/vnd.openxmlformats-officedocument.presentationml.slideMaster+xml"),
+ PmlTableStyles ("application/vnd.openxmlformats-officedocument.presentationml.tableStyles+xml"),
+ PmlViewProperties ("application/vnd.openxmlformats-officedocument.presentationml.viewProps+xml"),
+ Relationships ("application/vnd.openxmlformats-package.relationships+xml"),
+ SmlSheet ("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"),
+ Theme ("application/vnd.openxmlformats-officedocument.theme+xml"),
+ ThemeOverride ("application/vnd.openxmlformats-officedocument.themeOverride+xml"),
+ Thumbnail ("http://schemas.openxmlformats.org/package/2006/relationships/metadata/thumbnail"),
+ WmlDocument ("application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml"),
+ WmlEndNotes ("application/vnd.openxmlformats-officedocument.wordprocessingml.endnotes+xml"),
+ WmlFontTable ("application/vnd.openxmlformats-officedocument.wordprocessingml.fontTable+xml"),
+ WmlFootNotes ("application/vnd.openxmlformats-officedocument.wordprocessingml.footnotes+xml"),
+ WmlFooter ("application/vnd.openxmlformats-officedocument.wordprocessingml.footer+xml"),
+ WmlHeader ("application/vnd.openxmlformats-officedocument.wordprocessingml.header+xml"),
+ WmlNumbering ("application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml"),
+ WmlSettings ("application/vnd.openxmlformats-officedocument.wordprocessingml.settings+xml"),
+ WmlStyles ("application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml"),
+ WmlWebSettings ("application/vnd.openxmlformats-officedocument.wordprocessingml.webSettings+xml"),
+
+ Unknown("");
+
+
+
+
+ ContentType (final String sMimeType)
+ {
+ msMimeType = sMimeType;
+ }
+
+
+
+
+ public static ContentType CreateForString (final String sContentType)
+ {
+ for (final ContentType eType : values())
+ if (eType.msMimeType.equals(sContentType))
+ return eType;
+ System.err.printf("content type '%s' is not known\n", sContentType);
+ return Unknown;
+ }
+
+
+
+
+ public String GetLongName ()
+ {
+ return msMimeType;
+ }
+
+
+
+
+ private final String msMimeType;
+}
diff --git a/ooxml/source/framework/JavaPartManager/src/org/apache/openoffice/ooxml/framework/part/ContentTypes.java b/ooxml/source/framework/JavaPartManager/src/org/apache/openoffice/ooxml/framework/part/ContentTypes.java
new file mode 100644
index 000000000000..d17a082106a8
--- /dev/null
+++ b/ooxml/source/framework/JavaPartManager/src/org/apache/openoffice/ooxml/framework/part/ContentTypes.java
@@ -0,0 +1,150 @@
+package org.apache.openoffice.ooxml.framework.part;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.xml.stream.Location;
+
+import org.apache.openoffice.ooxml.framework.part.parser.ParserFactory;
+import org.apache.openoffice.ooxml.parser.ElementContext;
+import org.apache.openoffice.ooxml.parser.Parser;
+import org.apache.openoffice.ooxml.parser.action.ActionTrigger;
+import org.apache.openoffice.ooxml.parser.action.IAction;
+
+public class ContentTypes
+{
+ ContentTypes (final PartManager aPartManager)
+ {
+ maExtensionToContentTypeMap = new HashMap<>();
+ maPartNameToContentTypeMap = new HashMap<>();
+
+ // Technically the [Content_Types].xml stream is not a part and
+ // "[Content_Types].xml" is not a part name. But handling it like one
+ // makes the implementation a little bit easier and more readable.
+ final Part aContentTypesPart = new Part(
+ ContentType.ContentTypes,
+ aPartManager,
+ new PartName("/[Content_Types].xml"));
+
+ final Parser aParser = ParserFactory.getParser(
+ aContentTypesPart.getContentType(),
+ aContentTypesPart.getStream(),
+ null);
+ /*
+ DefineContext(
+ CT_Something,
+ int nValue,
+ CallbackObject aObject);
+
+ class CT_Something_Context : public Context
+ {
+ Context parent
+
+ attribute 1
+ ...
+ attribute n
+ int nValue;
+ CallbackObject aObject;
+ }
+
+ DefineElementStartAction(
+ CT_Something_Context,
+ aObject,
+ DoSomething);
+
+
+ case ElementStart of CT_Something:
+ maCurrentContext.aObject.DoSomething(maCurrentContext); // CT_Something_Context
+
+ //
+ CallbackObject.cxx
+
+ class CallbackObject
+ {
+ public: DoSomething(CT_Something_Context aContext)
+ {
+ aContext.attribute1
+ }
+ }
+
+ */
+ aParser.GetActionManager().AddElementStartAction(
+ ".*_CT_Default",
+ new IAction(){
+
+ @Override
+ public void Run(
+ final ActionTrigger eTrigger,
+ final ElementContext aContext,
+ final String sText,
+ final Location aStartLocation,
+ final Location aEndLocation)
+ {
+ ProcessDefault(
+ aContext.GetAttributes().GetRawAttributeValue("A_Extension"),
+ aContext.GetAttributes().GetRawAttributeValue("A_ContentType"));
+
+ }});
+ aParser.GetActionManager().AddElementStartAction(
+ ".*_CT_Override",
+ new IAction(){
+
+ @Override
+ public void Run(
+ final ActionTrigger eTrigger,
+ final ElementContext aContext,
+ final String sText,
+ final Location aStartLocation,
+ final Location aEndLocation)
+ {
+ ProcessOverride(
+ aContext.GetAttributes().GetRawAttributeValue("A_PartName"),
+ aContext.GetAttributes().GetRawAttributeValue("A_ContentType"));
+
+ }});
+
+
+ aParser.Parse();
+ }
+
+
+
+
+ public ContentType getTypeForPartName (final PartName aName)
+ {
+ ContentType eType = maPartNameToContentTypeMap.get(aName.GetFullname());
+ if (eType == null)
+ eType = maExtensionToContentTypeMap.get(aName.GetExtension());
+ if (eType == null)
+ eType = ContentType.Unknown;
+ return eType;
+ }
+
+
+
+
+ private void ProcessDefault (
+ final String sExtension,
+ final String sContentTypeName)
+ {
+ final ContentType eType = ContentType.CreateForString(sContentTypeName);
+ maExtensionToContentTypeMap.put(sExtension, eType);
+ }
+
+
+
+
+ private void ProcessOverride (
+ final String sPartName,
+ final String sContentTypeName)
+ {
+ final ContentType eType = ContentType.CreateForString(sContentTypeName);
+ maPartNameToContentTypeMap.put(sPartName, eType);
+ }
+
+
+
+
+ private final Map<String,ContentType> maExtensionToContentTypeMap;
+ private final Map<String,ContentType> maPartNameToContentTypeMap;
+}
diff --git a/ooxml/source/framework/JavaPartManager/src/org/apache/openoffice/ooxml/framework/part/IReferenceProvider.java b/ooxml/source/framework/JavaPartManager/src/org/apache/openoffice/ooxml/framework/part/IReferenceProvider.java
new file mode 100644
index 000000000000..9d47eb6f54fe
--- /dev/null
+++ b/ooxml/source/framework/JavaPartManager/src/org/apache/openoffice/ooxml/framework/part/IReferenceProvider.java
@@ -0,0 +1,6 @@
+package org.apache.openoffice.ooxml.framework.part;
+
+public interface IReferenceProvider
+{
+ RelatedParts getRelatedParts ();
+}
diff --git a/ooxml/source/framework/JavaPartManager/src/org/apache/openoffice/ooxml/framework/part/OOXMLPackage.java b/ooxml/source/framework/JavaPartManager/src/org/apache/openoffice/ooxml/framework/part/OOXMLPackage.java
new file mode 100644
index 000000000000..3e5310ada923
--- /dev/null
+++ b/ooxml/source/framework/JavaPartManager/src/org/apache/openoffice/ooxml/framework/part/OOXMLPackage.java
@@ -0,0 +1,56 @@
+package org.apache.openoffice.ooxml.framework.part;
+
+import java.io.File;
+import java.io.InputStream;
+
+public class OOXMLPackage
+ extends Package
+{
+ public static OOXMLPackage Create (final File aOOXMLFile)
+ {
+ return new OOXMLPackage(
+ aOOXMLFile.getAbsolutePath(),
+ new PartManager(aOOXMLFile));
+ }
+
+
+
+
+ private OOXMLPackage (final String sPath, final PartManager aPartManager)
+ {
+ super(sPath, aPartManager);
+ }
+
+
+
+
+ /** Return a list of stream names.
+ * Note that that list is not necessarily identical to the list of part
+ * names. It can contain entries that are not parts.
+ */
+ public String[] listStreamNames ()
+ {
+ return maPartManager.listStreamNames();
+ }
+
+
+
+
+ /** Return an InputStream object for the specified stream.
+ */
+ public InputStream getStream (final String sStreamName)
+ {
+ return maPartManager.getStreamForStreamName(sStreamName);
+ }
+
+
+
+
+ public Part getPart (final PartName aPartName)
+ {
+ return new Part (
+ maPartManager.getContentTypes().getTypeForPartName(aPartName),
+ maPartManager,
+ aPartName);
+ }
+} \ No newline at end of file
diff --git a/ooxml/source/framework/JavaPartManager/src/org/apache/openoffice/ooxml/framework/part/Package.java b/ooxml/source/framework/JavaPartManager/src/org/apache/openoffice/ooxml/framework/part/Package.java
new file mode 100644
index 000000000000..dd31292cf135
--- /dev/null
+++ b/ooxml/source/framework/JavaPartManager/src/org/apache/openoffice/ooxml/framework/part/Package.java
@@ -0,0 +1,158 @@
+package org.apache.openoffice.ooxml.framework.part;
+
+import java.io.File;
+import java.io.InputStream;
+import java.lang.ref.SoftReference;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.Vector;
+
+public class Package
+ implements IReferenceProvider
+{
+ public static Package Create (final File aOOXMLFile)
+ {
+ return new Package(
+ aOOXMLFile.getAbsolutePath(),
+ new PartManager(aOOXMLFile));
+ }
+
+
+
+
+ protected Package (
+ final String sFullFilename,
+ final PartManager aPartManager)
+ {
+ msFullFilename = sFullFilename;
+ maPartManager = aPartManager;
+ maRelatedParts = new RelatedParts(
+ new PartName(""),
+ aPartManager);
+
+ final PartName aDocumentPartName = maRelatedParts.GetSingleTargetForType(RelationshipType.OfficeDocument);
+ maOfficeDocumentPart = new Part(
+ maPartManager.getContentTypes().getTypeForPartName(aDocumentPartName),
+ maPartManager,
+ aDocumentPartName);
+ }
+
+
+
+
+ public Part getOfficeDocumentPart ()
+ {
+ return maOfficeDocumentPart;
+ }
+
+
+
+
+ public Iterable<Part> getDigitalSignaturesParts ()
+ {
+ // TODO
+ return new Vector<>();
+ }
+
+
+
+
+ public RelatedParts getRelatedParts ()
+ {
+ return maRelatedParts;
+ }
+
+
+
+
+ public boolean hasAppDefFilePropertiesPart ()
+ {
+ // TODO
+ return false;
+ }
+
+
+
+
+ public Part getAppDefFilePropertiesPart ()
+ {
+ // TODO
+ return null;
+ }
+
+
+
+
+ public boolean hasCoreFilePropertiesPart ()
+ {
+ // TODO
+ return false;
+ }
+
+
+
+
+ public Part getCoreFilePropertiesPart ()
+ {
+ // TODO
+ return null;
+ }
+
+
+
+
+ public boolean hasCustomFilePropertiesPart ()
+ {
+ // TODO
+ return false;
+ }
+
+
+
+
+ public Part getCustomFilePropertiesPart ()
+ {
+ // TODO
+ return null;
+ }
+
+
+
+
+ public String getFileName()
+ {
+ return msFullFilename;
+ }
+
+
+
+
+ /** Return a list of stream names.
+ * Note that that list is not necessarily identical to the list of part
+ * names. It can contain entries that are not parts.
+ */
+ public String[] listStreamNames ()
+ {
+ return maPartManager.listStreamNames();
+ }
+
+
+
+
+ /** Return an InputStream object for the specified stream.
+ */
+ public InputStream getStream (final String sStreamName)
+ {
+ return maPartManager.getStreamForStreamName(sStreamName);
+ }
+
+
+
+
+ private final String msFullFilename;
+ protected final PartManager maPartManager;
+ private final RelatedParts maRelatedParts;
+ private final Part maOfficeDocumentPart;
+} \ No newline at end of file
diff --git a/ooxml/source/framework/JavaPartManager/src/org/apache/openoffice/ooxml/framework/part/Part.java b/ooxml/source/framework/JavaPartManager/src/org/apache/openoffice/ooxml/framework/part/Part.java
new file mode 100644
index 000000000000..28b2617a1494
--- /dev/null
+++ b/ooxml/source/framework/JavaPartManager/src/org/apache/openoffice/ooxml/framework/part/Part.java
@@ -0,0 +1,89 @@
+package org.apache.openoffice.ooxml.framework.part;
+
+import java.io.InputStream;
+
+public class Part
+ implements IReferenceProvider
+{
+ public Part (
+ final ContentType eType,
+ final PartManager aPartManager,
+ final PartName aPartName)
+ {
+ meContentType = eType;
+ maPartManager = aPartManager;
+ maPartName = aPartName;
+ maRelatedParts = null;
+ }
+
+
+
+
+ public Part getPartById (final String sId)
+ {
+ final PartName aName = getRelatedParts().GetTargetForId(sId);
+ return new Part(
+ maPartManager.getContentTypes().getTypeForPartName(aName),
+ maPartManager,
+ aName);
+ }
+
+
+
+
+ public Part getPartByRelationshipType (final RelationshipType eType)
+ {
+ final PartName aName = getRelatedParts().GetSingleTargetForType(eType);
+ return new Part(
+ maPartManager.getContentTypes().getTypeForPartName(aName),
+ maPartManager,
+ aName);
+ }
+
+
+
+
+ public PartName getPartName ()
+ {
+ return maPartName;
+ }
+
+
+
+
+ public ContentType getContentType ()
+ {
+ return meContentType;
+ }
+
+
+
+
+ public InputStream getStream()
+ {
+ return maPartManager.getStreamForPartName(maPartName);
+ }
+
+
+
+
+ @Override
+ public RelatedParts getRelatedParts ()
+ {
+ if (maRelatedParts == null)
+ {
+ maRelatedParts = new RelatedParts(
+ maPartName,
+ maPartManager);
+ }
+ return maRelatedParts;
+ }
+
+
+
+
+ private final ContentType meContentType;
+ private final PartManager maPartManager;
+ private final PartName maPartName;
+ private RelatedParts maRelatedParts;
+}
diff --git a/ooxml/source/framework/JavaPartManager/src/org/apache/openoffice/ooxml/framework/part/PartManager.java b/ooxml/source/framework/JavaPartManager/src/org/apache/openoffice/ooxml/framework/part/PartManager.java
new file mode 100644
index 000000000000..c61f16572487
--- /dev/null
+++ b/ooxml/source/framework/JavaPartManager/src/org/apache/openoffice/ooxml/framework/part/PartManager.java
@@ -0,0 +1,145 @@
+package org.apache.openoffice.ooxml.framework.part;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.ref.SoftReference;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Vector;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+
+public class PartManager
+{
+ public PartManager (final File aFile)
+ {
+ ZipFile aZipFile = null;
+ try
+ {
+ aZipFile = new ZipFile(aFile);
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ maZipFile = aZipFile;
+ maPartNameToPartMap = new HashMap<>();
+ }
+
+
+
+
+ public InputStream getStreamForPartName (final PartName aPartName)
+ {
+ final ZipEntry aEntry = maZipFile.getEntry(
+ ToZipEntryName(aPartName.GetFullname()));
+ if (aEntry == null)
+ return null;
+
+ try
+ {
+ return maZipFile.getInputStream(aEntry);
+ }
+ catch (IOException e)
+ {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+
+
+
+ /** This is the low-level variant of getStreamForPartName().
+ * It can return streams for entries in the OOXML zip package
+ * that are not, technically, parts.
+ * @return
+ * Returns null when the named stream does not exist or can not be
+ * opened.
+ */
+ public InputStream getStreamForStreamName (final String sStreamName)
+ {
+ final ZipEntry aEntry = maZipFile.getEntry(
+ ToZipEntryName(sStreamName));
+ try
+ {
+ return maZipFile.getInputStream(aEntry);
+ }
+ catch (IOException e)
+ {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+
+
+
+ public ContentTypes getContentTypes ()
+ {
+ if (maContentTypes == null)
+ {
+ maContentTypes = new ContentTypes(this);
+ }
+ return maContentTypes;
+ }
+
+
+
+
+ private final String ToZipEntryName (final String sPath)
+ {
+ return sPath.substring(1);
+ }
+
+
+
+
+ /** Return a list of the names of all streams.
+ * Note that that list is not necessarily identical to the list of part
+ * names. It can contain entries that are not parts.
+ */
+ public final String[] listStreamNames ()
+ {
+ final Vector<String> aStreamNames = new Vector<>();
+
+ final Enumeration<? extends ZipEntry> aEntries = maZipFile.entries();
+ while (aEntries.hasMoreElements())
+ {
+ final ZipEntry aEntry = aEntries.nextElement();
+ aStreamNames.add(aEntry.getName());
+ }
+
+ return aStreamNames.toArray(new String[0]);
+ }
+
+
+
+
+ public Part getPart (final PartName aName)
+ {
+ SoftReference<Part> aSoftPart = maPartNameToPartMap.get(aName);
+ Part aPart = null;
+ if (aSoftPart != null)
+ aPart = aSoftPart.get();
+ if (aPart == null)
+ {
+ aPart = new Part(
+ getContentTypes().getTypeForPartName(aName),
+ this,
+ aName);
+ maPartNameToPartMap.put(aName, new SoftReference<Part>(aPart));
+ }
+
+ return aPart;
+ }
+
+
+
+
+ private ZipFile maZipFile;
+ private ContentTypes maContentTypes;
+ private final Map<PartName, SoftReference<Part>> maPartNameToPartMap;
+}
diff --git a/ooxml/source/framework/JavaPartManager/src/org/apache/openoffice/ooxml/framework/part/PartManagerPrototype.java b/ooxml/source/framework/JavaPartManager/src/org/apache/openoffice/ooxml/framework/part/PartManagerPrototype.java
new file mode 100644
index 000000000000..8aa820714d67
--- /dev/null
+++ b/ooxml/source/framework/JavaPartManager/src/org/apache/openoffice/ooxml/framework/part/PartManagerPrototype.java
@@ -0,0 +1,33 @@
+package org.apache.openoffice.ooxml.framework.part;
+
+import java.io.File;
+
+import org.apache.openoffice.ooxml.framework.part.parser.ParserFactory;
+import org.apache.openoffice.ooxml.parser.Log;
+
+public class PartManagerPrototype
+{
+ public static void main (final String ... aArgumentList)
+ {
+ if (aArgumentList.length != 3)
+ {
+ System.err.printf("usage: PartManagerPrototype <ooxml-file-name> <parser-table-filename> <log-filename>");
+ System.exit(1);
+ }
+
+ final long nStartTime = System.currentTimeMillis();
+
+ Log.Dbg = new Log(aArgumentList[2]);
+ ParserFactory.SetParserTableFilename(aArgumentList[1]);
+
+ final File aOOXMLFile = new File(aArgumentList[0]);
+ final Part aPart = OOXMLPackage.Create(aOOXMLFile).getOfficeDocumentPart().getPartById("rId1");
+
+ final long nEndTime = System.currentTimeMillis();
+
+ System.out.printf("got content type %s for %s in %fs\n",
+ aPart.getContentType(),
+ aPart.getPartName(),
+ (nEndTime-nStartTime)/1000.0);
+ }
+}
diff --git a/ooxml/source/framework/JavaPartManager/src/org/apache/openoffice/ooxml/framework/part/PartName.java b/ooxml/source/framework/JavaPartManager/src/org/apache/openoffice/ooxml/framework/part/PartName.java
new file mode 100644
index 000000000000..e91aa37eac49
--- /dev/null
+++ b/ooxml/source/framework/JavaPartManager/src/org/apache/openoffice/ooxml/framework/part/PartName.java
@@ -0,0 +1,130 @@
+package org.apache.openoffice.ooxml.framework.part;
+
+/** Operations around part names.
+ */
+public class PartName
+ implements Comparable<PartName>
+{
+ public PartName (final String sPath)
+ {
+ if ( ! (sPath.isEmpty() || sPath.startsWith("/")))
+ {
+ assert(sPath.isEmpty() || sPath.startsWith("/"));
+ }
+ assert(sPath.indexOf('\\') == -1);
+
+ msPath = sPath;
+ }
+
+
+
+
+ public PartName (
+ final String sPath,
+ final PartName aParentName,
+ final String sMode)
+ {
+ switch(sMode)
+ {
+ case "External":
+ msPath = sPath;
+ break;
+
+ case "Internal":
+ msPath = Cleanup(aParentName.GetPathname() + "/" + sPath);
+ break;
+
+ default:
+ throw new RuntimeException();
+ }
+ }
+
+
+
+
+ public PartName getRelationshipsPartName ()
+ {
+ return new PartName(GetPathname() + "/_rels/" + GetBasename() + ".rels");
+ }
+
+
+
+
+ private String GetPathname ()
+ {
+ if (msPath.isEmpty())
+ return "";
+ else
+ {
+ final int nPathnameEnd = msPath.lastIndexOf('/');
+ assert(nPathnameEnd>=0);
+ return msPath.substring(0, nPathnameEnd);
+ }
+ }
+
+
+
+
+ public String GetBasename ()
+ {
+ if (msPath.isEmpty())
+ return "";
+ else
+ {
+ final int nBasenameStart = msPath.lastIndexOf('/');
+ assert(nBasenameStart>=0);
+ return msPath.substring(nBasenameStart+1);
+ }
+ }
+
+
+
+
+ public String GetExtension ()
+ {
+ final int nExtensionStart = msPath.lastIndexOf('.');
+ if (nExtensionStart < 0)
+ return null;
+ else
+ return msPath.substring(nExtensionStart+1);
+ }
+
+
+
+
+ public String GetFullname()
+ {
+ return msPath;
+ }
+
+
+
+
+ @Override
+ public int compareTo (final PartName aOther)
+ {
+ return msPath.compareTo(aOther.msPath);
+ }
+
+
+
+
+ private String Cleanup (final String sName)
+ {
+ return sName.replaceAll("/[^/]+/\\.\\./", "/");
+ }
+
+
+
+
+ @Override
+ public String toString ()
+ {
+ return msPath;
+ }
+
+
+
+
+ private final String msPath;
+}
diff --git a/ooxml/source/framework/JavaPartManager/src/org/apache/openoffice/ooxml/framework/part/RelatedParts.java b/ooxml/source/framework/JavaPartManager/src/org/apache/openoffice/ooxml/framework/part/RelatedParts.java
new file mode 100644
index 000000000000..22cd218c9ab8
--- /dev/null
+++ b/ooxml/source/framework/JavaPartManager/src/org/apache/openoffice/ooxml/framework/part/RelatedParts.java
@@ -0,0 +1,131 @@
+package org.apache.openoffice.ooxml.framework.part;
+
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.Vector;
+
+import javax.xml.stream.Location;
+
+import org.apache.openoffice.ooxml.framework.part.parser.ParserFactory;
+import org.apache.openoffice.ooxml.parser.ElementContext;
+import org.apache.openoffice.ooxml.parser.Parser;
+import org.apache.openoffice.ooxml.parser.action.ActionTrigger;
+import org.apache.openoffice.ooxml.parser.action.IAction;
+
+public class RelatedParts
+{
+ RelatedParts (
+ final PartName aPartName,
+ final PartManager aPartManager)
+ {
+ maIdToTargetMap = new HashMap<>();
+ maTypeToTargetsMap = new HashMap<>();
+
+ final InputStream aStream = aPartManager.getStreamForPartName(aPartName.getRelationshipsPartName());
+ if (aStream != null)
+ {
+ final Parser aParser = ParserFactory.getParser(
+ ContentType.Relationships,
+ aStream,
+ null);
+ aParser.GetActionManager().AddElementStartAction(
+ "A_CT_Relationship",
+ new IAction()
+ {
+ @Override public void Run (
+ final ActionTrigger eTrigger,
+ final ElementContext aContext,
+ final String sText,
+ final Location aStartLocation,
+ final Location aEndLocation)
+ {
+ final String sId = aContext.GetAttributes().GetRawAttributeValue("A_Id");
+ final String sType = aContext.GetAttributes().GetRawAttributeValue("A_Type");
+ final String sTarget = aContext.GetAttributes().GetRawAttributeValue("A_Target");
+ String sTargetMode = aContext.GetAttributes().GetRawAttributeValue("A_TargetMode");
+ if (sTargetMode == null)
+ sTargetMode = "Internal";
+
+ AddRelationship(
+ sId,
+ RelationshipType.CreateFromString(sType),
+ new PartName(sTarget, aPartName, sTargetMode));
+ }
+ }
+ );
+ aParser.Parse();
+ }
+ }
+
+
+
+
+ private void AddRelationship (
+ final String sId,
+ final RelationshipType eType,
+ final PartName aTarget)
+ {
+ maIdToTargetMap.put(sId, aTarget);
+
+ Vector<PartName> aTargets = maTypeToTargetsMap.get(eType);
+ if (aTargets == null)
+ {
+ aTargets = new Vector<>();
+ maTypeToTargetsMap.put(eType, aTargets);
+ }
+ aTargets.add(aTarget);
+ }
+
+
+
+
+ public PartName GetTargetForId (final String sId)
+ {
+ return maIdToTargetMap.get(sId);
+ }
+
+
+
+
+ public Iterable<PartName> GetTargetsForType (final RelationshipType eType)
+ {
+ return maTypeToTargetsMap.get(eType);
+ }
+
+
+
+ public Iterable<PartName> getAllTargets ()
+ {
+ final Set<PartName> aAllNames = new TreeSet<>();
+ aAllNames.addAll(maIdToTargetMap.values());
+ return aAllNames;
+ }
+
+
+
+
+ public PartName GetSingleTargetForType (final RelationshipType eType)
+ {
+ if (maTypeToTargetsMap.get(eType).size() != 1)
+ {
+ System.out.printf("there are %d targets for relationship type %s\n",
+ maTypeToTargetsMap.get(eType).size(),
+ eType.toString());
+ for (final PartName aName : maTypeToTargetsMap.get(eType))
+ {
+ System.out.printf("%s\n", aName);
+ }
+ assert(false);
+ }
+ return maTypeToTargetsMap.get(eType).firstElement();
+ }
+
+
+
+
+ private final Map<String,PartName> maIdToTargetMap;
+ private final Map<RelationshipType, Vector<PartName>> maTypeToTargetsMap;
+}
diff --git a/ooxml/source/framework/JavaPartManager/src/org/apache/openoffice/ooxml/framework/part/RelationshipType.java b/ooxml/source/framework/JavaPartManager/src/org/apache/openoffice/ooxml/framework/part/RelationshipType.java
new file mode 100644
index 000000000000..3074d1b9b52a
--- /dev/null
+++ b/ooxml/source/framework/JavaPartManager/src/org/apache/openoffice/ooxml/framework/part/RelationshipType.java
@@ -0,0 +1,112 @@
+package org.apache.openoffice.ooxml.framework.part;
+
+public enum RelationshipType
+{
+ ExtendedProperties,
+ CoreProperties,
+ OfficeDocument,
+ Image,
+ Header,
+ Hyperlink,
+ Styles,
+ EndNotes,
+ Footer,
+ Numbering,
+ CustomXML,
+ FootNotes,
+ WebSettings,
+ Theme,
+ Settings,
+ FontTable,
+ Thumbnail,
+ Slide,
+ ViewProperties,
+ PresentationProperties,
+ HandoutMaster,
+ TableStyles,
+ SlideMaster,
+ NotesMaster,
+ SlideLayout,
+ NotesSlide,
+ VMLDrawing,
+ OLE,
+ Chart,
+ Package,
+ ThemeOverride,
+
+ Unknown
+ ;
+
+ public static RelationshipType CreateFromString (final String sType)
+ {
+ switch(sType)
+ {
+ case "http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties":
+ return ExtendedProperties;
+ case "http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties":
+ return CoreProperties;
+ case "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument":
+ return OfficeDocument;
+ case "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image":
+ return Image;
+ case "http://schemas.openxmlformats.org/officeDocument/2006/relationships/header":
+ return Header;
+ case "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink":
+ return Hyperlink;
+ case "http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles":
+ return Styles;
+ case "http://schemas.openxmlformats.org/officeDocument/2006/relationships/endnotes":
+ return EndNotes;
+ case "http://schemas.openxmlformats.org/officeDocument/2006/relationships/footer":
+ return Footer;
+ case "http://schemas.openxmlformats.org/officeDocument/2006/relationships/numbering":
+ return Numbering;
+ case "http://schemas.openxmlformats.org/officeDocument/2006/relationships/customXml":
+ return CustomXML;
+ case "http://schemas.openxmlformats.org/officeDocument/2006/relationships/footnotes":
+ return FootNotes;
+ case "http://schemas.openxmlformats.org/officeDocument/2006/relationships/webSettings":
+ return WebSettings;
+ case "http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme":
+ return Theme;
+ case "http://schemas.openxmlformats.org/officeDocument/2006/relationships/settings":
+ return Settings;
+ case "http://schemas.openxmlformats.org/officeDocument/2006/relationships/fontTable":
+ return FontTable;
+ case "http://schemas.openxmlformats.org/package/2006/relationships/metadata/thumbnail":
+ return Thumbnail;
+ case "http://schemas.openxmlformats.org/officeDocument/2006/relationships/slide":
+ return Slide;
+ case "http://schemas.openxmlformats.org/officeDocument/2006/relationships/viewProps":
+ return ViewProperties;
+ case "http://schemas.openxmlformats.org/officeDocument/2006/relationships/presProps":
+ return PresentationProperties;
+ case "http://schemas.openxmlformats.org/officeDocument/2006/relationships/handoutMaster":
+ return HandoutMaster;
+ case "http://schemas.openxmlformats.org/officeDocument/2006/relationships/tableStyles":
+ return TableStyles;
+ case "http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideMaster":
+ return SlideMaster;
+ case "http://schemas.openxmlformats.org/officeDocument/2006/relationships/notesMaster":
+ return NotesMaster;
+ case "http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideLayout":
+ return SlideLayout;
+ case "http://schemas.openxmlformats.org/officeDocument/2006/relationships/notesSlide":
+ return NotesSlide;
+ case "http://schemas.openxmlformats.org/officeDocument/2006/relationships/vmlDrawing":
+ return VMLDrawing;
+ case "http://schemas.openxmlformats.org/officeDocument/2006/relationships/oleObject":
+ return OLE;
+ case "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart":
+ return Chart;
+ case "http://schemas.openxmlformats.org/officeDocument/2006/relationships/package":
+ return Package;
+ case "http://schemas.openxmlformats.org/officeDocument/2006/relationships/themeOverride":
+ return ThemeOverride;
+
+ default:
+ System.err.printf(sType +" is not yet supported\n");
+ return Unknown;
+ }
+ }
+}
diff --git a/ooxml/source/framework/JavaPartManager/src/org/apache/openoffice/ooxml/framework/part/parser/ContentTypesParser.java b/ooxml/source/framework/JavaPartManager/src/org/apache/openoffice/ooxml/framework/part/parser/ContentTypesParser.java
new file mode 100644
index 000000000000..0d64f10cb1c3
--- /dev/null
+++ b/ooxml/source/framework/JavaPartManager/src/org/apache/openoffice/ooxml/framework/part/parser/ContentTypesParser.java
@@ -0,0 +1,30 @@
+package org.apache.openoffice.ooxml.framework.part.parser;
+
+import java.io.File;
+import java.io.InputStream;
+import java.util.Vector;
+
+import org.apache.openoffice.ooxml.parser.Parser;
+import org.apache.openoffice.ooxml.parser.StateMachine;
+
+public class ContentTypesParser
+ extends Parser
+{
+ public ContentTypesParser (
+ final InputStream aIn,
+ final String sParserTableFilename,
+ final Vector<String> aErrorsAndWarnings)
+ {
+ super(CreateStateMachine(sParserTableFilename, aErrorsAndWarnings), aIn);
+ }
+
+
+
+
+ private static StateMachine CreateStateMachine (
+ final String sParserTableFilename,
+ final Vector<String> aErrorsAndWarnings)
+ {
+ return new StateMachine(new File(sParserTableFilename), aErrorsAndWarnings);
+ }
+}
diff --git a/ooxml/source/framework/JavaPartManager/src/org/apache/openoffice/ooxml/framework/part/parser/ParserFactory.java b/ooxml/source/framework/JavaPartManager/src/org/apache/openoffice/ooxml/framework/part/parser/ParserFactory.java
new file mode 100644
index 000000000000..83a635ca4077
--- /dev/null
+++ b/ooxml/source/framework/JavaPartManager/src/org/apache/openoffice/ooxml/framework/part/parser/ParserFactory.java
@@ -0,0 +1,46 @@
+package org.apache.openoffice.ooxml.framework.part.parser;
+
+import java.io.File;
+import java.io.InputStream;
+import java.util.Vector;
+
+import org.apache.openoffice.ooxml.framework.part.ContentType;
+import org.apache.openoffice.ooxml.parser.Parser;
+import org.apache.openoffice.ooxml.parser.StateMachine;
+
+public class ParserFactory
+{
+ public static Parser getParser (
+ final ContentType eType,
+ final InputStream aStream,
+ final Vector<String> aErrorsAndWarnings)
+ {
+ switch(eType)
+ {
+ case Relationships:
+ return new RelationshipParser(aStream, msParserTableFilename, aErrorsAndWarnings);
+
+ case ContentTypes:
+ return new ContentTypesParser(aStream, msParserTableFilename, aErrorsAndWarnings);
+
+ default:
+ return new Parser(
+ new StateMachine(new File(msParserTableFilename), aErrorsAndWarnings),
+ aStream);
+ }
+ }
+
+
+
+
+ public static void SetParserTableFilename (final String sFilename)
+ {
+ assert(new File(sFilename).exists());
+ msParserTableFilename = sFilename;
+ }
+
+
+
+
+ private static String msParserTableFilename = null;
+}
diff --git a/ooxml/source/framework/JavaPartManager/src/org/apache/openoffice/ooxml/framework/part/parser/RelationshipParser.java b/ooxml/source/framework/JavaPartManager/src/org/apache/openoffice/ooxml/framework/part/parser/RelationshipParser.java
new file mode 100644
index 000000000000..bcbfd3344908
--- /dev/null
+++ b/ooxml/source/framework/JavaPartManager/src/org/apache/openoffice/ooxml/framework/part/parser/RelationshipParser.java
@@ -0,0 +1,30 @@
+package org.apache.openoffice.ooxml.framework.part.parser;
+
+import java.io.File;
+import java.io.InputStream;
+import java.util.Vector;
+
+import org.apache.openoffice.ooxml.parser.Parser;
+import org.apache.openoffice.ooxml.parser.StateMachine;
+
+public class RelationshipParser
+ extends Parser
+{
+ public RelationshipParser (
+ final InputStream aIn,
+ final String sParserTableFilename,
+ final Vector<String> aErrorsAndWarnings)
+ {
+ super(CreateStateMachine(sParserTableFilename, aErrorsAndWarnings), aIn);
+ }
+
+
+
+
+ private static StateMachine CreateStateMachine (
+ final String sParserTableFilename,
+ final Vector<String> aErrorsAndWarnings)
+ {
+ return new StateMachine(new File(sParserTableFilename), aErrorsAndWarnings);
+ }
+}
diff --git a/ooxml/source/framework/OOXMLViewer/.classpath b/ooxml/source/framework/OOXMLViewer/.classpath
new file mode 100755
index 000000000000..ecd0bc81845d
--- /dev/null
+++ b/ooxml/source/framework/OOXMLViewer/.classpath
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7"/>
+ <classpathentry combineaccessrules="false" kind="src" path="/JavaPartManager"/>
+ <classpathentry combineaccessrules="false" kind="src" path="/JavaOOXMLParser"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/ooxml/source/framework/OOXMLViewer/.project b/ooxml/source/framework/OOXMLViewer/.project
new file mode 100755
index 000000000000..51a963140df1
--- /dev/null
+++ b/ooxml/source/framework/OOXMLViewer/.project
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>OOXMLViewer</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
diff --git a/ooxml/source/framework/OOXMLViewer/.settings/org.eclipse.jdt.core.prefs b/ooxml/source/framework/OOXMLViewer/.settings/org.eclipse.jdt.core.prefs
new file mode 100755
index 000000000000..838bd9d69424
--- /dev/null
+++ b/ooxml/source/framework/OOXMLViewer/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,11 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.7
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.7
diff --git a/ooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/DetailViewManager.java b/ooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/DetailViewManager.java
new file mode 100755
index 000000000000..5bf1e194cfbd
--- /dev/null
+++ b/ooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/DetailViewManager.java
@@ -0,0 +1,131 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.viewer;
+
+import java.util.Vector;
+
+import javax.swing.JScrollPane;
+
+import org.apache.openoffice.ooxml.framework.part.ContentType;
+import org.apache.openoffice.ooxml.framework.part.OOXMLPackage;
+import org.apache.openoffice.ooxml.framework.part.Part;
+import org.apache.openoffice.ooxml.framework.part.PartName;
+import org.apache.openoffice.ooxml.framework.part.parser.ParserFactory;
+import org.apache.openoffice.ooxml.viewer.tokenview.TokenView;
+import org.apache.openoffice.ooxml.viewer.xml.TokenType;
+import org.apache.openoffice.ooxml.viewer.xml.XMLTokenViewFactory;
+import org.apache.openoffice.ooxml.viewer.xmltokenview.XMLViewFactory;
+
+public class DetailViewManager
+{
+ public DetailViewManager (
+ final JScrollPane aDetailViewContainer,
+ final OOXMLPackage aPackage)
+ {
+ maDetailViewContainer = aDetailViewContainer;
+ maPackage = aPackage;
+ maViewFactory = new XMLTokenViewFactory();
+ }
+
+
+
+
+ public void ShowPart (
+ final PartName aName,
+ final ContentType eType)
+ {
+ ShowPart(maPackage.getPart(aName));
+ }
+
+
+
+
+ public void ShowPart (final Part aPart)
+ {
+ switch(aPart.getContentType())
+ {
+ case ImageGIF:
+ case ImageJPG:
+ case ImagePNG:
+ maDetailViewContainer.setViewportView(
+ new ImageView(aPart.getStream()).GetComponent());
+ break;
+
+ case ApplicationDrawing:
+ case ApplicationExcel:
+ case ApplicationXML:
+ case Chart:
+ case ContentTypes:
+ case CoreProperties:
+ case CustomXMLProperties:
+ case ExtendedProperties:
+ case PmlDocument:
+ case PmlHandoutMaster:
+ case PmlNotesMaster:
+ case PmlNotesSlide:
+ case PmlProperties:
+ case PmlSlide:
+ case PmlSlideLayout:
+ case PmlSlideMaster:
+ case PmlTableStyles:
+ case PmlViewProperties:
+ case Relationships:
+ case SmlSheet:
+ case Theme:
+ case ThemeOverride:
+ case WmlDocument:
+ case WmlEndNotes:
+ case WmlFontTable:
+ case WmlFootNotes:
+ case WmlFooter:
+ case WmlHeader:
+ case WmlNumbering:
+ case WmlSettings:
+ case WmlStyles:
+ case WmlWebSettings:
+ final TokenView<TokenType> aTokenView = maViewFactory.Create(aPart.getStream());
+ maDetailViewContainer.setViewportView(aTokenView);
+ final Vector<String> aErrorsAndWarnings = new Vector<>();
+ XMLViewFactory.AddSemanticInformation(
+ aTokenView,
+ ParserFactory.getParser(
+ aPart.getContentType(),
+ aPart.getStream(),
+ aErrorsAndWarnings),
+ aErrorsAndWarnings);
+ break;
+
+ case OleObject:
+ case Unknown:
+ default:
+ maDetailViewContainer.setViewportView(null);
+ break;
+ }
+ }
+
+
+
+
+ private final JScrollPane maDetailViewContainer;
+ private XMLTokenViewFactory maViewFactory;
+ private OOXMLPackage maPackage;
+}
diff --git a/ooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/ImageView.java b/ooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/ImageView.java
new file mode 100755
index 000000000000..b7ea3baf4c7c
--- /dev/null
+++ b/ooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/ImageView.java
@@ -0,0 +1,75 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.viewer;
+
+import java.awt.Graphics;
+import java.awt.image.BufferedImage;
+import java.io.IOException;
+import java.io.InputStream;
+
+import javax.imageio.ImageIO;
+import javax.swing.JComponent;
+import javax.swing.JPanel;
+
+@SuppressWarnings("serial")
+public class ImageView
+ extends JPanel
+{
+ public ImageView (final InputStream aInputStream)
+ {
+ BufferedImage aImage = null;
+ try
+ {
+ aImage = ImageIO.read(aInputStream);
+ }
+ catch (IOException e)
+ {
+ e.printStackTrace();
+ }
+ maImage = aImage;
+ }
+
+
+
+
+ public JComponent GetComponent()
+ {
+ return this;
+ }
+
+
+
+
+ @Override
+ public void paintComponent (final Graphics aGraphics)
+ {
+ super.paintComponent(aGraphics);
+ if (maImage != null)
+ {
+ aGraphics.drawImage(maImage, 10, 10, null);
+ }
+ }
+
+
+
+ private final BufferedImage maImage;
+}
diff --git a/ooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/KeyListener.java b/ooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/KeyListener.java
new file mode 100755
index 000000000000..ed752ef8e465
--- /dev/null
+++ b/ooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/KeyListener.java
@@ -0,0 +1,50 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.viewer;
+
+import java.awt.event.KeyEvent;
+
+public class KeyListener
+ implements java.awt.event.KeyListener
+{
+
+ @Override
+ public void keyTyped(KeyEvent e)
+ {
+ System.out.println(e);
+ }
+
+ @Override
+ public void keyPressed(KeyEvent e)
+ {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void keyReleased(KeyEvent e)
+ {
+ // TODO Auto-generated method stub
+
+ }
+
+}
diff --git a/ooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/OOXMLViewer.java b/ooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/OOXMLViewer.java
new file mode 100755
index 000000000000..cc7f3636eb2f
--- /dev/null
+++ b/ooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/OOXMLViewer.java
@@ -0,0 +1,208 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.viewer;
+
+import java.awt.BorderLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.io.File;
+import java.util.Vector;
+
+import javax.swing.JComponent;
+import javax.swing.JFileChooser;
+import javax.swing.JFrame;
+import javax.swing.JMenu;
+import javax.swing.JMenuBar;
+import javax.swing.JMenuItem;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JSplitPane;
+import javax.swing.JTabbedPane;
+import javax.swing.UIManager;
+
+import org.apache.openoffice.ooxml.framework.part.OOXMLPackage;
+import org.apache.openoffice.ooxml.framework.part.parser.ParserFactory;
+import org.apache.openoffice.ooxml.parser.Log;
+import org.apache.openoffice.ooxml.viewer.content.ContentView;
+
+/** A simple viewer for the streams inside an OOXML file.
+ */
+public class OOXMLViewer
+{
+ public static void main (final String[] aArguments)
+ {
+ try
+ {
+ UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+
+ Log.Dbg = null;
+
+ // Process options.
+ final Vector<String> aFilenames = new Vector<>();
+ for (int nIndex=0; nIndex<aArguments.length; ++nIndex)
+ {
+ if (aArguments[nIndex].startsWith("-"))
+ {
+ switch (aArguments[nIndex])
+ {
+ case "-t":
+ ++nIndex;
+ if (nIndex >= aArguments.length)
+ {
+ System.err.printf("expecting argument after option '-t'");
+ System.exit(1);
+ }
+ ParserFactory.SetParserTableFilename(aArguments[nIndex]);
+ break;
+
+ default:
+ System.out.printf("unknown option '%s'\n", aArguments[nIndex]);
+ System.exit(1);;
+ break;
+
+ }
+ }
+ else
+ aFilenames.add(aArguments[nIndex]);
+ }
+
+ for (final String sFilename : aFilenames)
+ {
+ final OOXMLViewer aViewer = new OOXMLViewer();
+ aViewer.SetFile(new File(sFilename));
+ aViewer.maFrame.setVisible(true);
+ }
+ }
+
+
+
+
+ private OOXMLViewer ()
+ {
+ maFrame = new JFrame("OOXML Viewer");
+ maFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ maFrame.setSize(1024,768);
+ maContainer = new JPanel();
+ maFrame.add(maContainer, BorderLayout.CENTER);
+
+ maFrame.setJMenuBar(CreateMenuBar());
+ maFrame.addKeyListener(new KeyListener());
+ }
+
+
+
+
+ private void SetFile (final File aFile)
+ {
+ if ( ! aFile.exists())
+ {
+ JOptionPane.showMessageDialog(
+ maFrame,
+ "File '"+aFile.toString()+"' does not exist",
+ "File Error",
+ JOptionPane.ERROR_MESSAGE);
+ }
+ else if ( ! aFile.canRead())
+ {
+ JOptionPane.showMessageDialog(
+ maFrame,
+ "Can not open '"+aFile.toString()+"' for reading",
+ "File Error",
+ JOptionPane.ERROR_MESSAGE);
+ }
+ else
+ {
+ maContainer.removeAll();
+ maContainer.setLayout(new BorderLayout());
+
+ final OOXMLPackage aPackage = OOXMLPackage.Create(aFile);
+ final JScrollPane aDetailViewContainer = new JScrollPane(
+ JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
+ JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
+ aDetailViewContainer.getVerticalScrollBar().setUnitIncrement(10);
+ final DetailViewManager aDetailViewManager = new DetailViewManager(aDetailViewContainer, aPackage);
+
+ final JTabbedPane aLeftSidebar = new JTabbedPane();
+
+ final ContentView aContentView = new ContentView(aDetailViewManager, aPackage);
+ aLeftSidebar.addTab("Content", new JScrollPane(aContentView));
+
+ final StreamView aFragmentView = new StreamView(aDetailViewManager, aPackage);
+ aLeftSidebar.addTab("Streams", new JScrollPane(aFragmentView));
+
+ final PartsView aPartsView = new PartsView(aDetailViewManager, aPackage);
+ aLeftSidebar.addTab("Parts", new JScrollPane(aPartsView));
+
+ final JSplitPane aPane = new JSplitPane(
+ JSplitPane.HORIZONTAL_SPLIT,
+ aLeftSidebar,
+ aDetailViewContainer
+ );
+ aPane.setDividerLocation(200);
+
+ maContainer.add(aPane, BorderLayout.CENTER);
+
+ aFragmentView.ShowInitialPart();
+ }
+ }
+
+
+
+
+ private JMenuBar CreateMenuBar ()
+ {
+ final JMenuBar aMenuBar = new JMenuBar();
+
+ final JMenu aFileMenu = new JMenu("File");
+ aMenuBar.add(aFileMenu);
+
+ final JMenuItem aOpenItem = new JMenuItem("Open");
+ aOpenItem.addActionListener(new ActionListener()
+ {
+ @Override public void actionPerformed (final ActionEvent aEvent)
+ {
+ final JFileChooser aFileChooser = new JFileChooser();
+ final int nResult = aFileChooser.showOpenDialog(null);
+ if (nResult == JFileChooser.APPROVE_OPTION)
+ {
+ final OOXMLViewer aViewer = new OOXMLViewer();
+ aViewer.SetFile(aFileChooser.getSelectedFile());
+ }
+ }
+ });
+ aFileMenu.add(aOpenItem);
+
+ return aMenuBar;
+ }
+
+
+
+
+ private final JFrame maFrame;
+ private final JComponent maContainer;
+}
diff --git a/ooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/PartsView.java b/ooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/PartsView.java
new file mode 100755
index 000000000000..caa9b3a9e308
--- /dev/null
+++ b/ooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/PartsView.java
@@ -0,0 +1,137 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.viewer;
+
+import java.util.LinkedList;
+import java.util.Queue;
+import java.util.Set;
+import java.util.TreeSet;
+
+import javax.swing.JTree;
+import javax.swing.event.TreeSelectionEvent;
+import javax.swing.event.TreeSelectionListener;
+import javax.swing.tree.DefaultMutableTreeNode;
+import javax.swing.tree.DefaultTreeModel;
+import javax.swing.tree.TreeModel;
+import javax.swing.tree.TreePath;
+
+import org.apache.openoffice.ooxml.framework.part.ContentType;
+import org.apache.openoffice.ooxml.framework.part.IReferenceProvider;
+import org.apache.openoffice.ooxml.framework.part.OOXMLPackage;
+import org.apache.openoffice.ooxml.framework.part.Part;
+import org.apache.openoffice.ooxml.framework.part.PartName;
+
+@SuppressWarnings("serial")
+public class PartsView
+ extends JTree
+ implements TreeSelectionListener
+{
+ public PartsView (
+ final DetailViewManager aDetailViewManager,
+ final OOXMLPackage aPackage)
+ {
+ maPackage = aPackage;
+ maDetailViewManager = aDetailViewManager;
+
+ Initialize();
+
+ getSelectionModel().addTreeSelectionListener(this);
+ }
+
+
+
+ private final void Initialize ()
+ {
+ final DefaultMutableTreeNode aRootNode = new DefaultMutableTreeNode(
+ "top level relations");
+ final TreeModel aModel = new DefaultTreeModel(aRootNode);
+
+ final Queue<IReferenceProvider> aWorklist = new LinkedList<IReferenceProvider>();
+ aWorklist.add(maPackage);
+ final Set<PartName> aProcessedPartNames = new TreeSet<PartName>();
+ CreateChildren(aRootNode, aProcessedPartNames, maPackage);
+ setModel(aModel);
+ }
+
+
+
+
+ private void CreateChildren (
+ final DefaultMutableTreeNode aNode,
+ final Set<PartName> aProcessedPartNames,
+ final IReferenceProvider aReferences)
+ {
+ for (final PartName aTarget : aReferences.getRelatedParts().getAllTargets())
+ {
+ Part aPart = maPackage.getPart(aTarget);
+ final DefaultMutableTreeNode aRelationNode;
+ if ( ! aProcessedPartNames.contains(aPart.getPartName()))
+ {
+ aProcessedPartNames.add(aPart.getPartName());
+ aRelationNode = new DefaultMutableTreeNode(aPart.getPartName().GetFullname());
+ CreateChildren(aRelationNode, aProcessedPartNames, aPart);
+ }
+ else
+ {
+ aRelationNode = new DefaultMutableTreeNode(aPart.getPartName().GetFullname() + "...");
+ }
+ aNode.add(aRelationNode);
+ }
+ }
+
+
+
+
+ /** Callback for clicks on the part view.
+ */
+ @Override
+ public void valueChanged (final TreeSelectionEvent aEvent)
+ {
+ final TreePath aPath = aEvent.getNewLeadSelectionPath();
+ if (aPath != null)
+ {
+ final PartName aName= GetPackagePathForTreePath(aPath);
+ final ContentType eType = maPackage.getPart(
+ aName).getContentType();
+ maDetailViewManager.ShowPart(
+ aName,
+ eType);
+ }
+ }
+
+
+
+
+
+ private PartName GetPackagePathForTreePath (final TreePath aPath)
+ {
+ final PartName aName = new PartName(aPath.getLastPathComponent().toString());
+ return aName;
+ }
+
+
+
+
+
+ private final OOXMLPackage maPackage;
+ private final DetailViewManager maDetailViewManager;
+}
diff --git a/ooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/StreamView.java b/ooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/StreamView.java
new file mode 100755
index 000000000000..61d497d02a5f
--- /dev/null
+++ b/ooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/StreamView.java
@@ -0,0 +1,266 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.viewer;
+
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseMotionListener;
+
+import javax.swing.JTree;
+import javax.swing.SwingUtilities;
+import javax.swing.event.TreeSelectionEvent;
+import javax.swing.event.TreeSelectionListener;
+import javax.swing.tree.DefaultMutableTreeNode;
+import javax.swing.tree.DefaultTreeModel;
+import javax.swing.tree.TreeModel;
+import javax.swing.tree.TreeNode;
+import javax.swing.tree.TreePath;
+
+import org.apache.openoffice.ooxml.framework.part.ContentType;
+import org.apache.openoffice.ooxml.framework.part.OOXMLPackage;
+import org.apache.openoffice.ooxml.framework.part.Part;
+import org.apache.openoffice.ooxml.framework.part.PartName;
+
+/** Overview of the individual parts/streams in an OOXML file.
+ */
+@SuppressWarnings("serial")
+public class StreamView
+ extends JTree
+ implements TreeSelectionListener, MouseMotionListener
+{
+ /** Create a new PartsView object for the given OOXML file.
+ * When the user clicks on one part entry then the DetailViewManager is
+ * called and asked to display the part.
+ */
+ StreamView (
+ final DetailViewManager aDetailViewManager,
+ final OOXMLPackage aPackage)
+ {
+ maDetailViewManager = aDetailViewManager;
+ maOOXMLPackage = aPackage;
+ getSelectionModel().addTreeSelectionListener(this);
+
+ // Listen for motion events so that the tooltip can be set according to
+ // the entry under the mouse pointer.
+ addMouseMotionListener(this);
+
+ // Create a tree model for the streams in the (zip) file, set the model
+ // asynchronously at the JTree and finally expand all nodes.
+ final TreeModel aModel = CreateTreeModel(aPackage);
+ SwingUtilities.invokeLater(new Runnable()
+ {
+ public void run()
+ {
+ setModel(aModel);
+ for (int nIndex=0; nIndex<getRowCount(); ++nIndex)
+ {
+ expandRow(nIndex);
+ }
+ }
+ });
+
+ setToolTipText("hallo");
+ }
+
+
+
+
+ private TreeModel CreateTreeModel (final OOXMLPackage aPackage)
+ {
+ final DefaultMutableTreeNode aRootNode = new DefaultMutableTreeNode(
+ aPackage.getFileName());
+ final DefaultTreeModel aModel = new DefaultTreeModel(aRootNode);
+ try
+ {
+ for (final String sStreamName : aPackage.listStreamNames())
+ {
+ DefaultMutableTreeNode aNode = aRootNode;
+ for (final String sPart : sStreamName.split("/"))
+ {
+ DefaultMutableTreeNode aChild = GetChildNodeForName(aNode, sPart);
+ if (aChild == null)
+ {
+ aChild = new DefaultMutableTreeNode(sPart);
+ aNode.add(aChild);
+ }
+
+ aNode = aChild;
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ return aModel;
+ }
+
+
+
+
+ public void ShowInitialPart ()
+ {
+ final Part aPart = maOOXMLPackage.getOfficeDocumentPart();
+ MakePartVisible(aPart);
+ maDetailViewManager.ShowPart(aPart);
+ }
+
+
+
+
+ private DefaultMutableTreeNode GetChildNodeForName (final TreeNode aNode, final String sName)
+ {
+ for (int nIndex=0; nIndex<aNode.getChildCount(); ++nIndex)
+ {
+ final TreeNode aChild = aNode.getChildAt(nIndex);
+ if (aChild.toString().equals(sName))
+ {
+ return (DefaultMutableTreeNode)aChild;
+ }
+ }
+ return null;
+ }
+
+
+
+
+ /** Callback for clicks on the part view.
+ */
+ @Override
+ public void valueChanged (final TreeSelectionEvent aEvent)
+ {
+ final TreePath aPath = aEvent.getNewLeadSelectionPath();
+ if (aPath != null)
+ {
+ final String sPath = GetPackagePathForTreePath(aPath);
+ final PartName aName = new PartName(sPath);
+ final ContentType eType = maOOXMLPackage.getPart(
+ aName).getContentType();
+ maDetailViewManager.ShowPart(
+ aName,
+ eType);
+ }
+ }
+
+
+
+
+ @Override
+ public void mouseDragged (final MouseEvent aEvent)
+ {
+ }
+
+
+
+
+ @Override
+ public void mouseMoved (final MouseEvent aEvent)
+ {
+ final int nRow = getRowForLocation(aEvent.getX(), aEvent.getY());
+ if (nRow >= 0)
+ {
+ final String sPath = GetPackagePathForTreePath(getPathForRow(nRow));
+ SetPartUnderMouse(sPath);
+ }
+ }
+
+
+
+
+ private String GetPackagePathForTreePath (final TreePath aPath)
+ {
+ final StringBuffer sPath = new StringBuffer("");
+ final Object aNodes[] = aPath.getPath();
+ for (int nIndex=1; nIndex<aNodes.length; ++nIndex)
+ {
+ sPath.append("/");
+ sPath.append(aNodes[nIndex].toString());
+ }
+ return sPath.toString();
+ }
+
+
+
+
+ private void SetPartUnderMouse (final String sPartPath)
+ {
+ if (msPartPathUnderMouse==null
+ || ! msPartPathUnderMouse.equals(sPartPath))
+ {
+ msPartPathUnderMouse = sPartPath;
+
+ final ContentType eType = maOOXMLPackage.getPart(
+ new PartName(msPartPathUnderMouse)).getContentType();
+ String sToolTipText = eType.toString();
+ if ( ! eType.GetLongName().isEmpty())
+ sToolTipText += " (" + eType.GetLongName() + ")";
+ setToolTipText(sToolTipText);
+ }
+ }
+
+
+
+
+ private void MakePartVisible (final Part aPart)
+ {
+ final String[] aPathParts = aPart.getPartName().GetFullname().substring(1).split("/");
+ final TreeNode[] aTreeNodePath = new TreeNode[aPathParts.length+1];
+ TreeNode aNode = (TreeNode)getModel().getRoot();
+ int nDepth = 0;
+ aTreeNodePath[nDepth++] = aNode;
+ for (final String sPathPart : aPathParts)
+ {
+ boolean bFoundChild = false;
+ for (int nIndex=0; nIndex<aNode.getChildCount(); ++nIndex)
+ {
+ final TreeNode aChildNode = aNode.getChildAt(nIndex);
+ final String sChildName = aChildNode.toString();
+ if (sChildName.equals(sPathPart))
+ {
+ aNode = aChildNode;
+ aTreeNodePath[nDepth++] = aNode;
+ bFoundChild = true;
+ break;
+ }
+ }
+ if ( ! bFoundChild)
+ return;
+ }
+
+ SelectNode(new TreePath(aTreeNodePath));
+ }
+
+
+
+
+ private void SelectNode (final TreePath aTreePath)
+ {
+// getSelectionModel().setSelectionPath(aTreePath);
+// scrollPathToVisible(aTreePath);
+ }
+
+
+
+
+ private final DetailViewManager maDetailViewManager;
+ private final OOXMLPackage maOOXMLPackage;
+ private String msPartPathUnderMouse;
+}
diff --git a/ooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/content/ContentView.java b/ooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/content/ContentView.java
new file mode 100755
index 000000000000..a5049813ba5d
--- /dev/null
+++ b/ooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/content/ContentView.java
@@ -0,0 +1,77 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.viewer.content;
+
+import javax.swing.JTree;
+import javax.swing.tree.DefaultMutableTreeNode;
+import javax.swing.tree.DefaultTreeModel;
+import javax.swing.tree.TreeModel;
+
+import org.apache.openoffice.ooxml.framework.part.OOXMLPackage;
+import org.apache.openoffice.ooxml.viewer.DetailViewManager;
+
+/** Overview of the individual parts/streams in an OOXML file.
+ */
+@SuppressWarnings("serial")
+public class ContentView
+ extends JTree
+{
+ public ContentView (
+ final DetailViewManager aDetailViewManager,
+ final OOXMLPackage aPackage)
+ {
+ TreeModel aModel = null;
+ switch(aPackage.getOfficeDocumentPart().getContentType())
+ {
+ case PmlDocument:
+ aModel = CreateTreeForPresentationModel(new PresentationImporter().importModel(
+ aPackage.getOfficeDocumentPart()));
+ break;
+ //case SmlDocument:
+ //case WmlDocument:
+ default:
+ break;
+ }
+ if (aModel != null)
+ setModel(aModel);
+ }
+
+
+
+
+
+
+ private TreeModel CreateTreeForPresentationModel (final PresentationModel aModel)
+ {
+ final DefaultMutableTreeNode aRootNode = new DefaultMutableTreeNode(
+ "presentation");
+ final DefaultTreeModel aTreeModel = new DefaultTreeModel(aRootNode);
+
+ for (final Slide aSlide : aModel.GetSlideManager().GetSlides())
+ {
+ DefaultMutableTreeNode aNode = new DefaultMutableTreeNode(
+ aSlide.toString());
+ aRootNode.add(aNode);
+ }
+ return aTreeModel;
+ }
+}
diff --git a/ooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/content/PresentationImporter.java b/ooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/content/PresentationImporter.java
new file mode 100755
index 000000000000..5581ca41887a
--- /dev/null
+++ b/ooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/content/PresentationImporter.java
@@ -0,0 +1,81 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.viewer.content;
+
+import java.io.InputStream;
+import java.util.Vector;
+
+import javax.xml.stream.Location;
+
+import org.apache.openoffice.ooxml.framework.part.ContentType;
+import org.apache.openoffice.ooxml.framework.part.Part;
+import org.apache.openoffice.ooxml.framework.part.parser.ParserFactory;
+import org.apache.openoffice.ooxml.parser.ElementContext;
+import org.apache.openoffice.ooxml.parser.Parser;
+import org.apache.openoffice.ooxml.parser.action.ActionTrigger;
+import org.apache.openoffice.ooxml.parser.action.IAction;
+
+public class PresentationImporter
+{
+ public PresentationModel importModel (final Part aPart)
+ {
+ final PresentationModel aModel = new PresentationModel();
+ final Parser aParser = CreateParser(
+ aPart.getStream(),
+ aModel,
+ aPart);
+ aParser.Parse();
+ return aModel;
+ }
+
+
+
+ private Parser CreateParser (
+ final InputStream aStream,
+ final PresentationModel aModel,
+ final Part aPart)
+ {
+ final Parser aParser = ParserFactory.getParser(
+ ContentType.PmlDocument,
+ aStream,
+ new Vector<String>());
+
+ aParser.GetActionManager().AddElementStartAction(
+ "p06_CT_SlideIdListEntry",
+ new IAction()
+ {
+ @Override public void Run(ActionTrigger eTrigger,
+ ElementContext aContext, String sText,
+ Location aStartLocation, Location aEndLocation)
+ {
+ final String aReferenceId = aContext.GetAttributes().GetRawAttributeValue("r06_id");
+
+ aModel.GetSlideManager().GetSlideForPart(
+ aPart.getPartById(aReferenceId));
+
+ System.out.println(aReferenceId);
+ }
+ });
+
+ return aParser;
+ }
+}
diff --git a/ooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/content/PresentationModel.java b/ooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/content/PresentationModel.java
new file mode 100755
index 000000000000..b111ad58b382
--- /dev/null
+++ b/ooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/content/PresentationModel.java
@@ -0,0 +1,43 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.viewer.content;
+
+public class PresentationModel
+{
+ PresentationModel()
+ {
+ maSlideManager = new SlideManager();
+ }
+
+
+
+
+ public SlideManager GetSlideManager()
+ {
+ return maSlideManager;
+ }
+
+
+
+
+ private final SlideManager maSlideManager;
+}
diff --git a/ooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/content/Slide.java b/ooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/content/Slide.java
new file mode 100755
index 000000000000..3dc09db12cfd
--- /dev/null
+++ b/ooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/content/Slide.java
@@ -0,0 +1,56 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.viewer.content;
+
+public class Slide
+{
+ Slide (
+ final String sSlideName,
+ final int nShapeCount)
+ {
+ msSlideName = sSlideName;
+ mnShapeCount = nShapeCount;
+ }
+
+
+
+
+ public String getSlideName ()
+ {
+ return msSlideName;
+ }
+
+
+
+
+ @Override
+ public String toString ()
+ {
+ return msSlideName +" has "+mnShapeCount+" shapes";
+ }
+
+
+
+
+ private final String msSlideName;
+ private final int mnShapeCount;
+}
diff --git a/ooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/content/SlideManager.java b/ooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/content/SlideManager.java
new file mode 100755
index 000000000000..153ac3986ec6
--- /dev/null
+++ b/ooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/content/SlideManager.java
@@ -0,0 +1,77 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.viewer.content;
+
+import java.util.Map;
+import java.util.TreeMap;
+import java.util.Vector;
+
+import org.apache.openoffice.ooxml.framework.part.Part;
+import org.apache.openoffice.ooxml.framework.part.PartName;
+
+public class SlideManager
+{
+ SlideManager ()
+ {
+ maSlides = new Vector<>();
+ maPartNameToSlideMap = new TreeMap<>();
+ }
+
+
+
+ public void AddSlide (
+ final PartName aName,
+ final Slide aSlide)
+ {
+ maSlides.add(aSlide);
+ maPartNameToSlideMap.put(aName, aSlide);
+ }
+
+
+
+
+ public Iterable<Slide> GetSlides ()
+ {
+ return maSlides;
+ }
+
+
+
+
+ public Slide GetSlideForPart (final Part aPart)
+ {
+ Slide aSlide = maPartNameToSlideMap.get(aPart.getPartName());
+ if (aSlide == null)
+ {
+ aSlide = new SlideParser(aPart).ParseSlide(maSlides.size());
+
+ AddSlide(aPart.getPartName(), aSlide);
+ }
+ return aSlide;
+ }
+
+
+
+
+ private final Vector<Slide> maSlides;
+ private final Map<PartName,Slide> maPartNameToSlideMap;
+}
diff --git a/ooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/content/SlideParser.java b/ooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/content/SlideParser.java
new file mode 100755
index 000000000000..82dfedbdfcd2
--- /dev/null
+++ b/ooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/content/SlideParser.java
@@ -0,0 +1,80 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.viewer.content;
+
+import java.util.Vector;
+
+import javax.xml.stream.Location;
+
+import org.apache.openoffice.ooxml.framework.part.Part;
+import org.apache.openoffice.ooxml.framework.part.parser.ParserFactory;
+import org.apache.openoffice.ooxml.parser.ElementContext;
+import org.apache.openoffice.ooxml.parser.Parser;
+import org.apache.openoffice.ooxml.parser.action.ActionTrigger;
+import org.apache.openoffice.ooxml.parser.action.IAction;
+
+public class SlideParser
+{
+ SlideParser (final Part aPart)
+ {
+ maParser = ParserFactory.getParser(
+ aPart.getContentType(),
+ aPart.getStream(),
+ new Vector<String>());
+ mnShapeCount = 0;
+
+ maParser.GetActionManager().AddElementStartAction(
+ "p06_CT_Shape",
+ new IAction()
+ {
+ @Override public void Run(ActionTrigger eTrigger, ElementContext aContext,
+ String sText, Location aStartLocation, Location aEndLocation)
+ {
+ SlideParser.this.IncreaseShapeCount();
+ }
+ });
+ }
+
+
+
+
+ Slide ParseSlide (final int nSlideIndex)
+ {
+ maParser.Parse();
+ final Slide aSlide = new Slide("slide "+nSlideIndex, mnShapeCount);
+ return aSlide;
+ }
+
+
+
+
+ private void IncreaseShapeCount ()
+ {
+ ++mnShapeCount;
+ }
+
+
+
+
+ private final Parser maParser;
+ private int mnShapeCount;
+}
diff --git a/ooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/tokenview/DocumentFactory.java b/ooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/tokenview/DocumentFactory.java
new file mode 100755
index 000000000000..11f2ac566945
--- /dev/null
+++ b/ooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/tokenview/DocumentFactory.java
@@ -0,0 +1,127 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.viewer.tokenview;
+
+import java.util.Stack;
+
+
+public class DocumentFactory<TokenType>
+{
+ interface IRepaintTarget
+ {
+ void RequestRepaint();
+ }
+
+
+
+
+ DocumentFactory (
+ final LineContainer<TokenType> aLines,
+ final IRepaintTarget aRepaintTarget)
+ {
+ maLines = aLines;
+ maRepaintTarget = aRepaintTarget;
+ mbIsGroupBeginPending = false;
+ maGroupStartStack = new Stack<Run<TokenType>>();
+ maLastRun = null;
+ maCurrentGroup = null;
+ StartNewLine();
+ }
+
+
+
+
+ public void AddText (
+ final String sText,
+ final TokenType eTokenType,
+ final Style aStyle,
+ final int nOffset)
+ {
+ final Run<TokenType> aRun = new Run<TokenType>(sText, eTokenType, aStyle, nOffset);
+ synchronized(maLines)
+ {
+ maCurrentLine.AddRun(aRun);
+ if (sText.endsWith("\n"))
+ StartNewLine();
+ }
+
+ if (mbIsGroupBeginPending)
+ {
+ maGroupStartStack.push(maCurrentGroup);
+ aRun.SetGroupParent(maCurrentGroup);
+ maCurrentGroup = aRun;
+ mbIsGroupBeginPending = false;
+ }
+ else if (maCurrentGroup != null)
+ aRun.SetGroupParent(maCurrentGroup);
+ maLastRun = aRun;
+
+ maRepaintTarget.RequestRepaint();
+ }
+
+
+
+
+ public void FinishText ()
+ {
+ StartNewLine();
+ }
+
+
+
+
+ public void BeginGroup()
+ {
+ mbIsGroupBeginPending = true;
+ }
+
+
+
+
+ public void EndGroup ()
+ {
+ maCurrentGroup.SetGroupEnd(maLastRun);
+ maCurrentGroup = maGroupStartStack.pop();
+ }
+
+
+
+
+
+ private void StartNewLine ()
+ {
+ if (maCurrentLine != null)
+ maLines.AddLine(maCurrentLine);
+ maCurrentLine = new Line<TokenType>();
+ }
+
+
+
+
+ private final LineContainer<TokenType> maLines;
+ private final IRepaintTarget maRepaintTarget;
+ private Line<TokenType> maCurrentLine;
+ private boolean mbIsGroupBeginPending;
+ private Stack<Run<TokenType>> maGroupStartStack;
+ private Run<TokenType> maLastRun;
+ private Run<TokenType> maCurrentGroup;
+}
diff --git a/ooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/tokenview/FormatState.java b/ooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/tokenview/FormatState.java
new file mode 100755
index 000000000000..071ac1426472
--- /dev/null
+++ b/ooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/tokenview/FormatState.java
@@ -0,0 +1,61 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.viewer.tokenview;
+
+import java.awt.Dimension;
+import java.util.Iterator;
+import java.util.Vector;
+
+public class FormatState<TokenType>
+ implements Iterable<Line<TokenType>>
+{
+ FormatState (
+ final Dimension aBoundingSize,
+ final Vector<Line<TokenType>> aVisibleLines)
+ {
+ maBoundingSize = aBoundingSize;
+ maVisibleLines = aVisibleLines;
+ }
+
+
+
+
+ public Dimension GetTextBoundingSize()
+ {
+ return maBoundingSize;
+ }
+
+
+
+
+ @Override
+ public Iterator<Line<TokenType>> iterator ()
+ {
+ return maVisibleLines.iterator();
+ }
+
+
+
+
+ private final Dimension maBoundingSize;
+ private final Vector<Line<TokenType>> maVisibleLines;
+}
diff --git a/ooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/tokenview/Formatter.java b/ooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/tokenview/Formatter.java
new file mode 100755
index 000000000000..605aeab38950
--- /dev/null
+++ b/ooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/tokenview/Formatter.java
@@ -0,0 +1,93 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.viewer.tokenview;
+
+import java.awt.Dimension;
+import java.awt.Graphics2D;
+import java.util.Vector;
+
+public class Formatter<TokenType>
+{
+ public Formatter ()
+ {
+ mnLastFormattedLine = -1;
+ mnWidth = 0;
+ mnHeight = 0;
+ }
+
+
+
+
+ public FormatState<TokenType> FormatText (
+ final Graphics2D aG2,
+ final LineContainer<TokenType> aLines)
+ {
+ FormatLines(aG2, aLines);
+
+ final double nTop = aG2.getClipBounds().getMinY();
+ final double nBottom = aG2.getClipBounds().getMaxY();
+ final Vector<Line<TokenType>> aVisibleLines = new Vector<>();
+ for (final Line<TokenType> aLine : aLines.GetLines())
+ {
+ if (aLine.Overlaps(nTop, nBottom))
+ {
+ // Line is (partially) visible.
+ aVisibleLines.add(aLine);
+ }
+ }
+
+ return new FormatState<TokenType>(
+ new Dimension(mnWidth,mnHeight),
+ aVisibleLines);
+ }
+
+
+
+
+ private void FormatLines (
+ final Graphics2D aG2,
+ final LineContainer<TokenType> aLines)
+ {
+ for (int nIndex=mnLastFormattedLine+1,nCount=aLines.GetLineCount(); nIndex<nCount; ++nIndex)
+ {
+ final Line<TokenType> aLine = aLines.GetLine(nIndex);
+ final int nY;
+ if (nIndex > 0)
+ nY = aLines.GetLine(nIndex-1).GetBottom();
+ else
+ nY = 0;
+ aLine.Format(aG2, nY);
+ if (aLine.GetWidth() > mnWidth)
+ mnWidth = aLine.GetWidth();
+ if (aLine.GetBottom() > mnHeight)
+ mnHeight = aLine.GetBottom();
+ }
+ mnLastFormattedLine = aLines.GetLineCount()-1;
+ }
+
+
+
+
+ private int mnLastFormattedLine;
+ private int mnWidth;
+ private int mnHeight;
+}
diff --git a/ooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/tokenview/Line.java b/ooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/tokenview/Line.java
new file mode 100755
index 000000000000..c39e24bf6ed3
--- /dev/null
+++ b/ooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/tokenview/Line.java
@@ -0,0 +1,239 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.viewer.tokenview;
+
+import java.awt.Graphics2D;
+import java.util.Iterator;
+import java.util.Vector;
+
+public class Line<TokenType>
+
+ implements Iterable<Run<TokenType>>
+{
+ Line ()
+ {
+ maRuns = new Vector<Run<TokenType>>();
+ mnWidth = -1;
+ mnHeight = -1;
+ mnY = -1;
+ mnStartOffset = -1;
+ mnEndOffset = -1;
+ }
+
+
+
+
+ public void AddRun (final Run<TokenType> aRun)
+ {
+ maRuns.add(aRun);
+ mnWidth += aRun.GetWidth();
+ if (aRun.GetHeight() > mnHeight)
+ mnHeight = aRun.GetHeight();
+ aRun.SetLine(this);
+
+ if (aRun.GetStreamOffset() >= 0)
+ {
+ if (mnStartOffset < 0)
+ mnStartOffset = aRun.GetStreamOffset();
+
+ if (mnEndOffset < aRun.GetStreamEndOffset())
+ mnEndOffset = aRun.GetStreamEndOffset();
+ }
+ }
+
+
+
+
+ public void Format (
+ final Graphics2D aG2,
+ final int nY)
+ {
+ mnY = nY;
+
+ mnWidth = 0;
+ mnHeight = 0;
+ for (final Run<TokenType> aRun : maRuns)
+ {
+ aRun.Format(aG2);
+ mnWidth += aRun.GetWidth();
+ if (mnHeight < aRun.GetHeight())
+ mnHeight = aRun.GetHeight();
+ }
+ }
+
+
+
+
+ public int GetWidth ()
+ {
+ return mnWidth;
+ }
+
+
+
+
+ public int GetHeight ()
+ {
+ return mnHeight;
+ }
+
+
+
+
+ public int GetTop ()
+ {
+ return mnY;
+ }
+
+
+
+
+ public int GetBottom ()
+ {
+ return mnY + mnHeight;
+ }
+
+
+
+
+ public boolean Overlaps (
+ final double nTop,
+ final double nBottom)
+ {
+ return mnY<=nBottom && mnY+mnHeight>nTop;
+ }
+
+
+
+
+ public boolean Contains (final int nY)
+ {
+ return nY>=mnY && nY<mnY+mnHeight;
+ }
+
+
+
+
+ @Override
+ public Iterator<Run<TokenType>> iterator()
+ {
+ return maRuns.iterator();
+ }
+
+
+
+
+ public Run<TokenType> GetRunForX (final int nX)
+ {
+ int nRunX = 0;
+ for (final Run<TokenType> aRun : maRuns)
+ {
+ final int nRunWidth = aRun.GetWidth();
+ final int nRight = nRunX + nRunWidth;
+ if (nX>=nRunX && nX<nRight)
+ return aRun;
+ nRunX = nRight;
+ }
+ return null;
+ }
+
+
+
+
+ public Run<TokenType> GetRunForOffset (int nOffset)
+ {
+ for (int nIndex=0; nIndex<maRuns.size(); ++nIndex)
+ {
+ final Run<TokenType> aRun = maRuns.get(nIndex);
+ final int nRunOffset = aRun.GetStreamOffset();
+ if (nRunOffset >= 0)
+ if (nRunOffset<=nOffset && nOffset<=aRun.GetStreamEndOffset())
+ return aRun;
+ }
+ return null;
+ }
+
+
+
+
+ public Iterable<Run<TokenType>> GetRunsForOffsets (
+ final int nStartOffset,
+ final int nEndOffset)
+ {
+ final Vector<Run<TokenType>> aRuns = new Vector<>();
+
+ for (final Run<TokenType> aRun : maRuns)
+ {
+ if (aRun.GetStreamOffset() >= nEndOffset)
+ break;
+ else if (aRun.GetStreamEndOffset()<nStartOffset)
+ continue;
+ else
+ aRuns.add(aRun);
+ }
+
+ return aRuns;
+ }
+
+
+
+
+ public int GetStartOffset()
+ {
+ return mnStartOffset;
+ }
+
+
+
+
+ public int GetEndOffset ()
+ {
+ return mnEndOffset;
+ }
+
+
+
+
+ public boolean ContainsOffset (final int nOffset)
+ {
+ return mnStartOffset<=nOffset && nOffset<mnEndOffset;
+ }
+
+
+
+
+ @Override
+ public String toString ()
+ {
+ return String.format("line of %d runs: %s", maRuns.size(), maRuns.toString());
+ }
+
+
+
+
+ private final Vector<Run<TokenType>> maRuns;
+ private int mnY;
+ private int mnWidth;
+ private int mnHeight;
+ private int mnStartOffset;
+ private int mnEndOffset;
+}
diff --git a/ooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/tokenview/LineContainer.java b/ooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/tokenview/LineContainer.java
new file mode 100755
index 000000000000..c791fb201ec8
--- /dev/null
+++ b/ooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/tokenview/LineContainer.java
@@ -0,0 +1,194 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.viewer.tokenview;
+
+import java.util.Vector;
+
+public class LineContainer<TokenType>
+{
+ LineContainer ()
+ {
+ maLines = new Vector<>();
+ }
+
+
+
+
+ boolean IsLineInGroup (
+ final Line<TokenType> aLine,
+ final Run<TokenType> aGroup)
+ {
+ if (aGroup == null)
+ return false;
+
+ final Line<TokenType> aStartLine = aGroup.GetLine();
+ if (aLine.GetTop() < aStartLine.GetTop())
+ return false;
+ final Line<TokenType> aEndLine = aGroup.GetGroupEnd().GetLine();
+ if (aLine.GetTop() > aEndLine.GetTop())
+ return false;
+
+ return true;
+ }
+
+
+
+
+ Line<TokenType> GetLineForY (final int nY)
+ {
+ int nMin = 0;
+ int nMax = maLines.size()-1;
+ if (nMin <= nMax)
+ {
+ while (nMin < nMax-1)
+ {
+ final int nMed = (nMax+nMin)/2;
+ if (nY < maLines.get(nMed).GetTop())
+ nMax = nMed;
+ else
+ nMin = nMed;
+ }
+ for (int nIndex=nMin; nIndex<=nMax; ++nIndex)
+ if (maLines.get(nIndex).Contains(nY))
+ return maLines.get(nIndex);
+ }
+ return null;
+ }
+
+
+
+
+ public Line<TokenType> GetLineForOffset (final int nOffset)
+ {
+ final int nLineIndex = GetLineIndexForOffset(nOffset, 0);
+ if (nLineIndex < 0)
+ return null;
+ else
+ return maLines.get(nLineIndex);
+
+ }
+
+
+
+
+ public Iterable<Line<TokenType>> GetLinesForOffsets (
+ final int nStartOffset,
+ final int nEndOffset)
+ {
+ final Vector<Line<TokenType>> aLines = new Vector<>();
+
+ final int nStartLineIndex = GetLineIndexForOffset(nStartOffset, -1);
+ final int nEndLineIndex = GetLineIndexForOffset(nEndOffset, +1);
+ if (nStartLineIndex >= 0)
+ {
+ if (nEndLineIndex < 0)
+ aLines.add(maLines.get(nStartLineIndex));
+ else
+ for (int nIndex=nStartLineIndex; nIndex<=nEndLineIndex; ++nIndex)
+ aLines.add(maLines.get(nIndex));
+ }
+ return aLines;
+ }
+
+
+
+
+ public int GetLineCount()
+ {
+ return maLines.size();
+ }
+
+
+
+
+ public Line<TokenType> GetLine (final int nIndex)
+ {
+ return maLines.get(nIndex);
+ }
+
+
+
+
+ public Iterable<Line<TokenType>> GetLines ()
+ {
+ return maLines;
+ }
+
+
+
+
+ public void AddLine (final Line<TokenType> aLine)
+ {
+ maLines.add(aLine);
+ }
+
+
+
+
+ /** Return the index of the line that contains the given offset.
+ * When there is no line that contains the line that look at the bias
+ * to return the previous or next line.
+ */
+ private int GetLineIndexForOffset (
+ final int nOffset,
+ final int nBias)
+ {
+ int nMinIndex = 0;
+ int nMaxIndex = maLines.size()-1;
+ while (nMinIndex < nMaxIndex-1)
+ {
+ final int nMedIndex = (nMinIndex + nMaxIndex) / 2;
+ if (maLines.get(nMedIndex).GetEndOffset() <= nOffset)
+ nMinIndex = nMedIndex;
+ else
+ nMaxIndex = nMedIndex;
+ }
+ for (int nIndex=nMinIndex; nIndex<=nMaxIndex; ++nIndex)
+ {
+ if (maLines.get(nIndex).ContainsOffset(nOffset))
+ return nIndex;
+ }
+ if (nBias < 0)
+ {
+ for (int nIndex=nMinIndex; nIndex<=nMaxIndex; ++nIndex)
+ {
+ if (maLines.get(nIndex).GetStartOffset() > nOffset)
+ return nIndex;
+ }
+ }
+ else if (nBias > 0)
+ {
+ for (int nIndex=nMaxIndex; nIndex>=nMinIndex; ++nIndex)
+ {
+ if (maLines.get(nIndex).GetEndOffset() < nOffset)
+ return nIndex;
+ }
+ }
+
+ return -1;
+ }
+
+
+
+
+ private final Vector<Line<TokenType>> maLines;
+}
diff --git a/ooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/tokenview/Run.java b/ooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/tokenview/Run.java
new file mode 100755
index 000000000000..ad2677efcb77
--- /dev/null
+++ b/ooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/tokenview/Run.java
@@ -0,0 +1,249 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.viewer.tokenview;
+
+import java.awt.Color;
+import java.awt.FontMetrics;
+import java.awt.Graphics2D;
+
+public class Run<TokenType>
+{
+ Run (
+ final String sText,
+ final TokenType eTokenType,
+ final Style aStyle,
+ final int nOffset)
+ {
+ msText = sText;
+ meTokenType = eTokenType;
+ maStyle = aStyle!=null ? aStyle : Style.DefaultStyle;
+ mnStreamOffset = nOffset;
+
+ mnWidth = -1;
+ mnHeight = -1;
+ mnOffset = nOffset;
+ maParent = null;
+ maGroupEnd = null;
+ maLine = null;
+ }
+
+
+
+
+ public void Format (
+ final Graphics2D aG2)
+ {
+ final FontMetrics aMetrics = aG2.getFontMetrics(maStyle.GetFont());
+ mnWidth = aMetrics.stringWidth(msText);
+ mnHeight = aMetrics.getHeight();
+ mnOffset = -aMetrics.getDescent();
+ }
+
+
+
+
+ public void Paint (
+ final Graphics2D aG2,
+ final int nX,
+ final int nY,
+ final Color aBackgroundColor)
+ {
+ maStyle.Set(aG2);
+
+ if (mnWidth < 0)
+ {
+ mnWidth = aG2.getFontMetrics().stringWidth(msText);
+ mnHeight = aG2.getFontMetrics().getHeight();
+ }
+
+ if (aBackgroundColor != null)
+ {
+ final Color aSavedColor = aG2.getColor();
+ aG2.setColor(aBackgroundColor);
+ aG2.fillRect(nX,nY-mnHeight, mnWidth, mnHeight);
+ aG2.setColor(aSavedColor);
+ }
+ aG2.drawString(msText, nX, nY+mnOffset);
+
+ if (msToolTipText != null)
+ {
+ aG2.drawLine(nX, nY-1, nX+mnWidth, nY-1);
+ }
+ }
+
+
+
+
+ public String GetText()
+ {
+ return msText;
+ }
+
+
+
+
+ public Style GetStyle ()
+ {
+ return maStyle;
+ }
+
+
+
+
+ public int GetStreamOffset ()
+ {
+ return mnStreamOffset;
+ }
+
+
+
+
+ public int GetStreamEndOffset ()
+ {
+ return mnStreamOffset + msText.length();
+ }
+
+
+
+
+ public int GetWidth()
+ {
+ return mnWidth;
+ }
+
+
+
+
+ public int GetHeight ()
+ {
+ return mnHeight;
+ }
+
+
+
+
+ public void SetGroupParent (final Run<TokenType> aParent)
+ {
+ maParent = aParent;
+ }
+
+
+
+
+ public void SetGroupEnd (final Run<TokenType> aRun)
+ {
+ maGroupEnd = aRun;
+ }
+
+
+
+
+ public Run<TokenType> GetGroupEnd()
+ {
+ return maGroupEnd;
+ }
+
+
+
+
+ public boolean IsGroup ()
+ {
+ if (maGroupEnd == null)
+ return false;
+ else if (maLine == maGroupEnd.maLine)
+ return true;
+ else
+ return true;
+ }
+
+
+
+
+ public Run<TokenType> GetParent ()
+ {
+ return maParent;
+ }
+
+
+
+
+ public Line<TokenType> GetLine ()
+ {
+ return maLine;
+ }
+
+
+
+
+ public void SetLine (final Line<TokenType> aLine)
+ {
+ maLine = aLine;
+ }
+
+
+
+
+ public void SetToolTipText (final String sText)
+ {
+ msToolTipText = sText;
+ }
+
+
+
+
+ public String GetToolTipText ()
+ {
+ return msToolTipText;
+ }
+
+
+
+
+ public TokenType GetTokenType ()
+ {
+ return meTokenType;
+ }
+
+
+
+
+ @Override
+ public String toString ()
+ {
+ return "run '"+msText+"' @ "+mnOffset;
+ }
+
+
+
+
+ private final String msText;
+ private final TokenType meTokenType;
+ private final Style maStyle;
+ private final int mnStreamOffset;
+ private int mnWidth;
+ private int mnHeight;
+ private int mnOffset;
+ private Run<TokenType> maParent;
+ private Run<TokenType> maGroupEnd;
+ private Line<TokenType> maLine;
+ private String msToolTipText;
+}
diff --git a/ooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/tokenview/RunRange.java b/ooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/tokenview/RunRange.java
new file mode 100755
index 000000000000..2c980a92dd76
--- /dev/null
+++ b/ooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/tokenview/RunRange.java
@@ -0,0 +1,87 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.viewer.tokenview;
+
+import java.util.Vector;
+
+public class RunRange<TokenType>
+{
+ RunRange (final Vector<Run<TokenType>> aRuns)
+ {
+ maRuns = aRuns;
+ }
+
+
+
+
+ public int FindTokens (
+ @SuppressWarnings("unchecked")
+ final TokenType ... eTypeList)
+ {
+ return FindTokens(0, eTypeList);
+ }
+
+
+
+
+ public int FindTokens (
+ final int nFirstIndex,
+ @SuppressWarnings("unchecked")
+ final TokenType ... eTypeList)
+ {
+ for (int nIndex=nFirstIndex; nIndex<maRuns.size()-eTypeList.length; ++nIndex)
+ {
+ boolean bMatches = true;
+ for (int nInnerIndex=0; nInnerIndex<eTypeList.length && bMatches; ++nInnerIndex)
+ if (maRuns.get(nIndex+nInnerIndex).GetTokenType()
+ != eTypeList[nInnerIndex])
+ {
+ bMatches = false;
+ }
+ if (bMatches)
+ return nIndex;
+ }
+
+ return -1;
+ }
+
+
+
+
+ public boolean IsEmpty ()
+ {
+ return maRuns.isEmpty();
+ }
+
+
+
+
+ public Run<TokenType> Get (final int nIndex)
+ {
+ return maRuns.get(nIndex);
+ }
+
+
+
+
+ private final Vector<Run<TokenType>> maRuns;
+}
diff --git a/ooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/tokenview/Style.java b/ooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/tokenview/Style.java
new file mode 100755
index 000000000000..3f81cd8fb76b
--- /dev/null
+++ b/ooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/tokenview/Style.java
@@ -0,0 +1,109 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.viewer.tokenview;
+
+import java.awt.Color;
+import java.awt.Font;
+import java.awt.Graphics2D;
+
+import javax.swing.UIManager;
+
+public class Style
+{
+ public Style ()
+ {
+ maForegroundColor = Color.BLACK;
+ if (DefaultFont == null)
+ DefaultFont = UIManager.getDefaults().getFont("TextField.font");
+ maFont = DefaultFont;
+ }
+
+
+
+
+ public void Set(Graphics2D aG2)
+ {
+ aG2.setColor(maForegroundColor);
+ aG2.setFont(maFont);
+ }
+
+
+
+
+ public Style SetForegroundColor (final Color aColor)
+ {
+ maForegroundColor = aColor;
+ return this;
+ }
+
+
+
+
+ public Color GetForegroundColor()
+ {
+ return maForegroundColor;
+ }
+
+
+
+
+ public Style SetBackgroundColor (final Color aColor)
+ {
+ maBackgroundColor = aColor;
+ return this;
+ }
+
+
+
+
+ public Color GetBackgroundColor()
+ {
+ return maBackgroundColor;
+ }
+
+
+
+
+ public Style SetBold()
+ {
+ maFont = maFont.deriveFont(Font.BOLD);
+ return this;
+ }
+
+
+
+
+ public Font GetFont()
+ {
+ return maFont;
+ }
+
+
+
+
+ public static final Style DefaultStyle = new Style();
+ public static Font DefaultFont = null;
+
+ private Color maBackgroundColor;
+ private Color maForegroundColor;
+ private Font maFont;
+}
diff --git a/ooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/tokenview/TokenView.java b/ooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/tokenview/TokenView.java
new file mode 100755
index 000000000000..961524f382b0
--- /dev/null
+++ b/ooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/tokenview/TokenView.java
@@ -0,0 +1,406 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.viewer.tokenview;
+
+import java.awt.Color;
+import java.awt.Container;
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.Point;
+import java.awt.RenderingHints;
+import java.awt.event.ComponentEvent;
+import java.awt.event.ComponentListener;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseMotionListener;
+import java.util.Iterator;
+import java.util.Vector;
+
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.UIManager;
+
+/** A simple view of tokenized content.
+ *
+ * Create the content by calling GetDocumentFactory() and using the returned
+ * factory to add tokenized text.
+ */
+@SuppressWarnings("serial")
+public class TokenView<TokenType>
+ extends JPanel
+ implements MouseMotionListener, DocumentFactory.IRepaintTarget, ComponentListener
+{
+ public TokenView ()
+ {
+ maLines = new LineContainer<TokenType>();
+ maFormatter = new Formatter<TokenType>();
+
+ addMouseMotionListener(this);
+ addComponentListener(this);
+ }
+
+
+
+
+ @Override
+ public void paintComponent (final Graphics aGraphics)
+ {
+ super.paintComponent(aGraphics);
+
+ final Graphics2D aG2 = (Graphics2D)aGraphics;
+ aG2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_DEFAULT);
+
+ final FormatState<TokenType> aState;
+ synchronized(maLines)
+ {
+ aState = maFormatter.FormatText(aG2, maLines);
+ }
+ setPreferredSize(aState.GetTextBoundingSize());
+
+ for (final Line<TokenType> aLine : aState)
+ {
+ PaintLineHighlight(aG2, aLine);
+ PaintLineNumber(aG2, aLine);
+
+ int nX = mnTextStart;
+ for (final Run<TokenType> aRun : aLine)
+ {
+ final Color aRunColor;
+ if (aRun == maRunUnderMouse)
+ aRunColor = maRunUnderMouseColor;
+ else if (aRun == maHighlightedErrorRun)
+ aRunColor = maErrorHighlightColor;
+ else
+ aRunColor = null;
+ aRun.Paint(
+ (Graphics2D)aGraphics,
+ nX,
+ aLine.GetBottom(),
+ aRunColor);
+
+ nX += aRun.GetWidth();
+ }
+ }
+
+ aGraphics.setColor(maSeparatorColor);
+
+ final int nTop = aGraphics.getClipBounds().y;
+ final int nBottom = aGraphics.getClipBounds().y+aGraphics.getClipBounds().height;
+ aGraphics.drawLine(
+ mnBarPosition0,
+ nTop,
+ mnBarPosition0,
+ nBottom);
+ aGraphics.drawLine(
+ mnBarPosition1,
+ nTop,
+ mnBarPosition1,
+ nBottom);
+ }
+
+
+
+
+ /** Paint a line with a highlight.
+ * There are different kinds of highlight:
+ * - the current line
+ * - one of three groups of enclosing parent elements
+ */
+ private void PaintLineHighlight (
+ final Graphics2D aG2,
+ final Line<TokenType> aLine)
+ {
+ final Color aBackgroundColor;
+ if (aLine == maHighlightedLine)
+ aBackgroundColor = maHighlightColor;
+ else
+ aBackgroundColor = maBackgroundColor;
+
+ final Color aBarColor;
+ if (maLines.IsLineInGroup(aLine, maHighlightedGroup0))
+ aBarColor = maGroupHighlightColor0;
+ else if (maLines.IsLineInGroup(aLine, maHighlightedGroup1))
+ aBarColor = maGroupHighlightColor1;
+ else if (maLines.IsLineInGroup(aLine, maHighlightedGroup2))
+ aBarColor = maGroupHighlightColor2;
+ else
+ aBarColor = maBackgroundColor;
+
+ aG2.setColor(aBarColor);
+ aG2.fillRect(
+ 0,
+ aLine.GetTop(),
+ mnLeftBarWidth,
+ aLine.GetHeight());
+
+ aG2.setColor(aBackgroundColor);
+ aG2.fillRect(
+ mnLeftBarWidth,
+ aLine.GetTop(),
+ getWidth() - mnLeftBarWidth,
+ aLine.GetHeight());
+ }
+
+
+
+
+ private void PaintLineNumber (
+ final Graphics2D aG2,
+ final Line<TokenType> aLine)
+ {
+ final String sNumber = Integer.toString(aLine.GetStartOffset());
+ final FontMetrics aMetrics = aG2.getFontMetrics();
+ final int nWidth = aMetrics.stringWidth(sNumber);
+ final int nHeight = aMetrics.getHeight();
+
+ aG2.setColor(maLineNumberColor);
+ aG2.setFont(maLineNumberFont);
+ aG2.drawString(
+ sNumber,
+ mnBarPosition0+1 + mnNumberBarWidth-nWidth,
+ aLine.GetBottom() - (aLine.GetHeight()-nHeight)/2 - aMetrics.getDescent());
+ }
+
+
+
+
+ @Override
+ public void mouseDragged (final MouseEvent aEvent)
+ {
+ }
+
+
+
+
+ @Override
+ public void mouseMoved (final MouseEvent aEvent)
+ {
+ final Line<TokenType> aLine = maLines.GetLineForY(aEvent.getY());
+ if (aLine != null)
+ {
+ UpdateHighlightedLine(aLine);
+ final Run<TokenType> aRun = aLine.GetRunForX(aEvent.getX() - mnTextStart);
+ SetRunUnderMouse(aRun);
+ }
+ }
+
+
+
+
+ private void UpdateHighlightedLine (final Line<TokenType> aLine)
+ {
+ HighlightLine(aLine);
+
+ final Iterator<Run<TokenType>> aRunIterator = aLine.iterator();
+ if (aRunIterator.hasNext())
+ {
+ final Run<TokenType> aRun = aRunIterator.next();
+ if (aRun.IsGroup())
+ HighlightGroup(aRun);
+ else
+ HighlightGroup(aRun.GetParent());
+ }
+ }
+
+
+
+
+ @Override
+ public void RequestRepaint()
+ {
+ repaint();
+ }
+
+
+
+
+ public DocumentFactory<TokenType> GetDocumentFactory()
+ {
+ return new DocumentFactory<TokenType>(maLines, this);
+ }
+
+
+
+
+ private void HighlightLine (final Line<TokenType> aLine)
+ {
+ if (aLine != maHighlightedLine)
+ {
+ maHighlightedLine = aLine;
+ repaint();
+ }
+ }
+
+
+
+
+ private void HighlightGroup (final Run<TokenType> aRun)
+ {
+ if (maHighlightedGroup0 != aRun)
+ {
+ maHighlightedGroup0 = aRun;
+
+ if (aRun != null)
+ {
+ final Run<TokenType> aGroup1 = aRun.GetParent();
+ maHighlightedGroup1 = aGroup1;
+
+ if (aGroup1 != null)
+ {
+ final Run<TokenType> aGroup2 = aGroup1.GetParent();
+ maHighlightedGroup2 = aGroup2;
+ }
+ }
+ repaint();
+ }
+ }
+
+
+
+
+ @Override
+ public void componentHidden(ComponentEvent e)
+ {
+ }
+
+
+
+
+ @Override
+ public void componentMoved (final ComponentEvent aEvent)
+ {
+ final Point aPoint = getMousePosition();
+ if (aPoint != null)
+ UpdateHighlightedLine(maLines.GetLineForY(aPoint.y));
+ }
+
+
+
+
+ @Override
+ public void componentResized(ComponentEvent e)
+ {
+ }
+
+
+
+
+ @Override
+ public void componentShown(ComponentEvent e)
+ {
+ }
+
+
+
+
+ public Run<TokenType> GetRun (final int nOffset)
+ {
+ final Line<TokenType> aLine = maLines.GetLineForOffset(nOffset);
+ if (aLine != null)
+ return aLine.GetRunForOffset(nOffset);
+ else
+ return null;
+ }
+
+
+
+
+ /** Return all runs that completely or partially lie in the range from
+ * start offset (including) and end offset (excluding).
+ */
+ public RunRange<TokenType> GetRuns (final int nStartOffset, final int nEndOffset)
+ {
+ final Vector<Run<TokenType>> aRuns = new Vector<>();
+
+ for (final Line<TokenType> aLine : maLines.GetLinesForOffsets(nStartOffset, nEndOffset))
+ for (final Run<TokenType> aRun : aLine.GetRunsForOffsets(nStartOffset, nEndOffset))
+ aRuns.add(aRun);
+
+ return new RunRange<TokenType>(aRuns);
+ }
+
+
+
+
+ public void MarkError (final Run<TokenType> aRun)
+ {
+ maHighlightedErrorRun = aRun;
+ repaint();
+ }
+
+
+
+
+ public void ShowRun (final Run<TokenType> aRun)
+ {
+ final Container aComponent = getParent().getParent();
+ if (aComponent instanceof JScrollPane)
+ ((JScrollPane)aComponent).getVerticalScrollBar().setValue(
+ aRun.GetLine().GetTop());
+ }
+
+
+
+
+ private void SetRunUnderMouse (final Run<TokenType> aRun)
+ {
+ if (maRunUnderMouse != aRun)
+ {
+ maRunUnderMouse = aRun;
+ if (maRunUnderMouse != null)
+ setToolTipText(maRunUnderMouse.GetToolTipText());
+ else
+ setToolTipText(null);
+ repaint();
+ }
+ }
+
+
+
+
+ private final LineContainer<TokenType> maLines;
+ private final Formatter<TokenType> maFormatter;
+ private Line<TokenType> maHighlightedLine;
+ private Run<TokenType> maHighlightedGroup0;
+ private Run<TokenType> maHighlightedGroup1;
+ private Run<TokenType> maHighlightedGroup2;
+ private Run<TokenType> maHighlightedErrorRun;
+ private Run<TokenType> maRunUnderMouse;
+
+ private final static int mnLeftBarWidth = 10;
+ private final static int mnNumberBarWidth = 30;
+ private final static int mnBarPosition0 = mnLeftBarWidth;
+ private final static int mnBarPosition1 = mnBarPosition0 + mnNumberBarWidth ;
+ private final static int mnTextStart = mnBarPosition1 + 2;
+ private final static Color maSeparatorColor = Color.GRAY;
+ private final static Color maBackgroundColor = Color.WHITE;
+ private final static Color maHighlightColor = new Color(0xB0E0E6); // Powder Blue
+ private final static Color maGroupHighlightColor0 = new Color(0x32CD32); // Lime Green
+ private final static Color maGroupHighlightColor1 = new Color(0x90EE90); // Light Green
+ private final static Color maGroupHighlightColor2 = new Color(0xbbFfbb);
+ private final static Color maErrorHighlightColor = new Color(0xff3020);
+ private final static Color maLineNumberColor = new Color(0x808080);
+ private final static Color maRunUnderMouseColor = maGroupHighlightColor2;
+ private final static Font maLineNumberFont = UIManager.getDefaults().getFont("TextField.font").deriveFont(9.0f);
+
+}
diff --git a/ooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/xml/DocumentTokenFormatter.java b/ooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/xml/DocumentTokenFormatter.java
new file mode 100755
index 000000000000..e01f78afcac0
--- /dev/null
+++ b/ooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/xml/DocumentTokenFormatter.java
@@ -0,0 +1,399 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.viewer.xml;
+
+import java.awt.Color;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.openoffice.ooxml.viewer.tokenview.DocumentFactory;
+import org.apache.openoffice.ooxml.viewer.tokenview.Style;
+import org.apache.openoffice.ooxml.viewer.tokenview.TokenView;
+
+public class DocumentTokenFormatter
+{
+ DocumentTokenFormatter (
+ final XMLScanner aScanner,
+ final TokenView<TokenType> aView)
+ {
+ maScanner = aScanner;
+ maView = aView.GetDocumentFactory();
+
+ maTagStartEndStyle = new Style().SetForegroundColor(new Color(0x87CEFA)); // Light Sky Blue
+ maNamespaceNameStyle = new Style().SetForegroundColor(new Color(0x7B68EE)); // Medium Slate Blue
+ maIdentifierStyle = new Style()
+ .SetForegroundColor(new Color(0x7B68EE)) // Medium Slate Blue
+ .SetBold();
+ maTextStyle = new Style().SetForegroundColor(new Color(0xF08080)); // Light Coral
+ maAttributeValueStyle = new Style().SetForegroundColor(new Color(0xFFA07A)); // Light Salmon
+
+ msIndentation = "";
+
+ maNamespaceMap = new HashMap<String,String>();
+ }
+
+
+
+
+ public void Parse ()
+ {
+ try
+ {
+ ParseIntro();
+ AppendText("\n", TokenType.WHITESPACE, null, -1);
+ while (true)
+ {
+ switch (maScanner.Peek().Type)
+ {
+ case EOF:
+ return;
+
+ case TAG_START:
+ case END_TAG_START:
+ ParseTag();
+ AppendText("\n", TokenType.WHITESPACE, null, -1);
+ break;
+
+ default:
+ ParseText();
+ }
+ }
+ }
+ catch(final Exception aException)
+ {
+ aException.printStackTrace();
+ }
+ maView.FinishText();
+ }
+
+
+
+
+ Map<String,String> GetNamespaceMap ()
+ {
+ return maNamespaceMap;
+ }
+
+
+
+
+ private void ParseIntro ()
+ {
+ final Token aStartToken = maScanner.Next();
+ ExpectToken(aStartToken, TokenType.INTRO_START);
+ ShowToken(aStartToken);
+
+ ParseTagContent();
+
+ final Token aEndToken = maScanner.Next();
+ ExpectToken(aEndToken, TokenType.INTRO_END);
+ ShowToken(aEndToken);
+ }
+
+
+
+
+ private void ParseTag ()
+ {
+ final Token aStartToken = maScanner.Next();
+ ExpectToken(aStartToken, TokenType.TAG_START, TokenType.END_TAG_START);
+ if (aStartToken.Type == TokenType.TAG_START)
+ maView.BeginGroup();
+ if (aStartToken.Type == TokenType.END_TAG_START)
+ DecreaseIndentation();
+ ShowToken(aStartToken);
+
+ ParseTagContent();
+
+ final Token aEndToken = maScanner.Next();
+ if (aStartToken.Type == TokenType.TAG_START)
+ ExpectToken(aEndToken, TokenType.TAG_END, TokenType.ELEMENT_END);
+ else
+ ExpectToken(aEndToken, TokenType.TAG_END);
+ ShowToken(aEndToken);
+
+ if (aStartToken.Type != TokenType.END_TAG_START
+ && aEndToken.Type != TokenType.ELEMENT_END)
+ {
+ IncreaseIndentation();
+ }
+ else
+ {
+ maView.EndGroup();
+ }
+ }
+
+
+
+
+ private void ParseTagContent ()
+ {
+ ParseQualifiedName();
+
+ if (maScanner.Peek().Type != TokenType.IDENTIFIER)
+ return;
+
+ IncreaseIndentation();
+ while (true)
+ {
+ final Token aToken = maScanner.Peek();
+ if (aToken.Type != TokenType.IDENTIFIER)
+ break;
+
+ if (mbStartNewLineBeforeEachAttribute
+ || mbStartNewLineBeforeNamespaceDefinition && aToken.Text.startsWith("xmlns"))
+ {
+ AppendText("\n", TokenType.WHITESPACE, null, -1);
+ AppendText(" ", TokenType.WHITESPACE, null, -1);
+ }
+ else
+ {
+ AppendText(" ", TokenType.WHITESPACE, null, -1);
+ }
+
+ ParseQualifiedName();
+ final Token aAssignToken = maScanner.Next();
+ ExpectToken(aAssignToken, TokenType.ATTRIBUTE_DEFINE);
+ ShowToken(aAssignToken);
+
+ final Token aValueToken = maScanner.Next();
+ ExpectToken(aValueToken, TokenType.ATTRIBUTE_VALUE);
+ ShowToken(aValueToken, maAttributeValueStyle);
+
+ if (msLastNamespaceName.equals("xmlns"))
+ SaveNamespaceDefinition(msLastName, StripValueQuotes(aValueToken.Text));
+ }
+ DecreaseIndentation();
+ }
+
+
+
+
+ private void ParseQualifiedName ()
+ {
+ final Token aNameToken = maScanner.Next();
+ ExpectToken(aNameToken, TokenType.IDENTIFIER);
+ if (maScanner.Peek().Type == TokenType.COLON)
+ {
+ final Token aSeparatorToken = maScanner.Next();
+ final Token aSecondNameToken = maScanner.Next();
+ ExpectToken(aSecondNameToken, TokenType.IDENTIFIER);
+ ShowToken(aNameToken, maNamespaceNameStyle);
+ ShowToken(aSeparatorToken);
+ ShowToken(aSecondNameToken, maIdentifierStyle);
+
+ msLastNamespaceName = aNameToken.Text;
+ msLastName = aSecondNameToken.Text;
+ }
+ else
+ {
+ ShowToken(aNameToken, maIdentifierStyle);
+
+ msLastNamespaceName = "";
+ msLastName = aNameToken.Text;
+ }
+ }
+
+
+
+
+ private void ParseText ()
+ {
+ final Token aTextToken = maScanner.Next();
+ ExpectToken(aTextToken, TokenType.TEXT);
+ ShowToken(aTextToken, maTextStyle);
+ AppendText("\n", TokenType.WHITESPACE, null, -1);
+ }
+
+
+
+
+ private TokenType ExpectToken (final Token aToken, final TokenType ... aExcpectedTypes)
+ {
+ for (final TokenType eType : aExcpectedTypes)
+ if (aToken.Type == eType)
+ return eType;
+
+ if (aExcpectedTypes.length == 1)
+ {
+ throw new RuntimeException(
+ String.format(
+ "expected '%s' but got %s",
+ aExcpectedTypes[0].toString(),
+ aToken.toString()));
+ }
+ else
+ {
+ String sList = null;
+ for (final TokenType eType : aExcpectedTypes)
+ {
+ if (sList != null)
+ sList += String.format(", '%s'", eType.toString());
+ else
+ sList = String.format("'%s'", eType.toString());
+ }
+ throw new RuntimeException(
+ String.format(
+ "expected one of %s but got %s",
+ sList,
+ aToken.toString()));
+ }
+ }
+
+
+
+
+ private void ShowToken (final Token aToken)
+ {
+ AppendText(aToken.Text, aToken.Type, GetStyle(aToken.Type), aToken.Offset);
+ }
+
+
+
+
+ private void ShowToken (
+ final Token aToken,
+ final Style aStyle)
+ {
+ AppendText(aToken.Text, aToken.Type, aStyle, aToken.Offset);
+ }
+
+
+
+
+ private void AppendText (
+ final String sText,
+ final TokenType eTokenType,
+ final Style aStyle,
+ final int nOffset)
+ {
+ try
+ {
+ if (mbIsAtBeginningOfLine)
+ {
+ AddText(msIndentation, TokenType.WHITESPACE, aStyle, -1);
+ mbIsAtBeginningOfLine = false;
+ }
+ AddText(sText, eTokenType, aStyle, nOffset);
+ mbIsAtBeginningOfLine = sText.endsWith("\n");
+ }
+ catch (RuntimeException e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+
+
+
+ private void AddText (
+ final String sText,
+ final TokenType eTokenType,
+ final Style aStyle,
+ final int nOffset)
+ {
+ maView.AddText(sText, eTokenType, aStyle, nOffset);
+ }
+
+
+
+
+ private void IncreaseIndentation ()
+ {
+ msIndentation += " ";
+ }
+
+
+
+
+ private void DecreaseIndentation ()
+ {
+ if ( ! msIndentation.isEmpty())
+ msIndentation = msIndentation.substring(4);
+ }
+
+
+
+
+ private Style GetStyle (final TokenType eType)
+ {
+ switch(eType)
+ {
+ case TAG_START:
+ case TAG_END:
+ case END_TAG_START:
+ case INTRO_START:
+ case INTRO_END:
+ case ELEMENT_END:
+ return maTagStartEndStyle;
+
+ case IDENTIFIER:
+ return maIdentifierStyle;
+
+ case TEXT:
+ return maTextStyle;
+
+ case ATTRIBUTE_VALUE:
+ return maAttributeValueStyle;
+
+ default:
+ return null;
+ }
+ }
+
+
+
+
+ private String StripValueQuotes (final String sQuotedValue)
+ {
+ final String sValue = sQuotedValue.substring(1, sQuotedValue.length()-1);
+ return sValue;
+ }
+
+
+
+
+ private void SaveNamespaceDefinition (final String sShortName, final String sLongName)
+ {
+ maNamespaceMap.put(sShortName, sLongName);
+ }
+
+
+
+
+ private final XMLScanner maScanner;
+ private final DocumentFactory<TokenType> maView;
+ private final Style maTagStartEndStyle;
+ private final Style maNamespaceNameStyle;
+ private final Style maIdentifierStyle;
+ private final Style maTextStyle;
+ private final Style maAttributeValueStyle;
+ private String msIndentation;
+ private boolean mbIsAtBeginningOfLine;
+
+ private String msLastNamespaceName;
+ private String msLastName;
+ private Map<String,String> maNamespaceMap;
+
+ private final boolean mbStartNewLineBeforeEachAttribute = false;
+ private final boolean mbStartNewLineBeforeNamespaceDefinition = true;
+}
diff --git a/ooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/xml/Token.java b/ooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/xml/Token.java
new file mode 100755
index 000000000000..6919e8d0957b
--- /dev/null
+++ b/ooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/xml/Token.java
@@ -0,0 +1,51 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.viewer.xml;
+
+public class Token
+{
+ Token (
+ final TokenType eType,
+ final String sText,
+ final int nOffset)
+ {
+ Type = eType;
+ Text = sText;
+ Offset = nOffset;
+ }
+
+
+
+
+ @Override
+ public String toString ()
+ {
+ return String.format("%s(%s)", Type.toString(), Text);
+ }
+
+
+
+
+ public final TokenType Type;
+ public final String Text;
+ public final int Offset;
+}
diff --git a/ooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/xml/TokenType.java b/ooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/xml/TokenType.java
new file mode 100755
index 000000000000..ea2c82277dde
--- /dev/null
+++ b/ooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/xml/TokenType.java
@@ -0,0 +1,41 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.viewer.xml;
+
+public enum TokenType
+{
+ TAG_START,
+ TAG_END,
+ END_TAG_START,
+ INTRO_START,
+ INTRO_END,
+ IDENTIFIER,
+ ELEMENT_END,
+ ATTRIBUTE_DEFINE,
+ ATTRIBUTE_VALUE,
+ COLON,
+ COMMENT_START,
+ COMMENT_END,
+ TEXT,
+ WHITESPACE,
+ EOF
+}
diff --git a/ooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/xml/XMLScanner.java b/ooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/xml/XMLScanner.java
new file mode 100755
index 000000000000..7e83c2258492
--- /dev/null
+++ b/ooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/xml/XMLScanner.java
@@ -0,0 +1,438 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.viewer.xml;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.io.UnsupportedEncodingException;
+import java.util.Arrays;
+import java.util.Vector;
+
+public class XMLScanner
+{
+ XMLScanner (final InputStream aIn)
+ {
+ Reader aReader = null;
+ try
+ {
+ aReader = new InputStreamReader(aIn, "UTF8");
+ }
+ catch (UnsupportedEncodingException e)
+ {
+ e.printStackTrace();
+ }
+ maIn = aReader;
+ mnNextCharacter = 0;
+ maTokens = new Vector<Token>();
+ mnTokensReadIndex = 0;
+ mbIsInsideTag = false;
+ maTextBuffer = new int[1024];
+ }
+
+
+
+
+ public Token Next ()
+ {
+ while (maTokens.isEmpty())
+ ProvideToken();
+
+ final Token aToken = maTokens.get(mnTokensReadIndex);
+ ++mnTokensReadIndex;
+ if (mnTokensReadIndex >= maTokens.size())
+ {
+ maTokens.clear();
+ mnTokensReadIndex = 0;
+ }
+ return aToken;
+ }
+
+
+
+
+ public Token Peek()
+ {
+ while (maTokens.isEmpty())
+ ProvideToken();
+
+ return maTokens.get(mnTokensReadIndex);
+ }
+
+
+
+
+ private void ProvideToken ()
+ {
+ final int nC = PeekCharacter();
+ if (nC == -1)
+ {
+ AddToken(TokenType.EOF, "", mnOffset);
+ }
+ else if (mbIsInsideTag)
+ {
+ switch (Character.getType(nC))
+ {
+ case Character.DIRECTIONALITY_WHITESPACE:
+ case Character.DIRECTIONALITY_LEFT_TO_RIGHT_OVERRIDE:
+ ScanWhitespace();
+ break;
+
+ default:
+ switch(nC)
+ {
+ case '?':
+ case '/':
+ case '>':
+ case '=':
+ case ':':
+ case '-':
+ switch(ScanSymbol())
+ {
+ case TAG_END:
+ case INTRO_END:
+ case ELEMENT_END:
+ mbIsInsideTag = false;
+ break;
+ default:
+ break;
+ }
+ break;
+
+ case '"':
+ ScanQuotedValue();
+ break;
+
+ default:
+ ScanIdentifier();
+ break;
+ }
+ }
+ }
+ else
+ {
+ switch (Character.getType(PeekCharacter()))
+ {
+ case Character.DIRECTIONALITY_WHITESPACE:
+ case Character.DIRECTIONALITY_LEFT_TO_RIGHT_OVERRIDE:
+ ScanWhitespace();
+ break;
+
+ default:
+ if (nC == '<')
+ {
+ mbIsInsideTag = true;
+ ScanSymbol();
+ }
+ else
+ {
+ ScanText();
+ }
+ break;
+ }
+ }
+ }
+
+
+
+
+ Token NextNonWhitespaceToken ()
+ {
+ while(true)
+ {
+ final Token aToken = Next();
+ if (aToken.Type != TokenType.WHITESPACE)
+ return aToken;
+ }
+ }
+
+
+
+
+ private TokenType ScanSymbol ()
+ {
+ final int nStartOffset = mnOffset;
+
+ switch (PeekCharacter())
+ {
+ case -1:
+ AddToken(TokenType.EOF, "", nStartOffset);
+ return TokenType.EOF;
+
+ case '<':
+ GetNextCharacter();
+ switch(PeekCharacter())
+ {
+ case '/':
+ GetNextCharacter();
+ AddToken(TokenType.END_TAG_START, "</", nStartOffset);
+ break;
+
+ case '?':
+ GetNextCharacter();
+ AddToken(TokenType.INTRO_START, "<?", nStartOffset);
+ break;
+
+ case '!':
+ GetNextCharacter();
+ if (GetNextCharacter() != '-')
+ throw new RuntimeException("expected '-' after '<!'");
+ if (GetNextCharacter() != '-')
+ throw new RuntimeException("expected '-' after '<!-'");
+ AddToken(TokenType.COMMENT_START, "<!--", nStartOffset);
+ break;
+
+ default:
+ AddToken(TokenType.TAG_START, "<", nStartOffset);
+ break;
+ }
+ return maTokens.lastElement().Type;
+
+ case '>':
+ GetNextCharacter();
+ AddToken(TokenType.TAG_END, ">", nStartOffset);
+ return TokenType.TAG_END;
+
+ case '/':
+ GetNextCharacter();
+ if (GetNextCharacter() != '>')
+ throw new RuntimeException("expected '>' after '/'");
+ AddToken(TokenType.ELEMENT_END, "/>", nStartOffset);
+ return TokenType.ELEMENT_END;
+
+ case '?':
+ GetNextCharacter();
+ if (GetNextCharacter() != '>')
+ throw new RuntimeException("expected '>' after '?'");
+ AddToken(TokenType.INTRO_END, "?>", nStartOffset);
+ return TokenType.INTRO_END;
+
+ case '-':
+ GetNextCharacter();
+ if (GetNextCharacter() != '-')
+ throw new RuntimeException("expected '-' after '-'");
+ if (GetNextCharacter() != '>')
+ throw new RuntimeException("expected '>' after '--'");
+ AddToken(TokenType.COMMENT_END, "-->", nStartOffset);
+ return TokenType.COMMENT_END;
+
+ case '=':
+ GetNextCharacter();
+ AddToken(TokenType.ATTRIBUTE_DEFINE, "=", nStartOffset);
+ return TokenType.ATTRIBUTE_DEFINE;
+
+ case ':':
+ GetNextCharacter();
+ AddToken(TokenType.COLON, ":", nStartOffset);
+ return TokenType.COLON;
+
+ default:
+ throw new RuntimeException(String.format(
+ "unexpected character '%c' of type %d",
+ PeekCharacter(),
+ Character.getType(PeekCharacter())));
+ }
+ }
+
+
+
+
+ private boolean ScanIdentifier ()
+ {
+ final int nStartOffset = mnOffset;
+ int nBufferWriteIndex = 0;
+
+ while (true)
+ {
+ switch(Character.getType(PeekCharacter()))
+ {
+ default:
+ case -1:
+ if (nBufferWriteIndex == 0)
+ throw new RuntimeException(
+ String.format(
+ "missing identifier, got '%c' of type %d",
+ PeekCharacter(),
+ Character.getType(PeekCharacter())));
+ AddToken(
+ TokenType.IDENTIFIER,
+ new String(maTextBuffer, 0, nBufferWriteIndex),
+ nStartOffset);
+ return true;
+
+ case Character.LOWERCASE_LETTER:
+ case Character.UPPERCASE_LETTER:
+ case Character.DECIMAL_DIGIT_NUMBER:
+ if (nBufferWriteIndex >= maTextBuffer.length)
+ maTextBuffer = Arrays.copyOf(maTextBuffer, maTextBuffer.length*2);
+ maTextBuffer[nBufferWriteIndex] = GetNextCharacter();
+ ++nBufferWriteIndex;
+ break;
+ }
+ }
+ }
+
+
+
+
+ private void ScanWhitespace ()
+ {
+ final StringBuffer aBuffer = new StringBuffer();
+ final int nStartOffset = mnOffset;
+
+ while (true)
+ {
+ switch(Character.getType(PeekCharacter()))
+ {
+ default:
+ if (aBuffer.length() > 0)
+ AddToken(TokenType.WHITESPACE, aBuffer.toString(), nStartOffset);
+ return;
+
+ case -1:
+ AddToken(TokenType.WHITESPACE, aBuffer.toString(), nStartOffset);
+ AddToken(TokenType.EOF, "", nStartOffset);
+ return;
+
+ case Character.DIRECTIONALITY_WHITESPACE:
+ case Character.DIRECTIONALITY_LEFT_TO_RIGHT_OVERRIDE:
+ aBuffer.append((char)GetNextCharacter());
+ break;
+ }
+ }
+ }
+
+
+
+
+ private void ScanQuotedValue ()
+ {
+ if (PeekCharacter() == '"')
+ {
+ final int nStartOffset = mnOffset;
+ int nBufferWriteIndex = 0;
+ maTextBuffer[nBufferWriteIndex++] = GetNextCharacter();
+
+ while (PeekCharacter() != '"')
+ {
+ // Make sure that there is enough space for this character and the end quote.
+ if (nBufferWriteIndex >= maTextBuffer.length-1)
+ maTextBuffer = Arrays.copyOf(maTextBuffer, maTextBuffer.length*2);
+ maTextBuffer[nBufferWriteIndex++] = GetNextCharacter();
+ }
+
+ maTextBuffer[nBufferWriteIndex++] = GetNextCharacter();
+
+ AddToken(TokenType.ATTRIBUTE_VALUE, new String(maTextBuffer, 0, nBufferWriteIndex), nStartOffset);
+ }
+ }
+
+
+
+
+ private void ScanText ()
+ {
+ final int nStartOffset = mnOffset;
+ int nBufferWriteIndex = 0;
+ maTextBuffer[nBufferWriteIndex++] = GetNextCharacter();
+
+ while (PeekCharacter() != '<')
+ {
+ if (nBufferWriteIndex >= maTextBuffer.length)
+ maTextBuffer = Arrays.copyOf(maTextBuffer, maTextBuffer.length*2);
+ maTextBuffer[nBufferWriteIndex++] = GetNextCharacter();
+ }
+
+ AddToken(TokenType.TEXT, new String(maTextBuffer, 0, nBufferWriteIndex), nStartOffset);
+ }
+
+
+
+
+ private int GetNextCharacter ()
+ {
+ final int nC;
+ if (mnNextCharacter != 0)
+ {
+ nC = mnNextCharacter;
+ mnNextCharacter = 0;
+ }
+ else
+ {
+ try
+ {
+ nC = maIn.read();
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ return -1;
+ }
+ }
+ ++mnOffset;
+ return nC;
+ }
+
+
+
+
+ private int PeekCharacter ()
+ {
+ if (mnNextCharacter == 0)
+ {
+ try
+ {
+ mnNextCharacter = maIn.read();
+ }
+ catch (IOException e)
+ {
+ e.printStackTrace();
+ mnNextCharacter = -1;
+ }
+ }
+ return mnNextCharacter;
+ }
+
+
+
+
+ private void AddToken (
+ final TokenType eType,
+ final String sText,
+ final int nOffset)
+ {
+ if (eType != TokenType.WHITESPACE)
+ maTokens.add(new Token(eType, sText, nOffset));
+ }
+
+
+
+
+ private final Reader maIn;
+ private int mnNextCharacter;
+ private Vector<Token> maTokens;
+ private int mnTokensReadIndex;
+ private boolean mbIsInsideTag;
+ private int[] maTextBuffer;
+ private int mnOffset;
+}
diff --git a/ooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/xml/XMLTokenViewFactory.java b/ooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/xml/XMLTokenViewFactory.java
new file mode 100755
index 000000000000..cfa6d8478e58
--- /dev/null
+++ b/ooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/xml/XMLTokenViewFactory.java
@@ -0,0 +1,106 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.viewer.xml;
+
+import java.io.InputStream;
+
+import org.apache.openoffice.ooxml.viewer.KeyListener;
+import org.apache.openoffice.ooxml.viewer.tokenview.TokenView;
+
+public class XMLTokenViewFactory
+ extends Thread
+{
+ public XMLTokenViewFactory ()
+ {
+ maIn = null;
+ start();
+ }
+
+
+
+
+ public TokenView<TokenType> Create (final InputStream aIn)
+ {
+ TokenView<TokenType> aView = null;
+ synchronized(this)
+ {
+ maIn = aIn;
+ if (maIn != null)
+ {
+ aView = new TokenView<TokenType>();
+ aView.addKeyListener(new KeyListener());
+ maCurrentView = aView;
+
+ FillDocument();
+ //notify();
+ }
+ }
+
+ return aView;
+ }
+
+
+
+
+ @Override
+ public void run ()
+ {
+ while(true)
+ {
+ FillDocument();
+
+ synchronized(this)
+ {
+ if (maIn == null)
+ {
+ try
+ {
+ wait();
+ }
+ catch (InterruptedException e)
+ {
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+ }
+
+
+
+
+ private void FillDocument ()
+ {
+ final InputStream aIn = maIn;
+ maIn = null;
+ if (aIn != null)
+ {
+ new DocumentTokenFormatter(new XMLScanner(aIn), maCurrentView).Parse();
+ }
+ }
+
+
+
+
+ private InputStream maIn;
+ private TokenView<TokenType> maCurrentView;
+}
diff --git a/ooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/xmltokenview/XMLViewFactory.java b/ooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/xmltokenview/XMLViewFactory.java
new file mode 100755
index 000000000000..3ca361b2ad0e
--- /dev/null
+++ b/ooxml/source/framework/OOXMLViewer/src/org/apache/openoffice/ooxml/viewer/xmltokenview/XMLViewFactory.java
@@ -0,0 +1,143 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.viewer.xmltokenview;
+
+import java.util.Vector;
+
+import javax.xml.stream.Location;
+
+import org.apache.openoffice.ooxml.parser.ElementContext;
+import org.apache.openoffice.ooxml.parser.ParseException;
+import org.apache.openoffice.ooxml.parser.Parser;
+import org.apache.openoffice.ooxml.parser.action.ActionTrigger;
+import org.apache.openoffice.ooxml.parser.action.IAction;
+import org.apache.openoffice.ooxml.viewer.tokenview.Run;
+import org.apache.openoffice.ooxml.viewer.tokenview.RunRange;
+import org.apache.openoffice.ooxml.viewer.tokenview.TokenView;
+import org.apache.openoffice.ooxml.viewer.xml.TokenType;
+
+public class XMLViewFactory
+{
+ public static void AddSemanticInformation(
+ final TokenView<TokenType> aView,
+ final Parser aParser,
+ final Vector<String> aErrorsAndWarnings)
+ {
+ aParser.GetActionManager().AddElementStartAction(
+ "*",
+ new IAction()
+ {
+ public void Run (
+ final ActionTrigger eTrigger,
+ final ElementContext aContext,
+ final String sText,
+ final Location aStartLocation,
+ final Location aEndLocation)
+ {
+ final RunRange<TokenType> aRuns = aView.GetRuns(
+ aStartLocation.getCharacterOffset(),
+ aEndLocation.getCharacterOffset());
+ if (aRuns.IsEmpty())
+ aView.GetRuns(
+ aStartLocation.getCharacterOffset(),
+ aEndLocation.getCharacterOffset());
+
+ // Search for the name (including namespace prefix) of the element.
+ int nIndex = aRuns.FindTokens(
+ TokenType.TAG_START,
+ TokenType.IDENTIFIER,
+ TokenType.COLON,
+ TokenType.IDENTIFIER);
+ if (nIndex < 0)
+ return;
+
+ aRuns.Get(nIndex+1).SetToolTipText(aContext.GetTypeName());
+ aRuns.Get(nIndex+2).SetToolTipText(aContext.GetTypeName());
+ aRuns.Get(nIndex+3).SetToolTipText(aContext.GetTypeName());
+ nIndex += 4;
+
+ // Process the attributes.
+ while (true)
+ {
+ final int nStartIndex = nIndex;
+ nIndex = aRuns.FindTokens(
+ nStartIndex,
+ TokenType.IDENTIFIER,
+ TokenType.COLON,
+ TokenType.IDENTIFIER,
+ TokenType.ATTRIBUTE_DEFINE);
+ if (nIndex >= 0)
+ {
+ final String sAttributeName = aRuns.Get(nIndex+2).GetText();
+ aRuns.Get(nIndex+0).SetToolTipText("attribute define of "+sAttributeName);
+ aRuns.Get(nIndex+1).SetToolTipText("attribute define of "+sAttributeName);
+ aRuns.Get(nIndex+2).SetToolTipText("attribute define of "+sAttributeName);
+ nIndex += 5;
+ }
+ else
+ {
+ // Try the variant without namespace.
+ nIndex = aRuns.FindTokens(
+ nStartIndex,
+ TokenType.IDENTIFIER,
+ TokenType.ATTRIBUTE_DEFINE);
+ if (nIndex >= 0)
+ {
+ final String sAttributeName = aRuns.Get(nIndex).GetText();
+ aRuns.Get(nIndex).SetToolTipText("attribute define of "+sAttributeName);
+ nIndex += 3;
+ }
+ else
+ {
+ // No more attributes.
+ break;
+ }
+ }
+ }
+ }
+ });
+ try
+ {
+ aParser.Parse();
+ }
+ catch (final ParseException aException)
+ {
+ System.err.printf("caught exception when parsing %d,%d/%d\n",
+ aException.Location.getLineNumber(),
+ aException.Location.getColumnNumber(),
+ aException.Location.getCharacterOffset());
+
+ final Run<TokenType> aRun = aView.GetRun(aException.Location.getCharacterOffset());
+ if (aRun != null)
+ {
+ aView.MarkError(aRun);
+ aRun.SetToolTipText(
+ String.format(
+ "parse error at %d,%d/%d\n",
+ aException.Location.getLineNumber(),
+ aException.Location.getColumnNumber(),
+ aException.Location.getCharacterOffset()));
+ aView.ShowRun(aRun);
+ }
+ }
+ }
+}
diff --git a/ooxml/source/framework/SchemaParser/.classpath b/ooxml/source/framework/SchemaParser/.classpath
new file mode 100644
index 000000000000..fb565a588d8a
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/.classpath
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/ooxml/source/framework/SchemaParser/.project b/ooxml/source/framework/SchemaParser/.project
new file mode 100644
index 000000000000..05958e177e81
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/.project
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>SchemaParser</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
diff --git a/ooxml/source/framework/SchemaParser/.settings/org.eclipse.jdt.core.prefs b/ooxml/source/framework/SchemaParser/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 000000000000..7341ab1683c4
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,11 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.7
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.7
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/SchemaReader.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/SchemaReader.java
new file mode 100644
index 000000000000..bf15b39d71e2
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/SchemaReader.java
@@ -0,0 +1,510 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.schema;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Queue;
+import java.util.Set;
+import java.util.Vector;
+
+import javax.xml.stream.XMLStreamException;
+
+import org.apache.openoffice.ooxml.schema.automaton.FiniteAutomatonContainer;
+import org.apache.openoffice.ooxml.schema.automaton.NonValidatingCreator;
+import org.apache.openoffice.ooxml.schema.automaton.ValidatingCreator;
+import org.apache.openoffice.ooxml.schema.generator.LogGenerator;
+import org.apache.openoffice.ooxml.schema.generator.ParserTablesGenerator;
+import org.apache.openoffice.ooxml.schema.generator.html.HtmlGenerator;
+import org.apache.openoffice.ooxml.schema.model.schema.Schema;
+import org.apache.openoffice.ooxml.schema.model.schema.SchemaBase;
+import org.apache.openoffice.ooxml.schema.parser.SchemaParser;
+import org.apache.openoffice.ooxml.schema.simple.SimpleTypeContainer;
+
+public class SchemaReader
+{
+ public static void main (final String ... aArgumentList)
+ {
+ if (aArgumentList.length != 1)
+ {
+ System.err.printf("usage: SchemaParser <driver-file>\n");
+ System.err.printf(" driver file can contain these lines:\n");
+ System.err.printf("# Comments\n");
+ System.err.printf(" are ignored\n");
+ System.err.printf("schema <mark> <file-name>\n");
+ System.err.printf(" specifies a top-level schema file to read\n");
+ System.err.printf("output-schema <file-name>\n");
+ System.err.printf(" write schema information to file\n");
+ System.err.printf("output-optimized-schema <file-name>\n");
+ System.err.printf(" write information about optimized schema to file\n");
+ System.exit(1);
+ }
+
+ final SchemaReader aReader = new SchemaReader(new File(aArgumentList[0]));
+ aReader.Run();
+ }
+
+
+
+
+ private SchemaReader (final File aDriverFile)
+ {
+ maSchemaBase = new SchemaBase();
+ maTopLevelSchemas = new HashMap<>();
+ maMainSchemaFiles = new Vector<>();
+ maSchemaFiles = new HashSet<>();
+ maWorkList = new LinkedList<>();
+ maOutputOperations = new Vector<>();
+ mnTotalLineCount = 0;
+ mnTotalByteCount = 0;
+
+ ParseDriverFile(aDriverFile);
+ }
+
+
+
+
+ /** Read and parse the driver file that specifies which schema files to read
+ * and where the output should go.
+ */
+ private void ParseDriverFile (final File aDriverFile)
+ {
+ if (aDriverFile == null || ! aDriverFile.exists() || ! aDriverFile.canRead())
+ {
+ System.err.printf("can not read driver file\n");
+ System.exit(1);
+ }
+
+ try
+ {
+ final BufferedReader aIn = new BufferedReader(new FileReader(aDriverFile));
+ while(true)
+ {
+ String sLine = aIn.readLine();
+ if (sLine == null)
+ break;
+ // Lines starting with # are comment lines and are ignored.
+ if (sLine.matches("^\\s*#.*"))
+ continue;
+ // Lines containing only whitespace are also ignored.
+ else if (sLine.matches("^\\s*$"))
+ continue;
+
+ // Handle line continuation.
+ while (sLine.endsWith("\\"))
+ sLine = sLine.substring(0, sLine.length()-1) + aIn.readLine();
+
+ final Vector<String> aParts = SplitLine(sLine);
+ switch (aParts.get(0))
+ {
+ case "schema":
+ maMainSchemaFiles.add(new String[]{aParts.get(1), aParts.get(2)});
+ break;
+
+ case "output-schema":
+ maOutputOperations.add(new Runnable()
+ {
+ final File maFile = CreateCheckedOutputFile(aParts.get(1));
+ @Override public void run()
+ {
+ WriteSchema(maFile);
+ }
+ });
+ break;
+
+ case "output-optimized-schema":
+ maOutputOperations.add(new Runnable()
+ {
+ final File maFile = CreateCheckedOutputFile(aParts.get(1));
+ @Override public void run()
+ {
+ WriteOptimizedSchema(maFile);
+ }
+ });
+ break;
+
+ case "output-nonvalidating-parse-tables":
+ maOutputOperations.add(new Runnable()
+ {
+ final File aAutomatonLogFile = CreateCheckedOutputFile(aParts.get(1));
+ final File aSimpleTypeLogFile = CreateCheckedOutputFile(aParts.get(2));
+ final File aParseTableFile = CreateCheckedOutputFile(aParts.get(3));
+ @Override public void run()
+ {
+ WriteNonValidatingParseTables(
+ aAutomatonLogFile,
+ aSimpleTypeLogFile,
+ aParseTableFile);
+ }
+ });
+ break;
+
+ case "output-validating-parse-tables":
+ maOutputOperations.add(new Runnable()
+ {
+ final File aAutomatonLogFile = CreateCheckedOutputFile(aParts.get(1));
+ final File aSimpleTypeLogFile = CreateCheckedOutputFile(aParts.get(2));
+ final File aParseTableFile = CreateCheckedOutputFile(aParts.get(3));
+ @Override public void run()
+ {
+ WriteValidatingParseTables(
+ aAutomatonLogFile,
+ aSimpleTypeLogFile,
+ aParseTableFile);
+ }
+ });
+ break;
+
+ case "output-html-page":
+ maOutputOperations.add(new Runnable()
+ {
+ final File aHTMLPageFile = CreateCheckedOutputFile(aParts.get(1));
+ @Override public void run()
+ {
+ WriteHTMLPage(aHTMLPageFile);
+ }
+ });
+ break;
+
+ default:
+ System.err.printf("unknown command '%s' in driver file", aParts.get(0));
+ System.exit(1);
+ }
+ }
+ aIn.close();
+ }
+ catch (final Exception aException)
+ {
+ aException.printStackTrace();
+ }
+ }
+
+
+
+
+ private void Run ()
+ {
+ try
+ {
+ ParseSchemaFiles();
+ }
+ catch (final Exception aException)
+ {
+ aException.printStackTrace();
+ }
+
+ maOptimizedSchemaBase = maSchemaBase.GetOptimizedSchema(maTopLevelSchemas.values());
+ for (final Entry<String, Schema> aEntry : maTopLevelSchemas.entrySet())
+ aEntry.setValue(aEntry.getValue().GetOptimizedSchema(maOptimizedSchemaBase));
+
+ System.out.printf(" optimization left %d complex types and %d simple types\n",
+ maOptimizedSchemaBase.ComplexTypes.GetCount(),
+ maOptimizedSchemaBase.SimpleTypes.GetCount());
+
+ for (final Runnable aOperation : maOutputOperations)
+ {
+ aOperation.run();
+ }
+ }
+
+
+
+
+ private void ParseSchemaFiles ()
+ throws XMLStreamException
+ {
+ System.out.printf("parsing %d main schema files\n", maMainSchemaFiles.size());
+
+ for (final String[] aEntry : maMainSchemaFiles)
+ {
+ final String sMainSchemaShortname = aEntry[0];
+ final String sMainSchemaFile = aEntry[1];
+ final File aMainSchemaFile = new File(sMainSchemaFile);
+ if ( ! aMainSchemaFile.exists())
+ {
+ System.err.printf(" schema file does not exist\n");
+ System.exit(1);
+ }
+ if ( ! aMainSchemaFile.canRead())
+ {
+ System.err.printf("can not read schema file\n");
+ System.exit(1);
+ }
+
+ final Schema aSchema = new Schema(sMainSchemaShortname, maSchemaBase);
+ ParseSchemaFile(sMainSchemaFile, aSchema);
+ maTopLevelSchemas.put(sMainSchemaShortname, aSchema);
+ }
+
+ long nStartTime = System.currentTimeMillis();
+ while ( ! maWorkList.isEmpty())
+ {
+ ParseSchemaFile(maWorkList.poll(), null);
+ }
+ long nEndTime = System.currentTimeMillis();
+
+ System.out.printf("parsed %d schema files with a total of %d lines and %d bytes in %fs\n",
+ maSchemaFiles.size(),
+ mnTotalLineCount,
+ mnTotalByteCount,
+ (nEndTime-nStartTime)/1000.0);
+ System.out.printf(" found %d complex types and %d simple types\n",
+ maSchemaBase.ComplexTypes.GetCount(),
+ maSchemaBase.SimpleTypes.GetCount());
+
+ int nTopLevelElementCount = 0;
+ for (final Schema aSchema : maTopLevelSchemas.values())
+ nTopLevelElementCount += aSchema.TopLevelElements.GetCount();
+ System.out.printf(" the %d top level schemas have %d elements\n",
+ maTopLevelSchemas.size(),
+ nTopLevelElementCount);
+ }
+
+
+
+
+ private void ParseSchemaFile (
+ final String sSchemaFilename,
+ final Schema aSchema)
+ throws XMLStreamException
+ {
+ System.out.printf("parsing %s\n", sSchemaFilename);
+ maSchemaFiles.add(sSchemaFilename);
+
+ final SchemaParser aParser = new SchemaParser(new File(sSchemaFilename), aSchema, maSchemaBase);
+ aParser.Parse();
+
+ mnTotalLineCount += aParser.GetLineCount();
+ mnTotalByteCount += aParser.GetByteCount();
+ for (final File aFile : aParser.GetImportedSchemaFilenames())
+ AddSchemaReference(aFile.getAbsolutePath());
+ }
+
+
+
+
+ private void AddSchemaReference (final String sSchemaFilename)
+ {
+ if ( ! maSchemaFiles.contains(sSchemaFilename))
+ {
+ if (sSchemaFilename == null)
+ throw new RuntimeException();
+
+ // We don't know yet the file name of the schema, so just store null to mark the schema name as 'known'.
+ maSchemaFiles.add(sSchemaFilename);
+ maWorkList.add(sSchemaFilename);
+ }
+ }
+
+
+
+
+ /** Split the given string at whitespace but not at whitespace inside double quotes.
+ *
+ */
+ private Vector<String> SplitLine (final String sLine)
+ {
+ final Vector<String> aParts = new Vector<>();
+
+ boolean bIsInsideQuotes = false;
+ for (final String sPart : sLine.split("\""))
+ {
+ if (bIsInsideQuotes)
+ aParts.add(sPart);
+ else
+ for (final String sInnerPart : sPart.split("\\s+"))
+ {
+ if (sInnerPart == null)
+ throw new RuntimeException();
+ else if ( ! sInnerPart.isEmpty())
+ aParts.add(sInnerPart);
+ }
+
+ bIsInsideQuotes = ! bIsInsideQuotes;
+ }
+
+ return aParts;
+ }
+
+
+
+
+ /** Create a File object for a given file name.
+ * Check that the file is writable, i.e. its directory exists and that if
+ * the file already exists it can be replaced.
+ * Throws a RuntimeException when a check fails.
+ */
+ private File CreateCheckedOutputFile (final String sFilename)
+ {
+ final File aFile = new File(sFilename);
+ if ( ! aFile.getParentFile().exists())
+ throw new RuntimeException("directory of "+sFilename+" does not exist: can not create file");
+ if (aFile.exists() && ! aFile.canWrite())
+ throw new RuntimeException("file "+sFilename+" already exists and can not be replaced");
+ return aFile;
+ }
+
+
+
+
+ private void WriteSchema (final File aOutputFile)
+ {
+ LogGenerator.Write(aOutputFile, maSchemaBase, maTopLevelSchemas.values());
+ }
+
+
+
+
+ private void WriteOptimizedSchema (final File aOutputFile)
+ {
+ LogGenerator.Write(aOutputFile, maOptimizedSchemaBase, maTopLevelSchemas.values());
+ }
+
+
+
+
+ private void WriteNonValidatingParseTables (
+ final File aAutomatonLogFile,
+ final File aSimpleTypeLogFile,
+ final File aParseTableFile)
+ {
+ long nStartTime = System.currentTimeMillis();
+ final NonValidatingCreator aCreator = new NonValidatingCreator(maOptimizedSchemaBase, aAutomatonLogFile);
+ FiniteAutomatonContainer aAutomatons = aCreator.Create(maTopLevelSchemas.values());
+ long nEndTime = System.currentTimeMillis();
+ System.out.printf(
+ "created %d non-validating automatons with %d states and %d transitions in %fs\n",
+ aAutomatons.GetAutomatonCount(),
+ aAutomatons.GetStateCount(),
+ aAutomatons.GetTransitionCount(),
+ (nEndTime-nStartTime)/1000.0);
+
+ nStartTime = System.currentTimeMillis();
+ final SimpleTypeContainer aSimpleTypes = SimpleTypeContainer.Create(
+ maOptimizedSchemaBase,
+ aSimpleTypeLogFile);
+ nEndTime = System.currentTimeMillis();
+ System.out.printf(
+ "created %d simple type descriptions in %fs\n",
+ aSimpleTypes.GetSimpleTypeCount(),
+ (nEndTime-nStartTime)/1000.0);
+
+ new ParserTablesGenerator(
+ aAutomatons,
+ maOptimizedSchemaBase.Namespaces,
+ aSimpleTypes,
+ maOptimizedSchemaBase.AttributeValueToIdMap)
+ .Generate(aParseTableFile);
+ }
+
+
+
+
+ private void WriteValidatingParseTables (
+ final File aAutomatonLogFile,
+ final File aSimpleTypeLogFile,
+ final File aParseTableFile)
+ {
+ long nStartTime = System.currentTimeMillis();
+ final ValidatingCreator aCreator = new ValidatingCreator(maOptimizedSchemaBase, aAutomatonLogFile);
+ FiniteAutomatonContainer aAutomatons = aCreator.Create();
+ long nEndTime = System.currentTimeMillis();
+ System.out.printf(
+ "created %d validating stack automatons with %d states and %d transitions in %fs\n",
+ aAutomatons.GetAutomatonCount(),
+ aAutomatons.GetStateCount(),
+ aAutomatons.GetTransitionCount(),
+ (nEndTime-nStartTime)/1000.0);
+
+
+ nStartTime = System.currentTimeMillis();
+ aAutomatons = aAutomatons.CreateDFAs();
+ nEndTime = System.currentTimeMillis();
+ System.out.printf(
+ "created %d deterministic automatons with %d states and %d transitions in %fs\n",
+ aAutomatons.GetAutomatonCount(),
+ aAutomatons.GetStateCount(),
+ aAutomatons.GetTransitionCount(),
+ (nEndTime-nStartTime)/1000.0);
+
+ nStartTime = System.currentTimeMillis();
+ aAutomatons = aAutomatons.MinimizeDFAs();
+ nEndTime = System.currentTimeMillis();
+ System.out.printf(
+ "minimized automaton in %fs, there are now %d states and %d transitions\n",
+ (nEndTime-nStartTime)/1000.0,
+ aAutomatons.GetStateCount(),
+ aAutomatons.GetTransitionCount());
+
+ nStartTime = System.currentTimeMillis();
+ final SimpleTypeContainer aSimpleTypes = SimpleTypeContainer.Create(
+ maOptimizedSchemaBase,
+ aSimpleTypeLogFile);
+ nEndTime = System.currentTimeMillis();
+ System.out.printf(
+ "created %d simple type descriptions in %fs\n",
+ aSimpleTypes.GetSimpleTypeCount(),
+ (nEndTime-nStartTime)/1000.0);
+
+ new ParserTablesGenerator(
+ aAutomatons,
+ maOptimizedSchemaBase.Namespaces,
+ aSimpleTypes,
+ maOptimizedSchemaBase.AttributeValueToIdMap)
+ .Generate(aParseTableFile);
+ }
+
+
+
+
+ private void WriteHTMLPage (
+ final File aHTMLPageFile)
+ {
+ long nStartTime = System.currentTimeMillis();
+
+ new HtmlGenerator(maOptimizedSchemaBase, maTopLevelSchemas, aHTMLPageFile).Generate();
+
+ long nEndTime = System.currentTimeMillis();
+ System.out.printf(
+ "created HTML page in %fs\n",
+ (nEndTime-nStartTime)/1000.0);
+ }
+
+
+
+
+ private final SchemaBase maSchemaBase;
+ private SchemaBase maOptimizedSchemaBase;
+ private final Map<String,Schema> maTopLevelSchemas;
+ private final Vector<String[]> maMainSchemaFiles;
+ private final Queue<String> maWorkList;
+ private final Vector<Runnable> maOutputOperations;
+ private final Set<String> maSchemaFiles;
+ private int mnTotalLineCount;
+ private int mnTotalByteCount;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/Test.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/Test.java
new file mode 100644
index 000000000000..5cfb3663aaca
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/Test.java
@@ -0,0 +1,81 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.schema;
+
+import org.apache.openoffice.ooxml.schema.automaton.HopcroftMinimizer;
+import org.apache.openoffice.ooxml.schema.automaton.State;
+import org.apache.openoffice.ooxml.schema.automaton.StateContainer;
+import org.apache.openoffice.ooxml.schema.automaton.StateContext;
+import org.apache.openoffice.ooxml.schema.automaton.Transition;
+import org.apache.openoffice.ooxml.schema.model.base.QualifiedName;
+
+/** A simple test of the minimization algorithm for DFAs.
+ *
+ * May lead to the use of a testing framework in the future.
+ */
+public class Test
+{
+ public static void main (final String ... aArgumentList)
+ {
+ new Test("S", new String[]{"E"}, new String[][]{
+ {"S", "A", "a"},
+ {"A", "B", "b"},
+ {"A", "C", "b"},
+ {"B", "E", "c"},
+ {"C", "E", "c"},
+ });
+ }
+ private Test (
+ final String sStartState,
+ final String[] aAcceptingStates,
+ final String[][] aTransitions)
+ {
+ final StateContainer aOriginalStateContainer = new StateContainer();
+ final StateContext aStates = new StateContext(
+ aOriginalStateContainer,
+ sStartState);
+ for (final String sAcceptingState : aAcceptingStates)
+ {
+ final State s = aStates.CreateState(sAcceptingState);
+ s.SetIsAccepting();
+ }
+ for (final String[] aTransition : aTransitions)
+ {
+ final State start = aStates.GetOrCreateState(
+ new QualifiedName(aTransition[0]),
+ null);
+ final State end = aStates.GetOrCreateState(
+ new QualifiedName(aTransition[1]),
+ null);
+ final QualifiedName element = new QualifiedName(aTransition[2]);
+ final String type = "T_"+aTransition[2];
+
+ start.AddTransition(new Transition(start, end, element, type));
+ }
+ HopcroftMinimizer.MinimizeDFA (
+ new StateContainer(),
+ aStates,
+ null,
+ null,
+ System.out);
+ }
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/CreatorBase.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/CreatorBase.java
new file mode 100644
index 000000000000..7f93ece2d00c
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/CreatorBase.java
@@ -0,0 +1,124 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.schema.automaton;
+
+import java.io.File;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.Vector;
+
+import org.apache.openoffice.ooxml.schema.iterator.AttributeIterator;
+import org.apache.openoffice.ooxml.schema.iterator.DereferencingNodeIterator;
+import org.apache.openoffice.ooxml.schema.misc.Log;
+import org.apache.openoffice.ooxml.schema.model.attribute.Attribute;
+import org.apache.openoffice.ooxml.schema.model.base.INode;
+import org.apache.openoffice.ooxml.schema.model.schema.SchemaBase;
+
+/** Base class of the creator classes for DFAs and NFAs.
+ */
+public class CreatorBase
+{
+ CreatorBase (
+ final SchemaBase aSchemaBase,
+ final File aLogFile)
+ {
+ maSchemaBase = aSchemaBase;
+ maStateContainer = new StateContainer();
+ maLog = new Log(aLogFile);
+ msLogIndentation = "";
+ maElementSimpleTypes = new HashSet<>();
+ }
+
+
+
+
+ /** Create a very simple automaton:
+ * a) Its start state is also the accepting state.
+ * b) It does not allow any transitions.
+ * c) Its text items have the given simple type.
+ */
+ protected FiniteAutomaton CreateForSimpleType (final INode aSimpleType)
+ {
+ final StateContext aStateContext = new StateContext(
+ maStateContainer,
+ aSimpleType.GetName().GetStateName());
+ aStateContext.GetStartState().SetIsAccepting();
+ aStateContext.GetStartState().SetTextType(aSimpleType);
+ return new FiniteAutomaton(
+ aStateContext,
+ new Vector<Attribute>(),
+ aSimpleType.GetLocation());
+ }
+
+
+
+
+ protected Vector<Attribute> CollectAttributes (final INode aRoot)
+ {
+ final Vector<Attribute> aAttributes = new Vector<>();
+ for (final INode aNode : new DereferencingNodeIterator(aRoot, maSchemaBase, true))
+ for (final Attribute aAttribute : new AttributeIterator(aNode, maSchemaBase))
+ aAttributes.add(aAttribute);
+ return aAttributes;
+ }
+
+
+
+
+ protected void AddSkipTransition (
+ final State aState,
+ final SkipData aSkipData)
+ {
+ aState.AddSkipData(aSkipData);
+
+ if (maLog != null)
+ {
+ maLog.printf("%sskip state %s\n",
+ msLogIndentation,
+ aState.GetFullname());
+ }
+ }
+
+
+
+
+ protected void ProcessAttributes (final INode aNode)
+ {
+ for (final Attribute aAttribute : new AttributeIterator(aNode, maSchemaBase))
+ {
+ maLog.printf("%sattribute %s\n",
+ msLogIndentation,
+ aAttribute.GetName().GetDisplayName());
+ maAttributes.add(aAttribute);
+ }
+ }
+
+
+
+
+ protected final SchemaBase maSchemaBase;
+ protected final StateContainer maStateContainer;
+ protected final Log maLog;
+ protected String msLogIndentation;
+ protected Vector<Attribute> maAttributes;
+ protected final Set<INode> maElementSimpleTypes;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/DFACreator.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/DFACreator.java
new file mode 100644
index 000000000000..c6684acfbb53
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/DFACreator.java
@@ -0,0 +1,280 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.schema.automaton;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Queue;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.TreeSet;
+import java.util.Vector;
+
+import org.apache.openoffice.ooxml.schema.model.attribute.Attribute;
+import org.apache.openoffice.ooxml.schema.model.base.Location;
+import org.apache.openoffice.ooxml.schema.model.base.QualifiedName;
+
+/** Convert an NFA into a DFA via the powerset construction (also called subset
+ * construction).
+ */
+public class DFACreator
+{
+ /** For a given non-deterministic finite automaton create an equivalent
+ * deterministic finite automaton.
+ */
+ public static FiniteAutomaton CreateDFAforNFA (
+ final StateContainer aDFAStateContainer,
+ final StateContext aNFAStateContext,
+ final Vector<Attribute> aAttributes,
+ final QualifiedName aTypeName,
+ final Location aLocation)
+ {
+ final DFACreator aCreator = new DFACreator(aDFAStateContainer, aNFAStateContext, aTypeName);
+ aCreator.CreateDFAforNFA();
+ return new FiniteAutomaton(
+ aCreator.maDFAStateContext,
+ aAttributes,
+ aLocation);
+ }
+
+
+
+
+ private DFACreator (
+ final StateContainer aDFAStateContainer,
+ final StateContext aNFAStateContext,
+ final QualifiedName aTypeName)
+ {
+ maNFAStateContext = aNFAStateContext;
+
+ // Create the set of state sets where each element corresponds to a
+ // state in the DFA.
+ maNFASetToDFAStateMap = new TreeMap<>();
+ maDFAStateContext = new StateContext(
+ aDFAStateContainer,
+ aTypeName == null
+ ? "<TOP-LEVEL>"
+ : aTypeName.GetStateName());
+
+ maDFATransitions = new HashSet<>();
+ maAcceptingDFAStates = new Vector<>();
+ }
+
+
+
+
+ private void CreateDFAforNFA ()
+ {
+ final State aNFAStartState = maNFAStateContext.GetStartState();
+
+ // Initialize the creation process by adding the epsilon closure of the
+ // original start state to the work list.
+ final StateSet aStartSet = GetEpsilonClosure(new StateSet(aNFAStartState));
+ maNFASetToDFAStateMap.put(aStartSet, maDFAStateContext.GetStartState());
+
+ PropagateStateFlags(aStartSet, maDFAStateContext.GetStartState());
+
+ final Queue<StateSet> aWorklist = new LinkedList<>();
+ aWorklist.add(aStartSet);
+
+ while ( ! aWorklist.isEmpty())
+ {
+ final Collection<StateSet> aAdditionalWorkList = ProcessTransitionFront(
+ aWorklist.poll());
+
+ aWorklist.addAll(aAdditionalWorkList);
+ }
+ }
+
+
+
+
+ private Collection<StateSet> ProcessTransitionFront (
+ final StateSet aSet)
+ {
+ final Set<StateSet> aLocalWorklist = new TreeSet<>();
+
+ // Find all regular transitions that start from any state in the set.
+ final Map<String,Vector<Transition>> aTransitions = GetTransitionFront(aSet);
+
+ // Create new state sets for states that are reachable via the same element and
+ // the following epsilon transitions.
+ for (final Entry<String,Vector<Transition>> aEntry : aTransitions.entrySet())
+ {
+ // Create new state sets for both the end state of the transition.
+ final StateSet aEpsilonClosure = GetEpsilonClosure(GetEndStateSet(aEntry.getValue()));
+
+ // When these are new state sets then add them to the worklist
+ // and the set of sets.
+ State aDFAState = maNFASetToDFAStateMap.get(aEpsilonClosure);
+ if (aDFAState == null)
+ {
+ aLocalWorklist.add(aEpsilonClosure);
+ aDFAState = aEpsilonClosure.CreateStateForStateSet(maDFAStateContext);
+ PropagateStateFlags(aEpsilonClosure, aDFAState);
+ maNFASetToDFAStateMap.put(aEpsilonClosure, aDFAState);
+ if (aDFAState.IsAccepting())
+ maAcceptingDFAStates.add(aDFAState);
+ }
+
+ final State aStartState = maNFASetToDFAStateMap.get(aSet);
+ final QualifiedName aElementName = GetElementName(aEntry.getValue());
+ final String sElementTypeName = GetElementTypeName(aEntry.getValue());
+ assert(aElementName != null);
+ final Transition aTransition = new Transition(
+ aStartState,
+ aDFAState,
+ aElementName,
+ sElementTypeName);
+ aStartState.AddTransition(aTransition);
+ maDFATransitions.add(aTransition);
+ }
+
+ return aLocalWorklist;
+ }
+
+
+
+
+ private QualifiedName GetElementName (final Vector<Transition> aTransitions)
+ {
+ for (final Transition aTransition : aTransitions)
+ return aTransition.GetElementName();
+ return null;
+ }
+
+
+
+
+ private String GetElementTypeName (final Vector<Transition> aTransitions)
+ {
+ for (final Transition aTransition : aTransitions)
+ return aTransition.GetElementTypeName();
+ return null;
+ }
+
+
+
+
+ /** Return the epsilon closure of the given set of states.
+ * The result is the set of all states that are reachable via zero, one or
+ * more epsilon transitions from at least one state in the given set of
+ * states.
+ */
+ private StateSet GetEpsilonClosure ( final StateSet aSet)
+ {
+ final StateSet aClosure = new StateSet(aSet);
+
+ final Queue<State> aWorkList = new LinkedList<>();
+ for (final State aState : aSet.GetStates())
+ aWorkList.add(aState);
+
+ while( ! aWorkList.isEmpty())
+ {
+ final State aState = aWorkList.poll();
+ for (final EpsilonTransition aTransition : aState.GetEpsilonTransitions())
+ {
+ final State aEndState = aTransition.GetEndState();
+ if ( ! aClosure.ContainsState(aEndState))
+ {
+ aClosure.AddState(aEndState);
+ aWorkList.add(aEndState);
+ }
+ }
+ }
+
+ return aClosure;
+ }
+
+
+
+
+ /** Return the list of regular transitions (i.e. not epsilon transitions)
+ * that start from any of the states in the given set.
+ * The returned map is a partition of the transitions according to their
+ * triggering XML element.
+ */
+ private Map<String, Vector<Transition>> GetTransitionFront (final StateSet aSet)
+ {
+ final Map<String, Vector<Transition>> aTransitions = new HashMap<>();
+
+ for (final State aState : aSet.GetStates())
+ for (final Transition aTransition : aState.GetTransitions())
+ {
+ final String sElementName;
+ final QualifiedName aElementName = aTransition.GetElementName();
+ if (aElementName != null)
+ sElementName = aElementName.GetDisplayName();
+ else
+ sElementName = null; // For skip transitions.
+
+ Vector<Transition> aElementTransitions = aTransitions.get(sElementName);
+ if (aElementTransitions == null)
+ {
+ aElementTransitions = new Vector<>();
+ aTransitions.put(sElementName, aElementTransitions);
+ }
+ aElementTransitions.add(aTransition);
+ }
+ return aTransitions;
+ }
+
+
+
+
+ /** Return a state set that contains all end states of all the given transitions.
+ */
+ private StateSet GetEndStateSet (final Iterable<Transition> aTransitions)
+ {
+ final StateSet aStateSet = new StateSet();
+ for (final Transition aTransition : aTransitions)
+ aStateSet.AddState(aTransition.GetEndState());
+ return aStateSet;
+ }
+
+
+
+
+ /** Propagate accepting state flag and skip data.
+ */
+ private void PropagateStateFlags (
+ final StateSet aNFAStateSet,
+ final State aDFAState)
+ {
+ for (final State aNFAState : aNFAStateSet.GetStates())
+ aDFAState.CopyFrom(aNFAState);
+ }
+
+
+
+
+ private final StateContext maNFAStateContext;
+
+ private final Map<StateSet,State> maNFASetToDFAStateMap;
+ private final StateContext maDFAStateContext;
+ private final Set<Transition> maDFATransitions;
+ private final Vector<State> maAcceptingDFAStates;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/EpsilonTransition.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/EpsilonTransition.java
new file mode 100644
index 000000000000..75dca97ed6eb
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/EpsilonTransition.java
@@ -0,0 +1,70 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.schema.automaton;
+
+/** Transition from one state to another that does not consume an input token.
+ *
+ * Use in the process of creating a validating parser.
+ */
+public class EpsilonTransition
+{
+ EpsilonTransition (
+ final State aStartState,
+ final State aEndState)
+ {
+ maStartState = aStartState;
+ maEndState = aEndState;
+ }
+
+
+
+
+ public State GetStartState ()
+ {
+ return maStartState;
+ }
+
+
+
+
+ public State GetEndState ()
+ {
+ return maEndState;
+ }
+
+
+
+
+ @Override
+ public String toString ()
+ {
+ return String.format("%s -> %s",
+ maStartState.GetFullname(),
+ maEndState.GetFullname());
+ }
+
+
+
+
+ private final State maStartState;
+ private final State maEndState;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/FiniteAutomaton.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/FiniteAutomaton.java
new file mode 100644
index 000000000000..16bf2f737c8d
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/FiniteAutomaton.java
@@ -0,0 +1,169 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.schema.automaton;
+
+import java.util.Vector;
+
+import org.apache.openoffice.ooxml.schema.model.attribute.Attribute;
+import org.apache.openoffice.ooxml.schema.model.base.Location;
+import org.apache.openoffice.ooxml.schema.model.base.QualifiedName;
+
+
+/** Represents a DFA (deterministic FA) or a NFA (non-deterministic FA).
+ * There is one automaton for each complex type and one for the top level elements.
+ * Transitions correspond to 'element' elements in the schema or a start tag in
+ * the input file. During parsing the current automaton is pushed on a stack
+ * and the automaton that represents the complex type associated with the
+ * starting element is made the current automaton. An end tag pops an automaton
+ * from the stack and replaces the current automaton with it.
+ */
+public class FiniteAutomaton
+{
+ FiniteAutomaton (
+ final StateContext aContext,
+ final Vector<Attribute> aAttributes,
+ final Location aLocation)
+ {
+ maStateContext = aContext;
+ maAttributes = aAttributes!=null
+ ? aAttributes
+ : new Vector<Attribute>();
+ maLocation = aLocation;
+ }
+
+
+
+
+ public int GetStateCount ()
+ {
+ return maStateContext.GetStateCount();
+ }
+
+
+
+
+ public Iterable<State> GetStates()
+ {
+ return maStateContext.GetStates();
+ }
+
+
+
+
+ public Iterable<State> GetStatesSorted ()
+ {
+ return maStateContext.GetStatesSorted();
+ }
+
+
+
+
+ public State GetStartState ()
+ {
+ return maStateContext.GetStartState();
+ }
+
+
+
+
+ public Iterable<State> GetAcceptingStates ()
+ {
+ return maStateContext.GetAcceptingStates();
+ }
+
+
+
+
+ public FiniteAutomaton CreateDFA (
+ final StateContainer aDFAContainer,
+ final QualifiedName aTypeName)
+ {
+ return DFACreator.CreateDFAforNFA(
+ aDFAContainer,
+ maStateContext,
+ maAttributes,
+ aTypeName,
+ maLocation);
+ }
+
+
+
+
+ public StateContext GetStateContext()
+ {
+ return maStateContext;
+ }
+
+
+
+
+ public Iterable<Transition> GetTransitions ()
+ {
+ final Vector<Transition> aTransitions = new Vector<>();
+ for (final State aState : maStateContext.GetStates())
+ for (final Transition aTransition : aState.GetTransitions())
+ aTransitions.add(aTransition);
+ return aTransitions;
+ }
+
+
+
+
+ public int GetTransitionCount()
+ {
+ int nTransitionCount = 0;
+ for (final State aState : maStateContext.GetStates())
+ nTransitionCount += aState.GetTransitionCount();
+ return nTransitionCount;
+ }
+
+
+
+
+ public String GetTypeName ()
+ {
+ return maStateContext.GetStartState().GetFullname();
+ }
+
+
+
+
+ public Location GetLocation ()
+ {
+ return maLocation;
+ }
+
+
+
+
+ public Vector<Attribute> GetAttributes ()
+ {
+ return maAttributes;
+ }
+
+
+
+
+ private final StateContext maStateContext;
+ private final Vector<Attribute> maAttributes;
+ private final Location maLocation;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/FiniteAutomatonContainer.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/FiniteAutomatonContainer.java
new file mode 100644
index 000000000000..e76b7e8614e7
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/FiniteAutomatonContainer.java
@@ -0,0 +1,166 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.schema.automaton;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.PrintStream;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Vector;
+
+import org.apache.openoffice.ooxml.schema.model.base.QualifiedName;
+
+/** As there is one FA for each complex type and one for the top level elements,
+ * this container represents the whole set of schemas.
+ */
+public class FiniteAutomatonContainer
+{
+ FiniteAutomatonContainer (final StateContainer aStateContainer)
+ {
+ maComplexTypeNameToAutomatonMap = new HashMap<>();
+ }
+
+
+
+
+ public void AddAutomaton (
+ final QualifiedName aElementName,
+ final FiniteAutomaton aAutomaton)
+ {
+ maComplexTypeNameToAutomatonMap.put(aElementName, aAutomaton);
+ }
+
+
+
+
+ public Iterable<FiniteAutomaton> GetAutomatons()
+ {
+ return maComplexTypeNameToAutomatonMap.values();
+ }
+
+
+
+
+ public int GetAutomatonCount ()
+ {
+ return maComplexTypeNameToAutomatonMap.size();
+ }
+
+
+
+
+ public Iterable<State> GetStates()
+ {
+ final Vector<State> aStates = new Vector<>();
+ for (final FiniteAutomaton aAutomaton : maComplexTypeNameToAutomatonMap.values())
+ for (final State aState : aAutomaton.GetStates())
+ aStates.add(aState);
+ return aStates;
+ }
+
+
+
+
+ public int GetStateCount()
+ {
+ int nStateCount = 0;
+ for (final FiniteAutomaton aAutomaton : maComplexTypeNameToAutomatonMap.values())
+ nStateCount += aAutomaton.GetStateCount();
+ return nStateCount;
+ }
+
+
+
+
+ public int GetTransitionCount ()
+ {
+ int nTransitionCount = 0;
+ for (final FiniteAutomaton aAutomaton : maComplexTypeNameToAutomatonMap.values())
+ nTransitionCount += aAutomaton.GetTransitionCount();
+ return nTransitionCount;
+ }
+
+
+
+
+ public FiniteAutomatonContainer CreateDFAs ()
+ {
+ final StateContainer aDFAStateContainer = new StateContainer();
+ final FiniteAutomatonContainer aDFAs = new FiniteAutomatonContainer(aDFAStateContainer);
+ for (final Entry<QualifiedName, FiniteAutomaton> aEntry : maComplexTypeNameToAutomatonMap.entrySet())
+ {
+ aDFAs.AddAutomaton(
+ aEntry.getKey(),
+ aEntry.getValue().CreateDFA(
+ aDFAStateContainer,
+ aEntry.getKey()));
+ }
+ return aDFAs;
+ }
+
+
+
+
+ public FiniteAutomatonContainer MinimizeDFAs ()
+ {
+ PrintStream aLog = null;
+ try
+ {
+ aLog = new PrintStream(new FileOutputStream(new File("/tmp/minimization.log")));
+ }
+ catch(Exception e)
+ {
+ e.printStackTrace();
+ return null;
+ }
+
+ final StateContainer aNewStateContainer = new StateContainer();
+ final FiniteAutomatonContainer aDFAs = new FiniteAutomatonContainer(aNewStateContainer);
+ for (final Entry<QualifiedName, FiniteAutomaton> aEntry : maComplexTypeNameToAutomatonMap.entrySet())
+ {
+ aDFAs.AddAutomaton(
+ aEntry.getKey(),
+ HopcroftMinimizer.MinimizeDFA(
+ aNewStateContainer,
+ aEntry.getValue().GetStateContext(),
+ aEntry.getValue().GetAttributes(),
+ aEntry.getValue().GetLocation(),
+ aLog));
+ }
+ return aDFAs;
+ }
+
+
+
+
+ public FiniteAutomaton GetTopLevelAutomaton ()
+ {
+ return maComplexTypeNameToAutomatonMap.get(null);
+ }
+
+
+
+
+ private final Map<QualifiedName, FiniteAutomaton> maComplexTypeNameToAutomatonMap;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/HopcroftMinimizer.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/HopcroftMinimizer.java
new file mode 100644
index 000000000000..9177ccc707ae
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/HopcroftMinimizer.java
@@ -0,0 +1,380 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.schema.automaton;
+
+import java.io.PrintStream;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.TreeSet;
+import java.util.Vector;
+
+import org.apache.openoffice.ooxml.schema.model.attribute.Attribute;
+import org.apache.openoffice.ooxml.schema.model.base.Location;
+import org.apache.openoffice.ooxml.schema.model.base.QualifiedName;
+
+/** Minimize an DFA with respect to its number of states.
+ * This is most important for the use of the 'all' element in the OOXML
+ * specification which leads to a lot of additional states and transitions.
+ */
+public class HopcroftMinimizer
+{
+ /** Create a DFA that is equivalent to a given DFA but has the minimal
+ * number of states.
+ */
+ public static FiniteAutomaton MinimizeDFA (
+ final StateContainer aNewStateContainer,
+ final StateContext aOriginalStates,
+ final Vector<Attribute> aAttributes,
+ final Location aLocation,
+ final PrintStream aLog)
+ {
+ if (aLog != null)
+ {
+ aLog.printf("minimizing %d states and %d transitions\n",
+ aOriginalStates.GetStateCount(),
+ aOriginalStates.GetTransitionCount());
+ DisplayStates(aOriginalStates, aLog);
+ }
+
+ TreeSet<StateSet> aT = new TreeSet<>();
+ TreeSet<StateSet> aP = new TreeSet<>();
+ Map<State,StateSet> aTMap = new HashMap<>();
+ Map<State,StateSet> aPMap = new HashMap<>();
+ InitializeMap(aT, aTMap, aOriginalStates.GetStates());
+
+ // Split partitions until there is nothing else to do.
+ while ( ! AreSetsOfStateSetsEqual(aP, aT))
+ {
+ if (aLog != null)
+ aLog.printf("T has %d members\n", aT.size());
+
+ aP = aT;
+ aPMap = aTMap;
+ aT = new TreeSet<>();
+ aTMap = new HashMap<>();
+
+ for (final StateSet aSet : aP)
+ {
+ final Iterable<StateSet> aParts = Split(aSet, aP, aPMap);
+ if (aParts == null)
+ {
+ // No split necessary.
+ assert( ! aSet.IsEmpty());
+ aT.add(aSet);
+ for (final State aState : aSet.GetStates())
+ aTMap.put(aState, aSet);
+ }
+ else
+ {
+ for (final StateSet aPart : aParts)
+ {
+ assert( ! aPart.IsEmpty());
+ aT.add(aPart);
+
+ for (final State aState : aPart.GetStates())
+ aTMap.put(aState, aPart);
+ }
+ }
+ }
+ }
+
+ // Create new states.
+ final StateContext aMinimizedStates = CreateNewStates(
+ aP,
+ aPMap,
+ aNewStateContainer,
+ aOriginalStates);
+
+ if (aLog != null)
+ {
+ aLog.printf("to %d states and %d transitions\n",
+ aMinimizedStates.GetStateCount(),
+ aMinimizedStates.GetTransitionCount());
+ DisplayStates(aMinimizedStates, aLog);
+ for (final StateSet aSet : aT)
+ aLog.printf(" %s\n", aSet.toString());
+ }
+
+ // Create and return the new minimized automaton.
+ return new FiniteAutomaton(
+ aMinimizedStates,
+ aAttributes,
+ aLocation);
+ }
+
+
+
+
+ /** We start with two sets. One contains all start states (in our case
+ * just one), the other contains all other states.
+ */
+ private static void InitializeMap (
+ final Set<StateSet> aSet,
+ final Map<State,StateSet> aMap,
+ final Iterable<State> aStates)
+ {
+ final StateSet aAcceptingStates = new StateSet();
+ final StateSet aNonAcceptingStates = new StateSet();
+ for (final State aState : aStates)
+ {
+ if (aState.IsAccepting())
+ {
+ aAcceptingStates.AddState(aState);
+ aMap.put(aState, aAcceptingStates);
+ }
+ else
+ {
+ aNonAcceptingStates.AddState(aState);
+ aMap.put(aState, aNonAcceptingStates);
+ }
+ }
+ if (aAcceptingStates.IsEmpty())
+ throw new RuntimeException("there should be at least one accepting state");
+ aSet.add(aAcceptingStates);
+ if ( ! aNonAcceptingStates.IsEmpty())
+ aSet.add(aNonAcceptingStates);
+ }
+
+
+
+
+ private static Iterable<StateSet> Split (
+ final StateSet aSet,
+ final Set<StateSet> aT,
+ final Map<State,StateSet> aTMap)
+ {
+ if (aSet.GetStateCount() == 1)
+ return null;
+
+ final Set<QualifiedName> aElements = CollectElementNames(aSet);
+ for (final QualifiedName aElementName : aElements)
+ {
+ final Collection<StateSet> aPartitions = Split(aSet, aT, aTMap, aElementName);
+ if (aPartitions == null)
+ continue;
+ if (aPartitions.size() > 1)
+ return aPartitions;
+ }
+ return null;
+ }
+
+
+
+
+ /** Create a partition of the given set of states according to their
+ * transitions.
+ * All states whose transitions point to the same state set go in the same
+ * partition.
+ */
+ private static Collection<StateSet> Split (
+ final StateSet aSet,
+ final Set<StateSet> aT,
+ final Map<State,StateSet> aTMap,
+ final QualifiedName aElementName)
+ {
+ // Set up a forward map that does two steps:
+ // from s via transition regarding aElementName to s'
+ // from s' to a state set under aTMap(s).
+ final Map<State,StateSet> aForwardMap = new HashMap<>();
+ for (final State aState : aSet.GetStates())
+ {
+ final Transition aTransition = GetTransition(aState, aElementName);
+ if (aTransition == null)
+ aForwardMap.put(aState, null);
+ else
+ aForwardMap.put(aState, aTMap.get(aTransition.GetEndState()));
+ }
+
+ // Create the partion of aSet according to aForwardMap. All states that map
+ // to the same element go into the same state set.
+ if (aForwardMap.size() == 1)
+ {
+ // No split necessary.
+ return null;
+ }
+ else
+ {
+ // Set up a reverse map that maps that maps the values in aForwardMap to
+ // new state sets whose contents are the keys in aForwardMap.
+ final Map<StateSet,StateSet> aReverseMap = new HashMap<>();
+ for (final Entry<State,StateSet> aEntry : aForwardMap.entrySet())
+ {
+ StateSet aPartitionSet = aReverseMap.get(aEntry.getValue());
+ if (aPartitionSet == null)
+ {
+ aPartitionSet = new StateSet();
+ aReverseMap.put(aEntry.getValue(), aPartitionSet);
+ }
+ aPartitionSet.AddState(aEntry.getKey());
+ }
+ return aReverseMap.values();
+ }
+ }
+
+
+
+
+ private static Transition GetTransition (
+ final State aState,
+ final QualifiedName aElementName)
+ {
+ Transition aTransition = null;
+ for (final Transition aCandidate : aState.GetTransitions())
+ if (aCandidate.GetElementName().compareTo(aElementName) == 0)
+ {
+ assert(aTransition==null);
+ aTransition = aCandidate;
+ // break;
+ }
+ return aTransition;
+ }
+
+
+
+
+ private static Set<QualifiedName> CollectElementNames (final StateSet aSet)
+ {
+ final Set<QualifiedName> aNames = new TreeSet<>();
+ for (final State aState : aSet.GetStates())
+ for (final Transition aTransition : aState.GetTransitions())
+ aNames.add(aTransition.GetElementName());
+
+ return aNames;
+ }
+
+
+
+
+ private static boolean AreSetsOfStateSetsEqual (
+ final TreeSet<StateSet> aSetOfSetsA,
+ final TreeSet<StateSet> aSetOfSetsB)
+ {
+ if (aSetOfSetsA.size() != aSetOfSetsB.size())
+ return false;
+ else
+ {
+ final Iterator<StateSet> aSetIteratorA = aSetOfSetsA.iterator();
+ final Iterator<StateSet> aSetIteratorB = aSetOfSetsB.iterator();
+ while (aSetIteratorA.hasNext() && aSetIteratorB.hasNext())
+ {
+ if (aSetIteratorA.next().compareTo(aSetIteratorB.next()) != 0)
+ return false;
+ }
+ return true;
+ }
+ }
+
+
+
+
+ private static StateContext CreateNewStates (
+ final TreeSet<StateSet> aP,
+ final Map<State,StateSet> aPMap,
+ final StateContainer aNewStateContainer,
+ final StateContext aOriginalStates)
+ {
+ final StateContext aMinimizedStates = new StateContext(
+ aNewStateContainer,
+ aOriginalStates.GetStartState().GetFullname());
+
+ // Create the new states.
+ final Map<State,State> aOldStateToNewStateMap = new TreeMap<>();
+ for (final StateSet aSet : aP)
+ {
+ State aNewState = null;
+ for (final State aOldState : aSet.GetStates())
+ {
+ if (aNewState == null)
+ aNewState = aOldState.Clone(aMinimizedStates);
+ aOldStateToNewStateMap.put(aOldState, aNewState);
+ }
+ }
+
+ // Create the new transitions.
+ for (final StateSet aSet : aP)
+ {
+ final State aOldStartState = aSet.GetStates().iterator().next();
+ final State aNewStartState = aOldStateToNewStateMap.get(aOldStartState);
+
+ for (final Transition aTransition : aOldStartState.GetTransitions())
+ {
+ final State aOldEndState = aTransition.GetEndState();
+ final State aNewEndState = aOldStateToNewStateMap.get(aOldEndState);
+
+ // Check if the transition already exists.
+ if (HasTransition(aNewStartState, aTransition.GetElementName()))
+ continue;
+
+ aNewStartState.AddTransition(
+ new Transition(
+ aNewStartState,
+ aNewEndState,
+ aTransition.GetElementName(),
+ aTransition.GetElementTypeName()));
+ }
+ }
+
+ // Transfer skip data and accepting flags.
+ for (final State aOldState : aOriginalStates.GetStates())
+ {
+ final State aNewState = aOldStateToNewStateMap.get(aOldState);
+ aNewState.CopyFrom(aOldState);
+ }
+ return aMinimizedStates;
+ }
+
+
+
+
+ private static boolean HasTransition (
+ final State aState,
+ final QualifiedName aElementName)
+ {
+ for (final Transition aTransition : aState.GetTransitions())
+ if (aTransition.GetElementName().compareTo(aElementName) == 0)
+ return true;
+ return false;
+ }
+
+
+
+
+ private static void DisplayStates (
+ final StateContext aStates,
+ final PrintStream aLog)
+ {
+ for (final State aState : aStates.GetStates())
+ {
+ aLog.printf(" %s %s\n", aState.GetFullname(),
+ aState.IsAccepting() ? "is accepting" : "");
+ for (final Transition aTransition : aState.GetTransitions())
+ aLog.printf(" -> %s via %s\n",
+ aTransition.GetEndState().GetFullname(),
+ aTransition.GetElementName().GetStateName());
+ }
+ }
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/NonValidatingCreator.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/NonValidatingCreator.java
new file mode 100644
index 000000000000..f96e3237a431
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/NonValidatingCreator.java
@@ -0,0 +1,212 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.schema.automaton;
+
+import java.io.File;
+import java.util.Vector;
+
+import org.apache.openoffice.ooxml.schema.iterator.DereferencingNodeIterator;
+import org.apache.openoffice.ooxml.schema.model.base.INode;
+import org.apache.openoffice.ooxml.schema.model.base.NodeType;
+import org.apache.openoffice.ooxml.schema.model.complex.Any;
+import org.apache.openoffice.ooxml.schema.model.complex.ComplexType;
+import org.apache.openoffice.ooxml.schema.model.complex.Element;
+import org.apache.openoffice.ooxml.schema.model.schema.Schema;
+import org.apache.openoffice.ooxml.schema.model.schema.SchemaBase;
+
+/** Create a set of stack automatons for a given set of schemas.
+ * Creates one automaton for each complex type and one for the top level elements.
+ *
+ * Input files but are not validated to conform to the schemas.
+ */
+public class NonValidatingCreator
+ extends CreatorBase
+{
+ public NonValidatingCreator (
+ final SchemaBase aSchemaBase,
+ final File aLogFile)
+ {
+ super(aSchemaBase, aLogFile);
+ }
+
+
+
+
+ public FiniteAutomatonContainer Create (
+ final Iterable<Schema> aTopLevelSchemas)
+ {
+ final FiniteAutomatonContainer aAutomatons = new FiniteAutomatonContainer(maStateContainer);
+
+ // Create a single automaton for all top level elements.
+ aAutomatons.AddAutomaton(
+ null,
+ CreateForTopLevelElements(aTopLevelSchemas));
+
+ // Create one automaton for each complex type.
+ for (final ComplexType aComplexType : maSchemaBase.ComplexTypes.GetSorted())
+ aAutomatons.AddAutomaton(
+ aComplexType.GetName(),
+ CreateForComplexType(aComplexType));
+
+ // Create one automaton for each simple type that is referenced by an element.
+ for (final INode aSimpleType : maElementSimpleTypes)
+ aAutomatons.AddAutomaton(
+ aSimpleType.GetName(),
+ CreateForSimpleType(aSimpleType));
+
+ maLog.Close();
+
+ return aAutomatons;
+ }
+
+
+
+
+ private FiniteAutomaton CreateForTopLevelElements (
+ final Iterable<Schema> aTopLevelSchemas)
+ {
+ maLog.AddComment("top level elements");
+ maLog.StartBlock();
+ final String sTypeName = "<top-level>";
+ final StateContext aStateContext = new StateContext(
+ maStateContainer,
+ sTypeName);
+ final State aStartState = aStateContext.GetStartState();
+ final State aEndState = aStateContext.CreateEndState();
+
+ // top level elements
+ for (final Schema aSchema : aTopLevelSchemas)
+ {
+ maLog.AddComment("schema %s", aSchema.GetShortName());
+ maLog.StartBlock();
+ for (final Element aElement : aSchema.TopLevelElements.GetSorted())
+ {
+ maLog.AddComment("Element: on '%s' go from %s to %s via %s",
+ aElement.GetElementName().GetDisplayName(),
+ aStartState.GetFullname(),
+ aEndState.GetFullname(),
+ aElement.GetTypeName().GetStateName());
+
+ aStateContext.GetStartState().AddTransition(
+ new Transition(
+ aStartState,
+ aEndState,
+ aElement.GetElementName(),
+ aElement.GetTypeName().GetStateName()));
+ }
+ maLog.EndBlock();
+ }
+ maLog.EndBlock();
+
+ return new FiniteAutomaton(aStateContext, null, null);
+ }
+
+
+
+
+ private FiniteAutomaton CreateForComplexType (final ComplexType aComplexType)
+ {
+ maLog.printf("\n");
+ maLog.AddComment ("Complex Type %s defined in %s.",
+ aComplexType.GetName().GetDisplayName(),
+ aComplexType.GetLocation());
+ maLog.StartBlock();
+
+ final StateContext aStateContext = new StateContext(
+ maStateContainer,
+ aComplexType.GetName().GetStateName());
+
+ for (final Element aElement : CollectElements(aComplexType))
+ {
+ maLog.AddComment("Element: on '%s' go from %s to %s via %s",
+ aElement.GetElementName().GetDisplayName(),
+ aStateContext.GetStartState().GetFullname(),
+ aStateContext.GetStartState().GetFullname(),
+ aElement.GetTypeName().GetStateName());
+
+ aStateContext.GetStartState().AddTransition(
+ new Transition(
+ aStateContext.GetStartState(),
+ aStateContext.GetStartState(),
+ aElement.GetElementName(),
+ aElement.GetTypeName().GetStateName()));
+
+ // For elements whose type is a simple type we have to remember that
+ // simple type for later (and then create an NFA for it.)
+ final INode aSimpleType = maSchemaBase.GetSimpleTypeForName(
+ aElement.GetTypeName());
+ if (aSimpleType != null)
+ maElementSimpleTypes.add(aSimpleType);
+ }
+
+ for (final Any aAny : CollectAnys(aComplexType))
+ {
+ AddSkipTransition(
+ aStateContext.GetStartState(),
+ new SkipData(
+ aAny.GetProcessContentsFlag(),
+ aAny.GetNamespaces()));
+ }
+
+ // Collect all attributes.
+ maAttributes = new Vector<>();
+ for (final INode aNode : new DereferencingNodeIterator(aComplexType, maSchemaBase, true))
+ ProcessAttributes(aNode);
+
+ aStateContext.GetStartState().SetIsAccepting();
+
+ maLog.EndBlock();
+
+ return new FiniteAutomaton(aStateContext, maAttributes, aComplexType.GetLocation());
+ }
+
+
+
+
+ /** Collect all elements inside the type tree that is rooted in the given
+ * complex type.
+ */
+ private Vector<Element> CollectElements (final ComplexType aType)
+ {
+ final Vector<Element> aElements = new Vector<>();
+ for (final INode aNode : new DereferencingNodeIterator(aType, maSchemaBase, false))
+ {
+ if (aNode.GetNodeType() == NodeType.Element)
+ aElements.add((Element)aNode);
+ }
+ return aElements;
+ }
+
+
+
+
+ private Vector<Any> CollectAnys (final ComplexType aType)
+ {
+ final Vector<Any> aAnys = new Vector<>();
+ for (final INode aNode : new DereferencingNodeIterator(aType, maSchemaBase, false))
+ {
+ if (aNode.GetNodeType() == NodeType.Any)
+ aAnys.add((Any)aNode);
+ }
+ return aAnys;
+ }
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/SkipData.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/SkipData.java
new file mode 100644
index 000000000000..f5c051caad4d
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/SkipData.java
@@ -0,0 +1,54 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.schema.automaton;
+
+import org.apache.openoffice.ooxml.schema.model.complex.Any;
+
+/** Description of optional content that can be skipped when not supported.
+ * Corresponds to the 'any' schema element.
+ */
+public class SkipData
+{
+ public SkipData (
+ final Any.ProcessContents aProcessContents,
+ final String[] aNamespaces)
+ {
+ maProcessContents = aProcessContents;
+ maNamespaces = aNamespaces;
+ }
+
+
+
+
+ public SkipData Clone (final State aState)
+ {
+ return new SkipData(
+ maProcessContents,
+ maNamespaces);
+ }
+
+
+
+
+ final Any.ProcessContents maProcessContents;
+ final String[] maNamespaces;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/State.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/State.java
new file mode 100644
index 000000000000..7d9982c0e5c2
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/State.java
@@ -0,0 +1,263 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.schema.automaton;
+
+import java.util.Vector;
+
+import org.apache.openoffice.ooxml.schema.model.base.INode;
+import org.apache.openoffice.ooxml.schema.model.base.QualifiedName;
+
+/** Each complex type is represented by a State object (primary state).
+ * For a validating parser additional states are created for sequences, choices, etc. (secondary states).
+ * Secondary states have the same basename as primary states and suffixes to make their names unique.
+ * Full names of states contain both the basename and the suffix.
+ */
+public class State
+ implements Comparable<State>
+{
+ /** Create a new state from a basename and an optional suffix.
+ *
+ * Don't call this constructor directly. Use methods in StateContext instead.
+ * They ensure that states are unique per context.
+ */
+ State (
+ final QualifiedName aBasename,
+ final String sSuffix)
+ {
+ maBasename = aBasename;
+ msSuffix = sSuffix;
+ msFullname = GetStateName(aBasename, msSuffix);
+ maTransitions = new Vector<>();
+ maEpsilonTransitions = new Vector<>();
+ maSkipData = new Vector<>();
+ mbIsAccepting = false;
+ maTextType = null;
+ }
+
+
+
+
+ State Clone (final StateContext aContext)
+ {
+ return aContext.GetOrCreateState(maBasename, msSuffix);
+ }
+
+
+
+
+ static String GetStateName (
+ final QualifiedName aBasename,
+ final String sSuffix)
+ {
+ if (sSuffix == null)
+ return aBasename.GetStateName();
+ else
+ return aBasename.GetStateName()+"_"+sSuffix;
+ }
+
+
+
+
+ public String GetFullname ()
+ {
+ return msFullname;
+ }
+
+
+
+
+ public QualifiedName GetBasename ()
+ {
+ return maBasename;
+ }
+
+
+
+
+ /** Return a qualified name that contains the suffix.
+ * This is typically only used for sorting type names.
+ */
+ public QualifiedName GetQualifiedName ()
+ {
+ return new QualifiedName(
+ maBasename.GetNamespacePrefix(),
+ maBasename.GetNamespaceURI(),
+ msSuffix != null
+ ? maBasename.GetLocalPart() + "_" + msSuffix
+ : maBasename.GetLocalPart());
+ }
+
+
+
+
+ public String GetSuffix ()
+ {
+ return msSuffix;
+ }
+
+
+
+
+ public void AddTransition (final Transition aTransition)
+ {
+ assert(this == aTransition.GetStartState());
+ maTransitions.add(aTransition);
+ }
+
+
+
+
+ public Iterable<Transition> GetTransitions()
+ {
+ return maTransitions;
+ }
+
+
+
+
+ public int GetTransitionCount ()
+ {
+ return maTransitions.size();
+ }
+
+
+
+
+ public void AddEpsilonTransition (final EpsilonTransition aTransition)
+ {
+ assert(this == aTransition.GetStartState());
+ maEpsilonTransitions.add(aTransition);
+ }
+
+
+
+
+ public Iterable<EpsilonTransition> GetEpsilonTransitions()
+ {
+ return maEpsilonTransitions;
+ }
+
+
+
+
+ public void AddSkipData (final SkipData aSkipData)
+ {
+ maSkipData.add(aSkipData);
+ }
+
+
+
+
+ public Iterable<SkipData> GetSkipData ()
+ {
+ return maSkipData;
+ }
+
+
+
+
+ public void SetIsAccepting ()
+ {
+ mbIsAccepting = true;
+ }
+
+
+
+
+ public boolean IsAccepting ()
+ {
+ return mbIsAccepting;
+ }
+
+
+
+
+ /** The basename is the primary sort key. The suffix is the secondary key.
+ */
+ @Override
+ public int compareTo (final State aOther)
+ {
+ int nResult = maBasename.compareTo(aOther.maBasename);
+ if (nResult == 0)
+ {
+ if (msSuffix==null && aOther.msSuffix==null)
+ nResult = 0;
+ else if (msSuffix!=null && aOther.msSuffix!=null)
+ nResult = msSuffix.compareTo(aOther.msSuffix);
+ else if (msSuffix==null)
+ nResult = -1;
+ else
+ nResult = +1;
+ }
+ return nResult;
+ }
+
+
+
+
+ public void SetTextType (final INode aTextType)
+ {
+ assert(maTextType==null);
+ maTextType = aTextType;
+ }
+
+
+
+
+ public INode GetTextType ()
+ {
+ return maTextType;
+ }
+
+
+
+
+ public void CopyFrom (final State aOther)
+ {
+ if (aOther.IsAccepting())
+ SetIsAccepting();
+ for (final SkipData aSkipData : aOther.GetSkipData())
+ AddSkipData(aSkipData.Clone(this));
+ SetTextType(aOther.GetTextType());
+ }
+
+
+
+
+ @Override
+ public String toString ()
+ {
+ return msFullname;
+ }
+
+
+
+
+ private final QualifiedName maBasename;
+ private final String msSuffix;
+ private final String msFullname;
+ private final Vector<Transition> maTransitions;
+ private final Vector<EpsilonTransition> maEpsilonTransitions;
+ private final Vector<SkipData> maSkipData;
+ private boolean mbIsAccepting;
+ private INode maTextType;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/StateContainer.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/StateContainer.java
new file mode 100644
index 000000000000..2a8df93c96d5
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/StateContainer.java
@@ -0,0 +1,73 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.schema.automaton;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/** A container of states that spans all StateContext objects that represent each
+ * a single complex type.
+ */
+public class StateContainer
+{
+ public StateContainer ()
+ {
+ maNameToStateMap = new HashMap<>();
+ }
+
+
+
+
+ boolean HasState (final String sFullname)
+ {
+ return maNameToStateMap.containsKey(sFullname);
+ }
+
+
+
+
+ State GetStateForFullname (final String sFullname)
+ {
+ return maNameToStateMap.get(sFullname);
+ }
+
+
+
+
+ public void AddState (final State aState)
+ {
+ maNameToStateMap.put(aState.GetFullname(), aState);
+ }
+
+
+
+
+ public void RemoveState (final State aState)
+ {
+ maNameToStateMap.remove(aState);
+ }
+
+
+
+
+ private final Map<String,State> maNameToStateMap;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/StateContext.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/StateContext.java
new file mode 100644
index 000000000000..f2d877f2bdc1
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/StateContext.java
@@ -0,0 +1,269 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.schema.automaton;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.Vector;
+
+import org.apache.openoffice.ooxml.schema.model.base.QualifiedName;
+
+/** Represents the set of states of a single complex type.
+ *
+ * Because states have to be unique, the state container is an object shared
+ * by all StateContext objects.
+ *
+ * There is a single start state but there can be more than one accepting state.
+ */
+public class StateContext
+{
+ public StateContext (
+ final StateContainer aStateContainer,
+ final String sBaseStateName)
+ {
+ maStateContainer = aStateContainer;
+ maStates = new HashSet<>();
+ maStartState = GetOrCreateState(new QualifiedName(null, null, sBaseStateName), null);
+ maDisambiguateCounters = new HashMap<>();
+ }
+
+
+
+
+ public State CreateState (
+ final QualifiedName aBasename,
+ final String sSuffix)
+ {
+ final String sFullname = State.GetStateName(aBasename, sSuffix);
+ if (HasState(sFullname))
+ throw new RuntimeException("state with name '"+sFullname+"' can not be created because it already exists");
+ final State aState = new State(aBasename, sSuffix);
+ AddState(aState);
+ return aState;
+ }
+
+
+
+ public State CreateState (final String sBasename)
+ {
+ return CreateState(new QualifiedName(sBasename), null);
+ }
+
+
+
+
+ public State CreateState (
+ final State aState,
+ final String sSuffix)
+ {
+ if (sSuffix==null && aState.GetSuffix()==null)
+ return CreateState(aState.GetBasename(), null);
+ else if (sSuffix!=null && aState.GetSuffix()!=null)
+ return CreateState(aState.GetBasename(), aState.GetSuffix()+"_"+sSuffix);
+ else if (sSuffix != null)
+ return CreateState(aState.GetBasename(), sSuffix);
+ else
+ return CreateState(aState.GetBasename(), aState.GetSuffix());
+ }
+
+
+
+
+ public State GetState (
+ final QualifiedName aBasename,
+ final String sSuffix)
+ {
+ return maStateContainer.GetStateForFullname(State.GetStateName(aBasename, sSuffix));
+ }
+
+
+
+
+ public State GetOrCreateState (
+ final QualifiedName aBasename,
+ final String sSuffix)
+ {
+ State aState = GetState(aBasename, sSuffix);
+ if (aState == null)
+ {
+ aState = CreateState(aBasename, sSuffix);
+ AddState(aState);
+ }
+ return aState;
+ }
+
+
+
+
+ public State GetStartStateForTypeName (final QualifiedName aName)
+ {
+ return GetOrCreateState(aName, null);
+ }
+
+
+
+
+ public State CreateEndState ()
+ {
+ final State aEndState = CreateState(
+ maStartState.GetBasename(),
+ "end");
+ aEndState.SetIsAccepting();
+ return aEndState;
+ }
+
+
+
+ /** Some algorithms can not easily produce unique suffixes.
+ * Append an integer to the given suffix so that it becomes unique.
+ */
+ public String GetUnambiguousSuffix (final QualifiedName aBasename, final String sSuffix)
+ {
+ String sStateName = State.GetStateName(aBasename, sSuffix);
+ if ( ! HasState(sStateName))
+ {
+ // The given suffix can be used without modification.
+ return sSuffix;
+ }
+ else
+ {
+ int nIndex = 2;
+ final Integer nDisambiguateCounter = maDisambiguateCounters.get(sStateName);
+ if (nDisambiguateCounter != null)
+ nIndex = nDisambiguateCounter+1;
+ maDisambiguateCounters.put(sStateName, nIndex);
+
+ return sSuffix + "_" + nIndex;
+ }
+ }
+
+
+
+
+ public boolean HasState (
+ final QualifiedName aBasename,
+ final String sSuffix)
+ {
+ return maStateContainer.HasState(State.GetStateName(aBasename, sSuffix));
+ }
+
+
+
+
+ /** Return whether a state with the given name already belongs to the state
+ * context.
+ */
+ public boolean HasState (final String sFullname)
+ {
+ return maStateContainer.HasState(sFullname);
+ }
+
+
+
+
+ /** The start state is the state a parser is in initially.
+ */
+ public State GetStartState ()
+ {
+ return maStartState;
+ }
+
+
+
+
+ public Iterable<State> GetAcceptingStates ()
+ {
+ final Vector<State> aAcceptingStates = new Vector<>();
+ for (final State aState : maStates)
+ if (aState.IsAccepting())
+ aAcceptingStates.add(aState);
+ return aAcceptingStates;
+ }
+
+
+
+
+ /** Add the given state to the state context.
+ */
+ public void AddState (final State aState)
+ {
+ maStateContainer.AddState(aState);
+ maStates.add(aState);
+ }
+
+
+
+
+ public void RemoveState (final State aState)
+ {
+ maStateContainer.RemoveState(aState);
+ maStates.remove(aState);
+ }
+
+
+
+
+ public int GetStateCount ()
+ {
+ return maStates.size();
+ }
+
+
+
+
+ public Iterable<State> GetStatesSorted()
+ {
+ final Set<State> aSortedStates = new TreeSet<>();
+ aSortedStates.addAll(maStates);
+ return aSortedStates;
+ }
+
+
+
+
+ public Iterable<State> GetStates()
+ {
+ return maStates;
+ }
+
+
+
+
+ public int GetTransitionCount ()
+ {
+ int nStateCount = 0;
+ for (final State aState : maStates)
+ nStateCount += aState.GetTransitionCount();
+ return nStateCount;
+ }
+
+
+
+
+ private final StateContainer maStateContainer;
+ private final Set<State> maStates;
+ private final State maStartState;
+ private final Map<String,Integer> maDisambiguateCounters;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/StateSet.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/StateSet.java
new file mode 100644
index 000000000000..bac2092104fe
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/StateSet.java
@@ -0,0 +1,245 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.schema.automaton;
+
+import java.util.Iterator;
+import java.util.Set;
+import java.util.TreeSet;
+
+import org.apache.openoffice.ooxml.schema.model.base.INode;
+import org.apache.openoffice.ooxml.schema.model.base.QualifiedName;
+
+/** Used in the transformation of NFA to DFA and in the minimization of DFAs.
+ * References a set of regular states.
+ */
+public class StateSet
+ implements Comparable<StateSet>
+{
+ public StateSet ()
+ {
+ maStates = new TreeSet<>();
+ }
+
+
+
+
+ public StateSet (final State aState)
+ {
+ this();
+ maStates.add(aState);
+ }
+
+
+
+
+ public StateSet (final StateSet aSet)
+ {
+ this();
+ maStates.addAll(aSet.maStates);
+ }
+
+
+
+
+ public StateSet (final Iterable<State> aStates)
+ {
+ this();
+ for (final State aState : aStates)
+ maStates.add(aState);
+ }
+
+
+
+
+ public void AddState (final State aState)
+ {
+ maStates.add(aState);
+ }
+
+
+
+
+ public void AddStates (final StateSet aStates)
+ {
+ maStates.addAll(aStates.maStates);
+ }
+
+
+
+
+ public boolean IsDisjoint (final StateSet aOther)
+ {
+ for (final State aState : aOther.maStates)
+ if (maStates.contains(aState))
+ return false;
+ for (final State aState : maStates)
+ if (aOther.maStates.contains(aState))
+ return false;
+ return true;
+ }
+
+
+
+
+ public void RemoveState (final State aState)
+ {
+ maStates.remove(aState);
+ }
+
+
+
+
+ public Iterable<State> GetStates ()
+ {
+ return maStates;
+ }
+
+
+
+
+ public boolean ContainsState (final State aState)
+ {
+ return maStates.contains(aState);
+ }
+
+
+
+
+ public int GetStateCount ()
+ {
+ return maStates.size();
+ }
+
+
+
+
+ public boolean HasStates ()
+ {
+ return ! maStates.isEmpty();
+ }
+
+
+
+
+ public State CreateStateForStateSet (final StateContext aContext)
+ {
+ // Find a name for the new state. If there is type state in the given
+ // set then use its name.
+ QualifiedName aBaseName = null;
+ String sShortestSuffix = null;
+ for (final State aState : maStates)
+ {
+ final QualifiedName aName = aState.GetBasename();
+ final String sSuffix = aState.GetSuffix();
+
+ if (aBaseName == null)
+ {
+ aBaseName = aName;
+ sShortestSuffix = sSuffix;
+ }
+ else if (aBaseName.compareTo(aName) != 0)
+ {
+ System.out.printf("%s != %s\n", aBaseName, aName);
+ throw new RuntimeException("state set contains states with different base names: "+toString());
+ }
+
+ if (sShortestSuffix == null)
+ sShortestSuffix = sSuffix;
+ else if (sSuffix.length() < sShortestSuffix.length())
+ sShortestSuffix = sSuffix;
+ }
+ if (aBaseName == null)
+ throw new RuntimeException("can not create state for "+toString());
+
+ // Disambiguate new state name.
+ State aNewState = aContext.CreateState(
+ aBaseName,
+ aContext.GetUnambiguousSuffix(aBaseName, sShortestSuffix));
+ assert(aNewState!=null);
+
+ // Mark the new state as accepting if at least one of its original states
+ // is accepting.
+ for (final State aState : maStates)
+ {
+ if (aState.IsAccepting())
+ {
+ aNewState.SetIsAccepting();
+ break;
+ }
+ for (final SkipData aData : aState.GetSkipData())
+ aNewState.AddSkipData(aData.Clone(aNewState));
+ final INode aTextType = aState.GetTextType();
+ if (aTextType != null)
+ aNewState.SetTextType(aTextType);
+ }
+
+ return aNewState;
+ }
+
+
+
+
+ @Override
+ public int compareTo (final StateSet aOther)
+ {
+ final int nStateCount = maStates.size();
+
+ if (nStateCount != aOther.maStates.size())
+ return nStateCount - aOther.maStates.size();
+ else
+ {
+ final Iterator<State> aIterator = maStates.iterator();
+ final Iterator<State> aOtherIterator = aOther.maStates.iterator();
+ while (aIterator.hasNext())
+ {
+ final State aState = aIterator.next();
+ final State aOtherState = aOtherIterator.next();
+ final int nResult = aState.compareTo(aOtherState);
+ if (nResult != 0)
+ return nResult;
+ }
+ return 0;
+ }
+ }
+
+
+
+
+ public boolean IsEmpty()
+ {
+ return maStates.isEmpty();
+ }
+
+
+
+
+ @Override
+ public String toString ()
+ {
+ return "set of "+maStates.size()+" states "+maStates.toString();
+ }
+
+
+
+
+ private final Set<State> maStates;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/Transition.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/Transition.java
new file mode 100644
index 000000000000..ffacb1ad5ef9
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/Transition.java
@@ -0,0 +1,97 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.schema.automaton;
+
+import org.apache.openoffice.ooxml.schema.model.base.QualifiedName;
+
+/** Each transition corresponds to an 'element' schema element.
+ * It moves from the start state to the end state when a certain start tag is
+ * processed. The element corresponds to another complex type which will be
+ * parsed during the transition.
+ */
+public class Transition
+{
+ public Transition (
+ final State aStartState,
+ final State aEndState,
+ final QualifiedName aElementName,
+ final String sElementTypeName)
+ {
+ maStartState = aStartState;
+ maEndState = aEndState;
+ maElementName = aElementName;
+ msElementTypeName = sElementTypeName;
+ }
+
+
+
+
+ public State GetStartState ()
+ {
+ return maStartState;
+ }
+
+
+
+
+ public State GetEndState ()
+ {
+ return maEndState;
+ }
+
+
+
+
+ public QualifiedName GetElementName()
+ {
+ return maElementName;
+ }
+
+
+
+
+ public String GetElementTypeName()
+ {
+ return msElementTypeName;
+ }
+
+
+
+
+ @Override
+ public String toString ()
+ {
+ return String.format("%s --'%s'-> %s (via %s)\n",
+ maStartState.GetFullname(),
+ maElementName.GetDisplayName(),
+ maEndState.GetFullname(),
+ msElementTypeName);
+ }
+
+
+
+
+ private final State maStartState;
+ private final State maEndState;
+ private final QualifiedName maElementName;
+ private final String msElementTypeName;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/ValidatingCreator.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/ValidatingCreator.java
new file mode 100644
index 000000000000..c0dd5acf1781
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/automaton/ValidatingCreator.java
@@ -0,0 +1,793 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.schema.automaton;
+
+import java.io.File;
+import java.util.Iterator;
+import java.util.Stack;
+import java.util.Vector;
+
+import org.apache.openoffice.ooxml.schema.iterator.DereferencingNodeIterator;
+import org.apache.openoffice.ooxml.schema.iterator.PermutationIterator;
+import org.apache.openoffice.ooxml.schema.model.attribute.Attribute;
+import org.apache.openoffice.ooxml.schema.model.attribute.AttributeGroup;
+import org.apache.openoffice.ooxml.schema.model.attribute.AttributeGroupReference;
+import org.apache.openoffice.ooxml.schema.model.attribute.AttributeReference;
+import org.apache.openoffice.ooxml.schema.model.base.INode;
+import org.apache.openoffice.ooxml.schema.model.base.INodeVisitor;
+import org.apache.openoffice.ooxml.schema.model.base.Location;
+import org.apache.openoffice.ooxml.schema.model.base.NodeVisitorAdapter;
+import org.apache.openoffice.ooxml.schema.model.complex.All;
+import org.apache.openoffice.ooxml.schema.model.complex.Any;
+import org.apache.openoffice.ooxml.schema.model.complex.Choice;
+import org.apache.openoffice.ooxml.schema.model.complex.ComplexContent;
+import org.apache.openoffice.ooxml.schema.model.complex.ComplexType;
+import org.apache.openoffice.ooxml.schema.model.complex.ComplexTypeReference;
+import org.apache.openoffice.ooxml.schema.model.complex.Element;
+import org.apache.openoffice.ooxml.schema.model.complex.ElementReference;
+import org.apache.openoffice.ooxml.schema.model.complex.Extension;
+import org.apache.openoffice.ooxml.schema.model.complex.Group;
+import org.apache.openoffice.ooxml.schema.model.complex.GroupReference;
+import org.apache.openoffice.ooxml.schema.model.complex.OccurrenceIndicator;
+import org.apache.openoffice.ooxml.schema.model.complex.Sequence;
+import org.apache.openoffice.ooxml.schema.model.schema.SchemaBase;
+import org.apache.openoffice.ooxml.schema.model.simple.BuiltIn;
+import org.apache.openoffice.ooxml.schema.model.simple.List;
+import org.apache.openoffice.ooxml.schema.model.simple.Restriction;
+import org.apache.openoffice.ooxml.schema.model.simple.SimpleContent;
+import org.apache.openoffice.ooxml.schema.model.simple.SimpleType;
+import org.apache.openoffice.ooxml.schema.model.simple.SimpleTypeReference;
+import org.apache.openoffice.ooxml.schema.model.simple.Union;
+
+/** Create a set of validating stack automatons for a set of schemas.
+ * There is one DFA (deterministic finite automaton) for each complex type and
+ * one for the top level elements.
+ */
+public class ValidatingCreator
+ extends CreatorBase
+ implements INodeVisitor
+{
+ public ValidatingCreator (
+ final SchemaBase aSchemaBase,
+ final File aLogFile)
+ {
+ super(aSchemaBase, aLogFile);
+ maContextStack = new Stack<>();
+ maCurrentContext = null;
+ }
+
+
+
+
+ /** Create one automaton for the top-level elements and one for each complex
+ * type.
+ */
+ public FiniteAutomatonContainer Create ()
+ {
+ final FiniteAutomatonContainer aAutomatons = new FiniteAutomatonContainer(maStateContainer);
+
+ // Create the automaton for the top-level elements.
+ aAutomatons.AddAutomaton(
+ null,
+ CreateForTopLevelElements());
+
+ // Create one automation for each complex type.
+ for (final ComplexType aComplexType : maSchemaBase.ComplexTypes.GetSorted())
+ aAutomatons.AddAutomaton(
+ aComplexType.GetName(),
+ CreateForComplexType(aComplexType));
+
+ // Create one automaton for each simple type that is referenced by an element.
+ for (final INode aSimpleType : maElementSimpleTypes)
+ aAutomatons.AddAutomaton(
+ aSimpleType.GetName(),
+ CreateForSimpleType(aSimpleType));
+
+ maLog.Close();
+
+ return aAutomatons;
+ }
+
+
+
+
+ private FiniteAutomaton CreateForTopLevelElements ()
+ {
+ maStateContext = new StateContext(
+ maStateContainer,
+ "<top-level>");
+ final State aEndState = maStateContext.CreateEndState();
+
+ assert(maContextStack.isEmpty());
+ msLogIndentation = "";
+
+ // top level elements
+ for (final Element aElement : maSchemaBase.TopLevelElements.GetSorted())
+ ProcessType(
+ aElement,
+ maStateContext.GetStartState(),
+ maStateContext.GetStartState(),
+ aEndState);
+
+ return new FiniteAutomaton(maStateContext, null, null);
+ }
+
+
+
+
+ private FiniteAutomaton CreateForComplexType (final ComplexType aComplexType)
+ {
+ maStateContext = new StateContext(
+ maStateContainer,
+ aComplexType.GetName().GetStateName());
+ maAttributes = new Vector<>();
+ final State aEndState = maStateContext.CreateEndState();
+ ProcessType(
+ aComplexType,
+ maStateContext.GetStartState(),
+ maStateContext.GetStartState(),
+ aEndState);
+ return new FiniteAutomaton(
+ maStateContext,
+ maAttributes,
+ aComplexType.GetLocation());
+ }
+
+
+
+
+ @Override
+ public void Visit (final All aAll)
+ {
+ maLog.AddComment("All");
+ ProcessAttributes(aAll);
+
+ // Make a transformation of the children into a choice of sequences that
+ // can then be processed by already existing Visit() methods.
+ // These sequences enumerate all permutations of the original children.
+ final INode aReplacement = GetAllReplacement(aAll);
+
+ final State aLocalStartState = maStateContext.CreateState(
+ maCurrentContext.BaseState,
+ "As");
+ final State aLocalEndState = maStateContext.CreateState(
+ maCurrentContext.BaseState,
+ "Ae");
+
+ maLog.StartBlock();
+ AddEpsilonTransition(maCurrentContext.StartState, aLocalStartState);
+ final long nStartTime = System.currentTimeMillis();
+ ProcessType(
+ aReplacement,
+ maStateContext.CreateState(maCurrentContext.BaseState, "A"),
+ aLocalStartState,
+ aLocalEndState);
+ final long nEndTime = System.currentTimeMillis();
+ System.out.printf("processed 'all' children in %fs\n", (nEndTime-nStartTime)/1000.0);
+ AddEpsilonTransition(aLocalEndState, maCurrentContext.EndState);
+ maLog.EndBlock();
+ }
+
+
+
+
+ @Override
+ public void Visit (final Any aAny)
+ {
+ assert(aAny.GetChildCount() == 0);
+
+ maLog.AddComment("Any");
+ ProcessAttributes(aAny);
+
+ AddSkipTransition(
+ maCurrentContext.StartState,
+ new SkipData(
+ aAny.GetProcessContentsFlag(),
+ aAny.GetNamespaces()));
+ AddEpsilonTransition(maCurrentContext.StartState, maCurrentContext.EndState);
+ }
+
+
+
+
+ @Override
+ public void Visit (final ComplexContent aComplexContent)
+ {
+ assert(aComplexContent.GetChildCount() == 1);
+
+ maLog.AddComment ("Complex Content.");
+ ProcessAttributes(aComplexContent);
+
+ maLog.StartBlock();
+ ProcessType(
+ aComplexContent.GetChildren().iterator().next(),
+ maCurrentContext.BaseState,
+ maCurrentContext.StartState,
+ maCurrentContext.EndState);
+ maLog.EndBlock();
+ }
+
+
+
+
+ @Override
+ public void Visit (final ComplexType aComplexType)
+ {
+ if (maLog != null)
+ {
+ maLog.printf("\n");
+ maLog.AddComment ("Complex Type %s defined in %s.",
+ aComplexType.GetName().GetDisplayName(),
+ aComplexType.GetLocation());
+ }
+ ProcessAttributes(aComplexType);
+
+ maLog.StartBlock();
+ maLog.printf("%sstarting at state %s\n", msLogIndentation, maCurrentContext.StartState.GetFullname());
+
+ if (GetElementCount(aComplexType) == 0)
+ {
+ // There are elements. Therefore there will be no transitions.
+ // The start state is accepting and the end state is not necessary.
+ maCurrentContext.StartState.SetIsAccepting();
+ maStateContext.RemoveState(maCurrentContext.EndState);
+ }
+
+ for (final INode aChild : aComplexType.GetChildren())
+ ProcessType(aChild, maCurrentContext.BaseState, maCurrentContext.StartState, maCurrentContext.EndState);
+
+ maLog.EndBlock();
+ }
+
+
+
+
+ @Override
+ public void Visit (final ComplexTypeReference aNode)
+ {
+ throw new RuntimeException("can not handle "+aNode.toString());
+ }
+
+
+
+
+ @Override
+ public void Visit (final Choice aChoice)
+ {
+ maLog.AddComment("Choice");
+ ProcessAttributes(aChoice);
+
+ final State aLocalStartState = maStateContext.CreateState(maCurrentContext.BaseState, "Cs");
+ final State aLocalEndState = maStateContext.CreateState(maCurrentContext.BaseState, "Ce");
+ maLog.StartBlock();
+ AddEpsilonTransition(maCurrentContext.StartState, aLocalStartState);
+
+ int nStateIndex = 0;
+ for (final INode aChild : aChoice.GetChildren())
+ {
+ ProcessType(
+ aChild,
+ maStateContext.CreateState(maCurrentContext.BaseState, "C"+nStateIndex++),
+ aLocalStartState,
+ aLocalEndState);
+ }
+ AddEpsilonTransition(aLocalEndState, maCurrentContext.EndState);
+ maLog.EndBlock();
+ }
+
+
+
+
+ @Override
+ public void Visit (final Element aElement)
+ {
+ assert(aElement.GetChildCount()==0);
+
+ maLog.AddComment("Element: on '%s' go from %s to %s via %s",
+ aElement.GetElementName().GetDisplayName(),
+ maCurrentContext.StartState.GetFullname(),
+ maCurrentContext.EndState.GetFullname(),
+ aElement.GetTypeName().GetStateName());
+ ProcessAttributes(aElement);
+
+ final Transition aTransition = new Transition(
+ maCurrentContext.StartState,
+ maCurrentContext.EndState,
+ aElement.GetElementName(),
+ aElement.GetTypeName().GetStateName());
+ maCurrentContext.StartState.AddTransition(aTransition);
+
+ // For elements whose type is a simple type we have to remember that
+ // simple type for later (and then create an NFA for it.)
+ final INode aSimpleType = maSchemaBase.GetSimpleTypeForName(
+ aElement.GetTypeName());
+ if (aSimpleType != null)
+ maElementSimpleTypes.add(aSimpleType);
+ }
+
+
+
+
+ @Override
+ public void Visit (final ElementReference aReference)
+ {
+ assert(aReference.GetChildCount() == 0);
+
+ maLog.AddComment("Element reference to %s", aReference.GetReferencedElementName());
+ ProcessAttributes(aReference);
+
+ final Element aElement = aReference.GetReferencedElement(maSchemaBase);
+ if (aElement == null)
+ throw new RuntimeException("can't find referenced element "+aReference.GetReferencedElementName());
+ maLog.StartBlock();
+ ProcessType(aElement, maCurrentContext.BaseState, maCurrentContext.StartState, maCurrentContext.EndState);
+ maLog.EndBlock();
+ }
+
+
+
+
+ /** Treat extension nodes like sequences (for now).
+ */
+ @Override
+ public void Visit (final Extension aExtension)
+ {
+ assert(aExtension.GetChildCount() <= 1);
+
+ maLog.AddComment("Extension of base type %s", aExtension.GetBaseTypeName());
+ ProcessAttributes(aExtension);
+
+ final Vector<INode> aNodes = aExtension.GetTypeNodes(maSchemaBase);
+
+ maLog.StartBlock();
+ int nStateIndex = 0;
+ State aCurrentState = maStateContext.CreateState(maCurrentContext.BaseState, "E"+nStateIndex++);
+ AddEpsilonTransition(maCurrentContext.StartState, aCurrentState);
+
+ State aNextState = maStateContext.CreateState(maCurrentContext.BaseState, "E"+nStateIndex++);
+ ProcessType(aExtension.GetReferencedNode(maSchemaBase), aCurrentState, aCurrentState, aNextState);
+ aCurrentState = aNextState;
+
+ for (final INode aChild : aNodes)
+ {
+ aNextState = maStateContext.CreateState(maCurrentContext.BaseState, "E"+nStateIndex++);
+ ProcessType(aChild, aCurrentState, aCurrentState, aNextState);
+ aCurrentState = aNextState;
+ }
+ AddEpsilonTransition(aCurrentState, maCurrentContext.EndState);
+ maLog.EndBlock();
+ }
+
+
+
+
+ @Override
+ public void Visit (final Group aGroup)
+ {
+ assert(aGroup.GetChildCount() == 1);
+
+ maLog.AddComment("Group %s", aGroup.GetName());
+ ProcessAttributes(aGroup);
+
+ maLog.StartBlock();
+ final State aGroupBaseState = maStateContext.CreateState(maCurrentContext.BaseState, "G");
+ ProcessType(
+ aGroup.GetOnlyChild(),
+ aGroupBaseState,
+ maCurrentContext.StartState,
+ maCurrentContext.EndState);
+ maLog.EndBlock();
+ }
+
+
+
+
+ @Override
+ public void Visit (final GroupReference aReference)
+ {
+ maLog.AddComment("Group reference to %s", aReference.GetReferencedGroupName());
+ ProcessAttributes(aReference);
+
+ final Group aGroup = aReference.GetReferencedGroup(maSchemaBase);
+ if (aGroup == null)
+ throw new RuntimeException("can't find referenced group "+aReference.GetReferencedGroupName());
+
+ maLog.StartBlock();
+ ProcessType(aGroup, maCurrentContext.BaseState, maCurrentContext.StartState, maCurrentContext.EndState);
+ maLog.EndBlock();
+ }
+
+
+
+
+ /** An occurrence indicator defines how many times the single child can occur.
+ * The minimum value defines the mandatory number of times. The maximum value
+ * defines the optional number.
+ */
+ @Override
+ public void Visit (final OccurrenceIndicator aOccurrence)
+ {
+ assert(aOccurrence.GetChildCount() == 1);
+
+ maLog.AddComment("OccurrenceIndicator %s->%s",
+ aOccurrence.GetDisplayMinimum(),
+ aOccurrence.GetDisplayMaximum());
+ ProcessAttributes(aOccurrence);
+
+ maLog.StartBlock();
+
+ final INode aChild = aOccurrence.GetChildren().iterator().next();
+
+ int nIndex = 0;
+ State aCurrentState = maStateContext.CreateState(maCurrentContext.BaseState, "O"+nIndex++);
+ AddEpsilonTransition(maCurrentContext.StartState, aCurrentState);
+
+ if (aOccurrence.GetMinimum() == 0)
+ {
+ // A zero minimum means that all occurrences are optional.
+ // Add a short circuit from start to end.
+ maLog.AddComment("Occurrence: make whole element optional (min==0)");
+ AddEpsilonTransition(maCurrentContext.StartState, maCurrentContext.EndState);
+ }
+ else
+ {
+ // Write a row of mandatory transitions for the minimum.
+ for (; nIndex<=aOccurrence.GetMinimum(); ++nIndex)
+ {
+ // Add transition i-1 -> i (i == nIndex).
+ final State aNextState = maStateContext.CreateState(maCurrentContext.BaseState, "O"+nIndex);
+ maLog.AddComment("Occurrence: move from %d -> %d (%s -> %s) (minimum)",
+ nIndex-1,
+ nIndex,
+ aCurrentState,
+ aNextState);
+ maLog.StartBlock();
+ ProcessType(aChild, aCurrentState, aCurrentState, aNextState);
+ maLog.EndBlock();
+ aCurrentState = aNextState;
+ }
+ }
+
+ if (aOccurrence.GetMaximum() == OccurrenceIndicator.unbounded)
+ {
+ // Write loop on last state when max is unbounded.
+
+ // last -> loop
+ final State aLoopState = maStateContext.CreateState(maCurrentContext.BaseState, "OL");
+ maLog.AddComment("Occurrence: forward to loop (maximum)");
+ AddEpsilonTransition(aCurrentState, aLoopState);
+
+ // loop -> loop
+ maLog.AddComment("Occurrence: loop");
+ maLog.StartBlock();
+ ProcessType(aChild, aLoopState, aLoopState, aLoopState);
+ maLog.EndBlock();
+
+ // -> end
+ maLog.AddComment("Occurrence: forward to local end");
+ AddEpsilonTransition(aLoopState, maCurrentContext.EndState);
+ }
+ else
+ {
+ // Write a row of optional transitions for the maximum.
+ for (; nIndex<=aOccurrence.GetMaximum(); ++nIndex)
+ {
+ if (nIndex > 0)
+ {
+ // i-1 -> end
+ maLog.AddComment("Occurrence: make %d optional (maximum)", nIndex-1);
+ AddEpsilonTransition(aCurrentState, maCurrentContext.EndState);
+ }
+
+ // i-1 -> i
+ final State aNextState = maStateContext.CreateState(maCurrentContext.BaseState, "O"+nIndex);
+ maLog.AddComment("Occurrence: %d -> %d (%s -> %s) (maximum)",
+ nIndex-1,
+ nIndex,
+ aCurrentState,
+ aNextState);
+ maLog.StartBlock();
+ ProcessType(aChild, aCurrentState, aCurrentState, aNextState);
+ maLog.EndBlock();
+
+ aCurrentState = aNextState;
+ }
+
+ // max -> end
+ maLog.AddComment("Occurrence: forward to local end");
+ AddEpsilonTransition(aCurrentState, maCurrentContext.EndState);
+ }
+ maLog.EndBlock();
+ }
+
+
+
+
+ /** Ordered sequence of nodes.
+ * For n nodes create states S0 to Sn where Si and Si+1 become start and
+ * end states for the i-th child.
+ */
+ @Override
+ public void Visit (final Sequence aSequence)
+ {
+ maLog.AddComment("Sequence.");
+ ProcessAttributes(aSequence);
+
+ maLog.StartBlock();
+ int nStateIndex = 0;
+ State aCurrentState = maStateContext.CreateState(maCurrentContext.BaseState, "S"+nStateIndex++);
+ AddEpsilonTransition(maCurrentContext.StartState, aCurrentState);
+ for (final INode aChild : aSequence.GetChildren())
+ {
+ final State aNextState = maStateContext.CreateState(maCurrentContext.BaseState, "S"+nStateIndex++);
+ ProcessType(aChild, aCurrentState, aCurrentState, aNextState);
+ aCurrentState = aNextState;
+ }
+ AddEpsilonTransition(aCurrentState, maCurrentContext.EndState);
+ maLog.EndBlock();
+ }
+
+
+
+
+ @Override
+ public void Visit (final BuiltIn aNode)
+ {
+ // Ignored.
+ //throw new RuntimeException("can not handle "+aNode.toString());
+ }
+
+
+
+
+ @Override
+ public void Visit (final List aNode)
+ {
+ throw new RuntimeException("can not handle "+aNode.toString());
+ }
+
+
+
+
+ @Override
+ public void Visit (final Restriction aNode)
+ {
+ throw new RuntimeException("can not handle "+aNode.toString());
+ }
+
+
+
+ @Override
+ public void Visit (final SimpleContent aNode)
+ {
+ maLog.AddComment("SimpleContent.");
+ ProcessAttributes(aNode);
+
+ for (final INode aChild : aNode.GetChildren())
+ ProcessType(aChild, maCurrentContext.BaseState, maCurrentContext.StartState, maCurrentContext.EndState);
+ }
+
+
+
+
+ @Override
+ public void Visit (final SimpleType aNode)
+ {
+ maLog.AddComment("SimpleType.");
+ //for (final INode aChild : aNode.GetChildren())
+ //ProcessType(aChild, maCurrentContext.BaseState, maCurrentContext.StartState, maCurrentContext.EndState);
+ }
+
+
+
+
+ @Override
+ public void Visit (final SimpleTypeReference aNode)
+ {
+ throw new RuntimeException("can not handle "+aNode.toString());
+ }
+
+
+
+
+ @Override
+ public void Visit (final Union aNode)
+ {
+ throw new RuntimeException("can not handle "+aNode.toString());
+ }
+
+
+
+
+ @Override
+ public void Visit (final AttributeGroup aNode)
+ {
+ throw new RuntimeException("can not handle "+aNode.toString());
+ }
+
+
+
+
+ @Override
+ public void Visit (final AttributeReference aNode)
+ {
+ throw new RuntimeException("can not handle "+aNode.toString());
+ }
+
+
+
+
+ @Override
+ public void Visit (final Attribute aNode)
+ {
+ throw new RuntimeException("can not handle "+aNode.toString());
+ }
+
+
+
+
+ @Override
+ public void Visit (final AttributeGroupReference aNode)
+ {
+ throw new RuntimeException("can not handle "+aNode.toString());
+ }
+
+
+
+
+ private void ProcessType (
+ final INode aNode,
+ final State aBaseState,
+ final State aStartState,
+ final State aEndState)
+ {
+ maContextStack.push(maCurrentContext);
+ maCurrentContext = new Context(aBaseState, aStartState, aEndState);
+ aNode.AcceptVisitor(this);
+ maCurrentContext = maContextStack.pop();
+ }
+
+
+
+
+ private void AddEpsilonTransition (
+ final State aStartState,
+ final State aEndState)
+ {
+ // Silently ignore epsilon transitions from a state to itself.
+ // They may indicate a problem but usually are just artifacts
+ // that can be safely ignored.
+ if (aStartState == aEndState)
+ return;
+ else
+ {
+ final EpsilonTransition aTransition = new EpsilonTransition(
+ aStartState,
+ aEndState);
+ aStartState.AddEpsilonTransition(aTransition);
+
+ if (maLog != null)
+ {
+ maLog.printf("%sepsilon transition from %s to %s\n",
+ msLogIndentation,
+ aStartState.GetFullname(),
+ aEndState.GetFullname());
+ }
+ }
+ }
+
+
+
+
+ private int GetElementCount (final INode aNode)
+ {
+
+ class Visitor extends NodeVisitorAdapter
+ {
+ int nElementCount = 0;
+ @Override public void Visit (final Element aElement)
+ {
+ ++nElementCount;
+ }
+ int GetElementCount ()
+ {
+ return nElementCount;
+ }
+ };
+ final Visitor aVisitor = new Visitor();
+ for (final INode aChildNode : new DereferencingNodeIterator(aNode, maSchemaBase, false))
+ {
+ aChildNode.AcceptVisitor(aVisitor);
+ }
+ return aVisitor.GetElementCount();
+ }
+
+
+
+
+ private INode GetAllReplacement (final All aAll)
+ {
+ final long nStartTime = System.currentTimeMillis();
+
+ // By default each child of this node can appear exactly once, however
+ // the order is undefined. This corresponds to an enumeration of all
+ // permutations of the children.
+
+ // Set up an array of all children. This array will be modified to contain
+ // all permutations.
+ final INode[] aNodes = new INode[aAll.GetChildCount()];
+ final Iterator<INode> aChildren = aAll.GetChildren().iterator();
+ for (int nIndex=0; aChildren.hasNext(); ++nIndex)
+ aNodes[nIndex] = aChildren.next();
+
+ final Location aLocation = aAll.GetLocation();
+ final Choice aChoice = new Choice(aAll, aLocation);
+
+ // Treat every permutation as sequence so that the whole set of permutations
+ // is equivalent to a choice of sequences.
+ int nCount = 0;
+ for (final PermutationIterator<INode> aIterator = new PermutationIterator<>(aNodes); aIterator.HasMore(); aIterator.Next())
+ {
+ // Create a Sequence node for the current permutation and add it as
+ // choice to the Choice node.
+ final Sequence aSequence = new Sequence(aChoice, null, aLocation);
+ aChoice.AddChild(aSequence);
+
+ for (final INode aNode : aNodes)
+ aSequence.AddChild(aNode);
+
+ ++nCount;
+ }
+ final long nEndTime = System.currentTimeMillis();
+ System.out.printf("created %d permutations in %fs\n",
+ nCount,
+ (nEndTime-nStartTime)/1000.0);
+
+ return aChoice;
+ }
+
+
+
+
+ class Context
+ {
+ Context (
+ final State aBaseState,
+ final State aStartState,
+ final State aEndState)
+ {
+ BaseState = aBaseState;
+ StartState = aStartState;
+ EndState = aEndState;
+ }
+ final State BaseState;
+ final State StartState;
+ final State EndState;
+ }
+
+
+
+
+ private StateContext maStateContext;
+ private final Stack<Context> maContextStack;
+ private Context maCurrentContext;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/generator/LogGenerator.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/generator/LogGenerator.java
new file mode 100644
index 000000000000..36deab269b96
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/generator/LogGenerator.java
@@ -0,0 +1,313 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.schema.generator;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.PrintStream;
+import java.util.Map.Entry;
+
+import org.apache.openoffice.ooxml.schema.model.attribute.Attribute;
+import org.apache.openoffice.ooxml.schema.model.attribute.AttributeGroup;
+import org.apache.openoffice.ooxml.schema.model.attribute.AttributeGroupReference;
+import org.apache.openoffice.ooxml.schema.model.attribute.AttributeReference;
+import org.apache.openoffice.ooxml.schema.model.base.INode;
+import org.apache.openoffice.ooxml.schema.model.base.Node;
+import org.apache.openoffice.ooxml.schema.model.complex.ComplexType;
+import org.apache.openoffice.ooxml.schema.model.complex.Element;
+import org.apache.openoffice.ooxml.schema.model.schema.Schema;
+import org.apache.openoffice.ooxml.schema.model.schema.SchemaBase;
+import org.apache.openoffice.ooxml.schema.model.simple.Restriction;
+import org.apache.openoffice.ooxml.schema.model.simple.SimpleType;
+import org.apache.openoffice.ooxml.schema.model.simple.SimpleTypeReference;
+
+public class LogGenerator
+{
+ public static void Write (
+ final File aOutputFile,
+ final SchemaBase aSchemaBase,
+ final Iterable<Schema> aTopLevelSchemas)
+ {
+ final long nStartTime = System.currentTimeMillis();
+
+ try
+ {
+ final LogGenerator aGenerator = new LogGenerator(
+ new PrintStream(aOutputFile),
+ aSchemaBase);
+
+ aGenerator.WriteNamespaces(aSchemaBase);
+ aGenerator.WriteTopLevelElements(aTopLevelSchemas);
+ aGenerator.WriteComplexTypes(aSchemaBase);
+ aGenerator.WriteGroups(aSchemaBase);
+ aGenerator.WriteSimpleTypes(aSchemaBase);
+ aGenerator.WriteAttributeGroups(aSchemaBase);
+ aGenerator.WriteAttributes(aSchemaBase);
+ }
+ catch (final FileNotFoundException aException)
+ {
+ aException.printStackTrace();
+ }
+
+ final long nEndTime = System.currentTimeMillis();
+ System.out.printf("wrote log output to '%s' in %fs\n",
+ aOutputFile.toString(),
+ (nEndTime-nStartTime)/1000.0f);
+ }
+
+
+
+
+ private LogGenerator (
+ final PrintStream aOut,
+ final SchemaBase aSchemaBase)
+ {
+ maSchemaBase = aSchemaBase;
+ maOut = aOut;
+ }
+
+
+
+
+ private void WriteComment (final String sFormat, final Object ... aArgumentList)
+ {
+ maOut.printf("// "+sFormat+"\n", aArgumentList);
+ }
+
+
+
+
+ private void WriteNamespaces (final SchemaBase aSchema)
+ {
+ // Write namespace definitions.
+ WriteComment("%d Namespaces.", aSchema.Namespaces.GetCount());
+ for (final Entry<String,String> aEntry : aSchema.Namespaces.GetSorted())
+ {
+ maOut.printf(" %s -> %s\n",
+ aEntry.getValue()==null ? "<no-prefix>" : aEntry.getValue(),
+ aEntry.getKey());
+ }
+ }
+
+
+
+ private void WriteTopLevelElements (final Iterable<Schema> aTopLevelSchemas)
+ {
+ // Write top level elements.
+ WriteComment("Top-level elements.");
+ for (final Schema aSchema : aTopLevelSchemas)
+ {
+ WriteComment(" Schema %s.", aSchema.GetShortName());
+ for (final Element aElement : aSchema.TopLevelElements.GetSorted())
+ maOut.printf(" \"%s\" -> %s\n",
+ aElement.GetElementName().GetDisplayName(),
+ aElement.GetTypeName().GetDisplayName());
+ }
+ }
+
+
+
+
+ private void WriteComplexTypes (final SchemaBase aSchema)
+ {
+ WriteComment(" %d Complex Types.", aSchema.ComplexTypes.GetCount());
+ for (final ComplexType aType : aSchema.ComplexTypes.GetSorted())
+ {
+ WriteType(" ", aType, true);
+ }
+ }
+
+
+
+
+ private void WriteSimpleTypes (final SchemaBase aSchema)
+ {
+ WriteComment(" %d Simple Types.", aSchema.SimpleTypes.GetCount());
+ for (final SimpleType aType : aSchema.SimpleTypes.GetSorted())
+ {
+ WriteType(" ", aType, true);
+ }
+ }
+
+
+
+
+ private void WriteGroups (final SchemaBase aSchema)
+ {
+ WriteComment(" %d Groups.", aSchema.Groups.GetCount());
+ for (final Node aType : aSchema.Groups.GetSorted())
+ {
+ WriteType(" ", aType, true);
+ }
+ }
+
+
+
+
+ private void WriteAttributeGroups (final SchemaBase aSchema)
+ {
+ WriteComment(" %d Attribute Groups.", aSchema.AttributeGroups.GetCount());
+ for (final Node aType : aSchema.AttributeGroups.GetSorted())
+ {
+ WriteType(" ", aType, true);
+ }
+ }
+
+
+
+
+ private void WriteAttributes (final SchemaBase aSchema)
+ {
+ WriteComment(" %d Attributes.", aSchema.Attributes.GetCount());
+ for (final Node aType : aSchema.Attributes.GetSorted())
+ {
+ WriteType(" ", aType, true);
+ }
+ }
+
+
+
+
+ private void WriteType (
+ final String sIndentation,
+ final INode aType,
+ final boolean bIsTopLevel)
+ {
+ maOut.printf("%s%s", sIndentation, aType.toString());
+
+ if (bIsTopLevel)
+ {
+ final Node aNode = (Node)aType;
+ maOut.printf(" defined at %s",
+ aNode.GetLocation());
+ }
+ if ( ! HasChild(aType))
+ {
+ maOut.printf(" {}\n");
+ }
+ else
+ {
+ maOut.printf(" {\n");
+
+ // Write attributes.
+ switch(aType.GetNodeType())
+ {
+ case ComplexType:
+ for (final INode aAttribute : ((ComplexType)aType).GetAttributes())
+ WriteAttribute(sIndentation+" ", aAttribute);
+ break;
+
+ case SimpleTypeReference:
+ WriteType(
+ sIndentation+" ",
+ ((SimpleTypeReference)aType).GetReferencedSimpleType(maSchemaBase),
+ false);
+ break;
+
+ default:
+ break;
+ }
+
+
+ // Write child types.
+ for (final INode aChild : aType.GetChildren())
+ WriteType(sIndentation+" ", aChild, false);
+
+ maOut.printf("%s}\n", sIndentation);
+ }
+ }
+
+
+
+
+ private void WriteAttribute (
+ final String sIndentation,
+ final INode aAttribute)
+ {
+ switch(aAttribute.GetNodeType())
+ {
+ case Attribute:
+ maOut.printf(
+ "%sattribute %s of type %s\n",
+ sIndentation,
+ ((Attribute)aAttribute).GetName().GetDisplayName(),
+ ((Attribute)aAttribute).GetTypeName().GetDisplayName());
+ break;
+
+ case AttributeGroup:
+ maOut.printf(
+ "%sattribute group %s {\n",
+ sIndentation,
+ ((AttributeGroup)aAttribute).GetName().GetDisplayName());
+ for (final INode aChildAttribute : ((AttributeGroup)aAttribute).GetChildren())
+ WriteAttribute(sIndentation+" ", aChildAttribute);
+ maOut.printf("%s}\n", sIndentation);
+ break;
+ case AttributeGroupReference:
+ maOut.printf(
+ "%sreference to attribute group %s {\n",
+ sIndentation,
+ ((AttributeGroupReference)aAttribute).GetReferencedName().GetDisplayName());
+ WriteAttribute(sIndentation+" ", ((AttributeGroupReference)aAttribute).GetReferencedAttributeGroup(maSchemaBase));
+ maOut.printf("%s}\n", sIndentation);
+ break;
+
+ case AttributeReference:
+ maOut.printf(
+ "%sreference to attribute %s {\n",
+ sIndentation,
+ ((AttributeReference)aAttribute).GetReferencedName().GetDisplayName());
+ WriteAttribute(sIndentation+" ", ((AttributeReference)aAttribute).GetReferencedAttribute(maSchemaBase));
+ maOut.printf("%s}\n", sIndentation);
+ break;
+ default:
+ throw new RuntimeException();
+ }
+ }
+
+
+
+
+ private boolean HasChild (final INode aType)
+ {
+ if (aType.GetChildren().iterator().hasNext())
+ return true;
+
+ switch (aType.GetNodeType())
+ {
+ case ComplexType:
+ return ((ComplexType)aType).GetAttributes().iterator().hasNext();
+
+ case SimpleTypeReference:
+ return true;
+
+ default:
+ return false;
+ }
+ }
+
+
+
+
+ private final SchemaBase maSchemaBase;
+ private final PrintStream maOut;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/generator/ParserTablesGenerator.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/generator/ParserTablesGenerator.java
new file mode 100644
index 000000000000..99cfbe1161bb
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/generator/ParserTablesGenerator.java
@@ -0,0 +1,555 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.schema.generator;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.PrintStream;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.TreeSet;
+
+import org.apache.openoffice.ooxml.schema.automaton.FiniteAutomaton;
+import org.apache.openoffice.ooxml.schema.automaton.FiniteAutomatonContainer;
+import org.apache.openoffice.ooxml.schema.automaton.SkipData;
+import org.apache.openoffice.ooxml.schema.automaton.State;
+import org.apache.openoffice.ooxml.schema.automaton.Transition;
+import org.apache.openoffice.ooxml.schema.model.attribute.Attribute;
+import org.apache.openoffice.ooxml.schema.model.attribute.AttributeBase.Use;
+import org.apache.openoffice.ooxml.schema.model.base.INode;
+import org.apache.openoffice.ooxml.schema.model.base.QualifiedName;
+import org.apache.openoffice.ooxml.schema.model.schema.NamespaceMap;
+import org.apache.openoffice.ooxml.schema.parser.FormDefault;
+import org.apache.openoffice.ooxml.schema.simple.BlobNode;
+import org.apache.openoffice.ooxml.schema.simple.DateTimeNode;
+import org.apache.openoffice.ooxml.schema.simple.ISimpleTypeNode;
+import org.apache.openoffice.ooxml.schema.simple.ISimpleTypeNodeVisitor;
+import org.apache.openoffice.ooxml.schema.simple.NumberNode;
+import org.apache.openoffice.ooxml.schema.simple.SimpleTypeContainer;
+import org.apache.openoffice.ooxml.schema.simple.SimpleTypeDescriptor;
+import org.apache.openoffice.ooxml.schema.simple.StringNode;
+import org.apache.openoffice.ooxml.schema.simple.UnionNode;
+
+public class ParserTablesGenerator
+{
+ public ParserTablesGenerator (
+ final FiniteAutomatonContainer aAutomatons,
+ final NamespaceMap aNamespaces,
+ final SimpleTypeContainer aSimpleTypes,
+ final Map<String,Integer> aAttributeValueToIdMap)
+ {
+ maAutomatons = aAutomatons;
+ maSimpleTypes = aSimpleTypes;
+ maNamespaces = aNamespaces;
+ maNameToIdMap = new TreeMap<>();
+ maPrefixToIdMap = new HashMap<>();
+ maTypeNameToIdMap = new TreeMap<>();
+ maAttributeValueToIdMap = aAttributeValueToIdMap;
+ }
+
+
+
+
+ public void Generate (
+ final File aParseTableFile)
+ {
+ final long nStartTime = System.currentTimeMillis();
+
+ SetupNameList();
+ AssignNameIds();
+
+ try
+ {
+ final PrintStream aOut = new PrintStream(new FileOutputStream(aParseTableFile));
+
+ WriteNamespaceList(aOut);
+ WriteNameList(aOut);
+ WriteGlobalStartEndStates(aOut);
+ WriteAutomatonList(aOut);
+ WriteSimpleTypes(aOut);
+ WriteAttributeValues(aOut);
+ aOut.close();
+ }
+ catch (final FileNotFoundException aException)
+ {
+ aException.printStackTrace();
+ }
+
+ final long nEndTime = System.currentTimeMillis();
+ System.out.printf("wrote parse tables to %s in %fs\n",
+ aParseTableFile.toString(),
+ (nEndTime-nStartTime)/1000.0);
+ }
+
+
+
+
+ private void SetupNameList ()
+ {
+ final Set<String> aNames = new TreeSet<>();
+
+ // Add the element names.
+ for (final FiniteAutomaton aAutomaton : maAutomatons.GetAutomatons())
+ for (final Transition aTransition : aAutomaton.GetTransitions())
+ {
+ if (aTransition.GetElementName() == null)
+ throw new RuntimeException();
+ aNames.add(aTransition.GetElementName().GetLocalPart());
+ }
+
+ // Add the attribute names.
+ for (final FiniteAutomaton aAutomaton : maAutomatons.GetAutomatons())
+ for (final Attribute aAttribute : aAutomaton.GetAttributes())
+ aNames.add(aAttribute.GetName().GetLocalPart());
+
+ // Create unique ids for the names.
+ int nIndex = 1;
+ maNameToIdMap.clear();
+ for (final String sName : aNames)
+ maNameToIdMap.put(sName, nIndex++);
+
+ // Create unique ids for namespace prefixes.
+ nIndex = 1;
+ maPrefixToIdMap.clear();
+ for (final Entry<String, String> aEntry : maNamespaces)
+ {
+ maPrefixToIdMap.put(aEntry.getValue(), nIndex++);
+ }
+ }
+
+
+
+
+ /** During the largest part of the parsing process, states and elements are
+ * identified not via their name but via a unique id.
+ * That allows a fast lookup.
+ */
+ private void AssignNameIds ()
+ {
+ maTypeNameToIdMap.clear();
+ int nIndex = 0;
+
+ // Process state names.
+ final Set<QualifiedName> aSortedTypeNames = new TreeSet<>();
+ for (final State aState : maAutomatons.GetStates())
+ aSortedTypeNames.add(aState.GetQualifiedName());
+ for (final Entry<String, SimpleTypeDescriptor> aSimpleType : maSimpleTypes.GetSimpleTypes())
+ aSortedTypeNames.add(aSimpleType.getValue().GetName());
+
+ for (final QualifiedName aName : aSortedTypeNames)
+ maTypeNameToIdMap.put(aName.GetStateName(), nIndex++);
+ }
+
+
+
+
+ private void WriteNamespaceList (final PrintStream aOut)
+ {
+ aOut.printf("# namespaces\n");
+ for (final Entry<String, String> aEntry : maNamespaces)
+ {
+ aOut.printf("namespace %-8s %2d %s\n",
+ aEntry.getValue(),
+ maPrefixToIdMap.get(aEntry.getValue()),
+ aEntry.getKey());
+ }
+ }
+
+
+
+
+ private void WriteGlobalStartEndStates (final PrintStream aOut)
+ {
+ aOut.printf("\n# start and end states\n");
+
+ final FiniteAutomaton aAutomaton = maAutomatons.GetTopLevelAutomaton();
+ final State aStartState = aAutomaton.GetStartState();
+ aOut.printf("start-state %4d %s\n",
+ maTypeNameToIdMap.get(aStartState.GetFullname()),
+ aStartState.GetFullname());
+ for (final State aAcceptingState : aAutomaton.GetAcceptingStates())
+ aOut.printf("end-state %4d %s\n",
+ maTypeNameToIdMap.get(aAcceptingState.GetFullname()),
+ aAcceptingState.GetFullname());
+ }
+
+
+
+
+ private void WriteNameList (final PrintStream aOut)
+ {
+ aOut.printf("\n# %d names\n", maNameToIdMap.size());
+ for (final Entry<String, Integer> aEntry : maNameToIdMap.entrySet())
+ {
+ aOut.printf("name %4d %s\n",
+ aEntry.getValue(),
+ aEntry.getKey());
+ }
+
+ aOut.printf("\n# %s states\n", maTypeNameToIdMap.size());
+ for (final Entry<String, Integer> aEntry : maTypeNameToIdMap.entrySet())
+ {
+ aOut.printf("state-name %4d %s\n",
+ aEntry.getValue(),
+ aEntry.getKey());
+ }
+ }
+
+
+
+
+ private void WriteAutomatonList (final PrintStream aOut)
+ {
+ for (final FiniteAutomaton aAutomaton : maAutomatons.GetAutomatons())
+ {
+ aOut.printf("# %s at %s\n", aAutomaton.GetTypeName(), aAutomaton.GetLocation());
+
+ final State aStartState = aAutomaton.GetStartState();
+ final int nStartStateId = maTypeNameToIdMap.get(aStartState.GetFullname());
+
+ // Write start state.
+ aOut.printf("start-state %d %s\n",
+ nStartStateId,
+ aStartState);
+
+ // Write accepting states.
+ for (final State aState : aAutomaton.GetAcceptingStates())
+ {
+ aOut.printf("accepting-state %d %s\n",
+ maTypeNameToIdMap.get(aState.GetFullname()),
+ aState.GetFullname());
+ }
+
+ // Write text type.
+ final INode aTextType = aStartState.GetTextType();
+ if (aTextType != null)
+ {
+ switch(aTextType.GetNodeType())
+ {
+ case BuiltIn:
+ aOut.printf("text-type %d %d %s\n",
+ nStartStateId,
+ maTypeNameToIdMap.get(aTextType.GetName().GetStateName()),
+ aTextType.GetName().GetStateName());
+ break;
+ case SimpleType:
+ aOut.printf("text-type %d %d %s\n",
+ nStartStateId,
+ maTypeNameToIdMap.get(aTextType.GetName().GetStateName()),
+ aTextType.GetName().GetStateName());
+ break;
+ default:
+ throw new RuntimeException();
+ }
+ }
+
+ WriteAttributes(
+ aOut,
+ aStartState,
+ aAutomaton.GetAttributes());
+
+ // Write transitions.
+ for (final Transition aTransition : aAutomaton.GetTransitions())
+ {
+ final Integer nId = maTypeNameToIdMap.get(aTransition.GetElementTypeName());
+ aOut.printf("transition %4d %4d %2d %4d %4d %s %s %s %s\n",
+ maTypeNameToIdMap.get(aTransition.GetStartState().GetFullname()),
+ maTypeNameToIdMap.get(aTransition.GetEndState().GetFullname()),
+ maPrefixToIdMap.get(aTransition.GetElementName().GetNamespacePrefix()),
+ maNameToIdMap.get(aTransition.GetElementName().GetLocalPart()),
+ nId!=null ? nId : -1,
+ aTransition.GetStartState().GetFullname(),
+ aTransition.GetEndState().GetFullname(),
+ aTransition.GetElementName().GetStateName(),
+ aTransition.GetElementTypeName());
+ }
+ // Write skip data.
+ for (final State aState : aAutomaton.GetStates())
+ {
+ for (@SuppressWarnings("unused") final SkipData aSkipData : aState.GetSkipData())
+ aOut.printf("skip %4d %s\n",
+ maTypeNameToIdMap.get(aState.GetFullname()),
+ aState.GetFullname());
+ }
+ }
+ }
+
+
+
+
+ private void WriteAttributes (
+ final PrintStream aOut,
+ final State aState,
+ final Iterable<Attribute> aAttributes)
+ {
+ // Write attributes.
+ for (final Attribute aAttribute : aAttributes)
+ {
+ aOut.printf("attribute %4d %2d %c %4d %4d %s %s %s %s %s\n",
+ maTypeNameToIdMap.get(aState.GetFullname()),
+ maPrefixToIdMap.get(aAttribute.GetName().GetNamespacePrefix()),
+ aAttribute.GetFormDefault()==FormDefault.qualified ? 'q' : 'u',
+ maNameToIdMap.get(aAttribute.GetName().GetLocalPart()),
+ maTypeNameToIdMap.get(aAttribute.GetTypeName().GetStateName()),
+ aAttribute.GetUse()==Use.Optional ? 'o' : 'u',
+ aAttribute.GetDefault()==null ? "null" : '"'+aAttribute.GetDefault()+'"',
+ aState.GetFullname(),
+ aAttribute.GetName().GetStateName(),
+ aAttribute.GetTypeName().GetStateName());
+ }
+ }
+
+
+
+
+ private void WriteSimpleTypes (
+ final PrintStream aOut)
+ {
+ if (maSimpleTypes == null)
+ {
+ aOut.printf("\n// There is no simple type information.\n");
+ }
+ else
+ {
+ aOut.printf("\n// %d simple types.\n", maSimpleTypes.GetSimpleTypeCount());
+ for (final Entry<String,SimpleTypeDescriptor> aEntry : maSimpleTypes.GetSimpleTypesSorted())
+ {
+ int nIndex = 0;
+ for (final ISimpleTypeNode aSubType : aEntry.getValue().GetSubType())
+ {
+ final int nCurrentIndex = nIndex++;
+
+ final StringBuffer aLine = new StringBuffer();
+ aLine.append(String.format(
+ "simple-type %5d %1d %c ",
+ maTypeNameToIdMap.get(aEntry.getKey()),
+ nCurrentIndex,
+ aSubType.IsList() ? 'L' : 'T'));
+
+ aSubType.AcceptVisitor(new ISimpleTypeNodeVisitor()
+ {
+ @Override public void Visit(UnionNode aType)
+ {
+ throw new RuntimeException("unexpected");
+ }
+ @Override public void Visit(StringNode aType)
+ {
+ AppendStringDescription(aLine, aType);
+ }
+ @Override public void Visit(NumberNode<?> aType)
+ {
+ AppendNumberDescription(aLine, aType);
+ }
+ @Override public void Visit(DateTimeNode aType)
+ {
+ AppendDateTimeDescription(aLine, aType);
+ }
+ @Override public void Visit(BlobNode aType)
+ {
+ AppendBlobDescription(aLine, aType);
+ }
+ });
+ aOut.printf("%s\n", aLine.toString());
+ }
+ }
+ }
+ }
+
+
+
+
+ private void WriteAttributeValues (
+ final PrintStream aOut)
+ {
+ final Map<String,Integer> aSortedMap = new TreeMap<>();
+ aSortedMap.putAll(maAttributeValueToIdMap);
+ aOut.printf("// %d attribute values from enumerations.\n", maAttributeValueToIdMap.size());
+ for (final Entry<String,Integer> aEntry : aSortedMap.entrySet())
+ aOut.printf("attribute-value %5d %s\n", aEntry.getValue(), QuoteString(aEntry.getKey()));
+ }
+
+
+
+
+ private static void AppendStringDescription (
+ final StringBuffer aLine,
+ final StringNode aType)
+ {
+ aLine.append("S ");
+ switch(aType.GetRestrictionType())
+ {
+ case Enumeration:
+ aLine.append('E');
+ for (final int nValueId : aType.GetEnumerationRestriction())
+ {
+ aLine.append(' ');
+ aLine.append(nValueId);
+ }
+ break;
+ case Pattern:
+ aLine.append("P ");
+ aLine.append(QuoteString(aType.GetPatternRestriction()));
+ break;
+ case Length:
+ aLine.append("L ");
+ final int[] aLengthRestriction = aType.GetLengthRestriction();
+ aLine.append(aLengthRestriction[0]);
+ aLine.append(' ');
+ aLine.append(aLengthRestriction[1]);
+ break;
+ case None:
+ aLine.append('N');
+ break;
+ default:
+ throw new RuntimeException();
+ }
+ }
+
+
+
+
+ private static void AppendNumberDescription (
+ final StringBuffer aLine,
+ final NumberNode<?> aType)
+ {
+ aLine.append("N ");
+ switch(aType.GetNumberType())
+ {
+ case Boolean: aLine.append("u1"); break;
+ case Byte: aLine.append("s8"); break;
+ case UnsignedByte: aLine.append("u8"); break;
+ case Short: aLine.append("s16"); break;
+ case UnsignedShort: aLine.append("u16"); break;
+ case Int: aLine.append("s32"); break;
+ case UnsignedInt: aLine.append("u32"); break;
+ case Long: aLine.append("s64"); break;
+ case UnsignedLong: aLine.append("u64"); break;
+ case Integer: aLine.append("s*"); break;
+ case Float: aLine.append("f"); break;
+ case Double: aLine.append("d"); break;
+ default:
+ throw new RuntimeException("unsupported numerical type "+aType.GetNumberType());
+ }
+ aLine.append(' ');
+ switch(aType.GetRestrictionType())
+ {
+ case Enumeration:
+ aLine.append("E ");
+ for (final Object nValue : aType.GetEnumerationRestriction())
+ {
+ aLine.append(" ");
+ aLine.append(nValue);
+ }
+ break;
+ case Size:
+ aLine.append("S");
+ if (aType.GetMinimum() != null)
+ {
+ if (aType.IsMinimumInclusive())
+ aLine.append(" >= ");
+ else
+ aLine.append(" > ");
+ aLine.append(aType.GetMinimum());
+ }
+ if (aType.GetMaximum() != null)
+ {
+ if (aType.IsMaximumInclusive())
+ aLine.append(" <= ");
+ else
+ aLine.append(" < ");
+ aLine.append(aType.GetMaximum());
+ }
+ break;
+ case None:
+ aLine.append("N");
+ break;
+ default:
+ throw new RuntimeException("unsupported numerical restriction "+aType.GetRestrictionType());
+ }
+ }
+
+
+
+
+ private static void AppendDateTimeDescription (
+ final StringBuffer aLine,
+ final DateTimeNode aType)
+ {
+ aLine.append("D");
+ }
+
+
+
+
+ private static void AppendBlobDescription (
+ final StringBuffer aLine,
+ final BlobNode aType)
+ {
+ aLine.append("B ");
+ switch(aType.GetBlobType())
+ {
+ case Base64Binary:
+ aLine.append("B ");
+ break;
+ case HexBinary:
+ aLine.append ("H ");
+ break;
+ default:
+ throw new RuntimeException("unsupported blob type");
+ }
+ switch(aType.GetRestrictionType())
+ {
+ case Length:
+ aLine.append("L ");
+ aLine.append(aType.GetLengthRestriction());
+ break;
+ case None:
+ aLine.append("N");
+ break;
+ default:
+ throw new RuntimeException();
+ }
+ }
+
+
+
+
+ private static String QuoteString(final String sText)
+ {
+ return "\"" + sText.replace("\"", "&quot;").replace(" ", "%20") + "\"";
+ }
+
+
+
+
+ private final FiniteAutomatonContainer maAutomatons;
+ private final SimpleTypeContainer maSimpleTypes;
+ private final NamespaceMap maNamespaces;
+ private final Map<String,Integer> maNameToIdMap;
+ private final Map<String,Integer> maPrefixToIdMap;
+ private final Map<String,Integer> maTypeNameToIdMap;
+ private final Map<String,Integer> maAttributeValueToIdMap;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/generator/html/HtmlGenerator.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/generator/html/HtmlGenerator.java
new file mode 100644
index 000000000000..189554766ada
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/generator/html/HtmlGenerator.java
@@ -0,0 +1,623 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.schema.generator.html;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.InputStreamReader;
+import java.io.PrintStream;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.openoffice.ooxml.schema.model.attribute.Attribute;
+import org.apache.openoffice.ooxml.schema.model.attribute.AttributeGroup;
+import org.apache.openoffice.ooxml.schema.model.attribute.AttributeGroupReference;
+import org.apache.openoffice.ooxml.schema.model.attribute.AttributeReference;
+import org.apache.openoffice.ooxml.schema.model.base.INode;
+import org.apache.openoffice.ooxml.schema.model.base.INodeVisitor;
+import org.apache.openoffice.ooxml.schema.model.complex.All;
+import org.apache.openoffice.ooxml.schema.model.complex.Any;
+import org.apache.openoffice.ooxml.schema.model.complex.Choice;
+import org.apache.openoffice.ooxml.schema.model.complex.ComplexContent;
+import org.apache.openoffice.ooxml.schema.model.complex.ComplexType;
+import org.apache.openoffice.ooxml.schema.model.complex.ComplexTypeReference;
+import org.apache.openoffice.ooxml.schema.model.complex.Element;
+import org.apache.openoffice.ooxml.schema.model.complex.ElementReference;
+import org.apache.openoffice.ooxml.schema.model.complex.Extension;
+import org.apache.openoffice.ooxml.schema.model.complex.Group;
+import org.apache.openoffice.ooxml.schema.model.complex.GroupReference;
+import org.apache.openoffice.ooxml.schema.model.complex.OccurrenceIndicator;
+import org.apache.openoffice.ooxml.schema.model.complex.Sequence;
+import org.apache.openoffice.ooxml.schema.model.schema.Schema;
+import org.apache.openoffice.ooxml.schema.model.schema.SchemaBase;
+import org.apache.openoffice.ooxml.schema.model.simple.BuiltIn;
+import org.apache.openoffice.ooxml.schema.model.simple.List;
+import org.apache.openoffice.ooxml.schema.model.simple.Restriction;
+import org.apache.openoffice.ooxml.schema.model.simple.SimpleContent;
+import org.apache.openoffice.ooxml.schema.model.simple.SimpleType;
+import org.apache.openoffice.ooxml.schema.model.simple.SimpleTypeReference;
+import org.apache.openoffice.ooxml.schema.model.simple.Union;
+
+/** Create a single HTML page that shows information about all
+ * complex and simple types.
+ */
+public class HtmlGenerator
+ implements INodeVisitor
+{
+ public HtmlGenerator(
+ final SchemaBase aSchemaBase,
+ final Map<String, Schema> aTopLevelSchemas,
+ final File aOutputFile)
+ {
+ maSchemaBase = aSchemaBase;
+ maTopLevelSchemas = aTopLevelSchemas;
+ msIndentation = "";
+ msSingleIndentation = " ";
+ msSpace = " ";
+ try
+ {
+ maOut = new PrintStream(new FileOutputStream(aOutputFile));
+ } catch (FileNotFoundException aException)
+ {
+ aException.printStackTrace();
+ throw new RuntimeException(aException);
+ }
+ }
+
+
+
+
+ /** Read a template HTML file, expand its $... references and write the resulting content.
+ */
+ public void Generate ()
+ {
+ CopyFile("linking-template.html", true);
+ maOut.close();
+ }
+
+
+
+
+ private void CopyFile (
+ final String sBasename,
+ final boolean bIsTemplate)
+ {
+ try
+ {
+ final BufferedReader aIn = new BufferedReader(
+ new InputStreamReader(
+ new FileInputStream(
+ new File(
+ new File("bin/org/apache/openoffice/ooxml/schema/generator/html"),
+ sBasename))));
+
+ final Pattern aReferencePattern = Pattern.compile("^(.*?)\\$([^\\$]+)\\$(.*)$");
+ while (true)
+ {
+ final String sLine = aIn.readLine();
+ if (sLine == null)
+ break;
+
+ if (bIsTemplate)
+ {
+ final Matcher aMatcher = aReferencePattern.matcher(sLine);
+ if (aMatcher.matches())
+ {
+ maOut.println(aMatcher.group(1));
+ switch(aMatcher.group(2))
+ {
+ case "CSS":
+ CopyFile("display.css", false);
+ break;
+ case "CODE":
+ CopyFile("code.js", false);
+ break;
+ case "DATA":
+ WriteJsonData();
+ break;
+ }
+ maOut.printf("%s\n", aMatcher.group(3));
+ }
+ else
+ maOut.printf("%s\n", sLine);
+ }
+ else
+ maOut.printf("%s\n", sLine);
+ }
+ aIn.close();
+ }
+ catch (final Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+
+
+
+ private void WriteJsonData ()
+ {
+ maOut.printf("Data={\n");
+
+ WriteTopLevelNodes(maSchemaBase.ComplexTypes.GetSorted());
+ WriteTopLevelNodes(maSchemaBase.SimpleTypes.GetSorted());
+ WriteTopLevelNodes(maSchemaBase.Groups.GetSorted());
+ WriteTopLevelNodes(maSchemaBase.AttributeGroups.GetSorted());
+
+ maOut.printf("}\n");
+ }
+
+
+
+
+ private void WriteTopLevelNodes (final Iterable<? extends INode> aNodes)
+ {
+ for (final INode aNode : aNodes)
+ {
+ maOut.printf(" \"%s\" : {\n", aNode.GetName().GetDisplayName());
+
+ final String sSavedIndentation = msIndentation;
+ msIndentation += msSingleIndentation + msSingleIndentation;
+ aNode.AcceptVisitor(this);
+ msIndentation = sSavedIndentation;
+
+ maOut.printf(" }, \n");
+ }
+ }
+
+
+
+
+ @Override
+ public void Visit (final All aNode)
+ {
+ WritePair("type", "all");
+ WriteLocation(aNode);
+ WriteAttributes(aNode);
+ WriteChildren(aNode);
+ }
+
+
+
+
+ @Override
+ public void Visit (final Any aNode)
+ {
+ WritePair("type", "any");
+ WriteLocation(aNode);
+ WriteAttributes(aNode);
+ WriteChildren(aNode);
+ }
+
+
+
+
+ @Override
+ public void Visit (final ComplexContent aNode)
+ {
+ WritePair("type", "complex-content");
+ WriteLocation(aNode);
+ WriteAttributes(aNode);
+ WriteChildren(aNode);
+ }
+
+
+
+
+ @Override
+ public void Visit (final ComplexType aNode)
+ {
+ WritePair("type", "complex-type");
+ WritePair("name", aNode.GetName().GetDisplayName());
+ WriteLocation(aNode);
+ WriteAttributes(aNode);
+ WriteChildren(aNode);
+ }
+
+
+
+
+ @Override
+ public void Visit (final ComplexTypeReference aReference)
+ {
+ WritePair("type", "complex-type-reference");
+ WriteLocation(aReference);
+ WritePair("referenced-complex-type", aReference.GetReferencedTypeName().GetDisplayName());
+ WriteAttributes(aReference);
+ }
+
+
+
+
+ @Override
+ public void Visit (final Choice aNode)
+ {
+ WritePair("type", "choice");
+ WriteLocation(aNode);
+ WriteChildren(aNode);
+ WriteAttributes(aNode);
+ }
+
+
+
+
+ @Override
+ public void Visit (final Element aNode)
+ {
+ WritePair("type", "element");
+ WriteLocation(aNode);
+ WritePair("tag", aNode.GetElementName().GetDisplayName());
+ WritePair("result-type", aNode.GetTypeName().GetDisplayName());
+ WriteAttributes(aNode);
+ }
+
+
+
+
+ @Override
+ public void Visit (final ElementReference aReference)
+ {
+ WritePair("type", "element-type-reference");
+ WriteLocation(aReference);
+ WritePair("referenced-element", aReference.GetReferencedElementName().GetDisplayName());
+ WriteAttributes(aReference);
+ }
+
+
+
+
+ @Override
+ public void Visit (final Extension aNode)
+ {
+ WritePair("type", "extension");
+ WriteLocation(aNode);
+ WritePair("base-type", aNode.GetBaseTypeName().GetDisplayName());
+ WriteAttributes(aNode);
+ WriteChildren(aNode);
+ }
+
+
+
+
+ @Override
+ public void Visit (final Group aNode)
+ {
+ WritePair("type", "group");
+ WriteLocation(aNode);
+ WritePair("name", aNode.GetName().GetDisplayName());
+ WriteAttributes(aNode);
+ WriteChildren(aNode);
+ }
+
+
+
+
+ @Override
+ public void Visit (final GroupReference aReference)
+ {
+ WritePair("type", "group-reference");
+ WriteLocation(aReference);
+ WritePair("referenced-group", aReference.GetReferencedGroupName().GetDisplayName());
+ WriteAttributes(aReference);
+ }
+
+
+
+
+ @Override
+ public void Visit (final OccurrenceIndicator aNode)
+ {
+ WritePair("type", "occurrence");
+ WriteLocation(aNode);
+ WritePair("minimum", aNode.GetDisplayMinimum());
+ WritePair("maximum", aNode.GetDisplayMaximum());
+ WriteAttributes(aNode);
+ WriteChildren(aNode);
+ }
+
+
+
+
+ @Override
+ public void Visit (final Sequence aNode)
+ {
+ WritePair("type", "sequence");
+ WriteLocation(aNode);
+ WriteAttributes(aNode);
+ WriteChildren(aNode);
+ }
+
+
+
+
+ @Override
+ public void Visit (final BuiltIn aNode)
+ {
+ WritePair("type", "builtin");
+ WriteLocation(aNode);
+ WritePair("builtin-type", aNode.GetBuiltInType().GetQualifiedName().GetDisplayName());
+ WriteAttributes(aNode);
+ }
+
+
+
+
+ @Override
+ public void Visit (final List aNode)
+ {
+ WritePair("type", "list");
+ WriteLocation(aNode);
+ WriteAttributes(aNode);
+ WriteChildren(aNode);
+ }
+
+
+
+
+ @Override
+ public void Visit (final Restriction aNode)
+ {
+ WritePair("type", "restriction");
+ WriteLocation(aNode);
+ WritePair("base-type", aNode.GetBaseType().GetDisplayName());
+ WriteAttributes(aNode);
+
+ if (aNode.HasFeature(Restriction.EnumerationBit))
+ WritePair("enumeration", Join(aNode.GetEnumeration(), ";"));
+ if (aNode.HasFeature(Restriction.PatternBit))
+ WritePair("pattern", QuoteString(aNode.GetPattern()));
+ if (aNode.HasFeature(Restriction.MinExclusiveBit))
+ WritePair("exclusive-minimum", aNode.GetMinExclusive());
+ if (aNode.HasFeature(Restriction.MinInclusiveBit))
+ WritePair("inclusive-minimum", aNode.GetMinInclusive());
+ if (aNode.HasFeature(Restriction.MaxInclusiveBit))
+ WritePair("inclusive-maximum", aNode.GetMaxInclusive());
+ if (aNode.HasFeature(Restriction.MaxInclusiveBit))
+ WritePair("inclusive-maximum", aNode.GetMaxInclusive());
+ if (aNode.HasFeature(Restriction.LengthBit))
+ WritePair("length", Integer.toString(aNode.GetLength()));
+ if (aNode.HasFeature(Restriction.MinLengthBit))
+ WritePair("minimum-length", Integer.toString(aNode.GetMinimumLength()));
+ if (aNode.HasFeature(Restriction.MaxLengthBit))
+ WritePair("maximum-length", Integer.toString(aNode.GetMaximumLength()));
+ assert(aNode.GetChildCount() == 0);
+ }
+
+
+
+
+ @Override
+ public void Visit (final SimpleContent aNode)
+ {
+ WritePair("type", "simple-content");
+ WriteLocation(aNode);
+ WriteAttributes(aNode);
+ WriteChildren(aNode);
+ }
+
+
+
+
+ @Override
+ public void Visit (final SimpleType aNode)
+ {
+ WritePair("type", "simple-type");
+ WriteLocation(aNode);
+ WritePair("name", aNode.GetName().GetDisplayName());
+ WriteAttributes(aNode);
+ WriteChildren(aNode);
+ }
+
+
+
+
+ @Override
+ public void Visit (final SimpleTypeReference aReference)
+ {
+ WritePair("type", "simple-type-reference");
+ WriteLocation(aReference);
+ WritePair("referenced-simple-type", aReference.GetReferencedTypeName().GetDisplayName());
+ WriteAttributes(aReference);
+ }
+
+
+
+
+ @Override
+ public void Visit (final Union aNode)
+ {
+ WritePair("type", "union");
+ WriteLocation(aNode);
+ WriteAttributes(aNode);
+ WriteChildren(aNode);
+ }
+
+
+
+
+ @Override
+ public void Visit (final AttributeGroup aNode)
+ {
+ WritePair("type", "attribute-group");
+ WriteLocation(aNode);
+ WritePair("name", aNode.GetName().GetDisplayName());
+ WriteAttributes(aNode);
+ WriteChildren(aNode);
+ }
+
+
+
+
+ @Override
+ public void Visit (final AttributeReference aReference)
+ {
+ WritePair("type", "attribute-reference");
+ WriteLocation(aReference);
+ WritePair("referenced-attribute", aReference.GetReferencedName().GetDisplayName());
+ WriteAttributes(aReference);
+ }
+
+
+
+
+ @Override
+ public void Visit (final Attribute aNode)
+ {
+ WritePair("type", "attribute");
+ WriteLocation(aNode);
+ WritePair("name", aNode.GetName().GetDisplayName());
+ WritePair("default-value", aNode.GetDefault());
+ WritePair("value-type", aNode.GetTypeName().GetDisplayName());
+ WritePair("use", aNode.GetUse().toString());
+ WriteAttributes(aNode);
+ WriteChildren(aNode);
+ }
+
+
+
+
+ @Override
+ public void Visit (final AttributeGroupReference aReference)
+ {
+ WritePair("type", "attribute-group-reference");
+ WriteLocation(aReference);
+ WritePair("referenced-attribute-group", aReference.GetReferencedName().GetDisplayName());
+ WriteAttributes(aReference);
+ }
+
+
+
+
+ private void WriteChildren (
+ final INode aParent)
+ {
+ if (aParent.GetChildCount() > 0)
+ {
+ maOut.printf("%s\"children\" : [\n", msIndentation);
+ int nIndex = 0;
+ for (final INode aChild : aParent.GetChildren())
+ {
+ maOut.printf("%s%s{\n", msIndentation, msSingleIndentation, nIndex++);
+
+ final String sSavedIndentation = msIndentation;
+ msIndentation += msSingleIndentation + msSingleIndentation;
+ aChild.AcceptVisitor(this);
+ msIndentation = sSavedIndentation;
+
+ maOut.printf("%s%s},\n", msIndentation, msSingleIndentation);
+ }
+
+ maOut.printf("%s]\n", msIndentation);
+ }
+ }
+
+
+
+
+ private void WriteAttributes (
+ final INode aParent)
+ {
+ if (aParent.GetAttributeCount() > 0)
+ {
+ maOut.printf("%s\"attributes\" : [\n", msIndentation);
+ int nIndex = 0;
+ for (final INode aAttribute: aParent.GetAttributes())
+ {
+
+ maOut.printf("%s%s{\n", msIndentation, msSingleIndentation, nIndex++);
+
+ final String sSavedIndentation = msIndentation;
+ msIndentation += msSingleIndentation + msSingleIndentation;
+ aAttribute.AcceptVisitor(this);
+ msIndentation = sSavedIndentation;
+
+ maOut.printf("%s%s},\n", msIndentation, msSingleIndentation);
+ }
+
+ maOut.printf("%s],\n", msIndentation);
+ }
+ }
+
+
+
+
+ private void WriteLocation (
+ final INode aNode)
+ {
+ if (aNode.GetLocation() == null)
+ return;
+
+ WritePair("location", aNode.GetLocation().toString());
+ }
+
+
+
+
+ private void WritePair (
+ final String sKey,
+ final String sValue)
+ {
+ maOut.printf("%s\"%s\"%s:%s\"%s\"%s\n", msIndentation, sKey, msSpace, msSpace, sValue, ",");
+ }
+
+
+
+
+ private String Join (final Collection<String> aValues, final String sSeparator)
+ {
+ final Iterator<String> aIterator = aValues.iterator();
+ if ( ! aIterator.hasNext())
+ return "";
+
+ final StringBuffer aBuffer = new StringBuffer(aIterator.next());
+ while (aIterator.hasNext())
+ {
+ aBuffer.append(sSeparator);
+ aBuffer.append(aIterator.next());
+ }
+ return aBuffer.toString();
+ }
+
+
+
+
+ private String QuoteString (final String sValue)
+ {
+ return sValue.replace("<", "&lt;").replace(">", "&gt;").replace("\"", "&quot;");
+ }
+
+
+
+
+ private final SchemaBase maSchemaBase;
+ private final Map<String, Schema> maTopLevelSchemas;
+ private final PrintStream maOut;
+ private String msIndentation;
+ private final String msSingleIndentation;
+ private final String msSpace;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/generator/html/code.js b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/generator/html/code.js
new file mode 100644
index 000000000000..64be9682e913
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/generator/html/code.js
@@ -0,0 +1,442 @@
+function LoadData ()
+{
+ gTypeNames = [];
+ ComplexTypeNames = [];
+ SimpleTypeNames = [];
+ for (var sName in Data)
+ {
+ gTypeNames.push(sName);
+ switch(Data[sName].type)
+ {
+ case "complex-type":
+ ComplexTypeNames.push(sName);
+ break;
+
+ case "simple-type":
+ SimpleTypeNames.push(sName);
+ break;
+ }
+ }
+ document.getElementById("message").innerHTML = "there are " + ComplexTypeNames.length + " complex types and "
+ + SimpleTypeNames.length +" simple types";
+}
+
+
+
+
+function InitializeSearch ()
+{
+ CurrentTypeName = "";
+ TypeHistory = Array();
+ LoadData();
+ ShowType("A:ST_Overlap");
+}
+
+
+
+
+function CheckInput (aField, aEvent)
+{
+ switch(aEvent.keyCode)
+ {
+ case 38:
+ --selection_index;
+ if (selection_index < 0)
+ selection_index = matches.length-1;
+ break;
+ case 40:
+ ++selection_index;
+ if (selection_index >= matches.length)
+ selection_index = 0;
+ break;
+ default:
+ matches = GetMatches(aField.value);
+ selection_index = 0;
+ }
+
+ ShowMatches(matches, selection_index);
+}
+
+
+
+
+function GetMatches (sPattern)
+{
+ var aLcPatterns = sPattern.toLowerCase().split(/\s+/);
+
+ var nTypeCount = gTypeNames.length;
+
+ var aMatches = [];
+ for (index=0; index<nTypeCount; ++index)
+ {
+ var sTypeName = gTypeNames[index];
+ var aParts = new Array(sTypeName);
+ var sLcTypeName = sTypeName.toLowerCase();
+ var bIsMatch = true;
+ var nSearchStart = 0;
+ for (nPatternIndex=0; nPatternIndex<aLcPatterns.length && bIsMatch; ++nPatternIndex)
+ {
+ var sPattern = aLcPatterns[nPatternIndex];
+ var nMatchStart = sLcTypeName.indexOf(sPattern, nSearchStart);
+ if (nMatchStart >= 0)
+ {
+ var nMatchEnd = nMatchStart + sPattern.length;
+ aParts.push(sTypeName.substring(nSearchStart, nMatchStart));
+ aParts.push(sTypeName.substring(nMatchStart, nMatchEnd));
+ nSearchStart = nMatchEnd;
+ }
+ else
+ {
+ // Only some patterns are matched.
+ bIsMatch = false;
+ }
+ }
+ if (bIsMatch)
+ {
+ if (nMatchEnd < sTypeName.length-1)
+ aParts.push(sTypeName.substring(nMatchEnd));
+ aMatches.push(aParts);
+ }
+ }
+ return aMatches;
+}
+
+
+
+
+/** Show the matching types.
+ * As there can be a great many matching types, some sort of abbreviation is necessary.
+ * Format all matches into lines of n entries.
+ * Show the line containing the selected match and the ones before and after.
+ * Show also the number of ommited matches.
+ */
+function ShowMatches (aMatches, nSelectionIndex)
+{
+ var sText = "";
+
+ var nHalfRange = 10;
+ var nMatchesPerLine = 5;
+ var nLineCount = Math.floor((aMatches.length+nMatchesPerLine-1) / nMatchesPerLine);
+ var nLineOfSelection = Math.floor(nSelectionIndex / nMatchesPerLine);
+ var nFirstDisplayedLine = nLineOfSelection>0 ? nLineOfSelection-1 : 0;
+ var nLastDisplayedLine = nLineOfSelection<nLineCount-1 ? nLineOfSelection+1 : nLineCount-1;
+
+ for (nLineIndex=nFirstDisplayedLine; nLineIndex<=nLastDisplayedLine; ++nLineIndex)
+ {
+ var nLineStartIndex = nLineIndex * nMatchesPerLine;
+ var nLineEndIndex = nLineStartIndex + nMatchesPerLine - 1;
+ if (nLineEndIndex >= aMatches.length)
+ nLineEndIndex = aMatches.length-1;
+
+ sText += "<tr>"
+ for (nIndex=nLineStartIndex; nIndex<=nLineEndIndex; ++nIndex)
+ {
+ var aMatch = aMatches[nIndex];
+ var sTypeName = aMatch[0];
+ var sMatch = "";
+ for (nPartIndex=1; nPartIndex<aMatch.length; ++nPartIndex)
+ {
+ if ((nPartIndex%2)==0)
+ sMatch += "<span class=\"match-highlight\">"+aMatch[nPartIndex]+"</span>";
+ else
+ sMatch += aMatch[nPartIndex];
+ }
+ sText += "<td>"
+ if (nIndex == nSelectionIndex)
+ {
+ sText += " <span class=\"typelink current-match\">" + sMatch + "</span>";
+ }
+ else
+ {
+ sText += " " + GetTypeLink(sMatch, sTypeName, -1);
+ }
+ sText += "</td>"
+ }
+
+ sText += "</tr>";
+ }
+ if (nFirstDisplayedLine > 0)
+ sText = "<tr><td>["+(nFirstDisplayedLine*nMatchesPerLine)+" matches] ...</td><tr>" + sText;
+ if (nLastDisplayedLine+1 < nLineCount)
+ sText += "<tr><td>... ["+((nLineCount-nLastDisplayedLine-1)*nMatchesPerLine)+" matches]</td></tr>";
+
+ document.getElementById('matches').innerHTML = "<table>"+sText+"</table>";
+ if (aMatches.length == 0)
+ {
+ document.getElementById('match-count').innerHTML = "no match:";
+ }
+ else
+ {
+ if (aMatches.length == 1)
+ document.getElementById('match-count').innerHTML = "single match:";
+ else
+ document.getElementById('match-count').innerHTML = aMatches.length+" matches:";
+
+ ShowType(aMatches[nSelectionIndex][0]);
+ }
+}
+
+
+
+
+function GetTopLevelNodeForTypeName(sTypeName)
+{
+ if (sTypeName in Data)
+ return Data[sTypeName];
+ else
+ alert(sTypeName +" is not a known complex type, simple type, or group");
+}
+
+
+
+
+/** Show the specified type.
+ * When nHistoryIndex is not -1 then the history is shortened to that (before that) index.
+ */
+function ShowType (sTypeName, nHistoryIndex)
+{
+ if (nHistoryIndex == -1)
+ {
+ if (CurrentTypeName != "")
+ {
+ TypeHistory.push(CurrentTypeName);
+ ShowHistory();
+ }
+ }
+ else
+ {
+ TypeHistory = TypeHistory.slice(0,nHistoryIndex);
+ ShowHistory();
+ }
+ CurrentTypeName = sTypeName;
+
+ var aElement = document.getElementById('result');
+
+ // Remove the old content.
+ while(aElement.childNodes.length > 0)
+ aElement.removeChild(aElement.firstChild);
+
+ // Create the new content.
+ var list = CreateDomTreeForType(GetTopLevelNodeForTypeName(sTypeName), "ul");
+
+ // Show the new content.
+ aElement.appendChild(list);
+}
+
+
+
+
+/** Create a dom sub tree for the given OOXML type that is ready for insertion into the global DOM tree.
+ */
+function CreateDomTreeForType (aNode, sType)
+{
+ var aEntry = document.createElement(sType);
+
+ if (typeof aNode==='undefined')
+ {
+ aEntry.innerHTML = "undefined node";
+ }
+ else if (typeof aNode.type==='undefined')
+ {
+ aEntry.innerHTML = "unknown type";
+ }
+ else
+ {
+ switch(aNode.type)
+ {
+ case "attribute":
+ aEntry.innerHTML = CreateValueTable([
+ "attribute",
+ "type:", GetTypeLink(aNode["value-type"], aNode["value-type"], -1),
+ "use:", aNode.use]);
+ break;
+
+ case "attribute-reference":
+ aEntry.innerHTML = CreateReference(aNode["referenced-attribute"]);
+ break;
+
+ case "builtin":
+ aEntry.innerHTML = CreateValueTable(
+ ["builtin",
+ "name:", aNode['builtin-type']
+ ]);
+ break;
+
+ case "complex-type":
+ aEntry.innerHTML = aNode.type + " " + aNode.name;
+ break;
+
+ case "complex-type-reference":
+ aEntry.innerHTML = CreateReference(aNode["referenced-complex-type"]);
+ break;
+
+ case "group":
+ aEntry.innerHTML = aNode.type + " " + aNode.name;
+ break;
+
+ case "group-reference":
+ aEntry.innerHTML = CreateReference("group", aNode["referenced-group"]);
+ break;
+
+ case "element":
+ aEntry.innerHTML = "element <b>" + aNode["tag"] + "</b> -> " + GetTypeLink(aNode["result-type"], aNode["result-type"], -1);
+ break;
+
+ case "occurrence":
+ aEntry.innerHTML = aNode.minimum +" -> " + aNode.maximum;
+ break;
+
+ case "restriction":
+ aEntry.innerHTML = CreateRestrictionRepresentation(aNode);
+ break;
+
+ case "sequence":
+ aEntry.innerHTML = "sequence";
+ break;
+
+ case "simple-type":
+ aEntry.innerHTML = aNode.type + " " + aNode.name;
+ break;
+
+ case "simple-type-reference":
+ aEntry.innerHTML = CreateReference("simple-type", aNode["referenced-simple-type"]);
+ break;
+
+ default:
+ aEntry.innerHTML = aNode.type;
+ break;
+ }
+
+ // Add nodes for attributes.
+ var aAttributes= aNode["attributes"];
+ if ( ! (typeof aAttributes==='undefined' || aAttributes.length == 0))
+ {
+ var aAttributeList = document.createElement("ul");
+ aEntry.appendChild(aAttributeList);
+
+ for (var nIndex=0; nIndex<aAttributes.length; ++nIndex)
+ {
+ var aAttributeEntry = CreateDomTreeForType(aAttributes[nIndex], "li");
+ aAttributeList.appendChild(aAttributeEntry);
+ }
+ }
+
+ // Add nodes for children.
+ var aChildren = aNode["children"];
+ if ( ! (typeof aChildren==='undefined' || aChildren.length == 0))
+ {
+ var aChildrenList = document.createElement("ul");
+ aEntry.appendChild(aChildrenList);
+
+ for (var nIndex=0; nIndex<aChildren.length; ++nIndex)
+ {
+ var aChildrenEntry = CreateDomTreeForType(aChildren[nIndex], "li");
+ aChildrenList.appendChild(aChildrenEntry);
+ }
+ }
+ }
+ return aEntry;
+}
+
+
+
+
+function GetTypeLink (sText, sTarget, nIndex)
+{
+ return "<span class=\"typelink\" id=\""+sTarget+"\" onclick=\"ShowType('"+sTarget+"',"+nIndex+")\">"+sText+"</span>";
+}
+
+
+
+
+function CreateValueTable (aValues)
+{
+ var sResult = "<table class=\"value-table\"><tr><td>"+aValues[0]+"</td><td>"+aValues[1]+"</td><td>"+aValues[2]+"</td></tr>";
+ for (nIndex=3; nIndex<aValues.length; nIndex+=2)
+ {
+ sResult += "<tr><td></td><td>"+aValues[nIndex]+"</td><td>"+aValues[nIndex+1]+"</td></tr>";
+ }
+ sResult += "</table>";
+ return sResult;
+}
+
+
+
+
+function CreateReference (sWhat, sTypeName)
+{
+ return "reference to "+sWhat+" "+GetTypeLink(sTypeName, sTypeName, -1) + " "
+ +CreateButton(
+ sTypeName,
+ "show",
+ "ToggleTypeReferenceExpansion('"+sTypeName+"')")
+ +"<br><span id=\"expansion-"+sTypeName+"\"></span>";
+}
+
+
+
+
+function CreateButton (sId, sText, sExpandAction)
+{
+ return "<span class=\"button\" id=\"button-"+sId+"\" onClick=\""+sExpandAction+"\">"+sText+"</span>";
+}
+
+
+
+
+function ToggleTypeReferenceExpansion(sTypeName)
+{
+ var aButton = document.getElementById("button-"+sTypeName);
+ var aExpansion = document.getElementById("expansion-"+sTypeName);
+ if (aButton.innerHTML == "show")
+ {
+ aExpansion.appendChild(CreateDomTreeForType(Data[sTypeName], "span"));
+ aButton.innerHTML = "hide";
+ }
+ else
+ {
+ aExpansion.innerHTML = "";
+ aButton.innerHTML = "show";
+ }
+}
+
+
+
+
+function ShowHistory ()
+{
+ var aElement = document.getElementById('history');
+ var sContent = "History:";
+ for (nIndex=0; nIndex<TypeHistory.length; ++nIndex)
+ {
+ if (nIndex == 0)
+ sContent += " ";
+ else
+ sContent += ", ";
+ sContent += GetTypeLink(TypeHistory[nIndex], TypeHistory[nIndex], nIndex);
+ }
+ aElement.innerHTML = sContent;
+}
+
+
+
+
+function CreateRestrictionRepresentation (aNode)
+{
+ var aTableData = ["restriction", "based on:", GetTypeLink(aNode['base-type'], aNode['base-type'], -1)];
+ AddValue(aNode, "enumeration", aTableData);
+ AddValue(aNode, "pattern", aTableData);
+ AddValue(aNode, "length", aTableData);
+ return CreateValueTable(aTableData);
+}
+
+
+
+function AddValue (aMap, sKey, aTableData)
+{
+ if (sKey in aMap)
+ {
+ aTableData.push(sKey+":");
+ aTableData.push(aMap[sKey]);
+ }
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/generator/html/display.css b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/generator/html/display.css
new file mode 100644
index 000000000000..d7d267e9ed9d
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/generator/html/display.css
@@ -0,0 +1,57 @@
+* {
+ font-family: Arial;
+ font-style:normal;
+ }
+.typelink {
+ cursor: pointer; cursor: hand;
+ color: #688;
+ }
+.typelink:link { color:#003; background-color:transparent; }
+.typelink:visited { color:#003; background-color:transparent; }
+.typelink:hover {
+ text-decoration: underline;
+ }
+.typelink:active { color:#003; background-color:#acc; }
+
+.value-table { display: inline-table; }
+
+
+.button {
+ box-shadow:inset 0px 1px 0px 0px #ffffff;
+ background-color:#ededed;
+ border-top-left-radius:4px;
+ border-top-right-radius:4px;
+ border-bottom-right-radius:4px;
+ border-bottom-left-radius:4px;
+ border:1px solid #dcdcdc;
+ display: inline-block;
+ color: #777777;
+ font-size: 15px;
+ font-weight: bold;
+ height: 20px;
+ line-height: 20px;
+ width: 80px;
+ text-align:center;
+ vertical-align: middle;
+ text-shadow:1px 1px 0px #ffffff;
+ cursor: pointer; cursor: hand;
+ }
+
+.button:hover {
+ background-color:#dfdfdf;
+ }
+
+.button:active {
+ position: relative;
+ top: 1px;
+ background-color:#c0c0c0;
+ }
+
+.current-match {
+ font-weight: bold;
+ background-color:#c0c0c0;
+ }
+
+.match-highlight {
+ color: #ff0000;
+ }
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/generator/html/linking-template.html b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/generator/html/linking-template.html
new file mode 100644
index 000000000000..c20c67c57165
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/generator/html/linking-template.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="UTF-8" />
+ <link rel="stylesheet" type="text/css" href="C:\source\ooxml\git\main\ooxml\source\framework\SchemaParser\src\org\apache\openoffice\ooxml\schema\generator\html\display.css">
+ </link>
+ <script type="text/javascript">
+ $DATA$
+ </script>
+ <script type="text/javascript" src="C:\source\ooxml\git\main\ooxml\source\framework\SchemaParser\src\org\apache\openoffice\ooxml\schema\generator\html\code.js">
+ </script>
+ </head>
+ <body onLoad="InitializeSearch()">
+ <div id="message"></div>
+ <input onKeyUp="CheckInput(this,event)"></input>
+ <div id="history"></div>
+ <br><br><div id="match-count">Matches:</div><br>
+ <div id="matches" cols="100" rows="20" defaultValue="type text to see matching types"></div>
+ <br>
+ <div id="result">no result yet</div>
+ </body>
+</html>
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/generator/html/template.html b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/generator/html/template.html
new file mode 100644
index 000000000000..2c174c137717
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/generator/html/template.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="UTF-8" />
+ <style type="text/css">
+ $CSS$
+ </style>
+ <script type="text/javascript">
+ $DATA$
+ </script>
+ <script type="text/javascript">
+ $CODE$
+ </script>
+ </head>
+ <body onLoad="InitializeSearch()">
+ <div id="message"></div>
+ <input onKeyUp="CheckInput(this,event)"></input>
+ <br><br><div id="match-count">Matches:</div><br>
+ <div id="history"></div>
+ <div id="matches" cols="100" rows="20" defaultValue="type text to see matching types"></div>
+ <br>
+ <div id="result">no result yet</div>
+ </body>
+</html>
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/iterator/AttributeIterator.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/iterator/AttributeIterator.java
new file mode 100644
index 000000000000..2160b8b26623
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/iterator/AttributeIterator.java
@@ -0,0 +1,109 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.schema.iterator;
+
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.Queue;
+import java.util.Set;
+import java.util.TreeSet;
+
+import org.apache.openoffice.ooxml.schema.model.attribute.Attribute;
+import org.apache.openoffice.ooxml.schema.model.attribute.AttributeGroup;
+import org.apache.openoffice.ooxml.schema.model.attribute.AttributeGroupReference;
+import org.apache.openoffice.ooxml.schema.model.attribute.AttributeReference;
+import org.apache.openoffice.ooxml.schema.model.base.INode;
+import org.apache.openoffice.ooxml.schema.model.base.INodeVisitor;
+import org.apache.openoffice.ooxml.schema.model.base.NodeVisitorAdapter;
+import org.apache.openoffice.ooxml.schema.model.schema.SchemaBase;
+
+/** Iterate over all attributes of a given node.
+ * References to attributes and attribute groups and their references are resolved.
+ *
+ * If you want to iterate over all attributes in a node tree then add an outer NodeIterator.
+ */
+public class AttributeIterator
+ implements Iterable<Attribute>
+{
+ public AttributeIterator (
+ final INode aNode,
+ final SchemaBase aSchemaBase)
+ {
+ maAttributes = new TreeSet<Attribute>();
+ CollectAttributes(aNode, aSchemaBase);
+ }
+
+
+
+
+ public Iterator<Attribute> iterator ()
+ {
+ return maAttributes.iterator();
+ }
+
+
+
+
+ private void CollectAttributes (
+ final INode aType,
+ final SchemaBase aSchemaBase)
+ {
+ final Queue<INode> aTodo = new LinkedList<>();
+ for (final INode aAttribute : aType.GetAttributes())
+ aTodo.add(aAttribute);
+ final INodeVisitor aVisitor = new NodeVisitorAdapter()
+ {
+ @Override public void Visit (final Attribute aAttribute)
+ {
+ maAttributes.add(aAttribute);
+ }
+ @Override public void Visit (final AttributeReference aAttributeReference)
+ {
+ aTodo.add(aAttributeReference.GetReferencedAttribute(aSchemaBase));
+ }
+ @Override public void Visit (final AttributeGroup aAttributeGroup)
+ {
+ for (final INode aGroupAttribute : aAttributeGroup.GetAttributes())
+ aTodo.add(aGroupAttribute);
+ }
+ @Override public void Visit (final AttributeGroupReference aAttributeGroupReference)
+ {
+ aTodo.add(aAttributeGroupReference.GetReferencedAttributeGroup(aSchemaBase));
+ }
+ @Override public void Default (final INode aNode)
+ {
+ throw new RuntimeException("can not handle attribute of type "+aNode.GetNodeType());
+ }
+ };
+ while ( ! aTodo.isEmpty())
+ {
+ final INode aAttribute = aTodo.poll();
+ if (aAttribute != null)
+ aAttribute.AcceptVisitor(aVisitor);
+ }
+ }
+
+
+
+
+ private final Set<Attribute> maAttributes;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/iterator/AttributeNodeIterator.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/iterator/AttributeNodeIterator.java
new file mode 100644
index 000000000000..0a5bc410f073
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/iterator/AttributeNodeIterator.java
@@ -0,0 +1,112 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.schema.iterator;
+
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.Queue;
+import java.util.Vector;
+
+import org.apache.openoffice.ooxml.schema.model.attribute.Attribute;
+import org.apache.openoffice.ooxml.schema.model.attribute.AttributeGroup;
+import org.apache.openoffice.ooxml.schema.model.attribute.AttributeGroupReference;
+import org.apache.openoffice.ooxml.schema.model.attribute.AttributeReference;
+import org.apache.openoffice.ooxml.schema.model.base.INode;
+import org.apache.openoffice.ooxml.schema.model.base.INodeVisitor;
+import org.apache.openoffice.ooxml.schema.model.base.NodeVisitorAdapter;
+import org.apache.openoffice.ooxml.schema.model.schema.SchemaBase;
+
+/** This iterator is very similar to the AttributeIterator but it
+ * a) returns the attributes as INode objects and
+ * b) includes referencing nodes and group nodes in the iteration and
+ * c) if there are multiple references to the same attribute then each
+ * of them is visited.
+ */
+public class AttributeNodeIterator
+ implements Iterable<INode>
+{
+ public AttributeNodeIterator (
+ final INode aNode,
+ final SchemaBase aSchemaBase)
+ {
+ maAttributes = new Vector<INode>();
+ CollectAttributes(aNode, aSchemaBase);
+ }
+
+
+
+
+ public Iterator<INode> iterator ()
+ {
+ return maAttributes.iterator();
+ }
+
+
+
+
+ private void CollectAttributes (
+ final INode aType,
+ final SchemaBase aSchemaBase)
+ {
+ final Queue<INode> aTodo = new LinkedList<>();
+ for (final INode aAttribute : aType.GetAttributes())
+ aTodo.add(aAttribute);
+ final INodeVisitor aVisitor = new NodeVisitorAdapter()
+ {
+ @Override public void Visit (final Attribute aAttribute)
+ {
+ maAttributes.add(aAttribute);
+ }
+ @Override public void Visit (final AttributeReference aAttributeReference)
+ {
+ maAttributes.add(aAttributeReference);
+ aTodo.add(aAttributeReference.GetReferencedAttribute(aSchemaBase));
+ }
+ @Override public void Visit (final AttributeGroup aAttributeGroup)
+ {
+ maAttributes.add(aAttributeGroup);
+ for (final INode aGroupAttribute : aAttributeGroup.GetAttributes())
+ aTodo.add(aGroupAttribute);
+ }
+ @Override public void Visit (final AttributeGroupReference aAttributeGroupReference)
+ {
+ maAttributes.add(aAttributeGroupReference);
+ aTodo.add(aAttributeGroupReference.GetReferencedAttributeGroup(aSchemaBase));
+ }
+ @Override public void Default (final INode aNode)
+ {
+ throw new RuntimeException("can not handle attribute of type "+aNode.GetNodeType());
+ }
+ };
+ while ( ! aTodo.isEmpty())
+ {
+ final INode aAttribute = aTodo.poll();
+ if (aAttribute != null)
+ aAttribute.AcceptVisitor(aVisitor);
+ }
+ }
+
+
+
+
+ private final Vector<INode> maAttributes;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/iterator/DereferencingNodeIterator.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/iterator/DereferencingNodeIterator.java
new file mode 100644
index 000000000000..77c8f9837c55
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/iterator/DereferencingNodeIterator.java
@@ -0,0 +1,111 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.schema.iterator;
+
+import java.util.Iterator;
+import java.util.Vector;
+
+import org.apache.openoffice.ooxml.schema.model.base.INode;
+import org.apache.openoffice.ooxml.schema.model.base.INodeReference;
+import org.apache.openoffice.ooxml.schema.model.schema.SchemaBase;
+
+/** Iterate over all nodes in a node tree. References to groups and elements
+ * are resolved and the referenced nodes are included in the iteration.
+ */
+public class DereferencingNodeIterator
+ implements Iterable<INode>
+
+{
+ public DereferencingNodeIterator (
+ final INode aRoot,
+ final SchemaBase aSchemaBase,
+ final boolean bIncludeReferencingNodes)
+ {
+ maRoot = aRoot;
+ maSchemaBase = aSchemaBase;
+ mbIncludeReferencingNodes = bIncludeReferencingNodes;
+ }
+
+
+
+
+ @Override
+ public Iterator<INode> iterator()
+ {
+ return CollectNodes(maRoot, mbIncludeReferencingNodes).iterator();
+ }
+
+
+
+
+ private Vector<INode> CollectNodes (
+ final INode aRoot,
+ final boolean bIncludeReferencingNodes)
+ {
+ final Vector<INode> aNodes = new Vector<>();
+ AddNodes(aNodes, aRoot, bIncludeReferencingNodes);
+ return aNodes;
+ }
+
+
+
+
+ private void AddNodes (
+ final Vector<INode> aNodes,
+ final INode aRoot,
+ final boolean bIncludeReferencingNodes)
+ {
+ for (final INode aNode : new NodeIterator(aRoot))
+ {
+ switch(aNode.GetNodeType())
+ {
+ case AttributeGroupReference:
+ case AttributeReference:
+ case ComplexTypeReference:
+ case ElementReference:
+ case GroupReference:
+ case SimpleTypeReference:
+ case Extension:
+ if (mbIncludeReferencingNodes)
+ aNodes.add(aNode);
+ for (final INode aChild : new DereferencingNodeIterator(
+ ((INodeReference)aNode).GetReferencedNode(maSchemaBase),
+ maSchemaBase,
+ bIncludeReferencingNodes))
+ {
+ aNodes.add(aChild);
+ }
+ break;
+
+ default:
+ aNodes.add(aNode);
+ }
+ }
+ }
+
+
+
+
+ private final INode maRoot;
+ private final SchemaBase maSchemaBase;
+ private final boolean mbIncludeReferencingNodes;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/iterator/NodeIterator.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/iterator/NodeIterator.java
new file mode 100644
index 000000000000..8ecb2abe068c
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/iterator/NodeIterator.java
@@ -0,0 +1,68 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.schema.iterator;
+
+import java.util.Iterator;
+import java.util.Vector;
+
+import org.apache.openoffice.ooxml.schema.model.base.INode;
+
+/** Iterate over all nodes in a node tree.
+ * The root node is typically a simple or complex type.
+ * References to elements or groups etc. are not followed. Use the
+ * DereferencingNodeIterator for that.
+ */
+public class NodeIterator
+ implements Iterable<INode>
+{
+ public NodeIterator (final INode aRoot)
+ {
+ maNodes = new Vector<>();
+ AddNodes(aRoot);
+ }
+
+
+
+
+ @Override
+ public Iterator<INode> iterator ()
+ {
+ return maNodes.iterator();
+ }
+
+
+
+
+ /** Recursively add child nodes depth first.
+ */
+ private void AddNodes (final INode aNode)
+ {
+ maNodes.add(aNode);
+ for (final INode aChild : aNode.GetChildren())
+ AddNodes(aChild);
+ }
+
+
+
+
+ private Vector<INode> maNodes;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/iterator/PermutationIterator.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/iterator/PermutationIterator.java
new file mode 100644
index 000000000000..e71a6d4deac2
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/iterator/PermutationIterator.java
@@ -0,0 +1,137 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.schema.iterator;
+
+
+/** Enumerate all permutations of a given array with elements of type T.
+ * The permutations are created in place, i.e. the array given to the constructor
+ * is modified as side effect of calling HasMore().
+ *
+ * The algorithm is taken from "The Art of Computer Programming, Volume 4,
+ * Fasicle 2, by Donald E. Knuth" from section 7.2.1.2, Algorithm P.
+ */
+public class PermutationIterator<T>
+{
+ public PermutationIterator (
+ final T[] aItems)
+ {
+ // Count the nodes.
+ mnItemCount = aItems.length;
+
+ // Set up three arrays, one with the actual nodes, one for the inversions
+ // and one for directions.
+ maItems = aItems;
+ maInversions = new int[mnItemCount];
+ maDirections = new int[mnItemCount];
+ for (int nIndex=0; nIndex<mnItemCount; ++nIndex)
+ {
+ maInversions[nIndex] = 0;
+ maDirections[nIndex] = 1;
+ }
+
+ mbHasMorePermutations = mnItemCount>0;
+ mbIsNextPermutationReady = true;
+ }
+
+
+
+
+ public boolean HasMore ()
+ {
+ if ( ! mbIsNextPermutationReady)
+ ProvideNextPermutation();
+ return mbHasMorePermutations;
+ }
+
+
+
+
+ public T[] Next()
+ {
+ assert(mbHasMorePermutations && mbIsNextPermutationReady);
+ mbIsNextPermutationReady = false;
+ return maItems;
+ }
+
+
+
+
+ private void ProvideNextPermutation ()
+ {
+ mbIsNextPermutationReady = true;
+
+ // Create the next permutation.
+ int nJ = mnItemCount;
+ int nS = 0;
+
+ while (true)
+ {
+ final int nQ = maInversions[nJ-1] + maDirections[nJ-1];
+ if (nQ>=0 && nQ<nJ)
+ {
+ // Exchange j-cj+s and j-q+s
+ final int nIndexA = nJ-maInversions[nJ - 1]+nS - 1;
+ final int nIndexB = nJ-nQ+nS - 1;
+ final T aItem = maItems[nIndexA];
+ maItems[nIndexA] = maItems[nIndexB];
+ maItems[nIndexB] = aItem;
+
+ // cj=q
+ maInversions[nJ - 1] = nQ;
+
+ // Next permutation is ready.
+ break;
+ }
+ else
+ {
+ if (nQ==nJ)
+ {
+ // Increase s.
+ if (nJ == 1)
+ {
+ // All permutations generated.
+ mbHasMorePermutations = false;
+ break;
+ }
+ else
+ {
+ ++nS;
+ }
+ }
+
+ // Switch direction.
+ maDirections[nJ - 1] = -maDirections[nJ - 1];
+ --nJ;
+ }
+ }
+ }
+
+
+
+
+ private final int mnItemCount;
+ private final T[] maItems;
+ private final int[] maInversions;
+ private final int[] maDirections;
+ private boolean mbIsNextPermutationReady;
+ private boolean mbHasMorePermutations;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/misc/Log.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/misc/Log.java
new file mode 100644
index 000000000000..8ac464743dae
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/misc/Log.java
@@ -0,0 +1,126 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.schema.misc;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.PrintStream;
+
+/** Make output with indentation easier.
+ */
+public class Log
+{
+ public Log (final File aFile)
+ {
+ PrintStream aOut = null;
+ try
+ {
+ aOut = new PrintStream(new FileOutputStream(aFile));
+ }
+ catch (FileNotFoundException e)
+ {
+ e.printStackTrace();
+ }
+ maOut = aOut;
+ mbIsActive = maOut!=null;
+ msIndentation = "";
+ }
+
+
+
+
+ public void AddComment (
+ final String sFormat,
+ final Object ... aArgumentList)
+ {
+ if (mbIsActive)
+ {
+ maOut.print(msIndentation);
+ maOut.print("// ");
+ maOut.printf(sFormat, aArgumentList);
+ maOut.print("\n");
+ }
+ }
+
+
+
+
+ public void StartBlock ()
+ {
+ if (mbIsActive)
+ msIndentation += " ";
+ }
+
+
+
+
+ public void EndBlock ()
+ {
+ if (mbIsActive)
+ msIndentation = msIndentation.substring(4);
+ }
+
+
+
+
+ public void printf (
+ final String sFormat, final Object ... aArgumentList)
+ {
+ if (mbIsActive)
+ {
+ final String sMessage = String.format(sFormat, aArgumentList);
+ maOut.print(msIndentation);
+ maOut.print(sMessage);
+ }
+ }
+
+
+
+
+ public void println (
+ final String sMessage)
+ {
+ if (mbIsActive)
+ {
+ maOut.print(msIndentation);
+ maOut.print(sMessage);
+ maOut.print("\n");
+ }
+ }
+
+
+
+
+ public void Close()
+ {
+ if (mbIsActive)
+ maOut.close();
+ }
+
+
+
+
+ private final PrintStream maOut;
+ private final boolean mbIsActive;
+ private String msIndentation;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/attribute/Attribute.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/attribute/Attribute.java
new file mode 100644
index 000000000000..84f68cb77354
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/attribute/Attribute.java
@@ -0,0 +1,91 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.schema.model.attribute;
+
+import org.apache.openoffice.ooxml.schema.model.base.INodeVisitor;
+import org.apache.openoffice.ooxml.schema.model.base.Location;
+import org.apache.openoffice.ooxml.schema.model.base.NodeType;
+import org.apache.openoffice.ooxml.schema.model.base.QualifiedName;
+import org.apache.openoffice.ooxml.schema.parser.FormDefault;
+
+/* Representation of a single attribute.
+ */
+public class Attribute
+ extends AttributeBase
+{
+ public Attribute (
+ final QualifiedName aName,
+ final QualifiedName aTypeName,
+ final String sUse,
+ final String sDefault,
+ final String sFixed,
+ final FormDefault eFormDefault,
+ final Location aLocation)
+ {
+ super(aName, sUse, sDefault, sFixed, eFormDefault, aLocation);
+ maTypeName = aTypeName;
+ }
+
+
+
+
+ public QualifiedName GetTypeName ()
+ {
+ return maTypeName;
+ }
+
+
+
+
+ @Override
+ public NodeType GetNodeType ()
+ {
+ return NodeType.Attribute;
+ }
+
+
+
+
+ @Override
+ public void AcceptVisitor (final INodeVisitor aVisitor)
+ {
+ aVisitor.Visit(this);
+ }
+
+
+
+
+ @Override
+ public String toString ()
+ {
+ return String.format(
+ "attribute %s of type %s, %s",
+ GetName().GetDisplayName(),
+ maTypeName.GetDisplayName(),
+ super.toString());
+ }
+
+
+
+
+ private final QualifiedName maTypeName;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/attribute/AttributeBase.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/attribute/AttributeBase.java
new file mode 100644
index 000000000000..4fbf987a5be7
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/attribute/AttributeBase.java
@@ -0,0 +1,117 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.schema.model.attribute;
+
+import org.apache.openoffice.ooxml.schema.model.base.Location;
+import org.apache.openoffice.ooxml.schema.model.base.Node;
+import org.apache.openoffice.ooxml.schema.model.base.QualifiedName;
+import org.apache.openoffice.ooxml.schema.parser.FormDefault;
+
+/** Base class for both Attribute and AttributeReference classes.
+ */
+public abstract class AttributeBase
+ extends Node
+{
+ public enum Use
+ {
+ Optional,
+ Required
+ }
+
+
+
+ public AttributeBase (
+ final QualifiedName aName,
+ final String sUse,
+ final String sDefault,
+ final String sFixed,
+ final FormDefault eFormDefault,
+ final Location aLocation)
+ {
+ super(null, aName, aLocation);
+
+ switch(sUse)
+ {
+ case "optional":
+ meUse = Use.Optional;
+ break;
+ case "required":
+ meUse = Use.Required;
+ break;
+ default:
+ throw new RuntimeException("value of 'use' attribute is neither 'optional' nor 'required' but "+sUse);
+ }
+ msDefault = sDefault;
+ msFixed = sFixed;
+ meFormDefault = eFormDefault;
+ }
+
+
+
+
+ public FormDefault GetFormDefault()
+ {
+ return meFormDefault;
+ }
+
+
+
+
+ public Use GetUse ()
+ {
+ return meUse;
+ }
+
+
+
+
+ public String GetDefault()
+ {
+ return msDefault;
+ }
+
+
+
+
+ @Override
+ public String toString ()
+ {
+ String sText = "use "+meUse.toString();
+ if (msDefault != null)
+ sText += ", default "+msDefault;
+ else
+ sText += ", no default";
+ if (msFixed != null)
+ sText += ", fixed to "+msFixed;
+ else
+ sText += ", not fixed";
+ return sText;
+ }
+
+
+
+
+ private final Use meUse;
+ private final String msDefault;
+ private final String msFixed;
+ private final FormDefault meFormDefault;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/attribute/AttributeGroup.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/attribute/AttributeGroup.java
new file mode 100644
index 000000000000..92b7151678d4
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/attribute/AttributeGroup.java
@@ -0,0 +1,65 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.schema.model.attribute;
+
+import org.apache.openoffice.ooxml.schema.model.base.INodeVisitor;
+import org.apache.openoffice.ooxml.schema.model.base.Location;
+import org.apache.openoffice.ooxml.schema.model.base.Node;
+import org.apache.openoffice.ooxml.schema.model.base.NodeType;
+import org.apache.openoffice.ooxml.schema.model.base.QualifiedName;
+
+public class AttributeGroup
+ extends Node
+{
+ public AttributeGroup (
+ final QualifiedName aName,
+ final Location aLocation)
+ {
+ super(null, aName, aLocation);
+ }
+
+
+
+
+ @Override
+ public NodeType GetNodeType ()
+ {
+ return NodeType.AttributeGroup;
+ }
+
+
+
+
+ @Override
+ public void AcceptVisitor (final INodeVisitor aVisitor)
+ {
+ aVisitor.Visit(this);
+ }
+
+
+
+
+ public String toString ()
+ {
+ return "attribute group "+GetName().GetDisplayName();
+ }
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/attribute/AttributeGroupReference.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/attribute/AttributeGroupReference.java
new file mode 100644
index 000000000000..aa1e7470fe0e
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/attribute/AttributeGroupReference.java
@@ -0,0 +1,110 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.schema.model.attribute;
+
+import org.apache.openoffice.ooxml.schema.model.base.INode;
+import org.apache.openoffice.ooxml.schema.model.base.INodeReference;
+import org.apache.openoffice.ooxml.schema.model.base.INodeVisitor;
+import org.apache.openoffice.ooxml.schema.model.base.Location;
+import org.apache.openoffice.ooxml.schema.model.base.Node;
+import org.apache.openoffice.ooxml.schema.model.base.NodeType;
+import org.apache.openoffice.ooxml.schema.model.base.QualifiedName;
+import org.apache.openoffice.ooxml.schema.model.schema.SchemaBase;
+
+public class AttributeGroupReference
+ extends Node
+ implements INodeReference
+{
+ public AttributeGroupReference (
+ final QualifiedName aReferencedElementName,
+ final Location aLocation)
+ {
+ super(null, null, aLocation);
+ maReferencedElement = aReferencedElementName;
+ }
+
+
+
+
+ @Override
+ public INode GetOnlyChild ()
+ {
+ throw new RuntimeException("AttributeGroupReference has no children");
+ }
+
+
+
+
+ @Override
+ public void AcceptVisitor (final INodeVisitor aVisitor)
+ {
+ aVisitor.Visit(this);
+ }
+
+
+
+
+ public QualifiedName GetReferencedName ()
+ {
+ return maReferencedElement;
+ }
+
+
+
+
+ public AttributeGroup GetReferencedAttributeGroup (final SchemaBase aSchemaBase)
+ {
+ return aSchemaBase.AttributeGroups.Get(maReferencedElement);
+ }
+
+
+
+
+ @Override
+ public INode GetReferencedNode (final SchemaBase aSchemaBase)
+ {
+ return GetReferencedAttributeGroup(aSchemaBase);
+ }
+
+
+
+
+ @Override
+ public NodeType GetNodeType ()
+ {
+ return NodeType.AttributeGroupReference;
+ }
+
+
+
+
+ @Override
+ public String toString ()
+ {
+ return "reference to attribute group "+maReferencedElement.GetDisplayName();
+ }
+
+
+
+
+ private final QualifiedName maReferencedElement;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/attribute/AttributeReference.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/attribute/AttributeReference.java
new file mode 100644
index 000000000000..a1c97d6c2c4e
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/attribute/AttributeReference.java
@@ -0,0 +1,115 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.schema.model.attribute;
+
+import org.apache.openoffice.ooxml.schema.model.base.INode;
+import org.apache.openoffice.ooxml.schema.model.base.INodeReference;
+import org.apache.openoffice.ooxml.schema.model.base.INodeVisitor;
+import org.apache.openoffice.ooxml.schema.model.base.Location;
+import org.apache.openoffice.ooxml.schema.model.base.NodeType;
+import org.apache.openoffice.ooxml.schema.model.base.QualifiedName;
+import org.apache.openoffice.ooxml.schema.model.schema.SchemaBase;
+import org.apache.openoffice.ooxml.schema.parser.FormDefault;
+
+public class AttributeReference
+ extends AttributeBase
+ implements INodeReference
+{
+ public AttributeReference (
+ final QualifiedName aReferencedName,
+ final String sUse,
+ final String sDefault,
+ final String sFixed,
+ final FormDefault eFormDefault,
+ final Location aLocation)
+ {
+ super(aReferencedName, sUse, sDefault, sFixed, eFormDefault, aLocation);
+
+ maReferencedName = aReferencedName;
+ }
+
+
+
+
+ public Attribute GetReferencedAttribute (final SchemaBase aSchemaBase)
+ {
+ final Attribute aAttribute = aSchemaBase.Attributes.Get(maReferencedName);
+ if (aAttribute == null)
+ {
+ throw new RuntimeException(
+ String.format(
+ "can not find attribute %s, referenced at %s",
+ maReferencedName.GetDisplayName(),
+ GetLocation()));
+ }
+ return aAttribute;
+ }
+
+
+
+
+ @Override
+ public INode GetReferencedNode (final SchemaBase aSchemaBase)
+ {
+ return GetReferencedAttribute(aSchemaBase);
+ }
+
+
+
+
+ public QualifiedName GetReferencedName ()
+ {
+ return maReferencedName;
+ }
+
+
+
+
+ @Override
+ public NodeType GetNodeType ()
+ {
+ return NodeType.AttributeReference;
+ }
+
+
+
+
+ @Override
+ public void AcceptVisitor(INodeVisitor aVisitor)
+ {
+ aVisitor.Visit(this);
+ }
+
+
+
+
+ @Override
+ public String toString ()
+ {
+ return "attribute reference to "+maReferencedName;
+ }
+
+
+
+
+ private final QualifiedName maReferencedName;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/base/INode.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/base/INode.java
new file mode 100644
index 000000000000..df8208b9adeb
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/base/INode.java
@@ -0,0 +1,39 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.schema.model.base;
+
+
+/** Interface of all nodes in a tree of XML schema nodes.
+ * It is implemented by complex types, simple types, and attributes.
+ */
+public interface INode
+{
+ NodeType GetNodeType ();
+ QualifiedName GetName ();
+ int GetChildCount();
+ Iterable<INode> GetChildren();
+ INode GetOnlyChild();
+ int GetAttributeCount();
+ Iterable<INode> GetAttributes ();
+ void AcceptVisitor (final INodeVisitor aVisitor);
+ Location GetLocation ();
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/base/INodeReference.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/base/INodeReference.java
new file mode 100644
index 000000000000..e4644563be14
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/base/INodeReference.java
@@ -0,0 +1,32 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.schema.model.base;
+
+import org.apache.openoffice.ooxml.schema.model.schema.SchemaBase;
+
+/** Interface implemented by all references to INodes.
+ */
+public interface INodeReference
+ extends INode
+{
+ INode GetReferencedNode (final SchemaBase aSchema);
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/base/INodeVisitor.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/base/INodeVisitor.java
new file mode 100644
index 000000000000..664384dced5a
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/base/INodeVisitor.java
@@ -0,0 +1,85 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.schema.model.base;
+
+import org.apache.openoffice.ooxml.schema.model.attribute.Attribute;
+import org.apache.openoffice.ooxml.schema.model.attribute.AttributeGroup;
+import org.apache.openoffice.ooxml.schema.model.attribute.AttributeGroupReference;
+import org.apache.openoffice.ooxml.schema.model.attribute.AttributeReference;
+import org.apache.openoffice.ooxml.schema.model.complex.All;
+import org.apache.openoffice.ooxml.schema.model.complex.Any;
+import org.apache.openoffice.ooxml.schema.model.complex.Choice;
+import org.apache.openoffice.ooxml.schema.model.complex.ComplexContent;
+import org.apache.openoffice.ooxml.schema.model.complex.ComplexType;
+import org.apache.openoffice.ooxml.schema.model.complex.ComplexTypeReference;
+import org.apache.openoffice.ooxml.schema.model.complex.Element;
+import org.apache.openoffice.ooxml.schema.model.complex.ElementReference;
+import org.apache.openoffice.ooxml.schema.model.complex.Extension;
+import org.apache.openoffice.ooxml.schema.model.complex.Group;
+import org.apache.openoffice.ooxml.schema.model.complex.GroupReference;
+import org.apache.openoffice.ooxml.schema.model.complex.OccurrenceIndicator;
+import org.apache.openoffice.ooxml.schema.model.complex.Sequence;
+import org.apache.openoffice.ooxml.schema.model.simple.BuiltIn;
+import org.apache.openoffice.ooxml.schema.model.simple.List;
+import org.apache.openoffice.ooxml.schema.model.simple.Restriction;
+import org.apache.openoffice.ooxml.schema.model.simple.SimpleContent;
+import org.apache.openoffice.ooxml.schema.model.simple.SimpleType;
+import org.apache.openoffice.ooxml.schema.model.simple.SimpleTypeReference;
+import org.apache.openoffice.ooxml.schema.model.simple.Union;
+
+/** Interface for the visitor pattern.
+ * Use a node visitor instead of INode/NodeType and casting INode to a derived
+ * class.
+ * See also the default implementation NodeVisitorAdapter.
+ */
+public interface INodeVisitor
+{
+ // Complex nodes.
+ void Visit (final All aAll);
+ void Visit (final Any aAny);
+ void Visit (final ComplexContent aComplexContent);
+ void Visit (final ComplexType aNode);
+ void Visit (final ComplexTypeReference aTypeReference);
+ void Visit (final Choice aChoice);
+ void Visit (final Element aElement);
+ void Visit (final ElementReference aElementReference);
+ void Visit (final Extension aNode);
+ void Visit (final Group aGroup);
+ void Visit (final GroupReference aGroupReference);
+ void Visit (final OccurrenceIndicator aOccurrenceIndicator);
+ void Visit (final Sequence aNode);
+
+ // Simple nodes.
+ void Visit (final BuiltIn aType);
+ void Visit (final List aList);
+ void Visit (final Restriction aRestriction);
+ void Visit (final SimpleContent aSimpleContent);
+ void Visit (final SimpleType aSimpleType);
+ void Visit (final SimpleTypeReference aSimpleTypeReference);
+ void Visit (final Union aUnion);
+
+ // Attributes.
+ void Visit (final AttributeGroup attributeGroup);
+ void Visit (final AttributeReference attributeReference);
+ void Visit (final Attribute attribute);
+ void Visit (final AttributeGroupReference attributeGroupReference);
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/base/Location.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/base/Location.java
new file mode 100644
index 000000000000..8ebd8093b014
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/base/Location.java
@@ -0,0 +1,69 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.schema.model.base;
+
+/** The location in a file consisting of file name, line number, column number
+ * and byte index in the file.
+ */
+public class Location
+{
+ public Location (
+ final String sFilename,
+ final int nLineNumber,
+ final int nColumnNumber,
+ final int nOffset)
+ {
+ msFilename = sFilename;
+ mnLineNumber = nLineNumber;
+ mnColumnNumber = nColumnNumber;
+ mnOffset = nOffset;
+ }
+
+
+
+
+ public Location ()
+ {
+ this("<predefined>", 0,0,0);
+ }
+
+
+
+
+ @Override
+ public String toString ()
+ {
+ return String.format("%s:%d,%d/%d",
+ msFilename,
+ mnLineNumber,
+ mnColumnNumber,
+ mnOffset);
+ }
+
+
+
+
+ private final String msFilename;
+ private final int mnLineNumber;
+ private final int mnColumnNumber;
+ private final int mnOffset;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/base/Node.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/base/Node.java
new file mode 100644
index 000000000000..b965b0dba1cc
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/base/Node.java
@@ -0,0 +1,172 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.schema.model.base;
+
+import java.util.Vector;
+
+/** Base class for the nodes in the type hierarchies that represent complex
+ * types, simple types, and attributes.
+ */
+public abstract class Node
+ implements INode, Comparable<Node>
+{
+ abstract public NodeType GetNodeType ();
+
+
+
+ protected Node (
+ final Node aParent,
+ final QualifiedName aName,
+ final Location aLocation)
+ {
+ maParent = aParent;
+ maName = aName;
+
+ maLocation = aLocation;
+ maAttributes = new Vector<>();
+ maChildren = new Vector<>();
+ }
+
+
+
+
+ @Override
+ public QualifiedName GetName ()
+ {
+ return maName;
+ }
+
+
+
+
+ public Node GetParent ()
+ {
+ return maParent;
+ }
+
+
+
+
+ /** Store the location in the schema files. This is used for debugging or the creation of documentation.
+ */
+ public void SetLocation (
+ final Location aLocation)
+ {
+ maLocation = aLocation;
+ }
+
+
+
+
+ public Location GetLocation ()
+ {
+ return maLocation;
+ }
+
+
+
+
+ public void AddAttribute (final INode aAttribute)
+ {
+ maAttributes.add(aAttribute);
+ }
+
+
+
+
+ @Override
+ public int GetAttributeCount ()
+ {
+ return maAttributes.size();
+ }
+
+
+
+
+ @Override
+ public Iterable<INode> GetAttributes ()
+ {
+ return maAttributes;
+ }
+
+
+
+ public void ClearChildren ()
+ {
+ maChildren.clear();
+ }
+
+
+
+ public void AddChild (final INode aChild)
+ {
+ maChildren.add(aChild);
+ }
+
+
+
+
+ public Iterable<INode> GetChildren ()
+ {
+ return maChildren;
+ }
+
+
+
+
+ public INode GetOnlyChild ()
+ {
+ assert(maChildren.size() == 1);
+ return maChildren.get(0);
+ }
+
+
+
+
+ public int GetChildCount ()
+ {
+ return maChildren.size();
+ }
+
+
+
+
+ @Override
+ public int compareTo (final Node aOther)
+ {
+ if (maName==null || aOther.maName==null)
+ {
+ throw new RuntimeException("can not compare nodes that don't have a name");
+ }
+ else
+ return maName.compareTo(aOther.maName);
+ }
+
+
+
+
+ private final Node maParent;
+ private final QualifiedName maName;
+ private Location maLocation;
+ private final Vector<INode> maAttributes;
+ private final Vector<INode> maChildren;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/base/NodeType.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/base/NodeType.java
new file mode 100644
index 000000000000..98649af621f2
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/base/NodeType.java
@@ -0,0 +1,53 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.schema.model.base;
+
+/** Type of a node in the XML schema tree.
+ * It basically corresponds to the class of a node.
+ */
+public enum NodeType
+{
+ All,
+ Any,
+ Attribute,
+ AttributeReference,
+ AttributeGroup,
+ AttributeGroupReference,
+ BuiltIn,
+ Choice,
+ ComplexContent,
+ ComplexType,
+ ComplexTypeReference,
+ Element,
+ ElementReference,
+ Extension,
+ Group,
+ GroupReference,
+ List,
+ OccurrenceIndicator,
+ Restriction,
+ Sequence,
+ SimpleContent,
+ SimpleType,
+ SimpleTypeReference,
+ Union
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/base/NodeVisitorAdapter.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/base/NodeVisitorAdapter.java
new file mode 100644
index 000000000000..2096d8df95ee
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/base/NodeVisitorAdapter.java
@@ -0,0 +1,203 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.schema.model.base;
+
+import org.apache.openoffice.ooxml.schema.model.attribute.Attribute;
+import org.apache.openoffice.ooxml.schema.model.attribute.AttributeGroup;
+import org.apache.openoffice.ooxml.schema.model.attribute.AttributeGroupReference;
+import org.apache.openoffice.ooxml.schema.model.attribute.AttributeReference;
+import org.apache.openoffice.ooxml.schema.model.complex.All;
+import org.apache.openoffice.ooxml.schema.model.complex.Any;
+import org.apache.openoffice.ooxml.schema.model.complex.Choice;
+import org.apache.openoffice.ooxml.schema.model.complex.ComplexContent;
+import org.apache.openoffice.ooxml.schema.model.complex.ComplexType;
+import org.apache.openoffice.ooxml.schema.model.complex.ComplexTypeReference;
+import org.apache.openoffice.ooxml.schema.model.complex.Element;
+import org.apache.openoffice.ooxml.schema.model.complex.ElementReference;
+import org.apache.openoffice.ooxml.schema.model.complex.Extension;
+import org.apache.openoffice.ooxml.schema.model.complex.Group;
+import org.apache.openoffice.ooxml.schema.model.complex.GroupReference;
+import org.apache.openoffice.ooxml.schema.model.complex.OccurrenceIndicator;
+import org.apache.openoffice.ooxml.schema.model.complex.Sequence;
+import org.apache.openoffice.ooxml.schema.model.simple.BuiltIn;
+import org.apache.openoffice.ooxml.schema.model.simple.List;
+import org.apache.openoffice.ooxml.schema.model.simple.Restriction;
+import org.apache.openoffice.ooxml.schema.model.simple.SimpleContent;
+import org.apache.openoffice.ooxml.schema.model.simple.SimpleType;
+import org.apache.openoffice.ooxml.schema.model.simple.SimpleTypeReference;
+import org.apache.openoffice.ooxml.schema.model.simple.Union;
+
+/** Implementation of the INodeVisitor interface.
+ * All methods that are not overridden are redirected to the Default(INode)
+ * method.
+ */
+public class NodeVisitorAdapter
+ implements INodeVisitor
+{
+ @Override
+ public void Visit (final All aNode)
+ {
+ Default(aNode);
+ }
+
+ @Override
+ public void Visit (final Any aNode)
+ {
+ Default(aNode);
+ }
+
+ @Override
+ public void Visit (final Choice aNode)
+ {
+ Default(aNode);
+ }
+
+ @Override
+ public void Visit (final ComplexContent aNode)
+ {
+ Default(aNode);
+ }
+
+ @Override
+ public void Visit (final ComplexType aNode)
+ {
+ Default(aNode);
+ }
+
+ @Override
+ public void Visit (final ComplexTypeReference aTypeReference)
+ {
+ Default(aTypeReference);
+ }
+
+ @Override
+ public void Visit (final Element aNode)
+ {
+ Default(aNode);
+ }
+
+ @Override
+ public void Visit (final ElementReference aNode)
+ {
+ Default(aNode);
+ }
+
+ @Override
+ public void Visit (final Extension aNode)
+ {
+ Default(aNode);
+ }
+
+ @Override
+ public void Visit (final Group aNode)
+ {
+ Default(aNode);
+ }
+
+ @Override
+ public void Visit (final GroupReference aNode)
+ {
+ Default(aNode);
+ }
+
+ @Override
+ public void Visit (final OccurrenceIndicator aIndicator)
+ {
+ Default(aIndicator);
+ }
+
+ @Override
+ public void Visit(Sequence aNode)
+ {
+ Default(aNode);
+ }
+
+ @Override
+ public void Visit (final BuiltIn aType)
+ {
+ Default(aType);
+ }
+
+ @Override
+ public void Visit (final List aList)
+ {
+ Default(aList);
+ }
+
+ @Override
+ public void Visit (final SimpleContent aSimpleContent)
+ {
+ Default(aSimpleContent);
+ }
+
+ @Override
+ public void Visit (final SimpleType aSimpleType)
+ {
+ Default(aSimpleType);
+ }
+
+ @Override
+ public void Visit (final SimpleTypeReference aSimpleTypeReference)
+ {
+ Default(aSimpleTypeReference);
+ }
+
+ @Override
+ public void Visit (final Union aUnion)
+ {
+ Default(aUnion);
+ }
+
+ @Override
+ public void Visit (final Restriction aRestriction)
+ {
+ Default(aRestriction);
+ }
+
+ @Override
+ public void Visit (final AttributeGroup aAttributeGroup)
+ {
+ Default(aAttributeGroup);
+ }
+
+ @Override
+ public void Visit (final AttributeGroupReference aAttributeGroupReference)
+ {
+ Default(aAttributeGroupReference);
+ }
+
+ @Override
+ public void Visit (final AttributeReference aAttributeReference)
+ {
+ Default(aAttributeReference);
+ }
+
+ @Override
+ public void Visit (final Attribute aAttribute)
+ {
+ Default(aAttribute);
+ }
+
+ public void Default (final INode aNode)
+ {
+ }
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/base/QualifiedName.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/base/QualifiedName.java
new file mode 100644
index 000000000000..d56df52cb8cf
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/base/QualifiedName.java
@@ -0,0 +1,149 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.schema.model.base;
+
+import javax.xml.namespace.QName;
+
+/** Similar to the QName class. A qualified name that consists of the local
+ * part and a namespace.
+ * The namespace is stored both as URI and short form (prefix).
+ */
+public class QualifiedName
+ implements Comparable<QualifiedName>
+{
+ public QualifiedName (final QName aName)
+ {
+ msLocalPart = aName.getLocalPart();
+ msNamespacePrefix = aName.getPrefix();
+ msNamespaceURI = aName.getNamespaceURI();
+ }
+
+
+
+
+ public QualifiedName (
+ final String sNamespaceURI,
+ final String sNamespacePrefix,
+ final String sLocalPart)
+ {
+ msLocalPart = sLocalPart;
+ msNamespacePrefix = sNamespacePrefix;
+ msNamespaceURI = sNamespaceURI;
+ }
+
+
+
+
+ public QualifiedName (final String sLocalPart)
+ {
+ this(null, null, sLocalPart);
+ }
+
+
+
+
+ /** Return a textual representation for informal (and informative) display.
+ */
+ public String GetDisplayName ()
+ {
+ if (msNamespacePrefix == null)
+ return msLocalPart;
+ else
+ return msNamespacePrefix + ":" + msLocalPart;
+ }
+
+
+
+
+ public String GetStateName()
+ {
+ if (msNamespacePrefix == null)
+ return msLocalPart;
+ else
+ return msNamespacePrefix + "_" + msLocalPart;
+ }
+
+
+
+
+ public String GetNamespaceURI ()
+ {
+ return msNamespaceURI;
+ }
+
+
+
+
+ public String GetNamespacePrefix ()
+ {
+ return msNamespacePrefix;
+ }
+
+
+
+
+ public String GetLocalPart ()
+ {
+ return msLocalPart;
+ }
+
+
+
+
+ /** Compare QualifiedName objects (e.g. for sorting them).
+ * Primary sort key is the local part.
+ * Secondary key is the namespace prefix.
+ * Missing prefixes come before existing prefixes.
+ */
+ @Override
+ public int compareTo (final QualifiedName aOther)
+ {
+ final int nComparisonResult = msLocalPart.compareTo(aOther.msLocalPart);
+ if (nComparisonResult != 0)
+ return nComparisonResult;
+ else
+ if (msNamespacePrefix==null && aOther.msNamespacePrefix==null)
+ return 0;
+ else if (msNamespacePrefix!=null && aOther.msNamespacePrefix!=null)
+ return msNamespacePrefix.compareTo(aOther.msNamespacePrefix);
+ else if (msNamespacePrefix==null)
+ return -1;
+ else
+ return +1;
+ }
+
+
+
+
+ @Override
+ public String toString ()
+ {
+ return GetDisplayName();
+ }
+
+
+
+
+ private final String msLocalPart;
+ private final String msNamespacePrefix;
+ private final String msNamespaceURI;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/All.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/All.java
new file mode 100644
index 000000000000..cb1de8adf2b9
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/All.java
@@ -0,0 +1,96 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.schema.model.complex;
+
+import org.apache.openoffice.ooxml.schema.model.base.INodeVisitor;
+import org.apache.openoffice.ooxml.schema.model.base.Location;
+import org.apache.openoffice.ooxml.schema.model.base.Node;
+import org.apache.openoffice.ooxml.schema.model.base.NodeType;
+
+/** Representation of the 'all' XML schema element. All its children are
+ * expected to occur in any order. By default each child is optional but with
+ * a min=1 attribute the children can be made mandatory.
+ */
+public class All
+ extends Node
+{
+ public All (
+ final Node aParent,
+ final Location aLocation)
+ {
+ super(aParent, null, aLocation);
+
+ assert(CheckParent(aParent));
+ }
+
+
+
+
+ /** Occurrence values of an 'all' node must be
+ * min=(0,1)
+ * max=1.
+ */
+ private static boolean CheckParent (final Node aParent)
+ {
+ if (aParent == null)
+ return false;
+ if (aParent.GetNodeType() != NodeType.OccurrenceIndicator)
+ // Missing occurrence parent means that min and max have the default
+ // values of 0 and 1, which is valid.
+ return true;
+
+ final OccurrenceIndicator aIndicator = (OccurrenceIndicator)aParent;
+ if (aIndicator.GetMinimum() > 1)
+ return false;
+ else if (aIndicator.GetMaximum() != 1)
+ return false;
+ else
+ return true;
+ }
+
+
+
+
+ @Override
+ public void AcceptVisitor (final INodeVisitor aVisitor)
+ {
+ aVisitor.Visit(this);
+ }
+
+
+
+
+ @Override
+ public NodeType GetNodeType()
+ {
+ return NodeType.All;
+ }
+
+
+
+
+ @Override
+ public String toString ()
+ {
+ return "all";
+ }
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/Any.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/Any.java
new file mode 100644
index 000000000000..cc2573b86d46
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/Any.java
@@ -0,0 +1,112 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.schema.model.complex;
+
+import org.apache.openoffice.ooxml.schema.model.base.INodeVisitor;
+import org.apache.openoffice.ooxml.schema.model.base.Location;
+import org.apache.openoffice.ooxml.schema.model.base.Node;
+import org.apache.openoffice.ooxml.schema.model.base.NodeType;
+
+/** Representation of the 'any' XML schema element. It specifies that its
+ * children conform to a non-standard schema. If it is unknown than the
+ * children are to be ignored.
+ */
+public class Any
+ extends Node
+{
+ public enum ProcessContents
+ {
+ lax,
+ skip,
+ strict
+ }
+
+ public Any (
+ final Node aParent,
+ final Location aLocation,
+ final String sProcessContents,
+ final String sNamespace)
+ {
+ super(aParent, null, aLocation);
+ meProcessContents = ProcessContents.valueOf(sProcessContents);
+ maNamespaces = sNamespace.split("\\s+");
+ }
+
+
+
+ @Override
+ public NodeType GetNodeType ()
+ {
+ return NodeType.Any;
+ }
+
+
+
+
+ @Override
+ public void AcceptVisitor (final INodeVisitor aVisitor)
+ {
+ aVisitor.Visit(this);
+ }
+
+
+ public ProcessContents GetProcessContentsFlag ()
+ {
+ return meProcessContents;
+ }
+
+
+
+
+ public String[] GetNamespaces ()
+ {
+ return maNamespaces;
+ }
+
+
+
+
+ @Override
+ public String toString ()
+ {
+ final StringBuffer aBuffer = new StringBuffer();
+ aBuffer.append("any processContents=");
+ aBuffer.append(meProcessContents.toString());
+ aBuffer.append(", namespaces=");
+ boolean bFirst = true;
+ for (final String sNamespace : maNamespaces)
+ {
+ if (bFirst)
+ bFirst = false;
+ else
+ aBuffer.append('|');
+ aBuffer.append(sNamespace);
+ }
+ return aBuffer.toString();
+ }
+
+
+
+
+ private final ProcessContents meProcessContents;
+ private final String[] maNamespaces;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/Choice.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/Choice.java
new file mode 100644
index 000000000000..ab00f1237e3e
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/Choice.java
@@ -0,0 +1,68 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.schema.model.complex;
+
+import org.apache.openoffice.ooxml.schema.model.base.INodeVisitor;
+import org.apache.openoffice.ooxml.schema.model.base.Location;
+import org.apache.openoffice.ooxml.schema.model.base.Node;
+import org.apache.openoffice.ooxml.schema.model.base.NodeType;
+
+/** Representation of the 'choice' XML schema element.
+ * With the default max value (1) only one of its children may occur.
+ */
+public class Choice
+ extends Node
+{
+ public Choice (
+ final Node aParent,
+ final Location aLocation)
+ {
+ super(aParent, null, aLocation);
+ }
+
+
+
+
+ @Override
+ public NodeType GetNodeType ()
+ {
+ return NodeType.Choice;
+ }
+
+
+
+
+ @Override
+ public void AcceptVisitor (final INodeVisitor aVisitor)
+ {
+ aVisitor.Visit(this);
+ }
+
+
+
+
+ @Override
+ public String toString ()
+ {
+ return "choice";
+ }
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/ComplexContent.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/ComplexContent.java
new file mode 100644
index 000000000000..0ca462ffc56d
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/ComplexContent.java
@@ -0,0 +1,65 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.schema.model.complex;
+
+import org.apache.openoffice.ooxml.schema.model.base.INodeVisitor;
+import org.apache.openoffice.ooxml.schema.model.base.Location;
+import org.apache.openoffice.ooxml.schema.model.base.Node;
+import org.apache.openoffice.ooxml.schema.model.base.NodeType;
+
+public class ComplexContent
+ extends Node
+{
+ public ComplexContent (
+ final Node aParent,
+ final Location aLocation)
+ {
+ super(aParent, null, aLocation);
+ }
+
+
+
+
+ @Override
+ public void AcceptVisitor (final INodeVisitor aVisitor)
+ {
+ aVisitor.Visit(this);
+ }
+
+
+
+
+ @Override
+ public NodeType GetNodeType()
+ {
+ return NodeType.ComplexContent;
+ }
+
+
+
+
+ @Override
+ public String toString ()
+ {
+ return "complex content";
+ }
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/ComplexType.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/ComplexType.java
new file mode 100644
index 000000000000..7ea0de9404d1
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/ComplexType.java
@@ -0,0 +1,72 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.schema.model.complex;
+
+import org.apache.openoffice.ooxml.schema.model.base.INodeVisitor;
+import org.apache.openoffice.ooxml.schema.model.base.Location;
+import org.apache.openoffice.ooxml.schema.model.base.Node;
+import org.apache.openoffice.ooxml.schema.model.base.NodeType;
+import org.apache.openoffice.ooxml.schema.model.base.QualifiedName;
+
+/** Representation of the 'complexType' XML schema element. It specifies the
+ * structure of its children.
+ */
+public class ComplexType
+ extends Node
+{
+ public ComplexType (
+ final Node aParent,
+ final QualifiedName aName,
+ final Location aLocation)
+ {
+ super(aParent, aName, aLocation);
+
+ assert(aName!=null);
+ }
+
+
+
+
+ @Override
+ public NodeType GetNodeType ()
+ {
+ return NodeType.ComplexType;
+ }
+
+
+
+
+ @Override
+ public void AcceptVisitor (final INodeVisitor aVisitor)
+ {
+ aVisitor.Visit(this);
+ }
+
+
+
+
+ @Override
+ public String toString ()
+ {
+ return "complex type "+GetName().GetDisplayName();
+ }
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/ComplexTypeReference.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/ComplexTypeReference.java
new file mode 100644
index 000000000000..28266a4a5219
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/ComplexTypeReference.java
@@ -0,0 +1,100 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.schema.model.complex;
+
+import org.apache.openoffice.ooxml.schema.model.base.INode;
+import org.apache.openoffice.ooxml.schema.model.base.INodeReference;
+import org.apache.openoffice.ooxml.schema.model.base.INodeVisitor;
+import org.apache.openoffice.ooxml.schema.model.base.Location;
+import org.apache.openoffice.ooxml.schema.model.base.Node;
+import org.apache.openoffice.ooxml.schema.model.base.NodeType;
+import org.apache.openoffice.ooxml.schema.model.base.QualifiedName;
+import org.apache.openoffice.ooxml.schema.model.schema.SchemaBase;
+
+public class ComplexTypeReference
+ extends Node
+ implements INodeReference
+{
+ ComplexTypeReference (
+ final Node aParent,
+ final QualifiedName aReferencedTypeName,
+ final Location aLocation)
+ {
+ super(aParent, null, aLocation);
+ maReferencedTypeName = aReferencedTypeName;
+ }
+
+
+
+
+ public ComplexType GetReferencedComplexType (final SchemaBase aSchema)
+ {
+ final Node aType = aSchema.GetTypeForName(maReferencedTypeName);
+ if (aType == null)
+ throw new RuntimeException();
+ else if (aType.GetNodeType() != NodeType.ComplexType)
+ throw new RuntimeException();
+ else
+ return (ComplexType)aType;
+ }
+
+
+
+
+
+ public QualifiedName GetReferencedTypeName ()
+ {
+ return maReferencedTypeName;
+ }
+
+
+
+
+ @Override
+ public INode GetReferencedNode (final SchemaBase aSchema)
+ {
+ return GetReferencedComplexType(aSchema);
+ }
+
+
+
+
+ @Override
+ public void AcceptVisitor (final INodeVisitor aVisitor)
+ {
+ aVisitor.Visit(this);
+ }
+
+
+
+
+ @Override
+ public NodeType GetNodeType ()
+ {
+ return NodeType.SimpleTypeReference;
+ }
+
+
+
+
+ private final QualifiedName maReferencedTypeName;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/Element.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/Element.java
new file mode 100644
index 000000000000..27c00fe6cf8b
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/Element.java
@@ -0,0 +1,109 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.schema.model.complex;
+
+import org.apache.openoffice.ooxml.schema.model.base.INodeVisitor;
+import org.apache.openoffice.ooxml.schema.model.base.Location;
+import org.apache.openoffice.ooxml.schema.model.base.Node;
+import org.apache.openoffice.ooxml.schema.model.base.NodeType;
+import org.apache.openoffice.ooxml.schema.model.base.QualifiedName;
+
+/** Representation of the 'element' XML schema element.
+ */
+public class Element
+ extends Node
+{
+ /** Create a new element that represents a transition to aTypeName when a
+ * start tag of aElementName is processed.
+ */
+ public Element (
+ final Node aParent,
+ final QualifiedName aElementName,
+ final QualifiedName aTypeName,
+ final Location aLocation)
+ {
+ super(aParent, aElementName, aLocation);
+ maElementName = aElementName;
+ maTypeName = aTypeName;
+ }
+
+
+
+
+ public QualifiedName GetElementName ()
+ {
+ return maElementName;
+ }
+
+
+
+
+ public QualifiedName GetTypeName ()
+ {
+ return maTypeName;
+ }
+
+
+
+
+ @Override
+ public int compareTo (final Node aOther)
+ {
+ if (aOther.GetNodeType() != NodeType.Element)
+ throw new RuntimeException("can not compare Element object to non-Element object");
+ else
+ return maElementName.compareTo(((Element)aOther).maElementName);
+ }
+
+
+
+
+ @Override
+ public NodeType GetNodeType ()
+ {
+ return NodeType.Element;
+ }
+
+
+
+
+ @Override
+ public void AcceptVisitor (final INodeVisitor aVisitor)
+ {
+ aVisitor.Visit(this);
+ }
+
+
+
+
+ @Override
+ public String toString ()
+ {
+ return "element " + maElementName.GetDisplayName() +" -> " + maTypeName.GetDisplayName();
+ }
+
+
+
+
+ private final QualifiedName maElementName;
+ private final QualifiedName maTypeName;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/ElementReference.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/ElementReference.java
new file mode 100644
index 000000000000..48b2e7fa356f
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/ElementReference.java
@@ -0,0 +1,106 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.schema.model.complex;
+
+import org.apache.openoffice.ooxml.schema.model.base.INode;
+import org.apache.openoffice.ooxml.schema.model.base.INodeReference;
+import org.apache.openoffice.ooxml.schema.model.base.INodeVisitor;
+import org.apache.openoffice.ooxml.schema.model.base.Location;
+import org.apache.openoffice.ooxml.schema.model.base.Node;
+import org.apache.openoffice.ooxml.schema.model.base.NodeType;
+import org.apache.openoffice.ooxml.schema.model.base.QualifiedName;
+import org.apache.openoffice.ooxml.schema.model.schema.SchemaBase;
+
+public class ElementReference
+ extends Element
+ implements INodeReference
+{
+ public ElementReference (
+ final Node aParent,
+ final QualifiedName aReferencedElementName,
+ final Location aLocation)
+ {
+ super(aParent, null, null, aLocation);
+
+ maReferencedElementName = aReferencedElementName;
+ }
+
+
+
+
+ public QualifiedName GetReferencedElementName ()
+ {
+ return maReferencedElementName;
+ }
+
+
+
+
+ public Element GetReferencedElement (final SchemaBase aSchema)
+ {
+ final Element aElement = aSchema.TopLevelElements.Get(maReferencedElementName);
+ if (aElement == null)
+ throw new RuntimeException("can not find element "+maReferencedElementName.GetDisplayName());
+ return aElement;
+ }
+
+
+
+
+ @Override
+ public INode GetReferencedNode (final SchemaBase aSchema)
+ {
+ return GetReferencedElement(aSchema);
+ }
+
+
+
+
+ @Override
+ public NodeType GetNodeType ()
+ {
+ return NodeType.ElementReference;
+ }
+
+
+
+
+ @Override
+ public void AcceptVisitor (final INodeVisitor aVisitor)
+ {
+ aVisitor.Visit(this);
+ }
+
+
+
+
+ @Override
+ public String toString ()
+ {
+ return "element reference to "+maReferencedElementName.GetDisplayName();
+ }
+
+
+
+
+ private final QualifiedName maReferencedElementName;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/Extension.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/Extension.java
new file mode 100644
index 000000000000..749c608f6c27
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/Extension.java
@@ -0,0 +1,160 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.schema.model.complex;
+
+import java.util.Vector;
+
+import org.apache.openoffice.ooxml.schema.model.base.INode;
+import org.apache.openoffice.ooxml.schema.model.base.INodeReference;
+import org.apache.openoffice.ooxml.schema.model.base.INodeVisitor;
+import org.apache.openoffice.ooxml.schema.model.base.Location;
+import org.apache.openoffice.ooxml.schema.model.base.Node;
+import org.apache.openoffice.ooxml.schema.model.base.NodeType;
+import org.apache.openoffice.ooxml.schema.model.base.QualifiedName;
+import org.apache.openoffice.ooxml.schema.model.schema.SchemaBase;
+
+/** Representation of the 'extension' XML schema element.
+ * It extends a complex base type.
+ */
+public class Extension
+ extends Node
+ implements INodeReference
+{
+ public Extension (
+ final Node aParent,
+ final QualifiedName aBaseTypeName,
+ final Location aLocation)
+ {
+ super(aParent, null, aLocation);
+ maBaseTypeName = aBaseTypeName;
+ }
+
+
+
+
+ @Override
+ public void AcceptVisitor (final INodeVisitor aVisitor)
+ {
+ aVisitor.Visit(this);
+ }
+
+
+
+
+ @Override
+ public NodeType GetNodeType()
+ {
+ return NodeType.Extension;
+ }
+
+
+
+
+ public QualifiedName GetBaseTypeName()
+ {
+ return maBaseTypeName;
+ }
+
+
+
+
+ public INode GetBaseType (final SchemaBase aSchema)
+ {
+ return aSchema.GetTypeForName(maBaseTypeName);
+ }
+
+
+
+
+ @Override
+ public INode GetReferencedNode (final SchemaBase aSchema)
+ {
+ return GetBaseType(aSchema);
+ }
+
+
+
+
+ public Vector<INode> GetTypeNodes (final SchemaBase aSchemaBase)
+ {
+ final Vector<INode> aNodes = new Vector<>();
+
+ AddNodes(aSchemaBase.GetTypeForName(maBaseTypeName), aNodes, aSchemaBase);
+ for (final INode aChild : GetChildren())
+ AddNodes(aChild, aNodes, aSchemaBase);
+
+ return aNodes;
+ }
+
+
+
+
+ @Override
+ public String toString ()
+ {
+ return "extension of base type "+maBaseTypeName.GetDisplayName();
+ }
+
+
+
+
+ private void AddNodes (
+ final INode aParent,
+ final Vector<INode> aNodes,
+ final SchemaBase aSchemaBase)
+ {
+ INode aNode = aParent;
+ while (true)
+ {
+ switch (aNode.GetNodeType())
+ {
+ case Extension:
+ aNode = ((Extension)aNode).GetBaseType(aSchemaBase);
+ break;
+
+ case ComplexContent:
+ case SimpleContent:
+ case ComplexType:
+ switch(aNode.GetChildCount())
+ {
+ case 0:
+ return;
+ case 1:
+ aNode = aNode.GetOnlyChild();
+ break;
+ default:
+ throw new RuntimeException();
+ }
+ break;
+
+ default:
+ aNodes.add(aNode);
+ return;
+ }
+ }
+ }
+
+
+
+
+ public QualifiedName maBaseTypeName;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/Group.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/Group.java
new file mode 100644
index 000000000000..4358c20849a5
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/Group.java
@@ -0,0 +1,70 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.schema.model.complex;
+
+import org.apache.openoffice.ooxml.schema.model.base.INodeVisitor;
+import org.apache.openoffice.ooxml.schema.model.base.Location;
+import org.apache.openoffice.ooxml.schema.model.base.Node;
+import org.apache.openoffice.ooxml.schema.model.base.NodeType;
+import org.apache.openoffice.ooxml.schema.model.base.QualifiedName;
+
+/** Represents the 'group' XML schema element.
+ * The concepts of groups are similar to macros.
+ */
+public class Group
+ extends Node
+{
+ public Group (
+ final Node aParent,
+ final QualifiedName aName,
+ final Location aLocation)
+ {
+ super(aParent, aName, aLocation);
+ }
+
+
+
+
+ @Override
+ public NodeType GetNodeType ()
+ {
+ return NodeType.Group;
+ }
+
+
+
+
+ @Override
+ public void AcceptVisitor (final INodeVisitor aVisitor)
+ {
+ aVisitor.Visit(this);
+ }
+
+
+
+
+ @Override
+ public String toString ()
+ {
+ return "group "+GetName().GetDisplayName();
+ }
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/GroupReference.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/GroupReference.java
new file mode 100644
index 000000000000..048308ca9940
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/GroupReference.java
@@ -0,0 +1,109 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.schema.model.complex;
+
+import org.apache.openoffice.ooxml.schema.model.base.INode;
+import org.apache.openoffice.ooxml.schema.model.base.INodeReference;
+import org.apache.openoffice.ooxml.schema.model.base.INodeVisitor;
+import org.apache.openoffice.ooxml.schema.model.base.Location;
+import org.apache.openoffice.ooxml.schema.model.base.Node;
+import org.apache.openoffice.ooxml.schema.model.base.NodeType;
+import org.apache.openoffice.ooxml.schema.model.base.QualifiedName;
+import org.apache.openoffice.ooxml.schema.model.schema.SchemaBase;
+
+public class GroupReference
+ extends Node
+ implements INodeReference
+{
+ public GroupReference (
+ final Node aParent,
+ final QualifiedName aReferencedGroupName,
+ final Location aLocation)
+ {
+ super(aParent, null, aLocation);
+
+ maReferencedGroupName = aReferencedGroupName;
+ }
+
+
+
+
+ public QualifiedName GetReferencedGroupName ()
+ {
+ return maReferencedGroupName;
+ }
+
+
+
+
+ public Group GetReferencedGroup (final SchemaBase aSchemaBase)
+ {
+ final Node aType = aSchemaBase.GetTypeForName(maReferencedGroupName);
+ if (aType == null)
+ throw new RuntimeException("there is no type named '"+maReferencedGroupName+"' in the schema");
+ else if (aType.GetNodeType()!=NodeType.Group)
+ throw new RuntimeException("name '"+maReferencedGroupName+"' references a "+aType.GetNodeType()+" not a group");
+ else
+ return (Group)aType;
+ }
+
+
+
+
+ @Override
+ public INode GetReferencedNode (final SchemaBase aSchemaBase)
+ {
+ return GetReferencedGroup(aSchemaBase);
+ }
+
+
+
+
+ @Override
+ public NodeType GetNodeType ()
+ {
+ return NodeType.GroupReference;
+ }
+
+
+
+
+ @Override
+ public void AcceptVisitor (final INodeVisitor aVisitor)
+ {
+ aVisitor.Visit(this);
+ }
+
+
+
+
+ @Override
+ public String toString ()
+ {
+ return "group reference to "+maReferencedGroupName.GetDisplayName();
+ }
+
+
+
+
+ private final QualifiedName maReferencedGroupName;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/OccurrenceIndicator.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/OccurrenceIndicator.java
new file mode 100644
index 000000000000..dcc41bfbb7ce
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/OccurrenceIndicator.java
@@ -0,0 +1,152 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.schema.model.complex;
+
+import org.apache.openoffice.ooxml.schema.model.base.INodeVisitor;
+import org.apache.openoffice.ooxml.schema.model.base.Location;
+import org.apache.openoffice.ooxml.schema.model.base.Node;
+import org.apache.openoffice.ooxml.schema.model.base.NodeType;
+
+/** An occurrence indicator is based on a minimum and a maximum value.
+ * The minimum value is 0 or larger. If it is 0 then the child node is optional.
+ * The maximum value is at least as large as the minimum value.
+ * It can be 'unbounded' in which case the child node can appear any number of times.
+ * 'Unbounded' is internally stored as -1.
+ *
+ * An OccurrenceIndicator represents the minOccur and maxOccur attributes of
+ * XML schema elements.
+ *
+ * There is usually exactly one child.
+ */
+public class OccurrenceIndicator
+ extends Node
+{
+ public static int unbounded = -1;
+
+ public OccurrenceIndicator (
+ final Node aParent,
+ final String sMinimum,
+ final String sMaximum,
+ final Location aLocation)
+ {
+ super(aParent, null, aLocation);
+
+ mnMinimum = ParseValue(sMinimum);
+ mnMaximum = ParseValue(sMaximum);
+
+ assert(mnMinimum>=0);
+ assert(mnMaximum==unbounded || mnMaximum>=mnMinimum);
+ }
+
+
+
+
+ @Override
+ public NodeType GetNodeType ()
+ {
+ return NodeType.OccurrenceIndicator;
+ }
+
+
+
+
+ /** Return a string version of the minimum value for textual display.
+ */
+ public String GetDisplayMinimum ()
+ {
+ return Integer.toString(mnMinimum);
+ }
+
+
+
+
+ /** Return a string version of the maximum value for textual display.
+ */
+ public String GetDisplayMaximum ()
+ {
+ if (mnMaximum == unbounded)
+ return "unbounded";
+ else
+ return Integer.toString(mnMaximum);
+ }
+
+
+
+
+ public int GetMinimum ()
+ {
+ return mnMinimum;
+ }
+
+
+
+
+ public int GetMaximum ()
+ {
+ return mnMaximum;
+ }
+
+
+
+
+ @Override
+ public void AcceptVisitor (final INodeVisitor aVisitor)
+ {
+ aVisitor.Visit(this);
+ }
+
+
+
+
+ @Override
+ public String toString ()
+ {
+ return String.format("occurrence %s to %s",
+ GetDisplayMinimum(),
+ GetDisplayMaximum());
+ }
+
+
+
+
+ private static int ParseValue (final String sValue)
+ {
+ if (sValue == null)
+ {
+ // Missing values default to 1.
+ return 1;
+ }
+ else
+ switch (sValue)
+ {
+ case "0" : return 0;
+ case "1" : return 1;
+ case "unbounded" : return unbounded;
+ default: return Integer.parseInt(sValue);
+ }
+ }
+
+
+
+ private final int mnMinimum;
+ private final int mnMaximum;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/Sequence.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/Sequence.java
new file mode 100644
index 000000000000..da01a8c15e28
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/complex/Sequence.java
@@ -0,0 +1,73 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.schema.model.complex;
+
+import org.apache.openoffice.ooxml.schema.model.base.INodeVisitor;
+import org.apache.openoffice.ooxml.schema.model.base.Location;
+import org.apache.openoffice.ooxml.schema.model.base.Node;
+import org.apache.openoffice.ooxml.schema.model.base.NodeType;
+import org.apache.openoffice.ooxml.schema.model.base.QualifiedName;
+
+/** Representation of a 'sequence' XML schema element.
+ * It defines an order on its children.
+ */
+ public class Sequence
+ extends Node
+{
+ public Sequence (
+ final Node aParent,
+ final QualifiedName aName,
+ final Location aLocation)
+ {
+ super(aParent, aName, aLocation);
+ }
+
+
+
+
+ @Override
+ public NodeType GetNodeType ()
+ {
+ return NodeType.Sequence;
+ }
+
+
+
+
+ @Override
+ public void AcceptVisitor (final INodeVisitor aVisitor)
+ {
+ aVisitor.Visit(this);
+ }
+
+
+
+
+ @Override
+ public String toString ()
+ {
+ if (GetName() != null)
+ return "sequence "+GetName().GetDisplayName();
+ else
+ return "sequence";
+ }
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/optimize/CopyVisitor.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/optimize/CopyVisitor.java
new file mode 100644
index 000000000000..4fb84c909bf1
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/optimize/CopyVisitor.java
@@ -0,0 +1,112 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.schema.model.optimize;
+
+import org.apache.openoffice.ooxml.schema.model.attribute.AttributeGroupReference;
+import org.apache.openoffice.ooxml.schema.model.attribute.AttributeReference;
+import org.apache.openoffice.ooxml.schema.model.base.INode;
+import org.apache.openoffice.ooxml.schema.model.base.NodeVisitorAdapter;
+import org.apache.openoffice.ooxml.schema.model.complex.ComplexType;
+import org.apache.openoffice.ooxml.schema.model.complex.GroupReference;
+import org.apache.openoffice.ooxml.schema.model.schema.SchemaBase;
+import org.apache.openoffice.ooxml.schema.model.simple.SimpleType;
+
+/** This visitor is called to copy the used types from the source to the target
+ * schema base.
+ */
+public class CopyVisitor
+ extends NodeVisitorAdapter
+{
+ CopyVisitor (
+ final SchemaBase aSourceSchemaBase,
+ final SchemaBase aTargetSchemaBase)
+ {
+ maSourceSchemaBase = aSourceSchemaBase;
+ maTargetSchemaBase = aTargetSchemaBase;
+ }
+
+
+
+
+ @Override public void Visit (final ComplexType aComplexType)
+ {
+ maTargetSchemaBase.ComplexTypes.Add(aComplexType);
+ }
+
+ @Override public void Visit (final GroupReference aGroupReference)
+ {
+ maTargetSchemaBase.Groups.Add(
+ aGroupReference.GetReferencedGroup(maSourceSchemaBase));
+ }
+
+ @Override public void Visit (final SimpleType aSimpleType)
+ {
+ maTargetSchemaBase.SimpleTypes.Add(aSimpleType);
+ }
+
+ @Override public void Visit (final AttributeReference aAttributeReference)
+ {
+ maTargetSchemaBase.Attributes.Add(
+ aAttributeReference.GetReferencedAttribute(maSourceSchemaBase));
+ }
+
+ @Override public void Visit (final AttributeGroupReference aAttributeGroupReference)
+ {
+ maTargetSchemaBase.AttributeGroups.Add(
+ aAttributeGroupReference.GetReferencedAttributeGroup(maSourceSchemaBase));
+ }
+
+ @Override public void Default (final INode aNode)
+ {
+ switch(aNode.GetNodeType())
+ {
+ case All:
+ case Any:
+ case Attribute:
+ case AttributeGroup:
+ case BuiltIn:
+ case Choice:
+ case ComplexContent:
+ case Element:
+ case ElementReference:
+ case Extension:
+ case Group:
+ case List:
+ case OccurrenceIndicator:
+ case Restriction:
+ case Sequence:
+ case SimpleContent:
+ case SimpleTypeReference:
+ case Union:
+ break;
+
+ default:
+ throw new RuntimeException("don't know how to copy "+aNode.toString());
+ }
+ }
+
+
+
+
+ private final SchemaBase maSourceSchemaBase;
+ private final SchemaBase maTargetSchemaBase;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/optimize/RequestVisitor.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/optimize/RequestVisitor.java
new file mode 100644
index 000000000000..20aa02dd1752
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/optimize/RequestVisitor.java
@@ -0,0 +1,128 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.schema.model.optimize;
+
+import org.apache.openoffice.ooxml.schema.model.attribute.Attribute;
+import org.apache.openoffice.ooxml.schema.model.attribute.AttributeGroupReference;
+import org.apache.openoffice.ooxml.schema.model.attribute.AttributeReference;
+import org.apache.openoffice.ooxml.schema.model.base.INode;
+import org.apache.openoffice.ooxml.schema.model.base.NodeVisitorAdapter;
+import org.apache.openoffice.ooxml.schema.model.complex.Element;
+import org.apache.openoffice.ooxml.schema.model.complex.Extension;
+import org.apache.openoffice.ooxml.schema.model.complex.GroupReference;
+import org.apache.openoffice.ooxml.schema.model.schema.SchemaBase;
+import org.apache.openoffice.ooxml.schema.model.simple.List;
+import org.apache.openoffice.ooxml.schema.model.simple.Restriction;
+import org.apache.openoffice.ooxml.schema.model.simple.SimpleTypeReference;
+
+/** A visitor that is called for all nodes of a complex or simple type to mark
+ * the referenced types as being used.
+ */
+public class RequestVisitor
+ extends NodeVisitorAdapter
+{
+ RequestVisitor (
+ final SchemaBase aSourceSchema,
+ final SchemaOptimizer aOptimizer)
+ {
+ maSourceSchemaBase = aSourceSchema;
+ maSchemaOptimizer = aOptimizer;
+ }
+
+
+ @Override public void Visit (final Attribute aAttribute)
+ {
+ maSchemaOptimizer.RequestType(aAttribute.GetTypeName());
+ }
+
+ @Override public void Visit (final AttributeReference aAttributeReference)
+ {
+ maSchemaOptimizer.RequestType(aAttributeReference.GetReferencedName());
+ }
+
+ @Override public void Visit (final AttributeGroupReference aAttributeGroupReference)
+ {
+ maSchemaOptimizer.RequestType(aAttributeGroupReference.GetReferencedName());
+ }
+
+ @Override public void Visit (final Element aElement)
+ {
+ maSchemaOptimizer.RequestType(aElement.GetTypeName());
+ }
+
+ @Override public void Visit (final Extension aExtension)
+ {
+ maSchemaOptimizer.RequestType(aExtension.GetBaseTypeName());
+ }
+
+ @Override public void Visit (final GroupReference aReference)
+ {
+ maSchemaOptimizer.RequestType(aReference.GetReferencedGroup(maSourceSchemaBase));
+ }
+
+ @Override public void Visit (final List aList)
+ {
+ maSchemaOptimizer.RequestType(aList.GetItemType());
+ }
+
+ @Override public void Visit (final Restriction aRestriction)
+ {
+ maSchemaOptimizer.RequestType(aRestriction.GetBaseType());
+ }
+
+ @Override public void Visit (final SimpleTypeReference aReference)
+ {
+ maSchemaOptimizer.RequestType(aReference.GetReferencedSimpleType(maSourceSchemaBase));
+ }
+
+ @Override public void Default (final INode aNode)
+ {
+ switch (aNode.GetNodeType())
+ {
+ case All:
+ case Any:
+ case AttributeGroup:
+ case BuiltIn:
+ case Choice:
+ case ComplexContent:
+ case ComplexType:
+ case ElementReference:
+ case Group:
+ case List:
+ case OccurrenceIndicator:
+ case Sequence:
+ case SimpleContent:
+ case SimpleType:
+ case Union:
+ break;
+
+ default:
+ throw new RuntimeException(
+ String.format("don't know how to request %s which was defined at %s",
+ aNode.toString(),
+ aNode.GetLocation()));
+ }
+ }
+
+ private final SchemaBase maSourceSchemaBase;
+ private final SchemaOptimizer maSchemaOptimizer;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/optimize/SchemaOptimizer.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/optimize/SchemaOptimizer.java
new file mode 100644
index 000000000000..808f15dc1642
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/optimize/SchemaOptimizer.java
@@ -0,0 +1,140 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.schema.model.optimize;
+
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.Queue;
+import java.util.Set;
+
+import org.apache.openoffice.ooxml.schema.iterator.AttributeNodeIterator;
+import org.apache.openoffice.ooxml.schema.iterator.DereferencingNodeIterator;
+import org.apache.openoffice.ooxml.schema.model.base.INode;
+import org.apache.openoffice.ooxml.schema.model.base.INodeVisitor;
+import org.apache.openoffice.ooxml.schema.model.base.Node;
+import org.apache.openoffice.ooxml.schema.model.base.NodeType;
+import org.apache.openoffice.ooxml.schema.model.base.QualifiedName;
+import org.apache.openoffice.ooxml.schema.model.complex.Element;
+import org.apache.openoffice.ooxml.schema.model.schema.SchemaBase;
+
+/** Optimize the given schema base by creating a new one and adding only those
+ * complex types, simple types, groups, attributes and attribute groups, that
+ * are really used, i.e. used by one of the top level elements or by a type or
+ * group that is in use.
+ */
+public class SchemaOptimizer
+{
+ public SchemaOptimizer (
+ final SchemaBase aOriginalSchemaBase)
+ {
+ maOriginalSchemaBase = aOriginalSchemaBase;
+ maOptimizedSchemaBase = new SchemaBase();
+ maTodoList = new LinkedList<>();
+ maProcessedTypes = new HashSet<>();
+ }
+
+
+
+
+ public SchemaBase Run ()
+ {
+ // Seed the work list with the top-level elements.
+ for (final Element aElement : maOriginalSchemaBase.TopLevelElements.GetUnsorted())
+ {
+ maOptimizedSchemaBase.TopLevelElements.Add(aElement);
+ RequestType(aElement.GetTypeName());
+ }
+
+ final INodeVisitor aCopyVisitor = new CopyVisitor(
+ maOriginalSchemaBase,
+ maOptimizedSchemaBase);
+ final INodeVisitor aRequestVisitor = new RequestVisitor(
+ maOriginalSchemaBase,
+ this);
+
+ while ( ! maTodoList.isEmpty())
+ {
+ final INode aNode = maTodoList.poll();
+
+ // Iterate over all child nodes and attributes.
+ for (final INode aChild : new DereferencingNodeIterator(aNode, maOriginalSchemaBase, true))
+ {
+ aChild.AcceptVisitor(aCopyVisitor);
+ aChild.AcceptVisitor(aRequestVisitor);
+ for (final INode aAttribute : aChild.GetAttributes())
+ aAttribute.AcceptVisitor(aCopyVisitor);
+ for (final INode aAttribute : new AttributeNodeIterator(aChild, maOriginalSchemaBase))
+ aAttribute.AcceptVisitor(aRequestVisitor);
+ }
+
+ // Request used namespaces.
+ final QualifiedName aName = aNode.GetName();
+ if (aName != null)
+ maOptimizedSchemaBase.Namespaces.ProvideNamespace(aName.GetNamespaceURI(), aName.GetNamespacePrefix());
+ }
+
+ /*
+ System.out.printf("%d original attributes\n", maOriginalSchemaBase.Attributes.GetCount());
+ for (final Attribute aAttribute : maOriginalSchemaBase.Attributes.GetUnsorted())
+ System.out.printf("%s\n", aAttribute);
+ System.out.printf("%d optimized attributes\n", maOptimizedSchemaBase.Attributes.GetCount());
+ for (final Attribute aAttribute : maOptimizedSchemaBase.Attributes.GetUnsorted())
+ System.out.printf("%s\n", aAttribute);
+ */
+
+ return maOptimizedSchemaBase;
+ }
+
+
+
+
+ void RequestType (final QualifiedName aName)
+ {
+ final Node aNode = maOriginalSchemaBase.GetTypeForName(aName);
+ if (aNode == null)
+ throw new RuntimeException("there is no type named '"+aName+"' in the schema");
+ else
+ RequestType(aNode);
+ }
+
+
+
+
+ void RequestType (final INode aNode)
+ {
+ if (aNode.GetNodeType() == NodeType.SimpleTypeReference)
+ System.out.println(aNode);
+ if ( ! maProcessedTypes.contains(aNode))
+ {
+ maProcessedTypes.add(aNode);
+ maTodoList.add(aNode);
+ }
+ }
+
+
+
+
+ private final SchemaBase maOriginalSchemaBase;
+ private final SchemaBase maOptimizedSchemaBase;
+ private final Queue<INode> maTodoList;
+ private final Set<INode> maProcessedTypes;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/schema/NamespaceMap.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/schema/NamespaceMap.java
new file mode 100644
index 000000000000..d3cfdafd8a0b
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/schema/NamespaceMap.java
@@ -0,0 +1,178 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.schema.model.schema;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.TreeMap;
+
+/** Map between namespace prefixes and URIs.
+ * While namespace URIs can have different prefixes in different schemas,
+ * we will use only one prefix in the OOXML parser. This class
+ * provides these global prefixes.
+ */
+public class NamespaceMap
+ implements Iterable<Entry<String, String>>
+{
+ public NamespaceMap ()
+ {
+ maURIToPrefixMap = new HashMap<>(maPredefinedURIToPrefixMap);
+
+ // Predefine namespace prefixes.
+ // If possible then use the ones already in use in the schema files or documents written by MS Office,
+ // appended with a 06 or 12 for the ECMA-376 standards of 2006 (1st edition) or 2012 (4th edition).
+ maURIToPrefixMap.put("http://schemas.openxmlformats.org/drawingml/2006/main", "a06");
+ maURIToPrefixMap.put("http://purl.oclc.org/ooxml/drawingml/main", "a12");
+
+ maURIToPrefixMap.put("http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing", "wp06");
+ maURIToPrefixMap.put("http://purl.oclc.org/ooxml/drawingml/wordprocessingDrawing", "wp12");
+
+ maURIToPrefixMap.put("http://schemas.openxmlformats.org/wordprocessingml/2006/main", "w06");
+ maURIToPrefixMap.put("http://purl.oclc.org/ooxml/wordprocessingml/main", "w12");
+
+ maURIToPrefixMap.put("http://schemas.openxmlformats.org/drawingml/2006/picture", "dpct06");
+ maURIToPrefixMap.put("http://purl.oclc.org/ooxml/drawingml/picture", "dpct12");
+
+ maURIToPrefixMap.put("http://schemas.openxmlformats.org/officeDocument/2006/math", "m06");
+ maURIToPrefixMap.put("http://purl.oclc.org/ooxml/officeDocument/math", "m12");
+
+ maURIToPrefixMap.put("http://schemas.openxmlformats.org/officeDocument/2006/relationships", "r06");
+ maURIToPrefixMap.put("http://purl.oclc.org/ooxml/officeDocument/relationships", "r12");
+
+ // Invent prefixes that are not in use.
+ maURIToPrefixMap.put("http://schemas.openxmlformats.org/spreadsheetml/2006/main", "s06");
+ maURIToPrefixMap.put("http://purl.oclc.org/ooxml/spreadsheetml/main", "s12");
+
+ maURIToPrefixMap.put("http://schemas.openxmlformats.org/presentationml/2006/main", "p06");
+ maURIToPrefixMap.put("http://purl.oclc.org/ooxml/presentationml/main", "p12");
+
+ maURIToPrefixMap.put("http://schemas.openxmlformats.org/schemaLibrary/2006/main", "sl06");
+ maURIToPrefixMap.put("http://purl.oclc.org/ooxml/schemaLibrary/main", "sl12");
+
+ maURIToPrefixMap.put("http://purl.oclc.org/ooxml/drawingml/diagram", "dd12");
+ maURIToPrefixMap.put("http://purl.oclc.org/ooxml/drawingml/chart", "dc12");
+ maURIToPrefixMap.put("http://purl.oclc.org/ooxml/drawingml/lockedCanvas", "dlc12");
+ }
+
+
+
+
+ public void ProvideNamespace (
+ final String sNamespaceURI,
+ final String sDefaultPrefix)
+ {
+ if ( ! maURIToPrefixMap.containsKey(sNamespaceURI))
+ {
+ final String sPrefix;
+ // Check if we can use the given prefix.
+ if (sDefaultPrefix==null || IsPrefixUsed(sDefaultPrefix))
+ {
+ // Prefix is already used. We have to create a new and unique one.
+ String sCandidate = null;
+ for (int nIndex=0; nIndex<=26; ++nIndex)
+ {
+ if (nIndex == 26)
+ throw new RuntimeException("can not invent more than 26 namespace names");
+ sCandidate= new String(new byte[]{(byte)('A'+nIndex)});
+ if ( ! maURIToPrefixMap.containsKey(sCandidate))
+ break;
+ }
+ sPrefix = sCandidate;
+ }
+ else
+ {
+ // Use the given prefix.
+ sPrefix = sDefaultPrefix;
+ }
+
+ maURIToPrefixMap.put(sNamespaceURI, sPrefix);
+ }
+ }
+
+
+
+
+ public String GetNamespacePrefix (final String sURI)
+ {
+ return maURIToPrefixMap.get(sURI);
+ }
+
+
+
+
+ public Iterator<Entry<String,String>> iterator ()
+ {
+ return maURIToPrefixMap.entrySet().iterator();
+ }
+
+
+
+
+ public Object GetCount()
+ {
+ return maURIToPrefixMap.size();
+ }
+
+
+
+
+ /** Return all namespace entries sorted on the prefix.
+ */
+ public Iterable<Entry<String,String>> GetSorted ()
+ {
+ final Map<String,Entry<String,String>> aSortedEntries = new TreeMap<>();
+ for (final Entry<String,String> aEntry : maURIToPrefixMap.entrySet())
+ if (aEntry.getValue() == null)
+ aSortedEntries.put("", aEntry);
+ else
+ aSortedEntries.put(aEntry.getValue(), aEntry);
+ return aSortedEntries.values();
+ }
+
+
+
+
+ private boolean IsPrefixUsed (final String sPrefix)
+ {
+ for (final String sUsedPrefix : maURIToPrefixMap.values())
+ {
+ if (sUsedPrefix == null)
+ continue;
+ if (sUsedPrefix.equals(sPrefix))
+ return true;
+ }
+ return false;
+ }
+
+
+
+
+ private final Map<String,String> maURIToPrefixMap;
+ private final static Map<String,String> maPredefinedURIToPrefixMap;
+ static
+ {
+ maPredefinedURIToPrefixMap = new HashMap<>();
+ maPredefinedURIToPrefixMap.put("http://www.w3.org/2001/XMLSchema", "xsd");
+ }
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/schema/Schema.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/schema/Schema.java
new file mode 100644
index 000000000000..47c511ef4e12
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/schema/Schema.java
@@ -0,0 +1,107 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.schema.model.schema;
+
+import org.apache.openoffice.ooxml.schema.model.attribute.Attribute;
+import org.apache.openoffice.ooxml.schema.model.attribute.AttributeGroup;
+import org.apache.openoffice.ooxml.schema.model.base.Node;
+import org.apache.openoffice.ooxml.schema.model.base.QualifiedName;
+import org.apache.openoffice.ooxml.schema.model.complex.ComplexType;
+import org.apache.openoffice.ooxml.schema.model.complex.Element;
+import org.apache.openoffice.ooxml.schema.model.complex.Group;
+import org.apache.openoffice.ooxml.schema.model.simple.SimpleType;
+
+/** Front end of a shared SchemaBase object of a single master schema file (such
+ * as wml.xsd).
+ * Most important member is the TopLevelElements list of top level elements,
+ * which are unique to each master schema.
+ */
+public class Schema
+{
+ public Schema (
+ final String sShortName,
+ final SchemaBase aBase)
+ {
+ msShortName = sShortName;
+ TopLevelElements = new TypeContainer<>();
+
+ Namespaces = aBase.Namespaces;
+ ComplexTypes = aBase.ComplexTypes;
+ SimpleTypes = aBase.SimpleTypes;
+ Groups = aBase.Groups;
+ AttributeGroups = aBase.AttributeGroups;
+ Attributes = aBase.Attributes;
+ }
+
+
+
+
+ public Node GetTypeForName (final QualifiedName aName)
+ {
+ final String sTypeName = aName.GetDisplayName();
+
+ if (ComplexTypes.Contains(sTypeName))
+ return ComplexTypes.Get(sTypeName);
+ else if (SimpleTypes.Contains(sTypeName))
+ return SimpleTypes.Get(sTypeName);
+ else if (Groups.Contains(sTypeName))
+ return Groups.Get(sTypeName);
+ else if (TopLevelElements.Contains(sTypeName))
+ return TopLevelElements.Get(sTypeName);
+ else
+ return null;
+ }
+
+
+
+
+ public String GetShortName ()
+ {
+ return msShortName;
+ }
+
+
+
+
+ public Schema GetOptimizedSchema (final SchemaBase aSchemaBase)
+ {
+ final Schema aOptimizedSchema = new Schema(msShortName, aSchemaBase);
+ for (final Element aElement : TopLevelElements.GetUnsorted())
+ {
+ aOptimizedSchema.TopLevelElements.Add(aElement);
+ }
+
+ return aOptimizedSchema;
+ }
+
+
+
+
+ private final String msShortName;
+ public final TypeContainer<Element> TopLevelElements;
+ public final NamespaceMap Namespaces;
+ public final TypeContainer<ComplexType> ComplexTypes;
+ public final TypeContainer<SimpleType> SimpleTypes;
+ public final TypeContainer<Group> Groups;
+ public final TypeContainer<AttributeGroup> AttributeGroups;
+ public final TypeContainer<Attribute> Attributes;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/schema/SchemaBase.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/schema/SchemaBase.java
new file mode 100644
index 000000000000..8b456acea7f4
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/schema/SchemaBase.java
@@ -0,0 +1,121 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.schema.model.schema;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.openoffice.ooxml.schema.model.attribute.Attribute;
+import org.apache.openoffice.ooxml.schema.model.attribute.AttributeGroup;
+import org.apache.openoffice.ooxml.schema.model.base.Node;
+import org.apache.openoffice.ooxml.schema.model.base.QualifiedName;
+import org.apache.openoffice.ooxml.schema.model.complex.ComplexType;
+import org.apache.openoffice.ooxml.schema.model.complex.Element;
+import org.apache.openoffice.ooxml.schema.model.complex.Group;
+import org.apache.openoffice.ooxml.schema.model.optimize.SchemaOptimizer;
+import org.apache.openoffice.ooxml.schema.model.simple.BuiltIn;
+import org.apache.openoffice.ooxml.schema.model.simple.SimpleType;
+
+
+/** Container of elements, complex types, simple types, etc for a set of
+ * master schema files and the included and imported secondary schema files.
+ *
+ * See Schema objects for the set of top level elements that are unique to
+ * each master schema file.
+ */
+public class SchemaBase
+{
+ public SchemaBase ()
+ {
+ Namespaces = new NamespaceMap();
+ TopLevelElements = new TypeContainer<>();
+ ComplexTypes = new TypeContainer<>();
+ SimpleTypes = new TypeContainer<>();
+ Groups = new TypeContainer<>();
+ AttributeGroups = new TypeContainer<>();
+ Attributes = new TypeContainer<>();
+ AttributeValueToIdMap = new HashMap<>();
+
+ // Initialize the list of simple types with all known built ins (
+ // these are implicitly defined).
+ for (final BuiltIn aType : BuiltIn.GetTypes())
+ SimpleTypes.Add(aType);
+ }
+
+
+
+
+ public Node GetTypeForName (final QualifiedName aName)
+ {
+ final String sTypeName = aName.GetDisplayName();
+
+ if (ComplexTypes.Contains(sTypeName))
+ return ComplexTypes.Get(sTypeName);
+ else if (SimpleTypes.Contains(sTypeName))
+ return SimpleTypes.Get(sTypeName);
+ else if (Groups.Contains(sTypeName))
+ return Groups.Get(sTypeName);
+ else if (Attributes.Contains(sTypeName))
+ return Attributes.Get(sTypeName);
+ else if (AttributeGroups.Contains(sTypeName))
+ return AttributeGroups.Get(sTypeName);
+ else
+ return null;
+ }
+
+
+
+
+ public Node GetSimpleTypeForName (final QualifiedName aName)
+ {
+ final String sTypeName = aName.GetDisplayName();
+
+ if (SimpleTypes.Contains(sTypeName))
+ return SimpleTypes.Get(aName.GetDisplayName());
+ else
+ return null;
+ }
+
+
+
+
+ /** Create a new schema object that contains only the used types, i.e.
+ * types that are reachable via element transitions, starting with the
+ * top level elements.
+ */
+ public SchemaBase GetOptimizedSchema (final Iterable<Schema> aTopLevelSchemas)
+ {
+ return new SchemaOptimizer(this).Run();
+ }
+
+
+
+
+ public final NamespaceMap Namespaces;
+ public final TypeContainer<Element> TopLevelElements;
+ public final TypeContainer<ComplexType> ComplexTypes;
+ public final TypeContainer<SimpleType> SimpleTypes;
+ public final TypeContainer<Group> Groups;
+ public final TypeContainer<AttributeGroup> AttributeGroups;
+ public final TypeContainer<Attribute> Attributes;
+ public final Map<String,Integer> AttributeValueToIdMap;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/schema/TypeContainer.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/schema/TypeContainer.java
new file mode 100644
index 000000000000..1855469fbba9
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/schema/TypeContainer.java
@@ -0,0 +1,100 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.schema.model.schema;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+
+import org.apache.openoffice.ooxml.schema.model.base.Node;
+import org.apache.openoffice.ooxml.schema.model.base.QualifiedName;
+
+public class TypeContainer<T extends Node>
+{
+ TypeContainer ()
+ {
+ maTypes = new HashMap<>();
+ }
+
+
+
+
+ public void Add (final T aType)
+ {
+ maTypes.put(aType.GetName().GetDisplayName(), aType);
+ }
+
+
+
+
+ public T Get (final QualifiedName aName)
+ {
+ return maTypes.get(aName.GetDisplayName());
+ }
+
+
+
+
+ public T Get (final String sPrefixedName)
+ {
+ return maTypes.get(sPrefixedName);
+ }
+
+
+
+
+ public boolean Contains (final String sPrefixedName)
+ {
+ return maTypes.containsKey(sPrefixedName);
+ }
+
+
+
+
+ public int GetCount ()
+ {
+ return maTypes.size();
+ }
+
+
+
+
+ public Iterable<T> GetUnsorted ()
+ {
+ return maTypes.values();
+ }
+
+
+
+
+ public Iterable<T> GetSorted ()
+ {
+ final Set<T> aSortedItems = new TreeSet<T>(maTypes.values());
+ return aSortedItems;
+ }
+
+
+
+
+ Map<String,T> maTypes;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/simple/BuiltIn.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/simple/BuiltIn.java
new file mode 100644
index 000000000000..72ae7fc278a1
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/simple/BuiltIn.java
@@ -0,0 +1,103 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.schema.model.simple;
+
+import java.util.Vector;
+
+import org.apache.openoffice.ooxml.schema.model.base.INodeVisitor;
+import org.apache.openoffice.ooxml.schema.model.base.Location;
+import org.apache.openoffice.ooxml.schema.model.base.Node;
+import org.apache.openoffice.ooxml.schema.model.base.NodeType;
+import org.apache.openoffice.ooxml.schema.model.base.QualifiedName;
+
+/** Representation of built in types.
+ */
+public class BuiltIn
+ extends SimpleType
+{
+ public static Vector<BuiltIn> GetTypes ()
+ {
+ final Vector<BuiltIn> aTypes = new Vector<>();
+ for (final BuiltInType eType : BuiltInType.values())
+ aTypes.add(new BuiltIn(eType));
+ return aTypes;
+ }
+
+
+
+
+ protected BuiltIn (
+ final BuiltInType eType)
+ {
+ super(null, eType.GetQualifiedName(), new Location());
+ meType = eType;
+ }
+
+
+
+
+ @Override
+ public NodeType GetNodeType ()
+ {
+ return NodeType.BuiltIn;
+ }
+
+
+
+
+ public BuiltInType GetBuiltInType ()
+ {
+ return meType;
+ }
+
+
+
+
+ @Override
+ public void AcceptVisitor (final INodeVisitor aVisitor)
+ {
+ aVisitor.Visit(this);
+ }
+
+
+
+
+ @Override
+ public String toString ()
+ {
+ return "builtin "+GetName().GetDisplayName();
+ }
+
+
+
+
+ private final BuiltInType meType;
+
+
+
+
+ public static Node GetForName(QualifiedName aName)
+ {
+ // TODO Auto-generated method stub
+ return null;
+ }
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/simple/BuiltInType.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/simple/BuiltInType.java
new file mode 100644
index 000000000000..4befae2ee7f7
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/simple/BuiltInType.java
@@ -0,0 +1,109 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.schema.model.simple;
+
+import org.apache.openoffice.ooxml.schema.model.base.QualifiedName;
+import org.apache.openoffice.ooxml.schema.parser.XsdNamespace;
+
+public enum BuiltInType
+{
+ AnyURI,
+ Base64Binary,
+ Boolean,
+ Byte,
+ Float,
+ DateTime,
+ Double,
+ HexBinary,
+ ID,
+ Int,
+ Integer,
+ Long,
+ NcName,
+ Short,
+ String,
+ Token,
+ UnsignedByte,
+ UnsignedInt,
+ UnsignedLong,
+ UnsignedShort;
+
+ public static BuiltInType GetForName (final QualifiedName aName)
+ {
+ assert(aName.GetNamespacePrefix().equals(XsdNamespace.Prefix));
+ switch(aName.GetLocalPart())
+ {
+ case "anyURI": return AnyURI;
+ case "base64Binary": return Base64Binary;
+ case "boolean": return Boolean;
+ case "byte": return Byte;
+ case "dateTime": return DateTime;
+ case "double": return Double;
+ case "float": return Float;
+ case "hexBinary": return HexBinary;
+ case "ID": return ID;
+ case "int" : return Int;
+ case "integer": return Integer;
+ case "long": return Long;
+ case "NCName": return NcName;
+ case "short": return Short;
+ case "string": return String;
+ case "token": return Token;
+ case "unsignedByte": return UnsignedByte;
+ case "unsignedInt": return UnsignedInt;
+ case "unsignedLong": return UnsignedLong;
+ case "unsignedShort": return UnsignedShort;
+ default: throw new RuntimeException("there is no builtin type named "+aName.GetDisplayName());
+ }
+ }
+
+ public QualifiedName GetQualifiedName ()
+ {
+ final String sTypeName;
+ switch(this)
+ {
+ case AnyURI: sTypeName = "anyURI"; break;
+ case Base64Binary: sTypeName = "base64Binary"; break;
+ case Boolean: sTypeName = "boolean"; break;
+ case Byte: sTypeName = "byte"; break;
+ case Double: sTypeName = "double"; break;
+ case DateTime: sTypeName = "dateTime"; break;
+ case Float: sTypeName = "float"; break;
+ case HexBinary: sTypeName = "hexBinary"; break;
+ case ID: sTypeName = "ID"; break;
+ case Int: sTypeName = "int"; break;
+ case Integer: sTypeName = "integer"; break;
+ case Long: sTypeName = "long"; break;
+ case NcName: sTypeName = "NCName"; break;
+ case Short: sTypeName = "short"; break;
+ case String: sTypeName = "string"; break;
+ case Token: sTypeName = "token"; break;
+ case UnsignedByte: sTypeName = "unsignedByte"; break;
+ case UnsignedInt: sTypeName = "unsignedInt"; break;
+ case UnsignedLong: sTypeName = "unsignedLong"; break;
+ case UnsignedShort: sTypeName = "unsignedShort"; break;
+ default:
+ throw new RuntimeException();
+ }
+ return new QualifiedName(XsdNamespace.URI, XsdNamespace.Prefix, sTypeName);
+ }
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/simple/List.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/simple/List.java
new file mode 100644
index 000000000000..cac0a43e2591
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/simple/List.java
@@ -0,0 +1,84 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.schema.model.simple;
+
+import org.apache.openoffice.ooxml.schema.model.base.INodeVisitor;
+import org.apache.openoffice.ooxml.schema.model.base.Location;
+import org.apache.openoffice.ooxml.schema.model.base.Node;
+import org.apache.openoffice.ooxml.schema.model.base.NodeType;
+import org.apache.openoffice.ooxml.schema.model.base.QualifiedName;
+
+/** Representation of the 'list' XML schema element.
+ * It is similar to an array of objects that are all of the same simple type.
+ */
+public class List
+ extends Node
+{
+ public List (
+ final Node aParent,
+ final QualifiedName aItemType,
+ final Location aLocation)
+ {
+ super(aParent, null, aLocation);
+ maItemType = aItemType;
+ }
+
+
+
+
+ @Override
+ public NodeType GetNodeType ()
+ {
+ return NodeType.List;
+ }
+
+
+
+
+ @Override
+ public void AcceptVisitor (final INodeVisitor aVisitor)
+ {
+ aVisitor.Visit(this);
+ }
+
+
+
+
+ public QualifiedName GetItemType ()
+ {
+ return maItemType;
+ }
+
+
+
+
+ @Override
+ public String toString ()
+ {
+ return "list of "+maItemType.GetDisplayName()+" items";
+ }
+
+
+
+
+ private final QualifiedName maItemType;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/simple/Restriction.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/simple/Restriction.java
new file mode 100644
index 000000000000..8ee71d02f0c2
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/simple/Restriction.java
@@ -0,0 +1,337 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.schema.model.simple;
+
+import java.util.Set;
+import java.util.TreeSet;
+
+import org.apache.openoffice.ooxml.schema.model.base.INodeVisitor;
+import org.apache.openoffice.ooxml.schema.model.base.Location;
+import org.apache.openoffice.ooxml.schema.model.base.Node;
+import org.apache.openoffice.ooxml.schema.model.base.NodeType;
+import org.apache.openoffice.ooxml.schema.model.base.QualifiedName;
+
+/** Representation of the 'restriction' XML schema element.
+ * It defines constraints on a another simple type.
+ * Examples for such restrictions are minimum and maximum values
+ * (inclusive or exclusive), patterns or length constraints of strings,
+ * sets of valid values.
+ */
+public class Restriction
+ extends Node
+{
+ public final static int MinInclusiveBit = 0x0001;
+ public final static int MinExclusiveBit = 0x0002;
+ public final static int MaxInclusiveBit = 0x0004;
+ public final static int MaxExclusiveBit = 0x0008;
+ public final static int LengthBit = 0x0010;
+ public final static int MinLengthBit = 0x0020;
+ public final static int MaxLengthBit = 0x0040;
+ public final static int PatternBit = 0x0080;
+ public final static int EnumerationBit = 0x0100;
+
+ public Restriction (
+ final Node aParent,
+ final QualifiedName aBaseType,
+ final Location aLocation)
+ {
+ super(aParent, null, aLocation);
+ maBaseType = aBaseType;
+ maEnumerations = new TreeSet<>();
+ mnFeatures = 0;
+ }
+
+
+
+
+ @Override
+ public void AcceptVisitor (final INodeVisitor aVisitor)
+ {
+ aVisitor.Visit(this);
+ }
+
+
+
+
+ @Override
+ public NodeType GetNodeType()
+ {
+ return NodeType.Restriction;
+ }
+
+
+
+
+ public QualifiedName GetBaseType ()
+ {
+ return maBaseType;
+ }
+
+
+
+
+ @Override
+ public String toString ()
+ {
+ final StringBuffer aBuffer = new StringBuffer("restriction based on ");
+ aBuffer.append(maBaseType.GetDisplayName());
+
+ if (msMinInclusive != null)
+ {
+ aBuffer.append(",minInclusive=");
+ aBuffer.append(msMinInclusive);
+ }
+ if (msMinExclusive != null)
+ {
+ aBuffer.append(",minExclusive=");
+ aBuffer.append(msMinExclusive);
+ }
+ if (msMaxInclusive != null)
+ {
+ aBuffer.append(",maxInclusive=");
+ aBuffer.append(msMaxInclusive);
+ }
+ if (msMaxExclusive != null)
+ {
+ aBuffer.append(",maxExclusive=");
+ aBuffer.append(msMaxExclusive);
+ }
+ if (HasFeature(LengthBit))
+ {
+ aBuffer.append(",length=");
+ aBuffer.append(mnLength);
+ }
+ if (HasFeature(MinLengthBit))
+ {
+ aBuffer.append(",minLength=");
+ aBuffer.append(mnMinLength);
+ }
+ if (HasFeature(MaxLengthBit))
+ {
+ aBuffer.append(",maxLength=");
+ aBuffer.append(mnMaxLength);
+ }
+ if (msPattern != null)
+ {
+ aBuffer.append(",pattern=\"");
+ aBuffer.append(msPattern);
+ aBuffer.append('"');
+ }
+ if ( ! maEnumerations.isEmpty())
+ {
+ aBuffer.append(",enumerations");
+ aBuffer.append(maEnumerations);
+ }
+ return aBuffer.toString();
+ }
+
+
+
+ public void AddEnumeration (final String sValue)
+ {
+ maEnumerations.add(sValue);
+ mnFeatures |= EnumerationBit;
+ }
+
+
+
+
+ public void SetMinInclusive (final String sValue)
+ {
+ msMinInclusive = sValue;
+ assert( ! HasFeature(MinExclusiveBit));
+ mnFeatures |= MinInclusiveBit;
+ }
+
+
+
+
+ public void SetMinExclusive (final String sValue)
+ {
+ msMinExclusive = sValue;
+ assert( ! HasFeature(MinInclusiveBit));
+ mnFeatures |= MinExclusiveBit;
+ }
+
+
+
+
+ public void SetMaxInclusive (final String sValue)
+ {
+ msMaxInclusive = sValue;
+ assert( ! HasFeature(MaxExclusiveBit));
+ mnFeatures |= MaxInclusiveBit;
+ }
+
+
+
+
+ public void SetMaxExclusive (final String sValue)
+ {
+ msMaxExclusive = sValue;
+ assert( ! HasFeature(MaxInclusiveBit));
+ mnFeatures |= MaxExclusiveBit;
+ }
+
+
+
+
+ public void SetLength (final String sValue)
+ {
+ mnLength = Integer.parseInt(sValue);
+ assert( ! HasFeature(MinLengthBit|MaxLengthBit));
+ mnFeatures |= LengthBit;
+ }
+
+
+
+
+ public void SetMinLength (final String sValue)
+ {
+ mnMinLength = Integer.parseInt(sValue);
+ assert( ! HasFeature(LengthBit));
+ mnFeatures |= MinLengthBit;
+ }
+
+
+
+
+ public void SetMaxLength (final String sValue)
+ {
+ mnMaxLength = Integer.parseInt(sValue);
+ assert( ! HasFeature(LengthBit));
+ mnFeatures |= MaxLengthBit;
+ }
+
+
+
+
+ public void SetPattern (final String sValue)
+ {
+ msPattern = sValue;
+ mnFeatures |= PatternBit;
+ }
+
+
+
+
+ public String GetMinInclusive ()
+ {
+ return msMinInclusive;
+ }
+
+
+
+
+ public String GetMinExclusive ()
+ {
+ return msMinExclusive;
+ }
+
+
+
+
+ public String GetMaxInclusive ()
+ {
+ return msMaxInclusive;
+ }
+
+
+
+
+ public String GetMaxExclusive ()
+ {
+ return msMaxExclusive;
+ }
+
+
+
+
+ public Set<String> GetEnumeration()
+ {
+ return maEnumerations;
+ }
+
+
+
+
+ public int GetLength()
+ {
+ return mnLength;
+ }
+
+
+
+
+ public int GetMinimumLength()
+ {
+ return mnMinLength;
+ }
+
+
+
+
+ public int GetMaximumLength()
+ {
+ return mnMaxLength;
+ }
+
+
+
+
+
+ public String GetPattern()
+ {
+ return msPattern;
+ }
+
+
+
+
+ public int GetFeatureBits ()
+ {
+ return mnFeatures;
+ }
+
+
+
+
+ public boolean HasFeature (final int nBitMask)
+ {
+ return (mnFeatures & nBitMask) != 0;
+ }
+
+
+
+
+ private final QualifiedName maBaseType;
+ private final Set<String> maEnumerations;
+ private String msMinInclusive;
+ private String msMinExclusive;
+ private String msMaxInclusive;
+ private String msMaxExclusive;
+ private int mnLength;
+ private int mnMinLength;
+ private int mnMaxLength;
+ private String msPattern;
+ private int mnFeatures;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/simple/SimpleContent.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/simple/SimpleContent.java
new file mode 100644
index 000000000000..332df9c2b99a
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/simple/SimpleContent.java
@@ -0,0 +1,65 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.schema.model.simple;
+
+import org.apache.openoffice.ooxml.schema.model.base.INodeVisitor;
+import org.apache.openoffice.ooxml.schema.model.base.Location;
+import org.apache.openoffice.ooxml.schema.model.base.Node;
+import org.apache.openoffice.ooxml.schema.model.base.NodeType;
+
+public class SimpleContent
+ extends Node
+{
+ public SimpleContent (
+ final Node aParent,
+ final Location aLocation)
+ {
+ super(aParent, null, aLocation);
+ }
+
+
+
+
+ @Override
+ public void AcceptVisitor (final INodeVisitor aVisitor)
+ {
+ aVisitor.Visit(this);
+ }
+
+
+
+
+ @Override
+ public NodeType GetNodeType()
+ {
+ return NodeType.SimpleContent;
+ }
+
+
+
+
+ @Override
+ public String toString ()
+ {
+ return "simple content";
+ }
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/simple/SimpleType.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/simple/SimpleType.java
new file mode 100644
index 000000000000..52366fb9c614
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/simple/SimpleType.java
@@ -0,0 +1,102 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.schema.model.simple;
+
+import org.apache.openoffice.ooxml.schema.model.base.INodeVisitor;
+import org.apache.openoffice.ooxml.schema.model.base.Location;
+import org.apache.openoffice.ooxml.schema.model.base.Node;
+import org.apache.openoffice.ooxml.schema.model.base.NodeType;
+import org.apache.openoffice.ooxml.schema.model.base.QualifiedName;
+
+/** Representation of the 'simpleType' XML schema element.
+ * Simple types are used for attributes or the text of elements.
+ */
+public class SimpleType
+ extends Node
+{
+ public SimpleType (
+ final Node aParent,
+ final QualifiedName aName,
+ final Location aLocation)
+ {
+ super(aParent, aName, aLocation);
+ maFinalValues = null;
+ }
+
+
+
+
+ @Override
+ public NodeType GetNodeType ()
+ {
+ return NodeType.SimpleType;
+ }
+
+
+
+
+ public void SetFinal (final String[] aFinalValues)
+ {
+ maFinalValues = aFinalValues;
+ }
+
+
+
+
+ public boolean IsFinal (final String sCatgery)
+ {
+ if (maFinalValues != null)
+ {
+ for (final String sFinal : maFinalValues)
+ {
+ if (sFinal.equals(sCatgery))
+ return true;
+ else if (sFinal.equals("#all"))
+ return true;
+ }
+ }
+ return false;
+ }
+
+
+
+
+ @Override
+ public void AcceptVisitor (final INodeVisitor aVisitor)
+ {
+ aVisitor.Visit(this);
+ }
+
+
+
+
+ @Override
+ public String toString ()
+ {
+ return "simple type "+GetName().GetDisplayName();
+ }
+
+
+
+
+ private String[] maFinalValues;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/simple/SimpleTypeReference.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/simple/SimpleTypeReference.java
new file mode 100644
index 000000000000..5925b8fd0ead
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/simple/SimpleTypeReference.java
@@ -0,0 +1,107 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.schema.model.simple;
+
+import org.apache.openoffice.ooxml.schema.model.base.INode;
+import org.apache.openoffice.ooxml.schema.model.base.INodeReference;
+import org.apache.openoffice.ooxml.schema.model.base.INodeVisitor;
+import org.apache.openoffice.ooxml.schema.model.base.Location;
+import org.apache.openoffice.ooxml.schema.model.base.Node;
+import org.apache.openoffice.ooxml.schema.model.base.NodeType;
+import org.apache.openoffice.ooxml.schema.model.base.QualifiedName;
+import org.apache.openoffice.ooxml.schema.model.schema.SchemaBase;
+
+public class SimpleTypeReference
+ extends Node
+ implements INodeReference
+{
+ public SimpleTypeReference (
+ final Node aParent,
+ final QualifiedName aReferencedTypeName,
+ final Location aLocation)
+ {
+ super(aParent, null, aLocation);
+ maReferencedTypeName = aReferencedTypeName;
+ }
+
+
+
+
+ public SimpleType GetReferencedSimpleType (final SchemaBase aSchemaBase)
+ {
+ final Node aType = aSchemaBase.GetTypeForName(maReferencedTypeName);
+ if (aType == null)
+ throw new RuntimeException("there is no type named '"+maReferencedTypeName+"' in the schema");
+ else if (aType.GetNodeType()!=NodeType.SimpleType && aType.GetNodeType()!=NodeType.BuiltIn)
+ throw new RuntimeException("name '"+maReferencedTypeName+"' references a "+aType.GetNodeType()+" not a simple type or builtin");
+ else
+ return (SimpleType)aType;
+ }
+
+
+
+
+ @Override
+ public INode GetReferencedNode (final SchemaBase aSchemaBase)
+ {
+ return GetReferencedSimpleType(aSchemaBase);
+ }
+
+
+
+
+ public QualifiedName GetReferencedTypeName()
+ {
+ return maReferencedTypeName;
+ }
+
+
+
+
+ @Override
+ public void AcceptVisitor (final INodeVisitor aVisitor)
+ {
+ aVisitor.Visit(this);
+ }
+
+
+
+
+ @Override
+ public NodeType GetNodeType ()
+ {
+ return NodeType.SimpleTypeReference;
+ }
+
+
+
+ @Override
+ public String toString ()
+ {
+ return "reference to simple type "+maReferencedTypeName;
+ }
+
+
+
+
+ private final QualifiedName maReferencedTypeName;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/simple/Union.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/simple/Union.java
new file mode 100644
index 000000000000..78c2171c65dd
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/model/simple/Union.java
@@ -0,0 +1,68 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.schema.model.simple;
+
+import org.apache.openoffice.ooxml.schema.model.base.INodeVisitor;
+import org.apache.openoffice.ooxml.schema.model.base.Location;
+import org.apache.openoffice.ooxml.schema.model.base.Node;
+import org.apache.openoffice.ooxml.schema.model.base.NodeType;
+
+/** Representation of the 'union' XML schema element.
+ * Its set of valid values is the union of all of its children.
+ */
+public class Union
+ extends Node
+{
+ public Union (
+ final Node aParent,
+ final Location aLocation)
+ {
+ super(aParent, null, aLocation);
+ }
+
+
+
+
+ @Override
+ public NodeType GetNodeType ()
+ {
+ return NodeType.Union;
+ }
+
+
+
+
+ @Override
+ public void AcceptVisitor (final INodeVisitor aVisitor)
+ {
+ aVisitor.Visit(this);
+ }
+
+
+
+
+ @Override
+ public String toString ()
+ {
+ return "union";
+ }
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/parser/FormDefault.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/parser/FormDefault.java
new file mode 100644
index 000000000000..ac03f94d53a2
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/parser/FormDefault.java
@@ -0,0 +1,31 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.schema.parser;
+
+/** Enumeration of the form default values for attributes and elements in
+ * XML documents.
+ */
+public enum FormDefault
+{
+ qualified,
+ unqualified;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/parser/SchemaParser.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/parser/SchemaParser.java
new file mode 100644
index 000000000000..6e7bbb172691
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/parser/SchemaParser.java
@@ -0,0 +1,1211 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.schema.parser;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Vector;
+
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
+
+import org.apache.openoffice.ooxml.schema.model.attribute.Attribute;
+import org.apache.openoffice.ooxml.schema.model.attribute.AttributeGroup;
+import org.apache.openoffice.ooxml.schema.model.attribute.AttributeGroupReference;
+import org.apache.openoffice.ooxml.schema.model.attribute.AttributeReference;
+import org.apache.openoffice.ooxml.schema.model.base.INode;
+import org.apache.openoffice.ooxml.schema.model.base.Location;
+import org.apache.openoffice.ooxml.schema.model.base.Node;
+import org.apache.openoffice.ooxml.schema.model.base.QualifiedName;
+import org.apache.openoffice.ooxml.schema.model.complex.All;
+import org.apache.openoffice.ooxml.schema.model.complex.Any;
+import org.apache.openoffice.ooxml.schema.model.complex.Choice;
+import org.apache.openoffice.ooxml.schema.model.complex.ComplexContent;
+import org.apache.openoffice.ooxml.schema.model.complex.ComplexType;
+import org.apache.openoffice.ooxml.schema.model.complex.Element;
+import org.apache.openoffice.ooxml.schema.model.complex.ElementReference;
+import org.apache.openoffice.ooxml.schema.model.complex.Extension;
+import org.apache.openoffice.ooxml.schema.model.complex.Group;
+import org.apache.openoffice.ooxml.schema.model.complex.GroupReference;
+import org.apache.openoffice.ooxml.schema.model.complex.OccurrenceIndicator;
+import org.apache.openoffice.ooxml.schema.model.complex.Sequence;
+import org.apache.openoffice.ooxml.schema.model.schema.Schema;
+import org.apache.openoffice.ooxml.schema.model.schema.SchemaBase;
+import org.apache.openoffice.ooxml.schema.model.simple.List;
+import org.apache.openoffice.ooxml.schema.model.simple.Restriction;
+import org.apache.openoffice.ooxml.schema.model.simple.SimpleContent;
+import org.apache.openoffice.ooxml.schema.model.simple.SimpleType;
+import org.apache.openoffice.ooxml.schema.model.simple.SimpleTypeReference;
+import org.apache.openoffice.ooxml.schema.model.simple.Union;
+
+
+/** Parser for single schema file.
+ * Imports and includes of other schema files are stored and can be retrieved
+ * by calling GetImportedSchemas().
+ *
+ * Typical usage:
+ * 1) Create SchemaParser for top-level schema file.
+ * 2) Call Parse().
+ * 3) Repeat the same recursively for all imported schemas (as returned by
+ * GetImportedSchemas()).
+ *
+ * All top level types (complex types, simple types, elements, etc.) are
+ * stored in the given Schema object.
+ */
+public class SchemaParser
+{
+ public SchemaParser (
+ final File aSchemaFile,
+ final Schema aSchema,
+ final SchemaBase aSchemaBase)
+ {
+ maSchema = aSchema;
+ maSchemaBase = aSchemaBase;
+ maReader = GetStreamReader(aSchemaFile);
+ msBasename = aSchemaFile.getName();
+ maDirectory = aSchemaFile.getParentFile();
+ maLocalNamespaceMap = new HashMap<>();
+ maImportedSchemas = new Vector<>();
+ maLastLocation = null;
+ }
+
+
+
+
+ /** Parse the schema file.
+ * @return
+ * Return false if there is any error.
+ * @throws XMLStreamException
+ */
+ public void Parse ()
+ throws XMLStreamException
+ {
+ if (maReader == null)
+ return;
+
+ while (maReader.hasNext())
+ {
+ final int nCode = maReader.next();
+ switch (nCode)
+ {
+ case XMLStreamReader.START_ELEMENT:
+ if (maReader.getLocalName().equals("schema"))
+ {
+ ProcessSchemaTag();
+ ParseSchema();
+
+ maLastLocation = maReader.getLocation();
+ }
+ else
+ {
+ throw CreateErrorException("expecting top level element to be 'schema'");
+ }
+ break;
+
+ case XMLStreamReader.END_DOCUMENT:
+ return;
+
+ default:
+ throw CreateErrorException("unexpected XML event %d", nCode);
+ }
+ }
+ }
+
+
+
+
+ public Iterable<File> GetImportedSchemaFilenames ()
+ {
+ return maImportedSchemas;
+ }
+
+
+
+
+ public int GetLineCount ()
+ {
+ if (maLastLocation != null)
+ return maLastLocation.getLineNumber();
+ else
+ return 0;
+ }
+
+
+
+
+ public int GetByteCount ()
+ {
+ if (maLastLocation != null)
+ return maLastLocation.getCharacterOffset();
+ else
+ return 0;
+ }
+
+
+
+
+ /** Process the namespace definitions in the outer 'schema' element.
+ */
+ private void ProcessSchemaTag ()
+ {
+ GetOptionalAttributeValue("id", null);
+ meAttributeFormDefault = FormDefault.valueOf(
+ GetOptionalAttributeValue("attributeFormDefault", "unqualified"));
+ meElementFormDefault = FormDefault.valueOf(
+ GetOptionalAttributeValue("elementFormDefault", "unqualified"));
+ GetOptionalAttributeValue("blockDefault", null);//=(#all|list of (extension|restriction|substitution))
+ GetOptionalAttributeValue("finalDefault", null);//=(#all|list of (extension|restriction|list|union))
+ msTargetNamespace = GetOptionalAttributeValue("targetNamespace", null);
+ GetOptionalAttributeValue("version", null);
+
+ for (int nIndex=0; nIndex<maReader.getNamespaceCount(); ++nIndex)
+ {
+ final String sPrefix = maReader.getNamespacePrefix(nIndex);
+ final String sURI = maReader.getNamespaceURI(nIndex);
+ maLocalNamespaceMap.put(sPrefix, sURI);
+ maSchemaBase.Namespaces.ProvideNamespace(sURI, sPrefix);
+ }
+
+ maLocalNamespaceMap.put(null, msTargetNamespace);
+ maSchemaBase.Namespaces.ProvideNamespace(msTargetNamespace, null);
+ }
+
+
+
+
+ private void ParseSchema ()
+ throws XMLStreamException
+ {
+ while (true)
+ {
+ switch (Next())
+ {
+ case XMLStreamReader.START_ELEMENT:
+ ProcessTopLevelStartElement();
+ break;
+
+ case XMLStreamReader.END_ELEMENT:
+ return;
+
+ default:
+ throw CreateErrorException("unexpected event (expteced START_ELEMENT): %d", maReader.getEventType());
+ }
+ }
+ }
+
+
+
+
+ private void ProcessTopLevelStartElement ()
+ throws XMLStreamException
+ {
+ assert(GetAttributeValue("minOccurs") == null);
+ assert(GetAttributeValue("maxOccurs") == null);
+
+ switch (maReader.getLocalName())
+ {
+ case "attribute":
+ maSchemaBase.Attributes.Add(ParseAttribute());
+ break;
+
+ case "attributeGroup":
+ maSchemaBase.AttributeGroups.Add(ParseAttributeGroup());
+ break;
+
+ case "complexType":
+ maSchemaBase.ComplexTypes.Add(ParseComplexType());
+ break;
+
+ case "element":
+ final Element aElement = ParseElement(null);
+ if (maSchema != null)
+ maSchema.TopLevelElements.Add(aElement);
+ maSchemaBase.TopLevelElements.Add(aElement);
+ break;
+
+ case "group":
+ maSchemaBase.Groups.Add(ParseGroup(null));
+ break;
+
+ case "import":
+ ParseImport();
+ break;
+
+ case "include":
+ ParseInclude();
+ break;
+
+ case "simpleType":
+ maSchemaBase.SimpleTypes.Add(ParseSimpleType(null));
+ break;
+
+ default:
+ throw CreateErrorException("unexpected top level element %s", maReader.getLocalName());
+ }
+ }
+
+
+
+
+ private void ProcessStartElement (final Node aParent)
+ throws XMLStreamException
+ {
+ final String sMinimumOccurrence = GetOptionalAttributeValue("minOccurs", "1");
+ final String sMaximumOccurrence = GetOptionalAttributeValue("maxOccurs", "1");
+
+ final Node aLocalParent;
+ if ( ! (sMinimumOccurrence.equals("1") && sMaximumOccurrence.equals("1")))
+ {
+ // Occurrence does not only have default values (min=max=1).
+ // Have to create an intermediate node for the occurrence indicator.
+ final OccurrenceIndicator aIndicator = new OccurrenceIndicator(
+ aParent,
+ sMinimumOccurrence,
+ sMaximumOccurrence,
+ GetLocation());
+ aParent.AddChild(aIndicator);
+ aLocalParent = aIndicator;
+ }
+ else
+ aLocalParent = aParent;
+
+ switch (maReader.getLocalName())
+ {
+ case "all":
+ aLocalParent.AddChild(ParseAll(aLocalParent));
+ break;
+
+ case "any":
+ aLocalParent.AddChild(ParseAny(aLocalParent));
+ break;
+
+ case "attribute":
+ aLocalParent.AddAttribute(ParseAttributeOrReference());
+ break;
+
+ case "attributeGroup":
+ aLocalParent.AddAttribute(ParseAttributeGroupOrReference());
+ break;
+
+ case "choice":
+ aLocalParent.AddChild(ParseChoice(aLocalParent));
+ break;
+
+ case "complexContent":
+ aLocalParent.AddChild(ParseComplexContent(aLocalParent));
+ break;
+
+ case "element":
+ aLocalParent.AddChild(ParseElementOrReference(aLocalParent));
+ break;
+
+ case "extension":
+ aLocalParent.AddChild(ParseExtension(aLocalParent));
+ break;
+
+ case "group":
+ aLocalParent.AddChild(ParseGroupOrReference(aLocalParent));
+ break;
+
+ case "list":
+ aLocalParent.AddChild(ParseList(aLocalParent));
+ break;
+
+ case "sequence":
+ aLocalParent.AddChild(ParseSequence(aLocalParent));
+ break;
+
+ case "simpleContent":
+ aLocalParent.AddChild(ParseSimpleContent(aLocalParent));
+ break;
+
+ default:
+ throw CreateErrorException("unsupported content type %s", maReader.getLocalName());
+ }
+ }
+
+
+
+
+ private void IgnoreAnnotation ()
+ throws XMLStreamException
+ {
+ IgnoreContent();
+ }
+
+
+
+
+ private void IgnoreContent ()
+ throws XMLStreamException
+ {
+ while(true)
+ {
+ switch(maReader.next())
+ {
+ case XMLStreamReader.START_ELEMENT:
+ IgnoreContent();
+ break;
+
+ case XMLStreamReader.END_ELEMENT:
+ return;
+
+ case XMLStreamReader.COMMENT:
+ case XMLStreamReader.CHARACTERS:
+ break;
+
+ default:
+ throw CreateErrorException(
+ "unexpected XML event %d while ignoring content",
+ maReader.getEventType());
+ }
+ }
+ }
+
+
+
+
+ private All ParseAll (final Node aParent)
+ throws XMLStreamException
+ {
+ assert(HasOnlyAttributes("minOccurs", "maxOccurs"));
+
+ final All aAll = new All(aParent, GetLocation());
+ ParseContent(aAll);
+ return aAll;
+ }
+
+
+
+
+ private Any ParseAny (final Node aParent)
+ throws XMLStreamException
+ {
+ assert(HasOnlyAttributes("minOccurs", "maxOccurs", "namespace", "processContents"));
+
+ final Any aAny = new Any(
+ aParent,
+ GetLocation(),
+ GetOptionalAttributeValue("processContents", "strict"),
+ GetOptionalAttributeValue("namespace", "##any"));
+ ExpectEndElement("ParseAny");
+ return aAny;
+ }
+
+
+
+
+ private AttributeGroup ParseAttributeGroup ()
+ throws XMLStreamException
+ {
+ assert(HasOnlyAttributes("name"));
+
+ final AttributeGroup aGroup = new AttributeGroup(GetOptionalQualifiedName("name"), GetLocation());
+
+ while (true)
+ {
+ switch (Next())
+ {
+ case XMLStreamReader.START_ELEMENT:
+ if ( ! maReader.getLocalName().equals("attribute"))
+ throw CreateErrorException(
+ "attributeGroup expects element 'attribute' but got %s",
+ maReader.getLocalName());
+ else
+ aGroup.AddAttribute(ParseAttributeOrReference());
+ break;
+
+ case XMLStreamReader.END_ELEMENT:
+ return aGroup;
+
+ default:
+ throw CreateErrorException(
+ "unexpected event when parsing attributeGroup: %d",
+ maReader.getEventType());
+ }
+ }
+ }
+
+
+
+
+ private INode ParseAttributeGroupOrReference ()
+ throws XMLStreamException
+ {
+ assert(HasOnlyAttributes("ref"));
+
+ final INode aGroup;
+ if (GetAttributeValue("schemaLocation") != null)
+ {
+ aGroup = ParseAttributeGroup();
+ }
+ else
+ {
+ aGroup = new AttributeGroupReference(
+ CreateQualifiedName(
+ GetAttributeValue("ref")),
+ GetLocation());
+ ExpectEndElement("attribute group or reference");
+ }
+ return aGroup;
+ }
+
+
+
+
+ private INode ParseAttributeOrReference ()
+ throws XMLStreamException
+ {
+ final INode aAttribute;
+ if (GetAttributeValue("name") != null)
+ {
+ aAttribute = ParseAttribute();
+ }
+ else
+ {
+ assert(HasOnlyAttributes("default", "fixed", "ref", "use"));
+
+ aAttribute = new AttributeReference(
+ GetQualifiedName("ref"),
+ GetOptionalAttributeValue("use", "optional"),
+ GetOptionalAttributeValue("default", null),
+ GetOptionalAttributeValue("fixed", null),
+ meAttributeFormDefault,
+ GetLocation());
+ ExpectEndElement("attribute reference");
+ }
+ return aAttribute;
+ }
+
+
+
+
+ private Attribute ParseAttribute ()
+ throws XMLStreamException
+ {
+ assert(HasOnlyAttributes("default", "fixed", "name", "type", "use"));
+
+ final Attribute aAttribute = new Attribute(
+ GetQualifiedName("name"),
+ GetQualifiedName("type"),
+ GetOptionalAttributeValue("use", "optional"),
+ GetOptionalAttributeValue("default", null),
+ GetOptionalAttributeValue("fixed", null),
+ meAttributeFormDefault,
+ GetLocation());
+ ExpectEndElement("attribute");
+
+ return aAttribute;
+ }
+
+
+
+ private Choice ParseChoice (final Node aParent)
+ throws XMLStreamException
+ {
+ assert(HasOnlyAttributes("minOccurs", "maxOccurs"));
+
+ final Choice aChoice = new Choice(aParent, GetLocation());
+ ParseContent(aChoice);
+ return aChoice;
+ }
+
+
+
+
+ private ComplexContent ParseComplexContent (final Node aParent)
+ throws XMLStreamException
+ {
+ assert(HasOnlyAttributes("minOccurs", "maxOccurs"));
+
+ final ComplexContent aNode = new ComplexContent(aParent, GetLocation());
+ ParseContent(aNode);
+ return aNode;
+ }
+
+
+
+
+ private ComplexType ParseComplexType ()
+ throws XMLStreamException
+ {
+ assert(HasOnlyAttributes("mixed", "name"));
+
+ final ComplexType aComplexType = new ComplexType(
+ null,
+ GetQualifiedName("name"),
+ GetLocation());
+
+ ParseContent(aComplexType);
+
+ return aComplexType;
+ }
+
+
+
+
+ private Element ParseElement (final Node aParent)
+ throws XMLStreamException
+ {
+ assert(HasOnlyAttributes("minOccurs", "maxOccurs", "name", "type"));
+
+ final Element aElement = new Element(
+ aParent,
+ GetQualifiedName("name"),
+ GetQualifiedName("type"),
+ GetLocation());
+
+ ExpectEndElement("element");
+
+ return aElement;
+ }
+
+
+
+
+ private Element ParseElementOrReference (final Node aParent)
+ throws XMLStreamException
+ {
+ assert(HasOnlyAttributes("minOccurs", "maxOccurs", "name", "ref", "type"));
+
+ final Element aElement;
+ final String sName = GetOptionalAttributeValue("name", null);
+ if (sName != null)
+ {
+ aElement = ParseElement(aParent);
+ }
+ else
+ {
+ final String sElementReference = GetOptionalAttributeValue("ref", null);
+ if (sElementReference != null)
+ {
+ ExpectEndElement("element reference");
+ aElement = new ElementReference(
+ aParent,
+ CreateQualifiedName(sElementReference),
+ GetLocation());
+ }
+ else
+ {
+ throw CreateErrorException("element has no name and no ref");
+ }
+ }
+ return aElement;
+ }
+
+
+
+
+ private Extension ParseExtension (final Node aParent)
+ throws XMLStreamException
+ {
+ assert(HasOnlyAttributes("base", "minOccurs", "maxOccurs"));
+
+ final Extension aNode = new Extension(
+ aParent,
+ CreateQualifiedName(GetAttributeValue("base")),
+ GetLocation());
+ ParseContent(aNode);
+ return aNode;
+ }
+
+
+
+
+ private Group ParseGroup (final Node aParent)
+ throws XMLStreamException
+ {
+ assert(HasOnlyAttributes("name"));
+
+ final Group aGroup = new Group(
+ aParent,
+ GetQualifiedName("name"),
+ GetLocation());
+ ParseContent(aGroup);
+ return aGroup;
+ }
+
+
+
+
+ private Node ParseGroupOrReference (final Node aParent)
+ throws XMLStreamException
+ {
+ assert(HasOnlyAttributes("minOccurs", "maxOccurs", "name", "ref"));
+
+ final Node aGroup;
+ final String sName = GetOptionalAttributeValue("name", null);
+ if (sName != null)
+ {
+ aGroup = ParseGroup(aParent);
+ }
+ else
+ {
+ final String sGroupReference = GetOptionalAttributeValue("ref", null);
+ if (sGroupReference != null)
+ {
+ ExpectEndElement("group reference");
+ aGroup = new GroupReference(
+ aParent,
+ CreateQualifiedName(sGroupReference),
+ GetLocation());
+ }
+ else
+ {
+ throw CreateErrorException("group has no name and no ref");
+ }
+ }
+ return aGroup;
+ }
+
+
+
+
+ private Restriction ParseRestriction (final Node aParent)
+ throws XMLStreamException
+ {
+ assert(HasOnlyAttributes("base", "value"));
+
+ final String sBaseType = GetAttributeValue("base");
+ final Restriction aRestriction = new Restriction(
+ aParent,
+ CreateQualifiedName(sBaseType),
+ GetLocation());
+
+ while (true)
+ {
+ switch (Next())
+ {
+ case XMLStreamReader.START_ELEMENT:
+ final String sValue = GetAttributeValue("value");
+ switch (maReader.getLocalName())
+ {
+ case "enumeration":
+ aRestriction.AddEnumeration(sValue);
+ break;
+
+ case "minInclusive":
+ aRestriction.SetMinInclusive(sValue);
+ break;
+
+ case "minExclusive":
+ aRestriction.SetMinExclusive(sValue);
+ break;
+
+ case "maxInclusive":
+ aRestriction.SetMaxInclusive(sValue);
+ break;
+
+ case "maxExclusive":
+ aRestriction.SetMaxExclusive(sValue);
+ break;
+
+ case "length":
+ aRestriction.SetLength(sValue);
+ break;
+
+ case "minLength":
+ aRestriction.SetMinLength(sValue);
+ break;
+
+ case "maxLength":
+ aRestriction.SetMaxLength(sValue);
+ break;
+
+ case "pattern":
+ aRestriction.SetPattern(sValue);
+ break;
+
+ default:
+ throw CreateErrorException("unsupported restriction type "+maReader.getLocalName());
+ }
+ ExpectEndElement("restriction");
+ break;
+
+ case XMLStreamReader.END_ELEMENT:
+ return aRestriction;
+
+ default:
+ throw CreateErrorException("unexpected XML event while parsing restrictions: %d", maReader.getEventType());
+ }
+ }
+ }
+
+
+
+
+ private List ParseList (final Node aParent)
+ throws XMLStreamException
+ {
+ assert(HasOnlyAttributes("itemType"));
+
+ final List aList = new List(
+ aParent,
+ GetQualifiedName("itemType"),
+ GetLocation());
+ ExpectEndElement("list");
+ return aList;
+ }
+
+
+
+
+ private Sequence ParseSequence (final Node aParent)
+ throws XMLStreamException
+ {
+ assert(HasOnlyAttributes("minOccurs", "maxOccurs", "name"));
+
+ final Sequence aSequence = new Sequence(
+ aParent,
+ GetOptionalQualifiedName("name"),
+ GetLocation());
+ ParseContent(aSequence);
+ return aSequence;
+ }
+
+
+
+
+ private SimpleContent ParseSimpleContent (final Node aParent)
+ throws XMLStreamException
+ {
+ assert(HasOnlyAttributes("minOccurs", "maxOccurs"));
+
+ final SimpleContent aSimpleContent = new SimpleContent(
+ aParent,
+ GetLocation());
+ ParseContent(aSimpleContent);
+ return aSimpleContent;
+ }
+
+
+
+
+ private SimpleType ParseSimpleType (final Node aParent)
+ throws XMLStreamException
+ {
+ assert(HasOnlyAttributes("final", "name"));
+
+ final SimpleType aType = new SimpleType(
+ aParent,
+ GetQualifiedName("name"),
+ GetLocation());
+ final String sFinalValue = GetOptionalAttributeValue("final", null);
+ if (sFinalValue != null)
+ aType.SetFinal(sFinalValue.split("\\s+"));
+
+ while (true)
+ {
+ switch (Next())
+ {
+ case XMLStreamReader.START_ELEMENT:
+ switch(maReader.getLocalName())
+ {
+ case "list":
+ aType.AddChild(ParseList(aType));
+ break;
+
+ case "restriction":
+ aType.AddChild(ParseRestriction(aType));
+ break;
+
+ case "union":
+ aType.AddChild(ParseUnion(aType));
+ break;
+
+ default:
+ throw CreateErrorException("unsupported simple type part %s", maReader.getLocalName());
+ }
+ break;
+
+ case XMLStreamReader.END_ELEMENT:
+ return aType;
+
+ default:
+ throw CreateErrorException("unexpected XML event in ParseSimpleType: %s", maReader.getEventType());
+ }
+ }
+ }
+
+
+
+
+ private Union ParseUnion (final Node aParent)
+ throws XMLStreamException
+ {
+ assert(HasOnlyAttributes("memberTypes"));
+
+ final Union aUnion = new Union(
+ aParent,
+ GetLocation());
+ final String[] aMemberTypes = GetAttributeValue("memberTypes").split("\\s+");
+ for (int nIndex=0; nIndex<aMemberTypes.length; ++nIndex)
+ aUnion.AddChild(
+ new SimpleTypeReference(
+ aUnion,
+ CreateQualifiedName(aMemberTypes[nIndex]),
+ GetLocation()));
+
+ ParseContent(aUnion);
+
+ return aUnion;
+ }
+
+
+ private void ParseContent (final Node aParent)
+ throws XMLStreamException
+ {
+ while(true)
+ {
+ switch(Next())
+ {
+ case XMLStreamReader.START_ELEMENT:
+ ProcessStartElement(aParent);
+ break;
+
+ case XMLStreamReader.END_ELEMENT:
+ return;
+
+ default:
+ throw CreateErrorException(
+ "unexpected XML event %d while parsing content of %s",
+ maReader.getEventType(),
+ aParent.toString());
+ }
+ }
+ }
+
+
+
+
+ private void ParseImport ()
+ throws XMLStreamException
+ {
+ assert(HasOnlyAttributes("id", "namespace", "schemaLocation"));
+
+ final String sFilename = GetOptionalAttributeValue("schemaLocation", null);
+ if (sFilename == null)
+ {
+ final String sNamespaceName = GetAttributeValue("namespace");
+ if (sNamespaceName.equals(XmlNamespace.URI))
+ {
+ XmlNamespace.Apply(maSchemaBase);
+ maLocalNamespaceMap.put(XmlNamespace.Prefix, XmlNamespace.URI);
+ }
+ else
+ throw CreateErrorException("invalid import");
+ }
+ else
+ {
+ maImportedSchemas.add(new File(maDirectory, sFilename));
+ }
+
+ ExpectEndElement("import");
+ }
+
+
+
+
+ private void ParseInclude ()
+ throws XMLStreamException
+ {
+ assert(HasOnlyAttributes("id", "schemaLocation"));
+
+ final String sFilename = GetOptionalAttributeValue("schemaLocation", null);
+ if (sFilename == null)
+ {
+ throw CreateErrorException("invalid include");
+ }
+ else
+ {
+ maImportedSchemas.add(new File(maDirectory, sFilename));
+ }
+
+ ExpectEndElement("include");
+ }
+
+
+
+
+ private void ExpectEndElement (final String sCaller)
+ throws XMLStreamException
+ {
+ final int nNextEvent = Next();
+ if (nNextEvent != XMLStreamReader.END_ELEMENT)
+ throw CreateErrorException("expected END_ELEMENT of %s but got %s",
+ sCaller,
+ nNextEvent);
+ }
+
+
+
+
+ /** Return the next relevant token from the XML stream.
+ * Ignores comments.
+ * @return
+ * Returns the event code of the next relevant XML event or END_DOCUMENT when the end of the file has been reached.
+ */
+ private int Next ()
+ throws XMLStreamException
+ {
+ while (maReader.hasNext())
+ {
+ switch (maReader.next())
+ {
+ case XMLStreamReader.COMMENT:
+ // Ignore comments.
+ break;
+
+ case XMLStreamReader.CHARACTERS:
+ // Ignore whitespace.
+ if (maReader.getText().matches("^\\s+$"))
+ break;
+ else
+ {
+ // Character events are not expected in schema files
+ // and therefore not supported.
+ // Alternatively, they could easily be ignored.
+ throw CreateErrorException("unexpected CHARACTERS event with text [%s]", maReader.getText());
+ }
+
+ case XMLStreamReader.START_ELEMENT:
+ switch (maReader.getLocalName())
+ {
+ case "annotation":
+ IgnoreAnnotation();
+ break;
+ case "unique":
+ // Not supported.
+ IgnoreContent();
+ break;
+ default:
+ return XMLStreamReader.START_ELEMENT;
+ }
+ break;
+
+ default:
+ return maReader.getEventType();
+ }
+ }
+ return XMLStreamReader.END_DOCUMENT;
+ }
+
+
+
+
+ private String GetAttributeValue (final String sAttributeLocalName)
+ {
+ return maReader.getAttributeValue(null, sAttributeLocalName);
+ }
+
+
+
+
+ private String GetOptionalAttributeValue (
+ final String sAttributeLocalName,
+ final String sDefaultValue)
+ {
+ final String sValue = maReader.getAttributeValue(null, sAttributeLocalName);
+ if (sValue == null)
+ return sDefaultValue;
+ else
+ return sValue;
+ }
+
+
+
+
+ /** Read the specified attribute and return its value as QualifiedName object.
+ */
+ private QualifiedName GetQualifiedName (final String sAttributeLocalName)
+ {
+ final String sName = maReader.getAttributeValue(null, sAttributeLocalName);
+ if (sName == null)
+ throw CreateErrorException(
+ "did not find a qualified name as value of attribute '%s' at %s:%s",
+ sAttributeLocalName,
+ msBasename,
+ maReader.getLocation());
+ else
+ return CreateQualifiedName(sName);
+ }
+
+
+
+
+ private QualifiedName GetOptionalQualifiedName (final String sAttributeLocalName)
+ {
+ final String sName = maReader.getAttributeValue(null, sAttributeLocalName);
+ if (sName == null)
+ return null;
+ else
+ return CreateQualifiedName(sName);
+ }
+
+
+
+
+ /** Create a QualifiedName object from the given string.
+ * @param sName
+ * May or may not contain a namespace prefix (separated from the name
+ * by a colon).
+ */
+ private QualifiedName CreateQualifiedName (final String sName)
+ {
+ final String[] aParts = sName.split(":");
+ final String sNamespaceURL;
+ final String sLocalPart;
+ switch (aParts.length)
+ {
+ case 1:
+ // sName only consists of a local part.
+ // Use the target namespace as namespace.
+ sNamespaceURL = msTargetNamespace;
+ sLocalPart = aParts[0];
+ break;
+
+ case 2:
+ // sName is of the form prefix:local.
+ sNamespaceURL = maLocalNamespaceMap.get(aParts[0]);
+ sLocalPart = aParts[1];
+ break;
+
+ default:
+ throw new RuntimeException(
+ "the string '"+sName+"' can not be transformed into a qualified name");
+ }
+ if (sNamespaceURL == null)
+ throw CreateErrorException("can not determine namespace for '%s'", sName);
+ // Transform the local namespace prefix into a global namespace prefix
+ // (different schema files can use different prefixes for the same
+ // namespace URI).
+ final String sGlobalNamespacePrefix = maSchemaBase.Namespaces.GetNamespacePrefix(sNamespaceURL);
+ return new QualifiedName(
+ sNamespaceURL,
+ sGlobalNamespacePrefix,
+ sLocalPart);
+ }
+
+
+
+
+ /** Create an XMLStreamReader for the given file.
+ * Returns null when there is an error.
+ */
+ private static XMLStreamReader GetStreamReader (final File aSchemaFile)
+ {
+ final XMLInputFactory aFactory = (XMLInputFactory)XMLInputFactory.newInstance();
+ aFactory.setProperty(XMLInputFactory.IS_REPLACING_ENTITY_REFERENCES, false);
+ aFactory.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, false);
+ aFactory.setProperty(XMLInputFactory.IS_COALESCING, false);
+
+ try
+ {
+ return aFactory.createXMLStreamReader(
+ aSchemaFile.getName(),
+ new FileInputStream(aSchemaFile));
+ }
+ catch (Exception aException)
+ {
+ aException.printStackTrace();
+ return null;
+ }
+ }
+
+
+
+
+ private RuntimeException CreateErrorException (
+ final String sFormat,
+ final Object ... aArgumentList)
+ {
+ return new RuntimeException(String.format(sFormat, aArgumentList)
+ + String.format(" in %s at L%dC%dP%d",
+ msBasename,
+ maReader.getLocation().getLineNumber(),
+ maReader.getLocation().getColumnNumber(),
+ maReader.getLocation().getCharacterOffset()));
+ }
+
+
+
+
+ /** This predicate is only used for debugging to assert
+ * that no unsupported attributes are present.
+ * If there where then the parser has to be extended.
+ */
+ private boolean HasOnlyAttributes (final String ... aAttributeNameList)
+ {
+ for (int nIndex=0,nCount=maReader.getAttributeCount(); nIndex<nCount; ++nIndex)
+ {
+ final String sAttributeName = maReader.getAttributeLocalName(nIndex);
+ boolean bFound = false;
+ for (final String sName : aAttributeNameList)
+ if (sAttributeName.equals(sName))
+ {
+ bFound = true;
+ break;
+ }
+ if ( ! bFound)
+ {
+ // Attribute name was not found in the given list.
+ System.err.printf("attribute '%s' is not handled\n", sAttributeName);
+ return false;
+ }
+ }
+ return true;
+ }
+
+
+
+
+ private Location GetLocation ()
+ {
+ final javax.xml.stream.Location aLocation = maReader.getLocation();
+ return new Location(
+ msBasename,
+ aLocation.getLineNumber(),
+ aLocation.getColumnNumber(),
+ aLocation.getCharacterOffset());
+ }
+
+
+
+
+ private final Schema maSchema;
+ private final SchemaBase maSchemaBase;
+ private final XMLStreamReader maReader;
+ private final String msBasename;
+ private final File maDirectory;
+ private String msTargetNamespace;
+ /// Map of namespace prefix to URI, local to the currently read schema file.
+ private final Map<String,String> maLocalNamespaceMap;
+ /// The names of other schema files referenced by import elements.
+ private final Vector<File> maImportedSchemas;
+ /// Some values for tracking the number of read bytes and lines.
+ private javax.xml.stream.Location maLastLocation;
+ private FormDefault meAttributeFormDefault;
+ private FormDefault meElementFormDefault;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/parser/XmlNamespace.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/parser/XmlNamespace.java
new file mode 100644
index 000000000000..078c9e13de10
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/parser/XmlNamespace.java
@@ -0,0 +1,69 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.schema.parser;
+
+import org.apache.openoffice.ooxml.schema.model.attribute.Attribute;
+import org.apache.openoffice.ooxml.schema.model.base.Location;
+import org.apache.openoffice.ooxml.schema.model.base.QualifiedName;
+import org.apache.openoffice.ooxml.schema.model.schema.SchemaBase;
+import org.apache.openoffice.ooxml.schema.model.simple.Restriction;
+import org.apache.openoffice.ooxml.schema.model.simple.SimpleType;
+
+/** The http://www.w3.org/XML/1998/namespace namespace is
+ * implicitly included in all schema files.
+ *
+ * This class makes the necessary additions to namespace map and Schema object.
+ */
+public class XmlNamespace
+{
+ public static final String URI = "http://www.w3.org/XML/1998/namespace";
+ public static final String Prefix = "xml";
+
+ public static void Apply (final SchemaBase aSchemaBase)
+ {
+ aSchemaBase.Namespaces.ProvideNamespace(URI, Prefix);
+
+ final QualifiedName aStSpaceSimpleTypeName = new QualifiedName(URI, Prefix, "ST__space");
+ aSchemaBase.Attributes.Add(
+ new Attribute(
+ new QualifiedName(URI, Prefix, "space"),
+ aStSpaceSimpleTypeName,
+ "optional",
+ null,
+ null,
+ FormDefault.unqualified,
+ null));
+
+ final SimpleType aType = new SimpleType(
+ null,
+ aStSpaceSimpleTypeName,
+ new Location());
+ final Restriction aRestriction = new Restriction(
+ aType,
+ new QualifiedName(XsdNamespace.URI, XsdNamespace.Prefix, "token"),
+ null);
+ aRestriction.AddEnumeration("default");
+ aRestriction.AddEnumeration("preserve");
+ aType.AddChild(aRestriction);
+ aSchemaBase.SimpleTypes.Add(aType);
+ }
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/parser/XsdNamespace.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/parser/XsdNamespace.java
new file mode 100644
index 000000000000..901aca5efdc9
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/parser/XsdNamespace.java
@@ -0,0 +1,29 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.schema.parser;
+
+
+public class XsdNamespace
+{
+ public static final String URI = "http://www.w3.org/2001/XMLSchema";
+ public static final String Prefix = "xsd";
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/simple/BlobNode.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/simple/BlobNode.java
new file mode 100644
index 000000000000..ab0a4fcf44cc
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/simple/BlobNode.java
@@ -0,0 +1,131 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.schema.simple;
+
+import java.util.Map;
+
+import org.apache.openoffice.ooxml.schema.misc.Log;
+import org.apache.openoffice.ooxml.schema.model.simple.BuiltInType;
+import org.apache.openoffice.ooxml.schema.model.simple.Restriction;
+
+public class BlobNode
+ implements ISimpleTypeNode
+{
+ public BlobNode (final BuiltInType eType)
+ {
+ meType = eType;
+ mbIsList = false;
+ mnLengthRestriction = null;
+ }
+
+
+
+
+ public BuiltInType GetBlobType ()
+ {
+ return meType;
+ }
+
+
+
+
+ @Override
+ public void ApplyRestriction (
+ final Restriction aRestriction,
+ final Map<String,Integer> aValueToIdMap)
+ {
+ if (aRestriction.GetFeatureBits() == 0)
+ return;
+
+ if (aRestriction.GetFeatureBits() != Restriction.LengthBit)
+ throw new RuntimeException("unsupported restriction on blob: "+aRestriction);
+
+ mnLengthRestriction = aRestriction.GetLength();
+ }
+
+
+
+
+ @Override
+ public void Print (final Log aLog)
+ {
+ aLog.printf("blob of type %s\n", meType);
+ }
+
+
+
+
+ @Override
+ public boolean IsList ()
+ {
+ return mbIsList;
+ }
+
+
+
+
+ @Override
+ public void SetIsList ()
+ {
+ mbIsList = true;
+ }
+
+
+
+
+ @Override
+ public void AcceptVisitor (final ISimpleTypeNodeVisitor aVisitor)
+ {
+ aVisitor.Visit(this);
+ }
+
+
+
+
+ public enum RestrictionType
+ {
+ Length,
+ None;
+ }
+ public RestrictionType GetRestrictionType ()
+ {
+ if (mnLengthRestriction != null)
+ return RestrictionType.Length;
+ else
+ return RestrictionType.None;
+ }
+
+
+
+
+ public int GetLengthRestriction ()
+ {
+ return mnLengthRestriction;
+ }
+
+
+
+
+ private final BuiltInType meType;
+ private boolean mbIsList;
+ private Integer mnLengthRestriction;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/simple/DateTimeNode.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/simple/DateTimeNode.java
new file mode 100644
index 000000000000..9f32145bf55c
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/simple/DateTimeNode.java
@@ -0,0 +1,92 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.schema.simple;
+
+import java.util.Map;
+
+import org.apache.openoffice.ooxml.schema.misc.Log;
+import org.apache.openoffice.ooxml.schema.model.simple.BuiltInType;
+import org.apache.openoffice.ooxml.schema.model.simple.Restriction;
+
+public class DateTimeNode
+ implements ISimpleTypeNode
+{
+
+ public DateTimeNode (final BuiltInType eType)
+ {
+ mbIsList = false;
+ }
+
+
+
+
+ @Override
+ public void ApplyRestriction (
+ final Restriction aRestriction,
+ final Map<String,Integer> aValueToIdMap)
+ {
+ if (aRestriction.GetFeatureBits() == 0)
+ return;
+ System.out.println(aRestriction);
+ }
+
+
+
+
+ @Override
+ public void Print (final Log aLog)
+ {
+ aLog.printf("date or time\n");
+ }
+
+
+
+
+ @Override
+ public boolean IsList ()
+ {
+ return mbIsList;
+ }
+
+
+
+
+ @Override
+ public void SetIsList ()
+ {
+ mbIsList = true;
+ }
+
+
+
+
+ @Override
+ public void AcceptVisitor (final ISimpleTypeNodeVisitor aVisitor)
+ {
+ aVisitor.Visit(this);
+ }
+
+
+
+
+ private boolean mbIsList;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/simple/EnumerationNode.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/simple/EnumerationNode.java
new file mode 100644
index 000000000000..f4844aeaab59
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/simple/EnumerationNode.java
@@ -0,0 +1,27 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.schema.simple;
+
+public class EnumerationNode
+{
+
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/simple/ISimpleTypeNode.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/simple/ISimpleTypeNode.java
new file mode 100644
index 000000000000..6698b856ccc1
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/simple/ISimpleTypeNode.java
@@ -0,0 +1,48 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.schema.simple;
+
+import java.util.Map;
+
+import org.apache.openoffice.ooxml.schema.misc.Log;
+import org.apache.openoffice.ooxml.schema.model.simple.Restriction;
+
+/** Represent a single node in the node tree of a simple type.
+ */
+public interface ISimpleTypeNode
+{
+ void ApplyRestriction (
+ final Restriction aNode,
+ final Map<String,Integer> aValueToIdMap);
+ void Print (final Log aLog);
+
+ /** List elements are not represented by their own node (type).
+ * There is only this flag that makes this node a list of the item type
+ * which is represented by the node.
+ */
+ boolean IsList ();
+
+ /** Set the IsList flag.
+ */
+ void SetIsList ();
+ void AcceptVisitor (final ISimpleTypeNodeVisitor aVisitor);
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/simple/ISimpleTypeNodeVisitor.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/simple/ISimpleTypeNodeVisitor.java
new file mode 100644
index 000000000000..be7ea27b0b5d
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/simple/ISimpleTypeNodeVisitor.java
@@ -0,0 +1,31 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.schema.simple;
+
+public interface ISimpleTypeNodeVisitor
+{
+ void Visit (final BlobNode aType);
+ void Visit (final DateTimeNode aType);
+ void Visit (final NumberNode<?> aType);
+ void Visit (final StringNode aType);
+ void Visit (final UnionNode aType);
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/simple/NumberNode.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/simple/NumberNode.java
new file mode 100644
index 000000000000..6cbb320c6980
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/simple/NumberNode.java
@@ -0,0 +1,310 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.schema.simple;
+
+import java.util.Map;
+import java.util.Vector;
+
+import org.apache.openoffice.ooxml.schema.misc.Log;
+import org.apache.openoffice.ooxml.schema.model.simple.BuiltInType;
+import org.apache.openoffice.ooxml.schema.model.simple.Restriction;
+
+public class NumberNode<T extends Comparable<T>>
+ implements ISimpleTypeNode
+{
+ NumberNode (final BuiltInType eType)
+ {
+ meType = eType;
+ mbIsList = false;
+ }
+
+
+
+
+ public BuiltInType GetNumberType ()
+ {
+ return meType;
+ }
+
+
+
+
+ T ParseString (final String sValue)
+ {
+ switch(meType)
+ {
+ case Float:
+ return (T)(Float)Float.parseFloat(sValue);
+
+ case Double:
+ return (T)(Double)Double.parseDouble(sValue);
+
+ case Byte:
+ return (T)(Byte)Byte.parseByte(sValue);
+
+ case Int:
+ case UnsignedShort:
+ return (T)(Integer)Integer.parseInt(sValue);
+
+ case Short:
+ case UnsignedByte:
+ return (T)(Short)Short.parseShort(sValue);
+
+ case Long:
+ case UnsignedInt:
+ case Integer:
+ return (T)(Long)Long.parseLong(sValue);
+
+ default:
+ throw new RuntimeException("unsupported type "+meType);
+ }
+ }
+
+
+
+
+ @Override
+ public void ApplyRestriction (
+ final Restriction aNode,
+ final Map<String,Integer> aValueToIdMap)
+ {
+ if (aNode.HasFeature(Restriction.MinExclusiveBit))
+ ApplyMinimum(ParseString(aNode.GetMinExclusive()), false);
+ if (aNode.HasFeature(Restriction.MinInclusiveBit))
+ ApplyMinimum(ParseString(aNode.GetMinInclusive()), true);
+
+ if (aNode.HasFeature(Restriction.MaxExclusiveBit))
+ ApplyMaximum(ParseString(aNode.GetMaxExclusive()), false);
+ if (aNode.HasFeature(Restriction.MaxInclusiveBit))
+ ApplyMaximum(ParseString(aNode.GetMaxInclusive()), true);
+
+ if (aNode.HasFeature(Restriction.EnumerationBit))
+ {
+ final Vector<T> aValues = new Vector<>();
+ for (final String sEnumerationValue : aNode.GetEnumeration())
+ aValues.add(ParseString(sEnumerationValue));
+ ApplyEnumeration(aValues);
+ }
+ }
+
+
+
+
+ @Override
+ public void Print (final Log aLog)
+ {
+ aLog.printf("%s\n", toString());
+ }
+
+
+
+
+ @Override
+ public String toString ()
+ {
+ final StringBuffer sMessage = new StringBuffer();
+ sMessage.append(meType);
+ if (maEnumeration != null)
+ {
+ sMessage.append(", restricted to values");
+ for (final T nValue : maEnumeration)
+ {
+ sMessage.append(' ');
+ sMessage.append(nValue);
+ }
+ }
+ else if (maMinimumValue!=null || maMaximumValue!=null)
+ {
+ sMessage.append(" restricted to ");
+
+ if (maMinimumValue != null)
+ {
+ sMessage.append(maMinimumValue);
+ if (mbIsMinimumInclusive)
+ sMessage.append(" <= ");
+ else
+ sMessage.append(" < ");
+ }
+ sMessage.append("value");
+ if (maMaximumValue != null)
+ {
+ if (mbIsMaximumInclusive)
+ sMessage.append(" <= ");
+ else
+ sMessage.append(" < ");
+ sMessage.append(maMaximumValue);
+ }
+ }
+ else
+ sMessage.append(", not restricted");
+
+ return sMessage.toString();
+ }
+
+
+
+
+ private void ApplyMinimum (
+ final T nValue,
+ final boolean bIsInclusive)
+ {
+ if (maEnumeration != null)
+ throw new RuntimeException("minimum can not be applied to an enumeration");
+ else if (maMinimumValue != null)
+ {
+ final int nComparison = maMinimumValue.compareTo(nValue);
+ if (nComparison > 0)
+ throw new RuntimeException("second restriction tries to enlarge value space");
+ else if (nComparison == 0)
+ if (mbIsMinimumInclusive && ! bIsInclusive)
+ throw new RuntimeException("second restriction tries to enlarge value space");
+ }
+ maMinimumValue = nValue;
+ mbIsMinimumInclusive = bIsInclusive;
+ }
+
+
+
+
+
+ private void ApplyMaximum (
+ final T nValue,
+ final boolean bIsInclusive)
+ {
+ if (maEnumeration != null)
+ throw new RuntimeException("maximum can not be applied to an enumeration");
+ else if (maMaximumValue != null)
+ {
+ final int nComparison = maMaximumValue.compareTo(nValue);
+ if (nComparison < 0)
+ throw new RuntimeException("second restriction tries to enlarge value space");
+ else if (nComparison == 0)
+ if ( ! mbIsMaximumInclusive && bIsInclusive)
+ throw new RuntimeException("second restriction tries to enlarge value space");
+ }
+ maMaximumValue = nValue;
+ mbIsMaximumInclusive = bIsInclusive;
+ }
+
+
+
+
+ private void ApplyEnumeration (final Vector<T> aValues)
+ {
+ if (maEnumeration!=null || maMaximumValue!=null || maMinimumValue!=null)
+ throw new RuntimeException("can not apply enumeration to existing restriction");
+ maEnumeration = aValues;
+ }
+
+
+
+
+ @Override
+ public boolean IsList ()
+ {
+ return mbIsList;
+ }
+
+
+
+
+ @Override
+ public void SetIsList ()
+ {
+ mbIsList = true;
+ }
+
+
+
+
+ @Override
+ public void AcceptVisitor (final ISimpleTypeNodeVisitor aVisitor)
+ {
+ aVisitor.Visit(this);
+ }
+
+
+ public enum RestrictionType
+ {
+ Size,
+ Enumeration,
+ None
+ }
+ public RestrictionType GetRestrictionType ()
+ {
+ if (maEnumeration != null)
+ return RestrictionType.Enumeration;
+ else if (maMinimumValue!=null || maMaximumValue!=null)
+ return RestrictionType.Size;
+ else
+ return RestrictionType.None;
+ }
+
+
+
+ public Iterable<T> GetEnumerationRestriction ()
+ {
+ return maEnumeration;
+ }
+
+
+
+
+ public T GetMinimum ()
+ {
+ return maMinimumValue;
+ }
+
+
+
+
+ public T GetMaximum ()
+ {
+ return maMaximumValue;
+ }
+
+
+
+ public boolean IsMinimumInclusive ()
+ {
+ return mbIsMinimumInclusive;
+ }
+
+
+
+
+ public boolean IsMaximumInclusive ()
+ {
+ return mbIsMaximumInclusive;
+ }
+
+
+
+
+ private final BuiltInType meType;
+ private T maMinimumValue;
+ private boolean mbIsMinimumInclusive;
+ private T maMaximumValue;
+ private boolean mbIsMaximumInclusive;
+ private Vector<T> maEnumeration;
+ private boolean mbIsList;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/simple/SimpleTypeContainer.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/simple/SimpleTypeContainer.java
new file mode 100644
index 000000000000..c77294c557a9
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/simple/SimpleTypeContainer.java
@@ -0,0 +1,102 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.schema.simple;
+
+import java.io.File;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.TreeMap;
+
+import org.apache.openoffice.ooxml.schema.misc.Log;
+import org.apache.openoffice.ooxml.schema.model.schema.SchemaBase;
+import org.apache.openoffice.ooxml.schema.model.simple.SimpleType;
+
+public class SimpleTypeContainer
+{
+ public static SimpleTypeContainer Create (
+ final SchemaBase aSchemaBase,
+ final File aLogFile)
+ {
+ final SimpleTypeContainer aContainer = new SimpleTypeContainer(aLogFile);
+ for (final SimpleType aType : aSchemaBase.SimpleTypes.GetSorted())
+ {
+ aContainer.ProcessSimpleType(aType, aSchemaBase);
+ }
+ return aContainer;
+ }
+
+
+
+
+ public int GetSimpleTypeCount ()
+ {
+ return maSimpleTypes.size();
+ }
+
+
+
+
+ public Iterable<Entry<String,SimpleTypeDescriptor>> GetSimpleTypes ()
+ {
+ return maSimpleTypes.entrySet();
+ }
+
+
+
+
+ public Iterable<Entry<String,SimpleTypeDescriptor>> GetSimpleTypesSorted ()
+ {
+ final Map<String,SimpleTypeDescriptor> aSortedSimpleTypes = new TreeMap<>();
+ aSortedSimpleTypes.putAll(maSimpleTypes);
+ return aSortedSimpleTypes.entrySet();
+ }
+
+
+
+
+ private SimpleTypeContainer (final File aLogFile)
+ {
+ maSimpleTypes = new TreeMap<>();
+ maLog = new Log(aLogFile);
+ }
+
+
+
+
+ private void ProcessSimpleType (
+ final SimpleType aType,
+ final SchemaBase aSchemaBase)
+ {
+ maSimpleTypes.put(
+ aType.GetName().GetStateName(),
+ SimpleTypeDescriptorFactory.CreateSimpleTypeDescriptor(
+ aType,
+ aSchemaBase,
+ maLog));
+ }
+
+
+
+
+ private final Map<String,SimpleTypeDescriptor> maSimpleTypes;
+ private final Log maLog;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/simple/SimpleTypeDescriptor.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/simple/SimpleTypeDescriptor.java
new file mode 100644
index 000000000000..0c415e11a3a7
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/simple/SimpleTypeDescriptor.java
@@ -0,0 +1,86 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.schema.simple;
+
+import org.apache.openoffice.ooxml.schema.misc.Log;
+import org.apache.openoffice.ooxml.schema.model.base.QualifiedName;
+
+public class SimpleTypeDescriptor
+{
+ public SimpleTypeDescriptor (
+ final QualifiedName aName)
+ {
+ maName = aName;
+ maSubTypes = null;
+ }
+
+
+
+
+ public QualifiedName GetName()
+ {
+ return maName;
+ }
+
+
+
+
+ public void SetSubTypes (final ISimpleTypeNode[] aSubTypes)
+ {
+ maSubTypes = aSubTypes;
+ }
+
+
+
+
+ public ISimpleTypeNode[] GetSubType ()
+ {
+ return maSubTypes;
+ }
+
+
+
+
+ @Override
+ public String toString ()
+ {
+ return "simple type "+maName;
+ }
+
+
+
+
+ public void Print (final Log aLog)
+ {
+ aLog.printf("%s\n", toString());
+ aLog.StartBlock();
+ for (final ISimpleTypeNode aSubType : maSubTypes)
+ aSubType.Print(aLog);
+ aLog.EndBlock();
+ }
+
+
+
+
+ private final QualifiedName maName;
+ private ISimpleTypeNode[] maSubTypes;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/simple/SimpleTypeDescriptorFactory.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/simple/SimpleTypeDescriptorFactory.java
new file mode 100644
index 000000000000..55c1cf24c145
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/simple/SimpleTypeDescriptorFactory.java
@@ -0,0 +1,307 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.schema.simple;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.openoffice.ooxml.schema.misc.Log;
+import org.apache.openoffice.ooxml.schema.model.base.INode;
+import org.apache.openoffice.ooxml.schema.model.base.NodeType;
+import org.apache.openoffice.ooxml.schema.model.base.NodeVisitorAdapter;
+import org.apache.openoffice.ooxml.schema.model.schema.SchemaBase;
+import org.apache.openoffice.ooxml.schema.model.simple.BuiltIn;
+import org.apache.openoffice.ooxml.schema.model.simple.List;
+import org.apache.openoffice.ooxml.schema.model.simple.Restriction;
+import org.apache.openoffice.ooxml.schema.model.simple.SimpleType;
+import org.apache.openoffice.ooxml.schema.model.simple.SimpleTypeReference;
+import org.apache.openoffice.ooxml.schema.model.simple.Union;
+
+public class SimpleTypeDescriptorFactory
+ extends NodeVisitorAdapter
+{
+ class TypeCounter
+ extends NodeVisitorAdapter
+ {
+ public final Map<NodeType,Integer> Counters;
+ TypeCounter ()
+ {
+ Counters = new HashMap<>();
+ for (final NodeType eType : NodeType.values())
+ Counters.put(eType, 0);
+ }
+ @Override
+ public void Default (final INode aNode)
+ {
+ Counters.put(aNode.GetNodeType(), Counters.get(aNode.GetNodeType())+1);
+ }
+ }
+
+
+
+
+ public static SimpleTypeDescriptor CreateSimpleTypeDescriptor(
+ final SimpleType aSimpleType,
+ final SchemaBase aSchemaBase,
+ final Log aLog)
+ {
+ final SimpleTypeDescriptorFactory aFactory = new SimpleTypeDescriptorFactory(
+ aSchemaBase,
+ aLog);
+
+ aLog.AddComment("Simple type %s, defined at %s",
+ aSimpleType.GetName(),
+ aSimpleType.GetLocation().toString());
+
+ final ISimpleTypeNode aSubType = aFactory.ProcessSimpleType(aSimpleType);
+ final SimpleTypeDescriptor aDescriptor = new SimpleTypeDescriptor(aSimpleType.GetName());
+ aSubType.AcceptVisitor(new SimpleTypeNodeVisitorAdapter ()
+ {
+ @Override public void Visit (final UnionNode aType)
+ {
+ aDescriptor.SetSubTypes(aType.GetChildren());
+ }
+
+ @Override public void Default (final ISimpleTypeNode aType)
+ {
+ aDescriptor.SetSubTypes(new ISimpleTypeNode[]{aSubType});
+ }
+ });
+
+ aDescriptor.Print(aLog);
+ aLog.printf("\n");
+
+ return aDescriptor;
+ }
+
+
+
+
+ private SimpleTypeDescriptorFactory (
+ final SchemaBase aSchemaBase,
+ final Log aLog)
+ {
+ maSchemaBase = aSchemaBase;
+ maLog = aLog;
+ maResult = null;
+ }
+
+
+
+
+ ISimpleTypeNode ProcessSimpleType (final SimpleType aSimpleType)
+ {
+ return ApplyVisitor(aSimpleType);
+ }
+
+
+
+
+ @Override
+ public void Visit (final BuiltIn aNode)
+ {
+ assert(aNode.GetChildCount() == 0);
+ assert(maResult == null);
+
+ maLog.AddComment("builtin %s", aNode.toString());
+
+ switch(aNode.GetBuiltInType())
+ {
+ case Double:
+ maResult = new NumberNode<Double>(aNode.GetBuiltInType());
+ break;
+ case Float:
+ maResult = new NumberNode<Float>(aNode.GetBuiltInType());
+ break;
+
+ case Boolean:
+ maResult = new NumberNode<Boolean>(aNode.GetBuiltInType());
+ case Integer:
+ maResult = new NumberNode<Long>(aNode.GetBuiltInType());
+ break;
+ case Byte:
+ maResult = new NumberNode<Byte>(aNode.GetBuiltInType());
+ case Int:
+ maResult = new NumberNode<Integer>(aNode.GetBuiltInType());
+ case Long:
+ maResult = new NumberNode<Long>(aNode.GetBuiltInType());
+ case Short:
+ maResult = new NumberNode<Short>(aNode.GetBuiltInType());
+ case UnsignedByte:
+ maResult = new NumberNode<Integer>(aNode.GetBuiltInType());
+ case UnsignedInt:
+ maResult = new NumberNode<Long>(aNode.GetBuiltInType());
+ case UnsignedLong:
+ maResult = new NumberNode<Long>(aNode.GetBuiltInType());
+ case UnsignedShort:
+ maResult = new NumberNode<Integer>(aNode.GetBuiltInType());
+ break;
+
+ case AnyURI:
+ case ID:
+ case NcName:
+ case String:
+ case Token:
+ maResult = new StringNode(aNode.GetBuiltInType());
+ break;
+
+ case Base64Binary:
+ case HexBinary:
+ maResult = new BlobNode(aNode.GetBuiltInType());
+ break;
+
+ case DateTime:
+ maResult = new DateTimeNode(aNode.GetBuiltInType());
+ break;
+
+ default:
+ throw new RuntimeException(aNode.toString()+" is not supported");
+ }
+ }
+
+
+
+
+ @Override
+ public void Visit (final List aNode)
+ {
+ maLog.AddComment("list of type %s", aNode.GetItemType().toString());
+ maLog.StartBlock();
+ final ISimpleTypeNode aItemType = ApplyVisitor(maSchemaBase.GetSimpleTypeForName(aNode.GetItemType()));
+ maLog.EndBlock();
+
+ aItemType.SetIsList();
+ maResult = aItemType;
+ }
+
+
+
+
+ @Override
+ public void Visit (final Restriction aNode)
+ {
+ assert(aNode.GetChildCount() == 0);
+
+ maLog.AddComment("%s", aNode.toString());
+
+ final INode aBaseType = maSchemaBase.GetSimpleTypeForName(aNode.GetBaseType());
+ if (aBaseType == null)
+ throw new RuntimeException("got no type for name "+aNode.GetBaseType());
+ maLog.StartBlock();
+ maResult = ApplyVisitor(aBaseType);
+ maLog.EndBlock();
+ maResult.ApplyRestriction(
+ aNode,
+ maSchemaBase.AttributeValueToIdMap);
+ }
+
+
+
+
+ @Override
+ public void Visit (final SimpleType aNode)
+ {
+ maLog.AddComment(aNode.toString());
+
+ assert(aNode.GetChildCount() <= 1);
+ switch(aNode.GetChildCount())
+ {
+ case 0:
+ maResult = null;
+ break;
+ case 1:
+ maLog.StartBlock();
+ maResult = ApplyVisitor(aNode.GetOnlyChild());
+ maLog.EndBlock();
+ break;
+ default:
+ throw new RuntimeException();
+ }
+ }
+
+
+
+
+ @Override
+ public void Visit (final SimpleTypeReference aNode)
+ {
+ maLog.AddComment("reference to %s", aNode.GetReferencedTypeName());
+
+ maLog.StartBlock();
+ maResult = ApplyVisitor(aNode.GetReferencedNode(maSchemaBase));
+ maLog.EndBlock();
+ }
+
+
+
+
+ @Override
+ public void Visit (final Union aNode)
+ {
+ maLog.AddComment("union");
+
+ final UnionNode aUnion = new UnionNode();
+
+ // Make sure that all children have compatible types and value sets.
+ maLog.StartBlock();
+
+ for (final INode aChild : aNode.GetChildren())
+ {
+ aUnion.AddNode(ApplyVisitor(aChild));
+ }
+
+ maLog.EndBlock();
+
+ maResult = aUnion;
+ }
+
+
+
+
+ @Override
+ public void Default (final INode aNode)
+ {
+ switch(aNode.GetNodeType())
+ {
+ default:
+ throw new RuntimeException(aNode.GetNodeType() +" is not yet supported");
+ }
+ }
+
+
+
+
+ ISimpleTypeNode ApplyVisitor (final INode aNode)
+ {
+ aNode.AcceptVisitor(this);
+ final ISimpleTypeNode aResult = maResult;
+ maResult = null;
+ return aResult;
+ }
+
+
+
+
+ private final SchemaBase maSchemaBase;
+ private final Log maLog;
+ private ISimpleTypeNode maResult;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/simple/SimpleTypeNodeVisitorAdapter.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/simple/SimpleTypeNodeVisitorAdapter.java
new file mode 100644
index 000000000000..9e30d653bb9a
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/simple/SimpleTypeNodeVisitorAdapter.java
@@ -0,0 +1,60 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.schema.simple;
+
+public class SimpleTypeNodeVisitorAdapter
+ implements ISimpleTypeNodeVisitor
+{
+ @Override
+ public void Visit(BlobNode aType)
+ {
+ Default(aType);
+ }
+
+ @Override
+ public void Visit(DateTimeNode aType)
+ {
+ Default(aType);
+ }
+
+ @Override
+ public void Visit(NumberNode<?> aType)
+ {
+ Default(aType);
+ }
+
+ @Override
+ public void Visit(StringNode aType)
+ {
+ Default(aType);
+ }
+
+ @Override
+ public void Visit(UnionNode aType)
+ {
+ Default(aType);
+ }
+
+ public void Default (final ISimpleTypeNode aType)
+ {
+ }
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/simple/StringNode.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/simple/StringNode.java
new file mode 100644
index 000000000000..b88da5c7e40a
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/simple/StringNode.java
@@ -0,0 +1,269 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.schema.simple;
+
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
+
+import org.apache.openoffice.ooxml.schema.misc.Log;
+import org.apache.openoffice.ooxml.schema.model.simple.BuiltInType;
+import org.apache.openoffice.ooxml.schema.model.simple.Restriction;
+
+public class StringNode
+ implements ISimpleTypeNode
+{
+ public StringNode (
+ final BuiltInType eType)
+ {
+ meType = eType;
+ mbIsList = false;
+ }
+
+
+
+
+ @Override
+ public void ApplyRestriction (
+ final Restriction aRestriction,
+ final Map<String,Integer> aValueToIdMap)
+ {
+ assert( ! aRestriction.HasFeature(
+ Restriction.MinExclusiveBit
+ | Restriction.MinInclusiveBit
+ | Restriction.MaxExclusiveBit
+ | Restriction.MaxInclusiveBit));
+
+ if (aRestriction.HasFeature(Restriction.EnumerationBit))
+ {
+ if (aRestriction.HasFeature(Restriction.LengthBit|Restriction.MinLengthBit|Restriction.MaxLengthBit))
+ for (final String sValue : aRestriction.GetEnumeration())
+ assert(CheckLengthRestriction(sValue, aRestriction));
+ maEnumerationValues = new TreeSet<>();
+ maEnumerationValueIds = new HashSet<>();
+ for (final String sValue : aRestriction.GetEnumeration())
+ {
+ if ( ! aValueToIdMap.containsKey(sValue))
+ aValueToIdMap.put(sValue, aValueToIdMap.size());
+ maEnumerationValues.add(sValue);
+ maEnumerationValueIds.add(aValueToIdMap.get(sValue));
+ }
+ }
+ else if (aRestriction.HasFeature(Restriction.PatternBit))
+ {
+ msPattern = aRestriction.GetPattern();
+ // Make the regular expression understandable by Java (by replacing
+ // character class names like IsBasicLatin to InBasicLatin).
+ try
+ {
+ maPattern = Pattern.compile(msPattern.replace("\\p{Is", "\\p{In"), Pattern.UNICODE_CHARACTER_CLASS);
+ }
+ catch (PatternSyntaxException aException)
+ {
+ aException.printStackTrace();
+ }
+ }
+ else if (aRestriction.HasFeature(Restriction.LengthBit|Restriction.MinLengthBit|Restriction.MaxLengthBit))
+ {
+ if (aRestriction.HasFeature(Restriction.LengthBit))
+ mnMinimumLength = mnMaximumLength = aRestriction.GetLength();
+ if (aRestriction.HasFeature(Restriction.MinLengthBit))
+ mnMinimumLength = aRestriction.GetMinimumLength();
+ if (aRestriction.HasFeature(Restriction.MaxLengthBit))
+ mnMaximumLength = aRestriction.GetMaximumLength();
+ }
+ else
+ {
+ // no restriction.
+ assert(aRestriction.GetFeatureBits() == 0);
+ }
+ }
+
+
+
+
+ @Override
+ public void Print (final Log aLog)
+ {
+ aLog.println(toString());
+ }
+
+
+
+
+ @Override
+ public String toString ()
+ {
+ final StringBuffer aBuffer = new StringBuffer();
+ aBuffer.append(String.format("string (%s)", meType));
+ if (maEnumerationValueIds != null)
+ {
+ aBuffer.append(" [");
+ boolean bIsFirst = true;
+ for (final String sValue : maEnumerationValues)
+ {
+ if (bIsFirst)
+ bIsFirst = false;
+ else
+ aBuffer.append(", ");
+ aBuffer.append(sValue);
+ }
+ aBuffer.append("]");
+ }
+ else if (maPattern != null)
+ {
+ aBuffer.append("pattern=\"");
+ aBuffer.append(maPattern);
+ aBuffer.append("\"");
+ }
+ return aBuffer.toString();
+ }
+
+
+
+
+ @Override
+ public boolean IsList ()
+ {
+ return mbIsList;
+ }
+
+
+
+
+ @Override
+ public void SetIsList ()
+ {
+ mbIsList = true;
+ }
+
+
+
+
+ /** Try to join the called and the given string types.
+ * If that is possible then return the resulting type.
+ * Otherwise return null.
+ */
+ public ISimpleTypeNode Join (final StringNode aType)
+ {
+ if (maEnumerationValues!=null && aType.maEnumerationValues!=null)
+ {
+ // Join the enumeration values.
+ maEnumerationValues.addAll(aType.maEnumerationValues);
+ maEnumerationValueIds.addAll(aType.maEnumerationValueIds);
+ return this;
+ }
+ else
+ return null;
+ }
+
+
+ public enum RestrictionType
+ {
+ Pattern,
+ Enumeration,
+ Length,
+ None
+ }
+ public RestrictionType GetRestrictionType ()
+ {
+ if (maEnumerationValueIds != null)
+ return RestrictionType.Enumeration;
+ else if (maPattern != null)
+ return RestrictionType.Pattern;
+ else if (mnMinimumLength != null)
+ return RestrictionType.Length;
+ else
+ return RestrictionType.None;
+ }
+
+
+
+
+ public Set<Integer> GetEnumerationRestriction ()
+ {
+ final Set<Integer> aSortedIds = new TreeSet<>();
+ aSortedIds.addAll(maEnumerationValueIds);
+ return aSortedIds;
+ }
+
+
+
+
+ public String GetPatternRestriction ()
+ {
+ return msPattern;
+ }
+
+
+
+
+ public int[] GetLengthRestriction ()
+ {
+ return new int[]{mnMinimumLength, mnMaximumLength};
+ }
+
+
+
+
+ private boolean CheckLengthRestriction (
+ final String sValue,
+ final Restriction aRestriction)
+ {
+ final int nValueLength = sValue.length();
+ if (aRestriction.HasFeature(Restriction.LengthBit))
+ return nValueLength == aRestriction.GetLength();
+ else if (aRestriction.HasFeature(Restriction.MinLengthBit | Restriction.MaxLengthBit))
+ return nValueLength>=aRestriction.GetMinimumLength()
+ && nValueLength<=aRestriction.GetMaximumLength();
+ else if (aRestriction.HasFeature(Restriction.MinLengthBit))
+ return nValueLength>=aRestriction.GetMinimumLength();
+ else if (aRestriction.HasFeature(Restriction.MaxLengthBit))
+ return nValueLength<=aRestriction.GetMaximumLength();
+ else
+ throw new RuntimeException();
+ }
+
+
+
+
+ @Override
+ public void AcceptVisitor (final ISimpleTypeNodeVisitor aVisitor)
+ {
+ aVisitor.Visit(this);
+ }
+
+
+
+
+ private final BuiltInType meType;
+ private Set<String> maEnumerationValues;
+ private Set<Integer> maEnumerationValueIds;
+ private Pattern maPattern;
+ private String msPattern;
+ private Integer mnMinimumLength;
+ private Integer mnMaximumLength;
+ private boolean mbIsList;
+}
diff --git a/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/simple/UnionNode.java b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/simple/UnionNode.java
new file mode 100644
index 000000000000..94d428ae333a
--- /dev/null
+++ b/ooxml/source/framework/SchemaParser/src/org/apache/openoffice/ooxml/schema/simple/UnionNode.java
@@ -0,0 +1,151 @@
+/**************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you 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 org.apache.openoffice.ooxml.schema.simple;
+
+import java.util.Map;
+import java.util.Vector;
+
+import org.apache.openoffice.ooxml.schema.misc.Log;
+import org.apache.openoffice.ooxml.schema.model.simple.Restriction;
+
+public class UnionNode
+ implements ISimpleTypeNode
+{
+ UnionNode ()
+ {
+ maTypes = new Vector<>();
+ mbIsList = false;
+ }
+
+
+
+
+ @Override
+ public void ApplyRestriction (
+ final Restriction aNode,
+ final Map<String,Integer> aValueToIdMap)
+ {
+ throw new RuntimeException("can not handle restriction on union");
+ }
+
+
+
+
+
+ public void AddNode (final ISimpleTypeNode aType)
+ {
+ if (aType instanceof UnionNode)
+ {
+ // Integrate union of child into this union.
+ final UnionNode aChildUnion = (UnionNode)aType;
+ for (final ISimpleTypeNode aChildChild : aChildUnion.maTypes)
+ maTypes.add(aChildChild);
+ }
+ else if (aType instanceof StringNode)
+ {
+ // Is there already a string child?
+ for (int nIndex=0; nIndex<maTypes.size(); ++nIndex)
+ {
+ final ISimpleTypeNode aChild = maTypes.get(nIndex);
+
+ if (aChild instanceof StringNode)
+ {
+ // Yes. Can it be joined with the new child?
+ final ISimpleTypeNode aNewChild = ((StringNode)aChild).Join((StringNode)aType);
+ if (aNewChild != null)
+ {
+ // Yes. Replace the child with the joined child.
+ maTypes.set(nIndex, aNewChild);
+ return;
+ }
+ }
+ }
+ // When we reach this point then there was no join possible.
+ // Just add the new type.
+ maTypes.add(aType);
+
+ }
+ else
+ maTypes.add(aType);
+ }
+
+
+
+
+ @Override
+ public void Print (final Log aLog)
+ {
+ aLog.printf("union of %d sub types\n", maTypes.size());
+ aLog.StartBlock();
+ for (final ISimpleTypeNode aType : maTypes)
+ aType.Print(aLog);
+ aLog.EndBlock();
+ }
+
+
+
+
+ @Override
+ public boolean IsList ()
+ {
+ return mbIsList;
+ }
+
+
+
+
+ @Override
+ public void SetIsList ()
+ {
+ mbIsList = true;
+ }
+
+
+
+
+ @Override
+ public String toString ()
+ {
+ return "union";
+ }
+
+
+ ISimpleTypeNode[] GetChildren ()
+ {
+ return maTypes.toArray(new ISimpleTypeNode[maTypes.size()]);
+ }
+
+
+
+
+ @Override
+ public void AcceptVisitor (final ISimpleTypeNodeVisitor aVisitor)
+ {
+ aVisitor.Visit(this);
+ }
+
+
+
+
+ private final Vector<ISimpleTypeNode> maTypes;
+ private boolean mbIsList;
+}