From ed5640d8b587fbcfed7dd7967f3de04b37a76f26 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 11:06:44 +0200 Subject: Adding upstream version 4:7.4.7. Signed-off-by: Daniel Baumann --- xmerge/Jar_XMergeBridge.mk | 26 + xmerge/Jar_xmerge.mk | 118 +++ xmerge/Makefile | 14 + xmerge/Module_xmerge.mk | 17 + xmerge/README.md | 9 + xmerge/source/bridge/XMergeBridge.component | 25 + xmerge/source/bridge/java/XMergeBridge.java | 579 ++++++++++ xmerge/source/bridge/manifest.mf | 2 + xmerge/source/xmerge/converter.dtd | 84 ++ .../xmerge/java/org/openoffice/xmerge/Convert.java | 233 ++++ .../java/org/openoffice/xmerge/ConvertData.java | 101 ++ .../org/openoffice/xmerge/ConvertException.java | 34 + .../openoffice/xmerge/ConverterCapabilities.java | 54 + .../org/openoffice/xmerge/ConverterFactory.java | 85 ++ .../java/org/openoffice/xmerge/Document.java | 79 ++ .../openoffice/xmerge/DocumentDeserializer.java | 53 + .../openoffice/xmerge/DocumentDeserializer2.java | 61 ++ .../xmerge/DocumentDeserializerFactory.java | 51 + .../java/org/openoffice/xmerge/DocumentMerger.java | 74 ++ .../openoffice/xmerge/DocumentMergerFactory.java | 50 + .../org/openoffice/xmerge/DocumentSerializer.java | 54 + .../org/openoffice/xmerge/DocumentSerializer2.java | 63 ++ .../xmerge/DocumentSerializerFactory.java | 50 + .../java/org/openoffice/xmerge/MergeException.java | 34 + .../java/org/openoffice/xmerge/PluginFactory.java | 163 +++ .../xmerge/java/org/openoffice/xmerge/Version.java | 68 ++ .../xmerge/converter/dom/DOMDocument.java | 312 ++++++ .../xmerge/converter/dom/package-info.java | 40 + .../openoffice/xmerge/converter/palm/PalmDB.java | 360 +++++++ .../xmerge/converter/palm/PalmDocument.java | 148 +++ .../xmerge/converter/palm/PdbDecoder.java | 128 +++ .../xmerge/converter/palm/PdbEncoder.java | 168 +++ .../xmerge/converter/palm/PdbHeader.java | 145 +++ .../openoffice/xmerge/converter/palm/PdbUtil.java | 35 + .../openoffice/xmerge/converter/palm/Record.java | 176 ++++ .../xmerge/converter/palm/package-info.java | 122 +++ .../xmerge/converter/xml/EmbeddedBinaryObject.java | 109 ++ .../xmerge/converter/xml/EmbeddedObject.java | 101 ++ .../xmerge/converter/xml/EmbeddedXMLObject.java | 280 +++++ .../xmerge/converter/xml/OfficeConstants.java | 333 ++++++ .../xmerge/converter/xml/OfficeDocument.java | 1113 ++++++++++++++++++++ .../converter/xml/OfficeDocumentException.java | 112 ++ .../openoffice/xmerge/converter/xml/OfficeZip.java | 424 ++++++++ .../openoffice/xmerge/converter/xml/ParaStyle.java | 528 ++++++++++ .../org/openoffice/xmerge/converter/xml/Style.java | 191 ++++ .../xmerge/converter/xml/StyleCatalog.java | 284 +++++ .../openoffice/xmerge/converter/xml/TextStyle.java | 575 ++++++++++ .../xmerge/converter/xml/package-info.java | 23 + .../xmerge/converter/xml/sxc/BookSettings.java | 208 ++++ .../xmerge/converter/xml/sxc/CellStyle.java | 471 +++++++++ .../xmerge/converter/xml/sxc/ColumnRowInfo.java | 180 ++++ .../xmerge/converter/xml/sxc/ColumnStyle.java | 244 +++++ .../converter/xml/sxc/DocumentMergerImpl.java | 183 ++++ .../xmerge/converter/xml/sxc/Format.java | 426 ++++++++ .../xmerge/converter/xml/sxc/NameDefinition.java | 205 ++++ .../xmerge/converter/xml/sxc/RowStyle.java | 244 +++++ .../xmerge/converter/xml/sxc/SheetSettings.java | 346 ++++++ .../converter/xml/sxc/SpreadsheetDecoder.java | 152 +++ .../converter/xml/sxc/SpreadsheetEncoder.java | 81 ++ .../xmerge/converter/xml/sxc/SxcConstants.java | 37 + .../xmerge/converter/xml/sxc/SxcDocument.java | 80 ++ .../converter/xml/sxc/SxcDocumentDeserializer.java | 746 +++++++++++++ .../converter/xml/sxc/SxcDocumentSerializer.java | 885 ++++++++++++++++ .../xmerge/converter/xml/sxc/SxcPluginFactory.java | 69 ++ .../xmerge/converter/xml/sxc/package-info.java | 23 + .../xmerge/converter/xml/sxw/SxwDocument.java | 80 ++ .../xmerge/converter/xml/sxw/SxwPluginFactory.java | 67 ++ .../xmerge/converter/xml/sxw/package-info.java | 23 + .../xml/xslt/ConverterCapabilitiesImpl.java | 74 ++ .../xml/xslt/DocumentDeserializerImpl.java | 189 ++++ .../converter/xml/xslt/DocumentMergerImpl.java | 80 ++ .../converter/xml/xslt/DocumentSerializerImpl.java | 266 +++++ .../converter/xml/xslt/GenericOfficeDocument.java | 81 ++ .../converter/xml/xslt/PluginFactoryImpl.java | 174 +++ .../converter/xml/xslt/XsltPlugin.properties | 27 + .../xmerge/converter/xml/xslt/package-info.java | 58 + .../openoffice/xmerge/merger/DiffAlgorithm.java | 43 + .../org/openoffice/xmerge/merger/Difference.java | 223 ++++ .../org/openoffice/xmerge/merger/Iterator.java | 85 ++ .../openoffice/xmerge/merger/MergeAlgorithm.java | 46 + .../xmerge/merger/NodeMergeAlgorithm.java | 40 + .../xmerge/merger/diff/CellNodeIterator.java | 96 ++ .../xmerge/merger/diff/CharArrayLCSAlgorithm.java | 188 ++++ .../xmerge/merger/diff/CharacterParser.java | 127 +++ .../xmerge/merger/diff/IteratorLCSAlgorithm.java | 210 ++++ .../xmerge/merger/diff/IteratorRowCompare.java | 229 ++++ .../xmerge/merger/diff/NodeIterator.java | 358 +++++++ .../xmerge/merger/diff/ObjectArrayIterator.java | 179 ++++ .../xmerge/merger/diff/ParaNodeIterator.java | 69 ++ .../openoffice/xmerge/merger/diff/RowIterator.java | 66 ++ .../xmerge/merger/diff/TextNodeEntry.java | 75 ++ .../xmerge/merger/diff/TextNodeIterator.java | 69 ++ .../xmerge/merger/diff/package-info.java | 26 + .../merger/merge/CharacterBaseParagraphMerge.java | 281 +++++ .../xmerge/merger/merge/DocumentMerge.java | 218 ++++ .../xmerge/merger/merge/PositionBaseRowMerge.java | 242 +++++ .../openoffice/xmerge/merger/merge/SheetMerge.java | 76 ++ .../openoffice/xmerge/merger/merge/SheetUtil.java | 99 ++ .../xmerge/merger/merge/package-info.java | 25 + .../org/openoffice/xmerge/merger/package-info.java | 56 + .../java/org/openoffice/xmerge/package-info.java | 89 ++ .../openoffice/xmerge/test/ConverterInfoList.java | 91 ++ .../xmerge/test/ConverterInfoList.properties | 28 + .../java/org/openoffice/xmerge/test/Driver.java | 300 ++++++ .../openoffice/xmerge/util/ActiveSyncDriver.java | 143 +++ .../openoffice/xmerge/util/ColourConverter.java | 421 ++++++++ .../java/org/openoffice/xmerge/util/Debug.java | 230 ++++ .../org/openoffice/xmerge/util/Debug.properties | 29 + .../openoffice/xmerge/util/EndianConverter.java | 128 +++ .../org/openoffice/xmerge/util/IntArrayList.java | 125 +++ .../org/openoffice/xmerge/util/OfficeUtil.java | 123 +++ .../java/org/openoffice/xmerge/util/Resources.java | 74 ++ .../org/openoffice/xmerge/util/TwipsConverter.java | 84 ++ .../java/org/openoffice/xmerge/util/XmlUtil.java | 171 +++ .../org/openoffice/xmerge/util/package-info.java | 22 + .../xmerge/util/registry/ConverterInfo.java | 406 +++++++ .../xmerge/util/registry/ConverterInfoMgr.java | 477 +++++++++ .../xmerge/util/registry/ConverterInfoReader.java | 245 +++++ .../xmerge/util/registry/RegistryException.java | 38 + .../xmerge/util/registry/package-info.java | 59 ++ .../openoffice/xmerge/util/resources.properties | 59 ++ xmerge/source/xmerge/xmerge.mf | 6 + 122 files changed, 20061 insertions(+) create mode 100644 xmerge/Jar_XMergeBridge.mk create mode 100644 xmerge/Jar_xmerge.mk create mode 100644 xmerge/Makefile create mode 100644 xmerge/Module_xmerge.mk create mode 100644 xmerge/README.md create mode 100644 xmerge/source/bridge/XMergeBridge.component create mode 100644 xmerge/source/bridge/java/XMergeBridge.java create mode 100644 xmerge/source/bridge/manifest.mf create mode 100644 xmerge/source/xmerge/converter.dtd create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/Convert.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/ConvertData.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/ConvertException.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/ConverterCapabilities.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/ConverterFactory.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/Document.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/DocumentDeserializer.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/DocumentDeserializer2.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/DocumentDeserializerFactory.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/DocumentMerger.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/DocumentMergerFactory.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/DocumentSerializer.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/DocumentSerializer2.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/DocumentSerializerFactory.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/MergeException.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/PluginFactory.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/Version.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/converter/dom/DOMDocument.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/converter/dom/package-info.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm/PalmDB.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm/PalmDocument.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm/PdbDecoder.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm/PdbEncoder.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm/PdbHeader.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm/PdbUtil.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm/Record.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm/package-info.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/EmbeddedBinaryObject.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/EmbeddedObject.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/EmbeddedXMLObject.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/OfficeConstants.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/OfficeDocument.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/OfficeDocumentException.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/OfficeZip.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/ParaStyle.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/Style.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/StyleCatalog.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/TextStyle.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/package-info.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/BookSettings.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/CellStyle.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/ColumnRowInfo.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/ColumnStyle.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/DocumentMergerImpl.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/Format.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/NameDefinition.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/RowStyle.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/SheetSettings.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/SpreadsheetDecoder.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/SpreadsheetEncoder.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/SxcConstants.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/SxcDocument.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/SxcDocumentDeserializer.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/SxcDocumentSerializer.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/SxcPluginFactory.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/package-info.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxw/SxwDocument.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxw/SxwPluginFactory.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxw/package-info.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/xslt/ConverterCapabilitiesImpl.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/xslt/DocumentDeserializerImpl.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/xslt/DocumentMergerImpl.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/xslt/DocumentSerializerImpl.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/xslt/GenericOfficeDocument.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/xslt/PluginFactoryImpl.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/xslt/XsltPlugin.properties create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/xslt/package-info.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/merger/DiffAlgorithm.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/merger/Difference.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/merger/Iterator.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/merger/MergeAlgorithm.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/merger/NodeMergeAlgorithm.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/merger/diff/CellNodeIterator.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/merger/diff/CharArrayLCSAlgorithm.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/merger/diff/CharacterParser.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/merger/diff/IteratorLCSAlgorithm.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/merger/diff/IteratorRowCompare.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/merger/diff/NodeIterator.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/merger/diff/ObjectArrayIterator.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/merger/diff/ParaNodeIterator.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/merger/diff/RowIterator.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/merger/diff/TextNodeEntry.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/merger/diff/TextNodeIterator.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/merger/diff/package-info.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/merger/merge/CharacterBaseParagraphMerge.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/merger/merge/DocumentMerge.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/merger/merge/PositionBaseRowMerge.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/merger/merge/SheetMerge.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/merger/merge/SheetUtil.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/merger/merge/package-info.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/merger/package-info.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/package-info.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/test/ConverterInfoList.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/test/ConverterInfoList.properties create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/test/Driver.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/util/ActiveSyncDriver.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/util/ColourConverter.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/util/Debug.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/util/Debug.properties create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/util/EndianConverter.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/util/IntArrayList.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/util/OfficeUtil.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/util/Resources.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/util/TwipsConverter.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/util/XmlUtil.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/util/package-info.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/util/registry/ConverterInfo.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/util/registry/ConverterInfoMgr.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/util/registry/ConverterInfoReader.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/util/registry/RegistryException.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/util/registry/package-info.java create mode 100644 xmerge/source/xmerge/java/org/openoffice/xmerge/util/resources.properties create mode 100644 xmerge/source/xmerge/xmerge.mf (limited to 'xmerge') diff --git a/xmerge/Jar_XMergeBridge.mk b/xmerge/Jar_XMergeBridge.mk new file mode 100644 index 000000000..2ca6fede5 --- /dev/null +++ b/xmerge/Jar_XMergeBridge.mk @@ -0,0 +1,26 @@ +# +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# + +$(eval $(call gb_Jar_Jar,XMergeBridge)) + +$(eval $(call gb_Jar_set_componentfile,XMergeBridge,xmerge/source/bridge/XMergeBridge,OOO,services)) + +$(eval $(call gb_Jar_set_manifest,XMergeBridge,$(SRCDIR)/xmerge/source/bridge/manifest.mf)) + +$(eval $(call gb_Jar_set_packageroot,XMergeBridge,*.class)) + +$(eval $(call gb_Jar_use_jars,XMergeBridge,\ + xmerge \ + libreoffice \ +)) + +$(eval $(call gb_Jar_add_sourcefiles,XMergeBridge,\ + xmerge/source/bridge/java/XMergeBridge \ +)) diff --git a/xmerge/Jar_xmerge.mk b/xmerge/Jar_xmerge.mk new file mode 100644 index 000000000..f90139ca3 --- /dev/null +++ b/xmerge/Jar_xmerge.mk @@ -0,0 +1,118 @@ +# +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# + +$(eval $(call gb_Jar_Jar,xmerge)) + +$(eval $(call gb_Jar_set_manifest,xmerge,$(SRCDIR)/xmerge/source/xmerge/xmerge.mf)) + +$(eval $(call gb_Jar_use_jars,xmerge,\ + libreoffice \ +)) + +$(eval $(call gb_Jar_set_packageroot,xmerge,org)) + +$(eval $(call gb_Jar_add_sourcefiles,xmerge,\ + xmerge/source/xmerge/java/org/openoffice/xmerge/Convert \ + xmerge/source/xmerge/java/org/openoffice/xmerge/ConvertData \ + xmerge/source/xmerge/java/org/openoffice/xmerge/ConverterCapabilities \ + xmerge/source/xmerge/java/org/openoffice/xmerge/converter/dom/DOMDocument \ + xmerge/source/xmerge/java/org/openoffice/xmerge/ConverterFactory \ + xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm/PalmDB \ + xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm/PalmDocument \ + xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm/PdbDecoder \ + xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm/PdbEncoder \ + xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm/PdbHeader \ + xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm/PdbUtil \ + xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm/Record \ + xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/EmbeddedBinaryObject \ + xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/EmbeddedObject \ + xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/EmbeddedXMLObject \ + xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/OfficeConstants \ + xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/OfficeDocument \ + xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/OfficeDocumentException \ + xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/OfficeZip \ + xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/ParaStyle \ + xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/Style \ + xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/StyleCatalog \ + xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/BookSettings \ + xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/CellStyle \ + xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/ColumnRowInfo \ + xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/ColumnStyle \ + xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/DocumentMergerImpl \ + xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/Format \ + xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/NameDefinition \ + xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/RowStyle \ + xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/SheetSettings \ + xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/SpreadsheetDecoder \ + xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/SpreadsheetEncoder \ + xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/SxcConstants \ + xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/SxcDocument \ + xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/SxcDocumentDeserializer \ + xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/SxcDocumentSerializer \ + xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/SxcPluginFactory \ + xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxw/SxwDocument \ + xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxw/SxwPluginFactory \ + xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/TextStyle \ + xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/xslt/ConverterCapabilitiesImpl \ + xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/xslt/DocumentDeserializerImpl \ + xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/xslt/DocumentMergerImpl \ + xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/xslt/DocumentSerializerImpl \ + xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/xslt/GenericOfficeDocument \ + xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/xslt/PluginFactoryImpl \ + xmerge/source/xmerge/java/org/openoffice/xmerge/ConvertException \ + xmerge/source/xmerge/java/org/openoffice/xmerge/Document \ + xmerge/source/xmerge/java/org/openoffice/xmerge/DocumentDeserializer \ + xmerge/source/xmerge/java/org/openoffice/xmerge/DocumentDeserializer2 \ + xmerge/source/xmerge/java/org/openoffice/xmerge/DocumentDeserializerFactory \ + xmerge/source/xmerge/java/org/openoffice/xmerge/DocumentMerger \ + xmerge/source/xmerge/java/org/openoffice/xmerge/DocumentMergerFactory \ + xmerge/source/xmerge/java/org/openoffice/xmerge/DocumentSerializer \ + xmerge/source/xmerge/java/org/openoffice/xmerge/DocumentSerializer2 \ + xmerge/source/xmerge/java/org/openoffice/xmerge/DocumentSerializerFactory \ + xmerge/source/xmerge/java/org/openoffice/xmerge/MergeException \ + xmerge/source/xmerge/java/org/openoffice/xmerge/merger/DiffAlgorithm \ + xmerge/source/xmerge/java/org/openoffice/xmerge/merger/diff/CellNodeIterator \ + xmerge/source/xmerge/java/org/openoffice/xmerge/merger/diff/CharacterParser \ + xmerge/source/xmerge/java/org/openoffice/xmerge/merger/diff/CharArrayLCSAlgorithm \ + xmerge/source/xmerge/java/org/openoffice/xmerge/merger/Difference \ + xmerge/source/xmerge/java/org/openoffice/xmerge/merger/diff/IteratorLCSAlgorithm \ + xmerge/source/xmerge/java/org/openoffice/xmerge/merger/diff/IteratorRowCompare \ + xmerge/source/xmerge/java/org/openoffice/xmerge/merger/diff/NodeIterator \ + xmerge/source/xmerge/java/org/openoffice/xmerge/merger/diff/ObjectArrayIterator \ + xmerge/source/xmerge/java/org/openoffice/xmerge/merger/diff/ParaNodeIterator \ + xmerge/source/xmerge/java/org/openoffice/xmerge/merger/diff/RowIterator \ + xmerge/source/xmerge/java/org/openoffice/xmerge/merger/diff/TextNodeEntry \ + xmerge/source/xmerge/java/org/openoffice/xmerge/merger/diff/TextNodeIterator \ + xmerge/source/xmerge/java/org/openoffice/xmerge/merger/Iterator \ + xmerge/source/xmerge/java/org/openoffice/xmerge/merger/MergeAlgorithm \ + xmerge/source/xmerge/java/org/openoffice/xmerge/merger/merge/CharacterBaseParagraphMerge \ + xmerge/source/xmerge/java/org/openoffice/xmerge/merger/merge/DocumentMerge \ + xmerge/source/xmerge/java/org/openoffice/xmerge/merger/merge/PositionBaseRowMerge \ + xmerge/source/xmerge/java/org/openoffice/xmerge/merger/merge/SheetMerge \ + xmerge/source/xmerge/java/org/openoffice/xmerge/merger/merge/SheetUtil \ + xmerge/source/xmerge/java/org/openoffice/xmerge/merger/NodeMergeAlgorithm \ + xmerge/source/xmerge/java/org/openoffice/xmerge/PluginFactory \ + xmerge/source/xmerge/java/org/openoffice/xmerge/test/ConverterInfoList \ + xmerge/source/xmerge/java/org/openoffice/xmerge/test/Driver \ + xmerge/source/xmerge/java/org/openoffice/xmerge/util/ActiveSyncDriver \ + xmerge/source/xmerge/java/org/openoffice/xmerge/util/ColourConverter \ + xmerge/source/xmerge/java/org/openoffice/xmerge/util/Debug \ + xmerge/source/xmerge/java/org/openoffice/xmerge/util/EndianConverter \ + xmerge/source/xmerge/java/org/openoffice/xmerge/util/IntArrayList \ + xmerge/source/xmerge/java/org/openoffice/xmerge/util/OfficeUtil \ + xmerge/source/xmerge/java/org/openoffice/xmerge/util/registry/ConverterInfo \ + xmerge/source/xmerge/java/org/openoffice/xmerge/util/registry/ConverterInfoMgr \ + xmerge/source/xmerge/java/org/openoffice/xmerge/util/registry/ConverterInfoReader \ + xmerge/source/xmerge/java/org/openoffice/xmerge/util/registry/RegistryException \ + xmerge/source/xmerge/java/org/openoffice/xmerge/util/Resources \ + xmerge/source/xmerge/java/org/openoffice/xmerge/util/TwipsConverter \ + xmerge/source/xmerge/java/org/openoffice/xmerge/util/XmlUtil \ + xmerge/source/xmerge/java/org/openoffice/xmerge/Version \ +)) diff --git a/xmerge/Makefile b/xmerge/Makefile new file mode 100644 index 000000000..0997e6284 --- /dev/null +++ b/xmerge/Makefile @@ -0,0 +1,14 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +module_directory:=$(dir $(realpath $(firstword $(MAKEFILE_LIST)))) + +include $(module_directory)/../solenv/gbuild/partial_build.mk + +# vim: set noet sw=4 ts=4: diff --git a/xmerge/Module_xmerge.mk b/xmerge/Module_xmerge.mk new file mode 100644 index 000000000..e92da2ae9 --- /dev/null +++ b/xmerge/Module_xmerge.mk @@ -0,0 +1,17 @@ +# +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# +$(eval $(call gb_Module_Module,xmerge)) + +$(eval $(call gb_Module_add_targets,xmerge,\ + $(if $(ENABLE_JAVA), \ + Jar_xmerge \ + Jar_XMergeBridge \ + ) \ +)) diff --git a/xmerge/README.md b/xmerge/README.md new file mode 100644 index 000000000..aa7183dd4 --- /dev/null +++ b/xmerge/README.md @@ -0,0 +1,9 @@ +# Document Conversion and Merging + +For converting documents among from and into formats and also for merging them. + +Uses Java and plug-in architecture. + +## See also + + diff --git a/xmerge/source/bridge/XMergeBridge.component b/xmerge/source/bridge/XMergeBridge.component new file mode 100644 index 000000000..bea9a8d75 --- /dev/null +++ b/xmerge/source/bridge/XMergeBridge.component @@ -0,0 +1,25 @@ + + + + + + + + diff --git a/xmerge/source/bridge/java/XMergeBridge.java b/xmerge/source/bridge/java/XMergeBridge.java new file mode 100644 index 000000000..6506326c4 --- /dev/null +++ b/xmerge/source/bridge/java/XMergeBridge.java @@ -0,0 +1,579 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +/** You can find more + * information on the following web page: + * https://api.libreoffice.org/docs/common/ref/com/sun/star/module-ix.html + */ + +/*Java Uno Helper Classes*/ +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.net.URI; +import java.util.Iterator; + +import javax.xml.parsers.ParserConfigurationException; + +import org.openoffice.xmerge.Convert; +import org.openoffice.xmerge.ConvertData; +import org.openoffice.xmerge.ConverterFactory; +import org.openoffice.xmerge.Document; +import org.openoffice.xmerge.converter.xml.OfficeDocument; +import org.openoffice.xmerge.util.registry.ConverterInfo; +import org.openoffice.xmerge.util.registry.ConverterInfoMgr; +import org.openoffice.xmerge.util.registry.ConverterInfoReader; + +import com.sun.star.comp.loader.FactoryHelper; +import com.sun.star.frame.XConfigManager; +import com.sun.star.io.XInputStream; +import com.sun.star.io.XOutputStream; +import com.sun.star.lang.XMultiServiceFactory; +import com.sun.star.lang.XServiceInfo; +import com.sun.star.lang.XServiceName; +import com.sun.star.lang.XSingleServiceFactory; +import com.sun.star.lang.XTypeProvider; +import com.sun.star.lib.uno.adapter.XInputStreamToInputStreamAdapter; +import com.sun.star.lib.uno.adapter.XOutputStreamToOutputStreamAdapter; +import com.sun.star.registry.XRegistryKey; +import com.sun.star.uno.AnyConverter; +import com.sun.star.uno.Type; +import com.sun.star.uno.UnoRuntime; +import com.sun.star.xml.XExportFilter; +import com.sun.star.xml.XImportFilter; +import com.sun.star.xml.sax.InputSource; +import com.sun.star.xml.sax.XDocumentHandler; +import com.sun.star.xml.sax.XParser; + +/** This outer class provides an inner class to implement the service + * description and a method to instantiate the + * component on demand (__getServiceFactory()). + */ +public class XMergeBridge { + + private static XMultiServiceFactory xMSF; + private static XInputStream xInStream =null; + private static XOutputStream xOutStream=null; + private static String udJarPath=null; + private static XOutputStream xos = null; + private static String offMime=null; + private static String sdMime=null; + private static String sFileName=null; + private static String sURL=""; + + /** This inner class provides the component as a concrete implementation + * of the service description. It implements the needed interfaces. + */ + public static class _XMergeBridge implements + XImportFilter, + XExportFilter, + XServiceName, + XServiceInfo, + XDocumentHandler, + XTypeProvider { + + /** The component will be registered under this name. + */ + private static final String __serviceName = "com.sun.star.documentconversion.XMergeBridge"; + + public com.sun.star.uno.Type[] getTypes() { + Type[] typeReturn = {}; + + try { + typeReturn = new Type[] { + new Type( XTypeProvider.class ), + new Type( XImportFilter.class ), + new Type( XExportFilter.class ), + new Type( XServiceName.class ), + new Type( XServiceInfo.class ) }; + } + catch( Exception exception ) { + + } + + return typeReturn; + } + + private String getFileName(String origName) + { + String name; + if (origName !=null) + { + if(origName.equalsIgnoreCase("")) + name = "OutFile"; + else { + if (origName.lastIndexOf("/")>=0){ + origName=origName.substring(origName.lastIndexOf("/")+1,origName.length()); + } + if (origName.lastIndexOf(".")>=0){ + name = origName.substring(0, origName.lastIndexOf(".")); + } + else{ + name=origName; + } + } + } + else{ + name = "OutFile"; + } + return name; + } + + public boolean importer(com.sun.star.beans.PropertyValue[] aSourceData, + com.sun.star.xml.sax.XDocumentHandler xDocHandler, + String[] msUserData) throws com.sun.star.uno.RuntimeException { + + sFileName=""; + sURL=""; + udJarPath=msUserData[1]; + offMime =msUserData[4]; + sdMime = msUserData[5]; + com.sun.star.io.XInputStream xis=null; + com.sun.star.beans.PropertyValue[] pValue = aSourceData; + + for (int i = 0 ; i < pValue.length; i++) + { + + try{ + if (pValue[i].Name.equals("InputStream")){ + xis=(com.sun.star.io.XInputStream)AnyConverter.toObject(new Type(com.sun.star.io.XInputStream.class), pValue[i].Value); + } + if (pValue[i].Name.equals("FileName")){ + sFileName=(String)AnyConverter.toObject(new Type(String.class), pValue[i].Value); + } + + } + catch(com.sun.star.lang.IllegalArgumentException AnyExec){ + System.out.println("\nIllegalArgumentException "+AnyExec); + } + + } + + try{ + + Object xCfgMgrObj=xMSF.createInstance("com.sun.star.config.SpecialConfigManager"); + XConfigManager xCfgMgr = UnoRuntime.queryInterface( + XConfigManager.class , xCfgMgrObj ); + String PathString=xCfgMgr.substituteVariables("$(progurl)" ); + PathString= PathString.concat("/"); + udJarPath= PathString.concat(udJarPath); + + Object xPipeObj=xMSF.createInstance("com.sun.star.io.Pipe"); + xInStream = UnoRuntime.queryInterface( + XInputStream.class , xPipeObj ); + xOutStream = UnoRuntime.queryInterface( + XOutputStream.class , xPipeObj ); + convert (xis,xOutStream,false,udJarPath,sFileName,offMime,sdMime); + Object xSaxParserObj=xMSF.createInstance("com.sun.star.xml.sax.Parser"); + + XParser xParser = UnoRuntime.queryInterface( + XParser.class , xSaxParserObj ); + xOutStream.closeOutput(); + InputSource aInput = new InputSource(); + if (sFileName==null){ + sFileName=""; + } + aInput.sSystemId = sFileName; + aInput.aInputStream =xInStream; + xParser.setDocumentHandler ( xDocHandler ); + + xParser.parseStream ( aInput ); + xOutStream.closeOutput(); + xInStream.closeInput(); + + } + catch (IOException e){ + return false; + } + catch (Exception e){ + return false; + } + return true; + } + + public boolean exporter(com.sun.star.beans.PropertyValue[] aSourceData, + String[] msUserData) throws com.sun.star.uno.RuntimeException{ + + sFileName=null; + sURL=null; + udJarPath=msUserData[1]; + offMime =msUserData[4]; + sdMime = msUserData[5]; + + com.sun.star.beans.PropertyValue[] pValue = aSourceData; + for (int i = 0 ; i < pValue.length; i++) + { + + try{ + if (pValue[i].Name.equals("OutputStream")){ + xos=(com.sun.star.io.XOutputStream)AnyConverter.toObject(new Type(com.sun.star.io.XOutputStream.class), pValue[i].Value); + } + + if (pValue[i].Name.equals("FileName")){ + sFileName=(String)AnyConverter.toObject(new Type(String.class), pValue[i].Value); + } + + if (pValue[i].Name.equals("URL")){ + sURL=(String)AnyConverter.toObject(new Type(String.class), pValue[i].Value); + } + } + catch(com.sun.star.lang.IllegalArgumentException AnyExec){ + System.out.println("\nIllegalArgumentException "+AnyExec); + } + } + + if (sURL==null){ + sURL=""; + } + + try{ + + Object xCfgMgrObj=xMSF.createInstance("com.sun.star.config.SpecialConfigManager"); + XConfigManager xCfgMgr = UnoRuntime.queryInterface( + XConfigManager.class , xCfgMgrObj ); + + String PathString=xCfgMgr.substituteVariables("$(progurl)" ); + PathString= PathString.concat("/"); + udJarPath= PathString.concat(udJarPath); + + Object xPipeObj=xMSF.createInstance("com.sun.star.io.Pipe"); + xInStream = UnoRuntime.queryInterface( + XInputStream.class , xPipeObj ); + xOutStream = UnoRuntime.queryInterface( + XOutputStream.class , xPipeObj ); + } + catch (Exception e){ + System.out.println("Exception "+e); + return false; + } + + return true; + } + + private String needsMask(String origString){ + if (origString.contains("&")) { + origString = origString.replace("&","&"); + } + if (origString.contains("\"")) { + origString = origString.replace("\"","""); + } + if (origString.contains("<")) { + origString = origString.replace("<","<"); + } + if (origString.contains(">")) { + origString = origString.replace(">",">"); + } + return origString; + } + + public void startDocument () { + } + + public void endDocument()throws com.sun.star.uno.RuntimeException + { + + try{ + xOutStream.closeOutput(); + convert (xInStream,xos,true,udJarPath,sURL,offMime,sdMime); + + } + catch (IOException e){ + throw new com.sun.star.uno.RuntimeException(e); + + } + catch (Exception e){ + throw new com.sun.star.uno.RuntimeException(e); + + } + } + + public void startElement (String str, com.sun.star.xml.sax.XAttributeList xattribs) + { + + str="<".concat(str); + if (xattribs !=null) + { + str= str.concat(" "); + int len=xattribs.getLength(); + for (short i=0;i"); + + try{ + xOutStream.writeBytes(str.getBytes("UTF-8")); + } + catch (Exception e){ + System.out.println("\n"+e); + } + + } + + public void endElement(String str){ + + str=""); + try{ + xOutStream.writeBytes(str.getBytes("UTF-8")); + + } + catch (Exception e){ + System.out.println("\n"+e); + } + + } + public void characters(String str){ + str=needsMask(str); + try{ + xOutStream.writeBytes(str.getBytes("UTF-8")); + } + catch (Exception e){ + System.out.println("\n"+e); + } + + } + + public void ignorableWhitespace(String str){ + + } + public void processingInstruction(String aTarget, String aData){ + + } + + public void setDocumentLocator(com.sun.star.xml.sax.XLocator xLocator){ + + } + + private static void close(FileOutputStream c) throws IOException { + if (c == null) return; + c.close(); + } + + private void convert (com.sun.star.io.XInputStream xml,com.sun.star.io.XOutputStream device, + boolean convertFromOffice,String pluginUrl,String FileName,String offMime,String sdMime) throws com.sun.star.uno.RuntimeException, IOException { + + String jarName = pluginUrl; + String name= getFileName(FileName); + + Iterator ciEnum= null; + + XInputStreamToInputStreamAdapter xis =new XInputStreamToInputStreamAdapter(xml); + + XOutputStreamToOutputStreamAdapter newxos =new XOutputStreamToOutputStreamAdapter(device); + + /* make sure newxos and xis get closed */ + try{ + try{ + ConverterInfoReader cir = new ConverterInfoReader(jarName,false); + ciEnum =cir.getConverterInfoEnumeration(); + } + catch (ParserConfigurationException pexc){ + System.out.println("Error:"+pexc); + } + catch ( org.xml.sax.SAXException pexc){ + System.out.println("Error:"+pexc); + } + catch(Exception e){ + System.out.println("Error:"+e); + } + ConverterInfoMgr. removeByJar(jarName); + if (convertFromOffice) + { + + try { + + //Check to see if jar contains a plugin Impl + + ConverterInfoMgr.addPlugIn(ciEnum); + ConverterFactory cf = new ConverterFactory(); + + Convert cv = cf.getConverter(ConverterInfoMgr.findConverterInfo(sdMime,offMime),false); + if (cv == null) { + System.out.println("\nNo plug-in exists to convert from to "); + + } + else + { + cv.addInputStream(name,xis,false); + ConvertData dataOut = cv.convert(); + + Iterator docEnum = dataOut.getDocumentEnumeration(); + + if (docEnum.hasNext()){ + Document docOut = (Document)docEnum.next(); + docOut.write(newxos); + + newxos.flush(); + newxos.close(); + newxos = null; + + int i=1; + while (docEnum.hasNext() && sURL.startsWith("file:")) { + + URI uri=new URI(sURL); + String newFileName= getPath(uri); + + File newFile; + if (newFileName.lastIndexOf(".")!=-1){ + newFile =new File(newFileName.substring(0,newFileName.lastIndexOf("."))+String.valueOf(i)+newFileName.substring(newFileName.lastIndexOf("."))); + } + else{ + newFile =new File(newFileName.concat(String.valueOf(i))); + } + + FileOutputStream fos = null; + try { + fos = new FileOutputStream(newFile); + docOut = (Document)docEnum.next(); + docOut.write(fos); + fos.flush(); + } finally { + close(fos); + } + i++; + + } + + } + } + ConverterInfoMgr.removeByJar(jarName); + } + catch (Exception ex1) { + IOException ex2 = new IOException(); + ex2.initCause(ex1); + throw ex2; + } + } + else{ + + try { + //Check to see if jar contains a plugin Impl + ConverterInfoMgr.addPlugIn(ciEnum); + ConverterFactory cf = new ConverterFactory(); + Convert cv = cf.getConverter(ConverterInfoMgr.findConverterInfo(sdMime,offMime),true); + if (cv == null) { + System.out.println("\nNo plug-in exists to convert to from "); + } + else + { + + cv.addInputStream(name,xis,false); + ConvertData dataIn = cv.convert(); + Iterator docEnum = dataIn.getDocumentEnumeration(); + while (docEnum.hasNext()) { + OfficeDocument docIn = (OfficeDocument)docEnum.next(); + + docIn.write(newxos,false); + } + newxos.close(); + newxos = null; + } + ConverterInfoMgr.removeByJar(jarName); + } + catch (StackOverflowError sOE){ + System.out.println("\nERROR : Stack Overflow. \n Increase of the JRE by adding the following line to the end of the javarc file \n \"-Xss1m\"\n"); + } + catch (Exception ex1) { + IOException ex2 = new IOException(); + ex2.initCause(ex1); + throw ex2; + } + + } + } + finally{ + if (newxos != null){ + try { + newxos.flush(); + } catch (IOException e) { + } + newxos.close(); + } + xis.close(); + } + } + + private String getPath(URI uri){ + String path = uri.getPath(); + String opSys=System.getProperty("os.name"); + if(opSys.contains("Windows")){ + path= path.replace('/','\\'); + path = path.substring(1); + } + return path; + } + + // Implement methods from interface XTypeProvider + public byte[] getImplementationId() { + return new byte[0]; + } + + // Implement method from interface XServiceName + public String getServiceName() { + return __serviceName; + } + + // Implement methods from interface XServiceInfo + public boolean supportsService(String stringServiceName) { + return stringServiceName.equals( __serviceName ); + } + + public String getImplementationName() { + return _XMergeBridge.class.getName(); + } + + public String[] getSupportedServiceNames() { + String[] stringSupportedServiceNames = { __serviceName }; + return stringSupportedServiceNames; + } + } + + /** + * Returns a factory for creating the service. + * This method is called by the JavaLoader + * + * @return returns a XSingleServiceFactory for creating the + * component + * + * @param implName the name of the implementation for which a + * service is desired + * @param multiFactory the service manager to be used if needed + * @param regKey the registryKey + * + * @see com.sun.star.comp.loader.JavaLoader + */ + public static XSingleServiceFactory __getServiceFactory(String implName, + XMultiServiceFactory multiFactory, + XRegistryKey regKey) { + xMSF= multiFactory; + XSingleServiceFactory xSingleServiceFactory = null; + if (implName.equals(_XMergeBridge.class.getName()) ) { + xSingleServiceFactory = FactoryHelper.getServiceFactory(_XMergeBridge.class, + _XMergeBridge.__serviceName, + multiFactory, + regKey); + } + + return xSingleServiceFactory; + } +} diff --git a/xmerge/source/bridge/manifest.mf b/xmerge/source/bridge/manifest.mf new file mode 100644 index 000000000..1c63d9e6d --- /dev/null +++ b/xmerge/source/bridge/manifest.mf @@ -0,0 +1,2 @@ +RegistrationClassName: XMergeBridge +UNO-Type-Path: diff --git a/xmerge/source/xmerge/converter.dtd b/xmerge/source/xmerge/converter.dtd new file mode 100644 index 000000000..81ecbe69d --- /dev/null +++ b/xmerge/source/xmerge/converter.dtd @@ -0,0 +1,84 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/Convert.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/Convert.java new file mode 100644 index 000000000..728aa05ae --- /dev/null +++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/Convert.java @@ -0,0 +1,233 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +package org.openoffice.xmerge; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Iterator; + +import org.openoffice.xmerge.util.registry.ConverterInfo; + +/** + * The {@code Convert} class manages a conversion from one mime-type to another. + * + *

The {@code ConvertFactory} is responsible for returning the appropriate + * {@code Convert} class for a specified conversion. This class is responsible + * for all interactions with the {@code PluginFactory} implementation.

+ * + * @see ConverterFactory + * @see PluginFactory + * @see org.openoffice.xmerge.util.registry.ConverterInfo + */ +public class Convert implements Cloneable { + + /** ConvertInfo that corresponds to the from-mime/to-mime conversion. */ + private final ConverterInfo ci; + + /** + * {@code true} if converting to the Office format, {@code false} if + * converting to the device format. + */ + private final boolean toOffice; + + /** Holds the convert input data. */ + private final ConvertData inputCD = new ConvertData(); + + /** + * Construct a Convert class with specified {@code ConvertInfo} registry + * information. + * + * @param ci A {@code ConvertInfo} object containing registry + * information corresponding to a specific plug-in. + * @param toOffice {@code true} if converting to the Office format, + * {@code false} if converting to the device format. + */ + public Convert(ConverterInfo ci, boolean toOffice) { + this.ci = ci; + this.toOffice = toOffice; + } + + /** + * Adds an {@code InputStream} to be used as input by the {@code Convert} + * class. + * + *

It is possible that many files need to be converted into a single + * output {@code Document}, so this function may be called more than one + * time. It is the plug-in's responsibility to know how to handle the input. + *

+ * + * @param name The name corresponding to the {@code InputStream}. + * @param is {@code InputStream} to be used as input. + * + * @throws IOException If any I/O error occurs. + */ + public void addInputStream(String name, InputStream is) + throws IOException { + + Document inputDoc; + + if (toOffice) { + inputDoc = ci.getPluginFactory().createDeviceDocument(name, is); + } else { + inputDoc = ci.getPluginFactory().createOfficeDocument(name, is); + } + inputCD.addDocument(inputDoc); + } + + /** + * Adds an {@code InputStream} to be used as input by the {@code Convert} + * class. + * + *

It is possible that many files need to be converted into a single + * output {@code Document}, so this function may be called more than one + * time. It is the plug-in's responsibility to know how to handle the input. + *

+ * + * @param name The name corresponding to the {@code InputStream}. + * @param is {@code InputStream} to be used as input. + * @param isZip {@code boolean} to identify that incoming stream is * zipped. + * + * @throws IOException If any I/O error occurs. + */ + public void addInputStream(String name, InputStream is,boolean isZip) + throws IOException { + + Document inputDoc; + + if (toOffice) { + inputDoc = ci.getPluginFactory().createDeviceDocument(name, is); + } else { + inputDoc = ci.getPluginFactory().createOfficeDocument(name, is, isZip); + } + inputCD.addDocument(inputDoc); + } + + + /** + * Returns a {@code DocumentMerger} for the given {@code Document}. + * + * @param origDoc The {@code Document} were later changes will be merged to. + * + * @return The {@code DocumentMerger} object for the given document. + * + * @throws IOException If any I/O error occurs. + */ + public DocumentMerger getDocumentMerger(Document origDoc) throws IOException { + DocumentMergerFactory myDocMergerFactory = ci.getDocMergerFactory(); + DocumentMerger merger = myDocMergerFactory.createDocumentMerger(origDoc); + return merger; + } + + /** + * Resets the input queue, so that the user can use this class to perform + * another conversion. + * + *

This causes the {@code addInputStream} method to accept input for the + * next conversion.

+ */ + private void reset() { + inputCD.reset(); + } + + /** + * Clones a {@code Convert} object so another Convert object can do the same + * conversion. + * + *

{@code InputStream} objects passed in via calls to the + * {@code addInputStream} method are not copied.

+ * + * @return The cloned {@code Convert} object. + */ + @Override + public Object clone() { + + Convert aClone = null; + + try { + aClone = (Convert) super.clone(); + aClone.reset(); + } + catch (CloneNotSupportedException e) { + System.out.println("Convert clone could not be created"); + } + return aClone; + } + + /** + * Convert the input specified in calls to the {@code addInputStream} + * method to the output format specified by this {@code Convert} class. + * + * @return The output data. + * + * @throws ConvertException If any conversion error occurs. + * @throws IOException If any I/O error occurs. + */ + public ConvertData convert() throws ConvertException, IOException { + + ConvertData dataOut = new ConvertData(); + + if (toOffice) { + + // From device format to Office format + + DocumentDeserializerFactory myDocDeserializerFactory = + ci.getDocDeserializerFactory(); + DocumentDeserializer deser = + myDocDeserializerFactory.createDocumentDeserializer(inputCD); + Document deviceDoc = deser.deserialize(); + + + dataOut.addDocument(deviceDoc); + return dataOut; + + } else { + + // From Office format to device format + + DocumentSerializerFactory myDocSerializerFactory = + ci.getDocSerializerFactory(); + + Iterator e = inputCD.getDocumentEnumeration(); + + Document doc = (Document) e.next(); + DocumentSerializer ser = myDocSerializerFactory.createDocumentSerializer(doc); + dataOut = ser.serialize(); + + return dataOut; + } + } + + /** + * Returns the appropriate "Office" {@code Document} object for + * this plug-in. + * + * @param name The name of the {@code Document} to create. + * @param is The {@code InputStream} corresponding to the + * {@code Document} to create. + * + * @return The appropriate "Office" {@code Document} object for + * this plug-in. + * + * @throws IOException If any I/O error occurs. + */ + public Document getOfficeDocument(String name, InputStream is) + throws IOException { + return ci.getPluginFactory().createOfficeDocument(name, is); + } +} \ No newline at end of file diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/ConvertData.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/ConvertData.java new file mode 100644 index 000000000..d8f276bc3 --- /dev/null +++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/ConvertData.java @@ -0,0 +1,101 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +package org.openoffice.xmerge; + +import java.util.ArrayList; +import java.util.Iterator; + +/** + * {@code ConvertData} is used as a container for passing {@code Document} + * objects in and out of the {@code Convert} class. + * + *

The {@code ConvertData} contains a {@code String} name and a + * {@code Vector} of {@code Document} objects.

+ */ +public class ConvertData { + + /** + * Vector of {@code Document} objects. + */ + private final ArrayList v = new ArrayList(); + + /** + * Name of the {@code ConvertData} object. + */ + private String name; + + /** + * Resets ConvertData. + * + *

This empties all {@code Document} objects from this class. This allows + * reuse of a {@code ConvertData}.

+ */ + public void reset() { + name = null; + v.clear(); + } + + /** + * Returns the {@code Document} name. + * + * @return The {@code Document} name. + */ + public String getName() { + return name; + } + + /** + * Sets the {@code Document} name. + * + * @param docName The name of the {@code Document}. + */ + public void setName(String docName) { + name = docName; + } + + /** + * Adds a {@code Document} to the vector. + * + * @param doc The {@code Document} to add. + */ + public void addDocument(Document doc) { + v.add(doc); + } + + /** + * Gets an {@code Enumeration} to access the {@code Vector} of + * {@code Document} objects. + * + * @return The {@code Enumeration} to access the {@code Vector} of + * {@code Document} objects. + */ + public Iterator getDocumentEnumeration() { + Iterator enumerate = v.iterator(); + return enumerate; + } + + /** + * Gets the number of {@code Document} objects currently stored. + * + * @return The number of {@code Document} objects currently stored. + */ + public int getNumDocuments() { + return v.size(); + } +} diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/ConvertException.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/ConvertException.java new file mode 100644 index 000000000..6d05e8d26 --- /dev/null +++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/ConvertException.java @@ -0,0 +1,34 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +package org.openoffice.xmerge; + +/** + * This {@code Exception} is thrown by convert algorithms. + */ +public class ConvertException extends Exception { + + /** + * Exception thrown by convert algorithms. + * + * @param message Message to be included in the {@code Exception}. + */ + public ConvertException(String message) { + super(message); + } +} \ No newline at end of file diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/ConverterCapabilities.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/ConverterCapabilities.java new file mode 100644 index 000000000..da36f7da2 --- /dev/null +++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/ConverterCapabilities.java @@ -0,0 +1,54 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +package org.openoffice.xmerge; + +/** + * A {@code ConverterCapabilities} object is used by {@code DocumentMerger} + * implementations. + * + *

The {@code ConverterCapabilities} indicates which "Office" XML + * tags are supported by the "Device" format.

+ * + * @see org.openoffice.xmerge.PluginFactory + * @see org.openoffice.xmerge.DocumentMerger + */ +public interface ConverterCapabilities { + + /** + * Test to see if the device document format supports the tag in question. + * + * @param tag The tag to check. + * + * @return {@code true} if the device format supports the tag, + * {@code false} otherwise. + */ + boolean canConvertTag(String tag); + + /** + * Test to see if the device document format supports the tag attribute in + * question. + * + * @param tag The tag to check. + * @param attribute The tag attribute to check. + * + * @return {@code true} if the device format supports the attribute, + * {@code false} otherwise. + */ + boolean canConvertAttribute(String tag, String attribute); +} \ No newline at end of file diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/ConverterFactory.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/ConverterFactory.java new file mode 100644 index 000000000..5c1c246cb --- /dev/null +++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/ConverterFactory.java @@ -0,0 +1,85 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +package org.openoffice.xmerge; + +import org.openoffice.xmerge.util.registry.ConverterInfo; +import org.openoffice.xmerge.util.registry.ConverterInfoMgr; + +/** + * Factory that provides access to {@code Convert} objects, which are used to do + * a conversion. + * + *

The {@code ConvertFactory} does this via the {@code ConvertInfoMgr} which + * maintains a list of which {@code Convert} objects are available and their + * capabilities.

+ * + * @see Convert + * @see org.openoffice.xmerge.util.registry.ConverterInfoMgr + */ +public class ConverterFactory { + + /** + * Returns the {@code Convert} object that converts the specified device/office + * mime type conversion. + * + *

If there are multiple {@code Converter} objects registered that support + * this conversion, only the first is returned.

+ * + * @param mimeTypeIn The mime input type. + * @param mimeTypeOut The mime output type. + * + * @return The first {@code Convert} object that supports the specified + * conversion. + */ + public Convert getConverter(String mimeTypeIn, String mimeTypeOut) { + + ConverterInfo foundInfo; + boolean toOffice; + + toOffice = ConverterInfo.isValidOfficeType(mimeTypeOut); + + // findConverterInfo expects the second parameter to be the + // destination MimeType + if (toOffice) + foundInfo = ConverterInfoMgr.findConverterInfo(mimeTypeIn, mimeTypeOut); + else + foundInfo = ConverterInfoMgr.findConverterInfo(mimeTypeOut, mimeTypeIn); + + if (foundInfo != null) + return getConverter(foundInfo, toOffice); + else + return null; + } + + /** + * Returns the {@code Convert} object that is described by the + * {@code ConverterInfo} parameter. + * + * @param ci The {@code ConverterInfo} describing the converter. + * @param toOffice {@code true} to convert to office, {@code false} to + * convert to device. + * + * @return The {@code Convert} object + */ + public Convert getConverter(ConverterInfo ci, boolean toOffice) { + + Convert myConvert = new Convert(ci, toOffice); + return myConvert; + } +} diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/Document.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/Document.java new file mode 100644 index 000000000..851c1539d --- /dev/null +++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/Document.java @@ -0,0 +1,79 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +package org.openoffice.xmerge; + +import java.io.OutputStream; +import java.io.InputStream; +import java.io.IOException; + +/** + * A {@code Document} represents any {@code Document} to be converted and the + * resulting {@code Document} from any conversion. + * + *

It is created by the {@code PluginFactory} object's {@link + * org.openoffice.xmerge.PluginFactory#createOfficeDocument createOfficeDocument} + * method or the {@link org.openoffice.xmerge.PluginFactory#createDeviceDocument + * createDeviceDocument} method.

+ * + * @see org.openoffice.xmerge.PluginFactory + */ +public interface Document { + + /** + * Writes out the {@code Document} content to the specified + * {@code OutputStream}. + * + *

This method may not be thread-safe. Implementations may or may not + * synchronize this method. User code (i.e. caller) must make sure that + * calls to this method are thread-safe.

+ * + * @param os {@code OutputStream} to write out the {@code Document} + * content. + * + * @throws IOException If any I/O error occurs. + */ + void write(OutputStream os) throws IOException; + + /** + * Reads the content from the {@code InputStream} into the {@code Document}. + * + *

This method may not be thread-safe. Implementations may or may not + * synchronize this method. User code (i.e. caller) must make sure that + * calls to this method are thread-safe.

+ * + * @param is {@code InputStream} to read in the {@code Document} content. + * + * @throws IOException If any I/O error occurs. + */ + void read(InputStream is) throws IOException; + + /** + * Returns the {@code Document} name with no file extension. + * + * @return The {@code Document} name with no file extension. + */ + String getName(); + + /** + * Returns the {@code Document} name with file extension. + * + * @return The {@code Document} name with file extension. + */ + String getFileName(); +} \ No newline at end of file diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/DocumentDeserializer.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/DocumentDeserializer.java new file mode 100644 index 000000000..1bfadfcfe --- /dev/null +++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/DocumentDeserializer.java @@ -0,0 +1,53 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +package org.openoffice.xmerge; + +import java.io.IOException; + +/** + * A {@code DocumentDeserializer} represents a converter that converts + * "Device" {@code Document} objects into the "Office" + * {@code Document} format. + * + *

The {@code DocumentDeserializer} object is created by the + * {@code PluginFactory} {@link + * org.openoffice.xmerge.DocumentDeserializerFactory#createDocumentDeserializer + * createDocumentDeserializer} method. When it is constructed, a + * {@code ConvertData} object is passed in to be used as input.

+ * + * @see org.openoffice.xmerge.PluginFactory + * @see org.openoffice.xmerge.DocumentDeserializerFactory + */ +public interface DocumentDeserializer { + + /** + * Convert the data passed into the {@code DocumentDeserializer} constructor + * into the "Office" {@code Document} format. + * + *

This method may or may not be thread-safe. It is expected that the + * user code does not call this method in more than one thread. And for + * most cases, this method is only done once.

+ * + * @return The resulting {@code Document} object from conversion. + * + * @throws ConvertException If any Convert error occurs. + * @throws IOException If any I/O error occurs. + */ + Document deserialize() throws ConvertException, IOException; +} \ No newline at end of file diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/DocumentDeserializer2.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/DocumentDeserializer2.java new file mode 100644 index 000000000..95f34413e --- /dev/null +++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/DocumentDeserializer2.java @@ -0,0 +1,61 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +package org.openoffice.xmerge; + +import java.io.IOException; + +/** + * A {@code DocumentDeserializer} represents a converter that converts + * "Device" {@code Document} objects into the "Office" + * {@code Document} format. + * + *

The {@code PluginFactory} {@link + * org.openoffice.xmerge.DocumentDeserializerFactory#createDocumentDeserializer + * createDocumentDeserializer} method creates a {@code DocumentDeserializer}, + * which may or may not implement {@code DocumentDeserializer2}. When it is + * constructed, a {@code ConvertData} object is passed in to be used as input. + *

+ * + * @see org.openoffice.xmerge.PluginFactory + * @see org.openoffice.xmerge.DocumentDeserializerFactory + */ +public interface DocumentDeserializer2 extends DocumentSerializer { + + /** + * Convert the data passed into the {@code DocumentDeserializer2} + * constructor into the "Office" {@code Document} format. + * + *

The URL's passed may be used to resolve links and to choose the name + * of the output office document.

+ * + *

This method may or may not be thread-safe. It is expected that the + * user code does not call this method in more than one thread. And for + * most cases, this method is only done once.

+ * + * @return The resulting {@code Document} object from conversion. + * + * @param deviceURL URL of the device document (may be null if unknown) + * @param officeURL URL of the office document (may be null if unknown) + * + * @throws ConvertException If any Convert error occurs. + * @throws IOException If any I/O error occurs. + */ + Document deserialize(String deviceURL, String officeURL) throws + ConvertException, IOException; +} \ No newline at end of file diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/DocumentDeserializerFactory.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/DocumentDeserializerFactory.java new file mode 100644 index 000000000..3d10d03bf --- /dev/null +++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/DocumentDeserializerFactory.java @@ -0,0 +1,51 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +package org.openoffice.xmerge; + +/** + * A {@code DocumentDeserializer} object is used to convert from the + * "Device" {@code Document} format to the "Office" + * {@code Document} format. + * + *

All plug-in implementations of the {@code PluginFactory} interface that + * also support deserialization must also implement this interface.

+ * + * @see PluginFactory + * @see DocumentDeserializer + */ +public interface DocumentDeserializerFactory { + + /** + * The {@code DocumentDeserializer} is used to convert from the + * "Device" {@code Document} format to the "Office" + * {@code Document} format. + * + *

The {@code ConvertData} object is passed along to the created + * {@code DocumentDeserializer} via its constructor. The {@code ConvertData} + * is read and converted when the {@code DocumentDeserializer} object's + * {@code deserialize} method is called.

+ * + * @param cd {@code ConvertData} object that the created + * {@code DocumentDeserializer} object uses as input. + * + * @return A {@code DocumentDeserializer} object. + */ + + DocumentDeserializer createDocumentDeserializer(ConvertData cd); +} \ No newline at end of file diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/DocumentMerger.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/DocumentMerger.java new file mode 100644 index 000000000..3ec19e748 --- /dev/null +++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/DocumentMerger.java @@ -0,0 +1,74 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +package org.openoffice.xmerge; + +/** + * A {@code DocumentMerger} can merge changes from a modified "Device" + * {@code Document} to the assigned original "Office" {@code Document}. + * + *

Merge is useful when an {@code OfficeDocument} is converted to a + * "Device" {@code Document} format, and the "Device" + * {@code Document} version is modified. Those changes can be merged back into + * the original {@code OfficeDocument} with the merger. The merger is capable + * of doing this even if the "Device" format is lossy in + * comparison to the {@code OfficeDocument} format.

+ * + *

The {@code ConverterCapabilities} object is what the DocumentMerger + * utilizes to know how the "Office" {@code Document} tags are + * supported in the "Device" format.

+ * + *

The {@code DocumentMerger} object is created by the + * {@code DocumentMergerFactory} {@link + * org.openoffice.xmerge.DocumentMergerFactory#createDocumentMerger + * createDocumenMerger} method. When it is constructed, the "Original + * Office" {@code Document} object is passed in to be used as input.

+ * + * @see org.openoffice.xmerge.PluginFactory + * @see org.openoffice.xmerge.DocumentMergerFactory + * @see org.openoffice.xmerge.ConverterCapabilities + */ +public interface DocumentMerger { + + /** + * This method will find the changes that had happened in the + * {@code modifiedDoc} {@code Document} object given the designated original + * {@code Document}. + * + *

Note that this process may need the knowledge of the conversion + * process since some conversion process are lossy. Items/Data that are + * lost during the conversion process are not classified as changes. The + * main target of this method is to apply the changes done in + * {@code modifiedDoc} into the assigned original {@code Document} object, + * thus it also will try to preserve items that were originally in the + * original {@code Document}, but never got transferred during the + * {@link org.openoffice.xmerge.DocumentSerializer#serialize serialize} + * process/method call. After this method call, the original + * {@code Document} object will contain the changes applied.

+ * + *

This method may or may not be thread-safe. Also, it is expected that + * the user uses only one instance of a {@code DocumentMerger} object per + * merge process. Create another {@code DocumentMerger} object for another + * merge process.

+ * + * @param modifiedDoc device {@code Document} object. + * + * @throws MergeException If any merge error occurs. + */ + void merge(Document modifiedDoc) throws MergeException; +} diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/DocumentMergerFactory.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/DocumentMergerFactory.java new file mode 100644 index 000000000..e665d662a --- /dev/null +++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/DocumentMergerFactory.java @@ -0,0 +1,50 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +package org.openoffice.xmerge; + +/** + * All plug-in implementations of the {@code PluginFactory} interface that also + * support merging must also implement this interface. + * + *

Merge is useful when an {@code OfficeDocument} is converted to a + * "Device" {@code Document} format, and the "Device" + * {@code Document} version is modified.

+ * + *

Those changes can be merged back into the original {@code OfficeDocument} + * with the merger. The merger is capable of doing this even if the + * "Device" format is lossy in comparison to the {@code OfficeDocument} + * format.

+ * + * @see PluginFactory + * @see DocumentMerger + * @see ConverterCapabilities + */ +public interface DocumentMergerFactory { + + /** + * Create a {@code DocumentMerger} object given a {@code Document} object. + * + * @param doc {@code Document} object that the created + * {@code DocumentMerger} object uses as a base {@code Document} + * for merging changes into. + * + * @return A {@code DocumentMerger} object or {@code null} if none exists. + */ + DocumentMerger createDocumentMerger(Document doc); +} \ No newline at end of file diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/DocumentSerializer.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/DocumentSerializer.java new file mode 100644 index 000000000..87f5da1c2 --- /dev/null +++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/DocumentSerializer.java @@ -0,0 +1,54 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +package org.openoffice.xmerge; + +import java.io.IOException; + +/** + * A {@code DocumentSerializer} represents a converter that converts a + * "Office" {@code Document} to a "Device" {@code Document} + * format. + * + *

The {@code DocumentSerializer} object is created by the + * {@code PluginFactory} {@link + * org.openoffice.xmerge.DocumentSerializerFactory#createDocumentSerializer + * createDocumentSerializer} method. When it is constructed, an + * "Office" {@code Document} object is passed in to be used as input. + *

+ * + * @see org.openoffice.xmerge.PluginFactory + * @see org.openoffice.xmerge.DocumentSerializerFactory + */ +public interface DocumentSerializer { + + /** + * Convert the data passed into the {@code DocumentSerializer} constructor + * into the "Device" {@code Document} format. + * + *

This method may or may not be thread-safe. It is expected that the + * user code does not call this method in more than one thread. And for + * most cases, this method is only done once.

+ * + * @return {@code ConvertData} object to pass back the converted data. + * + * @throws ConvertException If any conversion error occurs. + * @throws IOException If any I/O error occurs. + */ + ConvertData serialize() throws ConvertException, IOException; +} diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/DocumentSerializer2.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/DocumentSerializer2.java new file mode 100644 index 000000000..56a1a1116 --- /dev/null +++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/DocumentSerializer2.java @@ -0,0 +1,63 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +package org.openoffice.xmerge; + +import java.io.IOException; + +/** + * A {@code DocumentSerializer2} represents a converter that converts a + * "Office" {@code Document} to a "Device" {@code Document} + * format. + * + *

The {@code PluginFactory} {@link + * org.openoffice.xmerge.DocumentSerializerFactory#createDocumentSerializer + * createDocumentSerializer} method creates a {@code DocumentSerializer}, which + * may or may not implement {@code DocumentSerializer2}. When it is constructed, + * a "Office" {@code Document} object is passed in to be used as + * input.

+ * + * @see org.openoffice.xmerge.PluginFactory + * @see org.openoffice.xmerge.DocumentSerializerFactory + */ +public interface DocumentSerializer2 extends DocumentSerializer { + + /** + * Convert the data passed into the {@code DocumentSerializer2} constructor + * into the "Device" {@code Document} format. + * + *

The URL's passed may be used to resolve links and to name the output + * device document(s).

+ * + *

This method may or may not be thread-safe. It is expected that the + * user code does not call this method in more than one thread. And for + * most cases, this method is only done once.

+ * + * @return {@code ConvertData} object to pass back the converted data. + * + * @param officeURL URL of the office document (may be null if + * unknown) + * @param deviceURL URL of the device document (may be null if + * unknown) + * + * @throws ConvertException If any conversion error occurs. + * @throws IOException If any I/O error occurs. + */ + ConvertData serialize(String officeURL, String deviceURL) throws + ConvertException, IOException; +} \ No newline at end of file diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/DocumentSerializerFactory.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/DocumentSerializerFactory.java new file mode 100644 index 000000000..e4852ff1e --- /dev/null +++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/DocumentSerializerFactory.java @@ -0,0 +1,50 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +package org.openoffice.xmerge; + +/** + * A {@code DocumentSerializer} object is used to convert from the + * "Office" {@code Document} format to the "Device" + * {@code Document} format. + * + *

All plug-in implementations of the {@code PluginFactory} interface that + * also support serialization must also implement this interface.

+ * + * @see PluginFactory + * @see DocumentSerializer + */ +public interface DocumentSerializerFactory { + + /** + * The {@code DocumentSerializer} is used to convert from the + * "Office" {@code Document} format to the "Device" + * {@code Document} format. + * + *

The {@code ConvertData} object is passed along to the created + * {@code DocumentSerializer} via its constructor. The {@code ConvertData} + * is read and converted when the {@code DocumentSerializer} object's + * {@code serialize} method is called.

+ * + * @param doc {@code Document} object that the created + * {@code DocumentSerializer} object uses as input. + * + * @return A DocumentSerializer object. + */ + DocumentSerializer createDocumentSerializer(Document doc); +} diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/MergeException.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/MergeException.java new file mode 100644 index 000000000..c592bfb65 --- /dev/null +++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/MergeException.java @@ -0,0 +1,34 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +package org.openoffice.xmerge; + +/** + * This {@code Exception} is thrown by merge algorithms. + */ +public class MergeException extends Exception { + + /** + * Exception thrown by merge algorithms. + * + * @param message Message to be included in the {@code Exception}. + */ + public MergeException(String message) { + super(message); + } +} \ No newline at end of file diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/PluginFactory.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/PluginFactory.java new file mode 100644 index 000000000..cb2e07a4a --- /dev/null +++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/PluginFactory.java @@ -0,0 +1,163 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +package org.openoffice.xmerge; + +import org.openoffice.xmerge.util.registry.ConverterInfo; +import java.io.InputStream; +import java.io.IOException; + +/** + * A {@code PluginFactory} encapsulates the conversions from one {@code Document} + * format to another. + * + *

It provides conversions in both directions. Refer to the + * package description + * for its usage.

+ * + *

Conversion from the "Office" {@code Document} format to a + * "Device" {@code Document} format may be lossy, i.e. some + * information may be lost. If a plug-in implements the + * {@code DocumentMergerFactory} interface, then there is the possibility for + * merging the changes done on the "Device" {@code Document} back to + * the original "Office" {@code Document} via the {@code DocumentMerger} + * interface.

+ * + *

Plug-ins that convert from the "Device" {@code Document} format + * to the "Office" {@code Document} format must implement the + * {@code DocumentDeserializerFactory} interface. Plug-ins that convert from + * the "Office" {@code Document} format to the "Device" + * format must implement the {@code DocumentSerializerFactory} interface.

+ * + *

All plug-ins should have an associated Plug-in Configuration XML File which + * describes the capabilities of the plug-in. If the plug-in is bundled in a + * jarfile, then this XML file is also bundled with the jarfile. The data in + * the XML file is managed by the {@code ConverterInfo} object. The + * {@code ConverterInfoMgr} manages a registry of all {@code ConverterInfo} + * objects. For more information about this XML file, refer to + * org.openoffice.xmerge.util.registry. + *

+ * + * @see Document + * @see DocumentSerializer + * @see DocumentSerializerFactory + * @see DocumentDeserializer + * @see DocumentDeserializerFactory + * @see DocumentMerger + * @see DocumentMergerFactory + * @see ConverterInfo + * @see org.openoffice.xmerge.util.registry.ConverterInfoMgr + */ + +public abstract class PluginFactory { + + /** + * Cached {@code ConvertInfo} object. + */ + private final ConverterInfo ciCache; + + /** + * Constructor that caches the {@code ConvertInfo} that corresponds to the + * registry information for this plug-in. + * + * @param ci {@code ConvertInfo} object. + */ + public PluginFactory(ConverterInfo ci) { + ciCache=ci; + } + + /** + * Returns the {@code ConvertInfo} that corresponds to this plug-in. + * + * @return The {@code ConvertInfo} that corresponds to this plug-in. + */ + public ConverterInfo getConverterInfo () { + return ciCache; + } + + /** + * Create a {@code Document} object that corresponds to the Office data + * passed in via the {@code InputStream} object. + * + *

This abstract method must be implemented for each plug-in.

+ * + *

This method will read from the given {@code InputStream} object. The + * returned {@code Document} object will contain the necessary data for the + * other objects created by the {@code PluginFactory} to process, like a + * {@code DocumentSerializer} object and a {@code DocumentMerger} object.

+ * + * @param name The {@code Document} name. + * @param is {@code InputStream} object corresponding to the + * {@code Document}. + * + * @return A {@code Document} object representing the particular + * {@code Document} format for the {@code PluginFactory}. + * + * @throws IOException If any I/O error occurs. + */ + public abstract Document createOfficeDocument(String name, InputStream is) + throws IOException; + + /** + * Create a {@code Document} object that corresponds to the Office data + * passed in via the {@code InputStream} object. + * + *

This abstract method must be implemented for each plug-in.

+ * + *

This method will read from the given {@code InputStream} object. The + * returned {@code Document} object will contain the necessary data for the + * other objects created by the {@code PluginFactory} to process, like a + * {@code DocumentSerializer} object and a {@code DocumentMerger} object.

+ * + * @param name The {@code Document} name. + * @param is {@code InputStream} object corresponding to the + * {@code Document}. + * @param isZip {@code boolean} to show that the created office document + * is to be zipped. + * + * @return A {@code Document} object representing the particular + * {@code Document} format for the {@code PluginFactory}. + * + * @throws IOException If any I/O error occurs. + */ + public abstract Document createOfficeDocument(String name, InputStream is, + boolean isZip) throws IOException; + + /** + * Create a {@code Document} object that corresponds to the device data + * passed in via the {@code InputStream} object. + * + *

This abstract method must be implemented for each plug-in.

+ * + *

This method will read from the given {@code InputStream} object. The + * returned {@code Document} object will contain the necessary data for the + * other objects created by the {@code PluginFactory} to process, like a + * {@code DocumentSerializer} object and a {@code DocumentMerger} object.

+ * + * @param name The {@code Document} name. + * @param is {@code InputStream} object corresponding to the + * {@code Document}. + * + * @return A {@code Document} object representing the particular + * {@code Document} format for the {@code PluginFactory}. + * + * @throws IOException If any I/O error occurs. + */ + public abstract Document createDeviceDocument(String name, InputStream is) + throws IOException; +} \ No newline at end of file diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/Version.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/Version.java new file mode 100644 index 000000000..02d16eedf --- /dev/null +++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/Version.java @@ -0,0 +1,68 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +package org.openoffice.xmerge; + +/** + * This class provides a quick utility to check the version of the jar file. + * + *

It has a main method that prints out the version info. It also provides + * two static methods for runtime classes to query.

+ */ +public final class Version { + + private static final Version version = new Version(); + + private static final Package pkg = version.getClass().getPackage(); + + /** + * Private constructor to provide a singleton instance. + */ + private Version() { + } + + /** + * Returns specification version. + * + * @return The specification version. + */ + public static String getSpecificationVersion() { + return pkg.getSpecificationVersion(); + } + + /** + * Returns implementation version. + * + * @return The implementation version. + */ + public static String getImplementationVersion() { + return pkg.getImplementationVersion(); + } + + /** + * Main method for printing out version info. + * + * @param args Array of arguments, not used. + */ + public static void main(String args[]) { + System.out.println("Specification-Title: " + pkg.getSpecificationTitle()); + System.out.println("Specification-Vendor: " + pkg.getSpecificationVendor()); + System.out.println("Specification-Version: " + pkg.getSpecificationVersion()); + System.out.println("Implementation-Version: " + pkg.getImplementationVersion()); + } +} \ No newline at end of file diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/dom/DOMDocument.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/dom/DOMDocument.java new file mode 100644 index 000000000..fc2139838 --- /dev/null +++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/dom/DOMDocument.java @@ -0,0 +1,312 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +package org.openoffice.xmerge.converter.dom; + +import java.io.InputStream; +import java.io.OutputStream; +import java.io.StringWriter; +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.Transformer; +import javax.xml.transform.stream.StreamResult; +import javax.xml.transform.dom.DOMSource; + +import org.w3c.dom.Node; +import org.w3c.dom.Document; +import org.xml.sax.SAXException; +import org.openoffice.xmerge.util.Debug; + +/** + * An implementation of {@code Document} for StarOffice documents. + */ +public class DOMDocument + implements org.openoffice.xmerge.Document { + + /** Factory for {@code DocumentBuilder} objects. */ + private static DocumentBuilderFactory factory = + DocumentBuilderFactory.newInstance(); + + /** DOM {@code Document} of content.xml. */ + private Document contentDoc = null; + + private String documentName = null; + private String fileName = null; + private String fileExt = null; + + /** + * Default constructor. + * + * @param name {@code Document} name. + * @param ext {@code Document} extension. + */ + public DOMDocument(String name,String ext) { + this(name,ext,true, false); + } + + /** + * Returns the file extension of the {@code Document} represented. + * + * @return file extension of the {@code Document}. + */ + private String getFileExtension() { + return fileExt; + } + + /** + * Constructor with arguments to set {@code namespaceAware} and + * {@code validating} flags. + * + * @param name {@code Document} name (may or may not contain + * extension). + * @param ext {@code Document} extension. + * @param namespaceAware Value for {@code namespaceAware} flag. + * @param validating Value for {@code validating} flag. + */ + private DOMDocument(String name, String ext,boolean namespaceAware, + boolean validating) { + + factory.setValidating(validating); + factory.setNamespaceAware(namespaceAware); + this.fileExt = ext; + this.documentName = trimDocumentName(name); + this.fileName = documentName + getFileExtension(); + } + + /** + * Removes the file extension from the {@code Document} name. + * + * @param name Full {@code Document} name with extension. + * + * @return Name of {@code Document} without the extension. + */ + private String trimDocumentName(String name) { + String temp = name.toLowerCase(); + String ext = getFileExtension(); + + if (temp.endsWith(ext)) { + // strip the extension + int nlen = name.length(); + int endIndex = nlen - ext.length(); + name = name.substring(0,endIndex); + } + + return name; + } + + /** + * Return a DOM {@code Document} object of the document content file. + * + *

Note that a content DOM is not created when the constructor is called. + * So, either the {@code read} method or the {@code initContentDOM} method + * will need to be called ahead on this object before calling this method. + *

+ * + * @return DOM {@code Document} object. + */ + public Document getContentDOM() { + + return contentDoc; + } + + /** + * Sets the Content of the {@code Document} to the contents of the supplied + * {@code Node} list. + * + * @param newDom DOM {@code Document} object. + */ + public void setContentDOM( Node newDom) { + contentDoc=(Document)newDom; + } + + /** + * Return the name of the {@code Document}. + * + * @return The name of {@code Document}. + */ + public String getName() { + + return documentName; + } + + /** + * Return the file name of the {@code Document}, possibly with the standard + * extension. + * + * @return The file name of {@code Document}. + */ + public String getFileName() { + + return fileName; + } + + /** + * Read the Office {@code Document} from the specified {@code InputStream}. + * + * @param is Office document {@code InputStream}. + * + * @throws IOException If any I/O error occurs. + */ + public void read(InputStream is) throws IOException { + Debug.log(Debug.INFO, "reading file"); + try { + DocumentBuilder builder = factory.newDocumentBuilder(); + contentDoc = builder.parse(is); + } catch (ParserConfigurationException ex) { + System.out.println("Error:"+ ex); + } catch (SAXException ex) { + System.out.println("Error:"+ ex); + } + } + + /** + * Write out content to the supplied {@code OutputStream}. + * + * @param os XML {@code OutputStream}. + * + * @throws IOException If any I/O error occurs. + */ + public void write(OutputStream os) throws IOException { + + // set bytes for writing to output stream + byte contentBytes[] = docToBytes(contentDoc); + + os.write(contentBytes); + } + + /** + * Write out a {@code org.w3c.dom.Document} object into a {@code byte} array. + * + *

TODO: remove dependency on {@code com.sun.xml.tree.XmlDocument} package! + *

+ * + * @param doc DOM {@code Document} object. + * + * @return {@code byte} array of DOM {@code Document} object. + * + * @throws IOException If any I/O error occurs. + */ + private byte[] docToBytes(Document doc) + throws IOException { + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + java.lang.reflect.Constructor con; + java.lang.reflect.Method meth; + + String domImpl = doc.getClass().getName(); + + System.err.println("type b " + domImpl); + + /* + * We may have multiple XML parsers in the Classpath. + * Depending on which one is first, the actual type of + * doc may vary. Need a way to find out which API is being + * used and use an appropriate serialization method. + */ + try { + // First of all try for JAXP 1.0 + if (domImpl.equals("com.sun.xml.tree.XmlDocument")) { + System.out.println("Using JAXP"); + Class jaxpDoc = Class.forName("com.sun.xml.tree.XmlDocument"); + + // The method is in the XMLDocument class itself, not a helper + meth = jaxpDoc.getMethod("write", + new Class[]{Class.forName("java.io.OutputStream")}); + + meth.invoke(doc, new Object[]{baos}); + } else if (domImpl.equals("org.apache.crimson.tree.XmlDocument")) { + System.out.println("Using Crimson"); + Class crimsonDoc = Class.forName("org.apache.crimson.tree.XmlDocument"); + // The method is in the XMLDocument class itself, not a helper + meth = crimsonDoc.getMethod("write", + new Class[]{Class.forName("java.io.OutputStream")}); + + meth.invoke(doc, new Object[]{baos}); + } else if (domImpl.equals("org.apache.xerces.dom.DocumentImpl") + || domImpl.equals("org.apache.xerces.dom.DeferredDocumentImpl")) { + System.out.println("Using Xerces"); + // Try for Xerces + Class xercesSer + = Class.forName("org.apache.xml.serialize.XMLSerializer"); + + // Get the OutputStream constructor + // May want to use the OutputFormat parameter at some stage too + con = xercesSer.getConstructor(new Class[]{Class.forName("java.io.OutputStream"), + Class.forName("org.apache.xml.serialize.OutputFormat")}); + + // Get the serialize method + meth = xercesSer.getMethod("serialize", + new Class[]{Class.forName("org.w3c.dom.Document")}); + + // Get an instance + Object serializer = con.newInstance(new Object[]{baos, null}); + + // Now call serialize to write the document + meth.invoke(serializer, new Object[]{doc}); + } else if (domImpl.equals("gnu.xml.dom.DomDocument")) { + System.out.println("Using GNU"); + + Class gnuSer = Class.forName("gnu.xml.dom.ls.DomLSSerializer"); + + // Get the serialize method + meth = gnuSer.getMethod("serialize", + new Class[]{Class.forName("org.w3c.dom.Node"), + Class.forName("java.io.OutputStream")}); + + // Get an instance + Object serializer = gnuSer.newInstance(); + + // Now call serialize to write the document + meth.invoke(serializer, new Object[]{doc, baos}); + } else { + // We don't have another parser + try { + DOMSource domSource = new DOMSource(doc); + StringWriter writer = new StringWriter(); + StreamResult result = new StreamResult(writer); + TransformerFactory tf = TransformerFactory.newInstance(); + Transformer transformer = tf.newTransformer(); + transformer.transform(domSource, result); + return writer.toString().getBytes(); + } catch (Exception e) { + // We don't have another parser + IOException ex2 = new IOException("No appropriate API (JAXP/Xerces) to serialize XML document: " + domImpl); + ex2.initCause(e); + throw ex2; + } + } + } + catch (Exception e) { + // We may get some other errors, but the bottom line is that + // the steps being executed no longer work + IOException newEx = new IOException(e.getMessage()); + newEx.initCause(e); + throw newEx; + } + + byte bytes[] = baos.toByteArray(); + + return bytes; + } +} diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/dom/package-info.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/dom/package-info.java new file mode 100644 index 000000000..79d5f797f --- /dev/null +++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/dom/package-info.java @@ -0,0 +1,40 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +/** + * Provides classes for converting basic document types to/from a + * {@code DOMDocument} object, which can be used by the framework. + * + *

This package provides classes that handle the writing of data to an + * {@code OutputStream} object for the {@link + * org.openoffice.xmerge.DocumentSerializer DocumentSerializer} interface for; + * as well as the reading of data from an {@code InputStream} object for the + * framework's {@link org.openoffice.xmerge.DocumentDeserializer + * DocumentDeserializer} interface. Both these framework interfaces are simply + * converters from server-side documents to device specific documents and + * vice-versa.

+ * + * + * + *

Important Note

+ * + *

Methods in these classes are not thread safe for performance reasons. + * Users of these classes will have to make sure that the usage of these classes + * are done in a proper manner. Possibly more on this later.

+ */ +package org.openoffice.xmerge.converter.dom; diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm/PalmDB.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm/PalmDB.java new file mode 100644 index 000000000..2f6ca0114 --- /dev/null +++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm/PalmDB.java @@ -0,0 +1,360 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +package org.openoffice.xmerge.converter.palm; + +import java.io.UnsupportedEncodingException; + +/** + * This class contains data for a single Palm database for use during a + * conversion process. + * + *

It contains zero or more {@code Record} objects stored in an array. The + * index of the {@code Record} object in the array is the {@code Record} id or + * number for that specific {@code Record} object. Note that this class does + * not check for maximum number of Records allowable in an actual PDB.

+ * + *

This class also contains the PDB name associated with the Palm database + * it represents. A PDB name consists of 32 bytes of a certain encoding + * (extended ASCII in this case).

+ * + *

The non default constructors take in a name parameter which may not be + * the exact PDB name to be used. The name parameter in {@code String} or + * {@code byte} array are converted to an exact {@code NAME_LENGTH} byte array. + * If the length of the name is less than {@code NAME_LENGTH}, it is padded + * with {@code '\0'} characters. If it is more, it gets truncated. The last + * character in the resulting byte array is always a {@code '\0'} character. + * The resulting byte array is stored in {@code bName}, and a corresponding + * {@code String} object {@code sName} that contains characters without the + * {@code '\0'} characters.

+ * + *

The {@code write} method is called within the {@link + * org.openoffice.xmerge.converter.palm.PalmDocument#write + * PalmDocument.write} method for writing out its data to the + * {@code OutputStream} object.

+ * + *

The {@code read} method is called within the {@link + * org.openoffice.xmerge.converter.palm.PalmDocument#read PalmDocument.read} + * method for reading in its data from the {@code InputStream} object.

+ * + * @see PalmDocument + * @see Record + */ + +public final class PalmDB { + + /** Number of bytes for the name field in the PDB. */ + public static final int NAME_LENGTH = 32; + + /** List of {@code Record} objects. */ + private Record[] records; + + /** PDB name in bytes. */ + private byte[] bName = null; + + /** PDB name in String. */ + private String sName = null; + + /** Creator ID. */ + private int creatorID = 0; + + /** Type ID */ + private int typeID = 0; + + /** + * PDB version. Palm UInt16. + * It is treated as a number here, since there is no unsigned 16 bit in Java, + * {@code int} is used instead, but only 2 bytes are written out or read in. + */ + private int version = 0; + + /** + * PDB attribute - flags for the database. + * Palm UInt16. Unsignedness should be irrelevant. + */ + private short attribute = 0; + + /** + * Default constructor. + * + * @param creatorID The PDB Creator ID. + * @param typeID The PDB Type ID. + * @param version The PDB header version. + * @param attribute The PDB header attribute. + */ + public PalmDB(int creatorID, int typeID, int version, short attribute) { + records = new Record[0]; + setAttributes(creatorID, typeID, version, attribute); + } + + /** + * Constructor to create {@code PalmDB} object with {@code Record} objects. + * + *

{@code recs.length} can be zero for an empty PDB.

+ * + * @param name Suggested PDB name in a {@code String}. + * @param creatorID The PDB Creator ID. + * @param typeID The PDB Type ID. + * @param version The PDB header version. + * @param attribute The PDB header attribute. + * @param recs Array of {@code Record} objects. + * + * @throws UnsupportedEncodingException If {@code name} is not properly + * encoded. + * @throws NullPointerException If {@code recs} is {@code null}. + */ + public PalmDB(String name, int creatorID, int typeID, int version, + short attribute, Record[] recs) + throws UnsupportedEncodingException { + + this(name.getBytes(PdbUtil.ENCODING), creatorID, typeID, version, + attribute, recs); + } + + /** + * Constructor to create object with {@code Record} objects. + * + *

{@code recs.length} can be zero for an empty PDB.

+ * + * @param name Suggested PDB name in a {@code byte} array. + * @param creatorID The PDB Creator ID. + * @param typeID The PDB Type ID. + * @param version The PDB header version. + * @param attribute The PDB header attribute. + * @param recs Array of {@code Record} objects. + * + * @throws UnsupportedEncodingException If {@code name} is not properly + * encoded. + * @throws NullPointerException If {@code recs} is {@code null}. + */ + public PalmDB(byte[] name, int creatorID, int typeID, int version, + short attribute, Record[] recs) + throws UnsupportedEncodingException { + + store(name); + + records = new Record[recs.length]; + System.arraycopy(recs, 0, records, 0, recs.length); + setAttributes(creatorID, typeID, version, attribute); + } + + /** + * Set the attributes for the {@code PalmDB} object. + * + * @param creatorID The PDB Creator ID. + * @param typeID The PDB Type ID. + * @param version The PDB header version. + * @param attribute The PDB header attribute. + */ + private void setAttributes (int creatorID, int typeID, int version, + short attribute) { + this.creatorID = creatorID; + this.typeID = typeID; + this.version = version; + this.attribute = attribute; + } + + /** + * This private method is mainly used by the constructors above. + * + *

to store bytes into name and also create a {@code String} + * representation, and also by the {@code read} method.

+ * + *

TODO: Note that this method assumes that the {@code byte} array + * parameter contains one character per {@code byte}, else it would + * truncate improperly.

+ * + * @param bytes PDB name in {@code byte<} array. + * + * @throws UnsupportedEncodingException If ENCODING is not supported. + */ + private void store(byte[] bytes) throws UnsupportedEncodingException { + + // note that this will initialize all bytes in name to 0. + bName = new byte[NAME_LENGTH]; + + // determine minimum length to copy over from bytes to bName. + // Note that the last byte in bName has to be '\0'. + + int lastIndex = NAME_LENGTH - 1; + int len = (bytes.length < lastIndex)? bytes.length: lastIndex; + + int i; + for (i = 0; i < len; i++) { + + if (bytes[i] == 0) { + break; + } + + bName[i] = bytes[i]; + } + + // set sName, no need to include the '\0' character. + sName = new String(bName, 0, i, PdbUtil.ENCODING); + } + + /** + * Returns creator ID. + * + * @return The creator ID. + */ + public int getCreatorID() { + return creatorID; + } + + /** + * Returns type ID. + * + * @return The type ID. + */ + public int getTypeID() { + return typeID; + } + + /** + * Returns attribute flag. + * + * @return The attribute flag. + */ + public short getAttribute() { + return attribute; + } + + /** + * Returns version. + * + * @return The version. + */ + public int getVersion() { + return version; + } + + /** + * Return the number of Records contained in this PDB {@code PalmDB} object. + * + * @return Number of {@code Record} objects. + */ + public int getRecordCount() { + return records.length; + } + + /** + * Return the specific {@code Record} object associated with the + * {@code Record} number. + * + * @param index {@code Record} index number. + * + * @return The {@code Record} object in the specified index + * + * @throws ArrayIndexOutOfBoundsException If index is out of bounds. + */ + public Record getRecord(int index) { + return records[index]; + } + + /** + * Return the list of {@code Record} objects. + * + * @return The array of {@code Record} objects. + */ + public Record[] getRecords() { + return records; + } + + /** + * Return the PDB name associated with this object. + * + * @return The PDB name. + */ + public String getPDBNameString() { + return sName; + } + + /** + * Return the PDB name associated with this object in {@code byte} array of + * exact length of 32 bytes. + * + * @return The PDB name in {@code byte} array of length 32. + */ + public byte[] getPDBNameBytes() { + return bName; + } + + /** + * Override equals method of {@code Object}. + * + *

Two {@code PalmDB} objects are equal if they contain the same + * information, i.e. PDB name and Records.

+ * + *

This is used primarily for testing purposes only for now.

+ * + * @param obj A {@code PalmDB} {@code Object} to compare. + * + * @return {@code true} if {@code obj} is equal to this, otherwise + * {@code false}. + */ + @Override + public boolean equals(Object obj) { + + boolean bool = false; + + if (obj instanceof PalmDB) { + + PalmDB pdb = (PalmDB) obj; + + checkLabel: { + + // compare sName + if (!sName.equals(pdb.sName)) { + break checkLabel; + } + + // compare bName + if (bName.length != pdb.bName.length) { + break checkLabel; + } + for (int i = 0; i < bName.length; i++) { + if (bName[i] != pdb.bName[i]) { + break checkLabel; + } + } + + // compare each Record + if (records.length != pdb.records.length) { + break checkLabel; + } + for (int i = 0; i < records.length; i++) { + if (!records[i].equals(pdb.records[i])) { + break checkLabel; + } + } + + // all checks done + bool = true; + } + } + + return bool; + } + + @Override + public int hashCode() { + return 0; + } + +} diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm/PalmDocument.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm/PalmDocument.java new file mode 100644 index 000000000..b7fb67bcf --- /dev/null +++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm/PalmDocument.java @@ -0,0 +1,148 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +package org.openoffice.xmerge.converter.palm; + +import java.io.IOException; +import java.io.InputStream; +import java.io.ByteArrayOutputStream; + +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; + +import org.openoffice.xmerge.Document; + +/** + * A {@code PalmDocument} is palm implementation of the {@code Document} + * interface. + * + *

This implementation allows the Palm device format to be read via an + * {@code InputStream} and written via an {@code OutputStream}.

+ */ +public class PalmDocument + implements Document { + + /** The internal representation of a pdb. */ + private PalmDB pdb; + + /** The file name. */ + private String fileName; + + /** + * Constructor to create a {@code PalmDocument} from an {@code InputStream}. + * + * @param is {@code InputStream} containing a PDB. + * + * @throws IOException If any I/O error occurs. + */ + public PalmDocument(InputStream is) throws IOException { + read(is); + } + + /** + * Constructor to create a {@code PalmDocument} with {@code Record} objects. + * + *

{@code recs.length} can be zero for an empty PDB.

+ * + * @param name Suggested PDB name in {@code String}. + * @param creatorID The PDB Creator ID. + * @param typeID The PDB Type ID. + * @param version The PDB header version. + * @param attribute The PDB header attribute. + * @param recs Array of {@code Record} objects. + * + * @throws NullPointerException If {@code recs} is {@code null}. + */ + public PalmDocument(String name, int creatorID, int typeID, int version, + short attribute, Record[] recs) + throws UnsupportedEncodingException { + pdb = new PalmDB(name, creatorID, typeID, version, attribute, recs); + fileName = pdb.getPDBNameString(); + } + + /** + * Reads in a file from the {@code InputStream}. + * + * @param is {@code InputStream} to read in its content. + * + * @throws IOException If any I/O error occurs. + */ + public void read(InputStream is) throws IOException { + PdbDecoder decoder = new PdbDecoder(); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + byte[] buf = new byte[4096]; + int n; + while ((n = is.read(buf)) > 0) { + baos.write(buf, 0, n); + } + byte[] bytearr = baos.toByteArray(); + pdb = decoder.parse(bytearr); + fileName = pdb.getPDBNameString(); + } + + /** + * Writes the {@code PalmDocument} to an {@code OutputStream}. + * + * @param os The {@code OutputStream} to write the content. + * + * @throws IOException If any I/O error occurs. + */ + public void write(OutputStream os) throws IOException { + PdbEncoder encoder = new PdbEncoder(pdb); + encoder.write(os); + } + + /** + * Returns the {@code PalmDB} contained in this object. + * + * @return The {@code PalmDB}. + */ + public PalmDB getPdb() { + return pdb; + } + + /** + * Sets the {@code PalmDocument} to a new {@code PalmDB} value. + * + * @param pdb The new {@code PalmDB} value. + */ + public void setPdb(PalmDB pdb) { + this.pdb = pdb; + + String name = pdb.getPDBNameString(); + fileName = name; + } + + /** + * Returns the name of the file. + * + * @return The name of the file represented in the {@code PalmDocument}. + */ + public String getFileName() { + return fileName + ".pdb"; + } + + /** + * Returns the {@code Document} name. + * + * @return The {@code Document} name. + */ + public String getName() { + return fileName; + } +} \ No newline at end of file diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm/PdbDecoder.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm/PdbDecoder.java new file mode 100644 index 000000000..b3fbd4df0 --- /dev/null +++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm/PdbDecoder.java @@ -0,0 +1,128 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +package org.openoffice.xmerge.converter.palm; + +import java.io.IOException; +import java.io.ByteArrayInputStream; +import java.io.DataInputStream; + +/** + * Provides functionality to decode a PDB formatted file into a {@code PalmDB} + * object given an {@code InputStream}. + * + *

This class is only used by the {@code PalmDB} object.

+ * + *

Sample usage:

+ *
{@code PdbDecoder decoder = new PdbDecoder("sample.pdb");
+ * PalmDB palmDB = decoder.parse();}
+ * + *

This decoder has the following assumptions on the PDB file:

+ *
    + *
  1. There is only one RecordList section in the PDB.
  2. + *
  3. The {@code Record} indices in the RecordList are sorted in order, i.e. + * the first {@code Record} index refers to {@code Record} 0, and so + * forth.
  4. + *
  5. The raw {@code Record} in the {@code Record} section are sorted as + * well in order, i.e. first {@code Record} comes ahead of second + * {@code Record}, etc.
  6. + *
+ * + *

Other decoders assume these as well.

+ * + * @see PalmDB + * @see Record + */ +public final class PdbDecoder { + + /** + * This method decodes a PDB file into a {@code PalmDB} object. + * + *

First, the header data is read using the {@code PdbHeader.read} + * method. Next, the RecordList section is read and the {@code Record} + * offsets are stored for use when parsing the Records. Based on these + * offsets, the bytes corresponding to each {@code Record} are read and + * each is stored in a {@code Record} object. Lastly, the data is used + * to create a {@code PalmDB} object.

+ * + * @param b {@code byte[]} containing PDB. + * + * @throws IOException If I/O error occurs. + */ + public PalmDB parse(byte[] b) throws IOException { + + ByteArrayInputStream bais = new ByteArrayInputStream(b); + DataInputStream dis = new DataInputStream(bais); + + // read the PDB header + PdbHeader header = new PdbHeader(); + header.read(dis); + + Record recArray[] = new Record[header.numRecords]; + if (header.numRecords != 0) { + + // read in the record indices + offsets + int recOffset[] = new int[header.numRecords]; + byte recAttrs[] = new byte[header.numRecords]; + + for (int i = 0; i < header.numRecords; i++) { + + recOffset[i] = dis.readInt(); + + // read in attributes (1 byte) + unique id (3 bytes) + // take away the unique id, store the attributes + int attr = dis.readInt(); + recAttrs[i] = (byte) (attr >>> 24); + } + + // read the records + int lastIndex = header.numRecords - 1; + + for (int i = 0; i < lastIndex; i++) { + + //dis.seek(recOffset[i]); + dis.reset(); + int nBytesToSkip = recOffset[i]; + while (nBytesToSkip > 0) { + nBytesToSkip -= dis.skip(nBytesToSkip); + } + int len = recOffset[i+1] - recOffset[i]; + byte[] bytes = new byte[len]; + dis.readFully(bytes); + recArray[i] = new Record(bytes, recAttrs[i]); + } + + // last record + dis.reset(); + int len = dis.available() - recOffset[lastIndex]; + int nBytesToSkip = recOffset[lastIndex]; + while (nBytesToSkip > 0) { + nBytesToSkip -= dis.skip(nBytesToSkip); + } + byte[] bytes = new byte[len]; + dis.readFully(bytes); + recArray[lastIndex] = new Record(bytes, recAttrs[lastIndex]); + } + + // create PalmDB and return it + PalmDB pdb = new PalmDB(header.pdbName, header.creatorID, + header.typeID, header.version, header.attribute, recArray); + + return pdb; + } +} diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm/PdbEncoder.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm/PdbEncoder.java new file mode 100644 index 000000000..ba32aed20 --- /dev/null +++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm/PdbEncoder.java @@ -0,0 +1,168 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +package org.openoffice.xmerge.converter.palm; + +import java.io.OutputStream; +import java.io.BufferedOutputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.Date; + +/** + * Provides functionality to encode a {@code PalmDB} object into a PDB + * formatted file given a file {@code OutputStream}. + * + *

This class is only used by the {@code PalmDB} object.

+ * + *

One needs to create one {@code PdbEncoder} object per {@code PalmDB} + * object to be encoded. This class keeps the PDB header data and functionality + * in the {@code PdbHeader} class.

+ * + *

Sample usage:

+ *
{@code PdbEncoder encoder = new PdbEncoder(palmDB, "STRW", "data");
+ * encoder.write(new FileOutputStream("sample.pdb"));}
+ * + * @see PalmDB + * @see Record + */ +public final class PdbEncoder { + + /** PDB header. */ + private final PdbHeader header; + + /** the PalmDB object. */ + private final PalmDB db; + + /** The pattern for unique_id=0x00BABE(start). */ + private static final int START_UNIQUE_ID = 0x00BABE; + + + /** + * Constructor. + * + * @param db The {@code PalmDB} to be encoded. + */ + public PdbEncoder(PalmDB db) { + + header = new PdbHeader(); + header.version = db.getVersion(); + + header.attribute = db.getAttribute(); + + this.db = db; + + header.pdbName = db.getPDBNameBytes(); + header.creatorID = db.getCreatorID(); + header.typeID = db.getTypeID(); + + // set the following dates to current date + Date date = new Date(); + header.creationDate = (date.getTime() / 1000) + PdbUtil.TIME_DIFF; + header.modificationDate = header.creationDate; + + header.numRecords = db.getRecordCount(); + } + + /** + * Write out a PDB into the given {@code OutputStream}. + * + *

First, write out the header data by using the {@code PdbHeader.write} + * method. Next, calculate the RecordList section and write it out. Lastly, + * write out the bytes corresponding to each {@code Record}.

+ * + *

The RecordList section contains a list of {@code Record} index info, + * where each {@code Record} index info contains:

+ * + *
    + *
  • 4 bytes local offset of the {@code Record} from the top of the + * PDB.
  • + *
  • 1 byte of {@code Record} attribute.
  • + *
  • 3 bytes unique {@code Record} ID.
  • + *
+ * + *

There should be a total of {@code header.numRecords} of {@code Record} + * index info.

+ * + * @param os {@code OutputStream} to write out PDB. + * + * @throws IOException If I/O error occurs. + */ + public void write(OutputStream os) throws IOException { + + BufferedOutputStream bos = new BufferedOutputStream(os); + DataOutputStream dos = new DataOutputStream(bos); + + // write out the PDB header + header.write(dos); + + if (header.numRecords > 0) { + + // compute for recOffset[] + int recOffset[] = new int[header.numRecords]; + byte recAttr[] = new byte[header.numRecords]; + + // first recOffset will be at PdbUtil.HEADER_SIZE + all the + // record indices (@ 8 bytes each) + recOffset[0] = PdbUtil.HEADER_SIZE + (header.numRecords * 8); + + int lastIndex = header.numRecords - 1; + for (int i = 0; i < lastIndex; i++) { + + Record rec = db.getRecord(i); + int size = rec.getSize(); + recAttr[i] = rec.getAttributes(); + + recOffset[i+1] = recOffset[i] + size; + } + + // grab the last record's attribute. + Record lastRec = db.getRecord(lastIndex); + recAttr[lastIndex] = lastRec.getAttributes(); + + int uid = START_UNIQUE_ID; + for (int i = 0; i < header.numRecords; i++) { + + // write out each record offset + dos.writeInt(recOffset[i]); + + // write out record attribute (recAttr) and + // unique ID (uid) in 4 bytes (int) chunk. + // unique ID's have to be unique, thus + // increment each time. + int attr = (recAttr[i] << 24 ); + attr |= uid; + dos.writeInt(attr); + uid++; + } + + // write out the raw records + for (int i = 0; i < header.numRecords; i++) { + + Record rec = db.getRecord(i); + byte bytes[] = rec.getBytes(); + dos.write(bytes); + } + } else { + // placeholder bytes if there are no records in the list. + dos.writeShort(0); + } + + dos.flush(); + } +} \ No newline at end of file diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm/PdbHeader.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm/PdbHeader.java new file mode 100644 index 000000000..280c6e3db --- /dev/null +++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm/PdbHeader.java @@ -0,0 +1,145 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +package org.openoffice.xmerge.converter.palm; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; + +/** + * Class used only internally by {@code PdbEncoder} and {@code PdbDecoder} to + * store, read and write a PDB header. + * + *

Note that fields are intended to be accessible only at the package + * level.

+ * + *

Some of the fields are internally represented using a larger type since + * Java does not have unsigned types. Some are not since they are not relevant + * for now. The {@code read} and {@code write} methods should handle them + * properly.

+ * + * @see PalmDB + * @see Record + */ +final class PdbHeader { + + /** Name of the database. 32 bytes. */ + byte[] pdbName = null; + + /** + * Flags for the database. Palm UInt16. Unsignedness should be irrelevant. + */ + short attribute = 0; + + /** Application-specific version for the database. Palm UInt16. */ + int version = 0; + + /** Date created. Palm UInt32. */ + long creationDate = 0; + + /** Date last modified. Palm UInt32. */ + long modificationDate = 0; + + /** Date last backup. Palm UInt32. */ + private long lastBackupDate = 0; + + /** + * Incremented every time a {@code Record} is added, deleted or modified. + * Palm UInt32. + */ + private long modificationNumber = 0; + + /** Optional field. Palm UInt32. Unsignedness should be irrelevant. */ + private int appInfoID = 0; + + /** Optional field. Palm UInt32. Unsignedness should be irrelevant. */ + private int sortInfoID = 0; + + /** Database type ID. Palm UInt32. Unsignedness should be irrelevant. */ + int typeID = 0; + + /** Database creator ID. Palm UInt32. Unsignedness should be irrelevant. */ + int creatorID = 0; + + /** ??? */ + private int uniqueIDSeed = 0; + + /** See numRecords. 4 bytes. */ + private int nextRecordListID = 0; + + /** + * Number of Records stored in the database header. + * If all the {@code Record} entries cannot fit in the header, then + * {@code nextRecordList} has the local ID of a RecordList that contains + * the next set of {@code Record}. + * Palm UInt16. + */ + int numRecords = 0; + + /** + * Read in the data for the PDB header. + * + *

Need to preserve the unsigned value for some of the fields.

+ * + * @param in A {@code DataInput} object. + * + * @throws IOException If any I/O error occurs. + */ + public void read(DataInput in) throws IOException { + pdbName = new byte[PalmDB.NAME_LENGTH]; + in.readFully(pdbName); + attribute = in.readShort(); + version = in.readUnsignedShort(); + creationDate = in.readInt() & 0xffffffffL; + modificationDate = in.readInt() & 0xffffffffL; + lastBackupDate = in.readInt() & 0xffffffffL; + modificationNumber = in.readInt() & 0xffffffffL; + appInfoID = in.readInt(); + sortInfoID = in.readInt(); + creatorID = in.readInt(); + typeID = in.readInt(); + uniqueIDSeed = in.readInt(); + nextRecordListID = in.readInt(); + numRecords = in.readUnsignedShort(); + } + + /** + * Write out PDB header data. + * + * @param out A {@code DataOutput} object. + * + * @throws IOException If any I/O error occurs. + */ + public void write(DataOutput out) throws IOException { + out.write(pdbName); + out.writeShort(attribute); + out.writeShort(version); + out.writeInt((int) creationDate); + out.writeInt((int) modificationDate); + out.writeInt((int) lastBackupDate); + out.writeInt((int) modificationNumber); + out.writeInt(appInfoID); + out.writeInt(sortInfoID); + out.writeInt(typeID); + out.writeInt(creatorID); + out.writeInt(uniqueIDSeed); + out.writeInt(nextRecordListID); + out.writeShort(numRecords); + } +} \ No newline at end of file diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm/PdbUtil.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm/PdbUtil.java new file mode 100644 index 000000000..829c1c733 --- /dev/null +++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm/PdbUtil.java @@ -0,0 +1,35 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +package org.openoffice.xmerge.converter.palm; + +/** + * Contains common static methods and constants for use within the package. + */ +public final class PdbUtil { + + /** Difference in seconds from Jan 01, 1904 to Jan 01, 1970. */ + static final long TIME_DIFF = 2082844800; + + /** Encoding scheme used. */ + static final String ENCODING = "8859_1"; + + /** Size of a PDB header in bytes. */ + static final int HEADER_SIZE = 78; + +} \ No newline at end of file diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm/Record.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm/Record.java new file mode 100644 index 000000000..12d7a0256 --- /dev/null +++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm/Record.java @@ -0,0 +1,176 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +package org.openoffice.xmerge.converter.palm; + +import java.io.OutputStream; +import java.io.InputStream; +import java.io.DataOutputStream; +import java.io.DataInputStream; +import java.io.IOException; + +/** + * Contains the raw bytes for a {@code Record} in a PDB. + * + *

Note that it is not associated with a {@code Record} number or ID.

+ * + * @see PalmDocument + * @see PalmDB + */ +public final class Record { + + /** {@code Record} {@code byte} array. */ + private byte[] data; + + /** {@code Record} attributes. */ + private byte attributes = 0; + + /** + * Default constructor. + */ + public Record() { + data = new byte[0]; + } + + /** + * Constructor to create a {@code Record} filled with bytes. + * + *

Note that this does not check for 64k {@code Record} sizes. User of + * this class must check for that.

+ * + * @param d {@code byte} array contents for this object. + */ + public Record(byte[] d) { + this(d, (byte) 0); + } + + /** + * Constructor to create a {@code Record} filled with bytes and assign + * {@code Record} attributes. + * + *

Note that this does not check for 64k {@code Record} sizes. User of + * this class must check for that.

+ * + * @param d {@code byte} array contents for this object. + * @param attrs {@code Record} attributes. + */ + public Record(byte[] d, byte attrs) { + data = new byte[d.length]; + attributes = attrs; + System.arraycopy(d, 0, data, 0, d.length); + } + + /** + * This method returns the number of bytes in this object. + * + * @return Number of bytes in this object. + */ + public int getSize() { + return data.length; + } + + /** + * This method returns the contents of this {@code Object}. + * + * @return Contents in {@code byte} array + */ + public byte[] getBytes() { + return data; + } + + /** + *

This method returns the {@code Record} attributes.

+ * + *
{@code Record} attributes consists of (from high to low bit)
+     *
+     * delete (1) - dirty (1) - busy (1) - secret (1) - category (4)
+ * + * @return {@code Record} attribute. + */ + public byte getAttributes() { + return attributes; + } + + /** + * Write out the {@code Record} attributes and {@code Record} length + * followed by the data in this {@code Record} object. + * + * @param outs The {@code OutputStream} to write the object. + * + * @throws IOException If any I/O error occurs. + */ + public void write(OutputStream outs) throws IOException { + DataOutputStream out = new DataOutputStream(outs); + out.writeByte(attributes); + out.writeShort(data.length); + out.write(data); + } + + /** + * Read the necessary data to create a PDB from the {@code InputStream}. + * + * @param ins The {@code InputStream} to read data from in order to + * restore the {@code object}. + * + * @throws IOException If any I/O error occurs. + */ + public void read(InputStream ins) throws IOException { + DataInputStream in = new DataInputStream(ins); + attributes = in.readByte(); + int len = in.readUnsignedShort(); + data = new byte[len]; + in.readFully(data); + } + + /** + * Override equals method of {@code Object}. + * + *

Two {@code Record} objects are equal if they contain the same bytes + * in the array and the same attributes.

+ * + *

This is used primarily for testing purposes only for now.

+ * + * @param obj A {@code Record} object to compare with + * + * @return {@code true} if {@code obj} is equal, otherwise {@code false}. + */ + @Override + public boolean equals(Object obj) { + if (!(obj instanceof Record)) { + return false; + } + Record rec = (Record) obj; + if (rec.getAttributes() != attributes) { + return false; + } + if (rec.getSize() == data.length) { + for (int i = 0; i < data.length; i++) { + if (data[i] != rec.data[i]) { + return false; + } + } + } + return false; + } + + @Override + public int hashCode() { + return 0; + } + +} diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm/package-info.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm/package-info.java new file mode 100644 index 000000000..4cc9fcd90 --- /dev/null +++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm/package-info.java @@ -0,0 +1,122 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +/** + * Provides classes for converting Palm database data to/from a + * {@code PalmDocument} object, which can be used by the framework. + * + *

This package provides classes that handle the writing of data to an + * {@code OutputStream} object for the {@link + * org.openoffice.xmerge.DocumentSerializer DocumentSerializer} interface for; + * as well as the reading of data from an {@code InputStream} object for the + * framework's {@link org.openoffice.xmerge.DocumentDeserializer + * DocumentDeserializer} interface. Both these framework interfaces are simply + * converters from server-side documents to device specific documents and + * vice-versa. + * Since all Palm databases have a general record oriented format, a Palm + * database converter specific I/O stream format is specified for the Palm sync + * client application to handle the byte stream in a generic way. + * This also means that Palm database converters should read and/or write using + * this I/O stream format as specified in the next section.

+ * + * + * + *

Palm database converter specific I/O stream format

+ * + *

Note that the format of the byte stream is not exactly that of a PDB file + * encoding. It does not need to contain the PDB header information nor record + * indices section. Instead, it contains the following ...

+ *
+ *    set header
+ *       4 bytes - creator id
+ *       4 bytes - type id
+ *       2 bytes - PDB header version
+ *       2 bytes - PDB header attribute
+ *       unsigned 2 bytes - number of PDB data to follow
+ *
+ *    for each PDB,
+ *       32 bytes - name of PDB i
+ *       unsigned 2 bytes - number of records in PDB i
+ *
+ *       for each record contained in PDB i,
+ *          1 byte - record attributes
+ *          unsigned 2 bytes - size of record j in PDB i
+ *          x bytes - data
+ * 
+ * + *

Note that each PDB section is appended by another if there is more than + * one.

+ * + *

Since the {@code PalmDocument} class takes care of the writing and reading + * of this format through its {@code write} and {@code read} methods, + * respectively, this format shall also be referred to as the PalmDocument + * stream format.

+ * + *

Usage of the classes for the specified I/O stream

+ * + *

When converting from a server document to device document(s), the + * framework requires writing the device document(s) to an {@code OutputStream} + * object via the {@code DocumentSerializer} interface. Note that a single + * server document may be converted into multiple PDB's on the Palm device. + * Each worksheet in the document is converted into a {@code PalmDocument}. + * Thus, if there is more than one worksheet in the document, more than one + * {@code PalmDocument} will be produced by the {@code DocumentSerializer}.

+ * + *

A {@code DocumentSerializer} creates a {@code ConvertData} object, which + * contains all of the {@code PalmDocuments}. The {@link + * org.openoffice.xmerge.converter.palm.PalmDocument#write write} method to + * write to the given {@code OutputStream}. + * The {@code PalmDocument} object will take care of writing the data in the + * specified format.

+ * + *

A {@code DocumentDeserializer} can use the {@code PalmDocument} object's + * {@link org.openoffice.xmerge.converter.palm.PalmDocument#read read} method + * to fill in all the {@code PalmDocument} object's data.

+ * + *

PDB file encoding/decoding

+ * + *

The {@code PalmDocument} object's read and write functions are provided by + * the {@code PdbDecoder} and {@code PdbEncoder} objects. + * The {@code PdbEncoder} class provides the functionality of encoding a + * {@code PalmDB} object into an {@code InputStream}, while the + * {@code PdbDecoder} class provides the functionality of decoding a PDB file + * into an {@code OutputStream}.

+ * + *

Refer to the class description of each for usage.

+ * + *

Important Note

+ * + *

Methods in these classes are not thread safe for performance reasons. + * Users of these classes will have to make sure that the usage of these classes + * are done in a proper manner. Possibly more on this later.

+ * + *

TODO list

+ * + *
    + *
  1. Merge the PalmDB, PdbDecoder and PdbEncoder classes into the PalmDocument + * class.
  2. + *
  3. After reading more on the palm file format spec, I realized that there + * are certain optional fields that may need to be addressed still, like the + * appInfo block and sortInfo block.
  4. + *
  5. The current PdbDecoder only returns a PalmDB object. There are other + * information that we may want to expose from the PDB decoding process.
  6. + *
  7. Investigate on different language encoding on the Palm and how that + * affects the PDB name.
  8. + *
+ */ +package org.openoffice.xmerge.converter.palm; diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/EmbeddedBinaryObject.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/EmbeddedBinaryObject.java new file mode 100644 index 000000000..6ac60f183 --- /dev/null +++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/EmbeddedBinaryObject.java @@ -0,0 +1,109 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +package org.openoffice.xmerge.converter.xml; + +import org.w3c.dom.Document; +import org.w3c.dom.DOMException; +import org.w3c.dom.Element; + +/** + * This class represents embedded object's in an OpenOffice.org document that + * have a binary representation. + */ +public class EmbeddedBinaryObject extends EmbeddedObject { + + /** The object's binary representation. */ + private byte[] objData = null; + + /** + * Constructor for an embedded object stored using an XML representation. + * + * @param name The name of the object. + * @param type The mime-type of the object. See the class summary. + */ + public EmbeddedBinaryObject(String name, String type) { + super(name, type); + } + + /** + * Package private constructor for use when reading an object from a + * compressed SX? file. + * + * @param name The name of the object. + * @param type The mime-type of the object. See the class summary. + * @param source The OfficeZip representation of the SX? file that stores + * the object. + */ + EmbeddedBinaryObject(String name, String type, OfficeZip source) { + super(name, type, source); + } + + /** + * This method returns the data for this object. + * + * @return A {@code byte} array containing the object's data. + */ + public byte[] getBinaryData() { + + // See if we came from a Zip file + if (objData == null && zipFile != null) { + objData = zipFile.getNamedBytes(objName); + } + + return objData; + } + + /** + * Sets the data for this object. + * + * @param data A {@code byte} array containing data for the object. + */ + public void setBinaryData(byte[] data) { + objData = data; + hasChanged = true; + } + + /** + * Package private method for writing the data of the EmbeddedObject to a + * SX? file. + * + * @param zip An {@code OfficeZip} instance representing the file the + * data is to be written to. + */ + @Override + void write(OfficeZip zip) { + if (hasChanged) { + zip.setNamedBytes(objName, objData); + } + } + + /** + * Package private method that constructs the manifest.xml entries for this + * embedded object. + */ + @Override + void writeManifestData(Document manifestDoc) throws DOMException { + Element objNode = manifestDoc.createElement(OfficeConstants.TAG_MANIFEST_FILE); + + objNode.setAttribute(OfficeConstants.ATTRIBUTE_MANIFEST_FILE_TYPE, objType); + objNode.setAttribute(OfficeConstants.ATTRIBUTE_MANIFEST_FILE_PATH, objName); + + manifestDoc.getDocumentElement().appendChild(objNode); + } +} \ No newline at end of file diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/EmbeddedObject.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/EmbeddedObject.java new file mode 100644 index 000000000..fc05447b2 --- /dev/null +++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/EmbeddedObject.java @@ -0,0 +1,101 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +package org.openoffice.xmerge.converter.xml; + +import java.io.IOException; + +import org.w3c.dom.Document; +import org.w3c.dom.DOMException; + +public abstract class EmbeddedObject { + protected String objName; + protected String objType; + + /** Representation of the file from which this object was read. */ + protected OfficeZip zipFile = null; + + /** Flag indicating if this document has changed since reading or is new. */ + protected boolean hasChanged = false; + + /** + * Constructor for an embedded object stored using an XML representation. + * + * @param name The name of the object. + * @param type The mime-type of the object. See the class summary. + */ + public EmbeddedObject(String name, String type) { + objName = name; + objType = type; + + hasChanged = true; + } + + /** + * Package private constructor for use when reading an object from a + * compressed SX? file. + * + * @param name The name of the object. + * @param type The mime-type of the object. See the class summary. + * @param source The OfficeZip representation of the SX? file that stores + * the object. + */ + EmbeddedObject(String name, String type, OfficeZip source) { + this(name, type); + zipFile = source; + } + + /** + * Retrieves the name of the embedded object represented by an instance of + * this class. + * + * N.B.The name refers to the name as found in the + * {@code META-INF/manifest.xml} file. + * + * @return The name of the object. + */ + public final String getName() { + return objName; + } + + /** + * Retrieves the type of the embedded object represented by an instance of + * this class. + * + * The {@code META-INF/manifest.xml} file currently represents the type of + * an object using MIME types. + */ + public final String getType() { + return objType; + } + + /** + * Package private method for writing the data of the EmbeddedObject to a + * SX? file. + * + * @param zip An {@code OfficeZip} instance representing the file the + * data is to be written to. + */ + abstract void write(OfficeZip zip) throws IOException; + + /** + * Package private method that constructs the manifest.xml entries for this + * embedded object. + */ + abstract void writeManifestData(Document manifestDoc) throws DOMException; +} \ No newline at end of file diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/EmbeddedXMLObject.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/EmbeddedXMLObject.java new file mode 100644 index 000000000..b081d6fa1 --- /dev/null +++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/EmbeddedXMLObject.java @@ -0,0 +1,280 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +package org.openoffice.xmerge.converter.xml; + +import java.io.IOException; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; + +import org.w3c.dom.Document; +import org.w3c.dom.DOMException; +import org.w3c.dom.Element; +import org.w3c.dom.Node; + +import org.xml.sax.SAXException; + +/** + * This class represents those embedded objects in an OpenOffice.org document + * that have an XML representation. + * + *

Currently, according to the OpenOffice.org File Format 1.0 document, + * there are 6 such objects:

+ *
+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
DescriptionObject
Formula created with Mathapplication/vnd.sun.xml.math
Charts created with Chartapplication/vnd.sun.xml.chart
Spreadsheets created with Calcapplication/vnd.sun.xml.calc
Text created with Writerapplication/vnd.sun.xml.writer
Drawings created with Drawapplication/vnd.sun.xml.draw
Presentations created with Impressapplication/vnd.sun.xml.impress
+ * + *

These object types are stored using a combination of content, settings and + * styles XML files.

+ */ +public class EmbeddedXMLObject extends EmbeddedObject { + + // Entries for the subdocuments that constitute this object; + private Document contentDOM = null; + private Document settingsDOM = null; + private Document stylesDOM = null; + + private DocumentBuilder builder = null; + + /** + * Constructor for an embedded object stored using an XML representation. + * + * @param name The name of the object. + * @param type The mime-type of the object. See the class summary. + */ + public EmbeddedXMLObject(String name, String type) { + super(name, type); + } + + /** + * Package private constructor for use when reading an object from a + * compressed SX? file. + * + * @param name The name of the object. + * @param type The mime-type of the object. See the class summary. + * @param source The OfficeZip representation of the SX? file that stores + * the object. + */ + EmbeddedXMLObject(String name, String type, OfficeZip source) { + super(name, type, source); + } + + /** + * Returns the content data for this embedded object. + * + * @return DOM representation of "content.xml". + * + * @throws SAXException If any parser error occurs. + * @throws IOException If any IO error occurs. + */ + public Document getContentDOM() throws SAXException, IOException { + + if (contentDOM == null) { + contentDOM = getNamedDOM("content.xml"); + } + + return contentDOM; + } + + /** + * Sets the content data for the embedded object. + * + * @param content DOM representation of the object's content. + */ + public void setContentDOM(Document content) { + contentDOM = content; + hasChanged = true; + } + + /** + * Returns the settings data for this embedded object. + * + * @return DOM representation of "settings.xml" + * + * @throws SAXException If any parser error occurs. + * @throws IOException If any IO error occurs. + */ + public Document getSettingsDOM() throws SAXException, IOException { + + if (settingsDOM == null) { + settingsDOM = getNamedDOM("settings.xml"); + } + + return settingsDOM; + } + + /** + * Sets the settings data for the embedded object. + * + * @param settings DOM representation of the object's styles. + */ + public void setSettingsDOM(Document settings) { + settingsDOM = settings; + hasChanged = true; + } + + /** + * Returns the style data for this embedded object. + * + * @return DOM representation of "styles.xml". + * + * @throws SAXException If any parser error occurs. + * @throws IOException If any IO error occurs. + */ + public Document getStylesDOM() throws SAXException, IOException { + + if (stylesDOM == null) { + stylesDOM = getNamedDOM("styles.xml"); + } + + return stylesDOM; + } + + /** + * Sets the styles data for the embedded object. + * + * @param styles DOM representation of the object's styles. + */ + public void setStylesDOM(Document styles) { + stylesDOM = styles; + hasChanged = true; + } + + /** + * This method extracts the data for the given XML file from the SX? file + * and creates a DOM representation of it. + * + * @param name The name of the XML file to retrieve. It is paired with + * the object name to access the SX? file. + * + * @return DOM representation of the named XML file. + * + * @throws SAXException If any parser error occurs. + * @throws IOException If any IO error occurs. + */ + private Document getNamedDOM(String name) throws SAXException, IOException { + if (zipFile == null) { + return null; + } + + try { + if (builder == null) { + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + + factory.setValidating(false); + builder = factory.newDocumentBuilder(); + } + + byte[] data = zipFile.getNamedBytes((objName + "/" + name)); + if (data != null) { + return OfficeDocument.parse(builder, data); + } else { + return null; + } + + } catch (ParserConfigurationException pce) { + throw new SAXException(pce); + } + } + + /** + * Package private method for writing the data of the EmbeddedObject to a + * SX? file. + * + * @param zip An {@code OfficeZip} instance representing the file the data + * is to be written to. + */ + @Override + void write(OfficeZip zip) throws IOException { + if (hasChanged) { + if (contentDOM != null) { + zip.setNamedBytes((objName + "/content.xml"), + OfficeDocument.docToBytes(contentDOM)); + } + if (settingsDOM != null) { + zip.setNamedBytes((objName + "/settings.xml"), + OfficeDocument.docToBytes(settingsDOM)); + } + if (stylesDOM != null) { + zip.setNamedBytes((objName + "/styles.xml"), + OfficeDocument.docToBytes(stylesDOM)); + } + } + } + + /** + * Package private method that constructs the manifest.xml entries for this + * embedded object. + * + * @param manifestDoc {@code Document} containing the manifest entries. + */ + @Override + void writeManifestData(Document manifestDoc) throws DOMException { + Node root = manifestDoc.getDocumentElement(); + + if (contentDOM != null) { + Element contentNode = manifestDoc.createElement(OfficeConstants.TAG_MANIFEST_FILE); + + contentNode.setAttribute(OfficeConstants.ATTRIBUTE_MANIFEST_FILE_TYPE, "text/xml"); + contentNode.setAttribute(OfficeConstants.ATTRIBUTE_MANIFEST_FILE_PATH, (objName + "/content.xml")); + + root.appendChild(contentNode); + } + + if (settingsDOM != null) { + Element settingsNode = manifestDoc.createElement(OfficeConstants.TAG_MANIFEST_FILE); + + settingsNode.setAttribute(OfficeConstants.ATTRIBUTE_MANIFEST_FILE_TYPE, "text/xml"); + settingsNode.setAttribute(OfficeConstants.ATTRIBUTE_MANIFEST_FILE_PATH, (objName + "/settings.xml")); + + root.appendChild(settingsNode); + } + + if (stylesDOM != null) { + Element stylesNode = manifestDoc.createElement(OfficeConstants.TAG_MANIFEST_FILE); + + stylesNode.setAttribute(OfficeConstants.ATTRIBUTE_MANIFEST_FILE_TYPE, "text/xml"); + stylesNode.setAttribute(OfficeConstants.ATTRIBUTE_MANIFEST_FILE_PATH, (objName + "/styles.xml")); + } + + Element objectNode = manifestDoc.createElement(OfficeConstants.TAG_MANIFEST_FILE); + + objectNode.setAttribute(OfficeConstants.ATTRIBUTE_MANIFEST_FILE_TYPE, objType); + objectNode.setAttribute(OfficeConstants.ATTRIBUTE_MANIFEST_FILE_PATH, (objName + "/")); + + root.appendChild(objectNode); + } +} \ No newline at end of file diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/OfficeConstants.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/OfficeConstants.java new file mode 100644 index 000000000..8605c6ad6 --- /dev/null +++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/OfficeConstants.java @@ -0,0 +1,333 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +package org.openoffice.xmerge.converter.xml; + +/** + * This interface contains constants for StarOffice XML tags, attributes + * (StarCalc cell types, etc.). + */ +public interface OfficeConstants { + + /** Element tag for office:document, this is the root tag. */ + String TAG_OFFICE_DOCUMENT = "office:document"; + + /** + * Element tag for office:document-content, this is the root tag in + * content.xml. + */ + String TAG_OFFICE_DOCUMENT_CONTENT = "office:document-content"; + + /** + * Element tag for office:document-settings, this is the root tag in + * content.xml. + */ + String TAG_OFFICE_DOCUMENT_SETTINGS= "office:document-settings"; + + /** + * Element tag for office:document-meta, this is the root tag in + * content.xml. + */ + String TAG_OFFICE_DOCUMENT_META= "office:document-meta"; + + /** + * Element tag for office:document-styles, this is the root tag in + * styles.xml. + */ + String TAG_OFFICE_DOCUMENT_STYLES = "office:document-styles"; + + /** Element tag for office:styles. */ + String TAG_OFFICE_STYLES = "office:styles"; + + /** Element tag for office:meta. */ + String TAG_OFFICE_META = "office:meta"; + + /** Element tag for office:automatic-styles. */ + String TAG_OFFICE_AUTOMATIC_STYLES = "office:automatic-styles"; + + /** Element tag for office:master-styles. */ + String TAG_OFFICE_MASTER_STYLES = "office:master-styles"; + + /** Element tag for office:body. */ + String TAG_OFFICE_BODY = "office:body"; + + /** Element tag for office:settings. */ + String TAG_OFFICE_SETTINGS = "office:settings"; + + /** Element tag for office:font-decls. */ + String TAG_OFFICE_FONT_DECLS = "office:font-decls"; + + /** Element tag for style:font-decl. */ + String TAG_STYLE_FONT_DECL = "style:font-decl"; + + /** Attribute tag for style:name of element style:name. */ + String ATTRIBUTE_STYLE_NAME = "style:name"; + + /** + * Attribute tag for style:font-pitch of element + * style:font-pitch. + */ + String ATTRIBUTE_STYLE_FONT_PITCH = "style:font-pitch"; + + /** + * Attribute tag for fo:font-family of element + * fo:font-family. + */ + String ATTRIBUTE_FO_FONT_FAMILY = "fo:font-family"; + + /** + * Attribute tag for fo:font-family of element + * fo:font-family. + */ + String ATTRIBUTE_FO_FONT_FAMILY_GENERIC = "fo:font-family-generic"; + + /** Element tag for text:p. */ + String TAG_PARAGRAPH = "text:p"; + + /** Element tag for text:h. */ + String TAG_HEADING = "text:h"; + + /** Element tag for text:s. */ + String TAG_SPACE = "text:s"; + + /** Element tag for text:tab-stop. */ + String TAG_TAB_STOP = "text:tab-stop"; + + /** Element tag for text:line-break. */ + String TAG_LINE_BREAK = "text:line-break"; + + /** Element tag for text:span. */ + String TAG_SPAN = "text:span"; + + /** Element tag for text:a. */ + String TAG_HYPERLINK = "text:a"; + + /** Element tag for text:unordered-list. */ + String TAG_UNORDERED_LIST = "text:unordered-list"; + + /** Element tag for text:ordered-list. */ + String TAG_ORDERED_LIST = "text:ordered-list"; + + /** Element tag for text:list-header. */ + String TAG_LIST_HEADER = "text:list-header"; + + /** Element tag for text:list-item. */ + String TAG_LIST_ITEM = "text:list-item"; + + /** Attribute tag for text:c of element text:s. */ + String ATTRIBUTE_SPACE_COUNT = "text:c"; + + /** Element tag for table:table. */ + String TAG_TABLE = "table:table"; + + /** Element tag for table:named-expression. */ + String TAG_NAMED_EXPRESSIONS = "table:named-expressions"; + + /** Element tag for table:named-range. */ + String TAG_TABLE_NAMED_RANGE= "table:named-range"; + + /** Element tag for table:named-expression. */ + String TAG_TABLE_NAMED_EXPRESSION= "table:named-expression"; + + /** Attribute tag for table:name of element table:table. */ + String ATTRIBUTE_TABLE_NAME = "table:name"; + + /** + * Attribute tag for table:expression of element + * table:named-range. + */ + String ATTRIBUTE_TABLE_EXPRESSION = "table:expression"; + + /** + * Attribute tag for table:base-cell-address of element + * table:named-range. + */ + String ATTRIBUTE_TABLE_BASE_CELL_ADDRESS = "table:base-cell-address"; + + /** + * Attribute tag for table:cell-range-address of element + * table:named-range. + */ + String ATTRIBUTE_TABLE_CELL_RANGE_ADDRESS = "table:cell-range-address"; + + /** Element tag for table:table-row. */ + String TAG_TABLE_ROW = "table:table-row"; + + /** Element tag for table:table-column. */ + String TAG_TABLE_COLUMN = "table:table-column"; + + /** + * Attribute tag for table:default-cell-style-name of element + * table:table-column. + */ + String ATTRIBUTE_DEFAULT_CELL_STYLE = "table:default-cell-style-name"; + + /** Element tag for table:scenario. */ + String TAG_TABLE_SCENARIO = "table:scenario"; + + /** Element tag for table:table-cell. */ + String TAG_TABLE_CELL = "table:table-cell"; + + /** + * Attribute tag for table:value-type of element + * table:table-cell. + */ + String ATTRIBUTE_TABLE_VALUE_TYPE = "table:value-type"; + + /** + * Attribute tag for table:number-columns-repeated of element + * table:table-cell. + */ + String ATTRIBUTE_TABLE_NUM_COLUMNS_REPEATED = + "table:number-columns-repeated"; + + /** + * Attribute tag for table:number-rows-repeated of element + * table:table-row. + */ + String ATTRIBUTE_TABLE_NUM_ROWS_REPEATED = "table:number-rows-repeated"; + + /** + * Attribute tag for table:formula of element + * table:table-cell. + */ + String ATTRIBUTE_TABLE_FORMULA = "table:formula"; + + /** + * Attribute tag for table:value of element table:table-cell. + */ + String ATTRIBUTE_TABLE_VALUE = "table:value"; + + /** + * Attribute tag for table:date-value of element + * table:table-cell. + */ + String ATTRIBUTE_TABLE_DATE_VALUE = "table:date-value"; + + /** + * Attribute tag for table:time-value of element + * table:table-cell. + */ + String ATTRIBUTE_TABLE_TIME_VALUE = "table:time-value"; + + /** + * Attribute tag for table:string-value of element + * table:table-cell. + */ + String ATTRIBUTE_TABLE_STRING_VALUE = "table:string-value"; + + /** + * Attribute tag for table:time-boolean-value of element + * table:table-cell. + */ + String ATTRIBUTE_TABLE_BOOLEAN_VALUE = "table:boolean-value"; + + /** Attribute tag for table:style-name of table elements. */ + String ATTRIBUTE_TABLE_STYLE_NAME = "table:style-name"; + + /** + * Attribute tag for table:currency of element + * table:table-cell. + */ + String ATTRIBUTE_TABLE_CURRENCY = "table:currency"; + + /** The cell contains data of type string. */ + String CELLTYPE_STRING = "string"; + + /** The cell contains data of type float. */ + String CELLTYPE_FLOAT = "float"; + + /** The cell contains data of type time. */ + String CELLTYPE_TIME = "time"; + + /** The cell contains data of type date. */ + String CELLTYPE_DATE = "date"; + + /** The cell contains data of type currency. */ + String CELLTYPE_CURRENCY = "currency"; + + /** The cell contains data of type boolean. */ + String CELLTYPE_BOOLEAN = "boolean"; + + /** The cell contains data of type percent. */ + String CELLTYPE_PERCENT = "percentage"; + + /** StarWriter XML file extension. */ + String SXW_FILE_EXTENSION = ".sxw"; + + /** StarWriter XML office:class value. */ + String SXW_TYPE = "text"; + + /** StarCalc XML file extension. */ + String SXC_FILE_EXTENSION = ".sxc"; + + /** StarCalc XML office:class value. */ + String SXC_TYPE = "spreadsheet"; + + /** Element tag for manifest:manifestentry in Manifest XML */ + String TAG_MANIFEST_ROOT = "manifest:manifest"; + + /** Element tag for manifest:file-entry entry in Manifest XML. */ + String TAG_MANIFEST_FILE = "manifest:file-entry"; + + /** + * Attribute tag for manifest:media-type of element + * manifest:file-entry. + */ + String ATTRIBUTE_MANIFEST_FILE_TYPE = "manifest:media-type"; + + /** + * Attribute tag for manifest:full-path of element + * manifest:file-entry. + */ + String ATTRIBUTE_MANIFEST_FILE_PATH = "manifest:full-path"; + + // Tags and Elements for the settings.xml + + /** Element tag for config:config-item. */ + String TAG_CONFIG_ITEM = "config:config-item"; + + /** Element tag for config:config-item-set. */ + String TAG_CONFIG_ITEM_SET = "config:config-item-set"; + + /** Element tag for config:config-item-map-indexed. */ + String TAG_CONFIG_ITEM_MAP_INDEXED = "config:config-item-map-indexed"; + + /** Element tag for config:config-item-map-named. */ + String TAG_CONFIG_ITEM_MAP_NAMED = "config:config-item-map-named"; + + /** Element tag for config:config-item-map-entry. */ + String TAG_CONFIG_ITEM_MAP_ENTRY= "config:config-item-map-entry"; + + /** + * Attribute tag for config:name of element config:config-item. + */ + String ATTRIBUTE_CONFIG_NAME = "config:name"; + + /** + * Attribute tag for config:type of element config:config-item. + */ + String ATTRIBUTE_CONFIG_TYPE = "config:type"; + + /** StarWriter XML MIME type. */ + String SXW_MIME_TYPE = "application/vnd.sun.xml.writer"; + + /** StarCalc XML MIME type. */ + String SXC_MIME_TYPE = "application/vnd.sun.xml.calc"; + +} \ No newline at end of file diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/OfficeDocument.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/OfficeDocument.java new file mode 100644 index 000000000..7fb3efe2b --- /dev/null +++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/OfficeDocument.java @@ -0,0 +1,1113 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +package org.openoffice.xmerge.converter.xml; + +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Reader; +import java.io.BufferedReader; +import java.io.StringReader; +import java.io.StringWriter; +import java.io.InputStreamReader; +import java.io.ByteArrayOutputStream; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.util.Iterator; +import java.util.Map; +import java.util.HashMap; + +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.ParserConfigurationException; + +import org.w3c.dom.Node; +import org.w3c.dom.Element; +import org.w3c.dom.Document; +import org.w3c.dom.DOMImplementation; +import org.w3c.dom.DocumentType; +import org.w3c.dom.NodeList; +import org.xml.sax.InputSource; +import org.w3c.dom.NamedNodeMap; +import org.xml.sax.SAXException; + +import javax.xml.transform.*; +import javax.xml.transform.dom.*; +import javax.xml.transform.stream.*; + +import org.openoffice.xmerge.util.Debug; + +/** + * An implementation of {@code Document} for StarOffice documents. + */ +public abstract class OfficeDocument + implements org.openoffice.xmerge.Document, OfficeConstants { + + /** Factory for {@code DocumentBuilder} objects. */ + private static DocumentBuilderFactory factory = + DocumentBuilderFactory.newInstance(); + + /** DOM {@code Document} of content.xml. */ + private Document contentDoc = null; + + /** DOM {@code Document} of meta.xml. */ + private Document metaDoc = null; + + /** DOM {@code Document} of settings.xml. */ + private Document settingsDoc = null; + + /** DOM {@code Document} of content.xml. */ + private Document styleDoc = null; + + /** DOM {@code Document} of @code META-INF/manifest.xml. */ + private Document manifestDoc = null; + + private String documentName = null; + private String fileName = null; + + /** + * {@code OfficeZip} object to store zip contents from read + * {@code InputStream}. + * + *

Note that this member will still be null if it was initialized using + * a template file instead of reading from a StarOffice zipped XML file.

+ */ + private OfficeZip zip = null; + + /** Collection to keep track of the embedded objects in the document. */ + private Map embeddedObjects = null; + + /** + * Default constructor. + * + * @param name {@code Document} name. + */ + public OfficeDocument(String name) { + this(name, true, false); + } + + /** + * Constructor with arguments to set {@code namespaceAware} and + * {@code validating} flags. + * + * @param name {@code Document} name (may or may not contain + * extension). + * @param namespaceAware Value for {@code namespaceAware} flag. + * @param validating Value for {@code validating} flag. + */ + public OfficeDocument(String name, boolean namespaceAware, boolean validating) { + factory.setValidating(validating); + factory.setNamespaceAware(namespaceAware); + this.documentName = trimDocumentName(name); + this.fileName = documentName + getFileExtension(); + } + + /** + * Removes the file extension from the {@code Document} name. + * + * @param name Full {@code Document} name with extension. + * + * @return Name of {@code Document} without the extension. + */ + private String trimDocumentName(String name) { + String temp = name.toLowerCase(); + String ext = getFileExtension(); + + if (temp.endsWith(ext)) { + // strip the extension + int nlen = name.length(); + int endIndex = nlen - ext.length(); + name = name.substring(0,endIndex); + } + + return name; + } + + /** + * Return a DOM {@code Document} object of the content.xml file. + * + *

Note that a content DOM is not created when the constructor is called. + * So, either the {@code read} method or the {@code initContentDOM} method + * will need to be called ahead on this object before calling this method.

+ * + * @return DOM {@code Document} object. + */ + public Document getContentDOM() { + + return contentDoc; + } + + /** + * Return a DOM {@code Document} object of the meta.xml file. + * + *

Note that a content DOM is not created when the constructor is called. + * So, either the {@code read} method or the {@code initContentDOM} method + * will need to be called ahead on this object before calling this method.

+ * + * @return DOM Document object. + */ + public Document getMetaDOM() { + + return metaDoc; + } + + /** + * Return a DOM {@code Document} object of the settings.xml file. + * + *

Note that a content DOM is not created when the constructor is called. + * So, either the {@code read} method or the {@code initContentDOM} method + * will need to be called ahead on this object before calling this method.

+ * + * @return DOM {@code Document} object. + */ + public Document getSettingsDOM() { + + return settingsDoc; + } + + /** + * Sets the content tree of the document. + * + * @param newDom {@code Node} containing the new content tree. + */ + public void setContentDOM( Node newDom) { + contentDoc = (Document)newDom; + } + + /** + * Sets the meta tree of the document. + * + * @param newDom {@code Node} containing the new meta tree. + */ + public void setMetaDOM (Node newDom) { + metaDoc = (Document)newDom; + } + + /** + * Sets the settings tree of the document. + * + * @param newDom {@code Node} containing the new settings tree. + */ + public void setSettingsDOM (Node newDom) { + settingsDoc = (Document)newDom; + } + + /** + * Sets the style tree of the document. + * + * @param newDom {@code Node} containing the new style tree. + */ + public void setStyleDOM (Node newDom) { + styleDoc = (Document)newDom; + } + + /** + * Return a DOM {@code Document} object of the style.xml file. + * + *

Note that this may return {@code null} if there is no style DOM.

+ *

Note that a style DOM is not created when the constructor is called. + * Depending on the {@code InputStream}, a {@code read} method may or may + * not build a style DOM. When creating a new style DOM, call the + * {@code initStyleDOM} method first.

+ * + * @return DOM {@code Document} object. + */ + public Document getStyleDOM() { + + return styleDoc; + } + + /** + * Return the name of the {@code Document}. + * + * @return The name of {@code Document}. + */ + public String getName() { + + return documentName; + } + + /** + * Return the file name of the {@code Document}, possibly with the standard + * extension. + * + * @return The file name of {@code Document}. + */ + public String getFileName() { + + return fileName; + } + + /** + * Returns the file extension for this type of {@code Document}. + * + * @return The file extension of {@code Document}. + */ + protected abstract String getFileExtension(); + + /** + * Returns all the embedded objects (graphics, formulae, etc.) present in + * this document. + * + * @return An {@code Iterator} of {@code EmbeddedObject} objects. + */ + private Iterator getEmbeddedObjects() { + + if (embeddedObjects == null && manifestDoc != null) { + embeddedObjects = new HashMap(); + + // Need to read the manifest file and construct a list of objects + NodeList nl = manifestDoc.getElementsByTagName(TAG_MANIFEST_FILE); + + // Don't create the HashMap if there are no embedded objects + int len = nl.getLength(); + for (int i = 0; i < len; i++) { + Node n = nl.item(i); + + NamedNodeMap attrs = n.getAttributes(); + + String type = attrs.getNamedItem(ATTRIBUTE_MANIFEST_FILE_TYPE).getNodeValue(); + String path = attrs.getNamedItem(ATTRIBUTE_MANIFEST_FILE_PATH).getNodeValue(); + + /* + * According to OpenOffice.org XML File Format document (ver. 1) + * there are only two types of embedded object: + * + * Objects with an XML representation. + * Objects without an XML representation. + * + * The former are represented by one or more XML files. + * The latter are in binary form. + */ + if (type.startsWith("application/vnd.sun.xml")) + { + if (path.equals("/")) { + // Exclude the main document entries + continue; + } + // Take off the trailing '/' + String name = path.substring(0, path.length() - 1); + embeddedObjects.put(name, new EmbeddedXMLObject(name, type, zip)); + } + else if (type.equals("text/xml")) { + // XML entries are either embedded StarOffice doc entries or main + // document entries + continue; + } + else { // FIX (HJ): allows empty MIME type + embeddedObjects.put(path, new EmbeddedBinaryObject(path, type, zip)); + } + } + } + + if (embeddedObjects == null) { + return null; + } + + return embeddedObjects.values().iterator(); + } + + /** + * Read the Office {@code Document} from the given {@code InputStream}. + * + * @param is Office document {@code InputStream}. + * + * @throws IOException If any I/O error occurs. + */ + public void read(InputStream is) throws IOException { + + Debug.log(Debug.INFO, "reading Office file"); + DocumentBuilder builder = null; + + try { + builder = factory.newDocumentBuilder(); + } catch (ParserConfigurationException ex) { + throw new OfficeDocumentException(ex); + } + + // read in Office zip file format + zip = new OfficeZip(); + zip.read(is); + + // grab the content.xml and + // parse it into contentDoc. + byte contentBytes[] = zip.getContentXMLBytes(); + if (contentBytes == null) { + throw new OfficeDocumentException("Entry content.xml not found in file"); + } + try { + contentDoc = parse(builder, contentBytes); + } catch (SAXException ex) { + throw new OfficeDocumentException(ex); + } + + // if style.xml exists, grab the style.xml + // parse it into styleDoc. + byte styleBytes[] = zip.getStyleXMLBytes(); + if (styleBytes != null) { + try { + styleDoc = parse(builder, styleBytes); + } catch (SAXException ex) { + throw new OfficeDocumentException(ex); + } + } + + byte metaBytes[] = zip.getMetaXMLBytes(); + if (metaBytes != null) { + try { + metaDoc = parse(builder, metaBytes); + } catch (SAXException ex) { + throw new OfficeDocumentException(ex); + } + } + + byte settingsBytes[] = zip.getSettingsXMLBytes(); + if (settingsBytes != null) { + try { + settingsDoc = parse(builder, settingsBytes); + + } catch (SAXException ex) { + throw new OfficeDocumentException(ex); + } + } + + // Read in the META-INF/manifest.xml file + byte manifestBytes[] = zip.getManifestXMLBytes(); + if (manifestBytes != null) { + try { + manifestDoc = parse(builder, manifestBytes); + } catch (SAXException ex) { + throw new OfficeDocumentException(ex); + } + } + } + + /** + * Read the Office {@code Document} from the given {@code InputStream}. + * + * @param is Office document {@code InputStream}. + * @param isZip {@code boolean} Identifies whether a file is zipped or not. + * + * @throws IOException If any I/O error occurs. + */ + public void read(InputStream is, boolean isZip) throws IOException { + + Debug.log(Debug.INFO, "reading Office file"); + + DocumentBuilder builder = null; + + try { + builder = factory.newDocumentBuilder(); + } catch (ParserConfigurationException ex) { + throw new OfficeDocumentException(ex); + } + + if (isZip) { + read(is); + } else { + try { + Reader r = secondHack(is); + InputSource ins = new InputSource(r); + org.w3c.dom.Document newDoc = builder.parse(ins); + Element rootElement = newDoc.getDocumentElement(); + + NodeList nodeList; + Node tmpNode; + Node rootNode = rootElement; + + /* content */ + contentDoc = createDOM(TAG_OFFICE_DOCUMENT_CONTENT); + rootElement = contentDoc.getDocumentElement(); + rootNode = rootElement; + + // FIX (HJ): Include office:font-decls in content DOM + nodeList = newDoc + .getElementsByTagName(TAG_OFFICE_FONT_DECLS); + if (nodeList.getLength() > 0) { + tmpNode = contentDoc.importNode(nodeList.item(0), true); + rootNode.appendChild(tmpNode); + } + + nodeList = newDoc + .getElementsByTagName(TAG_OFFICE_AUTOMATIC_STYLES); + if (nodeList.getLength() > 0) { + tmpNode = contentDoc.importNode(nodeList.item(0), true); + rootNode.appendChild(tmpNode); + } + + nodeList = newDoc.getElementsByTagName(TAG_OFFICE_BODY); + if (nodeList.getLength() > 0) { + tmpNode = contentDoc.importNode(nodeList.item(0), true); + rootNode.appendChild(tmpNode); + } + + /* Styles */ + styleDoc = createDOM(TAG_OFFICE_DOCUMENT_STYLES); + rootElement = styleDoc.getDocumentElement(); + rootNode = rootElement; + + // FIX (HJ): Include office:font-decls in styles DOM + nodeList = newDoc + .getElementsByTagName(TAG_OFFICE_FONT_DECLS); + if (nodeList.getLength() > 0) { + tmpNode = styleDoc.importNode(nodeList.item(0), true); + rootNode.appendChild(tmpNode); + } + + nodeList = newDoc.getElementsByTagName(TAG_OFFICE_STYLES); + if (nodeList.getLength() > 0) { + tmpNode = styleDoc.importNode(nodeList.item(0), true); + rootNode.appendChild(tmpNode); + } + + // FIX (HJ): Include office:automatic-styles in styles DOM + nodeList = newDoc + .getElementsByTagName(TAG_OFFICE_AUTOMATIC_STYLES); + if (nodeList.getLength() > 0) { + tmpNode = styleDoc.importNode(nodeList.item(0), true); + rootNode.appendChild(tmpNode); + } + + // FIX (HJ): Include office:master-styles in styles DOM + nodeList = newDoc + .getElementsByTagName(TAG_OFFICE_MASTER_STYLES); + if (nodeList.getLength() > 0) { + tmpNode = styleDoc.importNode(nodeList.item(0), true); + rootNode.appendChild(tmpNode); + } + + /* Settings */ + settingsDoc = createDOM(TAG_OFFICE_DOCUMENT_SETTINGS); + rootElement = settingsDoc.getDocumentElement(); + rootNode = rootElement; + nodeList = newDoc.getElementsByTagName(TAG_OFFICE_SETTINGS); + if (nodeList.getLength() > 0) { + tmpNode = settingsDoc + .importNode(nodeList.item(0), true); + rootNode.appendChild(tmpNode); + } + /* Meta */ + metaDoc = createDOM(TAG_OFFICE_DOCUMENT_META); + rootElement = metaDoc.getDocumentElement(); + rootNode = rootElement; + nodeList = newDoc.getElementsByTagName(TAG_OFFICE_META); + if (nodeList.getLength() > 0) { + tmpNode = metaDoc.importNode(nodeList.item(0), true); + rootNode.appendChild(tmpNode); + } + } catch (SAXException ex) { + throw new OfficeDocumentException(ex); + } + } + + } + + /** + * Parse given {@code byte} array into a DOM {@code Document} object using + * the {@code DocumentBuilder} object. + * + * @param builder {@code DocumentBuilder} object for parsing. + * @param bytes {@code byte} array for parsing. + * + * @return Resulting DOM {@code Document} object. + * + * @throws SAXException If any parsing error occurs. + */ + static Document parse(DocumentBuilder builder, byte bytes[]) + throws SAXException, IOException { + + Document doc = null; + + ByteArrayInputStream is = new ByteArrayInputStream(bytes); + + // TODO: replace hack with a more appropriate fix. + + Reader r = hack(is); + InputSource ins = new InputSource(r); + doc = builder.parse(ins); + + return doc; + } + + /** + * Method to return the MIME type of the document. + * + * @return String The document's MIME type. + */ + protected abstract String getDocumentMimeType(); + + /** + * Write out Office ZIP file format. + * + * @param os XML {@code OutputStream}. + * + * @throws IOException If any I/O error occurs. + */ + public void write(OutputStream os) throws IOException { + if (zip == null) { + zip = new OfficeZip(); + } + + initManifestDOM(); + + Element domEntry; + Element manifestRoot = manifestDoc.getDocumentElement(); + + // The EmbeddedObjects come first. + Iterator embObjs = getEmbeddedObjects(); + if (embObjs != null) { + while (embObjs.hasNext()) { + EmbeddedObject obj = embObjs.next(); + obj.writeManifestData(manifestDoc); + + obj.write(zip); + } + } + + // Add in the entry for the Pictures directory. Always present. + domEntry = manifestDoc.createElement(TAG_MANIFEST_FILE); + domEntry.setAttribute(ATTRIBUTE_MANIFEST_FILE_PATH, "Pictures/"); + domEntry.setAttribute(ATTRIBUTE_MANIFEST_FILE_TYPE, ""); + manifestRoot.appendChild(domEntry); + + // Write content to the Zip file and then write any of the optional + // data, if it exists. + zip.setContentXMLBytes(docToBytes(contentDoc)); + + domEntry = manifestDoc.createElement(TAG_MANIFEST_FILE); + domEntry.setAttribute(ATTRIBUTE_MANIFEST_FILE_PATH, "content.xml"); + domEntry.setAttribute(ATTRIBUTE_MANIFEST_FILE_TYPE, "text/xml"); + + manifestRoot.appendChild(domEntry); + + if (styleDoc != null) { + zip.setStyleXMLBytes(docToBytes(styleDoc)); + + domEntry = manifestDoc.createElement(TAG_MANIFEST_FILE); + domEntry.setAttribute(ATTRIBUTE_MANIFEST_FILE_PATH, "styles.xml"); + domEntry.setAttribute(ATTRIBUTE_MANIFEST_FILE_TYPE, "text/xml"); + manifestRoot.appendChild(domEntry); + } + + if (metaDoc != null) { + zip.setMetaXMLBytes(docToBytes(metaDoc)); + + domEntry = manifestDoc.createElement(TAG_MANIFEST_FILE); + domEntry.setAttribute(ATTRIBUTE_MANIFEST_FILE_PATH, "meta.xml"); + domEntry.setAttribute(ATTRIBUTE_MANIFEST_FILE_TYPE, "text/xml"); + manifestRoot.appendChild(domEntry); + } + + if (settingsDoc != null) { + zip.setSettingsXMLBytes(docToBytes(settingsDoc)); + + domEntry = manifestDoc.createElement(TAG_MANIFEST_FILE); + domEntry.setAttribute(ATTRIBUTE_MANIFEST_FILE_PATH, "settings.xml"); + domEntry.setAttribute(ATTRIBUTE_MANIFEST_FILE_TYPE, "text/xml"); + manifestRoot.appendChild(domEntry); + } + + zip.setManifestXMLBytes(docToBytes(manifestDoc)); + + zip.write(os); + } + + /** + * Write out Office ZIP file format. + * + * @param os XML {@code OutputStream}. + * @param isZip {@code boolean} + * + * @throws IOException If any I/O error occurs. + */ + public void write(OutputStream os, boolean isZip) throws IOException { + + // Create an OfficeZip object if one does not exist. + if (isZip){ + write(os); + } else { + try { + DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance(); + DocumentBuilder builder= builderFactory.newDocumentBuilder(); + DOMImplementation domImpl = builder.getDOMImplementation(); + domImpl.createDocumentType("office:document","-//OpenOffice.org//DTD OfficeDocument 1.0//EN",null); + org.w3c.dom.Document newDoc = domImpl.createDocument("http://openoffice.org/2000/office","office:document",null); + + Element rootElement=newDoc.getDocumentElement(); + rootElement.setAttribute("xmlns:office","http://openoffice.org/2000/office"); + rootElement.setAttribute("xmlns:style","http://openoffice.org/2000/style" ); + rootElement.setAttribute("xmlns:text","http://openoffice.org/2000/text"); + rootElement.setAttribute("xmlns:table","http://openoffice.org/2000/table"); + + rootElement.setAttribute("xmlns:draw","http://openoffice.org/2000/drawing"); + rootElement.setAttribute("xmlns:fo","http://www.w3.org/1999/XSL/Format" ); + rootElement.setAttribute("xmlns:xlink","http://www.w3.org/1999/xlink" ); + rootElement.setAttribute("xmlns:dc","http://purl.org/dc/elements/1.1/" ); + rootElement.setAttribute("xmlns:meta","http://openoffice.org/2000/meta" ); + rootElement.setAttribute("xmlns:number","http://openoffice.org/2000/datastyle" ); + rootElement.setAttribute("xmlns:svg","http://www.w3.org/2000/svg" ); + rootElement.setAttribute("xmlns:chart","http://openoffice.org/2000/chart" ); + rootElement.setAttribute("xmlns:dr3d","http://openoffice.org/2000/dr3d" ); + rootElement.setAttribute("xmlns:math","http://www.w3.org/1998/Math/MathML" ); + rootElement.setAttribute("xmlns:form","http://openoffice.org/2000/form" ); + rootElement.setAttribute("xmlns:script","http://openoffice.org/2000/script" ); + rootElement.setAttribute("xmlns:config","http://openoffice.org/2001/config" ); + // #i41033# OASIS format needs the "office:class" set. + if(getDocumentMimeType().equals(SXC_MIME_TYPE)) + rootElement.setAttribute("office:class","spreadsheet" ); + else if(getDocumentMimeType().equals(SXW_MIME_TYPE)) + rootElement.setAttribute("office:class","text" ); + rootElement.setAttribute("office:version","1.0"); + + NodeList nodeList; + Node tmpNode; + Node rootNode = rootElement; + if (metaDoc !=null) { + nodeList= metaDoc.getElementsByTagName(TAG_OFFICE_META); + if (nodeList.getLength()>0) { + tmpNode = newDoc.importNode(nodeList.item(0),true); + rootNode.appendChild(tmpNode); + } + } if (styleDoc !=null) { + nodeList= styleDoc.getElementsByTagName(TAG_OFFICE_STYLES); + if (nodeList.getLength()>0){ + tmpNode = newDoc.importNode(nodeList.item(0),true); + rootNode.appendChild(tmpNode); + } + } if (settingsDoc !=null) { + nodeList= settingsDoc.getElementsByTagName(TAG_OFFICE_SETTINGS); + if (nodeList.getLength()>0){ + tmpNode = newDoc.importNode(nodeList.item(0),true); + rootNode.appendChild(tmpNode); + } + } if (contentDoc !=null) { + nodeList= contentDoc.getElementsByTagName(TAG_OFFICE_AUTOMATIC_STYLES); + if (nodeList.getLength()>0){ + tmpNode = newDoc.importNode(nodeList.item(0),true); + rootNode.appendChild(tmpNode); + } + nodeList= contentDoc.getElementsByTagName(TAG_OFFICE_BODY); + if (nodeList.getLength()>0){ + tmpNode = newDoc.importNode(nodeList.item(0),true); + rootNode.appendChild(tmpNode); + } + } + + byte contentBytes[] = docToBytes(newDoc); + os.write(contentBytes); + } catch(Exception exc){ + System.out.println("\nException in OfficeDocument.write():" +exc); + } + } + } + + + /** + * Write out a {@code org.w3c.dom.Document} object into a {@code byte} + * array. + * + *

TODO: remove dependency on {@code com.sun.xml.tree.XmlDocument} + * package!

+ * + * @param doc DOM {@code Document} object. + * + * @return {@code byte} array of DOM {@code Document} object. + * + * @throws IOException If any I/O error occurs. + */ + static byte[] docToBytes(Document doc) + throws IOException { + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + java.lang.reflect.Constructor con; + java.lang.reflect.Method meth; + + String domImpl = doc.getClass().getName(); + + /* + * We may have multiple XML parsers in the Classpath. + * Depending on which one is first, the actual type of + * doc may vary. Need a way to find out which API is being + * used and use an appropriate serialization method. + */ + + try { + // First of all try for JAXP 1.0 + if (domImpl.equals("com.sun.xml.tree.XmlDocument")) { + + Debug.log(Debug.INFO, "Using JAXP"); + + Class jaxpDoc = Class.forName("com.sun.xml.tree.XmlDocument"); + + // The method is in the XMLDocument class itself, not a helper + meth = jaxpDoc.getMethod("write", + new Class[] { Class.forName("java.io.OutputStream") } ); + + meth.invoke(doc, new Object [] { baos } ); + } else if (domImpl.equals("org.apache.crimson.tree.XmlDocument")) { + Debug.log(Debug.INFO, "Using Crimson"); + + Class crimsonDoc = Class.forName("org.apache.crimson.tree.XmlDocument"); + // The method is in the XMLDocument class itself, not a helper + meth = crimsonDoc.getMethod("write", + new Class[] { Class.forName("java.io.OutputStream") } ); + + meth.invoke(doc, new Object [] { baos } ); + } else if (domImpl.equals("org.apache.xerces.dom.DocumentImpl") + || domImpl.equals("org.apache.xerces.dom.DeferredDocumentImpl")) { + + Debug.log(Debug.INFO, "Using Xerces"); + + // Try for Xerces + Class xercesSer = + Class.forName("org.apache.xml.serialize.XMLSerializer"); + + // Get the OutputStream constructor + // May want to use the OutputFormat parameter at some stage too + con = xercesSer.getConstructor(new Class [] + { Class.forName("java.io.OutputStream"), + Class.forName("org.apache.xml.serialize.OutputFormat") } ); + + // Get the serialize method + meth = xercesSer.getMethod("serialize", + new Class [] { Class.forName("org.w3c.dom.Document") } ); + + // Get an instance + Object serializer = con.newInstance(new Object [] { baos, null } ); + + // Now call serialize to write the document + meth.invoke(serializer, new Object [] { doc } ); + } else if (domImpl.equals("gnu.xml.dom.DomDocument")) { + Debug.log(Debug.INFO, "Using GNU"); + + Class gnuSer = Class.forName("gnu.xml.dom.ls.DomLSSerializer"); + + // Get the serialize method + meth = gnuSer.getMethod("serialize", + new Class [] { Class.forName("org.w3c.dom.Node"), + Class.forName("java.io.OutputStream") } ); + + // Get an instance + Object serializer = gnuSer.newInstance(); + + // Now call serialize to write the document + meth.invoke(serializer, new Object [] { doc, baos } ); + } else { + try { + DOMSource domSource = new DOMSource(doc); + StringWriter writer = new StringWriter(); + StreamResult result = new StreamResult(writer); + TransformerFactory tf = TransformerFactory.newInstance(); + Transformer transformer = tf.newTransformer(); + transformer.transform(domSource, result); + return writer.toString().getBytes(); + } catch (Exception e) { + // We don't have another parser + IOException newEx = new IOException("No appropriate API (JAXP/Xerces) to serialize XML document: " + domImpl); + newEx.initCause(e); + throw newEx; + } + } + } + catch (Exception e) { + // We may get some other errors, but the bottom line is that + // the steps being executed no longer work + IOException newEx = new IOException(e.getMessage()); + newEx.initCause(e); + throw newEx; + } + + byte bytes[] = baos.toByteArray(); + + return bytes; + } + + /** + * Initializes a new DOM {@code Document} with the content containing + * minimum OpenOffice XML tags. + * + * @throws IOException If any I/O error occurs. + */ + public final void initContentDOM() throws IOException { + + contentDoc = createDOM(TAG_OFFICE_DOCUMENT_CONTENT); + + // this is a work-around for a bug in Office6.0 - not really + // needed but StarCalc 6.0 will crash without this tag. + Element root = contentDoc.getDocumentElement(); + + Element child = contentDoc.createElement(TAG_OFFICE_FONT_DECLS); + root.appendChild(child); + + child = contentDoc.createElement(TAG_OFFICE_AUTOMATIC_STYLES); + root.appendChild(child); + + child = contentDoc.createElement(TAG_OFFICE_BODY); + root.appendChild(child); + } + + /** + * Initializes a new DOM {@code Document} with the content containing + * minimum OpenOffice XML tags. + * + * @throws IOException If any I/O error occurs. + */ + public final void initSettingsDOM() throws IOException { + + settingsDoc = createSettingsDOM(TAG_OFFICE_DOCUMENT_SETTINGS); + + // this is a work-around for a bug in Office6.0 - not really + // needed but StarCalc 6.0 will crash without this tag. + Element root = settingsDoc.getDocumentElement(); + + Element child = settingsDoc.createElement(TAG_OFFICE_SETTINGS); + root.appendChild(child); + } + + /** + * Initializes a new DOM Document with styles containing minimum OpenOffice + * XML tags. + * + * @throws IOException If any I/O error occurs. + */ + public final void initStyleDOM() throws IOException { + + styleDoc = createDOM(TAG_OFFICE_DOCUMENT_STYLES); + } + + /** + * Creates a new DOM {@code Document} containing minimum OpenOffice XML tags. + * + *

This method uses the subclass {@code getOfficeClassAttribute} method + * to get the attribute for office:class.

+ * + * @param rootName root name of {@code Document}. + * + * @throws IOException If any I/O error occurs. + */ + private final Document createSettingsDOM(String rootName) throws IOException { + + Document doc = null; + + try { + DocumentBuilder builder = factory.newDocumentBuilder(); + doc = builder.newDocument(); + } catch (ParserConfigurationException ex) { + throw new OfficeDocumentException(ex); + } + + Element root = doc.createElement(rootName); + doc.appendChild(root); + + root.setAttribute("xmlns:office", "http://openoffice.org/2000/office"); + root.setAttribute("xmlns:xlink", "http://openoffice.org/1999/xlink"); + root.setAttribute("xmlns:config", "http://openoffice.org/2001/config"); + root.setAttribute("office:version", "1.0"); + + return doc; + } + + /** + * Creates a new DOM {@code Document} containing minimum OpenOffice XML tags. + * + *

This method uses the subclass {@code getOfficeClassAttribute} method + * to get the attribute for office:class.

+ * + * @param rootName root name of Document. + * + * @throws IOException If any I/O error occurs. + */ + private final Document createDOM(String rootName) throws IOException { + + Document doc = null; + + try { + DocumentBuilder builder = factory.newDocumentBuilder(); + doc = builder.newDocument(); + } catch (ParserConfigurationException ex) { + throw new OfficeDocumentException(ex); + } + + Element root = doc.createElement(rootName); + doc.appendChild(root); + + root.setAttribute("xmlns:office", "http://openoffice.org/2000/office"); + root.setAttribute("xmlns:style", "http://openoffice.org/2000/style"); + root.setAttribute("xmlns:text", "http://openoffice.org/2000/text"); + root.setAttribute("xmlns:table", "http://openoffice.org/2000/table"); + root.setAttribute("xmlns:draw", "http://openoffice.org/2000/drawing"); + root.setAttribute("xmlns:fo", "http://www.w3.org/1999/XSL/Format"); + root.setAttribute("xmlns:xlink", "http://www.w3.org/1999/xlink"); + root.setAttribute("xmlns:number", "http://openoffice.org/2000/datastyle"); + root.setAttribute("xmlns:svg", "http://www.w3.org/2000/svg"); + root.setAttribute("xmlns:chart", "http://openoffice.org/2000/chart"); + root.setAttribute("xmlns:dr3d", "http://openoffice.org/2000/dr3d"); + root.setAttribute("xmlns:math", "http://www.w3.org/1998/Math/MathML"); + root.setAttribute("xmlns:form", "http://openoffice.org/2000/form"); + root.setAttribute("xmlns:script", "http://openoffice.org/2000/script"); + root.setAttribute("office:class", getOfficeClassAttribute()); + root.setAttribute("office:version", "1.0"); + + return doc; + } + + /** + * Return the office:class attribute value. + * + * @return The attribute value. + */ + protected abstract String getOfficeClassAttribute(); + + /** + * Hacked code to filter {@literal } tag before sending stream to + * parser. + * + *

This hacked code needs to be changed later on.

+ * + *

Issue: using current jaxp1.0 parser, there is no way to turn off + * processing of dtds. Current set of dtds have bugs, processing them will + * throw exceptions.

+ * + *

This is a simple hack that assumes the whole {@literal } tag + * are all in the same line. This is sufficient for current StarOffice 6.0 + * generated XML files. Since this hack really needs to go away, I don't + * want to spend too much time in making it a perfect hack.

+ * + * FIX (HJ): Removed requirement for DOCTYPE to be in one line + * FIX (HJ): No longer removes newlines + * + * @param is {@code InputStream} to be filtered. + * + * @return Reader value without the {@literal } tag. + * + * @throws IOException If any I/O error occurs. + */ + private static Reader hack(InputStream is) throws IOException { + + BufferedReader br = new BufferedReader(new InputStreamReader(is, "UTF-8")); + StringBuffer buffer = new StringBuffer(); + + String str; + while ((str = br.readLine()) != null) { + + int sIndex = str.indexOf(" -1) { + + buffer.append(str.substring(0, sIndex)); + + int eIndex = str.indexOf('>', sIndex + 8 ); + if (eIndex > -1) { + + buffer.append(str.substring(eIndex + 1, str.length())); + // FIX (HJ): Preserve the newline + buffer.append("\n"); + + } else { + + // FIX (HJ): More than one line. Search for '>' in following lines + boolean bOK = false; + while ((str = br.readLine())!=null) { + eIndex = str.indexOf('>'); + if (eIndex>-1) { + buffer.append(str.substring(eIndex+1)); + // FIX (HJ): Preserve the newline + buffer.append("\n"); + bOK = true; + break; + } + } + + if (!bOK) { throw new IOException("Invalid XML"); } + } + + } else { + + buffer.append(str); + // FIX (HJ): Preserve the newline + buffer.append("\n"); + } + } + + StringReader r = new StringReader(buffer.toString()); + return r; + } + + /** + * Transform the {@code InputStream} to a Reader Stream. + * + *

This hacked code needs to be changed later on.

+ * + *

Issue: the new oasis input file stream means that the old input stream + * fails. see #i33702#

+ * + * @param is {@code InputStream} to be filtered. + * + * @return Reader value of the {@code InputStream()}. + * + * @throws IOException If any I/O error occurs. + */ + private static Reader secondHack(InputStream is) throws IOException { + + BufferedReader br = new BufferedReader(new InputStreamReader(is, "UTF-8")); + char[] charArray = new char[4096]; + StringBuffer sBuf = new StringBuffer(); + int n; + while ((n=br.read(charArray, 0, charArray.length)) > 0) { + sBuf.append(charArray, 0, n); + } + + // ensure there is no trailing garbage after the end of the stream. + int sIndex = sBuf.lastIndexOf(""); + sBuf.delete(sIndex, sBuf.length()); + sBuf.append(""); + StringReader r = new StringReader(sBuf.toString()); + return r; + } + + /** + * Method to create the initial entries in the manifest.xml file stored + * in an SX? file. + */ + private void initManifestDOM() throws IOException { + + try { + DocumentBuilder builder = factory.newDocumentBuilder(); + DOMImplementation domImpl = builder.getDOMImplementation(); + + DocumentType docType = domImpl.createDocumentType(TAG_MANIFEST_ROOT, + "-//OpenOffice.org//DTD Manifest 1.0//EN", + "Manifest.dtd"); + manifestDoc = domImpl.createDocument("manifest", TAG_MANIFEST_ROOT, docType); + } catch (ParserConfigurationException ex) { + throw new OfficeDocumentException(ex); + } + + // Add the entry + Element manifestRoot = manifestDoc.getDocumentElement(); + + manifestRoot.setAttribute("xmlns:manifest", "http://openoffice.org/2001/manifest"); + + Element docRoot = manifestDoc.createElement(TAG_MANIFEST_FILE); + + docRoot.setAttribute(ATTRIBUTE_MANIFEST_FILE_PATH, "/"); + docRoot.setAttribute(ATTRIBUTE_MANIFEST_FILE_TYPE, getDocumentMimeType()); + + manifestRoot.appendChild(docRoot); + } +} diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/OfficeDocumentException.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/OfficeDocumentException.java new file mode 100644 index 000000000..12799065b --- /dev/null +++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/OfficeDocumentException.java @@ -0,0 +1,112 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +package org.openoffice.xmerge.converter.xml; + +import java.io.IOException; + +import org.xml.sax.SAXException; +import org.xml.sax.SAXParseException; + +import org.openoffice.xmerge.util.Resources; + +/** + * Used by OfficeDocument to encapsulate exceptions. + * + *

It will add more details to the message string if it is of type + * {@code SAXParseException}.

+ */ +public final class OfficeDocumentException extends IOException { + + /** + * Constructor, capturing additional information from the {@code SAXException}. + * + * @param e The {@code SAXException}. + */ + public OfficeDocumentException(SAXException e) { + super(constructMessage(e)); + if (e.getException() != null) { + initCause(e.getException()); + } else { + initCause(e); + } + } + + private static String constructMessage(SAXException e) { + StringBuffer message = new StringBuffer(); + if (e instanceof SAXParseException) { + String msgParseError = + Resources.getInstance().getString("PARSE_ERROR"); + String msgLine = + Resources.getInstance().getString("LINE"); + String msgColumn = + Resources.getInstance().getString("COLUMN"); + String msgPublicId = + Resources.getInstance().getString("PUBLIC_ID"); + String msgSystemId = + Resources.getInstance().getString("SYSTEM_ID"); + SAXParseException spe = (SAXParseException) e; + message.append(msgParseError); + message.append(": "); + message.append(msgLine); + message.append(": "); + message.append(spe.getLineNumber()); + message.append(", "); + message.append(msgColumn); + message.append(": "); + message.append(spe.getColumnNumber()); + message.append(", "); + message.append(msgSystemId); + message.append(": "); + message.append(spe.getSystemId()); + message.append(", "); + message.append(msgPublicId); + message.append(": "); + message.append(spe.getPublicId()); + message.append("\n"); + } + + // if there exists an embedded exception + Exception ex = e.getException(); + if (ex != null) { + message.append(ex.getMessage()); + } + return message.toString(); + } + + /** + * Constructor, creates exception with provided message. + * + * @param s Message value for the exception. + */ + public OfficeDocumentException(String s) { + super(s); + } + + /** + * Constructor, creates exception with the message corresponding to the + * message value of the provided exception. + * + * @param e The {@code Exception}. + */ + public OfficeDocumentException(Exception e) { + super(e.getMessage()); + initCause(e); + } + +} \ No newline at end of file diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/OfficeZip.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/OfficeZip.java new file mode 100644 index 000000000..4965885b4 --- /dev/null +++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/OfficeZip.java @@ -0,0 +1,424 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +package org.openoffice.xmerge.converter.xml; + +import java.util.List; +import java.util.ListIterator; +import java.util.LinkedList; +import java.util.zip.ZipInputStream; +import java.util.zip.ZipOutputStream; +import java.util.zip.ZipEntry; +import java.util.zip.CRC32; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.IOException; +import java.io.ByteArrayOutputStream; + +import org.openoffice.xmerge.util.Debug; + +/** + * Class used by {@link org.openoffice.xmerge.converter.xml.OfficeDocument + * OfficeDocument} to handle reading and writing from a ZIP file, as well as + * storing ZIP entries. + */ +class OfficeZip { + + /** File name of the XML file in a zipped document. */ + private static final String CONTENTXML = "content.xml"; + + private static final String STYLEXML = "styles.xml"; + private static final String METAXML = "meta.xml"; + private static final String SETTINGSXML = "settings.xml"; + private static final String MANIFESTXML = "META-INF/manifest.xml"; + + private static final int BUFFERSIZE = 1024; + + private final List entryList; + + private int contentIndex = -1; + private int styleIndex = -1; + private int metaIndex = -1; + private int settingsIndex = -1; + private int manifestIndex = -1; + + /** Default constructor. */ + OfficeZip() { + + entryList = new LinkedList(); + } + + /** + * Read each zip entry in the {@code InputStream} object and store in + * entryList both the {@code ZipEntry} object as well as the bits of each + * entry. + * + *

Call this method before calling the {@code getContentXMLBytes} method + * or the {@code getStyleXMLBytes} method.

+ * + *

Keep track of the {@code CONTENTXML} and {@code STYLEXML} using + * {@code contentIndex} and {@code styleIndex}, respectively.

+ * + * @param is {@code InputStream} object to read. + * + * @throws IOException If any I/O error occurs. + */ + void read(InputStream is) throws IOException { + + ZipInputStream zis = new ZipInputStream(is); + ZipEntry ze; + int i = -1; + + while ((ze = zis.getNextEntry()) != null) { + + String name = ze.getName(); + + Debug.log(Debug.TRACE, "reading entry: " + name); + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + int len; + byte buffer[] = new byte[BUFFERSIZE]; + + while ((len = zis.read(buffer)) > 0) { + baos.write(buffer, 0, len); + } + + byte bytes[] = baos.toByteArray(); + Entry entry = new Entry(ze,bytes); + + entryList.add(entry); + + i++; + + if (name.equalsIgnoreCase(CONTENTXML)) { + contentIndex = i; + } + else if (name.equalsIgnoreCase(STYLEXML)) { + styleIndex = i; + } + else if (name.equalsIgnoreCase(METAXML)) { + metaIndex = i; + } + else if (name.equalsIgnoreCase(SETTINGSXML)) { + settingsIndex = i; + } + else if (name.equalsIgnoreCase(MANIFESTXML)) { + manifestIndex = i; + } + + } + + zis.close(); + } + + /** + * This method returns the CONTENTXML file in a {@code byte} array. + * + *

It returns null if there is no {@code CONTENTXML} in this zip file.

+ * + * @return CONTENTXML in a {@code byte} array. + */ + byte[] getContentXMLBytes() { + + return getEntryBytes(contentIndex); + } + + /** + * This method returns the {@code STYLEXML} file in a {@code byte} array. + * + *

It returns {@code null} if there is no {@code STYLEXML} in this zip + * file.

+ * + * @return STYLEXML in a {@code byte} array. + */ + byte[] getStyleXMLBytes() { + + return getEntryBytes(styleIndex); + } + + /** + * This method returns the METAXML file in a {@code byte} array. + * + *

It returns {@code null} if there is no {@code METAXML} in this zip + * file.

+ * + * @return METAXML in a {@code byte} array. + */ + byte[] getMetaXMLBytes() { + return getEntryBytes(metaIndex); + } + + /** + * This method returns the {@code SETTINGSXML} file in a {@code byte} array. + * + *

It returns {@code null} if there is no {@code SETTINGSXML} in this zip + * file.

+ * + * @return SETTINGSXML in a byte array. + */ + byte[] getSettingsXMLBytes() { + return getEntryBytes(settingsIndex); + } + + /** + * This method returns the {@code MANIFESTXML} file in a {@code byte} array. + * + *

It returns {@code null} if there is no {@code MANIFESTXML} in this zip + * file.

+ * + * @return MANIFESTXML in a {@code byte} array. + */ + byte[] getManifestXMLBytes() { + return getEntryBytes(manifestIndex); + } + + /** + * This method returns the bytes corresponding to the entry named in the + * parameter. + * + * @param name The name of the entry in the Zip file to retrieve. + * + * @return The data for the named entry in a {@code byte} array or + * {@code null} if no entry is found. + */ + byte[] getNamedBytes(String name) { + + // The list is not sorted, and sorting it for a binary search would + // invalidate the indices stored for the main files. + + // Could improve performance by caching the name and index when + // iterating through the ZipFile in read(). + for (int i = 0; i < entryList.size(); i++) { + Entry e = entryList.get(i); + + if (e.zipEntry.getName().equals(name)) { + return getEntryBytes(i); + } + } + + return null; + } + + /** + * This method sets the bytes for the named entry. + * + *

It searches for a matching entry in the LinkedList. If no entry is + * found, a new one is created.

+ * + *

Writing of data is deferred to {@code setEntryBytes()}.

+ * + * @param name The name of the entry to search for. + * @param bytes The new data to write. + */ + void setNamedBytes(String name, byte[] bytes) { + for (int i = 0; i < entryList.size(); i++) { + Entry e = entryList.get(i); + + if (e.zipEntry.getName().equals(name)) { + setEntryBytes(i, bytes, name); + return; + } + } + + // If we're here, no entry was found. Call setEntryBytes with an index + // of -1 to insert a new entry. + setEntryBytes(-1, bytes, name); + } + + /** + * Used by the {@code getContentXMLBytes} method and the + * {@code getStyleXMLBytes} method to return the {@code byte} array from the + * corresponding {@code Entry} in the {@code entryList}. + * + * @param index Index of {@code Entry} object in {@code entryList}. + * + * @return {@code byte} array associated in that {@code Entry} object or + * {@code null}, if there is not such {@code Entry}. + */ + private byte[] getEntryBytes(int index) { + + byte[] bytes = null; + + if (index > -1) { + Entry entry = entryList.get(index); + bytes = entry.bytes; + } + return bytes; + } + + /** + * Set or replace the byte array for the {@code CONTENTXML} file. + * + * @param bytes {@code byte} array for the {@code CONTENTXML} file. + */ + void setContentXMLBytes(byte bytes[]) { + + contentIndex = setEntryBytes(contentIndex, bytes, CONTENTXML); + } + + /** + * Set or replace the {@code byte} array for the {@code STYLEXML} file. + * + * @param bytes {@code byte} array for the {@code STYLEXML} file. + */ + void setStyleXMLBytes(byte bytes[]) { + + styleIndex = setEntryBytes(styleIndex, bytes, STYLEXML); + } + + /** + * Set or replace the {@code byte} array for the {@code METAXML} file. + * + * @param bytes {@code byte} array for the {@code METAXML} file. + */ + void setMetaXMLBytes(byte bytes[]) { + + metaIndex = setEntryBytes(metaIndex, bytes, METAXML); + } + + /** + * Set or replace the {@code byte} array for the {@code SETTINGSXML} file. + * + * @param bytes {@code byte} array for the {@code SETTINGSXML} file. + */ + void setSettingsXMLBytes(byte bytes[]) { + + settingsIndex = setEntryBytes(settingsIndex, bytes, SETTINGSXML); + } + + /** + * Set or replace the {@code byte} array for the {@code MANIFESTXML} file. + * + * @param bytes {@code byte} array for the {@code MANIFESTXML} file. + */ + void setManifestXMLBytes(byte bytes[]) { + manifestIndex = setEntryBytes(manifestIndex, bytes, MANIFESTXML); + } + + /** + * Used by the {@code setContentXMLBytes} method and the + * {@code setStyleXMLBytes} to either replace an existing {@code Entry}, or + * create a new entry in {@code entryList}. + * + *

If there is an {@code Entry} object within {@code entryList} that + * corresponds to the index, replace the {@code ZipEntry} info.

+ * + * @param index Index of Entry to modify. + * @param bytes Entry value. + * @param name Name of Entry. + * + * @return Index of value added or modified in entryList + */ + private int setEntryBytes(int index, byte bytes[], String name) { + + if (index > -1) { + // replace existing entry in entryList + Entry entry = entryList.get(index); + name = entry.zipEntry.getName(); + int method = entry.zipEntry.getMethod(); + + ZipEntry ze = createZipEntry(name, bytes, method); + + entry.zipEntry = ze; + entry.bytes= bytes; + + } else { + // add a new entry into entryList + ZipEntry ze = createZipEntry(name, bytes, ZipEntry.DEFLATED); + Entry entry = new Entry(ze, bytes); + entryList.add(entry); + index = entryList.size() - 1; + } + + return index; + } + + /** + * Write out the ZIP entries into the {@code OutputStream} object. + * + * @param os OutputStream object to write ZIP. + * + * @throws IOException If any ZIP I/O error occurs. + */ + void write(OutputStream os) throws IOException { + + Debug.log(Debug.TRACE, "Writing out the following entries into zip."); + + ZipOutputStream zos = new ZipOutputStream(os); + + ListIterator iterator = entryList.listIterator(); + while (iterator.hasNext()) { + + Entry entry = iterator.next(); + ZipEntry ze = entry.zipEntry; + + String name = ze.getName(); + + Debug.log(Debug.TRACE, "... " + name); + + zos.putNextEntry(ze); + zos.write(entry.bytes); + } + + zos.close(); + } + + /** + * Creates a {@code ZipEntry} object based on the given parameters. + * + * @param name Name for the {@code ZipEntry}. + * @param bytes {@code byte} array for {@code ZipEntry}. + * @param method ZIP method to be used for {@code ZipEntry}. + * + * @return A {@code ZipEntry} object. + */ + private ZipEntry createZipEntry(String name, byte bytes[], int method) { + + ZipEntry ze = new ZipEntry(name); + + ze.setMethod(method); + ze.setSize(bytes.length); + + CRC32 crc = new CRC32(); + crc.reset(); + crc.update(bytes); + ze.setCrc(crc.getValue()); + + ze.setTime(System.currentTimeMillis()); + + return ze; + } + + /** + * This inner class is used as a data structure for holding a {@code ZipEntry} + * info and its corresponding bytes. + * + *

These are stored in {@code entryList}.

+ */ + private static class Entry { + + ZipEntry zipEntry = null; + byte bytes[] = null; + + Entry(ZipEntry zipEntry, byte bytes[]) { + this.zipEntry = zipEntry; + this.bytes = bytes; + } + } +} \ No newline at end of file diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/ParaStyle.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/ParaStyle.java new file mode 100644 index 000000000..786e82b77 --- /dev/null +++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/ParaStyle.java @@ -0,0 +1,528 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +package org.openoffice.xmerge.converter.xml; + +import org.w3c.dom.NodeList; +import org.w3c.dom.Node; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Element; + +import org.openoffice.xmerge.util.Debug; + +abstract class conversionAlgorithm { + abstract int I(String val); +} + +/** + * This algorithm expects only values in millimeters, e.g. {@literal "20.3mm"}. + */ +class horizSize extends conversionAlgorithm { + @Override + int I(String value) { + if (value.endsWith("mm")) { + float size = (float)0.0; + String num = value.substring(0, value.length() - 2); + try { + size = Float.parseFloat(num); + } catch (Exception e) { + Debug.log(Debug.ERROR, "Error parsing " + value, e); + } + size *= 100; + return (int)size; + } else { + Debug.log(Debug.ERROR, "Unexpected value (" + value + + ") in horizSize.I()"); + return 0; + } + } +} + +/** + * This algorithm does line height {@literal -} can be either millimeters or a + * percentage. + */ +class lineHeight extends conversionAlgorithm { + @Override + int I(String value) { + if (value.endsWith("mm")) { + float size = (float)0.0; + String num = value.substring(0, value.length() - 2); + try { + size = Float.parseFloat(num); + } catch (Exception e) { + Debug.log(Debug.ERROR, "Error parsing " + value, e); + } + size *= 100; + return (int)size; + } else if (value.endsWith("%")) { + float size = (float)0.0; + String num = value.substring(0, value.length() - 1); + try { + size = Float.parseFloat(num); + } catch (Exception e) { + Debug.log(Debug.ERROR, "Error parsing " + value, e); + } + int retval = (int) size; + retval |= ParaStyle.LH_PCT; + return retval; + } + return 0; + } +} + +/** + * This class converts alignment values. + */ +class alignment extends conversionAlgorithm { + @Override + int I(String value) { + if (value.equals("end")) + return ParaStyle.ALIGN_RIGHT; + if (value.equals("right")) + return ParaStyle.ALIGN_RIGHT; + if (value.equals("center")) + return ParaStyle.ALIGN_CENTER; + if (value.equals("justify")) + return ParaStyle.ALIGN_JUST; + if (value.equals("justified")) + return ParaStyle.ALIGN_JUST; + if (value.equals("start")) + return ParaStyle.ALIGN_LEFT; + if (value.equals("left")) + return ParaStyle.ALIGN_LEFT; + Debug.log(Debug.ERROR, "Unknown string (" + + value + ") in alignment.I()"); + return ParaStyle.ALIGN_LEFT; + } +} + +/** + * This class represents a paragraph {@code Style}. + * + *
+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Table with all paragraph style attributes and their values
AttributeValue
MARGIN_LEFTmm * 100
MARGIN_RIGHTmm * 100
MARGIN_TOPmm * 100 (space on top of paragraph)
MARGIN_BOTTOMmm * 100
TEXT_INDENTmm * 100 (first line indent)
LINE_HEIGHTmm * 100, unless or'ed with LH_PCT, in which case it is a percentage + * (e.g. 200% for double spacing) Can also be or'ed with LH_ATLEAST. + * Value is stored in bits indicated by LH_VALUEMASK.
TEXT_ALIGNALIGN_RIGHT, ALIGN_CENTER, ALIGN_JUST, ALIGN_LEFT
+ */ +public class ParaStyle extends Style implements Cloneable { + + /** Indent left property. */ + private static final int TEXT_INDENT = 4; + /** Indent right property. */ + private static final int LINE_HEIGHT = 5; + /** Align text property. */ + private static final int TEXT_ALIGN = 6; + // This must always be one more than highest property + /** Total number of properties. */ + private static final int NR_PROPERTIES = 7; + + /** + * Array of flags indicating which attributes are set for this paragraph + * {@code Style}. + */ + private boolean isSet[] = new boolean[NR_PROPERTIES]; + /** Array of attribute values for this paragraph {@code Style}. */ + private int value[] = new int[NR_PROPERTIES]; + /** Array of attribute names for this paragraph {@code Style}. */ + private final String attrName[] = { + "fo:margin-left", + "fo:margin-right", + "fo:margin-top", + "fo:margin-bottom", + "fo:text-indent", + "fo:line-height", + "fo:text-align" + }; + + /** Array of attribute structures for this paragraph {@code Style}. */ + private final Class algor[] = { + horizSize.class, + horizSize.class, + horizSize.class, + horizSize.class, + horizSize.class, + lineHeight.class, + alignment.class + }; + + /** Align right. */ + public static final int ALIGN_RIGHT = 1; + /** Align center. */ + public static final int ALIGN_CENTER = 2; + /** Align justified. */ + public static final int ALIGN_JUST = 3; + /** Align left. */ + public static final int ALIGN_LEFT = 4; + + /** Line height percentage. */ + public static final int LH_PCT = 0x40000000; + + /** Line height mask. */ + private static final int LH_VALUEMASK = 0x00FFFFFF; + + /** Ignored tags. */ + private static String[] ignored = { + "style:font-name", "fo:font-size", "fo:font-weight", "fo:color", + "fo:language", "fo:country", "style:font-name-asian", + "style:font-size-asian", "style:language-asian", + "style:country-asian", "style:font-name-complex", + "style:font-size-complex", "style:language-complex", + "style:country-complex", "style:text-autospace", "style:punctuation-wrap", + "style:line-break", "fo:keep-with-next", "fo:font-style", + "text:number-lines", "text:line-number" + }; + + /** + * Constructor for use when going from DOM to client device format. + * + * @param node A style:style {@code Node} which, which is assumed + * to have family attribute of paragraph. + * @param sc The {@code StyleCatalog}, which is used for looking up + * ancestor {@code Style} objects. + */ + public ParaStyle(Node node, StyleCatalog sc) { + + super(node, sc); + + // Look for children. Only ones we care about are "style:properties" + // nodes. If any are found, recursively traverse them, passing + // along the style element to add properties to. + + if (node.hasChildNodes()) { + NodeList children = node.getChildNodes(); + int len = children.getLength(); + for (int i = 0; i < len; i++) { + Node child = children.item(i); + String nodeName = child.getNodeName(); + if (nodeName.equals("style:properties")) { + NamedNodeMap childAttrNodes = child.getAttributes(); + if (childAttrNodes != null) { + int nChildAttrNodes = childAttrNodes.getLength(); + for (int j = 0; j < nChildAttrNodes; j++) { + Node attr = childAttrNodes.item(j); + setAttribute(attr.getNodeName(), attr.getNodeValue()); + } + } + } + } + } + } + + /** + * Constructor for use when going from client device format to DOM. + * + * @param name Name of the {@code Style}. Can be {@code null}. + * @param familyName Family of the {@code Style} {@literal -} usually + * paragraph, text, etc. Can be {@code null}. + * @param parentName Name of the parent {@code Style}, or {@code null} + * if none. + * @param attribs Array of attributes to set. + * @param values Array of values to set. + * @param sc The {@code StyleCatalog}, which is used for looking up + * ancestor {@code Style} objects. + */ + public ParaStyle(String name, String familyName, String parentName, + String attribs[], String values[], StyleCatalog sc) { + super(name, familyName, parentName, sc); + if (attribs != null) + for (int i = 0; i < attribs.length; i++) + setAttribute(attribs[i], values[i]); + } + + /** + * Alternate constructor for use when going from client device format to DOM. + * + * @param name Name of the {@code Style}. Can be {@code null}. + * @param familyName Family of the {@code Style} {@literal -} usually + * paragraph, text, etc. Can be {@code null}. + * @param parentName Name of the parent {@code Style}, or null if none. + * @param attribs Array of attributes indices to set. + * @param values Array of values to set. + * @param lookup The {@code StyleCatalog}, which is used for looking + * up ancestor {@code Style} objects. + */ + public ParaStyle(String name, String familyName, String parentName, + int attribs[], String values[], StyleCatalog lookup) { + super(name, familyName, parentName, lookup); + if (attribs != null) + for (int i = 0; i < attribs.length; i++) + setAttribute(attribs[i], values[i]); + } + + /** + * This code checks whether an attribute is one that we intentionally ignore. + * + * @param attribute The attribute to check. + * + * @return {@code true} if attribute can be ignored, {@code false} otherwise. + */ + private boolean isIgnored(String attribute) { + for (int i = 0; i < ignored.length; i++) { + if (ignored[i].equals(attribute)) + return true; + } + return false; + } + + /** + * Set an attribute for this paragraph {@code Style}. + * + * @param attr The attribute to set. + * @param value The attribute value to set. + */ + private void setAttribute(String attr, String value) { + for (int i = 0; i < NR_PROPERTIES; i++) { + if (attr.equals(attrName[i])) { + setAttribute(i, value); + return; + } + } + if (!isIgnored(attr)) + Debug.log(Debug.INFO, "ParaStyle Unhandled: " + attr + "=" + value); + } + + /** + * Set an attribute for this paragraph {@code Style}. + * + * @param attr The attribute index to set. + * @param value The attribute value to set. + */ + private void setAttribute(int attr, String value) { + isSet[attr] = true; + try { + this.value[attr] = ((conversionAlgorithm)algor[attr].newInstance()).I(value); + } catch (Exception e) { + Debug.log(Debug.ERROR, "Instantiation error", e); + } + } + + /** + * Return the {@code Style} in use. + * + * @return The fully-resolved copy of the {@code Style} in use. + */ + @Override + public Style getResolved() { + ParaStyle resolved = null; + try { + resolved = (ParaStyle)this.clone(); + } catch (Exception e) { + Debug.log(Debug.ERROR, "Can't clone", e); + } + + // Look up the parent style. (If there is no style catalog + // specified, we can't do any lookups). + ParaStyle parentStyle = null; + if (sc != null) { + if (parent != null) { + parentStyle = (ParaStyle)sc.lookup(parent, family, null, + this.getClass()); + if (parentStyle == null) + Debug.log(Debug.ERROR, "parent style lookup of " + + parent + " failed!"); + else + parentStyle = (ParaStyle)parentStyle.getResolved(); + } else if (!name.equals("DEFAULT_STYLE")) { + parentStyle = (ParaStyle)sc.lookup("DEFAULT_STYLE", null, null, + this.getClass()); + } + } + + // If we found a parent, for any attributes which we don't have + // set, try to get the values from the parent. + if (parentStyle != null) { + parentStyle = (ParaStyle)parentStyle.getResolved(); + for (int i = 0; i < NR_PROPERTIES; i++) { + if (!isSet[i] && parentStyle.isSet[i]) { + resolved.isSet[i] = true; + resolved.value[i] = parentStyle.value[i]; + } + } + } + return resolved; + } + + /** + * Private function to return the value as an element in a Comma Separated + * Value (CSV) format. + * + * @param value The value to format. + * + * @return The formatted value. + */ + private static String toCSV(String value) { + if (value != null) + return "\"" + value + "\","; + else + return "\"\","; + } + + /** + * Private function to return the value as a last element in a Comma + * Separated Value (CSV) format. + * + * @param value The value to format. + * + * @return The formatted value. + */ + private static String toLastCSV(String value) { + if (value != null) + return "\"" + value + "\""; + else + return "\"\""; + } + + /** + * Print a Comma Separated Value (CSV) header line for the spreadsheet dump. + */ + public static void dumpHdr() { + System.out.println(toCSV("Name") + toCSV("Family") + toCSV("parent") + + toCSV("left mgn") + toCSV("right mgn") + + toCSV("top mgn") + toCSV("bottom mgn") + toCSV("txt indent") + + toCSV("line height") + toLastCSV("txt align")); + } + + /** + * Dump this {@code Style} as a Comma Separated Value (CSV) line. + */ + public void dumpCSV() { + String attributes = ""; + for (int index = 0; index <= 6; index++) { + if (isSet[index]) { + attributes += toCSV("" + value[index]); + } + else + attributes += toCSV(null); // unspecified + } + System.out.println(toCSV(name) + toCSV(family) + toCSV(parent) + + attributes + toLastCSV(null)); + } + + /** + * Create the {@code Node} with the specified elements. + * + * @param parentDoc Parent {@code Document} of the {@code Node} to create. + * @param name Name of the {@code Node}. + * + * @return The created {@code Node}. + */ + @Override + public Node createNode(org.w3c.dom.Document parentDoc, String name) { + Element node = parentDoc.createElement(name); + writeAttributes(node); + return node; + } + + /** + * Return {@code true} if {@code style} is a subset of the {@code Style}. + * + * @param style {@code Style} to check. + * + * @return {@code true} if style is a subset, {@code false} + * otherwise. + */ + @Override + public boolean isSubset(Style style) { + + if (!super.isSubset(style)) + return false; + if (!this.getClass().isAssignableFrom(style.getClass())) + return false; + ParaStyle ps = (ParaStyle)style; + + for (int i = 0; i < NR_PROPERTIES; i++) { + if (ps.isSet[i]) { + if (i < NR_PROPERTIES - 1) { + // Compare the actual values. We allow a margin of error + // here because the conversion loses precision. + int diff; + if (value[i] > ps.value[i]) + diff = value[i] - ps.value[i]; + else + diff = ps.value[i] - value[i]; + if (diff > 32) + return false; + } else { + if (i == TEXT_ALIGN) + if ((value[i] == 0) && (ps.value[i] == 4)) + continue; + if (value[i] != ps.value[i]) + return false; + } + } + } + return true; + } + + /** + * Add {@code Style} attributes to the given {@code Node}. + * + *

This may involve writing child {@code Node} objects as well.

+ * + * @param node The {@code Node} to add {@code Style} attributes. + */ + private void writeAttributes(Element node) { + for (int i = 0; i <= TEXT_INDENT; i++) { + if (isSet[i]) { + double temp = value[i] / 100.0; + String stringVal = Double.toString(temp) + "mm"; + node.setAttribute(attrName[i], stringVal); + } + } + + if (isSet[LINE_HEIGHT]) { + String stringVal; + if ((value[LINE_HEIGHT] & LH_PCT) != 0) + stringVal = Integer.toString(value[LINE_HEIGHT] & LH_VALUEMASK) + "%"; + else { + double temp = (value[LINE_HEIGHT] & LH_VALUEMASK) / 100.0; + stringVal = Double.toString(temp) + "mm"; + } + node.setAttribute(attrName[LINE_HEIGHT], stringVal); + } + + if (isSet[TEXT_ALIGN]) { + String val; + switch (value[TEXT_ALIGN]) { + case ALIGN_RIGHT: val = "end"; break; + case ALIGN_CENTER: val = "center"; break; + case ALIGN_JUST: val = "justify"; break; + case ALIGN_LEFT: val = "left"; break; + default: val = "unknown"; break; + } + node.setAttribute(attrName[TEXT_ALIGN], val); + } + } +} \ No newline at end of file diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/Style.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/Style.java new file mode 100644 index 000000000..d28d6a45f --- /dev/null +++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/Style.java @@ -0,0 +1,191 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +package org.openoffice.xmerge.converter.xml; + +import org.w3c.dom.Node; +import org.w3c.dom.NamedNodeMap; + +/** + * An object of class {@code Style} represents a style in an OpenOffice + * document. + * + *

In practice subclasses of this {@code Style}, such as {@code TextStyle}, + * {@code ParaStyle} are used.

+ * + * @see TextStyle + * @see ParaStyle + */ +public class Style { + + /** Name of the {@code Style}. */ + protected String name = null; + /** Family of the {@code Style}. */ + protected String family = null; + /** Parent of the {@code Style}. */ + protected String parent = null; + + /** + * A reference to the {@code StyleCatalog} to be used for looking up ancestor + * {@code Style} objects. + */ + protected StyleCatalog sc; + + /** + * Constructor for use when going from DOM to client device format. + * + * @param node A style:style or style:default-style + * {@code Node} from the document being parsed. No checking of + * {@code Node} is done, so if it is not of the proper type + * the results will be unpredictable. + * @param sc The {@code StyleCatalog}, which is used for looking up + * ancestor {@code Style} objects. + */ + public Style(Node node, StyleCatalog sc) { + + this.sc = sc; + + // Run through the attributes of this node, saving + // the ones we're interested in. + if (node.getNodeName().equals("style:default-style")) + name = "DEFAULT_STYLE"; + NamedNodeMap attrNodes = node.getAttributes(); + if (attrNodes != null) { + int len = attrNodes.getLength(); + for (int i = 0; i < len; i++) { + Node attr = attrNodes.item(i); + if (attr.getNodeName().equals("style:family")) + family = attr.getNodeValue(); + else if (attr.getNodeName().equals("style:name")) { + name = attr.getNodeValue(); + } else if (attr.getNodeName().equals("style:parent-style-name")) + parent = attr.getNodeValue(); + + } + } + } + + /** + * Constructor for use when going from client device format to DOM. + * + * @param name Name of the {@code Style}. Can be {@code null}. + * @param family Family of the {@code Style} {@literal -} usually + * paragraph, text, etc. Can be {@code null}. + * @param parent Name of the parent {@code Style}, or {@code null} if none. + * @param sc The {@code StyleCatalog}, which is used for looking up + * ancestor {@code Style} objects. + */ + public Style(String name, String family, String parent, StyleCatalog sc) { + this.sc = sc; + this.name = name; + this.family = family; + this.parent = parent; + } + + /** + * Set the {@code StyleCatalog} to be used when looking up the {@code Style} + * parent. + * + * @param sc The {@code StyleCatalog}, which is used for looking up + * ancestor {@code Style} objects. + */ + public void setCatalog(StyleCatalog sc) { + this.sc = sc; + } + + /** + * Returns the name of this {@code Style}. + * + * @return The name of this {@code Style}. + */ + public String getName() { + return name; + } + + /** + * Sets the name of this {@code Style}. + * + * @param newName The new name of this {@code Style}. + */ + public void setName(String newName) { + name = newName; + } + + /** + * Return the family of this {@code Style}. + * + * @return The family of this {@code Style}. + */ + public String getFamily() { + return family; + } + + /** + * Return the name of the parent of this {@code Style}. + * + * @return The parent of this {@code Style}. + */ + public String getParent() { + return parent; + } + + /** + * Return a {@code Style} object corresponding to this one, but with all of + * the inherited information from parent {@code Style} objects filled in. + * + *

The object returned will be a new object, not a reference to this + * object, even if it does not need any information added.

+ * + * @return A resolved {@code Style} object in which to look up ancestors. + */ + public Style getResolved() { + return new Style(name, family, parent, sc); + } + + /** + * Write a {@code Node} in {@code parentDoc} representing this {@code Style}. + * + *

Note that the {@code Node} is returned unconnected.

+ * + * @param parentDoc Document to which new {@code Node} will belong. + * @param name Name to use for new {@code Node}. + */ + public Node createNode(org.w3c.dom.Document parentDoc, String name) { + // DJP: write this! Should call writeAttributes() + return null; + } + + /** + * Return {@code true} if {@code Style} is a subset of this one. + * + *

Note that this will return true even if {@code Style} is less specific + * than this {@code Style}, so long as it does not contradict this + * {@code Style} in any way.

+ * + *

This always returns true since only subclasses of {@code Style} + * contain any actual {@code Style} information.

+ * + * @param style The {@code Style} to check. + * + * @return {@code true} if the {@code Style} is a subset, {@code false} + * otherwise. + */ + public boolean isSubset(Style style) { + return true; + } +} \ No newline at end of file diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/StyleCatalog.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/StyleCatalog.java new file mode 100644 index 000000000..f08d664d9 --- /dev/null +++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/StyleCatalog.java @@ -0,0 +1,284 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +package org.openoffice.xmerge.converter.xml; + +import java.lang.reflect.Constructor; +import java.util.ArrayList; + +import org.openoffice.xmerge.util.Debug; +import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +/** + * A {@code StyleCatalog} holds a collection of {@code Style} objects. + * + *

It is intended for use when parsing or building a DOM document.

+ * + *

Each entry in the {@code StyleCatalog} represents a {@code Style}, and is + * an object which is a subclass of {@code Style}.

+ * + * @see Style + */ +public class StyleCatalog { + + private final ArrayList