summaryrefslogtreecommitdiff
path: root/xmerge
diff options
context:
space:
mode:
Diffstat (limited to 'xmerge')
-rw-r--r--xmerge/build.xml88
-rw-r--r--xmerge/inc/makefile.mk47
-rw-r--r--xmerge/inc/pch/precompiled_xmerge.cxx29
-rw-r--r--xmerge/inc/pch/precompiled_xmerge.hxx32
-rw-r--r--xmerge/prj/build.lst11
-rw-r--r--xmerge/prj/d.lst12
-rw-r--r--xmerge/source/activesync/BIN/xmergesync.dllbin0 -> 86016 bytes
-rw-r--r--xmerge/source/activesync/XMergeFactory.cpp90
-rw-r--r--xmerge/source/activesync/XMergeFactory.h34
-rw-r--r--xmerge/source/activesync/XMergeFilter.cpp495
-rw-r--r--xmerge/source/activesync/XMergeFilter.h73
-rw-r--r--xmerge/source/activesync/XMergeSync.cpp837
-rw-r--r--xmerge/source/activesync/XMergeSync.def9
-rw-r--r--xmerge/source/activesync/XMergeSync.dsp143
-rw-r--r--xmerge/source/activesync/XMergeSync.dsw33
-rw-r--r--xmerge/source/activesync/XMergeSync.h29
-rw-r--r--xmerge/source/activesync/XMergeSync.rc80
-rw-r--r--xmerge/source/activesync/exports.map12
-rw-r--r--xmerge/source/activesync/guids.txt60
-rw-r--r--xmerge/source/activesync/makefile.mk72
-rw-r--r--xmerge/source/activesync/resource.h17
-rw-r--r--xmerge/source/activesync/stdafx.cpp7
-rw-r--r--xmerge/source/activesync/stdafx.h28
-rw-r--r--xmerge/source/aportisdoc/build.xml76
-rw-r--r--xmerge/source/aportisdoc/converter.xml45
-rw-r--r--xmerge/source/aportisdoc/java/org/openoffice/xmerge/converter/xml/sxw/aportisdoc/ConverterCapabilitiesImpl.java93
-rw-r--r--xmerge/source/aportisdoc/java/org/openoffice/xmerge/converter/xml/sxw/aportisdoc/DocConstants.java69
-rw-r--r--xmerge/source/aportisdoc/java/org/openoffice/xmerge/converter/xml/sxw/aportisdoc/DocDecoder.java301
-rw-r--r--xmerge/source/aportisdoc/java/org/openoffice/xmerge/converter/xml/sxw/aportisdoc/DocEncoder.java213
-rw-r--r--xmerge/source/aportisdoc/java/org/openoffice/xmerge/converter/xml/sxw/aportisdoc/DocumentDeserializerImpl.java312
-rw-r--r--xmerge/source/aportisdoc/java/org/openoffice/xmerge/converter/xml/sxw/aportisdoc/DocumentMergerImpl.java97
-rw-r--r--xmerge/source/aportisdoc/java/org/openoffice/xmerge/converter/xml/sxw/aportisdoc/DocumentSerializerImpl.java531
-rw-r--r--xmerge/source/aportisdoc/java/org/openoffice/xmerge/converter/xml/sxw/aportisdoc/PluginFactoryImpl.java141
-rw-r--r--xmerge/source/aportisdoc/java/org/openoffice/xmerge/converter/xml/sxw/aportisdoc/package.html239
-rw-r--r--xmerge/source/aportisdoc/makefile.mk35
-rw-r--r--xmerge/source/bridge/XMergeBridge.component34
-rw-r--r--xmerge/source/bridge/antcall.txt19
-rw-r--r--xmerge/source/bridge/build.xml81
-rw-r--r--xmerge/source/bridge/java/XMergeBridge.java697
-rw-r--r--xmerge/source/bridge/makefile.mk43
-rw-r--r--xmerge/source/bridge/manifest.mf3
-rw-r--r--xmerge/source/htmlsoff/build.xml67
-rw-r--r--xmerge/source/htmlsoff/converter.xml52
-rw-r--r--xmerge/source/htmlsoff/htmltosoff.xsl176
-rw-r--r--xmerge/source/htmlsoff/makefile.mk35
-rw-r--r--xmerge/source/htmlsoff/package.html67
-rw-r--r--xmerge/source/htmlsoff/sofftohtml.xsl118
-rw-r--r--xmerge/source/inc/antbuild.properties12
-rw-r--r--xmerge/source/inc/antbuild.xml2
-rw-r--r--xmerge/source/minicalc/build.xml76
-rw-r--r--xmerge/source/minicalc/converter.xml45
-rw-r--r--xmerge/source/minicalc/java/org/openoffice/xmerge/converter/xml/sxc/minicalc/ConverterCapabilitiesImpl.java113
-rw-r--r--xmerge/source/minicalc/java/org/openoffice/xmerge/converter/xml/sxc/minicalc/MinicalcConstants.java45
-rw-r--r--xmerge/source/minicalc/java/org/openoffice/xmerge/converter/xml/sxc/minicalc/MinicalcDataString.java545
-rw-r--r--xmerge/source/minicalc/java/org/openoffice/xmerge/converter/xml/sxc/minicalc/MinicalcDecoder.java744
-rw-r--r--xmerge/source/minicalc/java/org/openoffice/xmerge/converter/xml/sxc/minicalc/MinicalcEncoder.java582
-rw-r--r--xmerge/source/minicalc/java/org/openoffice/xmerge/converter/xml/sxc/minicalc/PluginFactoryImpl.java129
-rw-r--r--xmerge/source/minicalc/java/org/openoffice/xmerge/converter/xml/sxc/minicalc/SxcDocumentDeserializerImpl.java138
-rw-r--r--xmerge/source/minicalc/java/org/openoffice/xmerge/converter/xml/sxc/minicalc/SxcDocumentSerializerImpl.java141
-rw-r--r--xmerge/source/minicalc/java/org/openoffice/xmerge/converter/xml/sxc/minicalc/package.html53
-rw-r--r--xmerge/source/minicalc/makefile.mk33
-rw-r--r--xmerge/source/palmtests/README50
-rw-r--r--xmerge/source/palmtests/bin/README6
-rwxr-xr-xxmerge/source/palmtests/bin/rd24
-rwxr-xr-xxmerge/source/palmtests/bin/spose108
-rwxr-xr-xxmerge/source/palmtests/bin/verify_sane.pl110
-rwxr-xr-xxmerge/source/palmtests/qa-wrapper/bin/qa_comparator.pl257
-rwxr-xr-xxmerge/source/palmtests/qa-wrapper/bin/qa_test_driver.pl846
-rwxr-xr-xxmerge/source/palmtests/qa-wrapper/bin/run-convtest538
-rw-r--r--xmerge/source/palmtests/qa-wrapper/env/master.env85
-rw-r--r--xmerge/source/palmtests/qa-wrapper/lists/master.list55
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_animatedgif.pdb6
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_bolddoc.pdb1
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_bookmarks.pdb10
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_bulletorderedlist.pdb8
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_emptydoc.pdb1
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_firstlineindent.pdb1
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_fontsize.pdb6
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_heading.pdb1
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_heading1.pdb1
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_heading2.pdb1
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_hyperlink.pdb6
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_justified.pdb4
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_linebreaks.pdb4
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_linespacing.pdb12
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_numberorderedlist.pdb9
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_pagebreak.pdb4
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_paragraph.pdb1
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_simple01.pdb1
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_simple02.pdb1
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_simple03.pdb1
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_simple04.pdb1
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_simple05.pdb1
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_standard.pdb1
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_subscript.pdb1
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_superscript.pdb1
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_symbols.pdb1
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_tab.pdb8
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_table.pdb2
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_textspan.pdb3
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_unorderedlist.pdb20
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_wordwrap.pdb1
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_addition-Sheet1.pdb1
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_addition-Sheet2.pdb1
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_addition-Sheet3.pdb1
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_alignment-Sheet1.pdb1
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_alignment-Sheet2.pdb1
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_alignment-Sheet3.pdb1
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_backwardrange-Sheet1.pdb1
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_backwardrange-Sheet2.pdb1
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_backwardrange-Sheet3.pdb1
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_basic-Sheet1.pdb1
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_basic-Sheet2.pdb1
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_basic-Sheet3.pdb1
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_boolean-Sheet1.pdb1
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_boolean-Sheet2.pdb1
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_boolean-Sheet3.pdb1
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_cellcurrencyalue-Sheet1.pdb1
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_cellcurrencyalue-Sheet2.pdb1
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_cellcurrencyalue-Sheet3.pdb1
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_cellpercentvalue-Sheet1.pdb1
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_cellpercentvalue-Sheet2.pdb1
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_cellpercentvalue-Sheet3.pdb1
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_cellstringvalue-Sheet1.pdb1
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_cellstringvalue-Sheet2.pdb1
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_cellstringvalue-Sheet3.pdb1
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_columnswidth-Sheet1.pdb1
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_columnswidth-Sheet2.pdb1
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_columnswidth-Sheet3.pdb1
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_cyclic-Sheet1.pdb1
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_cyclic-Sheet2.pdb1
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_cyclic-Sheet3.pdb1
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_dividefloating-Sheet1.pdb1
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_dividefloating-Sheet2.pdb1
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_dividefloating-Sheet3.pdb1
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_forwardrange-Sheet1.pdb1
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_forwardrange-Sheet2.pdb1
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_forwardrange-Sheet3.pdb1
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_insertimage-Sheet1.pdb1
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_insertimage-Sheet2.pdb1
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_insertimage-Sheet3.pdb1
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_invalidcellref-Sheet1.pdb1
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_invalidcellref-Sheet2.pdb1
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_invalidcellref-Sheet3.pdb1
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_largerange-Sheet1.pdb1
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_largerange-Sheet2.pdb1
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_largerange-Sheet3.pdb1
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_listrange-Sheet1.pdb2
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_listrange-Sheet2.pdb2
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_listrange-Sheet3.pdb2
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_mathematical-Sheet1.pdb2
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_mathematical-Sheet2.pdb2
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_mathematical-Sheet3.pdb2
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_protection-Sheet1.pdb1
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_protection-Sheet2.pdb1
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_protection-Sheet3.pdb1
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_sheetreference-Sheet1.pdb1
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_sheetreference-Sheet2.pdb1
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_sheetreference-Sheet3.pdb1
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_simple01-Sheet1.pdb1
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_simple01-Sheet2.pdb1
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_simple01-Sheet3.pdb1
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_simple02-Sheet1.pdb1
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_simple02-Sheet2.pdb1
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_simple02-Sheet3.pdb1
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_simple03-Sheet1.pdb1
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_simple03-Sheet2.pdb1
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_simple03-Sheet3.pdb1
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_simple04-Sheet1.pdb1
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_simple04-Sheet2.pdb1
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_simple04-Sheet3.pdb1
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_smallrange-Sheet1.pdb1
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_smallrange-Sheet2.pdb1
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_smallrange-Sheet3.pdb1
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_styles-Sheet1.pdb1
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_styles-Sheet2.pdb1
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_styles-Sheet3.pdb1
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_textimage-Sheet1.pdb1
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_textimage-Sheet2.pdb1
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_textimage-Sheet3.pdb1
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/Blocklist.dtd34
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_animatedgif.sxwbin0 -> 52952 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_bolddoc.sxwbin0 -> 5500 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_bookmarks.sxwbin0 -> 6047 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_bulletorderedlist.sxwbin0 -> 6347 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_emptydoc.sxwbin0 -> 5701 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_firstlineindent.sxwbin0 -> 5519 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_fontsize.sxwbin0 -> 6130 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_heading.sxwbin0 -> 5518 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_heading1.sxwbin0 -> 5640 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_heading2.sxwbin0 -> 5964 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_hyperlink.sxwbin0 -> 5514 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_justified.sxwbin0 -> 6088 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_linebreaks.sxwbin0 -> 6269 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_linespacing.sxwbin0 -> 5618 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_numberorderedlist.sxwbin0 -> 6188 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_pagebreak.sxwbin0 -> 5534 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_paragraph.sxwbin0 -> 5914 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_simple01.sxwbin0 -> 5823 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_simple02.sxwbin0 -> 5821 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_simple03.sxwbin0 -> 5817 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_simple04.sxwbin0 -> 5792 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_simple05.sxwbin0 -> 5791 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_standard.sxwbin0 -> 5797 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_subscript.sxwbin0 -> 5798 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_superscript.sxwbin0 -> 5799 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_symbols.sxwbin0 -> 4916 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_tab.sxwbin0 -> 5731 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_table.sxwbin0 -> 6011 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_textspan.sxwbin0 -> 5958 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_unorderedlist.sxwbin0 -> 6817 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_wordwrap.sxwbin0 -> 5363 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_addition.sxcbin0 -> 5829 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_alignment.sxcbin0 -> 6383 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_backwardrange.sxcbin0 -> 5995 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_basic.sxcbin0 -> 5830 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_boolean.sxcbin0 -> 6066 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_cellcurrencyalue.sxcbin0 -> 6776 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_cellpercentvalue.sxcbin0 -> 6318 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_cellstringvalue.sxcbin0 -> 6009 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_columnswidth.sxcbin0 -> 6127 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_cyclic.sxcbin0 -> 6005 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_dividefloating.sxcbin0 -> 6315 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_forwardrange.sxcbin0 -> 6058 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_insertimage.sxcbin0 -> 40476 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_invalidcellref.sxcbin0 -> 5838 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_largerange.sxcbin0 -> 6306 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_listrange.sxcbin0 -> 6162 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_mathematical.sxcbin0 -> 6026 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_protection.sxcbin0 -> 6839 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_sheetreference.sxcbin0 -> 6173 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_simple01.sxcbin0 -> 5080 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_simple02.sxcbin0 -> 4962 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_simple03.sxcbin0 -> 4995 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_simple04.sxcbin0 -> 5007 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_smallrange.sxcbin0 -> 5924 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_styles.sxcbin0 -> 6531 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_textimage.sxcbin0 -> 40702 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/chart.mod228
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/datastyl.mod168
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/drawing.mod837
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/dtypes.mod143
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/form.mod308
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/meta.mod90
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/nmspace.mod50
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/office.dtd54
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/office.mod234
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/script.mod51
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/settings.mod49
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/style.mod391
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/table.mod493
-rw-r--r--xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/text.mod1099
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/a_animatedgif.infile4
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/a_bolddoc.infile4
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/a_bookmarks.infile4
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/a_bulletorderedlist.infile4
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/a_emptydoc-mod.infile9
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/a_emptydoc.infile4
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/a_firstlineindent.infile4
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/a_fontsize.infile4
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/a_heading.infile4
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/a_heading1.infile4
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/a_heading2.infile4
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/a_hyperlink.infile4
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/a_justified.infile4
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/a_linebreaks.infile4
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/a_linespacing.infile4
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/a_numberorderedlist.infile4
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/a_pagebreak.infile4
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/a_paragraph.infile4
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/a_simple01.infile4
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/a_simple02.infile4
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/a_simple03.infile4
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/a_simple04.infile4
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/a_simple05.infile5
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/a_standard.infile4
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/a_subscript.infile4
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/a_superscript.infile4
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/a_symbols.infile4
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/a_tab.infile4
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/a_table.infile5
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/a_textspan.infile4
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/a_unorderedlist.infile4
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/a_wordwrap.infile4
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/c_addition01-mod.infile5
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/c_alignment.infile4
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/c_backwardrange-mod.infile6
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/c_basic-mod.infile5
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/c_bob-mod.infile5
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/c_boolean-mod.infile6
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/c_cellcurrencyvalue.infile5
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/c_cellpercentvalue-mod.infile8
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/c_cellstringvalue-mod.infile10
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/c_columnswidth-mod.infile3
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/c_cyclic-mod.infile12
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/c_dividefloating-mod.infile8
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/c_forwardrange-mod.infile6
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/c_insertimage.infile4
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/c_insertrow-mod.infile13
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/c_invalidcellref-mod.infile10
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/c_largerange-mod.infile6
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/c_listrange-mod.infile6
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/c_mathematical-mod.infile10
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/c_multi_boolean.infile5
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/c_protection-mod01.infile6
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/c_sheetreference-mod.infile6
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/c_simple01-mod.infile13
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/c_simple02-mod.infile13
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/c_simple03-mod.infile22
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/c_simple04-mod.infile14
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/c_smallrange-mod.infile6
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/c_styles.infile3
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/c_textimage.infile12
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/empty01.infile3
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/hyperlink01.infile4
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/image01.infile4
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/simple01.infile3
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/simple02.infile3
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/simple03.infile3
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/simple04.infile3
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/simple05.infile4
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/table01.infile3
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/table02.infile3
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/table03.infile4
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/table04.infile4
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_animatedgif.sxwbin0 -> 53136 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_bolddoc.sxwbin0 -> 5664 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_bookmarks.sxwbin0 -> 6227 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_bulletorderedlist.sxwbin0 -> 6347 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_emptydoc-mod.sxwbin0 -> 5880 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_emptydoc.sxwbin0 -> 5880 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_firstlineindent.sxwbin0 -> 5683 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_fontsize.sxwbin0 -> 6315 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_heading.sxwbin0 -> 5700 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_heading1.sxwbin0 -> 5819 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_heading2.sxwbin0 -> 6142 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_hyperlink.sxwbin0 -> 5673 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_justified.sxwbin0 -> 6269 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_linebreaks.sxwbin0 -> 6444 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_linespacing.sxwbin0 -> 5783 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_numberorderedlist.sxwbin0 -> 6366 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_pagebreak.sxwbin0 -> 5698 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_paragraph.sxwbin0 -> 6093 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_simple01.sxwbin0 -> 5978 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_simple02.sxwbin0 -> 5978 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_simple03.sxwbin0 -> 5978 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_simple04.sxwbin0 -> 5978 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_simple05.sxwbin0 -> 5978 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_standard.sxwbin0 -> 5978 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_subscript.sxwbin0 -> 5980 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_superscript.sxwbin0 -> 5981 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_symbols.sxwbin0 -> 5106 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_tab.sxwbin0 -> 5912 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_table.sxwbin0 -> 6181 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_textspan.sxwbin0 -> 6142 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_unorderedlist.sxwbin0 -> 6817 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_wordwrap.sxwbin0 -> 5524 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_addition.sxcbin0 -> 6020 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_alignment.sxcbin0 -> 6535 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_backwardrange.sxcbin0 -> 6204 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_basic.sxcbin0 -> 6020 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_boolean.sxcbin0 -> 6239 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_cellcurrencyalue.sxcbin0 -> 6776 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_cellpercentvalue.sxcbin0 -> 6495 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_cellstringvalue.sxcbin0 -> 6172 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_columnswidth.sxcbin0 -> 6287 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_cyclic.sxcbin0 -> 6005 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_dividefloating.sxcbin0 -> 6315 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_forwardrange.sxcbin0 -> 6259 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_insertimage.sxcbin0 -> 40702 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_insertrow.sxcbin0 -> 5157 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_invalidcellref.sxcbin0 -> 6035 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_largerange.sxcbin0 -> 6487 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_listrange.sxcbin0 -> 6370 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_mathematical.sxcbin0 -> 6351 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_multi_boolean.sxcbin0 -> 5338 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_protection.sxcbin0 -> 6839 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_sheetreference.sxcbin0 -> 6358 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_simple01.sxcbin0 -> 5176 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_simple02.sxcbin0 -> 4999 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_simple03.sxcbin0 -> 5044 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_simple04.sxcbin0 -> 5083 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_smallrange.sxcbin0 -> 6129 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_styles.sxcbin0 -> 6531 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_textimage.sxcbin0 -> 40702 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/empty01.sxwbin0 -> 5880 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/hyperlink01.sxwbin0 -> 6088 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/image01.sxwbin0 -> 53136 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/simple01.sxwbin0 -> 5978 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/simple02.sxwbin0 -> 5978 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/simple03.sxwbin0 -> 5978 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/simple04.sxwbin0 -> 5978 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/simple05.sxwbin0 -> 5978 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/table01.sxwbin0 -> 6443 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/table02.sxwbin0 -> 6443 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/table03.sxwbin0 -> 6443 bytes
-rw-r--r--xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/table04.sxwbin0 -> 6443 bytes
-rwxr-xr-xxmerge/source/palmtests/qa/bin/mysplit.pl58
-rwxr-xr-xxmerge/source/palmtests/qa/bin/tappen.pl61
-rwxr-xr-xxmerge/source/palmtests/qa/bin/template.pl55
-rwxr-xr-xxmerge/source/palmtests/qa/bin/test_driver.pl785
-rw-r--r--xmerge/source/palmtests/qa/comparator/OfficeZip.java241
-rw-r--r--xmerge/source/palmtests/qa/comparator/PDBDecoder.java135
-rw-r--r--xmerge/source/palmtests/qa/comparator/PDBHeader.java153
-rw-r--r--xmerge/source/palmtests/qa/comparator/PDBUtil.java100
-rw-r--r--xmerge/source/palmtests/qa/comparator/PalmDB.java348
-rw-r--r--xmerge/source/palmtests/qa/comparator/README10
-rw-r--r--xmerge/source/palmtests/qa/comparator/Record.java165
-rw-r--r--xmerge/source/palmtests/qa/comparator/SimplePdbCompare.java94
-rw-r--r--xmerge/source/palmtests/qa/comparator/XmlDiff.java464
-rw-r--r--xmerge/source/palmtests/qa/comparator/XmlDiff.properties14
-rw-r--r--xmerge/source/palmtests/qa/comparator/XmlWrapper.java153
-rw-r--r--xmerge/source/palmtests/qa/comparator/XmlZipExtract.java144
-rw-r--r--xmerge/source/palmtests/qa/comparator/comparator.pl248
-rw-r--r--xmerge/source/palmtests/qa/comparator/dtd/Blocklist.dtd34
-rw-r--r--xmerge/source/palmtests/qa/comparator/dtd/chart.mod228
-rw-r--r--xmerge/source/palmtests/qa/comparator/dtd/datastyl.mod168
-rw-r--r--xmerge/source/palmtests/qa/comparator/dtd/drawing.mod837
-rw-r--r--xmerge/source/palmtests/qa/comparator/dtd/dtypes.mod143
-rw-r--r--xmerge/source/palmtests/qa/comparator/dtd/form.mod308
-rw-r--r--xmerge/source/palmtests/qa/comparator/dtd/meta.mod90
-rw-r--r--xmerge/source/palmtests/qa/comparator/dtd/nmspace.mod50
-rw-r--r--xmerge/source/palmtests/qa/comparator/dtd/office.dtd54
-rw-r--r--xmerge/source/palmtests/qa/comparator/dtd/office.mod234
-rw-r--r--xmerge/source/palmtests/qa/comparator/dtd/script.mod51
-rw-r--r--xmerge/source/palmtests/qa/comparator/dtd/settings.mod49
-rw-r--r--xmerge/source/palmtests/qa/comparator/dtd/style.mod391
-rw-r--r--xmerge/source/palmtests/qa/comparator/dtd/table.mod493
-rw-r--r--xmerge/source/palmtests/qa/comparator/dtd/text.mod1099
-rw-r--r--xmerge/source/palmtests/qa/comparator/pdbcomparison.java542
-rw-r--r--xmerge/source/palmtests/qa/docs/Doc_descriptions.sxcbin0 -> 8347 bytes
-rw-r--r--xmerge/source/palmtests/qa/docs/Spreadsheet_descriptions.csv39
-rw-r--r--xmerge/source/palmtests/qa/docs/Spreadsheet_descriptions.sxcbin0 -> 5752 bytes
-rw-r--r--xmerge/source/palmtests/qa/lib/converterlib.pm1174
-rw-r--r--xmerge/source/palmtests/qa/palm-session/session8
-rw-r--r--xmerge/source/palmtests/qa/test_spec/convertor_test_spec.html2274
-rw-r--r--xmerge/source/pexcel/build.xml76
-rw-r--r--xmerge/source/pexcel/converter.xml45
-rw-r--r--xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/ConverterCapabilitiesImpl.java113
-rw-r--r--xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/PluginFactoryImpl.java130
-rw-r--r--xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/PocketExcelConstants.java67
-rw-r--r--xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/PocketExcelDecoder.java438
-rw-r--r--xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/PocketExcelEncoder.java289
-rw-r--r--xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/SxcDocumentDeserializerImpl.java129
-rw-r--r--xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/SxcDocumentSerializerImpl.java130
-rw-r--r--xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/package.html43
-rw-r--r--xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/BIFFRecord.java61
-rw-r--r--xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/BeginningOfFile.java116
-rw-r--r--xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/BlankCell.java115
-rw-r--r--xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/BoolErrCell.java125
-rw-r--r--xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/BoundSheet.java136
-rw-r--r--xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/CellValue.java136
-rw-r--r--xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/CodePage.java107
-rw-r--r--xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/ColInfo.java157
-rw-r--r--xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/DefColWidth.java94
-rw-r--r--xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/DefRowHeight.java96
-rw-r--r--xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/DefinedName.java226
-rw-r--r--xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/Eof.java70
-rw-r--r--xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/ExtendedFormat.java384
-rw-r--r--xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/FloatNumber.java120
-rw-r--r--xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/FontDescription.java286
-rw-r--r--xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/Formula.java257
-rw-r--r--xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/LabelCell.java139
-rw-r--r--xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/NumberFormat.java93
-rw-r--r--xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/Pane.java218
-rw-r--r--xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/Row.java138
-rw-r--r--xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/Selection.java142
-rw-r--r--xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/StringValue.java124
-rw-r--r--xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/UnsupportedFormulaException.java41
-rw-r--r--xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/Window1.java115
-rw-r--r--xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/Window2.java154
-rw-r--r--xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/Workbook.java539
-rw-r--r--xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/Worksheet.java319
-rw-r--r--xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/FormulaCompiler.java271
-rw-r--r--xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/FormulaHelper.java152
-rw-r--r--xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/FormulaParser.java561
-rw-r--r--xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/FormulaParsingException.java41
-rw-r--r--xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/FunctionLookup.java204
-rw-r--r--xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/OperandLookup.java62
-rw-r--r--xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/OperatorLookup.java73
-rw-r--r--xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/ParseToken.java42
-rw-r--r--xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/PrecedenceTable.java85
-rw-r--r--xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/SymbolLookup.java81
-rw-r--r--xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/Token.java151
-rw-r--r--xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/TokenConstants.java203
-rw-r--r--xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/TokenDecoder.java497
-rw-r--r--xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/TokenEncoder.java559
-rw-r--r--xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/TokenFactory.java118
-rw-r--r--xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/UnsupportedFunctionException.java40
-rw-r--r--xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/package.html42
-rw-r--r--xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/package.html47
-rw-r--r--xmerge/source/pexcel/makefile.mk35
-rw-r--r--xmerge/source/pocketword/build.xml76
-rw-r--r--xmerge/source/pocketword/converter.xml50
-rw-r--r--xmerge/source/pocketword/java/org/openoffice/xmerge/converter/xml/sxw/pocketword/ConverterCapabilitiesImpl.java93
-rw-r--r--xmerge/source/pocketword/java/org/openoffice/xmerge/converter/xml/sxw/pocketword/DocumentDescriptor.java235
-rw-r--r--xmerge/source/pocketword/java/org/openoffice/xmerge/converter/xml/sxw/pocketword/DocumentDeserializerImpl.java294
-rw-r--r--xmerge/source/pocketword/java/org/openoffice/xmerge/converter/xml/sxw/pocketword/DocumentMergerImpl.java97
-rw-r--r--xmerge/source/pocketword/java/org/openoffice/xmerge/converter/xml/sxw/pocketword/DocumentSerializerImpl.java433
-rw-r--r--xmerge/source/pocketword/java/org/openoffice/xmerge/converter/xml/sxw/pocketword/Paragraph.java858
-rw-r--r--xmerge/source/pocketword/java/org/openoffice/xmerge/converter/xml/sxw/pocketword/ParagraphTextSegment.java202
-rw-r--r--xmerge/source/pocketword/java/org/openoffice/xmerge/converter/xml/sxw/pocketword/PluginFactoryImpl.java164
-rw-r--r--xmerge/source/pocketword/java/org/openoffice/xmerge/converter/xml/sxw/pocketword/PocketWordConstants.java94
-rw-r--r--xmerge/source/pocketword/java/org/openoffice/xmerge/converter/xml/sxw/pocketword/PocketWordDocument.java404
-rw-r--r--xmerge/source/pocketword/java/org/openoffice/xmerge/converter/xml/sxw/pocketword/package.html58
-rw-r--r--xmerge/source/pocketword/makefile.mk35
-rw-r--r--xmerge/source/regutil/makefile.mk48
-rw-r--r--xmerge/source/regutil/regutil.cpp102
-rw-r--r--xmerge/source/regutil/regutil.dsp96
-rw-r--r--xmerge/source/regutil/regutil.dsw17
-rw-r--r--xmerge/source/wordsmith/build.xml76
-rw-r--r--xmerge/source/wordsmith/converter.xml17
-rw-r--r--xmerge/source/wordsmith/java/org/openoffice/xmerge/converter/xml/sxw/wordsmith/ConverterCapabilitiesImpl.java93
-rw-r--r--xmerge/source/wordsmith/java/org/openoffice/xmerge/converter/xml/sxw/wordsmith/DOCConstants.java61
-rw-r--r--xmerge/source/wordsmith/java/org/openoffice/xmerge/converter/xml/sxw/wordsmith/DocumentDeserializerImpl.java565
-rw-r--r--xmerge/source/wordsmith/java/org/openoffice/xmerge/converter/xml/sxw/wordsmith/DocumentMergerImpl.java99
-rw-r--r--xmerge/source/wordsmith/java/org/openoffice/xmerge/converter/xml/sxw/wordsmith/DocumentSerializerImpl.java536
-rw-r--r--xmerge/source/wordsmith/java/org/openoffice/xmerge/converter/xml/sxw/wordsmith/PluginFactoryImpl.java149
-rw-r--r--xmerge/source/wordsmith/java/org/openoffice/xmerge/converter/xml/sxw/wordsmith/WSDecoder.java352
-rw-r--r--xmerge/source/wordsmith/java/org/openoffice/xmerge/converter/xml/sxw/wordsmith/WSEncoder.java212
-rw-r--r--xmerge/source/wordsmith/java/org/openoffice/xmerge/converter/xml/sxw/wordsmith/Wse.java100
-rw-r--r--xmerge/source/wordsmith/java/org/openoffice/xmerge/converter/xml/sxw/wordsmith/WseColorTable.java247
-rw-r--r--xmerge/source/wordsmith/java/org/openoffice/xmerge/converter/xml/sxw/wordsmith/WseFontTable.java218
-rw-r--r--xmerge/source/wordsmith/java/org/openoffice/xmerge/converter/xml/sxw/wordsmith/WseHeader.java145
-rw-r--r--xmerge/source/wordsmith/java/org/openoffice/xmerge/converter/xml/sxw/wordsmith/WsePara.java299
-rw-r--r--xmerge/source/wordsmith/java/org/openoffice/xmerge/converter/xml/sxw/wordsmith/WseTextRun.java324
-rw-r--r--xmerge/source/wordsmith/java/org/openoffice/xmerge/converter/xml/sxw/wordsmith/textRecord.java115
-rw-r--r--xmerge/source/wordsmith/java/org/openoffice/xmerge/converter/xml/sxw/wordsmith/util.java68
-rw-r--r--xmerge/source/wordsmith/makefile.mk33
-rw-r--r--xmerge/source/xmerge/build.xml92
-rw-r--r--xmerge/source/xmerge/converter.dtd96
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/Convert.java327
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/ConvertData.java117
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/ConvertException.java45
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/ConverterCapabilities.java67
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/ConverterFactory.java124
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/Document.java99
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/DocumentDeserializer.java65
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/DocumentDeserializer2.java71
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/DocumentDeserializerFactory.java65
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/DocumentMerger.java93
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/DocumentMergerFactory.java63
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/DocumentSerializer.java67
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/DocumentSerializer2.java73
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/DocumentSerializerFactory.java63
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/MergeException.java45
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/PluginFactory.java193
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/Version.java88
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/converter/dom/DOMDocument.java412
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/converter/dom/package.html55
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm/PalmDB.java469
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm/PalmDocument.java177
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm/PdbDecoder.java233
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm/PdbEncoder.java196
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm/PdbHeader.java162
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm/PdbUtil.java105
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm/Record.java216
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm/package.html142
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/EmbeddedBinaryObject.java127
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/EmbeddedObject.java116
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/EmbeddedXMLObject.java295
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/OfficeConstants.java439
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/OfficeDocument.java1265
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/OfficeDocumentException.java130
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/OfficeZip.java458
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/ParaStyle.java601
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/Style.java227
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/StyleCatalog.java390
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/TextStyle.java679
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/package.html41
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/BookSettings.java228
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/CellStyle.java510
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/ColumnRowInfo.java195
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/ColumnStyle.java300
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/DocumentMergerImpl.java198
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/Format.java475
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/NameDefinition.java215
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/RowStyle.java300
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/SheetSettings.java373
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/SpreadsheetDecoder.java180
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/SpreadsheetEncoder.java129
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/SxcConstants.java49
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/SxcDocument.java92
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/SxcDocumentDeserializer.java792
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/SxcDocumentSerializer.java993
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/SxcPluginFactory.java82
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/package.html40
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxw/SxwDocument.java94
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxw/SxwPluginFactory.java76
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxw/package.html40
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/xslt/ConverterCapabilitiesImpl.java93
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/xslt/DocumentDeserializerImpl.java250
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/xslt/DocumentMergerImpl.java97
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/xslt/DocumentSerializerImpl.java297
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/xslt/GenericOfficeDocument.java93
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/xslt/PluginFactoryImpl.java202
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/xslt/XsltPlugin.properties37
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/xslt/package.html67
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/merger/DiffAlgorithm.java51
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/merger/Difference.java242
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/merger/Iterator.java123
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/merger/MergeAlgorithm.java61
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/merger/NodeMergeAlgorithm.java52
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/merger/diff/CellNodeIterator.java114
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/merger/diff/CharArrayLCSAlgorithm.java234
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/merger/diff/CharacterParser.java142
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/merger/diff/IteratorLCSAlgorithm.java236
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/merger/diff/IteratorRowCompare.java243
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/merger/diff/NodeIterator.java384
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/merger/diff/ObjectArrayIterator.java210
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/merger/diff/ParaNodeIterator.java90
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/merger/diff/RowIterator.java81
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/merger/diff/TextNodeEntry.java88
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/merger/diff/TextNodeIterator.java84
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/merger/diff/package.html43
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/merger/merge/CharacterBaseParagraphMerge.java310
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/merger/merge/DocumentMerge.java247
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/merger/merge/PositionBaseRowMerge.java260
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/merger/merge/SheetMerge.java89
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/merger/merge/SheetUtil.java107
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/merger/merge/package.html43
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/merger/package.html75
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/package.html113
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/test/ConverterInfoList.java105
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/test/ConverterInfoList.properties37
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/test/Driver.java318
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/util/ActiveSyncDriver.java144
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/util/ColourConverter.java446
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/util/Debug.java339
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/util/Debug.properties39
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/util/EndianConverter.java178
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/util/IntArrayList.java147
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/util/OfficeUtil.java135
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/util/Resources.java99
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/util/TwipsConverter.java99
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/util/XmlUtil.java189
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/util/package.html39
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/util/registry/ConverterInfo.java436
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/util/registry/ConverterInfoMgr.java536
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/util/registry/ConverterInfoReader.java279
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/util/registry/RegistryException.java47
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/util/registry/build.xml135
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/util/registry/package.html82
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/util/resources.properties69
-rw-r--r--xmerge/source/xmerge/makefile.mk34
-rw-r--r--xmerge/util/build.xml94
-rw-r--r--xmerge/util/makefile.mk34
-rw-r--r--xmerge/util/minicalc.mf3
-rw-r--r--xmerge/util/xmerge.mf8
-rw-r--r--xmerge/workben/XmlDiff.java458
-rw-r--r--xmerge/workben/XmlDiff.properties40
-rw-r--r--xmerge/workben/build.xml128
-rw-r--r--xmerge/workben/jstyle.pl541
-rw-r--r--xmerge/workben/makefile.mk32
654 files changed, 67427 insertions, 0 deletions
diff --git a/xmerge/build.xml b/xmerge/build.xml
new file mode 100644
index 000000000000..5878c1acf0b9
--- /dev/null
+++ b/xmerge/build.xml
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+
+ Copyright 2000, 2010 Oracle and/or its affiliates.
+
+ OpenOffice.org - a multi-platform office productivity suite
+
+ This file is part of OpenOffice.org.
+
+ OpenOffice.org is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License version 3
+ only, as published by the Free Software Foundation.
+
+ OpenOffice.org is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License version 3 for more details
+ (a copy is included in the LICENSE file that accompanied this code).
+
+ You should have received a copy of the GNU Lesser General Public License
+ version 3 along with OpenOffice.org. If not, see
+ <http://www.openoffice.org/license.html>
+ for a copy of the LGPLv3 License.
+
+-->
+<project name="xmerge" default="main" basedir=".">
+
+ <property environment="env"/>
+ <property name="solar.platform" value="${env.COMP_ENV}${env.PROEXT}"/>
+ <property name="out" location="${basedir}/${solar.platform}"/>
+ <property name="solar.jar" location="${env.SOLARVER}/${solar.platform}/bin${env.UPDMINOREXT}"/>
+ <property name="debug" value="yes"/>
+ <property name="optimize" value="no"/>
+
+ <target name="init">
+ <echoproperties prefix="solar"/>
+ <mkdir dir="${out}"/>
+ <mkdir dir="${out}/class"/>
+ </target>
+
+ <target name="xmerge" depends="init">
+ <ant dir="source/xmerge" target="all"/>
+ </target>
+
+ <target name="bridge" depends="xmerge, init">
+ <ant dir="source/bridge" target="all"/>
+ </target>
+
+ <target name="aportisdoc" depends="xmerge, init">
+ <ant dir="source/aportisdoc" target="all"/>
+ </target>
+
+ <target name="pexcel" depends="xmerge, init">
+ <ant dir="source/pexcel" target="all"/>
+ </target>
+
+ <target name="pocketword" depends="xmerge, init">
+ <ant dir="source/pocketword" target="all"/>
+ </target>
+
+ <target name="htmlsoff" depends="init">
+ <ant dir="source/htmlsoff" target="all"/>
+ </target>
+
+ <target name="wordsmith" depends="xmerge">
+ <echo>wordsmith filter is not supported</echo>
+ <ant dir="source/wordsmith" target="all"/>
+ </target>
+
+ <target name="minicalc" depends="xmerge">
+ <echo>minicalc filter is not supported</echo>
+ <ant dir="source/minicalc" target="all"/>
+ </target>
+
+ <target name="util" depends="xmerge, bridge, aportisdoc, pexcel, pocketword, htmlsoff">
+ <ant dir="util" target="all"/>
+ </target>
+
+ <target name="all" depends="xmerge, bridge, aportisdoc, pexcel, pocketword, htmlsoff, util">
+ </target>
+
+ <target name="clean">
+ <delete dir="${out}" />
+ </target>
+
+</project>
+
diff --git a/xmerge/inc/makefile.mk b/xmerge/inc/makefile.mk
new file mode 100644
index 000000000000..ed1c6f3d4ded
--- /dev/null
+++ b/xmerge/inc/makefile.mk
@@ -0,0 +1,47 @@
+#*************************************************************************
+#
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# Copyright 2000, 2010 Oracle and/or its affiliates.
+#
+# OpenOffice.org - a multi-platform office productivity suite
+#
+# This file is part of OpenOffice.org.
+#
+# OpenOffice.org is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License version 3
+# only, as published by the Free Software Foundation.
+#
+# OpenOffice.org is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License version 3 for more details
+# (a copy is included in the LICENSE file that accompanied this code).
+#
+# You should have received a copy of the GNU Lesser General Public License
+# version 3 along with OpenOffice.org. If not, see
+# <http://www.openoffice.org/license.html>
+# for a copy of the LGPLv3 License.
+#
+#*************************************************************************
+PRJ=..
+
+PRJNAME=xmerge
+TARGET=inc
+
+# --- Settings -----------------------------------------------------
+
+.INCLUDE : settings.mk
+
+# --- Files --------------------------------------------------------
+# --- Targets -------------------------------------------------------
+
+.INCLUDE : target.mk
+
+.IF "$(ENABLE_PCH)"!=""
+ALLTAR : \
+ $(SLO)$/precompiled.pch \
+ $(SLO)$/precompiled_ex.pch
+
+.ENDIF # "$(ENABLE_PCH)"!=""
+
diff --git a/xmerge/inc/pch/precompiled_xmerge.cxx b/xmerge/inc/pch/precompiled_xmerge.cxx
new file mode 100644
index 000000000000..a3c5d7a24808
--- /dev/null
+++ b/xmerge/inc/pch/precompiled_xmerge.cxx
@@ -0,0 +1,29 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "precompiled_xmerge.hxx"
+
diff --git a/xmerge/inc/pch/precompiled_xmerge.hxx b/xmerge/inc/pch/precompiled_xmerge.hxx
new file mode 100644
index 000000000000..33202852ae8d
--- /dev/null
+++ b/xmerge/inc/pch/precompiled_xmerge.hxx
@@ -0,0 +1,32 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): Generated on 2006-09-01 17:50:19.373276
+
+#ifdef PRECOMPILED_HEADERS
+#endif
+
diff --git a/xmerge/prj/build.lst b/xmerge/prj/build.lst
new file mode 100644
index 000000000000..c9f6a8e4d332
--- /dev/null
+++ b/xmerge/prj/build.lst
@@ -0,0 +1,11 @@
+xmrg xmerge : solenv unoil javaunohelper NULL
+xmrg xmerge usr1 - all xmrg_mkout NULL
+xmrg xmerge\inc nmake - all xmrg_inc NULL
+xmrg xmerge\source\xmerge nmake - all xmrg_xmerge xmrg_inc NULL
+xmrg xmerge\source\bridge nmake - all xmrg_bridge xmrg_xmerge xmrg_inc NULL
+xmrg xmerge\source\aportisdoc nmake - all xmrg_aportis xmrg_xmerge xmrg_inc NULL
+xmrg xmerge\source\pexcel nmake - all xmrg_pexcel xmrg_xmerge xmrg_inc NULL
+xmrg xmerge\source\pocketword nmake - all xmrg_pword xmrg_xmerge xmrg_inc NULL
+xmrg xmerge\source\htmlsoff nmake - all xmrg_htmlsoff xmrg_inc NULL
+xmrg xmerge\source\activesync nmake - all xmrg_activesync xmrg_inc NULL
+xmrg xmerge\util nmake - all xmrg_util xmrg_xmerge xmrg_bridge xmrg_aportis xmrg_pexcel xmrg_pword NULL
diff --git a/xmerge/prj/d.lst b/xmerge/prj/d.lst
new file mode 100644
index 000000000000..9cfd7927ed00
--- /dev/null
+++ b/xmerge/prj/d.lst
@@ -0,0 +1,12 @@
+..\%__SRC%\class\xmerge.jar %_DEST%\bin%_EXT%\xmerge.jar
+..\%__SRC%\class\pexcel.jar %_DEST%\bin%_EXT%\pexcel.jar
+..\%__SRC%\class\htmlsoff.jar %_DEST%\bin%_EXT%\htmlsoff.jar
+..\%__SRC%\class\aportisdoc.jar %_DEST%\bin%_EXT%\aportisdoc.jar
+..\%__SRC%\class\XMergeBridge.jar %_DEST%\bin%_EXT%\XMergeBridge.jar
+..\%__SRC%\class\pocketword.jar %_DEST%\bin%_EXT%\pocketword.jar
+..\%__SRC%\bin\xmergesync.dll %_DEST%\bin%_EXT%\xmergesync.dll
+mkdir: %_DEST%\doc%_EXT%\xmerge
+..\%__SRC%\doc\javadoc\package-list %_DEST%\doc%_EXT%\xmerge\package-list
+..\%__SRC%\doc\xmerge_javadoc.zip %_DEST%\doc%_EXT%\xmerge_javadoc.zip
+..\%__SRC%\doc\writer2latex_javadoc.zip %_DEST%\doc%_EXT%\writer2latex_javadoc.zip
+..\%__SRC%\misc\XMergeBridge.component %_DEST%\xml%_EXT%\XMergeBridge.component
diff --git a/xmerge/source/activesync/BIN/xmergesync.dll b/xmerge/source/activesync/BIN/xmergesync.dll
new file mode 100644
index 000000000000..768dea87d2bd
--- /dev/null
+++ b/xmerge/source/activesync/BIN/xmergesync.dll
Binary files differ
diff --git a/xmerge/source/activesync/XMergeFactory.cpp b/xmerge/source/activesync/XMergeFactory.cpp
new file mode 100644
index 000000000000..1c59cd79a8a0
--- /dev/null
+++ b/xmerge/source/activesync/XMergeFactory.cpp
@@ -0,0 +1,90 @@
+// XMergeFactory.cpp: implementation of the CXMergeFactory class.
+//
+//////////////////////////////////////////////////////////////////////
+
+#include "stdafx.h"
+
+#include "XMergeFilter.h"
+#include "XMergeFactory.h"
+
+//////////////////////////////////////////////////////////////////////
+// IUnknown implementation
+//////////////////////////////////////////////////////////////////////
+STDMETHODIMP CXMergeFactory::QueryInterface(REFIID riid, void **ppvObject)
+{
+ if(ppvObject == NULL)
+ return E_INVALIDARG;
+
+ if(::IsEqualIID(riid, IID_IUnknown) || ::IsEqualIID(riid, IID_IClassFactory))
+ {
+ *ppvObject = static_cast<IClassFactory*>(this);
+ }
+ else
+ {
+ *ppvObject = NULL;
+ return E_NOINTERFACE;
+ }
+
+ reinterpret_cast<IUnknown*>(*ppvObject)->AddRef();
+ return S_OK;
+}
+
+
+STDMETHODIMP_(ULONG) CXMergeFactory::AddRef()
+{
+ return ::InterlockedIncrement(&m_cRef);
+}
+
+
+STDMETHODIMP_(ULONG) CXMergeFactory::Release()
+{
+ if(::InterlockedDecrement(&m_cRef) == 0)
+ {
+ delete this;
+ return 0;
+ }
+
+ return m_cRef;
+}
+
+
+//////////////////////////////////////////////////////////////////////
+// IUnknown implementation
+//////////////////////////////////////////////////////////////////////
+STDMETHODIMP CXMergeFactory::CreateInstance(IUnknown *pUnkOuter, REFIID iid, void **ppvObject)
+{
+ if (ppvObject == NULL)
+ return E_INVALIDARG;
+
+ if (pUnkOuter != NULL) // cannot aggregate
+ {
+ *ppvObject = NULL;
+ return CLASS_E_NOAGGREGATION;
+ }
+
+ if (iid == IID_ICeFileFilter)
+ {
+ CXMergeFilter *pFilter = new CXMergeFilter();
+ if(pFilter == NULL)
+ {
+ *ppvObject = NULL;
+ return E_OUTOFMEMORY;
+ }
+
+ HRESULT hr = pFilter->QueryInterface(iid, ppvObject);
+ pFilter->Release();
+
+ return hr;
+ }
+
+ return E_INVALIDARG;
+}
+
+
+STDMETHODIMP CXMergeFactory::LockServer(BOOL fLock)
+{
+ _Module.LockServer(fLock);
+ return S_OK;
+}
+
+
diff --git a/xmerge/source/activesync/XMergeFactory.h b/xmerge/source/activesync/XMergeFactory.h
new file mode 100644
index 000000000000..bb24e8aab14e
--- /dev/null
+++ b/xmerge/source/activesync/XMergeFactory.h
@@ -0,0 +1,34 @@
+// XMergeFactory.h: interface for the CXMergeFactory class.
+//
+//////////////////////////////////////////////////////////////////////
+
+#if !defined(AFX_XMERGEFACTORY_H__3150043C_57FB_4BC8_9104_379506FA6B9F__INCLUDED_)
+#define AFX_XMERGEFACTORY_H__3150043C_57FB_4BC8_9104_379506FA6B9F__INCLUDED_
+
+#if _MSC_VER > 1000
+#pragma once
+#endif // _MSC_VER > 1000
+
+
+class CXMergeFactory : public IClassFactory
+{
+private:
+ LONG m_cRef;
+ virtual ~CXMergeFactory() {};
+
+public:
+ CXMergeFactory() : m_cRef(1) {}; // Set reference count when first created
+
+
+ /********** IUnknown methods **********/
+ STDMETHODIMP QueryInterface(REFIID riid, void **ppvObject);
+ STDMETHODIMP_(ULONG) AddRef(void);
+ STDMETHODIMP_(ULONG) Release();
+
+
+ /********** IUnknown methods **********/
+ STDMETHODIMP CreateInstance(IUnknown* pUnkOuter, REFIID riid, void **ppvObject);
+ STDMETHODIMP LockServer(BOOL fLock);
+};
+
+#endif // !defined(AFX_XMERGEFACTORY_H__3150043C_57FB_4BC8_9104_379506FA6B9F__INCLUDED_)
diff --git a/xmerge/source/activesync/XMergeFilter.cpp b/xmerge/source/activesync/XMergeFilter.cpp
new file mode 100644
index 000000000000..a02f11d03ad3
--- /dev/null
+++ b/xmerge/source/activesync/XMergeFilter.cpp
@@ -0,0 +1,495 @@
+// XMergeFilter.cpp: implementation of the CXMergeFilter class.
+//
+//////////////////////////////////////////////////////////////////////
+
+
+#include "stdafx.h"
+
+#include "XMergeFilter.h"
+
+#include <string>
+
+
+#define ERR_NOJAVA 1
+#define ERR_BADCLASSPATH 2
+#define ERR_INITJAVA 3
+
+
+const LPTSTR CXMergeFilter::m_pszPSWExportCLSID = _T("{BDD611C3-7BAB-460F-8711-5B9AC9EF6020}");
+const LPTSTR CXMergeFilter::m_pszPSWExportExt = _T("sxw");
+const LPTSTR CXMergeFilter::m_pszPSWExportDesc = _T("OpenOffice.org Writer XML Document");
+const LPTSTR CXMergeFilter::m_pszPSWExportShortDesc = _T("OpenOffice.org Writer");
+
+const LPTSTR CXMergeFilter::m_pszPSWImportCLSID = _T("{CB43F086-838D-4FA4-B5F6-3406B9A57439}");
+const LPTSTR CXMergeFilter::m_pszPSWImportExt = _T("psw");
+const LPTSTR CXMergeFilter::m_pszPSWImportDesc = _T("Pocket Word Document - Pocket PC");
+const LPTSTR CXMergeFilter::m_pszPSWImportShortDesc = _T("Pocket Word");
+
+const LPTSTR CXMergeFilter::m_pszPXLExportCLSID = _T("{C6AB3E74-9F4F-4370-8120-A8A6FABB7A7C}");
+const LPTSTR CXMergeFilter::m_pszPXLExportExt = _T("sxc");
+const LPTSTR CXMergeFilter::m_pszPXLExportDesc = _T("OpenOffice.org Calc XML Document");
+const LPTSTR CXMergeFilter::m_pszPXLExportShortDesc = _T("OpenOffice.org Calc");
+
+const LPTSTR CXMergeFilter::m_pszPXLImportCLSID = _T("{43887C67-4D5D-4127-BAAC-87A288494C7C}");
+const LPTSTR CXMergeFilter::m_pszPXLImportExt = _T("pxl");
+const LPTSTR CXMergeFilter::m_pszPXLImportDesc = _T("Pocket Excel Document - Pocket PC");
+const LPTSTR CXMergeFilter::m_pszPXLImportShortDesc = _T("Pocket Excel");
+
+
+//////////////////////////////////////////////////////////////////////
+// Construction/Destruction
+//////////////////////////////////////////////////////////////////////
+
+CXMergeFilter::CXMergeFilter() : m_cRef(1)
+{
+ m_bHaveExcel = FALSE;
+ m_bHaveWord = FALSE;
+
+ m_szClasspath = NULL;
+ m_szJavaBaseDir = NULL;
+}
+
+CXMergeFilter::~CXMergeFilter()
+{
+ if (m_szClasspath != NULL)
+ {
+ delete m_szClasspath;
+ }
+
+ if (m_szJavaBaseDir != NULL)
+ {
+ delete m_szJavaBaseDir;
+ }
+
+}
+
+
+//////////////////////////////////////////////////////////////////////
+// IUnknown Methods
+//////////////////////////////////////////////////////////////////////
+
+STDMETHODIMP CXMergeFilter::QueryInterface(REFIID riid, void **ppvObject)
+{
+ if(ppvObject == NULL)
+ return E_INVALIDARG;
+
+ if (::IsEqualIID(riid, IID_IUnknown))
+ {
+ *ppvObject = static_cast<IUnknown *>(this);
+ }
+ else if (::IsEqualIID(riid, IID_ICeFileFilter))
+ {
+ *ppvObject = static_cast<ICeFileFilter *>(this);
+ }
+ else
+ {
+ *ppvObject = NULL;
+ return E_NOINTERFACE;
+ }
+
+ reinterpret_cast<IUnknown *>(*ppvObject)->AddRef();
+ return S_OK;
+}
+
+
+STDMETHODIMP_(ULONG) CXMergeFilter::AddRef()
+{
+ return ::InterlockedIncrement(&m_cRef);
+}
+
+
+STDMETHODIMP_(ULONG) CXMergeFilter::Release()
+{
+ if(::InterlockedDecrement(&m_cRef) == 0)
+ {
+ delete this;
+ return 0;
+ }
+ return m_cRef;
+}
+
+
+//////////////////////////////////////////////////////////////////////
+// ICeFileFilter
+//////////////////////////////////////////////////////////////////////
+
+STDMETHODIMP CXMergeFilter::FilterOptions(HWND hwndParent)
+{
+ // We don't currently allow any options
+ return HRESULT_FROM_WIN32(NOERROR);
+}
+
+STDMETHODIMP CXMergeFilter::FormatMessage(DWORD dwFlags, DWORD dwMessageId,
+ DWORD dwLanguageId, LPTSTR lpBuffer, DWORD nSize,
+ va_list *Arguments, DWORD *pcb)
+{
+ TCHAR errMsg[1024];
+
+ HKEY hKey = NULL;
+ DWORD dwSize = 1024;
+
+
+ long lRet = 0;
+
+ // Attempt to find the messages in the registry
+ lRet = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\Sun Microsystems\\StarOffice\\XMergeSync\\Messages\\Error"),
+ 0, KEY_READ, &hKey);
+ if (lRet != ERROR_SUCCESS)
+ {
+ // Try the user's portion of the registry
+ lRet = ::RegOpenKeyEx(HKEY_CURRENT_USER, _T("Software\\Sun Microsystems\\StarOffice\\XMergeSync\\Messages\\Error"),
+ 0, KEY_READ, &hKey);
+ if (lRet != ERROR_SUCCESS)
+ {
+ hKey = NULL;
+ }
+ }
+
+
+ switch(dwMessageId)
+ {
+ case ERR_NOJAVA:
+ lRet = ::RegQueryValueEx(hKey, _T("Java"), 0, NULL, (LPBYTE)errMsg, &dwSize);
+ if (lRet != ERROR_SUCCESS)
+ {
+ lstrcpy(errMsg, "Unable to locate Java 1.4/1.5 installation.");
+ }
+ break;
+
+ case ERR_BADCLASSPATH:
+ lRet = ::RegQueryValueEx(hKey, _T("Classpath"), 0, NULL, (LPBYTE)errMsg, &dwSize);
+ if (lRet != ERROR_SUCCESS)
+ {
+ lstrcpy(errMsg, "Unable to locate XMerge Jar files.");
+ }
+ break;
+
+ case ERR_INITJAVA:
+ lRet = ::RegQueryValueEx(hKey, _T("JavaInit"), 0, NULL, (LPBYTE)errMsg, &dwSize);
+ if (lRet != ERROR_SUCCESS)
+ {
+ lstrcpy(errMsg, "Error initialising the Java Runtime Environment.");
+ }
+ break;
+ }
+
+ char* buf = (char*)LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, (lstrlen(errMsg) + 1) * sizeof(TCHAR));
+ lstrcpyn(buf, errMsg, lstrlen(errMsg));
+
+ *(char**)lpBuffer = buf;
+ *pcb = strlen(errMsg);
+
+ return HRESULT_FROM_WIN32(NOERROR);
+}
+
+
+STDMETHODIMP CXMergeFilter::NextConvertFile(int nConversion, CFF_CONVERTINFO *pci,
+ CFF_SOURCEFILE *psf, CFF_DESTINATIONFILE *pdf,
+ volatile BOOL *pbCancel, CF_ERROR *perr)
+{
+ std::string appArgs;
+ std::string appName;
+
+ STARTUPINFO si;
+ PROCESS_INFORMATION pi;
+
+ ZeroMemory( &si, sizeof(si) );
+ ZeroMemory( &pi, sizeof(pi) );
+
+ si.cb = sizeof(si);
+
+
+ /*
+ * First step: Locate Java and establish the classpath. If these can't
+ * be done succesfully, then avoid all further processing.
+ */
+
+ // Locate Java Home if it hasn't already been done.
+ if (m_szJavaBaseDir == NULL)
+ {
+ m_szJavaBaseDir = GetJavaBaseDir();
+
+ if (m_szJavaBaseDir == NULL)
+ {
+ *perr = ERR_NOJAVA;
+ return HRESULT_FROM_WIN32(E_FAIL);
+ }
+ }
+
+ // Get the StarOffice/OpenOffice class directory
+ if (m_szClasspath == NULL)
+ {
+ m_szClasspath = GetXMergeClassPath();
+
+ if (m_szClasspath == NULL)
+ {
+ *perr = ERR_BADCLASSPATH;
+ return HRESULT_FROM_WIN32(E_FAIL);
+ }
+ }
+
+
+ /*
+ * Second step: Check the files we're going to process. If we don't have
+ * an XMerge plugin for the file then we can't convert.
+ */
+ if ((!lstrcmp(psf->szExtension, "sxw") || !lstrcmp(psf->szExtension, "psw"))
+ && !m_bHaveWord)
+ {
+ *perr = ERR_BADCLASSPATH;
+ return HRESULT_FROM_WIN32(E_FAIL);
+ }
+ else if ((!lstrcmp(psf->szExtension, "sxc") || !lstrcmp(psf->szExtension, "pxl"))
+ && !m_bHaveExcel)
+ {
+ *perr = ERR_BADCLASSPATH;
+ return HRESULT_FROM_WIN32(E_FAIL);
+ }
+
+
+ /*
+ * Third step: Locate the Java executable and build and execute the command
+ * line to carry out the conversion.
+ */
+
+ // Find the Java executable and make sure it exists
+ appName += m_szJavaBaseDir;
+ appName += "\\bin\\javaw.exe";
+
+ if (GetFileAttributes(appName.c_str()) == INVALID_FILE_SIZE)
+ {
+ *perr = ERR_NOJAVA;
+ return HRESULT_FROM_WIN32(E_FAIL);
+ }
+
+ // Wrap the executable path in quotes in case of spaces
+ appName.insert(0, "\"");
+ appName.append("\"");
+
+
+
+ // Need to build the entire command line for calling out to Java
+ appArgs = appName + " -Djava.class.path=";
+ appArgs += m_szClasspath;
+ appArgs += " org.openoffice.xmerge.util.ActiveSyncDriver ";
+
+ if (!lstrcmp(psf->szExtension, "sxw"))
+ {
+ appArgs += "staroffice/sxw ";
+ appArgs += "application/x-pocket-word ";
+ }
+ else if(!lstrcmp(psf->szExtension, "psw"))
+ {
+ appArgs += "application/x-pocket-word ";
+ appArgs += "staroffice/sxw ";
+ }
+ else if(!lstrcmp(psf->szExtension, "sxc"))
+ {
+ appArgs += "staroffice/sxc ";
+ appArgs += "application/x-pocket-excel ";
+ }
+ else if(!lstrcmp(psf->szExtension, "pxl"))
+ {
+ appArgs += "application/x-pocket-excel ";
+ appArgs += "staroffice/sxc ";
+ }
+
+
+ // ActiveSync sometimes gives out long file names, especially when automatically syncing
+ appArgs += "\"";
+ appArgs += psf->szFullpath;
+ appArgs += "\" \"";
+ appArgs += pdf->szFullpath;
+ appArgs += "\"";
+
+ if(!CreateProcess(NULL,
+ (char*)appArgs.c_str(),
+ NULL, // No Process Attributes
+ NULL, // No Thread Attributes
+ FALSE, // Don't want this process getting handles
+ CREATE_NO_WINDOW, // No console
+ NULL, // No special environment
+ NULL, // Current Working Directory is okay
+ &si,
+ &pi))
+ {
+ *perr = ERR_INITJAVA;
+ return HRESULT_FROM_WIN32(E_FAIL);
+ }
+
+ // Wait for the new process to work
+ WaitForSingleObject(pi.hProcess, INFINITE);
+
+ CloseHandle(pi.hProcess);
+ CloseHandle(pi.hThread);
+
+ return HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS);
+}
+
+
+typedef HRESULT (WINAPI *SHGETFOLDERPATH)( HWND, int, HANDLE, DWORD, LPTSTR );
+
+
+TCHAR* CXMergeFilter::GetJavaBaseDir()
+{
+ HRESULT lRet;
+
+ HKEY hKey = NULL;
+ HKEY hDataKey = NULL;
+
+ TCHAR szClassName[_MAX_PATH] = "\0";
+ TCHAR szKeyName[_MAX_PATH] = "\0";
+ TCHAR szCurrentJava[_MAX_PATH] = "\0";
+ DWORD dwClassName = _MAX_PATH;
+ DWORD dwKeyName = _MAX_PATH;
+
+ /*
+ * Java leaves registry keys at HKLM\SOFTWARE\JavaSoft.
+ *
+ * Check for a JRE installation first
+ */
+ lRet = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\JavaSoft\\Java Runtime Environment"), 0, KEY_READ, &hKey);
+ if (lRet != ERROR_SUCCESS)
+ return NULL;
+
+ // Locations shouldn't be greater than _MAX_PATH
+ TCHAR* szJavaHome = new TCHAR[_MAX_PATH + 1];
+ DWORD dwSize = _MAX_PATH + 1;
+
+ /* use current version */
+ lRet = ::RegQueryValueEx(hKey, _T("CurrentVersion"), 0, NULL, (LPBYTE)szCurrentJava, &dwSize);
+
+ /*
+ for (DWORD i = 0; lRet != ERROR_NO_MORE_ITEMS; i++)
+ {
+ lRet = ::RegEnumKeyEx(hKey, i, szKeyName, &dwKeyName, 0, szClassName, &dwClassName, NULL);
+ if(!strncmp(szKeyName, "1.4", 3))
+ break;
+ dwKeyName = _MAX_PATH;
+ }
+ // Found a Java 1.4 installation. Can now read its home directory.
+ */
+
+
+ lRet = ::RegOpenKeyEx(hKey, _T(szCurrentJava), 0, KEY_READ, &hDataKey);
+ if (lRet != ERROR_SUCCESS)
+ {
+ RegCloseKey(hKey);
+ delete [] szJavaHome;
+ return NULL;
+ }
+
+
+ // Now read the JavaHome value
+ dwSize = _MAX_PATH + 1;
+ lRet = ::RegQueryValueEx(hDataKey, _T("JavaHome"), 0, NULL, (LPBYTE)szJavaHome, &dwSize);
+ if (lRet != ERROR_SUCCESS)
+ {
+ RegCloseKey(hDataKey);
+ RegCloseKey(hKey);
+ delete [] szJavaHome;
+ return NULL;
+ }
+
+ RegCloseKey(hDataKey);
+ RegCloseKey(hKey);
+
+
+ // Check that the directory exists before returning it
+ DWORD dwAttrs = GetFileAttributes(szJavaHome);
+
+ if (((dwAttrs & FILE_ATTRIBUTE_DIRECTORY) != FILE_ATTRIBUTE_DIRECTORY) || dwAttrs == INVALID_FILE_SIZE)
+ {
+ delete [] szJavaHome;
+ return NULL;
+ }
+
+ return szJavaHome;
+}
+
+
+
+TCHAR* CXMergeFilter::GetXMergeClassPath()
+{
+ /*
+ * The DLL will be installed by setup in the program directory of
+ * the installation. The XMerge Jar files, if present, will be
+ * located in the classes directory below program.
+ */
+
+ TCHAR szJarPath[MAX_PATH];
+ TCHAR szTmpPath[MAX_PATH];
+
+ ZeroMemory(szJarPath, MAX_PATH);
+ ZeroMemory(szTmpPath, MAX_PATH);
+
+ WIN32_FILE_ATTRIBUTE_DATA fInfo;
+
+ std::string clsPath;
+
+
+ // Get the location of the module.
+ GetModuleFileName(_Module.m_hInst, szTmpPath, MAX_PATH);
+
+ // Strip off the xmergesync.dll component
+ _strlwr(szTmpPath);
+ char* modName = strstr(szTmpPath, "xmergesync.dll");
+ strncpy(szJarPath, szTmpPath, modName - szTmpPath);
+
+ // Append the classes directory
+ strncat(szJarPath, "classes\\", 8);
+
+
+ // The core xmerge.jar must be present
+ ZeroMemory(szTmpPath, MAX_PATH);
+ _snprintf(szTmpPath, MAX_PATH, "%s%s\0", szJarPath, "xmerge.jar");
+
+ if (!GetFileAttributesEx(szTmpPath, GetFileExInfoStandard, &fInfo))
+ {
+ return NULL;
+ }
+ else
+ {
+ clsPath += szTmpPath;
+ clsPath += ";";
+ }
+
+
+ // Now check for Pocket Word
+ ZeroMemory(szTmpPath, MAX_PATH);
+ _snprintf(szTmpPath, MAX_PATH, "%s%s\0", szJarPath, "pocketword.jar");
+
+ if (!GetFileAttributesEx(szTmpPath, GetFileExInfoStandard, &fInfo))
+ {
+ m_bHaveWord = FALSE;
+ }
+ else
+ {
+ m_bHaveWord = TRUE;
+ clsPath += szTmpPath;
+ clsPath += ";";
+ }
+
+ // Now check for Pocket Excel
+ ZeroMemory(szTmpPath, MAX_PATH);
+ _snprintf(szTmpPath, MAX_PATH, "%s%s\0", szJarPath, "pexcel.jar");
+
+ if (!GetFileAttributesEx(szTmpPath, GetFileExInfoStandard, &fInfo))
+ {
+ m_bHaveExcel = FALSE;
+ }
+ else
+ {
+ m_bHaveExcel = TRUE;
+ clsPath += szTmpPath;
+ clsPath += ";";
+ }
+
+ // Quotes may be need around the ClassPath
+ clsPath.insert(0, "\"");
+ clsPath += "\"";
+
+
+ // Return the data
+ return _strdup(clsPath.c_str());
+}
diff --git a/xmerge/source/activesync/XMergeFilter.h b/xmerge/source/activesync/XMergeFilter.h
new file mode 100644
index 000000000000..54128f325125
--- /dev/null
+++ b/xmerge/source/activesync/XMergeFilter.h
@@ -0,0 +1,73 @@
+// XMergeFilter.h: interface for the CXMergeFilter class.
+//
+//////////////////////////////////////////////////////////////////////
+
+#if !defined(AFX_XMERGEFILTER_H__25C39F6B_A1D7_408E_8F58_9CBEE9A666CC__INCLUDED_)
+#define AFX_XMERGEFILTER_H__25C39F6B_A1D7_408E_8F58_9CBEE9A666CC__INCLUDED_
+
+#if _MSC_VER > 1000
+#pragma once
+#endif // _MSC_VER > 1000
+
+
+
+
+
+class CXMergeFilter : public ICeFileFilter
+{
+protected:
+ long m_cRef;
+
+private:
+ TCHAR* GetXMergeClassPath();
+ TCHAR* GetJavaBaseDir();
+
+ TCHAR* m_szJavaBaseDir;
+ TCHAR* m_szClasspath;
+
+ BOOL m_bHaveExcel;
+ BOOL m_bHaveWord;
+
+
+public:
+ static const LPTSTR m_pszPSWExportCLSID;
+ static const LPTSTR m_pszPSWExportExt;
+ static const LPTSTR m_pszPSWExportDesc;
+ static const LPTSTR m_pszPSWExportShortDesc;
+
+ static const LPTSTR m_pszPSWImportCLSID;
+ static const LPTSTR m_pszPSWImportExt;
+ static const LPTSTR m_pszPSWImportDesc;
+ static const LPTSTR m_pszPSWImportShortDesc;
+
+ static const LPTSTR m_pszPXLExportCLSID;
+ static const LPTSTR m_pszPXLExportExt;
+ static const LPTSTR m_pszPXLExportDesc;
+ static const LPTSTR m_pszPXLExportShortDesc;
+
+ static const LPTSTR m_pszPXLImportCLSID;
+ static const LPTSTR m_pszPXLImportExt;
+ static const LPTSTR m_pszPXLImportDesc;
+ static const LPTSTR m_pszPXLImportShortDesc;
+
+public:
+ CXMergeFilter();
+ virtual ~CXMergeFilter();
+
+
+ /********** IUnknown methods **********/
+ STDMETHODIMP QueryInterface(REFIID iid, void **ppvObject);
+ STDMETHODIMP_(ULONG) AddRef();
+ STDMETHODIMP_(ULONG) Release();
+
+ /********** ICeFileFilter methods *********/
+ STDMETHODIMP FilterOptions(HWND hwndParent);
+ STDMETHODIMP FormatMessage(DWORD dwFlags, DWORD dwMessageId, DWORD dwLanguageId,
+ LPTSTR lpBuffer, DWORD nSize, va_list *Arguments, DWORD *pcb);
+ STDMETHODIMP NextConvertFile(int nConversion, CFF_CONVERTINFO *pci,
+ CFF_SOURCEFILE *psf, CFF_DESTINATIONFILE *pdf,
+ volatile BOOL *pbCancel, CF_ERROR *perr);
+
+};
+
+#endif // !defined(AFX_XMERGEFILTER_H__25C39F6B_A1D7_408E_8F58_9CBEE9A666CC__INCLUDED_)
diff --git a/xmerge/source/activesync/XMergeSync.cpp b/xmerge/source/activesync/XMergeSync.cpp
new file mode 100644
index 000000000000..469c15b2f292
--- /dev/null
+++ b/xmerge/source/activesync/XMergeSync.cpp
@@ -0,0 +1,837 @@
+
+#include "stdafx.h"
+
+#include "XMergeFilter.h"
+#include "XMergeFactory.h"
+
+
+CXMergeSyncModule _Module;
+
+
+//////////////////////////////////////////////////////////////////////
+// DLL Functions
+//////////////////////////////////////////////////////////////////////
+BOOL WINAPI DllMain(HANDLE hInst, ULONG ulReason, LPVOID lpReserved)
+{
+ switch (ulReason)
+ {
+ case DLL_PROCESS_ATTACH:
+ _Module.m_hInst = reinterpret_cast<HINSTANCE>(hInst);
+ break;
+
+ case DLL_PROCESS_DETACH:
+ _Module.m_hInst = NULL;
+ break;
+
+ case DLL_THREAD_ATTACH:
+ break;
+
+ case DLL_THREAD_DETACH:
+ break;
+ }
+
+ return TRUE;
+}
+
+
+STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
+{
+ // Create the factory object
+ CXMergeFactory *pFactory = new CXMergeFactory();
+ if (pFactory == NULL)
+ {
+ *ppv = NULL;
+ return E_OUTOFMEMORY;
+ }
+
+ HRESULT hr = pFactory->QueryInterface(riid, ppv);
+ pFactory->Release();
+
+ return hr;
+}
+
+
+STDAPI DllCanUnloadNow()
+{
+ if (_Module.GetLockCount() == 0)
+ return S_OK;
+
+ return S_FALSE;
+}
+
+
+// Utility function to close open keys during registration
+static _signalRegError(long lRet, HKEY hKey, HKEY hDataKey)
+{
+ if (hKey)
+ ::RegCloseKey(hKey);
+
+
+ if (hDataKey)
+ ::RegCloseKey(hDataKey);
+
+ return HRESULT_FROM_WIN32(lRet);
+}
+
+
+STDAPI DllRegisterServer()
+{
+ HKEY hKey = NULL;
+ HKEY hDataKey = NULL;
+
+ long lRet = 0;
+ TCHAR sTemp[_MAX_PATH + 1] = "\0";
+
+
+ /*
+ * Following calls create the HKEY_CLASSES_ROOT\CLSID entry for the Writer export filter.
+ *
+ * Note that import are export are relative to the WinCE device, so files are
+ * exported to the desktop format.
+ */
+
+ // Get a handle to the CLSID key
+ lRet = ::RegOpenKeyEx(HKEY_CLASSES_ROOT, _T("CLSID"), 0, KEY_ALL_ACCESS, &hKey);
+ if (lRet != ERROR_SUCCESS)
+ return _signalRegError(lRet, hKey, hDataKey);
+
+ // Create the CLSID key for the XMergeFilter
+ lRet = ::RegCreateKeyEx(hKey, CXMergeFilter::m_pszPSWExportCLSID, 0, _T(""), 0, KEY_ALL_ACCESS, NULL, &hKey, NULL);
+ if (lRet != ERROR_SUCCESS)
+ return _signalRegError(lRet, hKey, hDataKey);
+
+ lRet = ::RegSetValueEx(hKey, _T(""), 0, REG_SZ, (LPBYTE)CXMergeFilter::m_pszPSWExportShortDesc,
+ (::_tcslen(CXMergeFilter::m_pszPSWExportShortDesc) * sizeof(TCHAR) + (1 * sizeof(TCHAR))));
+ if (lRet != ERROR_SUCCESS)
+ return _signalRegError(lRet, hKey, hDataKey);
+
+
+ // Create the DefaultIcon key. For the moment, use one of the Async supplied ones
+ lRet = ::RegCreateKeyEx(hKey, _T("DefaultIcon"), 0, _T(""), 0, KEY_ALL_ACCESS, NULL, &hDataKey, NULL);
+ if (lRet != ERROR_SUCCESS)
+ return _signalRegError(lRet, hKey, hDataKey);
+
+ lRet = ::RegSetValueEx(hDataKey, NULL, 0, REG_SZ, (LPBYTE)_T("C:\\Program Files\\Microsoft ActiveSync\\pwdcnv.dll,0"),
+ (::_tcslen(_T("C:\\Program Files\\Microsoft ActiveSync\\pwdcnv.dll,0"))
+ * sizeof(TCHAR) + (1 * sizeof(TCHAR))));
+ if (lRet != ERROR_SUCCESS)
+ return _signalRegError(lRet, hKey, hDataKey);
+ ::RegCloseKey(hDataKey); hDataKey = NULL;
+
+ // Create the InprocServer32 key
+ lRet = ::RegCreateKeyEx(hKey, _T("InProcServer32"), 0, _T(""), 0, KEY_ALL_ACCESS, NULL, &hDataKey, NULL);
+ if (lRet != ERROR_SUCCESS)
+ return _signalRegError(lRet, hKey, hDataKey);
+
+ lRet = ::RegSetValueEx(hDataKey, _T("ThreadingModel"), 0, REG_SZ, (LPBYTE)_T("Apartment"), 10);
+ if (lRet != ERROR_SUCCESS)
+ return _signalRegError(lRet, hKey, hDataKey);
+
+ // Create the key for the DLL file. First find the filename of the dll
+ if (!::GetModuleFileName((HMODULE)_Module.m_hInst, sTemp, (_MAX_PATH + 1)))
+ {
+ lRet = ::GetLastError();
+ if (lRet != ERROR_SUCCESS)
+ return _signalRegError(lRet, hKey, hDataKey);
+ }
+
+
+ lRet = ::RegSetValueEx(hDataKey, NULL, 0, REG_SZ, (LPBYTE)sTemp,
+ (::_tcslen(sTemp) * sizeof(TCHAR) + (1 * sizeof(TCHAR))));
+ if (lRet != ERROR_SUCCESS)
+ return _signalRegError(lRet, hKey, hDataKey);
+ ::RegCloseKey(hDataKey); hDataKey = NULL;
+
+
+ // Setup the PegasusFilter key values
+ lRet = ::RegCreateKeyEx(hKey, _T("PegasusFilter"), 0, _T(""), 0, KEY_ALL_ACCESS, NULL, &hDataKey, NULL);
+ if (lRet != ERROR_SUCCESS)
+ return _signalRegError(lRet, hKey, hDataKey);
+
+ lRet = ::RegSetValueEx(hDataKey, _T("Description"), 0, REG_SZ, (LPBYTE)CXMergeFilter::m_pszPSWExportDesc,
+ (::_tcslen(CXMergeFilter::m_pszPSWExportDesc) * sizeof(TCHAR) + (1 * sizeof(TCHAR))));
+ if (lRet != ERROR_SUCCESS)
+ return _signalRegError(lRet, hKey, hDataKey);
+
+
+ lRet = ::RegSetValueEx(hDataKey, _T("Export"), 0, REG_SZ, (LPBYTE)_T(""), (1 * sizeof(TCHAR)));
+ if (lRet != ERROR_SUCCESS)
+ return _signalRegError(lRet, hKey, hDataKey);
+
+
+ lRet = ::RegSetValueEx(hDataKey, _T("NewExtension"), 0, REG_SZ, (LPBYTE)CXMergeFilter::m_pszPSWExportExt,
+ (::_tcslen(CXMergeFilter::m_pszPSWExportExt) * sizeof(TCHAR) + (1 * sizeof(TCHAR))));
+ if (lRet != ERROR_SUCCESS)
+ return _signalRegError(lRet, hKey, hDataKey);
+
+
+ ::RegCloseKey(hKey); hKey = NULL;
+ ::RegCloseKey(hDataKey); hDataKey = NULL;
+
+
+
+
+ /*
+ * Following calls create the entries for the filter in
+ * HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows CE Services\Filters
+ */
+
+ lRet = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\Microsoft\\Windows CE Services\\Filters"),
+ 0, KEY_ALL_ACCESS, &hKey);
+ if (lRet != ERROR_SUCCESS)
+ return _signalRegError(lRet, hKey, hDataKey);
+
+ _snprintf(sTemp, _MAX_PATH + 1, "%c%s\\InstalledFilters\0", '.', CXMergeFilter::m_pszPSWImportExt);
+ lRet = ::RegCreateKeyEx(hKey, _T(sTemp),
+ 0, _T(""), 0, KEY_ALL_ACCESS, NULL, &hDataKey, NULL);
+ if (lRet != ERROR_SUCCESS)
+ return _signalRegError(lRet, hKey, hDataKey);
+
+ lRet = ::RegSetValueEx(hDataKey, CXMergeFilter::m_pszPSWExportCLSID, 0, REG_SZ, (LPBYTE)_T(""), (1 * sizeof(TCHAR)));
+ if (lRet != ERROR_SUCCESS)
+ return _signalRegError(lRet, hKey, hDataKey);
+
+ ::RegCloseKey(hKey); hKey = NULL;
+ ::RegCloseKey(hDataKey); hDataKey = NULL;
+
+
+
+ /*
+ * Following calls create the HKEY_CLASSES_ROOT\CLSID entry for the Writer import filter.
+ *
+ * Note that import are export are relative to the WinCE device, so files are
+ * exported to the desktop format.
+ */
+ // Get a handle to the CLSID key
+ lRet = ::RegOpenKeyEx(HKEY_CLASSES_ROOT, _T("CLSID"), 0, KEY_ALL_ACCESS, &hKey);
+ if (lRet != ERROR_SUCCESS)
+ return _signalRegError(lRet, hKey, hDataKey);
+
+ // Create the CLSID key for the XMergeFilter
+ lRet = ::RegCreateKeyEx(hKey, CXMergeFilter::m_pszPSWImportCLSID, 0, _T(""), 0, KEY_ALL_ACCESS, NULL, &hKey, NULL);
+ if (lRet != ERROR_SUCCESS)
+ return _signalRegError(lRet, hKey, hDataKey);
+
+ lRet = ::RegSetValueEx(hKey, _T(""), 0, REG_SZ, (LPBYTE)CXMergeFilter::m_pszPSWImportShortDesc,
+ (::_tcslen(CXMergeFilter::m_pszPSWImportShortDesc) * sizeof(TCHAR) + (1 * sizeof(TCHAR))));
+ if (lRet != ERROR_SUCCESS)
+ return _signalRegError(lRet, hKey, hDataKey);
+
+
+ // Create the DefaultIcon key. For the moment, use one of the Async supplied ones
+ lRet = ::RegCreateKeyEx(hKey, _T("DefaultIcon"), 0, _T(""), 0, KEY_ALL_ACCESS, NULL, &hDataKey, NULL);
+ if (lRet != ERROR_SUCCESS)
+ return _signalRegError(lRet, hKey, hDataKey);
+
+ lRet = ::RegSetValueEx(hDataKey, NULL, 0, REG_SZ, (LPBYTE)_T("C:\\Program Files\\Microsoft ActiveSync\\pwdcnv.dll,0"),
+ (::_tcslen(_T("C:\\Program Files\\Microsoft ActiveSync\\pwdcnv.dll,0"))
+ * sizeof(TCHAR) + (1 * sizeof(TCHAR))));
+ if (lRet != ERROR_SUCCESS)
+ return _signalRegError(lRet, hKey, hDataKey);
+ ::RegCloseKey(hDataKey); hDataKey = NULL;
+
+
+ // Create the InprocServer32 key
+ lRet = ::RegCreateKeyEx(hKey, _T("InProcServer32"), 0, _T(""), 0, KEY_ALL_ACCESS, NULL, &hDataKey, NULL);
+ if (lRet != ERROR_SUCCESS)
+ return _signalRegError(lRet, hKey, hDataKey);
+
+ lRet = ::RegSetValueEx(hDataKey, _T("ThreadingModel"), 0, REG_SZ, (LPBYTE)_T("Apartment"), 10);
+ if (lRet != ERROR_SUCCESS)
+ return _signalRegError(lRet, hKey, hDataKey);
+
+
+ // Create the key for the DLL file. First find the filename of the dll
+ if (!::GetModuleFileName((HMODULE)_Module.m_hInst, sTemp, (_MAX_PATH + 1)))
+ {
+ lRet = ::GetLastError();
+ if (lRet != ERROR_SUCCESS)
+ return _signalRegError(lRet, hKey, hDataKey);
+ }
+
+
+ lRet = ::RegSetValueEx(hDataKey, NULL, 0, REG_SZ, (LPBYTE)sTemp,
+ (::_tcslen(sTemp) * sizeof(TCHAR) + (1 * sizeof(TCHAR))));
+ if (lRet != ERROR_SUCCESS)
+ return _signalRegError(lRet, hKey, hDataKey);
+ ::RegCloseKey(hDataKey); hDataKey = NULL;
+
+
+ // Setup the PegasusFilter key values
+ lRet = ::RegCreateKeyEx(hKey, _T("PegasusFilter"), 0, _T(""), 0, KEY_ALL_ACCESS, NULL, &hDataKey, NULL);
+ if (lRet != ERROR_SUCCESS)
+ return _signalRegError(lRet, hKey, hDataKey);
+
+ lRet = ::RegSetValueEx(hDataKey, _T("Description"), 0, REG_SZ, (LPBYTE)CXMergeFilter::m_pszPSWImportDesc,
+ (::_tcslen(CXMergeFilter::m_pszPSWImportDesc) * sizeof(TCHAR) + (1 * sizeof(TCHAR))));
+ if (lRet != ERROR_SUCCESS)
+ return _signalRegError(lRet, hKey, hDataKey);
+
+
+ lRet = ::RegSetValueEx(hDataKey, _T("Import"), 0, REG_SZ, (LPBYTE)_T(""), (1 * sizeof(TCHAR)));
+ if (lRet != ERROR_SUCCESS)
+ return _signalRegError(lRet, hKey, hDataKey);
+
+
+ lRet = ::RegSetValueEx(hDataKey, _T("NewExtension"), 0, REG_SZ, (LPBYTE)CXMergeFilter::m_pszPSWImportExt,
+ (::_tcslen(CXMergeFilter::m_pszPSWImportExt) * sizeof(TCHAR) + (1 * sizeof(TCHAR))));
+ if (lRet != ERROR_SUCCESS)
+ return _signalRegError(lRet, hKey, hDataKey);
+
+
+ ::RegCloseKey(hKey); hKey = NULL;
+ ::RegCloseKey(hDataKey); hDataKey = NULL;
+
+
+ /*
+ * Following calls create the entries for the filter in
+ * HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows CE Services\Filters
+ */
+ lRet = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\Microsoft\\Windows CE Services\\Filters"),
+ 0, KEY_ALL_ACCESS, &hKey);
+ if (lRet != ERROR_SUCCESS)
+ return _signalRegError(lRet, hKey, hDataKey);
+
+ // Add in defaults for import and export
+ _snprintf(sTemp, _MAX_PATH +1, "%c%s\0", '.', CXMergeFilter::m_pszPSWExportExt);
+ lRet = ::RegCreateKeyEx(hKey, _T(sTemp), 0, _T(""), 0, KEY_ALL_ACCESS, NULL, &hDataKey, NULL);
+ if (lRet != ERROR_SUCCESS)
+ return _signalRegError(lRet, hKey, hDataKey);
+
+ lRet = ::RegSetValueEx(hDataKey, _T("DefaultImport"), 0, REG_SZ,
+ (LPBYTE)CXMergeFilter::m_pszPSWImportCLSID,
+ (::_tcslen(CXMergeFilter::m_pszPSWImportDesc) * sizeof(TCHAR) + (1 * sizeof(TCHAR))));
+ if (lRet != ERROR_SUCCESS)
+ return _signalRegError(lRet, hKey, hDataKey);
+
+
+ lRet = ::RegSetValueEx(hDataKey, _T("DefaultExport"), 0, REG_SZ, (LPBYTE)_T("Binary Copy"),
+ (::_tcslen(_T("Binary Copy")) * sizeof(TCHAR) + (1 * sizeof(TCHAR))));
+ if (lRet != ERROR_SUCCESS)
+ return _signalRegError(lRet, hKey, hDataKey);
+
+ ::RegCloseKey(hDataKey);
+
+ // Update registered filters
+ _snprintf(sTemp, _MAX_PATH + 1, "%c%s\\InstalledFilters\0", '.', CXMergeFilter::m_pszPSWExportExt);
+ lRet = ::RegCreateKeyEx(hKey, _T(sTemp),
+ 0, _T(""), 0, KEY_ALL_ACCESS, NULL, &hDataKey, NULL);
+ if (lRet != ERROR_SUCCESS)
+ return _signalRegError(lRet, hKey, hDataKey);
+
+
+ lRet = ::RegSetValueEx(hDataKey, CXMergeFilter::m_pszPSWImportCLSID, 0, REG_SZ, (LPBYTE)_T(""), (1 * sizeof(TCHAR)));
+ if (lRet != ERROR_SUCCESS)
+ return _signalRegError(lRet, hKey, hDataKey);
+
+ ::RegCloseKey(hKey); hKey = NULL;
+ ::RegCloseKey(hDataKey); hDataKey = NULL;
+
+
+
+ /*
+ * Following calls create the HKEY_CLASSES_ROOT\CLSID entry for the Calc export filter.
+ *
+ * Note that import are export are relative to the WinCE device, so files are
+ * exported to the desktop format.
+ */
+
+ // Get a handle to the CLSID key
+ lRet = ::RegOpenKeyEx(HKEY_CLASSES_ROOT, _T("CLSID"), 0, KEY_ALL_ACCESS, &hKey);
+ if (lRet != ERROR_SUCCESS)
+ return _signalRegError(lRet, hKey, hDataKey);
+
+ // Create the CLSID key for the XMerge Filter
+ lRet = ::RegCreateKeyEx(hKey, CXMergeFilter::m_pszPXLExportCLSID, 0, _T(""),
+ 0, KEY_ALL_ACCESS, NULL, &hKey, NULL);
+ if (lRet != ERROR_SUCCESS)
+ return _signalRegError(lRet, hKey, hDataKey);
+
+ lRet = ::RegSetValueEx(hKey, _T(""), 0, REG_SZ, (LPBYTE)CXMergeFilter::m_pszPXLExportShortDesc,
+ (::_tcslen(CXMergeFilter::m_pszPXLExportShortDesc) * sizeof(TCHAR) + (1 * sizeof(TCHAR))));
+ if (lRet != ERROR_SUCCESS)
+ return _signalRegError(lRet, hKey, hDataKey);
+
+
+ // Create the DefaultIcon key. For the moment, use one of the Async supplied ones
+ lRet = ::RegCreateKeyEx(hKey, _T("DefaultIcon"), 0, _T(""), 0, KEY_ALL_ACCESS, NULL, &hDataKey, NULL);
+ if (lRet != ERROR_SUCCESS)
+ return _signalRegError(lRet, hKey, hDataKey);
+
+ lRet = ::RegSetValueEx(hDataKey, NULL, 0, REG_SZ, (LPBYTE)_T("C:\\Program Files\\Microsoft ActiveSync\\pwdcnv.dll,0"),
+ (::_tcslen(_T("C:\\Program Files\\Microsoft ActiveSync\\pwdcnv.dll,0"))
+ * sizeof(TCHAR) + (1 * sizeof(TCHAR))));
+ if (lRet != ERROR_SUCCESS)
+ return _signalRegError(lRet, hKey, hDataKey);
+ ::RegCloseKey(hDataKey); hDataKey = NULL;
+
+
+ // Create the InprocServer32 key
+ lRet = ::RegCreateKeyEx(hKey, _T("InProcServer32"), 0, _T(""), 0, KEY_ALL_ACCESS, NULL, &hDataKey, NULL);
+ if (lRet != ERROR_SUCCESS)
+ return _signalRegError(lRet, hKey, hDataKey);
+
+ lRet = ::RegSetValueEx(hDataKey, _T("ThreadingModel"), 0, REG_SZ, (LPBYTE)_T("Apartment"), 10);
+ if (lRet != ERROR_SUCCESS)
+ return _signalRegError(lRet, hKey, hDataKey);
+
+
+ // Create the key for the DLL file. First find the filename of the dll
+ if (!::GetModuleFileName((HMODULE)_Module.m_hInst, sTemp, (_MAX_PATH + 1)))
+ {
+ lRet = ::GetLastError();
+ if (lRet != ERROR_SUCCESS)
+ return _signalRegError(lRet, hKey, hDataKey);
+ }
+
+
+ lRet = ::RegSetValueEx(hDataKey, NULL, 0, REG_SZ, (LPBYTE)sTemp,
+ (::_tcslen(sTemp) * sizeof(TCHAR) + (1 * sizeof(TCHAR))));
+ if (lRet != ERROR_SUCCESS)
+ return _signalRegError(lRet, hKey, hDataKey);
+ ::RegCloseKey(hDataKey); hDataKey = NULL;
+
+
+ // Setup the PegasusFilter key values
+ lRet = ::RegCreateKeyEx(hKey, _T("PegasusFilter"), 0, _T(""), 0, KEY_ALL_ACCESS, NULL, &hDataKey, NULL);
+ if (lRet != ERROR_SUCCESS)
+ return _signalRegError(lRet, hKey, hDataKey);
+
+ lRet = ::RegSetValueEx(hDataKey, _T("Description"), 0, REG_SZ, (LPBYTE)CXMergeFilter::m_pszPXLExportDesc,
+ (::_tcslen(CXMergeFilter::m_pszPXLExportDesc) * sizeof(TCHAR) + (1 * sizeof(TCHAR))));
+ if (lRet != ERROR_SUCCESS)
+ return _signalRegError(lRet, hKey, hDataKey);
+
+
+ lRet = ::RegSetValueEx(hDataKey, _T("Export"), 0, REG_SZ, (LPBYTE)_T(""), (1 * sizeof(TCHAR)));
+ if (lRet != ERROR_SUCCESS)
+ return _signalRegError(lRet, hKey, hDataKey);
+
+
+ lRet = ::RegSetValueEx(hDataKey, _T("NewExtension"), 0, REG_SZ, (LPBYTE)CXMergeFilter::m_pszPXLExportExt,
+ (::_tcslen(CXMergeFilter::m_pszPXLExportExt) * sizeof(TCHAR) + (1 * sizeof(TCHAR))));
+ if (lRet != ERROR_SUCCESS)
+ return _signalRegError(lRet, hKey, hDataKey);
+
+
+ ::RegCloseKey(hKey); hKey = NULL;
+ ::RegCloseKey(hDataKey); hDataKey = NULL;
+
+
+
+
+ /*
+ * Following calls create the entries for the filter in
+ * HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows CE Services\Filters
+ */
+
+ lRet = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\Microsoft\\Windows CE Services\\Filters"),
+ 0, KEY_ALL_ACCESS, &hKey);
+ if (lRet != ERROR_SUCCESS)
+ return _signalRegError(lRet, hKey, hDataKey);
+
+ _snprintf(sTemp, _MAX_PATH + 1, "%c%s\\InstalledFilters\0", '.', CXMergeFilter::m_pszPXLImportExt);
+ lRet = ::RegCreateKeyEx(hKey, _T(sTemp),
+ 0, _T(""), 0, KEY_ALL_ACCESS, NULL, &hDataKey, NULL);
+ if (lRet != ERROR_SUCCESS)
+ return _signalRegError(lRet, hKey, hDataKey);
+
+ lRet = ::RegSetValueEx(hDataKey, CXMergeFilter::m_pszPXLExportCLSID, 0, REG_SZ, (LPBYTE)_T(""), (1 * sizeof(TCHAR)));
+ if (lRet != ERROR_SUCCESS)
+ return _signalRegError(lRet, hKey, hDataKey);
+
+ ::RegCloseKey(hKey); hKey = NULL;
+ ::RegCloseKey(hDataKey); hDataKey = NULL;
+
+
+
+ /*
+ * Following calls create the HKEY_CLASSES_ROOT\CLSID entry for the Calc import filter.
+ *
+ * Note that import are export are relative to the WinCE device, so files are
+ * exported to the desktop format.
+ */
+ // Get a handle to the CLSID key
+ lRet = ::RegOpenKeyEx(HKEY_CLASSES_ROOT, _T("CLSID"), 0, KEY_ALL_ACCESS, &hKey);
+ if (lRet != ERROR_SUCCESS)
+ return _signalRegError(lRet, hKey, hDataKey);
+
+
+ // Create the CLSID key for the XMergeFilter
+ lRet = ::RegCreateKeyEx(hKey, CXMergeFilter::m_pszPXLImportCLSID, 0, _T(""), 0, KEY_ALL_ACCESS, NULL, &hKey, NULL);
+ if (lRet != ERROR_SUCCESS)
+ return _signalRegError(lRet, hKey, hDataKey);
+
+ lRet = ::RegSetValueEx(hKey, _T(""), 0, REG_SZ, (LPBYTE)CXMergeFilter::m_pszPXLImportShortDesc,
+ (::_tcslen(CXMergeFilter::m_pszPXLImportShortDesc) * sizeof(TCHAR) + (1 * sizeof(TCHAR))));
+ if (lRet != ERROR_SUCCESS)
+ return _signalRegError(lRet, hKey, hDataKey);
+
+ // Create the DefaultIcon key. For the moment, use one of the Async supplied ones
+ lRet = ::RegCreateKeyEx(hKey, _T("DefaultIcon"), 0, _T(""), 0, KEY_ALL_ACCESS, NULL, &hDataKey, NULL);
+ if (lRet != ERROR_SUCCESS)
+ return _signalRegError(lRet, hKey, hDataKey);
+
+ lRet = ::RegSetValueEx(hDataKey, NULL, 0, REG_SZ, (LPBYTE)_T("C:\\Program Files\\Microsoft ActiveSync\\pwdcnv.dll,0"),
+ (::_tcslen(_T("C:\\Program Files\\Microsoft ActiveSync\\pwdcnv.dll,0"))
+ * sizeof(TCHAR) + (1 * sizeof(TCHAR))));
+ if (lRet != ERROR_SUCCESS)
+ return _signalRegError(lRet, hKey, hDataKey);
+ ::RegCloseKey(hDataKey); hDataKey = NULL;
+
+
+ // Create the InprocServer32 key
+ lRet = ::RegCreateKeyEx(hKey, _T("InProcServer32"), 0, _T(""), 0, KEY_ALL_ACCESS, NULL, &hDataKey, NULL);
+ if (lRet != ERROR_SUCCESS)
+ return _signalRegError(lRet, hKey, hDataKey);
+
+ lRet = ::RegSetValueEx(hDataKey, _T("ThreadingModel"), 0, REG_SZ, (LPBYTE)_T("Apartment"), 10);
+ if (lRet != ERROR_SUCCESS)
+ return _signalRegError(lRet, hKey, hDataKey);
+
+
+ // Create the key for the DLL file. First find the filename of the dll
+ if (!::GetModuleFileName((HMODULE)_Module.m_hInst, sTemp, (_MAX_PATH + 1)))
+ {
+ lRet = ::GetLastError();
+ if (lRet != ERROR_SUCCESS)
+ return _signalRegError(lRet, hKey, hDataKey);
+ }
+
+
+ lRet = ::RegSetValueEx(hDataKey, NULL, 0, REG_SZ, (LPBYTE)sTemp,
+ (::_tcslen(sTemp) * sizeof(TCHAR) + (1 * sizeof(TCHAR))));
+ if (lRet != ERROR_SUCCESS)
+ return _signalRegError(lRet, hKey, hDataKey);
+ ::RegCloseKey(hDataKey); hDataKey = NULL;
+
+
+ // Setup the PegasusFilter key values
+ lRet = ::RegCreateKeyEx(hKey, _T("PegasusFilter"), 0, _T(""), 0, KEY_ALL_ACCESS, NULL, &hDataKey, NULL);
+ if (lRet != ERROR_SUCCESS)
+ return _signalRegError(lRet, hKey, hDataKey);
+
+ lRet = ::RegSetValueEx(hDataKey, _T("Description"), 0, REG_SZ, (LPBYTE)CXMergeFilter::m_pszPXLImportDesc,
+ (::_tcslen(CXMergeFilter::m_pszPXLImportDesc) * sizeof(TCHAR) + (1 * sizeof(TCHAR))));
+ if (lRet != ERROR_SUCCESS)
+ return _signalRegError(lRet, hKey, hDataKey);
+
+
+ lRet = ::RegSetValueEx(hDataKey, _T("Import"), 0, REG_SZ, (LPBYTE)_T(""), (1 * sizeof(TCHAR)));
+ if (lRet != ERROR_SUCCESS)
+ return _signalRegError(lRet, hKey, hDataKey);
+
+
+ lRet = ::RegSetValueEx(hDataKey, _T("NewExtension"), 0, REG_SZ, (LPBYTE)CXMergeFilter::m_pszPXLImportExt,
+ (::_tcslen(CXMergeFilter::m_pszPXLImportExt) * sizeof(TCHAR) + (1 * sizeof(TCHAR))));
+ if (lRet != ERROR_SUCCESS)
+ return _signalRegError(lRet, hKey, hDataKey);
+
+
+ ::RegCloseKey(hKey); hKey = NULL;
+ ::RegCloseKey(hDataKey); hDataKey = NULL;
+
+
+
+ /*
+ * Following calls create the entries for the filter in
+ * HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows CE Services\Filters
+ */
+ lRet = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\Microsoft\\Windows CE Services\\Filters"),
+ 0, KEY_ALL_ACCESS, &hKey);
+ if (lRet != ERROR_SUCCESS)
+ return _signalRegError(lRet, hKey, hDataKey);
+
+ // Add in defaults for import and export
+ _snprintf(sTemp, _MAX_PATH +1, "%c%s\0", '.', CXMergeFilter::m_pszPXLExportExt);
+ lRet = ::RegCreateKeyEx(hKey, _T(sTemp), 0, _T(""), 0, KEY_ALL_ACCESS, NULL, &hDataKey, NULL);
+ if (lRet != ERROR_SUCCESS)
+ return _signalRegError(lRet, hKey, hDataKey);
+
+ lRet = ::RegSetValueEx(hDataKey, _T("DefaultImport"), 0, REG_SZ,
+ (LPBYTE)CXMergeFilter::m_pszPXLImportCLSID,
+ (::_tcslen(CXMergeFilter::m_pszPSWImportDesc) * sizeof(TCHAR) + (1 * sizeof(TCHAR))));
+ if (lRet != ERROR_SUCCESS)
+ return _signalRegError(lRet, hKey, hDataKey);
+
+
+ lRet = ::RegSetValueEx(hDataKey, _T("DefaultExport"), 0, REG_SZ, (LPBYTE)_T("Binary Copy"),
+ (::_tcslen(_T("Binary Copy")) * sizeof(TCHAR) + (1 * sizeof(TCHAR))));
+ if (lRet != ERROR_SUCCESS)
+ return _signalRegError(lRet, hKey, hDataKey);
+
+ ::RegCloseKey(hDataKey);
+
+ // Update registered filters
+
+
+ _snprintf(sTemp, _MAX_PATH + 1, "%c%s\\InstalledFilters\0", '.', CXMergeFilter::m_pszPXLExportExt);
+ lRet = ::RegCreateKeyEx(hKey, _T(sTemp),
+ 0, _T(""), 0, KEY_ALL_ACCESS, NULL, &hDataKey, NULL);
+ if (lRet != ERROR_SUCCESS)
+ return _signalRegError(lRet, hKey, hDataKey);
+
+ lRet = ::RegSetValueEx(hDataKey, CXMergeFilter::m_pszPXLImportCLSID, 0, REG_SZ, (LPBYTE)_T(""), (1 * sizeof(TCHAR)));
+ if (lRet != ERROR_SUCCESS)
+ return _signalRegError(lRet, hKey, hDataKey);
+
+ ::RegCloseKey(hKey); hKey = NULL;
+ ::RegCloseKey(hDataKey); hDataKey = NULL;
+
+
+
+ return HRESULT_FROM_WIN32(lRet);
+}
+
+
+STDAPI DllUnregisterServer()
+{
+ long lRet = 0;
+ HKEY hKey = NULL;
+ HKEY hDataKey = NULL;
+
+ TCHAR szClassName[_MAX_PATH] = "\0";
+ TCHAR szKeyName[_MAX_PATH] = "\0";
+ DWORD dwClassName = _MAX_PATH;
+ DWORD dwKeyName = _MAX_PATH;
+
+ /*
+ * Remove HKEY_CLASS_ROOT\CLSID\{XXX} entry for the export and import filters
+ *
+ * Windows 95/98/Me allow one step deletion of a key and all subkeys.
+ * Windows NT/2000/XP do not so the subkeys must be deleted individually.
+ */
+ lRet = ::RegOpenKeyEx(HKEY_CLASSES_ROOT, _T("CLSID"), 0, KEY_ALL_ACCESS, &hKey);
+ if (lRet != ERROR_SUCCESS)
+ return _signalRegError(lRet, hKey, hDataKey);
+
+
+ // First up, the Writer export filter
+ lRet = ::RegOpenKeyEx(hKey, CXMergeFilter::m_pszPSWExportCLSID, 0, KEY_ALL_ACCESS, &hDataKey);
+ if (lRet != ERROR_SUCCESS)
+ return _signalRegError(lRet, hKey, hDataKey);
+
+
+ while ((lRet = ::RegEnumKeyEx(hDataKey, 0, szKeyName, &dwKeyName, 0, szClassName, &dwClassName, NULL))
+ != ERROR_NO_MORE_ITEMS)
+ {
+ lRet = ::RegDeleteKey(hDataKey, szKeyName);
+
+ ::lstrcpy(szKeyName, "\0");
+ ::lstrcpy(szClassName, "\0");
+
+ dwClassName = _MAX_PATH;
+ dwKeyName = _MAX_PATH;
+ }
+
+ ::RegCloseKey(hDataKey); hDataKey = NULL;
+
+ lRet = ::RegDeleteKey(hKey, CXMergeFilter::m_pszPSWExportCLSID);
+ if (lRet != ERROR_SUCCESS && lRet != ERROR_FILE_NOT_FOUND)
+ return _signalRegError(lRet, hKey, hDataKey);
+
+
+
+ // Next, the Writer import filter
+ lRet = ::RegOpenKeyEx(hKey, CXMergeFilter::m_pszPSWImportCLSID, 0, KEY_ALL_ACCESS, &hDataKey);
+ if (lRet != ERROR_SUCCESS)
+ return _signalRegError(lRet, hKey, hDataKey);
+
+
+ while ((lRet = ::RegEnumKeyEx(hDataKey, 0, szKeyName, &dwKeyName, 0, szClassName, &dwClassName, NULL))
+ != ERROR_NO_MORE_ITEMS)
+ {
+ lRet = ::RegDeleteKey(hDataKey, szKeyName);
+
+ ::lstrcpy(szKeyName, "\0");
+ ::lstrcpy(szClassName, "\0");
+
+ dwClassName = _MAX_PATH;
+ dwKeyName = _MAX_PATH;
+ }
+
+ ::RegCloseKey(hDataKey); hDataKey = NULL;
+
+ lRet = ::RegDeleteKey(hKey, CXMergeFilter::m_pszPSWImportCLSID);
+ if (lRet != ERROR_SUCCESS && lRet != ERROR_FILE_NOT_FOUND)
+ return _signalRegError(lRet, hKey, hDataKey);
+
+
+ // Next up, the Calc export filter
+ lRet = ::RegOpenKeyEx(hKey, CXMergeFilter::m_pszPXLExportCLSID, 0, KEY_ALL_ACCESS, &hDataKey);
+ if (lRet != ERROR_SUCCESS)
+ return _signalRegError(lRet, hKey, hDataKey);
+
+
+ while ((lRet = ::RegEnumKeyEx(hDataKey, 0, szKeyName, &dwKeyName, 0, szClassName, &dwClassName, NULL))
+ != ERROR_NO_MORE_ITEMS)
+ {
+ lRet = ::RegDeleteKey(hDataKey, szKeyName);
+
+ ::lstrcpy(szKeyName, "\0");
+ ::lstrcpy(szClassName, "\0");
+
+ dwClassName = _MAX_PATH;
+ dwKeyName = _MAX_PATH;
+ }
+
+ ::RegCloseKey(hDataKey); hDataKey = NULL;
+
+ lRet = ::RegDeleteKey(hKey, CXMergeFilter::m_pszPXLExportCLSID);
+ if (lRet != ERROR_SUCCESS && lRet != ERROR_FILE_NOT_FOUND)
+ return _signalRegError(lRet, hKey, hDataKey);
+
+
+ // Next, the Calc import filter
+ lRet = ::RegOpenKeyEx(hKey, CXMergeFilter::m_pszPXLImportCLSID, 0, KEY_ALL_ACCESS, &hDataKey);
+ if (lRet != ERROR_SUCCESS)
+ return _signalRegError(lRet, hKey, hDataKey);
+
+
+ while ((lRet = ::RegEnumKeyEx(hDataKey, 0, szKeyName, &dwKeyName, 0, szClassName, &dwClassName, NULL))
+ != ERROR_NO_MORE_ITEMS)
+ {
+ lRet = ::RegDeleteKey(hDataKey, szKeyName);
+
+ ::lstrcpy(szKeyName, "\0");
+ ::lstrcpy(szClassName, "\0");
+
+ dwClassName = _MAX_PATH;
+ dwKeyName = _MAX_PATH;
+ }
+
+ ::RegCloseKey(hDataKey); hDataKey = NULL;
+
+ lRet = ::RegDeleteKey(hKey, CXMergeFilter::m_pszPXLImportCLSID);
+ if (lRet != ERROR_SUCCESS && lRet != ERROR_FILE_NOT_FOUND)
+ return _signalRegError(lRet, hKey, hDataKey);
+
+ ::RegCloseKey(hKey); hKey = NULL;
+
+
+
+ /*
+ * Remove the HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows CE Services\Filters
+ */
+ lRet = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\Microsoft\\Windows CE Services\\Filters"),
+ 0, KEY_ALL_ACCESS, &hKey);
+ if (lRet != ERROR_SUCCESS)
+ return _signalRegError(lRet, hKey, hDataKey);
+
+
+ // Remove the Writer export filter from the Writer import file extension subkey.
+ _snprintf(szKeyName, _MAX_PATH, ".%s\\InstalledFilters", CXMergeFilter::m_pszPSWImportExt);
+ lRet = ::RegOpenKeyEx(hKey, _T(szKeyName), 0, KEY_ALL_ACCESS, &hDataKey);
+ if (lRet != ERROR_SUCCESS)
+ return _signalRegError(lRet, hKey, hDataKey);
+
+ lRet = ::RegDeleteValue(hDataKey, CXMergeFilter::m_pszPSWExportCLSID);
+ if (lRet != ERROR_SUCCESS)
+ return _signalRegError(lRet, hKey, hDataKey);
+
+ ::lstrcpyn(szKeyName, "\0", _MAX_PATH);
+ ::RegCloseKey(hDataKey); hDataKey = NULL;
+
+
+ // Remove the Writer import filter from the Writer export file extension subkey.
+ _snprintf(szKeyName, _MAX_PATH, ".%s\\InstalledFilters", CXMergeFilter::m_pszPSWExportExt);
+ lRet = ::RegOpenKeyEx(hKey, _T(szKeyName), 0, KEY_ALL_ACCESS, &hDataKey);
+ if (lRet != ERROR_SUCCESS)
+ return _signalRegError(lRet, hKey, hDataKey);
+
+ lRet = ::RegDeleteValue(hDataKey, CXMergeFilter::m_pszPSWImportCLSID);
+ if (lRet != ERROR_SUCCESS)
+ return _signalRegError(lRet, hKey, hDataKey);
+
+ ::lstrcpyn(szKeyName, "\0", _MAX_PATH);
+ ::RegCloseKey(hDataKey); hDataKey = NULL;
+
+
+ // Make Binary Copy the default for Writer export file extension subkey DefaultImport
+ _snprintf(szKeyName, _MAX_PATH, ".%s\0", CXMergeFilter::m_pszPSWExportExt);
+ lRet = ::RegOpenKeyEx(hKey, _T(szKeyName), 0, KEY_ALL_ACCESS, &hDataKey);
+ if (lRet != ERROR_SUCCESS)
+ return _signalRegError(lRet, hKey, hDataKey);
+
+ lRet = ::RegSetValueEx(hDataKey, _T("DefaultImport"), 0, REG_SZ, (LPBYTE)_T("Binary Copy"),
+ (::_tcslen(_T("Binary Copy")) * sizeof(TCHAR) + (1 * sizeof(TCHAR))));
+ if (lRet != ERROR_SUCCESS)
+ return _signalRegError(lRet, hKey, hDataKey);
+
+ ::lstrcpyn(szKeyName, "\0", _MAX_PATH);
+ ::RegCloseKey(hDataKey); hDataKey = NULL;
+
+
+ // Remove the Calc export filter from the Calc import file extension subkey.
+ _snprintf(szKeyName, _MAX_PATH, ".%s\\InstalledFilters", CXMergeFilter::m_pszPXLImportExt);
+ lRet = ::RegOpenKeyEx(hKey, _T(szKeyName), 0, KEY_ALL_ACCESS, &hDataKey);
+ if (lRet != ERROR_SUCCESS)
+ return _signalRegError(lRet, hKey, hDataKey);
+
+ lRet = ::RegDeleteValue(hDataKey, CXMergeFilter::m_pszPXLExportCLSID);
+ if (lRet != ERROR_SUCCESS)
+ return _signalRegError(lRet, hKey, hDataKey);
+
+ ::lstrcpyn(szKeyName, "\0", _MAX_PATH);
+ ::RegCloseKey(hDataKey); hDataKey = NULL;
+
+ // Remove the Calc import filter from the Calc export file extension subkey.
+ _snprintf(szKeyName, _MAX_PATH, ".%s\\InstalledFilters", CXMergeFilter::m_pszPXLExportExt);
+ lRet = ::RegOpenKeyEx(hKey, _T(szKeyName), 0, KEY_ALL_ACCESS, &hDataKey);
+ if (lRet != ERROR_SUCCESS)
+ return _signalRegError(lRet, hKey, hDataKey);
+
+ lRet = ::RegDeleteValue(hDataKey, CXMergeFilter::m_pszPXLImportCLSID);
+ if (lRet != ERROR_SUCCESS)
+ return _signalRegError(lRet, hKey, hDataKey);
+
+ ::lstrcpyn(szKeyName, "\0", _MAX_PATH);
+ ::RegCloseKey(hDataKey); hDataKey = NULL;
+
+
+ // Make Binary Copy the default for Calc export file extension subkey DefaultImport
+ _snprintf(szKeyName, _MAX_PATH, ".%s\0", CXMergeFilter::m_pszPXLExportExt);
+ lRet = ::RegOpenKeyEx(hKey, _T(szKeyName), 0, KEY_ALL_ACCESS, &hDataKey);
+ if (lRet != ERROR_SUCCESS)
+ return _signalRegError(lRet, hKey, hDataKey);
+
+ lRet = ::RegSetValueEx(hDataKey, _T("DefaultImport"), 0, REG_SZ, (LPBYTE)_T("Binary Copy"),
+ (::_tcslen(_T("Binary Copy")) * sizeof(TCHAR) + (1 * sizeof(TCHAR))));
+ if (lRet != ERROR_SUCCESS)
+ return _signalRegError(lRet, hKey, hDataKey);
+
+ ::lstrcpyn(szKeyName, "\0", _MAX_PATH);
+ ::RegCloseKey(hDataKey); hDataKey = NULL;
+
+
+
+ ::RegCloseKey(hKey); hKey = NULL;
+
+ return HRESULT_FROM_WIN32(lRet);
+}
+
+
+//////////////////////////////////////////////////////////////////////
+// CXMergeSyncModule methods
+//////////////////////////////////////////////////////////////////////
+CXMergeSyncModule::CXMergeSyncModule ()
+{
+}
+
+CXMergeSyncModule::~CXMergeSyncModule ()
+{
+}
+
+long CXMergeSyncModule::LockServer(BOOL fLock)
+{
+ if(fLock)
+ return ::InterlockedIncrement(&m_lLocks);
+ else
+ return ::InterlockedDecrement(&m_lLocks);
+}
+
+long CXMergeSyncModule::GetLockCount()
+{
+ return m_lLocks + m_lObjs;
+}
+
diff --git a/xmerge/source/activesync/XMergeSync.def b/xmerge/source/activesync/XMergeSync.def
new file mode 100644
index 000000000000..89de774085f8
--- /dev/null
+++ b/xmerge/source/activesync/XMergeSync.def
@@ -0,0 +1,9 @@
+
+LIBRARY "XMERGESYNC.DLL"
+DESCRIPTION 'XMerge Desktop Synchronization Module'
+
+EXPORTS
+ DllCanUnloadNow PRIVATE
+ DllGetClassObject PRIVATE
+ DllRegisterServer PRIVATE
+ DllUnregisterServer PRIVATE
diff --git a/xmerge/source/activesync/XMergeSync.dsp b/xmerge/source/activesync/XMergeSync.dsp
new file mode 100644
index 000000000000..3c13e028e50b
--- /dev/null
+++ b/xmerge/source/activesync/XMergeSync.dsp
@@ -0,0 +1,143 @@
+# Microsoft Developer Studio Project File - Name="XMergeSync" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
+
+CFG=XMergeSync - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "XMergeSync.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "XMergeSync.mak" CFG="XMergeSync - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "XMergeSync - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "XMergeSync - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""$/XMergeSync", BAAAAAAA"
+# PROP Scc_LocalPath "."
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "XMergeSync - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "XMERGESYNC_EXPORTS" /YX /FD /c
+# ADD CPP /nologo /MT /W3 /GX /O2 /I "C:\Program Files\Windows CE Tools\wce300\Pocket PC 2002\support\ActiveSync\inc" /I "C:\Java\j2sdk1.4.0\include" /I "C:\Java\j2sdk1.4.0\include\win32" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "XMERGESYNC_EXPORTS" /YX /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x1809 /d "NDEBUG"
+# ADD RSC /l 0x1809 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
+
+!ELSEIF "$(CFG)" == "XMergeSync - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "XMERGESYNC_EXPORTS" /YX /FD /GZ /c
+# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "C:\Program Files\Windows CE Tools\wce300\Pocket PC 2002\support\ActiveSync\inc" /I "C:\Java\j2sdk1.4.0\include" /I "C:\Java\j2sdk1.4.0\include\win32" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "XMERGESYNC_EXPORTS" /FR /YX /FD /GZ /c
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x1809 /d "_DEBUG"
+# ADD RSC /l 0x1809 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept /libpath:"C:\Java\j2sdk1.4.0\lib"
+
+!ENDIF
+
+# Begin Target
+
+# Name "XMergeSync - Win32 Release"
+# Name "XMergeSync - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=.\stdafx.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\XMergeFactory.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\XMergeFilter.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\XMergeSync.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\XMergeSync.def
+# End Source File
+# Begin Source File
+
+SOURCE=.\XMergeSync.rc
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Source File
+
+SOURCE=.\stdafx.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\XMergeFactory.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\XMergeFilter.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\XMergeSync.h
+# End Source File
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# End Group
+# End Target
+# End Project
diff --git a/xmerge/source/activesync/XMergeSync.dsw b/xmerge/source/activesync/XMergeSync.dsw
new file mode 100644
index 000000000000..eca2ade60ac1
--- /dev/null
+++ b/xmerge/source/activesync/XMergeSync.dsw
@@ -0,0 +1,33 @@
+Microsoft Developer Studio Workspace File, Format Version 6.00
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
+
+###############################################################################
+
+Project: "XMergeSync"=.\XMergeSync.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+ begin source code control
+ "$/XMergeSync", BAAAAAAA
+ .
+ end source code control
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/xmerge/source/activesync/XMergeSync.h b/xmerge/source/activesync/XMergeSync.h
new file mode 100644
index 000000000000..4242b755c1fa
--- /dev/null
+++ b/xmerge/source/activesync/XMergeSync.h
@@ -0,0 +1,29 @@
+// XMergeSyncModule.h: interface for the CXMergeSyncModule class.
+//
+//////////////////////////////////////////////////////////////////////
+
+#if !defined(AFX_XMERGESYNCMODULE_H__0788DA0C_4DCB_4876_9722_F9EAF1EB5462__INCLUDED_)
+#define AFX_XMERGESYNCMODULE_H__0788DA0C_4DCB_4876_9722_F9EAF1EB5462__INCLUDED_
+
+#if _MSC_VER > 1000
+#pragma once
+#endif // _MSC_VER > 1000
+
+
+// Used to keep track of the dll
+
+class CXMergeSyncModule
+{
+protected:
+ long m_lLocks;
+ long m_lObjs;
+
+public:
+ long GetLockCount();
+ long LockServer(BOOL fLock);
+ HINSTANCE m_hInst;
+ CXMergeSyncModule();
+ virtual ~CXMergeSyncModule();
+};
+
+#endif // !defined(AFX_XMERGESYNCMODULE_H__0788DA0C_4DCB_4876_9722_F9EAF1EB5462__INCLUDED_)
diff --git a/xmerge/source/activesync/XMergeSync.rc b/xmerge/source/activesync/XMergeSync.rc
new file mode 100644
index 000000000000..b355bcad7adc
--- /dev/null
+++ b/xmerge/source/activesync/XMergeSync.rc
@@ -0,0 +1,80 @@
+//Microsoft Developer Studio generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+<<<<<<< XMergeSync.rc
+// #include "afxres.h"
+=======
+//#include "afxres.h"
+>>>>>>> 1.1.12.1
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (Ireland) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENI)
+#ifdef _WIN32
+//LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_EIRE
+LANGUAGE 0x9, 0x1
+#pragma code_page(1252)
+#endif //_WIN32
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "#include ""afxres.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// String Table
+//
+
+STRINGTABLE DISCARDABLE
+BEGIN
+ IDS_NOJAVA "Unable to find JRE 1.4 installation."
+ IDS_BADCLASSPATH "Unable to locate necessary Jar files."
+END
+
+#endif // English (Ireland) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/xmerge/source/activesync/exports.map b/xmerge/source/activesync/exports.map
new file mode 100644
index 000000000000..8cda3e4980ad
--- /dev/null
+++ b/xmerge/source/activesync/exports.map
@@ -0,0 +1,12 @@
+UDK_3_0_0 {
+ global:
+ GetVersionInfo;
+ DllCanUnloadNow;
+ DllGetClassObject;
+ DllRegisterServer;
+ DllUnregisterServer;
+
+ local:
+ *;
+};
+
diff --git a/xmerge/source/activesync/guids.txt b/xmerge/source/activesync/guids.txt
new file mode 100644
index 000000000000..1bde5587c169
--- /dev/null
+++ b/xmerge/source/activesync/guids.txt
@@ -0,0 +1,60 @@
+INTERFACENAME = { /* bdd611c3-7bab-460f-8711-5b9ac9ef6020 - StarWriter Export*/
+ 0xbdd611c3,
+ 0x7bab,
+ 0x460f,
+ {0x87, 0x11, 0x5b, 0x9a, 0xc9, 0xef, 0x60, 0x20}
+ };
+INTERFACENAME = { /* cb43f086-838d-4fa4-b5f6-3406b9a57439 - Pocket Word Import */
+ 0xcb43f086,
+ 0x838d,
+ 0x4fa4,
+ {0xb5, 0xf6, 0x34, 0x06, 0xb9, 0xa5, 0x74, 0x39}
+ };
+INTERFACENAME = { /* c6ab3e74-9f4f-4370-8120-a8a6fabb7a7c - StarCalc Export*/
+ 0xc6ab3e74,
+ 0x9f4f,
+ 0x4370,
+ {0x81, 0x20, 0xa8, 0xa6, 0xfa, 0xbb, 0x7a, 0x7c}
+ };
+INTERFACENAME = { /* 43887c67-4d5d-4127-baac-87a288494c7c - Pocket Excel Import*/
+ 0x43887c67,
+ 0x4d5d,
+ 0x4127,
+ {0xba, 0xac, 0x87, 0xa2, 0x88, 0x49, 0x4c, 0x7c}
+ };
+INTERFACENAME = { /* 300b7580-50f6-448b-aabb-9b823cab6e88 */
+ 0x300b7580,
+ 0x50f6,
+ 0x448b,
+ {0xaa, 0xbb, 0x9b, 0x82, 0x3c, 0xab, 0x6e, 0x88}
+ };
+INTERFACENAME = { /* e88b223c-ffb4-456f-b93b-0f59594b228e */
+ 0xe88b223c,
+ 0xffb4,
+ 0x456f,
+ {0xb9, 0x3b, 0x0f, 0x59, 0x59, 0x4b, 0x22, 0x8e}
+ };
+INTERFACENAME = { /* 8a538ec1-7d68-4ad0-9cf9-6e4d9f8c6ff0 */
+ 0x8a538ec1,
+ 0x7d68,
+ 0x4ad0,
+ {0x9c, 0xf9, 0x6e, 0x4d, 0x9f, 0x8c, 0x6f, 0xf0}
+ };
+INTERFACENAME = { /* 7b613acf-9d1b-4bb9-b58e-15e0f5e21765 */
+ 0x7b613acf,
+ 0x9d1b,
+ 0x4bb9,
+ {0xb5, 0x8e, 0x15, 0xe0, 0xf5, 0xe2, 0x17, 0x65}
+ };
+INTERFACENAME = { /* fbf4de58-cfe8-4244-bf73-6162035ae0c6 */
+ 0xfbf4de58,
+ 0xcfe8,
+ 0x4244,
+ {0xbf, 0x73, 0x61, 0x62, 0x03, 0x5a, 0xe0, 0xc6}
+ };
+INTERFACENAME = { /* 62bf28c1-ce42-4b56-a218-980e8c4ba080 */
+ 0x62bf28c1,
+ 0xce42,
+ 0x4b56,
+ {0xa2, 0x18, 0x98, 0x0e, 0x8c, 0x4b, 0xa0, 0x80}
+ };
diff --git a/xmerge/source/activesync/makefile.mk b/xmerge/source/activesync/makefile.mk
new file mode 100644
index 000000000000..18d904f5e158
--- /dev/null
+++ b/xmerge/source/activesync/makefile.mk
@@ -0,0 +1,72 @@
+#*************************************************************************
+#
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# Copyright 2000, 2010 Oracle and/or its affiliates.
+#
+# OpenOffice.org - a multi-platform office productivity suite
+#
+# This file is part of OpenOffice.org.
+#
+# OpenOffice.org is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License version 3
+# only, as published by the Free Software Foundation.
+#
+# OpenOffice.org is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License version 3 for more details
+# (a copy is included in the LICENSE file that accompanied this code).
+#
+# You should have received a copy of the GNU Lesser General Public License
+# version 3 along with OpenOffice.org. If not, see
+# <http://www.openoffice.org/license.html>
+# for a copy of the LGPLv3 License.
+#
+#*************************************************************************
+
+PRJ = ..$/..
+PRJNAME = xmerge
+#PACKAGE = com$/sun$/star$/documentconversion$/XSLTFilter
+TARGET = xmergesync
+ENABLE_EXCEPTIONS=TRUE
+LIBTARGET=NO
+.IF "$(POCKETPCSDK_HOME)" != ""
+SOLARINC+=-I$(POCKETPCSDK_HOME)$/support$/ActiveSync$/inc
+.ENDIF # "$(POCKETPCSDK_HOME)" != ""
+
+# --- Settings -----------------------------------------------------
+.INCLUDE: settings.mk
+
+.IF 0
+.IF "$(GUI)" == "WNT"
+.IF "$(POCKETPCSDK_HOME)" != ""
+
+RCFILES=XMergeSync.rc
+
+SLOFILES= \
+ $(SLO)$/XMergeFactory.obj \
+ $(SLO)$/XMergeSync.obj \
+ $(SLO)$/XMergeFilter.obj
+LIBNAME=$(TARGET)
+SHL1TARGETDEPN=makefile.mk
+SHL1OBJS=$(SLOFILES) $(RES)$/xmergesync.res
+SHL1TARGET=$(LIBNAME)
+SHL1IMPLIB=i$(LIBNAME)
+SHL1DEF=XMergeSync.def
+USE_DEFFILE=true
+
+SHL1STDLIBS= uuid.lib Advapi32.lib
+
+.ENDIF # "$(POCKETPCSDK_HOME)" != ""
+.ENDIF
+.ENDIF
+
+
+# --- Targets ------------------------------------------------------
+.INCLUDE : target.mk
+
+ALLTAR :
+ .IF "$(GUI)" == "WNT"
+ $(COPY) BIN$/xmergesync.dll $(BIN)
+ .ENDIF
diff --git a/xmerge/source/activesync/resource.h b/xmerge/source/activesync/resource.h
new file mode 100644
index 000000000000..c670835a7455
--- /dev/null
+++ b/xmerge/source/activesync/resource.h
@@ -0,0 +1,17 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Developer Studio generated include file.
+// Used by XMergeSync.rc
+//
+#define IDS_NOJAVA 1
+#define IDS_BADCLASSPATH 2
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 101
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1000
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/xmerge/source/activesync/stdafx.cpp b/xmerge/source/activesync/stdafx.cpp
new file mode 100644
index 000000000000..eefe5176aad4
--- /dev/null
+++ b/xmerge/source/activesync/stdafx.cpp
@@ -0,0 +1,7 @@
+//
+// stdafx.cpp : source file that includes just the standard includes
+// stdafx.pch will be the pre-compiled header
+// stdafx.obj will contain the pre-compiled type information
+//
+#include "stdafx.h"
+
diff --git a/xmerge/source/activesync/stdafx.h b/xmerge/source/activesync/stdafx.h
new file mode 100644
index 000000000000..26faa277a87c
--- /dev/null
+++ b/xmerge/source/activesync/stdafx.h
@@ -0,0 +1,28 @@
+//
+// stdafx.h : include file for standard system include files,
+// or project specific include files that are used frequently,
+// but are changed infrequently
+//
+#pragma once
+
+#include <windows.h>
+#include <shlobj.h>
+#include <stdio.h>
+#include <tchar.h>
+#include <time.h>
+
+#define INITGUIDS
+#include <initguid.h>
+
+#include <cesync.h>
+#include <replfilt.h>
+
+#include "XMergeSync.h"
+
+//
+// This declares the one & only instance of the CXMergeSyncModule class.
+// You can access any public members of this class through the
+// global _Module. (Its definition is in XMergeSync.cpp.)
+//
+extern CXMergeSyncModule _Module;
+
diff --git a/xmerge/source/aportisdoc/build.xml b/xmerge/source/aportisdoc/build.xml
new file mode 100644
index 000000000000..6e9d22b84b9a
--- /dev/null
+++ b/xmerge/source/aportisdoc/build.xml
@@ -0,0 +1,76 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ #*************************************************************************
+ #
+ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+
+ Copyright 2000, 2010 Oracle and/or its affiliates.
+
+ OpenOffice.org - a multi-platform office productivity suite
+
+ This file is part of OpenOffice.org.
+
+ OpenOffice.org is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License version 3
+ only, as published by the Free Software Foundation.
+
+ OpenOffice.org is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License version 3 for more details
+ (a copy is included in the LICENSE file that accompanied this code).
+
+ You should have received a copy of the GNU Lesser General Public License
+ version 3 along with OpenOffice.org. If not, see
+ <http://www.openoffice.org/license.html>
+ for a copy of the LGPLv3 License.
+
+ #*************************************************************************
+ -->
+
+<project name="aportisdoc" default="all" basedir=".">
+
+ <property file="../inc/antbuild.properties"/>
+
+ <path id="classpath">
+ <pathelement location="${build.dir}/xmerge.jar"/>
+ </path>
+
+
+ <target name="init" >
+ <mkdir dir="${target.dir}"/>
+ </target>
+
+ <!-- compile java sources in ${package} -->
+ <target name="compile" depends="init">
+ <javac srcdir="${src.dir}"
+ destdir="${target.dir}"
+ debug="${debug}"
+ deprecation="${deprecation}"
+ optimize="${optimize}">
+ <classpath refid="classpath"/>
+ </javac>
+ </target>
+
+ <!-- package to jar -->
+ <target name="jar" depends="compile">
+ <jar destfile="${target.jar}">
+ <fileset dir="${target.dir}"
+ includes="**/*.class" />
+ <metainf dir="${basedir}">
+ <filename name="converter.xml"/>
+ </metainf>
+ </jar>
+ </target>
+
+ <!-- clean up -->
+ <target name="clean">
+ <delete dir="${class.dir}"/>
+ <delete file="${target.jar}"/>
+ </target>
+
+ <target name="all" depends="jar">
+ </target>
+
+</project>
+
diff --git a/xmerge/source/aportisdoc/converter.xml b/xmerge/source/aportisdoc/converter.xml
new file mode 100644
index 000000000000..3124e1e3876e
--- /dev/null
+++ b/xmerge/source/aportisdoc/converter.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0"?>
+<!--
+ #*************************************************************************
+ #
+ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+
+ Copyright 2000, 2010 Oracle and/or its affiliates.
+
+ OpenOffice.org - a multi-platform office productivity suite
+
+ This file is part of OpenOffice.org.
+
+ OpenOffice.org is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License version 3
+ only, as published by the Free Software Foundation.
+
+ OpenOffice.org is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License version 3 for more details
+ (a copy is included in the LICENSE file that accompanied this code).
+
+ You should have received a copy of the GNU Lesser General Public License
+ version 3 along with OpenOffice.org. If not, see
+ <http://www.openoffice.org/license.html>
+ for a copy of the LGPLv3 License.
+
+ #*************************************************************************
+ -->
+<converters>
+ <converter type="staroffice/sxw" version="1.0">
+ <converter-display-name>
+ AportisDoc
+ </converter-display-name>
+ <converter-description>
+ StarWriter XML to/from AportisDoc conversion
+ </converter-description>
+ <converter-vendor>OpenOffice.org</converter-vendor>
+ <converter-class-impl>
+ org.openoffice.xmerge.converter.xml.sxw.aportisdoc.PluginFactoryImpl
+ </converter-class-impl>
+ <converter-target type="application/x-aportisdoc" />
+ </converter>
+</converters>
+
diff --git a/xmerge/source/aportisdoc/java/org/openoffice/xmerge/converter/xml/sxw/aportisdoc/ConverterCapabilitiesImpl.java b/xmerge/source/aportisdoc/java/org/openoffice/xmerge/converter/xml/sxw/aportisdoc/ConverterCapabilitiesImpl.java
new file mode 100644
index 000000000000..733450bedad8
--- /dev/null
+++ b/xmerge/source/aportisdoc/java/org/openoffice/xmerge/converter/xml/sxw/aportisdoc/ConverterCapabilitiesImpl.java
@@ -0,0 +1,93 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxw.aportisdoc;
+
+import org.openoffice.xmerge.ConverterCapabilities;
+import org.openoffice.xmerge.converter.xml.OfficeConstants;
+
+/**
+ * <p>AportisDoc implementation of <code>ConverterCapabilities</code> for
+ * the {@link
+ * org.openoffice.xmerge.converter.xml.sxw.aportisdoc.PluginFactoryImpl
+ * PluginFactoryImpl}.</p>
+ *
+ * <p>Used with StarWriter XML to/from AportisDoc conversions. The
+ * <code>ConverterCapibilies</code> specify which &quot;Office&quot;
+ * <code>Document</code> tags and attributes are supported on the
+ * &quot;Device&quot; <code>Document</code> format.</p>
+ */
+public final class ConverterCapabilitiesImpl
+ implements ConverterCapabilities {
+
+ public boolean canConvertTag(String tag) {
+
+ if (OfficeConstants.TAG_OFFICE_DOCUMENT.equals(tag))
+ return true;
+ else if (OfficeConstants.TAG_OFFICE_DOCUMENT_CONTENT.equals(tag))
+ return true;
+ else if (OfficeConstants.TAG_OFFICE_BODY.equals(tag))
+ return true;
+ else if (OfficeConstants.TAG_PARAGRAPH.equals(tag))
+ return true;
+ else if (OfficeConstants.TAG_HEADING.equals(tag))
+ return true;
+ else if (OfficeConstants.TAG_ORDERED_LIST.equals(tag))
+ return true;
+ else if (OfficeConstants.TAG_UNORDERED_LIST.equals(tag))
+ return true;
+ else if (OfficeConstants.TAG_LIST_ITEM.equals(tag))
+ return true;
+ else if (OfficeConstants.TAG_LIST_HEADER.equals(tag))
+ return true;
+ else if (OfficeConstants.TAG_SPAN.equals(tag))
+ return true;
+ else if (OfficeConstants.TAG_HYPERLINK.equals(tag))
+ return true;
+ else if (OfficeConstants.TAG_LINE_BREAK.equals(tag))
+ return true;
+ else if (OfficeConstants.TAG_SPACE.equals(tag))
+ return true;
+ else if (OfficeConstants.TAG_TAB_STOP.equals(tag))
+ return true;
+
+ return false;
+ }
+
+ public boolean canConvertAttribute(String tag,
+ String attribute) {
+
+ if (OfficeConstants.TAG_SPACE.equals(tag)) {
+
+ if (OfficeConstants.ATTRIBUTE_SPACE_COUNT.equals(attribute))
+ return true;
+ }
+
+ return false;
+ }
+}
+
diff --git a/xmerge/source/aportisdoc/java/org/openoffice/xmerge/converter/xml/sxw/aportisdoc/DocConstants.java b/xmerge/source/aportisdoc/java/org/openoffice/xmerge/converter/xml/sxw/aportisdoc/DocConstants.java
new file mode 100644
index 000000000000..f022250bca10
--- /dev/null
+++ b/xmerge/source/aportisdoc/java/org/openoffice/xmerge/converter/xml/sxw/aportisdoc/DocConstants.java
@@ -0,0 +1,69 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxw.aportisdoc;
+
+import org.openoffice.xmerge.converter.palm.PdbUtil;
+
+/**
+ * Constants used for encoding and decoding the AportisDoc format.
+ *
+ * @author Herbie Ong
+ */
+interface DocConstants {
+
+ /** Creator id. */
+ public static final int CREATOR_ID = PdbUtil.intID("REAd");
+
+ /** Type id. */
+ public static final int TYPE_ID = PdbUtil.intID("TEXt");
+
+ /** Constant for uncompressed version. */
+ public static final short UNCOMPRESSED = 1;
+
+ /** Constant for compressed version. */
+ public static final short COMPRESSED = 2;
+
+ /** Constant used for spare fields. */
+ public static final int SPARE = 0;
+
+ /** AportisDoc record size. */
+ public static final short TEXT_RECORD_SIZE = 4096;
+
+ /** Constant for encoding scheme. */
+ public static final String ENCODING = "8859_1";
+
+ /** Constant for TAB character. */
+ public final static char TAB_CHAR = '\t';
+
+ /** Constant for EOL character. */
+ public final static char EOL_CHAR = '\n';
+
+ /** Constant for SPACE character. */
+ public final static char SPACE_CHAR = ' ';
+}
+
diff --git a/xmerge/source/aportisdoc/java/org/openoffice/xmerge/converter/xml/sxw/aportisdoc/DocDecoder.java b/xmerge/source/aportisdoc/java/org/openoffice/xmerge/converter/xml/sxw/aportisdoc/DocDecoder.java
new file mode 100644
index 000000000000..aea2f7cd1ac4
--- /dev/null
+++ b/xmerge/source/aportisdoc/java/org/openoffice/xmerge/converter/xml/sxw/aportisdoc/DocDecoder.java
@@ -0,0 +1,301 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxw.aportisdoc;
+
+import java.io.ByteArrayInputStream;
+import java.io.DataInputStream;
+import java.io.IOException;
+
+import org.openoffice.xmerge.converter.palm.Record;
+import org.openoffice.xmerge.util.Resources;
+import org.openoffice.xmerge.util.Debug;
+
+/**
+ * This class is used by {@link
+ * org.openoffice.xmerge.converter.xml.sxw.DocumentDeserializerImpl}
+ * to decode the AportisDoc format. It currently decodes
+ * the text content into a single <code>String</code> object.
+ *
+ * @author Herbie Ong
+ */
+final class DocDecoder implements DocConstants {
+
+ /** For decoding purposes. */
+ private final static int COUNT_BITS = 3;
+
+ /** Resources object for I18N. */
+ private Resources res = null;
+
+
+ /**
+ * Default constructor creates a header and a text buffer
+ * for holding all the text in the AportisDoc database.
+ */
+ DocDecoder() {
+ res = Resources.getInstance();
+ }
+
+
+ /**
+ * Decode the text records into a single <code>String</code>
+ * of text content.
+ *
+ * @param Record <code>Record</code> array holding AportisDoc
+ * contents.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ String parseRecords(Record[] recs) throws IOException {
+
+ // read the header record
+ HeaderInfo header = readHeader(recs[0].getBytes());
+
+ dumpHeader(header);
+
+ // store all the characters in textBuffer
+ StringBuffer textBuffer = new StringBuffer(header.textLen);
+
+ switch (header.version) {
+
+ case COMPRESSED:
+ for (int i = 1; i <= header.textRecordCount; i++) {
+
+ byte[] bytes = decompress(recs[i].getBytes(),
+ header.textRecordSize);
+ log("processing " + bytes.length + " bytes");
+ String str = new String(bytes, ENCODING);
+ textBuffer.append(str);
+ }
+
+ break;
+
+ case UNCOMPRESSED:
+ for (int i = 1; i <= header.textRecordCount; i++) {
+
+ byte[] bytes = recs[i].getBytes();
+ log("processing " + bytes.length + " bytes");
+ String str = new String(bytes, ENCODING);
+ textBuffer.append(str);
+ }
+
+ break;
+
+ default:
+ throw new IOException(res.getString("UNKNOWN_DOC_VERSION"));
+
+ }
+
+ return textBuffer.toString();
+ }
+
+
+ /**
+ * <p>Decompress the <code>byte</code> array.</p>
+ *
+ * <p>The resulting uncompressed <code>byte</code> array should
+ * be within <code>textRecordSize</code> length, definitely
+ * within twice the size it claims, else treat it as a problem
+ * with the encoding of that PDB and throw
+ * <code>IOException</code>.</p>
+ *
+ * @param bytes Compressed <code>byte</code> array.
+ * @param textRecordSize Size of uncompressed
+ * <code>byte</code> array.
+ *
+ * @throws IOException If <code>textRecordSize</code> &lt;
+ * <code>cBytes.length</code>.
+ */
+ private byte[] decompress(byte[] cBytes, int textRecordSize)
+ throws IOException {
+
+ // create byte array for storing uncompressed bytes
+ // it should be within textRecordSize range, definitely
+ // within twice of textRecordSize! if not, then
+ // an ArrayIndexOutOfBoundsException will get thrown,
+ // and it should be converted into an IOException, and
+ // treat it as a conversion error.
+ byte[] uBytes = new byte[textRecordSize*2];
+
+ int up = 0;
+ int cp = 0;
+
+ try {
+
+ while (cp < cBytes.length) {
+
+ int c = cBytes[cp++] & 0xff;
+
+ // codes 1...8 mean copy that many bytes
+ if (c > 0 && c < 9) {
+
+ while (c-- > 0)
+ uBytes[up++] = cBytes[cp++];
+ }
+
+ // codes 0, 9...0x7F represent themselves
+ else if (c < 0x80) {
+ uBytes[up++] = (byte) c;
+ }
+
+ // codes 0xC0...0xFF represent "space + ascii char"
+ else if (c >= 0xC0) {
+ uBytes[up++] = (byte) ' ';
+ uBytes[up++] = (byte) (c ^ 0x80);
+ }
+
+ // codes 0x80...0xBf represent sequences
+ else {
+ c <<= 8;
+ c += cBytes[cp++] & 0xff;
+ int m = (c & 0x3fff) >> COUNT_BITS;
+ int n = c & ((1 << COUNT_BITS) - 1);
+ n += COUNT_BITS;
+ while (n-- > 0) {
+ uBytes[up] = uBytes[up - m];
+ up++;
+ }
+ }
+ }
+
+ } catch (ArrayIndexOutOfBoundsException e) {
+
+ throw new IOException(
+ res.getString("DOC_TEXT_RECORD_SIZE_EXCEEDED"));
+ }
+
+ // note that ubytes may be larger that the amount of
+ // uncompressed bytes, so trim it to another byte array
+ // with the exact size.
+ byte[] textBytes = new byte[up];
+ System.arraycopy(uBytes, 0, textBytes, 0, up);
+
+ return textBytes;
+ }
+
+
+ /**
+ * Read the header <code>byte</code> array.
+ *
+ * @param bytes <code>byte</code> array containing header
+ * record data.
+ *
+ * @return <code>HeaderInfo</code> object.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ private HeaderInfo readHeader(byte[] bytes) throws IOException {
+
+ HeaderInfo header = new HeaderInfo();
+
+ ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
+ DataInputStream dis = new DataInputStream(bis);
+
+ // Normally the first 2 bytes comprised of the version
+ // which should either be COMPRESSED or UNCOMPRESSED
+ // SmartDoc/Quickword would add a 0x01 to the first
+ // byte, thus their version would be 0x0101 for UNCOMPRESSED
+ // instead of 0x0001 and 0x0102 for UNCOMPRESSED instead of
+ // 0x0002.
+
+ dis.readByte();
+ header.version = dis.readByte();
+
+ // read extra 2 unused bytes
+ dis.readShort();
+
+ // Read the text length, this should be unsigned 4 bytes.
+ // We could store the read value into a long, but then
+ // our current buffer limit is the max positive of an int.
+ // That is a large enough limit, thus we shall stay with
+ // storing the value in an int. If it exceeds, then
+ // an IOException should be thrown.
+ header.textLen = dis.readInt();
+ if (header.textLen < 0) {
+ throw new IOException(res.getString("DOC_TEXT_LENGTH_EXCEEDED"));
+ }
+
+ // read the number of records - unsigned 2 bytes
+ header.textRecordCount = ((int) dis.readShort()) & 0x0000ffff;
+
+ // read the record size - unsigned 2 bytes
+ header.textRecordSize = ((int) dis.readShort()) & 0x0000ffff;
+
+ // read extra 4 unused bytes
+ dis.readInt();
+
+ return header;
+ }
+
+
+ /**
+ * Prints out header info into log. Used for debugging purposes only.
+ *
+ * @param header <code>HeaderInfo</code> structure.
+ */
+ private void dumpHeader(HeaderInfo header) {
+
+ log("<DOC_INFO ");
+ log("version=\"" + header.version + "\" ");
+ log("text-length=\"" + header.textLen + "\" ");
+ log("number-of-records=\"" + header.textRecordCount + "\" ");
+ log("record-size=\"" + header.textRecordSize + "\" />");
+ }
+
+
+ /**
+ * Sends message to the log object.
+ *
+ * @param str Debug string message.
+ */
+ private void log(String str) {
+ Debug.log(Debug.TRACE, str);
+ }
+
+
+ /**
+ * Inner class to store AportisDoc header information.
+ */
+ private class HeaderInfo {
+
+ /** length of text section */
+ int textLen = 0;
+
+ /** number of text records */
+ int textRecordCount = 0;
+
+ /**
+ * size of a text record. This is normally the same as
+ * TEXT_RECORD_SIZE, but some applications may modify this.
+ */
+ int textRecordSize = 0;
+
+ /** compression type */
+ int version = 0;
+ }
+}
+
diff --git a/xmerge/source/aportisdoc/java/org/openoffice/xmerge/converter/xml/sxw/aportisdoc/DocEncoder.java b/xmerge/source/aportisdoc/java/org/openoffice/xmerge/converter/xml/sxw/aportisdoc/DocEncoder.java
new file mode 100644
index 000000000000..b1cb1cbe9905
--- /dev/null
+++ b/xmerge/source/aportisdoc/java/org/openoffice/xmerge/converter/xml/sxw/aportisdoc/DocEncoder.java
@@ -0,0 +1,213 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxw.aportisdoc;
+
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.util.List;
+import java.util.ArrayList;
+
+import org.openoffice.xmerge.converter.palm.Record;
+
+/**
+ * This class is used by {@link
+ * org.openoffice.xmerge.converter.xml.sxw.DocumentSerializerImpl
+ * DocumentSerializerImpl} to encode the AportisDoc format.
+ * It does not deal with any XML tags. It only knows how to encode
+ * from <code>String</code>.
+ *
+ * @author Herbie Ong
+ */
+final class DocEncoder implements DocConstants {
+
+ /** Text buffer to contain text section. */
+ private StringBuffer textBuffer = null;
+
+ /** Length of text section. */
+ private int textLen = 0;
+
+ /** Number of text records. */
+ private int textRecCount = 0;
+
+
+ /**
+ * Default constructor creates a header and
+ * a text buffer for holding all the text in
+ * the AportisDoc database.
+ */
+ DocEncoder() {
+
+ textBuffer = new StringBuffer(TEXT_RECORD_SIZE);
+ }
+
+
+ /**
+ * This method appends text into the text section of
+ * the AportisDoc database.
+ *
+ * @param text <code>String</code> to append.
+ */
+ void addText(String text) {
+
+ textBuffer.append(text);
+ }
+
+
+ /**
+ * This method appends text into the text section of
+ * the AportisDoc database.
+ *
+ * @param text <code>char</code> array to append.
+ */
+ void addText(char[] text) {
+
+ textBuffer.append(text);
+ }
+
+
+ /**
+ * This method appends text character into the text
+ * section of the AportisDoc database.
+ *
+ * @param text <code>char</code> to append.
+ */
+ void addText(char text) {
+
+ textBuffer.append(text);
+ }
+
+
+ /**
+ * This method encodes the information given to a
+ * palm <code>Record</code> array in the AportisDoc
+ * database format.
+ *
+ * @return <code>Record</code> array holding AportisDoc
+ * contents.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ Record[] getRecords() throws IOException {
+
+ byte textBytes[] = processTextBuffer();
+ textLen = textBytes.length;
+ textRecCount = (short) (textBytes.length / TEXT_RECORD_SIZE);
+
+ // recBytes to hold a record of bytes at a time
+ byte recBytes[] = new byte[TEXT_RECORD_SIZE];
+ int pos = 0;
+
+ List textRecords = new ArrayList(textRecCount + 1);
+
+ // split textBytes into chunks of Record objects
+ // and store in textRecords object.
+ for (int i = 0; i < textRecCount; i++) {
+
+ System.arraycopy(textBytes, pos, recBytes, 0, recBytes.length);
+ pos += recBytes.length;
+ Record zRec = new Record(recBytes);
+ textRecords.add(zRec);
+ }
+
+ // there's more if ...
+
+ if (pos < textLen) {
+
+ textRecCount++;
+
+ recBytes = new byte[textLen - pos];
+ System.arraycopy(textBytes, pos, recBytes, 0, recBytes.length);
+ Record rec = new Record(recBytes);
+ textRecords.add(rec);
+ }
+
+ // construct the Record array and copy
+ // references from textRecords.
+
+ Record[] allRecords = new Record[textRecords.size() + 1];
+
+ allRecords[0] = new Record(getHeaderBytes());
+
+ for (int i = 1; i < allRecords.length; i++) {
+
+ allRecords[i] = (Record) textRecords.get(i-1);
+ }
+
+ return allRecords;
+ }
+
+
+ /**
+ * This method converts the text buffer into a <code>byte</code>
+ * array with the proper encoding of the text section of the
+ * AportisDoc format.
+ *
+ * TODO: do compression.
+ *
+ * @return byte[] Converted <code>byte</code> array of text
+ * section.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ private byte[] processTextBuffer() throws IOException
+ {
+ String str = textBuffer.toString();
+ byte bytes[] = str.getBytes(ENCODING);
+
+ return bytes;
+ }
+
+
+ /**
+ * This method produces the <code>byte</code> array for the header.
+ *
+ * @return <code>byte</code> array containing header record data.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ private byte[] getHeaderBytes() throws IOException
+ {
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ DataOutputStream dos = new DataOutputStream(bos);
+
+ // TODO: for now, we shall use UNCOMPRESSED.
+ // later, we need to use COMPRESSED or a setting.
+ dos.writeShort(UNCOMPRESSED);
+ dos.writeShort(SPARE);
+ dos.writeInt(textLen);
+ dos.writeShort(textRecCount);
+ dos.writeShort(TEXT_RECORD_SIZE);
+ dos.writeInt(SPARE);
+
+ byte[] bytes = bos.toByteArray();
+
+ return bytes;
+ }
+}
+
diff --git a/xmerge/source/aportisdoc/java/org/openoffice/xmerge/converter/xml/sxw/aportisdoc/DocumentDeserializerImpl.java b/xmerge/source/aportisdoc/java/org/openoffice/xmerge/converter/xml/sxw/aportisdoc/DocumentDeserializerImpl.java
new file mode 100644
index 000000000000..2d29f8784dc5
--- /dev/null
+++ b/xmerge/source/aportisdoc/java/org/openoffice/xmerge/converter/xml/sxw/aportisdoc/DocumentDeserializerImpl.java
@@ -0,0 +1,312 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxw.aportisdoc;
+
+import org.w3c.dom.NodeList;
+import org.w3c.dom.Node;
+import org.w3c.dom.Element;
+import org.w3c.dom.Text;
+
+import java.io.IOException;
+import java.util.Enumeration;
+
+import org.openoffice.xmerge.Document;
+import org.openoffice.xmerge.ConvertData;
+import org.openoffice.xmerge.ConvertException;
+import org.openoffice.xmerge.DocumentDeserializer;
+import org.openoffice.xmerge.converter.xml.OfficeConstants;
+import org.openoffice.xmerge.converter.xml.sxw.SxwDocument;
+import org.openoffice.xmerge.converter.palm.PalmDB;
+import org.openoffice.xmerge.converter.palm.Record;
+import org.openoffice.xmerge.converter.palm.PalmDocument;
+import org.openoffice.xmerge.util.Debug;
+
+/**
+ * <p>AportisDoc implementation of <code>DocumentDeserializer</code>
+ * for the {@link
+ * org.openoffice.xmerge.converter.xml.sxw.aportisdoc.PluginFactoryImpl
+ * PluginFactoryImpl}.</p>
+ *
+ * <p>This converts an file in AportisDoc PDB format to StarOffice
+ * XML format.</p>
+ *
+ * <p>The <code>deserialize</code> method uses a <code>DocDecoder</code>
+ * to read the AportisDoc format into a <code>String</code> object, then
+ * it calls <code>buildDocument</code> to create a <code>SxwDocument</code>
+ * object from it.</p>
+ *
+ * @author Herbie Ong
+ */
+public final class DocumentDeserializerImpl
+ implements OfficeConstants, DocConstants, DocumentDeserializer {
+
+ /** A <code>ConvertData</code> object assigned to this object. */
+ private ConvertData cd = null;
+
+
+ /**
+ * Constructor that assigns the given <code>ConvertData</code>
+ * to this object as input.
+ *
+ * @param cd A <code>ConvertData</code> object to read data for
+ * the conversion process by the <code>deserialize</code>
+ * method.
+ */
+ public DocumentDeserializerImpl(ConvertData cd) {
+ this.cd = cd;
+ }
+
+
+ /**
+ * Convert the given <code>ConvertData</code> object
+ * into a <code>SxwDocument</code> object.
+ *
+ * @return Resulting <code>SxwDocument</code> object.
+ *
+ * @throws ConvertException If any conversion error occurs.
+ * @throws IOException If any I/O error occurs.
+ */
+ public Document deserialize() throws IOException, ConvertException {
+
+ int numberOfPDBs = cd.getNumDocuments();
+ Document doc = null;
+ int i=0;
+ ConvertData cdOut;
+ Enumeration e = cd.getDocumentEnumeration();
+ while (e.hasMoreElements()) {
+ PalmDocument palmDoc = (PalmDocument) e.nextElement();
+ PalmDB pdb = palmDoc.getPdb();
+
+ log("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
+ log("<AportisDoc>");
+
+ Record[] recs = pdb.getRecords();
+ String docName = palmDoc.getName();
+ DocDecoder decoder = new DocDecoder();
+ String text = decoder.parseRecords(recs);
+ doc = buildDocument(docName, text);
+
+ log("</AportisDoc>");
+ }
+
+ return doc;
+ }
+
+
+ /**
+ * Parses the text content of an AportisDoc format and build a
+ * <code>SxwDocument</code>.
+ *
+ * @param docName Name of <code>Document</code>.
+ * @param str Text content of AportisDoc format.
+ *
+ * @return Resulting <code>SxwDocument</code> object.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ private SxwDocument buildDocument(String docName, String str)
+ throws IOException {
+
+ // create minimum office xml document.
+ SxwDocument sxwDoc = new SxwDocument(docName);
+ sxwDoc.initContentDOM();
+
+ org.w3c.dom.Document doc = sxwDoc.getContentDOM();
+
+ // Grab hold of the office:body tag,
+ // Assume there should be one.
+ // This is where top level paragraphs will append to.
+ NodeList list = doc.getElementsByTagName(TAG_OFFICE_BODY);
+ Node bodyNode = list.item(0);
+
+ // Store all the text in a character array.
+ char[] text = str.toCharArray();
+
+ // startIndex has 2 purposes:
+ // if value is -1, it means that there are no text characters
+ // needed to be processed for a Text node. if value >= 0, it
+ // is the index of the starting position of a text section
+ // for a Text node.
+ int startIndex = -1;
+
+ // Create a paragraph node to start with.
+ Element paraNode = doc.createElement(TAG_PARAGRAPH);
+
+ log("<PARA>");
+
+ for (int i = 0; i < text.length; i++) {
+
+ switch (text[i]) {
+
+ case TAB_CHAR:
+
+ // Check if there are text to be processed first.
+ if (startIndex >= 0) {
+ addTextNode(doc, paraNode, text, startIndex, i - 1);
+ startIndex = -1;
+ }
+
+ // Then, add tab element.
+ Element tabNode = doc.createElement(TAG_TAB_STOP);
+ paraNode.appendChild(tabNode);
+
+ log("<TAB/>");
+ break;
+
+ case EOL_CHAR:
+
+ // Check if there are text to be processed first.
+ if (startIndex >= 0) {
+ addTextNode(doc, paraNode, text, startIndex, i - 1);
+ startIndex = -1;
+ }
+
+ // Then, add the current paragraph to body.
+ bodyNode.appendChild(paraNode);
+
+ // Create another paragraph element.
+ paraNode = doc.createElement(TAG_PARAGRAPH);
+
+ log("</PARA>");
+ log("<PARA>");
+ break;
+
+ case SPACE_CHAR:
+
+ // count is the number of space chars from i
+ int count = 0;
+
+ // Do a look ahead and count the number of space chars
+ while (text[i + 1 + count] == SPACE_CHAR) {
+ count++;
+ }
+
+ // Need to build a space node ONLY if count is > 1.
+
+ if (count > 0) {
+
+ // Check if there are text to be processed first
+ if (startIndex >= 0) {
+ addTextNode(doc, paraNode, text,
+ startIndex, i);
+ startIndex = -1;
+ }
+
+ // Then, create a space element
+ // with the proper attribute.
+ Element spaceNode = doc.createElement(TAG_SPACE);
+ spaceNode.setAttribute(ATTRIBUTE_SPACE_COUNT,
+ Integer.toString(count));
+
+ paraNode.appendChild(spaceNode);
+
+ // reposition i to the last space character.
+ i += count;
+
+ log("<SPACE count=\"" + count + "\" />");
+
+ } else {
+
+ // If there are no chars for text node yet,
+ // consider this one.
+ if (startIndex < 0) {
+
+ startIndex = i;
+ log("<TEXT>");
+ }
+ }
+
+ break;
+
+ default:
+
+ // If there are no chars for text node yet,
+ // this should be the start.
+ if (startIndex < 0) {
+
+ startIndex = i;
+ log("<TEXT>");
+ }
+
+ break;
+ }
+ }
+
+ int lastIndex = text.length - 1;
+
+ // Check if there are text to be processed first.
+
+ if (startIndex >= 0) {
+ addTextNode(doc, paraNode, text, startIndex, lastIndex);
+ }
+
+ // Then, add the last paragraph element if it is not added yet.
+ if (text[lastIndex] != EOL_CHAR) {
+ bodyNode.appendChild(paraNode);
+ }
+
+ log("</PARA>");
+
+ return sxwDoc;
+ }
+
+
+ /**
+ * Add a Text <code>Node</code> to the given paragraph node with the
+ * text starting at the given <code>startPos</code> until
+ * <code>endPos</code>.
+ *
+ * @param doc <code>org.w3c.dom.Document</code> object for creating
+ * <code>Node</code> objects.
+ * @param para The current paragraph <code>Node</code> to append
+ * text <code>Node</code>.
+ * @param text Array of characters containing text.
+ * @param startPos Starting index position for text value.
+ * @param endPos End index position for text value.
+ */
+ private void addTextNode(org.w3c.dom.Document doc, Node para, char text[],
+ int startPos, int endPos) {
+
+ String str = new String(text, startPos, endPos - startPos + 1);
+ Text textNode = doc.createTextNode(str);
+ para.appendChild(textNode);
+ log(str);
+ log("</TEXT>");
+ }
+
+ /**
+ * Sends message to the log object.
+ *
+ * @param str Debug message.
+ */
+ private void log(String str) {
+
+ Debug.log(Debug.TRACE, str);
+ }
+}
+
diff --git a/xmerge/source/aportisdoc/java/org/openoffice/xmerge/converter/xml/sxw/aportisdoc/DocumentMergerImpl.java b/xmerge/source/aportisdoc/java/org/openoffice/xmerge/converter/xml/sxw/aportisdoc/DocumentMergerImpl.java
new file mode 100644
index 000000000000..8c8b3c9333b3
--- /dev/null
+++ b/xmerge/source/aportisdoc/java/org/openoffice/xmerge/converter/xml/sxw/aportisdoc/DocumentMergerImpl.java
@@ -0,0 +1,97 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxw.aportisdoc;
+
+import org.w3c.dom.Document;
+
+import org.openoffice.xmerge.DocumentMerger;
+import org.openoffice.xmerge.MergeException;
+import org.openoffice.xmerge.ConverterCapabilities;
+import org.openoffice.xmerge.converter.xml.sxw.SxwDocument;
+import org.openoffice.xmerge.merger.DiffAlgorithm;
+import org.openoffice.xmerge.merger.Difference;
+import org.openoffice.xmerge.merger.NodeMergeAlgorithm;
+import org.openoffice.xmerge.merger.Iterator;
+import org.openoffice.xmerge.merger.diff.ParaNodeIterator;
+import org.openoffice.xmerge.merger.diff.IteratorLCSAlgorithm;
+import org.openoffice.xmerge.merger.merge.DocumentMerge;
+import org.openoffice.xmerge.merger.merge.CharacterBaseParagraphMerge;
+import org.openoffice.xmerge.util.Debug;
+
+
+/**
+ * AportisDoc implementation of <code>DocumentMerger</code>
+ * for the {@link
+ * org.openoffice.xmerge.converter.xml.sxw.aportisdoc.PluginFactoryImpl
+ * PluginFactoryImpl}.</p>
+ */
+public class DocumentMergerImpl implements DocumentMerger {
+
+ private ConverterCapabilities cc_;
+ private org.openoffice.xmerge.Document orig = null;
+
+ public DocumentMergerImpl(org.openoffice.xmerge.Document doc, ConverterCapabilities cc) {
+ cc_ = cc;
+ this.orig = doc;
+ }
+
+ public void merge(org.openoffice.xmerge.Document modifiedDoc) throws MergeException {
+
+ SxwDocument wdoc1 = (SxwDocument) orig;
+ SxwDocument wdoc2 = (SxwDocument) modifiedDoc;
+
+ Document doc1 = wdoc1.getContentDOM();
+ Document doc2 = wdoc2.getContentDOM();
+
+ Iterator i1 = new ParaNodeIterator(cc_, doc1.getDocumentElement());
+ Iterator i2 = new ParaNodeIterator(cc_, doc2.getDocumentElement());
+
+ DiffAlgorithm diffAlgo = new IteratorLCSAlgorithm();
+
+ // find out the paragrah level diffs
+ Difference[] diffTable = diffAlgo.computeDiffs(i1, i2);
+
+ if (Debug.isFlagSet(Debug.INFO)) {
+ Debug.log(Debug.INFO, "Diff Result: ");
+
+ for (int i = 0; i < diffTable.length; i++) {
+ Debug.log(Debug.INFO, diffTable[i].debug());
+ }
+ }
+
+ // merge the paragraphs
+ NodeMergeAlgorithm charMerge = new CharacterBaseParagraphMerge();
+ DocumentMerge docMerge = new DocumentMerge(cc_, charMerge);
+
+ Iterator result = null;
+
+ docMerge.applyDifference(i1, i2, diffTable);
+ }
+}
+
+
diff --git a/xmerge/source/aportisdoc/java/org/openoffice/xmerge/converter/xml/sxw/aportisdoc/DocumentSerializerImpl.java b/xmerge/source/aportisdoc/java/org/openoffice/xmerge/converter/xml/sxw/aportisdoc/DocumentSerializerImpl.java
new file mode 100644
index 000000000000..dc1fb4c4a1a3
--- /dev/null
+++ b/xmerge/source/aportisdoc/java/org/openoffice/xmerge/converter/xml/sxw/aportisdoc/DocumentSerializerImpl.java
@@ -0,0 +1,531 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxw.aportisdoc;
+
+import org.w3c.dom.NodeList;
+import org.w3c.dom.Node;
+import org.w3c.dom.NamedNodeMap;
+
+import java.io.IOException;
+import java.net.URLDecoder;
+
+import org.openoffice.xmerge.Document;
+import org.openoffice.xmerge.ConvertData;
+import org.openoffice.xmerge.ConvertException;
+import org.openoffice.xmerge.DocumentSerializer;
+import org.openoffice.xmerge.converter.xml.OfficeConstants;
+import org.openoffice.xmerge.converter.xml.sxw.SxwDocument;
+import org.openoffice.xmerge.converter.xml.sxw.aportisdoc.DocConstants;
+import org.openoffice.xmerge.converter.palm.PalmDB;
+import org.openoffice.xmerge.converter.palm.Record;
+import org.openoffice.xmerge.converter.palm.PalmDocument;
+import org.openoffice.xmerge.util.Debug;
+import org.openoffice.xmerge.util.XmlUtil;
+
+/**
+ * <p>AportisDoc implementation of
+ * org.openoffice.xmerge.DocumentSerializer
+ * for the {@link
+ * org.openoffice.xmerge.converter.xml.sxw.aportisdoc.PluginFactoryImpl
+ * PluginFactoryImpl}.</p>
+ *
+ * <p>The <code>serialize</code> method traverses the DOM
+ * document from the given <code>Document</code> object. It uses a
+ * <code>DocEncoder</code> object for the actual conversion of
+ * contents to the AportisDoc format.</p>
+ *
+ * @author Herbie Ong
+ */
+
+
+public final class DocumentSerializerImpl
+ implements OfficeConstants, DocConstants, DocumentSerializer {
+
+ /** A <code>DocEncoder</code> object for encoding to AportisDoc. */
+ private DocEncoder encoder = null;
+
+ /** SXW <code>Document</code> object that this converter processes. */
+ private SxwDocument sxwDoc = null;
+
+
+ /**
+ * Constructor.
+ *
+ * @param doc A SXW <code>Document</code> to be converted.
+ */
+ public DocumentSerializerImpl(Document doc) {
+ sxwDoc = (SxwDocument) doc;
+ }
+
+
+ /**
+ * <p>Method to convert a <code>Document</code> into a PDB.
+ * It passes back the converted data as a <code>ConvertData</code>
+ * object.</p>
+ *
+ * <p>This method is not thread safe for performance reasons.
+ * This method should not be called from within two threads.
+ * It would be best to call this method only once per object
+ * instance.</p>
+ *
+ * @return The <code>ConvertData</code> object containing the output.
+ *
+ * @throws ConvertException If any conversion error occurs.
+ * @throws IOException If any I/O error occurs.
+ */
+ public ConvertData serialize() throws ConvertException, IOException {
+
+
+ // get the server document name
+
+ String docName = URLDecoder.decode(sxwDoc.getName(), DocConstants.ENCODING);
+
+ // get DOM document
+
+ org.w3c.dom.Document domDoc = sxwDoc.getContentDOM();
+
+ encoder = new DocEncoder();
+
+ // Traverse to the office:body element.
+ // There should only be one.
+
+ NodeList list = domDoc.getElementsByTagName(TAG_OFFICE_BODY);
+ int len = list.getLength();
+
+ if (len > 0) {
+ Node node = list.item(0);
+ traverseBody(node);
+ }
+
+ // create a ConvertData object.
+ //
+ Record records[] = encoder.getRecords();
+ ConvertData cd = new ConvertData();
+
+ PalmDocument palmDoc = new PalmDocument(docName,
+ DocConstants.CREATOR_ID, DocConstants.TYPE_ID,
+ 0, PalmDB.PDB_HEADER_ATTR_BACKUP, records);
+
+ cd.addDocument(palmDoc);
+ return cd;
+ }
+
+
+ /**
+ * This method traverses <i>office:body</i> element.
+ *
+ * @param node <i>office:body</i> <code>Node</code>.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ private void traverseBody(Node node) throws IOException {
+
+ log("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
+ log("<AportisDOC>");
+
+ if (node.hasChildNodes()) {
+
+ NodeList nodeList = node.getChildNodes();
+ int len = nodeList.getLength();
+
+ for (int i = 0; i < len; i++) {
+ Node child = nodeList.item(i);
+
+ if (child.getNodeType() == Node.ELEMENT_NODE) {
+ String nodeName = child.getNodeName();
+
+ if (nodeName.equals(TAG_PARAGRAPH) ||
+ nodeName.equals(TAG_HEADING)) {
+
+ traverseParagraph(child);
+
+ } else if (nodeName.equals(TAG_UNORDERED_LIST)) {
+
+ traverseList(child);
+
+ } else if (nodeName.equals(TAG_ORDERED_LIST)) {
+
+ traverseList(child);
+
+ } else {
+
+ log("<OTHERS " + XmlUtil.getNodeInfo(child) + " />");
+ }
+ }
+ }
+ }
+
+ log("</AportisDOC>");
+ }
+
+
+ /**
+ * This method traverses the <i>text:p</i> and <i>text:h</i>
+ * element <code>Node</code> objects.
+ *
+ * @param node A <i>text:p</i> or <i>text:h</i>
+ * <code>Node</code>.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ private void traverseParagraph(Node node) throws IOException {
+
+ log("<PARA>");
+ traverseParaContents(node);
+ encoder.addText(EOL_CHAR);
+ log("</PARA>");
+ }
+
+
+ /**
+ * This method traverses a paragraph content.
+ * It uses the <code>traverseParaElem</code> method to
+ * traverse into Element <code>Node</code> objects.
+ *
+ * @param node A paragraph or content <code>Node</code>.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ private void traverseParaContents(Node node) throws IOException {
+
+ if (node.hasChildNodes()) {
+
+ NodeList nodeList = node.getChildNodes();
+ int len = nodeList.getLength();
+
+ for (int i = 0; i < len; i++) {
+
+ Node child = nodeList.item(i);
+ short nodeType = child.getNodeType();
+
+ switch (nodeType) {
+
+ case Node.TEXT_NODE:
+ // this is for grabbing text nodes.
+ String s = child.getNodeValue();
+
+ if (s.length() > 0) {
+ encoder.addText(s);
+ }
+
+ log("<TEXT>");
+ log(s);
+ log("</TEXT>");
+
+ break;
+
+ case Node.ELEMENT_NODE:
+
+ traverseParaElem(child);
+ break;
+
+ case Node.ENTITY_REFERENCE_NODE:
+
+ log("<ENTITY_REFERENCE>");
+ traverseParaContents(child);
+ log("<ENTITY_REFERENCE/>");
+ break;
+
+ default:
+ log("<OTHERS " + XmlUtil.getNodeInfo(node) + " />");
+ }
+ }
+ }
+ }
+
+
+ /**
+ * This method traverses an <code>Element</code> <code>Node</code>
+ * within a paragraph.
+ *
+ * @param node <code>Element</code> <code>Node</code> within a
+ * paragraph.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ private void traverseParaElem(Node node) throws IOException {
+
+ String nodeName = node.getNodeName();
+
+ if (nodeName.equals(TAG_SPACE)) {
+
+ // this is for text:s tags.
+ NamedNodeMap map = node.getAttributes();
+ Node attr = map.getNamedItem(ATTRIBUTE_SPACE_COUNT);
+ StringBuffer space = new StringBuffer(SPACE_CHAR);
+ int count = 1;
+
+ if (attr != null) {
+
+ try {
+
+ String countStr = attr.getNodeValue();
+ count = Integer.parseInt(countStr.trim());
+
+ } catch (NumberFormatException e) {
+
+ // TODO: for now, throw IOException.
+ // later, perhaps will have to throw
+ // some other conversion exception instead.
+ throw new IOException(e.getMessage());
+ }
+ }
+
+ for (int j = 0; j < count; j++) {
+
+ space.append(SPACE_CHAR);
+ }
+
+ encoder.addText(space.toString());
+
+ log("<SPACE count=\"" + count + "\" />");
+
+ } else if (nodeName.equals(TAG_TAB_STOP)) {
+
+ // this is for text:tab-stop
+ encoder.addText(TAB_CHAR);
+
+ log("<TAB/>");
+
+ } else if (nodeName.equals(TAG_LINE_BREAK)) {
+
+ // commented out by Csaba: There is no point to convert a linebreak
+ // into a EOL, because it messes up the number of XML nodes and the
+ // merge won't work properly. Other solution would be to implement such
+ // nodemerger, which would be able to merge embedded tags in a paragraph
+
+ // this is for text:line-break
+ // encoder.addText(EOL_CHAR);
+
+ log("skipped <LINE-BREAK/>");
+
+ } else if (nodeName.equals(TAG_SPAN)) {
+
+ // this is for text:span
+ log("<SPAN>");
+ traverseParaContents(node);
+ log("</SPAN>");
+
+ } else if (nodeName.equals(TAG_HYPERLINK)) {
+
+ // this is for text:a
+ log("<HYPERLINK>");
+ traverseParaContents(node);
+ log("<HYPERLINK/>");
+
+ } else if (nodeName.equals(TAG_BOOKMARK) ||
+ nodeName.equals(TAG_BOOKMARK_START)) {
+
+ log("<BOOKMARK/>");
+
+ } else if (nodeName.equals(TAG_TEXT_VARIABLE_SET)
+ || nodeName.equals(TAG_TEXT_VARIABLE_GET)
+ || nodeName.equals(TAG_TEXT_EXPRESSION)
+ || nodeName.equals(TAG_TEXT_USER_FIELD_GET)
+ || nodeName.equals(TAG_TEXT_PAGE_VARIABLE_GET)
+ || nodeName.equals(TAG_TEXT_SEQUENCE)
+ || nodeName.equals( TAG_TEXT_VARIABLE_INPUT)
+ || nodeName.equals(TAG_TEXT_TIME)
+ || nodeName.equals( TAG_TEXT_PAGE_COUNT)
+ || nodeName.equals(TAG_TEXT_PAGE_NUMBER )
+ || nodeName.equals(TAG_TEXT_SUBJECT)
+ || nodeName.equals(TAG_TEXT_TITLE)
+ || nodeName.equals(TAG_TEXT_CREATION_TIME)
+ || nodeName.equals(TAG_TEXT_DATE)
+ || nodeName.equals(TAG_TEXT_TEXT_INPUT)
+ || nodeName.equals(TAG_TEXT_AUTHOR_INITIALS)) {
+ log("<FIELD>");
+ traverseParaContents(node);
+ log("</FIELD>");
+
+ }else if (nodeName.startsWith(TAG_TEXT)) {
+ log("<Unknown text Field>");
+ traverseParaContents(node);
+ log("</Unknown text Field>");
+
+ }else {
+
+ log("<OTHERS " + XmlUtil.getNodeInfo(node) + " />");
+ }
+ }
+
+
+ /**
+ * This method traverses list tags <i>text:unordered-list</i> and
+ * <i>text:ordered-list</i>. A list can only contain one optional
+ * <i>text:list-header</i> and one or more <i>text:list-item</i>
+ * elements.
+ *
+ * @param node A list <code>Node</code>.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ private void traverseList(Node node) throws IOException {
+
+ log("<LIST>");
+
+ if (node.hasChildNodes()) {
+
+ NodeList nodeList = node.getChildNodes();
+ int len = nodeList.getLength();
+
+ for (int i = 0; i < len; i++) {
+
+ Node child = nodeList.item(i);
+
+ if (child.getNodeType() == Node.ELEMENT_NODE) {
+
+ String nodeName = child.getNodeName();
+
+ if (nodeName.equals(TAG_LIST_ITEM)) {
+
+ traverseListItem(child);
+
+ } else if (nodeName.equals(TAG_LIST_HEADER)) {
+
+ traverseListHeader(child);
+
+ } else {
+
+ log("<INVALID-XML-BUG " + XmlUtil.getNodeInfo(child) + " />");
+ }
+ }
+ }
+ }
+
+ log("</LIST>");
+ }
+
+
+ /**
+ * This method traverses a <i>text:list-header</i> element.
+ * It contains one or more <i>text:p</i> elements.
+ *
+ * @param node A list header <code>Node</code>.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ private void traverseListHeader(Node node) throws IOException {
+
+ log("<LIST-HEADER>");
+
+ if (node.hasChildNodes()) {
+
+ NodeList nodeList = node.getChildNodes();
+ int len = nodeList.getLength();
+
+ for (int i = 0; i < len; i++) {
+
+ Node child = nodeList.item(i);
+
+ if (child.getNodeType() == Node.ELEMENT_NODE) {
+
+ String nodeName = child.getNodeName();
+
+ if (nodeName.equals(TAG_PARAGRAPH)) {
+
+ traverseParagraph(child);
+
+ } else {
+
+ log("<INVALID-XML-BUG " + XmlUtil.getNodeInfo(child) + " />");
+ }
+ }
+ }
+ }
+
+ log("</LIST-HEADER>");
+ }
+
+
+ /**
+ * <p>This method will traverse a <i>text:list-item</i>.
+ * A list item may contain one or more of <i>text:p</i>,
+ * <i>text:h</i>, <i>text:section</i>, <i>text:ordered-list</i>
+ * and <i>text:unordered-list</i>.</p>
+ *
+ * <p>This method currently only implements grabbing <i>text:p</i>,
+ * <i>text:h</i>, <i>text:unordered-list</i> and
+ * <i>text:ordered-list</i>.</p>
+ *
+ * @param node The <code>Node</code>.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ private void traverseListItem(Node node) throws IOException {
+
+ log("<LIST-ITEM>");
+
+ if (node.hasChildNodes()) {
+
+ NodeList nodeList = node.getChildNodes();
+ int len = nodeList.getLength();
+
+ for (int i = 0; i < len; i++) {
+
+ Node child = nodeList.item(i);
+
+ if (child.getNodeType() == Node.ELEMENT_NODE) {
+
+ String nodeName = child.getNodeName();
+
+ if (nodeName.equals(TAG_PARAGRAPH)) {
+
+ traverseParagraph(child);
+
+ } else if (nodeName.equals(TAG_UNORDERED_LIST)) {
+
+ traverseList(child);
+
+ } else if (nodeName.equals(TAG_ORDERED_LIST)) {
+
+ traverseList(child);
+
+ } else {
+
+ log("<INVALID-XML-BUG " + XmlUtil.getNodeInfo(child) + " />");
+ }
+ }
+ }
+ }
+
+ log("</LIST-ITEM>");
+ }
+
+
+ /**
+ * Logs debug messages.
+ *
+ * @param str The debug message.
+ */
+ private void log(String str) {
+
+ Debug.log(Debug.TRACE, str);
+ }
+}
+
diff --git a/xmerge/source/aportisdoc/java/org/openoffice/xmerge/converter/xml/sxw/aportisdoc/PluginFactoryImpl.java b/xmerge/source/aportisdoc/java/org/openoffice/xmerge/converter/xml/sxw/aportisdoc/PluginFactoryImpl.java
new file mode 100644
index 000000000000..3a497cc0b5b7
--- /dev/null
+++ b/xmerge/source/aportisdoc/java/org/openoffice/xmerge/converter/xml/sxw/aportisdoc/PluginFactoryImpl.java
@@ -0,0 +1,141 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxw.aportisdoc;
+
+import org.openoffice.xmerge.Document;
+import org.openoffice.xmerge.ConvertData;
+import org.openoffice.xmerge.DocumentMerger;
+import org.openoffice.xmerge.DocumentMergerFactory;
+import org.openoffice.xmerge.DocumentSerializer;
+import org.openoffice.xmerge.DocumentSerializerFactory;
+import org.openoffice.xmerge.DocumentDeserializer;
+import org.openoffice.xmerge.DocumentDeserializerFactory;
+import org.openoffice.xmerge.ConverterCapabilities;
+import org.openoffice.xmerge.converter.xml.sxw.SxwPluginFactory;
+import org.openoffice.xmerge.converter.palm.PalmDocument;
+import org.openoffice.xmerge.util.registry.ConverterInfo;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * <p>AportisDoc implementation of the <code>PluginFactory</code>.
+ * This encapsulates conversion of StarWriter XML format to and from
+ * AportisDoc format.</p>
+ *
+ * <p>The superclass produces a particular
+ * {@link org.openoffice.xmerge.Document Document}
+ * object, i.e. {@link
+ * org.openoffice.xmerge.converter.xml.sxw.SxwDocument
+ * SxwDocument} that the converters in this class works with. Thus,
+ * this class only implements the methods that produces the converters,
+ * i.e. {@link
+ * org.openoffice.xmerge.DocumentSerializer
+ * DocumentSerializer} and {@link
+ * org.openoffice.xmerge.DocumentDeserializer
+ * DocumentDeserializer};
+ * as well as the {@link
+ * org.openoffice.xmerge.ConverterCapabilities
+ * ConverterCapabilities} object that is specific to this format
+ * conversion. That superclass also produces a {@link
+ * org.openoffice.xmerge.DocumentMerger DocumentMerger}
+ * object, i.e. {@link
+ * org.openoffice.xmerge.converter.xml.sxw.aportisdoc.DocumentMergerImpl
+ * DocumentMergerImpl} which this class derives the functionality.</p>
+ *
+ * @author Herbie Ong
+ */
+public final class PluginFactoryImpl extends SxwPluginFactory
+ implements DocumentDeserializerFactory, DocumentSerializerFactory,
+ DocumentMergerFactory {
+
+ public PluginFactoryImpl (ConverterInfo ci) {
+ super(ci);
+ }
+
+ /** ConverterCapabilities object for this type of conversion. */
+ private final static ConverterCapabilities converterCap =
+ new ConverterCapabilitiesImpl();
+
+
+ /**
+ * Returns an instance of <code>DocumentSerializerImpl</code>,
+ * which is an implementation of the <code>DocumentSerializer</code>
+ * interface.
+ *
+ * @param doc <code>Document</code> object to be
+ * converted/serialized.
+ *
+ * @return A <code>DocumentSerializerImpl</code> object.
+ */
+ public DocumentSerializer createDocumentSerializer(Document doc) {
+
+ return new DocumentSerializerImpl(doc);
+ }
+
+
+ /**
+ * Returns an instance of <code>DocumentDeserializerImpl</code>,
+ * which is an implementation of the <code>DocumentDeserializer</code>
+ * interface.
+ *
+ * @param cd <code>ConvertData</code> object for reading data
+ * which will be converted back to a
+ * <code>Document</code> object.
+ *
+ * @return A DocumentDeserializerImpl object.
+ */
+ public DocumentDeserializer createDocumentDeserializer(ConvertData cd) {
+
+ return new DocumentDeserializerImpl(cd);
+ }
+
+
+ /**
+ * Returns an instance of <code>DocumentMergerImpl</code>,
+ * which is an implementation of the <code>DocumentMerger</code>
+ * interface.
+ *
+ * @param doc <code>Document</code> to merge.
+ *
+ * @return A DocumentMergerImpl object.
+ */
+ public DocumentMerger createDocumentMerger(Document doc) {
+
+ ConverterCapabilities cc = converterCap;
+ DocumentMergerImpl merger = new DocumentMergerImpl(doc, cc);
+ return merger;
+ }
+
+ public Document createDeviceDocument(String name, InputStream is)
+ throws IOException {
+
+ PalmDocument palmDoc = new PalmDocument(is);
+ return palmDoc;
+ }
+}
+
diff --git a/xmerge/source/aportisdoc/java/org/openoffice/xmerge/converter/xml/sxw/aportisdoc/package.html b/xmerge/source/aportisdoc/java/org/openoffice/xmerge/converter/xml/sxw/aportisdoc/package.html
new file mode 100644
index 000000000000..ce4c4a28ae9f
--- /dev/null
+++ b/xmerge/source/aportisdoc/java/org/openoffice/xmerge/converter/xml/sxw/aportisdoc/package.html
@@ -0,0 +1,239 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<!--
+ #*************************************************************************
+ #
+ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+
+ Copyright 2000, 2010 Oracle and/or its affiliates.
+
+ OpenOffice.org - a multi-platform office productivity suite
+
+ This file is part of OpenOffice.org.
+
+ OpenOffice.org is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License version 3
+ only, as published by the Free Software Foundation.
+
+ OpenOffice.org is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License version 3 for more details
+ (a copy is included in the LICENSE file that accompanied this code).
+
+ You should have received a copy of the GNU Lesser General Public License
+ version 3 along with OpenOffice.org. If not, see
+ <http://www.openoffice.org/license.html>
+ for a copy of the LGPLv3 License.
+
+ #*************************************************************************
+ -->
+<html>
+<head>
+<title>org.openoffice.xmerge.converter.xml.sxw.aportisdoc package</title>
+</head>
+
+<body bgcolor="white">
+
+<p>Provides the tools for doing the conversion of StarWriter XML to
+and from AportisDoc format.</p>
+
+<p>It follows the {@link org.openoffice.xmerge} framework for the conversion process.</p>
+
+<p>Since it converts to/from a Palm application format, these converters
+follow the <a href=../../../../converter/palm/package-summary.html#streamformat>
+<code>PalmDB</code> stream format</a> for writing out to the Palm sync client or
+reading in from the Palm sync client.</p>
+
+<p>Note that <code>PluginFactoryImpl</code> also provides a
+<code>DocumentMerger</code> object, i.e. {@link org.openoffice.xmerge.converter.xml.sxw.aportisdoc.DocumentMergerImpl DocumentMergerImpl}.
+This functionality was derived from its superclass
+{@link org.openoffice.xmerge.converter.xml.sxw.SxwPluginFactory
+SxwPluginFactory}.</p>
+
+<h2>AportisDoc pdb format - Doc</h2>
+
+<p>The AportisDoc pdb format is widely used by different Palm applications,
+e.g. QuickWord, AportisDoc Reader, MiniWrite, etc. Note that some
+of these applications put tweaks into the format. The converters will only
+support the default AportisDoc format, plus some very minor tweaks to accommodate
+other applications.</p>
+
+<p>The text content of the format is plain text, i.e. there are no styles
+or structures. There is no notion of lists, list items, paragraphs,
+headings, etc. The format does have support for bookmarks.</p>
+
+<p>For most Doc applications, the default character encoding supported is
+the extended ASCII character set, i.e. ISO-8859-1. StarWriter XML is in
+UTF-8 encoding scheme. Since UTF-8 encoding scheme covers more characters,
+converting UTF-8 strings into extended ASCII would mean that there can be
+possible loss of character mappings.</p>
+
+<p>Using JAXP, XML files can be parsed and read in as Java <code>String</code>s
+which is in Unicode format, there is no loss of character mapping from UTF-8
+to Java Strings. There is possible loss of character mapping in
+converting Java <code>String</code>s to ASCII bytes. Java characters that
+cannot be represented in extended ASCII are converted into the ASCII
+character '?' or x3F in hex digit via the <code>String.getBytes(encoding)</code>
+API.</p>
+
+<h2>SXW to DOC Conversion</h2>
+
+<p>The <code>DocumentSerializerImpl</code> class implements the
+<code>org.openoffice.xmerge.DocumentSerializer</code>.
+This class specifically provides the conversion process from a given
+<code>SxwDocument</code> object to DOC formatted records, which are
+then passed back to the client via the <code>ConvertData</code> object.</p>
+
+<p>The following XML tags are handled. [Note that some may not be implemented yet.]</p>
+<ul>
+<li>
+ <p>Paragraphs <tt>&lt;text:p&gt;</tt> and Headings <tt>&lt;text:h&gt;</tt></p>
+
+ <p>Heading elements are classified the same as paragraph
+ elements since both have the same possible elements inside.
+ Their main difference is that they refer to different types
+ of style information, which is outside of their element tags.
+ Since there are no styles on the DOC format, headings should
+ be treated the same way a paragraph is converted.</p>
+
+ <p>For paragraph elements, convert and transfer text nodes
+ that are essential. Text nodes directly contained within paragraph
+ nodes are such. There are also a number of elements that
+ a paragraph element may contain. These are explained in their
+ own context.</p>
+
+ <p>At the end of the paragraph, an EOL character is added by
+ the converter to provide a separation for each paragraph,
+ since the Doc format does not have a notion of a paragraph.</p>
+</li>
+<li>
+ <p>White spaces <tt>&lt;text:s&gt;</tt> and Tabs <tt>&lt;text:tab-stop&gt;</tt></p>
+
+ <p>In SXW, normally 2 or more white-space characters are collapsed into
+ a single space character. In order to make sure that the document
+ content really contains those white-space characters, there are special
+ elements assigned to them.</p>
+
+ <p>The space element specifies the number of spaces are in it.
+ Thus, converting it just means providing the specific number of spaces
+ that the element requires.</p>
+
+ <p>There is also the tab-stop element. This is a bit tricky. In a
+ StarWriter document, tab-stops are specified by a column position.
+ A tab is not an exact number of space, but rather a specific column
+ positioning. Say, regular tab-stops are set at every 5th column.
+ At column 4, if I hit a tab, it goes to column 5. At column 1, hitting
+ a tab would put the cursor at column 5 as well. SmartDoc and AporticDoc
+ applications goes by columns for the ASCII tab character. The only problem
+ is that in StarWriter, one could specify a different tab-stop, but not
+ in most of these Doc applications, at least I have not seen one.
+ Solution for this is just to go with the converting to the ASCII tab
+ character and not do anything for different tab-stop positioning.</p>
+</li>
+<li>
+ <p>Line breaks <tt>&lt;text:line-break&gt;</tt></p>
+
+ <p>To represent line breaks, it is simpliest to just put an ASCII LF
+ character. Note that the side effect of this is that an end of paragraph
+ also contains an ASCII LF character. Thus, for the DOC to SXW conversion,
+ line breaks are not distinguishable from specifying the end of a
+ paragraph.</p>
+</li>
+<li>
+ <p>Text spans <tt>&lt;text:span&gt;</tt></p>
+
+ <p>Text spans contain text that have different style attributes
+ from the paragraphs'. Text spans can be embedded within another
+ text span. Since it is purely for style tagging, we only needed
+ to convert and transfer the text elements within these.</p>
+</li>
+<li>
+ <p>Hyperlinks <tt>&lt;text:a&gt;</tt>
+
+ <p>Convert and transfer the text portion.</p>
+</li>
+<li>
+ <p>Bookmarks <tt>&lt;text:bookmark&gt;</tt> <tt>&lt;text:bookmark-start&gt;</tt>
+ <tt>&lt;text:bookmark-end&gt;</tt> [Not implemented yet]</p>
+
+ <p>In SXW, bookmark elements are embedded inside paragraph elements.
+ Bookmarks can either mark a text position or a text range. <tt>&lt;text:bookmark&gt;</tt>
+ marks a position while the pair <tt>&lt;text:bookmark-start&gt;</tt> and
+ <tt>&lt;text:bookmark-end&gt;</tt></p> marks a text range. The DOC format only
+ supports bookmarking a text position. Thus, for the conversion,
+ <tt>&lt;text:bookmark&gt;</tt> and <tt>&lt;text:bookmark-start&gt;</tt> will both mark
+ a text position.</p>
+</li>
+<li>
+ <p>Change Tracking <tt>&lt;text:tracked-changes&gt;</tt>
+ <tt>&lt;text:change*&gt;</tt> [Not implemented yet]</p>
+
+ <p>Change tracking elements are not supported yet on the current
+ OpenOffice XML filters, will have to watch out on this. The text
+ within these elements have to be interpreted properly during the
+ conversion process.</p>
+</li>
+<li>
+ <p>Lists <tt>&lt;text:unordered-list&gt;</tt> and
+ <tt>&lt;text:ordered-lists&gt;</tt></p>
+
+ <p>A list can only contain one optional <tt>&lt;text:list-header&gt;</tt>
+ and one or more <tt>&lt;text:list-item&gt;</tt> elements.</p>
+
+ <p>A <tt>&lt;text:list-header&gt;</tt> contains one or more paragraph
+ elements. Since there are no styles, the conversion process does not
+ do anything special for list headers, conversion for the paragraphs
+ within list headers are the same as explained above.</p>
+
+ <p>A <tt>&lt;text:list-item&gt;</tt> may contain one or more of paragraphs,
+ headings, list, etc. Since the Doc format does not support any list
+ structure, there will not be any special handling for this element.
+ Conversion for elements within it shall be applied according to the
+ element type. Thus, lists with paragraphs within it will result in just
+ plain paragraphs. Sublists will not be identifiable. Paragraphs in
+ sublists will still appear.</p>
+</li>
+<li>
+ <p><tt>&lt;text:section&gt;</tt></p>
+
+ <p>I am not sure what this is yet, will need to investigate more on this.</p>
+</li>
+</ul>
+<p>There may be other tags that will still need to be addressed for this conversion.</p>
+
+<p>Refer to {@link org.openoffice.xmerge.converter.xml.sxw.aportisdoc.DocumentSerializerImpl DocumentSerializerImpl}
+for details of implementation. It uses <code>DocEncoder</code> class to do the encoding
+part.</p>
+
+<h2>DOC to SXW Conversion</h2>
+
+<p>The <code>DocumentDeserializerImpl</code> class implements the
+<code>org.openoffice.xmerge.DocumentDeserializer</code>. It is
+passed the device document in the form of a <code>ConvertData</code> object.
+It will then create a <code>SxwDocument</code> object from the conversion of
+the DOC formatted records.</p>
+
+<p>The text content of the Doc format will be transferred as text. Paragraph
+elements will be formed based on the existence of an ASCII LF character. There
+will be at least one paragraph element.</p>
+
+<p>Bookmarks in the Doc format will be converted to the bookmark element
+<tt>&lt;text:bookmark&gt;</tt> [Not implemented yet].</p>
+
+
+<h2>Merging changes</h2>
+
+<p>As mentioned above, the <code>DocumentMerger</code> object produced by
+<code>PluginFactoryImpl</code> is <code>DocumentMergerImpl</code>.
+Refer to the javadocs for that package/class on its merging specifications.
+</p>
+
+<h2>TODO list</h2>
+
+<p><ol>
+<li>Investigate Palm's with different character encodings.</li>
+<li>Investigate other StarWriter XML tags</li>
+</ol></p>
+
+</body>
+</html>
diff --git a/xmerge/source/aportisdoc/makefile.mk b/xmerge/source/aportisdoc/makefile.mk
new file mode 100644
index 000000000000..dad48f952b51
--- /dev/null
+++ b/xmerge/source/aportisdoc/makefile.mk
@@ -0,0 +1,35 @@
+#*************************************************************************
+#
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# Copyright 2000, 2010 Oracle and/or its affiliates.
+#
+# OpenOffice.org - a multi-platform office productivity suite
+#
+# This file is part of OpenOffice.org.
+#
+# OpenOffice.org is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License version 3
+# only, as published by the Free Software Foundation.
+#
+# OpenOffice.org is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License version 3 for more details
+# (a copy is included in the LICENSE file that accompanied this code).
+#
+# You should have received a copy of the GNU Lesser General Public License
+# version 3 along with OpenOffice.org. If not, see
+# <http://www.openoffice.org/license.html>
+# for a copy of the LGPLv3 License.
+#
+#*************************************************************************
+
+TARGET=aportisdoc
+PRJ=../..
+PRJNAME=xmerge
+
+.INCLUDE : ant.mk
+.IF "$(L10N_framework)"==""
+ALLTAR: ANTBUILD
+.ENDIF
diff --git a/xmerge/source/bridge/XMergeBridge.component b/xmerge/source/bridge/XMergeBridge.component
new file mode 100644
index 000000000000..c48aae6a0e20
--- /dev/null
+++ b/xmerge/source/bridge/XMergeBridge.component
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--**********************************************************************
+*
+* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+*
+* Copyright 2000, 2010 Oracle and/or its affiliates.
+*
+* OpenOffice.org - a multi-platform office productivity suite
+*
+* This file is part of OpenOffice.org.
+*
+* OpenOffice.org is free software: you can redistribute it and/or modify
+* it under the terms of the GNU Lesser General Public License version 3
+* only, as published by the Free Software Foundation.
+*
+* OpenOffice.org is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU Lesser General Public License version 3 for more details
+* (a copy is included in the LICENSE file that accompanied this code).
+*
+* You should have received a copy of the GNU Lesser General Public License
+* version 3 along with OpenOffice.org. If not, see
+* <http://www.openoffice.org/license.html>
+* for a copy of the LGPLv3 License.
+*
+**********************************************************************-->
+
+<component loader="com.sun.star.loader.Java2"
+ xmlns="http://openoffice.org/2010/uno-components">
+ <implementation name="XMergeBridge$_XMergeBridge">
+ <service name="com.sun.star.documentconversion.XMergeBridge"/>
+ </implementation>
+</component>
diff --git a/xmerge/source/bridge/antcall.txt b/xmerge/source/bridge/antcall.txt
new file mode 100644
index 000000000000..96abc7b24821
--- /dev/null
+++ b/xmerge/source/bridge/antcall.txt
@@ -0,0 +1,19 @@
+r:\btools\apache-ant-1.6.1\bin\ant
+-Dprj=../..
+-Dprjname=
+-Ddebug=off
+-Doptimize=on
+-Dtarget=xmrg_bridge
+-Dsolar.update=on
+-Dout=../..\wntmsci10.pro
+-Dinpath=wntmsci10.pro
+-Dproext=".pro"
+-Dsolar.bin=Y:\so-cwsserv03\lo8\SRC680\wntmsci10.pro\bin.m105
+-Dsolar.jar=Y:\so-cwsserv03\lo8\SRC680\wntmsci10.pro\bin.m105
+-Dsolar.doc=Y:\so-cwsserv03\lo8\SRC680\wntmsci10.pro\doc.m105
+-Dcommon.jar=Y:\so-cwsserv03\lo8\SRC680\common.pro\bin.m105
+-Dcommon.doc=Y:\so-cwsserv03\lo8\SRC680\common.pro\doc.m105
+-f build.xml
+-emacs
+
+Buildfile: build.xml
diff --git a/xmerge/source/bridge/build.xml b/xmerge/source/bridge/build.xml
new file mode 100644
index 000000000000..ad0aa33d0f0f
--- /dev/null
+++ b/xmerge/source/bridge/build.xml
@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ #*************************************************************************
+ #
+ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+
+ Copyright 2000, 2010 Oracle and/or its affiliates.
+
+ OpenOffice.org - a multi-platform office productivity suite
+
+ This file is part of OpenOffice.org.
+
+ OpenOffice.org is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License version 3
+ only, as published by the Free Software Foundation.
+
+ OpenOffice.org is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License version 3 for more details
+ (a copy is included in the LICENSE file that accompanied this code).
+
+ You should have received a copy of the GNU Lesser General Public License
+ version 3 along with OpenOffice.org. If not, see
+ <http://www.openoffice.org/license.html>
+ for a copy of the LGPLv3 License.
+
+ #*************************************************************************
+ -->
+
+<project name="XMergeBridge" default="all" basedir=".">
+
+ <property file="../inc/antbuild.properties"/>
+
+ <path id="classpath">
+ <pathelement location="${build.dir}/xmerge.jar"/>
+ <pathelement location="${solar.jar}/unoil.jar"/>
+ <pathelement location="${solar.jar}/ridl.jar"/>
+ <pathelement location="${solar.jar}/jurt.jar"/>
+ <pathelement location="${solar.jar}/juh.jar"/>
+ </path>
+
+
+ <target name="init" >
+ <mkdir dir="${target.dir}"/>
+ <echo message="--------------------------------------------------------------------------------" />
+ <echo message="debug is ${debug}"/>
+ <echo message="--------------------------------------------------------------------------------" />
+ </target>
+
+ <!-- compile java sources in ${package} -->
+ <target name="compile" depends="init">
+ <javac srcdir="${src.dir}"
+ destdir="${target.dir}"
+ debug="${debug}"
+ deprecation="${deprecation}"
+ optimize="${optimize}">
+ <classpath refid="classpath"/>
+ </javac>
+ </target>
+
+ <!-- package to jar -->
+ <target name="jar" depends="compile">
+ <jar destfile="${target.jar}"
+ manifest="manifest.mf">
+ <fileset dir="${target.dir}"
+ includes="**/*.class" />
+ </jar>
+ </target>
+
+ <!-- clean up -->
+ <target name="clean">
+ <delete dir="${class.dir}"/>
+ <delete file="${target.jar}"/>
+ </target>
+
+ <target name="all" depends="jar">
+ </target>
+
+</project>
+
diff --git a/xmerge/source/bridge/java/XMergeBridge.java b/xmerge/source/bridge/java/XMergeBridge.java
new file mode 100644
index 000000000000..c2dafd75c996
--- /dev/null
+++ b/xmerge/source/bridge/java/XMergeBridge.java
@@ -0,0 +1,697 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+/** You can find more
+ * information on the following web page:
+ * http://api.openoffice.org/common/ref/com/sun/star/index.html
+ */
+
+
+/*Java Uno Helper Classes*/
+import com.sun.star.lib.uno.adapter.XInputStreamToInputStreamAdapter;
+import com.sun.star.lib.uno.adapter.XOutputStreamToOutputStreamAdapter;
+
+/*StarOffice/Uno Classes*/
+import com.sun.star.lang.XMultiServiceFactory;
+import com.sun.star.lang.XServiceInfo;
+import com.sun.star.lang.XTypeProvider;
+import com.sun.star.uno.Type;
+import com.sun.star.uno.UnoRuntime;
+import com.sun.star.comp.loader.FactoryHelper;
+import com.sun.star.lang.XServiceName;
+import com.sun.star.lang.XSingleServiceFactory;
+import com.sun.star.registry.XRegistryKey;
+import com.sun.star.frame.XConfigManager;
+import com.sun.star.xml.sax.InputSource;
+import com.sun.star.xml.sax.XParser;
+import com.sun.star.io.XInputStream;
+import com.sun.star.io.XOutputStream;
+import com.sun.star.xml.sax.XDocumentHandler;
+import com.sun.star.uno.AnyConverter;
+
+/* Generated from Idls */
+import com.sun.star.xml.XImportFilter;
+import com.sun.star.xml.XExportFilter;
+
+/* XMerge Classes */
+import org.openoffice.xmerge.util.registry.ConverterInfoReader;
+import org.openoffice.xmerge.util.registry.ConverterInfo;
+import org.openoffice.xmerge.util.registry.ConverterInfoMgr;
+import org.openoffice.xmerge.Convert;
+import org.openoffice.xmerge.ConverterFactory;
+import org.openoffice.xmerge.Document;
+import org.openoffice.xmerge.ConvertData;
+import org.openoffice.xmerge.converter.xml.OfficeDocument;
+/*Java Classes*/
+import java.util.Enumeration;
+import java.io.*;
+import javax.xml.parsers.*;
+import java.net.URI;
+
+
+/** 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 XDocumentHandler exportDocHandler=null;
+ private static XInputStream xInStream =null;
+ private static XOutputStream xOutStream=null;
+ private static String udJarPath=null;
+ private static XOutputStream xos = null;
+ private static XOutputStreamToOutputStreamAdapter adaptedStream=null;
+ private static String offMime=null;
+ private static String sdMime=null;
+ private static String sFileName=null;
+ private static String sURL="";
+
+ //private static FileOutputStream adaptedStream =null;
+
+ /** This inner class provides the component as a concrete implementation
+ * of the service description. It implements the needed interfaces.
+ * @implements XTypeProvider
+ */
+ static public class _XMergeBridge implements
+ XImportFilter,
+ XExportFilter,
+ XServiceName,
+ XServiceInfo,
+ XDocumentHandler,
+ XTypeProvider {
+
+ /** The component will be registered under this name.
+ */
+ static private 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 );
+ }
+
+ String getFileName(String origName)
+ {
+ String name=null;
+ 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,
+ java.lang.String[] msUserData) throws com.sun.star.uno.RuntimeException {
+ /*
+ System.out.println("\nFound the Importer!\n");
+
+ System.out.println("\n"+msUserData[0]);
+ System.out.println("\n"+msUserData[1]);
+ System.out.println("\n"+msUserData[2]);
+ System.out.println("\n"+msUserData[3]);
+ System.out.println("\n"+msUserData[4]);
+ System.out.println("\n"+msUserData[5]);
+ */
+ sFileName="";
+ sURL="";
+ String sDirectory = null;
+ String udConvertClass=msUserData[0];
+ udJarPath=msUserData[1];
+ String udImport =msUserData[2];
+ String udExport =msUserData[3];
+ 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++)
+ {
+
+ //System.out.println("\n"+pValue[i].Name+" "+pValue[i].Value;
+
+ try{
+ //System.out.println("\n"+pValue[i].Name+" "+pValue[i].Value);
+ if (pValue[i].Name.compareTo("InputStream")==0){
+ xis=(com.sun.star.io.XInputStream)AnyConverter.toObject(new Type(com.sun.star.io.XInputStream.class), pValue[i].Value);
+ }
+ if (pValue[i].Name.compareTo("FileName")==0){
+ sFileName=(String)AnyConverter.toObject(new Type(java.lang.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 = (XConfigManager) 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 = (XInputStream) UnoRuntime.queryInterface(
+ XInputStream.class , xPipeObj );
+ xOutStream = (XOutputStream) 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 = (XParser) UnoRuntime.queryInterface(
+ XParser.class , xSaxParserObj );
+ if (xParser==null){
+ System.out.println("\nParser creation Failed");
+ }
+ 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){
+ //System.out.println("XMergeBridge IO Exception "+e.getMessage());
+ return false;
+ }
+ catch (Exception e){
+ //System.out.println("XMergeBridge Exception "+e+" "+e.getMessage());
+ return false;
+ }
+ return true;
+ }
+
+ public boolean exporter(com.sun.star.beans.PropertyValue[] aSourceData,
+ java.lang.String[] msUserData) throws com.sun.star.uno.RuntimeException{
+
+ /*
+ System.out.println("\nFound the Exporter!\n");
+
+ System.out.println("\n"+msUserData[0]);
+ System.out.println("\n"+msUserData[1]);
+ System.out.println("\n"+msUserData[2]);
+ System.out.println("\n"+msUserData[3]);
+ System.out.println("\n"+msUserData[4]);
+ System.out.println("\n"+msUserData[5]);
+ */
+ sFileName=null;
+ sURL=null;
+ String sDirectory = null;
+ String title=null;
+ String udConvertClass=msUserData[0];
+ udJarPath=msUserData[1];
+ String udImport =msUserData[2];
+ String udExport =msUserData[3];
+ offMime =msUserData[4];
+ sdMime = msUserData[5];
+
+ com.sun.star.beans.PropertyValue[] pValue = aSourceData;
+ for (int i = 0 ; i < pValue.length; i++)
+ {
+
+ //System.out.println("\n"+pValue[i].Name+" "+pValue[i].Value);
+
+
+ try{
+ //System.out.println("\n"+pValue[i].Name+" "+pValue[i].Value);
+ if (pValue[i].Name.compareTo("OutputStream")==0){
+ xos=(com.sun.star.io.XOutputStream)AnyConverter.toObject(new Type(com.sun.star.io.XOutputStream.class), pValue[i].Value);
+ // System.out.println(pValue[i].Name+" "+xos);
+ }
+ if (pValue[i].Name.compareTo("FileName")==0){
+ sFileName=(String)AnyConverter.toObject(new Type(java.lang.String.class), pValue[i].Value);
+ //System.out.println(pValue[i].Name+" "+sFileName);
+ }
+ if (pValue[i].Name.compareTo("URL")==0){
+ sURL=(String)AnyConverter.toObject(new Type(java.lang.String.class), pValue[i].Value);
+ // System.out.println("\nMediaDescriptor url "+pValue[i].Name+" "+sURL);
+
+ }
+ if (pValue[i].Name.compareTo("Title")==0){
+
+ title=(String)AnyConverter.toObject(new Type(java.lang.String.class), pValue[i].Value);
+ //System.out.println(pValue[i].Name+" "+title);
+ }
+ }
+ 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 = (XConfigManager) 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 = (XInputStream) UnoRuntime.queryInterface(
+ XInputStream.class , xPipeObj );
+ xOutStream = (XOutputStream) UnoRuntime.queryInterface(
+ XOutputStream.class , xPipeObj );
+ }
+ catch (Exception e){
+ System.out.println("Exception "+e);
+ return false;
+ }
+
+ return true;
+ }
+
+ public String replace(String origString, String origChar, String replaceChar){
+ String tmp="";
+ int index=origString.indexOf(origChar);
+ if(index !=-1){
+ while (index !=-1){
+ String first =origString.substring(0,index);
+ first=first.concat(replaceChar);
+ tmp=tmp.concat(first);
+ origString=origString.substring(index+1,origString.length());
+ index=origString.indexOf(origChar);
+ if(index==-1) {
+ tmp=tmp.concat(origString);
+ }
+
+ }
+
+ }
+ return tmp;
+ }
+
+ public String needsMask(String origString){
+ if (origString.indexOf("&")!=-1){
+ origString=replace(origString,"&","&amp;");
+ }
+ if (origString.indexOf("\"")!=-1){
+ origString=replace(origString,"\"","&quot;");
+ }
+ if (origString.indexOf("<")!=-1){
+ origString=replace(origString,"<","&lt;");
+ }
+ if (origString.indexOf(">")!=-1){
+ origString=replace(origString,">","&gt;");
+ }
+ return origString;
+
+ }
+
+
+
+ public void startDocument () {
+ //System.out.println("\nStart Document!");
+ }
+
+ public void endDocument()throws com.sun.star.uno.RuntimeException
+ {
+
+ try{
+ xOutStream.closeOutput();
+ convert (xInStream,xos,true,udJarPath,sURL,offMime,sdMime);
+
+ }
+ catch (IOException e){
+ //System.out.println("Exception "+e);
+ throw new com.sun.star.uno.RuntimeException(e.getMessage());
+
+ }
+ catch (Exception e){
+ //System.out.println("Exception "+e);
+ throw new com.sun.star.uno.RuntimeException("Xmerge Exception");
+
+ }
+ }
+
+
+
+ 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<len;i++)
+ {
+ str=str.concat(xattribs.getNameByIndex(i));
+ str=str.concat("=\"");
+ str=str.concat(needsMask(xattribs.getValueByIndex(i)));
+ str=str.concat("\" ");
+ }
+ }
+ str=str.concat(">");
+ // System.out.println(str);
+ try{
+ xOutStream.writeBytes(str.getBytes("UTF-8"));
+ }
+ catch (Exception e){
+ System.out.println("\n"+e);
+ }
+
+ }
+
+ public void endElement(String str){
+
+ str="</".concat(str);
+ str=str.concat(">");
+ 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){
+
+ }
+
+
+
+
+
+
+ public 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);
+
+ ConverterInfo converterInfo = null;
+ Enumeration ciEnum= null;
+
+ XInputStreamToInputStreamAdapter xis =new XInputStreamToInputStreamAdapter(xml);
+
+
+ XOutputStreamToOutputStreamAdapter newxos =new XOutputStreamToOutputStreamAdapter(device);
+ 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 <staroffice/sxw> to <specified format> ");
+
+ }
+ else
+ {
+ cv.addInputStream(name,(InputStream)xis,false);
+ ConvertData dataOut = cv.convert();
+
+ Enumeration docEnum = dataOut.getDocumentEnumeration();
+
+ if (docEnum.hasMoreElements()){
+ Document docOut = (Document)docEnum.nextElement();
+ String fileName = docOut.getFileName();
+ docOut.write(newxos);
+
+ newxos.flush();
+ newxos.close();
+
+
+ int i=1;
+ while (docEnum.hasMoreElements() && sURL.startsWith("file:")) {
+ //URI uri=new URI(sFileName);
+ URI uri=new URI(sURL);
+ String newFileName= getPath(uri);
+
+
+ //System.out.println("\nURI: "+uri.getPath());
+ File newFile=null;
+ 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 = new FileOutputStream(newFile);
+ docOut = (Document)docEnum.nextElement();
+ fileName = docOut.getFileName();
+ docOut.write(fos);
+ fos.flush();
+ fos.close();
+ i++;
+
+ }
+
+ }
+ }
+ 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 e) {
+ System.out.println("Error:"+e);
+ throw new IOException("Xmerge Exception");
+ }
+ }
+ 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 <staroffice/sxw> from <specified format>");
+ }
+ else
+ {
+ /*
+ ByteArrayOutputStream bout = new ByteArrayOutputStream();
+ byte[][] buf = new byte[1][4096];
+ int n=0;
+ while ((n=xml.readSomeBytes(buf, 4096))>0)
+ bout.write(buf[0], 0, n);
+ ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray());
+ cv.addInputStream(name, bin, false);
+ */
+ cv.addInputStream(name,(InputStream)xis,false);
+ //System.out.println("\nConverting");
+ ConvertData dataIn = cv.convert();
+ //System.out.println("\nFinished Converting");
+ Enumeration docEnum = dataIn.getDocumentEnumeration();
+ while (docEnum.hasMoreElements()) {
+ OfficeDocument docIn = (OfficeDocument)docEnum.nextElement();
+
+ docIn.write(newxos,false);
+ }
+ //newxos.write(-1); //EOF character
+ //newxos.flush();
+ newxos.close();
+ }
+ 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 e) {
+ System.out.println("Error:"+e);
+ throw new IOException("Xmerge Exception");
+ }
+
+
+ }
+
+ }
+
+ private String getPath(URI uri){
+ String path = uri.getPath();
+ String opSys=System.getProperty("os.name");
+ if(opSys.indexOf("Windows")!=-1){
+ path= path.replace('/','\\');
+ path = path.substring(1);
+ }
+ return path;
+ }
+
+
+
+
+
+
+
+ // Implement methods from interface XTypeProvider
+ public byte[] getImplementationId() {
+ byte[] byteReturn = {};
+
+ byteReturn = new String( "" + this.hashCode() ).getBytes();
+
+ return( byteReturn );
+ }
+
+ // 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 <code>JavaLoader</code>
+ *
+ * @return returns a <code>XSingleServiceFactory</code> 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/makefile.mk b/xmerge/source/bridge/makefile.mk
new file mode 100644
index 000000000000..05fa5a738d84
--- /dev/null
+++ b/xmerge/source/bridge/makefile.mk
@@ -0,0 +1,43 @@
+#*************************************************************************
+#
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# Copyright 2000, 2010 Oracle and/or its affiliates.
+#
+# OpenOffice.org - a multi-platform office productivity suite
+#
+# This file is part of OpenOffice.org.
+#
+# OpenOffice.org is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License version 3
+# only, as published by the Free Software Foundation.
+#
+# OpenOffice.org is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License version 3 for more details
+# (a copy is included in the LICENSE file that accompanied this code).
+#
+# You should have received a copy of the GNU Lesser General Public License
+# version 3 along with OpenOffice.org. If not, see
+# <http://www.openoffice.org/license.html>
+# for a copy of the LGPLv3 License.
+#
+#*************************************************************************
+
+TARGET=XMergeBridge
+PRJ=../..
+PRJNAME=xmerge
+
+.INCLUDE : ant.mk
+.IF "$(L10N_framework)"==""
+ALLTAR: ANTBUILD
+.ENDIF
+
+ALLTAR : $(MISC)/XMergeBridge.component
+
+$(MISC)/XMergeBridge.component .ERRREMOVE : \
+ $(SOLARENV)/bin/createcomponent.xslt XMergeBridge.component
+ $(XSLTPROC) --nonet --stringparam uri \
+ '$(COMPONENTPREFIX_BASIS_JAVA)XMergeBridge.jar' -o $@ \
+ $(SOLARENV)/bin/createcomponent.xslt XMergeBridge.component
diff --git a/xmerge/source/bridge/manifest.mf b/xmerge/source/bridge/manifest.mf
new file mode 100644
index 000000000000..167082c1e7dc
--- /dev/null
+++ b/xmerge/source/bridge/manifest.mf
@@ -0,0 +1,3 @@
+Class-Path: xmerge.jar
+RegistrationClassName: XMergeBridge
+UNO-Type-Path:
diff --git a/xmerge/source/htmlsoff/build.xml b/xmerge/source/htmlsoff/build.xml
new file mode 100644
index 000000000000..90cbcbb4beae
--- /dev/null
+++ b/xmerge/source/htmlsoff/build.xml
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ #*************************************************************************
+ #
+ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+
+ Copyright 2000, 2010 Oracle and/or its affiliates.
+
+ OpenOffice.org - a multi-platform office productivity suite
+
+ This file is part of OpenOffice.org.
+
+ OpenOffice.org is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License version 3
+ only, as published by the Free Software Foundation.
+
+ OpenOffice.org is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License version 3 for more details
+ (a copy is included in the LICENSE file that accompanied this code).
+
+ You should have received a copy of the GNU Lesser General Public License
+ version 3 along with OpenOffice.org. If not, see
+ <http://www.openoffice.org/license.html>
+ for a copy of the LGPLv3 License.
+
+ #*************************************************************************
+ -->
+
+<project name="htmlsoff" default="all" basedir=".">
+
+ <property file="../inc/antbuild.properties"/>
+
+ <path id="classpath">
+ <pathelement location="${build.dir}/xmerge.jar"/>
+ </path>
+
+
+ <target name="init" >
+ </target>
+
+ <!-- compile java sources in ${package} -->
+ <target name="compile" depends="init">
+ </target>
+
+ <!-- package to jar -->
+ <target name="jar" depends="compile">
+ <jar destfile="${target.jar}">
+ <fileset dir="${basedir}"
+ includes="*.xsl" />
+ <metainf dir="${basedir}">
+ <filename name="converter.xml"/>
+ </metainf>
+ </jar>
+ </target>
+
+ <!-- clean up -->
+ <target name="clean">
+ <delete file="${target.jar}"/>
+ </target>
+
+ <target name="all" depends="jar">
+ </target>
+
+</project>
+
diff --git a/xmerge/source/htmlsoff/converter.xml b/xmerge/source/htmlsoff/converter.xml
new file mode 100644
index 000000000000..3038d5b70d73
--- /dev/null
+++ b/xmerge/source/htmlsoff/converter.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0"?>
+<!--
+ #*************************************************************************
+ #
+ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+
+ Copyright 2000, 2010 Oracle and/or its affiliates.
+
+ OpenOffice.org - a multi-platform office productivity suite
+
+ This file is part of OpenOffice.org.
+
+ OpenOffice.org is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License version 3
+ only, as published by the Free Software Foundation.
+
+ OpenOffice.org is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License version 3 for more details
+ (a copy is included in the LICENSE file that accompanied this code).
+
+ You should have received a copy of the GNU Lesser General Public License
+ version 3 along with OpenOffice.org. If not, see
+ <http://www.openoffice.org/license.html>
+ for a copy of the LGPLv3 License.
+
+ #*************************************************************************
+ -->
+<!--<!DOCTYPE converters SYSTEM "converter.dtd">-->
+<converters>
+ <converter type="staroffice/sxw" version="1.0">
+ <converter-display-name>
+ XSLT Transformation
+ </converter-display-name>
+ <converter-description>
+ Converter which performs xslt transformations
+ </converter-description>
+ <converter-vendor>OpenOffice.org</converter-vendor>
+ <converter-class-impl>
+ org.openoffice.xmerge.converter.xml.xslt.PluginFactoryImpl
+ </converter-class-impl>
+ <converter-xslt-serialize>
+ sofftohtml.xsl
+ </converter-xslt-serialize>
+ <converter-xslt-deserialize>
+ htmltosoff.xsl
+ </converter-xslt-deserialize>
+ <converter-target type="text/html" />
+ </converter>
+</converters>
+
diff --git a/xmerge/source/htmlsoff/htmltosoff.xsl b/xmerge/source/htmlsoff/htmltosoff.xsl
new file mode 100644
index 000000000000..4a06a77f52aa
--- /dev/null
+++ b/xmerge/source/htmlsoff/htmltosoff.xsl
@@ -0,0 +1,176 @@
+<?xml version='1.0' encoding="UTF-8"?>
+<!--
+ #*************************************************************************
+ #
+ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+
+ Copyright 2000, 2010 Oracle and/or its affiliates.
+
+ OpenOffice.org - a multi-platform office productivity suite
+
+ This file is part of OpenOffice.org.
+
+ OpenOffice.org is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License version 3
+ only, as published by the Free Software Foundation.
+
+ OpenOffice.org is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License version 3 for more details
+ (a copy is included in the LICENSE file that accompanied this code).
+
+ You should have received a copy of the GNU Lesser General Public License
+ version 3 along with OpenOffice.org. If not, see
+ <http://www.openoffice.org/license.html>
+ for a copy of the LGPLv3 License.
+
+ #*************************************************************************
+ -->
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:office="http://openoffice.org/2000/office"
+ xmlns:style="http://openoffice.org/2000/style"
+ xmlns:text="http://openoffice.org/2000/text"
+ xmlns:table="http://openoffice.org/2000/table"
+ xmlns:draw="http://openoffice.org/2000/drawing"
+ xmlns:fo="http://www.w3.org/1999/XSL/Format"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:number="http://openoffice.org/2000/datastyle"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns:chart="http://openoffice.org/2000/chart"
+ xmlns:dr3d="http://openoffice.org/2000/dr3d"
+ xmlns:math="http://www.w3.org/1998/Math/MathML"
+ xmlns:form="http://openoffice.org/2000/form"
+ xmlns:script="http://openoffice.org/2000/script"
+ >
+<xsl:output method="xml" />
+
+
+<xsl:template match="/">
+ <xsl:apply-templates />
+</xsl:template>
+
+<xsl:template match="html">
+
+ <office:document-content xmlns:office="http://openoffice.org/2000/office"
+ xmlns:style="http://openoffice.org/2000/style"
+ xmlns:text="http://openoffice.org/2000/text"
+ xmlns:table="http://openoffice.org/2000/table"
+ xmlns:draw="http://openoffice.org/2000/drawing"
+ xmlns:fo="http://www.w3.org/1999/XSL/Format"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:number="http://openoffice.org/2000/datastyle"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns:chart="http://openoffice.org/2000/chart"
+ xmlns:dr3d="http://openoffice.org/2000/dr3d"
+ xmlns:math="http://www.w3.org/1998/Math/MathML"
+ xmlns:form="http://openoffice.org/2000/form"
+ xmlns:script="http://openoffice.org/2000/script"
+ office:class="text" office:version="1.0">
+
+<office:script/>
+ <office:font-decls>
+ <style:font-decl style:name="Letter Gothic" fo:font-family="&apos;Letter Gothic&apos;" style:font-family-generic="modern" style:font-pitch="fixed"/>
+ <style:font-decl style:name="Arial Unicode MS" fo:font-family="&apos;Arial Unicode MS&apos;" style:font-pitch="variable"/>
+ <style:font-decl style:name="HG Mincho Light J" fo:font-family="&apos;HG Mincho Light J&apos;" style:font-pitch="variable"/>
+ <style:font-decl style:name="CG Times" fo:font-family="&apos;CG Times&apos;" style:font-family-generic="roman" style:font-pitch="variable"/>
+ <style:font-decl style:name="Thorndale" fo:font-family="Thorndale" style:font-family-generic="roman" style:font-pitch="variable"/>
+ <style:font-decl style:name="Antique Olive" fo:font-family="&apos;Antique Olive&apos;" style:font-family-generic="swiss" style:font-pitch="variable"/>
+ <style:font-decl style:name="Arial Black" fo:font-family="&apos;Arial Black&apos;" style:font-family-generic="swiss" style:font-pitch="variable"/>
+ </office:font-decls>
+ <office:automatic-styles>
+ <style:style style:name="Table1" style:family="table">
+ <style:properties style:width="16.999cm" table:align="margins"/>
+ </style:style>
+ <style:style style:name="Table1.A" style:family="table-column">
+ <style:properties style:column-width="3.399cm" style:rel-column-width="13107*"/>
+ </style:style>
+ <style:style style:name="Table1.A1" style:family="table-cell">
+ <style:properties fo:padding="0.097cm" fo:border-left="0.002cm solid #000000" fo:border-right="none" fo:border-top="0.002cm solid #000000" fo:border-bottom="0.002cm solid #000000"/>
+ </style:style>
+ <style:style style:name="Table1.E1" style:family="table-cell">
+ <style:properties fo:padding="0.097cm" fo:border="0.002cm solid #000000"/>
+ </style:style>
+ <style:style style:name="Table1.A2" style:family="table-cell">
+ <style:properties fo:padding="0.097cm" fo:border-left="0.002cm solid #000000" fo:border-right="none" fo:border-top="none" fo:border-bottom="0.002cm solid #000000"/>
+ </style:style>
+ <style:style style:name="Table1.E2" style:family="table-cell">
+ <style:properties fo:padding="0.097cm" fo:border-left="0.002cm solid #000000" fo:border-right="0.002cm solid #000000" fo:border-top="none" fo:border-bottom="0.002cm solid #000000"/>
+ </style:style>
+ <style:style style:name="P1" style:family="paragraph" style:parent-style-name="Standard">
+ <style:properties fo:margin-left="0cm" fo:margin-right="0cm" fo:text-indent="0cm" style:auto-text-indent="false"/>
+ </style:style>
+ <style:style style:name="P2" style:family="paragraph" style:parent-style-name="Table Contents">
+ <style:properties style:font-name="Arial Black" fo:font-size="20pt"/>
+ </style:style>
+ </office:automatic-styles>
+
+
+
+
+
+ <office:body>
+ <text:sequence-decls>
+ <text:sequence-decl text:display-outline-level="0" text:name="Illustration"/>
+ <text:sequence-decl text:display-outline-level="0" text:name="Table"/>
+ <text:sequence-decl text:display-outline-level="0" text:name="Text"/>
+ <text:sequence-decl text:display-outline-level="0" text:name="Drawing"/>
+ </text:sequence-decls>
+
+ <xsl:apply-templates/>
+ </office:body>
+ </office:document-content>
+
+</xsl:template>
+
+<xsl:template match="body">
+ <xsl:apply-templates />
+</xsl:template>
+
+
+
+<xsl:template match="p">
+ <xsl:for-each select=".">
+ <text:p text:style-name="P1">
+ <!--<xsl:value-of select="."/>-->
+ <xsl:apply-templates />
+ </text:p>
+ </xsl:for-each>
+</xsl:template>
+
+<xsl:template match="br">
+ <xsl:if test="ancestor::p">
+ <xsl:text disable-output-escaping="yes">&lt;/text:p&gt; &lt;text:p text:style-name="P1"&gt;</xsl:text>
+ </xsl:if>
+</xsl:template>
+
+<xsl:template match="table">
+ <xsl:for-each select=".">
+ <table:table table:name="Table1" table:style-name="Table1">
+ <table:table-column table:style-name="Table1.A" table:number-columns-repeated="5"/>
+ <xsl:apply-templates/>
+ </table:table>
+ </xsl:for-each>
+</xsl:template>
+
+<xsl:template match="tr">
+ <xsl:for-each select=".">
+ <table:table-row>
+ <xsl:apply-templates/>
+ </table:table-row>
+ </xsl:for-each>
+</xsl:template>
+
+<xsl:template match="td">
+ <xsl:for-each select=".">
+ <table:table-cell table:style-name="Table1.A1" table:value-type="string">
+ <text:p text:style-name="P1">
+ <xsl:value-of select="."/>
+ </text:p>
+ </table:table-cell>
+ </xsl:for-each>
+</xsl:template>
+
+
+
+</xsl:stylesheet>
diff --git a/xmerge/source/htmlsoff/makefile.mk b/xmerge/source/htmlsoff/makefile.mk
new file mode 100644
index 000000000000..204b3fffa774
--- /dev/null
+++ b/xmerge/source/htmlsoff/makefile.mk
@@ -0,0 +1,35 @@
+#*************************************************************************
+#
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# Copyright 2000, 2010 Oracle and/or its affiliates.
+#
+# OpenOffice.org - a multi-platform office productivity suite
+#
+# This file is part of OpenOffice.org.
+#
+# OpenOffice.org is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License version 3
+# only, as published by the Free Software Foundation.
+#
+# OpenOffice.org is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License version 3 for more details
+# (a copy is included in the LICENSE file that accompanied this code).
+#
+# You should have received a copy of the GNU Lesser General Public License
+# version 3 along with OpenOffice.org. If not, see
+# <http://www.openoffice.org/license.html>
+# for a copy of the LGPLv3 License.
+#
+#*************************************************************************
+
+TARGET=htmlsoff
+PRJ=../..
+PRJNAME=xmerge
+
+.INCLUDE : ant.mk
+.IF "$(L10N_framework)"==""
+ALLTAR: ANTBUILD
+.ENDIF
diff --git a/xmerge/source/htmlsoff/package.html b/xmerge/source/htmlsoff/package.html
new file mode 100644
index 000000000000..30c71b15655f
--- /dev/null
+++ b/xmerge/source/htmlsoff/package.html
@@ -0,0 +1,67 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
+<!--
+ #*************************************************************************
+ #
+ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+
+ Copyright 2000, 2010 Oracle and/or its affiliates.
+
+ OpenOffice.org - a multi-platform office productivity suite
+
+ This file is part of OpenOffice.org.
+
+ OpenOffice.org is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License version 3
+ only, as published by the Free Software Foundation.
+
+ OpenOffice.org is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License version 3 for more details
+ (a copy is included in the LICENSE file that accompanied this code).
+
+ You should have received a copy of the GNU Lesser General Public License
+ version 3 along with OpenOffice.org. If not, see
+ <http://www.openoffice.org/license.html>
+ for a copy of the LGPLv3 License.
+
+ #*************************************************************************
+ -->
+<HTML>
+<HEAD>
+ <TITLE>org.openoffice.xmerge.converter.xml.xslt package</TITLE>
+</HEAD>
+<BODY>
+<P>Provides the tools for doing the conversion of StarWriter XML to
+and from supported formats, through the use of an XSLT
+transformation.</P>
+<P>It follows the {@link org.openoffice.xmerge}
+framework for the conversion process.</P>
+<P>This converter does not currently support merge.</P>
+<P><FONT FACE="Times New Roman, serif"><FONT SIZE=5><B>XSLT
+Transformation</B></FONT></FONT></P>
+<p>The converter makes use
+of one or more XSLT style sheets, which are used in the
+DocumentSerializer and DocumentDeserializer, to perform the actual
+translations. The location of these stylesheets is extracted from the {@link org.openoffice.xmerge.util.registry.ConverterInfo ConverterInfo} data structure, and are specified using the optional converter-xslt-serialize and converter-xsltdeserialize tags in a plugins converter.xml file. Please refer to the SDK document for more information about how to implement a Plugin Configuration XML File for a specific plugin.
+A sample OpenOffice to Html stylesheet and Html to
+Openffice stylesheet, has been provided as a sample implementation.
+The converter also makes use of an XsltPlugin.properties file, which may be edited by the user to provide MIME-TYPE to file extension mappings. This file is used by the {@link org.openoffice.xmerge.converter.xml.xslt.PluginFactoryImpl getDeviceFileExtension} method.
+</p>
+
+<H2>TODO list</H2>
+
+<p><ol>
+<li>Expand XSLT style sheets to support more office/html
+ capabilities</li>
+<li>Add support for certain character codes, such as &amp;nbsp
+ which currently causes the transformer to break.</li>
+<li>Change the DocumentDeserializer transformer, so that the DOMResult is serialized using the xalan serializer and create an SxwDocument from the result</li>
+</ol></p>
+
+@see org.openoffice.xmerge.util.registry
+
+</BODY>
+</HTML>
+
+
diff --git a/xmerge/source/htmlsoff/sofftohtml.xsl b/xmerge/source/htmlsoff/sofftohtml.xsl
new file mode 100644
index 000000000000..b01c4691c71a
--- /dev/null
+++ b/xmerge/source/htmlsoff/sofftohtml.xsl
@@ -0,0 +1,118 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+
+ Copyright 2000, 2010 Oracle and/or its affiliates.
+
+ OpenOffice.org - a multi-platform office productivity suite
+
+ This file is part of OpenOffice.org.
+
+ OpenOffice.org is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License version 3
+ only, as published by the Free Software Foundation.
+
+ OpenOffice.org is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License version 3 for more details
+ (a copy is included in the LICENSE file that accompanied this code).
+
+ You should have received a copy of the GNU Lesser General Public License
+ version 3 along with OpenOffice.org. If not, see
+ <http://www.openoffice.org/license.html>
+ for a copy of the LGPLv3 License.
+
+-->
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:style="http://openoffice.org/2000/style" xmlns:table="http://openoffice.org/2000/table" xmlns:text="http://openoffice.org/2000/text" xmlns:office="http://openoffice.org/2000/office" xmlns:fo="http://www.w3.org/1999/XSL/Format">
+ <xsl:output method="xml" omit-xml-declaration="yes" indent="yes" encoding="ISO-8859-1"/>
+ <!--doctype-system=[<!ENTITY acirc "">] -->
+ <xsl:strip-space elements="tokens"/>
+ <xsl:template match="office:document">
+ <html>
+ <xsl:apply-templates/>
+ </html>
+ </xsl:template>
+ <xsl:template match="office:document-content">
+ <html>
+ <xsl:apply-templates/>
+ </html>
+ </xsl:template>
+ <xsl:template match="office:automatic-styles">
+ <style type="text/css">p.Table-Heading{font-weight:bold;}<xsl:apply-templates/>
+ </style>
+ </xsl:template>
+ <xsl:template match="office:styles"/>
+ <xsl:template match="office:meta"/>
+ <xsl:template match="office:settings"/>
+ <xsl:template match="style:style">
+ <xsl:if test="@style:family ='paragraph'">p.<xsl:value-of select="@style:name"/>{<xsl:apply-templates/>}</xsl:if>
+ <xsl:if test="@style:family ='paragraph'">p.<xsl:value-of select="@style:name"/>{<xsl:if test="@style:parent-style-name='Table Heading'">font-weight:bold;font-style:italic;</xsl:if>
+ <xsl:apply-templates/>}</xsl:if>
+ <xsl:if test="@style:family ='table-cell'">td.<xsl:value-of select="@style:name"/>{<xsl:if test="@style:parent-style-name='Table Heading'">font-weight:bold;font-style:italic;</xsl:if>
+ <xsl:apply-templates/>}</xsl:if>
+ </xsl:template>
+ <xsl:template match="style:properties">
+ <!--<xsl:param name="style" select="@fo:font-weight"/>-->
+ <xsl:if test="@fo:font-weight">font-weight:<xsl:value-of select="@fo:font-weight"/>;</xsl:if>
+ <xsl:if test="@fo:font-style">font-style:<xsl:value-of select="@fo:font-style"/>;</xsl:if>
+ <xsl:if test="@style:font-name">font-family:<xsl:value-of select="@style:font-name"/>;</xsl:if>
+ <xsl:if test="@fo:font-size">font-size:<xsl:value-of select="@fo:font-size"/>;</xsl:if>
+ <xsl:if test="@style:text-underline='single'">text-decoration:underline;</xsl:if>
+ <xsl:if test="@style:text-crossing-out='single-line'">text-decoration:line-through;</xsl:if>
+ <xsl:if test="@fo:text-align='start'">text-align:left</xsl:if>
+ <xsl:if test="@fo:text-align='center'">text-align:center</xsl:if>
+ <xsl:if test="@fo:text-align='end'">text-align:right</xsl:if>
+ <!--<xsl:value-of select="$style"/>-->
+ </xsl:template>
+ <xsl:template match="office:body">
+ <xsl:apply-templates/>
+ </xsl:template>
+ <xsl:template match="table:table">
+ <table border="1" cellpadding="2" width="100%">
+ <xsl:apply-templates/>
+ </table>
+ </xsl:template>
+ <xsl:template match="table:table-header-rows">
+ <th>
+ <xsl:apply-templates/>
+ </th>
+ </xsl:template>
+ <xsl:template match="table:table-row">
+ <tr>
+ <xsl:apply-templates/>
+ </tr>
+ </xsl:template>
+ <xsl:template match="table:table-cell">
+ <xsl:text disable-output-escaping="yes">&lt;td class="</xsl:text>
+ <xsl:value-of select="@table:style-name"/>
+ <xsl:text disable-output-escaping="yes">"&gt;</xsl:text>
+ <!--<xsl:value-of select="."/>-->
+ <xsl:apply-templates/>
+ <xsl:text disable-output-escaping="yes">&lt;/td&gt;</xsl:text>
+ <!--<td width="20%">
+ <xsl:apply-templates />
+ </td>-->
+ </xsl:template>
+ <xsl:template match="text:p">
+ <xsl:if test="ancestor-or-self::table:table-cell">
+ <xsl:if test=".=''">
+ <br/>
+ </xsl:if>
+ </xsl:if>
+ <xsl:text disable-output-escaping="yes">&lt;p class="</xsl:text>
+ <xsl:choose>
+ <xsl:when test="@text:style-name ='Table Heading'">Table-Heading</xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="@text:style-name"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ <xsl:text disable-output-escaping="yes">"&gt;</xsl:text>
+ <xsl:apply-templates/>
+ <xsl:text disable-output-escaping="yes">&lt;/p&gt;</xsl:text>
+ <!--<xsl:value-of select="."/>-->
+ <!--<xsl:text disable-output-escaping="yes">&amp;nbsp;</xsl:text>-->
+ <!--<br/>-->
+ </xsl:template>
+</xsl:stylesheet>
diff --git a/xmerge/source/inc/antbuild.properties b/xmerge/source/inc/antbuild.properties
new file mode 100644
index 000000000000..a027bbb60218
--- /dev/null
+++ b/xmerge/source/inc/antbuild.properties
@@ -0,0 +1,12 @@
+# define how to handle CLASSPATH environment
+# x-no-translate
+build.sysclasspath=ignore
+
+# set wether we want to compile with or without deprecation
+deprecation=on
+
+src.dir=${basedir}/java
+
+build.dir=${out}/class
+target.dir=${build.dir}/${ant.project.name}
+target.jar=${build.dir}/${ant.project.name}.jar \ No newline at end of file
diff --git a/xmerge/source/inc/antbuild.xml b/xmerge/source/inc/antbuild.xml
new file mode 100644
index 000000000000..4598ae2261a5
--- /dev/null
+++ b/xmerge/source/inc/antbuild.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0"?>
+
diff --git a/xmerge/source/minicalc/build.xml b/xmerge/source/minicalc/build.xml
new file mode 100644
index 000000000000..1332fa05cd9a
--- /dev/null
+++ b/xmerge/source/minicalc/build.xml
@@ -0,0 +1,76 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ #*************************************************************************
+ #
+ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+
+ Copyright 2000, 2010 Oracle and/or its affiliates.
+
+ OpenOffice.org - a multi-platform office productivity suite
+
+ This file is part of OpenOffice.org.
+
+ OpenOffice.org is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License version 3
+ only, as published by the Free Software Foundation.
+
+ OpenOffice.org is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License version 3 for more details
+ (a copy is included in the LICENSE file that accompanied this code).
+
+ You should have received a copy of the GNU Lesser General Public License
+ version 3 along with OpenOffice.org. If not, see
+ <http://www.openoffice.org/license.html>
+ for a copy of the LGPLv3 License.
+
+ #*************************************************************************
+ -->
+
+<project name="minicalc" default="all" basedir=".">
+
+ <property file="../inc/antbuild.properties"/>
+
+ <path id="classpath">
+ <pathelement location="${build.dir}/xmerge.jar"/>
+ </path>
+
+
+ <target name="init" >
+ <mkdir dir="${target.dir}"/>
+ </target>
+
+ <!-- compile java sources in ${package} -->
+ <target name="compile" depends="init">
+ <javac srcdir="${src.dir}"
+ destdir="${target.dir}"
+ debug="${debug}"
+ deprecation="${deprecation}"
+ optimize="${optimize}">
+ <classpath refid="classpath"/>
+ </javac>
+ </target>
+
+ <!-- package to jar -->
+ <target name="jar" depends="compile">
+ <jar destfile="${target.jar}">
+ <fileset dir="${target.dir}"
+ includes="**/*.class" />
+ <metainf dir="${basedir}">
+ <filename name="converter.xml"/>
+ </metainf>
+ </jar>
+ </target>
+
+ <!-- clean up -->
+ <target name="clean">
+ <delete dir="${class.dir}"/>
+ <delete file="${target.jar}"/>
+ </target>
+
+ <target name="all" depends="jar">
+ </target>
+
+</project>
+
diff --git a/xmerge/source/minicalc/converter.xml b/xmerge/source/minicalc/converter.xml
new file mode 100644
index 000000000000..65d1fb774423
--- /dev/null
+++ b/xmerge/source/minicalc/converter.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0"?>
+<!--
+ #*************************************************************************
+ #
+ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+
+ Copyright 2000, 2010 Oracle and/or its affiliates.
+
+ OpenOffice.org - a multi-platform office productivity suite
+
+ This file is part of OpenOffice.org.
+
+ OpenOffice.org is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License version 3
+ only, as published by the Free Software Foundation.
+
+ OpenOffice.org is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License version 3 for more details
+ (a copy is included in the LICENSE file that accompanied this code).
+
+ You should have received a copy of the GNU Lesser General Public License
+ version 3 along with OpenOffice.org. If not, see
+ <http://www.openoffice.org/license.html>
+ for a copy of the LGPLv3 License.
+
+ #*************************************************************************
+ -->
+<converters>
+ <converter type="staroffice/sxc" version="1.0">
+ <converter-display-name>
+ Minicalc 6.4
+ </converter-display-name>
+ <converter-description>
+ StarCalc XML to/from Minicalc 6.4 conversion
+ </converter-description>
+ <converter-vendor>OpenOffice.org</converter-vendor>
+ <converter-class-impl>
+ org.openoffice.xmerge.converter.xml.sxc.minicalc.PluginFactoryImpl
+ </converter-class-impl>
+ <converter-target type="application/x-minicalc" />
+ </converter>
+</converters>
+
diff --git a/xmerge/source/minicalc/java/org/openoffice/xmerge/converter/xml/sxc/minicalc/ConverterCapabilitiesImpl.java b/xmerge/source/minicalc/java/org/openoffice/xmerge/converter/xml/sxc/minicalc/ConverterCapabilitiesImpl.java
new file mode 100644
index 000000000000..a1dc67a443e0
--- /dev/null
+++ b/xmerge/source/minicalc/java/org/openoffice/xmerge/converter/xml/sxc/minicalc/ConverterCapabilitiesImpl.java
@@ -0,0 +1,113 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxc.minicalc;
+
+import org.openoffice.xmerge.ConverterCapabilities;
+import org.openoffice.xmerge.converter.xml.OfficeConstants;
+
+
+/**
+ * <p>MiniCalc implementation of <code>ConverterCapabilities</code> for
+ * the {@link
+ * org.openoffice.xmerge.converter.xml.sxc.minicalc.PluginFactoryImpl
+ * PluginFactoryImpl}.</p>
+ *
+ * <p>Used with StarCalc SXC to/from MiniCalc conversions. The
+ * <code>ConverterCapibilies</code> specify which &quot;Office&quot;
+ * <code>Document</code> tags and attributes are supported on the
+ * &quot;Device&quot; <code>Document</code> format.</p>
+ */
+public final class ConverterCapabilitiesImpl
+ implements ConverterCapabilities {
+
+ public boolean canConvertTag(String tag) {
+
+ if (OfficeConstants.TAG_OFFICE_BODY.equals(tag))
+ return true;
+ else if (OfficeConstants.TAG_PARAGRAPH.equals(tag))
+ return true;
+ else if (OfficeConstants.TAG_TABLE.equals(tag))
+ return true;
+ else if (OfficeConstants.TAG_TABLE_ROW.equals(tag))
+ return true;
+ else if (OfficeConstants.TAG_TABLE_COLUMN.equals(tag))
+ return false;
+ // TODO - we currently do not handle the table column tag
+ else if (OfficeConstants.TAG_TABLE_SCENARIO.equals(tag))
+ return false;
+ // TODO - we currently do not handle the table scenario tag
+ else if (OfficeConstants.TAG_TABLE_CELL.equals(tag))
+ return true;
+
+ return false;
+ }
+
+ public boolean canConvertAttribute(String tag,
+ String attribute) {
+
+ if (OfficeConstants.TAG_TABLE.equals(tag)) {
+
+ if (OfficeConstants.ATTRIBUTE_TABLE_NAME.equals(attribute))
+ return true;
+
+ } else if (OfficeConstants.TAG_TABLE_CELL.equals(tag)) {
+
+ if (OfficeConstants.ATTRIBUTE_TABLE_VALUE_TYPE.equals(attribute))
+ return true;
+ else if (OfficeConstants.ATTRIBUTE_TABLE_FORMULA.
+ equals(attribute))
+ return true;
+ else if (OfficeConstants.ATTRIBUTE_TABLE_VALUE.equals(attribute))
+ return true;
+ else if (OfficeConstants.ATTRIBUTE_TABLE_BOOLEAN_VALUE.
+ equals(attribute))
+ return true;
+ else if (OfficeConstants.ATTRIBUTE_TABLE_CURRENCY.
+ equals(attribute))
+ return true;
+ else if (OfficeConstants.ATTRIBUTE_TABLE_TIME_VALUE.
+ equals(attribute))
+ return true;
+ else if (OfficeConstants.ATTRIBUTE_TABLE_DATE_VALUE.
+ equals(attribute))
+ return true;
+ else if (OfficeConstants.ATTRIBUTE_TABLE_NUM_COLUMNS_REPEATED.
+ equals(attribute))
+ return true;
+
+ } else if (OfficeConstants.TAG_TABLE_ROW.equals(tag)) {
+
+ if (OfficeConstants.ATTRIBUTE_TABLE_NUM_ROWS_REPEATED.
+ equals(attribute))
+ return true;
+ }
+
+ return false;
+ }
+}
+
diff --git a/xmerge/source/minicalc/java/org/openoffice/xmerge/converter/xml/sxc/minicalc/MinicalcConstants.java b/xmerge/source/minicalc/java/org/openoffice/xmerge/converter/xml/sxc/minicalc/MinicalcConstants.java
new file mode 100644
index 000000000000..78d48a5e4ee9
--- /dev/null
+++ b/xmerge/source/minicalc/java/org/openoffice/xmerge/converter/xml/sxc/minicalc/MinicalcConstants.java
@@ -0,0 +1,45 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxc.minicalc;
+
+import org.openoffice.xmerge.converter.palm.PdbUtil;
+
+/**
+ * Constants used for encoding and decoding the MiniCalc format.
+ *
+ * @author Herbie Ong
+ */
+interface MinicalcConstants {
+
+ /** Creator ID. */
+ public static final int CREATOR_ID = PdbUtil.intID("PiMC");
+
+ /** Type ID. */
+ public static final int TYPE_ID = PdbUtil.intID("Data");
+}
+
diff --git a/xmerge/source/minicalc/java/org/openoffice/xmerge/converter/xml/sxc/minicalc/MinicalcDataString.java b/xmerge/source/minicalc/java/org/openoffice/xmerge/converter/xml/sxc/minicalc/MinicalcDataString.java
new file mode 100644
index 000000000000..974e9d1b3079
--- /dev/null
+++ b/xmerge/source/minicalc/java/org/openoffice/xmerge/converter/xml/sxc/minicalc/MinicalcDataString.java
@@ -0,0 +1,545 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxc.minicalc;
+
+/**
+ * This class is used by <code>MinicalcDecoder</code> to manipulate a
+ * <code>String</code> containing MiniCalc cell data.
+ *
+ * @author Paul Rank
+ */
+public class MinicalcDataString {
+
+ /** The String representation of the MiniCalc data. */
+ private String data = null;
+
+
+ /**
+ * Constructor stores the MiniCalc data <code>String</code>.
+ *
+ * @param data A <code>String</code> containing MiniCalc
+ * cell data.
+ */
+ public MinicalcDataString(String data) {
+ this.data = data;
+ }
+
+
+ /**
+ * Checks if the MiniCalc data <code>String</code> is a <i>formula</i>.
+ *
+ * @return true if the MiniCalc data <code>String</code> is a
+ * <i>formula</i>, false if the MiniCalc data <code>String</code>
+ * is not a <i>formula</i>.
+ */
+ public boolean isFormula() {
+
+ if (data.startsWith("=")) {
+ return true;
+ }
+
+ return false;
+ }
+
+
+ /**
+ * Checks if the MiniCalc data <code>String</code> is a <i>percentage</i>.
+ *
+ * @return true if the MiniCalc data <code>String</code> is a
+ * <i>percentage</i>, false if the MiniCalc data
+ * <code>String</code> is not a <i>percentage</i>.
+ */
+ public boolean isPercent() {
+
+ if (data.endsWith("%")) {
+ return true;
+ }
+
+ return false;
+ }
+
+
+ /**
+ * Checks if the MiniCalc data <code>String</code> is a
+ * <i>boolean</i> value.
+ *
+ * @return true if the MiniCalc data <code>String</code> is
+ * a <i>boolean</i>, false if the MiniCalc data
+ * <code>String</code> is not a <i>boolean</i>.
+ */
+ public boolean isBoolean() {
+
+ if (data.equalsIgnoreCase("false") ||
+ data.equalsIgnoreCase("true")) {
+ return true;
+ }
+
+ return false;
+ }
+
+
+ /**
+ * Checks if the MiniCalc data <code>String</code> is a <i>date</i>.
+ *
+ * @return true if the MiniCalc data <code>String</code> is
+ * a <i>date</i>, false if the MiniCalc data <code>String</code>
+ * is not a <i>date</i>.
+ */
+ public boolean isDate() {
+
+ // Starting index into the date string - month
+ int start = 0;
+
+ // Search for "/", which separates month from day
+ int end = data.indexOf("/");
+
+ // Separator was found
+ if (end > 0) {
+
+ String monthString = data.substring(start, end);
+
+ try {
+ Float f = Float.valueOf(monthString);
+ if ((f.intValue() < 0) || (f.intValue() > 12)) {
+ return false;
+ }
+ }
+ catch (NumberFormatException e) {
+
+ // no, it is not a currency type
+ return false;
+ }
+
+ // start is now the starting index of day
+ start = end+1;
+
+ // Search for "/", which separates day from year
+ end = data.indexOf("/", start);
+
+ // Separator was found
+ if (end > 0) {
+
+ String dayString = data.substring(start, end);
+
+ try {
+ Float f = Float.valueOf(dayString);
+ if ((f.intValue() < 0) || (f.intValue() > 31))
+ return false;
+ }
+ catch (NumberFormatException e) {
+ // no, it is not a currency type
+ return false;
+ }
+ } else {
+ return false;
+ }
+
+ // start is now at the starting index of the year
+ start = end + 1;
+
+ String yearString = data.substring(start);
+ try {
+ Float f = Float.valueOf(yearString);
+ if (f.intValue() < 0) {
+ return false;
+ }
+ }
+ catch (NumberFormatException e) {
+ // no, it is not a currency type
+ return false;
+ }
+
+ } else {
+ return false;
+ }
+
+ return true;
+ }
+
+
+ /**
+ * Checks if the MiniCalc data <code>String</code> is a <i>time</i>.
+ *
+ * @return true if the MiniCalc data <code>String</code>
+ * is a <i>time</i>, false if the MiniCalc data
+ * <code>String</code> is not a <i>time</i>.
+ */
+ public boolean isTime() {
+
+ // Starting index into the time string - hour
+ int start = 0;
+
+ // Search for ":", which separates hour from minute
+ int end = data.indexOf(":");
+
+
+ // Separator was found
+ if (end > 0) {
+
+ String hourString = data.substring(start, end);
+ try {
+ Float f = Float.valueOf(hourString);
+ if ((f.intValue() < 0) || (f.intValue() > 24))
+ return false;
+ }
+ catch (NumberFormatException e) {
+ // no, it is not a time type
+ return false;
+ }
+
+ // start is now the starting index of minute
+ start = end+1;
+
+ // Search for ":", which separates minute from second
+ end = data.indexOf(":", start);
+
+ // Separator was found
+ if (end > 0) {
+
+ String minuteString = data.substring(start, end);
+
+ try {
+ Float f = Float.valueOf(minuteString);
+ if ((f.intValue() < 0) || (f.intValue() > 60))
+ return false;
+ }
+ catch (NumberFormatException e) {
+ // no, it is not a time type
+ return false;
+ }
+
+ // start is now at the starting index of the seconds
+ start = end+1;
+
+ // The seconds are in the string
+ if (data.length() > start) {
+
+ String secondString = data.substring(start);
+
+
+ try {
+ Float f = Float.valueOf(secondString);
+ if ((f.intValue() < 0) || (f.intValue() > 60))
+ return false;
+ }
+ catch (NumberFormatException e) {
+ // no, it is not a time type
+ return false;
+ }
+ }
+
+ }
+
+ return true;
+
+ }
+
+ return false;
+ }
+
+
+ /**
+ * Checks if the MiniCalc data <code>String</code> is a <i>currency</i>
+ * value.
+ *
+ * @return true if the MiniCalc data <code>String</code> is
+ * a <i>currency</i>, false if the MiniCalc data
+ * <code>String</code> is not a <i>currency</i>.
+ */
+ public boolean isCurrency() {
+
+ boolean result = false;
+
+ // TODO - we currently only check for US currencies
+
+ if (data.endsWith("$")) {
+ String number = data.substring(0, data.length()-1);
+ try {
+ Float f = Float.valueOf(number);
+ result = true;
+ }
+ catch (NumberFormatException e) {
+ // no, it is not a currency type
+ result = false;
+ }
+ }
+
+ else if (data.startsWith("$")) {
+ String number = data.substring(1, data.length());
+ try {
+ Float f = Float.valueOf(number);
+ result = true;
+ }
+ catch (NumberFormatException e) {
+ // no, it is not a currency type
+ result = false;
+ }
+ }
+
+ return result;
+
+ }
+
+
+ /**
+ * This method removes the percent sign from the MiniCalc data
+ * <code>String</code>. If the percent sign is not the last
+ * character of the MiniCalc data <code>String</code>, the
+ * MiniCalc data <code>String</code> is returned.
+ *
+ * @return The MiniCalc data <code>String</code> minus the
+ * percent sign. If the MiniCalc data <code>String</code>
+ * does not begin with a percent sign, the MiniCalc data
+ * <code>String</code> is returned.
+ */
+ public String percentRemoveSign() {
+
+ String number = data;
+
+ if (data.endsWith("%")) {
+ // "%" is the last character, so remove
+ number = data.substring(0, data.length()-1);
+
+ try {
+ Float f = Float.valueOf(number);
+ float f1 = f.floatValue()/100f;
+ Float f2 = new Float(f1);
+ number = f2.toString();
+ }
+ catch (NumberFormatException e) {
+ // no, it is not a float type
+ }
+ }
+
+ return number;
+ }
+
+
+ /**
+ * This method removes the currency sign from the MiniCalc data
+ * <code>String</code>. If the currency sign is not the first or
+ * last character of the MiniCalc data <code>String</code>, the
+ * MiniCalc data <code>String</code> is returned.
+ *
+ * @return The MiniCalc data <code>String</code> minus the currency
+ * sign. If the MiniCalc data <code>String</code> does not
+ * begin or end with a currency sign, the MiniCalc
+ * data <code>String</code> is returned.
+ */
+ public String currencyRemoveSign() {
+
+ String number = data;
+
+ // TODO - only works with US currencies
+
+ if (data.endsWith("$")) {
+
+ number = data.substring(0, data.length()-1);
+
+ } else if (data.startsWith("$")) {
+
+ number = data.substring(1, data.length());
+ }
+
+ return number;
+
+ }
+
+
+ /**
+ * <p>This method converts a MiniCalc date from MiniCalc
+ * format to StarOffice XML format.</p>
+ *
+ * <p>MiniCalc format:</p>
+ *
+ * <p><blockquote>
+ * MM/DD/YY or MM/DD/YYYY
+ * </blockquote></p>
+ *
+ * <p>StarOffice XML format:</p>
+ *
+ * <p><blockquote>
+ * YYYY-MM-DD
+ * </blockquote></p>
+ *
+ * @return The MiniCalc date converted to StarOffice XML
+ * format.
+ */
+ public String convertToStarDate() {
+
+ // The output date string
+ String out;
+
+ String monthString = "01";
+ String dayString = "01";
+ String yearString = "1900";
+
+ // Starting index into the date string - month
+ int start = 0;
+
+ // Search for "/", which separates month from day
+ int end = data.indexOf("/");
+
+ // Separator was found
+ if (end > 0) {
+
+ monthString = data.substring(start, end);
+
+ Integer monthInt = new Integer(monthString);
+
+ // Make sure month is 2 digits
+ if (monthInt.intValue() < 10) {
+ monthString = "0" + monthString;
+ }
+
+ // start is now the starting index of day
+ start = end+1;
+
+ // Search for "/", which separates day from year
+ end = data.indexOf("/", start);
+
+ // Separator was found
+ if (end > 0) {
+
+ dayString = data.substring(start, end);
+
+ Integer dayInt = new Integer(dayString);
+
+ // Make sure day is 2 digits
+ if (dayInt.intValue() < 10) {
+ dayString = "0" + dayString;
+ }
+
+ // start is now at the starting index of the year
+ start = end + 1;
+
+ // The year is in the string
+ if (data.length() > start) {
+
+ yearString = data.substring(start);
+
+ Integer yearInt = new Integer(yearString);
+ int year = yearInt.intValue();
+
+ if (year < 31) {
+
+ // MiniCalc years between 0 and 30 correspond to
+ // 2000 - 2030
+ year += 2000;
+
+ } else if (year < 100) {
+
+ // MiniCalc years between 31 and 99 correspond
+ // to 1931 - 1999
+ year += 1900;
+ }
+
+ yearString = Integer.toString(year);
+ }
+ }
+ }
+
+ // Set out to StarOffice XML date format
+ out = yearString + "-" + monthString + "-" + dayString;
+
+ return out;
+ }
+
+
+ /**
+ * This method converts the MiniCalc time from MiniCalc
+ * format to StarOffice XML format.
+ *
+ * <p>MiniCalc format:</p>
+ *
+ * <p><blockquote>
+ * hh:mm:ss
+ * </blockquote></p>
+ *
+ * <p>StarOffice XML format:</p>
+ *
+ * <p><blockquote>
+ * PThhHmmMssS
+ * </blockquote></p>
+ *
+ * @return The MiniCalc time converted to StarOffice XML
+ * format.
+ */
+ public String convertToStarTime() {
+
+ // The output time string
+ String out;
+
+ String hourString = "00";
+ String minuteString = "00";
+ String secondString = "00";
+
+ // Starting index into the time string - hour
+ int start = 0;
+
+ // Search for ":", which separates hour from minute
+ int end = data.indexOf(":");
+
+ // Separator was found
+ if (end > 0) {
+
+ hourString = data.substring(start, end);
+
+ // start is now the starting index of minute
+ start = end+1;
+
+ // Search for ":", which separates minute from second
+ end = data.indexOf(":", start);
+
+ // Separator was found
+ if (end > 0) {
+
+ minuteString = data.substring(start, end);
+
+ // start is now at the starting index of the seconds
+ start = end+1;
+
+ // The seconds are in the string
+ if (data.length() > start) {
+
+ secondString = data.substring(start);
+ }
+
+ }
+ }
+
+ // TODO - PT is for pacific time, where can we get the
+ // localized value from?
+
+ // Set to StarOffice XML time format
+ out = "PT"+hourString+"H"+minuteString+"M"+secondString+"S";
+
+ return out;
+ }
+}
+
diff --git a/xmerge/source/minicalc/java/org/openoffice/xmerge/converter/xml/sxc/minicalc/MinicalcDecoder.java b/xmerge/source/minicalc/java/org/openoffice/xmerge/converter/xml/sxc/minicalc/MinicalcDecoder.java
new file mode 100644
index 000000000000..37768fa4fb02
--- /dev/null
+++ b/xmerge/source/minicalc/java/org/openoffice/xmerge/converter/xml/sxc/minicalc/MinicalcDecoder.java
@@ -0,0 +1,744 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxc.minicalc;
+
+import jmc.Workbook;
+import jmc.Worksheet;
+import jmc.CellAttributes;
+import jmc.CellDescriptor;
+import jmc.JMCconstants;
+import jmc.JMCException;
+
+import java.io.ByteArrayOutputStream;
+import java.io.ByteArrayInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Enumeration;
+
+import org.openoffice.xmerge.ConvertData;
+import org.openoffice.xmerge.converter.xml.OfficeConstants;
+import org.openoffice.xmerge.converter.palm.PalmDB;
+import org.openoffice.xmerge.converter.palm.Record;
+import org.openoffice.xmerge.converter.palm.PalmDocument;
+import org.openoffice.xmerge.util.Debug;
+import org.openoffice.xmerge.converter.xml.sxc.SxcDocumentDeserializer;
+import org.openoffice.xmerge.converter.xml.sxc.SpreadsheetDecoder;
+import org.openoffice.xmerge.converter.xml.sxc.Format;
+
+/**
+ * This class is used by {@link
+ * org.openoffice.xmerge.converter.xml.sxc.SxcDocumentDeserializerImpl}
+ * SxcDocumentDeserializerImpl} to decode the MiniCalc format.
+ *
+ * @author Paul Rank
+ */
+final class MinicalcDecoder extends SpreadsheetDecoder {
+
+ /** MiniCalc WorkBook to store sheets. */
+ private Workbook wb;
+
+ /** MiniCalc sheet - only one sheet can be open at a time. */
+ private Worksheet ws;
+
+ /** The current cell - only one cell can be active at a time. */
+ private CellDescriptor cell = null;
+
+ /** Format object describing the current cell. */
+ private Format fmt = null;
+
+ /** The password for the WorkBook. */
+ private String password = null;
+
+ /** The number of rows in the current WorkSheet. */
+ private int maxRows = 0;
+
+ /** The number of columns in the current WorkSheet. */
+ private int maxCols = 0;
+
+ /** The names of the worksheets. */
+ private String[] worksheetNames = null;
+
+ /**
+ * Constructor creates a MiniCalc WorkBook.
+ *
+ * @param name The name of the WorkBook.
+ * @param password The password for the workBook.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ MinicalcDecoder(String name, String[] worksheetNames, String password) throws IOException {
+
+ super(name, password);
+
+ fmt = new Format();
+
+ this.password = password;
+ this.worksheetNames = worksheetNames;
+
+ try {
+
+ wb = new Workbook(name, password);
+
+ }
+ catch (JMCException e) {
+
+ Debug.log(Debug.ERROR, "MinicalcDecoder.constructor:" + e.getMessage());
+
+ throw new IOException(e.getMessage());
+ // e.printStackTrace();
+
+ }
+ }
+
+
+ /**
+ * This method takes a <code>ConvertData</code> as input and
+ * converts it into a MiniCalc WorkSheet. The WorkSheet is then
+ * added to the WorkBook.
+ *
+ * @param InputStream An <code>ConvertData</code> containing a
+ * MiniCalc WorkSheet.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ public void addDeviceContent(ConvertData cd) throws IOException {
+
+ try {
+ PalmDocument palmDoc;
+ int j = 0;
+
+ Enumeration e = cd.getDocumentEnumeration();
+ while(e.hasMoreElements()) {
+
+ palmDoc = (PalmDocument) e.nextElement();
+ // Convert PDB to WorkBook/WorkSheet format
+ PalmDB pdb = palmDoc.getPdb();
+
+ // This will be done at least once
+ String sheetName = worksheetNames[j];
+
+ // Get number of records in the pdb
+ int numRecords = pdb.getRecordCount();
+
+ // sheetName does not contain the WorkBook name, but we need the
+ // full name.
+ String fullSheetName = new String(wb.getWorkbookName() + "-" + sheetName);
+
+ // Create a new (empty) WorkSheet
+ ws = new Worksheet();
+
+ // Initialize the WorkSheet
+ ws.initWorksheet(fullSheetName, numRecords);
+
+ // Loop over the number of records in the PDB
+ for (int i = 0; i < numRecords; i++) {
+
+ // Read record i from the PDB
+ Record rec = pdb.getRecord(i);
+
+ byte cBytes[] = rec.getBytes();
+
+ // Create an InputStream
+ ByteArrayInputStream bis = new ByteArrayInputStream(cBytes);
+
+ // Get the size of the stream
+ int bisSize = cBytes.length;
+
+ // Add each record to the WorkSheet
+ ws.readNextRecord(bis, bisSize);
+ }
+
+
+ // Add the WorkSheet to the WorkBook
+ wb.addWorksheet(ws);
+ j++;
+ }
+ }
+ catch (JMCException e) {
+
+ Debug.log(Debug.ERROR, "MinicalcDecoder.addPDB:" + e.getMessage());
+
+ throw new IOException(e.getMessage());
+ }
+ }
+
+
+ /**
+ * This method returns the number of spreadsheets
+ * stored in the WorkBook.
+ *
+ * @return The number of sheets in the WorkBook.
+ */
+ public int getNumberOfSheets() {
+
+ return wb.getNumberOfSheets();
+ }
+
+
+ /**
+ * This method gets the requested WorkSheet from the
+ * WorkBook and sets it as the selected WorkSheet. All
+ * other "get" methods will now get data from this WorkSheet.
+ *
+ * @param sheetIndex The index number of the sheet to open.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ public void setWorksheet(int sheetIndex) throws IOException {
+
+ try {
+
+ ws = wb.getWorksheet(sheetIndex);
+
+ // Initialize access to the WorkSheet so that we can calculate
+ // the number of rows and columns
+ ws.initAccess(password);
+
+ maxRows = 0;
+ maxCols = 0;
+
+ while (goToNextCell()) {
+ maxRows = Math.max(maxRows, cell.getRowNumber());
+ maxCols = Math.max(maxCols, cell.getColNumber());
+ }
+
+ // Re-initialize access to the WorkSheet
+ ws.initAccess(password);
+
+ }
+ catch (JMCException e) {
+
+ Debug.log(Debug.ERROR, "MinicalcDecoder.setWorksheet:" + e.getMessage());
+
+ throw new IOException(e.getMessage());
+ // e.printStackTrace();
+
+ }
+ }
+
+
+ /**
+ * This method returns the name of the current spreadsheet.
+ *
+ * @return The name of the current WorkSheet.
+ */
+ public String getSheetName() {
+
+ String sheetName = ws.getName();
+
+ return sheetName;
+ }
+
+
+ /**
+ * This method gets the next cell from the WorkSheet
+ * and sets it as the selected cell. All other "get"
+ * methods will now get data from this cell.
+ *
+ * @return True if we were able to go to another cell
+ * in the sheet, false if there were no cells
+ * left.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ public boolean goToNextCell() throws IOException {
+
+ boolean gotCell = false;
+
+ try {
+ cell = ws.getNextCell();
+
+ if (cell != null) {
+ gotCell = true;
+ }
+
+ // As we read each cell, get its formatting info
+ readCellFormat();
+ }
+ catch (JMCException e) {
+
+ Debug.log(Debug.ERROR, "MinicalcDecoder.goToNextCell:" + e.getMessage());
+
+ throw new IOException(e.getMessage());
+ // e.printStackTrace();
+
+ }
+
+ return gotCell;
+ }
+
+
+ /**
+ * This method returns the row number of the current cell.
+ *
+ * @return The row number of the current cell. Returns
+ * -1 if no cell is currently selected.
+ */
+ public int getRowNumber() {
+
+ int row = -1;
+
+ if (cell != null) {
+
+ row = cell.getRowNumber();
+ }
+
+ return row;
+ }
+
+ /**
+ * This method returns the number of rows in the current sheet.
+ *
+ * @return The number of rows in the current sheet.
+ */
+ public int getNumberOfRows() {
+
+ return maxRows;
+ }
+
+ /**
+ * This method returns the number of columns in the current sheet.
+ *
+ * @return The number of columns in the current sheet.
+ */
+ public int getNumberOfColumns() {
+ return maxCols;
+ }
+
+
+ /**
+ * This method returns the col number of the current cell.
+ *
+ * @return The col number of the current cell. Returns
+ * -1 if no cell is currently selected.
+ */
+ public int getColNumber() {
+
+ int col = -1;
+
+ if (cell != null) {
+
+ col = cell.getColNumber();
+ }
+
+ return col;
+ }
+
+
+ /**
+ * This method returns the contents of the current cell.
+ *
+ * @return The contents of the current cell. Returns
+ * null if no cell is currently selected.
+ */
+ public String getCellContents() {
+
+ String contents = null;
+
+ if (cell != null) {
+ contents = cell.getCellContents();
+
+ // Active cell, but no content
+ if (contents == null)
+ return new String("");
+
+ // Does the cell contain a formula?
+ if (contents.startsWith("=")) {
+ contents = parseFormula(contents);
+ }
+ // Make sure that any MiniCalc peculiarities are stripped off
+ if (fmt.getCategory().equalsIgnoreCase(OfficeConstants.CELLTYPE_CURRENCY)) {
+ contents = currencyRemoveSign(contents);
+ }
+ else if (fmt.getCategory().equalsIgnoreCase(OfficeConstants.CELLTYPE_PERCENT)) {
+ contents = percentRemoveSign(contents);
+ }
+ else if (fmt.getCategory().equalsIgnoreCase(OfficeConstants.CELLTYPE_DATE)) {
+ contents = convertToStarDate(contents);
+ }
+ else if (fmt.getCategory().equalsIgnoreCase(OfficeConstants.CELLTYPE_TIME)) {
+ contents = convertToStarTime(contents);
+ }
+ }
+
+ return contents;
+ }
+
+ /**
+ * This method is meant to return the value of the formula cell. However
+ * in minicalc this value is not used so hence the stubbed function
+ *
+ * @return the value fo the formula cell
+ */
+ public String getCellValue() {
+ return null;
+ }
+
+ /**
+ * <p>This method takes a formula and parses it into
+ * StarOffice XML formula format.</p>
+ *
+ * <p>Many spreadsheets use ',' as a separator.
+ * StarOffice XML format uses ';' as a separator instead.</p>
+ *
+ * <p>Many spreadsheets use '!' as a separator when refencing
+ * a cell in a different sheet.</p>
+ *
+ * <blockquote>
+ * Example: =sheet1!A1
+ * </blockquote>
+ *
+ * <p>StarOffice XML format uses '.' as a separator instead.</p>
+ *
+ * <blockquote>
+ * Example: =sheet1.A1
+ * </blockquote>
+ *
+ * @param formula A formula string.
+ *
+ * @return A StarOffice XML format formula string.
+ */
+ protected String parseFormula(String formula) {
+
+ formula = formula.replace(',', ';');
+ formula = formula.replace('!', '.');
+
+ return formula;
+ }
+
+ /**
+ * <p>This method returns the type of the data in the current cell.</p>
+ *
+ * <p>Possible Data Types:</p>
+ *
+ * <ul><li>
+ * Percent - MiniCalc can store as a number or as a string.
+ *
+ * When stored as a string, the % sign is stored in the
+ * string . The MiniCalc format is "string".
+ * Example 10.1% is stored as the string "10.1%"
+ *
+ * When stored as a number, the decimal representation
+ * is stored. The MiniCalc format is "percentage".
+ * Example: 10.1% is stored as "0.101"
+ * </li><li>
+ * Currency - MiniCalc stores currency as a number with the format
+ * set to "currency".
+ * A user can also enter a value with a dollar sign
+ * (example $18.56) into MiniCalc and not set the format
+ * as currency. We treat this type of data as a
+ * currency data type.
+ * </li><li>
+ * Boolean - MiniCalc stores in a string as "true" or "false"
+ * </li><li>
+ *
+ * Date - MiniCalc stores a date in a string as either
+ * MM/DD/YY or MM/DD/YYYY. Any variation from the above
+ * format will not be considered a date.
+ * </li><li>
+ * Time - MiniCalc stores a time in a string as hh:mm:ss. Any
+ * variation from this format will not be considered a time.
+ * </li><li>
+ * Float - MiniCalc stores as a number and it is not percent
+ * or currency.
+ * </li><li>
+ * String - MiniCalc stores as a string (surprise). Doesn't parse
+ * to any of the other data types.
+ * </li><li>
+ * @return The type of the data in the current cell.
+ * </li></ul>
+ */
+ public String getCellDataType() {
+
+ boolean isNumber = false;
+
+ // Get format value set on the cell in MiniCalc
+ String format = getCellFormatType();
+
+ // Initialize the data type to the format
+ String type = format;
+
+ String contents = getCellContents();
+
+ if (contents != null) {
+
+ MinicalcDataString data = new MinicalcDataString(contents);
+
+ // Check if it is a formula
+ if (data.isFormula()) {
+ Debug.log(Debug.INFO, " " + contents + " Is a Function Format = "
+ + format + "\n");
+ return type;
+ }
+
+ try {
+ // Check to see if it is a number
+ Double d = Double.valueOf(contents);
+ isNumber = true;
+ Debug.log(Debug.INFO, " " + contents + " Is a Number Format = " + format);
+
+ } catch (NumberFormatException e) {
+ Debug.log(Debug.INFO, " " + contents + " Not a Number Format= " + format);
+ // no, it is not a number
+ isNumber = false;
+ }
+
+
+ if (isNumber) {
+
+ // Numbers are Float, Currency, and Percent
+ if (format.equals(OfficeConstants.CELLTYPE_CURRENCY)) {
+
+ type = OfficeConstants.CELLTYPE_CURRENCY;
+
+ } else if (format.equals(OfficeConstants.CELLTYPE_PERCENT)) {
+
+ type = OfficeConstants.CELLTYPE_PERCENT;
+
+ } else {
+
+ type = OfficeConstants.CELLTYPE_FLOAT;
+ }
+
+ } else if (data.isBoolean()) {
+
+ // Data is a Boolean type
+ type = OfficeConstants.CELLTYPE_BOOLEAN;
+
+ } else if (data.isDate()) {
+
+ // Data is a Date type
+ type = OfficeConstants.CELLTYPE_DATE;
+
+ } else if (data.isTime()) {
+
+ // Data is a Time type
+ type = OfficeConstants.CELLTYPE_TIME;
+
+ } else if (data.isPercent()) {
+
+ // Data is percent
+ type = OfficeConstants.CELLTYPE_PERCENT;
+
+ } else if (data.isCurrency()) {
+
+ // Data is a Currency type
+ type = OfficeConstants.CELLTYPE_CURRENCY;
+
+ } else {
+
+ // Data can't be float, since it isn't a number
+
+ // We've already tried parsing it as all other data
+ // types, the only remaining option is a string
+ type = OfficeConstants.CELLTYPE_STRING;
+ }
+ }
+
+ Debug.log(Debug.INFO, " TYPE = " + type + "\n");
+
+ return type;
+ }
+
+
+ /**
+ * This method returns the format of the data in the current cell.
+ *
+ * @return The format of the data in the current cell.
+ */
+ String getCellFormatType() {
+
+ // Set type to default data type
+ String type = OfficeConstants.CELLTYPE_FLOAT;
+
+ if (cell != null) {
+
+ // Get the attributes for the current cell
+ CellAttributes att = cell.getCellAttributes();
+
+ if (att != null) {
+
+ // Extract the format info from the attributes
+ long format = att.getFormat();
+
+ // The cell type is stored in bits 5-8
+ long cellType = format & 0x000000F0L;
+
+ // The number of decimal places is stored in bits 1-4
+ long decimals = format & 0x0000000FL;
+
+ if (cellType == JMCconstants.FF_FORMAT_GENERIC) {
+
+ // MiniCalc stores both Strings and Booleans
+ // in the generic type. We must check the contents
+ // to differentiate between the two.
+
+ // Get cell's contents
+ String contents = getCellContents();
+
+ if (contents.equalsIgnoreCase("false") ||
+ contents.equalsIgnoreCase("true")) {
+
+ type = OfficeConstants.CELLTYPE_BOOLEAN;
+
+
+ } else {
+
+ type = OfficeConstants.CELLTYPE_STRING;
+
+ }
+
+ } else if (cellType == JMCconstants.FF_FORMAT_DECIMAL) {
+
+ type = OfficeConstants.CELLTYPE_FLOAT;
+
+ } else if (cellType == JMCconstants.FF_FORMAT_TIME) {
+
+ type = OfficeConstants.CELLTYPE_TIME;
+
+ } else if (cellType == JMCconstants.FF_FORMAT_DATE) {
+
+ type = OfficeConstants.CELLTYPE_DATE;
+
+ } else if (cellType == JMCconstants.FF_FORMAT_CURRENCY) {
+
+ type = OfficeConstants.CELLTYPE_CURRENCY;
+
+ } else if (cellType == JMCconstants.FF_FORMAT_PERCENT) {
+
+ type = OfficeConstants.CELLTYPE_PERCENT;
+ }
+
+ }
+ }
+
+ return type;
+ }
+
+
+ /**
+ * This method takes a <code>String</code> that contains a
+ * currency value and removes the $ from the <code>String</code>.
+ * If the dollar sign is not the first or last character of the
+ * input <code>String</code>, the input <code>String</code> is
+ * simply returned.
+ *
+ * @param contents The input <code>String</code> from which to
+ * remove the dollar sign.
+ *
+ * @return The input <code>String</code> minus the dollar sign.
+ * If the input <code>String</code> did not begin or end
+ * with a dollar sign, contents is returned.
+ */
+ private String currencyRemoveSign(String contents) {
+ MinicalcDataString mcString = new MinicalcDataString(contents);
+ String currencyString = mcString.currencyRemoveSign();
+ return currencyString;
+ }
+
+
+ /**
+ * This method takes a <code>String</code> that contains a percent
+ * value and removes the % from the <code>String</code>. If the
+ * percent sign is not the last character of the input
+ * <code>String</code>, the input <code>String</code> is simply
+ * returned.
+ *
+ * @param contents The input String from which to remove the
+ * percent sign.
+ *
+ * @return The input <code>String</code> minus the percent sign.
+ * If the input <code>String</code> did not begin with
+ * a percent sign, contents is returned.
+ */
+ private String percentRemoveSign(String contents) {
+ MinicalcDataString mcString = new MinicalcDataString(contents);
+ String percentString = mcString.percentRemoveSign();
+ return percentString;
+ }
+
+
+ /**
+ * This method returns takes a <code>String</code> that contains
+ * a time value and converts it from MiniCalc format to StarOffice
+ * XML time format.
+ *
+ * @param contents The input <code>String</code> containing a
+ * MiniCalc time.
+ *
+ * @return The input <code>String</code> converted to StarOffice
+ * XML time format.
+ */
+ private String convertToStarTime(String contents) {
+ MinicalcDataString mcString = new MinicalcDataString(contents);
+ String timeString = mcString.convertToStarTime();
+ return timeString;
+ }
+
+ /**
+ * This method returns takes a <code>String</code> that contains
+ * a date value and converts it from MiniCalc format to StarOffice
+ * XML date format.
+ *
+ * @param contents The input <code>String</code> containing a
+ * MiniCalc date.
+ *
+ * @return The input <code>String</code> converted to StarOffice
+ * XML date format.
+ */
+ private String convertToStarDate(String contents) {
+ MinicalcDataString mcString = new MinicalcDataString(contents);
+ String dateString = mcString.convertToStarDate();
+ return dateString;
+ }
+
+
+ /**
+ * Return the Format object describing the active cell formatting.
+ *
+ * @return The Format object describing the active cell formatting.
+ */
+ public Format getCellFormat() {
+ return new Format(fmt);
+ }
+
+
+ /**
+ * Create the format data for the new cell.
+ */
+ private void readCellFormat() {
+ // Make sure there are no remnants from the last time
+ fmt.clearFormatting();
+
+ fmt.setCategory(getCellFormatType());
+
+ // TODO - Get any more formatting data here
+ }
+}
+
diff --git a/xmerge/source/minicalc/java/org/openoffice/xmerge/converter/xml/sxc/minicalc/MinicalcEncoder.java b/xmerge/source/minicalc/java/org/openoffice/xmerge/converter/xml/sxc/minicalc/MinicalcEncoder.java
new file mode 100644
index 000000000000..14e256918886
--- /dev/null
+++ b/xmerge/source/minicalc/java/org/openoffice/xmerge/converter/xml/sxc/minicalc/MinicalcEncoder.java
@@ -0,0 +1,582 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxc.minicalc;
+
+import jmc.Workbook;
+import jmc.Worksheet;
+import jmc.CellAttributes;
+import jmc.CellDescriptor;
+import jmc.JMCconstants;
+import jmc.JMCException;
+
+import java.awt.Color;
+
+import java.io.ByteArrayOutputStream;
+import java.io.ByteArrayInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+import org.openoffice.xmerge.converter.palm.Record;
+import org.openoffice.xmerge.util.Debug;
+import org.openoffice.xmerge.util.IntArrayList;
+
+import org.openoffice.xmerge.converter.xml.sxc.SpreadsheetEncoder;
+import org.openoffice.xmerge.converter.xml.sxc.Format;
+import org.openoffice.xmerge.converter.xml.OfficeConstants;
+
+/**
+ * This class is used by {@link
+ * org.openoffice.xmerge.converter.xml.sxc.SxcDocumentSerializerImpl
+ * SxcDocumentSerializerImpl} to encode the MiniCalc format.
+ *
+ * @author Paul Rank
+ */
+final class MinicalcEncoder extends SpreadsheetEncoder {
+
+ /** MiniCalc WorkBook to store sheets. */
+ private Workbook wb;
+
+ /** MiniCalc sheet - only one sheet can be open at a time. */
+ private Worksheet ws;
+
+ /**
+ * Estimate of the number of Palm pixels per character. Used for
+ * estimating the width of a cell on a Palm device.
+ */
+ private final static int pixelsPerChar = 6;
+
+ /**
+ * The minimum width (in pixels) that we allow a column to be set to
+ * on a Palm device.
+ */
+ private final static int minWidth = 10;
+
+ /**
+ * The maximum width (in pixels) that we allow a column to be set to
+ * on a Palm device.
+ */
+ private final static int maxWidth = 80;
+
+
+ /**
+ * Constructor creates a MiniCalc WorkBook.
+ *
+ * @param log Log object for logging.
+ * @param name The name of the WorkBook.
+ * @param password The password for the WorkBook.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ MinicalcEncoder(String name, String password) throws IOException {
+
+ super(name, password);
+
+ try {
+ wb = new Workbook(name, password);
+ }
+ catch (JMCException e) {
+ Debug.log(Debug.ERROR, "new Workbook threw exception:" + e.getMessage());
+ throw new IOException(e.getMessage());
+ }
+ }
+
+
+ /**
+ * This method creates a WorkSheet belonging to the
+ * WorkBook.
+ *
+ * @param sheetName The name of the WorkSheet.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ public void createWorksheet(String sheetName) throws IOException {
+
+ try {
+ ws = wb.createWorksheet(sheetName);
+ }
+ catch (JMCException e) {
+ Debug.log(Debug.ERROR, "wb.createWorksheet threw exception:" + e.getMessage());
+ throw new IOException(e.getMessage());
+ }
+ }
+
+
+ /**
+ * This method gets the number of sheets in the WorkBook.
+ *
+ * @return The number of sheets in the WorkBook.
+ */
+ public int getNumberOfSheets() {
+
+ int numSheets = wb.getNumberOfSheets();
+ return numSheets;
+ }
+
+
+ /**
+ * This method encodes the MiniCalc WorkBook information
+ * into an palm <code>Record</code> array in MiniCalc
+ * database format.
+ *
+ * @return Array of <code>Record</code> holding MiniCalc
+ * contents.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ public Record[] getRecords(int sheetID) throws IOException {
+
+ // Get the WorkSheet for the input sheetID
+ ws = wb.getWorksheet(sheetID);
+
+ // Need to call ws.initWrite() before we start querying the WorkSheet
+ try {
+ ws.initWrite();
+ }
+ catch (JMCException e) {
+ Debug.log(Debug.ERROR, "ws.initWrite in getRecords:" + e.getMessage());
+ throw new IOException(e.getMessage());
+ }
+
+ // Get the number of records in the WorkSheet
+ int numRecords = ws.getNumberOfRecords();
+
+ // Create the Record array
+ Record[] allRecords = new Record[numRecords];
+
+
+ // Get each record from the WorkSheet and store in allRecords[]
+ try {
+ for (int i = 0; i < allRecords.length; i++) {
+
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+
+ int length = ws.writeNextRecord(bos);
+
+ byte cBytes[] = bos.toByteArray();
+
+ allRecords[i] = new Record(cBytes);
+ }
+ }
+ catch (Exception e) {
+ Debug.log(Debug.ERROR, "ws.writeNextRecord in getRecords:" + e.getMessage());
+ throw new IOException(e.getMessage());
+ }
+
+ return allRecords;
+ }
+
+
+ /**
+ * A cell reference in a StarOffice formula looks like
+ * [.C2] (for cell C2). MiniCalc is expecting cell references
+ * to look like C2. This method strips out the braces and
+ * the period.
+ *
+ * @param formula A StarOffice formula <code>String</code>.
+ *
+ * @return A MiniCalc formula <code>String</code>.
+ */
+ protected String parseFormula(String formula) {
+
+ StringBuffer inFormula = new StringBuffer(formula);
+ StringBuffer outFormula = new StringBuffer();
+
+ boolean inBrace = false;
+ boolean firstCharAfterBrace = false;
+ boolean firstCharAfterColon = false;
+
+ int len = inFormula.length();
+
+ for (int in = 0; in < len; in++) {
+ switch (inFormula.charAt(in)) {
+ case '[':
+ // We are now inside a StarOffice cell reference.
+ // We also need to strip out the '['
+ inBrace = true;
+
+ // If the next character is a '.', we want to strip it out
+ firstCharAfterBrace = true;
+ break;
+
+ case ']':
+ // We are exiting a StarOffice cell reference
+ // We are stripping out the ']'
+ inBrace = false;
+ break;
+
+ case ':':
+ // We have a cell range reference.
+ // May need to strip out the leading '.'
+ if (inBrace)
+ firstCharAfterColon = true;
+ outFormula.append(inFormula.charAt(in));
+ break;
+
+ case '.':
+ if (inBrace == true) {
+ if (firstCharAfterBrace == false &&
+ firstCharAfterColon == false) {
+ // Not the first character after the open brace.
+ // We have hit a separator between a sheet reference
+ // and a cell reference. MiniCalc uses a ! as
+ // this type of separator.
+ outFormula.append('!');
+ }
+ else {
+ firstCharAfterBrace = false;
+ firstCharAfterColon = false;
+ // Since we are in a StarOffice cell reference,
+ // and we are the first character, we need to
+ // strip out the '.'
+ }
+ break;
+ } else {
+ // We hit valid data, lets add it to the formula string
+ outFormula.append(inFormula.charAt(in));
+ break;
+ }
+
+ case ';':
+ // StarOffice XML format uses ';' as a separator. MiniCalc (and
+ // many spreadsheets) use ',' as a separator instead.
+ outFormula.append(',');
+ break;
+
+ default:
+ // We hit valid data, lets add it to the formula string
+ outFormula.append(inFormula.charAt(in));
+
+ // Need to make sure that firstCharAfterBrace is not true.
+ firstCharAfterBrace = false;
+ break;
+ }
+ }
+
+ return outFormula.toString();
+ }
+
+ /**
+ * Add a cell to the current WorkSheet.
+ *
+ * @param row The row number of the cell.
+ * @param column The column number of the cell.
+ * @param fmt The <code>Format</code> object describing
+ * the appearance of this cell.
+ * @param cellContents The text or formula of the cell's contents.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ public void addCell(int row, int column, Format fmt, String cellContents) throws IOException {
+
+ CellAttributes ca = new CellAttributes(getFormat(fmt),
+ fmt.getForeground(),
+ fmt.getBackground());
+ if (cellContents.startsWith("=")) {
+ cellContents = parseFormula(cellContents);
+ Debug.log(Debug.INFO, "YAHOO Found Formula" + cellContents);
+ }
+
+ CellDescriptor cellDes = new CellDescriptor(row, column, ca, cellContents);
+
+ try {
+ ws.putCell(cellDes);
+ }
+ catch (JMCException jmce) {
+ Debug.log(Debug.ERROR, "ws.putCell threw exception: " + jmce.getMessage());
+ throw new IOException(jmce.getMessage());
+ }
+ }
+
+
+ /**
+ * Set the width of the columns in the WorkBook.
+ *
+ * @param columnWidths An <code>IntArrayList</code> of column
+ * widths.
+ */
+ public void setColumnWidths(IntArrayList columnWidths) throws IOException {
+ // Get the number of columns
+ int numColumns = columnWidths.size();
+
+ // Return if there are no columns in the listr
+ if (numColumns == 0) {
+ return;
+ }
+
+ // Need to set the FORM_FLAGS_NONDEFAULT flag for the column widths
+ // to be used in MiniCalc
+ long format = JMCconstants.FORM_FLAGS_NONDEFAULT;
+
+ CellAttributes ca = new CellAttributes(format);
+
+ try {
+ for (int i = 0; i < numColumns; i++) {
+ // Get the column width in Palm pixels
+ int width = columnWidths.get(i) * pixelsPerChar;
+
+ // Check limits on column width
+ if (width < minWidth) {
+ width = minWidth;
+ } else if (width > maxWidth) {
+ width = maxWidth;
+ }
+
+ // Add the column descriptor to the WorkSheet
+ ws.putColumn(i + 1, width, ca);
+ }
+ }
+ catch (JMCException jmce) {
+ Debug.log(Debug.ERROR, "ws.putColumn threw exception: " + jmce.getMessage());
+ throw new IOException(jmce.getMessage());
+ }
+ }
+
+
+ /**
+ * This method sets the format of a cell to <i>string</i>.
+ *
+ * @param format The cell format-may already contain display info,
+ * such as alignment or font type.
+ *
+ * @return The updated format of the cell.
+ */
+ private long setFormatString(long format) {
+
+ format = clearCellFormatType(format);
+
+ // Set format to generic, since MiniCalc does not have a string type.
+ format = format | JMCconstants.FF_FORMAT_GENERIC;
+
+ return format;
+ }
+
+
+ /**
+ * This method sets the format of a cell to <i>floating point</i>.
+ *
+ * @param format The cell format. May already contain
+ * display info, such as alignment or
+ * font type.
+ * @param decimalPlaces The number of decimal places to
+ * set in the floating point number.
+ *
+ * @return The updated format of the cell.
+ */
+ private long setFormatFloat(long format, int decimalPlaces) {
+
+ format = clearCellFormatType(format);
+
+ // Set format to floating point with correct number of decimal places
+ format = format | JMCconstants.FF_FORMAT_DECIMAL | decimalPlaces;
+
+ return format;
+ }
+
+
+ /**
+ * This method sets the format of a cell to <i>time</i>.
+ *
+ * @param format The cell format-may already contain display info,
+ * such as alignment or font type.
+ *
+ * @return The updated format of the cell.
+ */
+ private long setFormatTime(long format) {
+
+ format = clearCellFormatType(format);
+
+ // Set format to time.
+ format = format | JMCconstants.FF_FORMAT_TIME;
+
+ return format;
+ }
+
+
+ /**
+ * This method sets the format of a cell to <i>date</i>.
+ *
+ * @param format The cell format-may already contain display info,
+ * such as alignment or font type.
+ *
+ * @return The updated format of the cell.
+ */
+ private long setFormatDate(long format) {
+
+ format = clearCellFormatType(format);
+
+ // Set format to date.
+ format = format | JMCconstants.FF_FORMAT_DATE;
+
+ return format;
+ }
+
+
+ /**
+ * This method sets the format of a cell to <i>currency</i>.
+ *
+ * @param format The cell format-may already contain
+ * display info, such as alignment or
+ * font type.
+ * @param decimalPlaces The number of decimal places to set.
+ *
+ * @return The updated format of the cell.
+ */
+ private long setFormatCurrency(long format, int decimalPlaces) {
+
+ format = clearCellFormatType(format);
+
+ // Set format to Currency with correct number of decimal places
+ format = format | JMCconstants.FF_FORMAT_CURRENCY | decimalPlaces;
+
+ return format;
+ }
+
+
+ /**
+ * This method sets the format of a cell to <i>boolean</i>.
+ *
+ * @param format The cell format-may already contain display info,
+ * such as alignment or font type.
+ *
+ * @return The updated format of the cell.
+ */
+ private long setFormatBoolean(long format) {
+
+ format = clearCellFormatType(format);
+
+ // Set format to generic, since MiniCalc does not have a Boolean type.
+ format = format | JMCconstants.FF_FORMAT_GENERIC;
+
+ return format;
+ }
+
+
+ /**
+ * This method sets the format of a cell to <i>percent</i>.
+ *
+ * @param format The cell format-may already contain
+ * display info, such as alignment or
+ * font type.
+ * @param decimalPlaces The number of decimal places to set.
+ *
+ * @return The updated format of the cell.
+ */
+ private long setFormatPercent(long format, int decimalPlaces) {
+
+ format = clearCellFormatType(format);
+
+ // Set format to Percent with correct number of decimal places
+ format = format | JMCconstants.FF_FORMAT_PERCENT | decimalPlaces;
+
+ return format;
+ }
+
+
+ /**
+ * This method clears out the format bits associated with
+ * the type of data (<i>float</i>, <i>time</i>, etc...) in
+ * a cell.
+ *
+ * @param format The original format for the cell.
+ *
+ * @return The updated cell format with the bits associated
+ * with the type of data (float, time, etc...)
+ * zeroed out.
+ */
+ private long clearCellFormatType(long format) {
+
+ // First 4 bits are for the number of decimal places
+ // bits 5-8 are for the data format (float, time, etc...)
+
+ // Clear out first 8 bits
+ format = format & 0xFFFFFFFFFFFFFF00L;
+
+ return format;
+ }
+
+
+ /**
+ * Set a cell's formatting options via a separately create
+ * <code>Format</code> object.
+ *
+ * @param row The row number of the cell to be changed.
+ * @param column The column number of the cell to be changed.
+ * @param fmt Object containing formatting settings for
+ * this cell.
+ */
+ public void setCellFormat(int row, int column, Format fmt) {
+ }
+
+
+ /**
+ * Get the names of the sheets in the WorkBook.
+ *
+ * @param sheet The required sheet.
+ */
+ public String getSheetName(int sheet) {
+ return wb.getWorksheet(sheet).getName();
+ }
+
+
+ /*
+ * This method returns a MiniCalc style format from the
+ * <code>Format</code> object.
+ */
+ private long getFormat(Format fmt)
+ {
+ String category = fmt.getCategory();
+
+ if (category.equalsIgnoreCase(OfficeConstants.CELLTYPE_BOOLEAN)) {
+ return setFormatBoolean(0);
+ }
+ else if (category.equalsIgnoreCase(OfficeConstants.CELLTYPE_CURRENCY)) {
+ return setFormatCurrency(0, fmt.getDecimalPlaces());
+ }
+ else if (category.equalsIgnoreCase(OfficeConstants.CELLTYPE_DATE)) {
+ return setFormatDate(0);
+ }
+ else if (category.equalsIgnoreCase(OfficeConstants.CELLTYPE_FLOAT)) {
+ return setFormatFloat(0, fmt.getDecimalPlaces());
+ }
+ else if (category.equalsIgnoreCase(OfficeConstants.CELLTYPE_PERCENT)) {
+ return setFormatPercent(0, fmt.getDecimalPlaces());
+ }
+ else if (category.equalsIgnoreCase(OfficeConstants.CELLTYPE_STRING)) {
+ return setFormatString(0);
+ }
+ else if (category.equalsIgnoreCase(OfficeConstants.CELLTYPE_TIME)) {
+ return setFormatTime(0);
+ }
+ else {
+ // Should never get here, but just in case
+ System.out.println("XXXXX Formatting information not found");
+ return 0;
+ }
+ }
+}
+
diff --git a/xmerge/source/minicalc/java/org/openoffice/xmerge/converter/xml/sxc/minicalc/PluginFactoryImpl.java b/xmerge/source/minicalc/java/org/openoffice/xmerge/converter/xml/sxc/minicalc/PluginFactoryImpl.java
new file mode 100644
index 000000000000..037347d4c44c
--- /dev/null
+++ b/xmerge/source/minicalc/java/org/openoffice/xmerge/converter/xml/sxc/minicalc/PluginFactoryImpl.java
@@ -0,0 +1,129 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxc.minicalc;
+
+import org.openoffice.xmerge.ConvertData;
+import org.openoffice.xmerge.Document;
+import org.openoffice.xmerge.DocumentSerializer;
+import org.openoffice.xmerge.DocumentSerializerFactory;
+import org.openoffice.xmerge.DocumentDeserializer;
+import org.openoffice.xmerge.DocumentDeserializerFactory;
+import org.openoffice.xmerge.DocumentMerger;
+import org.openoffice.xmerge.ConverterCapabilities;
+import org.openoffice.xmerge.converter.xml.sxc.DocumentMergerImpl;
+import org.openoffice.xmerge.converter.xml.sxc.SxcPluginFactory;
+import org.openoffice.xmerge.converter.palm.PalmDocument;
+import org.openoffice.xmerge.util.registry.ConverterInfo;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * <p>MiniCalc implementation of the <code>PluginFactory</code>.
+ * This encapsulates conversion of StarCalc XML format to and from
+ * MiniCalc format.</p>
+ *
+ * <p>The superclass produces a particular
+ * {@link org.openoffice.xmerge.Document Document}
+ * object, i.e. {@link
+ * org.openoffice.xmerge.converter.xml.sxc.SxcDocument
+ * SxcDocument} that the converters in this class works with. Thus,
+ * this class only implements the methods that produces the converters,
+ * i.e. {@link
+ * org.openoffice.xmerge.DocumentSerializer
+ * DocumentSerializer} and {@link
+ * org.openoffice.xmerge.DocumentDeserializer
+ * DocumentDeserializer};
+ * as well as the {@link
+ * org.openoffice.xmerge.ConverterCapabilities
+ * ConverterCapabilities} object that is specific to this format
+ * conversion. That superclass also produces a {@link
+ * org.openoffice.xmerge.DocumentMerger DocumentMerger}
+ * object, i.e. {@link
+ * org.openoffice.xmerge.converter.xml.sxc.DocumentMergerImpl
+ * DocumentMergerImpl} which this class derives the functionality.</p>
+ */
+public final class PluginFactoryImpl extends SxcPluginFactory
+ implements DocumentDeserializerFactory, DocumentSerializerFactory {
+
+ /** ConverterCapabilities object for this type of conversion. */
+ private final static ConverterCapabilities converterCap =
+ new ConverterCapabilitiesImpl();
+
+
+ public PluginFactoryImpl(ConverterInfo ci) {
+ super(ci);
+ }
+
+
+ /**
+ * Returns an instance of <code>DocumentSerializerImpl</code>,
+ * which is an implementation of <code>DocumentSerializer</code>
+ * interface.
+ *
+ * @param doc <code>Document</code> object to be
+ * converted/serialized.
+ *
+ * @return A <code>DocumentSerializerImpl</code> object.
+ */
+ public DocumentSerializer createDocumentSerializer(Document doc) {
+
+ return new SxcDocumentSerializerImpl(doc);
+ }
+
+
+ /**
+ * Returns an instance of <code>DocumentDeserializerImpl</code>,
+ * which is an implementation of <code>DocumentDeserializer</code>
+ * interface.
+ *
+ * @param cd <code>ConvertData</code> object for reading data
+ * which will be converted back to a
+ * <code>Document</code> object.
+ *
+ * @return A <code>DocumentDeserializerImpl</code> object.
+ */
+ public DocumentDeserializer createDocumentDeserializer(ConvertData cd) {
+
+ return new SxcDocumentDeserializerImpl(cd);
+ }
+
+
+ public Document createDeviceDocument(String name, InputStream is)
+ throws IOException {
+
+ PalmDocument palmDoc = new PalmDocument(is);
+ return palmDoc;
+ }
+
+ public DocumentMerger createDocumentMerger(Document doc) {
+
+ DocumentMergerImpl merger = new DocumentMergerImpl(doc, converterCap);
+ return merger;
+ }
+}
+
diff --git a/xmerge/source/minicalc/java/org/openoffice/xmerge/converter/xml/sxc/minicalc/SxcDocumentDeserializerImpl.java b/xmerge/source/minicalc/java/org/openoffice/xmerge/converter/xml/sxc/minicalc/SxcDocumentDeserializerImpl.java
new file mode 100644
index 000000000000..61680e73f3a1
--- /dev/null
+++ b/xmerge/source/minicalc/java/org/openoffice/xmerge/converter/xml/sxc/minicalc/SxcDocumentDeserializerImpl.java
@@ -0,0 +1,138 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxc.minicalc;
+
+import org.openoffice.xmerge.converter.xml.sxc.SxcDocumentDeserializer;
+import org.openoffice.xmerge.converter.xml.sxc.SpreadsheetDecoder;
+import org.openoffice.xmerge.converter.palm.PalmDB;
+import org.openoffice.xmerge.ConvertData;
+import org.openoffice.xmerge.converter.palm.PalmDocument;
+
+import java.io.IOException;
+import java.util.Enumeration;
+
+/**
+ * <p>MiniCalc implementation of <code>DocumentDeserializer</code>
+ * for the {@link
+ * org.openoffice.xmerge.converter.xml.sxc.minicalc.PluginFactoryImpl
+ * PluginFactoryImpl}.</p>
+ *
+ * <p>This converts a set of files in MiniCalc PDB format to a StarOffice DOM.</p>
+ *
+ * @author Mark Murnane
+ */
+public final class SxcDocumentDeserializerImpl extends SxcDocumentDeserializer {
+
+ /**
+ * Creates new <code>SxcDocumentDeserializerImpl</code>.
+ *
+ * @param cd <code>ConvertData</code> Input data to convert.
+ */
+ public SxcDocumentDeserializerImpl(ConvertData cd) {
+ super(cd);
+ }
+
+
+ /**
+ * This method will be implemented by concrete subclasses and will
+ * return an application-specific decoder.
+ *
+ * @param workbook The WorkBook name.
+ * @param worksheetNames An array of WorkSheet names.
+ * @param password The password.
+ *
+ * @return An application-specific <code>SpreadsheetDecoder</code>.
+ */
+ public SpreadsheetDecoder createDecoder(String workbook,
+ String[] worksheetNames, String password) throws IOException {
+
+ return new MinicalcDecoder(workbook, worksheetNames, password);
+ }
+
+
+ /**
+ * This method will return the name of the WorkBook from the
+ * <code>ConvertData</code>. Allows for situations where the
+ * WorkBook name differs from the PDB name.
+ *
+ * Implemented in the Deserializer as the Decoder's constructor
+ * requires a name.
+ *
+ * @param cd The <code>ConvertData</code>.
+ *
+ * @return The name of the WorkBook.
+ */
+ protected String getWorkbookName(ConvertData cd)
+ throws IOException {
+
+ Enumeration e = cd.getDocumentEnumeration();
+ PalmDocument palmDoc = (PalmDocument) e.nextElement();
+ String workbookName = palmDoc.getName();
+
+ // Search for "-", which separates workbook from worksheet
+ int end = workbookName.indexOf("-");
+
+ if (end > 0) {
+ workbookName = workbookName.substring(0, end);
+ }
+
+ return workbookName;
+ }
+
+
+ /**
+ * This method will return an array of WorkSheet names from the
+ * <code>ConvertData</code>.
+ *
+ * @param cd The <code>ConvertData</code>.
+ *
+ * @return The name of the WorkSheet.
+ */
+ protected String[] getWorksheetNames(ConvertData cd)
+ throws IOException {
+ int numberOfPDBs = cd.getNumDocuments();
+ String worksheetName[] = new String[numberOfPDBs];
+ int i=0;
+ Enumeration e = cd.getDocumentEnumeration();
+ while (e.hasMoreElements()) {
+ PalmDocument palmDoc = (PalmDocument) e.nextElement();
+ worksheetName[i] = palmDoc.getName();
+
+ // Search for the "-", which seperates workbook from worksheet
+ int start = worksheetName[i].indexOf("-");
+
+ if (start != -1) {
+ worksheetName[i] = worksheetName[i].substring(start + 1);
+ }
+ i++;
+ }
+
+ return worksheetName;
+ }
+}
+
diff --git a/xmerge/source/minicalc/java/org/openoffice/xmerge/converter/xml/sxc/minicalc/SxcDocumentSerializerImpl.java b/xmerge/source/minicalc/java/org/openoffice/xmerge/converter/xml/sxc/minicalc/SxcDocumentSerializerImpl.java
new file mode 100644
index 000000000000..25ad6dda73f4
--- /dev/null
+++ b/xmerge/source/minicalc/java/org/openoffice/xmerge/converter/xml/sxc/minicalc/SxcDocumentSerializerImpl.java
@@ -0,0 +1,141 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxc.minicalc;
+
+import java.awt.Color;
+
+import org.w3c.dom.NodeList;
+import org.w3c.dom.Node;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Element;
+
+import java.io.IOException;
+
+import org.openoffice.xmerge.Document;
+import org.openoffice.xmerge.ConvertData;
+import org.openoffice.xmerge.ConvertException;
+import org.openoffice.xmerge.converter.palm.PalmDB;
+import org.openoffice.xmerge.converter.palm.Record;
+import org.openoffice.xmerge.converter.palm.PalmDocument;
+
+import jmc.JMCconstants;
+
+import org.openoffice.xmerge.converter.xml.sxc.Format;
+import org.openoffice.xmerge.converter.xml.sxc.SxcDocumentSerializer;
+
+/**
+ * <p>MiniCalc implementation of <code>SxcDocumentDeserializer</code>
+ * for the {@link
+ * org.openoffice.xmerge.converter.xml.sxc.minicalc.PluginFactoryImpl
+ * PluginFactoryImpl}.</p>
+ *
+ * <p>This converts StarOffice XML format to a set of files in
+ * MiniCalc PDB format.</p>
+ *
+ * @author Paul Rank
+ * @author Mark Murnane
+ */
+public final class SxcDocumentSerializerImpl extends SxcDocumentSerializer {
+
+
+ /**
+ * Constructor.
+ *
+ * @param document The <code>Document</code> to convert.
+ */
+ public SxcDocumentSerializerImpl(Document document) {
+ super(document);
+ }
+
+
+ public ConvertData serialize() throws ConvertException, IOException {
+
+
+ // Get the server side document name. This value should not
+ // contain a path or the file extension.
+ String docName = sxcDoc.getName();
+
+ // TODO - get real values for password when implemnted in XML
+ // Passwords are not currently stored in StarCalc XML format.
+ String password = null;
+
+ encoder = new MinicalcEncoder(docName, password);
+
+ // get dom document
+ org.w3c.dom.Document domDoc = sxcDoc.getContentDOM();
+
+ // Traverse to the office:body element.
+ // There should only be one.
+ NodeList list = domDoc.getElementsByTagName(TAG_OFFICE_BODY);
+ int len = list.getLength();
+
+ if (len > 0) {
+ Node node = list.item(0);
+ traverseBody(node);
+ }
+
+ // Get the number of sheets in the workbook
+ // This will equal the number of PDBs we need
+ ConvertData cd = new ConvertData();
+ int numSheets = encoder.getNumberOfSheets();
+
+ for (int i = 0; i < numSheets; i++) {
+
+ // Get records for sheet i
+ Record records[] = ((MinicalcEncoder) encoder).getRecords(i);
+
+ // Get the sheet name for sheet i
+ String fullSheetName = new String(docName
+ + "-"
+ + encoder.getSheetName(i));
+
+ // Create a PalmDB object
+ PalmDocument palmDoc = new PalmDocument(fullSheetName,
+ MinicalcConstants.CREATOR_ID,
+ MinicalcConstants.TYPE_ID, JMCconstants.AppVersion,
+ PalmDB.PDB_HEADER_ATTR_BACKUP, records);
+
+ cd.addDocument(palmDoc);
+ }
+
+
+ // OutputStream os = new FileOutputStream(docName);
+
+ //pdbSet.write(os);
+ //os.flush();
+
+ //ConvertDataEntry cde = new ConvertDataOutputStream(os, docName);
+ //cd.addCDE(cde);
+
+ return cd;
+ }
+
+
+
+}
+
diff --git a/xmerge/source/minicalc/java/org/openoffice/xmerge/converter/xml/sxc/minicalc/package.html b/xmerge/source/minicalc/java/org/openoffice/xmerge/converter/xml/sxc/minicalc/package.html
new file mode 100644
index 000000000000..2adb11ed36d4
--- /dev/null
+++ b/xmerge/source/minicalc/java/org/openoffice/xmerge/converter/xml/sxc/minicalc/package.html
@@ -0,0 +1,53 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<!--
+ #*************************************************************************
+ #
+ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+
+ Copyright 2000, 2010 Oracle and/or its affiliates.
+
+ OpenOffice.org - a multi-platform office productivity suite
+
+ This file is part of OpenOffice.org.
+
+ OpenOffice.org is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License version 3
+ only, as published by the Free Software Foundation.
+
+ OpenOffice.org is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License version 3 for more details
+ (a copy is included in the LICENSE file that accompanied this code).
+
+ You should have received a copy of the GNU Lesser General Public License
+ version 3 along with OpenOffice.org. If not, see
+ <http://www.openoffice.org/license.html>
+ for a copy of the LGPLv3 License.
+
+ #*************************************************************************
+ -->
+<html>
+<head>
+<title>org.openoffice.xmerge.converter.xml.sxc.minicalc package</title>
+</head>
+
+<body bgcolor="white">
+
+<p>Provides the tools for doing the conversion of StarWriter XML to
+and from MiniCalc format.</p>
+
+<p>It follows the {@link org.openoffice.xmerge} framework for the conversion process.</p>
+
+<p>Since it converts to/from a Palm application format, these converters
+follow the <a href=../../../../converter/palm/package-summary.html#streamformat>
+PalmDB stream format</a> for writing out to the Palm sync client or reading
+in from the Palm sync client.</p>
+
+<p>Note that <code>PluginFactoryImpl</code> also provides a
+<code>DocumentMerger</code> object, i.e. {@link org.openoffice.xmerge.converter.xml.sxw.aportisdoc.DocumentMergerImpl DocumentMergerImpl}.
+This functionality was derived from its superclass
+{@link org.openoffice.xmerge.converter.xml.sxw.SxwPluginFactory SxwPluginFactory}.</p>
+
+</body>
+</html>
diff --git a/xmerge/source/minicalc/makefile.mk b/xmerge/source/minicalc/makefile.mk
new file mode 100644
index 000000000000..fd05a5b21929
--- /dev/null
+++ b/xmerge/source/minicalc/makefile.mk
@@ -0,0 +1,33 @@
+#*************************************************************************
+#
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# Copyright 2000, 2010 Oracle and/or its affiliates.
+#
+# OpenOffice.org - a multi-platform office productivity suite
+#
+# This file is part of OpenOffice.org.
+#
+# OpenOffice.org is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License version 3
+# only, as published by the Free Software Foundation.
+#
+# OpenOffice.org is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License version 3 for more details
+# (a copy is included in the LICENSE file that accompanied this code).
+#
+# You should have received a copy of the GNU Lesser General Public License
+# version 3 along with OpenOffice.org. If not, see
+# <http://www.openoffice.org/license.html>
+# for a copy of the LGPLv3 License.
+#
+#*************************************************************************
+
+TARGET=minicalc
+PRJ=../..
+PRJNAME=xmerge
+
+.INCLUDE : ant.mk
+ALLTAR: ANTBUILD
diff --git a/xmerge/source/palmtests/README b/xmerge/source/palmtests/README
new file mode 100644
index 000000000000..924f32fe0824
--- /dev/null
+++ b/xmerge/source/palmtests/README
@@ -0,0 +1,50 @@
+The following is an outline of the usage of this test suite.
+
+Requirements
+^^^^^^^^^^^^
+The following are required for these qa scripts to run correctly.
+ 1. POSE: the Palm OS Emulator. This is available from the PalmOS website.
+ 2. A Palm pilot rom. Also available from Palm.
+ 3. Compiled xmerge jar files (xmerge.jar, aportisdoc.jar etc.)
+ 4. Xerces.jar: required by the xmerge framework. This is available from org.apache.com.
+
+
+
+Test directory Contents
+^^^^^^^^^^^^^^^^^^^^^^^
+This test environment consists on 3 directories.
+ 1. bin : This contains some helper scripts that are used by the test environment but can be used in a standalone fashion.
+ 2. qa : This directory contains the files necessary to run the POSE emulator and to compare this results of tests with a set of verified (golden-data) files.
+ 3. qa-wrapper: This directory contains some wrapper scripts and environment files, that allow a user to change the environment settings, without have to change the POSE control code itself.
+
+Setting up the environment
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+ The environment can be changes to reflect a particular users environment, by editing or creating an environment file. This files are usually kept in the qa-wrapper/env directory. These environment settings can then be used when running the scripts.
+
+Running the Scripts
+^^^^^^^^^^^^^^^^^^^
+ Once the environment file has been created, the test scripts can be run by executing the "run-convtest" script in the qa-wrapper/bin directory. This file takes the following arguments
+
+ run-convtest -env <ENVFILE> [-name RUNNAME]
+
+<ENVFILE> is the environment file to use
+optional <RUNNAME> This can be the name of the user running the scripts. This is used to name a directory for the test results to be kept in.
+
+ e.g. run-convtest -env ../env/master.env
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/xmerge/source/palmtests/bin/README b/xmerge/source/palmtests/bin/README
new file mode 100644
index 000000000000..36fbcc6e1298
--- /dev/null
+++ b/xmerge/source/palmtests/bin/README
@@ -0,0 +1,6 @@
+To run the spose script, you must set the following environmental variables:
+
+ POSE2_EXE = Directory and name of the POSE executable file.
+ POSE3_EXE = Directory and name of the POSE executable file.
+ POSE_PRC = Directory containing the PRC files to be loaded
+ into the emulator
diff --git a/xmerge/source/palmtests/bin/rd b/xmerge/source/palmtests/bin/rd
new file mode 100755
index 000000000000..db2dc56aee6b
--- /dev/null
+++ b/xmerge/source/palmtests/bin/rd
@@ -0,0 +1,24 @@
+#!/bin/ksh
+#
+# Directories commonly used by this script...
+#
+
+#export LBHOME=$ZPHOME/lib
+#export CVHOME=$ZPHOME/converters
+#export CVHOME=/export/home/test/qadir/qa-new/classes
+
+# Set up classpath to include needed ZenSync jars. Honor the users
+# CLASSPATH by leaving it first. This allows users to specify their
+# own versions of the jar files in their CLASSPATH if they wish to
+# override these defaults.
+#
+
+export CLASSPATH=$CLASSES_DIR/xerces.jar:$CLASSES_DIR/jmc.jar:$CLASSES_DIR/xmerge.jar:$CLASSES_DIR/minicalc.jar:$CLASSES_DIR/aportisdoc.jar:$CLASSES_DIR/wordsmith.jar
+
+echo "The classpath is $CLASSPATH"
+
+# Run the test driver, passing along args.
+#
+# java com.sun.star.comp.documentconversion.test.Driver $*
+java -cp $CLASSPATH org.openoffice.xmerge.test.Driver $*
+
diff --git a/xmerge/source/palmtests/bin/spose b/xmerge/source/palmtests/bin/spose
new file mode 100755
index 000000000000..29f6a9fe5218
--- /dev/null
+++ b/xmerge/source/palmtests/bin/spose
@@ -0,0 +1,108 @@
+#!/bin/perl
+#
+# spose - start pose
+#
+
+use Getopt::Std;
+
+# Location of needed files
+#
+$pose2_exe = $ENV{'POSE2_EXE'};
+$pose3_exe = $ENV{'POSE3_EXE'};
+$pose_prc = $ENV{'POSE_PRC'};
+
+
+if (getopts('23qmwo:r:d:v') != 1)
+{
+ &usage();
+}
+
+$apps_load = "";
+
+if ($opt_q)
+{
+ &add_app("$pose_prc/Quickword.PRC");
+}
+if ($opt_m)
+{
+ &add_app("$pose_prc/MiniCalc.prc");
+}
+if ($opt_w)
+{
+ &add_app("$pose_prc/WordSmith.PRC");
+}
+if ($opt_o)
+{
+ &add_app("$opt_o");
+}
+if ($opt_r)
+{
+ $run_prog .= "-run_app $opt_r";
+}
+if ($opt_d)
+{
+ $directory = $opt_d;
+ @files = `/bin/ls -1 $directory/*.pdb`;
+
+ for ($i=0; $i <= $#files; $i++)
+ {
+ $add_file = "$files[$i]";
+ chomp $add_file;
+ &add_app("$add_file");
+ }
+}
+
+if ($opt_3)
+{
+ $pose_exe = $pose3_exe;
+}
+else
+{
+ $pose_exe = $pose2_exe;
+}
+if ($pose_exe eq "")
+{
+ print "\nPose not found: Please set \n POSE2_EXE\n or POSE3_EXE\n";
+ exit 0;
+}
+if ($opt_v)
+{
+ print ("\n$pose_exe $apps_load $run_prog &\n\n");
+}
+else
+{
+ system ("$pose_exe $apps_load $run_prog &");
+}
+
+exit 0;
+
+sub usage
+{
+ print "\nUsage: getopt [ -m ] [ -q ] [ -w ] [ -o <PrcFile> ] [ -r <RunProg> ]\n";
+ print " -2 Runs pose version 3.2 [ current default ]\n";
+ print " -3 Runs pose version 3.3\n";
+ print " -d Load all PDB files in specified directory\n";
+ print " -m Load MiniCalc PRC file\n";
+ print " -q Load QuickWord PRC file\n";
+ print " -w Load WordSmith PRC file\n";
+ print " -o <PrcFile> Other PRC files to load\n";
+ print " -r <RunProg> Program to run on startup\n";
+ print " -v Display the command instead of running\n\n";
+ exit(-1);
+}
+
+sub add_app
+{
+ my $new_app = $_[0];
+
+ if ($apps_load ne "")
+ {
+ $apps_load .= ",";
+ }
+ else
+ {
+ $apps_load = "-load_apps ";
+ }
+
+ $apps_load .= "$new_app";
+}
diff --git a/xmerge/source/palmtests/bin/verify_sane.pl b/xmerge/source/palmtests/bin/verify_sane.pl
new file mode 100755
index 000000000000..dc085f3ddc44
--- /dev/null
+++ b/xmerge/source/palmtests/bin/verify_sane.pl
@@ -0,0 +1,110 @@
+#!/usr/bin/perl
+#########################################################################
+
+ #*************************************************************************
+ #
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# Copyright 2000, 2010 Oracle and/or its affiliates.
+#
+# OpenOffice.org - a multi-platform office productivity suite
+#
+# This file is part of OpenOffice.org.
+#
+# OpenOffice.org is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License version 3
+# only, as published by the Free Software Foundation.
+#
+# OpenOffice.org is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License version 3 for more details
+# (a copy is included in the LICENSE file that accompanied this code).
+#
+# You should have received a copy of the GNU Lesser General Public License
+# version 3 along with OpenOffice.org. If not, see
+# <http://www.openoffice.org/license.html>
+# for a copy of the LGPLv3 License.
+#
+ #*************************************************************************
+
+####################################################################
+# File Name: template.pl
+# Version : 1.0
+# Project : XMerge
+# Author : Brian Cameron
+# Date : 5th Sept. 2001
+#
+#
+# Takes x and y from the command line and taps the screen there.
+# Assumes pose is already running.
+#
+##########################################################################
+
+use POSIX "sys_wait_h"; # Need this for waitpid with WNOHANG
+use EmRPC; # EmRPC::OpenConnection, CloseConnection
+use EmFunctions;
+use EmUtils;
+
+if ($#ARGV != 0)
+{
+ print "\nUsage: $0 timeout\n\n";
+ exit -1;
+}
+
+$timeout = $ARGV[0];
+
+if (!defined($up_pid = fork()))
+{
+ print "ERROR, problem forking.\n"
+}
+elsif ($up_pid)
+{
+ print "\nChecking to see if pose is started properly.\n";
+
+ # Parent process
+ #
+ sleep($timeout);
+
+ waitpid($up_pid, WNOHANG);
+
+ if (kill(0, $up_pid))
+ {
+ print "Pose did not start successfully...\n";
+ kill(9, $up_pid);
+ exit(-1);
+ }
+ else
+ {
+ # The child process exited okay, so we know it will not
+ # hang...but the open_connection will just die if pose
+ # isn't started...so try it in the parent.
+ #
+ open_connection();
+ close_connection();
+
+ print "Verified pose started successfully...\n";
+ exit(0);
+ }
+}
+else
+{
+ # Child process - Try to open/close the connection. This
+ # can hang if pose did not start properly...
+ #
+ open_connection();
+ close_connection();
+}
+
+sub open_connection
+{
+ print "opening connection\n";
+ EmRPC::OpenConnection(6415, "localhost");
+}
+
+sub close_connection
+{
+ print "closing connection\n";
+ EmRPC::CloseConnection();
+}
+
diff --git a/xmerge/source/palmtests/qa-wrapper/bin/qa_comparator.pl b/xmerge/source/palmtests/qa-wrapper/bin/qa_comparator.pl
new file mode 100755
index 000000000000..6cc49da3570b
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/bin/qa_comparator.pl
@@ -0,0 +1,257 @@
+#!/usr/bin/perl
+#########################################################################
+
+ #*************************************************************************
+ #
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# Copyright 2000, 2010 Oracle and/or its affiliates.
+#
+# OpenOffice.org - a multi-platform office productivity suite
+#
+# This file is part of OpenOffice.org.
+#
+# OpenOffice.org is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License version 3
+# only, as published by the Free Software Foundation.
+#
+# OpenOffice.org is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License version 3 for more details
+# (a copy is included in the LICENSE file that accompanied this code).
+#
+# You should have received a copy of the GNU Lesser General Public License
+# version 3 along with OpenOffice.org. If not, see
+# <http://www.openoffice.org/license.html>
+# for a copy of the LGPLv3 License.
+#
+ #*************************************************************************
+
+$compare_home = $ENV{'QA_COMPARATOR_HOME'};
+
+if ($ENV{'CLASSPATH'})
+{
+ $classpath_val = "$compare_home:$ENV{'CLASSPATH'}";
+}
+else
+{
+ $classpath_val = "$compare_home";
+}
+
+print "classpath is $classpath_val\n";
+
+$list_file="";
+$orig_dir="";
+$new_dir="";
+$diff_type="";
+
+####### BEGIN MAIN ##############
+$cmdline_len = @ARGV;
+if ($cmdline_len <= 0)
+{
+ print_usage();
+ exit (0);
+}
+
+process_cmdline(@ARGV);
+print_env();
+open (LOGFILE, ">$logfile") || die "Cannot open log file $logfile";
+if ($test_list ne "")
+{
+ open (TESTLIST, $test_list) || die "Couldn't open diff list file $test_list";
+
+ while (<TESTLIST>)
+ {
+ chomp $_;
+ process_diff(get_file_title($_));
+ }
+}
+close TESTLIST;
+close LOGFILE;
+
+####### END MAIN ##############
+
+sub process_diff
+{
+# $_[0] =~ tr/A-Z/a-z/;
+
+ # chdir to the output directory so the temporary files created by
+ # the java programs are put in the right place.
+ #
+ chdir ($xml_new);
+
+ if ($diff_type eq "xml")
+ {
+ # Ugly hack, probably a way to tell xerces directly that the dtd's
+ # are in $compare_home/dtd.
+ #
+ `cp $compare_home/dtd/* $xml_new`;
+
+# $cmd = "java -classpath $classpath_val XmlWrapper $xml_orig/$_[0].sxw $xml_new/$_[0].sxw";
+ $cmd = "java -classpath $classpath_val XmlWrapper $xml_orig/$_[0] $xml_new/$_[0]";
+ print "Executing: $cmd\n";
+ $val = system($cmd)/256;
+ if ($val == 2)
+ {
+# print LOGFILE "$_[0]|TRUE|$xml_orig/$_[0].sxw|$xml_new/$_[0].sxw\n";
+ print LOGFILE "$_[0]|TRUE|$xml_orig/$_[0]|$xml_new/$_[0]\n";
+ }
+ elsif($val == 3)
+ {
+# print LOGFILE "$_[0]|FALSE|$xml_orig/$_[0].sxw|$xml_new/$_[0].sxw\n";
+ print LOGFILE "$_[0]|FALSE|$xml_orig/$_[0]|$xml_new/$_[0]\n";
+ }
+ else
+ {
+# print LOGFILE "$_[0]|ERROR|$xml_orig/$_[0].sxw|$xml_new/$_[0].sxw\n";
+ print LOGFILE "$_[0]|ERROR|$xml_orig/$_[0]|$xml_new/$_[0]\n";
+ }
+ }
+ elsif ($diff_type eq "pdb")
+ {
+# $cmd = "java -classpath $classpath_val SimplePdbCompare $pdb_orig/$_[0].pdb $pdb_new/$_[0].pdb\n";
+ $cmd = "java -classpath $classpath_val SimplePdbCompare $pdb_orig/$_[0] $pdb_new/$_[0]\n";
+ print "Executing: $cmd\n";
+ $val = system($cmd)/256;
+ if ($val == 2)
+ {
+# print LOGFILE "$_[0]|TRUE|$pdb_orig/$_[0].pdb|$pdb_new/$_[0].pdb\n";
+ print LOGFILE "$_[0]|TRUE|$pdb_orig/$_[0]|$pdb_new/$_[0]\n";
+ }
+ elsif($val == 3)
+ {
+# print LOGFILE "$_[0]|FALSE|$pdb_orig/$_[0].pdb|$pdb_new/$_[0].pdb\n";
+ print LOGFILE "$_[0]|FALSE|$pdb_orig/$_[0]|$pdb_new/$_[0]\n";
+ }
+ else
+ {
+# print LOGFILE "$_[0]|ERROR|$pdb_orig/$_[0].pdb|$pdb_new/$_[0].pdb\n";
+ print LOGFILE "$_[0]|ERROR|$pdb_orig/$_[0]|$pdb_new/$_[0]\n";
+ }
+ }
+ else
+ {
+ die "Don't understand test type of $diff_type.";
+ }
+}
+
+sub process_cmdline
+{
+ foreach $i (@_)
+ {
+ @arg= split('=', $i);
+ @arg[0] =~ tr/A-Z/a-z/;
+
+ if (@arg[0] eq "-pdb-orig")
+ {
+ $pdb_orig=$arg[1];
+ }
+ elsif (@arg[0] eq "-pdb-new")
+ {
+ $pdb_new=$arg[1];
+ }
+ elsif (@arg[0] eq "-xml-orig")
+ {
+ $xml_orig=$arg[1];
+ }
+ elsif (@arg[0] eq "-xml-new")
+ {
+ $xml_new=$arg[1];
+ }
+ elsif (@arg[0] eq "-env")
+ {
+ set_env_from_props($arg[1]);
+ }
+ elsif (@arg[0] eq "-list")
+ {
+ $test_list = $arg[1];
+ }
+ elsif (@arg[0] eq "-one")
+ {
+ $infile = $arg[1];
+ }
+ elsif (@arg[0] eq "-type")
+ {
+ $diff_type = $arg[1];
+ chomp $diff_type;
+ }
+ elsif (@arg[0] eq "-log")
+ {
+ $logfile = $arg[1];
+ }
+ else
+ {
+ print_usage();
+ die "Incorrect command line. Don't understand $i";
+ }
+ }
+}
+
+sub set_env_from_props
+{
+ open(PROPSFILE, $_[0]) || die "Could not open properties file";
+
+ while (<PROPSFILE>)
+ {
+ chomp $_;
+ @arg = split('=', $_);
+ @arg[0] =~ tr/a-z/A-Z/;
+ $len = @arg;
+ if ($len != 2)
+ {
+ die "Malformed property in $ARGV[0]";
+ }
+
+ if (@arg[0] eq "PDB_ORIG")
+ {
+ $pdb_orig=$arg[1];
+ }
+ elsif (@arg[0] eq "PDB_NEW")
+ {
+ $pdb_new=$arg[1];
+ }
+ elsif (@arg[0] eq "XML_ORIG")
+ {
+ $xml_orig=$arg[1];
+ }
+ elsif (@arg[0] eq "XML_NEW")
+ {
+ $xml_new=$arg[1];
+ }
+
+ }
+ close PROPSFILE;
+}
+
+sub print_usage
+{
+ print "Usage : compartor.pl - compare Office or pdb files\n";
+ print "\t-one=<file> :\t\t individual test case file to run\n";
+ print "\t-list=<file> :\t\t list of test case files\n";
+ print "\t-env=<file> :\t\t Properites like file defining env\n";
+ print "\t-pdb-orig=<path> :\t directory to hold original pdb files\n";
+ print "\t-pdb-new=<path> :\t directory to hold new pdb files\n";
+ print "\t-xml-orig=<path> :\t directory to hold original office documents\n";
+ print "\t-xml-new=<path> :\t directory to hold new office documents\n";
+ print "\t-type=<xml|pdb> :\t Invokes the merge option when converting\n";
+ print "\t-log=<logfile> :\t Save results to logfile.\n";
+}
+
+sub print_env
+{
+ print "Using the following environment:\n";
+ print "\tPDB_ORIG = $pdb_orig\n";
+ print "\tPDB_NEW = $pdb_new\n";
+ print "\tXML_ORIG = $xml_orig\n";
+ print "\tXML_NEW = $xml_new\n\n";
+}
+
+sub get_file_title
+{
+ @paths = split('\/', $_[0]);
+ $len = @paths;
+ return @paths[$len-1];
+# @names = split('\.', @paths[$len-1]);
+# return $names[0];
+}
diff --git a/xmerge/source/palmtests/qa-wrapper/bin/qa_test_driver.pl b/xmerge/source/palmtests/qa-wrapper/bin/qa_test_driver.pl
new file mode 100755
index 000000000000..fd57512fd171
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/bin/qa_test_driver.pl
@@ -0,0 +1,846 @@
+#!/usr/bin/perl
+#########################################################################
+
+ #*************************************************************************
+ #
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# Copyright 2000, 2010 Oracle and/or its affiliates.
+#
+# OpenOffice.org - a multi-platform office productivity suite
+#
+# This file is part of OpenOffice.org.
+#
+# OpenOffice.org is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License version 3
+# only, as published by the Free Software Foundation.
+#
+# OpenOffice.org is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License version 3 for more details
+# (a copy is included in the LICENSE file that accompanied this code).
+#
+# You should have received a copy of the GNU Lesser General Public License
+# version 3 along with OpenOffice.org. If not, see
+# <http://www.openoffice.org/license.html>
+# for a copy of the LGPLv3 License.
+#
+ #*************************************************************************
+
+####################################################################
+# File Name: test_driver.pl
+# Version : 1.0
+# Project : Xmerge
+# Author : Brian Cameron
+# Date : 5th Sept. 2001
+#
+#
+# This script does the following:
+#
+# Processes the input file, and runs the tests specified in that
+# file. This will do the following for each test:
+#
+# 1. Convert a file from XML to PDB format
+# 2. Starts up the Palm OS emulator with the appropriate program
+# running and the converted file loaded the program.
+# 3. Makes automated changes as specified in the inputfile to
+# this script..
+# 4. Returns to the main applications window.
+#
+# Parameter
+# Filename to convert and change
+#
+##########################################################################
+
+# Turn on auto-flushing
+#
+$|=1;
+
+use EmRPC;
+
+# Directory where converterlib is located...
+#
+#use lib "/export/home/test/qadir/qa/lib";
+use lib $ENV{'QA_LIB_HOME'};
+use converterlib;
+
+#-------------------- Start of main script ------------------------------------
+
+# Environmental Settings
+
+$pose_exe = "";
+$pose_prc = "";
+$test_list = "";
+$infile = "";
+$merge_opt = 0;
+# if testcase hasn't completed in 10 mins, then kill it off
+$testcase_timeout=600;
+
+# You may need to change this from the default if your pose emulator
+# starts faster or slower than mine.
+#
+if ($ENV{'POSE_TIMEOUT'})
+{
+ $pose_timeout = "$ENV{'POSE_TIMEOUT'}";
+}
+else
+{
+ $pose_timeout = 15;
+}
+
+$cmdline_len = @ARGV;
+if ($cmdline_len <= 0)
+{
+ print_usage();
+ exit (0);
+}
+
+&process_cmdline(@ARGV);
+&print_env();
+&verify_env_options();
+
+# Make the output directories with timestamps included in the
+# directory names.
+#
+mkdir $pdb_orig, 0777 || die "can not create directory <$pdb_orig>.";
+`chmod 777 $pdb_orig`;
+mkdir $pdb_new, 0777 || die "can not create directory <$pdb_new>.";
+`chmod 777 $pdb_new`;
+mkdir $xml_new, 0777 || die "can not create directory <$xml_new>.";
+`chmod 777 $xml_new`;
+
+&verify_prcs_exist("DBExporter.prc");
+
+if ($test_list ne "")
+{
+ open (TESTLIST, $test_list) || die "Couldn't open testcase list file $test_list";
+
+ while (<TESTLIST>)
+ {
+ &process_testcase($_);
+ }
+}
+elsif ($infile ne "")
+{
+ if (!defined($child_pid = fork()))
+ {
+ # there was an error forking a process
+ print "ERROR: Unable to fork process\n";
+ die "ERROR: Unable to fork process\n";
+ }
+ elsif ($child_pid)
+ {
+ # this is the parent process
+ # run the actual test here
+print "********\tPARENT (pid = $$): process_testcase...\n";
+ &process_testcase($infile);
+print "********\tPARENT (pid = $$): ...process_testcase finished normally\n";
+
+ # test finished normally, so kill the monitor
+ # that is running in the child process
+print "********\tPARENT (pid = $$): kill child process ($child_pid)\n";
+print "********\tPARENT Before:\n";
+system( "/usr/bin/ptree" );
+ kill( $child_pid );
+ kill( 9, $child_pid );
+print "********\tPARENT After:\n";
+system( "/usr/bin/ptree" );
+ }
+ else
+ {
+print "********\tCHILD (pid = $$): sleep for $testcase_timeout seconds\n";
+ # this is the child process
+ # wait on the test running in the parent, and
+ # kill it if it hasn't finished on time
+ sleep( $testcase_timeout );
+
+ # if the parent hasn't killed this process before it
+ # gets here, then it's probably hung, so we need to
+ # kill it.
+ print "********\tCHILD (pid = $$): TEST HUNG? still "
+ ."running after [$testcase_timeout] seconds - "
+ ."need to kill test process\n";
+ $parent = getppid;
+
+ if ( $parent != 1 ) {
+ print "********\nCHILD (pid = $$): Killing process ($parent)\n";
+ kill( $parent );
+ kill( 9, $parent );
+ } else {
+ # If we cannot get the ppid, then the parent might
+ # have died abnormally, before it got a chance to
+ # kill this (child) process.
+ print "********\nCHILD (pid = $$): cannot determine ppid - "
+ ."terminating\n";
+system( "/usr/bin/ptree" );
+ exit(2);
+ }
+
+ exit(1);
+ }
+}
+else
+{
+ die ("You didn't supply any test cases to process");
+}
+
+print "Finished.\n";
+exit(0);
+
+#-------------------- End of main script ----------------------------------------
+
+#--------------------------------------------------------------------------------
+# Various sub routines
+#--------------------------------------------------------------------------------
+
+# process_testcase
+# infile - test case file name
+#
+# This is the main driver function
+# Opens the infile, reads it in parses it, runs the appropriate conversion
+# starts pose and load the file into the emulator. It launches the
+# appropriate editor and then runs the commands specified in the test case.
+# It then exports the file and saves it locally. Finally it is converted
+# back to the original office format.
+#
+sub process_testcase
+{
+ my $infile = $_[0];
+ my $convert_file = "";
+ my $rc;
+
+ # Process the inputfile
+ #
+ open (INFILE, $infile) || die "Failed to open test case <$infile>";
+
+ $running_testtype = "";
+
+ # Process the input file.
+ #
+ while ($c_inline = <INFILE>)
+ {
+ chomp $c_inline;
+ @entry = split('\|', $c_inline);
+
+ # Process TEST
+ #
+ if ($c_inline =~ /^ *#/ || $c_inline =~ /^[ \t]*$/)
+ {
+ # skip comments and blank lines.
+ #
+ next;
+ }
+ elsif ("$entry[0]" eq "TEST")
+ {
+ # Close the test if one is running.
+ #
+ &close_program($convert_file);
+ $running_testtype = "";
+
+ $valid_test = 0;
+
+ if ($#entry != 3)
+ {
+ print "\nERROR, $entry[0] invalid number of arguments\n\n";
+ }
+ else
+ {
+ # Start the test.
+ #
+ print "\nStarting test: $entry[1]\n";
+ $convert_file = $entry[3];
+
+ if ("$entry[2]" =~ /[Qq][Uu][Ii][Cc][Kk][Ww][Oo][Rr][Dd]/)
+ {
+ $xml_extension = "sxw";
+ $convert_to = "application/x-aportisdoc";
+
+ # Convert XML file to pdb format.
+ #
+ $rc = &convert_to_pdb("$xml_orig", $convert_file, $xml_extension ,
+ $convert_to,"$pdb_orig");
+ if ($rc != 0)
+ {
+ print "\nERROR, problem converting file $convert_file\n\n";
+ }
+ else
+ {
+ # Start pose
+ #
+ $rc = &start_pose("$pose_exe",
+ "$pose_prc/Quickword.PRC,$pose_prc/DBExporter.prc,$pdb_orig/$convert_file.pdb",
+ "Quickword", $pose_timeout);
+
+ if ($rc == 0)
+ {
+ &start_quickword();
+ $valid_test = 1;
+ $running_testtype = "QUICKWORD";
+ print "\npose launched, begin automated test sequence for QuickWord\n";
+ }
+ else
+ {
+ &kill_pose();
+ $running_testtype = "";
+ }
+ }
+ }
+ elsif ("$entry[2]" =~ /[Mm][Ii][Nn][Ii][Cc][Aa][Ll][Cc]/)
+ {
+ $xml_extension = "sxc";
+ $convert_to = "application/x-minicalc";
+
+ # Convert XML file to pdb format.
+ #
+ $rc = &convert_to_pdb("$xml_orig", $convert_file,
+ $xml_extension, $convert_to,"$pdb_orig");
+ if ($rc != 0)
+ {
+ print "\nERROR, problem converting file $convert_file\n\n";
+ }
+ else
+ {
+ # Get minicalc PDB file names, since an SXC file can
+ # be converted to more than one.
+ #
+ $pdb_files="";
+ $i = 1;
+ while (-f "$pdb_orig/$convert_file-Sheet$i.pdb")
+ {
+ if ($i > 1)
+ {
+ $pdb_files .= ",";
+ }
+ $pdb_files .= "$pdb_orig/$convert_file-Sheet$i.pdb";
+ $i++;
+ }
+ $number = $i-1;
+
+ # Start pose
+ #
+ $rc = &start_pose("$pose_exe",
+ "$pose_prc/MiniCalc.prc,$pose_prc/DBExporter.prc,$pdb_files",
+ "MiniCalc", $pose_timeout);
+
+ if ($rc == 0)
+ {
+ &start_minicalc();
+ $valid_test = 1;
+ $running_testtype = "MINICALC";
+ print "pose launched, begin automated test sequence for MiniCalc\n";
+ }
+ else
+ {
+ &kill_pose();
+ $running_testtype = "";
+ }
+ }
+ }
+ else
+ {
+ print "\nERROR, invalid extension <$entry[2]>\n\n";
+ }
+ }
+ }
+
+ # Process DB_EXPORT
+ #
+ elsif ("$entry[0]" eq "DB_EXPORT")
+ {
+ if ($#entry != 1)
+ {
+ print "\nERROR, $entry[0] invalid number of arguments\n\n";
+ }
+ else
+ {
+ &db_export($entry[1]);
+ }
+ }
+
+ # Process TAP_APPLICATIONS
+ #
+ elsif ("$entry[0]" eq "TAP_APPLICATIONS")
+ {
+ if ($#entry != 0)
+ {
+ print "\nERROR, $entry[0] invalid number of arguments\n\n";
+ }
+ else
+ {
+ &tap_applications(0);
+ }
+ }
+
+ # Process ENTER_STRING_AT_LOCATION
+ #
+ elsif ("$entry[0]" eq "ENTER_STRING_AT_LOCATION")
+ {
+ if ($#entry != 3)
+ {
+ print "\nERROR, $entry[0] invalid number of arguments\n\n";
+ }
+ elsif ($valid_test == 0)
+ {
+ print "\nERROR, can not process $entry[0] for invalid test\n\n";
+ }
+ else
+ {
+ &enter_string_at_location($entry[1], $entry[2],
+ $entry[3], $running_testtype);
+ }
+ }
+
+ # Process TAP_PEN
+ #
+ elsif ("$entry[0]" eq "TAP_PEN")
+ {
+ if ($#entry != 2)
+ {
+ print "\nERROR, $entry[0] invalid number of arguments\n\n";
+ }
+ elsif ($valid_test == 0)
+ {
+ print "\nERROR, can not process $entry[0] for invalid test\n\n";
+ }
+ else
+ {
+ &pose_tap_pen($entry[1], $entry[2], 0);
+ }
+ }
+
+ # Process TAP_BUTTON
+ #
+ elsif ("$entry[0]" eq "TAP_BUTTON")
+ {
+ if ($#entry != 1)
+ {
+ print "\nERROR, $entry[0] invalid number of arguments\n\n";
+ }
+ elsif ($valid_test == 0)
+ {
+ print "\nERROR, can not process $entry[0] for invalid test\n\n";
+ }
+ else
+ {
+ &pose_tap_button($entry[1], 0);
+ }
+ }
+
+ # Process TAP_PEN_HARD
+ #
+ elsif ("$entry[0]" eq "TAP_PEN_HARD")
+ {
+ if ($#entry != 2)
+ {
+ print "\nERROR, $entry[0] invalid number of arguments\n\n";
+ }
+ elsif ($valid_test == 0)
+ {
+ print "\nERROR, can not process $entry[0] for invalid test\n\n";
+ }
+ else
+ {
+ &pose_tap_pen_hard($entry[1],$entry[2], 0);
+ }
+ }
+
+
+ # Process SLEEP
+ #
+ elsif ("$entry[0]" eq "SLEEP")
+ {
+ if ($#entry != 1)
+ {
+ print "\nERROR, $entry[0] invalid number of arguments\n\n";
+ }
+ else
+ {
+ &pose_sleep($entry[1]);
+ }
+ }
+
+ # Process MINICALC_ENTER_CELL
+ #
+ elsif ("$entry[0]" eq "MINICALC_ENTER_CELL")
+ {
+ if ($#entry != 3)
+ {
+ print "\nERROR, $entry[0] invalid number of arguments\n\n";
+ }
+ elsif ($valid_test == 0)
+ {
+ print "\nERROR, can not process $entry[0] for invalid test\n\n";
+ }
+ else
+ {
+ &minicalc_enter_cell($entry[1], $entry[2], $entry[3]);
+ }
+ }
+
+ # Process QUICKWORD_FIND_REPLACE
+ #
+ elsif ("$entry[0]" eq "QUICKWORD_FIND_REPLACE")
+ {
+ if ($#entry != 2)
+ {
+ print "\nERROR, $entry[0] invalid number of arguments\n\n";
+ }
+ elsif ($valid_test == 0)
+ {
+ print "\nERROR, can not process $entry[0] for invalid test\n\n";
+ }
+ else
+ {
+ &quickword_find_replace($entry[1], $entry[2]);
+ }
+ }
+ else
+ {
+ print "\nERROR, invalid line <$c_inline>\n";
+ }
+ }
+
+ &close_program($convert_file);
+}
+
+# close_program
+# convert_file - file to export
+#
+# closes the program running in pose and kills pose
+#
+sub close_program
+{
+ my $convert_file = $_[0];
+
+ if ($running_testtype eq "QUICKWORD")
+ {
+ print "QuickWord test completed.\n";
+ &close_program_quickword($convert_file);
+ }
+ elsif ($running_testtype eq "MINICALC")
+ {
+ print "MiniCalc test completed.\n";
+ &close_program_minicalc($convert_file, $number);
+ }
+}
+
+# close_program_quickword
+# convert_file - file to export
+#
+# Closes quickword and kills pose
+#
+sub close_program_quickword
+{
+ my $convert_file = $_[0];
+ my $error_file = "./error.txt";
+ my $rc;
+
+ &close_quickword();
+
+ &db_export($convert_file);
+ print "Moving /tmp/$convert_file.pdb to $pdb_new\n";
+ `mv /tmp/$convert_file.pdb $pdb_new`;
+ `chmod 666 $pdb_new/$convert_file.pdb`;
+
+ &close_connection(1);
+ &kill_pose();
+ print "\nFinishing test...\n";
+
+ # The path of where to put the error file should be specified
+ # in the properties file. Not sure if it is really necessary
+ # to put this out to a separate file. STDOUT should be fine.
+ #
+ $rc = &convert_to_xml($xml_new, $xml_orig,
+ "$pdb_new/$convert_file.pdb", "application/x-aportisdoc" ,
+ "sxw", $convert_file, $merge_opt);
+ if ($rc != 0)
+ {
+ print "\nERROR, problem converting file $pdb_new/$convert_file.pdb\n\n";
+ }
+}
+
+# close_program_minicalc
+# convert_file - file to export
+#
+# Closes minicalc and kills pose
+#
+sub close_program_minicalc
+{
+ my $convert_file = $_[0];
+ my $num_files = $_[1];
+ my $list="";
+ my $rc;
+
+ &close_minicalc();
+
+ for ($a=1; $a <= $num_files; $a++)
+ {
+ &db_export("$convert_file-Sheet$a");
+ print "Moving /tmp/$convert_file-Sheet$a.pdb to $pdb_new/\n";
+ `mv /tmp/$convert_file-Sheet$a.pdb $pdb_new/`;
+ `chmod 666 $pdb_new/$convert_file-Sheet$a.pdb`;
+ }
+
+ &close_connection(1);
+ &kill_pose();
+ print "\nFinishing test...\n";
+
+ for ($a=1; $a <= $num_files; $a++)
+ {
+ $list .="$pdb_new/$convert_file-Sheet$a.pdb "
+ }
+
+ $rc = &convert_to_xml($xml_new, $xml_orig, "$list",
+ "application/x-minicalc", "sxc", $convert_file, $merge_opt);
+ if ($rc != 0)
+ {
+ print "\nERROR, problem converting file(s) $list\n\n";
+ }
+
+ &pose_sleep(5);
+}
+
+# print_usage
+#
+# prints the usage for this program.
+#
+sub print_usage
+{
+ print "Usage : test_driver.pl\n";
+ print "\t-test=<file> \t\t: individual test case file to run\n";
+ print "\t-list=<file> \t\t: list of test case files\n";
+ print "\t-env=<file> \t\t: Properites like file defining env\n";
+ print "\t-pose-exe=<fullpath> \t: path to pose executable\n";
+ print "\t-pose-prc=<path> \t: path to directory holding prc files\n";
+ print "\t-pdb-orig=<path> \t: directory to hold original pdb files\n";
+ print "\t-pdb-new=<path> \t: directory to hold new pdb files\n";
+ print "\t-xml-orig=<path> \t: directory to hold original office documents\n";
+ print "\t-xml-new=<path> \t: directory to hold new office documents\n";
+ print "\t-merge \t: Invokes the merge option when converting\n";
+ print "\t \t from PDB back to XML.\n";
+}
+
+# print_env
+#
+# Prints the current environment.
+#
+sub print_env
+{
+ print "\nUsing the following environment:\n";
+ print "\tPOSE_EXE = $pose_exe\n";
+ print "\tPOSE_PRC = $pose_prc\n";
+ print "\tPDB_ORIG = $pdb_orig\n";
+ print "\tPDB_NEW = $pdb_new\n";
+ print "\tXML_ORIG = $xml_orig\n";
+ print "\tXML_NEW = $xml_new\n";
+}
+
+# process_cmdline
+#
+# command line options come in as key/value pairs.
+# read them and set the appropriate global variable
+#
+# Sets these globals: pose_exe, pose_prc, xml_orig, xml_new_dir,
+# xml_new, pdb_orig_dir, pdb_orig, pdb_new_dir, pdb_new.
+#
+sub process_cmdline
+{
+ foreach $i (@_)
+ {
+ my @arg= split('=', $i);
+ @arg[0] =~ tr/A-Z/a-z/;
+
+ if (@arg[0] eq "-pose-exe")
+ {
+ $pose_exe=$arg[1];
+ }
+ elsif (@arg[0] eq "-pose-prc")
+ {
+ $pose_prc=$arg[1];
+ }
+ elsif (@arg[0] eq "-pdb-orig")
+ {
+ $pdb_orig_dir=$arg[1];
+ $pdb_orig=$arg[1];
+ }
+ elsif (@arg[0] eq "-pdb-new")
+ {
+ $pdb_new_dir=$arg[1];
+ $pdb_new=$arg[1];
+ }
+ elsif (@arg[0] eq "-xml-orig")
+ {
+ $xml_orig=$arg[1];
+ }
+ elsif (@arg[0] eq "-xml-new")
+ {
+ $xml_new_dir=$arg[1];
+ $xml_new=$arg[1];
+ }
+ elsif (@arg[0] eq "-env")
+ {
+ &set_env_from_props($arg[1]);
+ }
+ elsif (@arg[0] eq "-list")
+ {
+ $test_list = $arg[1];
+ }
+ elsif (@arg[0] eq "-test")
+ {
+ $infile = $arg[1];
+ }
+ elsif (@arg[0] eq "-merge")
+ {
+ $merge_opt = 1;
+ }
+ else
+ {
+ print_usage();
+ die "Incorrect command line";
+ }
+ }
+}
+
+# set_env_from_props
+# infile - property file
+#
+# Read the properties file, of the form key=value
+# Valid key values are :
+# POSE_EXE
+# POSE_PRC
+# PDB_ORIG
+# PDB_NEW
+# XML_ORIG
+# XML_NEW
+# If a value is found the appropriate global variable is set.
+#
+# Sets these globals: pose_exe, pose_prc, xml_orig, xml_new_dir,
+# xml_new, pdb_orig_dir, pdb_orig, pdb_new_dir, pdb_new.
+#
+sub set_env_from_props
+{
+ my $infile = $_[0];
+
+ open(PROPSFILE, $infile) || die "Could not open properties file <$infile>";
+
+ while (<PROPSFILE>)
+ {
+ chomp $_;
+ my @arg = split('=', $_);
+ @arg[0] =~ tr/a-z/A-Z/;
+ my $len = @arg;
+ if ($len != 2)
+ {
+ die "Malformed property in $arg[0]";
+ }
+ if (@arg[0] eq "POSE_EXE")
+ {
+ $pose_exe=$arg[1];
+ }
+ elsif (@arg[0] eq "POSE_PRC")
+ {
+ $pose_prc=$arg[1];
+ }
+ elsif (@arg[0] eq "PDB_ORIG")
+ {
+ $pdb_orig_dir=$arg[1];
+ $pdb_orig=$arg[1];
+ }
+ elsif (@arg[0] eq "PDB_NEW")
+ {
+ $pdb_new_dir=$arg[1];
+ $pdb_new=$arg[1];
+ }
+ elsif (@arg[0] eq "XML_ORIG")
+ {
+ $xml_orig=$arg[1];
+ }
+ elsif (@arg[0] eq "XML_NEW")
+ {
+ $xml_new_dir=$arg[1];
+ $xml_new=$arg[1];
+ }
+
+ }
+ close PROPSFILE;
+}
+
+# verify_env_options
+#
+# Verify that input options are correctly set.
+# Assumes pose_exe, pose_prc, xml_orig, xml_new_dir,
+# pdb_orig_dir, and pdb_new_dir are already set.
+#
+sub verify_env_options
+{
+ if (!-e "$pose_exe")
+ {
+ die "The pose executable cannot be found at $pose_exe.";
+ }
+ if (!-x $pose_exe)
+ {
+ die "$pose_exe exists but is not executable.";
+ }
+
+ if (!-e "$pose_prc")
+ {
+ die "The PRC directory specified as $pose_prc does not exist.";
+ }
+ if (!-d "$pose_prc")
+ {
+ die "The PRC location specified as $pose_prc exists, but is not a directory.";
+ }
+
+ if (!-e "$pdb_orig_dir")
+ {
+ die "The original PDB directory specified as $pdb_orig_dir does not exist.";
+ }
+ if (!-d "$pdb_orig_dir")
+ {
+ die "The original PDB directory specified as $pdb_orig_dir exists but is not a directory.";
+ }
+
+ if (!-e "$pdb_new_dir")
+ {
+ die "The new PDB directory specified as $pdb_new_dir does not exist.";
+ }
+ if (!-d "$pdb_new_dir")
+ {
+ die "The new PDB directory specified as $pdb_new_dir exists but is not a directory.";
+ }
+
+ if (!-e "$xml_orig")
+ {
+ die "The original Office document directory specified as $xml_orig does not exist.";
+ }
+ if (!-d "$xml_orig")
+ {
+ die "The original Office document location specified as $xml_orig exists but is not a directory.";
+ }
+
+ if (!-e "$xml_new_dir")
+ {
+ die "The new Office document directory specified as $xml_new_dir does not exist.";
+ }
+ if (!-d "$xml_new_dir")
+ {
+ die "The new Office document location specified as $xml_new_dir exists but is not a directory.";
+ }
+}
+
+# verify_prcs_exist
+# prcfile - the PRC file to check
+#
+# Verifies that the specified PRC file exists.
+#
+sub verify_prcs_exist
+{
+ my $prcfile = $_[0];
+
+ if (!-e "$pose_prc/$prcfile")
+ {
+ die "The pose PRC directory ($pose_prc) is correct, but I can't find $prcfile there.";
+ }
+}
+
diff --git a/xmerge/source/palmtests/qa-wrapper/bin/run-convtest b/xmerge/source/palmtests/qa-wrapper/bin/run-convtest
new file mode 100755
index 000000000000..56c12509e215
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/bin/run-convtest
@@ -0,0 +1,538 @@
+#!/bin/ksh
+#########################################################################
+
+ #*************************************************************************
+ #
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# Copyright 2000, 2010 Oracle and/or its affiliates.
+#
+# OpenOffice.org - a multi-platform office productivity suite
+#
+# This file is part of OpenOffice.org.
+#
+# OpenOffice.org is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License version 3
+# only, as published by the Free Software Foundation.
+#
+# OpenOffice.org is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License version 3 for more details
+# (a copy is included in the LICENSE file that accompanied this code).
+#
+# You should have received a copy of the GNU Lesser General Public License
+# version 3 along with OpenOffice.org. If not, see
+# <http://www.openoffice.org/license.html>
+# for a copy of the LGPLv3 License.
+#
+ #*************************************************************************
+
+#set -x
+umask 0
+
+integer TOTAL_PASS=0
+integer TOTAL_FAIL=0
+integer TOTAL_RUN=0
+integer MAX_RETRIES=5
+typeset RUNNAME=`date +%Y%m%d%H%M%S`
+typeset PRINTDATE=`date`
+typeset PDB_INFILE_DIR
+typeset PDB_OUTFILE_DIR
+typeset XML_OUTFILE_DIR
+typeset REPORT
+typeset RESDIR
+typeset LOGFILE
+typeset COMPLOG
+typeset TEST_COMMENTS
+typeset BGCOLOR
+typeset ODD_BGCOLOR='#BBBBBB'
+typeset EVEN_BGCOLOR='#DCDCDC'
+typeset PASS_COLOR='#00ff00'
+typeset FAIL_COLOR='#ff4040'
+
+typeset ENVFILE=""
+# The following variables should be set in the env file
+typeset MASTERLIST=""
+typeset TESTCASEDIR=""
+typeset RESULTSBASE=""
+typeset XMERGE_JAR=""
+typeset APORTIS_JAR=""
+typeset WORDSMITH_JAR=""
+typeset MINICALC_JAR=""
+typeset PERL5LIB=""
+typeset POSE_EXE=""
+typeset POSE_PRC=""
+typeset TEST_DRIVER_PL=""
+typeset COMPARATOR_PL=""
+typeset COMPLIST=""
+typeset XML_INFILE_DIR=""
+typeset PDB_BASELINE_DIR=""
+typeset XML_BASELINE_DIR=""
+typeset EM_SCRIPT_HOME=""
+typeset QAWRAPPER_SCRIPT_HOME=""
+typeset EM_ROM_FILE=""
+typeset EM_SESSION_FILE=""
+typeset QA_LIB_HOME=""
+typeset QA_COMPARATOR_HOME=""
+typeset CLASSES_DIR=""
+
+
+
+################################################################################
+Usage() {
+ echo "Usage: run-convtest -env <ENVFILE> [-name RUNNAME]"
+ exit 1
+}
+
+
+################################################################################
+StartReportFile() {
+ typeset line=`date`
+
+ ReportLine "<HTML>"
+ ReportLine "<HEAD>"
+ ReportLine "<TITLE>XMerge Converters Test Results - ${RUNNAME}</TITLE>"
+ ReportLine "</HEAD>"
+ ReportLine "<BODY BGCOLOR=#ffffff>"
+ ReportLine "<H1 align=center>XMerge Converters Test Results - ${RUNNAME}</H1>"
+ ReportLine "<P>"
+ ReportLine "Test run on: ${PRINTDATE}"
+ ReportLine "<P>"
+ ReportLine "<CENTER>"
+ ReportLine "<TABLE WIDTH='100%' BORDER=1 CELLSPACING=0 CELLPADDING=2>"
+ ReportLine "<TR BGCOLOR='#9999CC'>"
+ ReportLine "<TH>Test Name</TH>"
+ ReportLine "<TH>Test File</TH>"
+ ReportLine "<TH>.ext</TH>"
+ ReportLine "<TH>Result</TH>"
+ ReportLine "<TH>Comments</TH>"
+ ReportLine "</TR>"
+}
+
+
+################################################################################
+EndReportFile() {
+ # remove full path from LOGFILE (link will be to current dir)
+ typeset loglink=${LOGFILE##*/}
+
+ ReportLine "<P>"
+ ReportLine "<CENTER>"
+ ReportLine "<TABLE BORDER=1 CELLSPACING=0 CELLPADDING=2>"
+ ReportLine "<TR>"
+ ReportLine "<TH>Total Tests PASSED</TH>"
+ ReportLine "<TH>${TOTAL_PASS}</TH>"
+ ReportLine "</TR>"
+ ReportLine "<TR>"
+ ReportLine "<TH>Total Tests FAILED</TH>"
+ ReportLine "<TH>${TOTAL_FAIL}</TH>"
+ ReportLine "</TR>"
+ ReportLine "<TR>"
+ ReportLine "<TH>Total Tests Run</TH>"
+ ReportLine "<TH>${TOTAL_RUN}</TH>"
+ ReportLine "</TR>"
+ ReportLine "</TABLE>"
+ ReportLine "</CENTER>"
+ ReportLine "<P>"
+ ReportLine "<A HREF=${loglink}>Full logfile for test run</A>"
+ ReportLine "<P>"
+ ReportLine "<CENTER>"
+ ReportLine "</BODY>"
+ ReportLine "</HTML>"
+}
+
+################################################################################
+ReportLine() {
+ echo $1 >> $REPORT
+}
+
+################################################################################
+LogLine() {
+ echo $1 >> $LOGFILE
+}
+
+################################################################################
+ReportTestComments() {
+ if [[ $TEST_COMMENTS == "" ]] ; then
+ TEST_COMMENTS="&nbsp;"
+ fi
+
+ ReportLine "<TD>${TEST_COMMENTS}</TD>"
+}
+
+################################################################################
+GetParams() {
+ integer argc=$#
+ integer i=0
+
+ if [[ $argc -lt 1 ]] ; then
+ Usage
+ fi
+
+ while (($i < $argc)) ; do
+ arg=$1
+ shift
+ i=i+1
+
+ if [[ $arg == '-name' ]] ; then
+ if (( $i < $argc )) ; then
+ RUNNAME=$1
+ echo "RUNNAME=[$RUNNAME]"
+ shift
+ i=i+1
+ else
+ Usage
+ fi
+ elif [[ $arg == '-env' ]] ; then
+ if (( $i < $argc )) ; then
+ ENVFILE=$1
+ shift
+ i=i+1
+ else
+ Usage
+ fi
+ else
+ Usage
+ fi
+ done
+
+ if [[ $ENVFILE == "" ]] ; then
+ Usage
+ fi
+}
+
+
+################################################################################
+ReadEnvFile() {
+ . $ENVFILE
+
+
+ echo ""
+ echo "The following values have been set from $ENVFILE:"
+ echo "MASTERLIST=$MASTERLIST"
+ echo "TESTCASEDIR=$TESTCASEDIR"
+ echo "XMERGE_JAR=$XMERGE_JAR"
+ echo "APORTIS_JAR=$APORTIS_JAR"
+ echo "WORDSMITH_JAR=$WORDSMITH_JAR"
+ echo "MINICALC_JAR=$MINICALC_JAR"
+ echo "RESULTSBASE=$RESULTSBASE"
+ echo "PERL5LIB=$PERL5LIB"
+ echo "POSE_EXE=$POSE_EXE"
+ echo "POSE_PRC=$POSE_PRC"
+ echo "TEST_DRIVER_PL=$TEST_DRIVER_PL"
+ echo "COMPARATOR_PL=$COMPARATOR_PL"
+ echo "XML_INFILE_DIR=$XML_INFILE_DIR"
+ echo "PDB_BASELINE_DIR=$PDB_BASELINE_DIR"
+ echo "XML_BASELINE_DIR=$XML_BASELINE_DIR"
+ echo "EM_SCRIPT_HOME=$EM_SCRIPT_HOME"
+ echo "QAWRAPPER_SCRIPT_HOME=$QAWRAPPER_SCRIPT_HOME"
+ echo "EM_ROM_FILE=$EM_ROM_FILE"
+ echo "EM_SESSION_FILE=$EM_SESSION_FILE"
+ echo "QA_LIB_HOME=$QA_LIB_HOME"
+ echo "QA_COMPARATOR_HOME=$QA_COMPARATOR_HOME"
+ echo "CLASSES_DIR=$CLASSES_DIR"
+ echo "COMPLIST=$COMPLIST"
+}
+
+################################################################################
+POSESetup() {
+ export PERL5LIB
+ export EM_SCRIPT_HOME
+ export QAWRAPPER_SCRIPT_HOME
+ export EM_ROM_FILE
+ export EM_SESSION_FILE
+ export QA_LIB_HOME
+ export QA_COMPARATOR_HOME
+ export CLASSES_DIR
+
+}
+
+################################################################################
+TestSetup() {
+
+
+ POSESetup
+
+ export ZENDEBUG=1
+
+ COMPLIST="${COMPLIST}/tempcomp.${RUNNAME}.list"
+ # create the directories for the results of this test run
+ RESDIR="${RESULTSBASE}/${RUNNAME}"
+ \rm -Rf $RESDIR
+ mkdir $RESDIR
+
+ # Define the directories for the test input files,
+ # test output files, working directories and baseline files
+ PDB_INFILE_DIR="${RESDIR}/pdb-orig"
+ mkdir "${PDB_INFILE_DIR}"
+ PDB_OUTFILE_DIR="${RESDIR}/pdb-new"
+ mkdir "${PDB_OUTFILE_DIR}"
+ XML_OUTFILE_DIR="${RESDIR}/xml-new"
+ mkdir "${XML_OUTFILE_DIR}"
+
+ LOGFILE="${RESDIR}/logfile"
+ COMPLOG="${RESDIR}/complog"
+ REPORT="${RESDIR}/report.html"
+ StartReportFile
+
+ echo "Results in: $RESDIR"
+ echo "Report file: $REPORT"
+}
+
+################################################################################
+TestCleanup() {
+ EndReportFile
+}
+
+################################################################################
+TestCaseSetup() {
+ # where to pick up converter classes
+ export CLASSPATH=""
+ export CLASSPATH=$CLASSPATH:$XMERGE_JAR
+ export CLASSPATH=$CLASSPATH:$APORTIS_JAR
+ export CLASSPATH=$CLASSPATH:$WORDSMITH_JAR
+ export CLASSPATH=$CLASSPATH:$MINICALC_JAR
+}
+
+################################################################################
+TestCaseCleanup() {
+ # empty function
+ a=42
+}
+
+################################################################################
+RunTestCase() {
+ testcase=$1
+
+ LogLine ""
+ LogLine "test_driver output:"
+
+ # run test_driver in foreground
+ $TEST_DRIVER_PL\
+ -pose-prc=${POSE_PRC}\
+ -pose-exe=${POSE_EXE}\
+ -xml-orig=${XML_INFILE_DIR}\
+ -pdb-orig=${PDB_INFILE_DIR}\
+ -pdb-new=${PDB_OUTFILE_DIR}\
+ -xml-new=${XML_OUTFILE_DIR}\
+ -test=$testcase -merge >> $LOGFILE 2>&1
+
+ # cleanup in case zombie POSE processes are hanging around
+ pkill pose
+ pkill -9 pose
+}
+
+
+################################################################################
+ComparisonSetup() {
+ typeset file=$1
+
+
+ export CLASSPATH="$CLASSES_DIR/xerces.jar"
+
+ # create temporary comparator list file for this test case
+ echo $file > $COMPLIST
+}
+
+################################################################################
+ComparisonCleanup() {
+ # remove temporary comparator list file used for this test case
+ \rm -f $COMPLIST
+}
+
+################################################################################
+RunComparison() {
+ typeset type=$1
+
+ LogLine ""
+ LogLine "Comparator output:"
+ $COMPARATOR_PL\
+ -xml-orig=${XML_BASELINE_DIR}\
+ -pdb-orig=${PDB_BASELINE_DIR}\
+ -pdb-new=${PDB_INFILE_DIR}\
+ -xml-new=${XML_OUTFILE_DIR}\
+ -list=$COMPLIST -log=$COMPLOG -type=$type >> $LOGFILE 2>&1
+# -list=$COMPLIST -log=$COMPLOG -type=$type | tee -a $LOGFILE 2>&1
+
+ pass=`grep TRUE $COMPLOG | wc -l`
+
+ LogLine ""
+ LogLine "COMPLIST file:"
+ cat $COMPLIST >> $LOGFILE
+ LogLine ""
+ LogLine "Comparator logfile:"
+ cat $COMPLOG >> $LOGFILE
+
+ if [ $pass -eq 0 ]
+ then
+ TEST_COMMENTS="${TEST_COMMENTS}$type comparison ERROR<BR>"
+ echo "$type comparison ERROR"
+ return 0
+ fi
+
+ echo "$type comparison OK"
+ return 1
+}
+
+################################################################################
+CheckOutput() {
+ typeset xmlfile="${XML_OUTFILE_DIR}/$1"
+ typeset pdbfile="${PDB_INFILE_DIR}/$2"
+
+ if [ ! -f $pdbfile ] ; then
+ TEST_COMMENTS="${TEST_COMMENTS}[$pdbfile] does not exist<BR>"
+ LogLine "ERROR: $pdbfile does not exist"
+ echo "ERROR: $pdbfile does not exist"
+ return 0
+ fi
+
+ if [ ! -f $xmlfile ] ; then
+ TEST_COMMENTS="${TEST_COMMENTS}[$xmlfile] does not exist<BR>"
+ LogLine "ERROR: $xmlfile does not exist"
+ echo "ERROR: $xmlfile does not exist"
+ return 0
+ fi
+
+ return 1
+}
+
+################################################################################
+RunTest() {
+ typeset testcasename
+ typeset testcase
+ typeset testfile
+ typeset pdbfile
+ typeset xmlfile
+ typeset ext
+ integer try
+ integer finished_with_test
+ integer test_pass
+
+ TestSetup
+
+ BGCOLOR=$ODD_BGCOLOR
+
+ while read line ; do
+ # get chars up to 1st space
+ testcasename=${line%% *}
+ testcase="${TESTCASEDIR}/$testcasename"
+
+ # get 2nd word
+ testfile=${line#* }
+ testfile=${testfile%% *}
+
+ # get last word
+ ext=${line##* }
+
+ LogLine "############################################"
+ LogLine "Starting the following testcase"
+ LogLine "testcase = $testcase"
+ LogLine "testfile = $testfile"
+ LogLine "ext = $ext"
+
+ ReportLine "<TR BGCOLOR='${BGCOLOR}'>"
+ ReportLine "<TD valign=top>$testcasename</TD>"
+ ReportLine "<TD valign=top>$testfile</TD>"
+ ReportLine "<TD valign=top>$ext</TD>"
+
+ echo ""
+ echo "testcase = $testcase"
+ echo "testfile = $testfile"
+ echo "ext = $ext"
+
+ try=1
+ finished_with_test=0
+ TEST_COMMENTS=""
+
+ while (($finished_with_test == 0)) ; do
+
+ TestCaseSetup
+ RunTestCase $testcase
+ TestCaseCleanup
+
+ xmlfile="${testfile}.${ext}"
+
+ if [[ $ext == "sxc" ]] ; then
+ pdbfile="${testfile}-Sheet1.pdb"
+ else
+ pdbfile="${testfile}.pdb"
+ fi
+
+ CheckOutput $xmlfile $pdbfile
+ res=$?
+
+ if [[ $res -eq 1 ]] ; then
+ ComparisonSetup $pdbfile
+ RunComparison pdb
+ res=$?
+# ignore result until pdb comparator is fixed...
+res=1
+ ComparisonCleanup
+ fi
+
+ if [[ $res -eq 1 ]] ; then
+ ComparisonSetup $xmlfile
+ RunComparison xml
+ res=$?
+ ComparisonCleanup
+ fi
+
+ if [[ $res -eq 1 ]] ; then
+ TOTAL_PASS=TOTAL_PASS+1
+ ReportLine "<TD valign=top BGCOLOR='${PASS_COLOR}'>PASS</TD>"
+ ReportTestComments
+ ReportLine "</TR>"
+ LogLine "Test PASSED (on try $try)"
+ echo "Test PASSED (on try $try)"
+ finished_with_test=1
+ else
+ TEST_COMMENTS="${TEST_COMMENTS}error on try ${try}<BR>"
+ LogLine "TEST FAILED (on try $try)"
+ echo "TEST FAILED (on try $try)"
+
+ if [[ $try -eq $MAX_RETRIES ]] ; then
+ TOTAL_FAIL=TOTAL_FAIL+1
+ ReportLine "<TD valign=top BGCOLOR='${FAIL_COLOR}'>FAIL</TD>"
+ ReportTestComments
+ ReportLine "</TR>"
+ finished_with_test=1
+ fi
+ fi
+
+ try=try+1
+ done
+
+ TOTAL_RUN=TOTAL_RUN+1
+
+ # toggle BGCOLOR for next report line
+ if [[ $BGCOLOR == $ODD_BGCOLOR ]] ; then
+ BGCOLOR=$EVEN_BGCOLOR
+ else
+ BGCOLOR=$ODD_BGCOLOR
+ fi
+
+ done < $MASTERLIST
+
+ ReportLine "</TABLE>"
+ ReportLine "</CENTER>"
+
+ TestCleanup
+
+ echo "Total Tests PASSED: "${TOTAL_PASS}
+ echo "Total Tests FAILED: "${TOTAL_FAIL}
+ echo "Total Tests RUN: "${TOTAL_RUN}
+ echo "Results in: $RESDIR"
+ echo "Report file: $REPORT"
+}
+
+################################################################################
+################################################################################
+# main
+################################################################################
+################################################################################
+
+GetParams $@
+ReadEnvFile
+RunTest
+
+exit 0
diff --git a/xmerge/source/palmtests/qa-wrapper/env/master.env b/xmerge/source/palmtests/qa-wrapper/env/master.env
new file mode 100644
index 000000000000..8a9462722bea
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/env/master.env
@@ -0,0 +1,85 @@
+#The Qa-Test environment is defined in this file. All of the fields are
+#necessary in order for the scripts to run effectlively
+
+###########################################################
+# MASTERLIST file defines which test to run. These list are usually located in
+# the qa-wrapper/lists dir
+
+MASTERLIST=<listdir/list file>
+
+###########################################################
+#The TESTCASE dir is where the testcases to be run are located
+
+TESTCASEDIR=<testcase dir>
+
+###########################################################
+# Results are stored in a new directory at ${RESULTSBASE}/results-${RUNNAME}
+
+RESULTSBASE=/export/home/test/qadir/qa-wrapper/results
+
+###########################################################
+# Where to find the Xmerge JAR files
+
+APORTIS_JAR=/export/home/test/qadir/qa-wrapper/classes/aportisdoc.jar
+WORDSMITH_JAR=/export/home/test/qadir/qa-wrapper/classes/wordsmith.jar
+MINICALC_JAR=/export/home/test/qadir/qa-wrapper/classes/minicalc.jar
+CLASSES_DIR=<qa-wrapperdir>/classes
+
+###########################################################
+# setup which version of POSE to use
+
+PERL5LIB=<Pose directory>/Scripting/Perl
+POSE_EXE=<Pose directory>/posedist/pose
+POSE_PRC=<location of prc files to use for testing>
+
+###########################################################
+
+# Location of files required to run Pose
+
+EM_ROM_FILE=<location and name of palm rom file>
+EM_SESSION_FILE=<location of palm session file>
+
+
+###########################################################
+
+
+# where to get the executables for the test_driver and the comparator
+
+TEST_DRIVER_PL=<qa-wrapperdir>/bin/qa_test_driver.pl
+COMPARATOR_PL=<qa-wrapperdir>/bin/qa_comparator.pl
+COMPLIST=<qa-wrapperdir>/lists
+
+###########################################################
+# where to get the original XML test files
+
+XML_INFILE_DIR=<qa-wrapperdir>/testcases/xml-orig
+
+###########################################################
+# where to find the baseline PDB files
+
+PDB_BASELINE_DIR=<qa-wrapperdir>/results/baseline/pdb-base
+
+###########################################################
+# where to find the baseline XML files
+
+XML_BASELINE_DIR=<qa-wrapperdir>/results/baseline/xml-base
+
+###########################################################
+#Location of script that runs the conversions
+EM_SCRIPT_HOME=<location of rd script>
+
+###########################################################
+#Location of run-convtest.pl
+QAWRAPPER_SCRIPT_HOME=<qa-wrapperdir>/bin
+
+###########################################################
+#Location of converterlib.pm
+QA_LIB_HOME=<qa dir>/lib
+
+###########################################################
+#Location of comparator.pl
+QA_COMPARATOR_HOME=<qa dir>/comparator/
+
+
+
+
diff --git a/xmerge/source/palmtests/qa-wrapper/lists/master.list b/xmerge/source/palmtests/qa-wrapper/lists/master.list
new file mode 100644
index 000000000000..d6be4fb063bd
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/lists/master.list
@@ -0,0 +1,55 @@
+c_addition01-mod.infile c_addition sxc
+c_alignment.infile c_alignment sxc
+c_backwardrange-mod.infile c_backwardrange sxc
+c_basic-mod.infile c_basic sxc
+c_boolean-mod.infile c_boolean sxc
+c_cellpercentvalue-mod.infile c_cellpercentvalue sxc
+c_cellstringvalue-mod.infile c_cellstringvalue sxc
+c_columnswidth-mod.infile c_columnswidth sxc
+c_cyclic-mod.infile c_cyclic sxc
+c_dividefloating-mod.infile c_dividefloating sxc
+c_forwardrange-mod.infile c_forwardrange sxc
+c_insertimage.infile c_insertimage sxc
+c_invalidcellref-mod.infile c_invalidcellref sxc
+c_largerange-mod.infile c_largerange sxc
+c_listrange-mod.infile c_listrange sxc
+c_mathematical-mod.infile c_mathematical sxc
+c_protection-mod01.infile c_protection sxc
+c_sheetreference-mod.infile c_sheetreference sxc
+c_simple01-mod.infile c_simple01 sxc
+c_simple02-mod.infile c_simple04 sxc
+c_simple03-mod.infile c_simple02 sxc
+c_simple04-mod.infile c_simple03 sxc
+c_smallrange-mod.infile c_smallrange sxc
+c_styles.infile c_styles sxc
+c_textimage.infile c_textimage sxc
+a_table.infile a_table sxw
+a_animatedgif.infile a_animatedgif sxw
+a_linebreaks.infile a_linebreaks sxw
+a_bulletorderedlist.infile a_bulletorderedlist sxw
+a_superscript.infile a_superscript sxw
+a_subscript.infile a_subscript sxw
+a_emptydoc.infile a_emptydoc sxw
+a_fontsize.infile a_fontsize sxw
+a_heading.infile a_heading sxw
+a_heading1.infile a_heading1 sxw
+a_heading2.infile a_heading2 sxw
+a_hyperlink.infile a_hyperlink sxw
+a_justified.infile a_justified sxw
+a_linespacing.infile a_linespacing sxw
+a_numberorderedlist.infile a_numberorderedlist sxw
+a_pagebreak.infile a_pagebreak sxw
+a_paragraph.infile a_paragraph sxw
+a_standard.infile a_standard sxw
+a_symbols.infile a_symbols sxw
+a_wordwrap.infile a_wordwrap sxw
+a_unorderedlist.infile a_unorderedlist sxw
+a_textspan.infile a_textspan sxw
+a_bolddoc.infile a_bolddoc sxw
+a_tab.infile a_tab sxw
+a_firstlineindent.infile a_firstlineindent sxw
+a_bookmarks.infile a_bookmarks sxw
+
+
+
+
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_animatedgif.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_animatedgif.pdb
new file mode 100644
index 000000000000..4bd289ac998f
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_animatedgif.pdb
@@ -0,0 +1,6 @@
+a_animatedgif
+Start of animated gif
+
+
+End of animated gif
+
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_bolddoc.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_bolddoc.pdb
new file mode 100644
index 000000000000..5761b33b2e80
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_bolddoc.pdb
@@ -0,0 +1 @@
+a_bolddoc \ No newline at end of file
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_bookmarks.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_bookmarks.pdb
new file mode 100644
index 000000000000..9bc503eeabb2
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_bookmarks.pdb
@@ -0,0 +1,10 @@
+a_bookmarksThe above line is bookmarked as 'BK1'.
+In the next paragraph Sthe word Silicon is bookmarked to 'BK2'
+
+12 June 2001) In a CBS Marketwatch article, Scott McNealy says that
+despite the failure of Net start-ups and declining stock prices, Silicon
+Valley is still operating under the same rules and values. He also says, "I
+ firmly believe that the Internet revolution is just beginning. Companies
+ may be pausing to catch their breath right now, but the benefits of the
+ Internet are too profound to hold back for long."
+
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_bulletorderedlist.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_bulletorderedlist.pdb
new file mode 100644
index 000000000000..5042141d32c7
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_bulletorderedlist.pdb
@@ -0,0 +1,8 @@
+a_bulletorderedlist
+Bullet 1
+Bullet 2
+Bullet 3
+Bullet 4
+
+End of bullet Ordered list
+
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_emptydoc.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_emptydoc.pdb
new file mode 100644
index 000000000000..5ba1ae5cd8ce
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_emptydoc.pdb
@@ -0,0 +1 @@
+a_emptydoc \ No newline at end of file
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_firstlineindent.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_firstlineindent.pdb
new file mode 100644
index 000000000000..b9f4514115ee
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_firstlineindent.pdb
@@ -0,0 +1 @@
+a_firstlineindent \ No newline at end of file
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_fontsize.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_fontsize.pdb
new file mode 100644
index 000000000000..48727c5e4ce8
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_fontsize.pdb
@@ -0,0 +1,6 @@
+a_fontsizeText with font size 10
+Text with font size 16
+Text with font size 20
+Text with fontsize 40
+Text with font size 96
+
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_heading.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_heading.pdb
new file mode 100644
index 000000000000..6b0e0e8894a1
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_heading.pdb
@@ -0,0 +1 @@
+a_heading \ No newline at end of file
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_heading1.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_heading1.pdb
new file mode 100644
index 000000000000..9bfca2098a4f
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_heading1.pdb
@@ -0,0 +1 @@
+a_heading1 \ No newline at end of file
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_heading2.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_heading2.pdb
new file mode 100644
index 000000000000..8b5f9d3dae8d
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_heading2.pdb
@@ -0,0 +1 @@
+a_heading2
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_hyperlink.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_hyperlink.pdb
new file mode 100644
index 000000000000..02f9ee2bfef0
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_hyperlink.pdb
@@ -0,0 +1,6 @@
+a_hyperlinkThis line is bookmarked to BK1 (Insert-Bookmark)
+
+The line SunWeb Home Page has a hyperlink to sunweb.central.
+
+This line is a hyperlink to BK1. Click here will take cursor to top of page.
+
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_justified.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_justified.pdb
new file mode 100644
index 000000000000..f4b96b63d290
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_justified.pdb
@@ -0,0 +1,4 @@
+a_justifiedCentre aligned
+Right aligned
+Justified
+
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_linebreaks.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_linebreaks.pdb
new file mode 100644
index 000000000000..fc49ceaeffde
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_linebreaks.pdb
@@ -0,0 +1,4 @@
+a_linebreaksA simple list
+second entry. A line break followsthe above line has been broken with a line break
+Third entry
+
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_linespacing.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_linespacing.pdb
new file mode 100644
index 000000000000..2d1c2d8a6663
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_linespacing.pdb
@@ -0,0 +1,12 @@
+a_linespacingSecond: Note the line-distance spacing
+
+
+First: This line and the next line is spaced by single-line spacing
+Second: Note the line-distance spacing
+
+First: This line and the next line is spaced by 1.5 line spacing
+Second: Not the line-distance spacing.
+
+
+
+
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_numberorderedlist.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_numberorderedlist.pdb
new file mode 100644
index 000000000000..d304a28ce332
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_numberorderedlist.pdb
@@ -0,0 +1,9 @@
+a_numberorderedlist
+First
+Second
+Third
+Fourth
+
+
+End of numbered Ordered list
+
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_pagebreak.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_pagebreak.pdb
new file mode 100644
index 000000000000..b72028d9a284
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_pagebreak.pdb
@@ -0,0 +1,4 @@
+a_pagebreakPage 1
+-now a page break-
+Page 2
+
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_paragraph.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_paragraph.pdb
new file mode 100644
index 000000000000..e98c7c053c1d
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_paragraph.pdb
@@ -0,0 +1 @@
+a_paragraph \ No newline at end of file
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_simple01.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_simple01.pdb
new file mode 100644
index 000000000000..64bc6a97b588
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_simple01.pdb
@@ -0,0 +1 @@
+a_simple01 \ No newline at end of file
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_simple02.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_simple02.pdb
new file mode 100644
index 000000000000..e36fccb49870
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_simple02.pdb
@@ -0,0 +1 @@
+a_simple02 \ No newline at end of file
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_simple03.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_simple03.pdb
new file mode 100644
index 000000000000..0f4e392c9405
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_simple03.pdb
@@ -0,0 +1 @@
+a_simple03 \ No newline at end of file
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_simple04.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_simple04.pdb
new file mode 100644
index 000000000000..6b7a7af49af7
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_simple04.pdb
@@ -0,0 +1 @@
+a_simple04 \ No newline at end of file
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_simple05.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_simple05.pdb
new file mode 100644
index 000000000000..7f011ecc7fe4
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_simple05.pdb
@@ -0,0 +1 @@
+a_simple05 \ No newline at end of file
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_standard.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_standard.pdb
new file mode 100644
index 000000000000..4fb892a16ac5
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_standard.pdb
@@ -0,0 +1 @@
+a_standard \ No newline at end of file
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_subscript.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_subscript.pdb
new file mode 100644
index 000000000000..0e73bccb8ed1
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_subscript.pdb
@@ -0,0 +1 @@
+a_subscript \ No newline at end of file
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_superscript.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_superscript.pdb
new file mode 100644
index 000000000000..c3acf29ff54b
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_superscript.pdb
@@ -0,0 +1 @@
+a_superscript \ No newline at end of file
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_symbols.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_symbols.pdb
new file mode 100644
index 000000000000..bdcde5a2d718
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_symbols.pdb
@@ -0,0 +1 @@
+a_symbols!?????$%^&*()_+}{~@:?><,./;'#][=-???
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_tab.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_tab.pdb
new file mode 100644
index 000000000000..9255692a482e
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_tab.pdb
@@ -0,0 +1,8 @@
+a_tab 1 Tab line
+ 2 tabbed line
+ 3 tabbed line
+ 2 tabbed line
+ 1 Tab line
+ 4 tab line
+ 2 tab line
+
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_table.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_table.pdb
new file mode 100644
index 000000000000..edc86848073d
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_table.pdb
@@ -0,0 +1,2 @@
+a_table
+
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_textspan.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_textspan.pdb
new file mode 100644
index 000000000000..11bdec19d9a7
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_textspan.pdb
@@ -0,0 +1,3 @@
+a_textspan
+This is a simple line with some amount of text. The whole line is in italic except the next 3 words which is also SET TO BOLD. Also the next word is UNDERLINED. The essence is differnet styles within the same text span.
+
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_unorderedlist.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_unorderedlist.pdb
new file mode 100644
index 000000000000..5ada3fee1b7e
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_unorderedlist.pdb
@@ -0,0 +1,20 @@
+a_unorderedlist
+Wag the Dog
+Gladiator
+Insider
+Usual Suspects
+Glengarry Glen Ross
+Host Shots
+Airplane
+Monty Python
+History of the World
+Sacry Movie
+Austin Powers
+Scarlet and the Black
+Operation Day Break
+Life is Beautiful
+Nephew (beutfiul soundtrack)
+
+
+End of un-ordered list
+
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_wordwrap.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_wordwrap.pdb
new file mode 100644
index 000000000000..231c87f13642
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/a_wordwrap.pdb
@@ -0,0 +1 @@
+a_wordwrap
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_addition-Sheet1.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_addition-Sheet1.pdb
new file mode 100644
index 000000000000..1b663460a871
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_addition-Sheet1.pdb
@@ -0,0 +1 @@
+c_addition-Sheet1 \ No newline at end of file
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_addition-Sheet2.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_addition-Sheet2.pdb
new file mode 100644
index 000000000000..248a19c8e88c
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_addition-Sheet2.pdb
@@ -0,0 +1 @@
+c_addition-Sheet2 \ No newline at end of file
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_addition-Sheet3.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_addition-Sheet3.pdb
new file mode 100644
index 000000000000..c29d1d900333
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_addition-Sheet3.pdb
@@ -0,0 +1 @@
+c_addition-Sheet3 \ No newline at end of file
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_alignment-Sheet1.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_alignment-Sheet1.pdb
new file mode 100644
index 000000000000..945a290e0d84
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_alignment-Sheet1.pdb
@@ -0,0 +1 @@
+c_alignment-Sheet1 \ No newline at end of file
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_alignment-Sheet2.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_alignment-Sheet2.pdb
new file mode 100644
index 000000000000..7e85a6278ed3
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_alignment-Sheet2.pdb
@@ -0,0 +1 @@
+c_alignment-Sheet2 \ No newline at end of file
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_alignment-Sheet3.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_alignment-Sheet3.pdb
new file mode 100644
index 000000000000..58aa4367497e
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_alignment-Sheet3.pdb
@@ -0,0 +1 @@
+c_alignment-Sheet3 \ No newline at end of file
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_backwardrange-Sheet1.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_backwardrange-Sheet1.pdb
new file mode 100644
index 000000000000..b6e9a4ab8ba5
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_backwardrange-Sheet1.pdb
@@ -0,0 +1 @@
+c_backwardrange-Sheet1 \ No newline at end of file
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_backwardrange-Sheet2.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_backwardrange-Sheet2.pdb
new file mode 100644
index 000000000000..eef60cb9e101
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_backwardrange-Sheet2.pdb
@@ -0,0 +1 @@
+c_backwardrange-Sheet2 \ No newline at end of file
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_backwardrange-Sheet3.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_backwardrange-Sheet3.pdb
new file mode 100644
index 000000000000..b671c120b133
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_backwardrange-Sheet3.pdb
@@ -0,0 +1 @@
+c_backwardrange-Sheet3 \ No newline at end of file
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_basic-Sheet1.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_basic-Sheet1.pdb
new file mode 100644
index 000000000000..82b4f6f93ae9
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_basic-Sheet1.pdb
@@ -0,0 +1 @@
+c_basic-Sheet1 \ No newline at end of file
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_basic-Sheet2.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_basic-Sheet2.pdb
new file mode 100644
index 000000000000..d24e07fa7d5b
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_basic-Sheet2.pdb
@@ -0,0 +1 @@
+c_basic-Sheet2 \ No newline at end of file
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_basic-Sheet3.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_basic-Sheet3.pdb
new file mode 100644
index 000000000000..3852118276ae
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_basic-Sheet3.pdb
@@ -0,0 +1 @@
+c_basic-Sheet3 \ No newline at end of file
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_boolean-Sheet1.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_boolean-Sheet1.pdb
new file mode 100644
index 000000000000..1a448ee0f59f
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_boolean-Sheet1.pdb
@@ -0,0 +1 @@
+c_boolean-Sheet1 \ No newline at end of file
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_boolean-Sheet2.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_boolean-Sheet2.pdb
new file mode 100644
index 000000000000..96075a80a0d3
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_boolean-Sheet2.pdb
@@ -0,0 +1 @@
+c_boolean-Sheet2 \ No newline at end of file
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_boolean-Sheet3.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_boolean-Sheet3.pdb
new file mode 100644
index 000000000000..c21f6f25bb27
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_boolean-Sheet3.pdb
@@ -0,0 +1 @@
+c_boolean-Sheet3 \ No newline at end of file
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_cellcurrencyalue-Sheet1.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_cellcurrencyalue-Sheet1.pdb
new file mode 100644
index 000000000000..5b43db654f53
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_cellcurrencyalue-Sheet1.pdb
@@ -0,0 +1 @@
+c_cellcurrencyalue-Sheet1 \ No newline at end of file
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_cellcurrencyalue-Sheet2.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_cellcurrencyalue-Sheet2.pdb
new file mode 100644
index 000000000000..3dba6341b356
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_cellcurrencyalue-Sheet2.pdb
@@ -0,0 +1 @@
+c_cellcurrencyalue-Sheet2 \ No newline at end of file
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_cellcurrencyalue-Sheet3.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_cellcurrencyalue-Sheet3.pdb
new file mode 100644
index 000000000000..7f4a82b085c0
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_cellcurrencyalue-Sheet3.pdb
@@ -0,0 +1 @@
+c_cellcurrencyalue-Sheet3 \ No newline at end of file
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_cellpercentvalue-Sheet1.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_cellpercentvalue-Sheet1.pdb
new file mode 100644
index 000000000000..16301a97eebe
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_cellpercentvalue-Sheet1.pdb
@@ -0,0 +1 @@
+c_cellpercentvalue-Sheet1 \ No newline at end of file
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_cellpercentvalue-Sheet2.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_cellpercentvalue-Sheet2.pdb
new file mode 100644
index 000000000000..751375e39d9e
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_cellpercentvalue-Sheet2.pdb
@@ -0,0 +1 @@
+c_cellpercentvalue-Sheet2 \ No newline at end of file
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_cellpercentvalue-Sheet3.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_cellpercentvalue-Sheet3.pdb
new file mode 100644
index 000000000000..bb1dbb85fda4
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_cellpercentvalue-Sheet3.pdb
@@ -0,0 +1 @@
+c_cellpercentvalue-Sheet3 \ No newline at end of file
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_cellstringvalue-Sheet1.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_cellstringvalue-Sheet1.pdb
new file mode 100644
index 000000000000..61d00a77efaa
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_cellstringvalue-Sheet1.pdb
@@ -0,0 +1 @@
+c_cellstringvalue-Sheet1 \ No newline at end of file
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_cellstringvalue-Sheet2.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_cellstringvalue-Sheet2.pdb
new file mode 100644
index 000000000000..7c73ec0f5011
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_cellstringvalue-Sheet2.pdb
@@ -0,0 +1 @@
+c_cellstringvalue-Sheet2 \ No newline at end of file
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_cellstringvalue-Sheet3.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_cellstringvalue-Sheet3.pdb
new file mode 100644
index 000000000000..15db29361b62
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_cellstringvalue-Sheet3.pdb
@@ -0,0 +1 @@
+c_cellstringvalue-Sheet3 \ No newline at end of file
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_columnswidth-Sheet1.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_columnswidth-Sheet1.pdb
new file mode 100644
index 000000000000..12ec99980a4b
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_columnswidth-Sheet1.pdb
@@ -0,0 +1 @@
+c_columnswidth-Sheet1 \ No newline at end of file
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_columnswidth-Sheet2.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_columnswidth-Sheet2.pdb
new file mode 100644
index 000000000000..ff02ed1504d2
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_columnswidth-Sheet2.pdb
@@ -0,0 +1 @@
+c_columnswidth-Sheet2 \ No newline at end of file
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_columnswidth-Sheet3.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_columnswidth-Sheet3.pdb
new file mode 100644
index 000000000000..708a9ad6b9e0
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_columnswidth-Sheet3.pdb
@@ -0,0 +1 @@
+c_columnswidth-Sheet3 \ No newline at end of file
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_cyclic-Sheet1.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_cyclic-Sheet1.pdb
new file mode 100644
index 000000000000..f65335269b9a
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_cyclic-Sheet1.pdb
@@ -0,0 +1 @@
+c_cyclic-Sheet1 \ No newline at end of file
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_cyclic-Sheet2.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_cyclic-Sheet2.pdb
new file mode 100644
index 000000000000..3fd2cb9c30b1
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_cyclic-Sheet2.pdb
@@ -0,0 +1 @@
+c_cyclic-Sheet2 \ No newline at end of file
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_cyclic-Sheet3.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_cyclic-Sheet3.pdb
new file mode 100644
index 000000000000..c3956f9ace77
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_cyclic-Sheet3.pdb
@@ -0,0 +1 @@
+c_cyclic-Sheet3 \ No newline at end of file
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_dividefloating-Sheet1.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_dividefloating-Sheet1.pdb
new file mode 100644
index 000000000000..3ce66ab3d866
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_dividefloating-Sheet1.pdb
@@ -0,0 +1 @@
+c_dividefloating-Sheet1 \ No newline at end of file
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_dividefloating-Sheet2.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_dividefloating-Sheet2.pdb
new file mode 100644
index 000000000000..e482d04d0e5b
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_dividefloating-Sheet2.pdb
@@ -0,0 +1 @@
+c_dividefloating-Sheet2 \ No newline at end of file
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_dividefloating-Sheet3.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_dividefloating-Sheet3.pdb
new file mode 100644
index 000000000000..2e487b31d179
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_dividefloating-Sheet3.pdb
@@ -0,0 +1 @@
+c_dividefloating-Sheet3 \ No newline at end of file
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_forwardrange-Sheet1.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_forwardrange-Sheet1.pdb
new file mode 100644
index 000000000000..3068ef996b56
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_forwardrange-Sheet1.pdb
@@ -0,0 +1 @@
+c_forwardrange-Sheet1 \ No newline at end of file
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_forwardrange-Sheet2.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_forwardrange-Sheet2.pdb
new file mode 100644
index 000000000000..e6ba9099929c
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_forwardrange-Sheet2.pdb
@@ -0,0 +1 @@
+c_forwardrange-Sheet2 \ No newline at end of file
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_forwardrange-Sheet3.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_forwardrange-Sheet3.pdb
new file mode 100644
index 000000000000..b95779ad41b8
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_forwardrange-Sheet3.pdb
@@ -0,0 +1 @@
+c_forwardrange-Sheet3 \ No newline at end of file
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_insertimage-Sheet1.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_insertimage-Sheet1.pdb
new file mode 100644
index 000000000000..6ee9808973fc
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_insertimage-Sheet1.pdb
@@ -0,0 +1 @@
+c_insertimage-Sheet1 \ No newline at end of file
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_insertimage-Sheet2.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_insertimage-Sheet2.pdb
new file mode 100644
index 000000000000..739363157fce
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_insertimage-Sheet2.pdb
@@ -0,0 +1 @@
+c_insertimage-Sheet2 \ No newline at end of file
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_insertimage-Sheet3.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_insertimage-Sheet3.pdb
new file mode 100644
index 000000000000..f83c9d696418
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_insertimage-Sheet3.pdb
@@ -0,0 +1 @@
+c_insertimage-Sheet3 \ No newline at end of file
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_invalidcellref-Sheet1.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_invalidcellref-Sheet1.pdb
new file mode 100644
index 000000000000..a4316fac6844
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_invalidcellref-Sheet1.pdb
@@ -0,0 +1 @@
+c_invalidcellref-Sheet1 \ No newline at end of file
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_invalidcellref-Sheet2.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_invalidcellref-Sheet2.pdb
new file mode 100644
index 000000000000..838495378e21
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_invalidcellref-Sheet2.pdb
@@ -0,0 +1 @@
+c_invalidcellref-Sheet2 \ No newline at end of file
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_invalidcellref-Sheet3.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_invalidcellref-Sheet3.pdb
new file mode 100644
index 000000000000..9d55e657c398
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_invalidcellref-Sheet3.pdb
@@ -0,0 +1 @@
+c_invalidcellref-Sheet3 \ No newline at end of file
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_largerange-Sheet1.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_largerange-Sheet1.pdb
new file mode 100644
index 000000000000..73eca53bf94f
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_largerange-Sheet1.pdb
@@ -0,0 +1 @@
+c_largerange-Sheet1 *Hf„¢ÀÞü \ No newline at end of file
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_largerange-Sheet2.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_largerange-Sheet2.pdb
new file mode 100644
index 000000000000..eea214038d32
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_largerange-Sheet2.pdb
@@ -0,0 +1 @@
+c_largerange-Sheet2 \ No newline at end of file
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_largerange-Sheet3.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_largerange-Sheet3.pdb
new file mode 100644
index 000000000000..4e35e1731899
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_largerange-Sheet3.pdb
@@ -0,0 +1 @@
+c_largerange-Sheet3 \ No newline at end of file
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_listrange-Sheet1.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_listrange-Sheet1.pdb
new file mode 100644
index 000000000000..41905c6c611a
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_listrange-Sheet1.pdb
@@ -0,0 +1,2 @@
+c_listrange-Sheet1¸­
+ \ No newline at end of file
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_listrange-Sheet2.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_listrange-Sheet2.pdb
new file mode 100644
index 000000000000..a40081c5bbaa
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_listrange-Sheet2.pdb
@@ -0,0 +1,2 @@
+c_listrange-Sheet2¸­
+ \ No newline at end of file
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_listrange-Sheet3.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_listrange-Sheet3.pdb
new file mode 100644
index 000000000000..858a841fa00a
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_listrange-Sheet3.pdb
@@ -0,0 +1,2 @@
+c_listrange-Sheet3¸­
+ \ No newline at end of file
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_mathematical-Sheet1.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_mathematical-Sheet1.pdb
new file mode 100644
index 000000000000..2a6aff0de7f1
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_mathematical-Sheet1.pdb
@@ -0,0 +1,2 @@
+c_mathematical-Sheet1|¸­
+| \ No newline at end of file
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_mathematical-Sheet2.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_mathematical-Sheet2.pdb
new file mode 100644
index 000000000000..dd8211068ff8
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_mathematical-Sheet2.pdb
@@ -0,0 +1,2 @@
+c_mathematical-Sheet2|¸­
+| \ No newline at end of file
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_mathematical-Sheet3.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_mathematical-Sheet3.pdb
new file mode 100644
index 000000000000..d7f97fe92e7c
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_mathematical-Sheet3.pdb
@@ -0,0 +1,2 @@
+c_mathematical-Sheet3|¸­
+| \ No newline at end of file
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_protection-Sheet1.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_protection-Sheet1.pdb
new file mode 100644
index 000000000000..449b6a9ab202
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_protection-Sheet1.pdb
@@ -0,0 +1 @@
+c_protection-Sheet1 \ No newline at end of file
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_protection-Sheet2.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_protection-Sheet2.pdb
new file mode 100644
index 000000000000..d0cc3c18e018
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_protection-Sheet2.pdb
@@ -0,0 +1 @@
+c_protection-Sheet2 \ No newline at end of file
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_protection-Sheet3.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_protection-Sheet3.pdb
new file mode 100644
index 000000000000..c3ba37e4ab0f
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_protection-Sheet3.pdb
@@ -0,0 +1 @@
+c_protection-Sheet3 \ No newline at end of file
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_sheetreference-Sheet1.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_sheetreference-Sheet1.pdb
new file mode 100644
index 000000000000..1b1657281cb9
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_sheetreference-Sheet1.pdb
@@ -0,0 +1 @@
+c_sheetreference-Sheet1 \ No newline at end of file
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_sheetreference-Sheet2.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_sheetreference-Sheet2.pdb
new file mode 100644
index 000000000000..aceeb0002a60
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_sheetreference-Sheet2.pdb
@@ -0,0 +1 @@
+c_sheetreference-Sheet2 \ No newline at end of file
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_sheetreference-Sheet3.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_sheetreference-Sheet3.pdb
new file mode 100644
index 000000000000..b916c84fcff9
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_sheetreference-Sheet3.pdb
@@ -0,0 +1 @@
+c_sheetreference-Sheet3 \ No newline at end of file
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_simple01-Sheet1.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_simple01-Sheet1.pdb
new file mode 100644
index 000000000000..1d396a47bbeb
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_simple01-Sheet1.pdb
@@ -0,0 +1 @@
+c_simple01-Sheet1 \ No newline at end of file
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_simple01-Sheet2.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_simple01-Sheet2.pdb
new file mode 100644
index 000000000000..8d1315fbf5d3
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_simple01-Sheet2.pdb
@@ -0,0 +1 @@
+c_simple01-Sheet2 \ No newline at end of file
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_simple01-Sheet3.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_simple01-Sheet3.pdb
new file mode 100644
index 000000000000..b32d5cd02eb9
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_simple01-Sheet3.pdb
@@ -0,0 +1 @@
+c_simple01-Sheet3 \ No newline at end of file
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_simple02-Sheet1.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_simple02-Sheet1.pdb
new file mode 100644
index 000000000000..f89a0b55fcb5
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_simple02-Sheet1.pdb
@@ -0,0 +1 @@
+c_simple02-Sheet1 \ No newline at end of file
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_simple02-Sheet2.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_simple02-Sheet2.pdb
new file mode 100644
index 000000000000..853ffd159a34
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_simple02-Sheet2.pdb
@@ -0,0 +1 @@
+c_simple02-Sheet2 \ No newline at end of file
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_simple02-Sheet3.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_simple02-Sheet3.pdb
new file mode 100644
index 000000000000..7fc9d01084b4
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_simple02-Sheet3.pdb
@@ -0,0 +1 @@
+c_simple02-Sheet3 \ No newline at end of file
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_simple03-Sheet1.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_simple03-Sheet1.pdb
new file mode 100644
index 000000000000..b9f7ed88ff48
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_simple03-Sheet1.pdb
@@ -0,0 +1 @@
+c_simple03-Sheet1 \ No newline at end of file
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_simple03-Sheet2.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_simple03-Sheet2.pdb
new file mode 100644
index 000000000000..08af1dee6ba7
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_simple03-Sheet2.pdb
@@ -0,0 +1 @@
+c_simple03-Sheet2 \ No newline at end of file
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_simple03-Sheet3.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_simple03-Sheet3.pdb
new file mode 100644
index 000000000000..b4b110ee99eb
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_simple03-Sheet3.pdb
@@ -0,0 +1 @@
+c_simple03-Sheet3 \ No newline at end of file
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_simple04-Sheet1.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_simple04-Sheet1.pdb
new file mode 100644
index 000000000000..7755afd9f15d
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_simple04-Sheet1.pdb
@@ -0,0 +1 @@
+c_simple04-Sheet1 \ No newline at end of file
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_simple04-Sheet2.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_simple04-Sheet2.pdb
new file mode 100644
index 000000000000..6760e298ee7e
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_simple04-Sheet2.pdb
@@ -0,0 +1 @@
+c_simple04-Sheet2 \ No newline at end of file
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_simple04-Sheet3.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_simple04-Sheet3.pdb
new file mode 100644
index 000000000000..45bbd9560e8e
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_simple04-Sheet3.pdb
@@ -0,0 +1 @@
+c_simple04-Sheet3 \ No newline at end of file
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_smallrange-Sheet1.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_smallrange-Sheet1.pdb
new file mode 100644
index 000000000000..8227d629b7bf
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_smallrange-Sheet1.pdb
@@ -0,0 +1 @@
+c_smallrange-Sheet1 \ No newline at end of file
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_smallrange-Sheet2.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_smallrange-Sheet2.pdb
new file mode 100644
index 000000000000..1c5c94cb7983
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_smallrange-Sheet2.pdb
@@ -0,0 +1 @@
+c_smallrange-Sheet2 \ No newline at end of file
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_smallrange-Sheet3.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_smallrange-Sheet3.pdb
new file mode 100644
index 000000000000..93c9e7db728a
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_smallrange-Sheet3.pdb
@@ -0,0 +1 @@
+c_smallrange-Sheet3 \ No newline at end of file
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_styles-Sheet1.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_styles-Sheet1.pdb
new file mode 100644
index 000000000000..223e4fd5782e
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_styles-Sheet1.pdb
@@ -0,0 +1 @@
+c_styles-Sheet1 \ No newline at end of file
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_styles-Sheet2.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_styles-Sheet2.pdb
new file mode 100644
index 000000000000..1065639c1fed
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_styles-Sheet2.pdb
@@ -0,0 +1 @@
+c_styles-Sheet2 \ No newline at end of file
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_styles-Sheet3.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_styles-Sheet3.pdb
new file mode 100644
index 000000000000..5656ca70883a
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_styles-Sheet3.pdb
@@ -0,0 +1 @@
+c_styles-Sheet3 \ No newline at end of file
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_textimage-Sheet1.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_textimage-Sheet1.pdb
new file mode 100644
index 000000000000..bd964aa136f7
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_textimage-Sheet1.pdb
@@ -0,0 +1 @@
+c_textimage-Sheet1 \ No newline at end of file
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_textimage-Sheet2.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_textimage-Sheet2.pdb
new file mode 100644
index 000000000000..7e0d3784e7dd
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_textimage-Sheet2.pdb
@@ -0,0 +1 @@
+c_textimage-Sheet2 \ No newline at end of file
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_textimage-Sheet3.pdb b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_textimage-Sheet3.pdb
new file mode 100644
index 000000000000..2c15b3d6ec50
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/pdb-base/c_textimage-Sheet3.pdb
@@ -0,0 +1 @@
+c_textimage-Sheet3 \ No newline at end of file
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/Blocklist.dtd b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/Blocklist.dtd
new file mode 100644
index 000000000000..f7bb8eb321bb
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/Blocklist.dtd
@@ -0,0 +1,34 @@
+<!--
+
+ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+
+ Copyright 2000, 2010 Oracle and/or its affiliates.
+
+ OpenOffice.org - a multi-platform office productivity suite
+
+ This file is part of OpenOffice.org.
+
+ OpenOffice.org is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License version 3
+ only, as published by the Free Software Foundation.
+
+ OpenOffice.org is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License version 3 for more details
+ (a copy is included in the LICENSE file that accompanied this code).
+
+ You should have received a copy of the GNU Lesser General Public License
+ version 3 along with OpenOffice.org. If not, see
+ <http://www.openoffice.org/license.html>
+ for a copy of the LGPLv3 License.
+
+-->
+<!ELEMENT block-list:block-list (block-list:block*) >
+<!ATTLIST block-list:block-list
+ block-list:list-name CDATA #REQUIRED>
+<!ELEMENT block-list:block EMPTY>
+<!ATTLIST block-list:block
+ block-list:abbreviated-name CDATA #REQUIRED
+ block-list:package-name CDATA #REQUIRED
+ block-list:name CDATA #REQUIRED>
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_animatedgif.sxw b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_animatedgif.sxw
new file mode 100644
index 000000000000..a8f7d91ef03f
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_animatedgif.sxw
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_bolddoc.sxw b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_bolddoc.sxw
new file mode 100644
index 000000000000..9f0cb66d69ba
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_bolddoc.sxw
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_bookmarks.sxw b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_bookmarks.sxw
new file mode 100644
index 000000000000..d3ea3431875d
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_bookmarks.sxw
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_bulletorderedlist.sxw b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_bulletorderedlist.sxw
new file mode 100644
index 000000000000..bd640d575fb2
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_bulletorderedlist.sxw
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_emptydoc.sxw b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_emptydoc.sxw
new file mode 100644
index 000000000000..d4a0621ad46d
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_emptydoc.sxw
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_firstlineindent.sxw b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_firstlineindent.sxw
new file mode 100644
index 000000000000..75a18d84a53f
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_firstlineindent.sxw
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_fontsize.sxw b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_fontsize.sxw
new file mode 100644
index 000000000000..b87aa37523d0
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_fontsize.sxw
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_heading.sxw b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_heading.sxw
new file mode 100644
index 000000000000..a6d25bd5cf8e
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_heading.sxw
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_heading1.sxw b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_heading1.sxw
new file mode 100644
index 000000000000..ed91418ab374
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_heading1.sxw
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_heading2.sxw b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_heading2.sxw
new file mode 100644
index 000000000000..2f767e6f1675
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_heading2.sxw
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_hyperlink.sxw b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_hyperlink.sxw
new file mode 100644
index 000000000000..6a04edd6a073
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_hyperlink.sxw
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_justified.sxw b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_justified.sxw
new file mode 100644
index 000000000000..ae33ab576588
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_justified.sxw
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_linebreaks.sxw b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_linebreaks.sxw
new file mode 100644
index 000000000000..27b1e73e0b50
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_linebreaks.sxw
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_linespacing.sxw b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_linespacing.sxw
new file mode 100644
index 000000000000..74436d8076c7
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_linespacing.sxw
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_numberorderedlist.sxw b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_numberorderedlist.sxw
new file mode 100644
index 000000000000..3d8e19970fd8
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_numberorderedlist.sxw
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_pagebreak.sxw b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_pagebreak.sxw
new file mode 100644
index 000000000000..d929cfe5c13f
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_pagebreak.sxw
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_paragraph.sxw b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_paragraph.sxw
new file mode 100644
index 000000000000..5c74827d5663
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_paragraph.sxw
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_simple01.sxw b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_simple01.sxw
new file mode 100644
index 000000000000..2d3384d5f9f0
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_simple01.sxw
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_simple02.sxw b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_simple02.sxw
new file mode 100644
index 000000000000..404cfd5ffd92
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_simple02.sxw
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_simple03.sxw b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_simple03.sxw
new file mode 100644
index 000000000000..9b90d54cfc54
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_simple03.sxw
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_simple04.sxw b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_simple04.sxw
new file mode 100644
index 000000000000..dddb02f91248
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_simple04.sxw
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_simple05.sxw b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_simple05.sxw
new file mode 100644
index 000000000000..c811aabcf28d
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_simple05.sxw
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_standard.sxw b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_standard.sxw
new file mode 100644
index 000000000000..b9ac1e688e71
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_standard.sxw
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_subscript.sxw b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_subscript.sxw
new file mode 100644
index 000000000000..78ed939f1f83
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_subscript.sxw
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_superscript.sxw b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_superscript.sxw
new file mode 100644
index 000000000000..7d44042aaf5f
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_superscript.sxw
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_symbols.sxw b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_symbols.sxw
new file mode 100644
index 000000000000..a48137a8ded5
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_symbols.sxw
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_tab.sxw b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_tab.sxw
new file mode 100644
index 000000000000..5602764f3c9d
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_tab.sxw
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_table.sxw b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_table.sxw
new file mode 100644
index 000000000000..a101ba833aa9
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_table.sxw
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_textspan.sxw b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_textspan.sxw
new file mode 100644
index 000000000000..beae7b8c8a7a
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_textspan.sxw
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_unorderedlist.sxw b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_unorderedlist.sxw
new file mode 100644
index 000000000000..ca5ee406ccc5
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_unorderedlist.sxw
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_wordwrap.sxw b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_wordwrap.sxw
new file mode 100644
index 000000000000..ece3fefae183
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/a_wordwrap.sxw
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_addition.sxc b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_addition.sxc
new file mode 100644
index 000000000000..6c4341f62ac2
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_addition.sxc
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_alignment.sxc b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_alignment.sxc
new file mode 100644
index 000000000000..b9df5dd3b00e
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_alignment.sxc
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_backwardrange.sxc b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_backwardrange.sxc
new file mode 100644
index 000000000000..c61f460e9fd8
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_backwardrange.sxc
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_basic.sxc b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_basic.sxc
new file mode 100644
index 000000000000..8a1ba23b78fc
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_basic.sxc
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_boolean.sxc b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_boolean.sxc
new file mode 100644
index 000000000000..c34e7608c129
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_boolean.sxc
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_cellcurrencyalue.sxc b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_cellcurrencyalue.sxc
new file mode 100644
index 000000000000..808d781162e6
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_cellcurrencyalue.sxc
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_cellpercentvalue.sxc b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_cellpercentvalue.sxc
new file mode 100644
index 000000000000..9b4b9f024a6a
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_cellpercentvalue.sxc
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_cellstringvalue.sxc b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_cellstringvalue.sxc
new file mode 100644
index 000000000000..b44496fdb57b
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_cellstringvalue.sxc
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_columnswidth.sxc b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_columnswidth.sxc
new file mode 100644
index 000000000000..9aeec30fb699
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_columnswidth.sxc
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_cyclic.sxc b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_cyclic.sxc
new file mode 100644
index 000000000000..196bd78962a9
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_cyclic.sxc
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_dividefloating.sxc b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_dividefloating.sxc
new file mode 100644
index 000000000000..1e2c55b448c8
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_dividefloating.sxc
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_forwardrange.sxc b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_forwardrange.sxc
new file mode 100644
index 000000000000..0e41c624511b
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_forwardrange.sxc
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_insertimage.sxc b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_insertimage.sxc
new file mode 100644
index 000000000000..bae72239f17e
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_insertimage.sxc
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_invalidcellref.sxc b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_invalidcellref.sxc
new file mode 100644
index 000000000000..881b4ffdb966
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_invalidcellref.sxc
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_largerange.sxc b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_largerange.sxc
new file mode 100644
index 000000000000..379b1cef6d62
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_largerange.sxc
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_listrange.sxc b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_listrange.sxc
new file mode 100644
index 000000000000..e0e05b128917
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_listrange.sxc
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_mathematical.sxc b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_mathematical.sxc
new file mode 100644
index 000000000000..c9cf3e8bbc5e
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_mathematical.sxc
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_protection.sxc b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_protection.sxc
new file mode 100644
index 000000000000..64f89cc61ce7
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_protection.sxc
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_sheetreference.sxc b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_sheetreference.sxc
new file mode 100644
index 000000000000..4239ab2fa908
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_sheetreference.sxc
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_simple01.sxc b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_simple01.sxc
new file mode 100644
index 000000000000..e508b749bb0d
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_simple01.sxc
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_simple02.sxc b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_simple02.sxc
new file mode 100644
index 000000000000..d490ed66fe3c
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_simple02.sxc
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_simple03.sxc b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_simple03.sxc
new file mode 100644
index 000000000000..1dee18c7ddd7
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_simple03.sxc
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_simple04.sxc b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_simple04.sxc
new file mode 100644
index 000000000000..5164313a79cf
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_simple04.sxc
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_smallrange.sxc b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_smallrange.sxc
new file mode 100644
index 000000000000..8283b04c54e3
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_smallrange.sxc
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_styles.sxc b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_styles.sxc
new file mode 100644
index 000000000000..21e0f1ab5ac0
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_styles.sxc
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_textimage.sxc b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_textimage.sxc
new file mode 100644
index 000000000000..9f42285d2881
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/c_textimage.sxc
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/chart.mod b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/chart.mod
new file mode 100644
index 000000000000..70cbe483ca9c
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/chart.mod
@@ -0,0 +1,228 @@
+<!--
+
+ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+
+ Copyright 2000, 2010 Oracle and/or its affiliates.
+
+ OpenOffice.org - a multi-platform office productivity suite
+
+ This file is part of OpenOffice.org.
+
+ OpenOffice.org is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License version 3
+ only, as published by the Free Software Foundation.
+
+ OpenOffice.org is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License version 3 for more details
+ (a copy is included in the LICENSE file that accompanied this code).
+
+ You should have received a copy of the GNU Lesser General Public License
+ version 3 along with OpenOffice.org. If not, see
+ <http://www.openoffice.org/license.html>
+ for a copy of the LGPLv3 License.
+
+-->
+
+
+<!ENTITY % chart-class "(line|area|circle|ring|scatter|radar|bar|stock|add-in)">
+<!ENTITY % chart-solid-type "(cuboid|cylinder|cone|pyramid)">
+
+<!-- Chart element -->
+<!ELEMENT chart:chart ( chart:title?, chart:subtitle?, chart:legend?,
+ chart:plot-area,
+ table:table? )>
+<!ATTLIST chart:chart
+ chart:class %chart-class; #REQUIRED
+ chart:add-in-name %string; #IMPLIED
+ chart:table-number-list %string; #IMPLIED
+ draw:name %string; #IMPLIED
+ %draw-position;
+ %draw-size;
+ %draw-style-name;
+ chart:style-name %styleName; #IMPLIED>
+
+<!ATTLIST chart:chart %presentation-class; >
+<!ATTLIST chart:chart %zindex;>
+<!ATTLIST chart:chart %draw-end-position; >
+<!ATTLIST chart:chart draw:id %draw-shape-id; >
+<!ATTLIST chart:chart draw:layer %layerName; #IMPLIED>
+
+<!ATTLIST style:properties
+ chart:scale-text %boolean; "true"
+ chart:stock-updown-bars %boolean; "false"
+ chart:stock-with-volume %boolean; "false"
+ chart:three-dimensional %boolean; "false"
+ chart:deep %boolean; "false"
+ chart:lines %boolean; "false"
+ chart:percentage %boolean; "false"
+ chart:solid-type %chart-solid-type; "cuboid"
+ chart:splines %nonNegativeInteger; "0"
+ chart:stacked %boolean; "false"
+ chart:symbol %integer; "-1"
+ chart:vertical %boolean; "false"
+ chart:lines-used %nonNegativeInteger; "0"
+ chart:connect-bars %boolean; "false">
+
+<!-- Main/Sub Title -->
+<!-- the cell-address attribute is currently not supported for titles -->
+<!ELEMENT chart:title (text:p)?>
+<!ATTLIST chart:title
+ table:cell-range %cell-address; #IMPLIED
+ svg:x %coordinate; #IMPLIED
+ svg:y %coordinate; #IMPLIED
+ chart:style-name %styleName; #IMPLIED >
+
+<!ELEMENT chart:subtitle (text:p)?>
+<!ATTLIST chart:subtitle
+ table:cell-range %cell-address; #IMPLIED
+ svg:x %coordinate; #IMPLIED
+ svg:y %coordinate; #IMPLIED
+ chart:style-name %styleName; #IMPLIED >
+
+<!-- you must specify either a legend-position or both, x and y coordinates -->
+<!ELEMENT chart:legend EMPTY>
+<!ATTLIST chart:legend
+ chart:legend-position (top|left|bottom|right) "right"
+ svg:x %coordinate; #IMPLIED
+ svg:y %coordinate; #IMPLIED
+ chart:style-name %styleName; #IMPLIED >
+
+<!-- Plot-Area specification -->
+
+<!ELEMENT chart:plot-area (dr3d:light*,
+ chart:axis*,
+ chart:categories?,
+ chart:series*,
+ chart:wall?,
+ chart:floor?) >
+
+<!ATTLIST chart:plot-area
+ svg:x %coordinate; #IMPLIED
+ svg:y %coordinate; #IMPLIED
+ svg:width %length; #IMPLIED
+ svg:height %length; #IMPLIED
+ chart:style-name %styleName; #IMPLIED
+ table:cell-range-address %cell-range-address; #IMPLIED
+ chart:table-number-list %string; #IMPLIED
+ chart:data-source-has-labels (none|row|column|both) "none" >
+
+<!-- 3d scene attributes on plot-area -->
+<!ATTLIST chart:plot-area
+ dr3d:vrp %vector3D; #IMPLIED
+ dr3d:vpn %vector3D; #IMPLIED
+ dr3d:vup %vector3D; #IMPLIED
+ dr3d:projection (parallel|perspective) #IMPLIED
+ dr3d:transform CDATA #IMPLIED
+ dr3d:distance %length; #IMPLIED
+ dr3d:focal-length %length; #IMPLIED
+ dr3d:shadow-slant %nonNegativeInteger; #IMPLIED
+ dr3d:shade-mode (flat|phong|gouraud|draft) #IMPLIED
+ dr3d:ambient-color %color; #IMPLIED
+ dr3d:lighting-mode %boolean; #IMPLIED >
+
+<!ATTLIST style:properties
+ chart:series-source (columns|rows) "columns" >
+
+<!ELEMENT chart:wall EMPTY>
+<!ATTLIST chart:wall
+ svg:width %length; #IMPLIED
+ chart:style-name %styleName; #IMPLIED >
+
+<!ELEMENT chart:floor EMPTY>
+<!ATTLIST chart:floor
+ svg:width %length; #IMPLIED
+ chart:style-name %styleName; #IMPLIED >
+
+<!-- Axis -->
+
+<!ELEMENT chart:axis (chart:title?, chart:grid*)>
+<!ATTLIST chart:axis
+ chart:class (category|value|series|domain) #REQUIRED
+ chart:name %string; #IMPLIED
+ chart:style-name %styleName; #IMPLIED >
+
+<!ATTLIST style:properties
+ chart:tick-marks-major-inner %boolean; "false"
+ chart:tick-marks-major-outer %boolean; "true"
+ chart:tick-marks-minor-inner %boolean; "false"
+ chart:tick-marks-minor-outer %boolean; "false"
+ chart:logarithmic %boolean; "false"
+ chart:maximum %float; #IMPLIED
+ chart:minimum %float; #IMPLIED
+ chart:origin %float; #IMPLIED
+ chart:interval-major %float; #IMPLIED
+ chart:interval-minor %float; #IMPLIED
+ chart:gap-width %integer; #IMPLIED
+ chart:overlap %integer; #IMPLIED
+ text:line-break %boolean; "true"
+ chart:display-label %boolean; "true"
+ chart:label-arrangement (side-by-side|stagger-even|stagger-odd) "side-by-side"
+ chart:visible %boolean; "true"
+ chart:link-data-style-to-source %boolean; "true" >
+
+<!ELEMENT chart:grid EMPTY>
+<!ATTLIST chart:grid
+ chart:class (major|minor) "major"
+ chart:style-name %styleName; #IMPLIED >
+
+
+<!ELEMENT chart:categories EMPTY>
+<!ATTLIST chart:categories
+ table:cell-range-address %cell-range-address; #REQUIRED >
+
+<!--
+ each series element must have an cell-range-address element that points
+ to the underlying table data.
+ Impl. Note: Internally all href elements are merged to one table range
+ that represents the data for the whole chart
+-->
+<!ELEMENT chart:series ( chart:domain*,
+ chart:data-point* )>
+<!ATTLIST chart:series
+ chart:values-cell-range-address %cell-range-address; #IMPLIED
+ chart:label-cell-address %cell-address; #IMPLIED
+ chart:class %chart-class; #IMPLIED
+ chart:attached-axis %string; #IMPLIED
+ chart:style-name %styleName; #IMPLIED >
+
+<!ELEMENT chart:domain EMPTY>
+<!ATTLIST chart:domain
+ table:cell-range-address %cell-range-address; #IMPLIED >
+
+<!ELEMENT chart:data-point EMPTY>
+<!ATTLIST chart:data-point
+ chart:repeated %nonNegativeInteger; #IMPLIED
+ chart:style-name %styleName; #IMPLIED >
+
+<!-- statistical properties -->
+
+<!ATTLIST style:properties
+ chart:mean-value %boolean; #IMPLIED
+ chart:error-category (none|variance|standard-deviation|percentage|error-margin|constant) "none"
+ chart:error-percentage %float; #IMPLIED
+ chart:error-margin %float; #IMPLIED
+ chart:error-lower-limit %float; #IMPLIED
+ chart:error-upper-limit %float; #IMPLIED
+ chart:error-upper-indicator %boolean; #IMPLIED
+ chart:error-lower-indicator %boolean; #IMPLIED
+ chart:regression-type (none|linear|logarithmic|exponential|power) "none" >
+
+<!-- data label properties -->
+
+<!ATTLIST style:properties
+ chart:data-label-number (none|value|percentage) "none"
+ chart:data-label-text %boolean; "false"
+ chart:data-label-symbol %boolean; "false" >
+
+<!-- general text properties -->
+
+<!ATTLIST style:properties text:rotation-angle %integer; "0" >
+
+<!-- symbol properties -->
+
+<!ATTLIST style:properties
+ chart:symbol-width %nonNegativeLength; #IMPLIED
+ chart:symbol-height %nonNegativeLength; #IMPLIED
+ chart:symbol-image-name %string; #IMPLIED >
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/datastyl.mod b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/datastyl.mod
new file mode 100644
index 000000000000..11bc8a8e40b7
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/datastyl.mod
@@ -0,0 +1,168 @@
+<!--
+
+ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+
+ Copyright 2000, 2010 Oracle and/or its affiliates.
+
+ OpenOffice.org - a multi-platform office productivity suite
+
+ This file is part of OpenOffice.org.
+
+ OpenOffice.org is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License version 3
+ only, as published by the Free Software Foundation.
+
+ OpenOffice.org is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License version 3 for more details
+ (a copy is included in the LICENSE file that accompanied this code).
+
+ You should have received a copy of the GNU Lesser General Public License
+ version 3 along with OpenOffice.org. If not, see
+ <http://www.openoffice.org/license.html>
+ for a copy of the LGPLv3 License.
+
+-->
+
+<!-- data styles -->
+<!ENTITY % any-number "( number:number | number:scientific-number | number:fraction )">
+<!ENTITY % number-style-content "( (number:text,(%any-number;,number:text?)?) | (%any-number;,number:text?) )">
+<!ELEMENT number:number-style ( style:properties?, %number-style-content;, style:map* )>
+<!ELEMENT number:number EMPTY>
+<!ELEMENT number:scientific-number EMPTY>
+<!ELEMENT number:fraction EMPTY>
+
+<!ENTITY % currency-symbol-and-text "number:currency-symbol,number:text?">
+<!ENTITY % number-and-text "number:number,number:text?">
+<!ENTITY % currency-symbol-and-number "((%number-and-text;),(%currency-symbol-and-text;)?) | ((%currency-symbol-and-text;),(%number-and-text;)?)">
+<!ENTITY % currency-style-content "number:text?, (%currency-symbol-and-number;)?">
+
+<!ELEMENT number:currency-style ( style:properties?, (%currency-style-content;), style:map* )>
+<!ELEMENT number:currency-symbol (#PCDATA)>
+<!ATTLIST number:currency-symbol number:language CDATA #IMPLIED>
+<!ATTLIST number:currency-symbol number:country CDATA #IMPLIED>
+
+<!ENTITY % percentage-style-content "( (number:text,(%number-and-text;)?) | (%number-and-text;) )">
+<!ELEMENT number:percentage-style ( style:properties?, %percentage-style-content;, style:map* )>
+
+<!ENTITY % any-date "( number:day | number:month | number:year | number:era | number:day-of-week | number:week-of-year | number:quarter| number:hours | number:am-pm | number:minutes | number:seconds )">
+<!ENTITY % date-style-content "( (number:text,(%any-date;,number:text?)+) | (%any-date;,number:text?)+ )">
+<!ELEMENT number:date-style ( style:properties?, %date-style-content;, style:map* )>
+<!ELEMENT number:day EMPTY>
+<!ATTLIST number:day number:style (short|long) "short">
+<!ATTLIST number:day number:calendar CDATA #IMPLIED>
+<!ELEMENT number:month EMPTY>
+<!ATTLIST number:month number:textual %boolean; "false">
+<!ATTLIST number:month number:style (short|long) "short">
+<!ATTLIST number:month number:calendar CDATA #IMPLIED>
+<!ELEMENT number:year EMPTY>
+<!ATTLIST number:year number:style (short|long) "short">
+<!ATTLIST number:year number:calendar CDATA #IMPLIED>
+<!ELEMENT number:era EMPTY>
+<!ATTLIST number:era number:style (short|long) "short">
+<!ATTLIST number:era number:calendar CDATA #IMPLIED>
+<!ELEMENT number:day-of-week EMPTY>
+<!ATTLIST number:day-of-week number:style (short|long) "short">
+<!ATTLIST number:day-of-week number:calendar CDATA #IMPLIED>
+<!ELEMENT number:week-of-year EMPTY>
+<!ATTLIST number:week-of-year number:calendar CDATA #IMPLIED>
+<!ELEMENT number:quarter EMPTY>
+<!ATTLIST number:quarter number:style (short|long) "short">
+<!ATTLIST number:quarter number:calendar CDATA #IMPLIED>
+
+<!ENTITY % any-time "( number:hours | number:am-pm | number:minutes | number:seconds )">
+<!ENTITY % time-style-content "( (number:text,(%any-time;,number:text?)+) | (%any-time;,number:text?)+)">
+<!ELEMENT number:time-style ( style:properties?, %time-style-content;, style:map* )>
+<!ELEMENT number:hours EMPTY>
+<!ATTLIST number:hours number:style (short|long) "short">
+<!ELEMENT number:minutes EMPTY>
+<!ATTLIST number:minutes number:style (short|long) "short">
+<!ELEMENT number:seconds EMPTY>
+<!ATTLIST number:seconds number:style (short|long) "short">
+<!ATTLIST number:seconds number:decimal-places %integer; "0">
+<!ELEMENT number:am-pm EMPTY>
+
+<!ENTITY % boolean-style-content "( (number:text,(number:boolean,number:text?)?) | (number:boolean,number:text?) )">
+<!ELEMENT number:boolean-style ( style:properties?,%boolean-style-content;, style:map* )>
+<!ELEMENT number:boolean EMPTY>
+
+<!ENTITY % text-style-content "( (number:text,(number:text-content,number:text?)?) | (number:text-content,number:text?) )">
+<!ELEMENT number:text-style ( style:properties?,%text-style-content;, style:map* )>
+<!ELEMENT number:text (#PCDATA)>
+<!ELEMENT number:text-content EMPTY>
+
+<!ATTLIST number:number-style style:name %styleName; #REQUIRED>
+<!ATTLIST number:currency-style style:name %styleName; #REQUIRED>
+<!ATTLIST number:percentage-style style:name %styleName; #REQUIRED>
+<!ATTLIST number:date-style style:name %styleName; #REQUIRED>
+<!ATTLIST number:time-style style:name %styleName; #REQUIRED>
+<!ATTLIST number:boolean-style style:name %styleName; #REQUIRED>
+<!ATTLIST number:text-style style:name %styleName; #REQUIRED>
+
+<!ATTLIST number:number-style style:family CDATA #REQUIRED>
+<!ATTLIST number:currency-style style:family CDATA #REQUIRED>
+<!ATTLIST number:percentage-style style:family CDATA #REQUIRED>
+<!ATTLIST number:date-style style:family CDATA #REQUIRED>
+<!ATTLIST number:time-style style:family CDATA #REQUIRED>
+<!ATTLIST number:boolean-style style:family CDATA #REQUIRED>
+<!ATTLIST number:text-style style:family CDATA #REQUIRED>
+
+<!ATTLIST number:number-style number:language CDATA #IMPLIED>
+<!ATTLIST number:currency-style number:language CDATA #IMPLIED>
+<!ATTLIST number:percentage-style number:language CDATA #IMPLIED>
+<!ATTLIST number:date-style number:language CDATA #IMPLIED>
+<!ATTLIST number:time-style number:language CDATA #IMPLIED>
+<!ATTLIST number:boolean-style number:language CDATA #IMPLIED>
+<!ATTLIST number:text-style number:language CDATA #IMPLIED>
+
+<!ATTLIST number:number-style number:country CDATA #IMPLIED>
+<!ATTLIST number:currency-style number:country CDATA #IMPLIED>
+<!ATTLIST number:percentage-style number:country CDATA #IMPLIED>
+<!ATTLIST number:date-style number:country CDATA #IMPLIED>
+<!ATTLIST number:time-style number:country CDATA #IMPLIED>
+<!ATTLIST number:boolean-style number:country CDATA #IMPLIED>
+<!ATTLIST number:text-style number:country CDATA #IMPLIED>
+
+<!ATTLIST number:number-style number:title CDATA #IMPLIED>
+<!ATTLIST number:currency-style number:title CDATA #IMPLIED>
+<!ATTLIST number:percentage-style number:title CDATA #IMPLIED>
+<!ATTLIST number:date-style number:title CDATA #IMPLIED>
+<!ATTLIST number:time-style number:title CDATA #IMPLIED>
+<!ATTLIST number:boolean-style number:title CDATA #IMPLIED>
+<!ATTLIST number:text-style number:title CDATA #IMPLIED>
+
+<!ATTLIST number:number-style style:volatile %boolean; #IMPLIED>
+<!ATTLIST number:currency-style style:volatile %boolean; #IMPLIED>
+<!ATTLIST number:percentage-style style:volatile %boolean; #IMPLIED>
+<!ATTLIST number:date-style style:volatile %boolean; #IMPLIED>
+<!ATTLIST number:time-style style:volatile %boolean; #IMPLIED>
+<!ATTLIST number:boolean-style style:volatile %boolean; #IMPLIED>
+<!ATTLIST number:text-style style:volatile %boolean; #IMPLIED>
+
+<!ATTLIST number:currency-style number:automatic-order %boolean; "false">
+<!ATTLIST number:date-style number:automatic-order %boolean; "false">
+
+<!ATTLIST number:date-style number:format-source (fixed|language) "fixed">
+<!ATTLIST number:time-style number:format-source (fixed|language) "fixed">
+
+<!ATTLIST number:time-style number:truncate-on-overflow %boolean; "true">
+
+<!ATTLIST number:number number:decimal-places %integer; #IMPLIED>
+<!ATTLIST number:scientific-number number:decimal-places %integer; #IMPLIED>
+
+<!ATTLIST number:number number:min-integer-digits %integer; #IMPLIED>
+<!ATTLIST number:scientific-number number:min-integer-digits %integer; #IMPLIED>
+<!ATTLIST number:fraction number:min-integer-digits %integer; #IMPLIED>
+
+<!ATTLIST number:number number:grouping %boolean; "false">
+<!ATTLIST number:scientific-number number:grouping %boolean; "false">
+<!ATTLIST number:fraction number:grouping %boolean; "false">
+
+<!ATTLIST number:number number:decimal-replacement CDATA #IMPLIED>
+
+<!ATTLIST number:scientific-number number:min-exponent-digits %integer; #IMPLIED>
+
+<!ATTLIST number:fraction number:min-numerator-digits %integer; #IMPLIED>
+
+<!ATTLIST number:fraction number:min-denominator-digits %integer; #IMPLIED>
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/drawing.mod b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/drawing.mod
new file mode 100644
index 000000000000..aa0a25822a45
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/drawing.mod
@@ -0,0 +1,837 @@
+<!--
+
+ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+
+ Copyright 2000, 2010 Oracle and/or its affiliates.
+
+ OpenOffice.org - a multi-platform office productivity suite
+
+ This file is part of OpenOffice.org.
+
+ OpenOffice.org is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License version 3
+ only, as published by the Free Software Foundation.
+
+ OpenOffice.org is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License version 3 for more details
+ (a copy is included in the LICENSE file that accompanied this code).
+
+ You should have received a copy of the GNU Lesser General Public License
+ version 3 along with OpenOffice.org. If not, see
+ <http://www.openoffice.org/license.html>
+ for a copy of the LGPLv3 License.
+
+-->
+
+<!ENTITY % points "CDATA" >
+<!ENTITY % pathData "CDATA" >
+<!ENTITY % gradient-style "(linear|axial|radial|ellipsoid|square|rectangular)" >
+<!ENTITY % draw-position "svg:x %coordinate; #IMPLIED svg:y %coordinate; #IMPLIED">
+<!ENTITY % draw-end-position "table:end-cell-address %cell-address; #IMPLIED table:end-x %coordinate; #IMPLIED table:end-y %coordinate; #IMPLIED">
+<!ENTITY % draw-size "svg:width %coordinate; #IMPLIED svg:height %coordinate; #IMPLIED">
+<!ENTITY % draw-transform "draw:transform CDATA #IMPLIED">
+<!ENTITY % draw-viewbox "svg:viewBox CDATA #REQUIRED">
+<!ENTITY % draw-style-name "draw:style-name %styleName; #IMPLIED presentation:style-name %styleName; #IMPLIED draw:text-style-name %styleName; #IMPLIED">
+<!ENTITY % draw-shape-id "CDATA #IMPLIED" >
+<!ENTITY % draw-text "(text:p|text:unordered-list|text:ordered-list)*">
+<!ENTITY % zindex "draw:z-index %nonNegativeInteger; #IMPLIED">
+<!ENTITY % distance "CDATA">
+<!ENTITY % rectanglePoint "(top-left|top|top-right|left|center|right|bottom-left|bottom|bottom-right)">
+<!ENTITY % vector3D "CDATA">
+<!ENTITY % text-anchor "text:anchor-type %anchorType; #IMPLIED text:anchor-page-number %positiveInteger; #IMPLIED">
+<!ENTITY % layerName "CDATA">
+<!ENTITY % table-background "table:table-background (true | false) #IMPLIED">
+
+<!-- commont presentation shape attributes -->
+<!ENTITY % presentation-style-name "presentation:style-name %styleName; #IMPLIED">
+<!ENTITY % presentation-classes "(title|outline|subtitle|text|graphic|object|chart|table|orgchart|page|notes)" >
+<!-- ENTITY % presentation-class "presentation:class %presentation-classes; #IMPLIED" -->
+<!ENTITY % presentation-class "presentation:class %presentation-classes; #IMPLIED presentation:placeholder (true|false) #IMPLIED presentation:user-transformed (true|false) #IMPLIED">
+<!ENTITY % presentationEffects "(none|fade|move|stripes|open|close|dissolve|wavyline|random|lines|laser|appear|hide|move-short|checkerboard|rotate|stretch)" >
+<!ENTITY % presentationEffectDirections "(none|from-left|from-top|from-right|from-bottom|from-center|from-upper-left|from-upper-right|from-lower-left|from-lower-right|to-left|to-top|to-right|to-bottom|to-upper-left|to-upper-right|to-lower-right|to-lower-left|path|spiral-inward-left|spiral-inward-right|spiral-outward-left|spiral-outward-right|vertical|horizontal|to-center|clockwise|counter-clockwise)" >
+<!ENTITY % presentationSpeeds "(slow|medium|fast)" >
+
+<!-- Drawing shapes -->
+<!ELEMENT draw:rect ( office:events?, %draw-text; )>
+<!ATTLIST draw:rect %draw-position; >
+<!ATTLIST draw:rect %draw-end-position; >
+<!ATTLIST draw:rect %table-background; >
+<!ATTLIST draw:rect %draw-size; >
+<!ATTLIST draw:rect %draw-style-name; >
+<!ATTLIST draw:rect %draw-transform; >
+<!ATTLIST draw:rect draw:corner-radius %nonNegativeLength; #IMPLIED>
+<!ATTLIST draw:rect %zindex;>
+<!ATTLIST draw:rect draw:id %draw-shape-id;>
+<!ATTLIST draw:rect %text-anchor;>
+<!ATTLIST draw:rect draw:layer %layerName; #IMPLIED>
+
+<!ELEMENT draw:line ( office:events?, %draw-text; )>
+<!ATTLIST draw:line svg:x1 %length; #REQUIRED>
+<!ATTLIST draw:line svg:y1 %length; #REQUIRED>
+<!ATTLIST draw:line svg:x2 %length; #REQUIRED>
+<!ATTLIST draw:line svg:y2 %length; #REQUIRED>
+<!ATTLIST draw:line %draw-style-name; >
+<!ATTLIST draw:line %draw-transform; >
+<!ATTLIST draw:line %zindex;>
+<!ATTLIST draw:line %draw-end-position; >
+<!ATTLIST draw:line %table-background; >
+<!ATTLIST draw:line draw:id %draw-shape-id;>
+<!ATTLIST draw:line %text-anchor;>
+<!ATTLIST draw:line draw:layer %layerName; #IMPLIED>
+
+<!ELEMENT draw:polyline ( office:events?, %draw-text; )>
+<!ATTLIST draw:polyline %draw-position; >
+<!ATTLIST draw:polyline %draw-size; >
+<!ATTLIST draw:polyline %draw-viewbox; >
+<!ATTLIST draw:polyline draw:points %points; #REQUIRED>
+<!ATTLIST draw:polyline %draw-style-name; >
+<!ATTLIST draw:polyline %draw-transform; >
+<!ATTLIST draw:polyline %zindex;>
+<!ATTLIST draw:polyline %draw-end-position; >
+<!ATTLIST draw:polyline %table-background; >
+<!ATTLIST draw:polyline draw:id %draw-shape-id;>
+<!ATTLIST draw:polyline %text-anchor;>
+<!ATTLIST draw:polyline draw:layer %layerName; #IMPLIED>
+
+<!ELEMENT draw:polygon ( office:events?, %draw-text; )>
+<!ATTLIST draw:polygon %draw-position; >
+<!ATTLIST draw:polygon %draw-end-position; >
+<!ATTLIST draw:polygon %table-background; >
+<!ATTLIST draw:polygon %draw-size; >
+<!ATTLIST draw:polygon %draw-viewbox; >
+<!ATTLIST draw:polygon draw:points %points; #REQUIRED >
+<!ATTLIST draw:polygon %draw-style-name; >
+<!ATTLIST draw:polygon %draw-transform; >
+<!ATTLIST draw:polygon %zindex;>
+<!ATTLIST draw:polygon draw:id %draw-shape-id;>
+<!ATTLIST draw:polygon %text-anchor;>
+<!ATTLIST draw:polygon draw:layer %layerName; #IMPLIED>
+
+<!ELEMENT draw:path ( office:events?, %draw-text; )>
+<!ATTLIST draw:path %draw-position;>
+<!ATTLIST draw:path %draw-end-position; >
+<!ATTLIST draw:path %table-background; >
+<!ATTLIST draw:path %draw-size; >
+<!ATTLIST draw:path %draw-viewbox; >
+<!ATTLIST draw:path svg:d %pathData; #REQUIRED >
+<!ATTLIST draw:path %draw-style-name; >
+<!ATTLIST draw:path %draw-transform; >
+<!ATTLIST draw:path %zindex;>
+<!ATTLIST draw:path draw:id %draw-shape-id;>
+<!ATTLIST draw:path %text-anchor;>
+<!ATTLIST draw:path draw:layer %layerName; #IMPLIED>
+
+<!ELEMENT draw:circle ( office:events?, %draw-text; )>
+<!ATTLIST draw:circle %draw-position; >
+<!ATTLIST draw:circle %draw-size; >
+<!ATTLIST draw:circle %draw-style-name; >
+<!ATTLIST draw:circle %draw-transform; >
+<!ATTLIST draw:circle %zindex;>
+<!ATTLIST draw:circle %draw-end-position; >
+<!ATTLIST draw:circle %table-background; >
+<!ATTLIST draw:circle draw:id %draw-shape-id;>
+<!ATTLIST draw:circle draw:kind (full|section|cut|arc) "full">
+<!ATTLIST draw:circle draw:start-angle %nonNegativeInteger; #IMPLIED>
+<!ATTLIST draw:circle draw:end-angle %nonNegativeInteger; #IMPLIED>
+<!ATTLIST draw:circle %text-anchor;>
+<!ATTLIST draw:circle draw:layer %layerName; #IMPLIED>
+
+<!ELEMENT draw:ellipse ( office:events?, %draw-text; )>
+<!ATTLIST draw:ellipse %draw-position; >
+<!ATTLIST draw:ellipse %draw-size; >
+<!ATTLIST draw:ellipse %draw-style-name; >
+<!ATTLIST draw:ellipse %draw-transform; >
+<!ATTLIST draw:ellipse %zindex;>
+<!ATTLIST draw:ellipse %draw-end-position; >
+<!ATTLIST draw:ellipse %table-background; >
+<!ATTLIST draw:ellipse draw:id %draw-shape-id;>
+<!ATTLIST draw:ellipse draw:kind (full|section|cut|arc) "full">
+<!ATTLIST draw:ellipse draw:start-angle %nonNegativeInteger; #IMPLIED>
+<!ATTLIST draw:ellipse draw:end-angle %nonNegativeInteger; #IMPLIED>
+<!ATTLIST draw:ellipse %text-anchor;>
+<!ATTLIST draw:ellipse draw:layer %layerName; #IMPLIED>
+
+<!ELEMENT draw:connector ( office:events?, %draw-text;)>
+<!ATTLIST draw:connector draw:type (standard|lines|line|curve) "standard">
+<!ATTLIST draw:connector draw:line-skew CDATA #IMPLIED>
+<!ATTLIST draw:connector %draw-style-name;>
+<!ATTLIST draw:connector svg:x1 %coordinate; #REQUIRED>
+<!ATTLIST draw:connector svg:y1 %coordinate; #REQUIRED>
+<!ATTLIST draw:connector svg:x2 %coordinate; #REQUIRED>
+<!ATTLIST draw:connector svg:y2 %coordinate; #REQUIRED>
+<!ATTLIST draw:connector draw:start-shape %draw-shape-id;>
+<!ATTLIST draw:connector draw:start-glue-point %integer; #IMPLIED>
+<!ATTLIST draw:connector draw:end-shape %draw-shape-id;>
+<!ATTLIST draw:connector draw:end-glue-point %integer; #IMPLIED>
+<!ATTLIST draw:connector %zindex;>
+<!ATTLIST draw:connector %draw-end-position; >
+<!ATTLIST draw:connector %table-background; >
+<!ATTLIST draw:connector draw:id %draw-shape-id;>
+<!ATTLIST draw:connector %text-anchor;>
+<!ATTLIST draw:connector draw:layer %layerName; #IMPLIED>
+
+<!ELEMENT draw:control EMPTY>
+<!ATTLIST draw:control %draw-style-name;>
+<!ATTLIST draw:control %draw-position; >
+<!ATTLIST draw:control %draw-size; >
+<!ATTLIST draw:control %control-id; >
+<!ATTLIST draw:control %zindex;>
+<!ATTLIST draw:control %draw-end-position; >
+<!ATTLIST draw:control %table-background; >
+<!ATTLIST draw:control draw:id %draw-shape-id;>
+<!ATTLIST draw:control %text-anchor;>
+<!ATTLIST draw:control draw:layer %layerName; #IMPLIED>
+
+<!ELEMENT draw:g ( office:events?, (%shapes;)* ) >
+<!ATTLIST draw:g %draw-transform; >
+<!ATTLIST draw:g %draw-style-name; >
+<!ATTLIST draw:g %zindex;>
+<!ATTLIST draw:g %draw-end-position; >
+<!ATTLIST draw:g %table-background; >
+<!ATTLIST draw:g draw:id %draw-shape-id;>
+<!ATTLIST draw:g %text-anchor;>
+<!ATTLIST draw:g draw:layer %layerName; #IMPLIED>
+
+<!ELEMENT draw:page-thumbnail EMPTY>
+<!ATTLIST draw:page-thumbnail draw:page-number %positiveInteger; #IMPLIED>
+<!ATTLIST draw:page-thumbnail %draw-position; >
+<!ATTLIST draw:page-thumbnail %draw-size; >
+<!ATTLIST draw:page-thumbnail %draw-style-name; >
+<!ATTLIST draw:page-thumbnail %presentation-class; >
+<!ATTLIST draw:page-thumbnail %zindex;>
+<!ATTLIST draw:page-thumbnail %draw-end-position; >
+<!ATTLIST draw:page-thumbnail %table-background; >
+<!ATTLIST draw:page-thumbnail draw:id %draw-shape-id;>
+<!ATTLIST draw:page-thumbnail %text-anchor;>
+<!ATTLIST draw:page-thumbnail draw:layer %layerName; #IMPLIED>
+
+<!ELEMENT draw:caption ( office:events?, %draw-text;)>
+<!ATTLIST draw:caption %draw-position; >
+<!ATTLIST draw:caption %draw-end-position; >
+<!ATTLIST draw:caption %table-background; >
+<!ATTLIST draw:caption %draw-size; >
+<!ATTLIST draw:caption %draw-style-name; >
+<!ATTLIST draw:caption %draw-transform; >
+<!ATTLIST draw:caption draw:caption-point-x %coordinate; #IMPLIED>
+<!ATTLIST draw:caption draw:caption-point-y %coordinate; #IMPLIED>
+<!ATTLIST draw:caption %zindex;>
+<!ATTLIST draw:caption draw:id %draw-shape-id;>
+<!ATTLIST draw:caption %text-anchor;>
+<!ATTLIST draw:caption draw:layer %layerName; #IMPLIED>
+<!ATTLIST draw:caption draw:corner-radius %nonNegativeLength; #IMPLIED>
+
+<!ELEMENT draw:measure ( office:events?, %draw-text;)>
+<!ATTLIST draw:measure svg:x1 %coordinate; #REQUIRED>
+<!ATTLIST draw:measure svg:y1 %coordinate; #REQUIRED>
+<!ATTLIST draw:measure svg:x2 %coordinate; #REQUIRED>
+<!ATTLIST draw:measure svg:y2 %coordinate; #REQUIRED>
+<!ATTLIST draw:measure %draw-end-position; >
+<!ATTLIST draw:measure %table-background; >
+<!ATTLIST draw:measure %draw-style-name; >
+<!ATTLIST draw:measure %draw-transform; >
+<!ATTLIST draw:measure %zindex;>
+<!ATTLIST draw:measure draw:id %draw-shape-id;>
+<!ATTLIST draw:measure %text-anchor;>
+<!ATTLIST draw:measure draw:layer %layerName; #IMPLIED>
+
+<!-- graphic style elements -->
+<!ELEMENT draw:gradient EMPTY >
+<!ATTLIST draw:gradient draw:name %styleName; #REQUIRED>
+<!ATTLIST draw:gradient draw:style %gradient-style; #REQUIRED>
+<!ATTLIST draw:gradient draw:cx %coordinate; #IMPLIED>
+<!ATTLIST draw:gradient draw:cy %coordinate; #IMPLIED>
+<!ATTLIST draw:gradient draw:start-color %color; #IMPLIED>
+<!ATTLIST draw:gradient draw:end-color %color; #IMPLIED>
+<!ATTLIST draw:gradient draw:start-intensity %percentage; #IMPLIED>
+<!ATTLIST draw:gradient draw:end-intensity %percentage; #IMPLIED>
+<!ATTLIST draw:gradient draw:angle %integer; #IMPLIED>
+<!ATTLIST draw:gradient draw:border %percentage; #IMPLIED>
+
+<!ELEMENT draw:hatch EMPTY >
+<!ATTLIST draw:hatch draw:name %styleName; #REQUIRED>
+<!ATTLIST draw:hatch draw:style (single|double|triple) #REQUIRED >
+<!ATTLIST draw:hatch draw:color %color; #IMPLIED>
+<!ATTLIST draw:hatch draw:distance %length; #IMPLIED>
+<!ATTLIST draw:hatch draw:rotation %integer; #IMPLIED>
+
+
+<!ELEMENT draw:fill-image EMPTY >
+<!ATTLIST draw:fill-image draw:name %styleName; #REQUIRED>
+<!ATTLIST draw:fill-image xlink:href %uriReference; #REQUIRED>
+<!ATTLIST draw:fill-image xlink:type (simple) #IMPLIED>
+<!ATTLIST draw:fill-image xlink:show (embed) #IMPLIED>
+<!ATTLIST draw:fill-image xlink:actuate (onLoad) #IMPLIED>
+<!ATTLIST draw:fill-image svg:width %length; #IMPLIED>
+<!ATTLIST draw:fill-image svg:height %length; #IMPLIED>
+
+<!ELEMENT draw:transparency EMPTY>
+<!ATTLIST draw:transparency draw:name %styleName; #REQUIRED>
+<!ATTLIST draw:transparency draw:style %gradient-style; #REQUIRED>
+<!ATTLIST draw:transparency draw:cx %coordinate; #IMPLIED>
+<!ATTLIST draw:transparency draw:cy %coordinate; #IMPLIED>
+<!ATTLIST draw:transparency draw:start %percentage; #IMPLIED>
+<!ATTLIST draw:transparency draw:end %percentage; #IMPLIED>
+<!ATTLIST draw:transparency draw:angle %integer; #IMPLIED>
+<!ATTLIST draw:transparency draw:border %percentage; #IMPLIED>
+
+<!ELEMENT draw:marker EMPTY>
+<!ATTLIST draw:marker draw:name %styleName; #REQUIRED>
+<!ATTLIST draw:marker %draw-viewbox; >
+<!ATTLIST draw:marker svg:d %pathData; #REQUIRED>
+
+<!ELEMENT draw:stroke-dash EMPTY>
+<!ATTLIST draw:stroke-dash draw:name %styleName; #REQUIRED>
+<!ATTLIST draw:stroke-dash draw:style (rect|round) #IMPLIED>
+<!ATTLIST draw:stroke-dash draw:dots1 %integer; #IMPLIED>
+<!ATTLIST draw:stroke-dash draw:dots1-length %length; #IMPLIED>
+<!ATTLIST draw:stroke-dash draw:dots2 %integer; #IMPLIED>
+<!ATTLIST draw:stroke-dash draw:dots2-length %length; #IMPLIED>
+<!ATTLIST draw:stroke-dash draw:distance %length; #IMPLIED>
+
+<!-- stroke attributes -->
+<!ATTLIST style:properties draw:stroke (none|dash|solid) #IMPLIED>
+<!ATTLIST style:properties draw:stroke-dash CDATA #IMPLIED>
+<!ATTLIST style:properties svg:stroke-width %length; #IMPLIED>
+<!ATTLIST style:properties svg:stroke-color %color; #IMPLIED>
+<!ATTLIST style:properties draw:marker-start %styleName; #IMPLIED>
+<!ATTLIST style:properties draw:marker-end %styleName; #IMPLIED>
+<!ATTLIST style:properties draw:marker-start-width %length; #IMPLIED>
+<!ATTLIST style:properties draw:marker-end-width %length; #IMPLIED>
+<!ATTLIST style:properties draw:marker-start-center %boolean; #IMPLIED>
+<!ATTLIST style:properties draw:marker-end-center %boolean; #IMPLIED>
+<!ATTLIST style:properties svg:stroke-opacity %floatOrPercentage; #IMPLIED>
+<!ATTLIST style:properties svg:stroke-linejoin (miter|round|bevel|middle|none|inherit) #IMPLIED>
+
+<!-- text attributes -->
+<!ATTLIST style:properties draw:auto-grow-width %boolean; #IMPLIED>
+<!ATTLIST style:properties draw:auto-grow-height %boolean; #IMPLIED>
+<!ATTLIST style:properties draw:fit-to-size %boolean; #IMPLIED>
+<!ATTLIST style:properties draw:fit-to-contour %boolean; #IMPLIED>
+<!ATTLIST style:properties draw:textarea-horizontal-align ( left | center | right | justify ) #IMPLIED>
+<!ATTLIST style:properties draw:textarea-vertical-align ( top | middle | bottom ) #IMPLIED>
+
+<!-- fill attributes -->
+<!ATTLIST style:properties draw:fill (none|solid|bitmap|gradient|hatch) #IMPLIED>
+<!ATTLIST style:properties draw:fill-color %color; #IMPLIED>
+<!ATTLIST style:properties draw:fill-gradient-name %styleName; #IMPLIED>
+<!ATTLIST style:properties draw:gradient-step-count CDATA #IMPLIED>
+<!ATTLIST style:properties draw:fill-hatch-name %styleName; #IMPLIED>
+<!ATTLIST style:properties draw:fill-hatch-solid %boolean; #IMPLIED>
+<!ATTLIST style:properties draw:fill-image-name %styleName; #IMPLIED>
+<!ATTLIST style:properties style:repeat (no-repeat|repeat|stretch) #IMPLIED>
+<!ATTLIST style:properties draw:fill-image-width %lengthOrPercentage; #IMPLIED>
+<!ATTLIST style:properties draw:fill-image-height %lengthOrPercentage; #IMPLIED>
+<!ATTLIST style:properties draw:fill-image-ref-point-x %percentage; #IMPLIED>
+<!ATTLIST style:properties draw:fill-image-ref-point-y %percentage; #IMPLIED>
+<!ATTLIST style:properties draw:fill-image-ref-point %rectanglePoint; #IMPLIED>
+<!ATTLIST style:properties draw:tile-repeat-offset CDATA #IMPLIED>
+<!ATTLIST style:properties draw:transparency %percentage; #IMPLIED>
+<!ATTLIST style:properties draw:transparency-name %styleName; #IMPLIED>
+
+<!-- graphic attributes -->
+<!ATTLIST style:properties draw:color-mode (greyscale|mono|watermark|standard) #IMPLIED>
+<!ATTLIST style:properties draw:luminance %percentage; #IMPLIED>
+<!ATTLIST style:properties draw:contrast %percentage; #IMPLIED>
+<!ATTLIST style:properties draw:gamma %percentage; #IMPLIED>
+<!ATTLIST style:properties draw:red %percentage; #IMPLIED>
+<!ATTLIST style:properties draw:green %percentage; #IMPLIED>
+<!ATTLIST style:properties draw:blue %percentage; #IMPLIED>
+<!ATTLIST style:properties draw:color-inversion %boolean; #IMPLIED>
+
+<!-- shadow attributes -->
+<!ATTLIST style:properties draw:shadow (visible|hidden) #IMPLIED>
+<!ATTLIST style:properties draw:shadow-offset-x %length; #IMPLIED>
+<!ATTLIST style:properties draw:shadow-offset-y %length; #IMPLIED>
+<!ATTLIST style:properties draw:shadow-color %color; #IMPLIED>
+<!ATTLIST style:properties draw:shadow-transparency CDATA #IMPLIED>
+
+<!-- connector attributes -->
+<!ATTLIST style:properties draw:start-line-spacing-horizontal %distance; #IMPLIED>
+<!ATTLIST style:properties draw:start-line-spacing-vertical %distance; #IMPLIED>
+<!ATTLIST style:properties draw:end-line-spacing-horizontal %distance; #IMPLIED>
+<!ATTLIST style:properties draw:end-line-spacing-vertical %distance; #IMPLIED>
+
+<!-- measure attributes -->
+<!ATTLIST style:properties draw:line-distance %distance; #IMPLIED>
+<!ATTLIST style:properties draw:guide-overhang %distance; #IMPLIED>
+<!ATTLIST style:properties draw:guide-distance %distance; #IMPLIED>
+<!ATTLIST style:properties draw:start-guide %distance; #IMPLIED>
+<!ATTLIST style:properties draw:end-guide %distance; #IMPLIED>
+<!ATTLIST style:properties draw:measure-align (automatic|left-outside|inside|right-outside) #IMPLIED>
+<!ATTLIST style:properties draw:measure-vertical-align (automatic|above|below|center) #IMPLIED>
+<!ATTLIST style:properties draw:unit (automatic|mm|cm|m|km|pt|pc|inch|ft|mi) #IMPLIED>
+<!ATTLIST style:properties draw:show-unit %boolean; #IMPLIED>
+<!ATTLIST style:properties draw:placing (below|above) #IMPLIED>
+<!ATTLIST style:properties draw:parallel %boolean; #IMPLIED>
+
+<!-- frame attributes -->
+<!ATTLIST style:properties draw:frame-display-scrollbar %boolean; #IMPLIED>
+<!ATTLIST style:properties draw:frame-display-border %boolean; #IMPLIED>
+<!ATTLIST style:properties draw:frame-margin-horizontal %nonNegativePixelLength; #IMPLIED>
+<!ATTLIST style:properties draw:frame-margin-vertical %nonNegativePixelLength; #IMPLIED>
+<!ATTLIST style:properties draw:size-protect %boolean; #IMPLIED>
+<!ATTLIST style:properties draw:move-protect %boolean; #IMPLIED>
+
+<!-- ole object attributes -->
+<!ATTLIST style:properties draw:visible-area-left %nonNegativeLength; #IMPLIED>
+<!ATTLIST style:properties draw:visible-area-top %nonNegativeLength; #IMPLIED>
+<!ATTLIST style:properties draw:visible-area-width %positiveLength; #IMPLIED>
+<!ATTLIST style:properties draw:visible-area-height %positiveLength; #IMPLIED>
+
+<!-- fontwork attributes -->
+<!ATTLIST style:properties draw:fontwork-style (rotate|upright|slant-x|slant-y|none) #IMPLIED>
+<!ATTLIST style:properties draw:fontwork-adjust (left|right|autosize|center) #IMPLIED>
+<!ATTLIST style:properties draw:fontwork-distance %distance; #IMPLIED>
+<!ATTLIST style:properties draw:fontwork-start %distance; #IMPLIED>
+<!ATTLIST style:properties draw:fontwork-mirror %boolean; #IMPLIED>
+<!ATTLIST style:properties draw:fontwork-outline %boolean; #IMPLIED>
+<!ATTLIST style:properties draw:fontwork-shadow (normal|slant|none) #IMPLIED>
+<!ATTLIST style:properties draw:fontwork-shadow-color %color; #IMPLIED>
+<!ATTLIST style:properties draw:fontwork-shadow-offset-x %distance; #IMPLIED>
+<!ATTLIST style:properties draw:fontwork-shadow-offset-y %distance; #IMPLIED>
+<!ATTLIST style:properties draw:fontwork-form (none|top-circle|bottom-circle|left-circle|right-circle|top-arc|bottom-arc|left-arc|right-arc|button1|button2|button3|button4) #IMPLIED>
+<!ATTLIST style:properties draw:fontwork-hide-form %boolean; #IMPLIED>
+<!ATTLIST style:properties draw:fontwork-shadow-transparence %percentage; #IMPLIED>
+
+<!-- caption attributes -->
+<!ATTLIST style:properties draw:caption-type (straight-line|angled-line|angled-connector-line) #IMPLIED>
+<!ATTLIST style:properties draw:caption-angle-type (fixed|free) #IMPLIED>
+<!ATTLIST style:properties draw:caption-angle %nonNegativeInteger; #IMPLIED>
+<!ATTLIST style:properties draw:caption-gap %distance; #IMPLIED>
+<!ATTLIST style:properties draw:caption-escape-direction (horizontal|vertical|auto) #IMPLIED>
+<!ATTLIST style:properties draw:caption-escape %lengthOrPercentage; #IMPLIED>
+<!ATTLIST style:properties draw:caption-line-length %distance; #IMPLIED>
+<!ATTLIST style:properties draw:caption-fit-line-length %boolean; #IMPLIED>
+
+<!-- Animations -->
+<!ELEMENT presentation:sound EMPTY>
+<!ATTLIST presentation:sound xlink:href %uriReference; #REQUIRED>
+<!ATTLIST presentation:sound xlink:type (simple) #FIXED "simple">
+<!ATTLIST presentation:sound xlink:show (new|replace) #IMPLIED>
+<!ATTLIST presentation:sound xlink:actuate (onRequest) "onRequest">
+<!ATTLIST presentation:sound presentation:play-full %boolean; #IMPLIED>
+
+<!ELEMENT presentation:show-shape (presentation:sound)?>
+<!ATTLIST presentation:show-shape draw:shape-id CDATA #REQUIRED>
+<!ATTLIST presentation:show-shape presentation:effect %presentationEffects; "none">
+<!ATTLIST presentation:show-shape presentation:direction %presentationEffectDirections; "none">
+<!ATTLIST presentation:show-shape presentation:speed %presentationSpeeds; "medium">
+<!ATTLIST presentation:show-shape presentation:start-scale %percentage; "100%">
+<!ATTLIST presentation:show-shape presentation:path-id CDATA #IMPLIED >
+
+<!ELEMENT presentation:show-text (presentation:sound)?>
+<!ATTLIST presentation:show-text draw:shape-id CDATA #REQUIRED>
+<!ATTLIST presentation:show-text presentation:effect %presentationEffects; "none">
+<!ATTLIST presentation:show-text presentation:direction %presentationEffectDirections; "none">
+<!ATTLIST presentation:show-text presentation:speed %presentationSpeeds; "medium">
+<!ATTLIST presentation:show-text presentation:start-scale %percentage; "100%">
+<!ATTLIST presentation:show-text presentation:path-id CDATA #IMPLIED >
+
+<!ELEMENT presentation:hide-shape (presentation:sound)?>
+<!ATTLIST presentation:hide-shape draw:shape-id CDATA #REQUIRED>
+<!ATTLIST presentation:hide-shape presentation:effect %presentationEffects; "none">
+<!ATTLIST presentation:hide-shape presentation:direction %presentationEffectDirections; "none">
+<!ATTLIST presentation:hide-shape presentation:speed %presentationSpeeds; "medium">
+<!ATTLIST presentation:hide-shape presentation:start-scale %percentage; "100%">
+<!ATTLIST presentation:hide-shape presentation:path-id CDATA #IMPLIED >
+
+<!ELEMENT presentation:hide-text (presentation:sound)?>
+<!ATTLIST presentation:hide-text draw:shape-id CDATA #REQUIRED>
+<!ATTLIST presentation:hide-text presentation:effect %presentationEffects; "none">
+<!ATTLIST presentation:hide-text presentation:direction %presentationEffectDirections; "none">
+<!ATTLIST presentation:hide-text presentation:speed %presentationSpeeds; "medium">
+<!ATTLIST presentation:hide-text presentation:start-scale %percentage; "100%">
+<!ATTLIST presentation:hide-text presentation:path-id CDATA #IMPLIED >
+
+<!ELEMENT presentation:dim (presentation:sound)?>
+<!ATTLIST presentation:dim draw:shape-id CDATA #REQUIRED>
+<!ATTLIST presentation:dim draw:color %color; #REQUIRED>
+
+<!ELEMENT presentation:play EMPTY>
+<!ATTLIST presentation:play draw:shape-id CDATA #REQUIRED>
+<!ATTLIST presentation:play presentation:speed %presentationSpeeds; "medium">
+
+<!ELEMENT presentation:animations (presentation:show-shape|presentation:show-text|presentation:hide-shape|presentation:hide-text|presentation:dim|presentation:play)*>
+
+<!ELEMENT presentation:show EMPTY>
+<!ATTLIST presentation:show presentation:name %styleName; #REQUIRED>
+<!ATTLIST presentation:show presentation:pages CDATA #REQUIRED>
+
+<!ELEMENT presentation:settings (presentation:show)*>
+<!ATTLIST presentation:settings presentation:start-page %styleName; #IMPLIED>
+<!ATTLIST presentation:settings presentation:show %styleName; #IMPLIED>
+<!ATTLIST presentation:settings presentation:full-screen %boolean; "true">
+<!ATTLIST presentation:settings presentation:endless %boolean; "false">
+<!ATTLIST presentation:settings presentation:pause %timeDuration; #IMPLIED>
+<!ATTLIST presentation:settings presentation:show-logo %boolean; "false">
+<!ATTLIST presentation:settings presentation:force-manual %boolean; "false">
+<!ATTLIST presentation:settings presentation:mouse-visible %boolean; "true">
+<!ATTLIST presentation:settings presentation:mouse-as-pen %boolean; "false">
+<!ATTLIST presentation:settings presentation:start-with-navigator %boolean; "false">
+<!ATTLIST presentation:settings presentation:animations (enabled|disabled) "enabled">
+<!ATTLIST presentation:settings presentation:stay-on-top %boolean; "false">
+<!ATTLIST presentation:settings presentation:transition-on-click (enabled|disabled) "enabled">
+
+<!-- Drawing page -->
+<!ELEMENT draw:page (office:forms?,(%shapes;)*,presentation:animations?,presentation:notes?)>
+<!ATTLIST draw:page draw:name %string; #IMPLIED>
+<!ATTLIST draw:page draw:style-name %styleName; #IMPLIED>
+<!ATTLIST draw:page draw:master-page-name %styleName; #REQUIRED>
+<!ATTLIST draw:page presentation:presentation-page-layout-name %styleName; #IMPLIED>
+<!ATTLIST draw:page draw:id %nonNegativeInteger; #IMPLIED>
+
+<!-- Presentation notes -->
+<!ELEMENT presentation:notes (%shapes;)*>
+
+
+<!-- presentation page layouts -->
+<!ELEMENT style:presentation-page-layout (presentation:placeholder)* >
+<!ATTLIST style:presentation-page-layout style:name %styleName; #REQUIRED>
+<!ELEMENT presentation:placeholder EMPTY >
+<!ATTLIST presentation:placeholder presentation:object (title|outline|subtitle|text|graphic|object|chart|orgchart|page|notes|handout) #REQUIRED>
+<!ATTLIST presentation:placeholder svg:x %coordinateOrPercentage; #REQUIRED>
+<!ATTLIST presentation:placeholder svg:y %coordinateOrPercentage; #REQUIRED>
+<!ATTLIST presentation:placeholder svg:width %lengthOrPercentage; #REQUIRED>
+<!ATTLIST presentation:placeholder svg:height %lengthOrPercentage; #REQUIRED>
+
+<!-- presentation page attributes -->
+<!ATTLIST style:properties presentation:transition-type (manual|automatic|semi-automatic) #IMPLIED >
+<!ATTLIST style:properties presentation:transition-style (none|fade-from-left|fade-from-top|fade-from-right|fade-from-bottom|fade-to-center|fade-from-center|move-from-left|move-from-top|move-from-right|move-from-bottom|roll-from-top|roll-from-left|roll-from-right|roll-from-bottom|vertical-stripes|horizontal-stripes|clockwise|counterclockwise|fade-from-upperleft|fade-from-upperright|fade-from-lowerleft|fade-from-lowerright|close-vertical|close-horizontal|open-vertical|open-horizontal|spiralin-left|spiralin-right|spiralout-left|spiralout-right|dissolve|wavyline-from-left|wavyline-from-top|wavyline-from-right|wavyline-from-bottom|random|stretch-from-left|stretch-from-top|stretch-from-right|stretch-from-bottom|vertical-lines|horizontal-lines) #IMPLIED >
+<!ATTLIST style:properties presentation:transition-speed %presentationSpeeds; #IMPLIED >
+<!ATTLIST style:properties presentation:duration %timeDuration; #IMPLIED>
+<!ATTLIST style:properties presentation:visibility (visible|hidden) #IMPLIED>
+<!ATTLIST style:properties draw:background-size (full|border) #IMPLIED>
+<!ATTLIST style:properties presentation:background-objects-visible %boolean; #IMPLIED>
+<!ATTLIST style:properties presentation:background-visible %boolean; #IMPLIED>
+
+
+<!-- text boxes -->
+<!ELEMENT draw:text-box (office:events?,draw:image-map?,
+ (text:h|text:p|text:ordered-list|
+ text:unordered-list|table:table|chart:chart|
+ draw:a|draw:text-box|draw:image)*)>
+<!ATTLIST draw:text-box %draw-style-name;>
+<!ATTLIST draw:text-box %draw-transform; >
+<!ATTLIST draw:text-box draw:name %string; #IMPLIED>
+<!ATTLIST draw:text-box draw:chain-next-name %string; #IMPLIED>
+
+<!ATTLIST draw:text-box %text-anchor;>
+<!ATTLIST draw:text-box %draw-position;>
+<!ATTLIST draw:text-box %draw-end-position; >
+<!ATTLIST draw:text-box %table-background; >
+<!ATTLIST draw:text-box svg:width %lengthOrPercentage; #IMPLIED>
+<!ATTLIST draw:text-box svg:height %lengthOrPercentage; #IMPLIED>
+<!ATTLIST draw:text-box fo:min-height %lengthOrPercentage; #IMPLIED>
+<!ATTLIST draw:text-box %zindex;>
+<!ATTLIST draw:text-box %presentation-class; >
+<!ATTLIST draw:text-box %draw-transform; >
+<!ATTLIST draw:text-box draw:id %draw-shape-id;>
+<!ATTLIST draw:text-box draw:layer %layerName; #IMPLIED>
+
+<!-- image -->
+<!ELEMENT draw:image (office:binary-data?,office:events?,draw:image-map?,svg:desc?,(draw:contour-polygon|draw:contour-path)?)>
+<!ATTLIST draw:image %draw-style-name;>
+<!ATTLIST draw:image draw:name %string; #IMPLIED>
+<!ATTLIST draw:image xlink:href %uriReference; #IMPLIED>
+<!ATTLIST draw:image xlink:type (simple) #IMPLIED>
+<!ATTLIST draw:image xlink:show (embed) #IMPLIED>
+<!ATTLIST draw:image xlink:actuate (onLoad) #IMPLIED>
+<!ATTLIST draw:image draw:filter-name %string; #IMPLIED>
+<!ATTLIST draw:image %text-anchor;>
+<!ATTLIST draw:image %draw-position;>
+<!ATTLIST draw:image %draw-end-position; >
+<!ATTLIST draw:image %table-background; >
+<!ATTLIST draw:image svg:width %lengthOrPercentage; #IMPLIED>
+<!ATTLIST draw:image svg:height %lengthOrPercentage; #IMPLIED>
+<!ATTLIST draw:image %presentation-class; >
+<!ATTLIST draw:image %zindex;>
+<!ATTLIST draw:image draw:id %draw-shape-id;>
+<!ATTLIST draw:image draw:layer %layerName; #IMPLIED>
+
+<!-- objects -->
+<!ELEMENT draw:thumbnail EMPTY>
+<!ATTLIST draw:thumbnail xlink:href %uriReference; #REQUIRED>
+<!ATTLIST draw:thumbnail xlink:type (simple) #IMPLIED>
+<!ATTLIST draw:thumbnail xlink:show (embed) #IMPLIED>
+<!ATTLIST draw:thumbnail xlink:actuate (onLoad) #IMPLIED>
+
+<!ELEMENT math:math ANY> <!-- dummy (we have no MathML DTD currently)-->
+<!ELEMENT draw:object (draw:thumbnail?,(office:document|math:math)?,office:events?, draw:image-map?, svg:desc?,(draw:contour-polygon|draw:contour-path)?)>
+<!ATTLIST draw:object %draw-style-name;>
+<!ATTLIST draw:object draw:name %string; #IMPLIED>
+<!ATTLIST draw:object xlink:href %uriReference; #IMPLIED>
+<!ATTLIST draw:object xlink:type (simple) #IMPLIED>
+<!ATTLIST draw:object xlink:show (embed) #IMPLIED>
+<!ATTLIST draw:object xlink:actuate (onLoad) #IMPLIED>
+<!ATTLIST draw:object %text-anchor;>
+<!ATTLIST draw:object %draw-position;>
+<!ATTLIST draw:object %draw-end-position; >
+<!ATTLIST draw:object %table-background; >
+<!ATTLIST draw:object svg:width %lengthOrPercentage; #IMPLIED>
+<!ATTLIST draw:object svg:height %lengthOrPercentage; #IMPLIED>
+<!ATTLIST draw:object %presentation-class; >
+<!ATTLIST draw:object %zindex;>
+<!ATTLIST draw:object draw:id %draw-shape-id;>
+<!ATTLIST draw:object draw:layer %layerName; #IMPLIED>
+<!ATTLIST draw:object draw:notify-on-update-of-ranges %string; #IMPLIED>
+
+<!ELEMENT draw:object-ole (office:binary-data?|office:events?|draw:image-map?|svg:desc?|draw:contour-polygon?|draw:contour-path?|draw:thumbnail?)>
+<!ATTLIST draw:object-ole draw:class-id CDATA #IMPLIED>
+<!ATTLIST draw:object-ole %draw-style-name;>
+<!ATTLIST draw:object-ole draw:name %string; #IMPLIED>
+<!ATTLIST draw:object-ole xlink:href %uriReference; #IMPLIED>
+<!ATTLIST draw:object-ole xlink:type (simple) #IMPLIED>
+<!ATTLIST draw:object-ole xlink:show (embed) #IMPLIED>
+<!ATTLIST draw:object-ole xlink:actuate (onLoad) #IMPLIED>
+<!ATTLIST draw:object-ole %text-anchor;>
+<!ATTLIST draw:object-ole %draw-position;>
+<!ATTLIST draw:object-ole %draw-end-position; >
+<!ATTLIST draw:object-ole %table-background; >
+<!ATTLIST draw:object-ole svg:width %lengthOrPercentage; #IMPLIED>
+<!ATTLIST draw:object-ole svg:height %lengthOrPercentage; #IMPLIED>
+<!ATTLIST draw:object-ole %presentation-class; >
+<!ATTLIST draw:object-ole %zindex;>
+<!ATTLIST draw:object-ole draw:id %draw-shape-id;>
+<!ATTLIST draw:object-ole draw:layer %layerName; #IMPLIED>
+
+<!ELEMENT svg:desc (#PCDATA)>
+
+<!ELEMENT draw:contour-polygon EMPTY>
+<!ATTLIST draw:contour-polygon svg:width %coordinate; #REQUIRED>
+<!ATTLIST draw:contour-polygon svg:height %coordinate; #REQUIRED>
+<!ATTLIST draw:contour-polygon %draw-viewbox;>
+<!ATTLIST draw:contour-polygon svg:points %points; #REQUIRED>
+
+<!ELEMENT draw:contour-path EMPTY>
+<!ATTLIST draw:contour-path svg:width %coordinate; #REQUIRED>
+<!ATTLIST draw:contour-path svg:height %coordinate; #REQUIRED>
+<!ATTLIST draw:contour-path %draw-viewbox;>
+<!ATTLIST draw:contour-path svg:d %pathData; #REQUIRED>
+
+<!-- hyperlink -->
+<!ELEMENT draw:a (draw:image|draw:text-box)>
+<!ATTLIST draw:a xlink:href %uriReference; #REQUIRED>
+<!ATTLIST draw:a xlink:type (simple) #FIXED "simple">
+<!ATTLIST draw:a xlink:show (new|replace) #IMPLIED>
+<!ATTLIST draw:a xlink:actuate (onRequest) "onRequest">
+<!ATTLIST draw:a office:name %string; #IMPLIED>
+<!ATTLIST draw:a office:target-frame-name %string; #IMPLIED>
+<!ATTLIST draw:a office:server-map %boolean; "false">
+
+<!-- 3d properties -->
+<!ATTLIST style:properties dr3d:horizontal-segments %nonNegativeInteger; #IMPLIED>
+<!ATTLIST style:properties dr3d:vertical-segments %nonNegativeInteger; #IMPLIED>
+<!ATTLIST style:properties dr3d:edge-rounding %percentage; #IMPLIED>
+<!ATTLIST style:properties dr3d:edge-rounding-mode (correct|attractive) #IMPLIED>
+<!ATTLIST style:properties dr3d:back-scale %percentage; #IMPLIED>
+<!ATTLIST style:properties dr3d:end-angle %nonNegativeInteger; #IMPLIED>
+<!ATTLIST style:properties dr3d:depth %length; #IMPLIED>
+<!ATTLIST style:properties dr3d:backface-culling (enabled|disabled) #IMPLIED>
+<!ATTLIST style:properties dr3d:lighting-mode (standard|double-sided) #IMPLIED>
+<!ATTLIST style:properties dr3d:normals-kind (object|flat|sphere) #IMPLIED>
+<!ATTLIST style:properties dr3d:normals-direction (normal|inverse) #IMPLIED>
+<!ATTLIST style:properties dr3d:texture-generation-mode-x (object|parallel|sphere) #IMPLIED>
+<!ATTLIST style:properties dr3d:texture-generation-mode-y (object|parallel|sphere) #IMPLIED>
+<!ATTLIST style:properties dr3d:texture-kind (luminance|intesity|color) #IMPLIED>
+<!ATTLIST style:properties dr3d:texture-filter (enabled|disabled) #IMPLIED>
+<!ATTLIST style:properties dr3d:texture-mode (replace|modulate|blend) #IMPLIED>
+<!ATTLIST style:properties dr3d:ambient-color %color; #IMPLIED>
+<!ATTLIST style:properties dr3d:emissive-color %color; #IMPLIED>
+<!ATTLIST style:properties dr3d:specular-color %color; #IMPLIED>
+<!ATTLIST style:properties dr3d:diffuse-color %color; #IMPLIED>
+<!ATTLIST style:properties dr3d:shininess %percentage; #IMPLIED>
+<!ATTLIST style:properties dr3d:shadow (visible|hidden) #IMPLIED>
+
+<!ELEMENT dr3d:light EMPTY>
+<!ATTLIST dr3d:light dr3d:diffuse-color %color; #IMPLIED>
+<!ATTLIST dr3d:light dr3d:direction %vector3D; #REQUIRED>
+<!ATTLIST dr3d:light dr3d:enabled %boolean; #IMPLIED>
+<!ATTLIST dr3d:light dr3d:specular %boolean; #IMPLIED>
+
+<!ENTITY % shapes3d "(dr3d:scene|dr3d:extrude|dr3d:sphere|dr3d:rotate|dr3d:cube)">
+
+<!ELEMENT dr3d:cube EMPTY>
+<!ATTLIST dr3d:cube dr3d:transform CDATA #IMPLIED>
+<!ATTLIST dr3d:cube dr3d:min-edge %vector3D; #IMPLIED>
+<!ATTLIST dr3d:cube dr3d:max-edge %vector3D; #IMPLIED>
+<!ATTLIST dr3d:cube %zindex;>
+<!ATTLIST dr3d:cube draw:id %draw-shape-id;>
+<!ATTLIST dr3d:cube %draw-end-position; >
+<!ATTLIST dr3d:cube %table-background; >
+<!ATTLIST dr3d:cube %draw-style-name; >
+<!ATTLIST dr3d:cube draw:layer %layerName; #IMPLIED>
+
+<!ELEMENT dr3d:sphere EMPTY>
+<!ATTLIST dr3d:sphere dr3d:transform CDATA #IMPLIED>
+<!ATTLIST dr3d:sphere dr3d:center %vector3D; #IMPLIED>
+<!ATTLIST dr3d:sphere dr3d:size %vector3D; #IMPLIED>
+<!ATTLIST dr3d:sphere %zindex;>
+<!ATTLIST dr3d:sphere draw:id %draw-shape-id;>
+<!ATTLIST dr3d:sphere %draw-end-position; >
+<!ATTLIST dr3d:sphere %table-background; >
+<!ATTLIST dr3d:sphere %draw-style-name; >
+<!ATTLIST dr3d:sphere draw:layer %layerName; #IMPLIED>
+
+<!ELEMENT dr3d:extrude EMPTY>
+<!ATTLIST dr3d:extrude dr3d:transform CDATA #IMPLIED>
+<!ATTLIST dr3d:extrude %draw-viewbox;>
+<!ATTLIST dr3d:extrude svg:d %pathData; #REQUIRED >
+<!ATTLIST dr3d:extrude %zindex;>
+<!ATTLIST dr3d:extrude draw:id %draw-shape-id;>
+<!ATTLIST dr3d:extrude %draw-end-position; >
+<!ATTLIST dr3d:extrude %table-background; >
+<!ATTLIST dr3d:extrude %draw-style-name; >
+<!ATTLIST dr3d:extrude draw:layer %layerName; #IMPLIED>
+
+<!ELEMENT dr3d:rotate EMPTY>
+<!ATTLIST dr3d:rotate dr3d:transform CDATA #IMPLIED>
+<!ATTLIST dr3d:rotate %draw-viewbox;>
+<!ATTLIST dr3d:rotate svg:d %pathData; #REQUIRED >
+<!ATTLIST dr3d:rotate %zindex;>
+<!ATTLIST dr3d:rotate draw:id %draw-shape-id;>
+<!ATTLIST dr3d:rotate %draw-end-position; >
+<!ATTLIST dr3d:rotate %table-background; >
+<!ATTLIST dr3d:rotate %draw-style-name; >
+<!ATTLIST dr3d:rotate draw:layer %layerName; #IMPLIED>
+
+<!ELEMENT dr3d:scene (dr3d:light*,(%shapes3d;)*)>
+<!ATTLIST dr3d:scene %draw-style-name; >
+<!ATTLIST dr3d:scene svg:x %coordinate; #IMPLIED>
+<!ATTLIST dr3d:scene svg:y %coordinate; #IMPLIED>
+<!ATTLIST dr3d:scene svg:width %length; #IMPLIED>
+<!ATTLIST dr3d:scene svg:height %length; #IMPLIED>
+<!ATTLIST dr3d:scene dr3d:vrp %vector3D; #IMPLIED>
+<!ATTLIST dr3d:scene dr3d:vpn %vector3D; #IMPLIED>
+<!ATTLIST dr3d:scene dr3d:vup %vector3D; #IMPLIED>
+<!ATTLIST dr3d:scene dr3d:projection (parallel|perspective) #IMPLIED>
+<!ATTLIST dr3d:scene dr3d:transform CDATA #IMPLIED>
+<!ATTLIST dr3d:scene dr3d:distance %length; #IMPLIED>
+<!ATTLIST dr3d:scene dr3d:focal-length %length; #IMPLIED>
+<!ATTLIST dr3d:scene dr3d:shadow-slant %nonNegativeInteger; #IMPLIED>
+<!ATTLIST dr3d:scene dr3d:shade-mode (flat|phong|gouraud|draft) #IMPLIED>
+<!ATTLIST dr3d:scene dr3d:ambient-color %color; #IMPLIED>
+<!ATTLIST dr3d:scene dr3d:lighting-mode %boolean; #IMPLIED>
+<!ATTLIST dr3d:scene %zindex;>
+<!ATTLIST dr3d:scene draw:id %draw-shape-id;>
+<!ATTLIST dr3d:scene %draw-end-position; >
+<!ATTLIST dr3d:scene %table-background; >
+
+<!-- layer -->
+
+<!ELEMENT draw:layer-set (draw:layer*)>
+
+<!ELEMENT draw:layer EMPTY>
+<!ATTLIST draw:layer draw:name %layerName; #REQUIRED>
+
+<!-- events -->
+<!ELEMENT presentation:event (presentation:sound)?>
+<!ATTLIST presentation:event %event-name;>
+<!ATTLIST presentation:event presentation:action (none|previous-page|next-page|first-page|last-page|hide|stop|execute|show|verb|fade-out|sound) #REQUIRED>
+<!ATTLIST presentation:event presentation:effect %presentationEffects; "none">
+<!ATTLIST presentation:event presentation:direction %presentationEffectDirections; "none">
+<!ATTLIST presentation:event presentation:speed %presentationSpeeds; "medium">
+<!ATTLIST presentation:event presentation:start-scale %percentage; "100%">
+<!ATTLIST presentation:event xlink:href %uriReference; #IMPLIED>
+<!ATTLIST presentation:event xlink:type (simple) #IMPLIED>
+<!ATTLIST presentation:event xlink:show (embed) #IMPLIED>
+<!ATTLIST presentation:event xlink:actuate (onRequest) #IMPLIED>
+<!ATTLIST presentation:event presentation:verb %nonNegativeInteger; #IMPLIED>
+
+<!-- applets -->
+<!ELEMENT draw:applet (draw:thumbnail?, draw:param*, svg:desc?)>
+<!ATTLIST draw:applet xlink:href %uriReference; #IMPLIED>
+<!ATTLIST draw:applet xlink:type (simple) #IMPLIED>
+<!ATTLIST draw:applet xlink:show (embed) #IMPLIED>
+<!ATTLIST draw:applet xlink:actuate (onLoad) #IMPLIED>
+<!ATTLIST draw:applet draw:code CDATA #REQUIRED>
+<!ATTLIST draw:applet draw:object CDATA #IMPLIED>
+<!ATTLIST draw:applet draw:archive CDATA #IMPLIED>
+<!ATTLIST draw:applet draw:may-script %boolean; "false">
+<!ATTLIST draw:applet draw:name CDATA #IMPLIED>
+<!ATTLIST draw:applet %draw-style-name;>
+<!ATTLIST draw:applet svg:width %lengthOrPercentage; #IMPLIED>
+<!ATTLIST draw:applet svg:height %lengthOrPercentage; #IMPLIED>
+<!ATTLIST draw:applet %zindex;>
+<!ATTLIST draw:applet draw:layer %layerName; #IMPLIED>
+<!ATTLIST draw:applet %draw-position;>
+<!ATTLIST draw:applet %draw-end-position; >
+
+<!-- plugins -->
+<!ELEMENT draw:plugin (draw:thumbnail?, draw:param*, svg:desc?)>
+<!ATTLIST draw:plugin xlink:href %uriReference; #IMPLIED>
+<!ATTLIST draw:plugin xlink:type (simple) #IMPLIED>
+<!ATTLIST draw:plugin xlink:show (embed) #IMPLIED>
+<!ATTLIST draw:plugin xlink:actuate (onLoad) #IMPLIED>
+<!ATTLIST draw:plugin draw:mime-type CDATA #IMPLIED>
+<!ATTLIST draw:plugin draw:name CDATA #IMPLIED>
+<!ATTLIST draw:plugin %draw-style-name;>
+<!ATTLIST draw:plugin svg:width %lengthOrPercentage; #IMPLIED>
+<!ATTLIST draw:plugin svg:height %lengthOrPercentage; #IMPLIED>
+<!ATTLIST draw:plugin %zindex;>
+<!ATTLIST draw:plugin draw:layer %layerName; #IMPLIED>
+<!ATTLIST draw:plugin %draw-position;>
+<!ATTLIST draw:plugin %draw-end-position; >
+
+<!-- Paramaters -->
+<!ELEMENT draw:param EMPTY>
+<!ATTLIST draw:param draw:name CDATA #IMPLIED>
+<!ATTLIST draw:param draw:value CDATA #IMPLIED>
+
+<!-- Floating Frames -->
+<!ELEMENT draw:floating-frame (draw:thumbnail?, svg:desc?)>
+<!ATTLIST draw:floating-frame xlink:href %uriReference; #IMPLIED>
+<!ATTLIST draw:floating-frame xlink:type (simple) #IMPLIED>
+<!ATTLIST draw:floating-frame xlink:show (embed) #IMPLIED>
+<!ATTLIST draw:floating-frame xlink:actuate (onLoad) #IMPLIED>
+<!ATTLIST draw:floating-frame draw:name CDATA #IMPLIED>
+<!ATTLIST draw:floating-frame draw:frame-name CDATA #IMPLIED>
+<!ATTLIST draw:floating-frame %draw-style-name;>
+<!ATTLIST draw:floating-frame svg:width %lengthOrPercentage; #IMPLIED>
+<!ATTLIST draw:floating-frame svg:height %lengthOrPercentage; #IMPLIED>
+<!ATTLIST draw:floating-frame %zindex;>
+<!ATTLIST draw:floating-frame draw:layer %layerName; #IMPLIED>
+<!ATTLIST draw:floating-frame %draw-position;>
+<!ATTLIST draw:floating-frame %draw-end-position; >
+
+<!-- Image Maps -->
+<!ELEMENT draw:image-map
+ (draw:area-rectangle|draw:area-circle|draw:area-polygon)*>
+
+<!ELEMENT draw:area-rectangle (svg:desc?,office:events?)>
+<!ATTLIST draw:area-rectangle xlink:href %uriReference; #IMPLIED>
+<!ATTLIST draw:area-rectangle xlink:type (simple) #IMPLIED>
+<!ATTLIST draw:area-rectangle office:target-frame-name CDATA #IMPLIED>
+<!ATTLIST draw:area-rectangle xlink:show (new|replace) #IMPLIED>
+<!ATTLIST draw:area-rectangle office:name CDATA #IMPLIED>
+<!ATTLIST draw:area-rectangle draw:nohref (nohref) #IMPLIED>
+<!ATTLIST draw:area-rectangle svg:x %coordinate; #REQUIRED>
+<!ATTLIST draw:area-rectangle svg:y %coordinate; #REQUIRED>
+<!ATTLIST draw:area-rectangle svg:width %coordinate; #REQUIRED>
+<!ATTLIST draw:area-rectangle svg:height %coordinate; #REQUIRED>
+
+<!ELEMENT draw:area-circle (svg:desc?,office:events?)>
+<!ATTLIST draw:area-circle xlink:href %uriReference; #IMPLIED>
+<!ATTLIST draw:area-circle xlink:type (simple) #IMPLIED>
+<!ATTLIST draw:area-circle office:target-frame-name CDATA #IMPLIED>
+<!ATTLIST draw:area-circle xlink:show (new|replace) #IMPLIED>
+<!ATTLIST draw:area-circle office:name CDATA #IMPLIED>
+<!ATTLIST draw:area-circle draw:nohref (nohref) #IMPLIED>
+<!ATTLIST draw:area-circle svg:cx %coordinate; #REQUIRED>
+<!ATTLIST draw:area-circle svg:cy %coordinate; #REQUIRED>
+<!ATTLIST draw:area-circle svg:r %coordinate; #REQUIRED>
+
+<!ELEMENT draw:area-polygon (svg:desc?,office:events?)>
+<!ATTLIST draw:area-polygon xlink:href %uriReference; #IMPLIED>
+<!ATTLIST draw:area-polygon xlink:type (simple) #IMPLIED>
+<!ATTLIST draw:area-polygon office:target-frame-name CDATA #IMPLIED>
+<!ATTLIST draw:area-polygon xlink:show (new|replace) #IMPLIED>
+<!ATTLIST draw:area-polygon office:name CDATA #IMPLIED>
+<!ATTLIST draw:area-polygon draw:nohref (nohref) #IMPLIED>
+<!ATTLIST draw:area-polygon svg:x %coordinate; #REQUIRED>
+<!ATTLIST draw:area-polygon svg:y %coordinate; #REQUIRED>
+<!ATTLIST draw:area-polygon svg:width %coordinate; #REQUIRED>
+<!ATTLIST draw:area-polygon svg:height %coordinate; #REQUIRED>
+<!ATTLIST draw:area-polygon svg:points %points; #REQUIRED>
+<!ATTLIST draw:area-polygon svg:viewBox CDATA #REQUIRED>
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/dtypes.mod b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/dtypes.mod
new file mode 100644
index 000000000000..e4d640d012c8
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/dtypes.mod
@@ -0,0 +1,143 @@
+<!--
+
+ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+
+ Copyright 2000, 2010 Oracle and/or its affiliates.
+
+ OpenOffice.org - a multi-platform office productivity suite
+
+ This file is part of OpenOffice.org.
+
+ OpenOffice.org is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License version 3
+ only, as published by the Free Software Foundation.
+
+ OpenOffice.org is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License version 3 for more details
+ (a copy is included in the LICENSE file that accompanied this code).
+
+ You should have received a copy of the GNU Lesser General Public License
+ version 3 along with OpenOffice.org. If not, see
+ <http://www.openoffice.org/license.html>
+ for a copy of the LGPLv3 License.
+
+-->
+
+<!-- datatypes corresponding to XML Schema Part 2 W3C Working draft of -->
+<!-- 07 April 2000 -->
+
+<!-- string -->
+<!ENTITY % string "CDATA">
+<!ENTITY % cString "#PCDATA">
+
+<!-- boolean (values are "true" and "false" -->
+<!ENTITY % boolean "CDATA">
+
+<!-- integer ( ..., -2, -1, 0, 1, 2, ...) -->
+<!ENTITY % integer "CDATA">
+
+<!-- non negative integer ( 0, 1, 2, ...) -->
+<!ENTITY % nonNegativeInteger "CDATA">
+
+<!-- positive integer ( 1, 2, ...) -->
+<!ENTITY % positiveInteger "CDATA">
+<!ENTITY % cPositiveInteger "#PCDATA">
+
+<!ENTITY % positiveNumberOrDefault "CDATA">
+
+<!-- time duration as specified by ISO8601, section 5.5.3.2 -->
+<!ENTITY % timeDuration "CDATA">
+<!ENTITY % cTimeDuration "#PCDATA">
+
+<!-- time instance as specified by ISO8601, section 5.4 -->
+<!ENTITY % timeInstance "CDATA">
+<!ENTITY % cTimeInstance "#PCDATA">
+
+<!-- date instance as specified by ISO8601, section 5.2.1.1, extended format-->
+<!ENTITY % date "CDATA">
+<!ENTITY % cDate "#PCDATA">
+
+<!-- date duration, like timDuration but truncated to full dates -->
+<!ENTITY % dateDuration "CDATA">
+<!ENTITY % cDateDuration "#PCDATA">
+
+<!-- URI reference -->
+<!ENTITY % uriReference "CDATA">
+
+<!-- language code as specified by RFC1766 -->
+<!ENTITY % language "CDATA">
+<!ENTITY % cLanguage "#PCDATA">
+
+<!-- float -->
+<!ENTITY % float "CDATA">
+
+<!-- Some other common used data types -->
+
+<!-- a single UNICODE character -->
+<!ENTITY % character "CDATA">
+
+<!-- a style name -->
+<!ENTITY % styleName "CDATA">
+
+<!-- a target frame mame -->
+<!ENTITY % targetFrameName "CDATA">
+
+<!-- a language without a country as specified by ISO639 -->
+<!ENTITY % languageOnly "CDATA">
+
+<!-- a country as specified by ISO3166 -->
+<!ENTITY % country "CDATA">
+
+<!-- a color value having the format #rrggbb -->
+<!ENTITY % color "CDATA">
+<!-- a color value having the format #rrggbb or "transparent" -->
+<!ENTITY % transparentOrColor "CDATA">
+
+<!-- a percentage -->
+<!ENTITY % percentage "CDATA">
+
+<!-- a length (i.e. 1cm or .6inch) -->
+<!ENTITY % length "CDATA">
+<!ENTITY % positiveLength "CDATA">
+<!ENTITY % nonNegativeLength "CDATA">
+<!ENTITY % lengthOrNoLimit "CDATA">
+
+<!-- a length or a percentage -->
+<!ENTITY % lengthOrPercentage "CDATA">
+<!ENTITY % positiveLengthOrPercentage "CDATA">
+
+<!-- a pixel length (i.e. 2px) -->
+<!ENTITY % nonNegativePixelLength "CDATA">
+
+<!-- a float or a percentage -->
+<!ENTITY % floatOrPercentage "CDATA">
+
+<!-- a text encoding -->
+<!ENTITY % textEncoding "CDATA">
+
+<!-- cell address and cell range address -->
+<!ENTITY % cell-address "CDATA">
+<!ENTITY % cell-range-address "CDATA">
+<!ENTITY % cell-range-address-list "CDATA">
+
+<!-- value types -->
+<!ENTITY % valueType "(float|time|date|percentage|currency|boolean|string)">
+
+<!-- an svg coordinate in different distance formats -->
+<!ENTITY % coordinate "CDATA">
+
+<!ENTITY % coordinateOrPercentage "CDATA">
+
+<!ENTITY % shape "draw:rect|draw:line|draw:polyline|draw:polygon|draw:path|
+ draw:circle|draw:ellipse|draw:g|draw:page-thumbnail|
+ draw:text-box|draw:image|draw:object|draw:object-ole|
+ draw:applet|draw:floating-frame|draw:plugin|
+ draw:measure|draw:caption|draw:connector|chart:chart|
+ dr3d:scene|draw:control" >
+<!ENTITY % shapes "(%shape;)" >
+
+<!ENTITY % anchorType "(page|frame|paragraph|char|as-char)">
+
+<!ENTITY % control-id "form:id CDATA #REQUIRED">
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/form.mod b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/form.mod
new file mode 100644
index 000000000000..77a91206c451
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/form.mod
@@ -0,0 +1,308 @@
+<!--
+
+ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+
+ Copyright 2000, 2010 Oracle and/or its affiliates.
+
+ OpenOffice.org - a multi-platform office productivity suite
+
+ This file is part of OpenOffice.org.
+
+ OpenOffice.org is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License version 3
+ only, as published by the Free Software Foundation.
+
+ OpenOffice.org is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License version 3 for more details
+ (a copy is included in the LICENSE file that accompanied this code).
+
+ You should have received a copy of the GNU Lesser General Public License
+ version 3 along with OpenOffice.org. If not, see
+ <http://www.openoffice.org/license.html>
+ for a copy of the LGPLv3 License.
+
+-->
+
+<!ENTITY % controls "form:text|form:textarea|form:fixed-text|form:file|
+ form:password|form:formatted-text|form:button|form:image|
+ form:checkbox|form:radio|form:listbox|form:combobox|form:frame|
+ form:hidden|form:image-frame|form:grid|form:generic-control">
+
+<!ENTITY % name "form:name CDATA #IMPLIED">
+<!ENTITY % service-name "form:service-name CDATA #IMPLIED">
+
+<!ENTITY % navigation "(none|current|parent)">
+<!ENTITY % cycles "(records|current|page)">
+<!ENTITY % url "CDATA">
+
+
+<!ENTITY % types "(submit|reset|push|url)">
+<!ENTITY % button-type "form:button-type %types; 'push'">
+<!ENTITY % current-selected "form:current-selected %boolean; 'false'">
+<!ENTITY % current-value "form:current-value CDATA #IMPLIED">
+<!ENTITY % value "form:value CDATA #IMPLIED">
+<!ENTITY % disabled "form:disabled %boolean; 'false'">
+<!ENTITY % dropdown "form:dropdown %boolean; 'false'">
+<!ENTITY % for "form:for CDATA #IMPLIED">
+<!ENTITY % image-data "form:image-data %url; #IMPLIED">
+<!ENTITY % label "form:label CDATA #IMPLIED">
+<!ENTITY % max-length "form:max-length CDATA #IMPLIED">
+<!ENTITY % printable "form:printable %boolean; 'true'">
+<!ENTITY % readonly "form:readonly %boolean; 'false'">
+<!ENTITY % size "form:size CDATA #IMPLIED">
+<!ENTITY % selected "form:selected %boolean; 'false'">
+<!ENTITY % size "form:size CDATA #IMPLIED">
+<!ENTITY % tab-index "form:tab-index CDATA #IMPLIED">
+<!ENTITY % target-frame "office:target-frame CDATA '_blank'">
+<!ENTITY % target-location "xlink:href %url; #IMPLIED">
+<!ENTITY % tab-stop "form:tab-stop %boolean; 'true'">
+<!ENTITY % title "form:title CDATA #IMPLIED">
+<!ENTITY % default-value "form:default-value CDATA #IMPLIED">
+<!ENTITY % bound-column "form:bound-column CDATA #IMPLIED">
+<!ENTITY % convert-empty "form:convert-empty-to-null %boolean; 'false'">
+<!ENTITY % data-field "form:data-field CDATA #IMPLIED">
+<!ENTITY % list-source "form:list-source CDATA #IMPLIED">
+<!ENTITY % list-source-types "(table|query|sql|sql-pass-through|value-list|table-fields)">
+<!ENTITY % list-source-type "form:list-source-type %list-source-types; #IMPLIED">
+
+<!ELEMENT form:control (%controls;)+>
+<!ATTLIST form:control %name;
+ %service-name;
+ %control-id;>
+
+<!ELEMENT form:form (form:properties?, office:events?, (form:control|form:form)*)>
+<!ATTLIST form:form %name; %service-name;>
+<!ATTLIST form:form xlink:href %url; #IMPLIED>
+<!ATTLIST form:form form:enctype CDATA "application/x-www-form-urlencoded">
+<!ATTLIST form:form form:method CDATA "get">
+<!ATTLIST form:form office:target-frame CDATA "_blank">
+<!ATTLIST form:form form:allow-deletes %boolean; "true">
+<!ATTLIST form:form form:allow-inserts %boolean; "true">
+<!ATTLIST form:form form:allow-updates %boolean; "true">
+<!ATTLIST form:form form:apply-filter %boolean; "false">
+<!ATTLIST form:form form:command CDATA #IMPLIED>
+<!ATTLIST form:form form:command-type (table|query|command) "command">
+<!ATTLIST form:form form:datasource CDATA #IMPLIED>
+<!ATTLIST form:form form:detail-fields CDATA #IMPLIED>
+<!ATTLIST form:form form:escape-processing %boolean; "true">
+<!ATTLIST form:form form:filter CDATA #IMPLIED>
+<!ATTLIST form:form form:ignore-result %boolean; "false">
+<!ATTLIST form:form form:master-fields CDATA #IMPLIED>
+<!ATTLIST form:form form:navigation-mode %navigation; #IMPLIED>
+<!ATTLIST form:form form:order CDATA #IMPLIED>
+<!ATTLIST form:form form:tab-cycle %cycles; #IMPLIED>
+
+<!ELEMENT office:forms (form:form*)>
+<!ATTLIST office:forms form:automatic-focus %boolean; "false">
+<!ATTLIST office:forms form:apply-design-mode %boolean; "true">
+
+<!ELEMENT form:text (form:properties?, office:events?)>
+<!ATTLIST form:text %current-value;
+ %disabled;
+ %max-length;
+ %printable;
+ %readonly;
+ %tab-index;
+ %tab-stop;
+ %title;
+ %value;
+ %convert-empty;
+ %data-field;>
+
+<!ELEMENT form:textarea (form:properties?, office:events?)>
+<!ATTLIST form:textarea %current-value;
+ %disabled;
+ %max-length;
+ %printable;
+ %readonly;
+ %tab-index;
+ %tab-stop;
+ %title;
+ %value;
+ %convert-empty;
+ %data-field;>
+
+<!ELEMENT form:password (form:properties?, office:events?)>
+<!ATTLIST form:password %disabled;
+ %max-length;
+ %printable;
+ %tab-index;
+ %tab-stop;
+ %title;
+ %value;
+ %convert-empty;>
+
+<!ATTLIST form:password form:echo-char CDATA "*">
+
+<!ELEMENT form:file (form:properties?, office:events?)>
+<!ATTLIST form:file %current-value;
+ %disabled;
+ %max-length;
+ %printable;
+ %readonly;
+ %tab-index;
+ %tab-stop;
+ %title;
+ %value;>
+
+<!ELEMENT form:formatted-text (form:properties?, office:events?)>
+<!ATTLIST form:formatted-text %current-value;
+ %disabled;
+ %max-length;
+ %printable;
+ %readonly;
+ %tab-index;
+ %tab-stop;
+ %title;
+ %value;
+ %convert-empty;
+ %data-field;>
+<!ATTLIST form:formatted-text form:max-value CDATA #IMPLIED>
+<!ATTLIST form:formatted-text form:min-value CDATA #IMPLIED>
+<!ATTLIST form:formatted-text form:validation %boolean; "false">
+
+<!ELEMENT form:fixed-text (form:properties?, office:events?)>
+<!ATTLIST form:fixed-text %for;
+ %disabled;
+ %label;
+ %printable;
+ %title;>
+<!ATTLIST form:fixed-text form:multi-line %boolean; "false">
+
+<!ELEMENT form:combobox (form:properties?, office:events?, form:item*)>
+<!ATTLIST form:combobox %current-value;
+ %disabled;
+ %dropdown;
+ %max-length;
+ %printable;
+ %readonly;
+ %size;
+ %tab-index;
+ %tab-stop;
+ %title;
+ %value;
+ %convert-empty;
+ %data-field;
+ %list-source;
+ %list-source-type;>
+<!ATTLIST form:combobox form:auto-complete %boolean; #IMPLIED>
+
+<!ELEMENT form:item (#PCDATA)>
+<!ATTLIST form:item %label;>
+
+<!ELEMENT form:listbox (form:properties?, office:events?, form:option*)>
+<!ATTLIST form:listbox %disabled;
+ %dropdown;
+ %printable;
+ %size;
+ %tab-index;
+ %tab-stop;
+ %title;
+ %bound-column;
+ %data-field;
+ %list-source;
+ %list-source-type;>
+<!ATTLIST form:listbox form:multiple %boolean; "false">
+
+<!ELEMENT form:option (#PCDATA)>
+<!ATTLIST form:option %current-selected;
+ %selected;
+ %label;
+ %value;>
+
+<!ELEMENT form:button (form:properties?, office:events?)>
+<!ATTLIST form:button %button-type;
+ %disabled;
+ %label;
+ %image-data;
+ %printable;
+ %tab-index;
+ %tab-stop;
+ %target-frame;
+ %target-location;
+ %title;
+ %value;>
+<!ATTLIST form:button form:default-button %boolean; "false">
+
+<!ELEMENT form:image (form:properties?, office:events?)>
+<!ATTLIST form:image %button-type;
+ %disabled;
+ %image-data;
+ %printable;
+ %tab-index;
+ %tab-stop;
+ %target-frame;
+ %target-location;
+ %title;
+ %value;>
+
+<!ELEMENT form:checkbox (form:properties?, office:events?)>
+<!ATTLIST form:checkbox %disabled;
+ %label;
+ %printable;
+ %tab-index;
+ %tab-stop;
+ %title;
+ %value;
+ %data-field;>
+<!ENTITY % states "(unchecked|checked|unknown)">
+<!ATTLIST form:checkbox form:current-state %states; #IMPLIED>
+<!ATTLIST form:checkbox form:is-tristate %boolean; "false">
+<!ATTLIST form:checkbox form:state %states; "unchecked">
+
+<!ELEMENT form:radio (form:properties?, office:events?)>
+<!ATTLIST form:radio %current-selected;
+ %disabled;
+ %label;
+ %printable;
+ %selected;
+ %tab-index;
+ %tab-stop;
+ %title;
+ %value;
+ %data-field;>
+
+<!ELEMENT form:frame (form:properties?, office:events?)>
+<!ATTLIST form:frame %disabled;
+ %for;
+ %label;
+ %printable;
+ %title;>
+
+<!ELEMENT form:image-frame (form:properties?, office:events?)>
+<!ATTLIST form:image-frame %disabled;
+ %image-data;
+ %printable;
+ %readonly;
+ %title;
+ %data-field;>
+
+<!ELEMENT form:hidden (form:properties?, office:events?)>
+<!ATTLIST form:hidden %name;
+ %service-name;
+ %value;>
+
+<!ELEMENT form:grid (form:properties?, office:events?, form:column*)>
+<!ATTLIST form:grid %disabled;
+ %printable;
+ %tab-index;
+ %tab-stop;
+ %title;>
+<!ENTITY % column-type "form:text| form:textarea| form:formatted-text|form:checkbox| form:listbox| form:combobox">
+<!ELEMENT form:column (%column-type;)+>
+<!ATTLIST form:column %name;
+ %service-name;
+ %label;>
+
+<!ELEMENT form:generic-control (form:properties?, office:events?)>
+
+
+<!ELEMENT form:properties (form:property+)>
+<!ELEMENT form:property (form:property-value*)>
+<!ATTLIST form:property form:property-is-list %boolean; #IMPLIED>
+<!ATTLIST form:property form:property-name CDATA #REQUIRED>
+<!ATTLIST form:property form:property-type (boolean|short|int|long|double|string) #REQUIRED>
+<!ELEMENT form:property-value (#PCDATA)>
+
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/meta.mod b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/meta.mod
new file mode 100644
index 000000000000..1ea845bcb02d
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/meta.mod
@@ -0,0 +1,90 @@
+<!--
+
+ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+
+ Copyright 2000, 2010 Oracle and/or its affiliates.
+
+ OpenOffice.org - a multi-platform office productivity suite
+
+ This file is part of OpenOffice.org.
+
+ OpenOffice.org is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License version 3
+ only, as published by the Free Software Foundation.
+
+ OpenOffice.org is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License version 3 for more details
+ (a copy is included in the LICENSE file that accompanied this code).
+
+ You should have received a copy of the GNU Lesser General Public License
+ version 3 along with OpenOffice.org. If not, see
+ <http://www.openoffice.org/license.html>
+ for a copy of the LGPLv3 License.
+
+-->
+
+
+<!ELEMENT meta:generator (%cString;)>
+
+<!ELEMENT dc:title (%cString;)>
+
+<!ELEMENT dc:description (%cString;)>
+
+<!ELEMENT dc:subject (%cString;)>
+
+<!ELEMENT meta:keywords (meta:keyword)*>
+<!ELEMENT meta:keyword (%cString;)>
+
+<!ELEMENT meta:initial-creator (%cString;)>
+
+<!ELEMENT dc:creator (%cString;)>
+
+<!ELEMENT meta:printed-by (%cString;)>
+
+<!ELEMENT meta:creation-date (%cTimeInstance;)>
+
+<!ELEMENT dc:date (%cTimeInstance;)>
+
+<!ELEMENT meta:print-date (%cTimeInstance;)>
+
+<!ELEMENT meta:template EMPTY>
+<!ATTLIST meta:template xlink:type (simple) #FIXED "simple">
+<!ATTLIST meta:template xlink:actuate (onRequest) "onRequest">
+<!ATTLIST meta:template xlink:href %uriReference; #REQUIRED>
+<!ATTLIST meta:template xlink:title %string; #IMPLIED>
+<!ATTLIST meta:template meta:date %timeInstance; #IMPLIED>
+
+<!ELEMENT meta:auto-reload EMPTY>
+<!ATTLIST meta:auto-reload xlink:type (simple) #IMPLIED>
+<!ATTLIST meta:auto-reload xlink:show (replace) #IMPLIED>
+<!ATTLIST meta:auto-reload xlink:actuate (onLoad) #IMPLIED>
+<!ATTLIST meta:auto-reload xlink:href %uriReference; #IMPLIED>
+<!ATTLIST meta:auto-reload meta:delay %timeDuration; "P0S">
+
+<!ELEMENT meta:hyperlink-behaviour EMPTY>
+<!ATTLIST meta:hyperlink-behaviour office:target-frame-name %targetFrameName; #IMPLIED>
+<!ATTLIST meta:hyperlink-behaviour xlink:show (new|replace) #IMPLIED>
+
+<!ELEMENT dc:language (%cLanguage;)>
+
+<!ELEMENT meta:editing-cycles (%cPositiveInteger;)>
+
+<!ELEMENT meta:editing-duration (%cTimeDuration;)>
+
+<!ELEMENT meta:user-defined (%cString;)>
+<!ATTLIST meta:user-defined meta:name %string; #REQUIRED>
+
+<!ELEMENT meta:document-statistic EMPTY>
+<!ATTLIST meta:document-statistic meta:page-count %positiveInteger; #IMPLIED
+ meta:table-count %nonNegativeInteger; #IMPLIED
+ meta:draw-count %nonNegativeInteger; #IMPLIED
+ meta:image-count %nonNegativeInteger; #IMPLIED
+ meta:ole-object-count %nonNegativeInteger; #IMPLIED
+ meta:paragraph-count %nonNegativeInteger; #IMPLIED
+ meta:word-count %nonNegativeInteger; #IMPLIED
+ meta:character-count %nonNegativeInteger; #IMPLIED
+ meta:row-count %nonNegativeInteger; #IMPLIED
+ meta:cell-count %nonNegativeInteger; #IMPLIED
+ meta:object-count %positiveInteger; #IMPLIED>
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/nmspace.mod b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/nmspace.mod
new file mode 100644
index 000000000000..b7f6b64140a6
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/nmspace.mod
@@ -0,0 +1,50 @@
+<!--
+
+ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+
+ Copyright 2000, 2010 Oracle and/or its affiliates.
+
+ OpenOffice.org - a multi-platform office productivity suite
+
+ This file is part of OpenOffice.org.
+
+ OpenOffice.org is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License version 3
+ only, as published by the Free Software Foundation.
+
+ OpenOffice.org is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License version 3 for more details
+ (a copy is included in the LICENSE file that accompanied this code).
+
+ You should have received a copy of the GNU Lesser General Public License
+ version 3 along with OpenOffice.org. If not, see
+ <http://www.openoffice.org/license.html>
+ for a copy of the LGPLv3 License.
+
+-->
+
+<!ENTITY nFO "http://www.w3.org/1999/XSL/Format">
+<!ENTITY nXLink "http://www.w3.org/1999/xlink">
+<!ENTITY nSVG "http://www.w3.org/2000/svg">
+
+<!-- StarOffice namespace names and prefixes -->
+
+<!ENTITY nOpenOffice "http://openoffice.org/2000">
+<!ENTITY nOpenOffice2001 "http://openoffice.org/2001">
+
+<!ENTITY nOffice "&nOpenOffice;/office">
+<!ENTITY nStyle "&nOpenOffice;/style">
+<!ENTITY nText "&nOpenOffice;/text">
+<!ENTITY nTable "&nOpenOffice;/table">
+<!ENTITY nMeta "&nOpenOffice;/meta">
+<!ENTITY nScript "&nOpenOffice;/script">
+<!ENTITY nDraw "&nOpenOffice;/drawing">
+<!ENTITY nChart "&nOpenOffice;/chart">
+<!ENTITY nNumber "&nOpenOffice;/datastyle">
+<!ENTITY nConfig "&nOpenOffice2001;/config">
+
+
+<!-- dublin core namespace name and prefic -->
+<!ENTITY nDC "http://purl.org/dc/elements/1.1/">
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/office.dtd b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/office.dtd
new file mode 100644
index 000000000000..9bcd37edf325
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/office.dtd
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+
+ Copyright 2000, 2010 Oracle and/or its affiliates.
+
+ OpenOffice.org - a multi-platform office productivity suite
+
+ This file is part of OpenOffice.org.
+
+ OpenOffice.org is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License version 3
+ only, as published by the Free Software Foundation.
+
+ OpenOffice.org is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License version 3 for more details
+ (a copy is included in the LICENSE file that accompanied this code).
+
+ You should have received a copy of the GNU Lesser General Public License
+ version 3 along with OpenOffice.org. If not, see
+ <http://www.openoffice.org/license.html>
+ for a copy of the LGPLv3 License.
+
+-->
+
+<!ENTITY % dtypes-mod SYSTEM "dtypes.mod">
+%dtypes-mod;
+<!ENTITY % nmspace-mod SYSTEM "nmspace.mod">
+%nmspace-mod;
+<!ENTITY % style-mod SYSTEM "style.mod">
+%style-mod;
+<!ENTITY % office-mod SYSTEM "office.mod">
+%office-mod;
+<!ENTITY % meta-mod SYSTEM "meta.mod">
+%meta-mod;
+<!ENTITY % script-mod SYSTEM "script.mod">
+%script-mod;
+<!ENTITY % drawing-mod SYSTEM "drawing.mod">
+%drawing-mod;
+<!ENTITY % text-mod SYSTEM "text.mod">
+%text-mod;
+<!ENTITY % table-mod SYSTEM "table.mod">
+%table-mod;
+<!ENTITY % chart-mod SYSTEM "chart.mod">
+%chart-mod;
+<!ENTITY % datastyl-mod SYSTEM "datastyl.mod">
+%datastyl-mod;
+<!ENTITY % form-mod SYSTEM "form.mod">
+%form-mod;
+<!ENTITY % settings-mod SYSTEM "settings.mod">
+%settings-mod;
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/office.mod b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/office.mod
new file mode 100644
index 000000000000..f8e3775fa6da
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/office.mod
@@ -0,0 +1,234 @@
+<!--
+
+ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+
+ Copyright 2000, 2010 Oracle and/or its affiliates.
+
+ OpenOffice.org - a multi-platform office productivity suite
+
+ This file is part of OpenOffice.org.
+
+ OpenOffice.org is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License version 3
+ only, as published by the Free Software Foundation.
+
+ OpenOffice.org is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License version 3 for more details
+ (a copy is included in the LICENSE file that accompanied this code).
+
+ You should have received a copy of the GNU Lesser General Public License
+ version 3 along with OpenOffice.org. If not, see
+ <http://www.openoffice.org/license.html>
+ for a copy of the LGPLv3 License.
+
+-->
+
+<!ELEMENT office:document ( office:meta?,
+ office:settings?,
+ office:script?,
+ office:font-decls?,
+ office:styles?,
+ office:automatic-styles?,
+ office:master-styles?,
+ office:body ) >
+
+<!ATTLIST office:document xmlns:office CDATA #FIXED "&nOffice;">
+<!ATTLIST office:document xmlns:meta CDATA #FIXED "&nMeta;">
+<!ATTLIST office:document xmlns:script CDATA #FIXED "&nScript;">
+<!ATTLIST office:document xmlns:style CDATA #FIXED "&nStyle;">
+<!ATTLIST office:document xmlns:text CDATA #FIXED "&nText;">
+<!ATTLIST office:document xmlns:table CDATA #FIXED "&nTable;">
+<!ATTLIST office:document xmlns:draw CDATA #FIXED "&nDraw;">
+<!ATTLIST office:document xmlns:chart CDATA #FIXED "&nChart;">
+<!ATTLIST office:document xmlns:number CDATA #FIXED "&nNumber;">
+<!ATTLIST office:document xmlns:fo CDATA #FIXED "&nFO;">
+<!ATTLIST office:document xmlns:xlink CDATA #FIXED "&nXLink;">
+<!ATTLIST office:document xmlns:svg CDATA #FIXED "&nSVG;">
+<!ATTLIST office:document xmlns:dc CDATA #FIXED "&nDC;">
+
+<!ATTLIST office:document office:class
+ (text|text-global|
+ drawing|presentation|
+ spreadsheet|chart) #REQUIRED>
+
+<!ATTLIST office:document office:version %string; #IMPLIED>
+
+<!-- document-styles -->
+<!ELEMENT office:document-styles (
+ office:font-decls?,
+ office:styles?,
+ office:automatic-styles?,
+ office:master-styles? ) >
+
+<!ATTLIST office:document-styles xmlns:office CDATA #FIXED "&nOffice;">
+<!ATTLIST office:document-styles xmlns:meta CDATA #FIXED "&nMeta;">
+<!ATTLIST office:document-styles xmlns:script CDATA #FIXED "&nScript;">
+<!ATTLIST office:document-styles xmlns:style CDATA #FIXED "&nStyle;">
+<!ATTLIST office:document-styles xmlns:text CDATA #FIXED "&nText;">
+<!ATTLIST office:document-styles xmlns:table CDATA #FIXED "&nTable;">
+<!ATTLIST office:document-styles xmlns:draw CDATA #FIXED "&nDraw;">
+<!ATTLIST office:document-styles xmlns:chart CDATA #FIXED "&nChart;">
+<!ATTLIST office:document-styles xmlns:number CDATA #FIXED "&nNumber;">
+<!ATTLIST office:document-styles xmlns:fo CDATA #FIXED "&nFO;">
+<!ATTLIST office:document-styles xmlns:xlink CDATA #FIXED "&nXLink;">
+<!ATTLIST office:document-styles xmlns:svg CDATA #FIXED "&nSVG;">
+<!ATTLIST office:document-styles xmlns:dc CDATA #FIXED "&nDC;">
+
+<!ATTLIST office:document-styles office:version %string; #IMPLIED>
+
+<!-- document-content -->
+
+<!ELEMENT office:document-content (
+ office:script?,
+ office:font-decls?,
+ office:automatic-styles?,
+ office:body ) >
+
+<!ATTLIST office:document-content xmlns:office CDATA #FIXED "&nOffice;">
+<!ATTLIST office:document-content xmlns:meta CDATA #FIXED "&nMeta;">
+<!ATTLIST office:document-content xmlns:script CDATA #FIXED "&nScript;">
+<!ATTLIST office:document-content xmlns:style CDATA #FIXED "&nStyle;">
+<!ATTLIST office:document-content xmlns:text CDATA #FIXED "&nText;">
+<!ATTLIST office:document-content xmlns:table CDATA #FIXED "&nTable;">
+<!ATTLIST office:document-content xmlns:draw CDATA #FIXED "&nDraw;">
+<!ATTLIST office:document-content xmlns:chart CDATA #FIXED "&nChart;">
+<!ATTLIST office:document-content xmlns:number CDATA #FIXED "&nNumber;">
+<!ATTLIST office:document-content xmlns:fo CDATA #FIXED "&nFO;">
+<!ATTLIST office:document-content xmlns:xlink CDATA #FIXED "&nXLink;">
+<!ATTLIST office:document-content xmlns:svg CDATA #FIXED "&nSVG;">
+<!ATTLIST office:document-content xmlns:dc CDATA #FIXED "&nDC;">
+
+<!ATTLIST office:document-content office:class
+ (text|text-global|
+ drawing|presentation|
+ spreadsheet|chart) #REQUIRED>
+
+<!ATTLIST office:document-content office:version %string; #IMPLIED>
+
+<!-- document-content -->
+
+<!ELEMENT office:document-meta ( office:meta? ) >
+
+<!ATTLIST office:document-meta xmlns:office CDATA #FIXED "&nOffice;">
+<!ATTLIST office:document-meta xmlns:meta CDATA #FIXED "&nMeta;">
+<!ATTLIST office:document-meta xmlns:script CDATA #FIXED "&nScript;">
+<!ATTLIST office:document-meta xmlns:style CDATA #FIXED "&nStyle;">
+<!ATTLIST office:document-meta xmlns:text CDATA #FIXED "&nText;">
+<!ATTLIST office:document-meta xmlns:table CDATA #FIXED "&nTable;">
+<!ATTLIST office:document-meta xmlns:draw CDATA #FIXED "&nDraw;">
+<!ATTLIST office:document-meta xmlns:chart CDATA #FIXED "&nChart;">
+<!ATTLIST office:document-meta xmlns:number CDATA #FIXED "&nNumber;">
+<!ATTLIST office:document-meta xmlns:fo CDATA #FIXED "&nFO;">
+<!ATTLIST office:document-meta xmlns:xlink CDATA #FIXED "&nXLink;">
+<!ATTLIST office:document-meta xmlns:svg CDATA #FIXED "&nSVG;">
+<!ATTLIST office:document-meta xmlns:dc CDATA #FIXED "&nDC;">
+
+<!ATTLIST office:document-meta office:version %string; #IMPLIED>
+
+<!ELEMENT office:document-settings (office:settings) >
+<!ATTLIST office:document-settings xmlns:office CDATA #FIXED "&nOffice;">
+<!ATTLIST office:document-settings xmlns:xlink CDATA #FIXED "&nXLink;">
+<!ATTLIST office:document-settings xmlns:config CDATA #FIXED "&nConfig;">
+
+<!ATTLIST office:document-settings office:version %string; #IMPLIED>
+
+<!ENTITY % meta "(meta:generator?,
+ dc:title?,
+ dc:description?,
+ dc:subject?,
+ meta:initial-creator?,
+ meta:creation-date?,
+ dc:creator?,
+ dc:date?,
+ meta:printed-by?,
+ meta:print-date?,
+ meta:keywords?,
+ dc:language?,
+ meta:editing-cycles?,
+ meta:editing-duration?,
+ meta:hyperlink-behaviour?,
+ meta:auto-reload?,
+ meta:template?,
+ meta:user-defined*,
+ meta:document-statistic?)">
+<!ELEMENT office:meta %meta;>
+
+<!ENTITY % script "(script:library-embedded |
+ script:library-linked)*">
+<!ELEMENT office:script %script;>
+
+<!ELEMENT office:font-decls (style:font-decl)*>
+
+<!ENTITY % styles "(style:default-style|style:style|text:list-style|
+ number:number-style|number:currency-style|number:percentage-style|
+ number:date-style|number:time-style|number:boolean-style|
+ number:text-style|
+ draw:gradient|draw:hatch|draw:fill-image|draw:marker|draw:stroke-dash|
+ style:presentation-page-layout|draw:transparency)">
+
+<!-- Validity constraint: The elements
+ text:outline-style,
+ text:footnotes-configuration,
+ text:endnotes-configuration,
+ text:bibliography-configuration and
+ text:linenumbering-configuration
+ may appear only once!
+ Unfortunatetly, this constraint cannot be easily specified in the DTD.
+-->
+<!ELEMENT office:styles (%styles;|text:outline-style|
+ text:footnotes-configuration|text:endnotes-configuration|
+ text:bibliography-configuration|text:linenumbering-configuration)*>
+
+<!ELEMENT office:automatic-styles (%styles;|style:page-master)*>
+
+<!ELEMENT office:master-styles (draw:layer-set?,style:handout-master?,style:master-page*) >
+
+<!ENTITY % text-decls "text:variable-decls?, text:sequence-decls?,
+ text:user-field-decls?, text:dde-connection-decls?,
+ text:alphabetical-index-auto-mark-file?" >
+
+<!ENTITY % change-marks "text:change | text:change-start | text:change-end">
+
+<!ENTITY % body "(office:forms?,(text:tracked-changes|table:tracked-changes)?,%text-decls;,table:calculation-settings?,table:content-validations?,table:label-ranges?,
+ (text:h|text:p|text:ordered-list|
+ text:unordered-list|table:table|draw:page|
+ draw:a|%shape;|text:section|text:table-of-content|
+ text:illustration-index|text:table-index|text:object-index|
+ text:user-index|text:alphabetical-index|text:bibliography|
+ %change-marks;)*,
+ table:named-expressions?,
+ table:database-ranges?,table:data-pilot-tables?,
+ table:consolidation?,
+ table:dde-links?,
+ presentation:settings?)">
+<!ELEMENT office:body %body;>
+<!ATTLIST office:body table:structure-protected %boolean; "false"
+ table:protection-key CDATA #IMPLIED>
+
+<!ELEMENT office:events (script:event|presentation:event)*>
+
+<!-- DDE source: for text sections and tables -->
+<!ELEMENT office:dde-source EMPTY>
+<!ATTLIST office:dde-source office:dde-application CDATA #IMPLIED>
+<!ATTLIST office:dde-source office:dde-topic CDATA #IMPLIED>
+<!ATTLIST office:dde-source office:dde-item CDATA #IMPLIED>
+<!ATTLIST office:dde-source office:automatic-update %boolean; "false">
+<!ATTLIST office:dde-source office:name CDATA #IMPLIED>
+<!ATTLIST office:dde-source table:conversion-mode (into-default-style-data-style|into-english-number|let-text) "into-default-style-data-style" >
+
+<!-- annotations -->
+<!-- limitation: in the current implementation, only plain text inside of
+ paragraphs is supported -->
+<!ELEMENT office:annotation (text:p)*>
+<!ATTLIST office:annotation office:author %string; #IMPLIED>
+<!ATTLIST office:annotation office:create-date %date; #IMPLIED>
+<!ATTLIST office:annotation office:create-date-string %string; #IMPLIED>
+<!ATTLIST office:annotation office:display %boolean; "false">
+
+<!ELEMENT office:change-info (text:p)*>
+<!ATTLIST office:change-info office:chg-author %string; #REQUIRED>
+<!ATTLIST office:change-info office:chg-date-time %timeInstance; #REQUIRED>
+
+<!ELEMENT office:binary-data (#PCDATA)>
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/script.mod b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/script.mod
new file mode 100644
index 000000000000..4d13ff74aebc
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/script.mod
@@ -0,0 +1,51 @@
+<!--
+
+ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+
+ Copyright 2000, 2010 Oracle and/or its affiliates.
+
+ OpenOffice.org - a multi-platform office productivity suite
+
+ This file is part of OpenOffice.org.
+
+ OpenOffice.org is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License version 3
+ only, as published by the Free Software Foundation.
+
+ OpenOffice.org is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License version 3 for more details
+ (a copy is included in the LICENSE file that accompanied this code).
+
+ You should have received a copy of the GNU Lesser General Public License
+ version 3 along with OpenOffice.org. If not, see
+ <http://www.openoffice.org/license.html>
+ for a copy of the LGPLv3 License.
+
+-->
+
+<!ELEMENT script:library-embedded (script:module*)>
+<!ATTLIST script:library-embedded script:name %string; #REQUIRED>
+<!ATTLIST script:library-embedded script:password %string; #IMPLIED>
+
+<!ELEMENT script:library-linked EMPTY>
+<!ATTLIST script:library-linked script:name %string; #REQUIRED>
+<!ATTLIST script:library-linked xlink:href %string; #REQUIRED>
+<!ATTLIST script:library-linked xlink:type (simple) #FIXED "simple">
+
+<!ELEMENT script:module (#PCDATA)>
+<!ATTLIST script:module script:name %string; #REQUIRED>
+<!ATTLIST script:module script:language %string; #IMPLIED>
+
+
+<!ENTITY % script-language "script:language %string; #REQUIRED">
+<!ENTITY % event-name "script:event-name %string; #REQUIRED">
+<!ENTITY % location "script:location (document|application) #REQUIRED">
+<!ENTITY % macro-name "script:macro-name %string; #REQUIRED">
+
+<!ELEMENT script:event (#PCDATA)>
+<!ATTLIST script:event %script-language;
+ %event-name;
+ %location;
+ %macro-name;>
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/settings.mod b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/settings.mod
new file mode 100644
index 000000000000..bb9224237fa8
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/settings.mod
@@ -0,0 +1,49 @@
+<!--
+
+ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+
+ Copyright 2000, 2010 Oracle and/or its affiliates.
+
+ OpenOffice.org - a multi-platform office productivity suite
+
+ This file is part of OpenOffice.org.
+
+ OpenOffice.org is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License version 3
+ only, as published by the Free Software Foundation.
+
+ OpenOffice.org is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License version 3 for more details
+ (a copy is included in the LICENSE file that accompanied this code).
+
+ You should have received a copy of the GNU Lesser General Public License
+ version 3 along with OpenOffice.org. If not, see
+ <http://www.openoffice.org/license.html>
+ for a copy of the LGPLv3 License.
+
+-->
+
+<!ELEMENT office:settings (config:config-item-set+)>
+
+<!ENTITY % items "(config:config-item |
+ config:config-item-set |
+ config:config-item-map-named |
+ config:config-item-map-indexed)+">
+
+<!ELEMENT config:config-item-set %items;>
+<!ATTLIST config:config-item-set config:name CDATA #REQUIRED>
+
+<!ELEMENT config:config-item (#PCDATA)>
+<!ATTLIST config:config-item config:name CDATA #REQUIRED
+ config:type (boolean | short | int | long | double | string | datetime | base64Binary) #REQUIRED>
+
+<!ELEMENT config:config-item-map-named (config:config-item-map-entry)+>
+<!ATTLIST config:config-item-map-named config:name CDATA #REQUIRED>
+
+<!ELEMENT config:config-item-map-indexed (config:config-item-map-entry)+>
+<!ATTLIST config:config-item-map-indexed config:name CDATA #REQUIRED>
+
+<!ELEMENT config:config-item-map-entry %items;>
+<!ATTLIST config:config-item-map-entry config:name CDATA #IMPLIED>
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/style.mod b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/style.mod
new file mode 100644
index 000000000000..21a3d9d17dd1
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/style.mod
@@ -0,0 +1,391 @@
+<!--
+
+ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+
+ Copyright 2000, 2010 Oracle and/or its affiliates.
+
+ OpenOffice.org - a multi-platform office productivity suite
+
+ This file is part of OpenOffice.org.
+
+ OpenOffice.org is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License version 3
+ only, as published by the Free Software Foundation.
+
+ OpenOffice.org is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License version 3 for more details
+ (a copy is included in the LICENSE file that accompanied this code).
+
+ You should have received a copy of the GNU Lesser General Public License
+ version 3 along with OpenOffice.org. If not, see
+ <http://www.openoffice.org/license.html>
+ for a copy of the LGPLv3 License.
+
+-->
+
+<!ELEMENT style:font-decl EMPTY>
+<!ATTLIST style:font-decl style:name %string; #REQUIRED>
+<!ATTLIST style:font-decl fo:font-family %string; #REQUIRED>
+<!ATTLIST style:font-decl style:font-style-name %string; #IMPLIED>
+<!ENTITY % fontFamilyGeneric "(roman|swiss|modern|decorative|script|system)">
+<!ATTLIST style:font-decl style:font-family-generic %fontFamilyGeneric;
+ #IMPLIED>
+<!ENTITY % fontPitch "(fixed|variable)">
+<!ATTLIST style:font-decl style:font-pitch %fontPitch; #IMPLIED>
+<!ATTLIST style:font-decl style:font-charset %textEncoding; #IMPLIED>
+
+<!ELEMENT style:style ( style:properties?,office:events?,style:map*)>
+
+<!ATTLIST style:style style:name %styleName; #REQUIRED>
+
+<!ENTITY % styleFamily "(paragraph|text|section|
+ table|table-column|table-row|table-cell|table-page|chart|graphics|default|drawing-page|presentation|control)">
+<!ATTLIST style:style style:family %styleFamily; #REQUIRED>
+
+<!ATTLIST style:style style:parent-style-name %styleName; #IMPLIED>
+<!ATTLIST style:style style:master-page-name %styleName; #IMPLIED>
+<!ATTLIST style:style style:next-style-name %styleName; #IMPLIED>
+<!ATTLIST style:style style:list-style-name %styleName; #IMPLIED>
+<!ATTLIST style:style style:data-style-name %styleName; #IMPLIED>
+
+<!ATTLIST style:style style:auto-update %boolean; "false">
+
+<!ATTLIST style:style style:class %string; #IMPLIED>
+
+<!ELEMENT style:default-style (style:properties?)>
+<!ATTLIST style:default-style style:family %styleFamily; #REQUIRED>
+
+<!ELEMENT style:map EMPTY>
+
+<!ATTLIST style:map style:condition %string; #REQUIRED>
+<!ATTLIST style:map style:apply-style-name %styleName; #REQUIRED>
+<!ATTLIST style:map style:base-cell-address %cell-address; #IMPLIED>
+
+<!ELEMENT style:properties ANY>
+
+<!-- number format properties -->
+<!ATTLIST style:properties style:num-prefix %string; #IMPLIED>
+<!ATTLIST style:properties style:num-suffix %string; #IMPLIED>
+<!ATTLIST style:properties style:num-format %string; #IMPLIED>
+<!ATTLIST style:properties style:num-letter-sync %boolean; #IMPLIED>
+
+<!-- frame properties -->
+<!ATTLIST style:properties fo:width %positiveLength; #IMPLIED>
+<!ATTLIST style:properties fo:height %positiveLength; #IMPLIED>
+<!ATTLIST style:properties style:vertical-pos (top|middle|bottom|from-top) #IMPLIED>
+<!ATTLIST style:properties style:vertical-rel (page|page-content|
+ frame|frame-content|
+ paragraph|paragraph-content|char|
+ line|baseline|text) #IMPLIED>
+<!ATTLIST style:properties style:horizontal-pos (left|center|right|from-left|inside|outside|from-inside) #IMPLIED>
+<!ATTLIST style:properties style:horizontal-rel (page|page-content|
+ frame|frame-content|
+ paragraph|paragraph-content|
+ char) #IMPLIED>
+<!ATTLIST style:properties svg:width %lengthOrPercentage; #IMPLIED>
+<!ATTLIST style:properties svg:height %lengthOrPercentage; #IMPLIED>
+<!ATTLIST style:properties fo:min-height %lengthOrPercentage; #IMPLIED>
+<!ATTLIST style:properties fo:min-width %lengthOrPercentage; #IMPLIED>
+<!ATTLIST style:properties fo:max-height %lengthOrPercentage; #IMPLIED>
+<!ATTLIST style:properties fo:max-width %lengthOrPercentage; #IMPLIED>
+<!ATTLIST style:properties text:anchor-type %anchorType; #IMPLIED>
+<!ATTLIST style:properties text:anchor-page-number %positiveInteger; #IMPLIED>
+<!ATTLIST style:properties svg:x %coordinate; #IMPLIED>
+<!ATTLIST style:properties svg:y %coordinate; #IMPLIED>
+<!ATTLIST style:properties style:print-content %boolean; #IMPLIED>
+<!ATTLIST style:properties style:protect %boolean; #IMPLIED>
+<!ATTLIST style:properties style:wrap (none|left|right|parallel|dynamic|run-through) #IMPLIED>
+<!ENTITY % noLimitOrPositiveInteger "CDATA">
+<!ATTLIST style:properties style:number-wrapped-paragraphs %noLimitOrPositiveInteger; #IMPLIED>
+<!ATTLIST style:properties style:wrap-contour %boolean; #IMPLIED>
+<!ATTLIST style:properties style:wrap-contour-mode (full|outside) #IMPLIED>
+<!ATTLIST style:properties style:run-through (foreground|background) #IMPLIED>
+<!ATTLIST style:properties style:editable %boolean; #IMPLIED>
+<!ATTLIST style:properties style:mirror CDATA #IMPLIED>
+<!ATTLIST style:properties fo:clip CDATA #IMPLIED>
+<!ATTLIST style:properties text:animation (none|scroll|alternate|slide) #IMPLIED>
+<!ATTLIST style:properties text:animation-direction (left|right|up|down) #IMPLIED>
+<!ATTLIST style:properties text:animation-start-inside %boolean; #IMPLIED>
+<!ATTLIST style:properties text:animation-stop-inside %boolean; #IMPLIED>
+<!ATTLIST style:properties text:animation-repeat %integer; #IMPLIED>
+<!ATTLIST style:properties text:animation-delay %timeDuration; #IMPLIED>
+<!ATTLIST style:properties text:animation-steps %length; #IMPLIED>
+
+<!-- text properties -->
+<!ATTLIST style:properties fo:font-variant (normal|small-caps) #IMPLIED>
+<!ATTLIST style:properties fo:text-transform (none|lowercase|
+ uppercase|capitalize) #IMPLIED>
+<!ATTLIST style:properties fo:color %color; #IMPLIED>
+<!ATTLIST style:properties style:use-window-font-color %boolean; #IMPLIED>
+<!ATTLIST style:properties style:text-outline %boolean; #IMPLIED>
+<!ATTLIST style:properties style:text-crossing-out
+ (none|single-line|double-line|thick-line|slash|X)
+ #IMPLIED>
+<!ATTLIST style:properties style:text-position CDATA #IMPLIED>
+<!ATTLIST style:properties style:text-align (left|right|start|center|end|justify|justified) #IMPLIED>
+
+<!ATTLIST style:properties style:font-name %string; #IMPLIED>
+<!ATTLIST style:properties fo:font-family %string; #IMPLIED>
+<!ATTLIST style:properties style:font-family-generic %fontFamilyGeneric;
+ #IMPLIED>
+<!ATTLIST style:properties style:font-style-name %string; #IMPLIED>
+<!ATTLIST style:properties style:font-pitch %fontPitch; #IMPLIED>
+<!ATTLIST style:properties style:font-charset %textEncoding; #IMPLIED>
+<!ATTLIST style:properties style:font-name-asian %string; #IMPLIED>
+<!ATTLIST style:properties style:font-family-asian %string; #IMPLIED>
+<!ATTLIST style:properties style:font-family-generic-asian %fontFamilyGeneric;
+ #IMPLIED>
+<!ATTLIST style:properties style:font-style-name-asian %string; #IMPLIED>
+<!ATTLIST style:properties style:font-pitch-asian %fontPitch; #IMPLIED>
+<!ATTLIST style:properties style:font-charset-asian %textEncoding; #IMPLIED>
+<!ATTLIST style:properties style:font-name-complex %string; #IMPLIED>
+<!ATTLIST style:properties style:font-family-complex %string; #IMPLIED>
+<!ATTLIST style:properties style:font-family-generic-complex %fontFamilyGeneric;
+ #IMPLIED>
+<!ATTLIST style:properties style:font-style-name-complex %string; #IMPLIED>
+<!ATTLIST style:properties style:font-pitch-complex %fontPitch; #IMPLIED>
+<!ATTLIST style:properties style:font-charset-complex %textEncoding; #IMPLIED>
+
+<!ATTLIST style:properties fo:font-size %positiveLengthOrPercentage; #IMPLIED>
+<!ATTLIST style:properties style:font-size-rel %length; #IMPLIED>
+<!ATTLIST style:properties style:font-size-asian %positiveLengthOrPercentage; #IMPLIED>
+<!ATTLIST style:properties style:font-size-rel-asian %length; #IMPLIED>
+<!ATTLIST style:properties style:font-size-complex %positiveLengthOrPercentage; #IMPLIED>
+<!ATTLIST style:properties style:font-size-rel-complex %length; #IMPLIED>
+<!ENTITY % normalOrLength "CDATA">
+<!ATTLIST style:properties fo:letter-spacing %normalOrLength; #IMPLIED>
+<!ATTLIST style:properties fo:language %languageOnly; #IMPLIED>
+<!ATTLIST style:properties style:language-asian %languageOnly; #IMPLIED>
+<!ATTLIST style:properties style:language-complex %languageOnly; #IMPLIED>
+<!ATTLIST style:properties fo:country %country; #IMPLIED>
+<!ATTLIST style:properties style:country-asian %country; #IMPLIED>
+<!ATTLIST style:properties style:country-complex %country; #IMPLIED>
+<!ENTITY % fontStyle "(normal|italic|oblique)">
+<!ATTLIST style:properties fo:font-style %fontStyle; #IMPLIED>
+<!ATTLIST style:properties style:font-style-asian %fontStyle; #IMPLIED>
+<!ATTLIST style:properties style:font-style-complex %fontStyle; #IMPLIED>
+<!ENTITY % fontRelief "(none|embossed|engraved)">
+<!ATTLIST style:properties style:font-relief %fontRelief; #IMPLIED>
+<!ATTLIST style:properties fo:text-shadow CDATA #IMPLIED>
+<!ATTLIST style:properties style:text-underline
+ (none|single|double|dotted|dash|long-dash|dot-dash|
+ dot-dot-dash|wave|bold|bold-dotted|bold-dash|
+ bold-long-dash|bold-dot-dash|bold-dot-dot-dash|
+ bold-wave|double-wave|small-wave) #IMPLIED>
+<!ATTLIST style:properties style:text-autospace (none | ideograph-alpha) #IMPLIED>
+<!ATTLIST style:properties style:punctuation-wrap (simple | hanging) #IMPLIED>
+<!ATTLIST style:properties style:line-break (normal | strict) #IMPLIED>
+<!ENTITY % fontColorOrColor "CDATA">
+<!ATTLIST style:properties style:text-underline-color %fontColorOrColor;
+ #IMPLIED>
+<!ATTLIST style:properties fo:font-weight CDATA #IMPLIED>
+<!ATTLIST style:properties style:font-weight-asian CDATA #IMPLIED>
+<!ATTLIST style:properties style:font-weight-complex CDATA #IMPLIED>
+<!ATTLIST style:properties fo:score-spaces %boolean; #IMPLIED>
+<!ATTLIST style:properties style:letter-kerning %boolean; #IMPLIED>
+<!ATTLIST style:properties style:text-blinking %boolean; #IMPLIED>
+<!ATTLIST style:properties style:text-background-color %transparentOrColor;
+ #IMPLIED>
+
+<!ATTLIST style:properties style:text-combine (none|letters|lines) #IMPLIED>
+<!ATTLIST style:properties style:text-combine-start-char %character; #IMPLIED>
+<!ATTLIST style:properties style:text-combine-end-char %character; #IMPLIED>
+<!ATTLIST style:properties style:text-emphasize CDATA #IMPLIED>
+<!ATTLIST style:properties style:text-scale %percentage; #IMPLIED>
+<!ATTLIST style:properties style:text-rotation-angle %integer; #IMPLIED>
+<!ATTLIST style:properties style:text-rotation-scale (fixed|line-height) #IMPLIED>
+
+<!-- paragraph properties -->
+<!ENTITY % nonNegativeLengthOrPercentageOrNormal "CDATA">
+<!ATTLIST style:properties fo:line-height
+ %nonNegativeLengthOrPercentageOrNormal; #IMPLIED>
+<!ATTLIST style:properties style:line-height-at-least %nonNegativeLength;
+ #IMPLIED>
+<!ATTLIST style:properties style:line-spacing %length; #IMPLIED>
+<!ATTLIST style:properties fo:text-align (start|end|center|justify) #IMPLIED>
+<!ATTLIST style:properties fo:text-align-last (start|center|justify) #IMPLIED>
+<!ATTLIST style:properties style:text-align-source (fix|value-type) #IMPLIED>
+<!ATTLIST style:properties style:justify-single-word %boolean; #IMPLIED>
+<!ATTLIST style:properties style:break-inside (auto|avoid) #IMPLIED>
+<!ATTLIST style:properties fo:widows %nonNegativeInteger; #IMPLIED>
+<!ATTLIST style:properties fo:orphans %nonNegativeInteger; #IMPLIED>
+
+<!ATTLIST style:properties fo:hyphenate %boolean; #IMPLIED>
+<!ATTLIST style:properties fo:hyphenate-keep (none|page) #IMPLIED>
+<!ATTLIST style:properties fo:hyphenation-remain-char-count %positiveInteger;
+ #IMPLIED>
+<!ATTLIST style:properties fo:hyphenation-push-char-count %positiveInteger;
+ #IMPLIED>
+<!ATTLIST style:properties fo:hyphenation-ladder-count
+ %noLimitOrPositiveInteger; #IMPLIED>
+<!ATTLIST style:properties style:page-number %positiveInteger; #IMPLIED>
+
+<!ELEMENT style:tab-stops (style:tab-stop)*>
+<!ELEMENT style:tab-stop EMPTY>
+<!ATTLIST style:tab-stop style:position %nonNegativeLength; #REQUIRED>
+<!ATTLIST style:tab-stop style:type (left|center|right|char|default) "left">
+<!ATTLIST style:tab-stop style:char %character; #IMPLIED>
+<!ATTLIST style:tab-stop style:leader-char %character; " ">
+
+<!ELEMENT style:drop-cap EMPTY>
+<!ENTITY % wordOrPositiveInteger "CDATA">
+<!ATTLIST style:drop-cap style:length %wordOrPositiveInteger; "1">
+<!ATTLIST style:drop-cap style:lines %positiveInteger; "1">
+<!ATTLIST style:drop-cap style:distance %length; "0cm">
+<!ATTLIST style:drop-cap style:style-name %styleName; #IMPLIED>
+
+<!ATTLIST style:properties style:register-true %boolean; #IMPLIED>
+<!ATTLIST style:properties style:register-truth-ref-style-name %styleName; #IMPLIED>
+<!ATTLIST style:properties fo:margin-left %positiveLengthOrPercentage; #IMPLIED>
+<!ATTLIST style:properties fo:margin-right %positiveLengthOrPercentage;
+ #IMPLIED>
+<!ATTLIST style:properties fo:text-indent %lengthOrPercentage; #IMPLIED>
+<!ATTLIST style:properties style:auto-text-indent %boolean; #IMPLIED>
+<!ATTLIST style:properties fo:margin-top %positiveLengthOrPercentage; #IMPLIED>
+<!ATTLIST style:properties fo:margin-bottom %positiveLengthOrPercentage; #IMPLIED>
+<!ATTLIST style:properties fo:break-before (auto|column|page) #IMPLIED>
+<!ATTLIST style:properties fo:break-after (auto|column|page) #IMPLIED>
+<!ATTLIST style:properties fo:background-color %transparentOrColor; #IMPLIED>
+
+<!ELEMENT style:background-image (office:binary-data?)>
+<!ATTLIST style:background-image xlink:type (simple) #IMPLIED>
+<!ATTLIST style:background-image xlink:href %uriReference; #IMPLIED>
+<!ATTLIST style:background-image xlink:show (embed) #IMPLIED>
+<!ATTLIST style:background-image xlink:actuate (onLoad) #IMPLIED>
+<!ATTLIST style:background-image style:repeat (no-repeat|repeat|stretch)
+ "repeat">
+<!ATTLIST style:background-image style:position CDATA "center">
+<!ATTLIST style:background-image style:filter-name %string; #IMPLIED>
+
+<!ELEMENT style:symbol-image (office:binary-data?)>
+<!ATTLIST style:symbol-image xlink:type (simple) #IMPLIED>
+<!ATTLIST style:symbol-image xlink:href %uriReference; #IMPLIED>
+<!ATTLIST style:symbol-image xlink:show (embed) #IMPLIED>
+<!ATTLIST style:symbol-image xlink:actuate (onLoad) #IMPLIED>
+
+<!ATTLIST style:properties fo:border CDATA #IMPLIED>
+<!ATTLIST style:properties fo:border-top CDATA #IMPLIED>
+<!ATTLIST style:properties fo:border-bottom CDATA #IMPLIED>
+<!ATTLIST style:properties fo:border-left CDATA #IMPLIED>
+<!ATTLIST style:properties fo:border-right CDATA #IMPLIED>
+<!ATTLIST style:properties style:border-line-width CDATA #IMPLIED>
+<!ATTLIST style:properties style:border-line-width-top CDATA #IMPLIED>
+<!ATTLIST style:properties style:border-line-width-bottom CDATA #IMPLIED>
+<!ATTLIST style:properties style:border-line-width-left CDATA #IMPLIED>
+<!ATTLIST style:properties style:border-line-width-right CDATA #IMPLIED>
+<!ATTLIST style:properties fo:padding %nonNegativeLength; #IMPLIED>
+<!ATTLIST style:properties fo:padding-top %nonNegativeLength; #IMPLIED>
+<!ATTLIST style:properties fo:padding-bottom %nonNegativeLength; #IMPLIED>
+<!ATTLIST style:properties fo:padding-left %nonNegativeLength; #IMPLIED>
+<!ATTLIST style:properties fo:padding-right %nonNegativeLength; #IMPLIED>
+<!ATTLIST style:properties style:shadow CDATA #IMPLIED>
+<!ATTLIST style:properties fo:keep-with-next %boolean; #IMPLIED>
+
+<!ATTLIST style:properties text:number-lines %boolean; "false">
+<!ATTLIST style:properties text:line-number %nonNegativeInteger; #IMPLIED>
+
+<!ATTLIST style:properties style:decimal-places %nonNegativeInteger; #IMPLIED>
+<!ATTLIST style:properties style:tab-stop-distance %nonNegativeLength; #IMPLIED>
+
+<!-- table properties -->
+<!ATTLIST style:properties style:width %positiveLength; #IMPLIED>
+<!ATTLIST style:properties style:rel-width %percentage; #IMPLIED>
+<!ATTLIST style:properties style:may-break-between-rows %boolean; #IMPLIED>
+<!ATTLIST style:properties table:page-style-name %styleName; #IMPLIED>
+<!ATTLIST style:properties table:display %boolean; #IMPLIED>
+
+<!-- table column properties -->
+<!ATTLIST style:properties style:column-width %positiveLength; #IMPLIED>
+<!ENTITY % relWidth "CDATA">
+<!ATTLIST style:properties style:rel-column-width %relWidth; #IMPLIED>
+<!ATTLIST style:properties style:use-optimal-column-width %boolean; #IMPLIED>
+
+<!-- table row properties -->
+<!ATTLIST style:properties style:row-height %positiveLength; #IMPLIED>
+<!ATTLIST style:properties style:min-row-height %nonNegativeLength; #IMPLIED>
+<!ATTLIST style:properties style:use-optimal-row-height %boolean; #IMPLIED>
+
+<!-- table cell properties -->
+<!ATTLIST style:properties
+ table:align (left | center | right | margins) #IMPLIED
+ table:border-model (collapsing | separating) #IMPLIED
+ fo:vertical-align (top | middle | bottom | automatic) #IMPLIED
+ fo:direction (ltr | ttb) #IMPLIED
+ style:rotation-angle %nonNegativeInteger; #IMPLIED
+ style:rotation-align (none | bottom | top | center) #IMPLIED
+ style:cell-protect CDATA #IMPLIED
+ fo:wrap-option (no-wrap | wrap) #IMPLIED
+>
+<!ELEMENT style:columns (style:column-sep?,style:column*)>
+<!ATTLIST style:columns fo:column-count %nonNegativeInteger; #IMPLIED>
+<!ATTLIST style:columns fo:column-gap %positiveLength; #IMPLIED>
+
+<!ELEMENT style:column EMPTY>
+<!ATTLIST style:column style:rel-width CDATA #IMPLIED>
+<!ATTLIST style:column fo:margin-left %positiveLength; #IMPLIED>
+<!ATTLIST style:column fo:margin-right %positiveLength; #IMPLIED>
+
+<!ELEMENT style:column-sep EMPTY>
+<!ATTLIST style:column-sep style:style (none|solid|dotted|dashed|dot-dashed)
+ "solid">
+<!ATTLIST style:column-sep style:width %length; #REQUIRED>
+<!ATTLIST style:column-sep style:height %percentage; "100%">
+<!ATTLIST style:column-sep style:vertical-align (top|middle|bottom) "top">
+<!ATTLIST style:column-sep style:color %color; "#000000">
+
+<!-- page master properties -->
+<!ELEMENT style:page-master (style:properties?, style:header-style?, style:footer-style?)>
+<!ATTLIST style:page-master style:name %styleName; #REQUIRED>
+<!ATTLIST style:page-master style:page-usage (all|left|right|mirrored) "all">
+
+<!ELEMENT style:header-style (style:properties?)>
+<!ELEMENT style:footer-style (style:properties?)>
+
+<!ATTLIST style:properties fo:page-width %length; #IMPLIED>
+<!ATTLIST style:properties fo:page-height %length; #IMPLIED>
+<!ATTLIST style:properties style:paper-tray-number %positiveNumberOrDefault; #IMPLIED>
+<!ATTLIST style:properties style:print-orientation (portrait|landscape) #IMPLIED>
+<!ATTLIST style:properties style:print CDATA #IMPLIED>
+<!ATTLIST style:properties style:print-page-order (ttb|ltr) #IMPLIED>
+<!ATTLIST style:properties style:first-page-number %positiveInteger; #IMPLIED>
+<!ATTLIST style:properties style:scale-to %percentage; #IMPLIED>
+<!ATTLIST style:properties style:scale-to-pages %positiveInteger; #IMPLIED>
+<!ATTLIST style:properties style:table-centering (horizontal | vertical | both | none) #IMPLIED>
+
+<!ATTLIST style:properties style:footnote-max-height %lengthOrNoLimit; #IMPLIED>
+<!ATTLIST style:properties style:vertical-align (top|bottom|middle|basline|auto) #IMPLIED>
+
+<!ELEMENT style:footnote-sep EMPTY>
+<!ATTLIST style:footnote-sep style:width %length; #IMPLIED>
+<!ATTLIST style:footnote-sep style:rel-width %percentage; #IMPLIED>
+<!ATTLIST style:footnote-sep style:color %color; #IMPLIED>
+<!ATTLIST style:footnote-sep style:adjustment (left|center|right) "left">
+<!ATTLIST style:footnote-sep style:distance-before-sep %length; #IMPLIED>
+<!ATTLIST style:footnote-sep style:distance-after-sep %length; #IMPLIED>
+
+<!-- master page -->
+<!ELEMENT style:master-page ( (style:header, style:header-left?)?, (style:footer, style:footer-left?)?,
+ office:forms?,style:style*, (%shapes;)*, presentation:notes? )>
+<!ATTLIST style:master-page style:name %styleName; #REQUIRED>
+<!ATTLIST style:master-page style:page-master-name %styleName; #REQUIRED>
+<!ATTLIST style:master-page style:next-style-name %styleName; #IMPLIED>
+<!ATTLIST style:master-page draw:style-name %styleName; #IMPLIED>
+
+<!-- handout master -->
+<!ELEMENT style:handout-master (%shapes;)*>
+<!ATTLIST style:handout-master presentation:presentation-page-layout-name %styleName; #IMPLIED>
+
+<!ENTITY % hd-ft-content "( text:p | (style:region-left?, style:region-center?, style:region-right?) )">
+<!ELEMENT style:header %hd-ft-content;>
+<!ELEMENT style:footer %hd-ft-content;>
+<!ELEMENT style:header-left %hd-ft-content;>
+<!ATTLIST style:header-left style:display %boolean; "true">
+<!ELEMENT style:footer-left %hd-ft-content;>
+<!ATTLIST style:footer-left style:display %boolean; "true">
+
+<!ENTITY % region-content "(text:p*)">
+<!ELEMENT style:region-left %region-content;>
+<!ELEMENT style:region-center %region-content;>
+<!ELEMENT style:region-right %region-content;>
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/table.mod b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/table.mod
new file mode 100644
index 000000000000..6d9f3cdb2a8f
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/table.mod
@@ -0,0 +1,493 @@
+<!--
+
+ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+
+ Copyright 2000, 2010 Oracle and/or its affiliates.
+
+ OpenOffice.org - a multi-platform office productivity suite
+
+ This file is part of OpenOffice.org.
+
+ OpenOffice.org is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License version 3
+ only, as published by the Free Software Foundation.
+
+ OpenOffice.org is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License version 3 for more details
+ (a copy is included in the LICENSE file that accompanied this code).
+
+ You should have received a copy of the GNU Lesser General Public License
+ version 3 along with OpenOffice.org. If not, see
+ <http://www.openoffice.org/license.html>
+ for a copy of the LGPLv3 License.
+
+-->
+
+<!ELEMENT table:calculation-settings (table:null-date?, table:iteration?)>
+<!ATTLIST table:calculation-settings
+ table:case-sensitive %boolean; "true"
+ table:precision-as-shown %boolean; "false"
+ table:search-criteria-must-apply-to-whole-cell %boolean; "true"
+ table:automatic-find-labels %boolean; "true"
+ table:use-regular-expressions %boolean; "true"
+ table:null-year %positiveInteger; "1930"
+>
+<!ELEMENT table:null-date EMPTY>
+<!ATTLIST table:null-date
+ table:value-type %valueType; #FIXED "date"
+ table:date-value %date; "1899-12-30"
+>
+<!ELEMENT table:iteration EMPTY>
+<!ATTLIST table:iteration
+ table:status (enable | disable) "disable"
+ table:steps %positiveInteger; "100"
+ table:maximum-difference %float; "0.001"
+>
+
+<!ELEMENT table:tracked-changes (table:cell-content-change | table:insertion | table:deletion | table:movement | table:rejection)*>
+<!ATTLIST table:tracked-changes table:track-changes %boolean; "true"
+ table:protected %boolean; "false"
+ table:protection-key CDATA #IMPLIED
+>
+
+<!ELEMENT table:dependences (table:dependence)+>
+<!ELEMENT table:dependence EMPTY>
+<!ATTLIST table:dependence
+ table:id CDATA #REQUIRED
+>
+<!ELEMENT table:deletions (table:cell-content-deletion | table:change-deletion)+>
+<!ELEMENT table:cell-content-deletion (table:cell-address?, table:change-track-table-cell?)>
+<!ATTLIST table:cell-content-deletion
+ table:id CDATA #IMPLIED
+>
+<!ELEMENT table:change-deletion EMPTY>
+<!ATTLIST table:change-deletion
+ table:id CDATA #IMPLIED
+>
+<!ELEMENT table:insertion (office:change-info, table:dependences?, table:deletions?)>
+<!ATTLIST table:insertion
+ table:id CDATA #REQUIRED
+ table:acceptance-state (accepted | rejected | pending) "pending"
+ table:rejecting-change-id %positiveInteger; #IMPLIED
+ table:type (row | column | table) #REQUIRED
+ table:position %integer; #REQUIRED
+ table:count %positiveInteger; "1"
+ table:table %integer; #IMPLIED
+>
+<!ELEMENT table:deletion (office:change-info, table:dependences?, table:deletions?, table:cut-offs?)>
+<!ATTLIST table:deletion
+ table:id CDATA #REQUIRED
+ table:acceptance-state (accepted | rejected | pending) "pending"
+ table:rejecting-change-id %positiveInteger; #IMPLIED
+ table:type (row | column | table) #REQUIRED
+ table:position %integer; #REQUIRED
+ table:count %positiveInteger; "1"
+ table:table %integer; #IMPLIED
+ table:multi-deletion-spanned %integer; #IMPLIED
+>
+<!ELEMENT table:cut-offs (table:movement-cut-off+ | (table:insertion-cut-off, table:movement-cut-off*))>
+<!ELEMENT table:insertion-cut-off EMPTY>
+<!ATTLIST table:insertion-cut-off
+ table:id CDATA #REQUIRED
+ table:position %integer; #REQUIRED
+>
+<!ELEMENT table:movement-cut-off EMPTY>
+<!ATTLIST table:movement-cut-off
+ table:id CDATA #REQUIRED
+ table:start-position %integer; #IMPLIED
+ table:end-position %integer; #IMPLIED
+ table:position %integer; #IMPLIED
+>
+<!ELEMENT table:movement (table:source-range-address, table:target-range-address, office:change-info, table:dependences?, table:deletions?)>
+<!ATTLIST table:movement
+ table:id CDATA #REQUIRED
+ table:acceptance-state (accepted | rejected | pending) "pending"
+ table:rejecting-change-id %positiveInteger; #IMPLIED
+>
+<!ELEMENT table:target-range-address EMPTY>
+<!ATTLIST table:target-range-address
+ table:column %integer; #IMPLIED
+ table:row %integer; #IMPLIED
+ table:table %integer; #IMPLIED
+ table:start-column %integer; #IMPLIED
+ table:start-row %integer; #IMPLIED
+ table:start-table %integer; #IMPLIED
+ table:end-column %integer; #IMPLIED
+ table:end-row %integer; #IMPLIED
+ table:end-table %integer; #IMPLIED
+>
+<!ELEMENT table:source-range-address EMPTY>
+<!ATTLIST table:source-range-address
+ table:column %integer; #IMPLIED
+ table:row %integer; #IMPLIED
+ table:table %integer; #IMPLIED
+ table:start-column %integer; #IMPLIED
+ table:start-row %integer; #IMPLIED
+ table:start-table %integer; #IMPLIED
+ table:end-column %integer; #IMPLIED
+ table:end-row %integer; #IMPLIED
+ table:end-table %integer; #IMPLIED
+>
+<!ELEMENT table:change-track-table-cell (text:p*)>
+<!ATTLIST table:change-track-table-cell
+ table:cell-address %cell-address; #IMPLIED
+ table:matrix-covered (true | false) "false"
+ table:formula %string; #IMPLIED
+ table:number-matrix-rows-spanned %positiveInteger; #IMPLIED
+ table:number-matrix-columns-spanned %positiveInteger; #IMPLIED
+ table:value-type %valueType; "string"
+ table:value %float; #IMPLIED
+ table:date-value %date; #IMPLIED
+ table:time-value %timeInstance; #IMPLIED
+ table:string-value %string; #IMPLIED
+>
+<!ELEMENT table:cell-content-change (table:cell-address, office:change-info, table:dependences?, table:deletions?, table:previous)>
+<!ATTLIST table:cell-content-change
+ table:id CDATA #REQUIRED
+ table:acceptance-state (accepted | rejected | pending) "pending"
+ table:rejecting-change-id %positiveInteger; #IMPLIED
+>
+<!ELEMENT table:cell-address EMPTY>
+<!ATTLIST table:cell-address
+ table:column %integer; #IMPLIED
+ table:row %integer; #IMPLIED
+ table:table %integer; #IMPLIED
+>
+<!ELEMENT table:previous (table:change-track-table-cell)>
+<!ATTLIST table:previous
+ table:id CDATA #IMPLIED
+>
+<!ELEMENT table:rejection (office:change-info, table:dependences?, table:deletions?)>
+<!ATTLIST table:rejection
+ table:id CDATA #REQUIRED
+ table:acceptance-state (accepted | rejected | pending) "pending"
+ table:rejecting-change-id %positiveInteger; #IMPLIED
+>
+
+<!ENTITY % table-columns "table:table-columns | ( table:table-column | table:table-column-group )+">
+<!ENTITY % table-header-columns "table:table-header-columns">
+<!ENTITY % table-rows "table:table-rows | ( table:table-row | table:table-row-group )+">
+<!ENTITY % table-header-rows "table:table-header-rows">
+<!ENTITY % table-column-groups "((%table-columns;),(%table-header-columns;,(%table-columns;)?)?) | (%table-header-columns;,(%table-columns;)?)">
+<!ENTITY % table-row-groups "((%table-rows;),(%table-header-rows;,(%table-rows;)?)?) | (%table-header-rows;,(%table-rows;)?)">
+<!ELEMENT table:table (table:table-source?, table:scenario?, office:forms?, table:shapes?, (%table-column-groups;), (%table-row-groups;))>
+<!ATTLIST table:table
+ table:name %string; #IMPLIED
+ table:style-name %styleName; #IMPLIED
+ table:protected %boolean; "false"
+ table:protection-key CDATA #IMPLIED
+ table:print-ranges %cell-range-address-list; #IMPLIED
+>
+<!ELEMENT table:table-source EMPTY>
+<!ATTLIST table:table-source
+ table:mode (copy-all | copy-results-only) "copy-all"
+ xlink:type (simple) #FIXED "simple"
+ xlink:actuate (onRequest) "onRequest"
+ xlink:href %uriReference; #REQUIRED
+ table:filter-name CDATA #IMPLIED
+ table:table-name CDATA #IMPLIED
+ table:filter-options CDATA #IMPLIED
+ table:refresh-delay %timeDuration; #IMPLIED
+>
+<!ELEMENT table:scenario EMPTY>
+<!ATTLIST table:scenario
+ table:display-border %boolean; "true"
+ table:border-color %color; #IMPLIED
+ table:copy-back %boolean; "true"
+ table:copy-styles %boolean; "true"
+ table:copy-formulas %boolean; "true"
+ table:is-active %boolean; #REQUIRED
+ table:scenario-ranges %cell-range-address-list; #REQUIRED
+ table:comment CDATA #IMPLIED
+>
+<!ELEMENT table:shapes %shapes;>
+<!ELEMENT table:table-column-group (table:table-header-columns | table:table-column | table:table-column-group)+>
+<!ATTLIST table:table-column-group
+ table:display %boolean; "true"
+>
+<!ELEMENT table:table-header-columns (table:table-column | table:table-column-group)+>
+<!ELEMENT table:table-columns (table:table-column | table:table-column-group)+>
+<!ELEMENT table:table-column EMPTY>
+<!ATTLIST table:table-column
+ table:number-columns-repeated %positiveInteger; "1"
+ table:style-name %styleName; #IMPLIED
+ table:visibility (visible | collapse | filter) "visible"
+ table:default-cell-style-name %styleName; #IMPLIED
+>
+<!ELEMENT table:table-row-group (table:table-header-rows | table:table-row | table:table-row-group)+>
+<!ATTLIST table:table-row-group
+ table:display %boolean; "true"
+>
+<!ELEMENT table:table-header-rows (table:table-row | table:table-row-group)+>
+<!ELEMENT table:table-rows (table:table-row | table:table-row-group)+>
+<!ENTITY % table-cells "(table:table-cell|table:covered-table-cell)+">
+<!ELEMENT table:table-row %table-cells;>
+<!ATTLIST table:table-row
+ table:number-rows-repeated %positiveInteger; "1"
+ table:style-name %styleName; #IMPLIED
+ table:visibility (visible | collapse | filter) "visible"
+ table:default-cell-style-name %styleName; #IMPLIED
+>
+
+<!ENTITY % text-wo-table "(text:h|text:p|text:ordered-list|text:unordered-list|%shapes;)*">
+<!ENTITY % cell-content "(table:cell-range-source?,office:annotation?,table:detective?,(table:sub-table|%text-wo-table;))">
+<!ELEMENT table:table-cell %cell-content;>
+<!ELEMENT table:covered-table-cell %cell-content;>
+<!ATTLIST table:table-cell
+ table:number-columns-repeated %positiveInteger; "1"
+ table:number-rows-spanned %positiveInteger; "1"
+ table:number-columns-spanned %positiveInteger; "1"
+ table:style-name %styleName; #IMPLIED
+ table:validation-name CDATA #IMPLIED
+ table:formula %string; #IMPLIED
+ table:number-matrix-rows-spanned %positiveInteger; #IMPLIED
+ table:number-matrix-columns-spanned %positiveInteger; #IMPLIED
+ table:value-type %valueType; "string"
+ table:value %float; #IMPLIED
+ table:date-value %date; #IMPLIED
+ table:time-value %timeInstance; #IMPLIED
+ table:boolean-value %boolean; #IMPLIED
+ table:string-value %string; #IMPLIED
+ table:currency %string; #IMPLIED
+>
+<!ATTLIST table:covered-table-cell
+ table:number-columns-repeated %positiveInteger; "1"
+ table:style-name %styleName; #IMPLIED
+ table:validation-name CDATA #IMPLIED
+ table:formula %string; #IMPLIED
+ table:number-matrix-rows-spanned %positiveInteger; #IMPLIED
+ table:number-matrix-columns-spanned %positiveInteger; #IMPLIED
+ table:value-type %valueType; "string"
+ table:value %float; #IMPLIED
+ table:date-value %date; #IMPLIED
+ table:time-value %timeInstance; #IMPLIED
+ table:boolean-value %boolean; #IMPLIED
+ table:string-value %string; #IMPLIED
+ table:currency %string; #IMPLIED
+>
+<!-- cell protection in writer: cell attribute; calc uses format -->
+<!ATTLIST table:table-cell table:protected %boolean; "false">
+
+<!ELEMENT table:cell-range-source EMPTY>
+<!ATTLIST table:cell-range-source
+ table:name %string; #REQUIRED
+ xlink:type (simple) #FIXED "simple"
+ xlink:actuate (onRequest) #FIXED "onRequest"
+ xlink:href %uriReference; #REQUIRED
+ table:filter-name %string; #REQUIRED
+ table:filter-options %string; #IMPLIED
+ table:last-column-spanned %positiveInteger; #REQUIRED
+ table:last-row-spanned %positiveInteger; #REQUIRED
+ table:refresh-delay %timeDuration; #IMPLIED
+>
+
+<!ELEMENT table:detective (table:highlighted-range*, table:operation*)>
+<!ELEMENT table:highlighted-range EMPTY>
+<!ATTLIST table:highlighted-range
+ table:cell-range-address %cell-range-address; #IMPLIED
+ table:direction (from-another-table | to-another-table | from-same-table | to-same-table) #REQUIRED
+ table:contains-error %boolean; "false"
+>
+<!ELEMENT table:operation EMPTY>
+<!ATTLIST table:operation
+ table:name (trace-dependents | remove-dependents | trace-precedents | remove-precedents | trace-errors) #REQUIRED
+ table:index %nonNegativeInteger; #REQUIRED
+>
+
+<!ELEMENT table:content-validations (table:content-validation)+>
+<!ELEMENT table:content-validation (table:help-message?, (table:error-message | (table:error-macro, office:events?))?)>
+<!ATTLIST table:content-validation
+ table:name CDATA #REQUIRED
+ table:condition CDATA #IMPLIED
+ table:base-cell-address %cell-address; #IMPLIED
+ table:allow-empty-cell %boolean; #IMPLIED
+>
+<!ELEMENT table:help-message (text:p*)>
+<!ATTLIST table:help-message
+ table:title CDATA #IMPLIED
+ table:display %boolean; #IMPLIED
+>
+<!ELEMENT table:error-message (text:p*)>
+<!ATTLIST table:error-message
+ table:title CDATA #IMPLIED
+ table:message-type (stop | warning | information) #IMPLIED
+ table:display %boolean; #IMPLIED
+>
+<!ELEMENT table:error-macro EMPTY>
+<!ATTLIST table:error-macro
+ table:name CDATA #IMPLIED
+ table:execute %boolean; #IMPLIED
+>
+
+<!ELEMENT table:sub-table ((%table-column-groups;) , (%table-row-groups;))>
+
+<!ELEMENT table:label-ranges (table:label-range)*>
+<!ELEMENT table:label-range EMPTY>
+<!ATTLIST table:label-range
+ table:label-cell-range-address %cell-range-address; #REQUIRED
+ table:data-cell-range-address %cell-range-address; #REQUIRED
+ table:orientation (column | row) #REQUIRED
+>
+
+<!ELEMENT table:named-expressions (table:named-range | table:named-expression)*>
+<!ELEMENT table:named-range EMPTY>
+<!ATTLIST table:named-range
+ table:name CDATA #REQUIRED
+ table:cell-range-address %cell-range-address; #REQUIRED
+ table:base-cell-address %cell-address; #IMPLIED
+ table:range-usable-as CDATA "none"
+>
+<!ELEMENT table:named-expression EMPTY>
+<!ATTLIST table:named-expression
+ table:name CDATA #REQUIRED
+ table:expression CDATA #REQUIRED
+ table:base-cell-address %cell-address; #IMPLIED
+>
+
+<!ELEMENT table:filter (table:filter-condition | table:filter-and | table:filter-or)>
+<!ATTLIST table:filter
+ table:target-range-address %cell-range-address; #IMPLIED
+ table:condition-source-range-address %cell-range-address; #IMPLIED
+ table:condition-source (self | cell-range) "self"
+ table:display-duplicates %boolean; "true"
+>
+<!ELEMENT table:filter-and (table:filter-or | table:filter-condition)+>
+<!ELEMENT table:filter-or (table:filter-and | table:filter-condition)+>
+<!ELEMENT table:filter-condition EMPTY>
+<!ATTLIST table:filter-condition
+ table:field-number %nonNegativeInteger; #REQUIRED
+ table:case-sensitive %boolean; "false"
+ table:data-type (text | number) "text"
+ table:value CDATA #REQUIRED
+ table:operator CDATA #REQUIRED
+>
+
+<!ELEMENT table:database-ranges (table:database-range)*>
+<!ELEMENT table:database-range ((table:database-source-sql | table:database-source-table | table:database-source-query)?, table:filter?, table:sort?, table:subtotal-rules?)>
+<!ATTLIST table:database-range
+ table:name CDATA #IMPLIED
+ table:is-selection %boolean; "false"
+ table:on-update-keep-styles %boolean; "false"
+ table:on-update-keep-size %boolean; "true"
+ table:has-persistant-data %boolean; "true"
+ table:orientation (row | column) "row"
+ table:contains-header %boolean; "true"
+ table:display-filter-buttons %boolean; "false"
+ table:target-range-address %cell-range-address; #REQUIRED
+ table:refresh-delay %timeDuration; #IMPLIED
+>
+<!ELEMENT table:database-source-sql EMPTY>
+<!ATTLIST table:database-source-sql
+ table:database-name CDATA #REQUIRED
+ table:sql-statement CDATA #REQUIRED
+ table:parse-sql-statements %boolean; "false"
+>
+<!ELEMENT table:database-source-table EMPTY>
+<!ATTLIST table:database-source-table
+ table:database-name CDATA #REQUIRED
+ table:table-name CDATA #REQUIRED
+>
+<!ELEMENT table:database-source-query EMPTY>
+<!ATTLIST table:database-source-query
+ table:database-name CDATA #REQUIRED
+ table:query-name CDATA #REQUIRED
+>
+
+<!ELEMENT table:sort (table:sort-by)+>
+<!ATTLIST table:sort
+ table:bind-styles-to-content %boolean; "true"
+ table:target-range-address %cell-range-address; #IMPLIED
+ table:case-sensitive %boolean; "false"
+ table:language CDATA #IMPLIED
+ table:country CDATA #IMPLIED
+ table:algorithm CDATA #IMPLIED
+>
+<!ELEMENT table:sort-by EMPTY>
+<!ATTLIST table:sort-by
+ table:field-number %nonNegativeInteger; #REQUIRED
+ table:data-type (text | number | automatic | qname-but-not-ncname) "automatic"
+ table:order (ascending | descending) "ascending"
+>
+
+<!ELEMENT table:subtotal-rules (table:sort-groups? | table:subtotal-rule*)?>
+<!ATTLIST table:subtotal-rules
+ table:bind-styles-to-content %boolean; "true"
+ table:case-sensitive %boolean; "false"
+ table:page-breaks-on-group-change %boolean; "false"
+>
+<!ELEMENT table:sort-groups EMPTY>
+<!ATTLIST table:sort-groups
+ table:data-type (text | number | automatic | qname-but-not-ncname) "automatic"
+ table:order (ascending | descending) "ascending"
+>
+<!ELEMENT table:subtotal-rule (table:subtotal-field)*>
+<!ATTLIST table:subtotal-rule
+ table:group-by-field-number %nonNegativeInteger; #REQUIRED
+>
+<!ELEMENT table:subtotal-field EMPTY>
+<!ATTLIST table:subtotal-field
+ table:field-number %nonNegativeInteger; #REQUIRED
+ table:function CDATA #REQUIRED
+>
+
+<!ELEMENT table:data-pilot-tables (table:data-pilot-table)*>
+<!ELEMENT table:data-pilot-table ((table:database-source-sql | table:database-source-table | table:database-source-query | table:source-service | table:source-cell-range)?, table:data-pilot-field+)>
+<!ATTLIST table:data-pilot-table
+ table:name CDATA #REQUIRED
+ table:application-data CDATA #IMPLIED
+ table:grand-total (none | row | column | both) "both"
+ table:ignore-empty-rows %boolean; "false"
+ table:identify-categories %boolean; "false"
+ table:target-range-address %cell-range-address; #REQUIRED
+ table:buttons %cell-range-address-list; #REQUIRED
+>
+<!ELEMENT table:source-service EMPTY>
+<!ATTLIST table:source-service
+ table:name CDATA #REQUIRED
+ table:source-name CDATA #REQUIRED
+ table:object-name CDATA #REQUIRED
+ table:username CDATA #IMPLIED
+ table:password CDATA #IMPLIED
+>
+<!ELEMENT table:source-cell-range (table:filter)?>
+<!ATTLIST table:source-cell-range
+ table:cell-range-address %cell-range-address; #REQUIRED
+>
+<!ELEMENT table:data-pilot-field (table:data-pilot-level)?>
+<!ATTLIST table:data-pilot-field
+ table:source-field-name CDATA #REQUIRED
+ table:is-data-layout-field %boolean; "false"
+ table:function CDATA #REQUIRED
+ table:orientation (row | column | data | page | hidden) #REQUIRED
+ table:used-hierarchy %positiveInteger; "1"
+>
+<!ELEMENT table:data-pilot-level (table:data-pilot-subtotals?, table:data-pilot-members?)>
+<!ATTLIST table:data-pilot-level
+ table:display-empty %boolean; #IMPLIED
+>
+<!ELEMENT table:data-pilot-subtotals (table:data-pilot-subtotal)*>
+<!ELEMENT table:data-pilot-subtotal EMPTY>
+<!ATTLIST table:data-pilot-subtotal
+ table:function CDATA #REQUIRED
+>
+<!ELEMENT table:data-pilot-members (table:data-pilot-member)*>
+<!ELEMENT table:data-pilot-member EMPTY>
+<!ATTLIST table:data-pilot-member
+ table:name CDATA #REQUIRED
+ table:display %boolean; #IMPLIED
+ table:display-details %boolean; #IMPLIED
+>
+
+<!ELEMENT table:consolidation EMPTY>
+<!ATTLIST table:consolidation
+ table:function CDATA #REQUIRED
+ table:source-cell-range-addresses %cell-range-address-list; #REQUIRED
+ table:target-cell-address %cell-address; #REQUIRED
+ table:use-label (none | column | row | both) "none"
+ table:link-to-source-data %boolean; "false"
+>
+
+<!ELEMENT table:dde-links (table:dde-link)+>
+<!ELEMENT table:dde-link (office:dde-source, table:table)>
diff --git a/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/text.mod b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/text.mod
new file mode 100644
index 000000000000..792b0fdde55e
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/results/baseline/xml-base/text.mod
@@ -0,0 +1,1099 @@
+<!--
+
+ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+
+ Copyright 2000, 2010 Oracle and/or its affiliates.
+
+ OpenOffice.org - a multi-platform office productivity suite
+
+ This file is part of OpenOffice.org.
+
+ OpenOffice.org is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License version 3
+ only, as published by the Free Software Foundation.
+
+ OpenOffice.org is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License version 3 for more details
+ (a copy is included in the LICENSE file that accompanied this code).
+
+ You should have received a copy of the GNU Lesser General Public License
+ version 3 along with OpenOffice.org. If not, see
+ <http://www.openoffice.org/license.html>
+ for a copy of the LGPLv3 License.
+
+-->
+
+<!ENTITY % fields "text:date |
+ text:time |
+ text:page-number |
+ text:page-continuation |
+ text:sender-firstname |
+ text:sender-lastname |
+ text:sender-initials |
+ text:sender-title |
+ text:sender-position |
+ text:sender-email |
+ text:sender-phone-private |
+ text:sender-fax |
+ text:sender-company |
+ text:sender-phone-work |
+ text:sender-street |
+ text:sender-city |
+ text:sender-postal-code |
+ text:sender-country |
+ text:sender-state-or-province |
+ text:author-name |
+ text:author-initials |
+ text:placeholder |
+ text:variable-set |
+ text:variable-get |
+ text:variable-input |
+ text:user-field-get |
+ text:user-field-input |
+ text:sequence |
+ text:expression |
+ text:text-input |
+ text:database-display |
+ text:database-next |
+ text:database-row-select |
+ text:database-row-number |
+ text:database-name |
+ text:initial-creator |
+ text:creation-date |
+ text:creation-time |
+ text:description |
+ text:user-defined |
+ text:print-time |
+ text:print-date |
+ text:printed-by |
+ text:title |
+ text:subject |
+ text:keywords |
+ text:editing-cycles |
+ text:editing-duration |
+ text:modification-time |
+ text:modification-date |
+ text:creator |
+ text:conditional-text |
+ text:hidden-text |
+ text:hidden-paragraph |
+ text:chapter |
+ text:file-name |
+ text:template-name |
+ text:set-page-variable |
+ text:get-page-variable |
+ text:execute-macro |
+ text:dde-connection |
+ text:reference-ref |
+ text:sequence-ref |
+ text:bookmark-ref |
+ text:footnote-ref |
+ text:endnote-ref |
+ text:sheet-name |
+ text:bibliography-mark |
+ text:page-count |
+ text:paragraph-count |
+ text:word-count |
+ text:character-count |
+ text:table-count |
+ text:image-count |
+ text:object-count |
+ office:annotation |
+ text:script |
+ text:measure" >
+
+<!ENTITY % inline-text "(#PCDATA|
+ text:span|text:tab-stop|text:s|text:line-break|
+ text:footnote|text:endnote|text:a|
+ text:bookmark|text:bookmark-start|text:bookmark-end|
+ text:reference-mark|text:reference-mark-start|
+ text:reference-mark-end|%fields;|%shape;|
+ text:toc-mark-start | text:toc-mark-end |
+ text:toc-mark | text:user-index-mark-start |
+ text:user-index-mark-end | text:user-index-mark |
+ text:alphabetical-index-mark-start |
+ text:alphabetical-index-mark-end |
+ text:alphabetical-index-mark |
+ %change-marks; | draw:a | text:ruby)*">
+
+<!ELEMENT text:p %inline-text;>
+<!ELEMENT text:h %inline-text;>
+
+<!ATTLIST text:p text:style-name %styleName; #IMPLIED>
+<!ATTLIST text:p text:cond-style-name %styleName; #IMPLIED>
+
+<!ATTLIST text:h text:style-name %styleName; #IMPLIED>
+<!ATTLIST text:h text:cond-style-name %styleName; #IMPLIED>
+<!ATTLIST text:h text:level %positiveInteger; "1">
+
+<!ELEMENT text:span %inline-text;>
+<!ATTLIST text:span text:style-name %styleName; #REQUIRED>
+
+<!ELEMENT text:a %inline-text;>
+<!ATTLIST text:a xlink:href %uriReference; #REQUIRED>
+<!ATTLIST text:a xlink:type (simple) #FIXED "simple">
+<!ATTLIST text:a xlink:actuate (onRequest) "onRequest">
+<!ATTLIST text:a xlink:show (new|replace) "replace">
+<!ATTLIST text:a office:name %string; #IMPLIED>
+<!ATTLIST text:a office:target-frame-name %string; #IMPLIED>
+<!ATTLIST text:a text:style-name %styleName; #IMPLIED>
+<!ATTLIST text:a text:visited-style-name %styleName; #IMPLIED>
+
+
+<!ELEMENT text:s EMPTY>
+<!ATTLIST text:s text:c %positiveInteger; "1">
+
+<!ELEMENT text:tab-stop EMPTY>
+
+<!ELEMENT text:line-break EMPTY>
+
+
+<!ENTITY % list-items "((text:list-header,text:list-item*)|text:list-item+)">
+<!ELEMENT text:ordered-list %list-items;>
+<!ELEMENT text:unordered-list %list-items;>
+
+
+<!ATTLIST text:ordered-list text:style-name %styleName; #IMPLIED>
+<!ATTLIST text:unordered-list text:style-name %styleName; #IMPLIED>
+
+<!ATTLIST text:ordered-list text:continue-numbering %boolean; "false">
+
+<!ELEMENT text:list-header (text:p)+>
+<!ELEMENT text:list-item (text:p|text:ordered-list|text:unordered-list)+>
+
+<!ATTLIST text:list-item text:restart-numbering %boolean; "false">
+<!ATTLIST text:list-item text:start-value %positiveInteger; #IMPLIED>
+
+<!ELEMENT text:list-style (text:list-level-style-number|
+ text:list-level-style-bullet|
+ text:list-level-style-image)+>
+
+<!ATTLIST text:list-style style:name %styleName; #IMPLIED>
+
+<!ATTLIST text:list-style text:consecutive-numbering %boolean; "false">
+
+
+<!ELEMENT text:list-level-style-number (style:properties?)>
+
+<!ATTLIST text:list-level-style-number text:level %positiveInteger;
+ #REQUIRED>
+<!ATTLIST text:list-level-style-number text:style-name %styleName; #IMPLIED>
+
+<!ATTLIST text:list-level-style-number style:num-format %string; #REQUIRED>
+<!ATTLIST text:list-level-style-number style:num-prefix %string; #IMPLIED>
+<!ATTLIST text:list-level-style-number style:num-suffix %string; #IMPLIED>
+<!ATTLIST text:list-level-style-number style:num-letter-sync %boolean;
+ "false">
+<!ATTLIST text:list-level-style-number text:display-levels %positiveInteger;
+ "1">
+<!ATTLIST text:list-level-style-number text:start-value %positiveInteger;
+ "1">
+<!ELEMENT text:list-level-style-bullet (style:properties?)>
+
+<!ATTLIST text:list-level-style-bullet text:level %positiveInteger; #REQUIRED>
+<!ATTLIST text:list-level-style-bullet text:style-name %styleName; #IMPLIED>
+<!ATTLIST text:list-level-style-bullet text:bullet-char %character; #REQUIRED>
+<!ATTLIST text:list-level-style-bullet style:num-prefix %string; #IMPLIED>
+<!ATTLIST text:list-level-style-bullet style:num-suffix %string; #IMPLIED>
+
+<!ELEMENT text:list-level-style-image (style:properties?,office:binary-data?)>
+
+<!ATTLIST text:list-level-style-image text:level %positiveInteger; #REQUIRED>
+<!ATTLIST text:list-level-style-image xlink:type (simple) #IMPLIED>
+<!ATTLIST text:list-level-style-image xlink:href %uriReference; #IMPLIED>
+<!ATTLIST text:list-level-style-image xlink:actuate (onLoad) #IMPLIED>
+<!ATTLIST text:list-level-style-image xlink:show (embed) #IMPLIED>
+
+
+<!-- list properties -->
+<!ATTLIST style:properties text:space-before %nonNegativeLength; #IMPLIED>
+<!ATTLIST style:properties text:min-label-width %nonNegativeLength; #IMPLIED>
+<!ATTLIST style:properties text:min-label-distance %nonNegativeLength; #IMPLIED>
+<!ATTLIST style:properties text:enable-numbering %boolean; #IMPLIED>
+<!ATTLIST style:properties style:list-style-name %styleName; #IMPLIED>
+
+<!ELEMENT text:outline-style (text:outline-level-style)+>
+
+<!ELEMENT text:outline-level-style (style:properties?)>
+
+<!ATTLIST text:outline-level-style text:level %positiveInteger;
+ #REQUIRED>
+<!ATTLIST text:outline-level-style text:style-name %styleName; #IMPLIED>
+
+<!ATTLIST text:outline-level-style style:num-format %string; #REQUIRED>
+<!ATTLIST text:outline-level-style style:num-prefix %string; #IMPLIED>
+<!ATTLIST text:outline-level-style style:num-suffix %string; #IMPLIED>
+<!ATTLIST text:outline-level-style style:num-letter-sync %boolean;
+ "false">
+<!ATTLIST text:outline-level-style text:display-levels %positiveInteger;
+ "1">
+<!ATTLIST text:outline-level-style text:start-value %positiveInteger;
+ "1">
+
+<!ENTITY % field-declarations "text:variable-decls?,
+ text:user-field-decls?,
+ text:sequence-decls?">
+
+<!ENTITY % variableName "CDATA">
+
+<!ENTITY % formula "CDATA">
+
+<!ENTITY % valueAttr "text:value-type %valueType; #REQUIRED">
+
+<!ENTITY % valueAndTypeAttr "%valueAttr;
+ text:value %float; #IMPLIED
+ text:date-value %date; #IMPLIED
+ text:time-value %timeInstance; #IMPLIED
+ text:boolean-value %boolean; #IMPLIED
+ text:string-value %string; #IMPLIED
+ text:currency CDATA #IMPLIED" >
+
+<!ENTITY % numFormat 'style:num-format CDATA #IMPLIED
+ style:num-letter-sync %boolean; "false"'>
+
+
+<!ELEMENT text:date (#PCDATA)>
+<!ATTLIST text:date text:date-value %date; #IMPLIED>
+<!ATTLIST text:date text:date-adjust %dateDuration; #IMPLIED>
+<!ATTLIST text:date text:fixed %boolean; "false">
+<!ATTLIST text:date style:data-style-name %styleName; #IMPLIED>
+
+<!ELEMENT text:time (#PCDATA)>
+<!ATTLIST text:time text:time-value %timeInstance; #IMPLIED>
+<!ATTLIST text:time text:time-adjust %timeDuration; #IMPLIED>
+<!ATTLIST text:time text:fixed %boolean; "false">
+<!ATTLIST text:time style:data-style-name %styleName; #IMPLIED>
+
+<!ELEMENT text:page-number (#PCDATA)>
+<!ATTLIST text:page-number text:page-adjust %positiveInteger; #IMPLIED>
+<!ATTLIST text:page-number text:select-page (previous|current|next) "current">
+<!ATTLIST text:page-number %numFormat;>
+
+<!ELEMENT text:page-continuation (#PCDATA)>
+<!ATTLIST text:page-continuation text:select-page (previous|next) #REQUIRED>
+<!ATTLIST text:page-continuation text:string-value %string; #IMPLIED>
+
+<!ELEMENT text:sender-firstname (#PCDATA)>
+<!ATTLIST text:sender-firstname text:fixed %boolean; "true">
+
+<!ELEMENT text:sender-lastname (#PCDATA)>
+<!ATTLIST text:sender-lastname text:fixed %boolean; "true">
+
+<!ELEMENT text:sender-initials (#PCDATA)>
+<!ATTLIST text:sender-initials text:fixed %boolean; "true">
+
+<!ELEMENT text:sender-title (#PCDATA)>
+<!ATTLIST text:sender-title text:fixed %boolean; "true">
+
+<!ELEMENT text:sender-position (#PCDATA)>
+<!ATTLIST text:sender-position text:fixed %boolean; "true">
+
+<!ELEMENT text:sender-email (#PCDATA)>
+<!ATTLIST text:sender-email text:fixed %boolean; "true">
+
+<!ELEMENT text:sender-phone-private (#PCDATA)>
+<!ATTLIST text:sender-phone-private text:fixed %boolean; "true">
+
+<!ELEMENT text:sender-fax (#PCDATA)>
+<!ATTLIST text:sender-fax text:fixed %boolean; "true">
+
+<!ELEMENT text:sender-company (#PCDATA)>
+<!ATTLIST text:sender-company text:fixed %boolean; "true">
+
+<!ELEMENT text:sender-phone-work (#PCDATA)>
+<!ATTLIST text:sender-phone-work text:fixed %boolean; "true">
+
+<!ELEMENT text:sender-street (#PCDATA)>
+<!ATTLIST text:sender-street text:fixed %boolean; "true">
+
+<!ELEMENT text:sender-city (#PCDATA)>
+<!ATTLIST text:sender-city text:fixed %boolean; "true">
+
+<!ELEMENT text:sender-postal-code (#PCDATA)>
+<!ATTLIST text:sender-postal-code text:fixed %boolean; "true">
+
+<!ELEMENT text:sender-country (#PCDATA)>
+<!ATTLIST text:sender-country text:fixed %boolean; "true">
+
+<!ELEMENT text:sender-state-or-province (#PCDATA)>
+<!ATTLIST text:sender-state-or-province text:fixed %boolean; "true">
+
+<!ELEMENT text:author-name (#PCDATA)>
+<!ATTLIST text:author-name text:fixed %boolean; "true">
+
+<!ELEMENT text:author-initials (#PCDATA)>
+<!ATTLIST text:author-initials text:fixed %boolean; "true">
+
+<!ELEMENT text:placeholder (#PCDATA)>
+<!ATTLIST text:placeholder text:placeholder-type (text|table|text-box|image|object) #REQUIRED>
+<!ATTLIST text:placeholder text:description %string; #IMPLIED>
+
+<!ELEMENT text:variable-decls (text:variable-decl)*>
+
+<!ELEMENT text:variable-decl EMPTY>
+<!ATTLIST text:variable-decl text:name %variableName; #REQUIRED>
+<!ATTLIST text:variable-decl %valueAndTypeAttr;>
+
+<!ELEMENT text:variable-set (#PCDATA)>
+<!ATTLIST text:variable-set text:name %variableName; #REQUIRED>
+<!ATTLIST text:variable-set text:formula %formula; #IMPLIED>
+<!ATTLIST text:variable-set %valueAndTypeAttr;>
+<!ATTLIST text:variable-set text:display (value|none) "value">
+<!ATTLIST text:variable-set style:data-style-name %styleName; #IMPLIED>
+
+<!ELEMENT text:variable-get (#PCDATA)>
+<!ATTLIST text:variable-get text:name %variableName; #REQUIRED>
+<!ATTLIST text:variable-get text:display (value|formula) "value">
+<!ATTLIST text:variable-get style:data-style-name %styleName; #IMPLIED>
+
+<!ELEMENT text:variable-input (#PCDATA)>
+<!ATTLIST text:variable-input text:name %variableName; #REQUIRED>
+<!ATTLIST text:variable-input text:description %string; #IMPLIED>
+<!ATTLIST text:variable-input %valueAndTypeAttr;>
+<!ATTLIST text:variable-input text:display (value|none) "value">
+<!ATTLIST text:variable-input style:data-style-name %styleName; #IMPLIED>
+
+<!ELEMENT text:user-field-decls (text:user-field-decl)*>
+
+<!ELEMENT text:user-field-decl EMPTY>
+<!ATTLIST text:user-field-decl text:name %variableName; #REQUIRED>
+<!ATTLIST text:user-field-decl text:formula %formula; #IMPLIED>
+<!ATTLIST text:user-field-decl %valueAndTypeAttr;>
+
+<!ELEMENT text:user-field-get (#PCDATA)>
+<!ATTLIST text:user-field-get text:name %variableName; #REQUIRED>
+<!ATTLIST text:user-field-get text:display (value|formula|none) "value">
+<!ATTLIST text:user-field-get style:data-style-name %styleName; #IMPLIED>
+
+<!ELEMENT text:user-field-input (#PCDATA)>
+<!ATTLIST text:user-field-input text:name %variableName; #REQUIRED>
+<!ATTLIST text:user-field-input text:description %string; #IMPLIED>
+<!ATTLIST text:user-field-input style:data-style-name %styleName; #IMPLIED>
+
+<!ELEMENT text:sequence-decls (text:sequence-decl)*>
+
+<!ELEMENT text:sequence-decl EMPTY>
+<!ATTLIST text:sequence-decl text:name %variableName; #REQUIRED>
+<!ATTLIST text:sequence-decl text:display-outline-level %positiveInteger; "0">
+<!ATTLIST text:sequence-decl text:separation-character %character; ".">
+
+<!ELEMENT text:sequence (#PCDATA)>
+<!ATTLIST text:sequence text:name %variableName; #REQUIRED>
+<!ATTLIST text:sequence text:formula %formula; #IMPLIED>
+<!ATTLIST text:sequence %numFormat;>
+<!ATTLIST text:sequence text:ref-name ID #IMPLIED>
+
+<!ELEMENT text:expression (#PCDATA)>
+<!ATTLIST text:expression text:formula %formula; #IMPLIED>
+<!ATTLIST text:expression text:display (value|formula ) "value">
+<!ATTLIST text:expression %valueAndTypeAttr;>
+<!ATTLIST text:expression style:data-style-name %styleName; #IMPLIED>
+
+<!ELEMENT text:text-input (#PCDATA)>
+<!ATTLIST text:text-input text:description %string; #IMPLIED>
+
+<!ENTITY % database-table "text:database-name CDATA #REQUIRED
+ text:table-name CDATA #REQUIRED">
+
+<!ELEMENT text:database-display (#PCDATA)>
+<!ATTLIST text:database-display %database-table;>
+<!ATTLIST text:database-display text:column-name %string; #REQUIRED>
+<!ATTLIST text:database-display style:data-style-name %styleName; #IMPLIED>
+
+<!ELEMENT text:database-next (#PCDATA)>
+<!ATTLIST text:database-next %database-table;>
+<!ATTLIST text:database-next text:condition %formula; #IMPLIED>
+
+<!ELEMENT text:database-row-select (#PCDATA)>
+<!ATTLIST text:database-row-select %database-table;>
+<!ATTLIST text:database-row-select text:condition %formula; #IMPLIED>
+<!ATTLIST text:database-row-select text:row-number %integer; #REQUIRED>
+
+<!ELEMENT text:database-row-number (#PCDATA)>
+<!ATTLIST text:database-row-number %database-table;>
+<!ATTLIST text:database-row-number %numFormat;>
+<!ATTLIST text:database-row-number text:value %integer; #IMPLIED>
+
+<!ELEMENT text:database-name (#PCDATA)>
+<!ATTLIST text:database-name %database-table;>
+
+<!ELEMENT text:initial-creator (#PCDATA)>
+<!ATTLIST text:initial-creator text:fixed %boolean; "false">
+
+<!ELEMENT text:creation-date (#PCDATA)>
+<!ATTLIST text:creation-date text:fixed %boolean; "false">
+<!ATTLIST text:creation-date text:date-value %date; #IMPLIED>
+<!ATTLIST text:creation-date style:data-style-name %styleName; #IMPLIED>
+
+<!ELEMENT text:creation-time (#PCDATA)>
+<!ATTLIST text:creation-time text:fixed %boolean; "false">
+<!ATTLIST text:creation-time text:time-value %timeInstance; #IMPLIED>
+<!ATTLIST text:creation-time style:data-style-name %styleName; #IMPLIED>
+
+<!ELEMENT text:description (#PCDATA)>
+<!ATTLIST text:description text:fixed %boolean; "false">
+
+<!ELEMENT text:user-defined (#PCDATA)>
+<!ATTLIST text:user-defined text:fixed %boolean; "false">
+<!ATTLIST text:user-defined text:name %string; #REQUIRED>
+
+<!ELEMENT text:print-time (#PCDATA)>
+<!ATTLIST text:print-time text:fixed %boolean; "false">
+<!ATTLIST text:print-time text:time-value %timeInstance; #IMPLIED>
+<!ATTLIST text:print-time style:data-style-name %styleName; #IMPLIED>
+
+<!ELEMENT text:print-date (#PCDATA)>
+<!ATTLIST text:print-date text:fixed %boolean; "false">
+<!ATTLIST text:print-date text:date-value %date; #IMPLIED>
+<!ATTLIST text:print-date style:data-style-name %styleName; #IMPLIED>
+
+<!ELEMENT text:printed-by (#PCDATA)>
+<!ATTLIST text:printed-by text:fixed %boolean; "false">
+
+<!ELEMENT text:title (#PCDATA)>
+<!ATTLIST text:title text:fixed %boolean; "false">
+
+<!ELEMENT text:subject (#PCDATA)>
+<!ATTLIST text:subject text:fixed %boolean; "false">
+
+<!ELEMENT text:keywords (#PCDATA)>
+<!ATTLIST text:keywords text:fixed %boolean; "false">
+
+<!ELEMENT text:editing-cycles (#PCDATA)>
+<!ATTLIST text:editing-cycles text:fixed %boolean; "false">
+
+<!ELEMENT text:editing-duration (#PCDATA)>
+<!ATTLIST text:editing-duration text:fixed %boolean; "false">
+<!ATTLIST text:editing-duration text:duration %timeDuration; #IMPLIED>
+<!ATTLIST text:editing-duration style:data-style-name %styleName; #IMPLIED>
+
+<!ELEMENT text:modification-time (#PCDATA)>
+<!ATTLIST text:modification-time text:fixed %boolean; "false">
+<!ATTLIST text:modification-time text:time-value %timeInstance; #IMPLIED>
+<!ATTLIST text:modification-time style:data-style-name %styleName; #IMPLIED>
+
+<!ELEMENT text:modification-date (#PCDATA)>
+<!ATTLIST text:modification-date text:fixed %boolean; "false">
+<!ATTLIST text:modification-date text:date-value %date; #IMPLIED>
+<!ATTLIST text:modification-date style:data-style-name %styleName; #IMPLIED>
+
+<!ELEMENT text:creator (#PCDATA)>
+<!ATTLIST text:creator text:fixed %boolean; "false">
+
+<!ELEMENT text:conditional-text (#PCDATA)>
+<!ATTLIST text:conditional-text text:condition %formula; #REQUIRED>
+<!ATTLIST text:conditional-text text:string-value-if-false %string; #REQUIRED>
+<!ATTLIST text:conditional-text text:string-value-if-true %string; #REQUIRED>
+<!ATTLIST text:conditional-text text:current-value %boolean; "false">
+
+<!ELEMENT text:hidden-text (#PCDATA)>
+<!ATTLIST text:hidden-text text:condition %formula; #REQUIRED>
+<!ATTLIST text:hidden-text text:string-value %string; #REQUIRED>
+<!ATTLIST text:hidden-text text:is-hidden %boolean; "false">
+
+<!ELEMENT text:hidden-paragraph EMPTY>
+<!ATTLIST text:hidden-paragraph text:condition %formula; #REQUIRED>
+<!ATTLIST text:hidden-paragraph text:is-hidden %boolean; "false">
+
+<!ELEMENT text:chapter (#PCDATA)>
+<!ATTLIST text:chapter text:display (name|number|number-and-name|
+ plain-number-and-name|plain-number)
+ "number-and-name">
+<!ATTLIST text:chapter text:outline-level %integer; "1">
+
+<!ELEMENT text:file-name (#PCDATA)>
+<!ATTLIST text:file-name text:display (full|path|name|name-and-extension)
+ "full">
+<!ATTLIST text:file-name text:fixed %boolean; "false">
+
+<!ELEMENT text:template-name (#PCDATA)>
+<!ATTLIST text:template-name text:display (full|path|name|name-and-extension|
+ area|title) "full">
+
+<!ELEMENT text:set-page-variable EMPTY>
+<!ATTLIST text:set-page-variable text:active %boolean; "true">
+<!ATTLIST text:set-page-variable text:page-adjust %integer; "0">
+
+<!ELEMENT text:get-page-variable (#PCDATA)>
+<!ATTLIST text:get-page-variable %numFormat;>
+
+<!ELEMENT text:execute-macro (#PCDATA|office:events)* >
+<!ATTLIST text:execute-macro text:description %string; #IMPLIED>
+
+
+<!ELEMENT text:dde-connection-decls (text:dde-connection-decl)*>
+
+<!ELEMENT text:dde-connection-decl EMPTY>
+<!ATTLIST text:dde-connection-decl text:name %string; #REQUIRED>
+<!ATTLIST text:dde-connection-decl text:dde-application %string; #REQUIRED>
+<!ATTLIST text:dde-connection-decl text:dde-topic %string; #REQUIRED>
+<!ATTLIST text:dde-connection-decl text:dde-item %string; #REQUIRED>
+<!ATTLIST text:dde-connection-decl text:automatic-update %boolean; "false">
+
+<!ELEMENT text:dde-connection (#PCDATA)>
+<!ATTLIST text:dde-connection text:connection-name %string; #REQUIRED>
+
+<!ELEMENT text:reference-ref (#PCDATA)>
+<!ATTLIST text:reference-ref text:ref-name %string; #REQUIRED>
+<!ATTLIST text:reference-ref text:reference-format (page|chapter|text|direction) #IMPLIED>
+
+<!ELEMENT text:sequence-ref (#PCDATA)>
+<!ATTLIST text:sequence-ref text:ref-name %string; #REQUIRED>
+<!ATTLIST text:sequence-ref text:reference-format (page|chapter|text|direction|category-and-value|caption|value) #IMPLIED>
+
+<!ELEMENT text:bookmark-ref (#PCDATA)>
+<!ATTLIST text:bookmark-ref text:ref-name %string; #REQUIRED>
+<!ATTLIST text:bookmark-ref text:reference-format (page|chapter|text|direction) #IMPLIED>
+
+<!ELEMENT text:footnote-ref (#PCDATA)>
+<!ATTLIST text:footnote-ref text:ref-name %string; #REQUIRED>
+<!ATTLIST text:footnote-ref text:reference-format (page|chapter|text|direction) #IMPLIED>
+
+<!ELEMENT text:endnote-ref (#PCDATA)>
+<!ATTLIST text:endnote-ref text:ref-name %string; #REQUIRED>
+<!ATTLIST text:endnote-ref text:reference-format (page|chapter|text|direction) #IMPLIED>
+
+<!ELEMENT text:sheet-name (#PCDATA)>
+
+<!ELEMENT text:page-count (#PCDATA)>
+<!ATTLIST text:page-count style:num-format %string; #IMPLIED>
+<!ATTLIST text:page-count style:num-letter-sync %boolean; "false">
+
+<!ELEMENT text:paragraph-count (#PCDATA)>
+<!ATTLIST text:paragraph-count style:num-format %string; #IMPLIED>
+<!ATTLIST text:paragraph-count style:num-letter-sync %boolean; "false">
+
+<!ELEMENT text:word-count (#PCDATA)>
+<!ATTLIST text:word-count style:num-format %string; #IMPLIED>
+<!ATTLIST text:word-count style:num-letter-sync %boolean; "false">
+
+<!ELEMENT text:character-count (#PCDATA)>
+<!ATTLIST text:character-count style:num-format %string; #IMPLIED>
+<!ATTLIST text:character-count style:num-letter-sync %boolean; "false">
+
+<!ELEMENT text:table-count (#PCDATA)>
+<!ATTLIST text:table-count style:num-format %string; #IMPLIED>
+<!ATTLIST text:table-count style:num-letter-sync %boolean; "false">
+
+<!ELEMENT text:image-count (#PCDATA)>
+<!ATTLIST text:image-count style:num-format %string; #IMPLIED>
+<!ATTLIST text:image-count style:num-letter-sync %boolean; "false">
+
+<!ELEMENT text:object-count (#PCDATA)>
+<!ATTLIST text:object-count style:num-format %string; #IMPLIED>
+<!ATTLIST text:object-count style:num-letter-sync %boolean; "false">
+
+<!ELEMENT text:bibliography-mark (#PCDATA)>
+<!ATTLIST text:bibliography-mark text:bibiliographic-type
+ ( article | book | booklet | conference | custom1 | custom2 | custom3 |
+ custom4 | custom5 | email | inbook | incollection | inproceedings |
+ journal | manual | mastersthesis | misc | phdthesis | proceedings |
+ techreport | unpublished | www ) #REQUIRED >
+<!ATTLIST text:bibliography-mark text:identifier CDATA #IMPLIED>
+<!ATTLIST text:bibliography-mark text:address CDATA #IMPLIED>
+<!ATTLIST text:bibliography-mark text:annote CDATA #IMPLIED>
+<!ATTLIST text:bibliography-mark text:author CDATA #IMPLIED>
+<!ATTLIST text:bibliography-mark text:booktitle CDATA #IMPLIED>
+<!ATTLIST text:bibliography-mark text:chapter CDATA #IMPLIED>
+<!ATTLIST text:bibliography-mark text:edition CDATA #IMPLIED>
+<!ATTLIST text:bibliography-mark text:editor CDATA #IMPLIED>
+<!ATTLIST text:bibliography-mark text:howpublished CDATA #IMPLIED>
+<!ATTLIST text:bibliography-mark text:institution CDATA #IMPLIED>
+<!ATTLIST text:bibliography-mark text:journal CDATA #IMPLIED>
+<!ATTLIST text:bibliography-mark text:month CDATA #IMPLIED>
+<!ATTLIST text:bibliography-mark text:note CDATA #IMPLIED>
+<!ATTLIST text:bibliography-mark text:number CDATA #IMPLIED>
+<!ATTLIST text:bibliography-mark text:organizations CDATA #IMPLIED>
+<!ATTLIST text:bibliography-mark text:pages CDATA #IMPLIED>
+<!ATTLIST text:bibliography-mark text:publisher CDATA #IMPLIED>
+<!ATTLIST text:bibliography-mark text:school CDATA #IMPLIED>
+<!ATTLIST text:bibliography-mark text:series CDATA #IMPLIED>
+<!ATTLIST text:bibliography-mark text:title CDATA #IMPLIED>
+<!ATTLIST text:bibliography-mark text:report-type CDATA #IMPLIED>
+<!ATTLIST text:bibliography-mark text:volume CDATA #IMPLIED>
+<!ATTLIST text:bibliography-mark text:year CDATA #IMPLIED>
+<!ATTLIST text:bibliography-mark text:url CDATA #IMPLIED>
+<!ATTLIST text:bibliography-mark text:custom1 CDATA #IMPLIED>
+<!ATTLIST text:bibliography-mark text:custom2 CDATA #IMPLIED>
+<!ATTLIST text:bibliography-mark text:custom3 CDATA #IMPLIED>
+<!ATTLIST text:bibliography-mark text:custom4 CDATA #IMPLIED>
+<!ATTLIST text:bibliography-mark text:custom5 CDATA #IMPLIED>
+<!ATTLIST text:bibliography-mark text:isbn CDATA #IMPLIED>
+
+
+<!ELEMENT text:bookmark EMPTY>
+<!ATTLIST text:bookmark text:name CDATA #REQUIRED>
+
+<!ELEMENT text:bookmark-start EMPTY>
+<!ATTLIST text:bookmark-start text:name CDATA #REQUIRED>
+
+<!ELEMENT text:bookmark-end EMPTY>
+<!ATTLIST text:bookmark-end text:name CDATA #REQUIRED>
+
+<!ELEMENT text:reference-mark EMPTY>
+<!ATTLIST text:reference-mark text:name CDATA #REQUIRED>
+
+<!ELEMENT text:reference-mark-start EMPTY>
+<!ATTLIST text:reference-mark-start text:name CDATA #REQUIRED>
+
+<!ELEMENT text:reference-mark-end EMPTY>
+<!ATTLIST text:reference-mark-end text:name CDATA #REQUIRED>
+
+<!ELEMENT text:footnotes-configuration (text:footnote-continuation-notice-forward?,text:footnote-continuation-notice-backward?)>
+<!ATTLIST text:footnotes-configuration style:num-prefix %string; #IMPLIED>
+<!ATTLIST text:footnotes-configuration style:num-suffix %string; #IMPLIED>
+<!ATTLIST text:footnotes-configuration style:num-format %string; #IMPLIED>
+<!ATTLIST text:footnotes-configuration style:num-letter-sync %string; #IMPLIED>
+<!ATTLIST text:footnotes-configuration text:citation-body-style-name %styleName; #IMPLIED>
+<!ATTLIST text:footnotes-configuration text:citation-style-name %styleName; #IMPLIED>
+<!ATTLIST text:footnotes-configuration text:default-style-name %styleName; #IMPLIED>
+<!ATTLIST text:footnotes-configuration text:master-page-name %styleName; #IMPLIED>
+<!ATTLIST text:footnotes-configuration text:start-value %integer; #IMPLIED>
+<!ATTLIST text:footnotes-configuration text:footnotes-position (document|page) "page">
+<!ATTLIST text:footnotes-configuration text:start-numbering-at (document|chapter|page) "document">
+
+<!ELEMENT text:footnote-continuation-notice-forward (#PCDATA)>
+<!ELEMENT text:footnote-continuation-notice-backward (#PCDATA)>
+
+<!ELEMENT text:endnotes-configuration EMPTY>
+<!ATTLIST text:endnotes-configuration style:num-prefix %string; #IMPLIED>
+<!ATTLIST text:endnotes-configuration style:num-suffix %string; #IMPLIED>
+<!ATTLIST text:endnotes-configuration style:num-format %string; #IMPLIED>
+<!ATTLIST text:endnotes-configuration style:num-letter-sync %string; #IMPLIED>
+<!ATTLIST text:endnotes-configuration text:start-value %integer; #IMPLIED>
+<!ATTLIST text:endnotes-configuration text:citation-style-name %styleName; #IMPLIED>
+<!ATTLIST text:endnotes-configuration text:citation-body-style-name %styleName; #IMPLIED>
+<!ATTLIST text:endnotes-configuration text:default-style-name %styleName; #IMPLIED>
+<!ATTLIST text:endnotes-configuration text:master-page-name %styleName; #IMPLIED>
+
+<!-- Validity constraint: text:footnote and text:endnote elements may not
+ contain other text:footnote or text:endnote elements, even though the DTD
+ allows this (via the %text; in the foot-/endnote-body).
+ Unfortunatetly, this constraint cannot be easily specified in the DTD.
+-->
+<!ELEMENT text:footnote (text:footnote-citation, text:footnote-body)>
+<!ATTLIST text:footnote text:id ID #IMPLIED>
+
+<!ELEMENT text:footnote-citation (#PCDATA)>
+<!ATTLIST text:footnote-citation text:label %string; #IMPLIED>
+
+<!ELEMENT text:footnote-body (text:h|text:p|
+ text:ordered-list|text:unordered-list)*>
+
+<!ELEMENT text:endnote (text:endnote-citation, text:endnote-body)>
+<!ATTLIST text:endnote text:id ID #IMPLIED>
+
+<!ELEMENT text:endnote-citation (#PCDATA)>
+<!ATTLIST text:endnote-citation text:label %string; #IMPLIED>
+
+<!ELEMENT text:endnote-body (text:h|text:p|
+ text:ordered-list|text:unordered-list)*>
+
+<!ENTITY % sectionText "(text:h|text:p|text:ordered-list|
+ text:unordered-list|table:table|chart:chart|draw:page|
+ draw:a|draw:text-box|draw:image|text:section|
+ text:table-of-content|text:illustration-index|
+ text:table-index|text:object-index|text:user-index|
+ text:alphabetical-index|text:bibliography|
+ text:index-title|%change-marks;)*">
+
+<!ELEMENT text:section ((text:section-source|office:dde-source)?,
+ %sectionText;) >
+
+<!ATTLIST text:section text:name CDATA #REQUIRED>
+<!ATTLIST text:section text:style-name %styleName; #IMPLIED>
+<!ATTLIST text:section text:display (true|none|condition) "true">
+<!ATTLIST text:section text:condition %formula; #IMPLIED>
+<!ATTLIST text:section text:protected %boolean; "false">
+<!ATTLIST text:section text:protection-key CDATA #IMPLIED>
+
+<!ELEMENT text:section-source EMPTY>
+<!ATTLIST text:section-source xlink:href %string; #IMPLIED>
+<!ATTLIST text:section-source xlink:type (simple) #FIXED "simple">
+<!ATTLIST text:section-source xlink:show (embed) #FIXED "embed">
+<!ATTLIST text:section-source text:section-name %string; #IMPLIED>
+<!ATTLIST text:section-source text:filter-name %string; #IMPLIED>
+
+<!ELEMENT text:table-of-content (text:table-of-content-source,
+ text:index-body) >
+<!ATTLIST text:table-of-content text:style-name %styleName; #IMPLIED>
+<!ATTLIST text:table-of-content text:protected %boolean; "false">
+
+<!ELEMENT text:table-of-content-source (text:index-title-template? ,
+ text:table-of-content-entry-template*,
+ text:index-source-styles* ) >
+<!ATTLIST text:table-of-content-source text:outline-level %integer; #IMPLIED>
+<!ATTLIST text:table-of-content-source text:use-index-marks %boolean; "true">
+<!ATTLIST text:table-of-content-source text:use-index-source-styles
+ %boolean; "false">
+<!ATTLIST text:table-of-content-source text:index-scope (document|chapter)
+ "document">
+<!ATTLIST text:table-of-content-source text:relative-tab-stop-position
+ %boolean; "true">
+<!ATTLIST text:table-of-content-source fo:language %string; #IMPLIED>
+<!ATTLIST text:table-of-content-source fo:country %string; #IMPLIED>
+<!ATTLIST text:table-of-content-source text:sort-algorithm %string; #IMPLIED>
+
+<!ELEMENT text:table-of-content-entry-template (text:index-entry-chapter-number |
+ text:index-entry-page-number |
+ text:index-entry-text |
+ text:index-entry-span |
+ text:index-entry-tab-stop |
+ text:index-entry-link-start |
+ text:index-entry-link-end)* >
+<!ATTLIST text:table-of-content-entry-template text:outline-level
+ %integer; #REQUIRED>
+<!ATTLIST text:table-of-content-entry-template text:style-name
+ %styleName; #REQUIRED>
+
+<!ELEMENT text:illustration-index
+ (text:illustration-index-source, text:index-body)>
+<!ATTLIST text:illustration-index text:style-name %styleName; #IMPLIED>
+<!ATTLIST text:illustration-index text:protected %boolean; "false">
+
+<!ELEMENT text:illustration-index-source (text:index-title-template?,
+ text:illustration-index-entry-template?) >
+<!ATTLIST text:illustration-index-source text:index-scope
+ (document|chapter) "document">
+<!ATTLIST text:illustration-index-source text:relative-tab-stop-position
+ %boolean; "true">
+<!ATTLIST text:illustration-index-source text:use-caption %boolean; "true">
+<!ATTLIST text:illustration-index-source text:caption-sequence-name
+ %string; #IMPLIED>
+<!ATTLIST text:illustration-index-source text:caption-sequence-format
+ (text|category-and-value|caption) "text">
+<!ATTLIST text:illustration-index-source fo:language %string; #IMPLIED>
+<!ATTLIST text:illustration-index-source fo:country %string; #IMPLIED>
+<!ATTLIST text:illustration-index-source text:sort-algorithm %string; #IMPLIED>
+
+<!ELEMENT text:illustration-index-entry-template
+ ( text:index-entry-page-number |
+ text:index-entry-text |
+ text:index-entry-span |
+ text:index-entry-tab-stop )* >
+<!ATTLIST text:illustration-index-entry-template text:style-name
+ %styleName; #REQUIRED>
+
+<!ELEMENT text:table-index (text:table-index-source, text:index-body)>
+<!ATTLIST text:table-index text:style-name %styleName; #IMPLIED>
+<!ATTLIST text:table-index text:protected %boolean; "false">
+
+<!ELEMENT text:table-index-source (text:index-title-template?,
+ text:table-index-entry-template?) >
+<!ATTLIST text:table-index-source text:index-scope
+ (document|chapter) "document">
+<!ATTLIST text:table-index-source text:relative-tab-stop-position
+ %boolean; "true">
+<!ATTLIST text:table-index-source text:use-caption %boolean; "true">
+<!ATTLIST text:table-index-source text:caption-sequence-name
+ %string; #IMPLIED>
+<!ATTLIST text:table-index-source text:caption-sequence-format
+ (text|category-and-value|caption) "text">
+<!ATTLIST text:table-index-source fo:language %string; #IMPLIED>
+<!ATTLIST text:table-index-source fo:country %string; #IMPLIED>
+<!ATTLIST text:table-index-source text:sort-algorithm %string; #IMPLIED>
+
+<!ELEMENT text:table-index-entry-template ( text:index-entry-page-number |
+ text:index-entry-text |
+ text:index-entry-span |
+ text:index-entry-tab-stop )* >
+<!ATTLIST text:table-index-entry-template text:style-name
+ %styleName; #REQUIRED>
+
+<!ELEMENT text:object-index ( text:object-index-source, text:index-body ) >
+<!ATTLIST text:object-index text:style-name %styleName; #IMPLIED>
+<!ATTLIST text:object-index text:protected %boolean; "false">
+
+<!ELEMENT text:object-index-source ( text:index-title-template?,
+ text:object-index-entry-template? ) >
+<!ATTLIST text:object-index-source text:index-scope
+ (document|chapter) "document">
+<!ATTLIST text:object-index-source text:relative-tab-stop-position
+ %boolean; "true">
+<!ATTLIST text:object-index-source text:use-spreadsheet-objects
+ %boolean; "false">
+<!ATTLIST text:object-index-source text:use-draw-objects %boolean; "false">
+<!ATTLIST text:object-index-source text:use-chart-objects %boolean; "false">
+<!ATTLIST text:object-index-source text:use-other-objects %boolean; "false">
+<!ATTLIST text:object-index-source text:use-math-objects %boolean; "false">
+<!ATTLIST text:object-index-source fo:language %string; #IMPLIED>
+<!ATTLIST text:object-index-source fo:country %string; #IMPLIED>
+<!ATTLIST text:object-index-source text:sort-algorithm %string; #IMPLIED>
+
+<!ELEMENT text:object-index-entry-template ( text:index-entry-page-number |
+ text:index-entry-text |
+ text:index-entry-span |
+ text:index-entry-tab-stop )* >
+<!ATTLIST text:object-index-entry-template text:style-name
+ %styleName; #REQUIRED >
+
+<!ELEMENT text:user-index (text:user-index-source, text:index-body) >
+<!ATTLIST text:user-index text:style-name %styleName; #IMPLIED>
+<!ATTLIST text:user-index text:protected %boolean; "false">
+
+<!ELEMENT text:user-index-source ( text:index-title-template?,
+ text:user-index-entry-template*,
+ text:index-source-styles* ) >
+<!ATTLIST text:user-index-source text:index-scope
+ (document|chapter) "document">
+<!ATTLIST text:user-index-source text:relative-tab-stop-position
+ %boolean; "true">
+<!ATTLIST text:user-index-source text:use-index-marks %boolean; "false">
+<!ATTLIST text:user-index-source text:use-graphics %boolean; "false">
+<!ATTLIST text:user-index-source text:use-tables %boolean; "false">
+<!ATTLIST text:user-index-source text:use-floating-frames %boolean; "false">
+<!ATTLIST text:user-index-source text:use-objects %boolean; "false">
+<!ATTLIST text:user-index-source text:use-index-source-styles
+ %boolean; "false">
+<!ATTLIST text:user-index-source text:copy-outline-level %boolean; "false">
+<!ATTLIST text:user-index-source fo:language %string; #IMPLIED>
+<!ATTLIST text:user-index-source fo:country %string; #IMPLIED>
+<!ATTLIST text:user-index-source text:sort-algorithm %string; #IMPLIED>
+
+<!ELEMENT text:user-index-entry-template ( text:index-entry-chapter |
+ text:index-entry-page-number |
+ text:index-entry-text |
+ text:index-entry-span |
+ text:index-entry-tab-stop )* >
+<!ATTLIST text:user-index-entry-template text:outline-level %integer; #REQUIRED>
+<!ATTLIST text:user-index-entry-template text:style-name %styleName; #REQUIRED>
+
+<!ELEMENT text:alphabetical-index (text:alphabetical-index-source,
+ text:index-body)>
+<!ATTLIST text:alphabetical-index text:style-name %styleName; #IMPLIED>
+<!ATTLIST text:alphabetical-index text:protected %boolean; "false">
+
+<!ELEMENT text:alphabetical-index-source ( text:index-title-template?,
+ text:alphabetical-index-entry-template* ) >
+<!ATTLIST text:alphabetical-index-source text:index-scope
+ (document|chapter) "document">
+<!ATTLIST text:alphabetical-index-source text:relative-tab-stop-position
+ %boolean; "true">
+<!ATTLIST text:alphabetical-index-source text:ignore-case %boolean; "false">
+<!ATTLIST text:alphabetical-index-source text:main-entry-style-name
+ %styleName; #IMPLIED>
+<!ATTLIST text:alphabetical-index-source text:alphabetical-separators
+ %boolean; "false">
+<!ATTLIST text:alphabetical-index-source text:combine-entries
+ %boolean; "true">
+<!ATTLIST text:alphabetical-index-source text:combine-entries-with-dash
+ %boolean; "false">
+<!ATTLIST text:alphabetical-index-source text:combine-entries-with-pp
+ %boolean; "true">
+<!ATTLIST text:alphabetical-index-source text:use-keys-as-entries
+ %boolean; "false">
+<!ATTLIST text:alphabetical-index-source text:capitalize-entries
+ %boolean; "false">
+<!ATTLIST text:alphabetical-index-source text:comma-separated
+ %boolean; "false">
+<!ATTLIST text:alphabetical-index-source fo:language %string; #IMPLIED>
+<!ATTLIST text:alphabetical-index-source fo:country %string; #IMPLIED>
+<!ATTLIST text:alphabetical-index-source text:sort-algorithm %string; #IMPLIED>
+
+<!ELEMENT text:alphabetical-index-entry-template ( text:index-entry-chapter |
+ text:index-entry-page-number |
+ text:index-entry-text |
+ text:index-entry-span |
+ text:index-entry-tab-stop )* >
+<!ATTLIST text:alphabetical-index-entry-template text:outline-level
+ (1|2|3|separator) #REQUIRED>
+<!ATTLIST text:alphabetical-index-entry-template text:style-name
+ %styleName; #REQUIRED>
+
+<!ELEMENT text:alphabetical-index-auto-mark-file EMPTY>
+<!ATTLIST text:alphabetical-index-auto-mark-file xlink:href CDATA #IMPLIED>
+<!ATTLIST text:alphabetical-index-auto-mark-file xlink:type (simple) #FIXED "simple">
+
+<!ELEMENT text:bibliography (text:bibliography-source, text:index-body) >
+<!ATTLIST text:bibliography text:style-name %styleName; #IMPLIED>
+<!ATTLIST text:bibliography text:protected %boolean; "false">
+
+<!ELEMENT text:bibliography-source ( text:index-title-template?,
+ text:bibliography-entry-template* ) >
+
+<!ELEMENT text:bibliography-entry-template ( text:index-entry-span |
+ text:index-entry-tab-stop |
+ text:index-entry-bibliography )* >
+<!ATTLIST text:bibliography-entry-template text:bibliography-type
+ ( article | book | booklet | conference | custom1 | custom2 |
+ custom3 | custom4 | custom5 | email | inbook | incollection |
+ inproceedings | journal | manual | mastersthesis | misc |
+ phdthesis | proceedings | techreport | unpublished | www )
+ #REQUIRED >
+<!ATTLIST text:bibliography-entry-template text:style-name
+ %styleName; #REQUIRED>
+
+<!ELEMENT text:index-body %sectionText; >
+
+<!--
+Validity constraint: text:index-title elements may appear only in
+indices, and there may be only one text:index-title element.
+-->
+<!ELEMENT text:index-title %sectionText; >
+<!ATTLIST text:index-title text:style-name %styleName; #IMPLIED>
+<!ATTLIST text:index-title text:name %string; #IMPLIED>
+
+<!ELEMENT text:index-title-template (#PCDATA)>
+<!ATTLIST text:index-title-template text:style-name %styleName; #IMPLIED>
+
+<!ELEMENT text:index-entry-chapter-number EMPTY>
+<!ATTLIST text:index-entry-chapter-number text:style-name %styleName; #IMPLIED>
+
+<!ELEMENT text:index-entry-chapter EMPTY>
+<!ATTLIST text:index-entry-chapter text:style-name %styleName; #IMPLIED>
+<!ATTLIST text:index-entry-chapter text:display (name|number|number-and-name)
+ "number-and-name" >
+
+<!ELEMENT text:index-entry-text EMPTY>
+<!ATTLIST text:index-entry-text text:style-name %styleName; #IMPLIED>
+
+<!ELEMENT text:index-entry-page-number EMPTY>
+<!ATTLIST text:index-entry-page-number text:style-name %styleName; #IMPLIED>
+
+<!ELEMENT text:index-entry-span (#PCDATA)>
+<!ATTLIST text:index-entry-span text:style-name %styleName; #IMPLIED>
+
+<!ELEMENT text:index-entry-bibliography EMPTY>
+<!ATTLIST text:index-entry-bibliography text:style-name %styleName; #IMPLIED>
+<!ATTLIST text:index-entry-bibliography text:bibliography-data-field
+ ( address | annote | author | bibiliographic_type |
+ booktitle | chapter | custom1 | custom2 |
+ custom3 | custom4 | custom5 | edition | editor |
+ howpublished | identifier | institution | isbn |
+ journal | month | note | number | organizations |
+ pages | publisher | report_type | school |
+ series | title | url | volume | year ) #REQUIRED>
+
+
+<!ELEMENT text:index-entry-tab-stop EMPTY>
+<!ATTLIST text:index-entry-tab-stop text:style-name %styleName; #IMPLIED>
+<!ATTLIST text:index-entry-tab-stop style:leader-char %character; " ">
+<!ATTLIST text:index-entry-tab-stop style:type (left|right) "left">
+<!ATTLIST text:index-entry-tab-stop style:position %length; #IMPLIED>
+
+<!ELEMENT text:index-entry-link-start EMPTY>
+<!ATTLIST text:index-entry-link-start text:style-name %styleName; #IMPLIED>
+
+<!ELEMENT text:index-entry-link-end EMPTY>
+<!ATTLIST text:index-entry-link-end text:style-name %styleName; #IMPLIED>
+
+<!ELEMENT text:index-source-styles (text:index-source-style)*>
+<!ATTLIST text:index-source-styles text:outline-level %integer; #REQUIRED>
+
+<!ELEMENT text:index-source-style EMPTY>
+<!ATTLIST text:index-source-style text:style-name %styleName; #REQUIRED>
+
+<!ELEMENT text:toc-mark-start EMPTY>
+<!ATTLIST text:toc-mark-start text:id %string; #REQUIRED>
+<!ATTLIST text:toc-mark-start text:outline-level %integer; #IMPLIED>
+
+<!ELEMENT text:toc-mark-end EMPTY>
+<!ATTLIST text:toc-mark-end text:id %string; #REQUIRED>
+
+<!ELEMENT text:toc-mark EMPTY>
+<!ATTLIST text:toc-mark text:string-value %string; #REQUIRED>
+<!ATTLIST text:toc-mark text:outline-level %integer; #IMPLIED>
+
+<!ELEMENT text:user-index-mark-start EMPTY>
+<!ATTLIST text:user-index-mark-start text:id %string; #REQUIRED>
+<!ATTLIST text:user-index-mark-start text:outline-level %integer; #IMPLIED>
+<!ATTLIST text:user-index-mark-start text:index-name %string; #IMPLIED>
+
+<!ELEMENT text:user-index-mark-end EMPTY>
+<!ATTLIST text:user-index-mark-end text:id %string; #REQUIRED>
+
+<!ELEMENT text:user-index-mark EMPTY>
+<!ATTLIST text:user-index-mark text:string-value %string; #REQUIRED>
+<!ATTLIST text:user-index-mark text:outline-level %integer; #IMPLIED>
+<!ATTLIST text:user-index-mark text:index-name %string; #IMPLIED>
+
+<!ELEMENT text:alphabetical-index-mark-start EMPTY>
+<!ATTLIST text:alphabetical-index-mark-start text:id %string; #REQUIRED>
+<!ATTLIST text:alphabetical-index-mark-start text:key1 %string; #IMPLIED>
+<!ATTLIST text:alphabetical-index-mark-start text:key2 %string; #IMPLIED>
+<!ATTLIST text:alphabetical-index-mark-start text:main-etry %boolean; "false">
+
+<!ELEMENT text:alphabetical-index-mark-end EMPTY>
+<!ATTLIST text:alphabetical-index-mark-end text:id %string; #REQUIRED>
+
+<!ELEMENT text:alphabetical-index-mark EMPTY>
+<!ATTLIST text:alphabetical-index-mark text:string-value %string; #REQUIRED>
+<!ATTLIST text:alphabetical-index-mark text:key1 %string; #IMPLIED>
+<!ATTLIST text:alphabetical-index-mark text:key2 %string; #IMPLIED>
+<!ATTLIST text:alphabetical-index-mark text:main-etry %boolean; "false">
+
+<!ELEMENT text:bibliography-configuration (text:sort-key)*>
+<!ATTLIST text:bibliography-configuration text:prefix %string; #IMPLIED>
+<!ATTLIST text:bibliography-configuration text:suffix %string; #IMPLIED>
+<!ATTLIST text:bibliography-configuration text:sort-by-position %boolean; "true">
+<!ATTLIST text:bibliography-configuration text:numbered-entries %boolean; "false">
+<!ATTLIST text:bibliography-configuration fo:language %string; #IMPLIED>
+<!ATTLIST text:bibliography-configuration fo:country %string; #IMPLIED>
+<!ATTLIST text:bibliography-configuration text:sort-algorithm %string; #IMPLIED>
+
+<!ELEMENT text:sort-key EMPTY>
+<!ATTLIST text:sort-key text:key ( address | annote | author |
+ bibiliographic_type | booktitle | chapter | custom1 | custom2 |
+ custom3 | custom4 | custom5 | edition | editor | howpublished |
+ identifier | institution | isbn | journal | month | note | number |
+ organizations | pages | publisher | report_type | school | series |
+ title | url | volume | year ) #REQUIRED>
+<!ATTLIST text:sort-key text:sort-ascending %boolean; "true">
+
+<!ELEMENT text:linenumbering-configuration (text:linenumbering-separator?)>
+<!ATTLIST text:linenumbering-configuration text:style-name %styleName; #IMPLIED>
+<!ATTLIST text:linenumbering-configuration text:number-lines %boolean; "true">
+<!ATTLIST text:linenumbering-configuration text:count-empty-lines %boolean; "true">
+<!ATTLIST text:linenumbering-configuration text:count-in-floating-frames %boolean; "false">
+<!ATTLIST text:linenumbering-configuration text:restart-numbering %boolean; "false">
+<!ATTLIST text:linenumbering-configuration text:offset %nonNegativeLength; #IMPLIED>
+<!ATTLIST text:linenumbering-configuration style:num-format (1|a|A|i|I) "1">
+<!ATTLIST text:linenumbering-configuration style:num-letter-sync %boolean; "false">
+<!ATTLIST text:linenumbering-configuration text:number-position (left|rigth|inner|outer) "left">
+<!ATTLIST text:linenumbering-configuration text:increment %nonNegativeInteger; #IMPLIED>
+
+<!ELEMENT text:linenumbering-separator (#PCDATA)>
+<!ATTLIST text:linenumbering-separator text:increment %nonNegativeInteger; #IMPLIED>
+
+<!ELEMENT text:script (#PCDATA)>
+<!ATTLIST text:script script:language CDATA #REQUIRED>
+<!ATTLIST text:script xlink:href CDATA #IMPLIED>
+<!ATTLIST text:script xlink:type (simple) #FIXED "simple">
+
+<!ELEMENT text:measure (#PCDATA)>
+<!ATTLIST text:measure text:kind (value|unit|gap) #REQUIRED>
+
+<!ELEMENT text:ruby (text:ruby-base, text:ruby-text)>
+<!ATTLIST text:ruby text:style-name %styleName; #IMPLIED>
+
+<!ELEMENT text:ruby-base %inline-text;>
+
+<!ELEMENT text:ruby-text (#PCDATA)>
+<!ATTLIST text:ruby-text text:style-name %styleName; #IMPLIED>
+
+<!-- elements for change tracking -->
+
+<!ELEMENT text:change EMPTY>
+<!ATTLIST text:change text:change-id CDATA #REQUIRED>
+
+<!ELEMENT text:change-start EMPTY>
+<!ATTLIST text:change-start text:change-id CDATA #REQUIRED>
+
+<!ELEMENT text:change-end EMPTY>
+<!ATTLIST text:change-end text:change-id CDATA #REQUIRED>
+
+<!ELEMENT text:tracked-changes (text:changed-region)*>
+<!ATTLIST text:tracked-changes text:track-changes %boolean; "true">
+<!ATTLIST text:tracked-changes text:protection-key CDATA #IMPLIED>
+
+<!ELEMENT text:changed-region (text:insertion |
+ (text:deletion, text:insertion?) |
+ text:format-change) >
+<!ATTLIST text:changed-region text:id ID #REQUIRED>
+
+<!ELEMENT text:insertion (office:change-info, %sectionText;)>
+<!ELEMENT text:deletion (office:change-info, %sectionText;)>
+<!ELEMENT text:format-change (office:change-info)>
+
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/a_animatedgif.infile b/xmerge/source/palmtests/qa-wrapper/testcases/a_animatedgif.infile
new file mode 100644
index 000000000000..e1e8de3632d0
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/a_animatedgif.infile
@@ -0,0 +1,4 @@
+#testing animated gif conversion
+#
+TEST||QUICKWORD|a_animatedgif
+SLEEP|10
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/a_bolddoc.infile b/xmerge/source/palmtests/qa-wrapper/testcases/a_bolddoc.infile
new file mode 100644
index 000000000000..c545805e37e2
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/a_bolddoc.infile
@@ -0,0 +1,4 @@
+#testing bold type conversion
+#
+TEST||QUICKWORD|a_bolddoc
+SLEEP|10
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/a_bookmarks.infile b/xmerge/source/palmtests/qa-wrapper/testcases/a_bookmarks.infile
new file mode 100644
index 000000000000..f350b6acdc18
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/a_bookmarks.infile
@@ -0,0 +1,4 @@
+#testing bookmark conversion
+#
+TEST||QUICKWORD|a_bookmarks
+SLEEP|10
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/a_bulletorderedlist.infile b/xmerge/source/palmtests/qa-wrapper/testcases/a_bulletorderedlist.infile
new file mode 100644
index 000000000000..bd9617d3892a
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/a_bulletorderedlist.infile
@@ -0,0 +1,4 @@
+#testing bullet ordered list conversion
+#
+TEST||QUICKWORD|a_bulletorderedlist
+SLEEP|10
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/a_emptydoc-mod.infile b/xmerge/source/palmtests/qa-wrapper/testcases/a_emptydoc-mod.infile
new file mode 100644
index 000000000000..846bb80b44d3
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/a_emptydoc-mod.infile
@@ -0,0 +1,9 @@
+#testing modification to an empty document conversion
+#
+TEST||QUICKWORD|a_emptydoc-mod
+ENTER_STRING_AT_LOCATION|108|20|New line of text added\n
+ENTER_STRING_AT_LOCATION|108|40|This is 108, 40\n
+ENTER_STRING_AT_LOCATION|150|208|This is 150, 208\n
+ENTER_STRING_AT_LOCATION|150|308|This is 150, 308\n
+
+SLEEP|10
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/a_emptydoc.infile b/xmerge/source/palmtests/qa-wrapper/testcases/a_emptydoc.infile
new file mode 100644
index 000000000000..ba5eef77ff2e
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/a_emptydoc.infile
@@ -0,0 +1,4 @@
+#testing empty document conversion
+#
+TEST||QUICKWORD|a_emptydoc
+SLEEP|10
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/a_firstlineindent.infile b/xmerge/source/palmtests/qa-wrapper/testcases/a_firstlineindent.infile
new file mode 100644
index 000000000000..31fb962eeb29
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/a_firstlineindent.infile
@@ -0,0 +1,4 @@
+#testing indent conversion
+#
+TEST||QUICKWORD|a_firstlineindent
+SLEEP|10
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/a_fontsize.infile b/xmerge/source/palmtests/qa-wrapper/testcases/a_fontsize.infile
new file mode 100644
index 000000000000..f9a12659ac67
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/a_fontsize.infile
@@ -0,0 +1,4 @@
+#testing fontsize conversion
+#
+TEST||QUICKWORD|a_fontsize
+SLEEP|10
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/a_heading.infile b/xmerge/source/palmtests/qa-wrapper/testcases/a_heading.infile
new file mode 100644
index 000000000000..ca580f445cec
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/a_heading.infile
@@ -0,0 +1,4 @@
+#testing basic heading conversion
+#
+TEST||QUICKWORD|a_heading
+SLEEP|10
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/a_heading1.infile b/xmerge/source/palmtests/qa-wrapper/testcases/a_heading1.infile
new file mode 100644
index 000000000000..4a73d5ead0e2
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/a_heading1.infile
@@ -0,0 +1,4 @@
+#testing heading1 type conversion
+#
+TEST||QUICKWORD|a_heading1
+SLEEP|10
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/a_heading2.infile b/xmerge/source/palmtests/qa-wrapper/testcases/a_heading2.infile
new file mode 100644
index 000000000000..265e2fd1e629
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/a_heading2.infile
@@ -0,0 +1,4 @@
+#testing heading2 type conversion
+#
+TEST||QUICKWORD|a_heading2
+SLEEP|10
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/a_hyperlink.infile b/xmerge/source/palmtests/qa-wrapper/testcases/a_hyperlink.infile
new file mode 100644
index 000000000000..19fb1fd93f74
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/a_hyperlink.infile
@@ -0,0 +1,4 @@
+#testing hyperlink conversion
+#
+TEST||QUICKWORD|a_hyperlink
+SLEEP|10
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/a_justified.infile b/xmerge/source/palmtests/qa-wrapper/testcases/a_justified.infile
new file mode 100644
index 000000000000..a9f1eee7016b
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/a_justified.infile
@@ -0,0 +1,4 @@
+#testing justified conversion
+#
+TEST||QUICKWORD|a_justified
+SLEEP|10
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/a_linebreaks.infile b/xmerge/source/palmtests/qa-wrapper/testcases/a_linebreaks.infile
new file mode 100644
index 000000000000..ebabb26a691a
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/a_linebreaks.infile
@@ -0,0 +1,4 @@
+#testing line break conversion
+#
+TEST||QUICKWORD|a_linebreaks
+SLEEP|10
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/a_linespacing.infile b/xmerge/source/palmtests/qa-wrapper/testcases/a_linespacing.infile
new file mode 100644
index 000000000000..ccb76ed0675f
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/a_linespacing.infile
@@ -0,0 +1,4 @@
+#testing line spacing conversion
+#
+TEST||QUICKWORD|a_linespacing
+SLEEP|10
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/a_numberorderedlist.infile b/xmerge/source/palmtests/qa-wrapper/testcases/a_numberorderedlist.infile
new file mode 100644
index 000000000000..4075e16b0516
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/a_numberorderedlist.infile
@@ -0,0 +1,4 @@
+#testing number ordered list conversion
+#
+TEST||QUICKWORD|a_numberorderedlist
+SLEEP|10
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/a_pagebreak.infile b/xmerge/source/palmtests/qa-wrapper/testcases/a_pagebreak.infile
new file mode 100644
index 000000000000..10d2f2ceba0a
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/a_pagebreak.infile
@@ -0,0 +1,4 @@
+#testing page break conversion
+#
+TEST||QUICKWORD|a_pagebreak
+SLEEP|10
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/a_paragraph.infile b/xmerge/source/palmtests/qa-wrapper/testcases/a_paragraph.infile
new file mode 100644
index 000000000000..c74558b60c7e
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/a_paragraph.infile
@@ -0,0 +1,4 @@
+#testing paragraph conversion
+#
+TEST||QUICKWORD|a_paragraph
+SLEEP|10
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/a_simple01.infile b/xmerge/source/palmtests/qa-wrapper/testcases/a_simple01.infile
new file mode 100644
index 000000000000..f08c1fa14af1
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/a_simple01.infile
@@ -0,0 +1,4 @@
+# simple01
+TEST|Simple 1|QUICKWORD|a_simple01
+ENTER_STRING_AT_LOCATION|LEFT|TOP|New text added to simple file.\n
+SLEEP|5
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/a_simple02.infile b/xmerge/source/palmtests/qa-wrapper/testcases/a_simple02.infile
new file mode 100644
index 000000000000..f56a6b0fe2c3
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/a_simple02.infile
@@ -0,0 +1,4 @@
+# simple02
+TEST|Simple 2|QUICKWORD|a_simple02
+ENTER_STRING_AT_LOCATION|64|20|, including this inserted phrase,
+SLEEP|5
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/a_simple03.infile b/xmerge/source/palmtests/qa-wrapper/testcases/a_simple03.infile
new file mode 100644
index 000000000000..3a957ab5e2ea
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/a_simple03.infile
@@ -0,0 +1,4 @@
+# simple03
+TEST|Simple 3|QUICKWORD|a_simple03
+ENTER_STRING_AT_LOCATION|LEFT|42|This is also in standard style\n
+SLEEP|5
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/a_simple04.infile b/xmerge/source/palmtests/qa-wrapper/testcases/a_simple04.infile
new file mode 100644
index 000000000000..1631885a6d77
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/a_simple04.infile
@@ -0,0 +1,4 @@
+# simple04
+TEST|Simple 4|QUICKWORD|a_simple04
+ENTER_STRING_AT_LOCATION|66|20|
+SLEEP|5
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/a_simple05.infile b/xmerge/source/palmtests/qa-wrapper/testcases/a_simple05.infile
new file mode 100644
index 000000000000..242285797c3b
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/a_simple05.infile
@@ -0,0 +1,5 @@
+# simple05
+TEST|Simple 5|QUICKWORD|a_simple05
+ENTER_STRING_AT_LOCATION|108|20|
+ENTER_STRING_AT_LOCATION|19|20|document uses
+SLEEP|5
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/a_standard.infile b/xmerge/source/palmtests/qa-wrapper/testcases/a_standard.infile
new file mode 100644
index 000000000000..c7a6ebf1fcfb
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/a_standard.infile
@@ -0,0 +1,4 @@
+#testing standard conversion
+#
+TEST||QUICKWORD|a_standard
+SLEEP|10
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/a_subscript.infile b/xmerge/source/palmtests/qa-wrapper/testcases/a_subscript.infile
new file mode 100644
index 000000000000..d4751de288c1
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/a_subscript.infile
@@ -0,0 +1,4 @@
+#testing subscript conversion
+#
+TEST||QUICKWORD|a_subscript
+SLEEP|10
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/a_superscript.infile b/xmerge/source/palmtests/qa-wrapper/testcases/a_superscript.infile
new file mode 100644
index 000000000000..1233754e9f37
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/a_superscript.infile
@@ -0,0 +1,4 @@
+#testing superscript conversion
+#
+TEST||QUICKWORD|a_superscript
+SLEEP|10
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/a_symbols.infile b/xmerge/source/palmtests/qa-wrapper/testcases/a_symbols.infile
new file mode 100644
index 000000000000..5a89e15ca22f
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/a_symbols.infile
@@ -0,0 +1,4 @@
+#testing symbol conversion
+#
+TEST||QUICKWORD|a_symbols
+SLEEP|10
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/a_tab.infile b/xmerge/source/palmtests/qa-wrapper/testcases/a_tab.infile
new file mode 100644
index 000000000000..7b5d319fa2a1
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/a_tab.infile
@@ -0,0 +1,4 @@
+#testing tab conversion
+#
+TEST||QUICKWORD|a_tab
+SLEEP|10
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/a_table.infile b/xmerge/source/palmtests/qa-wrapper/testcases/a_table.infile
new file mode 100644
index 000000000000..b7d991e7033d
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/a_table.infile
@@ -0,0 +1,5 @@
+#testing table contents conversion
+#
+TEST||QUICKWORD|a_table
+#ENTER_STRING_AT_LOCATION|LEFT|42|This is also in standard style\n
+SLEEP|10
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/a_textspan.infile b/xmerge/source/palmtests/qa-wrapper/testcases/a_textspan.infile
new file mode 100644
index 000000000000..493032299b1e
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/a_textspan.infile
@@ -0,0 +1,4 @@
+#testing textspan conversion
+#
+TEST||QUICKWORD|a_textspan
+SLEEP|10
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/a_unorderedlist.infile b/xmerge/source/palmtests/qa-wrapper/testcases/a_unorderedlist.infile
new file mode 100644
index 000000000000..6990e3ed58e6
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/a_unorderedlist.infile
@@ -0,0 +1,4 @@
+#testing unorderedlist conversion
+#
+TEST||QUICKWORD|a_unorderedlist
+SLEEP|10
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/a_wordwrap.infile b/xmerge/source/palmtests/qa-wrapper/testcases/a_wordwrap.infile
new file mode 100644
index 000000000000..22e5573f29d6
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/a_wordwrap.infile
@@ -0,0 +1,4 @@
+#testing wordwrapping conversion
+#
+TEST||QUICKWORD|a_wordwrap
+SLEEP|10
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/c_addition01-mod.infile b/xmerge/source/palmtests/qa-wrapper/testcases/c_addition01-mod.infile
new file mode 100644
index 000000000000..17c2293ed6be
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/c_addition01-mod.infile
@@ -0,0 +1,5 @@
+#
+#
+TEST||MINICALC|c_addition
+MINICALC_ENTER_CELL|0|0| 3\n
+SLEEP|5
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/c_alignment.infile b/xmerge/source/palmtests/qa-wrapper/testcases/c_alignment.infile
new file mode 100644
index 000000000000..ae607f2a9ca6
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/c_alignment.infile
@@ -0,0 +1,4 @@
+#
+#
+TEST||MINICALC|c_alignment
+SLEEP|10
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/c_backwardrange-mod.infile b/xmerge/source/palmtests/qa-wrapper/testcases/c_backwardrange-mod.infile
new file mode 100644
index 000000000000..5e869f491f5a
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/c_backwardrange-mod.infile
@@ -0,0 +1,6 @@
+#
+# Test for backwardrange of spreadsheet - change a value in a set range
+#
+TEST||MINICALC|c_backwardrange
+MINICALC_ENTER_CELL|1|1|=AVERAGE(2;5;5)\n
+SLEEP|5
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/c_basic-mod.infile b/xmerge/source/palmtests/qa-wrapper/testcases/c_basic-mod.infile
new file mode 100644
index 000000000000..a2f1d3c342f8
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/c_basic-mod.infile
@@ -0,0 +1,5 @@
+#
+# basic spreadsheet round trip conversion no modification
+#
+TEST||MINICALC|c_basic
+
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/c_bob-mod.infile b/xmerge/source/palmtests/qa-wrapper/testcases/c_bob-mod.infile
new file mode 100644
index 000000000000..f868004d1d5e
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/c_bob-mod.infile
@@ -0,0 +1,5 @@
+#
+#
+TEST||MINICALC|c_bob
+MINICALC_ENTER_CELL|0|0| 3\n
+SLEEP|5
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/c_boolean-mod.infile b/xmerge/source/palmtests/qa-wrapper/testcases/c_boolean-mod.infile
new file mode 100644
index 000000000000..2d69bb8cedf0
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/c_boolean-mod.infile
@@ -0,0 +1,6 @@
+#
+# Spreadsheet - test Boolean entry change.
+#
+TEST||MINICALC|c_boolean
+MINICALC_ENTER_CELL|1|0|TRUE\n
+SLEEP|5
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/c_cellcurrencyvalue.infile b/xmerge/source/palmtests/qa-wrapper/testcases/c_cellcurrencyvalue.infile
new file mode 100644
index 000000000000..f58003dedd23
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/c_cellcurrencyvalue.infile
@@ -0,0 +1,5 @@
+#
+# basic spreadsheet with currency format round trip conversion no modification
+#
+TEST||MINICALC|c_cellcurrencyalue
+
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/c_cellpercentvalue-mod.infile b/xmerge/source/palmtests/qa-wrapper/testcases/c_cellpercentvalue-mod.infile
new file mode 100644
index 000000000000..440c82d2fbc2
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/c_cellpercentvalue-mod.infile
@@ -0,0 +1,8 @@
+#
+# Spreadsheet percentage value precision
+#
+TEST||MINICALC|c_cellpercentvalue
+MINICALC_ENTER_CELL|0|0|120%\n
+SLEEP|3
+MINICALC_ENTER_CELL|0|1|10%\n
+SLEEP|5
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/c_cellstringvalue-mod.infile b/xmerge/source/palmtests/qa-wrapper/testcases/c_cellstringvalue-mod.infile
new file mode 100644
index 000000000000..5e67ea28c49f
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/c_cellstringvalue-mod.infile
@@ -0,0 +1,10 @@
+#
+# Spreadsheet string value changes.
+#
+TEST||MINICALC|c_cellstringvalue
+MINICALC_ENTER_CELL|1|2|Testing\n
+SLEEP|3
+MINICALC_ENTER_CELL|1|3|\n
+SLEEP|3
+MINICALC_ENTER_CELL|2|1|;\n
+SLEEP|5
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/c_columnswidth-mod.infile b/xmerge/source/palmtests/qa-wrapper/testcases/c_columnswidth-mod.infile
new file mode 100644
index 000000000000..5fe9942beabc
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/c_columnswidth-mod.infile
@@ -0,0 +1,3 @@
+#
+#
+TEST||MINICALC|c_columnswidth
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/c_cyclic-mod.infile b/xmerge/source/palmtests/qa-wrapper/testcases/c_cyclic-mod.infile
new file mode 100644
index 000000000000..ab9ac1b29d4a
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/c_cyclic-mod.infile
@@ -0,0 +1,12 @@
+#
+# Spreadsheet error messages.
+#
+TEST||MINICALC|c_cyclic
+MINICALC_ENTER_CELL|3|0|0\n
+SLEEP|3
+MINICALC_ENTER_CELL|4|0|0\n
+SLEEP|3
+MINICALC_ENTER_CELL|3|1|=(A1/A4)\n
+SLEEP|3
+MINICALC_ENTER_CELL|4|1|=(A4/A5)\n
+SLEEP|5
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/c_dividefloating-mod.infile b/xmerge/source/palmtests/qa-wrapper/testcases/c_dividefloating-mod.infile
new file mode 100644
index 000000000000..ce216e167f5e
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/c_dividefloating-mod.infile
@@ -0,0 +1,8 @@
+#
+# Spreadsheet - dividing floating points.
+#
+TEST||MINICALC|c_dividefloating
+MINICALC_ENTER_CELL|3|0|=-(12.2)/(5-1)\n
+SLEEP|3
+MINICALC_ENTER_CELL|1|1|=(12.2)/(5-1)\n
+SLEEP|5
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/c_forwardrange-mod.infile b/xmerge/source/palmtests/qa-wrapper/testcases/c_forwardrange-mod.infile
new file mode 100644
index 000000000000..0c29937a0198
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/c_forwardrange-mod.infile
@@ -0,0 +1,6 @@
+#
+# Spreadsheet forwardrange & logical function test
+#
+TEST||MINICALC|c_forwardrange
+MINICALC_ENTER_CELL|3|1|=IF(0;45.45;54.54)\n
+SLEEP|5
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/c_insertimage.infile b/xmerge/source/palmtests/qa-wrapper/testcases/c_insertimage.infile
new file mode 100644
index 000000000000..6801a23fa455
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/c_insertimage.infile
@@ -0,0 +1,4 @@
+#
+# Spreadsheet with image insert conversion test.
+#
+TEST||MINICALC|c_insertimage
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/c_insertrow-mod.infile b/xmerge/source/palmtests/qa-wrapper/testcases/c_insertrow-mod.infile
new file mode 100644
index 000000000000..a56fcf0b2a13
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/c_insertrow-mod.infile
@@ -0,0 +1,13 @@
+#
+# simple spreadsheet - insert a new row
+#
+TEST||MINICALC|c_insertrow
+TAP_PEN_HARD|10|40|
+SLEEP|3
+TAP_PEN_HARD|110|140
+SLEEP|3
+TAP_PEN_HARD|110|130
+SLEEP|3
+MINICALC_ENTER_CELL|3|0|1\n
+SLEEP|5
+
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/c_invalidcellref-mod.infile b/xmerge/source/palmtests/qa-wrapper/testcases/c_invalidcellref-mod.infile
new file mode 100644
index 000000000000..dc2675c2d13a
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/c_invalidcellref-mod.infile
@@ -0,0 +1,10 @@
+#
+# Spreadsheet invalid references test.
+#
+TEST||MINICALC|c_invalidcellref
+MINICALC_ENTER_CELL|2|0|=MAX(1;2;3)\n
+SLEEP|3
+MINICALC_ENTER_CELL|1|2| \n
+SLEEP|3
+MINICALC_ENTER_CELL|2|2|=a0 \n
+SLEEP|5
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/c_largerange-mod.infile b/xmerge/source/palmtests/qa-wrapper/testcases/c_largerange-mod.infile
new file mode 100644
index 000000000000..7bc7b53e8423
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/c_largerange-mod.infile
@@ -0,0 +1,6 @@
+#
+# Spreadsheet large range test
+#
+TEST||MINICALC|c_largerange
+MINICALC_ENTER_CELL|2|1|=SUM(E7:G10)\n
+SLEEP|5
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/c_listrange-mod.infile b/xmerge/source/palmtests/qa-wrapper/testcases/c_listrange-mod.infile
new file mode 100644
index 000000000000..252dbe45d34c
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/c_listrange-mod.infile
@@ -0,0 +1,6 @@
+#
+# Spreadsheet listrange test.
+#
+TEST||MINICALC|c_listrange
+MINICALC_ENTER_CELL|2|3|24\n
+SLEEP|5
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/c_mathematical-mod.infile b/xmerge/source/palmtests/qa-wrapper/testcases/c_mathematical-mod.infile
new file mode 100644
index 000000000000..f45b347b1760
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/c_mathematical-mod.infile
@@ -0,0 +1,10 @@
+#
+# Spreadsheet standard math functs
+#
+TEST||MINICALC|c_mathematical
+MINICALC_ENTER_CELL|0|1|=SIN(3.14/2)\n
+SLEEP8|
+MINICALC_ENTER_CELL|1|1|=COS(0)\n
+SLEEP|8
+MINICALC_ENTER_CELL|2|2|=TAN(1.57/2)\n
+SLEEP|8
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/c_multi_boolean.infile b/xmerge/source/palmtests/qa-wrapper/testcases/c_multi_boolean.infile
new file mode 100644
index 000000000000..ef77f2a143b2
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/c_multi_boolean.infile
@@ -0,0 +1,5 @@
+#
+# Spreadsheet - test multi Boolean entry no change.
+#
+TEST||MINICALC|c_multi_boolean
+SLEEP|5
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/c_protection-mod01.infile b/xmerge/source/palmtests/qa-wrapper/testcases/c_protection-mod01.infile
new file mode 100644
index 000000000000..d1557eab26da
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/c_protection-mod01.infile
@@ -0,0 +1,6 @@
+#
+# Spreadsheet change protection test.
+#
+TEST||MINICALC|c_protection
+MINICALC_ENTER_CELL|0|0| 1\n
+SLEEP|5
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/c_sheetreference-mod.infile b/xmerge/source/palmtests/qa-wrapper/testcases/c_sheetreference-mod.infile
new file mode 100644
index 000000000000..3b9d76bb02bf
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/c_sheetreference-mod.infile
@@ -0,0 +1,6 @@
+#
+# Spreadsheet sheet reference test.
+#
+TEST||MINICALC|c_sheetreference
+MINICALC_ENTER_CELL|2|0|=Sheet3.B1\n
+SLEEP|5
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/c_simple01-mod.infile b/xmerge/source/palmtests/qa-wrapper/testcases/c_simple01-mod.infile
new file mode 100644
index 000000000000..2ae81831384c
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/c_simple01-mod.infile
@@ -0,0 +1,13 @@
+#
+# simple spreadsheet - insert text & numbers
+#
+TEST||MINICALC|c_simple01
+MINICALC_ENTER_CELL|0|0|Col1\n
+SLEEP|3
+MINICALC_ENTER_CELL|1|0|1\n
+SLEEP|3
+MINICALC_ENTER_CELL|2|0|1\n
+SLEEP|3
+MINICALC_ENTER_CELL|3|0|1\n
+SLEEP|5
+
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/c_simple02-mod.infile b/xmerge/source/palmtests/qa-wrapper/testcases/c_simple02-mod.infile
new file mode 100644
index 000000000000..a6414e9a5168
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/c_simple02-mod.infile
@@ -0,0 +1,13 @@
+#
+# simple spreadsheet - append a new column to end
+#
+TEST||MINICALC|c_simple02
+MINICALC_ENTER_CELL|0|1|Col3\n
+SLEEP|3
+MINICALC_ENTER_CELL|1|1|3\n
+SLEEP|3
+MINICALC_ENTER_CELL|2|1|3\n
+SLEEP|3
+MINICALC_ENTER_CELL|3|1|3\n
+SLEEP|5
+
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/c_simple03-mod.infile b/xmerge/source/palmtests/qa-wrapper/testcases/c_simple03-mod.infile
new file mode 100644
index 000000000000..00ad02334b45
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/c_simple03-mod.infile
@@ -0,0 +1,22 @@
+#
+# simple spreadsheet - insert a new column in middle
+#
+TEST||MINICALC|c_simple03
+MINICALC_ENTER_CELL|0|1|Col2\n
+SLEEP|3
+MINICALC_ENTER_CELL|1|1|2\n
+SLEEP|3
+MINICALC_ENTER_CELL|2|1|2\n
+SLEEP|3
+MINICALC_ENTER_CELL|3|1|2\n
+SLEEP|5
+MINICALC_ENTER_CELL|0|2|Col3\n
+SLEEP|3
+MINICALC_ENTER_CELL|1|2|3\n
+SLEEP|3
+MINICALC_ENTER_CELL|2|2|3\n
+SLEEP|3
+MINICALC_ENTER_CELL|3|2|3\n
+SLEEP|5
+
+
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/c_simple04-mod.infile b/xmerge/source/palmtests/qa-wrapper/testcases/c_simple04-mod.infile
new file mode 100644
index 000000000000..4c5b8828038c
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/c_simple04-mod.infile
@@ -0,0 +1,14 @@
+#
+# simple spreadsheet - delete text & numbers
+#
+TEST||MINICALC|c_simple04
+MINICALC_ENTER_CELL|0|2|\n
+SLEEP|3
+MINICALC_ENTER_CELL|1|2|\n
+SLEEP|3
+MINICALC_ENTER_CELL|2|2|\n
+SLEEP|3
+MINICALC_ENTER_CELL|3|2|\n
+SLEEP|5
+
+
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/c_smallrange-mod.infile b/xmerge/source/palmtests/qa-wrapper/testcases/c_smallrange-mod.infile
new file mode 100644
index 000000000000..81c8ab33bdf8
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/c_smallrange-mod.infile
@@ -0,0 +1,6 @@
+#
+# Spreadsheet smallrange test.
+#
+TEST||MINICALC|c_smallrange
+MINICALC_ENTER_CELL|2|1|=AVERAGE(A1:B2)\n
+SLEEP|5
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/c_styles.infile b/xmerge/source/palmtests/qa-wrapper/testcases/c_styles.infile
new file mode 100644
index 000000000000..26c3446dffd5
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/c_styles.infile
@@ -0,0 +1,3 @@
+#
+#
+TEST||MINICALC|c_styles
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/c_textimage.infile b/xmerge/source/palmtests/qa-wrapper/testcases/c_textimage.infile
new file mode 100644
index 000000000000..71416244e9d4
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/c_textimage.infile
@@ -0,0 +1,12 @@
+#
+# Spreadsheet image text insert.
+#
+TEST||MINICALC|c_textimage
+MINICALC_ENTER_CELL|0|0|This is a green car.\n
+SLEEP|3
+MINICALC_ENTER_CELL|14|1|This line is below the green car.\n
+SLEEP|3
+MINICALC_ENTER_CELL|15|2|This is a bird.\n
+SLEEP|3
+MINICALC_ENTER_CELL|32|2|This line is below the bird.\n
+SLEEP|5
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/empty01.infile b/xmerge/source/palmtests/qa-wrapper/testcases/empty01.infile
new file mode 100644
index 000000000000..4100bb47178e
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/empty01.infile
@@ -0,0 +1,3 @@
+# empty01
+TEST|Empty 1|QUICKWORD|empty01
+ENTER_STRING_AT_LOCATION|LEFT|TOP|New text added to empty file.\n
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/hyperlink01.infile b/xmerge/source/palmtests/qa-wrapper/testcases/hyperlink01.infile
new file mode 100644
index 000000000000..75f4acb1123b
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/hyperlink01.infile
@@ -0,0 +1,4 @@
+# hyperlink01
+TEST|Hyperlink 1|QUICKWORD|hyperlink01
+ENTER_STRING_AT_LOCATION|114|64|
+ENTER_STRING_AT_LOCATION|33|64|SunWeb Central
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/image01.infile b/xmerge/source/palmtests/qa-wrapper/testcases/image01.infile
new file mode 100644
index 000000000000..88da6efab59d
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/image01.infile
@@ -0,0 +1,4 @@
+# image01
+TEST|Image 1|QUICKWORD|image01
+ENTER_STRING_AT_LOCATION|86|53|\nReal start of animated gif
+ENTER_STRING_AT_LOCATION|LEFT|97|Real end of animated gif\n
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/simple01.infile b/xmerge/source/palmtests/qa-wrapper/testcases/simple01.infile
new file mode 100644
index 000000000000..9b8d2c3f26eb
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/simple01.infile
@@ -0,0 +1,3 @@
+# simple01
+TEST|Simple 1|QUICKWORD|simple01
+ENTER_STRING_AT_LOCATION|LEFT|TOP|New text added to simple file.\n
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/simple02.infile b/xmerge/source/palmtests/qa-wrapper/testcases/simple02.infile
new file mode 100644
index 000000000000..ec139bdacafe
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/simple02.infile
@@ -0,0 +1,3 @@
+# simple02
+TEST|Simple 2|QUICKWORD|simple02
+ENTER_STRING_AT_LOCATION|64|20|, including this inserted phrase,
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/simple03.infile b/xmerge/source/palmtests/qa-wrapper/testcases/simple03.infile
new file mode 100644
index 000000000000..0755a23b55db
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/simple03.infile
@@ -0,0 +1,3 @@
+# simple03
+TEST|Simple 3|QUICKWORD|simple03
+ENTER_STRING_AT_LOCATION|LEFT|42|This is also in standard style\n
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/simple04.infile b/xmerge/source/palmtests/qa-wrapper/testcases/simple04.infile
new file mode 100644
index 000000000000..7c6419dd91a4
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/simple04.infile
@@ -0,0 +1,3 @@
+# simple04
+TEST|Simple 4|QUICKWORD|simple04
+ENTER_STRING_AT_LOCATION|66|20|
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/simple05.infile b/xmerge/source/palmtests/qa-wrapper/testcases/simple05.infile
new file mode 100644
index 000000000000..5296d4d953d9
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/simple05.infile
@@ -0,0 +1,4 @@
+# simple05
+TEST|Simple 5|QUICKWORD|simple05
+ENTER_STRING_AT_LOCATION|108|20|
+ENTER_STRING_AT_LOCATION|19|20|document uses
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/table01.infile b/xmerge/source/palmtests/qa-wrapper/testcases/table01.infile
new file mode 100644
index 000000000000..fe197e63ad82
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/table01.infile
@@ -0,0 +1,3 @@
+# table01
+TEST|Table 1|QUICKWORD|table01
+ENTER_STRING_AT_LOCATION|77|31|, immediately after this sentence
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/table02.infile b/xmerge/source/palmtests/qa-wrapper/testcases/table02.infile
new file mode 100644
index 000000000000..c5570610e083
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/table02.infile
@@ -0,0 +1,3 @@
+# table02
+TEST|Table 2|QUICKWORD|table02
+ENTER_STRING_AT_LOCATION|LEFT|64|This sentence comes after the table.
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/table03.infile b/xmerge/source/palmtests/qa-wrapper/testcases/table03.infile
new file mode 100644
index 000000000000..22a22cbaa492
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/table03.infile
@@ -0,0 +1,4 @@
+# table03
+TEST|Table 3|QUICKWORD|table03
+ENTER_STRING_AT_LOCATION|77|31|, immediately after this sentence
+ENTER_STRING_AT_LOCATION|LEFT|75|This sentence comes after the table.
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/table04.infile b/xmerge/source/palmtests/qa-wrapper/testcases/table04.infile
new file mode 100644
index 000000000000..beeb6baf6e06
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/table04.infile
@@ -0,0 +1,4 @@
+# table04
+TEST|Table 4|QUICKWORD|table04
+ENTER_STRING_AT_LOCATION|77|31|
+ENTER_STRING_AT_LOCATION|62|20|a une table avec 3 lignes et 3 colonnes
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_animatedgif.sxw b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_animatedgif.sxw
new file mode 100644
index 000000000000..690e5611a4b6
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_animatedgif.sxw
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_bolddoc.sxw b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_bolddoc.sxw
new file mode 100644
index 000000000000..314a4adc0eb9
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_bolddoc.sxw
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_bookmarks.sxw b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_bookmarks.sxw
new file mode 100644
index 000000000000..c0f7c7ba632c
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_bookmarks.sxw
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_bulletorderedlist.sxw b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_bulletorderedlist.sxw
new file mode 100644
index 000000000000..bd640d575fb2
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_bulletorderedlist.sxw
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_emptydoc-mod.sxw b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_emptydoc-mod.sxw
new file mode 100644
index 000000000000..d4d4eff4df96
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_emptydoc-mod.sxw
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_emptydoc.sxw b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_emptydoc.sxw
new file mode 100644
index 000000000000..d4d4eff4df96
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_emptydoc.sxw
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_firstlineindent.sxw b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_firstlineindent.sxw
new file mode 100644
index 000000000000..0729f3d25cdf
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_firstlineindent.sxw
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_fontsize.sxw b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_fontsize.sxw
new file mode 100644
index 000000000000..0b5717728617
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_fontsize.sxw
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_heading.sxw b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_heading.sxw
new file mode 100644
index 000000000000..915dce52c846
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_heading.sxw
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_heading1.sxw b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_heading1.sxw
new file mode 100644
index 000000000000..ebf0b2a44a3d
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_heading1.sxw
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_heading2.sxw b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_heading2.sxw
new file mode 100644
index 000000000000..42645eb2a0e6
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_heading2.sxw
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_hyperlink.sxw b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_hyperlink.sxw
new file mode 100644
index 000000000000..68632c7799cb
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_hyperlink.sxw
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_justified.sxw b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_justified.sxw
new file mode 100644
index 000000000000..37fa79a5db3b
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_justified.sxw
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_linebreaks.sxw b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_linebreaks.sxw
new file mode 100644
index 000000000000..519d12ef6acd
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_linebreaks.sxw
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_linespacing.sxw b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_linespacing.sxw
new file mode 100644
index 000000000000..f640bf826395
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_linespacing.sxw
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_numberorderedlist.sxw b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_numberorderedlist.sxw
new file mode 100644
index 000000000000..9ea9bcdb2195
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_numberorderedlist.sxw
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_pagebreak.sxw b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_pagebreak.sxw
new file mode 100644
index 000000000000..389520790d52
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_pagebreak.sxw
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_paragraph.sxw b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_paragraph.sxw
new file mode 100644
index 000000000000..b19b4439b2e0
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_paragraph.sxw
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_simple01.sxw b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_simple01.sxw
new file mode 100644
index 000000000000..be65343e2ffe
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_simple01.sxw
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_simple02.sxw b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_simple02.sxw
new file mode 100644
index 000000000000..be65343e2ffe
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_simple02.sxw
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_simple03.sxw b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_simple03.sxw
new file mode 100644
index 000000000000..be65343e2ffe
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_simple03.sxw
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_simple04.sxw b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_simple04.sxw
new file mode 100644
index 000000000000..be65343e2ffe
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_simple04.sxw
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_simple05.sxw b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_simple05.sxw
new file mode 100644
index 000000000000..be65343e2ffe
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_simple05.sxw
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_standard.sxw b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_standard.sxw
new file mode 100644
index 000000000000..be65343e2ffe
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_standard.sxw
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_subscript.sxw b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_subscript.sxw
new file mode 100644
index 000000000000..486a8fb92d8d
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_subscript.sxw
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_superscript.sxw b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_superscript.sxw
new file mode 100644
index 000000000000..cc65c10281df
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_superscript.sxw
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_symbols.sxw b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_symbols.sxw
new file mode 100644
index 000000000000..7d8961b142bd
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_symbols.sxw
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_tab.sxw b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_tab.sxw
new file mode 100644
index 000000000000..878707db6816
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_tab.sxw
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_table.sxw b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_table.sxw
new file mode 100644
index 000000000000..34634a4ec542
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_table.sxw
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_textspan.sxw b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_textspan.sxw
new file mode 100644
index 000000000000..c42751fa6ee4
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_textspan.sxw
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_unorderedlist.sxw b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_unorderedlist.sxw
new file mode 100644
index 000000000000..ca5ee406ccc5
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_unorderedlist.sxw
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_wordwrap.sxw b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_wordwrap.sxw
new file mode 100644
index 000000000000..168ebc72dfd1
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/a_wordwrap.sxw
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_addition.sxc b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_addition.sxc
new file mode 100644
index 000000000000..9bd5c1a7ee73
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_addition.sxc
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_alignment.sxc b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_alignment.sxc
new file mode 100644
index 000000000000..b1fdbd58b7a8
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_alignment.sxc
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_backwardrange.sxc b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_backwardrange.sxc
new file mode 100644
index 000000000000..f319ed9feb8d
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_backwardrange.sxc
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_basic.sxc b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_basic.sxc
new file mode 100644
index 000000000000..9bd5c1a7ee73
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_basic.sxc
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_boolean.sxc b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_boolean.sxc
new file mode 100644
index 000000000000..b6e876605be5
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_boolean.sxc
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_cellcurrencyalue.sxc b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_cellcurrencyalue.sxc
new file mode 100644
index 000000000000..808d781162e6
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_cellcurrencyalue.sxc
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_cellpercentvalue.sxc b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_cellpercentvalue.sxc
new file mode 100644
index 000000000000..e0499ce95c17
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_cellpercentvalue.sxc
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_cellstringvalue.sxc b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_cellstringvalue.sxc
new file mode 100644
index 000000000000..f6fb4dc5de1a
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_cellstringvalue.sxc
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_columnswidth.sxc b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_columnswidth.sxc
new file mode 100644
index 000000000000..24aa28e71fbd
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_columnswidth.sxc
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_cyclic.sxc b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_cyclic.sxc
new file mode 100644
index 000000000000..196bd78962a9
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_cyclic.sxc
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_dividefloating.sxc b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_dividefloating.sxc
new file mode 100644
index 000000000000..1e2c55b448c8
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_dividefloating.sxc
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_forwardrange.sxc b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_forwardrange.sxc
new file mode 100644
index 000000000000..f37c97d7e2a8
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_forwardrange.sxc
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_insertimage.sxc b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_insertimage.sxc
new file mode 100644
index 000000000000..9f42285d2881
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_insertimage.sxc
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_insertrow.sxc b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_insertrow.sxc
new file mode 100644
index 000000000000..e20c0fff4414
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_insertrow.sxc
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_invalidcellref.sxc b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_invalidcellref.sxc
new file mode 100644
index 000000000000..28fa241d7112
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_invalidcellref.sxc
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_largerange.sxc b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_largerange.sxc
new file mode 100644
index 000000000000..618e9ee73478
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_largerange.sxc
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_listrange.sxc b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_listrange.sxc
new file mode 100644
index 000000000000..b29b34d589ad
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_listrange.sxc
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_mathematical.sxc b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_mathematical.sxc
new file mode 100644
index 000000000000..deab6092dc97
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_mathematical.sxc
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_multi_boolean.sxc b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_multi_boolean.sxc
new file mode 100644
index 000000000000..38bc90cf0e52
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_multi_boolean.sxc
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_protection.sxc b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_protection.sxc
new file mode 100644
index 000000000000..64f89cc61ce7
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_protection.sxc
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_sheetreference.sxc b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_sheetreference.sxc
new file mode 100644
index 000000000000..0ebb013db25d
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_sheetreference.sxc
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_simple01.sxc b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_simple01.sxc
new file mode 100644
index 000000000000..b4417b983444
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_simple01.sxc
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_simple02.sxc b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_simple02.sxc
new file mode 100644
index 000000000000..7a4d69640f0a
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_simple02.sxc
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_simple03.sxc b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_simple03.sxc
new file mode 100644
index 000000000000..bb29f91d6b29
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_simple03.sxc
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_simple04.sxc b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_simple04.sxc
new file mode 100644
index 000000000000..318129c421c4
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_simple04.sxc
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_smallrange.sxc b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_smallrange.sxc
new file mode 100644
index 000000000000..ea7dacc2464d
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_smallrange.sxc
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_styles.sxc b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_styles.sxc
new file mode 100644
index 000000000000..21e0f1ab5ac0
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_styles.sxc
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_textimage.sxc b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_textimage.sxc
new file mode 100644
index 000000000000..9f42285d2881
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/c_textimage.sxc
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/empty01.sxw b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/empty01.sxw
new file mode 100644
index 000000000000..d4d4eff4df96
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/empty01.sxw
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/hyperlink01.sxw b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/hyperlink01.sxw
new file mode 100644
index 000000000000..d000f2974b23
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/hyperlink01.sxw
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/image01.sxw b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/image01.sxw
new file mode 100644
index 000000000000..690e5611a4b6
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/image01.sxw
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/simple01.sxw b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/simple01.sxw
new file mode 100644
index 000000000000..be65343e2ffe
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/simple01.sxw
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/simple02.sxw b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/simple02.sxw
new file mode 100644
index 000000000000..be65343e2ffe
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/simple02.sxw
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/simple03.sxw b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/simple03.sxw
new file mode 100644
index 000000000000..be65343e2ffe
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/simple03.sxw
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/simple04.sxw b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/simple04.sxw
new file mode 100644
index 000000000000..be65343e2ffe
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/simple04.sxw
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/simple05.sxw b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/simple05.sxw
new file mode 100644
index 000000000000..be65343e2ffe
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/simple05.sxw
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/table01.sxw b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/table01.sxw
new file mode 100644
index 000000000000..956bedcc24e2
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/table01.sxw
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/table02.sxw b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/table02.sxw
new file mode 100644
index 000000000000..956bedcc24e2
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/table02.sxw
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/table03.sxw b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/table03.sxw
new file mode 100644
index 000000000000..956bedcc24e2
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/table03.sxw
Binary files differ
diff --git a/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/table04.sxw b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/table04.sxw
new file mode 100644
index 000000000000..956bedcc24e2
--- /dev/null
+++ b/xmerge/source/palmtests/qa-wrapper/testcases/xml-orig/table04.sxw
Binary files differ
diff --git a/xmerge/source/palmtests/qa/bin/mysplit.pl b/xmerge/source/palmtests/qa/bin/mysplit.pl
new file mode 100755
index 000000000000..172a53a319cc
--- /dev/null
+++ b/xmerge/source/palmtests/qa/bin/mysplit.pl
@@ -0,0 +1,58 @@
+#!/usr/local/bin/perl
+#########################################################################
+
+ #*************************************************************************
+ #
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# Copyright 2000, 2010 Oracle and/or its affiliates.
+#
+# OpenOffice.org - a multi-platform office productivity suite
+#
+# This file is part of OpenOffice.org.
+#
+# OpenOffice.org is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License version 3
+# only, as published by the Free Software Foundation.
+#
+# OpenOffice.org is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License version 3 for more details
+# (a copy is included in the LICENSE file that accompanied this code).
+#
+# You should have received a copy of the GNU Lesser General Public License
+# version 3 along with OpenOffice.org. If not, see
+# <http://www.openoffice.org/license.html>
+# for a copy of the LGPLv3 License.
+#
+ #*************************************************************************
+
+open(TESTFILE, $ARGV[0]);
+
+while (<TESTFILE>)
+{
+ if ($_[1] eq "-q")
+ {
+ chomp $_;
+ @args = split('\|', $_);
+ @filestuff = split('\.', @args[0]);
+ $filename = @filestuff[0] . ".infile";
+ open (TESTCASE, ">$filename") || die "Error opening $filename";
+ print TESTCASE "# @args[1]\n# @args[2]\n";
+ print TESTCASE "TEST|@args[1]|QUICKWORD|@filestuff[0]\n" ;
+ close TESTCASE;
+ }
+ if ($_[1] eq "-m")
+ {
+ chomp $_;
+ @args = split('\|', $_);
+ @filestuff = split('\.', @args[0]);
+ $filename = @filestuff[0] . ".infile";
+ open (TESTCASE, ">$filename") || die "Error opening $filename";
+ print TESTCASE "# @args[1]\n# @args[2]\n";
+ print TESTCASE "TEST|@args[1]|MINICALC|@filestuff[0]\n" ;
+ close TESTCASE;
+ }
+
+}
diff --git a/xmerge/source/palmtests/qa/bin/tappen.pl b/xmerge/source/palmtests/qa/bin/tappen.pl
new file mode 100755
index 000000000000..5b365448f9e8
--- /dev/null
+++ b/xmerge/source/palmtests/qa/bin/tappen.pl
@@ -0,0 +1,61 @@
+#!/usr/bin/perl
+#########################################################################
+
+ #*************************************************************************
+ #
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# Copyright 2000, 2010 Oracle and/or its affiliates.
+#
+# OpenOffice.org - a multi-platform office productivity suite
+#
+# This file is part of OpenOffice.org.
+#
+# OpenOffice.org is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License version 3
+# only, as published by the Free Software Foundation.
+#
+# OpenOffice.org is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License version 3 for more details
+# (a copy is included in the LICENSE file that accompanied this code).
+#
+# You should have received a copy of the GNU Lesser General Public License
+# version 3 along with OpenOffice.org. If not, see
+# <http://www.openoffice.org/license.html>
+# for a copy of the LGPLv3 License.
+#
+ #*************************************************************************
+
+####################################################################
+# File Name: template.pl
+# Version : 1.0
+# Project : XMerge
+# Author : Brian Cameron
+# Date : 5th Sept. 2001
+#
+# Takes x and y from the command line and taps the screen there.
+# Assumes pose is already running.
+#
+##########################################################################
+
+if ($#ARGV != 1)
+{
+ print "\nUsage: $0 x y\n\n";
+ exit -1;
+}
+
+use lib "$ENV{qa-dir}/lib";
+use converterlib;
+
+# Put commands to run between the open_connection() and
+# close_connection() calls...
+#
+open_connection();
+
+TapPen($ARGV[0], $ARGV[1]);
+
+close_connection();
+
+
diff --git a/xmerge/source/palmtests/qa/bin/template.pl b/xmerge/source/palmtests/qa/bin/template.pl
new file mode 100755
index 000000000000..f5e3c0cf7668
--- /dev/null
+++ b/xmerge/source/palmtests/qa/bin/template.pl
@@ -0,0 +1,55 @@
+#!/usr/bin/perl
+#########################################################################
+
+ #*************************************************************************
+ #
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# Copyright 2000, 2010 Oracle and/or its affiliates.
+#
+# OpenOffice.org - a multi-platform office productivity suite
+#
+# This file is part of OpenOffice.org.
+#
+# OpenOffice.org is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License version 3
+# only, as published by the Free Software Foundation.
+#
+# OpenOffice.org is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License version 3 for more details
+# (a copy is included in the LICENSE file that accompanied this code).
+#
+# You should have received a copy of the GNU Lesser General Public License
+# version 3 along with OpenOffice.org. If not, see
+# <http://www.openoffice.org/license.html>
+# for a copy of the LGPLv3 License.
+#
+ #*************************************************************************
+
+####################################################################
+# File Name: template.pl
+# Version : 1.0
+# Project : XMERGE
+# Author : Brian Cameron
+# Date : 5th Sept. 2001
+#
+# This is just a useful script to use as a template to run
+# commands. Assumes that pose is already running.
+#
+##########################################################################
+
+use lib "$ENV{qa-dir}/lib";
+use converterlib;
+
+# Put commands to run between the open_connection() and
+# close_connection() calls...
+#
+open_connection();
+
+# command(s) go here.
+
+close_connection();
+
+
diff --git a/xmerge/source/palmtests/qa/bin/test_driver.pl b/xmerge/source/palmtests/qa/bin/test_driver.pl
new file mode 100755
index 000000000000..55d1d44f45d9
--- /dev/null
+++ b/xmerge/source/palmtests/qa/bin/test_driver.pl
@@ -0,0 +1,785 @@
+#!/usr/bin/perl
+#########################################################################
+
+ #*************************************************************************
+ #
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# Copyright 2000, 2010 Oracle and/or its affiliates.
+#
+# OpenOffice.org - a multi-platform office productivity suite
+#
+# This file is part of OpenOffice.org.
+#
+# OpenOffice.org is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License version 3
+# only, as published by the Free Software Foundation.
+#
+# OpenOffice.org is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License version 3 for more details
+# (a copy is included in the LICENSE file that accompanied this code).
+#
+# You should have received a copy of the GNU Lesser General Public License
+# version 3 along with OpenOffice.org. If not, see
+# <http://www.openoffice.org/license.html>
+# for a copy of the LGPLv3 License.
+#
+ #*************************************************************************
+
+####################################################################
+# File Name: test_driver.pl
+# Version : 1.0
+# Project : Xmerge
+# Author : Brian Cameron
+# Date : 5th Sept. 2001
+#
+# This script does the following:
+#
+# Processes the input file, and runs the tests specified in that
+# file. This will do the following for each test:
+#
+# 1. Convert a file from XML to PDB format
+# 2. Starts up the Palm OS emulator with the appropriate program
+# running and the converted file loaded the program.
+# 3. Makes automated changes as specified in the inputfile to
+# this script..
+# 4. Returns to the main applications window.
+#
+# Parameter
+# Filename to convert and change
+#
+##########################################################################
+
+# Turn on auto-flushing
+#
+$|=1;
+
+use EmRPC;
+
+# Directory where converterlib is located...
+#
+use lib "$ENV{qa-dir}/lib";
+use converterlib;
+
+#-------------------- Start of main script ------------------------------------
+
+# Environmental Settings
+
+$pose_exe = "$ENV{pose-dir}/pose/posedist/pose";
+$pose_prc = "$ENV{thirdpartyapps-dir}";
+$test_list = "";
+$infile = "";
+$merge_opt = 0;
+
+# You may need to change this from the default if your pose emulator
+# starts faster or slower than mine.
+#
+if ($ENV{'POSE_TIMEOUT'})
+{
+ $pose_timeout = "$ENV{'POSE_TIMEOUT'}";
+}
+else
+{
+ $pose_timeout = 15;
+}
+
+$cmdline_len = @ARGV;
+if ($cmdline_len <= 0)
+{
+ print_usage();
+ exit (0);
+}
+
+&process_cmdline(@ARGV);
+&print_env();
+&verify_env_options();
+
+# Make the output directories with timestamps included in the
+# directory names.
+#
+mkdir $pdb_orig, 0777 || die "can not create directory <$pdb_new>.";
+`chmod 777 $pdb_orig`;
+mkdir $pdb_new, 0777 || die "can not create directory <$pdb_new>.";
+`chmod 777 $pdb_new`;
+mkdir $xml_new, 0777 || die "can not create directory <$pdb_new>.";
+`chmod 777 $xml_new`;
+
+&verify_prcs_exist("DBExporter.prc");
+
+if ($test_list ne "")
+{
+ open (TESTLIST, $test_list) || die "Couldn't open testcase list file $test_list";
+
+ while (<TESTLIST>)
+ {
+ &process_testcase($_);
+ }
+}
+elsif ($infile ne "")
+{
+ &process_testcase($infile);
+}
+else
+{
+ die ("You didn't supply any test cases to process");
+}
+
+print "Finished.\n";
+exit(0);
+
+#-------------------- End of main script ----------------------------------------
+
+#--------------------------------------------------------------------------------
+# Various sub routines
+#--------------------------------------------------------------------------------
+
+# process_testcase
+# infile - test case file name
+#
+# This is the main driver function
+# Opens the infile, reads it in parses it, runs the appropriate conversion
+# starts pose and load the file into the emulator. It launches the
+# appropriate editor and then runs the commands specified in the test case.
+# It then exports the file and saves it locally. Finally it is converted
+# back to the original office format.
+#
+sub process_testcase
+{
+ my $infile = $_[0];
+ my $convert_file = "";
+ my $rc;
+
+ # Process the inputfile
+ #
+ open (INFILE, $infile) || die "Failed to open test case <$infile>";
+
+ $running_testtype = "";
+
+ # Process the input file.
+ #
+ while ($c_inline = <INFILE>)
+ {
+ chomp $c_inline;
+ @entry = split('\|', $c_inline);
+
+ # Process TEST
+ #
+ if ($c_inline =~ /^ *#/ || $c_inline =~ /^[ \t]*$/)
+ {
+ # skip comments and blank lines.
+ #
+ next;
+ }
+ elsif ("$entry[0]" eq "TEST")
+ {
+ # Close the test if one is running.
+ #
+ &close_program($convert_file);
+ $running_testtype = "";
+
+ $valid_test = 0;
+
+ if ($#entry != 3)
+ {
+ print "\nERROR, $entry[0] invalid number of arguments\n\n";
+ }
+ else
+ {
+ # Start the test.
+ #
+ print "\nStarting test: $entry[1]\n";
+ $convert_file = $entry[3];
+
+ if ("$entry[2]" =~ /[Qq][Uu][Ii][Cc][Kk][Ww][Oo][Rr][Dd]/)
+ {
+ $xml_extension = "sxw";
+ $convert_to = "doc";
+
+ # Convert XML file to pdb format.
+ #
+ $rc = &convert_to_pdb("$xml_orig", $convert_file, $xml_extension ,
+ $convert_to,"$pdb_orig");
+ if ($rc != 0)
+ {
+ print "\nERROR, problem converting file $convert_file\n\n";
+ }
+ else
+ {
+ # Start pose
+ #
+ $rc = &start_pose("$pose_exe",
+ "$pose_prc/Quickword.PRC,$pose_prc/DBExporter.prc,$pdb_orig/$convert_file.pdb",
+ "Quickword", $pose_timeout);
+
+ if ($rc == 0)
+ {
+ &start_quickword();
+ $valid_test = 1;
+ $running_testtype = "QUICKWORD";
+ print "\npose launched, begin automated test sequence for QuickWord\n";
+ }
+ else
+ {
+ &kill_pose();
+ $running_testtype = "";
+ }
+ }
+ }
+ elsif ("$entry[2]" =~ /[Mm][Ii][Nn][Ii][Cc][Aa][Ll][Cc]/)
+ {
+ $xml_extension = "sxc";
+ $convert_to = "minicalc";
+
+ # Convert XML file to pdb format.
+ #
+ $rc = &convert_to_pdb("$xml_orig", $convert_file,
+ $xml_extension, $convert_to,"$pdb_orig");
+ if ($rc != 0)
+ {
+ print "\nERROR, problem converting file $convert_file\n\n";
+ }
+ else
+ {
+ # Get minicalc PDB file names, since an SXC file can
+ # be converted to more than one.
+ #
+ $pdb_files="";
+ $i = 1;
+ while (-f "$pdb_orig/$convert_file-Sheet$i.pdb")
+ {
+ if ($i > 1)
+ {
+ $pdb_files .= ",";
+ }
+ $pdb_files .= "$pdb_orig/$convert_file-Sheet$i.pdb";
+ $i++;
+ }
+ $number = $i-1;
+
+ # Start pose
+ #
+ $rc = &start_pose("$pose_exe",
+ "$pose_prc/MiniCalc.prc,$pose_prc/DBExporter.prc,$pdb_files",
+ "MiniCalc", $pose_timeout);
+
+ if ($rc == 0)
+ {
+ &start_minicalc();
+ $valid_test = 1;
+ $running_testtype = "MINICALC";
+ print "pose launched, begin automated test sequence for MiniCalc\n";
+ }
+ else
+ {
+ &kill_pose();
+ $running_testtype = "";
+ }
+ }
+ }
+ else
+ {
+ print "\nERROR, invalid extension <$entry[2]>\n\n";
+ }
+ }
+ }
+
+ # Process DB_EXPORT
+ #
+ elsif ("$entry[0]" eq "DB_EXPORT")
+ {
+ if ($#entry != 1)
+ {
+ print "\nERROR, $entry[0] invalid number of arguments\n\n";
+ }
+ else
+ {
+ &db_export($entry[1]);
+ }
+ }
+
+ # Process TAP_APPLICATIONS
+ #
+ elsif ("$entry[0]" eq "TAP_APPLICATIONS")
+ {
+ if ($#entry != 0)
+ {
+ print "\nERROR, $entry[0] invalid number of arguments\n\n";
+ }
+ else
+ {
+ &tap_applications(0);
+ }
+ }
+
+ # Process ENTER_STRING_AT_LOCATION
+ #
+ elsif ("$entry[0]" eq "ENTER_STRING_AT_LOCATION")
+ {
+ if ($#entry != 3)
+ {
+ print "\nERROR, $entry[0] invalid number of arguments\n\n";
+ }
+ elsif ($valid_test == 0)
+ {
+ print "\nERROR, can not process $entry[0] for invalid test\n\n";
+ }
+ else
+ {
+ &enter_string_at_location($entry[1], $entry[2],
+ $entry[3], $running_testtype);
+ }
+ }
+
+ # Process TAP_PEN
+ #
+ elsif ("$entry[0]" eq "TAP_PEN")
+ {
+ if ($#entry != 2)
+ {
+ print "\nERROR, $entry[0] invalid number of arguments\n\n";
+ }
+ elsif ($valid_test == 0)
+ {
+ print "\nERROR, can not process $entry[0] for invalid test\n\n";
+ }
+ else
+ {
+ &pose_tap_pen($entry[1], $entry[2], 0);
+ }
+ }
+
+ # Process TAP_BUTTON
+ #
+ elsif ("$entry[0]" eq "TAP_BUTTON")
+ {
+ if ($#entry != 1)
+ {
+ print "\nERROR, $entry[0] invalid number of arguments\n\n";
+ }
+ elsif ($valid_test == 0)
+ {
+ print "\nERROR, can not process $entry[0] for invalid test\n\n";
+ }
+ else
+ {
+ &pose_tap_button($entry[1], 0);
+ }
+ }
+
+ # Process SLEEP
+ #
+ elsif ("$entry[0]" eq "SLEEP")
+ {
+ if ($#entry != 1)
+ {
+ print "\nERROR, $entry[0] invalid number of arguments\n\n";
+ }
+ else
+ {
+ &pose_sleep($entry[1]);
+ }
+ }
+
+ # Process MINICALC_ENTER_CELL
+ #
+ elsif ("$entry[0]" eq "MINICALC_ENTER_CELL")
+ {
+ if ($#entry != 3)
+ {
+ print "\nERROR, $entry[0] invalid number of arguments\n\n";
+ }
+ elsif ($valid_test == 0)
+ {
+ print "\nERROR, can not process $entry[0] for invalid test\n\n";
+ }
+ else
+ {
+ &minicalc_enter_cell($entry[1], $entry[2], $entry[3]);
+ }
+ }
+
+ # Process QUICKWORD_FIND_REPLACE
+ #
+ elsif ("$entry[0]" eq "QUICKWORD_FIND_REPLACE")
+ {
+ if ($#entry != 2)
+ {
+ print "\nERROR, $entry[0] invalid number of arguments\n\n";
+ }
+ elsif ($valid_test == 0)
+ {
+ print "\nERROR, can not process $entry[0] for invalid test\n\n";
+ }
+ else
+ {
+ &quickword_find_replace($entry[1], $entry[2]);
+ }
+ }
+ else
+ {
+ print "\nERROR, invalid line <$c_inline>\n";
+ }
+ }
+
+ &close_program($convert_file);
+}
+
+# close_program
+# convert_file - file to export
+#
+# closes the program running in pose and kills pose
+#
+sub close_program
+{
+ my $convert_file = $_[0];
+
+ if ($running_testtype eq "QUICKWORD")
+ {
+ print "QuickWord test completed.\n";
+ &close_program_quickword($convert_file);
+ }
+ elsif ($running_testtype eq "MINICALC")
+ {
+ print "MiniCalc test completed.\n";
+ &close_program_minicalc($convert_file, $number);
+ }
+}
+
+# close_program_quickword
+# convert_file - file to export
+#
+# Closes quickword and kills pose
+#
+sub close_program_quickword
+{
+ my $convert_file = $_[0];
+ my $error_file = "./error.txt";
+ my $rc;
+
+ &close_quickword();
+
+ &db_export($convert_file);
+ print "Moving /tmp/$convert_file.pdb to $pdb_new\n";
+ `mv /tmp/$convert_file.pdb $pdb_new`;
+ `chmod 666 $pdb_new/$convert_file.pdb`;
+
+ &close_connection(1);
+ &kill_pose();
+ print "\nFinishing test...\n";
+
+ # The path of where to put the error file should be specified
+ # in the properties file. Not sure if it is really necessary
+ # to put this out to a separate file. STDOUT should be fine.
+ #
+ $rc = &convert_to_xml($xml_new, $xml_orig,
+ "$pdb_new/$convert_file.pdb", "doc" ,
+ "sxw", $convert_file, $merge_opt);
+ if ($rc != 0)
+ {
+ print "\nERROR, problem converting file $pdb_new/$convert_file.pdb\n\n";
+ }
+}
+
+# close_program_minicalc
+# convert_file - file to export
+#
+# Closes minicalc and kills pose
+#
+sub close_program_minicalc
+{
+ my $convert_file = $_[0];
+ my $num_files = $_[1];
+ my $list="";
+ my $rc;
+
+ &close_minicalc();
+
+ for ($a=1; $a <= $num_files; $a++)
+ {
+ &db_export("$convert_file-Sheet$a");
+ print "Moving /tmp/$convert_file-Sheet$a.pdb to $pdb_new/\n";
+ `mv /tmp/$convert_file-Sheet$a.pdb $pdb_new/`;
+ `chmod 666 $pdb_new/$convert_file-Sheet$a.pdb`;
+ }
+
+ &close_connection(1);
+ &kill_pose();
+ print "\nFinishing test...\n";
+
+ for ($a=1; $a <= $num_files; $a++)
+ {
+ $list .="$pdb_new/$convert_file-Sheet$a.pdb "
+ }
+
+ $rc = &convert_to_xml($xml_new, $xml_orig, "$list",
+ "minicalc", "sxc", $convert_file, $merge_opt);
+ if ($rc != 0)
+ {
+ print "\nERROR, problem converting file(s) $list\n\n";
+ }
+
+ &pose_sleep(5);
+}
+
+# print_usage
+#
+# prints the usage for this program.
+#
+sub print_usage
+{
+ print "Usage : test_driver.pl\n";
+ print "\t-test=<file> \t\t: individual test case file to run\n";
+ print "\t-list=<file> \t\t: list of test case files\n";
+ print "\t-env=<file> \t\t: Properites like file defining env\n";
+ print "\t-pose-exe=<fullpath> \t: path to pose executable\n";
+ print "\t-pose-prc=<path> \t: path to directory holding prc files\n";
+ print "\t-pdb-orig=<path> \t: directory to hold original pdb files\n";
+ print "\t-pdb-new=<path> \t: directory to hold new pdb files\n";
+ print "\t-xml-orig=<path> \t: directory to hold original office documents\n";
+ print "\t-xml-new=<path> \t: directory to hold new office documents\n";
+ print "\t-merge \t: Invokes the merge option when converting\n";
+ print "\t \t from PDB back to XML.\n";
+}
+
+# print_env
+#
+# Prints the current environment.
+#
+sub print_env
+{
+ print "\nUsing the following environment:\n";
+ print "\tPOSE_EXE = $pose_exe\n";
+ print "\tPOSE_PRC = $pose_prc\n";
+ print "\tPDB_ORIG = $pdb_orig\n";
+ print "\tPDB_NEW = $pdb_new\n";
+ print "\tXML_ORIG = $xml_orig\n";
+ print "\tXML_NEW = $xml_new\n";
+}
+
+# process_cmdline
+#
+# command line options come in as key/value pairs.
+# read them and set the appropriate global variable
+#
+# Sets these globals: pose_exe, pose_prc, xml_orig, xml_new_dir,
+# xml_new, pdb_orig_dir, pdb_orig, pdb_new_dir, pdb_new.
+#
+sub process_cmdline
+{
+ my $lu_str = &get_date_string();
+
+ foreach $i (@_)
+ {
+ my @arg= split('=', $i);
+ @arg[0] =~ tr/A-Z/a-z/;
+
+ if (@arg[0] eq "-pose-exe")
+ {
+ $pose_exe=$arg[1];
+ }
+ elsif (@arg[0] eq "-pose-prc")
+ {
+ $pose_prc=$arg[1];
+ }
+ elsif (@arg[0] eq "-pdb-orig")
+ {
+ $pdb_orig_dir=$arg[1];
+ $pdb_orig=$arg[1];
+ $pdb_orig .= "/";
+ $pdb_orig .= "$lu_str";
+ }
+ elsif (@arg[0] eq "-pdb-new")
+ {
+ $pdb_new_dir=$arg[1];
+ $pdb_new=$arg[1];
+ $pdb_new .= "/";
+ $pdb_new .= "$lu_str";
+ }
+ elsif (@arg[0] eq "-xml-orig")
+ {
+ $xml_orig=$arg[1];
+ }
+ elsif (@arg[0] eq "-xml-new")
+ {
+ $xml_new_dir=$arg[1];
+ $xml_new=$arg[1];
+ $xml_new .= "/";
+ $xml_new .= "$lu_str";
+ }
+ elsif (@arg[0] eq "-env")
+ {
+ &set_env_from_props($arg[1]);
+ }
+ elsif (@arg[0] eq "-list")
+ {
+ $test_list = $arg[1];
+ }
+ elsif (@arg[0] eq "-test")
+ {
+ $infile = $arg[1];
+ }
+ elsif (@arg[0] eq "-merge")
+ {
+ $merge_opt = 1;
+ }
+ else
+ {
+ print_usage();
+ die "Incorrect command line";
+ }
+ }
+}
+
+# set_env_from_props
+# infile - property file
+#
+# Read the properties file, of the form key=value
+# Valid key values are :
+# POSE_EXE
+# POSE_PRC
+# POSE_PERL
+# TEST_HOME
+# PDB_ORIG
+# PDB_NEW
+# XML_ORIG
+# XML_NEW
+# If a value is found the appropriate global variable is set.
+#
+# Sets these globals: pose_exe, pose_prc, xml_orig, xml_new_dir,
+# xml_new, pdb_orig_dir, pdb_orig, pdb_new_dir, pdb_new.
+#
+sub set_env_from_props
+{
+ my $infile = $_[0];
+ my $lu_str = &get_date_string();
+
+ open(PROPSFILE, $infile) || die "Could not open properties file <$infile>";
+
+ while (<PROPSFILE>)
+ {
+ chomp $_;
+ my @arg = split('=', $_);
+ @arg[0] =~ tr/a-z/A-Z/;
+ my $len = @arg;
+ if ($len != 2)
+ {
+ die "Malformed property in $arg[0]";
+ }
+ if (@arg[0] eq "POSE_EXE")
+ {
+ $pose_exe=$arg[1];
+ }
+ elsif (@arg[0] eq "POSE_PRC")
+ {
+ $pose_prc=$arg[1];
+ }
+ elsif (@arg[0] eq "PDB_ORIG")
+ {
+ $pdb_orig_dir=$arg[1];
+ $pdb_orig=$arg[1];
+ $pdb_orig .= "/";
+ $pdb_orig .= "$lu_str";
+ }
+ elsif (@arg[0] eq "PDB_NEW")
+ {
+ $pdb_new_dir=$arg[1];
+ $pdb_new=$arg[1];
+ $pdb_new .= "/";
+ $pdb_new .= "$lu_str";
+ }
+ elsif (@arg[0] eq "XML_ORIG")
+ {
+ $xml_orig=$arg[1];
+ }
+ elsif (@arg[0] eq "XML_NEW")
+ {
+ $xml_new_dir=$arg[1];
+ $xml_new=$arg[1];
+ $xml_new .= "/";
+ $xml_new .= "$lu_str";
+ }
+
+ }
+ close PROPSFILE;
+}
+
+# verify_env_options
+#
+# Verify that input options are correctly set.
+# Assumes pose_exe, pose_prc, xml_orig, xml_new_dir,
+# pdb_orig_dir, and pdb_new_dir are already set.
+#
+sub verify_env_options
+{
+ if (!-e "$pose_exe")
+ {
+ die "The pose executable cannot be found at $pose_exe.";
+ }
+ if (!-x $pose_exe)
+ {
+ die "$pose_exe exists but is not executable.";
+ }
+
+ if (!-e "$pose_prc")
+ {
+ die "The PRC directory specified as $pose_prc does not exist.";
+ }
+ if (!-d "$pose_prc")
+ {
+ die "The PRC location specified as $pose_prc exists, but is not a directory.";
+ }
+
+ if (!-e "$pdb_orig_dir")
+ {
+ die "The original PDB directory specified as $pdb_orig_dir does not exist.";
+ }
+ if (!-d "$pdb_orig_dir")
+ {
+ die "The original PDB directory specified as $pdb_orig_dir exists but is not a directory.";
+ }
+
+ if (!-e "$pdb_new_dir")
+ {
+ die "The new PDB directory specified as $pdb_new_dir does not exist.";
+ }
+ if (!-d "$pdb_new_dir")
+ {
+ die "The new PDB directory specified as $pdb_new_dir exists but is not a directory.";
+ }
+
+ if (!-e "$xml_orig")
+ {
+ die "The original Office document directory specified as $xml_orig does not exist.";
+ }
+ if (!-d "$xml_orig")
+ {
+ die "The original Office document location specified as $xml_orig exists but is not a directory.";
+ }
+
+ if (!-e "$xml_new_dir")
+ {
+ die "The new Office document directory specified as $xml_new_dir does not exist.";
+ }
+ if (!-d "$xml_new_dir")
+ {
+ die "The new Office document location specified as $xml_new_dir exists but is not a directory.";
+ }
+}
+
+# verify_prcs_exist
+# prcfile - the PRC file to check
+#
+# Verifies that the specified PRC file exists.
+#
+sub verify_prcs_exist
+{
+ my $prcfile = $_[0];
+
+ if (!-e "$pose_prc/$prcfile")
+ {
+ die "The pose PRC directory ($pose_prc) is correct, but I can't find $prcfile there.";
+ }
+}
+
diff --git a/xmerge/source/palmtests/qa/comparator/OfficeZip.java b/xmerge/source/palmtests/qa/comparator/OfficeZip.java
new file mode 100644
index 000000000000..496949cf3d17
--- /dev/null
+++ b/xmerge/source/palmtests/qa/comparator/OfficeZip.java
@@ -0,0 +1,241 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+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 OfficeDocument to handle zip reading and writing,
+ * as well as storing zip entries.
+ *
+ * @author Herbie Ong
+ */
+
+class OfficeZip {
+
+ /** file name of the xml file in a zipped document. */
+ private final static String XMLFILE = "content.xml";
+
+ private final static int BUFFERSIZE = 1024;
+
+ private List entryList = null;
+
+ private int contentIndex = -1;
+
+ private String filename = null;
+
+ private class Entry {
+
+ ZipEntry zipEntry = null;
+ byte bytes[] = null;
+ }
+
+ /**
+ * Constructor
+ *
+ * @param filename Full Path to Zip file to process
+ *
+ */
+ public OfficeZip(String filename) {
+ this.filename = filename;
+ }
+
+
+ /**
+ * Read each zip entry in the given InputStream object
+ * and store in entryList both the ZipEntry object as well
+ * as the bits of each entry. Return the bytes for the
+ * entry of XMLFILE.
+ *
+ * @param is InputStream object to read from
+ * @return byte[] byte array of XML file
+ * @throws IOException if any I/O error occurs
+ */
+
+ byte[] read(InputStream is) throws IOException {
+
+ ZipInputStream zis = new ZipInputStream(is);
+ ZipEntry ze = null;
+ int i = -1;
+
+ entryList = new LinkedList();
+
+ while ((ze = zis.getNextEntry()) != null) {
+
+ String name = ze.getName();
+
+ Entry entry = new Entry();
+ entry.zipEntry = ze;
+
+ Debug.log(Debug.TRACE, "reading entry: " + name);
+
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+
+ int len = 0;
+ byte bytes[] = new byte[BUFFERSIZE];
+
+ while ((len = zis.read(bytes)) > 0) {
+ baos.write(bytes, 0, len);
+ }
+
+ entry.bytes = baos.toByteArray();
+
+ entryList.add(entry);
+
+ i++;
+
+ if (isContentXML(name)) {
+ contentIndex = i;
+ }
+ }
+
+ if (contentIndex == -1) {
+ throw new IOException(XMLFILE + " not found.");
+ }
+
+ Entry contentEntry = (Entry) entryList.get(contentIndex);
+
+ return contentEntry.bytes;
+ }
+
+ /**
+ * Write out the XMLFILE as a zip into the OutputStream object.
+ *
+ * If a zip inputstream was previously read, then use
+ * those zip contents to recreate the zip, except for XMLFILE,
+ * update it using the new content from xmlBytes.
+ *
+ * If there was no zip inputstream previously read, write
+ * XMLFILE out into the zip outputstream.
+ *
+ * @param os OutputStream object to write zip
+ * @param xmlBytes bytes of XMLFILE
+ * @throws IOException if any I/O errors occur.
+ */
+
+ void write(OutputStream os, byte xmlBytes[]) throws IOException {
+
+ ZipOutputStream zos = new ZipOutputStream(os);
+
+ // if read was not invoked previously, store the bytes directly.
+ if (contentIndex == -1) {
+
+ Debug.log(Debug.TRACE, "Writing out " + XMLFILE + " into zip.");
+
+ ZipEntry ze = new ZipEntry(XMLFILE);
+ ze.setSize(xmlBytes.length);
+
+ CRC32 crc = new CRC32();
+ crc.reset();
+ crc.update(xmlBytes);
+ ze.setCrc(crc.getValue());
+
+ ze.setTime(System.currentTimeMillis());
+ ze.setMethod(ZipEntry.DEFLATED);
+
+ zos.putNextEntry(ze);
+ zos.write(xmlBytes);
+
+ } else {
+
+ saveEntries(zos, xmlBytes);
+ }
+
+ zos.close();
+ }
+
+ /**
+ * Used by write method if there was a zip inputstream
+ * previously read. It would write out each ZipEntry of
+ * the previously read zip, except for XMLFILE, it would
+ * update it with new values and with the content from
+ * xmlBytes.
+ *
+ * @param os OutputStream object to write zip
+ * @param xmlBytes bytes of XMLFILE
+ * @throws ZipException if any zip I/O errors occur.
+ */
+
+ private void saveEntries(ZipOutputStream zos, byte xmlBytes[])
+ throws IOException {
+
+ Debug.log(Debug.TRACE, "Writing out the following entries into zip.");
+
+ ListIterator iterator = entryList.listIterator();
+
+ while (iterator.hasNext()) {
+
+ Entry entry = (Entry) iterator.next();
+ ZipEntry ze = entry.zipEntry;
+
+ String name = ze.getName();
+
+ Debug.log(Debug.TRACE, "... " + name);
+
+ if (isContentXML(name)) {
+
+ // set new values for this ZipEntry
+
+ ZipEntry zipEntry = new ZipEntry(name);
+
+ zipEntry.setMethod(ze.getMethod());
+ zipEntry.setSize(xmlBytes.length);
+
+ CRC32 crc = new CRC32();
+ crc.reset();
+ crc.update(xmlBytes);
+ zipEntry.setCrc(crc.getValue());
+
+ zipEntry.setTime(System.currentTimeMillis());
+
+ zos.putNextEntry(zipEntry);
+ zos.write(xmlBytes);
+
+ } else {
+
+ zos.putNextEntry(ze);
+ zos.write(entry.bytes);
+ }
+ }
+ }
+
+ private boolean isContentXML(String name) {
+
+ String lname = name.toLowerCase();
+ return lname.equals(XMLFILE);
+ }
+}
diff --git a/xmerge/source/palmtests/qa/comparator/PDBDecoder.java b/xmerge/source/palmtests/qa/comparator/PDBDecoder.java
new file mode 100644
index 000000000000..8f4dec82f4b5
--- /dev/null
+++ b/xmerge/source/palmtests/qa/comparator/PDBDecoder.java
@@ -0,0 +1,135 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+
+import java.io.RandomAccessFile;
+import java.io.IOException;
+
+
+/**
+ * <p>Provides functionality to decode a pdb formatted file into
+ * a <code>PalmDB</code> object given a file input stream</p>
+ *
+ * <p>Sample usage:</p>
+ *
+ * <p><blockquote><pre>
+ * PDBDecoder decoder = new PDBDecoder("sample.pdb");
+ * PalmDB palmDB = decoder.parse();
+ * </pre></blockquote></p>
+ *
+ * <p>Refer to the
+ * <a href="http://starlite.eng/zensync/eng/converters/palmfileformats.pdf">
+ * Palm file format specification</a> for details on the pdb format.</p>
+ *
+ * <p>This decoder has the following assumptions on the pdb file ...</p>
+ * <ol>
+ * <li><p>There is only one RecordList section in the pdb.</p></li>
+ * <li><p>The record indices in the RecordList are sorted in order, i.e. the
+ * first record index refers to record 0, and so forth.</p></li>
+ * <li><p>The raw records in the record section are sorted as well in order,
+ * i.e. first record comes ahead of second record, etc.</p></li>
+ * </ol>
+ *
+ * Other decoders assume these as well.
+ *
+ * @author Herbie Ong
+ * @see PalmDB
+ * @see PDBHeader
+ *
+ * @author Herbie Ong
+ */
+
+public final class PDBDecoder {
+
+ /**
+ * <p>This method decodes a pdb file into a PalmDB object.</p>
+ *
+ * <p>First, read in the header data using <code>PDBHeader</code>'s
+ * <code>read</code> method</p>. Next, read in the record list
+ * section. Store the record offsets for use when parsing the records.
+ * Based on these offsets, read in each record's bytes and store
+ * each in a <code>Record</code> object. Lastly, create a
+ * <code>PalmDB</code> object with the read in <code>Record</code>s.
+ *
+ * @param fileName pdb file name
+ * @throws IOException if I/O error occurs
+ */
+
+ public PalmDB parse(String fileName) throws IOException {
+
+ RandomAccessFile file = new RandomAccessFile(fileName, "r");
+
+ // read the pdb header
+ PDBHeader header = new PDBHeader();
+ header.read(file);
+
+ Record recArray[] = new Record[header.numRecords];
+
+ if (header.numRecords != 0) {
+
+ // read in the record indices + offsets
+
+ int recOffset[] = new int[header.numRecords];
+
+ for (int i = 0; i < header.numRecords; i++) {
+
+ recOffset[i] = file.readInt();
+ int attr = file.readInt(); // read in attribute.
+ }
+
+ // read the records
+
+ int len = 0;
+ byte[] bytes = null;
+
+ int lastIndex = header.numRecords - 1;
+
+ for (int i = 0; i < lastIndex; i++) {
+
+ file.seek(recOffset[i]);
+ len = recOffset[i+1] - recOffset[i];
+ bytes = new byte[len];
+ file.readFully(bytes);
+ recArray[i] = new Record(bytes);
+ }
+
+ // last record
+ file.seek(recOffset[lastIndex]);
+ len = (int) file.length() - recOffset[lastIndex];
+ bytes = new byte[len];
+ file.readFully(bytes);
+ recArray[lastIndex] = new Record(bytes);
+ }
+
+ file.close();
+
+ // create PalmDB and return it
+ PalmDB pdb = new PalmDB(header.pdbName, recArray);
+ return pdb;
+ }
+}
+
diff --git a/xmerge/source/palmtests/qa/comparator/PDBHeader.java b/xmerge/source/palmtests/qa/comparator/PDBHeader.java
new file mode 100644
index 000000000000..216fd8bd9351
--- /dev/null
+++ b/xmerge/source/palmtests/qa/comparator/PDBHeader.java
@@ -0,0 +1,153 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+
+/**
+ * <p>Class used only internally by <code>PDBEncoder</code> and
+ * <code>PDBDecoder</code> to store, read and write a pdb header.</p>
+ *
+ * <p>Note that fields are intended to be accessible only at the
+ * package level.</p>
+ *
+ * <p>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</code> and <code>write</code> methods should
+ * handle them properly.</p>
+ *
+ * @author Herbie Ong
+ */
+
+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 */
+ long lastBackupDate = 0;
+
+ /**
+ * incremented every time a record is
+ * added, deleted or modified. Palm UInt32.
+ */
+ long modificationNumber = 0;
+
+ /** optional field. Palm UInt32. Unsignedness should be irrelevant. */
+ int appInfoID = 0;
+
+ /** optional field. Palm UInt32. Unsignedness should be irrelevant. */
+ 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;
+
+ /** ??? */
+ int uniqueIDSeed = 0;
+
+ /** see numRecords. 4 bytes. */
+ int nextRecordListID = 0;
+
+ /**
+ * number of records stored in the database header.
+ * If all the record entries cannot fit in the header,
+ * then nextRecordList has the local ID of a
+ * recordList that contains the next set of records.
+ * 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 di a DataInput object
+ * @throws IOException if 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 = ((long) in.readInt()) & 0xffffffffL;
+ modificationDate = ((long) in.readInt()) & 0xffffffffL;
+ lastBackupDate = ((long) in.readInt()) & 0xffffffffL;
+ modificationNumber = ((long) 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 DataOut object
+ * @throws IOException if 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);
+ }
+}
+
diff --git a/xmerge/source/palmtests/qa/comparator/PDBUtil.java b/xmerge/source/palmtests/qa/comparator/PDBUtil.java
new file mode 100644
index 000000000000..bdf8a07d9360
--- /dev/null
+++ b/xmerge/source/palmtests/qa/comparator/PDBUtil.java
@@ -0,0 +1,100 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+/**
+ * Contains common static methods and contants for use within the package.
+ *
+ * @author Herbie Ong
+ */
+
+public final class PDBUtil {
+
+ /** difference in seconds from Jan 01, 1904 to Jan 01, 1970 */
+ final static long TIME_DIFF = 2082844800;
+
+ /** encoding scheme used */
+ final static String ENCODING = "8859_1";
+
+ /** size of a pdb header in bytes */
+ final static int HEADER_SIZE = 78;
+
+ /**
+ * This method converts a 4 letter string into the Palm ID integer.
+ *
+ * It is normally used to convert the Palm creator ID string into
+ * the integer version of it. Also use for data types, etc.
+ *
+ * @param s 4 character string.
+ * @return int Palm ID representing the string.
+ * @throws ArrayIndexOutOfBoundsException if string parameter
+ * contains less than 4 characters.
+ */
+
+ public static int intID(String s) {
+
+ int id = -1;
+ int temp = 0;
+
+ // grab the first char and put it in the high bits
+ // note that we only want 8 lower bits of it.
+ temp = (int) s.charAt(0);
+ id = temp << 24;
+
+ // grab the second char and add it in.
+ temp = ((int) s.charAt(1)) & 0x00ff;
+ id += temp << 16;
+
+ // grab the second char and add it in.
+ temp = ((int) s.charAt(2)) & 0x00ff;
+ id += temp << 8;
+
+ // grab the last char and add it in
+ id += ((int) s.charAt(3)) & 0x00ff;
+
+ return id;
+ }
+
+ /**
+ * This method converts an integer into a String given
+ * the Palm ID format.
+ *
+ * @param i Palm id.
+ * @return String string representation.
+ */
+
+ public static String stringID(int i) {
+
+ char ch[] = new char[4];
+ ch[0] = (char) (i >>> 24);
+ ch[1] = (char) ((i >> 16) & 0x00ff);
+ ch[2] = (char) ((i >> 8) & 0x00ff);
+ ch[3] = (char) (i & 0x00ff);
+
+ return new String(ch);
+ }
+}
+
diff --git a/xmerge/source/palmtests/qa/comparator/PalmDB.java b/xmerge/source/palmtests/qa/comparator/PalmDB.java
new file mode 100644
index 000000000000..e15e7fefa5ff
--- /dev/null
+++ b/xmerge/source/palmtests/qa/comparator/PalmDB.java
@@ -0,0 +1,348 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+import java.io.OutputStream;
+import java.io.InputStream;
+import java.io.DataOutputStream;
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+
+/**
+ * <p>This class contains data for a single Palm database for use during
+ * a conversion process.</p>
+ *
+ * <p>It contains zero or more <code>Record</code> objects stored in an
+ * array. The index of the <code>Record</code> object in the array is
+ * the record id or number for that specific <code>Record</code> object.
+ * Note that this class does not check for maximum number of records
+ * allowable in an actual pdb.</p>
+ *
+ * <p>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).</p>
+ *
+ * <p>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</code> or <code>byte[]</code> are converted to an exact
+ * <code>NAME_LENGTH</code> byte array. If the length of the name is less
+ * than <code>NAME_LENGTH</code>, it is padded with '\0' characters. If it
+ * is more, it gets truncated. The last character in the resulting byte
+ * array is always a '\0' character. The resulting byte array is stored in
+ * <code>bName</code>, and a corresponding String object <code>sName</code>
+ * that contains characters without the '\0' characters.</p>
+ *
+ * <p>The {@link #write write} method is called within the
+ * {@link zensync.util.palm.PalmDBSet#write PalmDBSet.write} method
+ * for writing out its data to the <code>OutputStream</code> object.</p>
+ *
+ * <p>The {@link #read read} method is called within the
+ * {@link zensync.util.palm.PalmDBSet#read PalmDBSet.read} method
+ * for reading in its data from the <code>InputStream</code> object.</p>
+ *
+ * @author Akhil Arora, Herbie Ong
+ * @see PalmDBSet
+ * @see Record
+ */
+
+public final class PalmDB {
+
+ /** number of bytes for the name field in the pdb */
+ public final static int NAME_LENGTH = 32;
+
+ /** list of Record objects */
+ private Record[] records;
+
+ /** pdb name in bytes */
+ private byte[] bName = null;
+
+ /** pdb name in String */
+ private String sName = null;
+
+
+ /**
+ * Default constructor for use after a read().
+ */
+
+ public PalmDB() {
+
+ records = new Record[0];
+ }
+
+ /**
+ * Constructor to create object with Record objects.
+ * recs.length can be zero for an empty pdb.
+ *
+ * @param name suggested pdb name in String
+ * @param recs array of Record objects
+ * @throws NullPointerException if recs is null
+ */
+
+ public PalmDB(String name, Record[] recs)
+ throws UnsupportedEncodingException {
+
+ this(name.getBytes(PDBUtil.ENCODING), recs);
+ }
+
+ /**
+ * Constructor to create object with Record objects.
+ * recs.length can be zero for an empty pdb.
+ *
+ * @param name suggested pdb name in byte array
+ * @param recs array of Record objects
+ * @throws NullPointerException if recs is null
+ */
+
+ public PalmDB(byte[] name, Record[] recs)
+ throws UnsupportedEncodingException {
+
+ store(name);
+
+ records = new Record[recs.length];
+ System.arraycopy(recs, 0, records, 0, recs.length);
+ }
+
+ /**
+ * This private method is mainly used by the constructors above.
+ * to store bytes into name and also create a String representation.
+ * and also by the read method.
+ *
+ * TODO: Note that this method assumes that the byte array parameter
+ * contains one character per byte, else it would truncate
+ * improperly.
+ *
+ * @param bytes pdb name in 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);
+ }
+
+ /**
+ * Return the number of records contained in this
+ * pdb PalmDB object.
+ *
+ * @return int number of Record objects
+ */
+
+ public int getRecordCount() {
+
+ return records.length;
+ }
+
+ /**
+ * Return the specific Record object associated
+ * with the record number.
+ *
+ * @param index record index number
+ * @return Record the 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 Record objects
+ *
+ * @return Record[] the list of Record objects
+ */
+
+ public Record[] getRecords() {
+
+ return records;
+ }
+
+ /**
+ * Return the PDBName associated with this object in String
+ *
+ * @return String pdb name in String
+ */
+
+ public String getPDBNameString() {
+
+ return sName;
+ }
+
+ /**
+ * Return the PDBName associated with this object
+ * in byte array of exact length of 32 bytes.
+ *
+ * @return byte[] pdb name in byte[] of length 32.
+ */
+
+ public byte[] getPDBNameBytes() {
+
+ return bName;
+ }
+
+ /**
+ * Write out the number of records followed by what
+ * will be written out by each Record object.
+ *
+ * @param os the stream to write the object to
+ * @throws IOException if any I/O error occurs
+ */
+
+ public void write(OutputStream os) throws IOException {
+
+ DataOutputStream out = new DataOutputStream(os);
+
+ // write out pdb name
+ out.write(bName);
+
+ // write out 2 bytes for number of records
+ out.writeShort(records.length);
+
+ // let each Record object write out its own info.
+ for (int i = 0; i < records.length; i++)
+ records[i].write(out);
+ }
+
+ /**
+ * Read the necessary data to create a pdb from
+ * the input stream.
+ *
+ * @param is the stream to read data from in order
+ * to restore the object
+ * @throws IOException if any I/O error occurs
+ */
+
+ public void read(InputStream is) throws IOException {
+
+ DataInputStream in = new DataInputStream(is);
+
+ // read in the pdb name.
+ byte[] bytes = new byte[NAME_LENGTH];
+ in.readFully(bytes);
+ store(bytes);
+
+ // read in number of records
+ int nrec = in.readUnsignedShort();
+ records = new Record[nrec];
+
+ // read in the Record infos
+ for (int i = 0; i < nrec; i++) {
+
+ records[i] = new Record();
+ records[i].read(in);
+ }
+ }
+
+ /**
+ * Override equals method of Object.
+ *
+ * 2 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 PalmDB object to compare with
+ * @return boolean true if obj is equal to this, else false.
+ */
+
+ 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;
+ }
+}
diff --git a/xmerge/source/palmtests/qa/comparator/README b/xmerge/source/palmtests/qa/comparator/README
new file mode 100644
index 000000000000..ad08e7592d0d
--- /dev/null
+++ b/xmerge/source/palmtests/qa/comparator/README
@@ -0,0 +1,10 @@
+Building the Comparator code
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+To build the comparator code, the following is required in your classpath.
+
+ xerces.jar
+ xmerge.jar
+
+To Build type
+
+ javac *.java
diff --git a/xmerge/source/palmtests/qa/comparator/Record.java b/xmerge/source/palmtests/qa/comparator/Record.java
new file mode 100644
index 000000000000..f506f1a2b190
--- /dev/null
+++ b/xmerge/source/palmtests/qa/comparator/Record.java
@@ -0,0 +1,165 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+import java.io.OutputStream;
+import java.io.InputStream;
+import java.io.DataOutputStream;
+import java.io.DataInputStream;
+import java.io.IOException;
+
+/**
+ * <p>Contains the raw bytes for a record in a pdb.</p>
+ *
+ * <p>Note that it is not associated with a record number or id.</p>
+ *
+ * @author Akhil Arora, Herbie Ong
+ * @see PalmDB
+ */
+
+
+public final class Record {
+
+ /** record bytes */
+ private byte[] data;
+
+ /**
+ * Default constructor.
+ */
+
+ public Record() {
+
+ data = new byte[0];
+ }
+
+ /**
+ * Constructor to create a Record filled with bytes.
+ * Note that this does not check for 64k record sizes.
+ * User of this class has to check for that.
+ *
+ * @param d byte array contents for this object.
+ */
+
+ public Record(byte[] d) {
+
+ data = new byte[d.length];
+ System.arraycopy(d, 0, data, 0, d.length);
+ }
+
+ /**
+ * This method returns the number of bytes in this object.
+ *
+ * @return int number of bytes in this object.
+ */
+
+ public int getSize() {
+
+ return data.length;
+ }
+
+ /**
+ * This method returns the contents of this object.
+ *
+ * @return byte[] contents in byte array
+ */
+
+ public byte[] getBytes() {
+
+ return data;
+ }
+
+ /**
+ * Write out the record length followed by the data
+ * in this Record object.
+ *
+ * @param out the stream to write the object to
+ * @throws IOException if any I/O error occurs
+ */
+
+
+ public void write(OutputStream outs) throws IOException {
+
+ DataOutputStream out = new DataOutputStream(outs);
+ out.writeShort(data.length);
+ out.write(data);
+ }
+
+ /**
+ * Read the necessary data to create a pdb from
+ * the input stream.
+ *
+ * @param in the stream to read data from in order to
+ * restore the object
+ * @throws IOException if any I/O error occurs
+ */
+
+ public void read(InputStream ins) throws IOException {
+
+ DataInputStream in = new DataInputStream(ins);
+ int len = in.readUnsignedShort();
+ data = new byte[len];
+ in.readFully(data);
+ }
+
+ /**
+ * Override equals method of Object.
+ *
+ * 2 Record objects are equal if they contain the same bytes
+ * in the array.
+ *
+ * This is used primarily for testing purposes only for now.
+ *
+ * @param obj a Record object to compare with
+ * @return boolean true if obj is equal to this, else false.
+ */
+
+ public boolean equals(Object obj) {
+
+ boolean bool = false;
+
+ if (obj instanceof Record) {
+
+ Record rec = (Record) obj;
+
+ checkLabel: {
+
+ if (rec.getSize() == data.length) {
+
+ for (int i = 0; i < data.length; i++) {
+
+ if (data[i] != rec.data[i]) {
+ break checkLabel;
+ }
+ }
+
+ bool = true;
+ }
+ }
+ }
+
+ return bool;
+ }
+}
diff --git a/xmerge/source/palmtests/qa/comparator/SimplePdbCompare.java b/xmerge/source/palmtests/qa/comparator/SimplePdbCompare.java
new file mode 100644
index 000000000000..da01306d9545
--- /dev/null
+++ b/xmerge/source/palmtests/qa/comparator/SimplePdbCompare.java
@@ -0,0 +1,94 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+/*
+ * SimplePdbCompare.java
+ *
+ * Created on September 21, 2001, 10:23 AM
+ */
+
+/**
+ *
+ * @author mh101528
+ * @version
+ */
+public final class SimplePdbCompare {
+
+ /** Creates new SimplePdbCompare */
+ public SimplePdbCompare() {
+ }
+
+ /**
+ * @param args the command line arguments
+ */
+ public static void main (String args[])
+ {
+ SimplePdbCompare comparator = new SimplePdbCompare();
+ if (comparator.comparePDB(args[0], args[1]))
+ System.exit(2);
+ else
+ System.exit(3);
+ }
+
+ public boolean comparePDB(String pdbname1, String pdbname2)
+ {
+ PalmDB pdb1=null, pdb2=null;
+ PDBDecoder decoder = new PDBDecoder();
+ try
+ {
+ pdb1 = decoder.parse(pdbname1);
+ }
+ catch (Exception e)
+ {
+ System.out.println("Could not parse PDB " + pdbname1);
+ return false;
+ }
+
+ try
+ {
+ pdb2 = decoder.parse(pdbname2);
+ }
+ catch (Exception e)
+ {
+ System.out.println("Could not parse PDB " + pdbname2);
+ return false;
+ }
+
+ if (pdb1.equals(pdb2))
+ {
+ //writeToLog("PDB " + pdbname1 + " and PDB " + pdbname2 + " are equal");
+ System.out.println("PDB " + pdbname1 + " and PDB " + pdbname2 + " are equal");
+ return true;
+ }
+ else
+ {
+ //writeToLog("PDB " + pdbname1 + " and PDB " + pdbname2 + " are not equal");
+ System.out.println("PDB " + pdbname1 + " and PDB " + pdbname2 + " are not equal");
+ return false;
+ }
+ }
+}
diff --git a/xmerge/source/palmtests/qa/comparator/XmlDiff.java b/xmerge/source/palmtests/qa/comparator/XmlDiff.java
new file mode 100644
index 000000000000..d592609d18f3
--- /dev/null
+++ b/xmerge/source/palmtests/qa/comparator/XmlDiff.java
@@ -0,0 +1,464 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+import java.io.FileWriter;
+import java.io.InputStream;
+import java.io.FileInputStream;
+import java.io.BufferedInputStream;
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.io.FileNotFoundException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+import java.io.PrintWriter;
+import java.util.Vector;
+import java.util.Properties;
+
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.w3c.dom.Node;
+import org.w3c.dom.Document;
+import org.w3c.dom.NodeList;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
+/**
+ * This class will diff 2 Xml files.
+ *
+ * @author Stephen Mak
+ */
+
+public final class XmlDiff {
+
+ private static final String PROPSFILE = "XmlDiff.properties";
+ private static final String FILE1 = "XmlDiff.file1";
+ private static final String FILE2 = "XmlDiff.file2";
+ private static final String OUTPUT= "XmlDiff.output";
+ private static final String IGNORE_TAGS= "XmlDiff.tags";
+
+ private Properties props_ = null;
+ private static PrintWriter writer_ = null;
+ private String[] tags_ = null;
+ private String file1_ = null;
+ private String file2_ = null;
+
+ /**
+ * Constructor. Load the properties file.
+ */
+
+ public XmlDiff() throws IOException {
+
+ Class c = this.getClass();
+ InputStream is = c.getResourceAsStream(PROPSFILE);
+ BufferedInputStream bis = new BufferedInputStream(is);
+ props_ = new Properties();
+ props_.load(bis);
+ bis.close();
+
+ String file1 = props_.getProperty(FILE1, "");
+ String file2 = props_.getProperty(FILE2, "");
+ String tagsString = props_.getProperty(IGNORE_TAGS, "");
+ String output = props_.getProperty("debug.output", "System.out");
+ setOutput(output);
+ tags_ = parseTags(tagsString);
+ }
+
+ /**
+ * diff 2 xml, but overwrite the property file's file1/2 setting with
+ * the input argument
+ */
+ public boolean diff(String file1, String file2) throws IOException {
+ file1_ = file1;
+ file2_ = file2;
+ return diff();
+ }
+
+ public boolean diff() throws IOException {
+
+ boolean result = false;
+
+ writer_.println("parsing "+ file1_ + "...");
+ // parse the Xml file
+ Document doc1 = parseXml(file1_);
+
+ writer_.println("parsing "+ file1_ + "...");
+ Document doc2 = parseXml(file2_);
+
+ if (doc1 != null && doc2 != null) {
+ writer_.println("diffing "+ file1_ + " & " + file2_ + "...");
+ result = compareNode(doc1, doc2);
+ }
+ return result;
+ }
+
+ private void diffLog(String errMsg, Node node1, Node node2) {
+
+ String node1Str = "";
+ String node2Str = "";
+
+ if (node1 != null) {
+ node1Str = "[Type]:" + nodeInfo(node1) +
+ " [Name]:" + node1.getNodeName();
+ if (node1.getNodeValue() != null)
+ node1Str += " [Value]:" + node1.getNodeValue();
+ }
+
+ if (node2 != null) {
+ node2Str = "[Type]:" + nodeInfo(node2) +
+ " [Name]:" + node2.getNodeName();
+ if (node2.getNodeValue() != null)
+ node2Str += " [Value]:" + node2.getNodeValue();
+ }
+
+ writer_.println(errMsg);
+ writer_.println(" Node1 - " + node1Str);
+ writer_.println(" Node2 - " + node2Str);
+ }
+
+ private String nodeInfo(Node node) {
+
+ String str = null;
+ switch (node.getNodeType()) {
+
+ case Node.ELEMENT_NODE:
+ str = "ELEMENT";
+ break;
+ case Node.ATTRIBUTE_NODE:
+ str = "ATTRIBUTE";
+ break;
+ case Node.TEXT_NODE:
+ str = "TEXT";
+ break;
+ case Node.CDATA_SECTION_NODE:
+ str = "CDATA_SECTION";
+ break;
+ case Node.ENTITY_REFERENCE_NODE:
+ str = "ENTITY_REFERENCE";
+ break;
+ case Node.ENTITY_NODE:
+ str = "ENTITY";
+ break;
+ case Node.PROCESSING_INSTRUCTION_NODE:
+ str = "PROCESSING_INSTRUCTION";
+ break;
+ case Node.COMMENT_NODE:
+ str = "COMMENT";
+ break;
+ case Node.DOCUMENT_NODE:
+ str = "DOCUMENT";
+ break;
+ case Node.DOCUMENT_TYPE_NODE:
+ str = "DOCUMENT_TYPE";
+ break;
+ case Node.DOCUMENT_FRAGMENT_NODE:
+ str = "DOCUMENT_FRAGMENT";
+ break;
+ case Node.NOTATION_NODE:
+ str = "NOTATION";
+ break;
+ }
+ return str;
+ }
+
+ private boolean ignoreTag(String nodeName) {
+
+
+ if (tags_ != null) {
+ for (int i = 0; i < tags_.length; i++) {
+ if (tags_[i].equals(nodeName))
+ return true;
+ }
+ }
+ return false;
+ }
+
+ // for future use if we want to compare attributes
+ private boolean attributesEqual(Node node1, Node node2) {
+ return true;
+ }
+
+ private boolean compareNode(Node node1, Node node2) {
+ boolean equal = false;
+
+ while (true) {
+
+ if (node1 == null && node2 == null) {
+ equal = true;
+ break;
+ } else if (node1 == null || node2 == null) {
+ diffLog("DIFF: one of the node is null", node1, node2);
+ break;
+ }
+
+ if (node1.getNodeType() != node2.getNodeType()) {
+ diffLog("DIFF: nodetype is different", node1, node2);
+ break;
+ }
+
+ if (node1.getNodeName() == null && node2.getNodeName() == null) {
+ // empty
+ } else if (node1.getNodeName() == null ||
+ node2.getNodeName() == null) {
+ diffLog("DIFF: one of the nodeName is null", node1, node2);
+ break;
+ } else if (!node1.getNodeName().equals(node2.getNodeName())) {
+ diffLog("DIFF: nodeName is different", node1, node2);
+ break;
+ }
+
+ if (ignoreTag(node1.getNodeName())) {
+ diffLog("DIFF: Some tag(s) is ignored", node1, node2);
+ equal = true;
+ break;
+ }
+
+ if (node1.getNodeValue() == null && node2.getNodeValue() == null) {
+ // empty
+ } else if (node1.getNodeValue() == null ||
+ node2.getNodeValue() == null) {
+ diffLog("DIFF: one of the nodevalue is null", node1, node2);
+ break;
+ } else if (!node1.getNodeValue().equals(node2.getNodeValue())) {
+ diffLog("DIFF: nodeValue is different", node1, node2);
+ break;
+ }
+
+ // try to compare attributes if necessary
+ if (!attributesEqual(node1, node2))
+ break;
+
+ NodeList node1Children = node1.getChildNodes();
+ NodeList node2Children = node2.getChildNodes();
+
+ // number of children have to be the same
+ if (node1Children == null && node2Children == null) {
+ equal = true;
+ break;
+ }
+
+ if (node1Children == null || node2Children == null) {
+ diffLog("DIFF: one node's children is null", node1, node2);
+ break;
+ }
+
+ if (node1Children.getLength() != node2Children.getLength()) {
+ diffLog("DIFF: num of children is different", node1, node2);
+ break;
+ }
+
+ // compare all the childrens
+ equal = true;
+
+ for (int i = 0; i < node1Children.getLength(); i++) {
+ if (!compareNode(node1Children.item(i),
+ node2Children.item(i))) {
+ equal = false;
+ break;
+ }
+ }
+ break;
+ }
+
+ return equal;
+ }
+
+ private Document parseXml (String filename) throws IOException {
+
+ Document w3cDocument = null;
+
+ FileInputStream fis;
+
+ try {
+ fis = new FileInputStream(filename);
+ } catch (FileNotFoundException ex) {
+ ex.printStackTrace(writer_);
+ writer_.println(ex.getMessage());
+ return w3cDocument;
+ }
+
+ /** factory for DocumentBuilder objects */
+ DocumentBuilderFactory factory = null;
+ factory = DocumentBuilderFactory.newInstance();
+ factory.setNamespaceAware(true);
+ factory.setValidating(false);
+
+ /** DocumentBuilder object */
+ DocumentBuilder builder = null;
+
+ try {
+ builder = factory.newDocumentBuilder();
+ } catch (ParserConfigurationException ex) {
+ ex.printStackTrace(writer_);
+ writer_.println(ex.getMessage());
+ return null;
+ }
+
+
+ builder.setErrorHandler(
+ new org.xml.sax.ErrorHandler() {
+ // ignore fatal errors (an exception is guaranteed)
+ public void fatalError(SAXParseException e)
+ throws SAXException {
+ throw e;
+ }
+
+ public void error(SAXParseException e)
+ throws SAXParseException {
+ // make sure validation error is thrown.
+ throw e;
+ }
+
+ public void warning(SAXParseException e)
+ throws SAXParseException {
+ }
+ }
+ );
+
+ try {
+ w3cDocument = builder.parse(fis);
+ w3cDocument.getDocumentElement().normalize();
+ } catch (SAXException ex) {
+ ex.printStackTrace(writer_);
+ writer_.println(ex.getMessage());
+ return w3cDocument;
+ }
+
+ return w3cDocument;
+ }
+
+ private String [] parseTags(String tagsString) {
+ Vector tagsVector = new Vector();
+ if (tagsString.length() == 0)
+ return null;
+
+ int start = 0;
+ int end = 0;
+ // break the tag string into a vector of strings by words
+ for (end = tagsString.indexOf(" ", start);
+ end != -1 ;
+ start = end + 1, end = tagsString.indexOf(" ", start)) {
+ tagsVector.add(tagsString.substring(start,end));
+ }
+
+ tagsVector.add(tagsString.substring(start,tagsString.length()));
+
+ // convert the vector to array
+ String[] tags= new String[tagsVector.size()];
+ tagsVector.copyInto(tags);
+
+ return tags;
+ }
+
+
+ /**
+ * Set the output to the specified argument.
+ * This method is only used internally to prevent
+ * invalid string parameter.
+ *
+ * @param str output specifier
+ */
+ private static void setOutput(String str) {
+
+ if (writer_ == null) {
+
+ if (str.equals("System.out")) {
+
+ setOutput(System.out);
+
+ } else if (str.equals("System.err")) {
+
+ setOutput(System.err);
+
+ } else {
+
+ try {
+
+ setOutput(new FileWriter(str));
+
+ } catch (IOException e) {
+
+ e.printStackTrace(System.err);
+ }
+ }
+ }
+ }
+
+ /**
+ * Set the output to an OutputStream object.
+ *
+ * @param stream OutputStream object
+ */
+
+ private static void setOutput(OutputStream stream) {
+
+ setOutput(new OutputStreamWriter(stream));
+ }
+
+ /**
+ * Set the Writer object to manage the output.
+ *
+ * @param w Writer object to write out
+ */
+
+ private static void setOutput(Writer w) {
+
+ if (writer_ != null) {
+
+ writer_.close();
+ }
+
+ writer_ = new PrintWriter(new BufferedWriter(w), true);
+ }
+
+ public static void main(String args[]) throws IOException {
+
+ if (args.length != 0 && args.length != 2) {
+ System.out.println("Usage: XmlDiff [<file1> <file2>].");
+ return;
+ }
+
+ XmlDiff xmldiff = new XmlDiff();
+
+ boolean same = false;
+ if (args.length == 2) {
+ same = xmldiff.diff(args[0], args[1]);
+ } else {
+ same = xmldiff.diff();
+ }
+
+ System.out.println("Diff result: " + same);
+ if (same)
+ {
+ System.out.println("XMLDIFFRESULT:PASSED");
+ } else {
+ System.out.println("XMLDIFFRESULT:FAILED");
+ }
+ }
+}
+
diff --git a/xmerge/source/palmtests/qa/comparator/XmlDiff.properties b/xmerge/source/palmtests/qa/comparator/XmlDiff.properties
new file mode 100644
index 000000000000..2fdff0953ed6
--- /dev/null
+++ b/xmerge/source/palmtests/qa/comparator/XmlDiff.properties
@@ -0,0 +1,14 @@
+#
+# $Id: XmlDiff.properties,v 1.2 2005-10-24 16:13:45 hr Exp $
+#
+# This properties file provides info for XmlDiff program
+# XmlDiff.file1 is the first input XML file
+# XmlDiff.file2 is the second input XML file
+# XmlDiff.output is where the output (err/message) go
+# XmlDiff.tags are what tagname should ignore (and the subtree under it)
+#
+# x-no-translate
+XmlDiff.file1=test1.xml
+XmlDiff.file2=test2.xml
+XmlDiff.output=System.err
+XmlDiff.tags=
diff --git a/xmerge/source/palmtests/qa/comparator/XmlWrapper.java b/xmerge/source/palmtests/qa/comparator/XmlWrapper.java
new file mode 100644
index 000000000000..16dddcb0a4f3
--- /dev/null
+++ b/xmerge/source/palmtests/qa/comparator/XmlWrapper.java
@@ -0,0 +1,153 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+import java.io.IOException;
+import java.io.File;
+import java.util.zip.*;
+
+public class XmlWrapper
+{
+ public static void main(String args[]) throws IOException
+ {
+ System.out.println("args.length is " + args.length);
+ if (args.length < 2) {
+ System.out.println("Usage: java XmlWrapper [<zipfile1> <zipfile2>].");
+ //return;
+ System.exit(-1);
+
+ }
+
+ XmlWrapper w = new XmlWrapper();
+ File currdirfp = null;
+ try {
+ currdirfp = new File(".");
+ } catch (Exception fx) {
+ System.out.println("Could not get File instance for current directory \n");
+ //return;
+ System.exit(-1);
+ }
+
+ File f1 = null;
+ File f2 = null;
+ String fname1,fname2;
+ try {
+ f1 = File.createTempFile("xmlcomp", ".tmp", currdirfp);
+ f2 = File.createTempFile("xmlcomp", ".tmp", currdirfp);
+ } catch (Exception tx) {
+ System.out.println("Could not create TempFile ");
+ System.out.println("Exception: " + tx.toString());
+ //return;
+ System.exit(-1);
+ }
+
+ fname1 = f1.getAbsolutePath();
+ fname2 = f2.getAbsolutePath();
+
+ // get content.xml file from zip file and copy it to temporary
+ // filename
+ XmlZipExtract xw1 = new XmlZipExtract(args[0]);
+ try {
+ xw1.getContentXml(fname1);
+ } catch (ZipException e) {
+ System.out.println("Exception: file is not a ZIP file: " + args[0]);
+ f1.delete();
+ f2.delete();
+ //return;
+ System.exit(-1);
+ } catch (Exception e) {
+ System.out.println("Exception: Could not extract XML from " + args[0]);
+ System.out.println("Exception: " + e.toString());
+ f1.delete();
+ f2.delete();
+ //return;
+ System.exit(-1);
+ }
+
+ // get content.xml file from zip file and copy it to temporary
+ // filename
+ XmlZipExtract xw2 = new XmlZipExtract(args[1]);
+ try {
+ xw2.getContentXml(fname2);
+ } catch (ZipException e) {
+ System.out.println("Exception: file is not a ZIP file: " + args[0]);
+ f1.delete();
+ f2.delete();
+ //return;
+ System.exit(-1);
+ } catch (Exception ex) {
+ System.out.println(ex.getMessage());
+ System.out.println("Exception: Could not extract XML from " + args[1]);
+ System.out.println("Exception: " + ex.toString());
+ f1.delete();
+ f2.delete();
+ //return;
+ System.exit(-1);
+ }
+
+ boolean same = false;
+
+ try
+ {
+ XmlDiff xmldiff = new XmlDiff();
+
+ if (args.length == 2) {
+ same = xmldiff.diff(fname1, fname2);
+ } else {
+ same = xmldiff.diff();
+ }
+ }
+ catch (Exception ex)
+ {
+ System.out.println("XmlDiff failed");
+ System.out.println("Exception: " + ex.toString());
+ f1.delete();
+ f2.delete();
+ //return;
+ System.exit(-1);
+ }
+
+ System.out.println("Diff result: " + same);
+ if (same)
+ {
+ System.out.println("XMLDIFFRESULT:PASSED");
+ } else {
+ System.out.println("XMLDIFFRESULT:FAILED");
+ }
+
+ f1.delete();
+ f2.delete();
+
+ if (same)
+ {
+ System.exit(2);
+ }
+ else
+ {
+ System.exit(3);
+ }
+ }
+}
diff --git a/xmerge/source/palmtests/qa/comparator/XmlZipExtract.java b/xmerge/source/palmtests/qa/comparator/XmlZipExtract.java
new file mode 100644
index 000000000000..2e47edd65160
--- /dev/null
+++ b/xmerge/source/palmtests/qa/comparator/XmlZipExtract.java
@@ -0,0 +1,144 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.FileInputStream;
+import java.io.RandomAccessFile;
+import java.io.BufferedInputStream;
+import java.io.ByteArrayOutputStream;
+import java.util.Enumeration;
+import java.util.zip.ZipFile;
+import java.util.zip.ZipEntry;
+
+public class XmlZipExtract
+{
+
+ public static final String CONTENT = "Content.xml";
+ public static final String OLDCONTENT = "content.xml";
+ private static final int BUFFER_SIZE = 2048;
+
+
+ /**
+ * Full path of the Zip file to process.
+ */
+ private String filename = null;
+
+
+ /**
+ * Constructor
+ *
+ * @param filename Full Path to Zip file to process
+ *
+ */
+ public XmlZipExtract(String filename) {
+ this.filename = filename;
+ }
+
+ /**
+ * Copies Content.xml from zip file onto the filename passed as
+ * an argument
+ *
+ * @param fname Full Path to file to which contents have to be copied
+ *
+ */
+ public void getContentXml(String fname) throws IOException
+ {
+ try
+ {
+ getContentXmlInt(fname, XmlZipExtract.CONTENT);
+ }
+ catch (NullPointerException e1)
+ {
+ // If the new name of the content file failed, try
+ // the older name.
+ //
+ System.out.println(filename + " Content.xml does not exist, trying content.xml...");
+ try
+ {
+ getContentXmlInt(fname, XmlZipExtract.OLDCONTENT);
+ }
+ catch (NullPointerException e2)
+ {
+ System.out.println(filename + " content.xml does not exist, trying content.xml...");
+ throw e2;
+ }
+ }
+ }
+
+ public void getContentXmlInt(String fname, String cname) throws IOException
+ {
+ byte b[] = getEntry(cname);
+
+ RandomAccessFile raf=null;
+ raf = new RandomAccessFile(fname, "rw");
+ raf.write(b);
+ raf.close();
+ }
+
+ /**
+ * Get the specified entry in the zip file as a stream.
+ *
+ * @param entryName The name of the entry in the zipfile to get.
+ * This should be one of the constants defined above.
+ *
+ * @return byte[] bits for entryName
+ *
+ * @throws IOException if something goes wrong
+ */
+ public byte[] getEntry(String entryName) throws IOException
+ {
+ ZipFile zf = new ZipFile(filename);
+ ZipEntry ze = zf.getEntry(entryName);
+ byte[] bits = readStream(zf.getInputStream(ze));
+ zf.close();
+ return bits;
+ }
+
+
+ /**
+ * Read an InputStream into an array of bytes.
+ *
+ * @param is InputStream of data from Zip file
+ *
+ * @return an array of Bytes
+ */
+ private byte[] readStream(InputStream is) throws IOException
+ {
+ BufferedInputStream bis = new BufferedInputStream(is);
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ byte[] buffer = new byte[BUFFER_SIZE];
+ int eof = 0;
+ while ((eof = bis.read(buffer, 0, buffer.length)) > 0) {
+ baos.write(buffer, 0, eof);
+ }
+
+ return baos.toByteArray();
+ }
+}
+
+
diff --git a/xmerge/source/palmtests/qa/comparator/comparator.pl b/xmerge/source/palmtests/qa/comparator/comparator.pl
new file mode 100644
index 000000000000..5ca4f2375689
--- /dev/null
+++ b/xmerge/source/palmtests/qa/comparator/comparator.pl
@@ -0,0 +1,248 @@
+#!/usr/bin/perl
+
+#########################################################################
+
+ #*************************************************************************
+ #
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# Copyright 2000, 2010 Oracle and/or its affiliates.
+#
+# OpenOffice.org - a multi-platform office productivity suite
+#
+# This file is part of OpenOffice.org.
+#
+# OpenOffice.org is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License version 3
+# only, as published by the Free Software Foundation.
+#
+# OpenOffice.org is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License version 3 for more details
+# (a copy is included in the LICENSE file that accompanied this code).
+#
+# You should have received a copy of the GNU Lesser General Public License
+# version 3 along with OpenOffice.org. If not, see
+# <http://www.openoffice.org/license.html>
+# for a copy of the LGPLv3 License.
+#
+ #*************************************************************************
+
+$compare_home = "$ENV{QA_COMPARATOR_HOME}";
+
+if ($ENV{'CLASSPATH'})
+{
+ $classpath_val = "$compare_home:$ENV{'CLASSPATH'}";
+}
+else
+{
+ $classpath_val = "$compare_home";
+}
+
+print "classpath is $classpath_val\n";
+
+$list_file="";
+$orig_dir="";
+$new_dir="";
+$diff_type="";
+
+####### BEGIN MAIN ##############
+$cmdline_len = @ARGV;
+if ($cmdline_len <= 0)
+{
+ print_usage();
+ exit (0);
+}
+
+process_cmdline(@ARGV);
+print_env();
+open (LOGFILE, ">$logfile") || die "Cannot open log file $logfile";
+if ($test_list ne "")
+{
+ open (TESTLIST, $test_list) || die "Couldn't open diff list file $test_list";
+
+ while (<TESTLIST>)
+ {
+ chomp $_;
+ process_diff(get_file_title($_));
+ }
+}
+close TESTLIST;
+close LOGFILE;
+
+####### END MAIN ##############
+
+sub process_diff
+{
+ $_[0] =~ tr/A-Z/a-z/;
+
+ # chdir to the output directory so the temporary files created by
+ # the java programs are put in the right place.
+ #
+ chdir ($xml_new);
+
+ if ($diff_type eq "xml")
+ {
+ # Ugly hack, probably a way to tell xerces directly that the dtd's
+ # are in $compare_home/dtd.
+ #
+ `cp $compare_home/dtd/* $xml_new`;
+
+ $cmd = "java -classpath $classpath_val XmlWrapper $xml_orig/$_[0].sxw $xml_new/$_[0].sxw";
+ $val = system($cmd)/256;
+ if ($val == 2)
+ {
+ print LOGFILE "$_[0]|TRUE|$xml_orig/$_[0].sxw|$xml_new/$_[0].sxw\n";
+ }
+ elsif($val == 3)
+ {
+ print LOGFILE "$_[0]|FALSE|$xml_orig/$_[0].sxw|$xml_new/$_[0].sxw\n";
+ }
+ else
+ {
+ print LOGFILE "$_[0]|ERROR|$xml_orig/$_[0].sxw|$xml_new/$_[0].sxw\n";
+ }
+ }
+ elsif ($diff_type eq "pdb")
+ {
+ $cmd = "java -classpath $classpath_val SimplePdbCompare $pdb_orig/$_[0].pdb $pdb_new/$_[0].pdb\n";
+ print "Executing: $cmd\n";
+ $val = system($cmd)/256;
+ if ($val == 2)
+ {
+ print LOGFILE "$_[0]|TRUE|$pdb_orig/$_[0].pdb|$pdb_new/$_[0].pdb\n";
+ }
+ elsif($val == 3)
+ {
+ print LOGFILE "$_[0]|FALSE|$pdb_orig/$_[0].pdb|$pdb_new/$_[0].pdb\n";
+ }
+ else
+ {
+ print LOGFILE "$_[0]|ERROR|$pdb_orig/$_[0].pdb|$pdb_new/$_[0].pdb\n";
+ }
+ }
+ else
+ {
+ die "Don't understand test type of $diff_type.";
+ }
+}
+
+sub process_cmdline
+{
+ foreach $i (@_)
+ {
+ @arg= split('=', $i);
+ @arg[0] =~ tr/A-Z/a-z/;
+
+ if (@arg[0] eq "-pdb-orig")
+ {
+ $pdb_orig=$arg[1];
+ }
+ elsif (@arg[0] eq "-pdb-new")
+ {
+ $pdb_new=$arg[1];
+ }
+ elsif (@arg[0] eq "-xml-orig")
+ {
+ $xml_orig=$arg[1];
+ }
+ elsif (@arg[0] eq "-xml-new")
+ {
+ $xml_new=$arg[1];
+ }
+ elsif (@arg[0] eq "-env")
+ {
+ set_env_from_props($arg[1]);
+ }
+ elsif (@arg[0] eq "-list")
+ {
+ $test_list = $arg[1];
+ }
+ elsif (@arg[0] eq "-one")
+ {
+ $infile = $arg[1];
+ }
+ elsif (@arg[0] eq "-type")
+ {
+ $diff_type = $arg[1];
+ chomp $diff_type;
+ }
+ elsif (@arg[0] eq "-log")
+ {
+ $logfile = $arg[1];
+ }
+ else
+ {
+ print_usage();
+ die "Incorrect command line. Don't understand $i";
+ }
+ }
+}
+
+sub set_env_from_props
+{
+ open(PROPSFILE, $_[0]) || die "Could not open properties file";
+
+ while (<PROPSFILE>)
+ {
+ chomp $_;
+ @arg = split('=', $_);
+ @arg[0] =~ tr/a-z/A-Z/;
+ $len = @arg;
+ if ($len != 2)
+ {
+ die "Malformed property in $ARGV[0]";
+ }
+
+ if (@arg[0] eq "PDB_ORIG")
+ {
+ $pdb_orig=$arg[1];
+ }
+ elsif (@arg[0] eq "PDB_NEW")
+ {
+ $pdb_new=$arg[1];
+ }
+ elsif (@arg[0] eq "XML_ORIG")
+ {
+ $xml_orig=$arg[1];
+ }
+ elsif (@arg[0] eq "XML_NEW")
+ {
+ $xml_new=$arg[1];
+ }
+
+ }
+ close PROPSFILE;
+}
+
+sub print_usage
+{
+ print "Usage : compartor.pl - compare Office or pdb files\n";
+ print "\t-one=<file> :\t\t individual test case file to run\n";
+ print "\t-list=<file> :\t\t list of test case files\n";
+ print "\t-env=<file> :\t\t Properites like file defining env\n";
+ print "\t-pdb-orig=<path> :\t directory to hold original pdb files\n";
+ print "\t-pdb-new=<path> :\t directory to hold new pdb files\n";
+ print "\t-xml-orig=<path> :\t directory to hold original office documents\n";
+ print "\t-xml-new=<path> :\t directory to hold new office documents\n";
+ print "\t-type=<xml|pdb> :\t Invokes the merge option when converting\n";
+ print "\t-log=<logfile> :\t Save results to logfile.\n";
+}
+
+sub print_env
+{
+ print "Using the following environment:\n";
+ print "\tPDB_ORIG = $pdb_orig\n";
+ print "\tPDB_NEW = $pdb_new\n";
+ print "\tXML_ORIG = $xml_orig\n";
+ print "\tXML_NEW = $xml_new\n\n";
+}
+
+sub get_file_title
+{
+ @paths = split('\/', $_[0]);
+ $len = @paths;
+ @names = split('\.', @paths[$len-1]);
+ return $names[0];
+}
diff --git a/xmerge/source/palmtests/qa/comparator/dtd/Blocklist.dtd b/xmerge/source/palmtests/qa/comparator/dtd/Blocklist.dtd
new file mode 100644
index 000000000000..f7bb8eb321bb
--- /dev/null
+++ b/xmerge/source/palmtests/qa/comparator/dtd/Blocklist.dtd
@@ -0,0 +1,34 @@
+<!--
+
+ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+
+ Copyright 2000, 2010 Oracle and/or its affiliates.
+
+ OpenOffice.org - a multi-platform office productivity suite
+
+ This file is part of OpenOffice.org.
+
+ OpenOffice.org is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License version 3
+ only, as published by the Free Software Foundation.
+
+ OpenOffice.org is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License version 3 for more details
+ (a copy is included in the LICENSE file that accompanied this code).
+
+ You should have received a copy of the GNU Lesser General Public License
+ version 3 along with OpenOffice.org. If not, see
+ <http://www.openoffice.org/license.html>
+ for a copy of the LGPLv3 License.
+
+-->
+<!ELEMENT block-list:block-list (block-list:block*) >
+<!ATTLIST block-list:block-list
+ block-list:list-name CDATA #REQUIRED>
+<!ELEMENT block-list:block EMPTY>
+<!ATTLIST block-list:block
+ block-list:abbreviated-name CDATA #REQUIRED
+ block-list:package-name CDATA #REQUIRED
+ block-list:name CDATA #REQUIRED>
diff --git a/xmerge/source/palmtests/qa/comparator/dtd/chart.mod b/xmerge/source/palmtests/qa/comparator/dtd/chart.mod
new file mode 100644
index 000000000000..70cbe483ca9c
--- /dev/null
+++ b/xmerge/source/palmtests/qa/comparator/dtd/chart.mod
@@ -0,0 +1,228 @@
+<!--
+
+ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+
+ Copyright 2000, 2010 Oracle and/or its affiliates.
+
+ OpenOffice.org - a multi-platform office productivity suite
+
+ This file is part of OpenOffice.org.
+
+ OpenOffice.org is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License version 3
+ only, as published by the Free Software Foundation.
+
+ OpenOffice.org is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License version 3 for more details
+ (a copy is included in the LICENSE file that accompanied this code).
+
+ You should have received a copy of the GNU Lesser General Public License
+ version 3 along with OpenOffice.org. If not, see
+ <http://www.openoffice.org/license.html>
+ for a copy of the LGPLv3 License.
+
+-->
+
+
+<!ENTITY % chart-class "(line|area|circle|ring|scatter|radar|bar|stock|add-in)">
+<!ENTITY % chart-solid-type "(cuboid|cylinder|cone|pyramid)">
+
+<!-- Chart element -->
+<!ELEMENT chart:chart ( chart:title?, chart:subtitle?, chart:legend?,
+ chart:plot-area,
+ table:table? )>
+<!ATTLIST chart:chart
+ chart:class %chart-class; #REQUIRED
+ chart:add-in-name %string; #IMPLIED
+ chart:table-number-list %string; #IMPLIED
+ draw:name %string; #IMPLIED
+ %draw-position;
+ %draw-size;
+ %draw-style-name;
+ chart:style-name %styleName; #IMPLIED>
+
+<!ATTLIST chart:chart %presentation-class; >
+<!ATTLIST chart:chart %zindex;>
+<!ATTLIST chart:chart %draw-end-position; >
+<!ATTLIST chart:chart draw:id %draw-shape-id; >
+<!ATTLIST chart:chart draw:layer %layerName; #IMPLIED>
+
+<!ATTLIST style:properties
+ chart:scale-text %boolean; "true"
+ chart:stock-updown-bars %boolean; "false"
+ chart:stock-with-volume %boolean; "false"
+ chart:three-dimensional %boolean; "false"
+ chart:deep %boolean; "false"
+ chart:lines %boolean; "false"
+ chart:percentage %boolean; "false"
+ chart:solid-type %chart-solid-type; "cuboid"
+ chart:splines %nonNegativeInteger; "0"
+ chart:stacked %boolean; "false"
+ chart:symbol %integer; "-1"
+ chart:vertical %boolean; "false"
+ chart:lines-used %nonNegativeInteger; "0"
+ chart:connect-bars %boolean; "false">
+
+<!-- Main/Sub Title -->
+<!-- the cell-address attribute is currently not supported for titles -->
+<!ELEMENT chart:title (text:p)?>
+<!ATTLIST chart:title
+ table:cell-range %cell-address; #IMPLIED
+ svg:x %coordinate; #IMPLIED
+ svg:y %coordinate; #IMPLIED
+ chart:style-name %styleName; #IMPLIED >
+
+<!ELEMENT chart:subtitle (text:p)?>
+<!ATTLIST chart:subtitle
+ table:cell-range %cell-address; #IMPLIED
+ svg:x %coordinate; #IMPLIED
+ svg:y %coordinate; #IMPLIED
+ chart:style-name %styleName; #IMPLIED >
+
+<!-- you must specify either a legend-position or both, x and y coordinates -->
+<!ELEMENT chart:legend EMPTY>
+<!ATTLIST chart:legend
+ chart:legend-position (top|left|bottom|right) "right"
+ svg:x %coordinate; #IMPLIED
+ svg:y %coordinate; #IMPLIED
+ chart:style-name %styleName; #IMPLIED >
+
+<!-- Plot-Area specification -->
+
+<!ELEMENT chart:plot-area (dr3d:light*,
+ chart:axis*,
+ chart:categories?,
+ chart:series*,
+ chart:wall?,
+ chart:floor?) >
+
+<!ATTLIST chart:plot-area
+ svg:x %coordinate; #IMPLIED
+ svg:y %coordinate; #IMPLIED
+ svg:width %length; #IMPLIED
+ svg:height %length; #IMPLIED
+ chart:style-name %styleName; #IMPLIED
+ table:cell-range-address %cell-range-address; #IMPLIED
+ chart:table-number-list %string; #IMPLIED
+ chart:data-source-has-labels (none|row|column|both) "none" >
+
+<!-- 3d scene attributes on plot-area -->
+<!ATTLIST chart:plot-area
+ dr3d:vrp %vector3D; #IMPLIED
+ dr3d:vpn %vector3D; #IMPLIED
+ dr3d:vup %vector3D; #IMPLIED
+ dr3d:projection (parallel|perspective) #IMPLIED
+ dr3d:transform CDATA #IMPLIED
+ dr3d:distance %length; #IMPLIED
+ dr3d:focal-length %length; #IMPLIED
+ dr3d:shadow-slant %nonNegativeInteger; #IMPLIED
+ dr3d:shade-mode (flat|phong|gouraud|draft) #IMPLIED
+ dr3d:ambient-color %color; #IMPLIED
+ dr3d:lighting-mode %boolean; #IMPLIED >
+
+<!ATTLIST style:properties
+ chart:series-source (columns|rows) "columns" >
+
+<!ELEMENT chart:wall EMPTY>
+<!ATTLIST chart:wall
+ svg:width %length; #IMPLIED
+ chart:style-name %styleName; #IMPLIED >
+
+<!ELEMENT chart:floor EMPTY>
+<!ATTLIST chart:floor
+ svg:width %length; #IMPLIED
+ chart:style-name %styleName; #IMPLIED >
+
+<!-- Axis -->
+
+<!ELEMENT chart:axis (chart:title?, chart:grid*)>
+<!ATTLIST chart:axis
+ chart:class (category|value|series|domain) #REQUIRED
+ chart:name %string; #IMPLIED
+ chart:style-name %styleName; #IMPLIED >
+
+<!ATTLIST style:properties
+ chart:tick-marks-major-inner %boolean; "false"
+ chart:tick-marks-major-outer %boolean; "true"
+ chart:tick-marks-minor-inner %boolean; "false"
+ chart:tick-marks-minor-outer %boolean; "false"
+ chart:logarithmic %boolean; "false"
+ chart:maximum %float; #IMPLIED
+ chart:minimum %float; #IMPLIED
+ chart:origin %float; #IMPLIED
+ chart:interval-major %float; #IMPLIED
+ chart:interval-minor %float; #IMPLIED
+ chart:gap-width %integer; #IMPLIED
+ chart:overlap %integer; #IMPLIED
+ text:line-break %boolean; "true"
+ chart:display-label %boolean; "true"
+ chart:label-arrangement (side-by-side|stagger-even|stagger-odd) "side-by-side"
+ chart:visible %boolean; "true"
+ chart:link-data-style-to-source %boolean; "true" >
+
+<!ELEMENT chart:grid EMPTY>
+<!ATTLIST chart:grid
+ chart:class (major|minor) "major"
+ chart:style-name %styleName; #IMPLIED >
+
+
+<!ELEMENT chart:categories EMPTY>
+<!ATTLIST chart:categories
+ table:cell-range-address %cell-range-address; #REQUIRED >
+
+<!--
+ each series element must have an cell-range-address element that points
+ to the underlying table data.
+ Impl. Note: Internally all href elements are merged to one table range
+ that represents the data for the whole chart
+-->
+<!ELEMENT chart:series ( chart:domain*,
+ chart:data-point* )>
+<!ATTLIST chart:series
+ chart:values-cell-range-address %cell-range-address; #IMPLIED
+ chart:label-cell-address %cell-address; #IMPLIED
+ chart:class %chart-class; #IMPLIED
+ chart:attached-axis %string; #IMPLIED
+ chart:style-name %styleName; #IMPLIED >
+
+<!ELEMENT chart:domain EMPTY>
+<!ATTLIST chart:domain
+ table:cell-range-address %cell-range-address; #IMPLIED >
+
+<!ELEMENT chart:data-point EMPTY>
+<!ATTLIST chart:data-point
+ chart:repeated %nonNegativeInteger; #IMPLIED
+ chart:style-name %styleName; #IMPLIED >
+
+<!-- statistical properties -->
+
+<!ATTLIST style:properties
+ chart:mean-value %boolean; #IMPLIED
+ chart:error-category (none|variance|standard-deviation|percentage|error-margin|constant) "none"
+ chart:error-percentage %float; #IMPLIED
+ chart:error-margin %float; #IMPLIED
+ chart:error-lower-limit %float; #IMPLIED
+ chart:error-upper-limit %float; #IMPLIED
+ chart:error-upper-indicator %boolean; #IMPLIED
+ chart:error-lower-indicator %boolean; #IMPLIED
+ chart:regression-type (none|linear|logarithmic|exponential|power) "none" >
+
+<!-- data label properties -->
+
+<!ATTLIST style:properties
+ chart:data-label-number (none|value|percentage) "none"
+ chart:data-label-text %boolean; "false"
+ chart:data-label-symbol %boolean; "false" >
+
+<!-- general text properties -->
+
+<!ATTLIST style:properties text:rotation-angle %integer; "0" >
+
+<!-- symbol properties -->
+
+<!ATTLIST style:properties
+ chart:symbol-width %nonNegativeLength; #IMPLIED
+ chart:symbol-height %nonNegativeLength; #IMPLIED
+ chart:symbol-image-name %string; #IMPLIED >
diff --git a/xmerge/source/palmtests/qa/comparator/dtd/datastyl.mod b/xmerge/source/palmtests/qa/comparator/dtd/datastyl.mod
new file mode 100644
index 000000000000..11bc8a8e40b7
--- /dev/null
+++ b/xmerge/source/palmtests/qa/comparator/dtd/datastyl.mod
@@ -0,0 +1,168 @@
+<!--
+
+ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+
+ Copyright 2000, 2010 Oracle and/or its affiliates.
+
+ OpenOffice.org - a multi-platform office productivity suite
+
+ This file is part of OpenOffice.org.
+
+ OpenOffice.org is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License version 3
+ only, as published by the Free Software Foundation.
+
+ OpenOffice.org is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License version 3 for more details
+ (a copy is included in the LICENSE file that accompanied this code).
+
+ You should have received a copy of the GNU Lesser General Public License
+ version 3 along with OpenOffice.org. If not, see
+ <http://www.openoffice.org/license.html>
+ for a copy of the LGPLv3 License.
+
+-->
+
+<!-- data styles -->
+<!ENTITY % any-number "( number:number | number:scientific-number | number:fraction )">
+<!ENTITY % number-style-content "( (number:text,(%any-number;,number:text?)?) | (%any-number;,number:text?) )">
+<!ELEMENT number:number-style ( style:properties?, %number-style-content;, style:map* )>
+<!ELEMENT number:number EMPTY>
+<!ELEMENT number:scientific-number EMPTY>
+<!ELEMENT number:fraction EMPTY>
+
+<!ENTITY % currency-symbol-and-text "number:currency-symbol,number:text?">
+<!ENTITY % number-and-text "number:number,number:text?">
+<!ENTITY % currency-symbol-and-number "((%number-and-text;),(%currency-symbol-and-text;)?) | ((%currency-symbol-and-text;),(%number-and-text;)?)">
+<!ENTITY % currency-style-content "number:text?, (%currency-symbol-and-number;)?">
+
+<!ELEMENT number:currency-style ( style:properties?, (%currency-style-content;), style:map* )>
+<!ELEMENT number:currency-symbol (#PCDATA)>
+<!ATTLIST number:currency-symbol number:language CDATA #IMPLIED>
+<!ATTLIST number:currency-symbol number:country CDATA #IMPLIED>
+
+<!ENTITY % percentage-style-content "( (number:text,(%number-and-text;)?) | (%number-and-text;) )">
+<!ELEMENT number:percentage-style ( style:properties?, %percentage-style-content;, style:map* )>
+
+<!ENTITY % any-date "( number:day | number:month | number:year | number:era | number:day-of-week | number:week-of-year | number:quarter| number:hours | number:am-pm | number:minutes | number:seconds )">
+<!ENTITY % date-style-content "( (number:text,(%any-date;,number:text?)+) | (%any-date;,number:text?)+ )">
+<!ELEMENT number:date-style ( style:properties?, %date-style-content;, style:map* )>
+<!ELEMENT number:day EMPTY>
+<!ATTLIST number:day number:style (short|long) "short">
+<!ATTLIST number:day number:calendar CDATA #IMPLIED>
+<!ELEMENT number:month EMPTY>
+<!ATTLIST number:month number:textual %boolean; "false">
+<!ATTLIST number:month number:style (short|long) "short">
+<!ATTLIST number:month number:calendar CDATA #IMPLIED>
+<!ELEMENT number:year EMPTY>
+<!ATTLIST number:year number:style (short|long) "short">
+<!ATTLIST number:year number:calendar CDATA #IMPLIED>
+<!ELEMENT number:era EMPTY>
+<!ATTLIST number:era number:style (short|long) "short">
+<!ATTLIST number:era number:calendar CDATA #IMPLIED>
+<!ELEMENT number:day-of-week EMPTY>
+<!ATTLIST number:day-of-week number:style (short|long) "short">
+<!ATTLIST number:day-of-week number:calendar CDATA #IMPLIED>
+<!ELEMENT number:week-of-year EMPTY>
+<!ATTLIST number:week-of-year number:calendar CDATA #IMPLIED>
+<!ELEMENT number:quarter EMPTY>
+<!ATTLIST number:quarter number:style (short|long) "short">
+<!ATTLIST number:quarter number:calendar CDATA #IMPLIED>
+
+<!ENTITY % any-time "( number:hours | number:am-pm | number:minutes | number:seconds )">
+<!ENTITY % time-style-content "( (number:text,(%any-time;,number:text?)+) | (%any-time;,number:text?)+)">
+<!ELEMENT number:time-style ( style:properties?, %time-style-content;, style:map* )>
+<!ELEMENT number:hours EMPTY>
+<!ATTLIST number:hours number:style (short|long) "short">
+<!ELEMENT number:minutes EMPTY>
+<!ATTLIST number:minutes number:style (short|long) "short">
+<!ELEMENT number:seconds EMPTY>
+<!ATTLIST number:seconds number:style (short|long) "short">
+<!ATTLIST number:seconds number:decimal-places %integer; "0">
+<!ELEMENT number:am-pm EMPTY>
+
+<!ENTITY % boolean-style-content "( (number:text,(number:boolean,number:text?)?) | (number:boolean,number:text?) )">
+<!ELEMENT number:boolean-style ( style:properties?,%boolean-style-content;, style:map* )>
+<!ELEMENT number:boolean EMPTY>
+
+<!ENTITY % text-style-content "( (number:text,(number:text-content,number:text?)?) | (number:text-content,number:text?) )">
+<!ELEMENT number:text-style ( style:properties?,%text-style-content;, style:map* )>
+<!ELEMENT number:text (#PCDATA)>
+<!ELEMENT number:text-content EMPTY>
+
+<!ATTLIST number:number-style style:name %styleName; #REQUIRED>
+<!ATTLIST number:currency-style style:name %styleName; #REQUIRED>
+<!ATTLIST number:percentage-style style:name %styleName; #REQUIRED>
+<!ATTLIST number:date-style style:name %styleName; #REQUIRED>
+<!ATTLIST number:time-style style:name %styleName; #REQUIRED>
+<!ATTLIST number:boolean-style style:name %styleName; #REQUIRED>
+<!ATTLIST number:text-style style:name %styleName; #REQUIRED>
+
+<!ATTLIST number:number-style style:family CDATA #REQUIRED>
+<!ATTLIST number:currency-style style:family CDATA #REQUIRED>
+<!ATTLIST number:percentage-style style:family CDATA #REQUIRED>
+<!ATTLIST number:date-style style:family CDATA #REQUIRED>
+<!ATTLIST number:time-style style:family CDATA #REQUIRED>
+<!ATTLIST number:boolean-style style:family CDATA #REQUIRED>
+<!ATTLIST number:text-style style:family CDATA #REQUIRED>
+
+<!ATTLIST number:number-style number:language CDATA #IMPLIED>
+<!ATTLIST number:currency-style number:language CDATA #IMPLIED>
+<!ATTLIST number:percentage-style number:language CDATA #IMPLIED>
+<!ATTLIST number:date-style number:language CDATA #IMPLIED>
+<!ATTLIST number:time-style number:language CDATA #IMPLIED>
+<!ATTLIST number:boolean-style number:language CDATA #IMPLIED>
+<!ATTLIST number:text-style number:language CDATA #IMPLIED>
+
+<!ATTLIST number:number-style number:country CDATA #IMPLIED>
+<!ATTLIST number:currency-style number:country CDATA #IMPLIED>
+<!ATTLIST number:percentage-style number:country CDATA #IMPLIED>
+<!ATTLIST number:date-style number:country CDATA #IMPLIED>
+<!ATTLIST number:time-style number:country CDATA #IMPLIED>
+<!ATTLIST number:boolean-style number:country CDATA #IMPLIED>
+<!ATTLIST number:text-style number:country CDATA #IMPLIED>
+
+<!ATTLIST number:number-style number:title CDATA #IMPLIED>
+<!ATTLIST number:currency-style number:title CDATA #IMPLIED>
+<!ATTLIST number:percentage-style number:title CDATA #IMPLIED>
+<!ATTLIST number:date-style number:title CDATA #IMPLIED>
+<!ATTLIST number:time-style number:title CDATA #IMPLIED>
+<!ATTLIST number:boolean-style number:title CDATA #IMPLIED>
+<!ATTLIST number:text-style number:title CDATA #IMPLIED>
+
+<!ATTLIST number:number-style style:volatile %boolean; #IMPLIED>
+<!ATTLIST number:currency-style style:volatile %boolean; #IMPLIED>
+<!ATTLIST number:percentage-style style:volatile %boolean; #IMPLIED>
+<!ATTLIST number:date-style style:volatile %boolean; #IMPLIED>
+<!ATTLIST number:time-style style:volatile %boolean; #IMPLIED>
+<!ATTLIST number:boolean-style style:volatile %boolean; #IMPLIED>
+<!ATTLIST number:text-style style:volatile %boolean; #IMPLIED>
+
+<!ATTLIST number:currency-style number:automatic-order %boolean; "false">
+<!ATTLIST number:date-style number:automatic-order %boolean; "false">
+
+<!ATTLIST number:date-style number:format-source (fixed|language) "fixed">
+<!ATTLIST number:time-style number:format-source (fixed|language) "fixed">
+
+<!ATTLIST number:time-style number:truncate-on-overflow %boolean; "true">
+
+<!ATTLIST number:number number:decimal-places %integer; #IMPLIED>
+<!ATTLIST number:scientific-number number:decimal-places %integer; #IMPLIED>
+
+<!ATTLIST number:number number:min-integer-digits %integer; #IMPLIED>
+<!ATTLIST number:scientific-number number:min-integer-digits %integer; #IMPLIED>
+<!ATTLIST number:fraction number:min-integer-digits %integer; #IMPLIED>
+
+<!ATTLIST number:number number:grouping %boolean; "false">
+<!ATTLIST number:scientific-number number:grouping %boolean; "false">
+<!ATTLIST number:fraction number:grouping %boolean; "false">
+
+<!ATTLIST number:number number:decimal-replacement CDATA #IMPLIED>
+
+<!ATTLIST number:scientific-number number:min-exponent-digits %integer; #IMPLIED>
+
+<!ATTLIST number:fraction number:min-numerator-digits %integer; #IMPLIED>
+
+<!ATTLIST number:fraction number:min-denominator-digits %integer; #IMPLIED>
diff --git a/xmerge/source/palmtests/qa/comparator/dtd/drawing.mod b/xmerge/source/palmtests/qa/comparator/dtd/drawing.mod
new file mode 100644
index 000000000000..aa0a25822a45
--- /dev/null
+++ b/xmerge/source/palmtests/qa/comparator/dtd/drawing.mod
@@ -0,0 +1,837 @@
+<!--
+
+ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+
+ Copyright 2000, 2010 Oracle and/or its affiliates.
+
+ OpenOffice.org - a multi-platform office productivity suite
+
+ This file is part of OpenOffice.org.
+
+ OpenOffice.org is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License version 3
+ only, as published by the Free Software Foundation.
+
+ OpenOffice.org is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License version 3 for more details
+ (a copy is included in the LICENSE file that accompanied this code).
+
+ You should have received a copy of the GNU Lesser General Public License
+ version 3 along with OpenOffice.org. If not, see
+ <http://www.openoffice.org/license.html>
+ for a copy of the LGPLv3 License.
+
+-->
+
+<!ENTITY % points "CDATA" >
+<!ENTITY % pathData "CDATA" >
+<!ENTITY % gradient-style "(linear|axial|radial|ellipsoid|square|rectangular)" >
+<!ENTITY % draw-position "svg:x %coordinate; #IMPLIED svg:y %coordinate; #IMPLIED">
+<!ENTITY % draw-end-position "table:end-cell-address %cell-address; #IMPLIED table:end-x %coordinate; #IMPLIED table:end-y %coordinate; #IMPLIED">
+<!ENTITY % draw-size "svg:width %coordinate; #IMPLIED svg:height %coordinate; #IMPLIED">
+<!ENTITY % draw-transform "draw:transform CDATA #IMPLIED">
+<!ENTITY % draw-viewbox "svg:viewBox CDATA #REQUIRED">
+<!ENTITY % draw-style-name "draw:style-name %styleName; #IMPLIED presentation:style-name %styleName; #IMPLIED draw:text-style-name %styleName; #IMPLIED">
+<!ENTITY % draw-shape-id "CDATA #IMPLIED" >
+<!ENTITY % draw-text "(text:p|text:unordered-list|text:ordered-list)*">
+<!ENTITY % zindex "draw:z-index %nonNegativeInteger; #IMPLIED">
+<!ENTITY % distance "CDATA">
+<!ENTITY % rectanglePoint "(top-left|top|top-right|left|center|right|bottom-left|bottom|bottom-right)">
+<!ENTITY % vector3D "CDATA">
+<!ENTITY % text-anchor "text:anchor-type %anchorType; #IMPLIED text:anchor-page-number %positiveInteger; #IMPLIED">
+<!ENTITY % layerName "CDATA">
+<!ENTITY % table-background "table:table-background (true | false) #IMPLIED">
+
+<!-- commont presentation shape attributes -->
+<!ENTITY % presentation-style-name "presentation:style-name %styleName; #IMPLIED">
+<!ENTITY % presentation-classes "(title|outline|subtitle|text|graphic|object|chart|table|orgchart|page|notes)" >
+<!-- ENTITY % presentation-class "presentation:class %presentation-classes; #IMPLIED" -->
+<!ENTITY % presentation-class "presentation:class %presentation-classes; #IMPLIED presentation:placeholder (true|false) #IMPLIED presentation:user-transformed (true|false) #IMPLIED">
+<!ENTITY % presentationEffects "(none|fade|move|stripes|open|close|dissolve|wavyline|random|lines|laser|appear|hide|move-short|checkerboard|rotate|stretch)" >
+<!ENTITY % presentationEffectDirections "(none|from-left|from-top|from-right|from-bottom|from-center|from-upper-left|from-upper-right|from-lower-left|from-lower-right|to-left|to-top|to-right|to-bottom|to-upper-left|to-upper-right|to-lower-right|to-lower-left|path|spiral-inward-left|spiral-inward-right|spiral-outward-left|spiral-outward-right|vertical|horizontal|to-center|clockwise|counter-clockwise)" >
+<!ENTITY % presentationSpeeds "(slow|medium|fast)" >
+
+<!-- Drawing shapes -->
+<!ELEMENT draw:rect ( office:events?, %draw-text; )>
+<!ATTLIST draw:rect %draw-position; >
+<!ATTLIST draw:rect %draw-end-position; >
+<!ATTLIST draw:rect %table-background; >
+<!ATTLIST draw:rect %draw-size; >
+<!ATTLIST draw:rect %draw-style-name; >
+<!ATTLIST draw:rect %draw-transform; >
+<!ATTLIST draw:rect draw:corner-radius %nonNegativeLength; #IMPLIED>
+<!ATTLIST draw:rect %zindex;>
+<!ATTLIST draw:rect draw:id %draw-shape-id;>
+<!ATTLIST draw:rect %text-anchor;>
+<!ATTLIST draw:rect draw:layer %layerName; #IMPLIED>
+
+<!ELEMENT draw:line ( office:events?, %draw-text; )>
+<!ATTLIST draw:line svg:x1 %length; #REQUIRED>
+<!ATTLIST draw:line svg:y1 %length; #REQUIRED>
+<!ATTLIST draw:line svg:x2 %length; #REQUIRED>
+<!ATTLIST draw:line svg:y2 %length; #REQUIRED>
+<!ATTLIST draw:line %draw-style-name; >
+<!ATTLIST draw:line %draw-transform; >
+<!ATTLIST draw:line %zindex;>
+<!ATTLIST draw:line %draw-end-position; >
+<!ATTLIST draw:line %table-background; >
+<!ATTLIST draw:line draw:id %draw-shape-id;>
+<!ATTLIST draw:line %text-anchor;>
+<!ATTLIST draw:line draw:layer %layerName; #IMPLIED>
+
+<!ELEMENT draw:polyline ( office:events?, %draw-text; )>
+<!ATTLIST draw:polyline %draw-position; >
+<!ATTLIST draw:polyline %draw-size; >
+<!ATTLIST draw:polyline %draw-viewbox; >
+<!ATTLIST draw:polyline draw:points %points; #REQUIRED>
+<!ATTLIST draw:polyline %draw-style-name; >
+<!ATTLIST draw:polyline %draw-transform; >
+<!ATTLIST draw:polyline %zindex;>
+<!ATTLIST draw:polyline %draw-end-position; >
+<!ATTLIST draw:polyline %table-background; >
+<!ATTLIST draw:polyline draw:id %draw-shape-id;>
+<!ATTLIST draw:polyline %text-anchor;>
+<!ATTLIST draw:polyline draw:layer %layerName; #IMPLIED>
+
+<!ELEMENT draw:polygon ( office:events?, %draw-text; )>
+<!ATTLIST draw:polygon %draw-position; >
+<!ATTLIST draw:polygon %draw-end-position; >
+<!ATTLIST draw:polygon %table-background; >
+<!ATTLIST draw:polygon %draw-size; >
+<!ATTLIST draw:polygon %draw-viewbox; >
+<!ATTLIST draw:polygon draw:points %points; #REQUIRED >
+<!ATTLIST draw:polygon %draw-style-name; >
+<!ATTLIST draw:polygon %draw-transform; >
+<!ATTLIST draw:polygon %zindex;>
+<!ATTLIST draw:polygon draw:id %draw-shape-id;>
+<!ATTLIST draw:polygon %text-anchor;>
+<!ATTLIST draw:polygon draw:layer %layerName; #IMPLIED>
+
+<!ELEMENT draw:path ( office:events?, %draw-text; )>
+<!ATTLIST draw:path %draw-position;>
+<!ATTLIST draw:path %draw-end-position; >
+<!ATTLIST draw:path %table-background; >
+<!ATTLIST draw:path %draw-size; >
+<!ATTLIST draw:path %draw-viewbox; >
+<!ATTLIST draw:path svg:d %pathData; #REQUIRED >
+<!ATTLIST draw:path %draw-style-name; >
+<!ATTLIST draw:path %draw-transform; >
+<!ATTLIST draw:path %zindex;>
+<!ATTLIST draw:path draw:id %draw-shape-id;>
+<!ATTLIST draw:path %text-anchor;>
+<!ATTLIST draw:path draw:layer %layerName; #IMPLIED>
+
+<!ELEMENT draw:circle ( office:events?, %draw-text; )>
+<!ATTLIST draw:circle %draw-position; >
+<!ATTLIST draw:circle %draw-size; >
+<!ATTLIST draw:circle %draw-style-name; >
+<!ATTLIST draw:circle %draw-transform; >
+<!ATTLIST draw:circle %zindex;>
+<!ATTLIST draw:circle %draw-end-position; >
+<!ATTLIST draw:circle %table-background; >
+<!ATTLIST draw:circle draw:id %draw-shape-id;>
+<!ATTLIST draw:circle draw:kind (full|section|cut|arc) "full">
+<!ATTLIST draw:circle draw:start-angle %nonNegativeInteger; #IMPLIED>
+<!ATTLIST draw:circle draw:end-angle %nonNegativeInteger; #IMPLIED>
+<!ATTLIST draw:circle %text-anchor;>
+<!ATTLIST draw:circle draw:layer %layerName; #IMPLIED>
+
+<!ELEMENT draw:ellipse ( office:events?, %draw-text; )>
+<!ATTLIST draw:ellipse %draw-position; >
+<!ATTLIST draw:ellipse %draw-size; >
+<!ATTLIST draw:ellipse %draw-style-name; >
+<!ATTLIST draw:ellipse %draw-transform; >
+<!ATTLIST draw:ellipse %zindex;>
+<!ATTLIST draw:ellipse %draw-end-position; >
+<!ATTLIST draw:ellipse %table-background; >
+<!ATTLIST draw:ellipse draw:id %draw-shape-id;>
+<!ATTLIST draw:ellipse draw:kind (full|section|cut|arc) "full">
+<!ATTLIST draw:ellipse draw:start-angle %nonNegativeInteger; #IMPLIED>
+<!ATTLIST draw:ellipse draw:end-angle %nonNegativeInteger; #IMPLIED>
+<!ATTLIST draw:ellipse %text-anchor;>
+<!ATTLIST draw:ellipse draw:layer %layerName; #IMPLIED>
+
+<!ELEMENT draw:connector ( office:events?, %draw-text;)>
+<!ATTLIST draw:connector draw:type (standard|lines|line|curve) "standard">
+<!ATTLIST draw:connector draw:line-skew CDATA #IMPLIED>
+<!ATTLIST draw:connector %draw-style-name;>
+<!ATTLIST draw:connector svg:x1 %coordinate; #REQUIRED>
+<!ATTLIST draw:connector svg:y1 %coordinate; #REQUIRED>
+<!ATTLIST draw:connector svg:x2 %coordinate; #REQUIRED>
+<!ATTLIST draw:connector svg:y2 %coordinate; #REQUIRED>
+<!ATTLIST draw:connector draw:start-shape %draw-shape-id;>
+<!ATTLIST draw:connector draw:start-glue-point %integer; #IMPLIED>
+<!ATTLIST draw:connector draw:end-shape %draw-shape-id;>
+<!ATTLIST draw:connector draw:end-glue-point %integer; #IMPLIED>
+<!ATTLIST draw:connector %zindex;>
+<!ATTLIST draw:connector %draw-end-position; >
+<!ATTLIST draw:connector %table-background; >
+<!ATTLIST draw:connector draw:id %draw-shape-id;>
+<!ATTLIST draw:connector %text-anchor;>
+<!ATTLIST draw:connector draw:layer %layerName; #IMPLIED>
+
+<!ELEMENT draw:control EMPTY>
+<!ATTLIST draw:control %draw-style-name;>
+<!ATTLIST draw:control %draw-position; >
+<!ATTLIST draw:control %draw-size; >
+<!ATTLIST draw:control %control-id; >
+<!ATTLIST draw:control %zindex;>
+<!ATTLIST draw:control %draw-end-position; >
+<!ATTLIST draw:control %table-background; >
+<!ATTLIST draw:control draw:id %draw-shape-id;>
+<!ATTLIST draw:control %text-anchor;>
+<!ATTLIST draw:control draw:layer %layerName; #IMPLIED>
+
+<!ELEMENT draw:g ( office:events?, (%shapes;)* ) >
+<!ATTLIST draw:g %draw-transform; >
+<!ATTLIST draw:g %draw-style-name; >
+<!ATTLIST draw:g %zindex;>
+<!ATTLIST draw:g %draw-end-position; >
+<!ATTLIST draw:g %table-background; >
+<!ATTLIST draw:g draw:id %draw-shape-id;>
+<!ATTLIST draw:g %text-anchor;>
+<!ATTLIST draw:g draw:layer %layerName; #IMPLIED>
+
+<!ELEMENT draw:page-thumbnail EMPTY>
+<!ATTLIST draw:page-thumbnail draw:page-number %positiveInteger; #IMPLIED>
+<!ATTLIST draw:page-thumbnail %draw-position; >
+<!ATTLIST draw:page-thumbnail %draw-size; >
+<!ATTLIST draw:page-thumbnail %draw-style-name; >
+<!ATTLIST draw:page-thumbnail %presentation-class; >
+<!ATTLIST draw:page-thumbnail %zindex;>
+<!ATTLIST draw:page-thumbnail %draw-end-position; >
+<!ATTLIST draw:page-thumbnail %table-background; >
+<!ATTLIST draw:page-thumbnail draw:id %draw-shape-id;>
+<!ATTLIST draw:page-thumbnail %text-anchor;>
+<!ATTLIST draw:page-thumbnail draw:layer %layerName; #IMPLIED>
+
+<!ELEMENT draw:caption ( office:events?, %draw-text;)>
+<!ATTLIST draw:caption %draw-position; >
+<!ATTLIST draw:caption %draw-end-position; >
+<!ATTLIST draw:caption %table-background; >
+<!ATTLIST draw:caption %draw-size; >
+<!ATTLIST draw:caption %draw-style-name; >
+<!ATTLIST draw:caption %draw-transform; >
+<!ATTLIST draw:caption draw:caption-point-x %coordinate; #IMPLIED>
+<!ATTLIST draw:caption draw:caption-point-y %coordinate; #IMPLIED>
+<!ATTLIST draw:caption %zindex;>
+<!ATTLIST draw:caption draw:id %draw-shape-id;>
+<!ATTLIST draw:caption %text-anchor;>
+<!ATTLIST draw:caption draw:layer %layerName; #IMPLIED>
+<!ATTLIST draw:caption draw:corner-radius %nonNegativeLength; #IMPLIED>
+
+<!ELEMENT draw:measure ( office:events?, %draw-text;)>
+<!ATTLIST draw:measure svg:x1 %coordinate; #REQUIRED>
+<!ATTLIST draw:measure svg:y1 %coordinate; #REQUIRED>
+<!ATTLIST draw:measure svg:x2 %coordinate; #REQUIRED>
+<!ATTLIST draw:measure svg:y2 %coordinate; #REQUIRED>
+<!ATTLIST draw:measure %draw-end-position; >
+<!ATTLIST draw:measure %table-background; >
+<!ATTLIST draw:measure %draw-style-name; >
+<!ATTLIST draw:measure %draw-transform; >
+<!ATTLIST draw:measure %zindex;>
+<!ATTLIST draw:measure draw:id %draw-shape-id;>
+<!ATTLIST draw:measure %text-anchor;>
+<!ATTLIST draw:measure draw:layer %layerName; #IMPLIED>
+
+<!-- graphic style elements -->
+<!ELEMENT draw:gradient EMPTY >
+<!ATTLIST draw:gradient draw:name %styleName; #REQUIRED>
+<!ATTLIST draw:gradient draw:style %gradient-style; #REQUIRED>
+<!ATTLIST draw:gradient draw:cx %coordinate; #IMPLIED>
+<!ATTLIST draw:gradient draw:cy %coordinate; #IMPLIED>
+<!ATTLIST draw:gradient draw:start-color %color; #IMPLIED>
+<!ATTLIST draw:gradient draw:end-color %color; #IMPLIED>
+<!ATTLIST draw:gradient draw:start-intensity %percentage; #IMPLIED>
+<!ATTLIST draw:gradient draw:end-intensity %percentage; #IMPLIED>
+<!ATTLIST draw:gradient draw:angle %integer; #IMPLIED>
+<!ATTLIST draw:gradient draw:border %percentage; #IMPLIED>
+
+<!ELEMENT draw:hatch EMPTY >
+<!ATTLIST draw:hatch draw:name %styleName; #REQUIRED>
+<!ATTLIST draw:hatch draw:style (single|double|triple) #REQUIRED >
+<!ATTLIST draw:hatch draw:color %color; #IMPLIED>
+<!ATTLIST draw:hatch draw:distance %length; #IMPLIED>
+<!ATTLIST draw:hatch draw:rotation %integer; #IMPLIED>
+
+
+<!ELEMENT draw:fill-image EMPTY >
+<!ATTLIST draw:fill-image draw:name %styleName; #REQUIRED>
+<!ATTLIST draw:fill-image xlink:href %uriReference; #REQUIRED>
+<!ATTLIST draw:fill-image xlink:type (simple) #IMPLIED>
+<!ATTLIST draw:fill-image xlink:show (embed) #IMPLIED>
+<!ATTLIST draw:fill-image xlink:actuate (onLoad) #IMPLIED>
+<!ATTLIST draw:fill-image svg:width %length; #IMPLIED>
+<!ATTLIST draw:fill-image svg:height %length; #IMPLIED>
+
+<!ELEMENT draw:transparency EMPTY>
+<!ATTLIST draw:transparency draw:name %styleName; #REQUIRED>
+<!ATTLIST draw:transparency draw:style %gradient-style; #REQUIRED>
+<!ATTLIST draw:transparency draw:cx %coordinate; #IMPLIED>
+<!ATTLIST draw:transparency draw:cy %coordinate; #IMPLIED>
+<!ATTLIST draw:transparency draw:start %percentage; #IMPLIED>
+<!ATTLIST draw:transparency draw:end %percentage; #IMPLIED>
+<!ATTLIST draw:transparency draw:angle %integer; #IMPLIED>
+<!ATTLIST draw:transparency draw:border %percentage; #IMPLIED>
+
+<!ELEMENT draw:marker EMPTY>
+<!ATTLIST draw:marker draw:name %styleName; #REQUIRED>
+<!ATTLIST draw:marker %draw-viewbox; >
+<!ATTLIST draw:marker svg:d %pathData; #REQUIRED>
+
+<!ELEMENT draw:stroke-dash EMPTY>
+<!ATTLIST draw:stroke-dash draw:name %styleName; #REQUIRED>
+<!ATTLIST draw:stroke-dash draw:style (rect|round) #IMPLIED>
+<!ATTLIST draw:stroke-dash draw:dots1 %integer; #IMPLIED>
+<!ATTLIST draw:stroke-dash draw:dots1-length %length; #IMPLIED>
+<!ATTLIST draw:stroke-dash draw:dots2 %integer; #IMPLIED>
+<!ATTLIST draw:stroke-dash draw:dots2-length %length; #IMPLIED>
+<!ATTLIST draw:stroke-dash draw:distance %length; #IMPLIED>
+
+<!-- stroke attributes -->
+<!ATTLIST style:properties draw:stroke (none|dash|solid) #IMPLIED>
+<!ATTLIST style:properties draw:stroke-dash CDATA #IMPLIED>
+<!ATTLIST style:properties svg:stroke-width %length; #IMPLIED>
+<!ATTLIST style:properties svg:stroke-color %color; #IMPLIED>
+<!ATTLIST style:properties draw:marker-start %styleName; #IMPLIED>
+<!ATTLIST style:properties draw:marker-end %styleName; #IMPLIED>
+<!ATTLIST style:properties draw:marker-start-width %length; #IMPLIED>
+<!ATTLIST style:properties draw:marker-end-width %length; #IMPLIED>
+<!ATTLIST style:properties draw:marker-start-center %boolean; #IMPLIED>
+<!ATTLIST style:properties draw:marker-end-center %boolean; #IMPLIED>
+<!ATTLIST style:properties svg:stroke-opacity %floatOrPercentage; #IMPLIED>
+<!ATTLIST style:properties svg:stroke-linejoin (miter|round|bevel|middle|none|inherit) #IMPLIED>
+
+<!-- text attributes -->
+<!ATTLIST style:properties draw:auto-grow-width %boolean; #IMPLIED>
+<!ATTLIST style:properties draw:auto-grow-height %boolean; #IMPLIED>
+<!ATTLIST style:properties draw:fit-to-size %boolean; #IMPLIED>
+<!ATTLIST style:properties draw:fit-to-contour %boolean; #IMPLIED>
+<!ATTLIST style:properties draw:textarea-horizontal-align ( left | center | right | justify ) #IMPLIED>
+<!ATTLIST style:properties draw:textarea-vertical-align ( top | middle | bottom ) #IMPLIED>
+
+<!-- fill attributes -->
+<!ATTLIST style:properties draw:fill (none|solid|bitmap|gradient|hatch) #IMPLIED>
+<!ATTLIST style:properties draw:fill-color %color; #IMPLIED>
+<!ATTLIST style:properties draw:fill-gradient-name %styleName; #IMPLIED>
+<!ATTLIST style:properties draw:gradient-step-count CDATA #IMPLIED>
+<!ATTLIST style:properties draw:fill-hatch-name %styleName; #IMPLIED>
+<!ATTLIST style:properties draw:fill-hatch-solid %boolean; #IMPLIED>
+<!ATTLIST style:properties draw:fill-image-name %styleName; #IMPLIED>
+<!ATTLIST style:properties style:repeat (no-repeat|repeat|stretch) #IMPLIED>
+<!ATTLIST style:properties draw:fill-image-width %lengthOrPercentage; #IMPLIED>
+<!ATTLIST style:properties draw:fill-image-height %lengthOrPercentage; #IMPLIED>
+<!ATTLIST style:properties draw:fill-image-ref-point-x %percentage; #IMPLIED>
+<!ATTLIST style:properties draw:fill-image-ref-point-y %percentage; #IMPLIED>
+<!ATTLIST style:properties draw:fill-image-ref-point %rectanglePoint; #IMPLIED>
+<!ATTLIST style:properties draw:tile-repeat-offset CDATA #IMPLIED>
+<!ATTLIST style:properties draw:transparency %percentage; #IMPLIED>
+<!ATTLIST style:properties draw:transparency-name %styleName; #IMPLIED>
+
+<!-- graphic attributes -->
+<!ATTLIST style:properties draw:color-mode (greyscale|mono|watermark|standard) #IMPLIED>
+<!ATTLIST style:properties draw:luminance %percentage; #IMPLIED>
+<!ATTLIST style:properties draw:contrast %percentage; #IMPLIED>
+<!ATTLIST style:properties draw:gamma %percentage; #IMPLIED>
+<!ATTLIST style:properties draw:red %percentage; #IMPLIED>
+<!ATTLIST style:properties draw:green %percentage; #IMPLIED>
+<!ATTLIST style:properties draw:blue %percentage; #IMPLIED>
+<!ATTLIST style:properties draw:color-inversion %boolean; #IMPLIED>
+
+<!-- shadow attributes -->
+<!ATTLIST style:properties draw:shadow (visible|hidden) #IMPLIED>
+<!ATTLIST style:properties draw:shadow-offset-x %length; #IMPLIED>
+<!ATTLIST style:properties draw:shadow-offset-y %length; #IMPLIED>
+<!ATTLIST style:properties draw:shadow-color %color; #IMPLIED>
+<!ATTLIST style:properties draw:shadow-transparency CDATA #IMPLIED>
+
+<!-- connector attributes -->
+<!ATTLIST style:properties draw:start-line-spacing-horizontal %distance; #IMPLIED>
+<!ATTLIST style:properties draw:start-line-spacing-vertical %distance; #IMPLIED>
+<!ATTLIST style:properties draw:end-line-spacing-horizontal %distance; #IMPLIED>
+<!ATTLIST style:properties draw:end-line-spacing-vertical %distance; #IMPLIED>
+
+<!-- measure attributes -->
+<!ATTLIST style:properties draw:line-distance %distance; #IMPLIED>
+<!ATTLIST style:properties draw:guide-overhang %distance; #IMPLIED>
+<!ATTLIST style:properties draw:guide-distance %distance; #IMPLIED>
+<!ATTLIST style:properties draw:start-guide %distance; #IMPLIED>
+<!ATTLIST style:properties draw:end-guide %distance; #IMPLIED>
+<!ATTLIST style:properties draw:measure-align (automatic|left-outside|inside|right-outside) #IMPLIED>
+<!ATTLIST style:properties draw:measure-vertical-align (automatic|above|below|center) #IMPLIED>
+<!ATTLIST style:properties draw:unit (automatic|mm|cm|m|km|pt|pc|inch|ft|mi) #IMPLIED>
+<!ATTLIST style:properties draw:show-unit %boolean; #IMPLIED>
+<!ATTLIST style:properties draw:placing (below|above) #IMPLIED>
+<!ATTLIST style:properties draw:parallel %boolean; #IMPLIED>
+
+<!-- frame attributes -->
+<!ATTLIST style:properties draw:frame-display-scrollbar %boolean; #IMPLIED>
+<!ATTLIST style:properties draw:frame-display-border %boolean; #IMPLIED>
+<!ATTLIST style:properties draw:frame-margin-horizontal %nonNegativePixelLength; #IMPLIED>
+<!ATTLIST style:properties draw:frame-margin-vertical %nonNegativePixelLength; #IMPLIED>
+<!ATTLIST style:properties draw:size-protect %boolean; #IMPLIED>
+<!ATTLIST style:properties draw:move-protect %boolean; #IMPLIED>
+
+<!-- ole object attributes -->
+<!ATTLIST style:properties draw:visible-area-left %nonNegativeLength; #IMPLIED>
+<!ATTLIST style:properties draw:visible-area-top %nonNegativeLength; #IMPLIED>
+<!ATTLIST style:properties draw:visible-area-width %positiveLength; #IMPLIED>
+<!ATTLIST style:properties draw:visible-area-height %positiveLength; #IMPLIED>
+
+<!-- fontwork attributes -->
+<!ATTLIST style:properties draw:fontwork-style (rotate|upright|slant-x|slant-y|none) #IMPLIED>
+<!ATTLIST style:properties draw:fontwork-adjust (left|right|autosize|center) #IMPLIED>
+<!ATTLIST style:properties draw:fontwork-distance %distance; #IMPLIED>
+<!ATTLIST style:properties draw:fontwork-start %distance; #IMPLIED>
+<!ATTLIST style:properties draw:fontwork-mirror %boolean; #IMPLIED>
+<!ATTLIST style:properties draw:fontwork-outline %boolean; #IMPLIED>
+<!ATTLIST style:properties draw:fontwork-shadow (normal|slant|none) #IMPLIED>
+<!ATTLIST style:properties draw:fontwork-shadow-color %color; #IMPLIED>
+<!ATTLIST style:properties draw:fontwork-shadow-offset-x %distance; #IMPLIED>
+<!ATTLIST style:properties draw:fontwork-shadow-offset-y %distance; #IMPLIED>
+<!ATTLIST style:properties draw:fontwork-form (none|top-circle|bottom-circle|left-circle|right-circle|top-arc|bottom-arc|left-arc|right-arc|button1|button2|button3|button4) #IMPLIED>
+<!ATTLIST style:properties draw:fontwork-hide-form %boolean; #IMPLIED>
+<!ATTLIST style:properties draw:fontwork-shadow-transparence %percentage; #IMPLIED>
+
+<!-- caption attributes -->
+<!ATTLIST style:properties draw:caption-type (straight-line|angled-line|angled-connector-line) #IMPLIED>
+<!ATTLIST style:properties draw:caption-angle-type (fixed|free) #IMPLIED>
+<!ATTLIST style:properties draw:caption-angle %nonNegativeInteger; #IMPLIED>
+<!ATTLIST style:properties draw:caption-gap %distance; #IMPLIED>
+<!ATTLIST style:properties draw:caption-escape-direction (horizontal|vertical|auto) #IMPLIED>
+<!ATTLIST style:properties draw:caption-escape %lengthOrPercentage; #IMPLIED>
+<!ATTLIST style:properties draw:caption-line-length %distance; #IMPLIED>
+<!ATTLIST style:properties draw:caption-fit-line-length %boolean; #IMPLIED>
+
+<!-- Animations -->
+<!ELEMENT presentation:sound EMPTY>
+<!ATTLIST presentation:sound xlink:href %uriReference; #REQUIRED>
+<!ATTLIST presentation:sound xlink:type (simple) #FIXED "simple">
+<!ATTLIST presentation:sound xlink:show (new|replace) #IMPLIED>
+<!ATTLIST presentation:sound xlink:actuate (onRequest) "onRequest">
+<!ATTLIST presentation:sound presentation:play-full %boolean; #IMPLIED>
+
+<!ELEMENT presentation:show-shape (presentation:sound)?>
+<!ATTLIST presentation:show-shape draw:shape-id CDATA #REQUIRED>
+<!ATTLIST presentation:show-shape presentation:effect %presentationEffects; "none">
+<!ATTLIST presentation:show-shape presentation:direction %presentationEffectDirections; "none">
+<!ATTLIST presentation:show-shape presentation:speed %presentationSpeeds; "medium">
+<!ATTLIST presentation:show-shape presentation:start-scale %percentage; "100%">
+<!ATTLIST presentation:show-shape presentation:path-id CDATA #IMPLIED >
+
+<!ELEMENT presentation:show-text (presentation:sound)?>
+<!ATTLIST presentation:show-text draw:shape-id CDATA #REQUIRED>
+<!ATTLIST presentation:show-text presentation:effect %presentationEffects; "none">
+<!ATTLIST presentation:show-text presentation:direction %presentationEffectDirections; "none">
+<!ATTLIST presentation:show-text presentation:speed %presentationSpeeds; "medium">
+<!ATTLIST presentation:show-text presentation:start-scale %percentage; "100%">
+<!ATTLIST presentation:show-text presentation:path-id CDATA #IMPLIED >
+
+<!ELEMENT presentation:hide-shape (presentation:sound)?>
+<!ATTLIST presentation:hide-shape draw:shape-id CDATA #REQUIRED>
+<!ATTLIST presentation:hide-shape presentation:effect %presentationEffects; "none">
+<!ATTLIST presentation:hide-shape presentation:direction %presentationEffectDirections; "none">
+<!ATTLIST presentation:hide-shape presentation:speed %presentationSpeeds; "medium">
+<!ATTLIST presentation:hide-shape presentation:start-scale %percentage; "100%">
+<!ATTLIST presentation:hide-shape presentation:path-id CDATA #IMPLIED >
+
+<!ELEMENT presentation:hide-text (presentation:sound)?>
+<!ATTLIST presentation:hide-text draw:shape-id CDATA #REQUIRED>
+<!ATTLIST presentation:hide-text presentation:effect %presentationEffects; "none">
+<!ATTLIST presentation:hide-text presentation:direction %presentationEffectDirections; "none">
+<!ATTLIST presentation:hide-text presentation:speed %presentationSpeeds; "medium">
+<!ATTLIST presentation:hide-text presentation:start-scale %percentage; "100%">
+<!ATTLIST presentation:hide-text presentation:path-id CDATA #IMPLIED >
+
+<!ELEMENT presentation:dim (presentation:sound)?>
+<!ATTLIST presentation:dim draw:shape-id CDATA #REQUIRED>
+<!ATTLIST presentation:dim draw:color %color; #REQUIRED>
+
+<!ELEMENT presentation:play EMPTY>
+<!ATTLIST presentation:play draw:shape-id CDATA #REQUIRED>
+<!ATTLIST presentation:play presentation:speed %presentationSpeeds; "medium">
+
+<!ELEMENT presentation:animations (presentation:show-shape|presentation:show-text|presentation:hide-shape|presentation:hide-text|presentation:dim|presentation:play)*>
+
+<!ELEMENT presentation:show EMPTY>
+<!ATTLIST presentation:show presentation:name %styleName; #REQUIRED>
+<!ATTLIST presentation:show presentation:pages CDATA #REQUIRED>
+
+<!ELEMENT presentation:settings (presentation:show)*>
+<!ATTLIST presentation:settings presentation:start-page %styleName; #IMPLIED>
+<!ATTLIST presentation:settings presentation:show %styleName; #IMPLIED>
+<!ATTLIST presentation:settings presentation:full-screen %boolean; "true">
+<!ATTLIST presentation:settings presentation:endless %boolean; "false">
+<!ATTLIST presentation:settings presentation:pause %timeDuration; #IMPLIED>
+<!ATTLIST presentation:settings presentation:show-logo %boolean; "false">
+<!ATTLIST presentation:settings presentation:force-manual %boolean; "false">
+<!ATTLIST presentation:settings presentation:mouse-visible %boolean; "true">
+<!ATTLIST presentation:settings presentation:mouse-as-pen %boolean; "false">
+<!ATTLIST presentation:settings presentation:start-with-navigator %boolean; "false">
+<!ATTLIST presentation:settings presentation:animations (enabled|disabled) "enabled">
+<!ATTLIST presentation:settings presentation:stay-on-top %boolean; "false">
+<!ATTLIST presentation:settings presentation:transition-on-click (enabled|disabled) "enabled">
+
+<!-- Drawing page -->
+<!ELEMENT draw:page (office:forms?,(%shapes;)*,presentation:animations?,presentation:notes?)>
+<!ATTLIST draw:page draw:name %string; #IMPLIED>
+<!ATTLIST draw:page draw:style-name %styleName; #IMPLIED>
+<!ATTLIST draw:page draw:master-page-name %styleName; #REQUIRED>
+<!ATTLIST draw:page presentation:presentation-page-layout-name %styleName; #IMPLIED>
+<!ATTLIST draw:page draw:id %nonNegativeInteger; #IMPLIED>
+
+<!-- Presentation notes -->
+<!ELEMENT presentation:notes (%shapes;)*>
+
+
+<!-- presentation page layouts -->
+<!ELEMENT style:presentation-page-layout (presentation:placeholder)* >
+<!ATTLIST style:presentation-page-layout style:name %styleName; #REQUIRED>
+<!ELEMENT presentation:placeholder EMPTY >
+<!ATTLIST presentation:placeholder presentation:object (title|outline|subtitle|text|graphic|object|chart|orgchart|page|notes|handout) #REQUIRED>
+<!ATTLIST presentation:placeholder svg:x %coordinateOrPercentage; #REQUIRED>
+<!ATTLIST presentation:placeholder svg:y %coordinateOrPercentage; #REQUIRED>
+<!ATTLIST presentation:placeholder svg:width %lengthOrPercentage; #REQUIRED>
+<!ATTLIST presentation:placeholder svg:height %lengthOrPercentage; #REQUIRED>
+
+<!-- presentation page attributes -->
+<!ATTLIST style:properties presentation:transition-type (manual|automatic|semi-automatic) #IMPLIED >
+<!ATTLIST style:properties presentation:transition-style (none|fade-from-left|fade-from-top|fade-from-right|fade-from-bottom|fade-to-center|fade-from-center|move-from-left|move-from-top|move-from-right|move-from-bottom|roll-from-top|roll-from-left|roll-from-right|roll-from-bottom|vertical-stripes|horizontal-stripes|clockwise|counterclockwise|fade-from-upperleft|fade-from-upperright|fade-from-lowerleft|fade-from-lowerright|close-vertical|close-horizontal|open-vertical|open-horizontal|spiralin-left|spiralin-right|spiralout-left|spiralout-right|dissolve|wavyline-from-left|wavyline-from-top|wavyline-from-right|wavyline-from-bottom|random|stretch-from-left|stretch-from-top|stretch-from-right|stretch-from-bottom|vertical-lines|horizontal-lines) #IMPLIED >
+<!ATTLIST style:properties presentation:transition-speed %presentationSpeeds; #IMPLIED >
+<!ATTLIST style:properties presentation:duration %timeDuration; #IMPLIED>
+<!ATTLIST style:properties presentation:visibility (visible|hidden) #IMPLIED>
+<!ATTLIST style:properties draw:background-size (full|border) #IMPLIED>
+<!ATTLIST style:properties presentation:background-objects-visible %boolean; #IMPLIED>
+<!ATTLIST style:properties presentation:background-visible %boolean; #IMPLIED>
+
+
+<!-- text boxes -->
+<!ELEMENT draw:text-box (office:events?,draw:image-map?,
+ (text:h|text:p|text:ordered-list|
+ text:unordered-list|table:table|chart:chart|
+ draw:a|draw:text-box|draw:image)*)>
+<!ATTLIST draw:text-box %draw-style-name;>
+<!ATTLIST draw:text-box %draw-transform; >
+<!ATTLIST draw:text-box draw:name %string; #IMPLIED>
+<!ATTLIST draw:text-box draw:chain-next-name %string; #IMPLIED>
+
+<!ATTLIST draw:text-box %text-anchor;>
+<!ATTLIST draw:text-box %draw-position;>
+<!ATTLIST draw:text-box %draw-end-position; >
+<!ATTLIST draw:text-box %table-background; >
+<!ATTLIST draw:text-box svg:width %lengthOrPercentage; #IMPLIED>
+<!ATTLIST draw:text-box svg:height %lengthOrPercentage; #IMPLIED>
+<!ATTLIST draw:text-box fo:min-height %lengthOrPercentage; #IMPLIED>
+<!ATTLIST draw:text-box %zindex;>
+<!ATTLIST draw:text-box %presentation-class; >
+<!ATTLIST draw:text-box %draw-transform; >
+<!ATTLIST draw:text-box draw:id %draw-shape-id;>
+<!ATTLIST draw:text-box draw:layer %layerName; #IMPLIED>
+
+<!-- image -->
+<!ELEMENT draw:image (office:binary-data?,office:events?,draw:image-map?,svg:desc?,(draw:contour-polygon|draw:contour-path)?)>
+<!ATTLIST draw:image %draw-style-name;>
+<!ATTLIST draw:image draw:name %string; #IMPLIED>
+<!ATTLIST draw:image xlink:href %uriReference; #IMPLIED>
+<!ATTLIST draw:image xlink:type (simple) #IMPLIED>
+<!ATTLIST draw:image xlink:show (embed) #IMPLIED>
+<!ATTLIST draw:image xlink:actuate (onLoad) #IMPLIED>
+<!ATTLIST draw:image draw:filter-name %string; #IMPLIED>
+<!ATTLIST draw:image %text-anchor;>
+<!ATTLIST draw:image %draw-position;>
+<!ATTLIST draw:image %draw-end-position; >
+<!ATTLIST draw:image %table-background; >
+<!ATTLIST draw:image svg:width %lengthOrPercentage; #IMPLIED>
+<!ATTLIST draw:image svg:height %lengthOrPercentage; #IMPLIED>
+<!ATTLIST draw:image %presentation-class; >
+<!ATTLIST draw:image %zindex;>
+<!ATTLIST draw:image draw:id %draw-shape-id;>
+<!ATTLIST draw:image draw:layer %layerName; #IMPLIED>
+
+<!-- objects -->
+<!ELEMENT draw:thumbnail EMPTY>
+<!ATTLIST draw:thumbnail xlink:href %uriReference; #REQUIRED>
+<!ATTLIST draw:thumbnail xlink:type (simple) #IMPLIED>
+<!ATTLIST draw:thumbnail xlink:show (embed) #IMPLIED>
+<!ATTLIST draw:thumbnail xlink:actuate (onLoad) #IMPLIED>
+
+<!ELEMENT math:math ANY> <!-- dummy (we have no MathML DTD currently)-->
+<!ELEMENT draw:object (draw:thumbnail?,(office:document|math:math)?,office:events?, draw:image-map?, svg:desc?,(draw:contour-polygon|draw:contour-path)?)>
+<!ATTLIST draw:object %draw-style-name;>
+<!ATTLIST draw:object draw:name %string; #IMPLIED>
+<!ATTLIST draw:object xlink:href %uriReference; #IMPLIED>
+<!ATTLIST draw:object xlink:type (simple) #IMPLIED>
+<!ATTLIST draw:object xlink:show (embed) #IMPLIED>
+<!ATTLIST draw:object xlink:actuate (onLoad) #IMPLIED>
+<!ATTLIST draw:object %text-anchor;>
+<!ATTLIST draw:object %draw-position;>
+<!ATTLIST draw:object %draw-end-position; >
+<!ATTLIST draw:object %table-background; >
+<!ATTLIST draw:object svg:width %lengthOrPercentage; #IMPLIED>
+<!ATTLIST draw:object svg:height %lengthOrPercentage; #IMPLIED>
+<!ATTLIST draw:object %presentation-class; >
+<!ATTLIST draw:object %zindex;>
+<!ATTLIST draw:object draw:id %draw-shape-id;>
+<!ATTLIST draw:object draw:layer %layerName; #IMPLIED>
+<!ATTLIST draw:object draw:notify-on-update-of-ranges %string; #IMPLIED>
+
+<!ELEMENT draw:object-ole (office:binary-data?|office:events?|draw:image-map?|svg:desc?|draw:contour-polygon?|draw:contour-path?|draw:thumbnail?)>
+<!ATTLIST draw:object-ole draw:class-id CDATA #IMPLIED>
+<!ATTLIST draw:object-ole %draw-style-name;>
+<!ATTLIST draw:object-ole draw:name %string; #IMPLIED>
+<!ATTLIST draw:object-ole xlink:href %uriReference; #IMPLIED>
+<!ATTLIST draw:object-ole xlink:type (simple) #IMPLIED>
+<!ATTLIST draw:object-ole xlink:show (embed) #IMPLIED>
+<!ATTLIST draw:object-ole xlink:actuate (onLoad) #IMPLIED>
+<!ATTLIST draw:object-ole %text-anchor;>
+<!ATTLIST draw:object-ole %draw-position;>
+<!ATTLIST draw:object-ole %draw-end-position; >
+<!ATTLIST draw:object-ole %table-background; >
+<!ATTLIST draw:object-ole svg:width %lengthOrPercentage; #IMPLIED>
+<!ATTLIST draw:object-ole svg:height %lengthOrPercentage; #IMPLIED>
+<!ATTLIST draw:object-ole %presentation-class; >
+<!ATTLIST draw:object-ole %zindex;>
+<!ATTLIST draw:object-ole draw:id %draw-shape-id;>
+<!ATTLIST draw:object-ole draw:layer %layerName; #IMPLIED>
+
+<!ELEMENT svg:desc (#PCDATA)>
+
+<!ELEMENT draw:contour-polygon EMPTY>
+<!ATTLIST draw:contour-polygon svg:width %coordinate; #REQUIRED>
+<!ATTLIST draw:contour-polygon svg:height %coordinate; #REQUIRED>
+<!ATTLIST draw:contour-polygon %draw-viewbox;>
+<!ATTLIST draw:contour-polygon svg:points %points; #REQUIRED>
+
+<!ELEMENT draw:contour-path EMPTY>
+<!ATTLIST draw:contour-path svg:width %coordinate; #REQUIRED>
+<!ATTLIST draw:contour-path svg:height %coordinate; #REQUIRED>
+<!ATTLIST draw:contour-path %draw-viewbox;>
+<!ATTLIST draw:contour-path svg:d %pathData; #REQUIRED>
+
+<!-- hyperlink -->
+<!ELEMENT draw:a (draw:image|draw:text-box)>
+<!ATTLIST draw:a xlink:href %uriReference; #REQUIRED>
+<!ATTLIST draw:a xlink:type (simple) #FIXED "simple">
+<!ATTLIST draw:a xlink:show (new|replace) #IMPLIED>
+<!ATTLIST draw:a xlink:actuate (onRequest) "onRequest">
+<!ATTLIST draw:a office:name %string; #IMPLIED>
+<!ATTLIST draw:a office:target-frame-name %string; #IMPLIED>
+<!ATTLIST draw:a office:server-map %boolean; "false">
+
+<!-- 3d properties -->
+<!ATTLIST style:properties dr3d:horizontal-segments %nonNegativeInteger; #IMPLIED>
+<!ATTLIST style:properties dr3d:vertical-segments %nonNegativeInteger; #IMPLIED>
+<!ATTLIST style:properties dr3d:edge-rounding %percentage; #IMPLIED>
+<!ATTLIST style:properties dr3d:edge-rounding-mode (correct|attractive) #IMPLIED>
+<!ATTLIST style:properties dr3d:back-scale %percentage; #IMPLIED>
+<!ATTLIST style:properties dr3d:end-angle %nonNegativeInteger; #IMPLIED>
+<!ATTLIST style:properties dr3d:depth %length; #IMPLIED>
+<!ATTLIST style:properties dr3d:backface-culling (enabled|disabled) #IMPLIED>
+<!ATTLIST style:properties dr3d:lighting-mode (standard|double-sided) #IMPLIED>
+<!ATTLIST style:properties dr3d:normals-kind (object|flat|sphere) #IMPLIED>
+<!ATTLIST style:properties dr3d:normals-direction (normal|inverse) #IMPLIED>
+<!ATTLIST style:properties dr3d:texture-generation-mode-x (object|parallel|sphere) #IMPLIED>
+<!ATTLIST style:properties dr3d:texture-generation-mode-y (object|parallel|sphere) #IMPLIED>
+<!ATTLIST style:properties dr3d:texture-kind (luminance|intesity|color) #IMPLIED>
+<!ATTLIST style:properties dr3d:texture-filter (enabled|disabled) #IMPLIED>
+<!ATTLIST style:properties dr3d:texture-mode (replace|modulate|blend) #IMPLIED>
+<!ATTLIST style:properties dr3d:ambient-color %color; #IMPLIED>
+<!ATTLIST style:properties dr3d:emissive-color %color; #IMPLIED>
+<!ATTLIST style:properties dr3d:specular-color %color; #IMPLIED>
+<!ATTLIST style:properties dr3d:diffuse-color %color; #IMPLIED>
+<!ATTLIST style:properties dr3d:shininess %percentage; #IMPLIED>
+<!ATTLIST style:properties dr3d:shadow (visible|hidden) #IMPLIED>
+
+<!ELEMENT dr3d:light EMPTY>
+<!ATTLIST dr3d:light dr3d:diffuse-color %color; #IMPLIED>
+<!ATTLIST dr3d:light dr3d:direction %vector3D; #REQUIRED>
+<!ATTLIST dr3d:light dr3d:enabled %boolean; #IMPLIED>
+<!ATTLIST dr3d:light dr3d:specular %boolean; #IMPLIED>
+
+<!ENTITY % shapes3d "(dr3d:scene|dr3d:extrude|dr3d:sphere|dr3d:rotate|dr3d:cube)">
+
+<!ELEMENT dr3d:cube EMPTY>
+<!ATTLIST dr3d:cube dr3d:transform CDATA #IMPLIED>
+<!ATTLIST dr3d:cube dr3d:min-edge %vector3D; #IMPLIED>
+<!ATTLIST dr3d:cube dr3d:max-edge %vector3D; #IMPLIED>
+<!ATTLIST dr3d:cube %zindex;>
+<!ATTLIST dr3d:cube draw:id %draw-shape-id;>
+<!ATTLIST dr3d:cube %draw-end-position; >
+<!ATTLIST dr3d:cube %table-background; >
+<!ATTLIST dr3d:cube %draw-style-name; >
+<!ATTLIST dr3d:cube draw:layer %layerName; #IMPLIED>
+
+<!ELEMENT dr3d:sphere EMPTY>
+<!ATTLIST dr3d:sphere dr3d:transform CDATA #IMPLIED>
+<!ATTLIST dr3d:sphere dr3d:center %vector3D; #IMPLIED>
+<!ATTLIST dr3d:sphere dr3d:size %vector3D; #IMPLIED>
+<!ATTLIST dr3d:sphere %zindex;>
+<!ATTLIST dr3d:sphere draw:id %draw-shape-id;>
+<!ATTLIST dr3d:sphere %draw-end-position; >
+<!ATTLIST dr3d:sphere %table-background; >
+<!ATTLIST dr3d:sphere %draw-style-name; >
+<!ATTLIST dr3d:sphere draw:layer %layerName; #IMPLIED>
+
+<!ELEMENT dr3d:extrude EMPTY>
+<!ATTLIST dr3d:extrude dr3d:transform CDATA #IMPLIED>
+<!ATTLIST dr3d:extrude %draw-viewbox;>
+<!ATTLIST dr3d:extrude svg:d %pathData; #REQUIRED >
+<!ATTLIST dr3d:extrude %zindex;>
+<!ATTLIST dr3d:extrude draw:id %draw-shape-id;>
+<!ATTLIST dr3d:extrude %draw-end-position; >
+<!ATTLIST dr3d:extrude %table-background; >
+<!ATTLIST dr3d:extrude %draw-style-name; >
+<!ATTLIST dr3d:extrude draw:layer %layerName; #IMPLIED>
+
+<!ELEMENT dr3d:rotate EMPTY>
+<!ATTLIST dr3d:rotate dr3d:transform CDATA #IMPLIED>
+<!ATTLIST dr3d:rotate %draw-viewbox;>
+<!ATTLIST dr3d:rotate svg:d %pathData; #REQUIRED >
+<!ATTLIST dr3d:rotate %zindex;>
+<!ATTLIST dr3d:rotate draw:id %draw-shape-id;>
+<!ATTLIST dr3d:rotate %draw-end-position; >
+<!ATTLIST dr3d:rotate %table-background; >
+<!ATTLIST dr3d:rotate %draw-style-name; >
+<!ATTLIST dr3d:rotate draw:layer %layerName; #IMPLIED>
+
+<!ELEMENT dr3d:scene (dr3d:light*,(%shapes3d;)*)>
+<!ATTLIST dr3d:scene %draw-style-name; >
+<!ATTLIST dr3d:scene svg:x %coordinate; #IMPLIED>
+<!ATTLIST dr3d:scene svg:y %coordinate; #IMPLIED>
+<!ATTLIST dr3d:scene svg:width %length; #IMPLIED>
+<!ATTLIST dr3d:scene svg:height %length; #IMPLIED>
+<!ATTLIST dr3d:scene dr3d:vrp %vector3D; #IMPLIED>
+<!ATTLIST dr3d:scene dr3d:vpn %vector3D; #IMPLIED>
+<!ATTLIST dr3d:scene dr3d:vup %vector3D; #IMPLIED>
+<!ATTLIST dr3d:scene dr3d:projection (parallel|perspective) #IMPLIED>
+<!ATTLIST dr3d:scene dr3d:transform CDATA #IMPLIED>
+<!ATTLIST dr3d:scene dr3d:distance %length; #IMPLIED>
+<!ATTLIST dr3d:scene dr3d:focal-length %length; #IMPLIED>
+<!ATTLIST dr3d:scene dr3d:shadow-slant %nonNegativeInteger; #IMPLIED>
+<!ATTLIST dr3d:scene dr3d:shade-mode (flat|phong|gouraud|draft) #IMPLIED>
+<!ATTLIST dr3d:scene dr3d:ambient-color %color; #IMPLIED>
+<!ATTLIST dr3d:scene dr3d:lighting-mode %boolean; #IMPLIED>
+<!ATTLIST dr3d:scene %zindex;>
+<!ATTLIST dr3d:scene draw:id %draw-shape-id;>
+<!ATTLIST dr3d:scene %draw-end-position; >
+<!ATTLIST dr3d:scene %table-background; >
+
+<!-- layer -->
+
+<!ELEMENT draw:layer-set (draw:layer*)>
+
+<!ELEMENT draw:layer EMPTY>
+<!ATTLIST draw:layer draw:name %layerName; #REQUIRED>
+
+<!-- events -->
+<!ELEMENT presentation:event (presentation:sound)?>
+<!ATTLIST presentation:event %event-name;>
+<!ATTLIST presentation:event presentation:action (none|previous-page|next-page|first-page|last-page|hide|stop|execute|show|verb|fade-out|sound) #REQUIRED>
+<!ATTLIST presentation:event presentation:effect %presentationEffects; "none">
+<!ATTLIST presentation:event presentation:direction %presentationEffectDirections; "none">
+<!ATTLIST presentation:event presentation:speed %presentationSpeeds; "medium">
+<!ATTLIST presentation:event presentation:start-scale %percentage; "100%">
+<!ATTLIST presentation:event xlink:href %uriReference; #IMPLIED>
+<!ATTLIST presentation:event xlink:type (simple) #IMPLIED>
+<!ATTLIST presentation:event xlink:show (embed) #IMPLIED>
+<!ATTLIST presentation:event xlink:actuate (onRequest) #IMPLIED>
+<!ATTLIST presentation:event presentation:verb %nonNegativeInteger; #IMPLIED>
+
+<!-- applets -->
+<!ELEMENT draw:applet (draw:thumbnail?, draw:param*, svg:desc?)>
+<!ATTLIST draw:applet xlink:href %uriReference; #IMPLIED>
+<!ATTLIST draw:applet xlink:type (simple) #IMPLIED>
+<!ATTLIST draw:applet xlink:show (embed) #IMPLIED>
+<!ATTLIST draw:applet xlink:actuate (onLoad) #IMPLIED>
+<!ATTLIST draw:applet draw:code CDATA #REQUIRED>
+<!ATTLIST draw:applet draw:object CDATA #IMPLIED>
+<!ATTLIST draw:applet draw:archive CDATA #IMPLIED>
+<!ATTLIST draw:applet draw:may-script %boolean; "false">
+<!ATTLIST draw:applet draw:name CDATA #IMPLIED>
+<!ATTLIST draw:applet %draw-style-name;>
+<!ATTLIST draw:applet svg:width %lengthOrPercentage; #IMPLIED>
+<!ATTLIST draw:applet svg:height %lengthOrPercentage; #IMPLIED>
+<!ATTLIST draw:applet %zindex;>
+<!ATTLIST draw:applet draw:layer %layerName; #IMPLIED>
+<!ATTLIST draw:applet %draw-position;>
+<!ATTLIST draw:applet %draw-end-position; >
+
+<!-- plugins -->
+<!ELEMENT draw:plugin (draw:thumbnail?, draw:param*, svg:desc?)>
+<!ATTLIST draw:plugin xlink:href %uriReference; #IMPLIED>
+<!ATTLIST draw:plugin xlink:type (simple) #IMPLIED>
+<!ATTLIST draw:plugin xlink:show (embed) #IMPLIED>
+<!ATTLIST draw:plugin xlink:actuate (onLoad) #IMPLIED>
+<!ATTLIST draw:plugin draw:mime-type CDATA #IMPLIED>
+<!ATTLIST draw:plugin draw:name CDATA #IMPLIED>
+<!ATTLIST draw:plugin %draw-style-name;>
+<!ATTLIST draw:plugin svg:width %lengthOrPercentage; #IMPLIED>
+<!ATTLIST draw:plugin svg:height %lengthOrPercentage; #IMPLIED>
+<!ATTLIST draw:plugin %zindex;>
+<!ATTLIST draw:plugin draw:layer %layerName; #IMPLIED>
+<!ATTLIST draw:plugin %draw-position;>
+<!ATTLIST draw:plugin %draw-end-position; >
+
+<!-- Paramaters -->
+<!ELEMENT draw:param EMPTY>
+<!ATTLIST draw:param draw:name CDATA #IMPLIED>
+<!ATTLIST draw:param draw:value CDATA #IMPLIED>
+
+<!-- Floating Frames -->
+<!ELEMENT draw:floating-frame (draw:thumbnail?, svg:desc?)>
+<!ATTLIST draw:floating-frame xlink:href %uriReference; #IMPLIED>
+<!ATTLIST draw:floating-frame xlink:type (simple) #IMPLIED>
+<!ATTLIST draw:floating-frame xlink:show (embed) #IMPLIED>
+<!ATTLIST draw:floating-frame xlink:actuate (onLoad) #IMPLIED>
+<!ATTLIST draw:floating-frame draw:name CDATA #IMPLIED>
+<!ATTLIST draw:floating-frame draw:frame-name CDATA #IMPLIED>
+<!ATTLIST draw:floating-frame %draw-style-name;>
+<!ATTLIST draw:floating-frame svg:width %lengthOrPercentage; #IMPLIED>
+<!ATTLIST draw:floating-frame svg:height %lengthOrPercentage; #IMPLIED>
+<!ATTLIST draw:floating-frame %zindex;>
+<!ATTLIST draw:floating-frame draw:layer %layerName; #IMPLIED>
+<!ATTLIST draw:floating-frame %draw-position;>
+<!ATTLIST draw:floating-frame %draw-end-position; >
+
+<!-- Image Maps -->
+<!ELEMENT draw:image-map
+ (draw:area-rectangle|draw:area-circle|draw:area-polygon)*>
+
+<!ELEMENT draw:area-rectangle (svg:desc?,office:events?)>
+<!ATTLIST draw:area-rectangle xlink:href %uriReference; #IMPLIED>
+<!ATTLIST draw:area-rectangle xlink:type (simple) #IMPLIED>
+<!ATTLIST draw:area-rectangle office:target-frame-name CDATA #IMPLIED>
+<!ATTLIST draw:area-rectangle xlink:show (new|replace) #IMPLIED>
+<!ATTLIST draw:area-rectangle office:name CDATA #IMPLIED>
+<!ATTLIST draw:area-rectangle draw:nohref (nohref) #IMPLIED>
+<!ATTLIST draw:area-rectangle svg:x %coordinate; #REQUIRED>
+<!ATTLIST draw:area-rectangle svg:y %coordinate; #REQUIRED>
+<!ATTLIST draw:area-rectangle svg:width %coordinate; #REQUIRED>
+<!ATTLIST draw:area-rectangle svg:height %coordinate; #REQUIRED>
+
+<!ELEMENT draw:area-circle (svg:desc?,office:events?)>
+<!ATTLIST draw:area-circle xlink:href %uriReference; #IMPLIED>
+<!ATTLIST draw:area-circle xlink:type (simple) #IMPLIED>
+<!ATTLIST draw:area-circle office:target-frame-name CDATA #IMPLIED>
+<!ATTLIST draw:area-circle xlink:show (new|replace) #IMPLIED>
+<!ATTLIST draw:area-circle office:name CDATA #IMPLIED>
+<!ATTLIST draw:area-circle draw:nohref (nohref) #IMPLIED>
+<!ATTLIST draw:area-circle svg:cx %coordinate; #REQUIRED>
+<!ATTLIST draw:area-circle svg:cy %coordinate; #REQUIRED>
+<!ATTLIST draw:area-circle svg:r %coordinate; #REQUIRED>
+
+<!ELEMENT draw:area-polygon (svg:desc?,office:events?)>
+<!ATTLIST draw:area-polygon xlink:href %uriReference; #IMPLIED>
+<!ATTLIST draw:area-polygon xlink:type (simple) #IMPLIED>
+<!ATTLIST draw:area-polygon office:target-frame-name CDATA #IMPLIED>
+<!ATTLIST draw:area-polygon xlink:show (new|replace) #IMPLIED>
+<!ATTLIST draw:area-polygon office:name CDATA #IMPLIED>
+<!ATTLIST draw:area-polygon draw:nohref (nohref) #IMPLIED>
+<!ATTLIST draw:area-polygon svg:x %coordinate; #REQUIRED>
+<!ATTLIST draw:area-polygon svg:y %coordinate; #REQUIRED>
+<!ATTLIST draw:area-polygon svg:width %coordinate; #REQUIRED>
+<!ATTLIST draw:area-polygon svg:height %coordinate; #REQUIRED>
+<!ATTLIST draw:area-polygon svg:points %points; #REQUIRED>
+<!ATTLIST draw:area-polygon svg:viewBox CDATA #REQUIRED>
diff --git a/xmerge/source/palmtests/qa/comparator/dtd/dtypes.mod b/xmerge/source/palmtests/qa/comparator/dtd/dtypes.mod
new file mode 100644
index 000000000000..e4d640d012c8
--- /dev/null
+++ b/xmerge/source/palmtests/qa/comparator/dtd/dtypes.mod
@@ -0,0 +1,143 @@
+<!--
+
+ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+
+ Copyright 2000, 2010 Oracle and/or its affiliates.
+
+ OpenOffice.org - a multi-platform office productivity suite
+
+ This file is part of OpenOffice.org.
+
+ OpenOffice.org is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License version 3
+ only, as published by the Free Software Foundation.
+
+ OpenOffice.org is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License version 3 for more details
+ (a copy is included in the LICENSE file that accompanied this code).
+
+ You should have received a copy of the GNU Lesser General Public License
+ version 3 along with OpenOffice.org. If not, see
+ <http://www.openoffice.org/license.html>
+ for a copy of the LGPLv3 License.
+
+-->
+
+<!-- datatypes corresponding to XML Schema Part 2 W3C Working draft of -->
+<!-- 07 April 2000 -->
+
+<!-- string -->
+<!ENTITY % string "CDATA">
+<!ENTITY % cString "#PCDATA">
+
+<!-- boolean (values are "true" and "false" -->
+<!ENTITY % boolean "CDATA">
+
+<!-- integer ( ..., -2, -1, 0, 1, 2, ...) -->
+<!ENTITY % integer "CDATA">
+
+<!-- non negative integer ( 0, 1, 2, ...) -->
+<!ENTITY % nonNegativeInteger "CDATA">
+
+<!-- positive integer ( 1, 2, ...) -->
+<!ENTITY % positiveInteger "CDATA">
+<!ENTITY % cPositiveInteger "#PCDATA">
+
+<!ENTITY % positiveNumberOrDefault "CDATA">
+
+<!-- time duration as specified by ISO8601, section 5.5.3.2 -->
+<!ENTITY % timeDuration "CDATA">
+<!ENTITY % cTimeDuration "#PCDATA">
+
+<!-- time instance as specified by ISO8601, section 5.4 -->
+<!ENTITY % timeInstance "CDATA">
+<!ENTITY % cTimeInstance "#PCDATA">
+
+<!-- date instance as specified by ISO8601, section 5.2.1.1, extended format-->
+<!ENTITY % date "CDATA">
+<!ENTITY % cDate "#PCDATA">
+
+<!-- date duration, like timDuration but truncated to full dates -->
+<!ENTITY % dateDuration "CDATA">
+<!ENTITY % cDateDuration "#PCDATA">
+
+<!-- URI reference -->
+<!ENTITY % uriReference "CDATA">
+
+<!-- language code as specified by RFC1766 -->
+<!ENTITY % language "CDATA">
+<!ENTITY % cLanguage "#PCDATA">
+
+<!-- float -->
+<!ENTITY % float "CDATA">
+
+<!-- Some other common used data types -->
+
+<!-- a single UNICODE character -->
+<!ENTITY % character "CDATA">
+
+<!-- a style name -->
+<!ENTITY % styleName "CDATA">
+
+<!-- a target frame mame -->
+<!ENTITY % targetFrameName "CDATA">
+
+<!-- a language without a country as specified by ISO639 -->
+<!ENTITY % languageOnly "CDATA">
+
+<!-- a country as specified by ISO3166 -->
+<!ENTITY % country "CDATA">
+
+<!-- a color value having the format #rrggbb -->
+<!ENTITY % color "CDATA">
+<!-- a color value having the format #rrggbb or "transparent" -->
+<!ENTITY % transparentOrColor "CDATA">
+
+<!-- a percentage -->
+<!ENTITY % percentage "CDATA">
+
+<!-- a length (i.e. 1cm or .6inch) -->
+<!ENTITY % length "CDATA">
+<!ENTITY % positiveLength "CDATA">
+<!ENTITY % nonNegativeLength "CDATA">
+<!ENTITY % lengthOrNoLimit "CDATA">
+
+<!-- a length or a percentage -->
+<!ENTITY % lengthOrPercentage "CDATA">
+<!ENTITY % positiveLengthOrPercentage "CDATA">
+
+<!-- a pixel length (i.e. 2px) -->
+<!ENTITY % nonNegativePixelLength "CDATA">
+
+<!-- a float or a percentage -->
+<!ENTITY % floatOrPercentage "CDATA">
+
+<!-- a text encoding -->
+<!ENTITY % textEncoding "CDATA">
+
+<!-- cell address and cell range address -->
+<!ENTITY % cell-address "CDATA">
+<!ENTITY % cell-range-address "CDATA">
+<!ENTITY % cell-range-address-list "CDATA">
+
+<!-- value types -->
+<!ENTITY % valueType "(float|time|date|percentage|currency|boolean|string)">
+
+<!-- an svg coordinate in different distance formats -->
+<!ENTITY % coordinate "CDATA">
+
+<!ENTITY % coordinateOrPercentage "CDATA">
+
+<!ENTITY % shape "draw:rect|draw:line|draw:polyline|draw:polygon|draw:path|
+ draw:circle|draw:ellipse|draw:g|draw:page-thumbnail|
+ draw:text-box|draw:image|draw:object|draw:object-ole|
+ draw:applet|draw:floating-frame|draw:plugin|
+ draw:measure|draw:caption|draw:connector|chart:chart|
+ dr3d:scene|draw:control" >
+<!ENTITY % shapes "(%shape;)" >
+
+<!ENTITY % anchorType "(page|frame|paragraph|char|as-char)">
+
+<!ENTITY % control-id "form:id CDATA #REQUIRED">
diff --git a/xmerge/source/palmtests/qa/comparator/dtd/form.mod b/xmerge/source/palmtests/qa/comparator/dtd/form.mod
new file mode 100644
index 000000000000..77a91206c451
--- /dev/null
+++ b/xmerge/source/palmtests/qa/comparator/dtd/form.mod
@@ -0,0 +1,308 @@
+<!--
+
+ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+
+ Copyright 2000, 2010 Oracle and/or its affiliates.
+
+ OpenOffice.org - a multi-platform office productivity suite
+
+ This file is part of OpenOffice.org.
+
+ OpenOffice.org is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License version 3
+ only, as published by the Free Software Foundation.
+
+ OpenOffice.org is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License version 3 for more details
+ (a copy is included in the LICENSE file that accompanied this code).
+
+ You should have received a copy of the GNU Lesser General Public License
+ version 3 along with OpenOffice.org. If not, see
+ <http://www.openoffice.org/license.html>
+ for a copy of the LGPLv3 License.
+
+-->
+
+<!ENTITY % controls "form:text|form:textarea|form:fixed-text|form:file|
+ form:password|form:formatted-text|form:button|form:image|
+ form:checkbox|form:radio|form:listbox|form:combobox|form:frame|
+ form:hidden|form:image-frame|form:grid|form:generic-control">
+
+<!ENTITY % name "form:name CDATA #IMPLIED">
+<!ENTITY % service-name "form:service-name CDATA #IMPLIED">
+
+<!ENTITY % navigation "(none|current|parent)">
+<!ENTITY % cycles "(records|current|page)">
+<!ENTITY % url "CDATA">
+
+
+<!ENTITY % types "(submit|reset|push|url)">
+<!ENTITY % button-type "form:button-type %types; 'push'">
+<!ENTITY % current-selected "form:current-selected %boolean; 'false'">
+<!ENTITY % current-value "form:current-value CDATA #IMPLIED">
+<!ENTITY % value "form:value CDATA #IMPLIED">
+<!ENTITY % disabled "form:disabled %boolean; 'false'">
+<!ENTITY % dropdown "form:dropdown %boolean; 'false'">
+<!ENTITY % for "form:for CDATA #IMPLIED">
+<!ENTITY % image-data "form:image-data %url; #IMPLIED">
+<!ENTITY % label "form:label CDATA #IMPLIED">
+<!ENTITY % max-length "form:max-length CDATA #IMPLIED">
+<!ENTITY % printable "form:printable %boolean; 'true'">
+<!ENTITY % readonly "form:readonly %boolean; 'false'">
+<!ENTITY % size "form:size CDATA #IMPLIED">
+<!ENTITY % selected "form:selected %boolean; 'false'">
+<!ENTITY % size "form:size CDATA #IMPLIED">
+<!ENTITY % tab-index "form:tab-index CDATA #IMPLIED">
+<!ENTITY % target-frame "office:target-frame CDATA '_blank'">
+<!ENTITY % target-location "xlink:href %url; #IMPLIED">
+<!ENTITY % tab-stop "form:tab-stop %boolean; 'true'">
+<!ENTITY % title "form:title CDATA #IMPLIED">
+<!ENTITY % default-value "form:default-value CDATA #IMPLIED">
+<!ENTITY % bound-column "form:bound-column CDATA #IMPLIED">
+<!ENTITY % convert-empty "form:convert-empty-to-null %boolean; 'false'">
+<!ENTITY % data-field "form:data-field CDATA #IMPLIED">
+<!ENTITY % list-source "form:list-source CDATA #IMPLIED">
+<!ENTITY % list-source-types "(table|query|sql|sql-pass-through|value-list|table-fields)">
+<!ENTITY % list-source-type "form:list-source-type %list-source-types; #IMPLIED">
+
+<!ELEMENT form:control (%controls;)+>
+<!ATTLIST form:control %name;
+ %service-name;
+ %control-id;>
+
+<!ELEMENT form:form (form:properties?, office:events?, (form:control|form:form)*)>
+<!ATTLIST form:form %name; %service-name;>
+<!ATTLIST form:form xlink:href %url; #IMPLIED>
+<!ATTLIST form:form form:enctype CDATA "application/x-www-form-urlencoded">
+<!ATTLIST form:form form:method CDATA "get">
+<!ATTLIST form:form office:target-frame CDATA "_blank">
+<!ATTLIST form:form form:allow-deletes %boolean; "true">
+<!ATTLIST form:form form:allow-inserts %boolean; "true">
+<!ATTLIST form:form form:allow-updates %boolean; "true">
+<!ATTLIST form:form form:apply-filter %boolean; "false">
+<!ATTLIST form:form form:command CDATA #IMPLIED>
+<!ATTLIST form:form form:command-type (table|query|command) "command">
+<!ATTLIST form:form form:datasource CDATA #IMPLIED>
+<!ATTLIST form:form form:detail-fields CDATA #IMPLIED>
+<!ATTLIST form:form form:escape-processing %boolean; "true">
+<!ATTLIST form:form form:filter CDATA #IMPLIED>
+<!ATTLIST form:form form:ignore-result %boolean; "false">
+<!ATTLIST form:form form:master-fields CDATA #IMPLIED>
+<!ATTLIST form:form form:navigation-mode %navigation; #IMPLIED>
+<!ATTLIST form:form form:order CDATA #IMPLIED>
+<!ATTLIST form:form form:tab-cycle %cycles; #IMPLIED>
+
+<!ELEMENT office:forms (form:form*)>
+<!ATTLIST office:forms form:automatic-focus %boolean; "false">
+<!ATTLIST office:forms form:apply-design-mode %boolean; "true">
+
+<!ELEMENT form:text (form:properties?, office:events?)>
+<!ATTLIST form:text %current-value;
+ %disabled;
+ %max-length;
+ %printable;
+ %readonly;
+ %tab-index;
+ %tab-stop;
+ %title;
+ %value;
+ %convert-empty;
+ %data-field;>
+
+<!ELEMENT form:textarea (form:properties?, office:events?)>
+<!ATTLIST form:textarea %current-value;
+ %disabled;
+ %max-length;
+ %printable;
+ %readonly;
+ %tab-index;
+ %tab-stop;
+ %title;
+ %value;
+ %convert-empty;
+ %data-field;>
+
+<!ELEMENT form:password (form:properties?, office:events?)>
+<!ATTLIST form:password %disabled;
+ %max-length;
+ %printable;
+ %tab-index;
+ %tab-stop;
+ %title;
+ %value;
+ %convert-empty;>
+
+<!ATTLIST form:password form:echo-char CDATA "*">
+
+<!ELEMENT form:file (form:properties?, office:events?)>
+<!ATTLIST form:file %current-value;
+ %disabled;
+ %max-length;
+ %printable;
+ %readonly;
+ %tab-index;
+ %tab-stop;
+ %title;
+ %value;>
+
+<!ELEMENT form:formatted-text (form:properties?, office:events?)>
+<!ATTLIST form:formatted-text %current-value;
+ %disabled;
+ %max-length;
+ %printable;
+ %readonly;
+ %tab-index;
+ %tab-stop;
+ %title;
+ %value;
+ %convert-empty;
+ %data-field;>
+<!ATTLIST form:formatted-text form:max-value CDATA #IMPLIED>
+<!ATTLIST form:formatted-text form:min-value CDATA #IMPLIED>
+<!ATTLIST form:formatted-text form:validation %boolean; "false">
+
+<!ELEMENT form:fixed-text (form:properties?, office:events?)>
+<!ATTLIST form:fixed-text %for;
+ %disabled;
+ %label;
+ %printable;
+ %title;>
+<!ATTLIST form:fixed-text form:multi-line %boolean; "false">
+
+<!ELEMENT form:combobox (form:properties?, office:events?, form:item*)>
+<!ATTLIST form:combobox %current-value;
+ %disabled;
+ %dropdown;
+ %max-length;
+ %printable;
+ %readonly;
+ %size;
+ %tab-index;
+ %tab-stop;
+ %title;
+ %value;
+ %convert-empty;
+ %data-field;
+ %list-source;
+ %list-source-type;>
+<!ATTLIST form:combobox form:auto-complete %boolean; #IMPLIED>
+
+<!ELEMENT form:item (#PCDATA)>
+<!ATTLIST form:item %label;>
+
+<!ELEMENT form:listbox (form:properties?, office:events?, form:option*)>
+<!ATTLIST form:listbox %disabled;
+ %dropdown;
+ %printable;
+ %size;
+ %tab-index;
+ %tab-stop;
+ %title;
+ %bound-column;
+ %data-field;
+ %list-source;
+ %list-source-type;>
+<!ATTLIST form:listbox form:multiple %boolean; "false">
+
+<!ELEMENT form:option (#PCDATA)>
+<!ATTLIST form:option %current-selected;
+ %selected;
+ %label;
+ %value;>
+
+<!ELEMENT form:button (form:properties?, office:events?)>
+<!ATTLIST form:button %button-type;
+ %disabled;
+ %label;
+ %image-data;
+ %printable;
+ %tab-index;
+ %tab-stop;
+ %target-frame;
+ %target-location;
+ %title;
+ %value;>
+<!ATTLIST form:button form:default-button %boolean; "false">
+
+<!ELEMENT form:image (form:properties?, office:events?)>
+<!ATTLIST form:image %button-type;
+ %disabled;
+ %image-data;
+ %printable;
+ %tab-index;
+ %tab-stop;
+ %target-frame;
+ %target-location;
+ %title;
+ %value;>
+
+<!ELEMENT form:checkbox (form:properties?, office:events?)>
+<!ATTLIST form:checkbox %disabled;
+ %label;
+ %printable;
+ %tab-index;
+ %tab-stop;
+ %title;
+ %value;
+ %data-field;>
+<!ENTITY % states "(unchecked|checked|unknown)">
+<!ATTLIST form:checkbox form:current-state %states; #IMPLIED>
+<!ATTLIST form:checkbox form:is-tristate %boolean; "false">
+<!ATTLIST form:checkbox form:state %states; "unchecked">
+
+<!ELEMENT form:radio (form:properties?, office:events?)>
+<!ATTLIST form:radio %current-selected;
+ %disabled;
+ %label;
+ %printable;
+ %selected;
+ %tab-index;
+ %tab-stop;
+ %title;
+ %value;
+ %data-field;>
+
+<!ELEMENT form:frame (form:properties?, office:events?)>
+<!ATTLIST form:frame %disabled;
+ %for;
+ %label;
+ %printable;
+ %title;>
+
+<!ELEMENT form:image-frame (form:properties?, office:events?)>
+<!ATTLIST form:image-frame %disabled;
+ %image-data;
+ %printable;
+ %readonly;
+ %title;
+ %data-field;>
+
+<!ELEMENT form:hidden (form:properties?, office:events?)>
+<!ATTLIST form:hidden %name;
+ %service-name;
+ %value;>
+
+<!ELEMENT form:grid (form:properties?, office:events?, form:column*)>
+<!ATTLIST form:grid %disabled;
+ %printable;
+ %tab-index;
+ %tab-stop;
+ %title;>
+<!ENTITY % column-type "form:text| form:textarea| form:formatted-text|form:checkbox| form:listbox| form:combobox">
+<!ELEMENT form:column (%column-type;)+>
+<!ATTLIST form:column %name;
+ %service-name;
+ %label;>
+
+<!ELEMENT form:generic-control (form:properties?, office:events?)>
+
+
+<!ELEMENT form:properties (form:property+)>
+<!ELEMENT form:property (form:property-value*)>
+<!ATTLIST form:property form:property-is-list %boolean; #IMPLIED>
+<!ATTLIST form:property form:property-name CDATA #REQUIRED>
+<!ATTLIST form:property form:property-type (boolean|short|int|long|double|string) #REQUIRED>
+<!ELEMENT form:property-value (#PCDATA)>
+
diff --git a/xmerge/source/palmtests/qa/comparator/dtd/meta.mod b/xmerge/source/palmtests/qa/comparator/dtd/meta.mod
new file mode 100644
index 000000000000..1ea845bcb02d
--- /dev/null
+++ b/xmerge/source/palmtests/qa/comparator/dtd/meta.mod
@@ -0,0 +1,90 @@
+<!--
+
+ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+
+ Copyright 2000, 2010 Oracle and/or its affiliates.
+
+ OpenOffice.org - a multi-platform office productivity suite
+
+ This file is part of OpenOffice.org.
+
+ OpenOffice.org is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License version 3
+ only, as published by the Free Software Foundation.
+
+ OpenOffice.org is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License version 3 for more details
+ (a copy is included in the LICENSE file that accompanied this code).
+
+ You should have received a copy of the GNU Lesser General Public License
+ version 3 along with OpenOffice.org. If not, see
+ <http://www.openoffice.org/license.html>
+ for a copy of the LGPLv3 License.
+
+-->
+
+
+<!ELEMENT meta:generator (%cString;)>
+
+<!ELEMENT dc:title (%cString;)>
+
+<!ELEMENT dc:description (%cString;)>
+
+<!ELEMENT dc:subject (%cString;)>
+
+<!ELEMENT meta:keywords (meta:keyword)*>
+<!ELEMENT meta:keyword (%cString;)>
+
+<!ELEMENT meta:initial-creator (%cString;)>
+
+<!ELEMENT dc:creator (%cString;)>
+
+<!ELEMENT meta:printed-by (%cString;)>
+
+<!ELEMENT meta:creation-date (%cTimeInstance;)>
+
+<!ELEMENT dc:date (%cTimeInstance;)>
+
+<!ELEMENT meta:print-date (%cTimeInstance;)>
+
+<!ELEMENT meta:template EMPTY>
+<!ATTLIST meta:template xlink:type (simple) #FIXED "simple">
+<!ATTLIST meta:template xlink:actuate (onRequest) "onRequest">
+<!ATTLIST meta:template xlink:href %uriReference; #REQUIRED>
+<!ATTLIST meta:template xlink:title %string; #IMPLIED>
+<!ATTLIST meta:template meta:date %timeInstance; #IMPLIED>
+
+<!ELEMENT meta:auto-reload EMPTY>
+<!ATTLIST meta:auto-reload xlink:type (simple) #IMPLIED>
+<!ATTLIST meta:auto-reload xlink:show (replace) #IMPLIED>
+<!ATTLIST meta:auto-reload xlink:actuate (onLoad) #IMPLIED>
+<!ATTLIST meta:auto-reload xlink:href %uriReference; #IMPLIED>
+<!ATTLIST meta:auto-reload meta:delay %timeDuration; "P0S">
+
+<!ELEMENT meta:hyperlink-behaviour EMPTY>
+<!ATTLIST meta:hyperlink-behaviour office:target-frame-name %targetFrameName; #IMPLIED>
+<!ATTLIST meta:hyperlink-behaviour xlink:show (new|replace) #IMPLIED>
+
+<!ELEMENT dc:language (%cLanguage;)>
+
+<!ELEMENT meta:editing-cycles (%cPositiveInteger;)>
+
+<!ELEMENT meta:editing-duration (%cTimeDuration;)>
+
+<!ELEMENT meta:user-defined (%cString;)>
+<!ATTLIST meta:user-defined meta:name %string; #REQUIRED>
+
+<!ELEMENT meta:document-statistic EMPTY>
+<!ATTLIST meta:document-statistic meta:page-count %positiveInteger; #IMPLIED
+ meta:table-count %nonNegativeInteger; #IMPLIED
+ meta:draw-count %nonNegativeInteger; #IMPLIED
+ meta:image-count %nonNegativeInteger; #IMPLIED
+ meta:ole-object-count %nonNegativeInteger; #IMPLIED
+ meta:paragraph-count %nonNegativeInteger; #IMPLIED
+ meta:word-count %nonNegativeInteger; #IMPLIED
+ meta:character-count %nonNegativeInteger; #IMPLIED
+ meta:row-count %nonNegativeInteger; #IMPLIED
+ meta:cell-count %nonNegativeInteger; #IMPLIED
+ meta:object-count %positiveInteger; #IMPLIED>
diff --git a/xmerge/source/palmtests/qa/comparator/dtd/nmspace.mod b/xmerge/source/palmtests/qa/comparator/dtd/nmspace.mod
new file mode 100644
index 000000000000..b7f6b64140a6
--- /dev/null
+++ b/xmerge/source/palmtests/qa/comparator/dtd/nmspace.mod
@@ -0,0 +1,50 @@
+<!--
+
+ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+
+ Copyright 2000, 2010 Oracle and/or its affiliates.
+
+ OpenOffice.org - a multi-platform office productivity suite
+
+ This file is part of OpenOffice.org.
+
+ OpenOffice.org is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License version 3
+ only, as published by the Free Software Foundation.
+
+ OpenOffice.org is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License version 3 for more details
+ (a copy is included in the LICENSE file that accompanied this code).
+
+ You should have received a copy of the GNU Lesser General Public License
+ version 3 along with OpenOffice.org. If not, see
+ <http://www.openoffice.org/license.html>
+ for a copy of the LGPLv3 License.
+
+-->
+
+<!ENTITY nFO "http://www.w3.org/1999/XSL/Format">
+<!ENTITY nXLink "http://www.w3.org/1999/xlink">
+<!ENTITY nSVG "http://www.w3.org/2000/svg">
+
+<!-- StarOffice namespace names and prefixes -->
+
+<!ENTITY nOpenOffice "http://openoffice.org/2000">
+<!ENTITY nOpenOffice2001 "http://openoffice.org/2001">
+
+<!ENTITY nOffice "&nOpenOffice;/office">
+<!ENTITY nStyle "&nOpenOffice;/style">
+<!ENTITY nText "&nOpenOffice;/text">
+<!ENTITY nTable "&nOpenOffice;/table">
+<!ENTITY nMeta "&nOpenOffice;/meta">
+<!ENTITY nScript "&nOpenOffice;/script">
+<!ENTITY nDraw "&nOpenOffice;/drawing">
+<!ENTITY nChart "&nOpenOffice;/chart">
+<!ENTITY nNumber "&nOpenOffice;/datastyle">
+<!ENTITY nConfig "&nOpenOffice2001;/config">
+
+
+<!-- dublin core namespace name and prefic -->
+<!ENTITY nDC "http://purl.org/dc/elements/1.1/">
diff --git a/xmerge/source/palmtests/qa/comparator/dtd/office.dtd b/xmerge/source/palmtests/qa/comparator/dtd/office.dtd
new file mode 100644
index 000000000000..9bcd37edf325
--- /dev/null
+++ b/xmerge/source/palmtests/qa/comparator/dtd/office.dtd
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+
+ Copyright 2000, 2010 Oracle and/or its affiliates.
+
+ OpenOffice.org - a multi-platform office productivity suite
+
+ This file is part of OpenOffice.org.
+
+ OpenOffice.org is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License version 3
+ only, as published by the Free Software Foundation.
+
+ OpenOffice.org is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License version 3 for more details
+ (a copy is included in the LICENSE file that accompanied this code).
+
+ You should have received a copy of the GNU Lesser General Public License
+ version 3 along with OpenOffice.org. If not, see
+ <http://www.openoffice.org/license.html>
+ for a copy of the LGPLv3 License.
+
+-->
+
+<!ENTITY % dtypes-mod SYSTEM "dtypes.mod">
+%dtypes-mod;
+<!ENTITY % nmspace-mod SYSTEM "nmspace.mod">
+%nmspace-mod;
+<!ENTITY % style-mod SYSTEM "style.mod">
+%style-mod;
+<!ENTITY % office-mod SYSTEM "office.mod">
+%office-mod;
+<!ENTITY % meta-mod SYSTEM "meta.mod">
+%meta-mod;
+<!ENTITY % script-mod SYSTEM "script.mod">
+%script-mod;
+<!ENTITY % drawing-mod SYSTEM "drawing.mod">
+%drawing-mod;
+<!ENTITY % text-mod SYSTEM "text.mod">
+%text-mod;
+<!ENTITY % table-mod SYSTEM "table.mod">
+%table-mod;
+<!ENTITY % chart-mod SYSTEM "chart.mod">
+%chart-mod;
+<!ENTITY % datastyl-mod SYSTEM "datastyl.mod">
+%datastyl-mod;
+<!ENTITY % form-mod SYSTEM "form.mod">
+%form-mod;
+<!ENTITY % settings-mod SYSTEM "settings.mod">
+%settings-mod;
diff --git a/xmerge/source/palmtests/qa/comparator/dtd/office.mod b/xmerge/source/palmtests/qa/comparator/dtd/office.mod
new file mode 100644
index 000000000000..f8e3775fa6da
--- /dev/null
+++ b/xmerge/source/palmtests/qa/comparator/dtd/office.mod
@@ -0,0 +1,234 @@
+<!--
+
+ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+
+ Copyright 2000, 2010 Oracle and/or its affiliates.
+
+ OpenOffice.org - a multi-platform office productivity suite
+
+ This file is part of OpenOffice.org.
+
+ OpenOffice.org is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License version 3
+ only, as published by the Free Software Foundation.
+
+ OpenOffice.org is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License version 3 for more details
+ (a copy is included in the LICENSE file that accompanied this code).
+
+ You should have received a copy of the GNU Lesser General Public License
+ version 3 along with OpenOffice.org. If not, see
+ <http://www.openoffice.org/license.html>
+ for a copy of the LGPLv3 License.
+
+-->
+
+<!ELEMENT office:document ( office:meta?,
+ office:settings?,
+ office:script?,
+ office:font-decls?,
+ office:styles?,
+ office:automatic-styles?,
+ office:master-styles?,
+ office:body ) >
+
+<!ATTLIST office:document xmlns:office CDATA #FIXED "&nOffice;">
+<!ATTLIST office:document xmlns:meta CDATA #FIXED "&nMeta;">
+<!ATTLIST office:document xmlns:script CDATA #FIXED "&nScript;">
+<!ATTLIST office:document xmlns:style CDATA #FIXED "&nStyle;">
+<!ATTLIST office:document xmlns:text CDATA #FIXED "&nText;">
+<!ATTLIST office:document xmlns:table CDATA #FIXED "&nTable;">
+<!ATTLIST office:document xmlns:draw CDATA #FIXED "&nDraw;">
+<!ATTLIST office:document xmlns:chart CDATA #FIXED "&nChart;">
+<!ATTLIST office:document xmlns:number CDATA #FIXED "&nNumber;">
+<!ATTLIST office:document xmlns:fo CDATA #FIXED "&nFO;">
+<!ATTLIST office:document xmlns:xlink CDATA #FIXED "&nXLink;">
+<!ATTLIST office:document xmlns:svg CDATA #FIXED "&nSVG;">
+<!ATTLIST office:document xmlns:dc CDATA #FIXED "&nDC;">
+
+<!ATTLIST office:document office:class
+ (text|text-global|
+ drawing|presentation|
+ spreadsheet|chart) #REQUIRED>
+
+<!ATTLIST office:document office:version %string; #IMPLIED>
+
+<!-- document-styles -->
+<!ELEMENT office:document-styles (
+ office:font-decls?,
+ office:styles?,
+ office:automatic-styles?,
+ office:master-styles? ) >
+
+<!ATTLIST office:document-styles xmlns:office CDATA #FIXED "&nOffice;">
+<!ATTLIST office:document-styles xmlns:meta CDATA #FIXED "&nMeta;">
+<!ATTLIST office:document-styles xmlns:script CDATA #FIXED "&nScript;">
+<!ATTLIST office:document-styles xmlns:style CDATA #FIXED "&nStyle;">
+<!ATTLIST office:document-styles xmlns:text CDATA #FIXED "&nText;">
+<!ATTLIST office:document-styles xmlns:table CDATA #FIXED "&nTable;">
+<!ATTLIST office:document-styles xmlns:draw CDATA #FIXED "&nDraw;">
+<!ATTLIST office:document-styles xmlns:chart CDATA #FIXED "&nChart;">
+<!ATTLIST office:document-styles xmlns:number CDATA #FIXED "&nNumber;">
+<!ATTLIST office:document-styles xmlns:fo CDATA #FIXED "&nFO;">
+<!ATTLIST office:document-styles xmlns:xlink CDATA #FIXED "&nXLink;">
+<!ATTLIST office:document-styles xmlns:svg CDATA #FIXED "&nSVG;">
+<!ATTLIST office:document-styles xmlns:dc CDATA #FIXED "&nDC;">
+
+<!ATTLIST office:document-styles office:version %string; #IMPLIED>
+
+<!-- document-content -->
+
+<!ELEMENT office:document-content (
+ office:script?,
+ office:font-decls?,
+ office:automatic-styles?,
+ office:body ) >
+
+<!ATTLIST office:document-content xmlns:office CDATA #FIXED "&nOffice;">
+<!ATTLIST office:document-content xmlns:meta CDATA #FIXED "&nMeta;">
+<!ATTLIST office:document-content xmlns:script CDATA #FIXED "&nScript;">
+<!ATTLIST office:document-content xmlns:style CDATA #FIXED "&nStyle;">
+<!ATTLIST office:document-content xmlns:text CDATA #FIXED "&nText;">
+<!ATTLIST office:document-content xmlns:table CDATA #FIXED "&nTable;">
+<!ATTLIST office:document-content xmlns:draw CDATA #FIXED "&nDraw;">
+<!ATTLIST office:document-content xmlns:chart CDATA #FIXED "&nChart;">
+<!ATTLIST office:document-content xmlns:number CDATA #FIXED "&nNumber;">
+<!ATTLIST office:document-content xmlns:fo CDATA #FIXED "&nFO;">
+<!ATTLIST office:document-content xmlns:xlink CDATA #FIXED "&nXLink;">
+<!ATTLIST office:document-content xmlns:svg CDATA #FIXED "&nSVG;">
+<!ATTLIST office:document-content xmlns:dc CDATA #FIXED "&nDC;">
+
+<!ATTLIST office:document-content office:class
+ (text|text-global|
+ drawing|presentation|
+ spreadsheet|chart) #REQUIRED>
+
+<!ATTLIST office:document-content office:version %string; #IMPLIED>
+
+<!-- document-content -->
+
+<!ELEMENT office:document-meta ( office:meta? ) >
+
+<!ATTLIST office:document-meta xmlns:office CDATA #FIXED "&nOffice;">
+<!ATTLIST office:document-meta xmlns:meta CDATA #FIXED "&nMeta;">
+<!ATTLIST office:document-meta xmlns:script CDATA #FIXED "&nScript;">
+<!ATTLIST office:document-meta xmlns:style CDATA #FIXED "&nStyle;">
+<!ATTLIST office:document-meta xmlns:text CDATA #FIXED "&nText;">
+<!ATTLIST office:document-meta xmlns:table CDATA #FIXED "&nTable;">
+<!ATTLIST office:document-meta xmlns:draw CDATA #FIXED "&nDraw;">
+<!ATTLIST office:document-meta xmlns:chart CDATA #FIXED "&nChart;">
+<!ATTLIST office:document-meta xmlns:number CDATA #FIXED "&nNumber;">
+<!ATTLIST office:document-meta xmlns:fo CDATA #FIXED "&nFO;">
+<!ATTLIST office:document-meta xmlns:xlink CDATA #FIXED "&nXLink;">
+<!ATTLIST office:document-meta xmlns:svg CDATA #FIXED "&nSVG;">
+<!ATTLIST office:document-meta xmlns:dc CDATA #FIXED "&nDC;">
+
+<!ATTLIST office:document-meta office:version %string; #IMPLIED>
+
+<!ELEMENT office:document-settings (office:settings) >
+<!ATTLIST office:document-settings xmlns:office CDATA #FIXED "&nOffice;">
+<!ATTLIST office:document-settings xmlns:xlink CDATA #FIXED "&nXLink;">
+<!ATTLIST office:document-settings xmlns:config CDATA #FIXED "&nConfig;">
+
+<!ATTLIST office:document-settings office:version %string; #IMPLIED>
+
+<!ENTITY % meta "(meta:generator?,
+ dc:title?,
+ dc:description?,
+ dc:subject?,
+ meta:initial-creator?,
+ meta:creation-date?,
+ dc:creator?,
+ dc:date?,
+ meta:printed-by?,
+ meta:print-date?,
+ meta:keywords?,
+ dc:language?,
+ meta:editing-cycles?,
+ meta:editing-duration?,
+ meta:hyperlink-behaviour?,
+ meta:auto-reload?,
+ meta:template?,
+ meta:user-defined*,
+ meta:document-statistic?)">
+<!ELEMENT office:meta %meta;>
+
+<!ENTITY % script "(script:library-embedded |
+ script:library-linked)*">
+<!ELEMENT office:script %script;>
+
+<!ELEMENT office:font-decls (style:font-decl)*>
+
+<!ENTITY % styles "(style:default-style|style:style|text:list-style|
+ number:number-style|number:currency-style|number:percentage-style|
+ number:date-style|number:time-style|number:boolean-style|
+ number:text-style|
+ draw:gradient|draw:hatch|draw:fill-image|draw:marker|draw:stroke-dash|
+ style:presentation-page-layout|draw:transparency)">
+
+<!-- Validity constraint: The elements
+ text:outline-style,
+ text:footnotes-configuration,
+ text:endnotes-configuration,
+ text:bibliography-configuration and
+ text:linenumbering-configuration
+ may appear only once!
+ Unfortunatetly, this constraint cannot be easily specified in the DTD.
+-->
+<!ELEMENT office:styles (%styles;|text:outline-style|
+ text:footnotes-configuration|text:endnotes-configuration|
+ text:bibliography-configuration|text:linenumbering-configuration)*>
+
+<!ELEMENT office:automatic-styles (%styles;|style:page-master)*>
+
+<!ELEMENT office:master-styles (draw:layer-set?,style:handout-master?,style:master-page*) >
+
+<!ENTITY % text-decls "text:variable-decls?, text:sequence-decls?,
+ text:user-field-decls?, text:dde-connection-decls?,
+ text:alphabetical-index-auto-mark-file?" >
+
+<!ENTITY % change-marks "text:change | text:change-start | text:change-end">
+
+<!ENTITY % body "(office:forms?,(text:tracked-changes|table:tracked-changes)?,%text-decls;,table:calculation-settings?,table:content-validations?,table:label-ranges?,
+ (text:h|text:p|text:ordered-list|
+ text:unordered-list|table:table|draw:page|
+ draw:a|%shape;|text:section|text:table-of-content|
+ text:illustration-index|text:table-index|text:object-index|
+ text:user-index|text:alphabetical-index|text:bibliography|
+ %change-marks;)*,
+ table:named-expressions?,
+ table:database-ranges?,table:data-pilot-tables?,
+ table:consolidation?,
+ table:dde-links?,
+ presentation:settings?)">
+<!ELEMENT office:body %body;>
+<!ATTLIST office:body table:structure-protected %boolean; "false"
+ table:protection-key CDATA #IMPLIED>
+
+<!ELEMENT office:events (script:event|presentation:event)*>
+
+<!-- DDE source: for text sections and tables -->
+<!ELEMENT office:dde-source EMPTY>
+<!ATTLIST office:dde-source office:dde-application CDATA #IMPLIED>
+<!ATTLIST office:dde-source office:dde-topic CDATA #IMPLIED>
+<!ATTLIST office:dde-source office:dde-item CDATA #IMPLIED>
+<!ATTLIST office:dde-source office:automatic-update %boolean; "false">
+<!ATTLIST office:dde-source office:name CDATA #IMPLIED>
+<!ATTLIST office:dde-source table:conversion-mode (into-default-style-data-style|into-english-number|let-text) "into-default-style-data-style" >
+
+<!-- annotations -->
+<!-- limitation: in the current implementation, only plain text inside of
+ paragraphs is supported -->
+<!ELEMENT office:annotation (text:p)*>
+<!ATTLIST office:annotation office:author %string; #IMPLIED>
+<!ATTLIST office:annotation office:create-date %date; #IMPLIED>
+<!ATTLIST office:annotation office:create-date-string %string; #IMPLIED>
+<!ATTLIST office:annotation office:display %boolean; "false">
+
+<!ELEMENT office:change-info (text:p)*>
+<!ATTLIST office:change-info office:chg-author %string; #REQUIRED>
+<!ATTLIST office:change-info office:chg-date-time %timeInstance; #REQUIRED>
+
+<!ELEMENT office:binary-data (#PCDATA)>
diff --git a/xmerge/source/palmtests/qa/comparator/dtd/script.mod b/xmerge/source/palmtests/qa/comparator/dtd/script.mod
new file mode 100644
index 000000000000..4d13ff74aebc
--- /dev/null
+++ b/xmerge/source/palmtests/qa/comparator/dtd/script.mod
@@ -0,0 +1,51 @@
+<!--
+
+ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+
+ Copyright 2000, 2010 Oracle and/or its affiliates.
+
+ OpenOffice.org - a multi-platform office productivity suite
+
+ This file is part of OpenOffice.org.
+
+ OpenOffice.org is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License version 3
+ only, as published by the Free Software Foundation.
+
+ OpenOffice.org is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License version 3 for more details
+ (a copy is included in the LICENSE file that accompanied this code).
+
+ You should have received a copy of the GNU Lesser General Public License
+ version 3 along with OpenOffice.org. If not, see
+ <http://www.openoffice.org/license.html>
+ for a copy of the LGPLv3 License.
+
+-->
+
+<!ELEMENT script:library-embedded (script:module*)>
+<!ATTLIST script:library-embedded script:name %string; #REQUIRED>
+<!ATTLIST script:library-embedded script:password %string; #IMPLIED>
+
+<!ELEMENT script:library-linked EMPTY>
+<!ATTLIST script:library-linked script:name %string; #REQUIRED>
+<!ATTLIST script:library-linked xlink:href %string; #REQUIRED>
+<!ATTLIST script:library-linked xlink:type (simple) #FIXED "simple">
+
+<!ELEMENT script:module (#PCDATA)>
+<!ATTLIST script:module script:name %string; #REQUIRED>
+<!ATTLIST script:module script:language %string; #IMPLIED>
+
+
+<!ENTITY % script-language "script:language %string; #REQUIRED">
+<!ENTITY % event-name "script:event-name %string; #REQUIRED">
+<!ENTITY % location "script:location (document|application) #REQUIRED">
+<!ENTITY % macro-name "script:macro-name %string; #REQUIRED">
+
+<!ELEMENT script:event (#PCDATA)>
+<!ATTLIST script:event %script-language;
+ %event-name;
+ %location;
+ %macro-name;>
diff --git a/xmerge/source/palmtests/qa/comparator/dtd/settings.mod b/xmerge/source/palmtests/qa/comparator/dtd/settings.mod
new file mode 100644
index 000000000000..bb9224237fa8
--- /dev/null
+++ b/xmerge/source/palmtests/qa/comparator/dtd/settings.mod
@@ -0,0 +1,49 @@
+<!--
+
+ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+
+ Copyright 2000, 2010 Oracle and/or its affiliates.
+
+ OpenOffice.org - a multi-platform office productivity suite
+
+ This file is part of OpenOffice.org.
+
+ OpenOffice.org is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License version 3
+ only, as published by the Free Software Foundation.
+
+ OpenOffice.org is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License version 3 for more details
+ (a copy is included in the LICENSE file that accompanied this code).
+
+ You should have received a copy of the GNU Lesser General Public License
+ version 3 along with OpenOffice.org. If not, see
+ <http://www.openoffice.org/license.html>
+ for a copy of the LGPLv3 License.
+
+-->
+
+<!ELEMENT office:settings (config:config-item-set+)>
+
+<!ENTITY % items "(config:config-item |
+ config:config-item-set |
+ config:config-item-map-named |
+ config:config-item-map-indexed)+">
+
+<!ELEMENT config:config-item-set %items;>
+<!ATTLIST config:config-item-set config:name CDATA #REQUIRED>
+
+<!ELEMENT config:config-item (#PCDATA)>
+<!ATTLIST config:config-item config:name CDATA #REQUIRED
+ config:type (boolean | short | int | long | double | string | datetime | base64Binary) #REQUIRED>
+
+<!ELEMENT config:config-item-map-named (config:config-item-map-entry)+>
+<!ATTLIST config:config-item-map-named config:name CDATA #REQUIRED>
+
+<!ELEMENT config:config-item-map-indexed (config:config-item-map-entry)+>
+<!ATTLIST config:config-item-map-indexed config:name CDATA #REQUIRED>
+
+<!ELEMENT config:config-item-map-entry %items;>
+<!ATTLIST config:config-item-map-entry config:name CDATA #IMPLIED>
diff --git a/xmerge/source/palmtests/qa/comparator/dtd/style.mod b/xmerge/source/palmtests/qa/comparator/dtd/style.mod
new file mode 100644
index 000000000000..21a3d9d17dd1
--- /dev/null
+++ b/xmerge/source/palmtests/qa/comparator/dtd/style.mod
@@ -0,0 +1,391 @@
+<!--
+
+ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+
+ Copyright 2000, 2010 Oracle and/or its affiliates.
+
+ OpenOffice.org - a multi-platform office productivity suite
+
+ This file is part of OpenOffice.org.
+
+ OpenOffice.org is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License version 3
+ only, as published by the Free Software Foundation.
+
+ OpenOffice.org is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License version 3 for more details
+ (a copy is included in the LICENSE file that accompanied this code).
+
+ You should have received a copy of the GNU Lesser General Public License
+ version 3 along with OpenOffice.org. If not, see
+ <http://www.openoffice.org/license.html>
+ for a copy of the LGPLv3 License.
+
+-->
+
+<!ELEMENT style:font-decl EMPTY>
+<!ATTLIST style:font-decl style:name %string; #REQUIRED>
+<!ATTLIST style:font-decl fo:font-family %string; #REQUIRED>
+<!ATTLIST style:font-decl style:font-style-name %string; #IMPLIED>
+<!ENTITY % fontFamilyGeneric "(roman|swiss|modern|decorative|script|system)">
+<!ATTLIST style:font-decl style:font-family-generic %fontFamilyGeneric;
+ #IMPLIED>
+<!ENTITY % fontPitch "(fixed|variable)">
+<!ATTLIST style:font-decl style:font-pitch %fontPitch; #IMPLIED>
+<!ATTLIST style:font-decl style:font-charset %textEncoding; #IMPLIED>
+
+<!ELEMENT style:style ( style:properties?,office:events?,style:map*)>
+
+<!ATTLIST style:style style:name %styleName; #REQUIRED>
+
+<!ENTITY % styleFamily "(paragraph|text|section|
+ table|table-column|table-row|table-cell|table-page|chart|graphics|default|drawing-page|presentation|control)">
+<!ATTLIST style:style style:family %styleFamily; #REQUIRED>
+
+<!ATTLIST style:style style:parent-style-name %styleName; #IMPLIED>
+<!ATTLIST style:style style:master-page-name %styleName; #IMPLIED>
+<!ATTLIST style:style style:next-style-name %styleName; #IMPLIED>
+<!ATTLIST style:style style:list-style-name %styleName; #IMPLIED>
+<!ATTLIST style:style style:data-style-name %styleName; #IMPLIED>
+
+<!ATTLIST style:style style:auto-update %boolean; "false">
+
+<!ATTLIST style:style style:class %string; #IMPLIED>
+
+<!ELEMENT style:default-style (style:properties?)>
+<!ATTLIST style:default-style style:family %styleFamily; #REQUIRED>
+
+<!ELEMENT style:map EMPTY>
+
+<!ATTLIST style:map style:condition %string; #REQUIRED>
+<!ATTLIST style:map style:apply-style-name %styleName; #REQUIRED>
+<!ATTLIST style:map style:base-cell-address %cell-address; #IMPLIED>
+
+<!ELEMENT style:properties ANY>
+
+<!-- number format properties -->
+<!ATTLIST style:properties style:num-prefix %string; #IMPLIED>
+<!ATTLIST style:properties style:num-suffix %string; #IMPLIED>
+<!ATTLIST style:properties style:num-format %string; #IMPLIED>
+<!ATTLIST style:properties style:num-letter-sync %boolean; #IMPLIED>
+
+<!-- frame properties -->
+<!ATTLIST style:properties fo:width %positiveLength; #IMPLIED>
+<!ATTLIST style:properties fo:height %positiveLength; #IMPLIED>
+<!ATTLIST style:properties style:vertical-pos (top|middle|bottom|from-top) #IMPLIED>
+<!ATTLIST style:properties style:vertical-rel (page|page-content|
+ frame|frame-content|
+ paragraph|paragraph-content|char|
+ line|baseline|text) #IMPLIED>
+<!ATTLIST style:properties style:horizontal-pos (left|center|right|from-left|inside|outside|from-inside) #IMPLIED>
+<!ATTLIST style:properties style:horizontal-rel (page|page-content|
+ frame|frame-content|
+ paragraph|paragraph-content|
+ char) #IMPLIED>
+<!ATTLIST style:properties svg:width %lengthOrPercentage; #IMPLIED>
+<!ATTLIST style:properties svg:height %lengthOrPercentage; #IMPLIED>
+<!ATTLIST style:properties fo:min-height %lengthOrPercentage; #IMPLIED>
+<!ATTLIST style:properties fo:min-width %lengthOrPercentage; #IMPLIED>
+<!ATTLIST style:properties fo:max-height %lengthOrPercentage; #IMPLIED>
+<!ATTLIST style:properties fo:max-width %lengthOrPercentage; #IMPLIED>
+<!ATTLIST style:properties text:anchor-type %anchorType; #IMPLIED>
+<!ATTLIST style:properties text:anchor-page-number %positiveInteger; #IMPLIED>
+<!ATTLIST style:properties svg:x %coordinate; #IMPLIED>
+<!ATTLIST style:properties svg:y %coordinate; #IMPLIED>
+<!ATTLIST style:properties style:print-content %boolean; #IMPLIED>
+<!ATTLIST style:properties style:protect %boolean; #IMPLIED>
+<!ATTLIST style:properties style:wrap (none|left|right|parallel|dynamic|run-through) #IMPLIED>
+<!ENTITY % noLimitOrPositiveInteger "CDATA">
+<!ATTLIST style:properties style:number-wrapped-paragraphs %noLimitOrPositiveInteger; #IMPLIED>
+<!ATTLIST style:properties style:wrap-contour %boolean; #IMPLIED>
+<!ATTLIST style:properties style:wrap-contour-mode (full|outside) #IMPLIED>
+<!ATTLIST style:properties style:run-through (foreground|background) #IMPLIED>
+<!ATTLIST style:properties style:editable %boolean; #IMPLIED>
+<!ATTLIST style:properties style:mirror CDATA #IMPLIED>
+<!ATTLIST style:properties fo:clip CDATA #IMPLIED>
+<!ATTLIST style:properties text:animation (none|scroll|alternate|slide) #IMPLIED>
+<!ATTLIST style:properties text:animation-direction (left|right|up|down) #IMPLIED>
+<!ATTLIST style:properties text:animation-start-inside %boolean; #IMPLIED>
+<!ATTLIST style:properties text:animation-stop-inside %boolean; #IMPLIED>
+<!ATTLIST style:properties text:animation-repeat %integer; #IMPLIED>
+<!ATTLIST style:properties text:animation-delay %timeDuration; #IMPLIED>
+<!ATTLIST style:properties text:animation-steps %length; #IMPLIED>
+
+<!-- text properties -->
+<!ATTLIST style:properties fo:font-variant (normal|small-caps) #IMPLIED>
+<!ATTLIST style:properties fo:text-transform (none|lowercase|
+ uppercase|capitalize) #IMPLIED>
+<!ATTLIST style:properties fo:color %color; #IMPLIED>
+<!ATTLIST style:properties style:use-window-font-color %boolean; #IMPLIED>
+<!ATTLIST style:properties style:text-outline %boolean; #IMPLIED>
+<!ATTLIST style:properties style:text-crossing-out
+ (none|single-line|double-line|thick-line|slash|X)
+ #IMPLIED>
+<!ATTLIST style:properties style:text-position CDATA #IMPLIED>
+<!ATTLIST style:properties style:text-align (left|right|start|center|end|justify|justified) #IMPLIED>
+
+<!ATTLIST style:properties style:font-name %string; #IMPLIED>
+<!ATTLIST style:properties fo:font-family %string; #IMPLIED>
+<!ATTLIST style:properties style:font-family-generic %fontFamilyGeneric;
+ #IMPLIED>
+<!ATTLIST style:properties style:font-style-name %string; #IMPLIED>
+<!ATTLIST style:properties style:font-pitch %fontPitch; #IMPLIED>
+<!ATTLIST style:properties style:font-charset %textEncoding; #IMPLIED>
+<!ATTLIST style:properties style:font-name-asian %string; #IMPLIED>
+<!ATTLIST style:properties style:font-family-asian %string; #IMPLIED>
+<!ATTLIST style:properties style:font-family-generic-asian %fontFamilyGeneric;
+ #IMPLIED>
+<!ATTLIST style:properties style:font-style-name-asian %string; #IMPLIED>
+<!ATTLIST style:properties style:font-pitch-asian %fontPitch; #IMPLIED>
+<!ATTLIST style:properties style:font-charset-asian %textEncoding; #IMPLIED>
+<!ATTLIST style:properties style:font-name-complex %string; #IMPLIED>
+<!ATTLIST style:properties style:font-family-complex %string; #IMPLIED>
+<!ATTLIST style:properties style:font-family-generic-complex %fontFamilyGeneric;
+ #IMPLIED>
+<!ATTLIST style:properties style:font-style-name-complex %string; #IMPLIED>
+<!ATTLIST style:properties style:font-pitch-complex %fontPitch; #IMPLIED>
+<!ATTLIST style:properties style:font-charset-complex %textEncoding; #IMPLIED>
+
+<!ATTLIST style:properties fo:font-size %positiveLengthOrPercentage; #IMPLIED>
+<!ATTLIST style:properties style:font-size-rel %length; #IMPLIED>
+<!ATTLIST style:properties style:font-size-asian %positiveLengthOrPercentage; #IMPLIED>
+<!ATTLIST style:properties style:font-size-rel-asian %length; #IMPLIED>
+<!ATTLIST style:properties style:font-size-complex %positiveLengthOrPercentage; #IMPLIED>
+<!ATTLIST style:properties style:font-size-rel-complex %length; #IMPLIED>
+<!ENTITY % normalOrLength "CDATA">
+<!ATTLIST style:properties fo:letter-spacing %normalOrLength; #IMPLIED>
+<!ATTLIST style:properties fo:language %languageOnly; #IMPLIED>
+<!ATTLIST style:properties style:language-asian %languageOnly; #IMPLIED>
+<!ATTLIST style:properties style:language-complex %languageOnly; #IMPLIED>
+<!ATTLIST style:properties fo:country %country; #IMPLIED>
+<!ATTLIST style:properties style:country-asian %country; #IMPLIED>
+<!ATTLIST style:properties style:country-complex %country; #IMPLIED>
+<!ENTITY % fontStyle "(normal|italic|oblique)">
+<!ATTLIST style:properties fo:font-style %fontStyle; #IMPLIED>
+<!ATTLIST style:properties style:font-style-asian %fontStyle; #IMPLIED>
+<!ATTLIST style:properties style:font-style-complex %fontStyle; #IMPLIED>
+<!ENTITY % fontRelief "(none|embossed|engraved)">
+<!ATTLIST style:properties style:font-relief %fontRelief; #IMPLIED>
+<!ATTLIST style:properties fo:text-shadow CDATA #IMPLIED>
+<!ATTLIST style:properties style:text-underline
+ (none|single|double|dotted|dash|long-dash|dot-dash|
+ dot-dot-dash|wave|bold|bold-dotted|bold-dash|
+ bold-long-dash|bold-dot-dash|bold-dot-dot-dash|
+ bold-wave|double-wave|small-wave) #IMPLIED>
+<!ATTLIST style:properties style:text-autospace (none | ideograph-alpha) #IMPLIED>
+<!ATTLIST style:properties style:punctuation-wrap (simple | hanging) #IMPLIED>
+<!ATTLIST style:properties style:line-break (normal | strict) #IMPLIED>
+<!ENTITY % fontColorOrColor "CDATA">
+<!ATTLIST style:properties style:text-underline-color %fontColorOrColor;
+ #IMPLIED>
+<!ATTLIST style:properties fo:font-weight CDATA #IMPLIED>
+<!ATTLIST style:properties style:font-weight-asian CDATA #IMPLIED>
+<!ATTLIST style:properties style:font-weight-complex CDATA #IMPLIED>
+<!ATTLIST style:properties fo:score-spaces %boolean; #IMPLIED>
+<!ATTLIST style:properties style:letter-kerning %boolean; #IMPLIED>
+<!ATTLIST style:properties style:text-blinking %boolean; #IMPLIED>
+<!ATTLIST style:properties style:text-background-color %transparentOrColor;
+ #IMPLIED>
+
+<!ATTLIST style:properties style:text-combine (none|letters|lines) #IMPLIED>
+<!ATTLIST style:properties style:text-combine-start-char %character; #IMPLIED>
+<!ATTLIST style:properties style:text-combine-end-char %character; #IMPLIED>
+<!ATTLIST style:properties style:text-emphasize CDATA #IMPLIED>
+<!ATTLIST style:properties style:text-scale %percentage; #IMPLIED>
+<!ATTLIST style:properties style:text-rotation-angle %integer; #IMPLIED>
+<!ATTLIST style:properties style:text-rotation-scale (fixed|line-height) #IMPLIED>
+
+<!-- paragraph properties -->
+<!ENTITY % nonNegativeLengthOrPercentageOrNormal "CDATA">
+<!ATTLIST style:properties fo:line-height
+ %nonNegativeLengthOrPercentageOrNormal; #IMPLIED>
+<!ATTLIST style:properties style:line-height-at-least %nonNegativeLength;
+ #IMPLIED>
+<!ATTLIST style:properties style:line-spacing %length; #IMPLIED>
+<!ATTLIST style:properties fo:text-align (start|end|center|justify) #IMPLIED>
+<!ATTLIST style:properties fo:text-align-last (start|center|justify) #IMPLIED>
+<!ATTLIST style:properties style:text-align-source (fix|value-type) #IMPLIED>
+<!ATTLIST style:properties style:justify-single-word %boolean; #IMPLIED>
+<!ATTLIST style:properties style:break-inside (auto|avoid) #IMPLIED>
+<!ATTLIST style:properties fo:widows %nonNegativeInteger; #IMPLIED>
+<!ATTLIST style:properties fo:orphans %nonNegativeInteger; #IMPLIED>
+
+<!ATTLIST style:properties fo:hyphenate %boolean; #IMPLIED>
+<!ATTLIST style:properties fo:hyphenate-keep (none|page) #IMPLIED>
+<!ATTLIST style:properties fo:hyphenation-remain-char-count %positiveInteger;
+ #IMPLIED>
+<!ATTLIST style:properties fo:hyphenation-push-char-count %positiveInteger;
+ #IMPLIED>
+<!ATTLIST style:properties fo:hyphenation-ladder-count
+ %noLimitOrPositiveInteger; #IMPLIED>
+<!ATTLIST style:properties style:page-number %positiveInteger; #IMPLIED>
+
+<!ELEMENT style:tab-stops (style:tab-stop)*>
+<!ELEMENT style:tab-stop EMPTY>
+<!ATTLIST style:tab-stop style:position %nonNegativeLength; #REQUIRED>
+<!ATTLIST style:tab-stop style:type (left|center|right|char|default) "left">
+<!ATTLIST style:tab-stop style:char %character; #IMPLIED>
+<!ATTLIST style:tab-stop style:leader-char %character; " ">
+
+<!ELEMENT style:drop-cap EMPTY>
+<!ENTITY % wordOrPositiveInteger "CDATA">
+<!ATTLIST style:drop-cap style:length %wordOrPositiveInteger; "1">
+<!ATTLIST style:drop-cap style:lines %positiveInteger; "1">
+<!ATTLIST style:drop-cap style:distance %length; "0cm">
+<!ATTLIST style:drop-cap style:style-name %styleName; #IMPLIED>
+
+<!ATTLIST style:properties style:register-true %boolean; #IMPLIED>
+<!ATTLIST style:properties style:register-truth-ref-style-name %styleName; #IMPLIED>
+<!ATTLIST style:properties fo:margin-left %positiveLengthOrPercentage; #IMPLIED>
+<!ATTLIST style:properties fo:margin-right %positiveLengthOrPercentage;
+ #IMPLIED>
+<!ATTLIST style:properties fo:text-indent %lengthOrPercentage; #IMPLIED>
+<!ATTLIST style:properties style:auto-text-indent %boolean; #IMPLIED>
+<!ATTLIST style:properties fo:margin-top %positiveLengthOrPercentage; #IMPLIED>
+<!ATTLIST style:properties fo:margin-bottom %positiveLengthOrPercentage; #IMPLIED>
+<!ATTLIST style:properties fo:break-before (auto|column|page) #IMPLIED>
+<!ATTLIST style:properties fo:break-after (auto|column|page) #IMPLIED>
+<!ATTLIST style:properties fo:background-color %transparentOrColor; #IMPLIED>
+
+<!ELEMENT style:background-image (office:binary-data?)>
+<!ATTLIST style:background-image xlink:type (simple) #IMPLIED>
+<!ATTLIST style:background-image xlink:href %uriReference; #IMPLIED>
+<!ATTLIST style:background-image xlink:show (embed) #IMPLIED>
+<!ATTLIST style:background-image xlink:actuate (onLoad) #IMPLIED>
+<!ATTLIST style:background-image style:repeat (no-repeat|repeat|stretch)
+ "repeat">
+<!ATTLIST style:background-image style:position CDATA "center">
+<!ATTLIST style:background-image style:filter-name %string; #IMPLIED>
+
+<!ELEMENT style:symbol-image (office:binary-data?)>
+<!ATTLIST style:symbol-image xlink:type (simple) #IMPLIED>
+<!ATTLIST style:symbol-image xlink:href %uriReference; #IMPLIED>
+<!ATTLIST style:symbol-image xlink:show (embed) #IMPLIED>
+<!ATTLIST style:symbol-image xlink:actuate (onLoad) #IMPLIED>
+
+<!ATTLIST style:properties fo:border CDATA #IMPLIED>
+<!ATTLIST style:properties fo:border-top CDATA #IMPLIED>
+<!ATTLIST style:properties fo:border-bottom CDATA #IMPLIED>
+<!ATTLIST style:properties fo:border-left CDATA #IMPLIED>
+<!ATTLIST style:properties fo:border-right CDATA #IMPLIED>
+<!ATTLIST style:properties style:border-line-width CDATA #IMPLIED>
+<!ATTLIST style:properties style:border-line-width-top CDATA #IMPLIED>
+<!ATTLIST style:properties style:border-line-width-bottom CDATA #IMPLIED>
+<!ATTLIST style:properties style:border-line-width-left CDATA #IMPLIED>
+<!ATTLIST style:properties style:border-line-width-right CDATA #IMPLIED>
+<!ATTLIST style:properties fo:padding %nonNegativeLength; #IMPLIED>
+<!ATTLIST style:properties fo:padding-top %nonNegativeLength; #IMPLIED>
+<!ATTLIST style:properties fo:padding-bottom %nonNegativeLength; #IMPLIED>
+<!ATTLIST style:properties fo:padding-left %nonNegativeLength; #IMPLIED>
+<!ATTLIST style:properties fo:padding-right %nonNegativeLength; #IMPLIED>
+<!ATTLIST style:properties style:shadow CDATA #IMPLIED>
+<!ATTLIST style:properties fo:keep-with-next %boolean; #IMPLIED>
+
+<!ATTLIST style:properties text:number-lines %boolean; "false">
+<!ATTLIST style:properties text:line-number %nonNegativeInteger; #IMPLIED>
+
+<!ATTLIST style:properties style:decimal-places %nonNegativeInteger; #IMPLIED>
+<!ATTLIST style:properties style:tab-stop-distance %nonNegativeLength; #IMPLIED>
+
+<!-- table properties -->
+<!ATTLIST style:properties style:width %positiveLength; #IMPLIED>
+<!ATTLIST style:properties style:rel-width %percentage; #IMPLIED>
+<!ATTLIST style:properties style:may-break-between-rows %boolean; #IMPLIED>
+<!ATTLIST style:properties table:page-style-name %styleName; #IMPLIED>
+<!ATTLIST style:properties table:display %boolean; #IMPLIED>
+
+<!-- table column properties -->
+<!ATTLIST style:properties style:column-width %positiveLength; #IMPLIED>
+<!ENTITY % relWidth "CDATA">
+<!ATTLIST style:properties style:rel-column-width %relWidth; #IMPLIED>
+<!ATTLIST style:properties style:use-optimal-column-width %boolean; #IMPLIED>
+
+<!-- table row properties -->
+<!ATTLIST style:properties style:row-height %positiveLength; #IMPLIED>
+<!ATTLIST style:properties style:min-row-height %nonNegativeLength; #IMPLIED>
+<!ATTLIST style:properties style:use-optimal-row-height %boolean; #IMPLIED>
+
+<!-- table cell properties -->
+<!ATTLIST style:properties
+ table:align (left | center | right | margins) #IMPLIED
+ table:border-model (collapsing | separating) #IMPLIED
+ fo:vertical-align (top | middle | bottom | automatic) #IMPLIED
+ fo:direction (ltr | ttb) #IMPLIED
+ style:rotation-angle %nonNegativeInteger; #IMPLIED
+ style:rotation-align (none | bottom | top | center) #IMPLIED
+ style:cell-protect CDATA #IMPLIED
+ fo:wrap-option (no-wrap | wrap) #IMPLIED
+>
+<!ELEMENT style:columns (style:column-sep?,style:column*)>
+<!ATTLIST style:columns fo:column-count %nonNegativeInteger; #IMPLIED>
+<!ATTLIST style:columns fo:column-gap %positiveLength; #IMPLIED>
+
+<!ELEMENT style:column EMPTY>
+<!ATTLIST style:column style:rel-width CDATA #IMPLIED>
+<!ATTLIST style:column fo:margin-left %positiveLength; #IMPLIED>
+<!ATTLIST style:column fo:margin-right %positiveLength; #IMPLIED>
+
+<!ELEMENT style:column-sep EMPTY>
+<!ATTLIST style:column-sep style:style (none|solid|dotted|dashed|dot-dashed)
+ "solid">
+<!ATTLIST style:column-sep style:width %length; #REQUIRED>
+<!ATTLIST style:column-sep style:height %percentage; "100%">
+<!ATTLIST style:column-sep style:vertical-align (top|middle|bottom) "top">
+<!ATTLIST style:column-sep style:color %color; "#000000">
+
+<!-- page master properties -->
+<!ELEMENT style:page-master (style:properties?, style:header-style?, style:footer-style?)>
+<!ATTLIST style:page-master style:name %styleName; #REQUIRED>
+<!ATTLIST style:page-master style:page-usage (all|left|right|mirrored) "all">
+
+<!ELEMENT style:header-style (style:properties?)>
+<!ELEMENT style:footer-style (style:properties?)>
+
+<!ATTLIST style:properties fo:page-width %length; #IMPLIED>
+<!ATTLIST style:properties fo:page-height %length; #IMPLIED>
+<!ATTLIST style:properties style:paper-tray-number %positiveNumberOrDefault; #IMPLIED>
+<!ATTLIST style:properties style:print-orientation (portrait|landscape) #IMPLIED>
+<!ATTLIST style:properties style:print CDATA #IMPLIED>
+<!ATTLIST style:properties style:print-page-order (ttb|ltr) #IMPLIED>
+<!ATTLIST style:properties style:first-page-number %positiveInteger; #IMPLIED>
+<!ATTLIST style:properties style:scale-to %percentage; #IMPLIED>
+<!ATTLIST style:properties style:scale-to-pages %positiveInteger; #IMPLIED>
+<!ATTLIST style:properties style:table-centering (horizontal | vertical | both | none) #IMPLIED>
+
+<!ATTLIST style:properties style:footnote-max-height %lengthOrNoLimit; #IMPLIED>
+<!ATTLIST style:properties style:vertical-align (top|bottom|middle|basline|auto) #IMPLIED>
+
+<!ELEMENT style:footnote-sep EMPTY>
+<!ATTLIST style:footnote-sep style:width %length; #IMPLIED>
+<!ATTLIST style:footnote-sep style:rel-width %percentage; #IMPLIED>
+<!ATTLIST style:footnote-sep style:color %color; #IMPLIED>
+<!ATTLIST style:footnote-sep style:adjustment (left|center|right) "left">
+<!ATTLIST style:footnote-sep style:distance-before-sep %length; #IMPLIED>
+<!ATTLIST style:footnote-sep style:distance-after-sep %length; #IMPLIED>
+
+<!-- master page -->
+<!ELEMENT style:master-page ( (style:header, style:header-left?)?, (style:footer, style:footer-left?)?,
+ office:forms?,style:style*, (%shapes;)*, presentation:notes? )>
+<!ATTLIST style:master-page style:name %styleName; #REQUIRED>
+<!ATTLIST style:master-page style:page-master-name %styleName; #REQUIRED>
+<!ATTLIST style:master-page style:next-style-name %styleName; #IMPLIED>
+<!ATTLIST style:master-page draw:style-name %styleName; #IMPLIED>
+
+<!-- handout master -->
+<!ELEMENT style:handout-master (%shapes;)*>
+<!ATTLIST style:handout-master presentation:presentation-page-layout-name %styleName; #IMPLIED>
+
+<!ENTITY % hd-ft-content "( text:p | (style:region-left?, style:region-center?, style:region-right?) )">
+<!ELEMENT style:header %hd-ft-content;>
+<!ELEMENT style:footer %hd-ft-content;>
+<!ELEMENT style:header-left %hd-ft-content;>
+<!ATTLIST style:header-left style:display %boolean; "true">
+<!ELEMENT style:footer-left %hd-ft-content;>
+<!ATTLIST style:footer-left style:display %boolean; "true">
+
+<!ENTITY % region-content "(text:p*)">
+<!ELEMENT style:region-left %region-content;>
+<!ELEMENT style:region-center %region-content;>
+<!ELEMENT style:region-right %region-content;>
diff --git a/xmerge/source/palmtests/qa/comparator/dtd/table.mod b/xmerge/source/palmtests/qa/comparator/dtd/table.mod
new file mode 100644
index 000000000000..6d9f3cdb2a8f
--- /dev/null
+++ b/xmerge/source/palmtests/qa/comparator/dtd/table.mod
@@ -0,0 +1,493 @@
+<!--
+
+ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+
+ Copyright 2000, 2010 Oracle and/or its affiliates.
+
+ OpenOffice.org - a multi-platform office productivity suite
+
+ This file is part of OpenOffice.org.
+
+ OpenOffice.org is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License version 3
+ only, as published by the Free Software Foundation.
+
+ OpenOffice.org is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License version 3 for more details
+ (a copy is included in the LICENSE file that accompanied this code).
+
+ You should have received a copy of the GNU Lesser General Public License
+ version 3 along with OpenOffice.org. If not, see
+ <http://www.openoffice.org/license.html>
+ for a copy of the LGPLv3 License.
+
+-->
+
+<!ELEMENT table:calculation-settings (table:null-date?, table:iteration?)>
+<!ATTLIST table:calculation-settings
+ table:case-sensitive %boolean; "true"
+ table:precision-as-shown %boolean; "false"
+ table:search-criteria-must-apply-to-whole-cell %boolean; "true"
+ table:automatic-find-labels %boolean; "true"
+ table:use-regular-expressions %boolean; "true"
+ table:null-year %positiveInteger; "1930"
+>
+<!ELEMENT table:null-date EMPTY>
+<!ATTLIST table:null-date
+ table:value-type %valueType; #FIXED "date"
+ table:date-value %date; "1899-12-30"
+>
+<!ELEMENT table:iteration EMPTY>
+<!ATTLIST table:iteration
+ table:status (enable | disable) "disable"
+ table:steps %positiveInteger; "100"
+ table:maximum-difference %float; "0.001"
+>
+
+<!ELEMENT table:tracked-changes (table:cell-content-change | table:insertion | table:deletion | table:movement | table:rejection)*>
+<!ATTLIST table:tracked-changes table:track-changes %boolean; "true"
+ table:protected %boolean; "false"
+ table:protection-key CDATA #IMPLIED
+>
+
+<!ELEMENT table:dependences (table:dependence)+>
+<!ELEMENT table:dependence EMPTY>
+<!ATTLIST table:dependence
+ table:id CDATA #REQUIRED
+>
+<!ELEMENT table:deletions (table:cell-content-deletion | table:change-deletion)+>
+<!ELEMENT table:cell-content-deletion (table:cell-address?, table:change-track-table-cell?)>
+<!ATTLIST table:cell-content-deletion
+ table:id CDATA #IMPLIED
+>
+<!ELEMENT table:change-deletion EMPTY>
+<!ATTLIST table:change-deletion
+ table:id CDATA #IMPLIED
+>
+<!ELEMENT table:insertion (office:change-info, table:dependences?, table:deletions?)>
+<!ATTLIST table:insertion
+ table:id CDATA #REQUIRED
+ table:acceptance-state (accepted | rejected | pending) "pending"
+ table:rejecting-change-id %positiveInteger; #IMPLIED
+ table:type (row | column | table) #REQUIRED
+ table:position %integer; #REQUIRED
+ table:count %positiveInteger; "1"
+ table:table %integer; #IMPLIED
+>
+<!ELEMENT table:deletion (office:change-info, table:dependences?, table:deletions?, table:cut-offs?)>
+<!ATTLIST table:deletion
+ table:id CDATA #REQUIRED
+ table:acceptance-state (accepted | rejected | pending) "pending"
+ table:rejecting-change-id %positiveInteger; #IMPLIED
+ table:type (row | column | table) #REQUIRED
+ table:position %integer; #REQUIRED
+ table:count %positiveInteger; "1"
+ table:table %integer; #IMPLIED
+ table:multi-deletion-spanned %integer; #IMPLIED
+>
+<!ELEMENT table:cut-offs (table:movement-cut-off+ | (table:insertion-cut-off, table:movement-cut-off*))>
+<!ELEMENT table:insertion-cut-off EMPTY>
+<!ATTLIST table:insertion-cut-off
+ table:id CDATA #REQUIRED
+ table:position %integer; #REQUIRED
+>
+<!ELEMENT table:movement-cut-off EMPTY>
+<!ATTLIST table:movement-cut-off
+ table:id CDATA #REQUIRED
+ table:start-position %integer; #IMPLIED
+ table:end-position %integer; #IMPLIED
+ table:position %integer; #IMPLIED
+>
+<!ELEMENT table:movement (table:source-range-address, table:target-range-address, office:change-info, table:dependences?, table:deletions?)>
+<!ATTLIST table:movement
+ table:id CDATA #REQUIRED
+ table:acceptance-state (accepted | rejected | pending) "pending"
+ table:rejecting-change-id %positiveInteger; #IMPLIED
+>
+<!ELEMENT table:target-range-address EMPTY>
+<!ATTLIST table:target-range-address
+ table:column %integer; #IMPLIED
+ table:row %integer; #IMPLIED
+ table:table %integer; #IMPLIED
+ table:start-column %integer; #IMPLIED
+ table:start-row %integer; #IMPLIED
+ table:start-table %integer; #IMPLIED
+ table:end-column %integer; #IMPLIED
+ table:end-row %integer; #IMPLIED
+ table:end-table %integer; #IMPLIED
+>
+<!ELEMENT table:source-range-address EMPTY>
+<!ATTLIST table:source-range-address
+ table:column %integer; #IMPLIED
+ table:row %integer; #IMPLIED
+ table:table %integer; #IMPLIED
+ table:start-column %integer; #IMPLIED
+ table:start-row %integer; #IMPLIED
+ table:start-table %integer; #IMPLIED
+ table:end-column %integer; #IMPLIED
+ table:end-row %integer; #IMPLIED
+ table:end-table %integer; #IMPLIED
+>
+<!ELEMENT table:change-track-table-cell (text:p*)>
+<!ATTLIST table:change-track-table-cell
+ table:cell-address %cell-address; #IMPLIED
+ table:matrix-covered (true | false) "false"
+ table:formula %string; #IMPLIED
+ table:number-matrix-rows-spanned %positiveInteger; #IMPLIED
+ table:number-matrix-columns-spanned %positiveInteger; #IMPLIED
+ table:value-type %valueType; "string"
+ table:value %float; #IMPLIED
+ table:date-value %date; #IMPLIED
+ table:time-value %timeInstance; #IMPLIED
+ table:string-value %string; #IMPLIED
+>
+<!ELEMENT table:cell-content-change (table:cell-address, office:change-info, table:dependences?, table:deletions?, table:previous)>
+<!ATTLIST table:cell-content-change
+ table:id CDATA #REQUIRED
+ table:acceptance-state (accepted | rejected | pending) "pending"
+ table:rejecting-change-id %positiveInteger; #IMPLIED
+>
+<!ELEMENT table:cell-address EMPTY>
+<!ATTLIST table:cell-address
+ table:column %integer; #IMPLIED
+ table:row %integer; #IMPLIED
+ table:table %integer; #IMPLIED
+>
+<!ELEMENT table:previous (table:change-track-table-cell)>
+<!ATTLIST table:previous
+ table:id CDATA #IMPLIED
+>
+<!ELEMENT table:rejection (office:change-info, table:dependences?, table:deletions?)>
+<!ATTLIST table:rejection
+ table:id CDATA #REQUIRED
+ table:acceptance-state (accepted | rejected | pending) "pending"
+ table:rejecting-change-id %positiveInteger; #IMPLIED
+>
+
+<!ENTITY % table-columns "table:table-columns | ( table:table-column | table:table-column-group )+">
+<!ENTITY % table-header-columns "table:table-header-columns">
+<!ENTITY % table-rows "table:table-rows | ( table:table-row | table:table-row-group )+">
+<!ENTITY % table-header-rows "table:table-header-rows">
+<!ENTITY % table-column-groups "((%table-columns;),(%table-header-columns;,(%table-columns;)?)?) | (%table-header-columns;,(%table-columns;)?)">
+<!ENTITY % table-row-groups "((%table-rows;),(%table-header-rows;,(%table-rows;)?)?) | (%table-header-rows;,(%table-rows;)?)">
+<!ELEMENT table:table (table:table-source?, table:scenario?, office:forms?, table:shapes?, (%table-column-groups;), (%table-row-groups;))>
+<!ATTLIST table:table
+ table:name %string; #IMPLIED
+ table:style-name %styleName; #IMPLIED
+ table:protected %boolean; "false"
+ table:protection-key CDATA #IMPLIED
+ table:print-ranges %cell-range-address-list; #IMPLIED
+>
+<!ELEMENT table:table-source EMPTY>
+<!ATTLIST table:table-source
+ table:mode (copy-all | copy-results-only) "copy-all"
+ xlink:type (simple) #FIXED "simple"
+ xlink:actuate (onRequest) "onRequest"
+ xlink:href %uriReference; #REQUIRED
+ table:filter-name CDATA #IMPLIED
+ table:table-name CDATA #IMPLIED
+ table:filter-options CDATA #IMPLIED
+ table:refresh-delay %timeDuration; #IMPLIED
+>
+<!ELEMENT table:scenario EMPTY>
+<!ATTLIST table:scenario
+ table:display-border %boolean; "true"
+ table:border-color %color; #IMPLIED
+ table:copy-back %boolean; "true"
+ table:copy-styles %boolean; "true"
+ table:copy-formulas %boolean; "true"
+ table:is-active %boolean; #REQUIRED
+ table:scenario-ranges %cell-range-address-list; #REQUIRED
+ table:comment CDATA #IMPLIED
+>
+<!ELEMENT table:shapes %shapes;>
+<!ELEMENT table:table-column-group (table:table-header-columns | table:table-column | table:table-column-group)+>
+<!ATTLIST table:table-column-group
+ table:display %boolean; "true"
+>
+<!ELEMENT table:table-header-columns (table:table-column | table:table-column-group)+>
+<!ELEMENT table:table-columns (table:table-column | table:table-column-group)+>
+<!ELEMENT table:table-column EMPTY>
+<!ATTLIST table:table-column
+ table:number-columns-repeated %positiveInteger; "1"
+ table:style-name %styleName; #IMPLIED
+ table:visibility (visible | collapse | filter) "visible"
+ table:default-cell-style-name %styleName; #IMPLIED
+>
+<!ELEMENT table:table-row-group (table:table-header-rows | table:table-row | table:table-row-group)+>
+<!ATTLIST table:table-row-group
+ table:display %boolean; "true"
+>
+<!ELEMENT table:table-header-rows (table:table-row | table:table-row-group)+>
+<!ELEMENT table:table-rows (table:table-row | table:table-row-group)+>
+<!ENTITY % table-cells "(table:table-cell|table:covered-table-cell)+">
+<!ELEMENT table:table-row %table-cells;>
+<!ATTLIST table:table-row
+ table:number-rows-repeated %positiveInteger; "1"
+ table:style-name %styleName; #IMPLIED
+ table:visibility (visible | collapse | filter) "visible"
+ table:default-cell-style-name %styleName; #IMPLIED
+>
+
+<!ENTITY % text-wo-table "(text:h|text:p|text:ordered-list|text:unordered-list|%shapes;)*">
+<!ENTITY % cell-content "(table:cell-range-source?,office:annotation?,table:detective?,(table:sub-table|%text-wo-table;))">
+<!ELEMENT table:table-cell %cell-content;>
+<!ELEMENT table:covered-table-cell %cell-content;>
+<!ATTLIST table:table-cell
+ table:number-columns-repeated %positiveInteger; "1"
+ table:number-rows-spanned %positiveInteger; "1"
+ table:number-columns-spanned %positiveInteger; "1"
+ table:style-name %styleName; #IMPLIED
+ table:validation-name CDATA #IMPLIED
+ table:formula %string; #IMPLIED
+ table:number-matrix-rows-spanned %positiveInteger; #IMPLIED
+ table:number-matrix-columns-spanned %positiveInteger; #IMPLIED
+ table:value-type %valueType; "string"
+ table:value %float; #IMPLIED
+ table:date-value %date; #IMPLIED
+ table:time-value %timeInstance; #IMPLIED
+ table:boolean-value %boolean; #IMPLIED
+ table:string-value %string; #IMPLIED
+ table:currency %string; #IMPLIED
+>
+<!ATTLIST table:covered-table-cell
+ table:number-columns-repeated %positiveInteger; "1"
+ table:style-name %styleName; #IMPLIED
+ table:validation-name CDATA #IMPLIED
+ table:formula %string; #IMPLIED
+ table:number-matrix-rows-spanned %positiveInteger; #IMPLIED
+ table:number-matrix-columns-spanned %positiveInteger; #IMPLIED
+ table:value-type %valueType; "string"
+ table:value %float; #IMPLIED
+ table:date-value %date; #IMPLIED
+ table:time-value %timeInstance; #IMPLIED
+ table:boolean-value %boolean; #IMPLIED
+ table:string-value %string; #IMPLIED
+ table:currency %string; #IMPLIED
+>
+<!-- cell protection in writer: cell attribute; calc uses format -->
+<!ATTLIST table:table-cell table:protected %boolean; "false">
+
+<!ELEMENT table:cell-range-source EMPTY>
+<!ATTLIST table:cell-range-source
+ table:name %string; #REQUIRED
+ xlink:type (simple) #FIXED "simple"
+ xlink:actuate (onRequest) #FIXED "onRequest"
+ xlink:href %uriReference; #REQUIRED
+ table:filter-name %string; #REQUIRED
+ table:filter-options %string; #IMPLIED
+ table:last-column-spanned %positiveInteger; #REQUIRED
+ table:last-row-spanned %positiveInteger; #REQUIRED
+ table:refresh-delay %timeDuration; #IMPLIED
+>
+
+<!ELEMENT table:detective (table:highlighted-range*, table:operation*)>
+<!ELEMENT table:highlighted-range EMPTY>
+<!ATTLIST table:highlighted-range
+ table:cell-range-address %cell-range-address; #IMPLIED
+ table:direction (from-another-table | to-another-table | from-same-table | to-same-table) #REQUIRED
+ table:contains-error %boolean; "false"
+>
+<!ELEMENT table:operation EMPTY>
+<!ATTLIST table:operation
+ table:name (trace-dependents | remove-dependents | trace-precedents | remove-precedents | trace-errors) #REQUIRED
+ table:index %nonNegativeInteger; #REQUIRED
+>
+
+<!ELEMENT table:content-validations (table:content-validation)+>
+<!ELEMENT table:content-validation (table:help-message?, (table:error-message | (table:error-macro, office:events?))?)>
+<!ATTLIST table:content-validation
+ table:name CDATA #REQUIRED
+ table:condition CDATA #IMPLIED
+ table:base-cell-address %cell-address; #IMPLIED
+ table:allow-empty-cell %boolean; #IMPLIED
+>
+<!ELEMENT table:help-message (text:p*)>
+<!ATTLIST table:help-message
+ table:title CDATA #IMPLIED
+ table:display %boolean; #IMPLIED
+>
+<!ELEMENT table:error-message (text:p*)>
+<!ATTLIST table:error-message
+ table:title CDATA #IMPLIED
+ table:message-type (stop | warning | information) #IMPLIED
+ table:display %boolean; #IMPLIED
+>
+<!ELEMENT table:error-macro EMPTY>
+<!ATTLIST table:error-macro
+ table:name CDATA #IMPLIED
+ table:execute %boolean; #IMPLIED
+>
+
+<!ELEMENT table:sub-table ((%table-column-groups;) , (%table-row-groups;))>
+
+<!ELEMENT table:label-ranges (table:label-range)*>
+<!ELEMENT table:label-range EMPTY>
+<!ATTLIST table:label-range
+ table:label-cell-range-address %cell-range-address; #REQUIRED
+ table:data-cell-range-address %cell-range-address; #REQUIRED
+ table:orientation (column | row) #REQUIRED
+>
+
+<!ELEMENT table:named-expressions (table:named-range | table:named-expression)*>
+<!ELEMENT table:named-range EMPTY>
+<!ATTLIST table:named-range
+ table:name CDATA #REQUIRED
+ table:cell-range-address %cell-range-address; #REQUIRED
+ table:base-cell-address %cell-address; #IMPLIED
+ table:range-usable-as CDATA "none"
+>
+<!ELEMENT table:named-expression EMPTY>
+<!ATTLIST table:named-expression
+ table:name CDATA #REQUIRED
+ table:expression CDATA #REQUIRED
+ table:base-cell-address %cell-address; #IMPLIED
+>
+
+<!ELEMENT table:filter (table:filter-condition | table:filter-and | table:filter-or)>
+<!ATTLIST table:filter
+ table:target-range-address %cell-range-address; #IMPLIED
+ table:condition-source-range-address %cell-range-address; #IMPLIED
+ table:condition-source (self | cell-range) "self"
+ table:display-duplicates %boolean; "true"
+>
+<!ELEMENT table:filter-and (table:filter-or | table:filter-condition)+>
+<!ELEMENT table:filter-or (table:filter-and | table:filter-condition)+>
+<!ELEMENT table:filter-condition EMPTY>
+<!ATTLIST table:filter-condition
+ table:field-number %nonNegativeInteger; #REQUIRED
+ table:case-sensitive %boolean; "false"
+ table:data-type (text | number) "text"
+ table:value CDATA #REQUIRED
+ table:operator CDATA #REQUIRED
+>
+
+<!ELEMENT table:database-ranges (table:database-range)*>
+<!ELEMENT table:database-range ((table:database-source-sql | table:database-source-table | table:database-source-query)?, table:filter?, table:sort?, table:subtotal-rules?)>
+<!ATTLIST table:database-range
+ table:name CDATA #IMPLIED
+ table:is-selection %boolean; "false"
+ table:on-update-keep-styles %boolean; "false"
+ table:on-update-keep-size %boolean; "true"
+ table:has-persistant-data %boolean; "true"
+ table:orientation (row | column) "row"
+ table:contains-header %boolean; "true"
+ table:display-filter-buttons %boolean; "false"
+ table:target-range-address %cell-range-address; #REQUIRED
+ table:refresh-delay %timeDuration; #IMPLIED
+>
+<!ELEMENT table:database-source-sql EMPTY>
+<!ATTLIST table:database-source-sql
+ table:database-name CDATA #REQUIRED
+ table:sql-statement CDATA #REQUIRED
+ table:parse-sql-statements %boolean; "false"
+>
+<!ELEMENT table:database-source-table EMPTY>
+<!ATTLIST table:database-source-table
+ table:database-name CDATA #REQUIRED
+ table:table-name CDATA #REQUIRED
+>
+<!ELEMENT table:database-source-query EMPTY>
+<!ATTLIST table:database-source-query
+ table:database-name CDATA #REQUIRED
+ table:query-name CDATA #REQUIRED
+>
+
+<!ELEMENT table:sort (table:sort-by)+>
+<!ATTLIST table:sort
+ table:bind-styles-to-content %boolean; "true"
+ table:target-range-address %cell-range-address; #IMPLIED
+ table:case-sensitive %boolean; "false"
+ table:language CDATA #IMPLIED
+ table:country CDATA #IMPLIED
+ table:algorithm CDATA #IMPLIED
+>
+<!ELEMENT table:sort-by EMPTY>
+<!ATTLIST table:sort-by
+ table:field-number %nonNegativeInteger; #REQUIRED
+ table:data-type (text | number | automatic | qname-but-not-ncname) "automatic"
+ table:order (ascending | descending) "ascending"
+>
+
+<!ELEMENT table:subtotal-rules (table:sort-groups? | table:subtotal-rule*)?>
+<!ATTLIST table:subtotal-rules
+ table:bind-styles-to-content %boolean; "true"
+ table:case-sensitive %boolean; "false"
+ table:page-breaks-on-group-change %boolean; "false"
+>
+<!ELEMENT table:sort-groups EMPTY>
+<!ATTLIST table:sort-groups
+ table:data-type (text | number | automatic | qname-but-not-ncname) "automatic"
+ table:order (ascending | descending) "ascending"
+>
+<!ELEMENT table:subtotal-rule (table:subtotal-field)*>
+<!ATTLIST table:subtotal-rule
+ table:group-by-field-number %nonNegativeInteger; #REQUIRED
+>
+<!ELEMENT table:subtotal-field EMPTY>
+<!ATTLIST table:subtotal-field
+ table:field-number %nonNegativeInteger; #REQUIRED
+ table:function CDATA #REQUIRED
+>
+
+<!ELEMENT table:data-pilot-tables (table:data-pilot-table)*>
+<!ELEMENT table:data-pilot-table ((table:database-source-sql | table:database-source-table | table:database-source-query | table:source-service | table:source-cell-range)?, table:data-pilot-field+)>
+<!ATTLIST table:data-pilot-table
+ table:name CDATA #REQUIRED
+ table:application-data CDATA #IMPLIED
+ table:grand-total (none | row | column | both) "both"
+ table:ignore-empty-rows %boolean; "false"
+ table:identify-categories %boolean; "false"
+ table:target-range-address %cell-range-address; #REQUIRED
+ table:buttons %cell-range-address-list; #REQUIRED
+>
+<!ELEMENT table:source-service EMPTY>
+<!ATTLIST table:source-service
+ table:name CDATA #REQUIRED
+ table:source-name CDATA #REQUIRED
+ table:object-name CDATA #REQUIRED
+ table:username CDATA #IMPLIED
+ table:password CDATA #IMPLIED
+>
+<!ELEMENT table:source-cell-range (table:filter)?>
+<!ATTLIST table:source-cell-range
+ table:cell-range-address %cell-range-address; #REQUIRED
+>
+<!ELEMENT table:data-pilot-field (table:data-pilot-level)?>
+<!ATTLIST table:data-pilot-field
+ table:source-field-name CDATA #REQUIRED
+ table:is-data-layout-field %boolean; "false"
+ table:function CDATA #REQUIRED
+ table:orientation (row | column | data | page | hidden) #REQUIRED
+ table:used-hierarchy %positiveInteger; "1"
+>
+<!ELEMENT table:data-pilot-level (table:data-pilot-subtotals?, table:data-pilot-members?)>
+<!ATTLIST table:data-pilot-level
+ table:display-empty %boolean; #IMPLIED
+>
+<!ELEMENT table:data-pilot-subtotals (table:data-pilot-subtotal)*>
+<!ELEMENT table:data-pilot-subtotal EMPTY>
+<!ATTLIST table:data-pilot-subtotal
+ table:function CDATA #REQUIRED
+>
+<!ELEMENT table:data-pilot-members (table:data-pilot-member)*>
+<!ELEMENT table:data-pilot-member EMPTY>
+<!ATTLIST table:data-pilot-member
+ table:name CDATA #REQUIRED
+ table:display %boolean; #IMPLIED
+ table:display-details %boolean; #IMPLIED
+>
+
+<!ELEMENT table:consolidation EMPTY>
+<!ATTLIST table:consolidation
+ table:function CDATA #REQUIRED
+ table:source-cell-range-addresses %cell-range-address-list; #REQUIRED
+ table:target-cell-address %cell-address; #REQUIRED
+ table:use-label (none | column | row | both) "none"
+ table:link-to-source-data %boolean; "false"
+>
+
+<!ELEMENT table:dde-links (table:dde-link)+>
+<!ELEMENT table:dde-link (office:dde-source, table:table)>
diff --git a/xmerge/source/palmtests/qa/comparator/dtd/text.mod b/xmerge/source/palmtests/qa/comparator/dtd/text.mod
new file mode 100644
index 000000000000..792b0fdde55e
--- /dev/null
+++ b/xmerge/source/palmtests/qa/comparator/dtd/text.mod
@@ -0,0 +1,1099 @@
+<!--
+
+ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+
+ Copyright 2000, 2010 Oracle and/or its affiliates.
+
+ OpenOffice.org - a multi-platform office productivity suite
+
+ This file is part of OpenOffice.org.
+
+ OpenOffice.org is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License version 3
+ only, as published by the Free Software Foundation.
+
+ OpenOffice.org is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License version 3 for more details
+ (a copy is included in the LICENSE file that accompanied this code).
+
+ You should have received a copy of the GNU Lesser General Public License
+ version 3 along with OpenOffice.org. If not, see
+ <http://www.openoffice.org/license.html>
+ for a copy of the LGPLv3 License.
+
+-->
+
+<!ENTITY % fields "text:date |
+ text:time |
+ text:page-number |
+ text:page-continuation |
+ text:sender-firstname |
+ text:sender-lastname |
+ text:sender-initials |
+ text:sender-title |
+ text:sender-position |
+ text:sender-email |
+ text:sender-phone-private |
+ text:sender-fax |
+ text:sender-company |
+ text:sender-phone-work |
+ text:sender-street |
+ text:sender-city |
+ text:sender-postal-code |
+ text:sender-country |
+ text:sender-state-or-province |
+ text:author-name |
+ text:author-initials |
+ text:placeholder |
+ text:variable-set |
+ text:variable-get |
+ text:variable-input |
+ text:user-field-get |
+ text:user-field-input |
+ text:sequence |
+ text:expression |
+ text:text-input |
+ text:database-display |
+ text:database-next |
+ text:database-row-select |
+ text:database-row-number |
+ text:database-name |
+ text:initial-creator |
+ text:creation-date |
+ text:creation-time |
+ text:description |
+ text:user-defined |
+ text:print-time |
+ text:print-date |
+ text:printed-by |
+ text:title |
+ text:subject |
+ text:keywords |
+ text:editing-cycles |
+ text:editing-duration |
+ text:modification-time |
+ text:modification-date |
+ text:creator |
+ text:conditional-text |
+ text:hidden-text |
+ text:hidden-paragraph |
+ text:chapter |
+ text:file-name |
+ text:template-name |
+ text:set-page-variable |
+ text:get-page-variable |
+ text:execute-macro |
+ text:dde-connection |
+ text:reference-ref |
+ text:sequence-ref |
+ text:bookmark-ref |
+ text:footnote-ref |
+ text:endnote-ref |
+ text:sheet-name |
+ text:bibliography-mark |
+ text:page-count |
+ text:paragraph-count |
+ text:word-count |
+ text:character-count |
+ text:table-count |
+ text:image-count |
+ text:object-count |
+ office:annotation |
+ text:script |
+ text:measure" >
+
+<!ENTITY % inline-text "(#PCDATA|
+ text:span|text:tab-stop|text:s|text:line-break|
+ text:footnote|text:endnote|text:a|
+ text:bookmark|text:bookmark-start|text:bookmark-end|
+ text:reference-mark|text:reference-mark-start|
+ text:reference-mark-end|%fields;|%shape;|
+ text:toc-mark-start | text:toc-mark-end |
+ text:toc-mark | text:user-index-mark-start |
+ text:user-index-mark-end | text:user-index-mark |
+ text:alphabetical-index-mark-start |
+ text:alphabetical-index-mark-end |
+ text:alphabetical-index-mark |
+ %change-marks; | draw:a | text:ruby)*">
+
+<!ELEMENT text:p %inline-text;>
+<!ELEMENT text:h %inline-text;>
+
+<!ATTLIST text:p text:style-name %styleName; #IMPLIED>
+<!ATTLIST text:p text:cond-style-name %styleName; #IMPLIED>
+
+<!ATTLIST text:h text:style-name %styleName; #IMPLIED>
+<!ATTLIST text:h text:cond-style-name %styleName; #IMPLIED>
+<!ATTLIST text:h text:level %positiveInteger; "1">
+
+<!ELEMENT text:span %inline-text;>
+<!ATTLIST text:span text:style-name %styleName; #REQUIRED>
+
+<!ELEMENT text:a %inline-text;>
+<!ATTLIST text:a xlink:href %uriReference; #REQUIRED>
+<!ATTLIST text:a xlink:type (simple) #FIXED "simple">
+<!ATTLIST text:a xlink:actuate (onRequest) "onRequest">
+<!ATTLIST text:a xlink:show (new|replace) "replace">
+<!ATTLIST text:a office:name %string; #IMPLIED>
+<!ATTLIST text:a office:target-frame-name %string; #IMPLIED>
+<!ATTLIST text:a text:style-name %styleName; #IMPLIED>
+<!ATTLIST text:a text:visited-style-name %styleName; #IMPLIED>
+
+
+<!ELEMENT text:s EMPTY>
+<!ATTLIST text:s text:c %positiveInteger; "1">
+
+<!ELEMENT text:tab-stop EMPTY>
+
+<!ELEMENT text:line-break EMPTY>
+
+
+<!ENTITY % list-items "((text:list-header,text:list-item*)|text:list-item+)">
+<!ELEMENT text:ordered-list %list-items;>
+<!ELEMENT text:unordered-list %list-items;>
+
+
+<!ATTLIST text:ordered-list text:style-name %styleName; #IMPLIED>
+<!ATTLIST text:unordered-list text:style-name %styleName; #IMPLIED>
+
+<!ATTLIST text:ordered-list text:continue-numbering %boolean; "false">
+
+<!ELEMENT text:list-header (text:p)+>
+<!ELEMENT text:list-item (text:p|text:ordered-list|text:unordered-list)+>
+
+<!ATTLIST text:list-item text:restart-numbering %boolean; "false">
+<!ATTLIST text:list-item text:start-value %positiveInteger; #IMPLIED>
+
+<!ELEMENT text:list-style (text:list-level-style-number|
+ text:list-level-style-bullet|
+ text:list-level-style-image)+>
+
+<!ATTLIST text:list-style style:name %styleName; #IMPLIED>
+
+<!ATTLIST text:list-style text:consecutive-numbering %boolean; "false">
+
+
+<!ELEMENT text:list-level-style-number (style:properties?)>
+
+<!ATTLIST text:list-level-style-number text:level %positiveInteger;
+ #REQUIRED>
+<!ATTLIST text:list-level-style-number text:style-name %styleName; #IMPLIED>
+
+<!ATTLIST text:list-level-style-number style:num-format %string; #REQUIRED>
+<!ATTLIST text:list-level-style-number style:num-prefix %string; #IMPLIED>
+<!ATTLIST text:list-level-style-number style:num-suffix %string; #IMPLIED>
+<!ATTLIST text:list-level-style-number style:num-letter-sync %boolean;
+ "false">
+<!ATTLIST text:list-level-style-number text:display-levels %positiveInteger;
+ "1">
+<!ATTLIST text:list-level-style-number text:start-value %positiveInteger;
+ "1">
+<!ELEMENT text:list-level-style-bullet (style:properties?)>
+
+<!ATTLIST text:list-level-style-bullet text:level %positiveInteger; #REQUIRED>
+<!ATTLIST text:list-level-style-bullet text:style-name %styleName; #IMPLIED>
+<!ATTLIST text:list-level-style-bullet text:bullet-char %character; #REQUIRED>
+<!ATTLIST text:list-level-style-bullet style:num-prefix %string; #IMPLIED>
+<!ATTLIST text:list-level-style-bullet style:num-suffix %string; #IMPLIED>
+
+<!ELEMENT text:list-level-style-image (style:properties?,office:binary-data?)>
+
+<!ATTLIST text:list-level-style-image text:level %positiveInteger; #REQUIRED>
+<!ATTLIST text:list-level-style-image xlink:type (simple) #IMPLIED>
+<!ATTLIST text:list-level-style-image xlink:href %uriReference; #IMPLIED>
+<!ATTLIST text:list-level-style-image xlink:actuate (onLoad) #IMPLIED>
+<!ATTLIST text:list-level-style-image xlink:show (embed) #IMPLIED>
+
+
+<!-- list properties -->
+<!ATTLIST style:properties text:space-before %nonNegativeLength; #IMPLIED>
+<!ATTLIST style:properties text:min-label-width %nonNegativeLength; #IMPLIED>
+<!ATTLIST style:properties text:min-label-distance %nonNegativeLength; #IMPLIED>
+<!ATTLIST style:properties text:enable-numbering %boolean; #IMPLIED>
+<!ATTLIST style:properties style:list-style-name %styleName; #IMPLIED>
+
+<!ELEMENT text:outline-style (text:outline-level-style)+>
+
+<!ELEMENT text:outline-level-style (style:properties?)>
+
+<!ATTLIST text:outline-level-style text:level %positiveInteger;
+ #REQUIRED>
+<!ATTLIST text:outline-level-style text:style-name %styleName; #IMPLIED>
+
+<!ATTLIST text:outline-level-style style:num-format %string; #REQUIRED>
+<!ATTLIST text:outline-level-style style:num-prefix %string; #IMPLIED>
+<!ATTLIST text:outline-level-style style:num-suffix %string; #IMPLIED>
+<!ATTLIST text:outline-level-style style:num-letter-sync %boolean;
+ "false">
+<!ATTLIST text:outline-level-style text:display-levels %positiveInteger;
+ "1">
+<!ATTLIST text:outline-level-style text:start-value %positiveInteger;
+ "1">
+
+<!ENTITY % field-declarations "text:variable-decls?,
+ text:user-field-decls?,
+ text:sequence-decls?">
+
+<!ENTITY % variableName "CDATA">
+
+<!ENTITY % formula "CDATA">
+
+<!ENTITY % valueAttr "text:value-type %valueType; #REQUIRED">
+
+<!ENTITY % valueAndTypeAttr "%valueAttr;
+ text:value %float; #IMPLIED
+ text:date-value %date; #IMPLIED
+ text:time-value %timeInstance; #IMPLIED
+ text:boolean-value %boolean; #IMPLIED
+ text:string-value %string; #IMPLIED
+ text:currency CDATA #IMPLIED" >
+
+<!ENTITY % numFormat 'style:num-format CDATA #IMPLIED
+ style:num-letter-sync %boolean; "false"'>
+
+
+<!ELEMENT text:date (#PCDATA)>
+<!ATTLIST text:date text:date-value %date; #IMPLIED>
+<!ATTLIST text:date text:date-adjust %dateDuration; #IMPLIED>
+<!ATTLIST text:date text:fixed %boolean; "false">
+<!ATTLIST text:date style:data-style-name %styleName; #IMPLIED>
+
+<!ELEMENT text:time (#PCDATA)>
+<!ATTLIST text:time text:time-value %timeInstance; #IMPLIED>
+<!ATTLIST text:time text:time-adjust %timeDuration; #IMPLIED>
+<!ATTLIST text:time text:fixed %boolean; "false">
+<!ATTLIST text:time style:data-style-name %styleName; #IMPLIED>
+
+<!ELEMENT text:page-number (#PCDATA)>
+<!ATTLIST text:page-number text:page-adjust %positiveInteger; #IMPLIED>
+<!ATTLIST text:page-number text:select-page (previous|current|next) "current">
+<!ATTLIST text:page-number %numFormat;>
+
+<!ELEMENT text:page-continuation (#PCDATA)>
+<!ATTLIST text:page-continuation text:select-page (previous|next) #REQUIRED>
+<!ATTLIST text:page-continuation text:string-value %string; #IMPLIED>
+
+<!ELEMENT text:sender-firstname (#PCDATA)>
+<!ATTLIST text:sender-firstname text:fixed %boolean; "true">
+
+<!ELEMENT text:sender-lastname (#PCDATA)>
+<!ATTLIST text:sender-lastname text:fixed %boolean; "true">
+
+<!ELEMENT text:sender-initials (#PCDATA)>
+<!ATTLIST text:sender-initials text:fixed %boolean; "true">
+
+<!ELEMENT text:sender-title (#PCDATA)>
+<!ATTLIST text:sender-title text:fixed %boolean; "true">
+
+<!ELEMENT text:sender-position (#PCDATA)>
+<!ATTLIST text:sender-position text:fixed %boolean; "true">
+
+<!ELEMENT text:sender-email (#PCDATA)>
+<!ATTLIST text:sender-email text:fixed %boolean; "true">
+
+<!ELEMENT text:sender-phone-private (#PCDATA)>
+<!ATTLIST text:sender-phone-private text:fixed %boolean; "true">
+
+<!ELEMENT text:sender-fax (#PCDATA)>
+<!ATTLIST text:sender-fax text:fixed %boolean; "true">
+
+<!ELEMENT text:sender-company (#PCDATA)>
+<!ATTLIST text:sender-company text:fixed %boolean; "true">
+
+<!ELEMENT text:sender-phone-work (#PCDATA)>
+<!ATTLIST text:sender-phone-work text:fixed %boolean; "true">
+
+<!ELEMENT text:sender-street (#PCDATA)>
+<!ATTLIST text:sender-street text:fixed %boolean; "true">
+
+<!ELEMENT text:sender-city (#PCDATA)>
+<!ATTLIST text:sender-city text:fixed %boolean; "true">
+
+<!ELEMENT text:sender-postal-code (#PCDATA)>
+<!ATTLIST text:sender-postal-code text:fixed %boolean; "true">
+
+<!ELEMENT text:sender-country (#PCDATA)>
+<!ATTLIST text:sender-country text:fixed %boolean; "true">
+
+<!ELEMENT text:sender-state-or-province (#PCDATA)>
+<!ATTLIST text:sender-state-or-province text:fixed %boolean; "true">
+
+<!ELEMENT text:author-name (#PCDATA)>
+<!ATTLIST text:author-name text:fixed %boolean; "true">
+
+<!ELEMENT text:author-initials (#PCDATA)>
+<!ATTLIST text:author-initials text:fixed %boolean; "true">
+
+<!ELEMENT text:placeholder (#PCDATA)>
+<!ATTLIST text:placeholder text:placeholder-type (text|table|text-box|image|object) #REQUIRED>
+<!ATTLIST text:placeholder text:description %string; #IMPLIED>
+
+<!ELEMENT text:variable-decls (text:variable-decl)*>
+
+<!ELEMENT text:variable-decl EMPTY>
+<!ATTLIST text:variable-decl text:name %variableName; #REQUIRED>
+<!ATTLIST text:variable-decl %valueAndTypeAttr;>
+
+<!ELEMENT text:variable-set (#PCDATA)>
+<!ATTLIST text:variable-set text:name %variableName; #REQUIRED>
+<!ATTLIST text:variable-set text:formula %formula; #IMPLIED>
+<!ATTLIST text:variable-set %valueAndTypeAttr;>
+<!ATTLIST text:variable-set text:display (value|none) "value">
+<!ATTLIST text:variable-set style:data-style-name %styleName; #IMPLIED>
+
+<!ELEMENT text:variable-get (#PCDATA)>
+<!ATTLIST text:variable-get text:name %variableName; #REQUIRED>
+<!ATTLIST text:variable-get text:display (value|formula) "value">
+<!ATTLIST text:variable-get style:data-style-name %styleName; #IMPLIED>
+
+<!ELEMENT text:variable-input (#PCDATA)>
+<!ATTLIST text:variable-input text:name %variableName; #REQUIRED>
+<!ATTLIST text:variable-input text:description %string; #IMPLIED>
+<!ATTLIST text:variable-input %valueAndTypeAttr;>
+<!ATTLIST text:variable-input text:display (value|none) "value">
+<!ATTLIST text:variable-input style:data-style-name %styleName; #IMPLIED>
+
+<!ELEMENT text:user-field-decls (text:user-field-decl)*>
+
+<!ELEMENT text:user-field-decl EMPTY>
+<!ATTLIST text:user-field-decl text:name %variableName; #REQUIRED>
+<!ATTLIST text:user-field-decl text:formula %formula; #IMPLIED>
+<!ATTLIST text:user-field-decl %valueAndTypeAttr;>
+
+<!ELEMENT text:user-field-get (#PCDATA)>
+<!ATTLIST text:user-field-get text:name %variableName; #REQUIRED>
+<!ATTLIST text:user-field-get text:display (value|formula|none) "value">
+<!ATTLIST text:user-field-get style:data-style-name %styleName; #IMPLIED>
+
+<!ELEMENT text:user-field-input (#PCDATA)>
+<!ATTLIST text:user-field-input text:name %variableName; #REQUIRED>
+<!ATTLIST text:user-field-input text:description %string; #IMPLIED>
+<!ATTLIST text:user-field-input style:data-style-name %styleName; #IMPLIED>
+
+<!ELEMENT text:sequence-decls (text:sequence-decl)*>
+
+<!ELEMENT text:sequence-decl EMPTY>
+<!ATTLIST text:sequence-decl text:name %variableName; #REQUIRED>
+<!ATTLIST text:sequence-decl text:display-outline-level %positiveInteger; "0">
+<!ATTLIST text:sequence-decl text:separation-character %character; ".">
+
+<!ELEMENT text:sequence (#PCDATA)>
+<!ATTLIST text:sequence text:name %variableName; #REQUIRED>
+<!ATTLIST text:sequence text:formula %formula; #IMPLIED>
+<!ATTLIST text:sequence %numFormat;>
+<!ATTLIST text:sequence text:ref-name ID #IMPLIED>
+
+<!ELEMENT text:expression (#PCDATA)>
+<!ATTLIST text:expression text:formula %formula; #IMPLIED>
+<!ATTLIST text:expression text:display (value|formula ) "value">
+<!ATTLIST text:expression %valueAndTypeAttr;>
+<!ATTLIST text:expression style:data-style-name %styleName; #IMPLIED>
+
+<!ELEMENT text:text-input (#PCDATA)>
+<!ATTLIST text:text-input text:description %string; #IMPLIED>
+
+<!ENTITY % database-table "text:database-name CDATA #REQUIRED
+ text:table-name CDATA #REQUIRED">
+
+<!ELEMENT text:database-display (#PCDATA)>
+<!ATTLIST text:database-display %database-table;>
+<!ATTLIST text:database-display text:column-name %string; #REQUIRED>
+<!ATTLIST text:database-display style:data-style-name %styleName; #IMPLIED>
+
+<!ELEMENT text:database-next (#PCDATA)>
+<!ATTLIST text:database-next %database-table;>
+<!ATTLIST text:database-next text:condition %formula; #IMPLIED>
+
+<!ELEMENT text:database-row-select (#PCDATA)>
+<!ATTLIST text:database-row-select %database-table;>
+<!ATTLIST text:database-row-select text:condition %formula; #IMPLIED>
+<!ATTLIST text:database-row-select text:row-number %integer; #REQUIRED>
+
+<!ELEMENT text:database-row-number (#PCDATA)>
+<!ATTLIST text:database-row-number %database-table;>
+<!ATTLIST text:database-row-number %numFormat;>
+<!ATTLIST text:database-row-number text:value %integer; #IMPLIED>
+
+<!ELEMENT text:database-name (#PCDATA)>
+<!ATTLIST text:database-name %database-table;>
+
+<!ELEMENT text:initial-creator (#PCDATA)>
+<!ATTLIST text:initial-creator text:fixed %boolean; "false">
+
+<!ELEMENT text:creation-date (#PCDATA)>
+<!ATTLIST text:creation-date text:fixed %boolean; "false">
+<!ATTLIST text:creation-date text:date-value %date; #IMPLIED>
+<!ATTLIST text:creation-date style:data-style-name %styleName; #IMPLIED>
+
+<!ELEMENT text:creation-time (#PCDATA)>
+<!ATTLIST text:creation-time text:fixed %boolean; "false">
+<!ATTLIST text:creation-time text:time-value %timeInstance; #IMPLIED>
+<!ATTLIST text:creation-time style:data-style-name %styleName; #IMPLIED>
+
+<!ELEMENT text:description (#PCDATA)>
+<!ATTLIST text:description text:fixed %boolean; "false">
+
+<!ELEMENT text:user-defined (#PCDATA)>
+<!ATTLIST text:user-defined text:fixed %boolean; "false">
+<!ATTLIST text:user-defined text:name %string; #REQUIRED>
+
+<!ELEMENT text:print-time (#PCDATA)>
+<!ATTLIST text:print-time text:fixed %boolean; "false">
+<!ATTLIST text:print-time text:time-value %timeInstance; #IMPLIED>
+<!ATTLIST text:print-time style:data-style-name %styleName; #IMPLIED>
+
+<!ELEMENT text:print-date (#PCDATA)>
+<!ATTLIST text:print-date text:fixed %boolean; "false">
+<!ATTLIST text:print-date text:date-value %date; #IMPLIED>
+<!ATTLIST text:print-date style:data-style-name %styleName; #IMPLIED>
+
+<!ELEMENT text:printed-by (#PCDATA)>
+<!ATTLIST text:printed-by text:fixed %boolean; "false">
+
+<!ELEMENT text:title (#PCDATA)>
+<!ATTLIST text:title text:fixed %boolean; "false">
+
+<!ELEMENT text:subject (#PCDATA)>
+<!ATTLIST text:subject text:fixed %boolean; "false">
+
+<!ELEMENT text:keywords (#PCDATA)>
+<!ATTLIST text:keywords text:fixed %boolean; "false">
+
+<!ELEMENT text:editing-cycles (#PCDATA)>
+<!ATTLIST text:editing-cycles text:fixed %boolean; "false">
+
+<!ELEMENT text:editing-duration (#PCDATA)>
+<!ATTLIST text:editing-duration text:fixed %boolean; "false">
+<!ATTLIST text:editing-duration text:duration %timeDuration; #IMPLIED>
+<!ATTLIST text:editing-duration style:data-style-name %styleName; #IMPLIED>
+
+<!ELEMENT text:modification-time (#PCDATA)>
+<!ATTLIST text:modification-time text:fixed %boolean; "false">
+<!ATTLIST text:modification-time text:time-value %timeInstance; #IMPLIED>
+<!ATTLIST text:modification-time style:data-style-name %styleName; #IMPLIED>
+
+<!ELEMENT text:modification-date (#PCDATA)>
+<!ATTLIST text:modification-date text:fixed %boolean; "false">
+<!ATTLIST text:modification-date text:date-value %date; #IMPLIED>
+<!ATTLIST text:modification-date style:data-style-name %styleName; #IMPLIED>
+
+<!ELEMENT text:creator (#PCDATA)>
+<!ATTLIST text:creator text:fixed %boolean; "false">
+
+<!ELEMENT text:conditional-text (#PCDATA)>
+<!ATTLIST text:conditional-text text:condition %formula; #REQUIRED>
+<!ATTLIST text:conditional-text text:string-value-if-false %string; #REQUIRED>
+<!ATTLIST text:conditional-text text:string-value-if-true %string; #REQUIRED>
+<!ATTLIST text:conditional-text text:current-value %boolean; "false">
+
+<!ELEMENT text:hidden-text (#PCDATA)>
+<!ATTLIST text:hidden-text text:condition %formula; #REQUIRED>
+<!ATTLIST text:hidden-text text:string-value %string; #REQUIRED>
+<!ATTLIST text:hidden-text text:is-hidden %boolean; "false">
+
+<!ELEMENT text:hidden-paragraph EMPTY>
+<!ATTLIST text:hidden-paragraph text:condition %formula; #REQUIRED>
+<!ATTLIST text:hidden-paragraph text:is-hidden %boolean; "false">
+
+<!ELEMENT text:chapter (#PCDATA)>
+<!ATTLIST text:chapter text:display (name|number|number-and-name|
+ plain-number-and-name|plain-number)
+ "number-and-name">
+<!ATTLIST text:chapter text:outline-level %integer; "1">
+
+<!ELEMENT text:file-name (#PCDATA)>
+<!ATTLIST text:file-name text:display (full|path|name|name-and-extension)
+ "full">
+<!ATTLIST text:file-name text:fixed %boolean; "false">
+
+<!ELEMENT text:template-name (#PCDATA)>
+<!ATTLIST text:template-name text:display (full|path|name|name-and-extension|
+ area|title) "full">
+
+<!ELEMENT text:set-page-variable EMPTY>
+<!ATTLIST text:set-page-variable text:active %boolean; "true">
+<!ATTLIST text:set-page-variable text:page-adjust %integer; "0">
+
+<!ELEMENT text:get-page-variable (#PCDATA)>
+<!ATTLIST text:get-page-variable %numFormat;>
+
+<!ELEMENT text:execute-macro (#PCDATA|office:events)* >
+<!ATTLIST text:execute-macro text:description %string; #IMPLIED>
+
+
+<!ELEMENT text:dde-connection-decls (text:dde-connection-decl)*>
+
+<!ELEMENT text:dde-connection-decl EMPTY>
+<!ATTLIST text:dde-connection-decl text:name %string; #REQUIRED>
+<!ATTLIST text:dde-connection-decl text:dde-application %string; #REQUIRED>
+<!ATTLIST text:dde-connection-decl text:dde-topic %string; #REQUIRED>
+<!ATTLIST text:dde-connection-decl text:dde-item %string; #REQUIRED>
+<!ATTLIST text:dde-connection-decl text:automatic-update %boolean; "false">
+
+<!ELEMENT text:dde-connection (#PCDATA)>
+<!ATTLIST text:dde-connection text:connection-name %string; #REQUIRED>
+
+<!ELEMENT text:reference-ref (#PCDATA)>
+<!ATTLIST text:reference-ref text:ref-name %string; #REQUIRED>
+<!ATTLIST text:reference-ref text:reference-format (page|chapter|text|direction) #IMPLIED>
+
+<!ELEMENT text:sequence-ref (#PCDATA)>
+<!ATTLIST text:sequence-ref text:ref-name %string; #REQUIRED>
+<!ATTLIST text:sequence-ref text:reference-format (page|chapter|text|direction|category-and-value|caption|value) #IMPLIED>
+
+<!ELEMENT text:bookmark-ref (#PCDATA)>
+<!ATTLIST text:bookmark-ref text:ref-name %string; #REQUIRED>
+<!ATTLIST text:bookmark-ref text:reference-format (page|chapter|text|direction) #IMPLIED>
+
+<!ELEMENT text:footnote-ref (#PCDATA)>
+<!ATTLIST text:footnote-ref text:ref-name %string; #REQUIRED>
+<!ATTLIST text:footnote-ref text:reference-format (page|chapter|text|direction) #IMPLIED>
+
+<!ELEMENT text:endnote-ref (#PCDATA)>
+<!ATTLIST text:endnote-ref text:ref-name %string; #REQUIRED>
+<!ATTLIST text:endnote-ref text:reference-format (page|chapter|text|direction) #IMPLIED>
+
+<!ELEMENT text:sheet-name (#PCDATA)>
+
+<!ELEMENT text:page-count (#PCDATA)>
+<!ATTLIST text:page-count style:num-format %string; #IMPLIED>
+<!ATTLIST text:page-count style:num-letter-sync %boolean; "false">
+
+<!ELEMENT text:paragraph-count (#PCDATA)>
+<!ATTLIST text:paragraph-count style:num-format %string; #IMPLIED>
+<!ATTLIST text:paragraph-count style:num-letter-sync %boolean; "false">
+
+<!ELEMENT text:word-count (#PCDATA)>
+<!ATTLIST text:word-count style:num-format %string; #IMPLIED>
+<!ATTLIST text:word-count style:num-letter-sync %boolean; "false">
+
+<!ELEMENT text:character-count (#PCDATA)>
+<!ATTLIST text:character-count style:num-format %string; #IMPLIED>
+<!ATTLIST text:character-count style:num-letter-sync %boolean; "false">
+
+<!ELEMENT text:table-count (#PCDATA)>
+<!ATTLIST text:table-count style:num-format %string; #IMPLIED>
+<!ATTLIST text:table-count style:num-letter-sync %boolean; "false">
+
+<!ELEMENT text:image-count (#PCDATA)>
+<!ATTLIST text:image-count style:num-format %string; #IMPLIED>
+<!ATTLIST text:image-count style:num-letter-sync %boolean; "false">
+
+<!ELEMENT text:object-count (#PCDATA)>
+<!ATTLIST text:object-count style:num-format %string; #IMPLIED>
+<!ATTLIST text:object-count style:num-letter-sync %boolean; "false">
+
+<!ELEMENT text:bibliography-mark (#PCDATA)>
+<!ATTLIST text:bibliography-mark text:bibiliographic-type
+ ( article | book | booklet | conference | custom1 | custom2 | custom3 |
+ custom4 | custom5 | email | inbook | incollection | inproceedings |
+ journal | manual | mastersthesis | misc | phdthesis | proceedings |
+ techreport | unpublished | www ) #REQUIRED >
+<!ATTLIST text:bibliography-mark text:identifier CDATA #IMPLIED>
+<!ATTLIST text:bibliography-mark text:address CDATA #IMPLIED>
+<!ATTLIST text:bibliography-mark text:annote CDATA #IMPLIED>
+<!ATTLIST text:bibliography-mark text:author CDATA #IMPLIED>
+<!ATTLIST text:bibliography-mark text:booktitle CDATA #IMPLIED>
+<!ATTLIST text:bibliography-mark text:chapter CDATA #IMPLIED>
+<!ATTLIST text:bibliography-mark text:edition CDATA #IMPLIED>
+<!ATTLIST text:bibliography-mark text:editor CDATA #IMPLIED>
+<!ATTLIST text:bibliography-mark text:howpublished CDATA #IMPLIED>
+<!ATTLIST text:bibliography-mark text:institution CDATA #IMPLIED>
+<!ATTLIST text:bibliography-mark text:journal CDATA #IMPLIED>
+<!ATTLIST text:bibliography-mark text:month CDATA #IMPLIED>
+<!ATTLIST text:bibliography-mark text:note CDATA #IMPLIED>
+<!ATTLIST text:bibliography-mark text:number CDATA #IMPLIED>
+<!ATTLIST text:bibliography-mark text:organizations CDATA #IMPLIED>
+<!ATTLIST text:bibliography-mark text:pages CDATA #IMPLIED>
+<!ATTLIST text:bibliography-mark text:publisher CDATA #IMPLIED>
+<!ATTLIST text:bibliography-mark text:school CDATA #IMPLIED>
+<!ATTLIST text:bibliography-mark text:series CDATA #IMPLIED>
+<!ATTLIST text:bibliography-mark text:title CDATA #IMPLIED>
+<!ATTLIST text:bibliography-mark text:report-type CDATA #IMPLIED>
+<!ATTLIST text:bibliography-mark text:volume CDATA #IMPLIED>
+<!ATTLIST text:bibliography-mark text:year CDATA #IMPLIED>
+<!ATTLIST text:bibliography-mark text:url CDATA #IMPLIED>
+<!ATTLIST text:bibliography-mark text:custom1 CDATA #IMPLIED>
+<!ATTLIST text:bibliography-mark text:custom2 CDATA #IMPLIED>
+<!ATTLIST text:bibliography-mark text:custom3 CDATA #IMPLIED>
+<!ATTLIST text:bibliography-mark text:custom4 CDATA #IMPLIED>
+<!ATTLIST text:bibliography-mark text:custom5 CDATA #IMPLIED>
+<!ATTLIST text:bibliography-mark text:isbn CDATA #IMPLIED>
+
+
+<!ELEMENT text:bookmark EMPTY>
+<!ATTLIST text:bookmark text:name CDATA #REQUIRED>
+
+<!ELEMENT text:bookmark-start EMPTY>
+<!ATTLIST text:bookmark-start text:name CDATA #REQUIRED>
+
+<!ELEMENT text:bookmark-end EMPTY>
+<!ATTLIST text:bookmark-end text:name CDATA #REQUIRED>
+
+<!ELEMENT text:reference-mark EMPTY>
+<!ATTLIST text:reference-mark text:name CDATA #REQUIRED>
+
+<!ELEMENT text:reference-mark-start EMPTY>
+<!ATTLIST text:reference-mark-start text:name CDATA #REQUIRED>
+
+<!ELEMENT text:reference-mark-end EMPTY>
+<!ATTLIST text:reference-mark-end text:name CDATA #REQUIRED>
+
+<!ELEMENT text:footnotes-configuration (text:footnote-continuation-notice-forward?,text:footnote-continuation-notice-backward?)>
+<!ATTLIST text:footnotes-configuration style:num-prefix %string; #IMPLIED>
+<!ATTLIST text:footnotes-configuration style:num-suffix %string; #IMPLIED>
+<!ATTLIST text:footnotes-configuration style:num-format %string; #IMPLIED>
+<!ATTLIST text:footnotes-configuration style:num-letter-sync %string; #IMPLIED>
+<!ATTLIST text:footnotes-configuration text:citation-body-style-name %styleName; #IMPLIED>
+<!ATTLIST text:footnotes-configuration text:citation-style-name %styleName; #IMPLIED>
+<!ATTLIST text:footnotes-configuration text:default-style-name %styleName; #IMPLIED>
+<!ATTLIST text:footnotes-configuration text:master-page-name %styleName; #IMPLIED>
+<!ATTLIST text:footnotes-configuration text:start-value %integer; #IMPLIED>
+<!ATTLIST text:footnotes-configuration text:footnotes-position (document|page) "page">
+<!ATTLIST text:footnotes-configuration text:start-numbering-at (document|chapter|page) "document">
+
+<!ELEMENT text:footnote-continuation-notice-forward (#PCDATA)>
+<!ELEMENT text:footnote-continuation-notice-backward (#PCDATA)>
+
+<!ELEMENT text:endnotes-configuration EMPTY>
+<!ATTLIST text:endnotes-configuration style:num-prefix %string; #IMPLIED>
+<!ATTLIST text:endnotes-configuration style:num-suffix %string; #IMPLIED>
+<!ATTLIST text:endnotes-configuration style:num-format %string; #IMPLIED>
+<!ATTLIST text:endnotes-configuration style:num-letter-sync %string; #IMPLIED>
+<!ATTLIST text:endnotes-configuration text:start-value %integer; #IMPLIED>
+<!ATTLIST text:endnotes-configuration text:citation-style-name %styleName; #IMPLIED>
+<!ATTLIST text:endnotes-configuration text:citation-body-style-name %styleName; #IMPLIED>
+<!ATTLIST text:endnotes-configuration text:default-style-name %styleName; #IMPLIED>
+<!ATTLIST text:endnotes-configuration text:master-page-name %styleName; #IMPLIED>
+
+<!-- Validity constraint: text:footnote and text:endnote elements may not
+ contain other text:footnote or text:endnote elements, even though the DTD
+ allows this (via the %text; in the foot-/endnote-body).
+ Unfortunatetly, this constraint cannot be easily specified in the DTD.
+-->
+<!ELEMENT text:footnote (text:footnote-citation, text:footnote-body)>
+<!ATTLIST text:footnote text:id ID #IMPLIED>
+
+<!ELEMENT text:footnote-citation (#PCDATA)>
+<!ATTLIST text:footnote-citation text:label %string; #IMPLIED>
+
+<!ELEMENT text:footnote-body (text:h|text:p|
+ text:ordered-list|text:unordered-list)*>
+
+<!ELEMENT text:endnote (text:endnote-citation, text:endnote-body)>
+<!ATTLIST text:endnote text:id ID #IMPLIED>
+
+<!ELEMENT text:endnote-citation (#PCDATA)>
+<!ATTLIST text:endnote-citation text:label %string; #IMPLIED>
+
+<!ELEMENT text:endnote-body (text:h|text:p|
+ text:ordered-list|text:unordered-list)*>
+
+<!ENTITY % sectionText "(text:h|text:p|text:ordered-list|
+ text:unordered-list|table:table|chart:chart|draw:page|
+ draw:a|draw:text-box|draw:image|text:section|
+ text:table-of-content|text:illustration-index|
+ text:table-index|text:object-index|text:user-index|
+ text:alphabetical-index|text:bibliography|
+ text:index-title|%change-marks;)*">
+
+<!ELEMENT text:section ((text:section-source|office:dde-source)?,
+ %sectionText;) >
+
+<!ATTLIST text:section text:name CDATA #REQUIRED>
+<!ATTLIST text:section text:style-name %styleName; #IMPLIED>
+<!ATTLIST text:section text:display (true|none|condition) "true">
+<!ATTLIST text:section text:condition %formula; #IMPLIED>
+<!ATTLIST text:section text:protected %boolean; "false">
+<!ATTLIST text:section text:protection-key CDATA #IMPLIED>
+
+<!ELEMENT text:section-source EMPTY>
+<!ATTLIST text:section-source xlink:href %string; #IMPLIED>
+<!ATTLIST text:section-source xlink:type (simple) #FIXED "simple">
+<!ATTLIST text:section-source xlink:show (embed) #FIXED "embed">
+<!ATTLIST text:section-source text:section-name %string; #IMPLIED>
+<!ATTLIST text:section-source text:filter-name %string; #IMPLIED>
+
+<!ELEMENT text:table-of-content (text:table-of-content-source,
+ text:index-body) >
+<!ATTLIST text:table-of-content text:style-name %styleName; #IMPLIED>
+<!ATTLIST text:table-of-content text:protected %boolean; "false">
+
+<!ELEMENT text:table-of-content-source (text:index-title-template? ,
+ text:table-of-content-entry-template*,
+ text:index-source-styles* ) >
+<!ATTLIST text:table-of-content-source text:outline-level %integer; #IMPLIED>
+<!ATTLIST text:table-of-content-source text:use-index-marks %boolean; "true">
+<!ATTLIST text:table-of-content-source text:use-index-source-styles
+ %boolean; "false">
+<!ATTLIST text:table-of-content-source text:index-scope (document|chapter)
+ "document">
+<!ATTLIST text:table-of-content-source text:relative-tab-stop-position
+ %boolean; "true">
+<!ATTLIST text:table-of-content-source fo:language %string; #IMPLIED>
+<!ATTLIST text:table-of-content-source fo:country %string; #IMPLIED>
+<!ATTLIST text:table-of-content-source text:sort-algorithm %string; #IMPLIED>
+
+<!ELEMENT text:table-of-content-entry-template (text:index-entry-chapter-number |
+ text:index-entry-page-number |
+ text:index-entry-text |
+ text:index-entry-span |
+ text:index-entry-tab-stop |
+ text:index-entry-link-start |
+ text:index-entry-link-end)* >
+<!ATTLIST text:table-of-content-entry-template text:outline-level
+ %integer; #REQUIRED>
+<!ATTLIST text:table-of-content-entry-template text:style-name
+ %styleName; #REQUIRED>
+
+<!ELEMENT text:illustration-index
+ (text:illustration-index-source, text:index-body)>
+<!ATTLIST text:illustration-index text:style-name %styleName; #IMPLIED>
+<!ATTLIST text:illustration-index text:protected %boolean; "false">
+
+<!ELEMENT text:illustration-index-source (text:index-title-template?,
+ text:illustration-index-entry-template?) >
+<!ATTLIST text:illustration-index-source text:index-scope
+ (document|chapter) "document">
+<!ATTLIST text:illustration-index-source text:relative-tab-stop-position
+ %boolean; "true">
+<!ATTLIST text:illustration-index-source text:use-caption %boolean; "true">
+<!ATTLIST text:illustration-index-source text:caption-sequence-name
+ %string; #IMPLIED>
+<!ATTLIST text:illustration-index-source text:caption-sequence-format
+ (text|category-and-value|caption) "text">
+<!ATTLIST text:illustration-index-source fo:language %string; #IMPLIED>
+<!ATTLIST text:illustration-index-source fo:country %string; #IMPLIED>
+<!ATTLIST text:illustration-index-source text:sort-algorithm %string; #IMPLIED>
+
+<!ELEMENT text:illustration-index-entry-template
+ ( text:index-entry-page-number |
+ text:index-entry-text |
+ text:index-entry-span |
+ text:index-entry-tab-stop )* >
+<!ATTLIST text:illustration-index-entry-template text:style-name
+ %styleName; #REQUIRED>
+
+<!ELEMENT text:table-index (text:table-index-source, text:index-body)>
+<!ATTLIST text:table-index text:style-name %styleName; #IMPLIED>
+<!ATTLIST text:table-index text:protected %boolean; "false">
+
+<!ELEMENT text:table-index-source (text:index-title-template?,
+ text:table-index-entry-template?) >
+<!ATTLIST text:table-index-source text:index-scope
+ (document|chapter) "document">
+<!ATTLIST text:table-index-source text:relative-tab-stop-position
+ %boolean; "true">
+<!ATTLIST text:table-index-source text:use-caption %boolean; "true">
+<!ATTLIST text:table-index-source text:caption-sequence-name
+ %string; #IMPLIED>
+<!ATTLIST text:table-index-source text:caption-sequence-format
+ (text|category-and-value|caption) "text">
+<!ATTLIST text:table-index-source fo:language %string; #IMPLIED>
+<!ATTLIST text:table-index-source fo:country %string; #IMPLIED>
+<!ATTLIST text:table-index-source text:sort-algorithm %string; #IMPLIED>
+
+<!ELEMENT text:table-index-entry-template ( text:index-entry-page-number |
+ text:index-entry-text |
+ text:index-entry-span |
+ text:index-entry-tab-stop )* >
+<!ATTLIST text:table-index-entry-template text:style-name
+ %styleName; #REQUIRED>
+
+<!ELEMENT text:object-index ( text:object-index-source, text:index-body ) >
+<!ATTLIST text:object-index text:style-name %styleName; #IMPLIED>
+<!ATTLIST text:object-index text:protected %boolean; "false">
+
+<!ELEMENT text:object-index-source ( text:index-title-template?,
+ text:object-index-entry-template? ) >
+<!ATTLIST text:object-index-source text:index-scope
+ (document|chapter) "document">
+<!ATTLIST text:object-index-source text:relative-tab-stop-position
+ %boolean; "true">
+<!ATTLIST text:object-index-source text:use-spreadsheet-objects
+ %boolean; "false">
+<!ATTLIST text:object-index-source text:use-draw-objects %boolean; "false">
+<!ATTLIST text:object-index-source text:use-chart-objects %boolean; "false">
+<!ATTLIST text:object-index-source text:use-other-objects %boolean; "false">
+<!ATTLIST text:object-index-source text:use-math-objects %boolean; "false">
+<!ATTLIST text:object-index-source fo:language %string; #IMPLIED>
+<!ATTLIST text:object-index-source fo:country %string; #IMPLIED>
+<!ATTLIST text:object-index-source text:sort-algorithm %string; #IMPLIED>
+
+<!ELEMENT text:object-index-entry-template ( text:index-entry-page-number |
+ text:index-entry-text |
+ text:index-entry-span |
+ text:index-entry-tab-stop )* >
+<!ATTLIST text:object-index-entry-template text:style-name
+ %styleName; #REQUIRED >
+
+<!ELEMENT text:user-index (text:user-index-source, text:index-body) >
+<!ATTLIST text:user-index text:style-name %styleName; #IMPLIED>
+<!ATTLIST text:user-index text:protected %boolean; "false">
+
+<!ELEMENT text:user-index-source ( text:index-title-template?,
+ text:user-index-entry-template*,
+ text:index-source-styles* ) >
+<!ATTLIST text:user-index-source text:index-scope
+ (document|chapter) "document">
+<!ATTLIST text:user-index-source text:relative-tab-stop-position
+ %boolean; "true">
+<!ATTLIST text:user-index-source text:use-index-marks %boolean; "false">
+<!ATTLIST text:user-index-source text:use-graphics %boolean; "false">
+<!ATTLIST text:user-index-source text:use-tables %boolean; "false">
+<!ATTLIST text:user-index-source text:use-floating-frames %boolean; "false">
+<!ATTLIST text:user-index-source text:use-objects %boolean; "false">
+<!ATTLIST text:user-index-source text:use-index-source-styles
+ %boolean; "false">
+<!ATTLIST text:user-index-source text:copy-outline-level %boolean; "false">
+<!ATTLIST text:user-index-source fo:language %string; #IMPLIED>
+<!ATTLIST text:user-index-source fo:country %string; #IMPLIED>
+<!ATTLIST text:user-index-source text:sort-algorithm %string; #IMPLIED>
+
+<!ELEMENT text:user-index-entry-template ( text:index-entry-chapter |
+ text:index-entry-page-number |
+ text:index-entry-text |
+ text:index-entry-span |
+ text:index-entry-tab-stop )* >
+<!ATTLIST text:user-index-entry-template text:outline-level %integer; #REQUIRED>
+<!ATTLIST text:user-index-entry-template text:style-name %styleName; #REQUIRED>
+
+<!ELEMENT text:alphabetical-index (text:alphabetical-index-source,
+ text:index-body)>
+<!ATTLIST text:alphabetical-index text:style-name %styleName; #IMPLIED>
+<!ATTLIST text:alphabetical-index text:protected %boolean; "false">
+
+<!ELEMENT text:alphabetical-index-source ( text:index-title-template?,
+ text:alphabetical-index-entry-template* ) >
+<!ATTLIST text:alphabetical-index-source text:index-scope
+ (document|chapter) "document">
+<!ATTLIST text:alphabetical-index-source text:relative-tab-stop-position
+ %boolean; "true">
+<!ATTLIST text:alphabetical-index-source text:ignore-case %boolean; "false">
+<!ATTLIST text:alphabetical-index-source text:main-entry-style-name
+ %styleName; #IMPLIED>
+<!ATTLIST text:alphabetical-index-source text:alphabetical-separators
+ %boolean; "false">
+<!ATTLIST text:alphabetical-index-source text:combine-entries
+ %boolean; "true">
+<!ATTLIST text:alphabetical-index-source text:combine-entries-with-dash
+ %boolean; "false">
+<!ATTLIST text:alphabetical-index-source text:combine-entries-with-pp
+ %boolean; "true">
+<!ATTLIST text:alphabetical-index-source text:use-keys-as-entries
+ %boolean; "false">
+<!ATTLIST text:alphabetical-index-source text:capitalize-entries
+ %boolean; "false">
+<!ATTLIST text:alphabetical-index-source text:comma-separated
+ %boolean; "false">
+<!ATTLIST text:alphabetical-index-source fo:language %string; #IMPLIED>
+<!ATTLIST text:alphabetical-index-source fo:country %string; #IMPLIED>
+<!ATTLIST text:alphabetical-index-source text:sort-algorithm %string; #IMPLIED>
+
+<!ELEMENT text:alphabetical-index-entry-template ( text:index-entry-chapter |
+ text:index-entry-page-number |
+ text:index-entry-text |
+ text:index-entry-span |
+ text:index-entry-tab-stop )* >
+<!ATTLIST text:alphabetical-index-entry-template text:outline-level
+ (1|2|3|separator) #REQUIRED>
+<!ATTLIST text:alphabetical-index-entry-template text:style-name
+ %styleName; #REQUIRED>
+
+<!ELEMENT text:alphabetical-index-auto-mark-file EMPTY>
+<!ATTLIST text:alphabetical-index-auto-mark-file xlink:href CDATA #IMPLIED>
+<!ATTLIST text:alphabetical-index-auto-mark-file xlink:type (simple) #FIXED "simple">
+
+<!ELEMENT text:bibliography (text:bibliography-source, text:index-body) >
+<!ATTLIST text:bibliography text:style-name %styleName; #IMPLIED>
+<!ATTLIST text:bibliography text:protected %boolean; "false">
+
+<!ELEMENT text:bibliography-source ( text:index-title-template?,
+ text:bibliography-entry-template* ) >
+
+<!ELEMENT text:bibliography-entry-template ( text:index-entry-span |
+ text:index-entry-tab-stop |
+ text:index-entry-bibliography )* >
+<!ATTLIST text:bibliography-entry-template text:bibliography-type
+ ( article | book | booklet | conference | custom1 | custom2 |
+ custom3 | custom4 | custom5 | email | inbook | incollection |
+ inproceedings | journal | manual | mastersthesis | misc |
+ phdthesis | proceedings | techreport | unpublished | www )
+ #REQUIRED >
+<!ATTLIST text:bibliography-entry-template text:style-name
+ %styleName; #REQUIRED>
+
+<!ELEMENT text:index-body %sectionText; >
+
+<!--
+Validity constraint: text:index-title elements may appear only in
+indices, and there may be only one text:index-title element.
+-->
+<!ELEMENT text:index-title %sectionText; >
+<!ATTLIST text:index-title text:style-name %styleName; #IMPLIED>
+<!ATTLIST text:index-title text:name %string; #IMPLIED>
+
+<!ELEMENT text:index-title-template (#PCDATA)>
+<!ATTLIST text:index-title-template text:style-name %styleName; #IMPLIED>
+
+<!ELEMENT text:index-entry-chapter-number EMPTY>
+<!ATTLIST text:index-entry-chapter-number text:style-name %styleName; #IMPLIED>
+
+<!ELEMENT text:index-entry-chapter EMPTY>
+<!ATTLIST text:index-entry-chapter text:style-name %styleName; #IMPLIED>
+<!ATTLIST text:index-entry-chapter text:display (name|number|number-and-name)
+ "number-and-name" >
+
+<!ELEMENT text:index-entry-text EMPTY>
+<!ATTLIST text:index-entry-text text:style-name %styleName; #IMPLIED>
+
+<!ELEMENT text:index-entry-page-number EMPTY>
+<!ATTLIST text:index-entry-page-number text:style-name %styleName; #IMPLIED>
+
+<!ELEMENT text:index-entry-span (#PCDATA)>
+<!ATTLIST text:index-entry-span text:style-name %styleName; #IMPLIED>
+
+<!ELEMENT text:index-entry-bibliography EMPTY>
+<!ATTLIST text:index-entry-bibliography text:style-name %styleName; #IMPLIED>
+<!ATTLIST text:index-entry-bibliography text:bibliography-data-field
+ ( address | annote | author | bibiliographic_type |
+ booktitle | chapter | custom1 | custom2 |
+ custom3 | custom4 | custom5 | edition | editor |
+ howpublished | identifier | institution | isbn |
+ journal | month | note | number | organizations |
+ pages | publisher | report_type | school |
+ series | title | url | volume | year ) #REQUIRED>
+
+
+<!ELEMENT text:index-entry-tab-stop EMPTY>
+<!ATTLIST text:index-entry-tab-stop text:style-name %styleName; #IMPLIED>
+<!ATTLIST text:index-entry-tab-stop style:leader-char %character; " ">
+<!ATTLIST text:index-entry-tab-stop style:type (left|right) "left">
+<!ATTLIST text:index-entry-tab-stop style:position %length; #IMPLIED>
+
+<!ELEMENT text:index-entry-link-start EMPTY>
+<!ATTLIST text:index-entry-link-start text:style-name %styleName; #IMPLIED>
+
+<!ELEMENT text:index-entry-link-end EMPTY>
+<!ATTLIST text:index-entry-link-end text:style-name %styleName; #IMPLIED>
+
+<!ELEMENT text:index-source-styles (text:index-source-style)*>
+<!ATTLIST text:index-source-styles text:outline-level %integer; #REQUIRED>
+
+<!ELEMENT text:index-source-style EMPTY>
+<!ATTLIST text:index-source-style text:style-name %styleName; #REQUIRED>
+
+<!ELEMENT text:toc-mark-start EMPTY>
+<!ATTLIST text:toc-mark-start text:id %string; #REQUIRED>
+<!ATTLIST text:toc-mark-start text:outline-level %integer; #IMPLIED>
+
+<!ELEMENT text:toc-mark-end EMPTY>
+<!ATTLIST text:toc-mark-end text:id %string; #REQUIRED>
+
+<!ELEMENT text:toc-mark EMPTY>
+<!ATTLIST text:toc-mark text:string-value %string; #REQUIRED>
+<!ATTLIST text:toc-mark text:outline-level %integer; #IMPLIED>
+
+<!ELEMENT text:user-index-mark-start EMPTY>
+<!ATTLIST text:user-index-mark-start text:id %string; #REQUIRED>
+<!ATTLIST text:user-index-mark-start text:outline-level %integer; #IMPLIED>
+<!ATTLIST text:user-index-mark-start text:index-name %string; #IMPLIED>
+
+<!ELEMENT text:user-index-mark-end EMPTY>
+<!ATTLIST text:user-index-mark-end text:id %string; #REQUIRED>
+
+<!ELEMENT text:user-index-mark EMPTY>
+<!ATTLIST text:user-index-mark text:string-value %string; #REQUIRED>
+<!ATTLIST text:user-index-mark text:outline-level %integer; #IMPLIED>
+<!ATTLIST text:user-index-mark text:index-name %string; #IMPLIED>
+
+<!ELEMENT text:alphabetical-index-mark-start EMPTY>
+<!ATTLIST text:alphabetical-index-mark-start text:id %string; #REQUIRED>
+<!ATTLIST text:alphabetical-index-mark-start text:key1 %string; #IMPLIED>
+<!ATTLIST text:alphabetical-index-mark-start text:key2 %string; #IMPLIED>
+<!ATTLIST text:alphabetical-index-mark-start text:main-etry %boolean; "false">
+
+<!ELEMENT text:alphabetical-index-mark-end EMPTY>
+<!ATTLIST text:alphabetical-index-mark-end text:id %string; #REQUIRED>
+
+<!ELEMENT text:alphabetical-index-mark EMPTY>
+<!ATTLIST text:alphabetical-index-mark text:string-value %string; #REQUIRED>
+<!ATTLIST text:alphabetical-index-mark text:key1 %string; #IMPLIED>
+<!ATTLIST text:alphabetical-index-mark text:key2 %string; #IMPLIED>
+<!ATTLIST text:alphabetical-index-mark text:main-etry %boolean; "false">
+
+<!ELEMENT text:bibliography-configuration (text:sort-key)*>
+<!ATTLIST text:bibliography-configuration text:prefix %string; #IMPLIED>
+<!ATTLIST text:bibliography-configuration text:suffix %string; #IMPLIED>
+<!ATTLIST text:bibliography-configuration text:sort-by-position %boolean; "true">
+<!ATTLIST text:bibliography-configuration text:numbered-entries %boolean; "false">
+<!ATTLIST text:bibliography-configuration fo:language %string; #IMPLIED>
+<!ATTLIST text:bibliography-configuration fo:country %string; #IMPLIED>
+<!ATTLIST text:bibliography-configuration text:sort-algorithm %string; #IMPLIED>
+
+<!ELEMENT text:sort-key EMPTY>
+<!ATTLIST text:sort-key text:key ( address | annote | author |
+ bibiliographic_type | booktitle | chapter | custom1 | custom2 |
+ custom3 | custom4 | custom5 | edition | editor | howpublished |
+ identifier | institution | isbn | journal | month | note | number |
+ organizations | pages | publisher | report_type | school | series |
+ title | url | volume | year ) #REQUIRED>
+<!ATTLIST text:sort-key text:sort-ascending %boolean; "true">
+
+<!ELEMENT text:linenumbering-configuration (text:linenumbering-separator?)>
+<!ATTLIST text:linenumbering-configuration text:style-name %styleName; #IMPLIED>
+<!ATTLIST text:linenumbering-configuration text:number-lines %boolean; "true">
+<!ATTLIST text:linenumbering-configuration text:count-empty-lines %boolean; "true">
+<!ATTLIST text:linenumbering-configuration text:count-in-floating-frames %boolean; "false">
+<!ATTLIST text:linenumbering-configuration text:restart-numbering %boolean; "false">
+<!ATTLIST text:linenumbering-configuration text:offset %nonNegativeLength; #IMPLIED>
+<!ATTLIST text:linenumbering-configuration style:num-format (1|a|A|i|I) "1">
+<!ATTLIST text:linenumbering-configuration style:num-letter-sync %boolean; "false">
+<!ATTLIST text:linenumbering-configuration text:number-position (left|rigth|inner|outer) "left">
+<!ATTLIST text:linenumbering-configuration text:increment %nonNegativeInteger; #IMPLIED>
+
+<!ELEMENT text:linenumbering-separator (#PCDATA)>
+<!ATTLIST text:linenumbering-separator text:increment %nonNegativeInteger; #IMPLIED>
+
+<!ELEMENT text:script (#PCDATA)>
+<!ATTLIST text:script script:language CDATA #REQUIRED>
+<!ATTLIST text:script xlink:href CDATA #IMPLIED>
+<!ATTLIST text:script xlink:type (simple) #FIXED "simple">
+
+<!ELEMENT text:measure (#PCDATA)>
+<!ATTLIST text:measure text:kind (value|unit|gap) #REQUIRED>
+
+<!ELEMENT text:ruby (text:ruby-base, text:ruby-text)>
+<!ATTLIST text:ruby text:style-name %styleName; #IMPLIED>
+
+<!ELEMENT text:ruby-base %inline-text;>
+
+<!ELEMENT text:ruby-text (#PCDATA)>
+<!ATTLIST text:ruby-text text:style-name %styleName; #IMPLIED>
+
+<!-- elements for change tracking -->
+
+<!ELEMENT text:change EMPTY>
+<!ATTLIST text:change text:change-id CDATA #REQUIRED>
+
+<!ELEMENT text:change-start EMPTY>
+<!ATTLIST text:change-start text:change-id CDATA #REQUIRED>
+
+<!ELEMENT text:change-end EMPTY>
+<!ATTLIST text:change-end text:change-id CDATA #REQUIRED>
+
+<!ELEMENT text:tracked-changes (text:changed-region)*>
+<!ATTLIST text:tracked-changes text:track-changes %boolean; "true">
+<!ATTLIST text:tracked-changes text:protection-key CDATA #IMPLIED>
+
+<!ELEMENT text:changed-region (text:insertion |
+ (text:deletion, text:insertion?) |
+ text:format-change) >
+<!ATTLIST text:changed-region text:id ID #REQUIRED>
+
+<!ELEMENT text:insertion (office:change-info, %sectionText;)>
+<!ELEMENT text:deletion (office:change-info, %sectionText;)>
+<!ELEMENT text:format-change (office:change-info)>
+
diff --git a/xmerge/source/palmtests/qa/comparator/pdbcomparison.java b/xmerge/source/palmtests/qa/comparator/pdbcomparison.java
new file mode 100644
index 000000000000..785abbad0e75
--- /dev/null
+++ b/xmerge/source/palmtests/qa/comparator/pdbcomparison.java
@@ -0,0 +1,542 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+import java.io.*;
+import java.util.*;
+
+public class pdbcomparison
+{
+
+ private String LOGTAG ="LOGFILE";
+ private String OUTTAG ="OUTFILE";
+ private String LISTTAG ="LISTFILE";
+ private String PDBTAG1 ="PDBNAME1";
+ private String PDBTAG2 ="PDBNAME2";
+
+ private String OUTFILE="pdbcomparison.out";
+ private String LOGFILE="pdbcomparison.log";
+
+ private String pdbarr1[];
+ private String pdbarr2[];
+
+
+ /**
+ * Default Constructor
+ *
+ * @param
+ * @return
+ *
+ */
+ public void pdbcomparison()
+ {
+ }
+
+ /**
+ * Prints the command line arguments for this class
+ *
+ * @param
+ *
+ * @return void
+ *
+ */
+ public void usage()
+ {
+ String str = new String();
+ str += "********************************************************\n";
+ str += " java pdbcomparison.java <propFile> \n";
+ str += " where propFile is name of Property File...\n";
+ str += "********************************************************\n";
+
+ System.out.println(str);
+
+ }
+
+ /**
+ * This method, read the Property file and validates the
+ * entries in that file, and accordingly sets the log file
+ * output file and updates the array pdbarr1 and pdbarr2 with
+ * list of pdb's to be compared.
+ *
+ * @param propFile Property filename which list the log/outputfile/list/pdb
+ * names
+ * @return
+ *
+ */
+ public void parsePropertyFile(String propFile)
+ {
+ Properties defaultProps = new Properties();
+
+ try {
+ FileInputStream in = new FileInputStream(propFile);
+ defaultProps.load(in);
+ in.close();
+ } catch (IOException e) {
+ System.out.println("Could not open Property File " + propFile);
+ return;
+ }
+
+
+ String logFile = defaultProps.getProperty(this.LOGTAG);
+ String outFile = defaultProps.getProperty(this.OUTTAG);
+ String listFile = defaultProps.getProperty(this.LISTTAG);
+ String pdbname1 = defaultProps.getProperty(this.PDBTAG1);
+ String pdbname2 = defaultProps.getProperty(this.PDBTAG2);
+
+ // validate all command line arguments
+ if ((listFile == null) && ((pdbname1 == null) || (pdbname2 == null)))
+ {
+ System.out.println("Missing listFile or missing pdb filenames in Property file " + propFile);
+ return;
+ }
+
+ if (logFile == null || logFile.length() == 0)
+ logFile = this.LOGFILE;
+
+ if (outFile == null || outFile.length() == 0)
+ outFile = this.LOGFILE;
+
+
+ // validate log and output files
+ if (! validateAndCreateFile(logFile)) return;
+ if (! validateAndCreateFile(outFile)) return;
+ LOGFILE = logFile;
+ OUTFILE = outFile;
+
+ System.out.println("Output is written to log file... " + LOGFILE);
+ if (listFile != null)
+ {
+ if (! checkFile(listFile)) return;
+ populatePDBArray(listFile);
+ } else {
+ if (! checkFile(pdbname1)) return;
+ if (! checkFile(pdbname2)) return;
+ populatePDBArray(pdbname1, pdbname2);
+ }
+ }
+
+ /**
+ * This method validates if the file passed exists.
+ * If it does , then it is moved to <filename>.bak and then creates a newFile.
+ * Also validates permissions to create.
+ *
+ * @param filename name of file to be created
+ * @return true, if file could be created
+ * false, if could not.
+ *
+ */
+ private boolean validateAndCreateFile (String filename)
+ {
+ if (filename == null) return false;
+
+ File f = null;
+ try {
+ f = new File(filename);
+ } catch (NullPointerException e) {
+ System.out.println("Could not create a File object for file " + filename);
+ return false;
+ }
+
+ if (f.exists())
+ {
+ String newFile = filename + ".bak";
+ File newF=null;
+ try {
+ newF = new File(newFile);
+ } catch (Exception ex) {
+ System.out.println("Could not get File Object instance for " + newFile);
+ return false;
+ }
+
+ if (newF.exists())
+ {
+ try {
+ newF.delete();
+ } catch ( SecurityException se) {
+ System.out.println("Could not get delete " + newFile);
+ return false;
+ }
+ }
+
+ try {
+ if (! f.renameTo(newF))
+ {
+ System.out.println("Could not rename " + filename + " to " + newFile );
+ return false;
+ }
+ } catch (SecurityException s) {
+ System.out.println("SecurityException: " + s.toString());
+ return false;
+ } catch (NullPointerException n) {
+ System.out.println("NullPointerException: " + n.toString());
+ return false;
+ }
+ } else {
+ try {
+ if (! f.createNewFile())
+ {
+ System.out.println("Could not create " + filename + " Check permissions..");
+ return false;
+ }
+ } catch (IOException e) {
+ System.out.println("IOException: " + e.toString());
+ return false;
+ } catch (SecurityException s) {
+ System.out.println("SecuriityException: " + s.toString() );
+ return false;
+ }
+
+ }
+
+ return true;
+
+ }
+
+ /**
+ * This method validates if the file exists and is readable
+ *
+ * @param filename name of file to be created
+ * @return true, if file exists and is readable
+ * false, if not.
+ *
+ */
+ private boolean checkFile(String filename)
+ {
+ if (filename == null) return false;
+
+ File f = null;
+ try {
+ f = new File(filename);
+ } catch (NullPointerException e) {
+ System.out.println("Could not create a File object for file " + filename);
+ return false;
+ }
+
+ if (! f.exists())
+ {
+ System.out.println("File " + filename + " does not exist... ");
+ return false;
+ }
+
+ if (! f.canRead())
+ {
+ System.out.println("Cannot read file " + filename);
+ return false;
+ }
+
+ return true;
+
+ }
+
+ /**
+ * This method populates the pdb arrays with the names of the pdbs to
+ * compare. Ths listFile lists a series of entries, wherein each
+ * line indicates the PDB names to be compared.
+ * <pdbname1>=<pdbname2>
+ *
+ * @param listFile name of the listfile
+ * @return
+ *
+ */
+ private void populatePDBArray(String listFile)
+ {
+ // open ListFile and populate the PDB list to be compared
+ if (listFile != null)
+ {
+ Properties listProps = new Properties();
+ try {
+ FileInputStream in = new FileInputStream(listFile);
+ listProps.load(in);
+ in.close();
+ } catch (IOException ex) {
+ System.out.println("Could not open List File " + listFile);
+ return;
+ }
+
+ pdbarr1 = new String[listProps.size()];
+ pdbarr2 = new String[listProps.size()];
+ Enumeration e = listProps.keys();
+ int j=0;
+ while (e.hasMoreElements())
+ {
+ pdbarr1[j] = (String)e.nextElement();
+ pdbarr2[j] = listProps.getProperty(pdbarr1[j]);
+ j++;
+ }
+
+ }
+ }
+
+ /**
+ * This method populates the pdb arrays with the names of the pdbs to
+ * compare.
+ *
+ * @param pdbname1 Name of 2nd PDB file to be compared
+ * @param pdbname2 Name of 2nd PDB file to be compared
+ * @return
+ *
+ */
+ private void populatePDBArray(String pdbname1, String pdbname2)
+ {
+ if (pdbname1 == null) return;
+ if (pdbname2 == null) return;
+
+ if ((pdbname1 != null) && (pdbname2 != null))
+ {
+ pdbarr1 = new String[1];
+ pdbarr2 = new String[1];
+
+ pdbarr1[0] = pdbname1;
+ pdbarr2[0] = pdbname2;
+ }
+ }
+
+ /**
+ * This method populates the pdb arrays with the names of the pdbs to
+ * compare.
+ *
+ * @param arrayno Array number which corresponds to the pdb array
+ * containing list of pdbs
+ * If 1 then send pdbarr1, if 2 send pdbarr2 else null
+ *
+ * @return PDB string array containing list of PDB's
+ *
+ */
+ private String[] getPDBArray(int arrayno)
+ {
+ if (arrayno == 1) return pdbarr1;
+ if (arrayno == 2) return pdbarr2;
+
+ return null;
+ }
+
+ /**
+ * This method comares 2 PDB's and returns true if comparison is equal.
+ * It uses the PDB Decoder class to decode to a PDB structure and then
+ * does record comparison
+ *
+ * @param pdbname1 Name of one PDB file to be compared
+ * @param pdbname2 Name of other PDB file to be compared
+ *
+ * @return returns true if both PDB's are equal else returns false
+ *
+ */
+ private boolean comparePDB(String pdbname1, String pdbname2)
+ {
+ PalmDB pdb1=null, pdb2=null;
+ PDBDecoder decoder = new PDBDecoder();
+ try {
+ pdb1 = decoder.parse(pdbname1);
+ } catch (Exception e) {
+ System.out.println("Could not parse PDB " + pdbname1);
+ return false;
+ }
+
+ try {
+ pdb2 = decoder.parse(pdbname2);
+ } catch (Exception e) {
+ System.out.println("Could not parse PDB " + pdbname2);
+ return false;
+ }
+
+ if (pdb1.equals(pdb2)) {
+ writeToLog("PDB " + pdbname1 + " and PDB " + pdbname2 + " are equal");
+
+ return true;
+ } else {
+ writeToLog("PDB " + pdbname1 + " and PDB " + pdbname2 + " are not equal");
+ return false;
+ }
+ }
+
+
+
+ /**
+ * Write message to LOGFILE
+ *
+ * @param msg Message to be written to log file
+ * @return
+ *
+ */
+ private void writeToLog(String msg)
+ {
+ if (msg == null) return;
+
+ // Get Output Stream from Log file
+ RandomAccessFile raf=null;
+ try {
+ raf = new RandomAccessFile(LOGFILE, "rw");
+ } catch (Exception e) {
+ System.out.println ("Could not open file " + LOGFILE);
+ return;
+ }
+
+ try {
+ long len = raf.length();
+ raf.seek(len);
+ raf.write(msg.getBytes());
+ raf.write("\n".getBytes());
+ } catch (IOException e) {
+ System.out.println("ERROR: Could not write to File " + LOGFILE);
+ return;
+ }
+ }
+
+ /**
+ * Write status of comparison to OUTFILE
+ *
+ * @param status Indicates whether comparsion of PDB's PASSED or FAILED
+ * @param pdbname1 file name of pdb which was compared.
+ * @param pdbname2 file name of pdb which was compared.
+ *
+ * @return
+ *
+ */
+ private void writeToOutputFile(String status, String pdbname1, String pdbname2)
+ {
+ if (status == null) return;
+ if (pdbname1 == null) return;
+ if (pdbname2 == null) return;
+
+ String msg = pdbname1 + "=" + pdbname2 + ":" + status;
+
+ // Get Output Stream from Log file
+ RandomAccessFile raf=null;
+ try {
+ raf = new RandomAccessFile(OUTFILE, "rw");
+ } catch (Exception e) {
+ System.out.println ("Could not open file " + OUTFILE);
+ return;
+ }
+
+ try {
+ long len = raf.length();
+ raf.seek(len);
+
+ raf.write(msg.getBytes());
+ raf.write("\n".getBytes());
+ } catch (IOException e) {
+ System.out.println("ERROR: Could not write to File " + OUTFILE);
+ return;
+ }
+
+ try {
+ raf.close();
+ } catch (Exception e) {
+ System.out.println("ERROR: Could not close File " + OUTFILE);
+ return;
+ }
+
+ }
+
+
+
+ /**
+ * Main starting block of execution
+ *
+ * @param command line args captured in an array of Strings
+ * @return
+ *
+ */
+ public static void main(String args[])
+ {
+
+ Date startTime = new Date();
+ pdbcomparison pdbcmp = new pdbcomparison();
+ int nargs = args.length;
+ int status=0;
+
+ if (nargs != 1)
+ {
+ System.out.println("Incorrect no. of arguments passed...");
+ pdbcmp.usage();
+ System.exit(-1);
+
+ }
+
+ String propFile = args[0];
+
+ File f=null;
+ try {
+ f = new File(propFile);
+ } catch (Exception e) {
+ System.out.println("Exception: Could not open file " + propFile);
+ System.exit(-1);
+ }
+
+ if (! f.canRead()) {
+ System.out.println("Exception: " + propFile + " is not a file ");
+ System.exit(-1);
+ }
+
+ if (! f.canRead()) {
+ System.out.println("Exception: Cannot open file for reading. Please check permissions ");
+ System.exit(-1);
+ }
+
+ // parse Property file
+ pdbcmp.parsePropertyFile(propFile);
+
+ String pdbarr1[] = pdbcmp.getPDBArray(1);
+ String pdbarr2[] = pdbcmp.getPDBArray(2);
+ if ( (pdbarr1 == null) ||
+ (pdbarr2 == null) ||
+ (pdbarr1.length == 0) ||
+ (pdbarr1.length == 0))
+ {
+ System.out.println("pdbArray is empty. No PDBS to compare... \n");
+ System.exit(-1);
+ }
+
+
+ pdbcmp.writeToLog("************** Start *****************");
+ pdbcmp.writeToLog("PDB Comparison: start time " + startTime);
+ for (int i=0; i<pdbarr1.length; i++)
+ {
+ Date pdb_startTime = new Date();
+ pdbcmp.writeToLog("\n");
+ pdbcmp.writeToLog("start time " + pdb_startTime);
+ boolean val = pdbcmp.comparePDB(pdbarr1[i], pdbarr2[i]);
+ Date pdb_endTime = new Date();
+ pdbcmp.writeToLog("end time " + pdb_endTime);
+
+ if (val) {
+ pdbcmp.writeToOutputFile("PASSED", pdbarr1[i], pdbarr2[i]);
+ status=0;
+ } else {
+ pdbcmp.writeToOutputFile("FAILED", pdbarr1[i], pdbarr2[i]);
+ status=-1;
+ }
+ }
+
+ Date endTime = new Date();
+ pdbcmp.writeToLog("PDB Comparison: end time " + endTime);
+ pdbcmp.writeToLog("************** End *****************n");
+ pdbcmp.writeToLog("\n");
+
+ System.exit(status);
+ }
+}
diff --git a/xmerge/source/palmtests/qa/docs/Doc_descriptions.sxc b/xmerge/source/palmtests/qa/docs/Doc_descriptions.sxc
new file mode 100644
index 000000000000..ba6817d889ac
--- /dev/null
+++ b/xmerge/source/palmtests/qa/docs/Doc_descriptions.sxc
Binary files differ
diff --git a/xmerge/source/palmtests/qa/docs/Spreadsheet_descriptions.csv b/xmerge/source/palmtests/qa/docs/Spreadsheet_descriptions.csv
new file mode 100644
index 000000000000..c798a553e78f
--- /dev/null
+++ b/xmerge/source/palmtests/qa/docs/Spreadsheet_descriptions.csv
@@ -0,0 +1,39 @@
+File|Test Name|Description
+c_addition.sxc||
+c_alignment.sxc||
+c_backwardrange.sxc||
+c_boolean.sxc||
+c_cellcurrencyalue.sxc||
+c_cellfloatvalue.sxc||
+c_cellpercentvalue.sxc||
+c_cellstringvalue.sxc||
+c_cellvalue.sxc||
+c_changetracking.sxc||
+c_character.sxc||
+c_chart.sxc||
+c_check.sxc||
+c_columnswidth.sxc||
+c_cyclic.sxc||
+c_dividebyzero.sxc||
+c_dividefloating.sxc||
+c_emptysheet.sxc||
+c_filter.sxc||
+c_forwardrange.sxc||
+c_hiddenrow.sxc||
+c_insertimage.sxc||
+c_invalidcellref.sxc||
+c_largerange.sxc||
+c_listrange.sxc||
+c_mathematical.sxc||
+c_null.sxc||
+c_protection.sxc||
+c_renamedsheets.sxc||
+c_rowheight.sxc||
+c_rowstyles.sxc||
+c_sheetreference.sxc||
+c_simpleformula.sxc||
+c_smallrange.sxc||
+c_styles.sxc||
+c_sumbackward.sxc||
+c_sumforward.sxc||
+c_threeemptysheet.sxc||
diff --git a/xmerge/source/palmtests/qa/docs/Spreadsheet_descriptions.sxc b/xmerge/source/palmtests/qa/docs/Spreadsheet_descriptions.sxc
new file mode 100644
index 000000000000..7e9d37d3fa50
--- /dev/null
+++ b/xmerge/source/palmtests/qa/docs/Spreadsheet_descriptions.sxc
Binary files differ
diff --git a/xmerge/source/palmtests/qa/lib/converterlib.pm b/xmerge/source/palmtests/qa/lib/converterlib.pm
new file mode 100644
index 000000000000..d4e4eb6ea649
--- /dev/null
+++ b/xmerge/source/palmtests/qa/lib/converterlib.pm
@@ -0,0 +1,1174 @@
+#!/usr/bin/perl
+#########################################################################
+
+ #*************************************************************************
+ #
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# Copyright 2000, 2010 Oracle and/or its affiliates.
+#
+# OpenOffice.org - a multi-platform office productivity suite
+#
+# This file is part of OpenOffice.org.
+#
+# OpenOffice.org is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License version 3
+# only, as published by the Free Software Foundation.
+#
+# OpenOffice.org is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License version 3 for more details
+# (a copy is included in the LICENSE file that accompanied this code).
+#
+# You should have received a copy of the GNU Lesser General Public License
+# version 3 along with OpenOffice.org. If not, see
+# <http://www.openoffice.org/license.html>
+# for a copy of the LGPLv3 License.
+#
+ #*************************************************************************
+
+####################################################################
+# File Name: converterlib.pm
+# Version : 1.0
+# Project : XMerge
+# Author : Brian Cameron
+# Date : 5th Sept. 2001
+#
+# This script enters text at position x,y on screen.
+#
+# Parameter
+# x-coordinate
+# y-coordinate
+# Text to enter
+#
+##########################################################################
+
+use EmRPC; # EmRPC::OpenConnection, CloseConnection
+use EmFunctions;
+use EmUtils;
+
+# Set global_debug flag
+#
+$global_debug = $ENV{'ZENDEBUG'};
+#$em_script_home = "/export/home/test/qadir/bin";
+$em_script_home = $ENV{'EM_SCRIPT_HOME'};
+#$qa_script_home = "/export/home/test/qadir/qa-new/bin";
+ $qa_script_home = $ENV{'QA_SCRIPT_HOME'};
+#
+# CONVERT FUNCTIONS
+#
+
+# convert_to_pdb
+# directory - directory containing the xml-orig and pdb-orig
+# subdirectories.
+# file - file to convert
+# extension - extension of file to convert (sxw or sxc)
+# convert_to - what PDB format to convert into.
+#
+# Returns 0 if success, -1 otherwise.
+#
+# Converts file from XML to PDB
+#
+sub convert_to_pdb
+{
+ my $directory = $_[0];
+ my $file = $_[1];
+ my $extension = $_[2];
+ my $convert_to = $_[3];
+ my $pdb_directory = $_[4];
+ my $rc = 0;
+ my $xmlfile = "$directory/$file.$extension";
+ my $pdbdir = "$pdb_directory";
+
+ &enter_func("convert_to_pdb");
+
+ if (! -f "$xmlfile")
+ {
+ print "\nERROR, file $xmlfile does not exist\n";
+ $rc = -1;
+ }
+ if (! -d "$pdbdir")
+ {
+ print "\nERROR, directory $directory/pdb-orig does not exist\n";
+ $rc = -1;
+ }
+
+ if ($rc != -1)
+ {
+ if ("$convert_to" eq "application/x-minicalc")
+ {
+ # Move all files over.
+ #
+ my $i = 1;
+
+ while (-f "$pdbdir/$file-Sheet$i.pdb")
+ {
+ my $pdbfile = "$pdbdir/$file-Sheet$i.pdb";
+
+ print "\n";
+
+ if (-f "$pdbfile.old")
+ {
+ print "Removing $pdbfile.old\n";
+ `/bin/rm -f $pdbfile.old`;
+ }
+
+ print "Moving $pdbfile file to $pdbfile.old\n";
+ `mv "$pdbfile" "$pdbfile.old"`;
+
+ $i++;
+ }
+ }
+ else
+ {
+ if (-f "$pdbdir/$file.pdb")
+ {
+ print "\n";
+
+ if (-f "$pdbdir/$file.pdb.old")
+ {
+ print "Removing $pdbdir/$file.pdb.old\n";
+ `/bin/rm -f $pdbdir/$file.pdb.old`;
+ }
+
+ print "Moving $pdbdir/$file.pdb file to $pdbdir/$file.pdb.old\n";
+ `mv "$pdbdir/$file.pdb" "$pdbdir/$file.pdb.old"`
+ }
+ }
+
+ &start_rd($extension, $convert_to, $xmlfile, "");
+
+ if ("$convert_to" eq "application/x-minicalc")
+ {
+ # Must handle minicalc separately since it can
+ # convert to multiple files with this file name
+ # convention.
+ #
+ print "Moving $file-Sheet*.pdb files to $pdbdir\n";
+ `mv $file-Sheet*.pdb $pdbdir`;
+ `chmod 666 $pdbdir/$file-*.pdb`;
+ }
+ else
+ {
+ print "Moving $file.pdb file to $pdbdir\n";
+ `mv $file.pdb $pdbdir`;
+ `chmod 666 $pdbdir/$file.pdb`;
+ }
+ }
+
+ &leave_func("convert_to_pdb");
+
+ return $rc;
+}
+
+# convert_to_xml
+# xmldir - directory to contain the xml output.
+# xmlorigdir - directory to contain the xml input (used for merge)
+# pdbfile - file to convert
+# convert_from - what PDB format to convert from.
+# extension - extension of file to convert (sxw or sxc)
+# output - output filename to create
+# merge_opt - 1 if convert and merge, 0 if convert only
+#
+# Returns 0 if success, -1 otherwise.
+#
+# Converts file from PDB to XML
+#
+sub convert_to_xml
+{
+ my $xmldir = $_[0];
+ my $xmlorigdir = $_[1];
+ my $pdbfile = $_[2];
+ my $convert_from = $_[3];
+ my $extension = $_[4];
+ my $output = $_[5];
+ my $merge_opt = $_[6];
+ my $rc = 0;
+
+ &enter_func("convert_to_xml");
+
+ my @args = split(/ /,$pdbfile);
+
+ for ($i=0;$i <= $#args; $i++)
+ {
+ if (! -f "@args[$i]")
+ {
+ print "\nERROR, file $pdbfile does not exist\n";
+ $rc = -1;
+ }
+ }
+
+ if (! -f "$xmlorigdir/$output.$extension")
+ {
+ print "\nERROR, file $xmlorigdir/$output.$extension does not exist\n";
+ $rc = -1;
+ }
+ if (! -d "$xmldir")
+ {
+ print "\nERROR, directory $xmlorigdir does not exist\n";
+ $rc = -1;
+ }
+ if (! -d "$xmlorigdir")
+ {
+ print "\nERROR, directory $xmldir does not exist\n";
+ $rc = -1;
+ }
+
+ if ($rc != -1)
+ {
+ if ($merge_opt == 1)
+ {
+ print "Copying <$xmlorigdir/$output.$extension> to <$xmldir>\n";
+ `cp $xmlorigdir/$output.$extension $xmldir/`;
+
+ my $check_stamp = (stat("$xmldir/$output.$extension"))[9];
+
+ &start_rd($convert_from, $extension, $pdbfile,
+ "$xmldir/$output.$extension");
+
+
+ # No need to move the file to the $xmldir since the merge
+ # argument specifies the output file.
+
+ my $check_stamp_update = (stat("$xmldir/$output.$extension"))[9];
+ if ($check_stamp eq $check_stamp_update)
+ {
+ print "\nERROR, Problem while merging <$xmldir/$output.$extension>\n";
+ `mv $xmldir/$output.$extension $xmldir/$output.$extension.err`;
+ }
+ }
+ else
+ {
+ &start_rd($convert_from, $extension, $pdbfile, "");
+
+ print "Moving $output.$extension to $xmldir\n";
+ `mv $output.$extension $xmldir`;
+ `chmod 666 $xmldir/$output.$extension`;
+ }
+ }
+
+ &leave_func("convert_to_xml");
+
+ return $rc;
+}
+
+# start_rd
+# from - format to convert from
+# to - format to convert to
+# file - file to convert
+# merge - merge filename ("" indicates convert-only with no merge)
+#
+# converts file from/to the specified formats.
+#
+sub start_rd
+{
+ my $from = $_[0];
+ my $to = $_[1];
+ my $file = $_[2];
+ my $merge = $_[3];
+
+ print "\nConverting from $from to $to.\n";
+ if ($global_debug)
+ {
+ &print_debug ("rd command is:\n");
+ }
+
+ if ($merge eq "")
+ {
+ &print_debug (" $em_script_home/rd -from $from -to $to $file\n");
+ print "\nConverting from $from to $to with no merge.\n";
+ `$em_script_home/rd -from $from -to $to $file`;
+ }
+ else
+ {
+ &print_debug (" $em_script_home/rd -from $from -to $to -merge $merge $file\n");
+ print "\nConverting from $from to $to with merge.\n";
+ `$em_script_home/rd -from $from -to $to -merge $merge $file`;
+ }
+
+ print "Done converting.\n\n";
+}
+
+#
+# POSE INTERACTION FUNCTIONS
+#
+
+# open_connection
+# display_debug - debug will be displayed if not 0
+#
+# Opens the connection to pose.
+#
+sub open_connection
+{
+ my $display_debug = $_[0];
+ my $rc;
+
+ EmRPC::OpenConnection(6415, "localhost");
+
+ if ($display_debug && $global_debug)
+ {
+ print "\nPose Connection Opened\n";
+ }
+}
+
+# close_connection
+# display_debug - debug will be displayed if not 0
+#
+# Closes the connection to pose.
+#
+sub close_connection
+{
+ my $display_debug = $_[0];
+
+ EmRPC::CloseConnection();
+
+ if ($display_debug && $global_debug)
+ {
+ print "\nPose Connection Closed\n";
+ }
+}
+
+# start_pose
+# pose_exe - name of pose executable.
+# apps_load - The PRC files to load into pose, can be a comma
+# separated list.
+# run_prog - Program to run at startup.
+# timeout - Timeout value to use when starting pose.
+#
+# Starts the Palm OS Emulator, loads PRC files, and starts
+# a program.
+#
+sub start_pose
+{
+ my $pose_exe = $_[0];
+ my $sessionfile = $ENV{'EM_SESSION_FILE'};
+ my $romfile = $ENV{'EM_ROM_FILE'};
+ my $apps_load = $_[1];
+ my $run_prog = $_[2];
+ my $timeout = $_[3];
+ my $stay_in_loop = 1;
+ my $address;
+ my $title;
+ my $form;
+ my $label_id;
+ my $num_objects;
+ my $i;
+ my $ii;
+ my $rc = 1;
+
+ my $pose_cmd = "$pose_exe ";
+ $pose_cmd .= " -psf $sessionfile ";
+ $pose_cmd .= "-load_apps $apps_load ";
+ $pose_cmd .= "-run_app $run_prog";
+
+# It is more effective to use the -psf argument to
+# set these values.
+#
+# $pose_cmd .= -rom $romfile ";
+# $pose_cmd .= "-ram_size 8192 ";
+# $pose_cmd .= "-device PalmVx ";
+
+ &enter_func("start_pose");
+
+ if ($global_debug)
+ {
+ &print_debug("\n");
+ &print_debug("pose command is:\n");
+ &print_debug(" $pose_cmd\n");
+ }
+
+ print "\nLaunching pose...\n";
+ system ("$pose_cmd &");
+
+ # Give time for pose to get started...
+ #
+ for ($i=0; $i < $timeout; $i++)
+ {
+ $tmp = $i + 1;
+ print "$tmp\n";
+
+ # Do not use pose_sleep here
+ #
+ sleep(1);
+ }
+
+ # Verify pose started successfully, and fail otherwise...
+ #
+ $rc = &verify_pose(5);
+ if ($rc != 0)
+ {
+ $stay_in_loop = 0;
+ }
+ else
+ {
+ # Sleep before opening the connection again, after testing in
+ # the verify_pose function.
+ #
+ pose_sleep(2);
+ &open_connection(1);
+ print "\nChecking if the appropriate window is on screen...\n";
+ }
+
+ # Stop looping when the specified window has started.
+ #
+ for ($i=0; $i < $timeout && $stay_in_loop == 1; $i++)
+ {
+ $form = FrmGetActiveForm();
+ $num_objects = FrmGetNumberOfObjects($form);
+
+ for $ii (0..$num_objects - 1)
+ {
+ my ($object_type) = FrmGetObjectType($form, $ii);
+
+ if ("$run_prog" eq "Quickword")
+ {
+ if ($object_type == frmTitleObj)
+ {
+ ($address, $title) = FrmGetTitle($form,);
+
+ # Display count and title.
+ #
+ $tmp = $i + 1;
+ print "$tmp - title is $title\n";
+
+ if ("$title" eq "Quickword")
+ {
+ $stay_in_loop = 0;
+ $rc = 0;
+ last;
+ }
+ }
+ }
+ elsif ("$run_prog" eq "MiniCalc")
+ {
+ if ($object_type == frmLabelObj)
+ {
+ $label_id = FrmGetObjectId ($form, $ii);
+ ($address, $label) = FrmGetLabel($form, $label_id);
+
+ # Display count and label.
+ #
+ $tmp = $i + 1;
+ print "$tmp - label is $label\n";
+ if ("$label" =~ "Solutions In Hand")
+ {
+ $stay_in_loop = 0;
+ $rc = 0;
+ last;
+ }
+ }
+ }
+ }
+
+ # Do not use pose_sleep here
+ #
+ sleep(1);
+ }
+
+ # Do not use pose_sleep here
+ #
+ sleep(1);
+
+ &leave_func("start_pose");
+ return($rc);
+}
+
+# kill_pose
+#
+# Kills all pose processes
+#
+sub kill_pose
+{
+ if ($global_debug)
+ {
+ print "Stopping pose process...\n";
+ }
+
+ `pkill pose`;
+}
+
+# verify_pose
+# timeout - timeout to wait for pose
+#
+# Tries to do a connect/close to Pose to see if
+# it is working okay.
+#
+sub verify_pose
+{
+ my $timeout = $_[0];
+ my $rc = 0;
+
+ $rc = system("$em_script_home/verify_sane.pl $timeout");
+ return $rc;
+}
+
+# db_export
+# dbname - Name of database to export
+#
+# Exports a palmdb file to /tmp
+#
+sub db_export
+{
+ my $dbname = $_[0];
+
+ &enter_func("db_export");
+ print "\nExporting PDB file <$dbname> from pose\n";
+ &pose_tap_pen(22, 20, 2);
+ &pose_tap_pen (15, 85, 2);
+ &enter_string($dbname, 1);
+ &pose_tap_pen (15, 126, 1);
+ &enter_string("/tmp/", 1);
+ &pose_tap_button("OK", 4);
+ &tap_applications(3);
+ print "Export of PDB file <$dbname> completed.\n";
+ &leave_func("db_export");
+}
+
+#
+# QUICKWORD SPECIFIC
+#
+
+# start_quickword
+#
+# Assuming pose was launched with the -run_app flag to launch
+# QuickWord on startup, this starts up QuickWord with the first
+# file in the list and turns off write-protect.
+#
+sub start_quickword
+{
+ &enter_func("start_quickword");
+
+ # This will open the first file in the list.
+ # Assuming this will always be the case.
+ #
+ &pose_tap_pen(20, 18, 1);
+ &quickword_press_write_protect();
+
+ &leave_func("start_quickword");
+}
+
+# quickword_press_write_protect
+#
+# Useful function for pressing the write protect button
+# to allow changes to be made.
+#
+sub quickword_press_write_protect
+{
+ &enter_func("quickword_press_write_protect");
+
+ my ($form) = FrmGetActiveForm();
+ my ($num_objects) = FrmGetNumberOfObjects($form);
+
+ for $ii (0..$num_objects - 1)
+ {
+ my ($object_type) = FrmGetObjectType($form, $ii);
+
+ # The write protect button is the only frmGadgetObj
+ # on the QuickWord screen.
+ #
+ if ($object_type == frmGadgetObj)
+ {
+ my (%bounds) = FrmGetObjectBounds($form, $ii);
+
+ if ($global_debug)
+ {
+ &print_debug(" Found QuickWord WriteProtect button\n");
+ &print_debug(" left = $bounds{left}\n");
+ &print_debug(" right = $bounds{right}\n");
+ &print_debug(" top = $bounds{top}\n");
+ &print_debug(" bottom = $bounds{bottom}\n");
+ }
+
+ # For some reason, the tapping of the write-protect button
+ # doesn't work unless you tap somewhere else first.
+ #
+ &pose_sleep(1);
+ &pose_tap_pen($bounds{left} + 2, $bounds{top} + 2, 1);
+ last;
+ }
+ }
+
+ &leave_func("quickword_press_write_protect");
+}
+
+# quickword_find_replace
+# from_string - string to replace
+# to_string - string to replace with
+#
+# Uses QuickWord's find/replace utility to replace
+# one string with another.
+#
+sub quickword_find_replace
+{
+ my $from_string = $_[0];
+ my $to_string = $_[1];
+
+ &enter_func("quickword_find_replace");
+
+ # Move cursor to beginning...
+ #
+ &quickword_tap_at_top(1);
+
+ # Move to "Find" field:
+ # Triple-click to highlight all the text in the field,
+ # so it is removed when the string is entered...
+ #
+ &pose_tap_button("Find", 2);
+ &pose_tap_pen(50, 100, 0);
+ &pose_tap_pen(50, 100, 0);
+ &pose_tap_pen(50, 100, 1);
+
+ # sleep for 2 seconds to avoid double click after moving
+ # to replace field
+ #
+ &enter_string("$from_string", 2);
+
+ # Move to "Replace" field:
+ # Triple-click to highlight all the text in the field,
+ # so it is removed when the string is entered...
+ #
+ &pose_tap_pen(50, 120, 0);
+ &pose_tap_pen(50, 120, 0);
+ &pose_tap_pen(50, 120, 1);
+ &enter_string("$to_string", 1);
+
+ # Do find, then replace...
+ #
+ &pose_tap_button("Find", 1);
+ &pose_tap_button("Replace", 1);
+ &pose_tap_button("Cancel", 1);
+
+ &leave_func("quickword_find_replace");
+}
+
+# quickword_tap_at_top
+# secs - seconds to sleep after the tap
+#
+# Tap's at the top of the QuickWord document.
+#
+sub quickword_tap_at_top
+{
+ my $secs = $_[0];
+
+ &enter_func("quickword_tap_at_top");
+
+ # Sleep for a second to avoid any double-clicks
+ # from happening.
+ #
+ &pose_sleep(1);
+
+ &pose_tap_pen(0, 15, $secs);
+ &leave_func("quickword_tap_at_top");
+}
+
+# Saves file and returns to the Application list.
+#
+sub close_quickword
+{
+ &enter_func("close_quickword");
+
+ &pose_tap_button("Done", 2);
+ &tap_applications(2);
+
+ &leave_func("close_quickword");
+}
+
+#
+# MINICALC SPECIFIC
+#
+
+# start_minicalc
+#
+# Assuming pose was launched with the -run_app flag to launch
+# Minicalc on startup, this starts up Minicalc with the first
+# file in the list.
+#
+sub start_minicalc
+{
+ &enter_func("start_minicalc");
+ &pose_tap_button("OK", 1);
+
+ # For now just tap on the first spreadsheet. Add support
+ # for multiple sheets later.
+ #
+ &pose_tap_pen(10, 40, 5);
+
+ &leave_func("start_minicalc");
+}
+
+# close_minicalc
+#
+# Returns to the Application list (no need to save).
+#
+sub close_minicalc
+{
+ &enter_func("close_minicalc");
+ &tap_applications(3);
+ &leave_func("close_minicalc");
+}
+
+# minicalc_enter_cell
+# row - row to enter value, starting with 1
+# col - column to enter value, starting with 1
+# val - value to enter
+#
+# Only valid for minicalc.
+#
+# This only works if the val passed in has a '\n' at the
+# end.
+#
+sub minicalc_enter_cell
+{
+ my $row = $_[0];
+ my $col = $_[1];
+ my $val = $_[2];
+ my $i;
+ my $j;
+
+ &enter_func("minicalc_enter_cell");
+
+ if ($global_debug)
+ {
+ &print_debug (" tapping to cell row=<$row> col=<$col>\n");
+ }
+
+ # Tap pen on home button to start with row=1, col=A
+ # at top left.
+ #
+ pose_tap_pen(1, 1, 3);
+
+ # Now the cell should be in the top-left corner,
+ # so click there. However we must first click
+ # in another cell or pose doesn't acknowledge the
+ # click.
+ #
+ # pose_tap_pen(120, 95, 1);
+ # pose_tap_pen(21, 9, 1);
+
+ # Click the down button once for each row.
+ # Must pause 3 seconds each time, otherwise MiniCalc
+ # will not keep up.
+ #
+ for ($i=0; $i < $row; $i++)
+ {
+ if ($global_debug)
+ {
+ &print_debug (" Typing carrage return to go down\n");
+ }
+ enter_string("\n", 1);
+ }
+
+ # Click the right button once for each col.
+ # Must pause 3 seconds each time, otherwise MiniCalc
+ # will not keep up.
+ #
+ for ($i=0; $i < $col; $i++)
+ {
+ if ($global_debug)
+ {
+ &print_debug (" Typing tab to go right\n");
+ }
+
+ enter_string("\t", 1);
+ }
+
+ # enter string
+ #
+ &enter_string($val, 1);
+
+ &leave_func("minicalc_enter_cell");
+}
+
+#
+# GENERIC UTILIIES (pose)
+#
+
+# tap_applications
+# secs - seconds to sleep after the tap
+#
+# taps pen on the Applications button.
+#
+sub tap_applications
+{
+ my $secs = $_[0];
+
+ &enter_func("tap_applications");
+
+ &pose_tap_pen(15, 170, 1);
+ &pose_tap_pen(155, 10, 1);
+ &pose_tap_pen(155, 10, $secs);
+
+ &leave_func("tap_applications");
+}
+
+# enter_string_at_location
+# x - x-location to enter string
+# y - y-location to enter string
+# in_string - string to enter
+# application - appliation (QUICKWORD or MINICALC)
+#
+# Enters a string at the specified x,y position.
+#
+sub enter_string_at_location
+{
+ my $x_val = $_[0];
+ my $y_val = $_[1];
+ my $in_string = $_[2];
+ my $application = $_[3];
+ my $x;
+ my $y;
+
+ &enter_func("enter_string_at_location");
+
+ $x = $x_val;
+ $y = $y_val;
+
+ if ($application eq "QUICKWORD")
+ {
+ # Allow users to specify TOP/BOTTOM/LEFT/RIGHT
+ # for QuickWord.
+ #
+ if ($y_val eq "TOP")
+ {
+ if ($global_debug)
+ {
+ &print_debug(" Converting TOP to 15\n");
+ }
+
+ $y = 15;
+ }
+ if ($y_val eq "BOTTOM")
+ {
+ if ($global_debug)
+ {
+ &print_debug(" Converting BOTTOM to 144\n");
+ }
+
+ $y = 144;
+ }
+ if ($x_val eq "LEFT")
+ {
+ if ($global_debug)
+ {
+ &print_debug(" Converting LEFT to 0\n");
+ }
+
+ $x = 0;
+ }
+ if ($x_val eq "RIGHT")
+ {
+ if ($global_debug)
+ {
+ &print_debug(" Converting RIGHT to 152\n");
+ }
+
+ $x = 152;
+ }
+ }
+
+ # Just to make sure the offset isn't outside the
+ # proper area.
+ #
+ if ($x >= 100)
+ {
+ $offset = -2;
+ }
+ else
+ {
+ $offset = 2;
+ }
+
+ &off_tap_pen($x, $y, $offset);
+ &enter_string($in_string, 1);
+
+ &leave_func("enter_string_at_location");
+}
+
+# off_tap_pen
+# x - x-location to tap
+# y - y-location to tap
+# offset - x-offset to use for first tap.
+#
+# For some reason, pose does not register a single
+# pen tap if the last single pen tap was also
+# at the same x,y coordinate (even if the last tap
+# was a while ago). So this function does two
+# slightly different pen taps to ensure then pen
+# tap happens.
+#
+sub off_tap_pen
+{
+ my $x = $_[0];
+ my $y = $_[1];
+ my $offset = $_[2];
+
+ &enter_func("off_tap_pen");
+
+ # sleep for 2 seconds to avoid double-click.
+ #
+ &pose_tap_pen_hard($x + $offset, $y, 2);
+ &pose_tap_pen_hard($x, $y, 1);
+
+ &leave_func("off_tap_pen");
+}
+
+# enter_string
+# in_string - string to enter
+# secs - seconds to sleep after entering the string
+#
+# Enters a string
+#
+sub enter_string
+{
+ my $in_string = $_[0];
+ my $secs = $_[1];
+ my $j;
+
+ &enter_func("enter_string");
+
+ if ($global_debug)
+ {
+ # Display in_string so \n and \t values
+ # show up as normal ASCII.
+ #
+ if ($in_string eq "\n")
+ {
+ &print_debug(" Entering string : <\\n>\n");
+ }
+ elsif ($in_string eq "\t")
+ {
+ &print_debug(" Entering string : <\\t>\n");
+ }
+ else
+ {
+ &print_debug(" Entering string : <$in_string>\n");
+ }
+ }
+
+ # Replace "\n" with real carrage returns.
+ #
+ my $string_val = $in_string;
+ $string_val =~ s#\\n#\n#g;
+
+ # Replace "\t" with a real tab.
+ #
+ $string_val =~ s#\\t#\t#g;
+
+ # Convert string to ASCII numeric values
+ #
+ my @array = unpack("C*", $string_val);
+
+ # Enter string one key at a time.
+ #
+ for ($j=0; $j <= $#array; $j++)
+ {
+ $queue_size = EnterKey($array[$j], 0, 0);
+ }
+
+ if ($secs > 0)
+ {
+ pose_sleep($secs);
+ }
+
+ &leave_func("enter_string");
+}
+
+#
+# GENERIC UTILIIES (non pose)
+#
+
+# get_date_string
+#
+# Returns a timestampe string in yyyymmddHHMM format, where:
+# yyyy = year
+# mm = month
+# dd = day
+# HH = hour
+# MM = minute
+#
+# This sort of datestamp is used to create the output directory
+# names, so it used in various places.
+#
+sub get_date_string
+{
+ my $cur_secs = time;
+ my @lu = localtime $cur_secs;
+ my $lu_secs = $lu[1];
+ my $lu_hours = $lu[2];
+ my $lu_day = $lu[3];
+ my $lu_mon = $lu[4] + 1;
+ my $lu_year = $lu[5] + 1900;
+ my $lu_str = $lu_year;
+
+ if ($lu_mon < 10)
+ {
+ $lu_str .= "0";
+ }
+ $lu_str .= $lu_mon;
+
+ if ($lu_day < 10)
+ {
+ $lu_str .= "0";
+ }
+ $lu_str .= $lu_day;
+
+ if ($lu_hours < 10)
+ {
+ $lu_str .= "0";
+ }
+ $lu_str .= $lu_hours;
+
+ if ($lu_secs < 10)
+ {
+ $lu_str .= "0";
+ }
+ $lu_str .= $lu_secs;
+
+ return $lu_str;
+}
+
+#
+# DEBUG FUNCTIONS - Wrapper functions
+#
+
+# pose_tap_pen
+# x - x-position of pen tap
+# y - y-position of pen tap
+# secs - seconds to sleep after the tap
+#
+# Taps pen at specified position and displays debug info
+#
+sub pose_tap_pen
+{
+ my $x = $_[0];
+ my $y = $_[1];
+ my $secs = $_[2];
+
+ if ($global_debug)
+ {
+ &print_debug(" Tapping pen at : $x,$y\n");
+ }
+
+ TapPen($x, $y);
+
+ if ($secs > 0)
+ {
+ pose_sleep($secs);
+ }
+}
+
+# pose_tap_pen_hard
+# x - x-position of pen tap
+# y - y-position of pen tap
+# secs - seconds to sleep after the tap
+#
+# Taps pen at specified position and displays debug info
+# This function works more effectively in situations where
+# pose_tap_pen is flakey. This function is not good for
+# double/triple click situations since it is slow.
+#
+sub pose_tap_pen_hard
+{
+ my $x = $_[0];
+ my $y = $_[1];
+ my $secs = $_[2];
+
+ if ($global_debug)
+ {
+ &print_debug(" Tapping pen hard at : $x,$y\n");
+ }
+
+ `$qa_script_home/tappen.pl $x $y`;
+
+ if ($secs > 0)
+ {
+ pose_sleep($secs);
+ }
+}
+
+# pose_tap_button
+# button - button to press
+# secs - seconds to sleep after the button press
+#
+# Presses specified button and displays debug info
+#
+sub pose_tap_button
+{
+ my $button = $_[0];
+ my $secs = $_[1];
+
+ if ($global_debug)
+ {
+ &print_debug(" Tapping button : $button\n");
+ }
+
+ TapButton($button);
+
+ if ($secs > 0)
+ {
+ pose_sleep($secs);
+ }
+}
+
+# pose_sleep
+# secs - seconds to sleep
+#
+# Sleeps the specified amount of time and displays debug info
+#
+sub pose_sleep
+{
+ my $secs = $_[0];
+
+ if ($global_debug)
+ {
+ &print_debug(" Sleeping : $secs seconds\n");
+ }
+
+ sleep($secs);
+}
+
+# enter_func
+# func - function name
+#
+# Displays debug info about entering specified function.
+#
+sub enter_func
+{
+ my $func = $_[0];
+
+ if ($global_debug)
+ {
+ &print_debug("Function enter : $func\n");
+ }
+}
+
+# leave_func
+# func - function name
+#
+# Displays debug info about leaving specified function.
+#
+sub leave_func
+{
+ my $func = $_[0];
+
+ if ($global_debug)
+ {
+ &print_debug("Function exit : $func\n");
+ }
+}
+
+# print_debug
+# string - string to print
+#
+# Displays debug message with a # at the beginning of the line.
+#
+sub print_debug
+{
+ my $string = $_[0];
+
+ print "# $string";
+}
+
+1;
+
diff --git a/xmerge/source/palmtests/qa/palm-session/session b/xmerge/source/palmtests/qa/palm-session/session
new file mode 100644
index 000000000000..900c4981cc0c
--- /dev/null
+++ b/xmerge/source/palmtests/qa/palm-session/session
@@ -0,0 +1,8 @@
+DStrÇ£¾š{07¯lÙ;¢;¯l=8¯¬­È+ÛfDœñݼr‹#.É+G’WŽz8¯Œc`å6E<’Wn»8¯|Á­Oå•ÛŸžWn·>¯Üᣑ¬ã'ç•/šWîëüƒs÷ïß—»ß17w¿óÎÜ=ç¹û´ûs÷ûî‰x:wŸº{îüô;"îÌ=ÎŽønîým[îùð¹¹çïψ¸?÷|äšÜýòs÷¤›"çžíÑ‘Wï0;âò¼zä§óêQ£óêí‰ñ yõèk#äÕ[‘W¿ð®jX½cÊ«_tMÄ=yõ„ÏD,Ϋ_|XDÔ³ó¤ˆCòê]åÕ/‰:_uLønÄS¹{—Žˆër÷®÷åîÝÆä•SžÌ+_ú‹¼r÷Ïä•{>‘W¾,Ö{RkD¸LZšW¾<ÖïÈ7ùŒÈ®ûœ±.¯Üw—ˆEy嫯Ê+_»{Ä11Ž¯kÏ«—IJ,‰åZó_ãÝyõé÷åÕŒå;-Öåc±|Kß“W¿Û¼úoÇäÕgÄ:0–ïƒD¾é_Ï«—õçÕg]±2¯>'ò}W^}þ~yõߎ|WæÕç.Ï«Ï›•W(æó÷³#ΈºÏ¿9¯þÀyõ‘öá7Gz¤ïiOE¹ù‘viÄ7c™.É«Oåß»(ÒbÚ…£"®ÍÝ;Ä6Ýa}î~ᕹ{üG#b{m5þ‰Ü½ãŒˆ˜¾ãN¹;ì»_ü¾¼º3êï¼!¯îíÏ«¿ÛìGQï:"fåÕß?&â܈/çÕ7wä5m±>7¯‹ü±N·Äòݲ ¯¾5åÕ?h‹þž±ì?8/¯þak^}{äûÅ”¼ú—»æÕwñÕ¼úÇs#îΫû–×÷ƒŸ‡Å¯¢®ûc>ä¼úÁ½òêßÆúývD^ýh¬ÓãQþ–X¶'bú®‹<çÕOžózr}^ýŸÓbÚ²ˆå1|W^½îM1Ÿ°úɉUýk>~n^sI{^óŠœ×ìÇöÞWE¼&bAÄíŽi±œ_Šy}þ¾¼úò¾¼úŠö¼úª¥yõŠ‹"=œ¯80Ưϫ¿õ_ù¾²&¦×lmÄMyÍøè¿ðyMû˜¼f‡ûb¸-w¿ Ž­íFGL‰8!â“ýyÍ7#ß7¯‰ˆ|ß¾$¯ùÎWóšÎˆ®)yÍÊX¦ïŒÈkºwÏk¾wD^ssL_}XDôo¾3¯¹e‡H_–×Ü´oÄü¼fM¤¯y2¯é]±"¦ÅôÞ‡òšµëóšžî˜Çyyͪû£Ü1Qî–Oç5ß¿!òõFù»büÖ˜ç®Q wG™ïoõEÝ=“">ãq¬õƾ²öŒÜý½cs÷MGDÜi=1Üóù˜ûQϺèG»ÒmBïù‘ç–Er÷÷cßûþ#¹ûæ›s÷í³s÷Wäî[ŠØ!wÿ Æ°gDoî¾mLDÌç¶þÜýÓ¥¹ûÞ £¿2úí¹ûgQÏ}³".ËÝ¿úzî~à®Üýà“QöÁ˜ß-1»b?¿;œïþfîþX–ÿˆ´ŸLÊÝÏÌÝ¿¹$æwTî¾?êúñ^yåÉц¾÷ƒÑ¾M^¹lq^uÝWóª¯E|}nÄSyÕõÇF[ðá¼ò Ñ^mÊ~—敯ÿz^¹ÿ yå´sÏÛžÎ=_œ{þbÛÜsÌÔÜóöèÿÕò¾<¦}=÷Ì{NŒ6ôƒŸÎ=³¿š{>Й{Î</ò7b]î9áìÜsòÌH‹rgÎÊ=ïz*÷|â£÷æžONŠx_Äc¹çŒ:ŽˆØ5ÚäØ7NýáüÛòš×î•×Lýe¹{¯X×W,ˆØ;w¿2¶Í+[s÷ÞWFÿôÜ=ùúÜýª]cÚõyÍ¡Kóš×ÇþwÀéyÍþ;÷œó?û„ÜsnÜ×~è°ÜsÁ‚hëGÅpIõ9ûž¼æ½Ûå5Kâzãq]òÎ箿ž™»f‡å9SóÊ úòÊŒóÎ?öç•—^㟚qQD´ÍŸž™W^íïeqûç8ýsGÄyågâ¼ô™Ë"¢Ýþl”½l×¼òÃ7å•Ÿ¼?wÍk‘“—æ®S¾œWž¹<¯<+ç•'Fÿëyõ·ÞÑq^ÄŠˆ‡rÏ_ÆùiÖ‡sÏ[¦çž£bø¨"V䞣WäUÛÞœW;$¯Úæ31×açĵÈýïÉ«VMÏ«þí¦¼æÞÉyÕÜòª.Ï]÷žŸWóî>=¯¾òâ¼æGoÎkîzW^óã;óÚm®ÏkÇœ×nû®¼6›×n× ÿqiÄʈ÷åÞßǵȺ«òê¶ýâØç¿Î¼zÛ‡âZêþÜûë¸~‰k²Þ_¿+÷ÞûùÇÅù*Öï-oŽež×¼»¼rqì—KÃhÙµyåiÑN®‹ë­Yq=ø¢8¦o~sîÞ9Ú¤í;ùrî|ô˜¼jû¸n{ǹëmoŽ}:Žé¾uyÍ_GÝí»äî—ìÇôµyÍ­kb¢]ýÈQ¹sÕ®±ß…íÕýÑ,Ï]omx"¯¹?Úü§¦åU<‘»n‰}ýM±MœWûÓKçÇuJlû#ã:äôÎhÛöΫ—GÛ»Ý]yÕŸÌ«>þ_<6Ž¯óãœyœçŽÍ«ï‹cû¡¯æî×ıþšûóÊ£â8{ÛNqL½-ö·Å6>vTÄaŸÌ+ŽcêkªXóÛh{×<ðp^ó`XÌyW^ù®ØŸæ½#¯<aLDìïÞ+¯|ψˆåÑ~ź¬ŠvíÑ{ã|ç¦1q÷h\ß­Šk¾Çb9~眧>\ º¿çÒ?Ä9í¿NŒëŠ{Â$Îÿvk^“å5-">˜W]ûÄò7åUŸ‹}âsçU_øf^uåùyÕÏ‹èÏ«®ú`^ÓûÏÝ—DÜ»×ߦq|wÄõãnÊ«î¸0¯º§;üÊ«Ÿ~ºšoußQî="zf÷Å5åcyÍ“qõpÛ)Öá‚ѹûG·EÛûêOc¿¼÷Œ¼êgÍ«úÆçU¿qc^õ˱qýº8wwOîú›¸æþ›xRZêûl´Ÿ½5÷|æ‘è·Eìñš¼rúÞ¹kÞü¼æ·GåUÿqsîyßî¹ëËÑŒ;&â©Ü½ÍuqŽŠmÞé[Źm|\‡—úÞ=6÷,üfî9å¹;Ú±îïD;ÿŽhCþzJî~W´#§ï•;/‹ëä8Ž;Wïín¤ßÕíl´?LÎÝqvÄws÷ãÑÞ>~^Ä͹û‰Ò†G{ýÀŠj>ÃMži¸û‰C¢Ü ¹ûwã#fDÄ9áwwEÛ~nĹûÉXžu÷åîßOÏÝÝoÊÝ«ŸŒsÉ¥yÍ'¦G¬Œˆsã'÷Ž8#â±¼ú¥ÑþuÅðFÛV‹}ðµ—æî}?˜»¾*w]÷*ÿžóš¥ïÊ=F[}ðìˆhƒßñ©h?ÕŸ{>mÊeÓrÏ?ÇqtÙ×sÏ_±(÷wql×ãrÏ'&äžÎ=—¬§Ðwæ5ã.ÉkÎ:,¯Ù-å5»_”×ìíë±qyYÌ{b,û«>™×|,öó|&Žï¶8^ßçï8¾Žc²µ5¯Ù)öË¢ Ú)Ú¼ŸÄuÒħóêö‡#fǺÄþ~ÃòÜýí/G¬‹ítYDì±M:ß“»¿mëëÎ+ÿ&î_¾}ã3ß¹ÿoNi¯?­L[¤Þ2ߎ”â)狦FÌŠ8#"ž1Lˆ§™&§41žÿ¿ä¨èÏŒXñΔv»7ž›ÃçÇðÓ1<&â¢xDO&w»®ñL}^ã¹óÑ1‹“"æD¼7â¯#N8-âgEü]ĉø‡ˆOD|*âŸ#>qEÄ—"þ%â_#¾ñˆoGtE¬ŽXñýˆDÜñ㈟Fü<âWFü&âшßEü>âñô·%b‹ˆ-#¶ŽØ&bûˆ#^ñ’ˆÝ"^ñŠˆWE¼:âuoˆ8 â‡FñÖˆ£#Þñ×s"æEœqJÄ{#N8-âgEü]ĉø‡ˆOD|*âŸ#>qEÄ—"þ%â_#¾ñˆoGtE¬ŽXñýˆDÜñ㈟Fü<âWFü&âшßEü>âñÀº%b‹ˆ-#¶ŽØ&bûˆ#^ñ’ˆÝ"^ñŠˆWE¼:âuoˆ8 â‡FñÖˆ£#Þñ×s"æEœqJÄ{#N8-âgEü]ĉø‡ˆOD|*âŸ#>qEÄ—"þ%â_#¾ñˆoGtE¬ŽXñýˆDÜñ㈟Fü<âWFü&âшßEü>âq(´Dl±eÄÖÛDl±cÄ‹c‰éi|N-ñ7šè"g9JêÉi¯H¿´ŒÕŸó·§ÜyNü]äEñÄ¢ôÓNñ8¦âì–Z®ÉçF«}Qœ}nX—»¿!w <”Wþm\EŒ½2¯ú§¹{븒~ÛvyuËÍyõ?ÅÃ+§å5—>‘{F̈8&"®^G¬Ì=#£g”Ñï,ùÉ=ÛŸŸ{^g½×çž7\ó+Ëü‹X–©e™ËÑë[>Ê2ÇñkQÖ,Å2÷|îÀÈÑ^ï§Uñ8ökÛå(“{¾WÖ_ëÈ=_þ×ãªû†ÈÛuOîY9!÷ô^›{n_–{îˆþërÏ]3rÏcüîY¹ç§{åžû.Í=¿Ú.br7÷üæÉÜ[;&÷¶íœ{·xOÄ#¹wdkÄ؈x²4rJÄ'F|>÷ŽŠi£fFqFÄùWF\Ñq[îOžF?–{·Š:·zSD\ne·Šic¢ü˜IQ~ÌÅk"žÊ½[ïñ®ˆOF|7➈X¶±3rï¶QǶ7åÞ¼9âÖܻݷG<‘{·ß.÷î0¿ü•(â’ˆ/GÜ™{Çï1=âôˆ¨kÇx:¶Óå¹÷EQÇ‹nνŽˆ´ËöâGrïÎ7FÄ<'N‰¸,÷¶Çz¾ä¨ˆoF¬Ï½»¼'"–y—¯G<–{_ºoÄÒÜ»kÌc×HÛu]îÝmjÄ¢ˆXŽÝʽ»Žˆ§s»ÇñîO”¿iEÜ–{÷üLî}Y¬×Ëbž“&D\’{÷™ë²ï/"â‰Ù«£Î×|7âΈH{mÔ¿ßÊÜûúŹ÷ ±|ÓcY¦_iÓoˆ23âªú€0: òÛïÀY¹÷ 0žùÎÜûÆÎÜ{H,áïȽoº7÷þe¬Ãá#rï¬X–£ŽË½o‹ùüÕu¹wvļÏGÄ:Ì‹uŸåOˆe<áéÜûî¨ç¤¨óü˜~Á“¹÷Ãνÿù?~Qî]Ëô/;äÞ½/÷^ãÿ¶kD,ßW÷Šˆyíˆ{roì³½_ïϽÿëúïŸÎ½×/ν߈º¾¹_DäÿÖv1ŸoÅôo…Û·®Ì½7ܘ{o<8"Öë;×äÞ®‡sïÊû〉ãªvn?§‘õ³azA9ŽÊqU»°:ÒZâo£fÇß[þ©£­åÓ©m›bzu´•ŒÑ•:.‹Ò3Kj9cÆäOÇǤ8æ®ýãÿ,y#÷‡#ç÷êÃ>ÿWZÒèø“ì`×’bÛ~26òqMsÓ!ñ_J[Æ)ÆRËk¢½][©lÓÆeÆÿÛ]Ê«Rg^Õ÷f­qÏZ»/¯jëÿ_ÙnfBàÿ^8«Œøbuž‰³Ê3ãj­úæÍn77¾3¢1wd©=ò~/ÆoÍk_ÏÅ®¿/¯ýF[ÄÁGÄô±ñ•¦;â„ÓÖò…›¹Ë·œê]ù&Óóëâ'ÀrUÖ¿EÕÚ e‰ãž0ÎjƒKühwˆ~zm½_îÓ}QÇNyí·~‘×~'¾#öÈóXêÎÛóÚ•æµÝ3óÚÕq¿ö3yíwc­nzG^ûý‘ïûñðæí"âI`<¡_{óÝym<]_{ËwóÚø ÈÚ[¯Ék°_ÄUyímñ´ÛN8?ââˆÏG\qCÄšˆ'òÚ†Ô·Ø5"ÊýðˆwDÌx8¯½ý›‘÷öxy{,ï;E‘×ÞÒwÆ2ÜõT^ûã]"ÌkîîÌkò¦XÇþXÇ8[ï:ÚZŽñúA|Öâû>›~jx±jø€ùó7IÛ4aBHO˜]¿
+ÿñ²æ v¿*¶ÃòˆËÓÕ<wŠ}b§´åÈ4¾¡UU4·%¾·TûܨMkÝLÊo;.‰ÔŽ¸ò©wµÏo›F>•–ǵ¯<±S=±Œ•î³ñ_ý›qõï¶}´öÀç« )åµ—Uÿ^b|•*v¬=¯*'Ò=oS>(K»çúrÿò²íÊ—É^¶oùœtgÜ°¥——«²F·ç½Sö›òšöE§Äxí?:SÚ7Ö}—ræ®wµ‡Óy1´SŠ‚{ÜØW­v­ý&9Ë<º—í[ï}Ö‰ámËxg¹ÜN/û`äŽU˜´{™öœºÃ"Wcƒ7òoš’s¨ç«Ïíø9­ÎŸK¦ÚocI¶§FíŒM_}¯Z´—·ÇrLDÙîÏ­Û§ì[yí•Õö®Š<—””^Zò–çIÑ=ëpsˆ~Ù­Ë.ÑÖèhôËPÒ«íýr(”ñÜèÇ“Šj|»F?žZ”ñúQq ¦ ký%¹tUýµ9ŸŽ‡AñÝÂx‚WV´tJK#ýìH<ÒK+çšåL±G\åîžÚÆ^i;DT]ä£åÁŸÎ;~éI TIåËŽ¥[ßÈ’NY8÷”EsÌO[ä[OŽ3Oéfžôî“–žtú¼Åéø»£üê©CŸsczU¦%ßšÛëé/\|Êœ¥K†2•¡ý;ÇOX|ÊÒf™ÞÛêÉ1oÁ¼ÅsæG»´™KÌH{÷‚Åó›evê®—yó¼¥ï_¸øär…?¸Õ”F bzUfD¾ýér?Ý[Þó©¦tf_sh°¿ðý 7çsÏåõä#O\¸xéA§n¼Fƒe–œxüàúüf¯zrGíoî¯Ýâ¬zïà6‹­é7Gz<©ÚýüÈÛlvÙfŠmv^j;¦ìñÕ¾Uj‰¼Ÿ¼µÜû½{sïMq×üòæq}KUoìXõ®õÞؾ—¥–~3To\wôþðÖø6pÜ—~jmô£Þ9‹"ïrïíÓ"Ê~4;ÆoÉw|dVÄì|ÇE÷Fôç;þaDĤˆioŠ8.bQDGÄ%+"nˆ¸3âá|ÇÅm{EÌŒxgIJˆ‹#®‰¸=ßñ‰{òÿøšˆ§óŸšqs¾ãÓí'FÜ”ï¸ìîˆ'óŸ‰:¾óýÂ…ùŽ+®Íw\y¿eW\˺s,ëiÍ5ÿïö;j³ïŒzŽ.åÏì(ŸvÃv×Á “û&/˜<yöÎiƆ'ãH³Ù´Î ƒåÊÀäöþ1©o£´Ù›Ië¼vLꟶAÙמui¤5vÀÆ”É-ãǤuq\ ë&×&ŒIw6,%æ[[?¦åž›7Lk;¦å¦n˜6bĘ–”Ýt¨›Ü6rLˇF %ÄÐä1µ±Ûl”¶lç‘Ÿ}|å¸ ò ô 6‡Zrsh¨ßúÀÐps¨µ·>4r]3%öö«êÃ;JkÖ7uÔÛÚößù O/;kU_}úäQ«ÚÚv¼pÇ)“;Ïk™ÝrÖycÆß4~òä¾ ››sv-Ý<¶J뿬Ys¤Ý²s•vý¥ÃÓvØñÂ({Ù`Ú¢Zúþ×'Ž‰´^ÚÜt“kéÇ__Ò>tYs¾ã·<ëÒ_Viç\ØL;~Uü7vêäÉg}¨™6rݧtÃÈþe§užÓßœñÿx¿|§}ãîøŽSâ¯E›K»¡uâ¯û×ïß8ÅV…æ\Úú‚—nsÞŽg 6_QöÒ‘µèÆw3Tïñã·¨ÕF´\ºêœ¡ŠŒßúœÚý‘Ö3”6»¤íÞò©sVOuN”ýlí”áiWEÚ§Î;±35»Ùãǯ*ó]3uxÚµÇ×ZÎÂä¡´þý×ýç‡:ÖOû`îkÕ'@€aôF_ù¾É¿,šÐOÅöhsÒÑ?ˆ´/zÈ}—§´d׋¢ìÅÌýp¤}åÐC䧻`f¤m¹g#­ýÜH›uÁÌèm¹Ç¡“ωúœpiP}ôÝ3gƤ»Q'ÄxÞLÚ3'•,4‡g¨ße7LÆWj}ñÒÛ¹4TѪUÛ¨ F7µÖŸã¦¯+#î]Uó6qçõÍ„°8»j‹'ŽžÖÚÕ9öQßÚUæ–Vµo˜vvuUºaZçäE›”íŠm¶q}¿8orIÛaø<~^n7šoÿŒiG [¾Ô¿¼ä›Ø1<mÝŒ¾H×3|}—Uë;ò×ý1¥ÙM׃µÿìk&DBÕ’nè<¶¾`ná•+ÿìƒ#;§–[Ý]Ï–µ%íÚûȆicv™³åõiÒ§öyýøfÖ–mwù‡Ñ9Mºbæå±·Ö»’¶e|ãü 3/¿a(m×uQÚæ%3/_>˜6fêœÿ•¶yñ>»^ÖLÓ'@€næãÙòl®})íçGÌŠË9±qgó‹¶êÙfWÚ³?šççw~™ß’÷/^Ô¸SŠïTÕ¿ý+¸™õj&=[žgœß¥½~×Ò¥ ò­ûuGmq>?ðÔ¥K.l>›³Ø ÿlyžq~O”ùÍ=éÝ'å[s{}~3cléI§Ï«_>l0›Á‘gËóLó1©Ìï„ŧ,Í·öÞVŸßÁ Ÿ2§\ý‘îÙò<ãüf—ù•+™Æ¿øž1oÁ¼ÅÏrúy¶<››_Ëì–4â†rÍqØœSãŠ'Ž½ú%ÞŸéÄÔrîÅçuÄõDóû Šë‰ï¤¶Ö¿(WCÕ5ËÔ´C…±CLyùÌr½×ÖòÊè—+}¢_‹þk£_þ¯×G?þ}Æ–ý£?"ú05.ÐÚZþ"ú£¢ÿ—Ñß2úo‰~Üùµù¶ŠþÛâ:rLôÿ*ú[Gÿo¢wW-ÇG\ôßýý“£¿MôFÛè/‰þ ¢ÿþèoý¿þöÑ?3ú;l°ªÿ£#áÇÿÈËö\øþ‹ó­÷\i±=ßòþØždß)“ž-Ïæ¶g5¿ee~KN<>ö×ß”'f1¿#‡.äŸq®Ï–g³ó‹wÇüòà·ÏŸ±î2!noZfÍ™Jû[Žlã)îöãÚsä×˵gu<ícß
+¸ÅÇo¹h\ôÞ9¥ðe>³_|üVéÀhºÓáG87’GD´´\tøQÕµáŽé¢ùgŽ›ŸÎÙux/ ¼2uÔÿ¶ÏÄwnÆΪ_L—ýó—3Ê؉1µ\×~¬ºÌ.SßµMµõ_ÄUÊ Ñª´ƒ¾{tÄ}ÚuÇ÷±awA/ˆ²UwÊœã¿;ʧï,¯'´””=ʾùÙêéÕ±­iÔNe}ƤæÏY|ÊæWhïtÑ»Î|S4ÚsæÙ{þM:k»g+k‹~LÔ;³Yï¼ÅK7_ïËÓE³Ïœ6;M«>Ï™ýL#¥ÒžŽºÎýƒgêjiÔgÊ_ªóšüä’ãckD×¹¹†c8ןÁpì+ñÐaËtô‚%sÞ7onu»Ùû§€,[5âñúæ«_<”áò/œUíÝ^³ê“FUc¥uûx5TÚ·sÊÖÀbèßÊýe5ô便¬†¾Uî3«¡V%¢åkYýËi±O¶îŸo½nB¾ãüËò­îšoÿ·CòÚ¾±¹wÕ/Ê·ÄòÚ߯þUôœoïïÏ?8½³ü;º¹÷‡·–³o9#–³T9s”»µrUZª%ˆ9±#¥öPxC¾ãš åÛ˹gù¥±”ºk™Þš¶¼ v¥Þ½_9'¿jò”ÉõnêÑ{O‰¼‘²ïPÊ>©­Öº÷¾ñY‹Û¹¶ZÛÞñT«¶ÅÞ¯Ï{Gk_¹w<ûŠR¯zu”šRʶî}R=åµC)Kª”ƒß8˜ò®ò´oñ¼9'Ÿ0gÉÒæF‰™'Å=ç⹑sÆÌ#GͳG9ÿÔxâVN];œ2/ž»Í›·ô¤ïÞ:&¶Í8êÈQ¥õ3Ũ87mvŠZ¶5þ­Æ½ãsJÚ7>§Æ“òÖøgÄçÌtp|¾)9g¥ãâó]ñšì­ÓÒtvlýóÒEÑØ\’âûXé3éóQë•iEœÃ¾œ¾g®ëc÷¯¥îðšÐšFO7¾Ÿ<ò´%KçRßaÊç_Ì9%îÙ‡º£—ž4?ššÁ´xâóGÊýÙmrÝßQ=•Ùé¼r­ß²ß Òè}lÇ´s¹+ô–É©<a(MXj)×Ê‘ÖGÛÂ%óêëX)-µY“ëOHâ¶=¦–ïP–oMÖÓÚ‡â©Zza5µœ êùFN{ˆomUM[‚–íª¡ò¬^ËV1T«ÒÆÄP½l<K#«´r×Rϧ³ÆPiõëiÛ-Šó[•/žã5Êî°äÔS.9åÝ‹ëë¶tÉ)eÝfMþo´—Qe_KÚjj}oj?üЙ‡¶¹ðÔqL4çV-iìï-Ñv=V¢L‰®~mKN9aqµ„cg‘òËæy°­å×q>,×kÿýÒ¢ý6ú¥={<úåzí?£_®×þ+ú#óÍÆ¿=ù£uùÖ}‹;›ø7ž¿17ßòãóò÷žúßkÃbÞÔš¶úð¢E‹þ¦Z¶ÆGã[Qï5ò€“N‰cø´ôº½Ò«^õÚÉ{¥½¢Kƒ÷“­çEM¿Jã6>ŸíÉÎ[O=éø“7sã¹Á<ÿoÙäHŒ…ß`à°hVÛD3ÔX—ƒOZ¼AÂA O‰ËÈ¡›á·môøíxZ:œáà9ßÅÕëÒ7¸Â}ã+ª§ÐƒEÏ0Ç:iéÐÌ"õÈ¥q✚Ò;NZÔ~йƒIÅ~¿tØÍúQ'-?81Êtê’¥ OisX½kŒOÙh|ŸÆ÷mŽ¿yá³O·È³æ¼{ƒõ;|á»â)W³tós[D3µõ{Ê¿ŒZ®žñùýP±æЉmûn,ÔœÔìo|=ÍßÄrWQiYKwf_JŸ]·ëSËȧSË âŸ¸ßj £6r cäg:G~(bUÄÏ#úÝ9rÝ‘#×ÐY{º­£6ÐÚÑ2ЕâßÙ3ù‡=ãßj¹3‹úÊ<¢ ©½Ë,âß@YqUÕ_µbEG ÔÚZ±¼ôGíWM¨¥±+VÄøVé£U†­:ö«ú“V=´¢dœÔã¥}ä+ý/×®~¨ô¯îxx¿Ò_Ñ7elÕ¿~r-ú£W|9µw–þÕËGE¿uÅŠ§¾¢[±â+ëK“=iÅŠ/”þè˜ÍãÓÊ„jùÊr··§QqÞ(7ñ·5»Û¦×»fJéN1b 1}úô¡Íé#®Øl†¡éñoel¦†aÓ7[Ccúô˜ýˆÈ0´eœµ¯¿¹Œõé±àQÁ”a¥#¥Z‰¡é¥‚ 2l8}úÀÆ6š>”a ^ÍÆÓ›bIª ›Lodh:l:½Ê0eĈX’¨aØôæ–«×P F T“›ÛopËUk&n8}°‚飛ҘÜ,ÛP†È]Ô>ÿ M–¡ØƤ¦ÏPJ—Éñ°¸¾˜õÏÆRO*+·,×8q,W.gÇ0ûS_\’þmzCÇÄŽêä]òÄñÇb9鱗³ß1Qþp²Ä+#a«Ç;Së@gŒDB)3zè8ˆ{Ö祃Ño]185–¹ž1ݶcŒÿcÊ`d/kS›ëÅbNѵſ½6îÒþ•¿«=ãßûꙇžX;¶üMpxÒÆÛiÿvˆëœzû·S•;ZÖu¤‘}iÜù3ÒøÍH³/mONNšÑŸ.}éøÔ¹WDoúå F¥‡óÜÔè¹é±óÛÒ{»§¦e—÷§×싦3‰’id¬UËú¨¹Ì'®,Ã}·j>uêÖ«;;£ù¹!Åçw:;ã DûOŽ­rNç˜Hk36uîß· «:G®u\›F-/Ÿ+Rç5£[Ç¥Îk–·¦i“¯N“Ïéœ|õ˜ÎŽÔÿòZû¸4©ó¦ö§ÒèUiÿ«RëµãJëxíS¥±}eÕ²¶®ˆ„j™vÚ®Ãw¦Ám×L,;ÜÀÀŽ;îØØö%½™U ¥V;ýŽ;V{Ô`r½dä+;J#µ¤•„’V¦TÉõ´zr5- ÄÑ[M¯JVK%õÔfÉR Z¸é·M¯WVUÑœÅPj”¬fQ
+–V¼d®—,ýR{=µY²¤TJ;4´Àƒ™KjŒTk[O;î8e¨âªú”"©
+õÌõÜ%­Þ25ª¨JV bݼJ®JçzVÐ%7H,ÉUK9<gUM•m¨tu,k#ÎLåWØ]è8³¬ïFmĤ8—óo‰å­öZÑ—†2ÃÚˆÛbO)Ým±Vnƒ¡²
+gsbÚ4mJcò”tÛ”zWÎÃÑFìÕš¶YWÚˆò¬$ïE7Eb<³œcÍ/8T7þ8±6íÙòl¦Ø~Ãk¤–Xß‘ˆö¡¿#MŒãwÿÚìtƘEiÑ«&§¾h~?ÈybÛñiÝù‡¤þ¿ŸúÏ]–ÿ»uiÑÈþ*¦Æ5Ñ„‰iÜðö¡ÌcDÕ>ìZ-t늯DÒŠÇã3£5^Ñ?º/þų´|jšÔ?ºu¿hš—·MѤv\ý•õ£jWO®¥—v¬èì\™:¯N“kÕçôŽ«ÇuîóPÇËã•[‘âs¿itgz¨´ µÒ|åéÒ2ÄEPÌ«Þ2ÄÂã¿MÛ†ÆÞ4Ø®—]l0í=ÍÖ~0q`à=ÑUÉ¥½¯r6Òª#¸œJb3-æ_ìT)õ²eߊÃ+öàHž/ÒKæ¥Ë<êùš™#µj‡Ê.U¥U™©1EKzUsI­·UBu(ÇG#±9ZåÞLj9ìyëó*uV‡bY‹j&¥h#­Z‹á©eÞÕº ËÜ8ëW Í:‹YQ«Ž–FñH¨R‹[³+¹©ƒÛ¨J‹Ô趎£|X;0q]µÿº™£V\uñ¨³¯šÃ<qnl^+Äesg‰qqÐOžœ:oºéüÎUqšês~5ÿ¶pgUïØ Î)óš]uÎoŽÌ+c±ñÜPÕf)Œñß”ø¯ôÿÈ2XõëÓ6,WÕYÑ4¶F|-·5m7¦´ó–-Z’oþ« Q8ÚŠ7.[4oAóQQUãFÑV<[žçÐVĹ¿\Œ{<ÚŠ®h+vìKgÄ;M‹+³.K}ï[–˜:5=pÏÔôÄúñé‰eãÓS“ïJ§ï39} þm¾7ìÓ—v¾¥3ÝصĦmÅòXöI+ʯAW|elGi+jË£­¨­º*ÚŠZçCqÔë(]“ö_¿_G|N‹ÏŽqcãóñþ±W·ôGëѾg­cEï¸ô…ŽI½ãFM“®KËã*âºÑ㢭¸fùS1›kÆ•¶âåO=綢¹ÏUýÆÎYj¼±/—är@6’Kj•³~6’#µ™/ÝpC•y¨­ˆ5 ØH-™78Ênˆ®™Ú<˜"çPr½õ=ª¤Ö\¥^Ѩ¶Ô[Õ1˜Z嬒c~õã?27«­2¦VÉU ±p%5æWj®7]qEI-«6”i‘XZ¼Áä’¯jDÊ1ÝLm¦UÍäF¾J¸á[Ö¯Þ(UìUjT‡H™ÁðmÑ”o¤ÕÛŠ‘q'^o+F—ÕÿMOŒûŠ©ñЮOëÒäø/ºF¾h/ª|µÎZç¸õû¯ß?ë¬Å?N=Ð9.þäÚÈ7jƒ6â†êmU£_ß:·58K?–+–º(K_Ú~cz3_éׯvUŽýò$)ß²ÝüHŒc?žÌ”¡gîâض<ÏáØö‘ñ­Íê:aeû#ã:ad\'´Fãvãã>böøÔuá¨Ô7y|êë\–úã_n-× Ë&ö§©ñ,æÅѤ>ïë„1ÕuÂôr^Y®RÜGôÇÚŽíèL±UâbZŠÏZgÜAÄ6©ÅgŠë„xÓ¸Nè˜ÔY{¨\'Lg!­ÿöP¹N¸±\þŸ_'4®ÿûfÙÿâR0–nãë„H‹»±rAÐØçùÒ?ýSœ†ŽýR6º)ÿôO‘Z5õúêÉŸ¨×‘⺹ž0øY¹C©'ï_ŸRŽÑfêÉÓ›¹«#·j'ª| ;–+‚2— Ùú±e›ù"­ÑN .EÉWV¾qìW3j¦5ŽýªæÁ´jÝêÇþ°´Ác Q_©³aVš„jUZI,’ÑÕÇ«Ïj¼ž:˜^¥UGÐÆ× ë:FuœØqâÇFuŒ*1°™ë„qБRÄžõ(Ã~4;›\' ޔƣÈJ$ZÊA±ØÀÃÇF6ÆNŽ®ä6mpì§]1¬«fÔ¶gk?¡j+âo­ù¦õgGri+b¬}Öœ¹U¦Í}”¶âYò<‡¶b}ìì}iÜo—§‰ÿØž¦ÿÅìtZë¢4·µ?ݺïºÔ·z]úåŽëRÿ{Ö¥G/^–Öíqû²êZâŒı÷;ïÿ¬mÅòXIW?{úŠïì÷o©õêþ›W¥Ñß3ö¦ôòþÎÚØôÊ1ñÓ§k:k7í­Á´1u\]ë¼ö©Ž¸êÛg¿øì_5¶cŵ­7•Ïiñ9)ŽýR|®z(¾:M¶âêÚC1›Ï÷ž¢¹ÏUýjϬŸžâ³±×–Ä+ùô]©´rY8}à´Ò†Ä¾\ÏW](–ÔF[QÊViP²VÇÓ°´’ZêŽ{ŠæEæŽWLIWTY«£·:þKZ3ë`jIÛqJÉZoƒÇɵVËܼOH7Fæ’5j‰Ù5®¢Î¸Ùo,ó°ÔRÁPjuäV‹s*‹Q-ïðÔH«a°ÍŒ\Í´Á¶¢ºâ©çÞV ]ü·ÚŠ­â¼?ìžâ¨40û¬åg͸±ãïÒ·ÒGâµ\,ÏôãÛYÕ=Åز\q™›¾õÍ=SGëùíécë:RÇ.ñÅš§Ôñùˆ¨oRy_ÊvÍP=­·]±]«î¶]*¨ju—47aXÏÒÛ¢+ƒe¸ä(ƒõôl §ê44XOÉSnS¢+3‹‚ms[ÓN{—v¢|ÿ"¯ýÉõ‘íDùõCó›!e›t'Öæ–<Õ^7™XOØL;ñ Ÿ=Äãšx­ÌŒ4ò÷q¬ßßž&^:9Mkˆ×ui:aĘ´lü˜ôÞÎx9cn:­ëì´lDk:cј4mÑÔ4}Ѻ´s­?‹¶bd´µ¨+=s.óQm“]ë˱âêÎòǯ-­ÅCñ¹âÆ«ÆÄ‘ýPÇØ4úÆ«âè[=ÔQ[Õ±÷Uq!Ñ·wG­3õ½¼µ/¥É/¯ÅÓËÉ“VöÕ:ÇLꌩc&]»wJý£¯}}×1úš½ÓS­qɱ"¥«ÓS±a_>®\YŒ®žM6þìR-ÏøaÛºÈG»zég²¡Ô“ß^m¢Fz3ïÛO~ûÉÃÒ5Db9eÔ·i£êH}{¤FzãüYÍm0µ1¡´/¥Þ*ou6[˜F½%gã ­_ Ï[•ŠÍçSJ{ÒìÊ3òXÇÜës¨ÒË„fþæ†_? ηlµL.>e½bÍÕÔzËPtbB#Õ>”ý°@YÈFëROoÖÔHÝ ÕˆŠ†µ0ü¥ªfj•{0½šIY€²©KWÞô´Á}Gì^éô—}ÑdÄвô·ÕPŒ”|õ6e\YÂÒ•öŽˆ­¯†›i¯Œ´WK«ÊoWêón|^qÅàhÜU ŽTÃÕõCL–g0shî¦eð­o­ï‚ÍáfÙayJ‘Fm̉­iÂq¥Y2ïøÅyí¯¢E,mÌ‘óŽ?uñFõ.k6ØX»þÙòl¦Ùq£6æÌø›Å@i¢x2î?~Ÿ&ü<⬴ÿÓmû¯»·cÚKoéxÝÇI¯ÿÙÓU¼î³OÇß<ÖGžõ‘]”ë¯Ê—zRÔqý ¸<UŽ.(-/ýøÓkiæËÝÅŠiÑÞÕ«ªÉ+â˃%ÛÕÑl7¤k;ãÙÆ­|üáè_;æ•×þ6ÒWu>uÍÑ¿ùßV|¥Ñ/Ž^õ½ªâÖk÷®fÔú•§ê3ŒúËÍL5¿è ο¹<1¡$W˽ӦmQul ÛY«£¤l¿²7ºææ¬÷›©U¿žTŽ¬ J”iÕŽSMÙ D9læ—3Ù&%Jú’Ó7R¥/YR/3¬®FúéQ(j+SÊé­ªÿô8Þ8=>êSæGÝQ¤Gâé%S}JY–Ryu­ùËq[•©†«FÍÏ0¥Z¢f™ÓKmQýPWobÑN/+7”^š‡†AµÔ›N¾ êS‹r)³©uI«OÙ°TIœ2|R}B³LŒ5æßH2ÑmgÓ¸n‰¿Ãƽg|§+žülÝÏÖ­‹/)UÓêmUi¢ªŸÍ¹#¾{ãußy¨sEç¤ølœ1Kc‡íwa=4%K.MK.¸-¦6ºúØÑE©¤^P
+F?–:’«Z¢|u-÷<;_Tog–.Êwô¿&©jg–žº¨,Þ3uqÏó¶yóßè =äÞL;³ñßQª{žT=ߘ—Óþ+žþm:ãõýiý‹ÖmUO;ãEýéƒq³ÿľ4ñ³qô³Žhog}¦g£åh®ùÖ«žZ‡{Ú/ž®ˆo–ÄçòøŒfb¿ÏüyþàÔI%g”º:‚F{ÍL4¥«ê e^Ïéï(-ºÉ¾Y¥W©Ãvïú™±¤FâwËÎ]™)‘Z†¾ûÝê¯dõÃ¥¤–ÄH­’Ñ°Ô’<˜Ze-yKîFjýÞ¤ªáO•šž}nƒk1lškQ-pÃ!$Õ×W¨ÑúÔëˆÜÔºYóðm¤öJ½‘»Ê[©ÍìÍK”²¿o¹á5Ê@GGǃÿut¬ˆñr™]åvR”ÿnY¿i”ô›nªO/ùª²£‡Ú‚j×æ]Ju©X¥>¯¡XªèJ-Cÿ ¦5gR%´ÅW<Û?_µñûæüƒ-/Žäøí! — õB›û<±vî³åÙL;1~£ïdD;QëëKãÎêû—uiÚÈõiê+oH‹öß9-š>6õM‹˜>2ÅÕJ=Î_‰8clZ¶~lzÃÒþ}ÓÒÄx¾Zê9²3U_t)ó©ß÷ìV_øêRdôUñL;­ˆ¯³¥Ö«¢qê½<þÄÝ?ºcÌÀ-ý“"¡¶>>קõ11ªø\_¾eÝàç¤(1)•r“R ¯ŸÔ±">G~E{­t´ãúKó°g}.qØ¿?Š‹6,­ïÆmëjï‹ÏU]s¬Ù¯ËœS<çj&ÖóV©%ypBÉ\O­'7&lš\ŸÐÌ}r=wõY_aU—[ ú,šÙ¹Kž2ëÁä*}°äFé;©(0”¿ž·ú|.éQpøê ÍàÒ‡å/ËY¡Å̪äS•^ŸPÏ]O¯'WéÃ*i0Ô…Jzcù#wsË Ë]R›ÉÕ¼›ë9,µ±=«¬ƒyãffƒ¿Û¾4½¥ã¦ÎÎè˜qÙŒ›:Ï訾¼ZòÔÛš­K½£ÆÅ}P´#ËûûSG¼¤¨#îžÎ^>9-_Þ{gg×ÕU½ÃÚ˜Ûn;;«¥‰5©/nY§rÛ[©šV›«Y Õ×:¶aq,ùêH1T±D¡yÑ”FW¾ãµKoiOʯoó÷Oút$ÆuÇ3þ†·*]|ÇëÙòl¦=‰o2¸«ÇkL ?‘ÒÈUqÌÕ:Ò„–Îôª–¾Ô—=kvê‰{Ë®ñ·Ùx‰~_ÇÔôèAñŽ ãûí£Ò²YãÓí‹Ò´È¿óÈø»ìĸöˆû›ê;^e>´'ñG•¸øJ¹aÔ_žw}%íHñH·¶<æœjW¥þZùëlgmZz(]»|5£ãÚ­Òžåo´­ñ×ÙÖ¾(pumrë9W·öííŒkÃÎIûÄßlÊ“•éqTÞöÏT¦/¿ÎÆŸoâ™J|Í#šÌ‡"!îºâ›g›¶'eç¼û¬Ÿóª³ÛÀ@óëCgÂ8ÑŒHñ5Êj‡¬ò–;†HŠÿâB¡$—ÔH«’†’#µÊ÷¹zÞ껜‘·‘ïsiDüÅ"&•‹ò$®Êõ¹ñÇ›F‘#FÄÎôoÃk.Ÿ)9Ú«z£Žzå/1U1©ü(†£æ’Zã©ÉàÄúÓÕ’\N|#RUE¬JõÔ¶™w°ŠúóÙH®êhTRºRÕu4ë©Õ ËSš’—hE'V±™+«R«Ì“«K¹†dä®×\d}K%±uª´aÛ"Ê O+ØFmÄ@êè<§ãßÓ—uœß¼Ù¨(׬ñåÁÔ1®3},öíïHçÄ÷›::#â¿êf¹”ÖFÔ/®¸bJýûy±³}v9…•þÙ‘vöÙñÿÇËÔ?ûãñü$¦–úPŠxW/Q 5¯9ª6"ßšv=»úõç1í‡Ç×øO©ªn|tDÿçõ#º%®74eJ¤pÔî»o#ËÿD/ê®–£sæI‹ãå%í›ü“ ‘!–£\Fý)»–˜Ï¤he.8gZ¾ãú›¿Å‹ßÕülãßãŲ,mM»½¬ü¢s\Š7ª¿é\¸ùuœ.:ø̳98My{ôÞž¦üÕ™Sþ*ž ÖGÞvæÜ·•‘¹o&’þªd+#Í ç#ñ{Ï£ã=3bžsê¿"uâÂó6;ÖíÓE‡Ÿ9þðxóÊ™ãß?==3Þ†•þ‡RÎûŸªhÓzþ„UW~±ë, ¿â·u:òø“^qÂI›L‡§‹N8sçR:åÌã€Øtxþ™Óæ§çœ¹óœ8[ž¹ó‰)=Ópý׿ïiM»¿®ÌwlzÛœ“çµÇ}ÿf(ý†tÑñg.‹KýãÎ\v\JÕð9³ŸKRcIGÄœŽ}æßi½qÎâ¥'Î?iÁÉ釽ù•§.™·xØOʱµá¯¶¢Mª~ý‘qX´.Ž½~nÔa³þ›Î<«å¦3—·”&%Ê–ßµûQíñ“¤ùsã-©YÿŒxGÐü¹ñ±½ç,]º÷F?ÛpŽ½1«b74çõVÝÐ<Ê/ JÍï›×œ¶¤ý¸ÃSõñþöøåÔ~1|СG6SYv=úÈ7qèÌzå»îµ_UR3W,âÜ*߬Ž<òmo9¢äŒZßß>kÖ¬j>.g[GÕVÔ>ûìmE”Ž¶b}ÊÓªªk´¤m­ñ›¾x ]íŠF“ºÇ;ƒù5ƒéQ0÷Þ·I©£JK1½vÅ%e<¥=âßf(Óöˆk+â7Å_Þ=†ßYÒRѲïqrùuXüY½ýø}6lÝ£‚ÿ­–½/ÞÐõµh!讀¹ù7YŒª~Ù=ü—‘ÕUu,fýÍbå7¨yk[OñËÇÖÚŒ¿¼µü*{«è‡bë¸èÇ/#[_ý¶ÿ½Ÿ´ÇÒ„óž/:ôˆö¥ Ûç´Ï:蕇ÌY0÷ÄyóçƤêß‘Š?*öé?ñ™+ö›[Òž?*<Ñ|µµ\±*â{áòÂèÿ¨üέüÖ£|—»|G3¯ÝgZù¾VùFùkùHy>Yž=”û…Üó†sïâé·Ÿ[ÞÉ“ð›ùŽÞØ+ïžYÞ™S½Ç¦­e¨ûŸòíÿ¹"ß~À%ùöo¶æï>ïœyëò|óvûæ›þí°|ë gýÏÿ*õ¹ý²>–í ¹ó9¥±§îùt´[Ñœ»é3ï©_Ýk {Øox㸮wåMGѺ½?=Zo2Êbë‹fÄƉþÄè—=õ¥Ñ/{êÑ/{òË£¿ám}eôã7¼­ûD¿¼yàµÑw®´¾>ú[þŸïѱÖš^6÷™ÛÕXóxÖœ^ÚlµÓP·aÛW"ifÔuþ3×5ëÈC£º¡
+bhÓ:GW=sG/8iY³†÷·/|÷I 6lÇ«ÖùšíªÜ¦sŒ·•¼ìgdŽGo´Ð›ÖpHÔðô3×ð¶“Ì]øþ%íGpdsÑK£zÊÉ´%M:ãÈ?ú¶‹xŸã–)5Þïó»Fu[5«Ýä …­Õ¯ÇcŸjùûúo÷cß9èÿ|¿ùÓÔÐñ·W‘Þpûô?Míj%@€ @€ @€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€¿™L»×çØ´YÅ B —òámÅ˼û¼'·¶¾7ÖÚ¯¯ÕïÉ­­#p4Ö3ÑŠ×úoåFÜ‘žF`ÜßÁ¸Nóâi”d|®eÔX½Q O‘Þ#÷z6øE'-ŸV¼lm™·œ•¹¯ùZÞÚõW¥iêɯË8ÏÚ;«NFOŸ¬ÑëЛÿNo±×å#òßÙók[óøë<Î~  @€ @€ @€@€€UIAppShellÀ‚" ðr \ No newline at end of file
diff --git a/xmerge/source/palmtests/qa/test_spec/convertor_test_spec.html b/xmerge/source/palmtests/qa/test_spec/convertor_test_spec.html
new file mode 100644
index 000000000000..5b77f3263654
--- /dev/null
+++ b/xmerge/source/palmtests/qa/test_spec/convertor_test_spec.html
@@ -0,0 +1,2274 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
+<HTML>
+<HEAD>
+ <META HTTP-EQUIV="CONTENT-TYPE" CONTENT="text/html; charset=iso-8859-1">
+ <TITLE></TITLE>
+ <META NAME="GENERATOR" CONTENT="StarOffice 6.0 (Solaris Sparc)">
+ <META NAME="AUTHOR" CONTENT="dermot mccluskey">
+ <META NAME="CREATED" CONTENT="20011001;14124200">
+ <META NAME="CHANGED" CONTENT="20020103;15592900">
+ <STYLE>
+ <!--
+ P.text-body-indent { margin-left: 0.5cm }
+ -->
+ </STYLE>
+</HEAD>
+<BODY>
+<H1 ALIGN=CENTER>Xmerge Test Spec</H1>
+<H2>1.0 Intorduction</H2>
+<BLOCKQUOTE>This document outlines the tests to be performed on
+Xmerge, the XML-to-PDB converter for the SunONE Webtop.</BLOCKQUOTE>
+<H2>1.1 Authors</H2>
+<UL>
+ <LI><P STYLE="margin-bottom: 0cm">Dermot McCluskey
+ (dermot.mccluskey@sun.com)
+ </P>
+ <LI><P>Keelin Boyle (keelin.boyle@sun.com)
+ </P>
+</UL>
+<H2>1.2 Project/Product Identifier</H2>
+<BLOCKQUOTE>XMerge</BLOCKQUOTE>
+<H2>1.3 Reision History</H2>
+<P STYLE="margin-bottom: 0cm">&nbsp;
+</P>
+<TABLE COLS=4 WIDTH=100% BORDER=1 CELLPADDING=2 CELLSPACING=0>
+ <TR>
+ <TD>
+ <P><B>Date</B></P>
+ </TD>
+ <TD>
+ <P><B>Revision</B></P>
+ </TD>
+ <TD>
+ <P><B>Comments</B></P>
+ </TD>
+ <TD>
+ <P><B>Approval</B></P>
+ </TD>
+ </TR>
+ <TR>
+ <TD>
+ <P>28-Sep-2001</P>
+ </TD>
+ <TD>
+ <P>0.3</P>
+ </TD>
+ <TD>
+ <P>Draft 3.</P>
+ </TD>
+ <TD></TD>
+ </TR>
+ <TR>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ </TR>
+</TABLE>
+<H2>1.4 Document Customers</H2>
+<UL>
+ <LI><P STYLE="margin-bottom: 0cm">XMerge Development team
+ </P>
+ <LI><P STYLE="margin-bottom: 0cm">Ireland Desktop Test team
+ </P>
+ <LI><P>SunONE Webtop C-team
+ </P>
+</UL>
+<H2>1.5 References</H2>
+<H2>2.0 Requirements &amp; Dependencies</H2>
+<BLOCKQUOTE>Successful automation of the tests outlined in this
+specification is dependent on the stability and reliability of the
+POSE emulator and the EmRPC Perl module that allows test
+automation.&nbsp;&nbsp; There is a risk associated with this in that
+the emulator software may not accurately emulate every aspect of the
+PalmOS and so the automated tests may not discover bugs which occur
+in &quot;real world&quot; scenarios.&nbsp; Also, if the automation
+software we use proves not to be reliable enough to consistently
+return the same test results, then the effort spent creating the test
+automation scripts will not be worthwhile.
+</BLOCKQUOTE>
+<BLOCKQUOTE>Verification of test results will depend on the usability
+of the Java-based Comparator applications, developed by the US&nbsp;Webtop
+QA&nbsp;team, which will be used to compare the output XML and
+PDB&nbsp;files with the expected results.
+</BLOCKQUOTE>
+<BLOCKQUOTE>Many of the tests described in this specification are
+very time consuming and it would not be practical to execute them
+manually on a regular basis.</BLOCKQUOTE>
+<H2>2.1Required Tools &amp; Technologies</H2>
+<UL>
+ <LI><P STYLE="margin-bottom: 0cm">PalmOS Emulator (POSE)
+ </P>
+ <LI><P STYLE="margin-bottom: 0cm">EmRPC Perl module and Test Driver
+ harness
+ </P>
+ <LI><P STYLE="margin-bottom: 0cm">Comparator applications (XML and
+ PDB&nbsp;comparison utilities)
+ </P>
+ <LI><P STYLE="margin-bottom: 0cm">Palm V device ???
+ </P>
+ <LI><P>StarOffice 6.X.
+ </P>
+</UL>
+<H2>2.2 Test Framework Used</H2>
+<BLOCKQUOTE>These tests are to be automated using the POSE emulator
+and the Test Driver developed by the XMerge team, which interacts
+with the EmRPC module and allows test engineers to write test scripts
+to control the conversion of documents and the interaction with the
+POSE emulator.&nbsp; Using this software, it is possible to automate
+the process of loading documents into the appropriate Palm
+application, apply edits to the document within the Palm emulator and
+export the document.</BLOCKQUOTE>
+<H2>3.0 Scope of Work</H2>
+<H2>4.0 Test Strategy</H2>
+<H2>4.1Test Suite Location</H2>
+<H2>4.2 Strategy overview</H2>
+<H2>4.3 Test Cases and Assertions</H2>
+<H2>4.4 Testing Not Performed</H2>
+<UL>
+ <LI><P STYLE="margin-bottom: 0cm">Performance Testing
+ </P>
+ <LI><P>Internationalization (I18N) related testing.
+ </P>
+</UL>
+<H2>5.0 Test Cases</H2>
+<BLOCKQUOTE>The test cases are divided into seperate sections for
+each PDB format supported by XMerge, and further divided into
+Convert and Merge tests within each format.&nbsp; The Convert tests
+validate that XMerge can perform the round trip conversion from
+StarOffice XML-based file format to PalmOS PDB format and back to
+StarOffice XML format again, without any loss of content.&nbsp; The
+Merge tests validate that XMerge can merge edits made on the Palm
+device with the original StarOffice XML file, while retaining any
+information in the original document which could not to translated
+into PDB format, eg embedded tables.
+</BLOCKQUOTE>
+<BLOCKQUOTE>Each section is further divided into Content and Style
+tests.&nbsp; The Content tests deal with the ability of XMerge to
+retain all the meaningful content, eg text, after the conversion and
+merging process.&nbsp; The Style tests deal with the ability of
+XMerge to retain the stylistic details, eg bold face; justification;
+line breaks, from the same round-trip conversion.&nbsp; The
+Content-retaining functionality is considered of much higher priority
+than the Style-retaining functionality in version 1.1. <BR>&nbsp;</BLOCKQUOTE>
+<H2>5.1 AportisDoc Tests</H2>
+<H2>5.1.1 AportisDoc Convert Tests</H2>
+<H2>5.1.1.1 AportisDoc Convert Content Tests</H2>
+<TABLE WIDTH=100% BORDER=1 CELLPADDING=2 CELLSPACING=0>
+ <TR VALIGN=TOP>
+ <TD WIDTH=30%>
+ <P><BR>
+ </P>
+ </TD>
+ <TD>
+ <P><BR>
+ </P>
+ </TD>
+ </TR>
+ <TR VALIGN=TOP>
+ <TD>
+ <P><BR>
+ </P>
+ </TD>
+ <TD>
+ <P><BR>
+ </P>
+ </TD>
+ </TR>
+</TABLE>
+<H2>5.1.1.2 AportisDoc Convert Style Tests</H2>
+<P><BR>&nbsp;
+</P>
+<H2>5.1.2 Aportis Merge Tests</H2>
+<H2>5.1.2.1 AportisDoc Merge Content Tests</H2>
+<TABLE WIDTH=100% BORDER=1 CELLPADDING=2 CELLSPACING=0>
+ <COL WIDTH=77*>
+ <COL WIDTH=179*>
+ <TR VALIGN=TOP>
+ <TD WIDTH=30%>
+ <P><BR>
+ </P>
+ </TD>
+ <TD WIDTH=70%>
+ <P><BR>
+ </P>
+ </TD>
+ </TR>
+ <TR VALIGN=TOP>
+ <TD WIDTH=30%>
+ <P><BR>
+ </P>
+ </TD>
+ <TD WIDTH=70%>
+ <P><BR>
+ </P>
+ </TD>
+ </TR>
+ <TR VALIGN=TOP>
+ <TD WIDTH=30%>
+ <P><BR>
+ </P>
+ </TD>
+ <TD WIDTH=70%>
+ <P><BR>
+ </P>
+ </TD>
+ </TR>
+</TABLE>
+<H2>5.1.2.2 AportisDoc Merge Style Tests</H2>
+<TABLE WIDTH=100% BORDER=1 CELLPADDING=2 CELLSPACING=0>
+ <COL WIDTH=72*>
+ <COL WIDTH=184*>
+ <TR VALIGN=TOP>
+ <TD WIDTH=28%>
+ <P><B>aportis/merge/style/animatedgif</B></P>
+ </TD>
+ <TD WIDTH=72%>
+ <P><B>Summary</B>: document with an embedded image &#8211;
+ straight forward convert and merge</P>
+ <P><B>Procedure:</B> <BR>Use test file <B>a_animatedgif.sxw</B>.
+ </P>
+ <P>Convert a_animatedgif.sxw to a_animatedgif.pdb, in AportisDoc
+ PDB format. <BR>Start POSE with AportisDoc application and import
+ a_animatedgif.pdb. <BR>Export the doc back to a_animatedgif.pdb.
+ <BR>Merge a_animatedgif.pdb and the original document to
+ a_animatedgif.sxw.
+ </P>
+ <P><B>Expected result:</B> <BR>The resultant document should
+ contain:
+ </P>
+ <BLOCKQUOTE>This document has a animated gif embedded in it.</BLOCKQUOTE>
+ <BLOCKQUOTE>Start of animated gif.</BLOCKQUOTE>
+ <BLOCKQUOTE>&lt;Image of spinning globe&gt;</BLOCKQUOTE>
+ <BLOCKQUOTE>End of animated gif.
+ </BLOCKQUOTE>
+ </TD>
+ </TR>
+ <TR VALIGN=TOP>
+ <TD WIDTH=28%>
+ <P><B>aportis/content/style/bolddoc</B></P>
+ </TD>
+ <TD WIDTH=72%>
+ <P><B>Summary</B>: document with bold type and varying font &#8211;
+ straight forward convert</P>
+ <P><B>Procedure:</B> <BR>Use test file <B>a_bolddoc.sxw</B>.
+ </P>
+ <P>Convert a_bolddoc.sxw to a_bolddoc.pdb, in AportisDoc PDB
+ format. <BR>Start POSE with AportisDoc application and import
+ a_bolddoc.pdb. <BR>Export the doc back to a_bolddoc.pdb. <BR>Merge
+ a_bolddoc.pdb and the original document to a_bolddoc.sxw.
+ </P>
+ <P><B>Expected result:</B> <BR>The resultant document should
+ contain:
+ </P>
+ <BLOCKQUOTE><STRONG>This complete line is in <FONT SIZE=6 STYLE="font-size: 22pt">bold</FONT>
+ with font set to Times New Roman. The word bold is of size 22,
+ while rest of the words are of size 12. </STRONG>
+ </BLOCKQUOTE>
+ </TD>
+ </TR>
+ <TR VALIGN=TOP>
+ <TD WIDTH=28%>
+ <P><B>aportis/merge/style/bookmarks</B></P>
+ </TD>
+ <TD WIDTH=72%>
+ <P><B>Summary</B>: document with inserted bookmarks &#8211;
+ straight forward convert</P>
+ <P><B>Procedure:</B> <BR>Use test file <B>a_bookmarks.sxw</B>.
+ </P>
+ <P>Convert a_bookmarks.sxw to a_bookmarks.pdb, in AportisDoc PDB
+ format. <BR>Start POSE with AportisDoc application and import
+ a_bookmarks.pdb. <BR>Export the doc back to a_bookmarks.pdb.
+ <BR>Merge a_bookmarks.pdb and the original document to
+ a_bookmarks.sxw.
+ </P>
+ <P><B>Expected result:</B> <BR>The resultant document should
+ contain:
+ </P>
+ <BLOCKQUOTE>Two paragraphes of text with 2 bookmarks set. To
+ identify bookmarks, select Edit -&gt; Navigator and bookmarks,
+ user should see BK1 and BK2 and clicking on these labels in the
+ navigator popup places the cursor in the position of the original
+ bookmark, .i.e.
+ </BLOCKQUOTE>
+ <BLOCKQUOTE>BK1 = Bookmark|</BLOCKQUOTE>
+ <BLOCKQUOTE>BK2 = Silicon
+ </BLOCKQUOTE>
+ </TD>
+ </TR>
+ <TR VALIGN=TOP>
+ <TD WIDTH=28%>
+ <P><B>aportis/merge/style/bulletorderedlist</B></P>
+ </TD>
+ <TD WIDTH=72%>
+ <P><B>Summary</B>: document with bulletorderedlist &#8211;
+ straight forward convert</P>
+ <P><B>Procedure:</B> <BR>Use test file <B>a_bulletorderedlist.sxw</B>.
+ </P>
+ <P>Convert a_bulletorderedlist.sxw to a_bulletorderedlist.pdb, in
+ AportisDoc PDB format. <BR>Start POSE with AportisDoc application
+ and import a_bulletorderedlist.pdb. <BR>Export the doc back to
+ a_bulletorderedlist.pdb. <BR>Merge a_bulletorderedlist.pdb and the
+ original document to a_bulletorderedlist.sxw.
+ </P>
+ <P><B>Expected result:</B> <BR>The resultant document should
+ contain:
+ </P>
+ <P STYLE="margin-bottom: 0cm; font-style: normal">This document is
+ an example of a simple bullet ordered list.</P>
+ <P STYLE="margin-bottom: 0cm"><BR>
+ </P>
+ <UL>
+ <LI><P STYLE="margin-bottom: 0cm; font-style: normal">Bullet 1</P>
+ <LI><P STYLE="margin-bottom: 0cm; font-style: normal">Bullet 2</P>
+ <LI><P STYLE="margin-bottom: 0cm; font-style: normal">Bullet 3</P>
+ <LI><P STYLE="margin-bottom: 0cm; font-style: normal">Bullet 4</P>
+ </UL>
+ <P STYLE="margin-bottom: 0cm"><BR>
+ </P>
+ <BLOCKQUOTE STYLE="font-style: normal">End of bullet Ordered list.</BLOCKQUOTE>
+ <BLOCKQUOTE><BR>
+ </BLOCKQUOTE>
+ </TD>
+ </TR>
+ <TR VALIGN=TOP>
+ <TD WIDTH=28%>
+ <P><B>aportis/content/style/emptydoc</B></P>
+ </TD>
+ <TD WIDTH=72%>
+ <P><B>Summary</B>: empty document &#8211; straight forward convert</P>
+ <P><B>Procedure:</B> <BR>Use test file <B>a_emptydoc.sxw</B>.
+ </P>
+ <P>Convert a_emptydoc.sxw to a_emptydoc.pdb, in AportisDoc PDB
+ format. <BR>Start POSE with AportisDoc application and import
+ a_emptydoc.pdb. <BR>Export the doc back to a_emptydoc.pdb. <BR>Merge
+ a_emptydoc.pdb and the original document to a_emptydoc.sxw.
+ </P>
+ <P><B>Expected result:</B> <BR>The resultant document should
+ contain:
+ </P>
+ <BLOCKQUOTE><STRONG>&lt;empty document&gt;. </STRONG>
+ </BLOCKQUOTE>
+ </TD>
+ </TR>
+ <TR VALIGN=TOP>
+ <TD WIDTH=28%>
+ <P><B>aportis/merge/style/firstlineindent</B></P>
+ </TD>
+ <TD WIDTH=72%>
+ <P><B>Summary</B>: document with line indent &#8211; straight
+ forward convert</P>
+ <P><B>Procedure:</B> <BR>Use test file <B>a_firstlineindent.sxw</B>.
+ </P>
+ <P>Convert a_firstlineindent.sxw to a_firstlineindent.pdb, in
+ AportisDoc PDB format. <BR>Start POSE with AportisDoc application
+ and import a_firstlineindent.pdb. <BR>Export the doc back to
+ a_firstlineindent.pdb. <BR>Merge a_firstlineindent.pdb and the
+ original document to a_firstlineindent.sxw.
+ </P>
+ <P><B>Expected result:</B> <BR>The resultant document should
+ contain:
+ </P>
+ <BLOCKQUOTE>This line is using First Line indent style. Now isnt
+ that Kool... Also Im running short of words to say here, to wrap
+ this particular sentence.</BLOCKQUOTE>
+ </TD>
+ </TR>
+ <TR VALIGN=TOP>
+ <TD WIDTH=28%>
+ <P><B>aportis/content/style/fontsize</B></P>
+ </TD>
+ <TD WIDTH=72%>
+ <P><B>Summary</B>: document with varying font size &#8211;
+ straight forward convert</P>
+ <P><B>Procedure:</B> <BR>Use test file <B>a_fontsize.sxw</B>.
+ </P>
+ <P>Convert a_fontsize.sxw to a_fontsize.pdb, in AportisDoc PDB
+ format. <BR>Start POSE with AportisDoc application and import
+ a_fontsize.pdb. <BR>Export the doc back to a_fontsize.pdb. <BR>Merge
+ a_fontsize.pdb and the original document to a_fontsize.sxw.
+ </P>
+ <P><B>Expected result:</B> <BR>The resultant document should
+ contain:
+ </P>
+ <BLOCKQUOTE>Text with font size 10, 16, 20, 40, 96.</BLOCKQUOTE>
+ </TD>
+ </TR>
+ <TR VALIGN=TOP>
+ <TD WIDTH=28%>
+ <P><B>aportis/content/style/heading</B></P>
+ </TD>
+ <TD WIDTH=72%>
+ <P><B>Summary</B>: document with heading type style &#8211;
+ straight forward convert</P>
+ <P><B>Procedure:</B> <BR>Use test file <B>a_heading.sxw</B>.
+ </P>
+ <P>Convert a_heading.sxw to a_heading.pdb, in AportisDoc PDB
+ format. <BR>Start POSE with AportisDoc application and import
+ a_heading.pdb. <BR>Export the doc back to a_heading.pdb. <BR>Merge
+ a_heading.pdb and the original document to a_heading.sxw.
+ </P>
+ <P><B>Expected result:</B> <BR>The resultant document should
+ contain:
+ </P>
+ <P STYLE="margin-top: 0.42cm; page-break-after: avoid"><FONT FACE="Times New Roman, serif"><FONT SIZE=4>This
+ piece of text is in Heading paragraph style.</FONT></FONT></P>
+ </TD>
+ </TR>
+ <TR VALIGN=TOP>
+ <TD WIDTH=28%>
+ <P><B>aportis/content/style/heading1</B></P>
+ </TD>
+ <TD WIDTH=72%>
+ <P><B>Summary</B>: document with heading1 type style &#8211;
+ straight forward convert</P>
+ <P><B>Procedure:</B> <BR>Use test file <B>a_heading1.sxw</B>.
+ </P>
+ <P>Convert a_heading1.sxw to a_heading1.pdb, in AportisDoc PDB
+ format. <BR>Start POSE with AportisDoc application and import
+ a_heading1.pdb. <BR>Export the doc back to a_heading1.pdb. <BR>Merge
+ a_heading1.pdb and the original document to a_heading1.sxw.
+ </P>
+ <P><B>Expected result:</B> <BR>The resultant document should
+ contain:
+ </P>
+ <H1 STYLE="font-weight: medium">This piece of text is in Heading1
+ paragraph style</H1>
+ </TD>
+ </TR>
+ <TR VALIGN=TOP>
+ <TD WIDTH=28%>
+ <P><B>aportis/content/style/heading2</B></P>
+ </TD>
+ <TD WIDTH=72%>
+ <P><B>Summary</B>: document with heading2 type style &#8211;
+ straight forward convert</P>
+ <P><B>Procedure:</B> <BR>Use test file <B>a_heading2.sxw</B>.
+ </P>
+ <P>Convert a_heading2.sxw to a_heading2.pdb, in AportisDoc PDB
+ format. <BR>Start POSE with AportisDoc application and import
+ a_heading2.pdb. <BR>Export the doc back to a_heading2.pdb. <BR>Merge
+ a_heading2.pdb and the original document to a_heading2.sxw.
+ </P>
+ <P><B>Expected result:</B> <BR>The resultant document should
+ contain:
+ </P>
+ <H2>This document is set in Heading2 style.</H2>
+ </TD>
+ </TR>
+ <TR VALIGN=TOP>
+ <TD WIDTH=28%>
+ <P><B>aportis/content/style/hyperlink</B></P>
+ </TD>
+ <TD WIDTH=72%>
+ <P><B>Summary</B>: document with embedded hyperlink &#8211;
+ straight forward convert</P>
+ <P><B>Procedure:</B> <BR>Use test file <B>a_hyperlink.sxw</B>.
+ </P>
+ <P>Convert a_hyperlink.sxw to a_hyperlink.pdb, in AportisDoc PDB
+ format. <BR>Start POSE with AportisDoc application and import
+ a_hyperlink.pdb. <BR>Export the doc back to a_hyperlink.pdb.
+ <BR>Merge a_hyperlink.pdb and the original document to
+ a_hyperlink.sxw.
+ </P>
+ <P><B>Expected result:</B> <BR>The resultant document should
+ contain:
+ </P>
+ <P STYLE="margin-bottom: 0cm">This line is bookmarked to BK1
+ (Insert-Bookmark)</P>
+ <P STYLE="margin-bottom: 0cm"><BR>
+ </P>
+ <P STYLE="margin-bottom: 0cm">The line <A HREF="http://sunweb.central/allhome.html">SunWeb
+ Home Page</A> has a hyperlink to sunweb.central.</P>
+ <P STYLE="margin-bottom: 0cm"><BR>
+ </P>
+ <P STYLE="margin-bottom: 0cm">This line is a hyperlink to <A HREF="#BK1">BK1</A>.
+ Click here will take cursor to top of page.</P>
+ <P STYLE="margin-bottom: 0cm"><BR>
+ </P>
+ <P>&lt;Check hyperlink has the correct address.&gt;</P>
+ </TD>
+ </TR>
+ <TR VALIGN=TOP>
+ <TD WIDTH=28%>
+ <P><B>aportis/content/style/justified</B></P>
+ </TD>
+ <TD WIDTH=72%>
+ <P><B>Summary</B>: document with justified styling &#8211;
+ straight forward convert</P>
+ <P><B>Procedure:</B> <BR>Use test file <B>a_justified.sxw</B>.
+ </P>
+ <P>Convert a_justified.sxw to a_justified.pdb, in AportisDoc PDB
+ format. <BR>Start POSE with AportisDoc application and import
+ a_justified.pdb. <BR>Export the doc back to a_justified.pdb.
+ <BR>Merge a_justified.pdb and the original document to
+ a_justified.sxw.
+ </P>
+ <P><B>Expected result:</B> <BR>The resultant document should
+ contain:
+ </P>
+ <P STYLE="margin-bottom: 0cm; font-style: normal"><SUP><FONT SIZE=5 STYLE="font-size: 20pt">Left
+ aligned text</FONT></SUP></P>
+ <P ALIGN=CENTER STYLE="margin-bottom: 0cm; font-style: normal"><SUP><FONT SIZE=5 STYLE="font-size: 20pt">Centre
+ aligned</FONT></SUP></P>
+ <P ALIGN=RIGHT STYLE="margin-bottom: 0cm; font-style: normal"><SUP><FONT SIZE=5 STYLE="font-size: 20pt">Right
+ aligned </FONT></SUP>
+ </P>
+ <P ALIGN=JUSTIFY STYLE="font-style: normal"><SUP><FONT SIZE=5 STYLE="font-size: 20pt">Justified</FONT></SUP></P>
+ </TD>
+ </TR>
+ <TR VALIGN=TOP>
+ <TD WIDTH=28%>
+ <P><B>aportis/merge/style/linebreaks</B></P>
+ </TD>
+ <TD WIDTH=72%>
+ <P><B>Summary</B>: document with linebreaks &#8211; straight
+ forward convert</P>
+ <P><B>Procedure:</B> <BR>Use test file <B>a_linebreaks.sxw</B>.
+ </P>
+ <P>Convert a_linebreaks.sxw to a_linebreaks.pdb, in AportisDoc PDB
+ format. <BR>Start POSE with AportisDoc application and import
+ a_linebreaks.pdb. <BR>Export the doc back to a_linebreaks.pdb.
+ <BR>Merge a_linebreaks.pdb and the original document to
+ a_linebreaks.sxw.
+ </P>
+ <P><B>Expected result:</B> <BR>The resultant document should
+ contain:
+ </P>
+ <P STYLE="margin-bottom: 0cm">This page has a line breaks inserted
+ at end of this line.<BR>When coverted to doc format it should
+ accordingly be broken up at the same point.</P>
+ <P ALIGN=LEFT STYLE="text-indent: 0.2cm; margin-top: 0.4cm; margin-bottom: 0.41cm">
+ A simple list</P>
+ <OL>
+ <LI><P ALIGN=LEFT>second entry. A line break follows<BR>the above
+ line has been broken with a line break</P>
+ </OL>
+ <P STYLE="font-style: normal"><SUP><FONT SIZE=5 STYLE="font-size: 20pt">Third
+ entry</FONT></SUP></P>
+ </TD>
+ </TR>
+ <TR VALIGN=TOP>
+ <TD WIDTH=28%>
+ <P><B>aportis/merge/style/linespacing</B></P>
+ </TD>
+ <TD WIDTH=72%>
+ <P><B>Summary</B>: document with varied linespacing &#8211;
+ straight forward convert</P>
+ <P><B>Procedure:</B> <BR>Use test file <B>a_linespacing.sxw</B>.
+ </P>
+ <P>Convert a_linespacing.sxw to a_linespacing.pdb, in AportisDoc
+ PDB format. <BR>Start POSE with AportisDoc application and import
+ a_linespacing.pdb. <BR>Export the doc back to a_linespacing.pdb.
+ <BR>Merge a_linespacing.pdb and the original document to
+ a_linespacing.sxw.
+ </P>
+ <P><B>Expected result:</B> <BR>The resultant document should
+ contain:
+ </P>
+ <P STYLE="margin-bottom: 0cm"><I>First: This line and thenext line
+ is spaced by double-line spacing</I></P>
+ <P STYLE="margin-bottom: 0cm"><I>Second: Note the line-distance
+ spacing</I></P>
+ <P STYLE="margin-bottom: 0cm"><BR>
+ </P>
+ <P STYLE="margin-bottom: 0cm"><BR>
+ </P>
+ <P STYLE="margin-bottom: 0cm"><B>First: This line and the next
+ line is spaced by single-line spacing</B></P>
+ <P STYLE="margin-bottom: 0cm"><B>Second: Note the line-distance
+ spacing</B></P>
+ <P STYLE="margin-bottom: 0cm"><BR>
+ </P>
+ <P STYLE="margin-bottom: 0cm; font-weight: medium">First: This
+ line and the next line is spaced by 1.5 line spacing</P>
+ <P STYLE="font-weight: medium">Second: Not the line-distance
+ spacing.</P>
+ </TD>
+ </TR>
+ <TR VALIGN=TOP>
+ <TD WIDTH=28%>
+ <P><B>aportis/merge/style/numberorderedlist</B></P>
+ </TD>
+ <TD WIDTH=72%>
+ <P><B>Summary</B>: document with numberorderedlist &#8211;
+ straight forward convert</P>
+ <P><B>Procedure:</B> <BR>Use test file <B>a_numberorderedlist.sxw</B>.
+ </P>
+ <P>Convert a_numberorderedlist.sxw to a_numberorderedlist.pdb, in
+ AportisDoc PDB format. <BR>Start POSE with AportisDoc application
+ and import a_numberorderedlist.pdb. <BR>Export the doc back to
+ a_numberorderedlist.pdb. <BR>Merge a_numberorderedlist.pdb and the
+ original document to a_numberorderedlist.sxw.
+ </P>
+ <P><B>Expected result:</B> <BR>The resultant document should
+ contain:
+ </P>
+ <P STYLE="margin-bottom: 0cm; font-style: normal">This document is
+ an example of a simple numbered ordered list.</P>
+ <P STYLE="margin-bottom: 0cm"><BR>
+ </P>
+ <OL>
+ <LI><P STYLE="margin-bottom: 0cm; font-style: normal">First</P>
+ <LI><P STYLE="margin-bottom: 0cm; font-style: normal">Second</P>
+ <LI><P STYLE="margin-bottom: 0cm; font-style: normal">Third</P>
+ <LI><P STYLE="margin-bottom: 0cm; font-style: normal">Fourth</P>
+ </OL>
+ <P STYLE="margin-bottom: 0cm"><BR>
+ </P>
+ <P STYLE="margin-bottom: 0cm"><BR>
+ </P>
+ <P STYLE="margin-bottom: 0cm; font-style: normal">End of numbered
+ Ordered list</P>
+ <BLOCKQUOTE><BR>
+ </BLOCKQUOTE>
+ </TD>
+ </TR>
+ <TR VALIGN=TOP>
+ <TD WIDTH=28%>
+ <P><B>aportis/content/style/pagebreak</B></P>
+ </TD>
+ <TD WIDTH=72%>
+ <P><B>Summary</B>: document with pagebreaks &#8211; straight
+ forward convert</P>
+ <P><B>Procedure:</B> <BR>Use test file <B>a_pagebreak.sxw</B>.
+ </P>
+ <P>Convert a_pagebreak.sxw to a_pagebreak.pdb, in AportisDoc PDB
+ format. <BR>Start POSE with AportisDoc application and import
+ a_pagebreak.pdb. <BR>Export the doc back to a_pagebreak.pdb.
+ <BR>Merge a_pagebreak.pdb and the original document to
+ a_pagebreak.sxw.
+ </P>
+ <P><B>Expected result:</B> <BR>The resultant document should
+ contain:
+ </P>
+ <P STYLE="margin-bottom: 0cm">The document has page breaks</P>
+ <P STYLE="margin-bottom: 0cm">Page 1
+ </P>
+ <P>-now a page break-</P>
+ </TD>
+ </TR>
+ <TR VALIGN=TOP>
+ <TD WIDTH=28%>
+ <P><B>aportis/merge/style/paragraph</B></P>
+ </TD>
+ <TD WIDTH=72%>
+ <P><B>Summary</B>: document with set paragraph styling&#8211;
+ straight forward convert</P>
+ <P><B>Procedure:</B> <BR>Use test file <B>a_paragraph.sxw</B>.
+ </P>
+ <P>Convert a_paragraph.sxw to a_paragraph.pdb, in AportisDoc PDB
+ format. <BR>Start POSE with AportisDoc application and import
+ a_paragraph.pdb. <BR>Export the doc back to a_paragraph.pdb.
+ <BR>Merge a_paragraph.pdb and the original document to
+ a_paragraph.sxw.
+ </P>
+ <P><B>Expected result:</B> <BR>The resultant document should
+ contain:
+ </P>
+ <P STYLE="margin-bottom: 0cm">This line is a paragraph. It is
+ indented from left hand side by 1.0 inch and from right and side
+ by 1.0 inch (paragraph
+ </P>
+ <P>settings).</P>
+ </TD>
+ </TR>
+ <TR VALIGN=TOP>
+ <TD WIDTH=28%>
+ <P><B>aportis/content/style/standard</B></P>
+ </TD>
+ <TD WIDTH=72%>
+ <P><B>Summary</B>: document with standard text and default
+ settings &#8211; straight forward convert</P>
+ <P><B>Procedure:</B> <BR>Use test file <B>a_standard.sxw</B>.
+ </P>
+ <P>Convert a_standard.sxw to a_standard.pdb, in AportisDoc PDB
+ format. <BR>Start POSE with AportisDoc application and import
+ a_standard.pdb. <BR>Export the doc back to a_standard.pdb. <BR>Merge
+ a_standard.pdb and the original document to a_standard.sxw.
+ </P>
+ <P><B>Expected result:</B> <BR>The resultant document should
+ contain:
+ </P>
+ <P><FONT FACE="Times New Roman">This line of text is listed in
+ standard style.</FONT></P>
+ </TD>
+ </TR>
+ <TR VALIGN=TOP>
+ <TD WIDTH=28%>
+ <P><B>aportis/content/style/subscript</B></P>
+ </TD>
+ <TD WIDTH=72%>
+ <P><B>Summary</B>: document with subscript text setting &#8211;
+ straight forward convert</P>
+ <P><B>Procedure:</B> <BR>Use test file <B>a_subscript.sxw</B>.
+ </P>
+ <P>Convert a_subscript.sxw to a_subscript.pdb, in AportisDoc PDB
+ format. <BR>Start POSE with AportisDoc application and import
+ a_subscript.pdb. <BR>Export the doc back to a_subscript.pdb.
+ <BR>Merge a_subscript.pdb and the original document to
+ a_subscript.sxw.
+ </P>
+ <P><B>Expected result:</B> <BR>The resultant document should
+ contain:
+ </P>
+ <P STYLE="margin-bottom: 0cm"><FONT FACE="Times New Roman"><FONT SIZE=4>The
+ last word on this line is in subscript. <SPAN STYLE="font-style: normal"><SUB>Dude</SUB></SPAN></FONT></FONT></P>
+ <P><BR>
+ </P>
+ </TD>
+ </TR>
+ <TR VALIGN=TOP>
+ <TD WIDTH=28%>
+ <P><B>aportis/content/style/superscript</B></P>
+ </TD>
+ <TD WIDTH=72%>
+ <P><B>Summary</B>: document with superscript text setting &#8211;
+ straight forward convert</P>
+ <P><B>Procedure:</B> <BR>Use test file <B>a_subscript.sxw</B>.
+ </P>
+ <P>Convert a_superscript.sxw to a_superscript.pdb, in AportisDoc
+ PDB format. <BR>Start POSE with AportisDoc application and import
+ a_superscript.pdb. <BR>Export the doc back to a_superscript.pdb.
+ <BR>Merge a_superscript.pdb and the original document to
+ a_superscript.sxw.
+ </P>
+ <P><B>Expected result:</B> <BR>The resultant document should
+ contain:
+ </P>
+ <P STYLE="margin-bottom: 0cm"><FONT FACE="Times New Roman"><FONT SIZE=4>The
+ last word on this line is in superscript. <SPAN STYLE="font-style: normal"><SUP>Dude
+ </SUP></SPAN></FONT></FONT>
+ </P>
+ <P><BR>
+ </P>
+ </TD>
+ </TR>
+ <TR VALIGN=TOP>
+ <TD WIDTH=28%>
+ <P><B>aportis/content/style/symbols</B></P>
+ </TD>
+ <TD WIDTH=72%>
+ <P><B>Summary</B>: document with various symbol types &#8211;
+ straight forward convert</P>
+ <P><B>Procedure:</B> <BR>Use test file <B>a_symbols.sxw</B>.
+ </P>
+ <P>Convert a_symbols.sxw to a_symbols.pdb, in AportisDoc PDB
+ format. <BR>Start POSE with AportisDoc application and import
+ a_symbols.pdb. <BR>Export the doc back to a_symbols.pdb. <BR>Merge
+ a_symbols.pdb and the original document to a_symbols.sxw.
+ </P>
+ <P><B>Expected result:</B> <BR>The resultant document should
+ contain:
+ </P>
+ <P STYLE="margin-bottom: 0cm">'-'-'-'-&gt;-&gt;-&gt;-&gt;.
+ '''''''. -------. &gt;&gt;&gt;&gt;&gt;&gt;&gt;</P>
+ <P STYLE="margin-bottom: 0cm; font-style: normal"><SUP><FONT FACE="Times New Roman"><FONT SIZE=4>!&#8221;&pound;$%^&amp;*()_+}{~@:?&gt;&lt;,./;'#][=-???
+ </FONT></FONT></SUP>
+ </P>
+ <P><BR>
+ </P>
+ </TD>
+ </TR>
+ <TR VALIGN=TOP>
+ <TD WIDTH=28%>
+ <P><B>aportis/content/style/tab</B></P>
+ </TD>
+ <TD WIDTH=72%>
+ <P><B>Summary</B>: document with tab styling &#8211; straight
+ forward convert</P>
+ <P><B>Procedure:</B> <BR>Use test file <B>a_tab.sxw</B>.
+ </P>
+ <P>Convert a_tab.sxw to a_tab.pdb, in AportisDoc PDB format.
+ <BR>Start POSE with AportisDoc application and import a_tab.pdb.
+ <BR>Export the doc back to a_tab.pdb. <BR>Merge a_tab.pdb and the
+ original document to a_tab.sxw.
+ </P>
+ <P><B>Expected result:</B> <BR>The resultant document should
+ contain:
+ </P>
+ <P STYLE="margin-bottom: 0cm">This is a tabbed document</P>
+ <P STYLE="margin-bottom: 0cm">1 Tab line</P>
+ <P STYLE="margin-bottom: 0cm">2 tabbed line</P>
+ <P STYLE="margin-bottom: 0cm">3 tabbed line</P>
+ <P STYLE="margin-bottom: 0cm">2 tabbed line</P>
+ <P STYLE="margin-bottom: 0cm">1 Tab line</P>
+ <P STYLE="margin-bottom: 0cm">4 tab line</P>
+ <P STYLE="margin-bottom: 0cm">2 tab line</P>
+ <P><BR>
+ </P>
+ </TD>
+ </TR>
+ <TR VALIGN=TOP>
+ <TD WIDTH=28%>
+ <P><B>aportis/merge/style/table</B></P>
+ </TD>
+ <TD WIDTH=72%>
+ <P><B>Summary</B>: document with table &#8211; straight forward
+ convert</P>
+ <P><B>Procedure:</B> <BR>Use test file <B>a_table.sxw</B>.
+ </P>
+ <P>Convert a_table.sxw to a_table.pdb, in AportisDoc PDB format.
+ <BR>Start POSE with AportisDoc application and import a_table.pdb.
+ <BR>Export the doc back to a_table.pdb. <BR>Merge a_table.pdb and
+ the original document to a_table.sxw.
+ </P>
+ <P><B>Expected result:</B>
+ </P>
+ <P>The resultant document should contain:
+ </P>
+ <P STYLE="margin-bottom: 0cm">&lt;Check table &amp; contents are
+ identical to original.&gt;
+ </P>
+ <P STYLE="margin-bottom: 0cm"><BR>
+ </P>
+ <P STYLE="margin-bottom: 0cm">This document has a table with 3
+ rows and 3 columns:</P>
+ <P STYLE="margin-bottom: 0cm"><BR>
+ </P>
+ <P><BR><BR>
+ </P>
+ <P STYLE="margin-bottom: 0cm">&lt;TABLE &amp; CONTENTS&gt;</P>
+ <P><BR>
+ </P>
+ </TD>
+ </TR>
+ <TR VALIGN=TOP>
+ <TD WIDTH=28%>
+ <P><B>aportis/content/style/textspan</B></P>
+ </TD>
+ <TD WIDTH=72%>
+ <P><B>Summary</B>: document testing textspan
+ italics,bolds,underline together&#8211; straight forward convert</P>
+ <P><B>Procedure:</B> <BR>Use test file <B>a_textspan.sxw</B>.
+ </P>
+ <P>Convert a_textspan.sxw to a_textspan.pdb, in AportisDoc PDB
+ format. <BR>Start POSE with AportisDoc application and import
+ a_textspan.pdb. <BR>Export the doc back to a_textspan.pdb. <BR>Merge
+ a_textspan.pdb and the original document to a_textspan.sxw.
+ </P>
+ <P><B>Expected result:</B>
+ </P>
+ <P>The resultant document should contain:
+ </P>
+ <P STYLE="margin-bottom: 0cm">Document indicating Text Span</P>
+ <P STYLE="margin-bottom: 0cm"><BR>
+ </P>
+ <P STYLE="margin-bottom: 0cm; font-weight: medium"><I>This is a
+ simple line with some amount of text. The whole line is in italic
+ except the next 3 words which is also <B>SET TO BOLD</B>. Also the
+ next word is <U>UNDERLINED</U>. The essence is differnet styles
+ within the same text span.</I></P>
+ <P><BR>
+ </P>
+ </TD>
+ </TR>
+ <TR VALIGN=TOP>
+ <TD WIDTH=28%>
+ <P><B>aportis/merge/style/unorderedlist</B></P>
+ </TD>
+ <TD WIDTH=72%>
+ <P><B>Summary</B>: document with unorderedlist &#8211; straight
+ forward convert</P>
+ <P><B>Procedure:</B> <BR>Use test file <B>a_unorderedlist.sxw</B>.
+ </P>
+ <P>Convert a_unorderedlist.sxw to a_unorderedlist.pdb, in
+ AportisDoc PDB format. <BR>Start POSE with AportisDoc application
+ and import a_unorderedlist.pdb. <BR>Export the doc back to
+ a_unorderedlist.pdb. <BR>Merge a_unorderedlist.pdb and the
+ original document to a_unorderedlist.sxw.
+ </P>
+ <P><B>Expected result:</B>
+ </P>
+ <P>The resultant document should contain:
+ </P>
+ <P STYLE="margin-bottom: 0cm; font-style: normal">This document is
+ an example of a simple un- ordered list</P>
+ <P STYLE="margin-bottom: 0cm"><BR>
+ </P>
+ <OL>
+ <LI><P STYLE="margin-bottom: 0cm; font-style: normal">Wag the Dog</P>
+ <LI><P STYLE="margin-bottom: 0cm; font-style: normal">Gladiator</P>
+ <LI><P STYLE="margin-bottom: 0cm; font-style: normal">Insider</P>
+ <LI><P STYLE="margin-bottom: 0cm; font-style: normal">Usual
+ Suspects</P>
+ <LI><P STYLE="margin-bottom: 0cm; font-style: normal">Glengarry
+ Glen Ross</P>
+ </OL>
+ <OL>
+ <LI><P STYLE="margin-bottom: 0cm; font-style: normal">Host Shots</P>
+ <LI><P STYLE="margin-bottom: 0cm; font-style: normal">Airplane</P>
+ <LI><P STYLE="margin-bottom: 0cm; font-style: normal">Monty
+ Python</P>
+ <LI><P STYLE="margin-bottom: 0cm; font-style: normal">History of
+ the World</P>
+ <LI><P STYLE="margin-bottom: 0cm; font-style: normal">Sacry Movie</P>
+ <LI><P STYLE="margin-bottom: 0cm; font-style: normal">Austin
+ Powers</P>
+ </OL>
+ <UL>
+ <LI><P STYLE="margin-bottom: 0cm; font-style: normal">Scarlet and
+ the Black</P>
+ <LI><P STYLE="margin-bottom: 0cm; font-style: normal">Operation
+ Day Break</P>
+ <LI><P STYLE="margin-bottom: 0cm; font-style: normal">Life is
+ Beautiful</P>
+ <LI><P STYLE="margin-bottom: 0cm; font-style: normal">Nephew
+ (beutfiul soundtrack)</P>
+ </UL>
+ <P STYLE="margin-bottom: 0cm"><BR>
+ </P>
+ <P STYLE="margin-bottom: 0cm; font-style: normal; font-weight: medium">
+ End of un-ordered list.</P>
+ <P><BR>
+ </P>
+ </TD>
+ </TR>
+ <TR VALIGN=TOP>
+ <TD WIDTH=28%>
+ <P><B>aportis/content/style/wordwrap</B></P>
+ </TD>
+ <TD WIDTH=72%>
+ <P><B>Summary</B>: document which tests wordwrapping &#8211;
+ straight forward convert</P>
+ <P><B>Procedure:</B> <BR>Use test file <B>a_wordwrap.sxw</B>.
+ </P>
+ <P>Convert a_wordwrap.sxw to a_wordwrap.pdb, in AportisDoc PDB
+ format. <BR>Start POSE with AportisDoc application and import
+ a_wordwrap.pdb. <BR>Export the doc back to a_wordwrap.pdb. <BR>Merge
+ a_wordwrap.pdb and the original document to a_wordwrap.sxw.
+ </P>
+ <P><B>Expected result:</B>
+ </P>
+ <P>The resultant document should contain:</P>
+ <P STYLE="margin-bottom: 0cm; font-weight: medium"><I>This line is
+ a long line just to check if the word wrap feature works fine,
+ when it is synched onto the PDA..</I></P>
+ <P><BR>
+ </P>
+ </TD>
+ </TR>
+ <TR VALIGN=TOP>
+ <TD WIDTH=28%>
+ <P><B>aportis/merge/content/simple01</B></P>
+ </TD>
+ <TD WIDTH=72%>
+ <P><B>Summary</B>: simple document - insert text at beginning
+ </P>
+ <P><B>Procedure:</B> <BR>Use test file <B>a_standard.sxw</B>.
+ </P>
+ <P>Convert a_standard.sxw to a_standard.pdb, in AportisDoc PDB
+ format. <BR>Start POSE with AportisDoc application and import
+ a_standard.pdb. <BR>Insert the following text, including the
+ terminating line-feed, at the beginning of the first line:
+ </P>
+ <BLOCKQUOTE>New text added to simple file.</BLOCKQUOTE>
+ <P>Export the doc back to a_standard.pdb. <BR>Merge a_standard.pdb
+ and the original document to a_standard.sxw.
+ </P>
+ <P><B>Expected result:</B> <BR>The resultant file should contain:
+ </P>
+ <BLOCKQUOTE>New text added to simple file. <BR>This&nbsp; line of
+ text is listed in standard&nbsp; style&nbsp;</BLOCKQUOTE>
+ </TD>
+ </TR>
+ <TR VALIGN=TOP>
+ <TD WIDTH=28%>
+ <P><B>aportis/merge/content/simple02</B></P>
+ </TD>
+ <TD WIDTH=72%>
+ <P><B>Summary</B>: simple document - insert text in middle
+ </P>
+ <P><B>Procedure:</B> <BR>Use test file <B>a_standard.sxw</B>.
+ </P>
+ <P>Convert a_standard.sxw to a_standard.pdb, in AportisDoc PDB
+ format. <BR>Start POSE with AportisDoc application and import
+ a_standard.pdb. <BR>Insert the following text immediately after
+ the word &quot;text&quot;:
+ </P>
+ <BLOCKQUOTE>, including this inserted phrase,&nbsp;</BLOCKQUOTE>
+ <P>Export the doc back to a_standard.pdb. <BR>Merge a_standard.pdb
+ and the original document to a_standard.sxw.
+ </P>
+ <P><B>Expected result:</B> <BR>The resultant file should contain:
+ </P>
+ <BLOCKQUOTE>This&nbsp; line of text, including this inserted
+ phrase, is listed in standard&nbsp; style&nbsp;</BLOCKQUOTE>
+ </TD>
+ </TR>
+ <TR VALIGN=TOP>
+ <TD WIDTH=28%>
+ <P><B>aportis/merge/content/simple03</B></P>
+ </TD>
+ <TD WIDTH=72%>
+ <P><B>Summary</B>: simple document - append text
+ </P>
+ <P><B>Procedure:</B> <BR>Use test file <B>a_standard.sxw</B>.
+ </P>
+ <P>Convert a_standard.sxw to a_standard.pdb, in AportisDoc PDB
+ format. <BR>Start POSE with AportisDoc application and import
+ a_standard.pdb. <BR>Append a new-line at the end of the line and
+ add the following line:
+ </P>
+ <BLOCKQUOTE>This is also in standard style</BLOCKQUOTE>
+ <P>Export the doc back to a_standard.pdb. <BR>Merge a_standard.pdb
+ and the original document to a_standard.sxw.
+ </P>
+ <P><B>Expected result:</B> <BR>The resultant file should contain:
+ </P>
+ <BLOCKQUOTE>This&nbsp; line of text is listed in standard&nbsp;
+ style <BR>This is also in standard style</BLOCKQUOTE>
+ </TD>
+ </TR>
+</TABLE>
+<H2>5.2 MiniCalc Tests</H2>
+<H2>5.2.1 MiniCalc Convert Tests</H2>
+<H2>5.2.1.1 MiniCalc Merge Style Tests</H2>
+<TABLE WIDTH=100% BORDER=1 CELLPADDING=2 CELLSPACING=0>
+ <COL WIDTH=77*>
+ <COL WIDTH=179*>
+ <TR VALIGN=TOP>
+ <TD WIDTH=30%>
+ <P><B>minicalc/merge/style/columnswidth</B> <BR>&nbsp;</P>
+ </TD>
+ <TD WIDTH=70%>
+ <P><B>Summary</B>: Spreadsheet with 5 columns 10 entries -
+ Spreadsheet columnwidth variation.&nbsp;
+ </P>
+ <P><B>Procedure:</B> <BR>Use test file <B>c_columnswidth.sxc</B>.&nbsp;
+ </P>
+ <P>Convert c_columnswidth.sxc to c_columnswidth.pdb, in MiniCalc
+ PDB format.&nbsp; <BR>Start POSE with MiniCalc application and
+ import c_columnswidth.pdb.&nbsp;</P>
+ <P>Choose Cell Reference &quot;B1&quot; &amp; alter column width
+ to 1.55 by selecting, Format -&gt; Column -&gt; Width... &lt; make
+ width change via spin button&gt; -&gt; OK, also decrease &quot;E1&quot;
+ similarly to have a column width of 1.68.<BR><BR><BR>
+ </P>
+ <P>Export the doc back to c_columnswidth.pdb.&nbsp; <BR>Merge
+ c_columnswidth.pdb to c_columnswidth.sxw.&nbsp;
+ </P>
+ <P><B>Expected result:</B> <BR>&nbsp;Spreadsheet should display
+ column B with a width increase of 1.0 , and column E with a width
+ decrease of 1.0, as compared with the original file, reflecting
+ the changes stated above.</P>
+ </TD>
+ </TR>
+ <TR VALIGN=TOP>
+ <TD WIDTH=30%>
+ <P><B>minicalc/merge/style/rowheight</B></P>
+ </TD>
+ <TD WIDTH=70%>
+ <P><B>Summary</B>: Spreadsheet with 4 columns 3 rows 12 entries -
+ Spreadsheet rowheight variation.&nbsp;
+ </P>
+ <P><B>Procedure:</B> <BR>Use test file <B>c_rowheight.sxc</B>.&nbsp;
+ </P>
+ <P>Convert c_rowheight.sxc to c_rowheight.pdb, in MiniCalc PDB
+ format.&nbsp; <BR>Start POSE with MiniCalc application and import
+ c_rowheight.pdb.&nbsp;</P>
+ <P><BR>Choose Cell Reference &quot;A1&quot; &amp; alter row height
+ to 1.17 by selecting Format -&gt; Row -&gt; Height... &lt;make
+ height change via spin button&gt; -&gt; OK., also decrease &quot;A3&#8221;
+ similarly to have a row height of 0.30.&nbsp;
+ </P>
+ <P>Export the doc back to c_rowheight.pdb.&nbsp; <BR>Merge
+ c_rowheight.pdb to c_rowheight.sxw.&nbsp;
+ </P>
+ <P><B>Expected result:</B> <BR>&nbsp;Spreadsheet should display
+ row &#8220;Row 1&#8221; with a height increase of 1.0 and &quot;Row
+ 3&quot; with a height decrease of 0.41, as compared with the
+ original file, reflecting the changes stated above.</P>
+ </TD>
+ </TR>
+ <TR VALIGN=TOP>
+ <TD WIDTH=30%>
+ <P><B>minicalc/merge/style/rowstyles</B></P>
+ </TD>
+ <TD WIDTH=70%>
+ <P><B>Summary</B>: Spreadsheet with 5 columns 6 rows 18 entries -
+ Spreadsheet rowstyle variation.&nbsp;
+ </P>
+ <P><B>Procedure:</B> <BR>Use test file <B>c_rowstyle.sxc</B>.
+ </P>
+ <P>Convert c_rowstyles.sxc to c_rowstyles.pdb, in MiniCalc PDB
+ format.&nbsp; <BR>Start POSE with MiniCalc application and import
+ c_rowstyles.pdb.&nbsp;</P>
+ <P>Choose Cell Reference &quot;B3&quot; and change Heading style
+ to default, by selecting, Format -&gt; Style Catelog -&gt; &lt;choose
+ heading type from listbox&gt;, also choose cellreference &quot;D5&quot;
+ and change Heading style to Heading1, also change &quot;C5&quot;
+ to remove bold, underline &amp; italic.&nbsp;
+ </P>
+ <P><BR>Export the doc back to c_rowstyles.pdb.&nbsp; <BR>Merge
+ c_rowstyles.pdb to c_rowstyles.sxw.&nbsp;
+ </P>
+ <P><B>Expected result:</B> <BR>&nbsp;Spreadsheet should display
+ value's and style types as in original file, except cells &quot;B3,
+ &amp; D5&quot; which should display heading types default &amp;
+ Heading 1 resp. and &quot;C5&quot; which should be plain text,
+ reflecting the changes stated above.</P>
+ </TD>
+ </TR>
+</TABLE>
+<H2>5.2.1.2 MiniCalc Convert Style Tests</H2>
+<TABLE WIDTH=100% BORDER=1 CELLPADDING=2 CELLSPACING=0>
+ <COL WIDTH=77*>
+ <COL WIDTH=179*>
+ <TR VALIGN=TOP>
+ <TD WIDTH=30%>
+ <P><B>minicalc/convert/style/styles</B> <BR>&nbsp;</P>
+ </TD>
+ <TD WIDTH=70%>
+ <P><B>Summary</B>: Spreadsheet with 3 columns 10 rows 13 entries -
+ Spreadsheet styles test.&nbsp;
+ </P>
+ <P><B>Procedure:</B> <BR>Use test file <B>c_styles.sxc</B>.&nbsp;
+ </P>
+ <P>Convert c_styles.sxc to c_styles.pdb, in MiniCalc PDB format.&nbsp;
+ <BR>Start POSE with MiniCalc application and import c_styles.pdb.&nbsp;
+ <BR>Export the doc back to c_styles.pdb.&nbsp; <BR>Merge
+ c_styles.pdb to c_styles.sxw.&nbsp;</P>
+ <P><B>Expected result:</B> <BR>&nbsp;Spreadsheet should display
+ all original sheet values with style features, .i.e Bold, Italics,
+ .</P>
+ </TD>
+ </TR>
+ <TR VALIGN=TOP>
+ <TD WIDTH=30%>
+ <P><B>minicalc/convert/style/alignment</B><BR>&nbsp;</P>
+ </TD>
+ <TD WIDTH=70%>
+ <P><B>Summary</B>: Spreadsheet with 4 columns 8 rows 24 entries -
+ Spreadsheet alignment test.&nbsp;
+ </P>
+ <P><B>Procedure:</B> <BR>Use test file <B>c_alignment.sxc</B>.&nbsp;
+ </P>
+ <P>Convert c_alignment.sxc to c_alignment.pdb, in MiniCalc PDB
+ format.&nbsp; <BR>Start POSE with MiniCalc application and import
+ c_alignment.pdb.&nbsp; <BR>Export the doc back to
+ c_alignment.pdb.&nbsp; <BR>Merge c_alignment.pdb to
+ c_alignment.sxw.&nbsp;</P>
+ <P><B>Expected result:</B> <BR>&nbsp;Spreadsheet should display
+ all original sheet values with identical alignment to original
+ file.</P>
+ </TD>
+ </TR>
+</TABLE>
+<H2><BR><BR>
+</H2>
+<H2>5.2.2.1 MiniCalc Merge Content Tests</H2>
+<TABLE WIDTH=100% BORDER=1 CELLPADDING=2 CELLSPACING=0>
+ <COL WIDTH=77*>
+ <COL WIDTH=179*>
+ <TR>
+ <TD WIDTH=30% VALIGN=TOP>
+ <P><B>minicalc/merge/content/insertimage</B><BR>&nbsp;</P>
+ </TD>
+ <TD WIDTH=70% VALIGN=BOTTOM>
+ <P><B>Summary</B>: Spreadsheet with 6 columns 2 image inserts -
+ Spreadsheet image insert.&nbsp;
+ </P>
+ <P><B>Procedure:</B> <BR>Use test file <B>c_insertimage.sxc</B>.&nbsp;
+ </P>
+ <P>Convert c_insertimage.sxc to c_insertimage.pdb, in MiniCalc PDB
+ format.&nbsp; <BR>Start POSE with MiniCalc application and import
+ c_insertimage.pdb.&nbsp; <BR>Export the doc back to
+ c_insertimage.pdb.&nbsp; <BR>Merge c_insertimage.pdb to
+ c_insertimage.sxw.&nbsp;
+ </P>
+ <P><B>Expected result:</B> <BR>&nbsp;Spreadsheet should display
+ original file with both original images.</P>
+ </TD>
+ </TR>
+ <TR>
+ <TD WIDTH=30% VALIGN=TOP>
+ <P><B>minicalc/merge/content/textimage</B><BR>&nbsp;</P>
+ </TD>
+ <TD WIDTH=70% VALIGN=BOTTOM>
+ <P><B>Summary</B>: Spreadsheet with 6 columns 2 image inserts -
+ Spreadsheet image text insert.&nbsp;
+ </P>
+ <P><B>Procedure:</B> <BR>Use test file <B>c_textimage.sxc</B>.&nbsp;
+ </P>
+ <P>Convert c_textimage.sxc to c_textimage.pdb, in MiniCalc PDB
+ format.&nbsp; <BR>Start POSE with MiniCalc application and import
+ c_textimage.pdb.&nbsp;</P>
+ <P>Insert text immediately before and directly after the inserted
+ image.</P>
+ <P>Export the doc back to c_textimage.pdb.&nbsp; <BR>Merge
+ c_textimage.pdb to c_textimage.sxw.&nbsp;
+ </P>
+ <P><B>Expected result:</B> <BR>&nbsp;Spreadsheet should display
+ original image surrounded by text .i.e text before &amp; after the
+ insert.</P>
+ </TD>
+ </TR>
+</TABLE>
+<H2>5.2.2.2 MiniCalc Convert Contents Tests</H2>
+<TABLE WIDTH=1025 BORDER=1 CELLPADDING=2 CELLSPACING=0>
+ <COL WIDTH=431>
+ <COL WIDTH=584>
+ <TR VALIGN=TOP>
+ <TD WIDTH=431>
+ <P><BR>
+ </P>
+ </TD>
+ <TD WIDTH=584>
+ <P><BR>
+ </P>
+ </TD>
+ </TR>
+ <TR VALIGN=TOP>
+ <TD WIDTH=431>
+ <P><B>minicalc/convert/content/basic</B></P>
+ </TD>
+ <TD WIDTH=584>
+ <P><B>Summary: </B>simple spreadsheet - round-trip conversion&nbsp;
+ </P>
+ <P><B>Procedure:</B> <BR>Use test file <B>c_standard.sxc</B>.&nbsp;
+ </P>
+ <P>Convert c_standard.sxc to c_standard.pdb, in MiniCalc PDB
+ format.&nbsp; <BR>Start POSE with MiniCalc application and import
+ c_standard.pdb. Export the doc back to c_standard.pdb, without
+ making and changes to the spreadsheet.&nbsp; <BR>Merge
+ c_standard.pdb to c_standard.sxc.&nbsp;
+ </P>
+ <P><B>Expected result:</B> <BR>The resultant file should be
+ equivalent to the original spreadsheet.&nbsp; <BR>&nbsp;</P>
+ </TD>
+ </TR>
+ <TR VALIGN=TOP>
+ <TD WIDTH=431>
+ <P><B>minicalc/convert/content/simple01</B></P>
+ </TD>
+ <TD WIDTH=584>
+ <P><B>Summary</B>: simple spreadsheet - insert text &amp; column
+ of numeric values at beginning of empty sheet.&nbsp;
+ </P>
+ <P><B>Procedure:</B> <BR>Use test file <B>c_standard.sxc</B>.&nbsp;
+ </P>
+ <P>Convert c_standard.sxc to c_standard.pdb, in Minicalc PDB
+ format.&nbsp; <BR>Start POSE with Minicalc application and import
+ c_standard.pdb.&nbsp; <BR>Insert the following text &amp; values
+ at the beginning of the the spreadsheet, .i.e in Column 1:&nbsp;
+ </P>
+ <BLOCKQUOTE>Col 1</BLOCKQUOTE>
+ <BLOCKQUOTE>1</BLOCKQUOTE>
+ <BLOCKQUOTE>1</BLOCKQUOTE>
+ <BLOCKQUOTE>1</BLOCKQUOTE>
+ <P>Export the doc back to c_standard.pdb.&nbsp; <BR>Merge
+ c_standard.pdb to c_standard.sxc.&nbsp;
+ </P>
+ <P><B>Expected result:</B> <BR>The resultant file should contain:&nbsp;
+ </P>
+ <BLOCKQUOTE STYLE="margin-left: 6.05cm">New column of values as
+ shown above.&nbsp;</BLOCKQUOTE>
+ </TD>
+ </TR>
+ <TR VALIGN=TOP>
+ <TD WIDTH=431>
+ <P><B>minicalc/convert/content/simple02</B></P>
+ </TD>
+ <TD WIDTH=584>
+ <P><B>Summary</B>: simple spreadsheet - append a new column to
+ end&nbsp;
+ </P>
+ <P><B>Procedure:</B> <BR>Use test file <B>c_standard.sxc</B>.&nbsp;
+ </P>
+ <P>Convert c_standard.sxc to c_standard.pdb, in MiniCalc PDB
+ format.&nbsp; <BR>Start POSE with MiniCalc application and import
+ c_standard.pdb.&nbsp; <BR>Insert the following column immediately
+ after the first:&nbsp;
+ </P>
+ <BLOCKQUOTE>Col 3</BLOCKQUOTE>
+ <BLOCKQUOTE>3</BLOCKQUOTE>
+ <BLOCKQUOTE>3</BLOCKQUOTE>
+ <BLOCKQUOTE>3</BLOCKQUOTE>
+ <P>Export the doc back to c_standard.pdb.&nbsp; <BR>Merge
+ c_standard.pdb to c_standard.sxc.&nbsp;
+ </P>
+ <P><B>Expected result:</B> <BR>The resultant file should contain:&nbsp;
+ </P>
+ <P CLASS="text-body-indent">Col 1 Col 3</P>
+ <BLOCKQUOTE>1 3
+ </BLOCKQUOTE>
+ <BLOCKQUOTE>1 3</BLOCKQUOTE>
+ <BLOCKQUOTE>1 3</BLOCKQUOTE>
+ </TD>
+ </TR>
+ <TR VALIGN=TOP>
+ <TD WIDTH=431>
+ <P><B>minicalc/convert/content/simple03</B></P>
+ </TD>
+ <TD WIDTH=584>
+ <P><B>Summary</B>: simple spreadsheet - insert a new column in
+ middle&nbsp;
+ </P>
+ <P><B>Procedure:</B> <BR>Use test file <B>c_standard.sxc</B>.&nbsp;
+ </P>
+ <P>Convert c_standard.sxc to c_standard.pdb, in MiniCalc PDB
+ format.&nbsp; <BR>Start POSE with MiniCalc application and import
+ c_standard.pdb.&nbsp; <BR>Insert the following column immediately
+ after the first and before the second:&nbsp;
+ </P>
+ <BLOCKQUOTE>Col 2</BLOCKQUOTE>
+ <BLOCKQUOTE>2</BLOCKQUOTE>
+ <BLOCKQUOTE>2</BLOCKQUOTE>
+ <BLOCKQUOTE>2</BLOCKQUOTE>
+ <P>Export the doc back to c_standard.pdb.&nbsp; <BR>Merge
+ c_standard.pdb to c_standard.sxc.&nbsp;
+ </P>
+ <P><B>Expected result:</B> <BR>The resultant file should contain:&nbsp;
+ </P>
+ <BLOCKQUOTE>Col 1 Col 2 Col 3</BLOCKQUOTE>
+ <BLOCKQUOTE>1 2 3</BLOCKQUOTE>
+ <BLOCKQUOTE>1 2 3</BLOCKQUOTE>
+ <BLOCKQUOTE>1 2 3</BLOCKQUOTE>
+ </TD>
+ </TR>
+ <TR VALIGN=TOP>
+ <TD WIDTH=431>
+ <P><B>minicalc/convert/content/simple04</B></P>
+ </TD>
+ <TD WIDTH=584>
+ <P><B>Summary</B>: simple spreadsheet - delete text&nbsp;
+ </P>
+ <P><B>Procedure:</B> <BR>Use test file <B>c_standard.sxc</B>.&nbsp;
+ </P>
+ <P>Convert c_standard.sxc to c_standard.pdb, in MiniCalc PDB
+ format.&nbsp; <BR>Start POSE with MiniCalc application and import
+ c_standard.pdb.&nbsp; <BR>Delete &#8220;Column 3&#8221;, so that
+ it reads:&nbsp;
+ </P>
+ <BLOCKQUOTE>Col 1 Col 2</BLOCKQUOTE>
+ <BLOCKQUOTE>1 2</BLOCKQUOTE>
+ <BLOCKQUOTE>1 2</BLOCKQUOTE>
+ <P>Export the doc back to c_standard.pdb.&nbsp; <BR>Merge
+ c_standard.pdb to c_standard.sxc.&nbsp;
+ </P>
+ <P><B>Expected result:</B> <BR>The resultant file should contain:&nbsp;
+ </P>
+ <BLOCKQUOTE>Col 1 Col 2</BLOCKQUOTE>
+ <BLOCKQUOTE>1 2</BLOCKQUOTE>
+ <BLOCKQUOTE>1 2</BLOCKQUOTE>
+ </TD>
+ </TR>
+ <TR VALIGN=TOP>
+ <TD WIDTH=431>
+ <P><B>minicalc/convert/content/addition</B></P>
+ </TD>
+ <TD WIDTH=584>
+ <P><B>Summary</B>: Spreadsheet with 4 columns 10 entries -
+ Spreadsheet Simple Addition using various formulae.&nbsp;
+ </P>
+ <P><B>Procedure:</B> <BR>Use test file <B>c_addition.sxc</B>.
+ </P>
+ <P>Convert c_addition.sxc to c_addition.pdb, in MiniCalc PDB
+ format.&nbsp; <BR>Start POSE with MiniCalc application and import
+ c_addition.pdb.&nbsp; <BR>Change Cell Reference &quot;A1&quot; = 3
+ in formula bar.&nbsp; <BR>Export the doc back to c_addition.pdb.&nbsp;
+ <BR>Merge c_addition.pdb to c_addition.sxc.&nbsp;
+ </P>
+ <P>A1 =3 ; B1 = 3 ; C1 =4 ;D1 =5;&nbsp;
+ </P>
+ <P>Addition types:
+ </P>
+ <P>Cell reference + Integer = A1+2 =5
+ </P>
+ <P>Integer + Decimal = 3+0.1 =3.1
+ </P>
+ <P>Cell Reference + Cell Reference = A1+B1 = 6
+ </P>
+ <P>(Bracketed Cell Reference) + (Integer + Integer) =
+ (A1+B1)+(2+45) = 53
+ </P>
+ <P>Integer + (Integer) + (Integer+Integer) = 2+(0)+(3+0) = 5
+ </P>
+ <P>(SUM(Cell Ref;Cell Ref) +SUM(Cell Ref;Cell Ref) =
+ (SUM(A1;B1)+SUM(B1;C1) = 13
+ </P>
+ <P><B>Expected result:</B> <BR>&nbsp;All spreadsheet entered
+ values &amp; the standard formula SUM of each cell should be
+ displayed as above, formulae as stated above should be visible in
+ the Formula Bar.&nbsp;</P>
+ </TD>
+ </TR>
+ <TR VALIGN=TOP>
+ <TD WIDTH=431>
+ <P><B>minicalc/convert/content/backwardrange</B></P>
+ </TD>
+ <TD WIDTH=584>
+ <P><B>Summary</B>: Spreadsheet with 2 columns 7 entries -
+ Spreadsheet backwardranging using various formulae.&nbsp;
+ </P>
+ <P><B>Procedure:</B> <BR>Use test file <B>c_backwardrange.sxc</B>.&nbsp;
+ </P>
+ <P>Convert c_alignment.sxc to c_alignment.pdb, in MiniCalc PDB
+ format.&nbsp; <BR>Start POSE with MiniCalc application and import
+ c_alignment.pdb.&nbsp; <BR>Change Cell Reference &quot;B2&quot; =
+ AVERAGE(2;5;5) in formula bar.&nbsp; <BR>Export the doc back to
+ c_alignment.pdb.&nbsp; <BR>Merge c_alignment.pdb to
+ c_alignment.sxc.&nbsp;
+ </P>
+ <P>Logical Funtion test B4:
+ </P>
+ <P>IF(Logical Test; Then Value;Else Value)
+ </P>
+ <P>.e.g. IF(23;45.45;54.54) = 45.45&nbsp;
+ </P>
+ <P>read as if logical test TRUE then place THEN VALUE in cell else
+ place ELSE VALUE. <BR>&nbsp; <BR>&nbsp; <BR>&nbsp;
+ </P>
+ <P>Statistical Functional tests B2 , B3 resp.:
+ </P>
+ <P>AVERAGE(2;5;5) - Returns sum of arguments divided by number of
+ arguments =4 .
+ </P>
+ <P>MAX(10;3;3) - Returns the maximum value in a list of arguments
+ =10. <BR>&nbsp; <BR>&nbsp; <BR>&nbsp;
+ </P>
+ <P>Negative addition test B1:
+ </P>
+ <P>=B2-B3 = 4 - 10 = -6 <BR>&nbsp; <BR>&nbsp; <BR>&nbsp;
+ </P>
+ <P>Range Addition tests A1, A5, B5:
+ </P>
+ <P>SUM(B2;B4) = B2 + B3 + B4 = 4 + 10 + 45.45 = 59.45.
+ </P>
+ <P>SUM(A1:B2) -B4 = (59.45 + (-6) +4) - 45.45 = 12</P>
+ <P>SUM(A1;B1)-A2 = (59.45 + (-6)) - 0 = 53.45
+ </P>
+ <P><B>Expected result:</B> <BR>&nbsp;All spreadsheet entered
+ values &amp; the standard formula SUM of each cell should be
+ displayed on sheet as detailed above, formulae as stated above
+ should be visible in the Formula Bar.</P>
+ </TD>
+ </TR>
+ <TR VALIGN=TOP>
+ <TD WIDTH=431>
+ <P><B>minicalc/convert/content/boolean</B></P>
+ </TD>
+ <TD WIDTH=584>
+ <P><B>Summary</B>: Spreadsheet with 1 column 2 entries -
+ Spreadsheet boolean entry.&nbsp;
+ </P>
+ <P><B>Procedure:</B> <BR>Use test file <B>c_boolean.sxc</B>.
+ </P>
+ <P>Convert c_boolean.sxc to c_boolean.pdb, in MiniCalc PDB
+ format.&nbsp; <BR>Start POSE with MiniCalc application and import
+ c_boolean.pdb.&nbsp; <BR>Change Cell Reference &quot;A2&quot; =
+ TRUE in formula bar.&nbsp; <BR>Export the doc back to
+ c_boolean.pdb.&nbsp; <BR>Merge c_boolean.pdb to c_boolean.sxc.&nbsp;
+ </P>
+ <P>Logical Funtion test : cells A1, A2:
+ </P>
+ <P>A1=TRUE
+ </P>
+ <P>A2=TRUE
+ </P>
+ <P>Returns the logical values TRUE to the cells resp.
+ </P>
+ <P><B>Expected result:</B> <BR>&nbsp;The logical entry of each
+ cell should be displayed on the sheet as stated above.</P>
+ </TD>
+ </TR>
+ <TR VALIGN=TOP>
+ <TD WIDTH=431>
+ <P><B>minicalc/convert/content/cellcurrencyvalue</B></P>
+ </TD>
+ <TD WIDTH=584>
+ <P><B>Summary</B>: Spreadsheet with 2 columns 10 entries -
+ Spreadsheet Currency number Format conversion test.&nbsp;
+ </P>
+ <P><B>Procedure:</B> <BR>Use test file <B>c_cellcurrencyvalue.sxc</B>.
+ </P>
+ <P>Convert c_cellcurrencyvalue.sxc to c_cellcurrencyvalue.pdb, in
+ MiniCalc PDB format.&nbsp; <BR>Start POSE with MiniCalc
+ application and import c_cellcurrencyvalue.pdb.&nbsp; <BR>Export
+ the doc back to c_cellcurrencyvalue.pdb.&nbsp; <BR>Merge
+ c_cellcurrencyvalue.pdb to c_cellcurrencyvalue.sxc.&nbsp;
+ </P>
+ <P>Display Sheet : 12 DM.
+ </P>
+ <P><B>Expected result:</B> <BR>&nbsp;Spreadsheet entered values or
+ the sum of each cell should be displayed with specified Currency
+ symbol, formulae should be visible in the Formula Bar but not the
+ currency symbol.</P>
+ </TD>
+ </TR>
+ <TR VALIGN=TOP>
+ <TD WIDTH=431>
+ <P><B>minicalc/convert/content/cellcurrencychange</B></P>
+ </TD>
+ <TD WIDTH=584>
+ <P><B>Summary</B>: Spreadsheet with 2 columns 10 entries -
+ Spreadsheet Currency number Format modification test.&nbsp;
+ </P>
+ <P><B>Procedure:</B> <BR>Use test file <B>c_cellcurrencychange.sxc</B>.
+ </P>
+ <P>Convert c_cellcurrencychange.sxc to c_cellcurrencychange.pdb,
+ in MiniCalc PDB format.&nbsp; <BR>Start POSE with MiniCalc
+ application and import c_cellcurrencychange.pdb.&nbsp; <BR>Change
+ Cell Reference &quot;A1&quot; to have currency format in Danish
+ Marks (DM).&nbsp; <BR>Export the doc back to
+ c_cellcurrencychange.pdb.&nbsp; <BR>Merge c_cellcurrencychange.pdb
+ to c_cellcurrencychange.sxc.&nbsp;
+ </P>
+ <P>Select cell A1 = 12 ; then tap pen icon option on palm, choose
+ Currency from palm listbox, tap on the down arrow to the right of
+ the flashing cursor, tap on the intended currency type .e.g DM
+ (Danish Mark) and tap apply &amp; OK.
+ </P>
+ <P>Display Sheet : 12 DM.
+ </P>
+ <P><B>Expected result:</B> <BR>&nbsp;Spreadsheet entered values or
+ the sum of each cell should be displayed with specified Currency
+ symbol, formulae should be visible in the Formula Bar but not the
+ currency symbol.</P>
+ </TD>
+ </TR>
+ <TR VALIGN=TOP>
+ <TD WIDTH=431>
+ <P><B>minicalc/convert/content/cellfloatvalue</B></P>
+ </TD>
+ <TD WIDTH=584>
+ <P><B>Summary</B>: Spreadsheet with 2 columns 6 entries -
+ Spreadsheet float values.&nbsp;
+ </P>
+ <P><B>Procedure:</B> <BR>Use test file <B>c_cellfloatvalue.sxc</B>.&nbsp;
+ </P>
+ <P>Convert c_cellfloatvalue.sxc to c_cellfloatvalue.pdb, in
+ MiniCalc PDB format.&nbsp; <BR>Start POSE with MiniCalc
+ application and import c_cellfloatvalue.pdb.&nbsp; <BR>Change Cell
+ Reference &quot;A1&quot; = 11 &amp; &quot;A2&quot; = 2.38 &amp; B3
+ 100.02450 in formula bar.&nbsp; <BR>Export the doc back to
+ c_cellfloatvalue.pdb.&nbsp; <BR>Merge c_cellfloatvalue.pdb to
+ c_cellfloatvalue.sxc.&nbsp;
+ </P>
+ <P>The original sheet has selected Format -&gt; Cells... -&gt;
+ Numbers Tab -&gt; &amp; Numbers from the list box, choosen
+ -1234.12, tho set the Format Code to 0.00 preventing the sheet
+ display rounding values to two decimal places. It also has
+ fraction display enabled in certain cells.</P>
+ <P>Formula Bar : Display Sheet:
+ </P>
+ <P>A1 = 11 -&gt; 11.00
+ </P>
+ <P>A2 = 2.38 -&gt; 2 19/50
+ </P>
+ <P>A3 = 0.45 -&gt; 0.45
+ </P>
+ <P>B2 = 0.23 -&gt; 2/9
+ </P>
+ <P>B3 = 100.02450 -&gt; 100.02
+ </P>
+ <P><B>Expected result:</B> <BR>&nbsp;Spreadsheet fractional &amp;
+ decimal values should be displayed with specified precision as
+ stated above, formulae should be visible in the Formula Bar.</P>
+ </TD>
+ </TR>
+ <TR VALIGN=TOP>
+ <TD WIDTH=431>
+ <P><B>minicalc/convert/content/cellpercentvalue</B></P>
+ </TD>
+ <TD WIDTH=584>
+ <P><B>Summary</B>: Spreadsheet with 2 columns 3 entries -
+ Spreadsheet percentage value precision.&nbsp;
+ </P>
+ <P><B>Procedure:</B> <BR>Use test file <B>c_cellpercentvalue.sxc</B>.&nbsp;
+ </P>
+ <P>Convert c_cellpercentvalue.sxc to c_cellpercentvalue.pdb, in
+ MiniCalc PDB format.&nbsp; <BR>Start POSE with MiniCalc
+ application and import c_cellpercentvalue.pdb.&nbsp; <BR>Change
+ Cell Reference &quot;A1&quot; = 120% &amp; &quot;B1&quot; = 10% in
+ formula bar.&nbsp; <BR>Export the doc back to
+ c_cellpercentvalue.pdb.&nbsp; <BR>Merge c_cellpercentvalue.pdb to
+ c_cellpercentvalue.sxc.&nbsp;
+ </P>
+ <P>For cell A1 enter 120% in the Formula Bar. Sheet Display =
+ 120.00%&nbsp;
+ </P>
+ <P>For cell B1 enter 10% in the Formula Bar. Sheet Display = 10%
+ </P>
+ <P><B>Expected result:</B> <BR>&nbsp;Spreadsheet percentage values
+ should be displayed with specified precision as stated above,
+ formulae should be visible in the Formula Bar.</P>
+ </TD>
+ </TR>
+ <TR VALIGN=TOP>
+ <TD WIDTH=431>
+ <P><B>minicalc/convert/content/cellstringvalue</B></P>
+ </TD>
+ <TD WIDTH=584>
+ <P><B>Summary</B>: Spreadsheet with 4 columns 11 entries -
+ Spreadsheet String values.&nbsp;
+ </P>
+ <P><B>Procedure:</B> <BR>Use test file <B>c_cellstringvalue.sxc</B>.&nbsp;
+ </P>
+ <P>Convert c_cellstringvalue.sxc to c_cellstringvalue.pdb, in
+ MiniCalc PDB format.&nbsp; <BR>Start POSE with MiniCalc
+ application and import c_cellstringvalue.pdb.&nbsp; <BR>Change
+ Cell Reference &quot;C2&quot; = Testing &amp; DELETE contents of
+ &quot;D2&quot; &amp; insert a ';' in &quot;B3&quot; in formula
+ bar.&nbsp; <BR>Export the doc back to c_cellstringvalue.pdb.&nbsp;
+ <BR>Merge c_cellstringvalue.pdb to c_cellstringvalue.sxc.&nbsp;
+ </P>
+ <P>A1 = This A2 = With A3 = For
+ </P>
+ <P>B1 = Cell B2 = Strings B3 = ;
+ </P>
+ <P>C1 = Is C2 = Testing C3 = string values
+ </P>
+ <P>D1 = Filled D2 = &quot;blank&quot;&nbsp;
+ </P>
+ <P><B>Expected result:</B> <BR>&nbsp;Spreadsheet strings values
+ should be displayed as stated above.</P>
+ </TD>
+ </TR>
+ <TR VALIGN=TOP>
+ <TD WIDTH=431>
+ <P><B>minicalc/convert/content/character</B> <BR>&nbsp;</P>
+ </TD>
+ <TD WIDTH=584>
+ <P><B>Summary</B>: Spreadsheet with 4 columns 23 entries -
+ Spreadsheet character values.&nbsp;
+ </P>
+ <P><B>Procedure:</B> <BR>Use test file <B>c_character.sxc</B>.&nbsp;
+ </P>
+ <P>Convert c_character.sxc to c_character.pdb, in MiniCalc PDB
+ format.&nbsp; <BR>Start POSE with MiniCalc application and import
+ c_character.pdb.&nbsp; <BR>Change Cell Reference &quot;C7&quot; =
+ -??%, .i.e appending a % sign.&nbsp; <BR>Export the doc back to
+ c_character.pdb.&nbsp; <BR>Merge c_character.pdb to
+ c_character.sxc.&nbsp;
+ </P>
+ <P>C7 = -??%&nbsp;
+ </P>
+ <P><B>Expected result:</B> <BR>&nbsp;Spreadsheet character values
+ should be displayed as in original file including minor change
+ stated above.</P>
+ </TD>
+ </TR>
+ <TR VALIGN=TOP>
+ <TD WIDTH=431>
+ <P><B>minicalc/convert/content/cyclic</B> <BR>&nbsp;</P>
+ </TD>
+ <TD WIDTH=584>
+ <P><B>Summary</B>: Spreadsheet with 2 columns 8 entries -
+ Spreadsheet error messages.&nbsp;
+ </P>
+ <P><B>Procedure:</B> <BR>Use test file <B>c_cyclic.sxc</B>.&nbsp;
+ </P>
+ <P>Convert c_cyclic.sxc to c_cyclic.pdb, in MiniCalc PDB format.&nbsp;
+ <BR>Start POSE with MiniCalc application and import c_cyclic.pdb.&nbsp;
+ <BR>Change Cell Reference &quot;A4&quot; &amp; &quot;A5&quot; = 0
+ &amp; &quot;B4&quot; = A1/A4, &quot;B5&quot;= A4/A5 in formula
+ bar.&nbsp; <BR>Export the doc back to c_cyclic.pdb.&nbsp; <BR>Merge
+ c_cyclic.pdb to c_cyclic.sxc.&nbsp;
+ </P>
+ <P>Changes should generate 2 extra errors shown below.
+ </P>
+ <P>B4 = Err.503</P>
+ <P>B5 = #VALUE!
+ </P>
+ <P><B>Expected result:</B> <BR>&nbsp;Spreadsheet should display
+ all original sheet values including 2 extra errors generated by
+ the changes detailed above.</P>
+ </TD>
+ </TR>
+ <TR VALIGN=TOP>
+ <TD WIDTH=431>
+ <P><B>minicalc/convert/content/dividefloating</B> <BR>&nbsp;</P>
+ </TD>
+ <TD WIDTH=584>
+ <P><B>Summary</B>: Spreadsheet with 2 columns 7 entries -
+ Spreadsheet dividing floating points.&nbsp;
+ </P>
+ <P><B>Procedure:</B> <BR>Use test file <B>c_dividefloating.sxc</B>.&nbsp;
+ </P>
+ <P>Convert c_dividefloating.sxc to c_dividefloating.pdb, in
+ MiniCalc PDB format.&nbsp; <BR>Start POSE with MiniCalc
+ application and import c_dividefloating.pdb.&nbsp; <BR>Change Cell
+ Reference &quot;A4&quot; = -(12.2)/(5-1) &amp; &quot;B2&quot; = to
+ be positive, in formula bar.&nbsp; <BR>Export the doc back to
+ c_dividefloating.pdb.&nbsp; <BR>Merge c_dividefloating.pdb to
+ c_dividefloating.sxc.&nbsp;
+ </P>
+ <P>B2 = 03.050000&nbsp;
+ </P>
+ <P>A4 = -03.05</P>
+ <P>Spreadsheet setting : Format -&gt; Cells... -&gt; Decimal
+ Places=6, Negative numbers red= TRUE, Leading zero's =2 -&gt; OK.
+ </P>
+ <P><B>Expected result:</B> <BR>&nbsp;Spreadsheet should display
+ all original sheet values and newly entered floating point
+ division with specified precision &amp; colour, as stated above.</P>
+ </TD>
+ </TR>
+ <TR VALIGN=TOP>
+ <TD WIDTH=431>
+ <P><B>minicalc/convert/content/forwardrange</B> <BR>&nbsp;</P>
+ </TD>
+ <TD WIDTH=584>
+ <P><B>Summary</B>: Spreadsheet with 2 columns 4 rows 5 entries -
+ Spreadsheet tests forwardranging.&nbsp;
+ </P>
+ <P><B>Procedure:</B> <BR>Use test file <B>c_forwardrange.sxc</B>.&nbsp;
+ </P>
+ <P>Convert c_forwardrange.sxc to c_forwardrange.pdb, in MiniCalc
+ PDB format.&nbsp; <BR>Start POSE with MiniCalc application and
+ import c_forwardrange.pdb.&nbsp; <BR>Change Cell Reference &quot;B4&quot;
+ = IF(0;45.45;54.54), in formula bar.&nbsp; <BR>Export the doc back
+ to c_forwardrange.pdb.&nbsp; <BR>Merge c_forwardrange.pdb to
+ c_forwardrange.sxc.&nbsp;
+ </P>
+ <P>Changes IF statement to False so ELSE VALUE now valid.
+ </P>
+ <P>B4 = 54.54
+ </P>
+ <P>A1 = SUM(B2;B4) = B2+B3+B4 =56.23 + 560 + 54.54 = 670.77
+ </P>
+ <P><B>Expected result:</B> <BR>Spreadsheet values &amp; the
+ modified standard formula SUM'sl should be displayed in each cell
+ on sheet to reflect the changes as stated above, formulae should
+ be visible in the Formula Bar.&nbsp;</P>
+ </TD>
+ </TR>
+ <TR VALIGN=TOP>
+ <TD WIDTH=431>
+ <P><B>minicalc/convert/content/hiddenrow</B> <BR>&nbsp;</P>
+ </TD>
+ <TD WIDTH=584>
+ <P><B>Summary</B>: Spreadsheet with 5 columns 2 rows 9 entries -
+ Spreadsheet tests hidden row.&nbsp;
+ </P>
+ <P><B>Procedure:</B> <BR>Use test file <B>c_hiddenrow.sxc</B>.&nbsp;
+ </P>
+ <P>Convert c_hiddenrow.sxc to c_hiddenrow.pdb, in MiniCalc PDB
+ format.&nbsp; <BR>Start POSE with MiniCalc application and import
+ c_hiddenrow.pdb.&nbsp; <BR>Select Format -&gt; Row -&gt; Show.&nbsp;
+ <BR>Export the doc back to c_hiddenrow.pdb.&nbsp; <BR>Merge
+ c_hiddenrow.pdb to c_hiddenrow.sxc.&nbsp;
+ </P>
+ <P>A previously hidden row 2 appears.
+ </P>
+ <P><B>Expected result:</B> <BR>Spreadsheet values &amp; standard
+ formula SUM's should be displayed in each cell on sheet as before
+ including a new row #2 which reflects the change stated above.&nbsp;</P>
+ </TD>
+ </TR>
+ <TR VALIGN=TOP>
+ <TD WIDTH=431>
+ <P><B>minicalc/convert/content/invalidcellref</B> <BR>&nbsp;</P>
+ </TD>
+ <TD WIDTH=584>
+ <P><B>Summary</B>: Spreadsheet with 3 columns 3 rows 8 entries -
+ Spreadsheet invalid cell references.&nbsp;
+ </P>
+ <P><B>Procedure:</B> <BR>Use test file <B>c_invalidcellref.sxc</B>.&nbsp;
+ </P>
+ <P>Convert c_invalidcellref.sxc to c_invalidcellref.pdb, in
+ MiniCalc PDB format.&nbsp; <BR>Start POSE with MiniCalc
+ application and import c_invalidcellref.pdb.&nbsp; <BR>Change Cell
+ Reference &quot;A3&quot; = MAX(1;2;3) , &quot;C2&quot; = &quot;blank&quot;,
+ &quot;C3&quot; = a0, in formula bar.&nbsp; <BR>Export the doc back
+ to c_invalidcellref.pdb.&nbsp; <BR>Merge c_invalidcellref.pdb to
+ c_invalidcellref.sxc.&nbsp;
+ </P>
+ <P>Changes should generate 2 extra errors shown below.
+ </P>
+ <P>A3 = 3&nbsp;
+ </P>
+ <P>C2 = &quot;blank&quot;
+ </P>
+ <P>C3 = #NAME?
+ </P>
+ <P><B>Expected result:</B> <BR>&nbsp;Spreadsheet should display
+ all original sheet values, excpet &quot;C3&quot; which holds new
+ invalid input warning generated by the change detailed above,
+ sheet should also show removal of 2 types of invalid input with
+ valid input replacements &quot;A3&quot; &amp; &quot;C2&quot;.</P>
+ </TD>
+ </TR>
+ <TR VALIGN=TOP>
+ <TD WIDTH=431>
+ <P><B>minicalc/convert/content/largerange</B> <BR>&nbsp;</P>
+ </TD>
+ <TD WIDTH=584>
+ <P><B>Summary</B>: Spreadsheet with 3 columns 3 rows 8 entries -
+ Spreadsheet large range test.&nbsp;
+ </P>
+ <P><B>Procedure:</B> <BR>Use test file <B>c_largerange.sxc</B>.&nbsp;
+ </P>
+ <P>Convert c_largerange.sxc to c_largerange.pdb, in MiniCalc PDB
+ format.&nbsp; <BR>Start POSE with MiniCalc application and import
+ c_largerange.pdb.&nbsp; <BR>Change Cell Reference &quot;B3&quot; =
+ SUM(E7:G10), in formula bar.&nbsp; <BR>Export the doc back to
+ c_largerange.pdb.&nbsp; <BR>Merge c_largerange.pdb to
+ c_largerange.sxc.&nbsp;
+ </P>
+ <P>Increases the range by an extra row.
+ </P>
+ <P>B3 = SUM(E7:G10) = E7+F7+G7+E8+F8+G8+E9+F9+G9+E10+F10+G10 =
+ </P>
+ <P>= 4+4+4+2+2+4+1+4+4+1+1+12 = 31 +12 = 43
+ </P>
+ <P><B>Expected result:</B> <BR>&nbsp;Spreadsheet should display
+ all original sheet values, except &quot;B3&quot; which holds new
+ larger range standard formula SUM generated by the change detailed
+ above.</P>
+ </TD>
+ </TR>
+ <TR VALIGN=TOP>
+ <TD WIDTH=431>
+ <P><B>minicalc/convert/content/listrange</B> <BR>&nbsp;</P>
+ </TD>
+ <TD WIDTH=584>
+ <P><B>Summary</B>: Spreadsheet with 5 columns 4 rows 20 entries -
+ Spreadsheet listrange test.&nbsp;
+ </P>
+ <P><B>Procedure:</B> <BR>Use test file <B>c_listrange.sxc</B>.&nbsp;
+
+ </P>
+ <P>Convert c_listrange.sxc to c_listrange.pdb, in MiniCalc PDB
+ format.&nbsp; <BR>Start POSE with MiniCalc application and import
+ c_listrange.pdb.&nbsp; <BR>Change Cell Reference &quot;D3&quot; =
+ 24, in formula bar.&nbsp; <BR>Export the doc back to
+ c_listrange.pdb.&nbsp; <BR>Merge c_listrange.pdb to
+ c_listrange.sxc.&nbsp;
+ </P>
+ <P>D3 = 24
+ </P>
+ <P>A4 = SUM(A1:A3) = 256.1
+ </P>
+ <P>B4 = AVERAGE(A1:A3) = 17.07
+ </P>
+ <P>C4 = AVERAGE(A4:B4) = AVERAGE( 256.1+17.07) = 136.59
+ </P>
+ <P>D4 = AVERAGE(D1;D2;D3) = AVERAGE( 13.1+18+24) = 18.37
+ </P>
+ <P>E5 = SUM(A4:B4:C4:D4) = (256.1+17.07+136.59+18.37) = 428.13<BR>&nbsp;
+ <BR>&nbsp; <BR>&nbsp;
+ </P>
+ <P><B>Expected result:</B> <BR>&nbsp;Spreadsheet should display
+ all original sheet values, except cells &quot;A4-E4&quot; which
+ hold the modified standard formula SUM &amp; AVERAGE value's
+ generated by the change in D3 detailed above.</P>
+ </TD>
+ </TR>
+ <TR VALIGN=TOP>
+ <TD WIDTH=431>
+ <P><B>minicalc/convert/content/mathematical</B> <BR>&nbsp;</P>
+ </TD>
+ <TD WIDTH=584>
+ <P><B>Summary</B>: Spreadsheet with 5 columns 3 rows 15 entries -
+ Spreadsheet stanadard math functs test in (Rad).&nbsp;
+ </P>
+ <P><B>Procedure:</B> <BR>Use test file <B>c_mathematical.sxc</B>.&nbsp;
+
+ </P>
+ <P>Convert c_mathematical.sxc to c_mathematical.pdb, in MiniCalc
+ PDB format.&nbsp; <BR>Start POSE with MiniCalc application and
+ import c_mathematical.pdb.&nbsp; <BR>Change Cell Reference &quot;B1&quot;
+ = SIN(3.14/2), &quot;B2&quot; =COS(0), &quot;C3&quot;= TAN(1.57/2)
+ in formula bar.&nbsp; <BR>Export the doc back to
+ c_mathematical.pdb.&nbsp; <BR>Merge c_mathematical.pdb to
+ c_mathematical.sxc.&nbsp;
+ </P>
+ <P>B1 = 1</P>
+ <P>B2 = 1
+ </P>
+ <P>C3 =1
+ </P>
+ <P><B>Expected result:</B> <BR>&nbsp;Spreadsheet should display
+ all original sheet values except cells &quot;B1,B2,C3&quot; which
+ hold modified sin,cos &amp; tan value's generated by the changes
+ stated above.</P>
+ </TD>
+ </TR>
+ <TR VALIGN=TOP>
+ <TD WIDTH=431>
+ <P><B>minicalc/convert/content/protection</B> <BR>&nbsp;</P>
+ </TD>
+ <TD WIDTH=584>
+ <P><B>Summary</B>: Spreadsheet with 1 column 3 rows 3 entries -
+ Spreadsheet protection test.&nbsp;
+ </P>
+ <P><B>Procedure:</B> <BR>Use test file <B>c_protection.sxc</B>.&nbsp;
+
+ </P>
+ <P>Convert c_protection.sxc to c_protection.pdb, in MiniCalc PDB
+ format.&nbsp; <BR>Start POSE with MiniCalc application and import
+ c_protection.pdb.&nbsp; <BR>Attempt to Change Cell Reference &quot;A1&quot;
+ either directly or in formula bar from the value 12 to 1.&nbsp;
+ <BR>Export the doc back to c_protection.pdb.&nbsp; <BR>Merge
+ c_protection.pdb to c_protection.sxc.&nbsp;
+ </P>
+ <P>User should be unable to change cell contents, popup error
+ message &quot;Protected cells can not be modified&quot; should
+ appear.
+ </P>
+ <P>This is because the Tools -&gt; Protect Document -&gt; Sheet
+ option has been enabled with a password and therefore all cells on
+ sheet are write protected.&nbsp;
+ </P>
+ <P><B>Expected result:</B> <BR>&nbsp;Spreadsheet should display
+ all original sheet values.</P>
+ </TD>
+ </TR>
+ <TR VALIGN=TOP>
+ <TD WIDTH=431>
+ <P><B>minicalc/convert/content/renamedsheet</B> <BR>&nbsp;</P>
+ </TD>
+ <TD WIDTH=584>
+ <P><B>Summary</B>: Spreadsheet with 3 sheets 0 entries -
+ Spreadsheet rename test.&nbsp;
+ </P>
+ <P><B>Procedure:</B> <BR>Use test file <B>c_renamedsheet.sxc</B>.&nbsp;
+
+ </P>
+ <P>Convert c_renamedsheet.sxc to c_renamedsheet.pdb, in MiniCalc
+ PDB format.&nbsp; <BR>Start POSE with MiniCalc application and
+ import c_renamedsheet.pdb.&nbsp; <BR>Change sheet named &quot;testplan&quot;
+ to &quot;renamed&quot;.&nbsp; <BR>Export the doc back to
+ c_renamedsheet.pdb.&nbsp; <BR>Merge c_renamedsheet.pdb to
+ c_renamedsheet.sxc.&nbsp;
+ </P>
+ <P>Click on &quot;testplan&quot; sheet tab, and using 3<SUP>rd</SUP>
+ mouse button, choose Rename..., from popup menu, enter new sheet
+ name &amp; OK.
+ </P>
+ <P>OR choose Format -&gt; Sheet -&gt; Rename... enter new sheet
+ name &amp; OK.
+ </P>
+ <P><B>Expected result:</B> <BR>&nbsp;Spreadsheet should display
+ all original sheets &amp; names, with the exception of the
+ &quot;testplan&quot; sheet which should now be labelled &quot;renamed&quot;
+ .</P>
+ </TD>
+ </TR>
+ <TR VALIGN=TOP>
+ <TD WIDTH=431>
+ <P><B>minicalc/convert/content/sheetreference</B></P>
+ </TD>
+ <TD WIDTH=584>
+ <P><B>Summary</B>: Spreadsheet with 3 sheets 4 columns 4 rows 11
+ entries - Spreadsheet sheetreference test.&nbsp;
+ </P>
+ <P><B>Procedure:</B> <BR>Use test file <B>c_sheetreference.sxc</B>.&nbsp;
+
+ </P>
+ <P>Convert c_sheetreference.sxc to c_sheetreference.pdb, in
+ MiniCalc PDB format.&nbsp; <BR>Start POSE with MiniCalc
+ application and import c_sheetreference.pdb.&nbsp; <BR>Change Cell
+ Reference &quot;A3&quot; = Sheet3.B1.&nbsp; <BR>Export the doc
+ back to c_sheetrefernce.pdb.&nbsp; <BR>Merge c_sheetreference.pdb
+ to c_sheetreference.sxc.&nbsp;
+ </P>
+ <P>A3 = 3.
+ </P>
+ <P>B4 =26.</P>
+ <P><B>Expected result:</B> <BR>&nbsp;Spreadsheet should display
+ all original value's &amp; formulae as in original file, except
+ cells &quot;A3&quot;&amp; &quot;A4&quot; which should display a
+ different sheet reference value and the modified sheet reference
+ formula, reflecting the changes stated above.</P>
+ </TD>
+ </TR>
+ <TR VALIGN=TOP>
+ <TD WIDTH=431>
+ <P><B>minicalc/convert/content/smallrange</B> <BR>&nbsp;</P>
+ </TD>
+ <TD WIDTH=584>
+ <P><B>Summary</B>: Spreadsheet with 4 columns 3 rows 10 entries -
+ Spreadsheet small range test.&nbsp;
+ </P>
+ <P><B>Procedure:</B> <BR>Use test file <B>c_smallrange.sxc</B>.&nbsp;
+
+ </P>
+ <P>Convert c_smallrange.sxc to c_smallrange.pdb, in MiniCalc PDB
+ format.&nbsp; <BR>Start POSE with MiniCalc application and import
+ c_smallrange.pdb.&nbsp; <BR>Change Cell Reference &quot;B3&quot; =
+ AVERAGE(A1:B2), in formula bar.&nbsp; <BR>Export the doc back to
+ c_smallrange.pdb.&nbsp; <BR>Merge c_smallrange.pdb to
+ c_smallrange.sxc.&nbsp;
+ </P>
+ <P>Decrease the range by 1 row.
+ </P>
+ <P>B3 = AVERAGE(A1:B2) = (1+2+3+3)/4 = 2.25
+ </P>
+ <P><B>Expected result:</B> <BR>&nbsp;Spreadsheet should display
+ all original sheet values, except &quot;A3&quot; which now holds
+ average value of new smaller range generated by the change
+ detailed above.</P>
+ </TD>
+ </TR>
+ <TR VALIGN=TOP>
+ <TD WIDTH=431>
+ <P><B>minicalc/convert/content/cancel</B><BR>&nbsp;</P>
+ </TD>
+ <TD WIDTH=584>
+ <P><B>Summary</B>: Spreadsheet with 1 columns 4 rows 4entries -
+ Spreadsheet palm confirm &amp;cancel test.&nbsp;
+ </P>
+ <P><B>Procedure:</B> <BR>Use test file <B>c_cancel.sxc</B>.&nbsp;
+ </P>
+ <P>Convert c_cancel.sxc to c_cancel.pdb, in MiniCalc PDB format.&nbsp;
+ <BR>Start POSE with MiniCalc application and import c_cancel.pdb.&nbsp;
+ <BR>Select with mouse Cell Reference &quot;A2&quot; on dotted line
+ on palm type 14, tap &#8220;TICK&#8221; option (leftmost option on
+ palm) to confirm, repeat this step this time Changing Cell
+ Reference &#8220;A2&#8221; = 1, except this time tap the &#8220;X&#8221;
+ option to cancel.&nbsp; <BR>Export the doc back to c_cancel.pdb.&nbsp;
+ <BR>Merge c_cancel.pdb to c_cancel.sxc.&nbsp;
+ </P>
+ <P>A2 = 14.
+ </P>
+ <P><B>Expected result:</B> <BR>&nbsp;Spreadsheet should display
+ all original sheet values, except &quot;A2&quot; which now holds
+ the value 14 generated by the change detailed above.</P>
+ </TD>
+ </TR>
+ <TR VALIGN=TOP>
+ <TD WIDTH=431>
+ <P><B>minicalc/convert/content/cut&amp;paste</B><BR>&nbsp;</P>
+ </TD>
+ <TD WIDTH=584>
+ <P><B>Summary</B>: Spreadsheet with 1 columns 4 rows 4entries -
+ Spreadsheet palm cut&amp;paste test.&nbsp;
+ </P>
+ <P><B>Procedure:</B> <BR>Use test file <B>c_cut&amp;paste.sxc</B>.&nbsp;
+
+ </P>
+ <P>Convert c_cut&amp;paste.sxc to c_cut&amp;paste.pdb, in MiniCalc
+ PDB format.&nbsp; <BR>Start POSE with MiniCalc application and
+ import c_cut&amp;paste.pdb.&nbsp; <BR>Choose Cell Reference &quot;A2&quot;
+ with mouse, tap cut option on palm, choose Cell Reference &#8220;A5&#8221;
+ and tap paste option.&nbsp; <BR>Export the doc back to
+ c_cut&amp;paste.pdb.&nbsp; <BR>Merge c_cut&amp;paste.pdb to
+ c_cut&amp;paste.sxc.&nbsp;
+ </P>
+ <P>A2 = &#8220;blank&#8221;.</P>
+ <P>A5 = 14.
+ </P>
+ <P><B>Expected result:</B> <BR>&nbsp;Spreadsheet should display
+ all original sheet values, except &quot;A2&quot; &amp; &#8220;A5&#8221;
+ which now holds the values blank &amp; 14 resp. generated by the
+ changes detailed above.</P>
+ </TD>
+ </TR>
+ <TR VALIGN=TOP>
+ <TD WIDTH=431>
+ <P><B>minicalc/convert/content/copy&amp;paste</B><BR>&nbsp;</P>
+ </TD>
+ <TD WIDTH=584>
+ <P><B>Summary</B>: Spreadsheet with 1 columns 4 rows 4entries -
+ Spreadsheet palm copy&amp;paste test.&nbsp;
+ </P>
+ <P><B>Procedure:</B> <BR>Use test file <B>c_copy&amp;paste.sxc</B>.&nbsp;
+
+ </P>
+ <P>Convert c_copy&amp;paste.sxc to c_copy&amp;paste.pdb, in
+ MiniCalc PDB format.&nbsp; <BR>Start POSE with MiniCalc
+ application and import c_copy&amp;paste.pdb.&nbsp; <BR>Choose Cell
+ Reference &quot;A5&quot; with mouse, tap copy option on palm,
+ choose Cell Reference &#8220;A2&#8221; and tap paste option.&nbsp;
+ <BR>Export the doc back to c_copy&amp;paste.pdb.&nbsp; <BR>Merge
+ c_copy&amp;paste.pdb to c_copy&amp;paste.sxc.&nbsp;
+ </P>
+ <P>A2 = 14.</P>
+ <P>A5 = 14.
+ </P>
+ <P><B>Expected result:</B> <BR>&nbsp;Spreadsheet should display
+ all original sheet values, except &quot;A2&quot; which now holds
+ the value 14 generated by the change detailed above.</P>
+ </TD>
+ </TR>
+ <TR VALIGN=TOP>
+ <TD WIDTH=431>
+ <P><B>minicalc/convert/content/textentry</B><BR>&nbsp;</P>
+ </TD>
+ <TD WIDTH=584>
+ <P><B>Summary</B>: Spreadsheet with 1 columns 4 rows 4entries -
+ Spreadsheet palm text entry test.&nbsp;
+ </P>
+ <P><B>Procedure:</B> <BR>Use test file <B>c_textentry.sxc</B>.&nbsp;
+
+ </P>
+ <P>Convert c_textentry.sxc to c_textentry.pdb, in MiniCalc PDB
+ format.&nbsp; <BR>Start POSE with MiniCalc application and import
+ c_textentry.pdb.&nbsp; <BR>Choose Cell Reference &quot;A1&quot;
+ with mouse, tap textentry option on palm, type the following text
+ string into the popup text box &#8220;This is a MiniCalc text
+ entry test.&#8221;.<BR>Export the doc back to c_textentry.pdb.&nbsp;
+ <BR>Merge c_textentry.pdb to c_textentry.sxc.&nbsp;
+ </P>
+ <P>A1 = &#8220;This is a MiniCalc text entry test.&#8221;</P>
+ <P><B>Expected result:</B> <BR>&nbsp;Spreadsheet should display
+ all original sheet values, except &quot;A1&quot; which now holds
+ the string &#8220;This is a MiniCalc text entry test&#8221;,
+ generated by the change detailed above.</P>
+ </TD>
+ </TR>
+ <TR VALIGN=TOP>
+ <TD WIDTH=431>
+ <P><B>minicalc/convert/content/function</B><BR>&nbsp;</P>
+ </TD>
+ <TD WIDTH=584>
+ <P><B>Summary</B>: Spreadsheet with 1 columns 4 rows 4entries -
+ Spreadsheet palm function test.&nbsp;
+ </P>
+ <P><B>Procedure:</B> <BR>Use test file <B>c_function.sxc</B>.&nbsp;
+
+ </P>
+ <P>Convert c_function.sxc to c_function.pdb, in MiniCalc PDB
+ format.&nbsp; <BR>Start POSE with MiniCalc application and import
+ c_function.pdb.&nbsp; <BR>Choose Cell Reference &quot;A1&quot;
+ with mouse, tap standard function option on palm, choose the
+ function AVERAGE from the popup list by tapping, type the values
+ &#8220;1;2;3&#8221; between the function brackets on the dotted
+ line were the cursor is placed and press return.<BR>Export the doc
+ back to c_function.pdb.&nbsp; <BR>Merge c_function.pdb to
+ c_function.sxc.&nbsp;
+ </P>
+ <P>A1 = AVERAGE(1;2;3) = 2.</P>
+ <P><B>Expected result:</B> <BR>&nbsp;Spreadsheet should display
+ all original sheet values, except &quot;A1&quot; which now holds
+ the result of the average function given args (1;2;3) = 2
+ generated by the change detailed above.</P>
+ </TD>
+ </TR>
+ <TR VALIGN=TOP>
+ <TD WIDTH=431>
+ <P><B>minicalc/convert/content/numberpad</B><BR>&nbsp;</P>
+ </TD>
+ <TD WIDTH=584>
+ <P><B>Summary</B>: Spreadsheet with 1 columns 4 rows 4entries -
+ Spreadsheet palm numberpad test.&nbsp;
+ </P>
+ <P><B>Procedure:</B> <BR>Use test file <B>c_numberpad.sxc</B>.&nbsp;
+
+ </P>
+ <P>Convert c_numberpad.sxc to c_numberpad.pdb, in MiniCalc PDB
+ format.&nbsp; <BR>Start POSE with MiniCalc application and import
+ c_numberpad.pdb.&nbsp; <BR>Choose Cell Reference &quot;A1&quot;
+ with mouse, tap the &#8220;123&#8221; option on the palm, tap
+ &#8220;-&gt;&#8221;, &#8220;=&#8221;, &#8220;5-0+2&#8221; from
+ popup numberpad, and press return.<BR>Export the doc back to
+ c_numberpad.pdb.&nbsp; <BR>Merge c_numberpad.pdb to
+ c_numberpad.sxc.&nbsp;
+ </P>
+ <P>A1 = 5-0+2 = 7.</P>
+ <P><B>Expected result:</B> <BR>&nbsp;Spreadsheet should display
+ all original sheet values, except &quot;A1&quot; which now holds
+ the result of the formula 5-0+2, generated by the change detailed
+ above.</P>
+ </TD>
+ </TR>
+ <TR VALIGN=TOP>
+ <TD WIDTH=431>
+ <P><B>minicalc/convert/content/math_funcs</B></P>
+ </TD>
+ <TD WIDTH=584>
+ <P><B>Summary</B>: Spreadsheet with 1 columns 4 rows 4entries -
+ Spreadsheet palm numberpad test.&nbsp;
+ </P>
+ <P><B>Procedure:</B> <BR>Use test file <B>c_math_funcs.sxc</B>.&nbsp;
+
+ </P>
+ <P>Convert c_math_funcs.sxc to c_math_funcs.pdb, in MiniCalc PDB
+ format.&nbsp; <BR>Start POSE with MiniCalc application and import
+ c_math_funcs.pdb.&nbsp; <BR>Choose the Cell References below with
+ mouse,and for each type on the palm the corresponding entry before
+ pressing return.</P>
+ <P>A1 = <BR>Export the doc back to c_math_funcs.pdb.&nbsp; <BR>Merge
+ c_math_funcs.pdb to c_math_funcs.sxc.&nbsp;
+ </P>
+ <P>A1 = .</P>
+ <P>A2 =</P>
+ <P>A3 =
+ </P>
+ <P>A4 =</P>
+ <P><BR><BR>
+ </P>
+ <P><B>Expected result:</B> <BR>&nbsp;Spreadsheet should display
+ all original sheet values, except &quot;A1&quot; which now holds
+ the result of the formula 5-0+2, generated by the change detailed
+ above.</P>
+ </TD>
+ </TR>
+ <TR VALIGN=TOP>
+ <TD WIDTH=431>
+ <P><B>minicalc/convert/content/insertrow</B><BR>&nbsp;</P>
+ </TD>
+ <TD WIDTH=584>
+ <P><B>Summary</B>: Spreadsheet with 1 columns 4 rows 4entries -
+ Spreadsheet palm insert row test.&nbsp;
+ </P>
+ <P><B>Procedure:</B> <BR>Use test file <B>c_insertrow.sxc</B>.&nbsp;
+
+ </P>
+ <P>Convert c_insertrow.sxc to c_insertrow.pdb, in MiniCalc PDB
+ format.&nbsp; <BR>Start POSE with MiniCalc application and import
+ c_insertrow.pdb.&nbsp;</P>
+ <P><BR>Select Cell Reference &quot;A3&quot; with mouse, tap the
+ side bar of the spreadsheet at position 3 on the palm, tap
+ &#8220;Insert&#8221; from popup menu, and press return. Select the
+ newly inserted Cell Reference with mouse and enter the number &#8220;2&#8221;,
+ press return.<BR><BR><BR>
+ </P>
+ <P>Export the doc back to c_insertrow.pdb.&nbsp; <BR>Merge
+ c_insertrow.pdb to c_insertrow.sxc.&nbsp;
+ </P>
+ <P>A1 = .</P>
+ <P><B>Expected result:</B> <BR>&nbsp;Spreadsheet should display
+ all original sheet values, except &quot;A1&quot; which now holds
+ the result of the formula 5-0+2, generated by the change detailed
+ above.</P>
+ </TD>
+ </TR>
+ <TR VALIGN=TOP>
+ <TD WIDTH=431>
+ <P><B>minicalc/convert/content/multi_boolean</B></P>
+ </TD>
+ <TD WIDTH=584>
+ <P><B>Summary</B>: Spreadsheet with 1 column 8 entries -
+ Spreadsheet multi boolean entry.&nbsp;
+ </P>
+ <P><B>Procedure:</B> <BR>Use test file <B>c_multi_boolean.sxc</B>.
+
+ </P>
+ <P>Convert c_multi_boolean.sxc to c_multi_boolean.pdb, in MiniCalc
+ PDB format.&nbsp; <BR>Start POSE with MiniCalc application and
+ import c_multi_boolean.pdb.&nbsp; <BR>Export the doc back to
+ c_multi_boolean.pdb.&nbsp; <BR>Merge c_multi_boolean.pdb to
+ c_multi_boolean.sxc.&nbsp;
+ </P>
+ <P>Logical Funtion test : cells A1-A4:
+ </P>
+ <P>A1-A4 = FALSE
+ </P>
+ <P>A5-A8 = TRUE
+ </P>
+ <P>Returns 4 logical FALSE &amp; TRUE values resp..
+ </P>
+ <P><B>Expected result:</B> <BR>&nbsp;The logical entry of each
+ cell should be displayed on the sheet as stated above.</P>
+ </TD>
+ </TR>
+ <TR VALIGN=TOP>
+ <TD WIDTH=431>
+ <P><BR>
+ </P>
+ </TD>
+ <TD WIDTH=584>
+ <P><BR>
+ </P>
+ </TD>
+ </TR>
+</TABLE>
+<P><BR>&nbsp; <BR>&nbsp; <BR>&nbsp;
+</P>
+</BODY>
+</HTML> \ No newline at end of file
diff --git a/xmerge/source/pexcel/build.xml b/xmerge/source/pexcel/build.xml
new file mode 100644
index 000000000000..caaf8cefbfcd
--- /dev/null
+++ b/xmerge/source/pexcel/build.xml
@@ -0,0 +1,76 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ #*************************************************************************
+ #
+ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+
+ Copyright 2000, 2010 Oracle and/or its affiliates.
+
+ OpenOffice.org - a multi-platform office productivity suite
+
+ This file is part of OpenOffice.org.
+
+ OpenOffice.org is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License version 3
+ only, as published by the Free Software Foundation.
+
+ OpenOffice.org is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License version 3 for more details
+ (a copy is included in the LICENSE file that accompanied this code).
+
+ You should have received a copy of the GNU Lesser General Public License
+ version 3 along with OpenOffice.org. If not, see
+ <http://www.openoffice.org/license.html>
+ for a copy of the LGPLv3 License.
+
+ #*************************************************************************
+ -->
+
+<project name="pexcel" default="all" basedir=".">
+
+ <property file="../inc/antbuild.properties"/>
+
+ <path id="classpath">
+ <pathelement location="${build.dir}/xmerge.jar"/>
+ </path>
+
+
+ <target name="init" >
+ <mkdir dir="${target.dir}"/>
+ </target>
+
+ <!-- compile java sources in ${package} -->
+ <target name="compile" depends="init">
+ <javac srcdir="${src.dir}"
+ destdir="${target.dir}"
+ debug="${debug}"
+ deprecation="${deprecation}"
+ optimize="${optimize}">
+ <classpath refid="classpath"/>
+ </javac>
+ </target>
+
+ <!-- package to jar -->
+ <target name="jar" depends="compile">
+ <jar destfile="${target.jar}">
+ <fileset dir="${target.dir}"
+ includes="**/*.class" />
+ <metainf dir="${basedir}">
+ <filename name="converter.xml"/>
+ </metainf>
+ </jar>
+ </target>
+
+ <!-- clean up -->
+ <target name="clean">
+ <delete dir="${class.dir}"/>
+ <delete file="${target.jar}"/>
+ </target>
+
+ <target name="all" depends="jar">
+ </target>
+
+</project>
+
diff --git a/xmerge/source/pexcel/converter.xml b/xmerge/source/pexcel/converter.xml
new file mode 100644
index 000000000000..205f60ef59d5
--- /dev/null
+++ b/xmerge/source/pexcel/converter.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0"?>
+<!--
+ #*************************************************************************
+ #
+ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+
+ Copyright 2000, 2010 Oracle and/or its affiliates.
+
+ OpenOffice.org - a multi-platform office productivity suite
+
+ This file is part of OpenOffice.org.
+
+ OpenOffice.org is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License version 3
+ only, as published by the Free Software Foundation.
+
+ OpenOffice.org is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License version 3 for more details
+ (a copy is included in the LICENSE file that accompanied this code).
+
+ You should have received a copy of the GNU Lesser General Public License
+ version 3 along with OpenOffice.org. If not, see
+ <http://www.openoffice.org/license.html>
+ for a copy of the LGPLv3 License.
+
+ #*************************************************************************
+ -->
+<converters>
+ <converter type="staroffice/sxc" version="1.0">
+ <converter-display-name>
+ Pocket Excel 2.0
+ </converter-display-name>
+ <converter-description>
+ StarCalc XML to/from Pocket Excel 2.0 conversion
+ </converter-description>
+ <converter-vendor>OpenOffice.org</converter-vendor>
+ <converter-class-impl>
+ org.openoffice.xmerge.converter.xml.sxc.pexcel.PluginFactoryImpl
+ </converter-class-impl>
+ <converter-target type="application/x-pocket-excel" />
+ </converter>
+</converters>
+
diff --git a/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/ConverterCapabilitiesImpl.java b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/ConverterCapabilitiesImpl.java
new file mode 100644
index 000000000000..c39b95a173ad
--- /dev/null
+++ b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/ConverterCapabilitiesImpl.java
@@ -0,0 +1,113 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxc.pexcel;
+
+import org.openoffice.xmerge.ConverterCapabilities;
+import org.openoffice.xmerge.converter.xml.OfficeConstants;
+
+
+/**
+ * <p>Pocket Excel implementation of <code>ConverterCapabilities</code> for
+ * the {@link
+ * org.openoffice.xmerge.converter.xml.sxc.pexcel.PluginFactoryImpl
+ * PluginFactoryImpl}.</p>
+ *
+ * <p>Used with StarCalc SXC to/from Pocket Excel conversions. The
+ * <code>ConverterCapibilies</code> specify which &quot;Office&quot;
+ * <code>Document</code> tags and attributes are supported on the
+ * &quot;Device&quot; <code>Document</code> format.</p>
+ */
+public final class ConverterCapabilitiesImpl
+ implements ConverterCapabilities {
+
+ public boolean canConvertTag(String tag) {
+
+ if (OfficeConstants.TAG_OFFICE_BODY.equals(tag))
+ return true;
+ else if (OfficeConstants.TAG_PARAGRAPH.equals(tag))
+ return true;
+ else if (OfficeConstants.TAG_TABLE.equals(tag))
+ return true;
+ else if (OfficeConstants.TAG_TABLE_ROW.equals(tag))
+ return true;
+ else if (OfficeConstants.TAG_TABLE_COLUMN.equals(tag))
+ return false;
+ // TODO - we currently do not handle the table column tag
+ else if (OfficeConstants.TAG_TABLE_SCENARIO.equals(tag))
+ return false;
+ // TODO - we currently do not handle the table scenario tag
+ else if (OfficeConstants.TAG_TABLE_CELL.equals(tag))
+ return true;
+
+ return false;
+ }
+
+ public boolean canConvertAttribute(String tag,
+ String attribute) {
+
+ if (OfficeConstants.TAG_TABLE.equals(tag)) {
+
+ if (OfficeConstants.ATTRIBUTE_TABLE_NAME.equals(attribute))
+ return true;
+
+ } else if (OfficeConstants.TAG_TABLE_CELL.equals(tag)) {
+
+ if (OfficeConstants.ATTRIBUTE_TABLE_VALUE_TYPE.equals(attribute))
+ return true;
+ else if (OfficeConstants.ATTRIBUTE_TABLE_FORMULA.
+ equals(attribute))
+ return true;
+ else if (OfficeConstants.ATTRIBUTE_TABLE_VALUE.equals(attribute))
+ return true;
+ else if (OfficeConstants.ATTRIBUTE_TABLE_BOOLEAN_VALUE.
+ equals(attribute))
+ return true;
+ else if (OfficeConstants.ATTRIBUTE_TABLE_CURRENCY.
+ equals(attribute))
+ return true;
+ else if (OfficeConstants.ATTRIBUTE_TABLE_TIME_VALUE.
+ equals(attribute))
+ return true;
+ else if (OfficeConstants.ATTRIBUTE_TABLE_DATE_VALUE.
+ equals(attribute))
+ return true;
+ else if (OfficeConstants.ATTRIBUTE_TABLE_NUM_COLUMNS_REPEATED.
+ equals(attribute))
+ return true;
+
+ } else if (OfficeConstants.TAG_TABLE_ROW.equals(tag)) {
+
+ if (OfficeConstants.ATTRIBUTE_TABLE_NUM_ROWS_REPEATED.
+ equals(attribute))
+ return true;
+ }
+
+ return false;
+ }
+}
+
diff --git a/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/PluginFactoryImpl.java b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/PluginFactoryImpl.java
new file mode 100644
index 000000000000..3b45b2bf680c
--- /dev/null
+++ b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/PluginFactoryImpl.java
@@ -0,0 +1,130 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxc.pexcel;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.openoffice.xmerge.ConvertData;
+import org.openoffice.xmerge.Document;
+import org.openoffice.xmerge.DocumentSerializer;
+import org.openoffice.xmerge.DocumentSerializerFactory;
+import org.openoffice.xmerge.DocumentDeserializer;
+import org.openoffice.xmerge.DocumentDeserializerFactory;
+import org.openoffice.xmerge.DocumentMerger;
+import org.openoffice.xmerge.ConverterCapabilities;
+import org.openoffice.xmerge.converter.xml.sxc.DocumentMergerImpl;
+import org.openoffice.xmerge.converter.xml.sxc.SxcPluginFactory;
+import org.openoffice.xmerge.converter.xml.sxc.pexcel.records.Workbook;
+import org.openoffice.xmerge.util.registry.ConverterInfo;
+
+/**
+ * <p>Pocket Excel implementation of the <code>PluginFactory</code>.
+ * This encapsulates conversion of StarCalc XML format to and from
+ * Pocket Excel format.</p>
+ *
+ * <p>The superclass produces a particular
+ * {@link org.openoffice.xmerge.Document Document}
+ * object, i.e. {@link
+ * org.openoffice.xmerge.converter.xml.sxc.SxcDocument
+ * SxcDocument} that the converters in this class works with. Thus,
+ * this class only implements the methods that produces the converters,
+ * i.e. {@link
+ * org.openoffice.xmerge.DocumentSerializer
+ * DocumentSerializer} and {@link
+ * org.openoffice.xmerge.DocumentDeserializer
+ * DocumentDeserializer};
+ * as well as the {@link
+ * org.openoffice.xmerge.ConverterCapabilities
+ * ConverterCapabilities} object that is specific to this format
+ * conversion. That superclass also produces a {@link
+ * org.openoffice.xmerge.DocumentMerger DocumentMerger}
+ * object, i.e. {@link
+ * org.openoffice.xmerge.converter.xml.sxc.DocumentMergerImpl
+ * DocumentMergerImpl} which this class derives the functionality.</p>
+ */
+public final class PluginFactoryImpl extends SxcPluginFactory
+ implements DocumentDeserializerFactory, DocumentSerializerFactory {
+
+ /** ConverterCapabilities object for this type of conversion. */
+ private final static ConverterCapabilities converterCap =
+ new ConverterCapabilitiesImpl();
+
+
+ public PluginFactoryImpl(ConverterInfo ci) {
+ super(ci);
+ }
+
+
+ /**
+ * Returns an instance of <code>DocumentSerializerImpl</code>,
+ * which is an implementation of <code>DocumentSerializer</code>
+ * interface.
+ *
+ * @param doc <code>Document</code> object to be
+ * converted/serialized.
+ *
+ * @return A <code>DocumentSerializerImpl</code> object.
+ */
+ public DocumentSerializer createDocumentSerializer(Document doc) {
+
+ return new SxcDocumentSerializerImpl(doc);
+ }
+
+
+ /**
+ * Returns an instance of <code>DocumentDeserializerImpl</code>,
+ * which is an implementation of <code>DocumentDeserializer</code>
+ * interface.
+ *
+ * @param cd <code>ConvertData</code> object for reading data
+ * which will be converted back to a
+ * <code>Document</code> object.
+ *
+ * @return A <code>DocumentDeserializerImpl</code> object.
+ */
+ public DocumentDeserializer createDocumentDeserializer(ConvertData cd) {
+
+ return new SxcDocumentDeserializerImpl(cd);
+ }
+
+
+ public Document createDeviceDocument(String name, InputStream is)
+ throws IOException {
+
+ Workbook wb = new Workbook(name, is);
+ return wb;
+ }
+
+ public DocumentMerger createDocumentMerger(Document doc) {
+
+ DocumentMergerImpl merger = new DocumentMergerImpl(doc, converterCap);
+ return merger;
+ }
+}
+
diff --git a/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/PocketExcelConstants.java b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/PocketExcelConstants.java
new file mode 100644
index 000000000000..13f73f18fdae
--- /dev/null
+++ b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/PocketExcelConstants.java
@@ -0,0 +1,67 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxc.pexcel;
+
+
+/**
+ * Interface defining constants for Pocket Excel attributes.
+ *
+ * @author Martin Maher
+ */
+public interface PocketExcelConstants {
+ /** File extension for Pocket Word files. */
+ public static final String FILE_EXTENSION = ".pxl";
+
+ /** Constants for pexcel BIFF records */
+ public static final int BLANK_CELL = 0x01;
+ public static final int NUMBER_CELL = 0x03;
+ public static final int LABEL_CELL = 0x04;
+ public static final int BOOLERR_CELL = 0x05;
+ public static final int FORMULA_CELL = 0x06;
+ public static final int FORMULA_STRING = 0x07;
+ public static final int ROW_DESCRIPTION = 0x08;
+ public static final int BOF_RECORD = 0x09;
+ public static final int EOF_MARKER = 0x0A;
+ public static final int DEFINED_NAME = 0x18;
+ public static final int CURRENT_SELECTION = 0x1D;
+ public static final int NUMBER_FORMAT = 0x1E;
+ public static final int DEFAULT_ROW_HEIGHT = 0x25;
+ public static final int FONT_DESCRIPTION = 0x31;
+ public static final int WINDOW_INFO = 0x3D;
+ public static final int SHEET_WINDOW_INFO = 0x3E;
+ public static final int PANE_INFO = 0x41;
+ public static final int CODEPAGE = 0x42;
+ public static final int DEF_COL_WIDTH = 0x55;
+ public static final int COLINFO = 0x7D;
+ public static final int BOUND_SHEET = 0x85;
+ public static final int EXTENDED_FORMAT = 0xE0;
+
+ /** Colour lookup table for mapping pexcel color values
+ (See util/ColourConverter.java */
+ public short cLookup[] = { 0, 14, 15, 1, 2, 3, 4, 7, 6, 5, 8, 9, 10, 13, 12, 11 };
+}
diff --git a/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/PocketExcelDecoder.java b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/PocketExcelDecoder.java
new file mode 100644
index 000000000000..dbfc43a64cd6
--- /dev/null
+++ b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/PocketExcelDecoder.java
@@ -0,0 +1,438 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxc.pexcel;
+
+import java.io.IOException;
+import java.util.Vector;
+import java.util.Enumeration;
+import java.util.NoSuchElementException;
+
+import org.openoffice.xmerge.ConvertData;
+import org.openoffice.xmerge.converter.xml.OfficeConstants;
+import org.openoffice.xmerge.util.Debug;
+import org.openoffice.xmerge.converter.xml.sxc.BookSettings;
+import org.openoffice.xmerge.converter.xml.sxc.SpreadsheetDecoder;
+import org.openoffice.xmerge.converter.xml.sxc.Format;
+import org.openoffice.xmerge.converter.xml.sxc.NameDefinition;
+import org.openoffice.xmerge.converter.xml.sxc.ColumnRowInfo;
+import org.openoffice.xmerge.converter.xml.sxc.pexcel.records.*;
+
+/**
+ * This class is used by {@link
+ * org.openoffice.xmerge.converter.xml.sxc.SxcDocumentDeserializerImpl}
+ * SxcDocumentDeserializerImpl} to decode the Pocket Excel format.
+ *
+ * @author Paul Rank
+ */
+final class PocketExcelDecoder extends SpreadsheetDecoder {
+
+ private Workbook wb;
+ private Worksheet ws;
+ private CellValue cell;
+ private int maxRows = 0;
+ private int maxCols = 0;
+ private int wsIndex;
+ private Enumeration cellValue;
+ private Format fmt = null;
+
+ /**
+ * Constructor creates a Pocket Excel WorkBook.
+ *
+ * @param name The name of the WorkBook.
+ * @param worksheetNames set of Strings equivalent to the worksheets
+ * contained in the workbook
+ * @param password The password for the workBook.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ PocketExcelDecoder(String name, String[] worksheetNames, String password) throws IOException {
+ super(name, password);
+
+ fmt = new Format();
+ }
+
+
+ /**
+ * This method takes a <code>ConvertData</code> as input and
+ * converts it into a PocketWord WorkSheet. The WorkSheet is then
+ * added to the WorkBook.
+ *
+ * @param InputStream An <code>ConvertData</code> containing a
+ * Pocket Excel WorkSheet.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ public void addDeviceContent(ConvertData cd) throws IOException {
+
+ Enumeration e = cd.getDocumentEnumeration();
+ wb = (Workbook) e.nextElement();
+ }
+
+
+ /**
+ * This method returns the number of spreadsheets
+ * stored in the WorkBook.
+ *
+ * @return The number of sheets in the WorkBook.
+ */
+ public int getNumberOfSheets() {
+
+ Vector v = wb.getWorksheetNames();
+ Debug.log(Debug.TRACE,"Total Number of Sheets : " + v.size());
+ return (v.size());
+ }
+
+ /**
+ * This method returns the number of spreadsheets
+ * stored in the WorkBook.
+ *
+ * @return The number of sheets in the WorkBook.
+ */
+ public Enumeration getNameDefinitions() {
+
+ Enumeration e = wb.getDefinedNames();
+ Vector nameDefinitionVector = new Vector();
+ while(e.hasMoreElements()) {
+ DefinedName dn = (DefinedName)e.nextElement();
+ NameDefinition nameDefinitionEntry = dn.getNameDefinition();
+ nameDefinitionVector.add(nameDefinitionEntry);
+ }
+ Debug.log(Debug.TRACE,"Getting " + nameDefinitionVector.size() + " DefinedName records");
+ return (nameDefinitionVector.elements());
+ }
+
+ /**
+ * This method returns an enumeration of Settings object(s),
+ * one for each worksheet
+ *
+ * @return An enumerattion of <code>Settings</code>
+ */
+ public BookSettings getSettings() {
+
+ return (wb.getSettings());
+ }
+ /**
+ * This method returns the number of spreadsheets
+ * stored in the WorkBook.
+ *
+ * @return The number of sheets in the WorkBook.
+ */
+ public Enumeration getColumnRowInfos() {
+
+ Vector colRowVector = new Vector();
+
+ // Collect Columns from worksheet and add them to the vector
+ for(Enumeration e = ws.getColInfos();e.hasMoreElements();) {
+ ColInfo ci = (ColInfo)e.nextElement();
+ int repeated = ci.getLast() - ci.getFirst() + 1;
+ ColumnRowInfo colInfo = new ColumnRowInfo( ci.getColWidth(),
+ repeated,
+ ColumnRowInfo.COLUMN);
+ colRowVector.add(colInfo);
+ }
+
+ // Collect Rows from worksheet and add them to the vector
+ for(Enumeration e = ws.getRows();e.hasMoreElements();) {
+ Row rw = (Row)e.nextElement();
+ // We will use the repeat field for number (unlike columns rows
+ // cannot be repeated, we have unique record for each row in pxl
+ int repeated = rw.getRowNumber();
+ ColumnRowInfo rowInfo = new ColumnRowInfo( rw.getRowHeight(),
+ repeated,
+ ColumnRowInfo.ROW);
+ colRowVector.add(rowInfo);
+ }
+ Debug.log(Debug.TRACE,"Getting " + colRowVector.size() + " ColRowInfo records");
+ return (colRowVector.elements());
+ }
+
+ /**
+ * This method gets the requested WorkSheet from the
+ * WorkBook and sets it as the selected WorkSheet. All
+ * other "get" methods will now get data from this WorkSheet.
+ *
+ * @param sheetIndex The index number of the sheet to open.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ public void setWorksheet(int sheetIndex) throws IOException {
+ Debug.log(Debug.TRACE,"Setting to worksheet : " + sheetIndex);
+ ws = wb.getWorksheet(sheetIndex);
+ cellValue = ws.getCellEnumerator();
+ wsIndex = sheetIndex;
+ while(goToNextCell()) {
+ maxRows = Math.max(maxRows, cell.getRow());
+ maxCols = Math.max(maxCols, cell.getCol());
+ }
+ cellValue = ws.getCellEnumerator();
+ Debug.log(Debug.TRACE,"Max Cols : " + maxCols + " MaxRows : " + maxRows);
+ }
+
+
+ /**
+ * This method returns the name of the current spreadsheet.
+ *
+ * @return The name of the current WorkSheet.
+ */
+ public String getSheetName() {
+
+ String wsName = wb.getSheetName(wsIndex);
+ Debug.log(Debug.TRACE,"The name of the current Worksheet is : " + wsName);
+ return wsName;
+ }
+
+
+ /**
+ * This method gets the next cell from the WorkSheet
+ * and sets it as the selected cell. All other "get"
+ * methods will now get data from this cell.
+ *
+ * @return True if we were able to go to another cell
+ * in the sheet, false if there were no cells
+ * left.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ public boolean goToNextCell() throws IOException {
+
+ boolean success = false;
+
+ try {
+ cell = (CellValue) cellValue.nextElement();
+ Debug.log(Debug.TRACE,"Current Cell : " + cell.getString());
+ readCellFormat();
+ success = true;
+ } catch (NoSuchElementException e) {
+ Debug.log(Debug.TRACE,"Could't find current cell");
+ }
+
+ return success;
+ }
+
+
+ /**
+ * This method returns the row number of the current cell.
+ *
+ * @return The row number of the current cell. Returns
+ * -1 if no cell is currently selected.
+ */
+ public int getRowNumber() {
+
+ int row = -1;
+
+ if (cell != null) {
+ row = cell.getRow();
+ Debug.log(Debug.TRACE,"cell row is " + row);
+ }
+ return (row);
+ }
+
+ /**
+ * This method returns the number of rows in the current sheet.
+ *
+ * @return The number of rows in the current sheet.
+ */
+ public int getNumberOfRows() {
+ return maxRows;
+ }
+
+ /**
+ * This method returns the number of columns in the current sheet.
+ *
+ * @return The number of columns in the current sheet.
+ */
+ public int getNumberOfColumns() {
+ return maxCols;
+ }
+
+
+ /**
+ * This method returns the col number of the current cell.
+ *
+ * @return The col number of the current cell. Returns
+ * -1 if no cell is currently selected.
+ */
+ public int getColNumber() {
+
+ int col = -1;
+
+ if (cell != null) {
+ col = cell.getCol();
+ Debug.log(Debug.TRACE,"cell col is " + col);
+ }
+ return (col);
+ }
+
+ /**
+ * This method returns the contents of the current cell.
+ *
+ * @return The contents of the current cell. Returns
+ * null if no cell is currently selected.
+ */
+ public String getCellContents() {
+
+ String contents = new String("");
+
+ if (cell != null) {
+ try {
+ contents = cell.getString();
+ if (contents.startsWith("=")) {
+ contents = parseFormula(contents);
+ }
+ }
+ catch (IOException e) {
+ System.err.println("Could Not retrieve Cell contents");
+ System.err.println("Setting contents of cell(" + cell.getRow()
+ + "," + cell.getCol() + ") to an empty string");
+ System.err.println("Error msg: " + e.getMessage());
+ }
+ }
+
+ return contents;
+ }
+
+ /**
+ * <p>This method takes a formula and parses it into
+ * StarOffice XML formula format.</p>
+ *
+ * <p>Many spreadsheets use ',' as a separator.
+ * StarOffice XML format uses ';' as a separator instead.</p>
+ *
+ * <p>Many spreadsheets use '!' as a separator when refencing
+ * a cell in a different sheet.</p>
+ *
+ * <blockquote>
+ * Example: =sheet1!A1
+ * </blockquote>
+ *
+ * <p>StarOffice XML format uses '.' as a separator instead.</p>
+ *
+ * <blockquote>
+ * Example: =sheet1.A1
+ * </blockquote>
+ *
+ * @param formula A formula string.
+ *
+ * @return A StarOffice XML format formula string.
+ */
+ protected String parseFormula(String formula) {
+
+ formula = formula.replace(',', ';');
+ formula = formula.replace('!', '.');
+
+ return formula;
+ }
+
+ /**
+ * This method returns the contents of the current cell.
+ *
+ * @return The contents of the current cell. Returns
+ * null if no cell is currently selected.
+ */
+ public String getCellValue() {
+
+ String contents = new String("");
+
+ if (cell != null) {
+ try {
+ contents = ((Formula)cell).getValue();
+ }
+ catch (IOException e) {
+ System.err.println("Could Not retrieve Cell value");
+ System.err.println("Setting value of cell(" + cell.getRow()
+ + "," + cell.getCol() + ") to an empty string");
+ System.err.println("Error msg: " + e.getMessage());
+ }
+ }
+ return contents;
+ }
+
+ /**
+ * <p>This method returns the type of the data in the current cell.
+ * Currently the only type supported is String.</p>
+ *
+ * @return The type of the data in the current cell.
+ */
+ public String getCellDataType() {
+
+ String type = OfficeConstants.CELLTYPE_STRING;
+
+ if(cell instanceof FloatNumber)
+ type = OfficeConstants.CELLTYPE_FLOAT;
+ if(cell instanceof Formula)
+ type = OfficeConstants.CELLTYPE_FLOAT;
+
+ return type;
+ }
+
+
+ /**
+ * Return the Format object describing the active cell formatting.
+ *
+ * @return The Format object describing the active cell formatting.
+ */
+ public Format getCellFormat() {
+ return new Format(fmt);
+ }
+
+
+ /**
+ * Create the format data for the new cell.
+ */
+ private void readCellFormat() throws IOException {
+
+ fmt.clearFormatting();
+
+ Debug.log(Debug.TRACE," ixfe for Current Cell " + cell.getIxfe());
+ ExtendedFormat xf = wb.getExtendedFormat(cell.getIxfe());
+ Debug.log(Debug.TRACE," ixfnt for Current Cell " + xf.getFontIndex());
+ FontDescription fd = wb.getFontDescription(xf.getFontIndex());
+
+ fmt.setAttribute(Format.ITALIC, fd.isItalic());
+ fmt.setAttribute(Format.BOLD, fd.isBold());
+ fmt.setAttribute(Format.UNDERLINE, fd.isUnderline());
+ fmt.setForeground(fd.getForeground());
+
+ fmt.setBackground(xf.getBackground());
+ fmt.setAlign(xf.getAlign());
+ fmt.setVertAlign(xf.getVertAlign());
+ fmt.setAttribute(Format.WORD_WRAP, xf.isWordWrap());
+
+ fmt.setAttribute(Format.TOP_BORDER, xf.isBorder(ExtendedFormat.TOP_BORDER));
+ fmt.setAttribute(Format.BOTTOM_BORDER, xf.isBorder(ExtendedFormat.BOTTOM_BORDER));
+ fmt.setAttribute(Format.RIGHT_BORDER, xf.isBorder(ExtendedFormat.RIGHT_BORDER));
+ fmt.setAttribute(Format.LEFT_BORDER, xf.isBorder(ExtendedFormat.LEFT_BORDER));
+
+ fmt.setFontName(fd.getFont());
+ fmt.setFontSize(fd.getFontSize());
+
+ fmt.setCategory(getCellDataType());
+
+ }
+}
+
diff --git a/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/PocketExcelEncoder.java b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/PocketExcelEncoder.java
new file mode 100644
index 000000000000..52ef18d252f0
--- /dev/null
+++ b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/PocketExcelEncoder.java
@@ -0,0 +1,289 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxc.pexcel;
+
+import java.io.IOException;
+import java.util.Vector;
+
+import org.openoffice.xmerge.util.Debug;
+
+import org.openoffice.xmerge.converter.xml.sxc.SpreadsheetEncoder;
+import org.openoffice.xmerge.converter.xml.sxc.Format;
+import org.openoffice.xmerge.converter.xml.sxc.BookSettings;
+import org.openoffice.xmerge.converter.xml.sxc.NameDefinition;
+import org.openoffice.xmerge.converter.xml.sxc.pexcel.records.Workbook;
+
+/**
+ * This class is used by {@link
+ * org.openoffice.xmerge.converter.xml.sxc.SxcDocumentSerializerImpl
+ * SxcDocumentSerializerImpl} to encode the Pocket Excel format.
+ *
+ * @author Martin Maher
+ */
+final class PocketExcelEncoder extends SpreadsheetEncoder {
+
+ private Workbook wb;
+
+ /**
+ * Constructor creates a Pocket Excel WorkBook.
+ *
+ * @param name The name of the WorkBook.
+ * @param password The password for the WorkBook.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ PocketExcelEncoder(String name, String password) throws IOException {
+
+ super(name, password);
+ wb = new Workbook(name);
+
+ }
+
+
+ /**
+ * This method creates a WorkSheet belonging to the
+ * WorkBook.
+ *
+ * @param sheetName The name of the WorkSheet.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ public void createWorksheet(String sheetName) throws IOException {
+
+ wb.addWorksheet(sheetName);
+ }
+
+
+ /**
+ * This method gets the number of sheets in the WorkBook.
+ *
+ * @return The number of sheets in the WorkBook.
+ */
+ public int getNumberOfSheets() {
+
+ Vector v = wb.getWorksheetNames();
+ return (v.size());
+ }
+
+
+ /**
+ * This method returns the Workbook created.
+ *
+ * @return Returns a <code>Workbook</code>
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ public Workbook getWorkbook() throws IOException {
+
+ return wb;
+ }
+
+ /**
+ * This method converts a String containing a formula in infix notation
+ * to a String in Reverse Polish Notation (RPN)
+ *
+ * @return a parsed pexcel formula in RPN
+ */
+ protected String parseFormula(String formula) {
+
+ Debug.log(Debug.TRACE,"Strip Formula (Before) : " + formula);
+
+ StringBuffer inFormula = new StringBuffer(formula);
+ StringBuffer outFormula = new StringBuffer();
+
+ boolean inBrace = false;
+ boolean firstCharAfterBrace = false;
+ boolean firstCharAfterColon = false;
+
+ int len = inFormula.length();
+
+ for (int in = 0; in < len; in++) {
+ switch (inFormula.charAt(in)) {
+ case '[':
+ // We are now inside a StarOffice cell reference.
+ // We also need to strip out the '['
+ Debug.log(Debug.TRACE,"brace Found");
+ inBrace = true;
+
+ // If the next character is a '.', we want to strip it out
+ firstCharAfterBrace = true;
+ break;
+
+ case ']':
+ // We are exiting a StarOffice cell reference
+ // We are stripping out the ']'
+ inBrace = false;
+ break;
+ case '.':
+ if (inBrace == true && (firstCharAfterBrace == true ||
+ firstCharAfterColon == true) ) {
+
+ Debug.log(Debug.TRACE,"dot Found and in brace");
+ // Since we are in a StarOffice cell reference,
+ // and we are the first character, we need to
+ // strip out the '.'
+ firstCharAfterBrace = false;
+ firstCharAfterColon = false;
+
+ } else if(firstCharAfterColon == true) {
+ firstCharAfterColon = false;
+ } else {
+ outFormula.append(inFormula.charAt(in));
+ }
+ break;
+
+ case ':':
+ // We have a cell range reference.
+ // May need to strip out the leading '.'
+ firstCharAfterColon = true;
+ outFormula.append(inFormula.charAt(in));
+ break;
+
+ case ';':
+ // StarOffice XML format uses ';' as a separator. MiniCalc (and
+ // many spreadsheets) use ',' as a separator instead.
+ outFormula.append(',');
+ break;
+
+ default:
+ // We hit valid data, lets add it to the formula string
+ outFormula.append(inFormula.charAt(in));
+
+ // Need to make sure that firstCharAfterBrace is not true.
+ firstCharAfterBrace = false;
+ break;
+ }
+ }
+
+ Debug.log(Debug.TRACE,"Strip Formula (After) : " + outFormula);
+ return outFormula.toString();
+ }
+
+ /**
+ * Add a cell to the current WorkSheet.
+ *
+ * @param row The row number of the cell.
+ * @param column The column number of the cell.
+ * @param fmt The <code>Format</code> object describing
+ * the appearance of this cell.
+ * @param cellContents The text or formula of the cell's contents.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ public void addCell(int row, int column, Format fmt, String cellContents) throws IOException {
+
+ if (cellContents.startsWith("=")) {
+ cellContents = parseFormula(cellContents);
+ Debug.log(Debug.TRACE,"Parsing Formula " + cellContents);
+ }
+ wb.addCell(row, column, fmt, cellContents);
+ }
+
+
+ /**
+ * Set the width of the columns in the WorkBook.
+ *
+ * @param columnWidths An <code>IntArrayList</code> of column
+ * widths.
+ */
+ public void setColumnRows(Vector columnRows) throws IOException {
+
+ wb.addColInfo(columnRows);
+ }
+
+ /**
+ * Set the width of the columns in the WorkBook.
+ *
+ * @param columnWidths An <code>IntArrayList</code> of column
+ * widths.
+ */
+ public void setNameDefinition(NameDefinition nd) throws IOException {
+
+ String parsedName = nd.getDefinition();
+ nd.setDefinition(parseFormula(parsedName));
+
+ wb.addNameDefinition(nd);
+ }
+
+ /**
+ * Set the width of the columns in the WorkBook.
+ *
+ * @param columnWidths An <code>IntArrayList</code> of column
+ * widths.
+ */
+ public void addSettings(BookSettings s) throws IOException {
+
+ wb.addSettings(s);
+ }
+
+ /**
+ * This method sets the format of a cell to <i>string</i>.
+ *
+ * @param format The cell format-may already contain display info,
+ * such as alignment or font type.
+ *
+ * @return The updated format of the cell.
+ */
+ private long setFormatString(long format) {
+
+ return 0;
+ }
+
+
+ /**
+ * Set a cell's formatting options via a separately create
+ * <code>Format</code> object.
+ *
+ * @param row The row number of the cell to be changed.
+ * @param column The column number of the cell to be changed.
+ * @param fmt Object containing formatting settings for
+ * this cell.
+ */
+ public void setCellFormat(int row, int column, Format fmt) {
+ Debug.log(Debug.TRACE,"bold : " + fmt.getAttribute(Format.BOLD) +
+ ",Italic : " + fmt.getAttribute(Format.ITALIC) +
+ ",Underline : " + fmt.getAttribute(Format.UNDERLINE));
+ }
+
+
+ /**
+ * Get the names of the sheets in the WorkBook.
+ *
+ * @param sheet The required sheet.
+ */
+ public String getSheetName(int sheet) {
+
+ Vector v = wb.getWorksheetNames();
+ String wsName = (String) (v.elementAt(sheet));
+
+ return wsName;
+ }
+
+
+}
+
diff --git a/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/SxcDocumentDeserializerImpl.java b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/SxcDocumentDeserializerImpl.java
new file mode 100644
index 000000000000..e95a6aa41e19
--- /dev/null
+++ b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/SxcDocumentDeserializerImpl.java
@@ -0,0 +1,129 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxc.pexcel;
+
+import java.io.IOException;
+import java.util.Enumeration;
+import java.util.Vector;
+
+import org.openoffice.xmerge.util.Debug;
+import org.openoffice.xmerge.ConvertData;
+import org.openoffice.xmerge.converter.xml.sxc.SpreadsheetDecoder;
+import org.openoffice.xmerge.converter.xml.sxc.SxcDocumentDeserializer;
+import org.openoffice.xmerge.converter.xml.sxc.pexcel.PocketExcelDecoder;
+import org.openoffice.xmerge.converter.xml.sxc.pexcel.records.Workbook;
+
+
+/**
+ * <p>Pocket Excel implementation of <code>DocumentDeserializer</code>
+ * for the {@link
+ * org.openoffice.xmerge.converter.xml.sxc.pexcel.PluginFactoryImpl
+ * PluginFactoryImpl}.</p>
+ *
+ * <p>This converts a set of files in Pocket Excel PXL format to a StarOffice DOM.</p>
+ *
+ * @author Mark Murnane
+ */
+public final class SxcDocumentDeserializerImpl extends SxcDocumentDeserializer {
+
+ /**
+ * Creates new <code>SxcDocumentDeserializerImpl</code>.
+ *
+ * @param cd <code>ConvertData</code> Input data to convert.
+ */
+ public SxcDocumentDeserializerImpl(ConvertData cd) {
+ super(cd);
+ }
+
+
+ /**
+ * This method will be implemented by concrete subclasses and will
+ * return an application-specific decoder.
+ *
+ * @param workbook The WorkBook name.
+ * @param worksheetNames An array of WorkSheet names.
+ * @param password The password.
+ *
+ * @return An application-specific <code>SpreadsheetDecoder</code>.
+ */
+ public SpreadsheetDecoder createDecoder(String workbook,
+ String[] worksheetNames, String password) throws IOException {
+
+ return new PocketExcelDecoder(workbook, worksheetNames, password);
+ }
+
+
+ /**
+ * This method will return the name of the WorkBook from the
+ * <code>ConvertData</code>. Allows for situations where the
+ * WorkBook name differs from the PDB name.
+ *
+ * Implemented in the Deserializer as the Decoder's constructor
+ * requires a name.
+ *
+ * @param cd The <code>ConvertData</code>.
+ *
+ * @return The name of the WorkBook.
+ */
+ protected String getWorkbookName(ConvertData cd)
+ throws IOException {
+
+ Enumeration e = cd.getDocumentEnumeration();
+ Workbook wb = (Workbook) e.nextElement();
+
+ String workbookName = wb.getName();
+ return workbookName;
+ }
+
+
+ /**
+ * This method will return an array of WorkSheet names from the
+ * <code>ConvertData</code>.
+ *
+ * @param cd The <code>ConvertData</code>.
+ *
+ * @return The name of the WorkSheet.
+ */
+ protected String[] getWorksheetNames(ConvertData cd)
+ throws IOException {
+
+ Enumeration e = cd.getDocumentEnumeration();
+ Workbook wb = (Workbook) e.nextElement();
+ Vector v = wb.getWorksheetNames();
+ e = v.elements();
+ String worksheetNames[] = new String[v.size()];
+ int i = 0;
+ while(e.hasMoreElements()) {
+ worksheetNames[i] = (String) e.nextElement();
+ Debug.log(Debug.TRACE,"Worksheet Name : " + worksheetNames[i]);
+ i++;
+ }
+ return worksheetNames;
+ }
+}
+
diff --git a/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/SxcDocumentSerializerImpl.java b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/SxcDocumentSerializerImpl.java
new file mode 100644
index 000000000000..26d4546bd369
--- /dev/null
+++ b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/SxcDocumentSerializerImpl.java
@@ -0,0 +1,130 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxc.pexcel;
+
+import org.w3c.dom.NodeList;
+import org.w3c.dom.Node;
+
+import java.io.IOException;
+
+import org.openoffice.xmerge.Document;
+import org.openoffice.xmerge.ConvertData;
+import org.openoffice.xmerge.ConvertException;
+import org.openoffice.xmerge.converter.xml.sxc.SxcDocumentSerializer;
+import org.openoffice.xmerge.converter.xml.sxc.pexcel.records.Workbook;
+
+/**
+ * <p>Pocket Excel implementation of <code>SxcDocumentDeserializer</code>
+ * for the {@link
+ * org.openoffice.xmerge.converter.xml.sxc.pexcel.PluginFactoryImpl
+ * PluginFactoryImpl}.</p>
+ *
+ * <p>This converts StarOffice XML format to a set of files in
+ * Pocket Excel PXL format.</p>
+ *
+ * @author Paul Rank
+ * @author Mark Murnane
+ */
+public final class SxcDocumentSerializerImpl extends SxcDocumentSerializer {
+
+
+ /**
+ * Constructor.
+ *
+ * @param document The <code>Document</code> to convert.
+ */
+ public SxcDocumentSerializerImpl(Document document) {
+ super(document);
+ }
+
+
+ public ConvertData serialize() throws ConvertException, IOException {
+
+ // Get the server side document name. This value should not
+ // contain a path or the file extension.
+ String docName = sxcDoc.getName();
+
+ // TODO - get real values for password when implemnted in XML
+ // Passwords are not currently stored in StarCalc XML format.
+ String password = null;
+
+ encoder = new PocketExcelEncoder(docName, password);
+
+ // get dom document
+ org.w3c.dom.Document domDoc = sxcDoc.getContentDOM();
+
+ // load the styles
+ loadStyles(sxcDoc);
+ // Traverse to the office:body element.
+ // There should only be one.
+ NodeList list = domDoc.getElementsByTagName(TAG_OFFICE_BODY);
+ int len = list.getLength();
+
+ if (len > 0) {
+ Node node = list.item(0);
+ traverseBody(node);
+ }
+
+ // get settings for this document
+ org.w3c.dom.Document settingsDoc = sxcDoc.getSettingsDOM();
+ if(settingsDoc!=null) {
+ NodeList settingsList = settingsDoc.getElementsByTagName(TAG_OFFICE_SETTINGS);
+ int slen = settingsList.getLength();
+
+ if (slen > 0) {
+ Node settingsNode = settingsList.item(0);
+ traverseSettings(settingsNode);
+ }
+ }
+
+ // Get the number of sheets in the workbook
+ // This will equal the number of PDBs we need
+ ConvertData cd = new ConvertData();
+ Workbook wb = ((PocketExcelEncoder) encoder).getWorkbook();
+ cd.addDocument(wb);
+
+ return cd;
+ }
+
+
+ /**
+ * A cell reference in a StarOffice formula looks like
+ * [.C2] (for cell C2). MiniCalc is expecting cell references
+ * to look like C2. This method strips out the braces and
+ * the period.
+ *
+ * @param formula A StarOffice formula <code>String</code>.
+ *
+ * @return A MiniCalc formula <code>String</code>.
+ */
+ protected String parseFormula(String formula) {
+
+ return null;
+ }
+}
+
diff --git a/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/package.html b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/package.html
new file mode 100644
index 000000000000..61c1f3f0a79d
--- /dev/null
+++ b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/package.html
@@ -0,0 +1,43 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<!--
+ #*************************************************************************
+ #
+ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+
+ Copyright 2000, 2010 Oracle and/or its affiliates.
+
+ OpenOffice.org - a multi-platform office productivity suite
+
+ This file is part of OpenOffice.org.
+
+ OpenOffice.org is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License version 3
+ only, as published by the Free Software Foundation.
+
+ OpenOffice.org is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License version 3 for more details
+ (a copy is included in the LICENSE file that accompanied this code).
+
+ You should have received a copy of the GNU Lesser General Public License
+ version 3 along with OpenOffice.org. If not, see
+ <http://www.openoffice.org/license.html>
+ for a copy of the LGPLv3 License.
+
+ #*************************************************************************
+ -->
+<html>
+<head>
+<title>org.openoffice.xmerge.converter.xml.sxc.pexcel package</title>
+</head>
+
+<body bgcolor="white">
+
+<p>Provides the tools for doing the conversion of StarWriter XML to
+and from Pocket Excel format.</p>
+
+<p>It follows the {@link org.openoffice.xmerge} framework for the conversion process.</p>
+
+</body>
+</html>
diff --git a/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/BIFFRecord.java b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/BIFFRecord.java
new file mode 100644
index 000000000000..190cb0925c21
--- /dev/null
+++ b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/BIFFRecord.java
@@ -0,0 +1,61 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxc.pexcel.records;
+
+import java.io.OutputStream;
+import java.io.InputStream;
+import java.io.IOException;
+
+ public interface BIFFRecord {
+
+ /**
+ * Get the type of the record. In the BIFF file format each record has a type
+ * designated with a byte value. See @link PocketExcelBiffConstants
+ * for a list of the BIFF constants and what they mean.
+ *
+ * @return byte The BIFF record value.
+ */
+ public short getBiffType();
+
+ /**
+ * Read from the input stream <b>NB</b>The input stream is assumed to be in
+ * Little Endian format. The Biff identifier is expected to be in the stream.
+ *
+ * @param input The InputStream to read from.
+ * @return The number of bytes that were read in.
+ */
+ public int read(InputStream input) throws IOException;
+
+ /**
+ * Writes the record, including the BIFF record byte to the outputstream
+ * @param output The output stream to write to in LittleEndian format.
+ */
+ public void write(OutputStream output) throws IOException;
+
+}
+
diff --git a/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/BeginningOfFile.java b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/BeginningOfFile.java
new file mode 100644
index 000000000000..df45b708d89c
--- /dev/null
+++ b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/BeginningOfFile.java
@@ -0,0 +1,116 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxc.pexcel.records;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.IOException;
+
+import org.openoffice.xmerge.util.Debug;
+import org.openoffice.xmerge.util.EndianConverter;
+import org.openoffice.xmerge.converter.xml.sxc.pexcel.PocketExcelConstants;
+
+/**
+ * This class describes the beginning of file. It is the
+ * the Biff record that marks the beginning of a a worbook
+ * or the beginning of worksheets in the workbook
+ *
+ */
+public class BeginningOfFile implements BIFFRecord {
+
+ private byte[] version = new byte[2];
+ private byte[] subStream = new byte[2];
+
+ /**
+ * Constructor that initializes the member values.
+ *
+ * @param ver Version Number
+ * Substream type (workbook = 0x05, worksheet = 0x10)
+ */
+ public BeginningOfFile(boolean global) {
+ setVersion((short) 271);
+ if(global)
+ setSubStreamWBGlobal();
+ else
+ setSubStreamWorkSheet();
+ // this.subStream = EndianConverter.writeShort(dt);
+ }
+
+ public BeginningOfFile(InputStream is) throws IOException {
+ read(is);
+ }
+
+ private void setVersion(short version) {
+ this.version = EndianConverter.writeShort(version);
+ }
+
+ int getVersion() {
+ return EndianConverter.readShort(version);
+ }
+
+ private void setSubStreamWBGlobal() {
+ // subStream = new byte[] {0x05};
+ subStream = EndianConverter.writeShort((short) 0x05);
+ }
+
+ private void setSubStreamWorkSheet() {
+ // subStream = new byte[] {0x10};
+ subStream = EndianConverter.writeShort((short) 0x10);
+ }
+
+ int getSubStreamType() {
+ return EndianConverter.readShort(subStream);
+ }
+
+ public int read(InputStream input) throws IOException {
+ int numBytesRead = input.read(version);
+ numBytesRead += input.read(subStream);
+ Debug.log(Debug.TRACE,"\tVersion : "+ EndianConverter.readShort(version) +
+ " Stream : " + EndianConverter.readShort(subStream));
+
+ return numBytesRead;
+ }
+
+ public void write(OutputStream output) throws IOException {
+
+ output.write(getBiffType());
+ output.write(version);
+ output.write(subStream);
+
+ Debug.log(Debug.TRACE, "Writing BeginningOfFile record");
+ }
+
+ /**
+ * Get the hex code for this particular <code>BIFFRecord</code>
+ *
+ * @return the hex code for <code>BeginningOfFile</code>
+ */
+ public short getBiffType() {
+ return PocketExcelConstants.BOF_RECORD;
+ }
+}
diff --git a/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/BlankCell.java b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/BlankCell.java
new file mode 100644
index 000000000000..da826a8d9058
--- /dev/null
+++ b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/BlankCell.java
@@ -0,0 +1,115 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxc.pexcel.records;
+
+import java.io.OutputStream;
+import java.io.InputStream;
+import java.io.IOException;
+
+import org.openoffice.xmerge.util.Debug;
+import org.openoffice.xmerge.util.EndianConverter;
+import org.openoffice.xmerge.converter.xml.sxc.pexcel.PocketExcelConstants;
+
+/**
+ * Represents a BIFF Record that describes a blank cell
+ */
+public class BlankCell extends CellValue {
+
+ /**
+ * Constructs a BlankCell <code>InputStream</code>
+ *
+ * @param is InputStream containing a BlankCell.
+ */
+ public BlankCell(InputStream is) throws IOException {
+ read(is);
+ }
+
+ /**
+ * Constructs a <code>BlankCell</code> using specified attributes
+ *
+ * @param row row number
+ * @param col column number
+ * @param cellContents contents of the cell
+ * @param ixfe font index
+ */
+ public BlankCell(int row, int column, int ixfe) throws IOException {
+
+ setRow(row);
+ setCol(column);
+ setIxfe(ixfe);
+ }
+
+ /**
+ * Get the hex code for this particular <code>BIFFRecord</code>
+ *
+ * @return the hex code for <code>BlankCell</code>
+ */
+ public short getBiffType() {
+ return PocketExcelConstants.BLANK_CELL;
+ }
+
+ public void write(OutputStream output) throws IOException {
+
+ output.write(getBiffType());
+ output.write(rw);
+ output.write(col);
+ output.write(ixfe);
+
+ Debug.log(Debug.TRACE, "Writing BlankCell record");
+
+ }
+
+ /**
+ * Reads a BlankCell <code>InputStream</code>
+ *
+ * @param is InputStream containing a BlankCell.
+ */
+ public int read(InputStream input) throws IOException {
+
+ int numOfBytesRead = input.read(rw);
+ numOfBytesRead++;
+ col += input.read();
+ numOfBytesRead += input.read(ixfe);
+
+ Debug.log(Debug.TRACE, "\tRow : "+ EndianConverter.readShort(rw) +
+ " Column : " + col +
+ " ixfe : " + EndianConverter.readShort(ixfe));
+
+ return numOfBytesRead;
+ }
+
+ /**
+ * Gets the <code>String</code> representing the cells contents
+ *
+ * @return the <code>String</code> representing the cells contents
+ */
+ public String getString() throws IOException {
+
+ return (new String(""));
+ }
+}
diff --git a/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/BoolErrCell.java b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/BoolErrCell.java
new file mode 100644
index 000000000000..9a370ccd8a59
--- /dev/null
+++ b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/BoolErrCell.java
@@ -0,0 +1,125 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxc.pexcel.records;
+
+import java.io.OutputStream;
+import java.io.InputStream;
+import java.io.IOException;
+
+
+import org.openoffice.xmerge.util.Debug;
+import org.openoffice.xmerge.converter.xml.sxc.pexcel.PocketExcelConstants;
+
+/**
+ * Represents a BIFF Record that describes a Boolean or Error value
+ */
+public class BoolErrCell extends CellValue {
+
+ private byte bBoolErr;
+ private byte fError;
+
+ /**
+ * Constructs a BoolErrCell from arguments
+ *
+ * @param row row number
+ * @param col column number
+ * @param ixfe font index
+ * @param bBoolErr Boolean value or error value
+ * @param fError Boolean error flag
+ */
+ public BoolErrCell(int row, int column, int ixfe, int bBoolErr, int fError) throws IOException {
+
+ setIxfe(ixfe);
+ this.bBoolErr = (byte)bBoolErr;
+ this.fError = (byte)fError;
+ setRow(row);
+ setCol(column);
+ }
+
+ /**
+ * Constructs a BoolErrCell from the <code>InputStream</code>
+ *
+ * @param is InputStream containing a BoolErrCell
+ */
+ public BoolErrCell(InputStream is) throws IOException {
+ read(is);
+ }
+
+ /**
+ * Get the hex code for this particular <code>BIFFRecord</code>
+ *
+ * @return the hex code for <code>BoolErrCEll</code>
+ */
+ public short getBiffType() {
+ return PocketExcelConstants.BOOLERR_CELL;
+ }
+
+ /**
+ * Writes a <code>BoolErrCell</code> to the specified <code>Outputstream</code>
+ *
+ * @param os the <code>OutputStream</code> to write to
+ */
+ public void write(OutputStream output) throws IOException {
+
+ output.write(getBiffType());
+
+ super.write(output);
+
+ output.write(bBoolErr);
+ output.write(fError);
+
+ Debug.log(Debug.TRACE,"Writing BoolErrCell record");
+ }
+
+ /**
+ * Reads a BoolErrCell from the <code>InputStream</code>
+ *
+ * @param is InputStream containing a BoolErrCell
+ */
+ public int read(InputStream input) throws IOException {
+
+ int numOfBytesRead = super.read(input);
+
+ bBoolErr = (byte) input.read();
+ fError = (byte) input.read();
+ numOfBytesRead += 2;
+
+ Debug.log(Debug.TRACE, " bBoolErr : " + bBoolErr +
+ " fError : " + fError);
+ return numOfBytesRead;
+ }
+
+ /**
+ * Gets the <code>String</code> representing the cells contents
+ *
+ * @return the <code>String</code> representing the cells contents
+ */
+ public String getString() throws IOException {
+ return ("Error Cell");
+ }
+}
diff --git a/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/BoundSheet.java b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/BoundSheet.java
new file mode 100644
index 000000000000..679224634bfa
--- /dev/null
+++ b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/BoundSheet.java
@@ -0,0 +1,136 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxc.pexcel.records;
+
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.io.OutputStream;
+import java.io.InputStream;
+
+import org.openoffice.xmerge.util.Debug;
+import org.openoffice.xmerge.converter.xml.sxc.pexcel.PocketExcelConstants;
+
+/**
+ * Represents a BoundSheet Record which describes the name of a worksheet
+ */
+public class BoundSheet implements BIFFRecord {
+
+ private byte reserved;
+ private byte cch;
+ private byte[] sheetName;
+
+ /**
+ * Constructs a pocket Excel Document assigns it the document name passed in
+ *
+ * @param name name of the worksheet represented
+ */
+ public BoundSheet(String name) throws IOException {
+ setSheetName(name);
+ reserved = 0;
+ }
+
+ /**
+ * Constructs a pocket Excel Document from the
+ * <code>InputStream</code> and assigns it the document name passed in
+ *
+ * @param is InputStream containing a Pocket Excel Data file.
+ */
+ public BoundSheet(InputStream is) throws IOException {
+ read(is);
+ }
+
+ /**
+ * Sets the worksheet name. The sheetname length must be doubled as the
+ * String is stored in unicode format.
+ *
+ * @param sheetname worksheet name
+ */
+ void setSheetName(String sheetName) throws IOException {
+ this.cch = (byte) sheetName.length();
+ this.sheetName = new byte[cch*2];
+ this.sheetName = sheetName.getBytes("UTF-16LE");
+ }
+
+ public String getSheetName() {
+ String name;
+
+ try {
+ name = new String(sheetName, "UTF-16LE");
+ } catch (UnsupportedEncodingException e){
+ name = "unknown";
+ }
+ return name;
+ }
+
+ /**
+ * Get the hex code for this particular <code>BIFFRecord</code>
+ *
+ * @return the hex code for <code>BoundSheet</code>
+ */
+ public short getBiffType() {
+ return PocketExcelConstants.BOUND_SHEET;
+ }
+
+ /**
+ * Write this particular <code>BIFFRecord</code> to the <code>OutputStream</code>
+ *
+ * @param ouput the <code>OutputStream</code>
+ */
+ public void write(OutputStream output) throws IOException {
+
+ output.write(getBiffType());
+ output.write(reserved);
+ output.write(cch);
+ output.write(sheetName);
+
+ Debug.log(Debug.TRACE,"Writing BoundSheet record");
+ }
+
+ /**
+ * Reads a BoundSheet from the <code>InputStream</code> The byte array
+ * must be twice the size of the String as it uses unicode.
+ *
+ * @param is InputStream containing the record data
+ */
+ public int read(InputStream input) throws IOException {
+
+ reserved = (byte) input.read();
+ cch = (byte) input.read();
+ int numOfBytesRead = 2;
+ int strLen = cch*2;
+ sheetName = new byte[strLen];
+ numOfBytesRead += input.read(sheetName, 0, strLen);
+
+ Debug.log(Debug.TRACE,"\tReserved : "+ reserved +
+ " cch : " + cch +
+ " sheetName : " + new String(sheetName,"UTF-16LE"));
+
+ return numOfBytesRead;
+ }
+
+}
diff --git a/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/CellValue.java b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/CellValue.java
new file mode 100644
index 000000000000..c09cde5a32c1
--- /dev/null
+++ b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/CellValue.java
@@ -0,0 +1,136 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxc.pexcel.records;
+
+import java.io.OutputStream;
+import java.io.InputStream;
+import java.io.IOException;
+
+import org.openoffice.xmerge.util.Debug;
+import org.openoffice.xmerge.util.EndianConverter;
+
+public abstract class CellValue implements BIFFRecord {
+
+ protected byte[] rw = new byte[2];
+ protected byte col;
+ protected byte[] ixfe = new byte[2];
+
+ /**
+ * Get the row number of this cell
+ *
+ * @return the row number of this cell
+ */
+ public int getRow() {
+ return EndianConverter.readShort(rw) + 1;
+ }
+
+ /**
+ * Set the row number of this cell
+ *
+ * @param row sets the row number for this cell
+ */
+ public void setRow(int row) {
+ this.rw = EndianConverter.writeShort((short) (row - 1));
+ }
+ /**
+ * Get the Index to the <code>ExtendedFormat</code>
+ *
+ * @return the index number of this cell's <code>ExtendedFormat</code>
+ */
+ public int getIxfe() {
+ return EndianConverter.readShort(ixfe);
+ }
+
+ /**
+ * Sets the Index to the <code>ExtendedFormat</code>
+ *
+ * @param ixfe sets the index number for this cell's <code>ExtendedFormat</code>
+ */
+ public void setIxfe(int ixfe) {
+ this.ixfe = EndianConverter.writeShort((short) (ixfe));
+ }
+
+ /**
+ * Get the column number of this cell
+ *
+ * @return the column number of this cell
+ */
+ public int getCol() {
+ return col + 1; // The cols start at 1
+ }
+
+ /**
+ * Set the row number of this cell
+ *
+ * @param col sets the row number for this cell
+ */
+ public void setCol(int col) {
+ this.col = (byte) (col - 1); // The cols start at 1
+ }
+
+ /**
+ * Writes basic cell value attributes to the specified <code>Outputstream</code>
+ *
+ * @param os the <code>OutputStream</code> to write to
+ */
+ public void write(OutputStream output) throws IOException {
+
+ output.write(rw);
+ output.write(col);
+ output.write(ixfe);
+ }
+
+ /**
+ * Writes a<code>LabelCell</code> to the specified <code>Outputstream</code>
+ *
+ * @param os the <code>OutputStream</code> to write to
+ */
+ public int read(InputStream input) throws IOException {
+
+ int numOfBytesRead = input.read(rw);
+ col += input.read();
+ numOfBytesRead++;
+ numOfBytesRead += input.read(ixfe);
+
+ Debug.log(Debug.TRACE, "\tRow : "+ EndianConverter.readShort(rw) +
+ " Column : " + col +
+ " ixfe : " + EndianConverter.readShort(ixfe));
+
+ return numOfBytesRead;
+ }
+
+
+ /**
+ * Returns the contents of the cell as a String
+ *
+ * @return the contents of the cell
+ */
+ abstract public String getString() throws IOException;
+
+}
+
diff --git a/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/CodePage.java b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/CodePage.java
new file mode 100644
index 000000000000..91186fa27c3c
--- /dev/null
+++ b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/CodePage.java
@@ -0,0 +1,107 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxc.pexcel.records;
+
+import java.io.OutputStream;
+import java.io.InputStream;
+import java.io.IOException;
+
+import org.openoffice.xmerge.util.Debug;
+import org.openoffice.xmerge.util.EndianConverter;
+import org.openoffice.xmerge.converter.xml.sxc.pexcel.PocketExcelConstants;
+
+/**
+ * Represents the codepage for the document. There is a number of unknown
+ * fields which are hardcoded at construction
+ */
+public class CodePage implements BIFFRecord {
+
+ private byte[] codepage = new byte[2];
+ private byte[] unknown1 = new byte[2];
+ private byte[] unknown2 = new byte[2];
+ private byte unknown3;
+
+ /**
+ * Constructs a pocket Excel Codepage
+ */
+ public CodePage() {
+ codepage = new byte[] {(byte)0xE4, (byte)0x04};
+ unknown1 = new byte[] {(byte)0x8C, (byte)0x01};
+ unknown2 = new byte[] {(byte)0x00, (byte)0x01};
+ unknown3 = 0x00;
+ }
+
+ /**
+ * Constructs a pocket Excel Codepage from the<code>InputStream</code>
+ *
+ * @param is InputStream containing a Pocket Excel Data file.
+ */
+ public CodePage(InputStream is) throws IOException {
+ read(is);
+ }
+
+ /**
+ * Get the hex code for this particular <code>BIFFRecord</code>
+ *
+ * @return the hex code for <code>BoundSheet</code>
+ */
+ public short getBiffType() {
+ return PocketExcelConstants.CODEPAGE;
+ }
+
+ public int read(InputStream input) throws IOException {
+
+ int numOfBytesRead = input.read(codepage);
+ numOfBytesRead += input.read(unknown1);
+ numOfBytesRead += input.read(unknown2);
+ // numOfBytesRead += input.read(unknown3);
+ unknown3 = (byte) input.read();
+ numOfBytesRead++;
+
+ Debug.log(Debug.TRACE,"\tcodepage : "+ EndianConverter.readShort(codepage) +
+ " unknown1 : " + EndianConverter.readShort(unknown1) +
+ " unknown2 : " + EndianConverter.readShort(unknown2) +
+ " unknown3 : " + unknown3);
+
+ return numOfBytesRead;
+ }
+
+ public void write(OutputStream output) throws IOException {
+
+ output.write(getBiffType());
+ output.write(codepage);
+ output.write(unknown1);
+ output.write(unknown2);
+ output.write(unknown3);
+
+ Debug.log(Debug.TRACE,"Writing CodePage record");
+
+
+ }
+
+}
diff --git a/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/ColInfo.java b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/ColInfo.java
new file mode 100644
index 000000000000..6ce59c7ca72c
--- /dev/null
+++ b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/ColInfo.java
@@ -0,0 +1,157 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxc.pexcel.records;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.openoffice.xmerge.util.Debug;
+import org.openoffice.xmerge.util.EndianConverter;
+import org.openoffice.xmerge.converter.xml.sxc.pexcel.PocketExcelConstants;
+
+/**
+ * ColInfo describes the formatting for a column
+ *
+ */
+public class ColInfo implements BIFFRecord {
+
+ private byte[] colFirst = new byte[2]; // first column this formatting applies to
+ private byte[] colLast = new byte[2]; // last column this formatting applies to
+ private byte[] colDX = new byte[2]; // column width
+ private byte[] ixfe = new byte[2]; // index for formatting
+ private byte grbit; // options flags
+ private float scale = (float) 2.5; // 1.798;
+
+ /**
+ * Constructs a pocket Excel Document from the
+ * <code>InputStream</code> and assigns it the document name passed in
+ *
+ * @param colFirst the first column this formatting applies to
+ * @param colLast last column this formatting applies to
+ * @param coldx column width
+ * @param grbit options flags
+ */
+ public ColInfo(int colFirst, int colLast, int colDX, int ixfe) {
+ this.colFirst = EndianConverter.writeShort((short)colFirst);
+ this.colLast = EndianConverter.writeShort((short)colLast);
+ colDX *= scale;
+ this.colDX = EndianConverter.writeShort((short)colDX);
+ this.ixfe = EndianConverter.writeShort((short)ixfe);
+ this.grbit = 0x00;
+ }
+
+ /**
+ * Construct a ColInfo from the InputStream
+ *
+ * @param is the <code>Inputstream</code> to read from
+ */
+ public ColInfo(InputStream is) throws IOException {
+ read(is);
+ }
+
+ /**
+ * Reads ColInfo record from the InputStream
+ *
+ * @param input the InputStream to read from
+ * @return the number of bytes read
+ */
+ public int read(InputStream input) throws IOException {
+
+ int numOfBytesRead = input.read(colFirst);
+ numOfBytesRead += input.read(colLast);
+ numOfBytesRead += input.read(colDX);
+ short scaledDX = (short) (EndianConverter.readShort(colDX) / scale);
+ colDX = EndianConverter.writeShort(scaledDX);
+ numOfBytesRead += input.read(ixfe);
+ grbit = (byte) input.read();
+ numOfBytesRead ++;
+
+ Debug.log(Debug.TRACE,"\tcolFirst : "+ EndianConverter.readShort(colFirst) +
+ " colLast : " + EndianConverter.readShort(colLast) +
+ " colDX : " + EndianConverter.readShort(colDX) +
+ " ixfe : " + EndianConverter.readShort(ixfe) +
+ " grbit : " + grbit);
+
+ return numOfBytesRead;
+ }
+
+ /**
+ * Get the hex code for this particular <code>BIFFRecord</code>
+ *
+ * @return the hex code for <code>ColInfo</code>
+ */
+ public short getBiffType() {
+ return PocketExcelConstants.COLINFO;
+ }
+ /**
+ * Get the width of this column
+ *
+ * @return the width of this column
+ */
+ public short getColWidth() {
+ return EndianConverter.readShort(colDX);
+ }
+
+ /**
+ * Get the hex code for this particular <code>BIFFRecord</code>
+ *
+ * @return the hex code for <code>ColInfo</code>
+ */
+ public short getFirst() {
+ return EndianConverter.readShort(colFirst);
+ }
+
+ /**
+ * Get the hex code for this particular <code>BIFFRecord</code>
+ *
+ * @return the hex code for <code>ColInfo</code>
+ */
+ public short getLast() {
+ return EndianConverter.readShort(colLast);
+ }
+
+ /**
+ * Writes a ColInfo to the specified <code>Outputstream</code>
+ *
+ * @param os the <code>OutputStream</code> to write to
+ */
+ public void write(OutputStream output) throws IOException {
+
+ output.write(getBiffType());
+ output.write(colFirst);
+ output.write(colLast);
+ output.write(colDX);
+ output.write(ixfe);
+ output.write(grbit);
+
+ Debug.log(Debug.TRACE,"Writing ColInfo record");
+
+ }
+
+}
diff --git a/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/DefColWidth.java b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/DefColWidth.java
new file mode 100644
index 000000000000..b3e3a8e6b0e3
--- /dev/null
+++ b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/DefColWidth.java
@@ -0,0 +1,94 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxc.pexcel.records;
+
+import java.io.OutputStream;
+import java.io.InputStream;
+import java.io.IOException;
+
+import org.openoffice.xmerge.util.Debug;
+import org.openoffice.xmerge.util.EndianConverter;
+import org.openoffice.xmerge.converter.xml.sxc.pexcel.PocketExcelConstants;
+
+/**
+ * Represents a BIFF record defiuning the defualt column width
+ */
+public class DefColWidth implements BIFFRecord {
+
+ private byte[] grbit = new byte[2];
+ private byte[] coldx = new byte[2];
+ private byte[] ixfe = new byte[2];
+
+/**
+ * Constructs a pocket Excel Document from the
+ * <code>InputStream</code> and assigns it the document name passed in
+ *
+ * @param is InputStream containing a Pocket Excel Data file.
+ */
+ public DefColWidth() {
+ grbit = new byte[] {0x00, 0x00};
+ coldx = new byte[] {0x00, 0x09};
+ ixfe = new byte[] {0x00, 0x00};
+ }
+
+ public DefColWidth(InputStream is) throws IOException {
+ read(is);
+ }
+
+ /**
+ * Get the hex code for this particular <code>BIFFRecord</code>
+ *
+ * @return the hex code for <code>DefColWidth</code>
+ */
+ public short getBiffType() {
+ return PocketExcelConstants.DEF_COL_WIDTH;
+ }
+
+ public void write(OutputStream output) throws IOException {
+
+ output.write(getBiffType());
+ output.write(grbit);
+ output.write(coldx);
+ output.write(ixfe);
+
+ Debug.log(Debug.TRACE, "Writing DefColWidth record");
+ }
+
+ public int read(InputStream input) throws IOException {
+
+ int numOfBytesRead = input.read(grbit);
+ numOfBytesRead += input.read(coldx);
+ numOfBytesRead += input.read(ixfe);
+
+ Debug.log(Debug.TRACE,"\tgrbit : "+ EndianConverter.readShort(grbit) +
+ " coldx : " + EndianConverter.readShort(coldx) +
+ " ixfe : " + EndianConverter.readShort(ixfe));
+ return 0;
+ }
+
+}
diff --git a/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/DefRowHeight.java b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/DefRowHeight.java
new file mode 100644
index 000000000000..454a5ed87520
--- /dev/null
+++ b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/DefRowHeight.java
@@ -0,0 +1,96 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxc.pexcel.records;
+
+import java.io.OutputStream;
+import java.io.InputStream;
+import java.io.IOException;
+
+import org.openoffice.xmerge.util.Debug;
+import org.openoffice.xmerge.util.EndianConverter;
+import org.openoffice.xmerge.converter.xml.sxc.pexcel.PocketExcelConstants;
+
+/**
+ * Represents a BIFF record defiuning the default row height
+ */
+public class DefRowHeight implements BIFFRecord {
+
+ private byte[] unknown1 = new byte[2];
+ private byte[] unknown2 = new byte[2];
+
+ /**
+ * Constructs a pocket Excel Document from the
+ * <code>InputStream</code> and assigns it the document name passed in
+ *
+ * @param is InputStream containing a Pocket Excel Data file.
+ */
+ public DefRowHeight() {
+ unknown1 = new byte[] {(byte)0x00, (byte)0x00};
+ unknown2 = new byte[] {(byte)0xFF, (byte)0x00};
+ }
+
+ /**
+ * Constructs a DefRowHeight from the <code>InputStream</code>
+ *
+ * @param is InputStream containing a Pocket Excel Data file.
+ */
+ public DefRowHeight(InputStream is) throws IOException {
+ read(is);
+ }
+
+ /**
+ * Get the hex code for this particular <code>BIFFRecord</code>
+ *
+ * @return the hex code for <code>DefRowHeight</code>
+ */
+ public short getBiffType() {
+ return PocketExcelConstants.DEFAULT_ROW_HEIGHT;
+ }
+
+ public int read(InputStream input) throws IOException {
+
+ int numOfBytesRead = input.read(unknown1);
+ numOfBytesRead += input.read(unknown2);
+
+ Debug.log(Debug.TRACE,"\tunknown1 : "+ EndianConverter.readShort(unknown1) +
+ " unknown2 : " + EndianConverter.readShort(unknown2));
+ return numOfBytesRead;
+ }
+
+ public void write(OutputStream output) throws IOException {
+
+ output.write(getBiffType());
+ output.write(unknown1);
+ output.write(unknown2);
+
+ Debug.log(Debug.TRACE,"Writing DefRowHeight record");
+
+
+ }
+
+}
diff --git a/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/DefinedName.java b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/DefinedName.java
new file mode 100644
index 000000000000..0f8c535a9b92
--- /dev/null
+++ b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/DefinedName.java
@@ -0,0 +1,226 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxc.pexcel.records;
+
+import java.io.OutputStream;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+
+import org.openoffice.xmerge.util.Debug;
+import org.openoffice.xmerge.util.EndianConverter;
+import org.openoffice.xmerge.converter.xml.sxc.pexcel.records.Workbook;
+import org.openoffice.xmerge.converter.xml.sxc.pexcel.records.formula.FormulaHelper;
+import org.openoffice.xmerge.converter.xml.sxc.NameDefinition;
+import org.openoffice.xmerge.converter.xml.sxc.pexcel.PocketExcelConstants;
+
+/**
+ * Represents a BIFF Record representing a defined name in the workbook
+ */
+public class DefinedName implements BIFFRecord {
+
+ private byte[] grbit = new byte[2];
+ private byte cch;
+ private byte[] cce = new byte[2];
+ private byte[] ixals = new byte[2];
+ private byte[] rgch;
+ private byte[] rgce;
+ private FormulaHelper fh = new FormulaHelper();
+ private String definition = new String("");
+ private Workbook wb;
+
+ /**
+ * Constructs a Defined Name from the <code>InputStream</code>
+ *
+ * @param is InputStream containing the record data
+ */
+ public DefinedName(NameDefinition nd, Workbook wb) throws IOException {
+
+ fh.setWorkbook(wb);
+ this.wb = wb;
+ String name = nd.getName();
+
+ // we have to insert an = to stop the formulaParser throwing an exception
+ definition = "=" + nd.getDefinition();
+
+ cch = (byte)name.length();
+ rgch = new byte[cch*2];
+ rgch = name.getBytes("UTF-16LE");
+ grbit = EndianConverter.writeShort((short)0);
+ ixals[0] = (byte)0xFF;ixals[1] = (byte)0xFF;
+ }
+ /**
+ * Constructs a Defined Name from the <code>InputStream</code>
+ *
+ * @param is InputStream containing the record data
+ */
+ public DefinedName(InputStream is, Workbook wb) throws IOException {
+
+ read(is);
+ fh.setWorkbook(wb);
+ this.wb = wb;
+ }
+
+ /**
+ * Get the hex code for this particular <code>BIFFRecord</code>
+ *
+ * @return the hex code for <code>DefinedName</code>
+ */
+ public short getBiffType() {
+ return PocketExcelConstants.DEFINED_NAME;
+ }
+
+ /**
+ * Reads a Defined Name from the <code>InputStream</code> The byte array
+ * must be twice the size of the String as it uses unicode.
+ *
+ * @param is InputStream containing the record data
+ */
+ public int read(InputStream input) throws IOException {
+
+ int numOfBytesRead = input.read(grbit);
+ cch = (byte) input.read();
+ numOfBytesRead++;
+ numOfBytesRead += input.read(cce);
+ numOfBytesRead += input.read(ixals);
+
+ rgch = new byte[cch*2];
+ input.read(rgch, 0, cch*2);
+
+ rgce = new byte[EndianConverter.readShort(cce)];
+ input.read(rgce, 0, EndianConverter.readShort(cce));
+
+
+
+ Debug.log(Debug.TRACE, "\tgrbit : "+ EndianConverter.readShort(grbit) +
+ " cch : " + cch +
+ " cce : " + EndianConverter.readShort(cce) +
+ " ixals : " + EndianConverter.readShort(ixals) +
+ "\n\trgch : " + rgch +
+ " rgce : " + rgce);
+
+ return numOfBytesRead;
+ }
+
+ /**
+ * Write this particular <code>BIFFRecord</code> to the <code>OutputStream</code>
+ *
+ * @param ouput the <code>OutputStream</code>
+ */
+ public void write(OutputStream output) throws IOException {
+
+ try {
+ Debug.log(Debug.TRACE,"Writing out " + definition);
+ rgce = fh.convertCalcToPXL(definition);
+ cce = EndianConverter.writeShort((short) rgce.length);
+ } catch(Exception e) {
+ Debug.log(Debug.TRACE,"Error in Parsing Name Definition");
+ cce = EndianConverter.writeShort((short) 0);
+ }
+
+
+ output.write(getBiffType());
+ output.write(grbit);
+ output.write(cch);
+ output.write(cce);
+ output.write(ixals);
+ output.write(rgch);
+ if(rgce.length!=0)
+ output.write(rgce);
+
+ Debug.log(Debug.TRACE,"Writing DefinedName record");
+ }
+
+ /**
+ * Returns definition name. This is public because the
+ * <code>TokenDecoder</code> has to substitue the Name token with this
+ * String when writing out to sxc
+ *
+ * @return the <code>String</code> containing the name
+ */
+ public String getName() {
+ String name;
+
+ try {
+ name = new String(rgch, "UTF-16LE");
+ } catch (UnsupportedEncodingException e){
+ name = "unknown";
+ }
+ return name;
+ }
+
+ /**
+ * Returns a definition table which can be used by the pocket excel
+ * decoder to build a complete definitions table for writing to the sxc
+ * document
+ */
+ public NameDefinition getNameDefinition() {
+
+ String baseCellAddress;
+ getDefinition(); // This must be called first so we know the type
+
+ baseCellAddress = "$" + wb.getSheetName(0) + ".A1";
+
+ NameDefinition nd = new NameDefinition(getName(),definition, baseCellAddress, isRangeType(), isExpressionType());
+ return nd;
+ }
+
+ /**
+ * Returns the definition
+ *
+ * @return the <code>String</code> containing the definition
+ */
+ private String getDefinition() {
+ // pexcel sometimes creates Name definition with no defintion, bug??
+ if(EndianConverter.readShort(cce)!=0) {
+ definition = fh.convertPXLToCalc(rgce);
+ definition = definition.substring(1); // remove the '='
+ definition = definition.replace(',', ';');
+ }
+ return definition;
+ }
+
+ /**
+ * Returns the defintion
+ *
+ * @return the <code>String</code> containing the definition
+ */
+ private boolean isRangeType() {
+
+ return fh.isRangeType();
+ }
+ /**
+ * Returns the defintion
+ *
+ * @return the <code>String</code> containing the definition
+ */
+ private boolean isExpressionType() {
+
+ return fh.isExpressionType();
+ }
+}
diff --git a/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/Eof.java b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/Eof.java
new file mode 100644
index 000000000000..d0a2fec3e90e
--- /dev/null
+++ b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/Eof.java
@@ -0,0 +1,70 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxc.pexcel.records;
+
+import java.io.OutputStream;
+import java.io.InputStream;
+import java.io.IOException;
+
+import org.openoffice.xmerge.util.Debug;
+import org.openoffice.xmerge.converter.xml.sxc.pexcel.PocketExcelConstants;
+
+/**
+ * Represents a BIFF Record used to mark the end of a section of file
+ */
+public class Eof implements BIFFRecord {
+
+ /**
+ * Constructor
+ */
+ public Eof() {
+ }
+
+ /**
+ * Get the hex code for this particular <code>BIFFRecord</code>
+ *
+ * @return the hex code for <code>BeginningOfFile</code>
+ */
+ public short getBiffType() {
+ return PocketExcelConstants.EOF_MARKER;
+ }
+
+ public int read(InputStream input) throws IOException {
+ return 0;
+ }
+
+ public void write(OutputStream output) throws IOException {
+
+ output.write(getBiffType());
+
+ Debug.log(Debug.TRACE,"Writing Eof record");
+
+
+ }
+
+}
diff --git a/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/ExtendedFormat.java b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/ExtendedFormat.java
new file mode 100644
index 000000000000..5165efd84460
--- /dev/null
+++ b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/ExtendedFormat.java
@@ -0,0 +1,384 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxc.pexcel.records;
+
+import java.io.OutputStream;
+import java.io.InputStream;
+import java.io.IOException;
+import java.awt.Color;
+
+import org.openoffice.xmerge.util.Debug;
+import org.openoffice.xmerge.util.EndianConverter;
+import org.openoffice.xmerge.util.ColourConverter;
+import org.openoffice.xmerge.converter.xml.sxc.Format;
+import org.openoffice.xmerge.converter.xml.sxc.pexcel.PocketExcelConstants;
+
+/**
+ * Represents a BIFF Record descibing extended formatting information
+ *
+ */
+public class ExtendedFormat implements BIFFRecord,
+org.openoffice.xmerge.converter.xml.OfficeConstants {
+
+ private byte[] ixfnt = new byte[2]; // Index to Font Record
+ private byte[] ixnf = new byte[2];
+ private byte[] fattributes = new byte[4];
+ private byte[] fBaseAttr = new byte[2]; // base attribute flags
+ private byte[] fTextAttr = new byte[2]; // text attribute flags
+ private byte[] icvFore = new byte[2]; // Background colour of the cell
+ private byte[] icvFill = new byte[2];
+ private byte bRight; // Right border Style
+ private byte bTop; // Top border style
+ private byte bLeft; // Left border style
+ private byte bBottom; // Bottom border style
+ private byte backstyle;
+ private byte borderstyle;
+
+ public static final int TOP_BORDER = 0x01;
+ public static final int LEFT_BORDER = 0x02;
+ public static final int BOTTOM_BORDER = 0x04;
+ public static final int RIGHT_BORDER = 0x08;
+
+ // Horizontal Alignment Styles
+ public static final int NORMAL_ALIGN = 0x00;
+ public static final int LEFT_ALIGN = 0x01;
+ public static final int CENTER_ALIGN = 0x02;
+ public static final int RIGHT_ALIGN = 0x03;
+
+ // Vertical Alignment Styles
+ public static final int TOP_ALIGN = 0x10;
+ public static final int MIDDLE_ALIGN = 0x20;
+ public static final int BOTTOM_ALIGN = 0x30;
+
+ public static final int WORD_WRAP = 0x08;
+
+ /**
+ * Constructs an <code>ExtendedFormat</code> from the
+ * <code>InputStream</code>
+ *
+ * @param is <code>InputStream</code> to read from
+ */
+ public ExtendedFormat(InputStream is) throws IOException {
+ read(is);
+ }
+
+ /**
+ * Constructs a pocket Excel Document using defualt values and sets the
+ * font index using the specified attribute
+ *
+ * @param ixfnt index of the font this format should use
+ */
+ public ExtendedFormat(int ixfnt, Format fmt) {
+
+ this.ixfnt = EndianConverter.writeShort((short)ixfnt);
+ String category = fmt.getCategory();
+ if(category.equalsIgnoreCase(CELLTYPE_CURRENCY)) {
+ this.ixnf = EndianConverter.writeShort((short) 0);
+ } else if(category.equalsIgnoreCase(CELLTYPE_DATE)) {
+ this.ixnf = EndianConverter.writeShort((short) 0x12);
+ } else if(category.equalsIgnoreCase(CELLTYPE_TIME)) {
+ this.ixnf = EndianConverter.writeShort((short) 0x1E);
+ } else {
+ this.ixnf = EndianConverter.writeShort((short) 0);
+ }
+ this.fattributes = new byte[] {(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF};
+ this.fBaseAttr = new byte[] {(byte)0x02,(byte)0x00};
+
+ this.fTextAttr = new byte[] {(byte)0x00, (byte)0x00};
+
+ int align = fmt.getAlign();
+
+ // Horizontal alignment
+ if(align==Format.CENTER_ALIGN) {
+ fTextAttr[0] |= CENTER_ALIGN;
+ } else if(align==Format.LEFT_ALIGN) {
+ fTextAttr[0] |= LEFT_ALIGN;
+ } else if(align==Format.RIGHT_ALIGN) {
+ fTextAttr[0] |= RIGHT_ALIGN;
+ } else {
+ fTextAttr[0] |= NORMAL_ALIGN;
+ }
+
+ int vertAlign = fmt.getVertAlign();
+
+ // Vertical alignment
+ if(vertAlign==Format.TOP_ALIGN) {
+ fTextAttr[0] |= TOP_ALIGN;
+ } else if(vertAlign==Format.BOTTOM_ALIGN) {
+ fTextAttr[0] |= BOTTOM_ALIGN;
+ } else if(vertAlign==Format.MIDDLE_ALIGN) {
+ fTextAttr[0] |= MIDDLE_ALIGN;
+ } else {
+ fTextAttr[0] |= BOTTOM_ALIGN;
+ }
+
+ if(fmt.getAttribute(Format.WORD_WRAP)) {
+ fTextAttr[0] |= WORD_WRAP;
+ }
+
+ if(fmt.getAttribute(Format.LEFT_BORDER)) {
+ fTextAttr[1] |= LEFT_BORDER;
+ }
+ if(fmt.getAttribute(Format.RIGHT_BORDER)) {
+ fTextAttr[1] |= RIGHT_BORDER;
+ }
+ if(fmt.getAttribute(Format.TOP_BORDER)) {
+ fTextAttr[1] |= TOP_BORDER;
+ }
+ if(fmt.getAttribute(Format.BOTTOM_BORDER)) {
+ fTextAttr[1] |= BOTTOM_BORDER;
+ }
+
+ Color background = fmt.getBackground();
+ if( background != null ) {
+ ColourConverter cc = new ColourConverter(PocketExcelConstants.cLookup);
+ icvFill = EndianConverter.writeShort(cc.convertFromRGB(background));
+ } else {
+ icvFill = new byte[] {(byte)0xFF,(byte)0x00};
+ }
+
+ icvFore = new byte[] {(byte)0xFF,(byte)0x00};
+
+ bRight = (byte) 0xFF;
+ bTop = (byte) 0xFF;
+ bLeft = (byte) 0xFF;
+ bBottom = (byte) 0xFF;
+ backstyle = (byte) 0x00;
+ borderstyle = (byte) 0x00;
+
+ }
+
+ /**
+ * Get the font index this format uses
+ *
+ * @return the font index
+ */
+ public int getFontIndex() {
+ return EndianConverter.readShort(ixfnt);
+ }
+
+ /**
+ * Get the font index this format uses
+ *
+ * @return the font index
+ */
+ public int getFormatIndex() {
+ return EndianConverter.readShort(ixnf);
+ }
+
+ /**
+ * Get the font index this format uses
+ *
+ * @return the font index
+ */
+ public int getTextAttr() {
+ return EndianConverter.readShort(fTextAttr);
+ }
+
+ /**
+ * Get the background color this format uses
+ *
+ * @return the background color
+ */
+ public Color getBackground() {
+ short rgb = EndianConverter.readShort(icvFill);
+ Color c = null;
+ if(rgb!=0xFF) {
+ ColourConverter cc = new ColourConverter(PocketExcelConstants.cLookup);
+ c = cc.convertToRGB(rgb);
+ }
+ return c;
+ }
+
+ /**
+ * Get the Vertical alignment for this Format
+ *
+ * @return the alignment
+ */
+ public int getVertAlign() {
+
+ int mask = MIDDLE_ALIGN | BOTTOM_ALIGN | TOP_ALIGN;
+ int masked = fTextAttr[0] & mask;
+
+ if(masked == MIDDLE_ALIGN)
+ return Format.MIDDLE_ALIGN;
+
+ if(masked == BOTTOM_ALIGN)
+ return Format.BOTTOM_ALIGN;
+
+ if(masked == TOP_ALIGN)
+ return Format.TOP_ALIGN;
+
+ return Format.BOTTOM_ALIGN;
+ }
+
+ /**
+ * Get the alignment for this Format
+ *
+ * @return the alignment
+ */
+ public int getAlign() {
+
+ int mask = LEFT_ALIGN | CENTER_ALIGN | RIGHT_ALIGN;
+ int masked = fTextAttr[0] & mask;
+
+ if(masked == MIDDLE_ALIGN)
+ return Format.LEFT_ALIGN;
+
+ if(masked == CENTER_ALIGN)
+ return Format.CENTER_ALIGN;
+
+ if(masked == RIGHT_ALIGN)
+ return Format.RIGHT_ALIGN;
+
+ return Format.LEFT_ALIGN;
+ }
+
+ /**
+ * Is the word wrap set
+ *
+ * @return true if it is selected
+ */
+ public boolean isWordWrap() {
+ return (!((fTextAttr[0] & WORD_WRAP) == 0));
+ }
+ /**
+ * Get the border style
+ *
+ * @param side the side to test
+ * @return true if it is selected
+ */
+ public boolean isBorder(int side) {
+ return (!((fTextAttr[1] & side) == 0));
+ }
+
+ /**
+ * Compare two ExtendedFormat to see if the font index is the same
+ *
+ * @param the ExtendedFormat to be used in the comaprison
+ * @return boolean if the two are the same otherwise false
+ */
+ public boolean compareTo(ExtendedFormat rhs) {
+
+ if(EndianConverter.readShort(icvFill) !=
+ EndianConverter.readShort(rhs.icvFill))
+ return false;
+
+ if(this.getTextAttr() != rhs.getTextAttr())
+ return false;
+
+ if(this.getVertAlign() != rhs.getVertAlign())
+ return false;
+
+ if(this.getAlign() != rhs.getAlign())
+ return false;
+
+ if (this.getFontIndex() != rhs.getFontIndex())
+ return false;
+
+ if (this.getFormatIndex() != rhs.getFormatIndex())
+ return false;
+
+ return true;
+ }
+
+ /**
+ * Get the hex code for this particular <code>BIFFRecord</code>
+ *
+ * @return the hex code for <code>ExtendedFormat</code>
+ */
+ public short getBiffType() {
+ return PocketExcelConstants.EXTENDED_FORMAT;
+ }
+
+ /**
+ * Reads the extended format from the <code>Inputstream</code>
+ *
+ * @param input the <code>Inputstream</code>to read
+ * @return toal number of bytes read
+ */
+ public int read(InputStream input) throws IOException {
+
+ int numOfBytesRead = input.read(ixfnt);
+ numOfBytesRead += input.read(ixnf);
+ numOfBytesRead += input.read(fattributes);
+ numOfBytesRead += input.read(fBaseAttr);
+ numOfBytesRead += input.read(fTextAttr);
+ numOfBytesRead += input.read(icvFore);
+ numOfBytesRead += input.read(icvFill);
+ bRight = (byte) input.read();
+ bTop = (byte) input.read();
+ bLeft = (byte) input.read();
+ bBottom = (byte) input.read();
+ backstyle = (byte) input.read();
+ borderstyle = (byte) input.read();
+ numOfBytesRead += 6;
+
+ Debug.log(Debug.TRACE,"\tixfnt : "+ EndianConverter.readShort(ixfnt) +
+ " ixnf : " + EndianConverter.readShort(ixnf) +
+ " fattributes : " + EndianConverter.readInt(fattributes) +
+ " fBaseAttr : " + EndianConverter.readShort(fBaseAttr) +
+ "\n\tfTextAttr : " + EndianConverter.readShort(fTextAttr) +
+ " icvFore : " + EndianConverter.readShort(icvFore) +
+ " icvFill : " + EndianConverter.readShort(icvFill) +
+ " bRight : " + bRight +
+ "\n\tbTop : " + bTop +
+ " bLeft : " + bLeft +
+ " bBottom : " + bBottom +
+ " backstyle : " + backstyle +
+ " borderstyle : " + borderstyle);
+ return numOfBytesRead;
+ }
+
+ /**
+ * Writes the ExtendedFormat to the <code>Outputstream<code>
+ *
+ * @param output the <code>Outputstream</code>to write to
+ */
+ public void write(OutputStream output) throws IOException {
+
+ output.write(getBiffType());
+ output.write(ixfnt);
+ output.write(ixnf);
+ output.write(fattributes);
+ output.write(fBaseAttr);
+ output.write(fTextAttr);
+ output.write(icvFore);
+ output.write(icvFill);
+ output.write(bRight);
+ output.write(bTop);
+ output.write(bLeft);
+ output.write(bBottom);
+ output.write(backstyle);
+ output.write(borderstyle);
+
+ Debug.log(Debug.TRACE,"Writing ExtendedFormat record");
+
+ }
+
+}
diff --git a/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/FloatNumber.java b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/FloatNumber.java
new file mode 100644
index 000000000000..8d702640a500
--- /dev/null
+++ b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/FloatNumber.java
@@ -0,0 +1,120 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxc.pexcel.records;
+
+import java.io.OutputStream;
+import java.io.InputStream;
+import java.io.IOException;
+
+import org.openoffice.xmerge.util.Debug;
+import org.openoffice.xmerge.util.EndianConverter;
+import org.openoffice.xmerge.converter.xml.sxc.pexcel.PocketExcelConstants;
+
+/**
+ * Represents a BIFF Record describing a floating point
+ */
+public class FloatNumber extends CellValue {
+
+ protected byte[] num = new byte[8];
+
+ /**
+ * Constructs a pocket Excel Document from the
+ * <code>InputStream</code> and assigns it the document name passed in
+ *
+ * @param is InputStream containing a Pocket Excel Data file.
+ */
+ public FloatNumber(InputStream is) throws IOException {
+ read(is);
+ }
+
+ /**
+ * Constructs a <code>FloatNumber</code> using specified attributes
+ *
+ * @param row row number
+ * @param col column number
+ * @param cellContents contents of the cell
+ * @param ixfe font index
+ */
+ public FloatNumber(int row, int column, String cellContents, int ixfe) throws IOException {
+
+ setIxfe(ixfe);
+ setRow(row);
+ setCol(column);
+ double cellLong = (double) Double.parseDouble(cellContents);
+ num = EndianConverter.writeDouble(cellLong);
+ }
+
+ /**
+ * Get the hex code for this particular <code>BIFFRecord</code>
+ *
+ * @return the hex code for <code>FloatNumber</code>
+ */
+ public short getBiffType() {
+ return PocketExcelConstants.NUMBER_CELL;
+ }
+
+ /**
+ * Reads a<code>FloatNumber</code> from the specified <code>InputStream</code>
+ *
+ * @param input the <code>InputStram</code> to read from
+ */
+ public int read(InputStream input) throws IOException {
+
+ int numOfBytesRead = super.read(input);
+
+ numOfBytesRead += input.read(num);
+
+ Debug.log(Debug.TRACE," num : " + getString());
+ return numOfBytesRead;
+ }
+
+ public void write(OutputStream output) throws IOException {
+
+ output.write(getBiffType());
+
+ super.write(output);
+
+ output.write(num);
+
+ Debug.log(Debug.TRACE,"Writing FloatNumber record");
+ }
+
+
+ /**
+ * Gets the numerical value the cell represents
+ *
+ * @return the <code>String</code> representing a double value
+ */
+ public String getString() throws IOException {
+
+ double value = EndianConverter.readDouble(num);
+ Double myDo = new Double(value);
+ return myDo.toString();
+ }
+
+}
diff --git a/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/FontDescription.java b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/FontDescription.java
new file mode 100644
index 000000000000..61d9746c80d3
--- /dev/null
+++ b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/FontDescription.java
@@ -0,0 +1,286 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxc.pexcel.records;
+
+import java.io.OutputStream;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.awt.Color;
+
+import org.openoffice.xmerge.converter.xml.sxc.Format;
+import org.openoffice.xmerge.util.Debug;
+import org.openoffice.xmerge.util.EndianConverter;
+import org.openoffice.xmerge.util.ColourConverter;
+import org.openoffice.xmerge.converter.xml.sxc.pexcel.PocketExcelConstants;
+
+
+/**
+ * Represents a BIFF Record descibing a font used
+ */
+public class FontDescription implements BIFFRecord {
+
+ private byte[] dwHeight = new byte[2];
+ private byte[] grbit = new byte[2];
+ private byte[] icvFore = new byte[2];
+ private byte[] bls = new byte[2];
+ private byte[] Reserved2 = new byte[2];
+ private byte uls;
+ private byte bFamily;
+ private byte bCharSet;
+ private byte Reserved3;
+ private byte cch;
+ private byte[] rgch;
+
+ public static final int UNDERLINE = 0x01;
+ public static final int ITALIC = 0x02;
+
+ /**
+ * Constructs a FontDescription from the bold italic and undelrine attributes
+ *
+ * @param italic Italic attribute
+ * @param bold Bold attribute
+ * @param underline Underline attribute
+ */
+ public FontDescription(Format fmt) throws IOException {
+
+ Debug.log(Debug.TRACE,"Building FontDescriptor based on Format : " + fmt);
+
+ this.dwHeight = EndianConverter.writeShort((short) (fmt.getFontSize()*20));
+
+ grbit = new byte[] {(byte)0x00, (byte)0x00};
+ bls = EndianConverter.writeShort((short) 400);
+ uls = 0;
+
+ if (fmt.getAttribute(Format.ITALIC))
+ grbit[0] |= ITALIC;
+
+ if (fmt.getAttribute(Format.BOLD))
+ bls = EndianConverter.writeShort((short) 700);
+
+ if (fmt.getAttribute(Format.UNDERLINE))
+ uls |= UNDERLINE;
+
+
+ bFamily = 0;
+ bCharSet = 0;
+
+ String fontName = fmt.getFontName();
+ if( !fontName.equals("Tahoma") &&
+ !fontName.equals("Courier New")) {
+ // We will set our default font to be Tahoma
+ fontName = new String("Tahoma");
+ }
+
+ cch = (byte) fontName.length();
+ rgch = fontName.getBytes("UTF-16LE");
+
+ Color foreground = fmt.getForeground();
+ if( foreground != null ) {
+ ColourConverter cc = new ColourConverter(PocketExcelConstants.cLookup);
+ icvFore = EndianConverter.writeShort(cc.convertFromRGB(foreground));
+ } else {
+ icvFore = new byte[] {(byte)0xFF,(byte)0x00};
+ }
+
+ Reserved2 = EndianConverter.writeShort((short) 0);
+ Reserved3 = 0;
+
+ }
+
+ /**
+ * Tests if this font descriptor defines italic
+ *
+ * @return true if italic otherwise false
+ */
+ public boolean isItalic() {
+
+ return (EndianConverter.readShort(grbit) == 2);
+ }
+
+ /**
+ * Tests if this font descriptor defines underline
+ *
+ * @return true if underline otherwise false
+ */
+ public boolean isUnderline() {
+
+ return (uls == 1);
+ }
+
+ /**
+ * Tests if this font descriptor defines bold
+ *
+ * @return true if bold otherwise false
+ */
+ public boolean isBold() {
+
+ return (EndianConverter.readShort(bls) == 700);
+ }
+
+ /**
+ * Get the background color this format uses
+ *
+ * @return the background color
+ */
+ public Color getForeground() {
+ short rgb = EndianConverter.readShort(icvFore);
+ Color c = null;
+ if(rgb!=0xFF) {
+ ColourConverter cc = new ColourConverter(PocketExcelConstants.cLookup);
+ c = cc.convertToRGB(rgb);
+ }
+ return c;
+ }
+
+ /**
+ * Compares current font descriptor against one passed in
+ *
+ * @return true if attrbitues are the same
+ */
+ public boolean compareTo(FontDescription rhs) {
+
+ if(EndianConverter.readShort(icvFore) !=
+ EndianConverter.readShort(rhs.icvFore))
+ return false;
+
+ if (EndianConverter.readShort(dwHeight) !=
+ EndianConverter.readShort(dwHeight))
+ return false;
+
+ if (this.getFont() != rhs.getFont())
+ return false;
+
+ if (this.isBold() != rhs.isBold())
+ return false;
+
+ if (this.isUnderline() != rhs.isUnderline())
+ return false;
+
+ if (this.isItalic() != rhs.isItalic())
+ return false;
+
+ return true;
+ }
+
+
+ /**
+ * Constructs a Font Description from the <code>InputStream</code>
+ *
+ * @param is InputStream containing a <code>FontDescription</code>
+ */
+ public FontDescription(InputStream is) throws IOException {
+ read(is);
+ }
+
+ /**
+ * Get the hex code for this particular <code>BIFFRecord</code>
+ *
+ * @return the hex code for <code>FontDescription</code>
+ */
+ public short getBiffType() {
+ return PocketExcelConstants.FONT_DESCRIPTION;
+ }
+
+ /**
+ * Get the Font size
+ *
+ */
+ public int getFontSize() {
+ return EndianConverter.readShort(dwHeight)/20;
+ }
+
+ /**
+ * Get the font name
+ *
+ */
+ public String getFont() {
+
+ String name;
+
+ try {
+ name = new String(rgch, "UTF-16LE");
+ } catch (UnsupportedEncodingException e){
+ name = "Tahoma";
+ }
+ return name;
+ }
+
+ /**
+ * Constructs a Font Description from the <code>InputStream</code>
+ *
+ * @param is InputStream containing a <code>FontDescription</code>
+ */
+ public int read(InputStream input) throws IOException {
+
+ int numOfBytesRead = input.read(dwHeight);
+ numOfBytesRead += input.read(grbit);
+ numOfBytesRead += input.read(icvFore);
+ numOfBytesRead += input.read(bls);
+ numOfBytesRead += input.read(Reserved2);
+ uls = (byte) input.read();
+ bFamily = (byte) input.read();
+ bCharSet = (byte) input.read();
+ Reserved3 = (byte) input.read();
+ cch = (byte) input.read();
+ numOfBytesRead += 5;
+
+ rgch = new byte[cch*2];
+ input.read(rgch, 0, cch*2);
+
+ Debug.log(Debug.TRACE,"\tdwHeight : "+ EndianConverter.readShort(dwHeight) +
+ " grbit : " + EndianConverter.readShort(grbit) +
+ " bls : " + EndianConverter.readShort(bls) +
+ " uls : " + uls +
+ "\n\tFamily : " + bFamily +
+ " bCharSet : " + bCharSet +
+ " cch : " + cch +
+ " rgch : " + new String(rgch,"UTF-16LE"));
+
+ return numOfBytesRead;
+ }
+
+ public void write(OutputStream output) throws IOException {
+
+ output.write(getBiffType());
+ output.write(dwHeight);
+ output.write(grbit);
+ output.write(icvFore);
+ output.write(bls);
+ output.write(Reserved2);
+ output.write(uls);
+ output.write(bFamily);
+ output.write(bCharSet);
+ output.write(Reserved3);
+ output.write(cch);
+ output.write(rgch);
+
+ Debug.log(Debug.TRACE,"Writing FontDescription record");
+ }
+
+}
diff --git a/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/Formula.java b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/Formula.java
new file mode 100644
index 000000000000..a073883b2e8e
--- /dev/null
+++ b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/Formula.java
@@ -0,0 +1,257 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxc.pexcel.records;
+
+import java.io.OutputStream;
+import java.io.InputStream;
+import java.io.IOException;
+
+import org.openoffice.xmerge.util.Debug;
+import org.openoffice.xmerge.util.EndianConverter;
+import org.openoffice.xmerge.converter.xml.OfficeConstants;
+import org.openoffice.xmerge.converter.xml.sxc.Format;
+import org.openoffice.xmerge.converter.xml.sxc.pexcel.records.formula.FormulaHelper;
+import org.openoffice.xmerge.converter.xml.sxc.pexcel.records.Workbook;
+import org.openoffice.xmerge.converter.xml.sxc.pexcel.PocketExcelConstants;
+
+
+/**
+ * Represents a BIFF Record describing a formula
+ */
+public class Formula extends CellValue implements OfficeConstants {
+
+ private byte[] num = new byte[8];
+ private byte grbit;
+ private byte[] cce = new byte[2];
+ private byte[] rgce;
+ private FormulaHelper fh = new FormulaHelper();
+
+ /**
+ * Constructs a <code>Formula</code> using specified attributes
+ *
+ * @param row row number
+ * @param col column number
+ * @param cellContents contents of the cell
+ * @param ixfe font index
+ * @param value the value of the cell
+ */
+ public Formula(int row, int column, String cellContents, int ixfe, Format fmt, Workbook wb)
+ throws Exception {
+
+ fh.setWorkbook(wb);
+
+ setRow(row);
+ setCol(column);
+ setIxfe(ixfe);
+ setFormula(cellContents);
+
+ String category = fmt.getCategory();
+ String value = fmt.getValue();
+
+ if(category.equalsIgnoreCase(CELLTYPE_BOOLEAN)) {
+ num[0]=(byte)0x01;
+ num[1]=(byte)0x00;
+ if(value.equalsIgnoreCase("true")) {
+ num[2]=(byte)0x01;
+ } else {
+ num[2]=(byte)0x00;
+ }
+ num[3]=(byte)0x00;num[4]=(byte)0x00;num[5]=(byte)0x00;
+ num[6]=(byte)0xFF;num[7]=(byte)0xFF;
+ } else if(category.equalsIgnoreCase(CELLTYPE_DATE)) {
+ Debug.log(Debug.TRACE,"Date Formula");
+ num = EndianConverter.writeDouble(toExcelSerialDate(fmt.getValue()));
+ } else if(category.equalsIgnoreCase(CELLTYPE_TIME)) {
+ Debug.log(Debug.TRACE,"Time Formula");
+ num = EndianConverter.writeDouble(toExcelSerialTime(fmt.getValue()));
+ } else if(category.equalsIgnoreCase(CELLTYPE_PERCENT)) {
+ Debug.log(Debug.TRACE,"Percent Formula");
+ double percent = (double) Double.parseDouble(fmt.getValue());
+ num = EndianConverter.writeDouble(percent);
+ } else if(category.equalsIgnoreCase(CELLTYPE_CURRENCY)) {
+ Debug.log(Debug.TRACE,"Currency Formula");
+ } else if(category.equalsIgnoreCase(CELLTYPE_STRING)) {
+ Debug.log(Debug.TRACE,"String Formula");
+ num[0]=(byte)0x00;
+ num[1]=(byte)0x00;
+ num[2]=(byte)0x00;
+ num[3]=(byte)0x00;
+ num[4]=(byte)0x00;
+ num[5]=(byte)0x00;
+ num[6]=(byte)0xFF;
+ num[7]=(byte)0xFF;
+ } else {
+ Debug.log(Debug.TRACE,"Float Formula");
+ double cellLong = (double) Double.parseDouble(fmt.getValue());
+ num = EndianConverter.writeDouble(cellLong);
+ }
+ }
+
+ /**
+ * Translates a <code>String</code> written in infix which represents a
+ * formula into a byte[] what can be written to pocket excel file.
+ *
+ * @param formula string
+ */
+ public void setFormula(String inFormula) throws Exception {
+
+ rgce = fh.convertCalcToPXL(inFormula);
+ cce = EndianConverter.writeShort((short) rgce.length);
+ }
+
+ /**
+ * Constructs a pocket Excel formula from the
+ * <code>InputStream</code>
+ *
+ * @param is InputStream containing a Pocket Excel Data file.
+ */
+ public Formula(InputStream is, Workbook wb) throws IOException {
+ read(is);
+ fh.setWorkbook(wb);
+ }
+
+ /**
+ * Get the hex code for this particular <code>BIFFRecord</code>
+ *
+ * @return the hex code for <code>Formula</code>
+ */
+ public short getBiffType() {
+ return PocketExcelConstants.FORMULA_CELL;
+ }
+
+ /**
+ * Reads the formula data members from the stream. Byte arrays for Strings
+ * are doubled as they are stored as unicode
+ *
+ * @return total number of bytes read
+ */
+ public int read(InputStream input) throws IOException {
+
+ int numOfBytesRead = super.read(input);
+
+ numOfBytesRead += input.read(num);
+ grbit = (byte) input.read();
+ numOfBytesRead ++;
+ numOfBytesRead += input.read(cce);
+
+ int strLen = EndianConverter.readShort(cce);
+ rgce = new byte[strLen];
+ input.read(rgce, 0, strLen);
+
+ Debug.log(Debug.TRACE, " num : " + num +
+ "\n\tgrbit : " + grbit +
+ " cce : " + EndianConverter.readShort(cce) +
+ " rgce : " + new String(rgce,"UTF-16LE") +
+ "\n" + numOfBytesRead + " Bytes Read");
+
+ return numOfBytesRead;
+ }
+
+ /**
+ * Writes the Formula record to the <code>OutputStream</code>
+ *
+ * @param the <code>OutputStream</code> being written to
+ */
+ public void write(OutputStream output) throws IOException {
+
+ output.write(getBiffType());
+
+ super.write(output);
+
+ output.write(num);
+ output.write(grbit);
+ output.write(cce);
+ output.write(rgce);
+
+ Debug.log(Debug.TRACE,"Writing Formula record");
+ }
+
+ /**
+ * Gets the <code>String</code> representing the cell value
+ *
+ * @return the <code>String</code> representing the cell value
+ */
+ public String getValue() throws IOException {
+
+ double value = EndianConverter.readDouble(num);
+ Double myDo = new Double(value);
+ return myDo.toString();
+ }
+
+ /**
+ * Gets the <code>String</code> representing the cells contents
+ *
+ * @return the <code>String</code> representing the cells contents
+ */
+ public String getString() throws IOException {
+
+ return fh.convertPXLToCalc(rgce);
+ }
+
+ /**
+ * Excel dates are the number of days since 1/1/1900. This method converts
+ * to this date.
+ *
+ * @param s String representing a date in the form YYYY-MM-DD
+ * @return The excel serial date
+ */
+ public long toExcelSerialDate(String s) throws IOException {
+
+ int year = Integer.parseInt(s.substring(0,4));
+ int month = Integer.parseInt(s.substring(5,7));
+ int day = Integer.parseInt(s.substring(8,10));
+
+ long serialDate = (1461 * (year + 4800 + (month - 14) / 12)) / 4 +
+ (367 * (month - 2 - 12 * ((month - 14) / 12))) / 12 -
+ (3 * ((year + 4900 + (month - 14) / 12)) / 100) / 4 +
+ day - 2415019 - 32075;
+
+ return serialDate;
+ }
+
+ /**
+ * Excel times are a fraction of a 24 hour day expressed in seconds. This method converts
+ * to this time.
+ *
+ * @param s String representing a time in the form ??HH?MM?SS?
+ * @return The excel serial time
+ */
+ public double toExcelSerialTime(String s) throws IOException {
+
+ int hours = Integer.parseInt(s.substring(2,4));
+ int mins = Integer.parseInt(s.substring(5,7));
+ int secs = Integer.parseInt(s.substring(8,10));
+
+ int timeSecs = (hours*3600) + (mins*60) + (secs);
+
+ double d = (double) timeSecs / (24 * 3600);
+
+ return d;
+ }
+
+}
diff --git a/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/LabelCell.java b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/LabelCell.java
new file mode 100644
index 000000000000..d4ad28cc7e2b
--- /dev/null
+++ b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/LabelCell.java
@@ -0,0 +1,139 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxc.pexcel.records;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.IOException;
+
+import org.openoffice.xmerge.util.Debug;
+import org.openoffice.xmerge.util.EndianConverter;
+import org.openoffice.xmerge.converter.xml.sxc.pexcel.PocketExcelConstants;
+
+
+/**
+ * Reperesent a BIFF Record descibing a cell containing a string
+ */
+public class LabelCell extends CellValue {
+
+ private byte[] cch = new byte[2];
+ private byte[] rgch;
+
+ /**
+ * Constructs a <code>LabelCell</code> using specified attributes
+ *
+ * @param row row number
+ * @param col column number
+ * @param cellContents contents of the cell
+ * @param ixfe font index
+ */
+ public LabelCell(int row, int column, String cellContents, int ixfe)
+ throws IOException {
+
+ setLabel(cellContents);
+ setRow(row);
+ setCol(column);
+ setIxfe(ixfe);
+ }
+
+ /**
+ * Reads a LabelCell from the <code>InputStream</code>
+ *
+ * @param is the <code>Inputstream</code> to read from
+ */
+ public LabelCell(InputStream is) throws IOException {
+ read(is);
+ }
+
+ /**
+ * Writes a <code>LabelCell</code> to the specified <code>Outputstream</code>
+ *
+ * @param os the <code>OutputStream</code> to write to
+ */
+ public void write(OutputStream output) throws IOException {
+
+ output.write(getBiffType());
+
+ super.write(output);
+
+ output.write(cch);
+ output.write(rgch);
+
+ Debug.log(Debug.TRACE,"Writing Label record");
+ }
+
+ /**
+ * Get the hex code for this particular <code>BIFFRecord</code>
+ *
+ * @return the hex code for <code>LabelCell</code>
+ */
+ public short getBiffType() {
+ return PocketExcelConstants.LABEL_CELL;
+ }
+
+ /**
+ * Reads a<code>LabelCell</code> from the specified <code>InputStream</code>
+ *
+ * @param input the <code>InputStram</code> to read from
+ */
+ public int read(InputStream input) throws IOException {
+
+ int numOfBytesRead = super.read(input);
+
+ numOfBytesRead += input.read(cch);
+
+ int strLen = EndianConverter.readShort(cch)*2;
+ rgch = new byte[strLen];
+ input.read(rgch, 0, strLen);
+
+ Debug.log(Debug.TRACE, " cch : " + EndianConverter.readShort(cch) +
+ " rgch : " + new String(rgch, "UTF-16LE"));
+
+ return numOfBytesRead;
+ }
+
+
+ /**
+ * Gets the <code>String</code> representing the cells contents
+ *
+ * @return the <code>String</code> representing the cells contents
+ */
+ public String getString() throws IOException {
+ return (new String(rgch,"UTF-16LE"));
+ }
+
+ /**
+ * Sets the <code>String</code> representing the cells contents
+ *
+ * @return the <code>String</code> representing the cells contents
+ */
+ private void setLabel(String cellContents) throws IOException {
+ rgch = cellContents.getBytes("UTF-16LE");
+ cch = EndianConverter.writeShort((short)cellContents.length());
+ }
+}
diff --git a/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/NumberFormat.java b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/NumberFormat.java
new file mode 100644
index 000000000000..342d9b676bcd
--- /dev/null
+++ b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/NumberFormat.java
@@ -0,0 +1,93 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxc.pexcel.records;
+
+import java.io.OutputStream;
+import java.io.InputStream;
+import java.io.IOException;
+
+import org.openoffice.xmerge.util.Debug;
+import org.openoffice.xmerge.converter.xml.sxc.pexcel.PocketExcelConstants;
+
+
+/**
+ * Represents a BIFF Record describing a number format
+ */
+public class NumberFormat implements BIFFRecord {
+
+ private byte cce;
+ private byte[] rgch;
+
+ /**
+ * Constructs a NumberFormat Record from the <code>InputStream</code>
+ *
+ * @param is InputStream containing the record data
+ */
+ public NumberFormat(InputStream is) throws IOException {
+ read(is);
+ }
+
+ /**
+ * Get the hex code for this particular <code>BIFFRecord</code>
+ *
+ * @return the hex code for <code>NumberFormat</code>
+ */
+ public short getBiffType() {
+ return PocketExcelConstants.NUMBER_FORMAT;
+ }
+
+ /**
+ * Reads the NumberFormat from the <code>InputStream</code> Byte array
+ * containg strings are doubled in length becuse they use unicode
+ *
+ * @return the total number of bytes read
+ */
+ public int read(InputStream input) throws IOException {
+
+ cce = (byte) input.read();
+ int numOfBytesRead = 1;
+
+ rgch = new byte[cce*2];
+ numOfBytesRead += input.read(rgch, 0, cce*2);
+
+ Debug.log(Debug.TRACE, "\tcce : "+ cce +
+ " rgch : " + new String(rgch,"UTF-16LE"));
+
+ return numOfBytesRead;
+ }
+
+ public void write(OutputStream output) throws IOException {
+
+ output.write(getBiffType());
+ output.write(cce);
+ output.write(rgch);
+
+ Debug.log(Debug.TRACE,"Writing NumberFormat record");
+ }
+
+}
diff --git a/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/Pane.java b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/Pane.java
new file mode 100644
index 000000000000..b65d1027f969
--- /dev/null
+++ b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/Pane.java
@@ -0,0 +1,218 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxc.pexcel.records;
+
+import java.io.OutputStream;
+import java.io.InputStream;
+import java.io.IOException;
+import java.awt.Point;
+
+import org.openoffice.xmerge.util.Debug;
+import org.openoffice.xmerge.util.EndianConverter;
+import org.openoffice.xmerge.converter.xml.sxc.pexcel.PocketExcelConstants;
+import org.openoffice.xmerge.converter.xml.sxc.SheetSettings;
+
+/**
+ * Represents a BIFF Record that describes the number and position of unfrozen
+ * panes.
+ */
+public class Pane implements BIFFRecord {
+
+ private byte[] x = new byte[2];
+ private byte[] y = new byte[2];
+ private byte[] rwTop = new byte[2];
+ private byte[] colLeft = new byte[2];
+ private byte pnnAcct;
+
+ /**
+ * Default Constructor
+ */
+ public Pane() {
+ pnnAcct = (byte) 0x02; // Default setting
+ }
+
+ /**
+ * Constructs a Pane Record from the <code>InputStream</code>
+ *
+ * @param is InputStream containing a Pane record
+ */
+ public Pane(InputStream is) throws IOException {
+ read(is);
+ }
+
+ /**
+ * Get the hex code for this particular <code>BIFFRecord</code>
+ *
+ * @return the hex code for <code>Pane</code>
+ */
+ public short getBiffType() {
+ return PocketExcelConstants.PANE_INFO;
+ }
+
+ /**
+ * Gets the split point for this pane, in the case of splits this will be
+ * in twips.
+ *
+ * @return the split point
+ */
+ public Point getSplitPoint() {
+
+ int xTwips = EndianConverter.readShort(x)/11;
+ int yTwips = EndianConverter.readShort(y)/15;
+ return (new Point(xTwips, yTwips));
+ }
+
+ /**
+ * Gets the freeze point for this pane, in the case of freezes this will
+ * be a zero-based index to either the column or row.
+ *
+ * @return the freeze point
+ */
+ public Point getFreezePoint() {
+
+ return (new Point(EndianConverter.readShort(x),
+ EndianConverter.readShort(y)));
+ }
+
+ /**
+ * Sets the split point for this pane, coordinates are in column row units
+ * if the split type is freeze or twips if split type is split.
+ *
+ * @param splitType contains the X and Y split types (freeze or split)
+ * @param p the split point
+ */
+ public void setSplitPoint(Point splitType, Point p) {
+
+ if(splitType.getX()==SheetSettings.SPLIT
+ || splitType.getY()==SheetSettings.SPLIT) {
+ int yTwips = (int) p.getY();
+ short yPxl = (short) (yTwips * 15);
+ y = EndianConverter.writeShort(yPxl);
+ int xTwips = (int) p.getX();
+ short xPxl = (short) (xTwips * 11);
+ x = EndianConverter.writeShort(xPxl);
+ } else {
+ y = EndianConverter.writeShort((short) p.getY());
+ x = EndianConverter.writeShort((short) p.getX());
+ }
+
+ }
+
+ /**
+ * Get the hex code for this particular <code>BIFFRecord</code>
+ *
+ * @return the hex code for <code>Pane</code>
+ */
+ public void setPaneNumber(int paneNumber) {
+ pnnAcct = (byte) paneNumber;
+ }
+
+ /**
+ * Get the pane number of the active pane
+ * 0 - bottom right, 1 - top right
+ * 2 - bottom left, 3 - top left
+ *
+ * @return the hex code for <code>Pane</code>
+ */
+ public int getPaneNumber() {
+ return pnnAcct;
+ }
+
+ /**
+ * Set the top row visible in the lower pane
+ *
+ * @param top 0-based inex of the top row
+ */
+ public void setTop(int top) {
+ rwTop = EndianConverter.writeShort((short)top);
+ }
+
+ /**
+ * Set leftmost column visible in the right pane
+ *
+ * @param left 0-based index of the leftmost column
+ */
+ public void setLeft(int left) {
+ colLeft = EndianConverter.writeShort((short)left);
+ }
+
+ /**
+ * Get the top row visible in the lower pane
+ *
+ * @return the hex code for <code>Pane</code>
+ */
+ public int getTop() {
+ return EndianConverter.readShort(rwTop);
+ }
+
+ /**
+ * Get leftmost column visible in the right pane
+ *
+ * @return 0-based index of the column
+ */
+ public int getLeft() {
+ return EndianConverter.readShort(colLeft);
+ }
+
+
+ /**
+ * Reads a <code>Pane</code> record from the <code>InputStream</code>
+ *
+ * @param input <code>InputStream</code> to read from
+ * @return the total number of bytes read
+ */
+ public int read(InputStream input) throws IOException {
+
+ int numOfBytesRead = input.read(x);
+ numOfBytesRead += input.read(y);
+ numOfBytesRead += input.read(rwTop);
+ numOfBytesRead += input.read(colLeft);
+ pnnAcct = (byte) input.read();
+ numOfBytesRead++;
+
+ Debug.log(Debug.TRACE, "\tx : "+ EndianConverter.readShort(x) +
+ " y : " + EndianConverter.readShort(y) +
+ " rwTop : " + EndianConverter.readShort(rwTop) +
+ " colLeft : " + EndianConverter.readShort(colLeft) +
+ " pnnAcct : " + pnnAcct);
+
+ return numOfBytesRead;
+ }
+
+ public void write(OutputStream output) throws IOException {
+
+ output.write(getBiffType());
+ output.write(x);
+ output.write(y);
+ output.write(rwTop);
+ output.write(colLeft);
+ output.write(pnnAcct);
+
+ Debug.log(Debug.TRACE,"Writing Pane record");
+ }
+}
diff --git a/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/Row.java b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/Row.java
new file mode 100644
index 000000000000..8e3067d26c6b
--- /dev/null
+++ b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/Row.java
@@ -0,0 +1,138 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxc.pexcel.records;
+
+import java.io.OutputStream;
+import java.io.InputStream;
+import java.io.IOException;
+
+import org.openoffice.xmerge.util.Debug;
+import org.openoffice.xmerge.util.EndianConverter;
+import org.openoffice.xmerge.converter.xml.sxc.pexcel.PocketExcelConstants;
+
+
+/**
+ * Represents s BIFF Record that describes the format of a column
+ */
+public class Row implements BIFFRecord {
+
+ private byte[] rw = new byte[2];
+ private byte[] miyRw = new byte[2];
+ private byte[] grbit = new byte[2];
+ private byte[] ixfe = new byte[2];
+ private float scale = (float) 1;
+
+ /**
+ * Constructs a pocket Excel Document from the
+ * <code>InputStream</code> and assigns it the document name passed in
+ *
+ * @param rw Zero based row number
+ * @param miyRw row height
+ */
+ public Row(int rw, int miyRw, boolean userDefined) {
+ this.rw = EndianConverter.writeShort((short) rw);
+ miyRw *= scale;
+ this.miyRw = EndianConverter.writeShort((short) miyRw);
+ if(userDefined) {
+ grbit = EndianConverter.writeShort((short) 2);
+ } else {
+ grbit = EndianConverter.writeShort((short) 0);
+ }
+ ixfe = EndianConverter.writeShort((short) 0);
+ }
+
+ /**
+ * Constructs a Row fro man <code>InputStream</code>
+ *
+ * @param is InputStream containing a Pane Record
+ */
+ public Row(InputStream is) throws IOException {
+ read(is);
+ }
+
+ /**
+ * Get the hex code for this particular <code>BIFFRecord</code>
+ *
+ * @return the hex code for <code>Row</code>
+ */
+ public short getBiffType() {
+ return PocketExcelConstants.ROW_DESCRIPTION;
+ }
+
+ /**
+ * Get the height of this row
+ *
+ * @return the height of this row
+ */
+ public short getRowHeight() {
+ return EndianConverter.readShort(miyRw);
+ }
+
+ /**
+ * Get the rown number for this style
+ *
+ * @return the row this style applies to
+ */
+ public short getRowNumber() {
+ return EndianConverter.readShort(rw);
+ }
+
+ /**
+ * Reads a Row from an <code>InputStream</code>
+ *
+ * @param is InputStream containing a Pane Record
+ */
+ public int read(InputStream input) throws IOException {
+
+ int numOfBytesRead = input.read(rw);
+ numOfBytesRead += input.read(miyRw);
+ short scaledHeight = (short) (EndianConverter.readShort(miyRw) / scale);
+ miyRw = EndianConverter.writeShort(scaledHeight);
+ numOfBytesRead += input.read(grbit);
+ numOfBytesRead += input.read(ixfe);
+
+ Debug.log(Debug.TRACE,"\trw : "+ EndianConverter.readShort(rw) +
+ " miyRw : " + EndianConverter.readShort(miyRw) +
+ " grbit : " + EndianConverter.readShort(grbit) +
+ " ixfe : " + EndianConverter.readShort(ixfe));
+ return numOfBytesRead;
+ }
+
+ public void write(OutputStream output) throws IOException {
+
+ output.write(getBiffType());
+ output.write(rw);
+ output.write(miyRw);
+ output.write(grbit);
+ output.write(ixfe);
+
+ Debug.log(Debug.TRACE,"Writing Row record");
+
+ }
+
+}
diff --git a/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/Selection.java b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/Selection.java
new file mode 100644
index 000000000000..308eae29227e
--- /dev/null
+++ b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/Selection.java
@@ -0,0 +1,142 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxc.pexcel.records;
+
+import java.io.OutputStream;
+import java.io.InputStream;
+import java.io.IOException;
+import java.awt.Point;
+
+import org.openoffice.xmerge.util.Debug;
+import org.openoffice.xmerge.util.EndianConverter;
+import org.openoffice.xmerge.converter.xml.sxc.pexcel.PocketExcelConstants;
+
+
+/**
+ * Represents a BIFF Record that describes the selected area of a worksheet
+ */
+public class Selection implements BIFFRecord {
+
+ private byte[] rwTop = new byte[2];
+ private byte colLeft;
+ private byte[] rwBottom = new byte[2];
+ private byte colRight;
+ private byte[] rwActive = new byte[2];
+ private byte colActive;
+
+ /**
+ * Default Constructor
+ */
+ public Selection() {
+ this.rwTop = EndianConverter.writeShort((short) 0);
+ this.colLeft = 0;
+ this.rwBottom = EndianConverter.writeShort((short) 0);
+ this.colRight = 0;
+ this.rwActive = EndianConverter.writeShort((short) 0);
+ this.colActive = 0;
+
+ }
+
+ /**
+ * Constructs a Selection Record from the <code>InputStream</code>
+ *
+ * @param is InputStream containing a Pocket Excel Data file.
+ */
+ public Selection(InputStream is) throws IOException {
+ read(is);
+ }
+
+ /**
+ * Get the hex code for this particular <code>BIFFRecord</code>
+ *
+ * @return the hex code for <code>Selection</code>
+ */
+ public short getBiffType() {
+ return PocketExcelConstants.CURRENT_SELECTION;
+ }
+
+ /**
+ * Get the hex code for this particular <code>BIFFRecord</code>
+ *
+ * @return the hex code for <code>Selection</code>
+ */
+ public Point getActiveCell() {
+ Point p = new Point(colActive, EndianConverter.readShort(rwActive));
+ return p;
+ }
+
+ /**
+ * Get the hex code for this particular <code>BIFFRecord</code>
+ *
+ * @return the hex code for <code>Selection</code>
+ */
+ public void setActiveCell(Point p) {
+
+ colActive = (byte) p.getX();
+ rwActive = EndianConverter.writeShort((short) p.getY());
+ }
+
+ /**
+ * Reads a Selection Record from the <code>InputStream</code>
+ *
+ * @param is InputStream containing a Pocket Excel Data file.
+ */
+ public int read(InputStream input) throws IOException {
+
+ int numOfBytesRead = input.read(rwTop);
+ colLeft += (byte) input.read();
+ numOfBytesRead += input.read(rwBottom);
+ colRight += (byte) input.read();
+ numOfBytesRead += input.read(rwActive);
+ colActive += (byte) input.read();
+ numOfBytesRead += 3;
+
+ Debug.log(Debug.TRACE,"\trwTop : "+ EndianConverter.readShort(rwTop) +
+ " colLeft : " + colLeft +
+ " rwBottom : " + EndianConverter.readShort(rwBottom) +
+ " colRight : "+ colRight +
+ " rwActive : " + EndianConverter.readShort(rwActive) +
+ " colActive : " + colActive);
+
+ return numOfBytesRead;
+ }
+
+ public void write(OutputStream output) throws IOException {
+
+ output.write(getBiffType());
+ output.write(rwTop);
+ output.write(colLeft);
+ output.write(rwBottom);
+ output.write(colRight);
+ output.write(rwActive);
+ output.write(colActive);
+
+ Debug.log(Debug.TRACE,"Writing Selection record");
+ }
+
+}
diff --git a/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/StringValue.java b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/StringValue.java
new file mode 100644
index 000000000000..c516eca69b1b
--- /dev/null
+++ b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/StringValue.java
@@ -0,0 +1,124 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxc.pexcel.records;
+
+import java.io.OutputStream;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+
+import org.openoffice.xmerge.util.Debug;
+import org.openoffice.xmerge.util.EndianConverter;
+import org.openoffice.xmerge.converter.xml.sxc.pexcel.PocketExcelConstants;
+
+
+/**
+ * Represents a BIFF Record that describes the value of a formula that
+ * evaluates to a string
+ */
+public class StringValue implements BIFFRecord {
+
+ private byte[] cch = new byte[2];
+ private byte[] rgch;
+
+ /**
+ * Constructs a StringValue Record from an <code>InputStream</code>
+ *
+ * @param is InputStream containing a StringValue Record
+ */
+ public StringValue(String str) throws IOException {
+ cch = EndianConverter.writeShort((short) str.length());
+ rgch = new byte[str.length()];
+ rgch = str.getBytes("UTF-16LE");
+ }
+
+ /**
+ * Constructs a StringValue Record from an <code>InputStream</code>
+ *
+ * @param is InputStream containing a StringValue Record
+ */
+ public StringValue(InputStream is) throws IOException {
+ read(is);
+ }
+
+ /**
+ * Get the hex code for this particular <code>BIFFRecord</code>
+ *
+ * @return the hex code for <code>StringValue</code>
+ */
+ public short getBiffType() {
+ return PocketExcelConstants.FORMULA_STRING;
+ }
+
+ /**
+ * Reads a StringVlaue Record from an <code>InputStream</code>
+ *
+ * @param is InputStream containing a StringValue Record
+ */
+ public int read(InputStream input) throws IOException {
+
+ cch[0] = (byte) input.read();
+ cch[1] = (byte) input.read();
+ int numOfBytesRead = 1;
+
+ int strlen = EndianConverter.readShort(cch)*2;
+ rgch = new byte[strlen];
+ numOfBytesRead += input.read(rgch, 0, strlen);
+
+ Debug.log(Debug.TRACE,"\tcch : "+ cch +
+ " rgch : " + rgch);
+
+ return numOfBytesRead;
+ }
+
+ public void write(OutputStream output) throws IOException {
+
+ output.write(getBiffType());
+ output.write(cch);
+ output.write(rgch);
+
+ Debug.log(Debug.TRACE,"Writing StringValue record");
+ }
+
+ /**
+ * Gets the <code>String</code> representing the cells contents
+ *
+ * @return the <code>String</code> representing the cells contents
+ */
+ public String getString() throws IOException {
+ String name;
+
+ try {
+ name = new String(rgch, "UTF-16LE");
+ } catch (UnsupportedEncodingException e){
+ name = "unknown";
+ }
+ return name;
+ }
+
+}
diff --git a/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/UnsupportedFormulaException.java b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/UnsupportedFormulaException.java
new file mode 100644
index 000000000000..e6f941d46556
--- /dev/null
+++ b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/UnsupportedFormulaException.java
@@ -0,0 +1,41 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxc.pexcel.records;
+
+import java.lang.Exception;
+
+/**
+ * At the moment any functions within a formula will result in this exception
+ * being thrown.
+ */
+public class UnsupportedFormulaException extends Exception {
+
+ public UnsupportedFormulaException(String message){
+ super(message);
+ }
+}
diff --git a/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/Window1.java b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/Window1.java
new file mode 100644
index 000000000000..c060db90d60d
--- /dev/null
+++ b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/Window1.java
@@ -0,0 +1,115 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxc.pexcel.records;
+
+import java.io.OutputStream;
+import java.io.InputStream;
+import java.io.IOException;
+
+import org.openoffice.xmerge.util.Debug;
+import org.openoffice.xmerge.util.EndianConverter;
+import org.openoffice.xmerge.converter.xml.sxc.pexcel.PocketExcelConstants;
+
+
+/**
+ * Represents a BIFF REcord that describes workbook window attributes
+ */
+public class Window1 implements BIFFRecord {
+
+ private byte[] grbit = new byte[2];
+ private byte[] itabCur = new byte[2]; // index of selected worksheet
+
+ /**
+ * Constructor
+ */
+ public Window1() {
+ grbit = EndianConverter.writeShort((short) 0);
+ itabCur = EndianConverter.writeShort((short) 0);
+ }
+
+ /**
+ * Constructs a Window1 Record from an <code>InputStream</code>
+ *
+ * @param is InputStream containing a Window1 Record
+ */
+ public Window1(InputStream is) throws IOException{
+ read(is);
+ }
+
+ /**
+ * Set the number of the active sheet
+ *
+ * @param activeSheet number of the active sheet
+ */
+ public void setActiveSheet(int activeSheet) {
+ itabCur = EndianConverter.writeShort((short) activeSheet);
+ }
+
+ /**
+ * Get the number of the active sheet
+ *
+ * @return number of the active sheet
+ */
+ public int getActiveSheet() {
+ return EndianConverter.readShort(itabCur);
+ }
+
+ /**
+ * Get the hex code for this particular <code>BIFFRecord</code>
+ *
+ * @return the hex code for <code>Window1</code>
+ */
+ public short getBiffType() {
+ return PocketExcelConstants.WINDOW_INFO;
+ }
+
+ /**
+ * Reads a Window1 Record from an <code>InputStream</code>
+ *
+ * @param is InputStream containing a Window1 Record
+ */
+ public int read(InputStream input) throws IOException {
+
+ int numOfBytesRead = input.read(grbit);
+ numOfBytesRead += input.read(itabCur);
+
+ Debug.log(Debug.TRACE,"\tgrbit : "+ EndianConverter.readShort(grbit) +
+ " itabCur : " + EndianConverter.readShort(itabCur));
+
+ return numOfBytesRead;
+ }
+
+ public void write(OutputStream output) throws IOException {
+
+ output.write(getBiffType());
+ output.write(grbit);
+ output.write(itabCur);
+
+ Debug.log(Debug.TRACE,"Writing Window1 record");
+ }
+}
diff --git a/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/Window2.java b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/Window2.java
new file mode 100644
index 000000000000..4c49a941219c
--- /dev/null
+++ b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/Window2.java
@@ -0,0 +1,154 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxc.pexcel.records;
+
+import java.io.OutputStream;
+import java.io.InputStream;
+import java.io.IOException;
+import java.awt.Point;
+
+import org.openoffice.xmerge.util.Debug;
+import org.openoffice.xmerge.util.EndianConverter;
+import org.openoffice.xmerge.converter.xml.sxc.pexcel.PocketExcelConstants;
+import org.openoffice.xmerge.converter.xml.sxc.SheetSettings;
+
+
+/**
+ * Represents a BIFF Record that describes worksheet window attributes
+ */
+public class Window2 implements BIFFRecord {
+
+ private final static int FROZEN = 0x08;
+ private final static int NOSPLIT = 0x01;
+
+ private byte[] rwTop = new byte[2];
+ private byte colLeft;
+ private byte[] grbit = new byte[2];
+
+ /**
+ * Constructor
+ */
+ public Window2() {
+ this.rwTop = EndianConverter.writeShort((short) 0);
+ this.colLeft = 0;
+ this.grbit = EndianConverter.writeShort((short) 0);
+ }
+
+ /**
+ * Constructs a Window2 Record from an <code>InputStream</code>
+ *
+ * @param is InputStream containing a Window2 Record
+ */
+ public Window2(InputStream is) throws IOException {
+ read(is);
+ }
+
+ /**
+ * Get the hex code for this particular <code>BIFFRecord</code>
+ *
+ * @return the hex code for <code>Window2</code>
+ */
+ public short getBiffType() {
+ return PocketExcelConstants.SHEET_WINDOW_INFO;
+ }
+
+ /**
+ * Sets the split type for this pane, the split type is the same for both
+ * x and y so we only test against one.
+ *
+ * @param splitType the split type based on types defined in
+ * <code>sheetSettings</code>
+ */
+ public void setSplitType(Point splitType) {
+ if(splitType.getX()==SheetSettings.SPLIT) {
+ grbit[0] &= ~FROZEN;
+ grbit[1] &= ~NOSPLIT;
+ } else {
+ grbit[0] |= FROZEN;
+ grbit[1] |= NOSPLIT;
+ }
+ }
+
+ /**
+ * This method tests if this object describes a freeze
+ *
+ * @return true if freeze otherwise false
+ */
+ public boolean isFrozen() {
+ if((grbit[0] & FROZEN) != FROZEN)
+ return false;
+
+ if((grbit[1] & NOSPLIT) != NOSPLIT)
+ return false;
+
+ return true;
+ }
+
+ /**
+ * This method tests if this object describes a split
+ *
+ * @return true if split otherwise false
+ */
+ public boolean isSplit() {
+ if((grbit[0] & FROZEN) == FROZEN)
+ return false;
+
+ if((grbit[1] & NOSPLIT) == NOSPLIT)
+ return false;
+
+ return true;
+ }
+
+ /**
+ * Reads a Window2 Record from an <code>InputStream</code>
+ *
+ * @param is InputStream containing a Window2 Record
+ */
+ public int read(InputStream input) throws IOException {
+
+ int numOfBytesRead = input.read(rwTop);
+ colLeft = (byte) input.read();
+ numOfBytesRead++;
+ numOfBytesRead += input.read(grbit);
+
+ Debug.log(Debug.TRACE,"\trwTop : "+ EndianConverter.readShort(rwTop) +
+ " colLeft : " + colLeft +
+ " grbit : " + EndianConverter.readShort(grbit));
+ return numOfBytesRead;
+ }
+
+ public void write(OutputStream output) throws IOException {
+
+ output.write(getBiffType());
+ output.write(rwTop);
+ output.write(colLeft);
+ output.write(grbit);
+
+ Debug.log(Debug.TRACE,"Writing Window2 record");
+ }
+}
diff --git a/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/Workbook.java b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/Workbook.java
new file mode 100644
index 000000000000..5a9f329e4667
--- /dev/null
+++ b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/Workbook.java
@@ -0,0 +1,539 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxc.pexcel.records;
+
+import java.io.OutputStream;
+import java.io.InputStream;
+import java.io.IOException;
+import java.util.Vector;
+import java.util.Enumeration;
+
+import org.openoffice.xmerge.converter.xml.OfficeConstants;
+import org.openoffice.xmerge.converter.xml.sxc.Format;
+import org.openoffice.xmerge.converter.xml.sxc.NameDefinition;
+import org.openoffice.xmerge.converter.xml.sxc.BookSettings;
+import org.openoffice.xmerge.converter.xml.sxc.SheetSettings;
+import org.openoffice.xmerge.util.Debug;
+import org.openoffice.xmerge.converter.xml.sxc.pexcel.PocketExcelConstants;
+import org.openoffice.xmerge.converter.xml.sxc.ColumnRowInfo;
+
+/**
+ * This class is used by <code> PxlDocument</code> to maintain pexcel
+ * workbooks.
+ *
+ * @author Martin Maher
+ */
+public class Workbook implements org.openoffice.xmerge.Document,
+OfficeConstants {
+
+ private Vector fonts = new Vector();
+ private Vector extendedFormats = new Vector();
+ private Vector worksheets = new Vector();
+ private Vector boundsheets = new Vector();
+ private Vector definedNames = new Vector();
+ private static final CodePage cp;
+ private static final Window1 win1;
+ private static final BeginningOfFile bof;;
+ private static final Eof eof;
+ private String fileName;
+
+ static {
+ cp = new CodePage();
+ win1 = new Window1();
+ bof = new BeginningOfFile(true);
+ eof = new Eof();
+ }
+
+
+ /**
+ * Constructs a pocket Excel Workbook with the name of the file passed in
+ * as an argument. Also fills out a basic header block containing the
+ * minimum number of objects that can be created at this time.
+ *
+ * @param name Name of the Pocket Excel Data file. (excluding the file
+ * extension)
+ */
+ public Workbook(String name) throws IOException {
+ fileName = name + PocketExcelConstants.FILE_EXTENSION;
+ Format defaultFormat = new Format();
+ FontDescription fd = new FontDescription(defaultFormat);
+ fonts.add(fd);
+ ExtendedFormat xf = new ExtendedFormat(0, defaultFormat);
+ extendedFormats.add(xf);
+ }
+
+ /**
+ * Constructs a pocket Excel Workbook from the
+ * <code>InputStream</code> and assigns it the document name passed in
+ *
+ * @param is InputStream containing a Pocket Excel Data file.
+ */
+ public Workbook(String name, InputStream is) throws IOException {
+ read(is);
+ fileName = name;
+ }
+
+ /**
+ * Writes the current workbook to the <code>Outputstream</code>
+ *
+ * @param os The destination outputstream
+ */
+ public void write(OutputStream os) throws IOException {
+ bof.write(os);
+ cp.write(os);
+ for(Enumeration e = definedNames.elements();e.hasMoreElements();) {
+ DefinedName dn = (DefinedName) e.nextElement();
+ dn.write(os);
+ }
+ win1.write(os);
+ for(Enumeration e = fonts.elements();e.hasMoreElements();) {
+ FontDescription fd = (FontDescription) e.nextElement();
+ fd.write(os);
+ }
+ for(Enumeration e = extendedFormats.elements();e.hasMoreElements();) {
+ ExtendedFormat xf = (ExtendedFormat) e.nextElement();
+ xf.write(os);
+ }
+ for(Enumeration e = boundsheets.elements();e.hasMoreElements();) {
+ BoundSheet bs = (BoundSheet) e.nextElement();
+ bs.write(os);
+ }
+ eof.write(os);
+
+ for(Enumeration e = worksheets.elements();e.hasMoreElements();) {
+ Worksheet ws = (Worksheet) e.nextElement();
+ ws.write(os);
+ }
+ }
+
+ /**
+ * Reads a workbook from the <code>InputStream</code> and contructs a
+ * workbook object from it
+ *
+ * @param is InputStream containing a Pocket Excel Data file.
+ */
+ public void read(InputStream is) throws IOException {
+
+ boolean done = false;
+
+ int b = 0;
+ while (!done)
+ {
+ b = is.read();
+ if (b == -1)
+ {
+ Debug.log(Debug.TRACE,"End of file reached");
+ break;
+ }
+
+ switch (b)
+ {
+ case PocketExcelConstants.DEFINED_NAME:
+ Debug.log(Debug.TRACE,"NAME: Defined Name (18h)");
+ DefinedName dn = new DefinedName(is, this);
+ definedNames.add(dn);
+ break;
+
+ case PocketExcelConstants.BOF_RECORD:
+ Debug.log(Debug.TRACE,"BOF Record");
+ bof.read(is);
+ break;
+
+ case PocketExcelConstants.EOF_MARKER:
+ Debug.log(Debug.TRACE,"EOF Marker");
+ eof.read(is);
+ Worksheet ws = new Worksheet(this);
+ while(ws.read(is)) {
+ worksheets.add(ws);
+ ws = new Worksheet(this);
+ }
+ break;
+
+ case PocketExcelConstants.FONT_DESCRIPTION:
+ Debug.log(Debug.TRACE,"FONT: Font Description (31h)");
+ FontDescription fd = new FontDescription(is);
+ fonts.add(fd);
+ break;
+
+ case PocketExcelConstants.WINDOW_INFO:
+ Debug.log(Debug.TRACE,"WINDOW1: Window Information (3Dh) [PXL 2.0]");
+ win1.read(is);
+ break;
+
+ case PocketExcelConstants.CODEPAGE:
+ Debug.log(Debug.TRACE,"CODEPAGE : Codepage and unknown fields (42h)");
+ cp.read(is);
+ break;
+
+ case PocketExcelConstants.BOUND_SHEET:
+ Debug.log(Debug.TRACE,"BOUNDSHEET: Sheet Information (85h)");
+ BoundSheet bs = new BoundSheet(is);
+ boundsheets.add(bs);
+ break;
+
+ case PocketExcelConstants.EXTENDED_FORMAT:
+ Debug.log(Debug.TRACE,"XF: Extended Format (E0h) [PXL 2.0]");
+ ExtendedFormat xf = new ExtendedFormat(is);
+ extendedFormats.add(xf);
+ break;
+
+ default:
+ b = is.read();
+ break;
+ }
+
+ }
+ is.close();
+ }
+
+ /**
+ * Adds a font recrod to the workbook
+ *
+ * @param f the font record to add
+ */
+ public int addFont(FontDescription f) {
+
+ boolean alreadyExists = false;
+ int i = 0;
+
+ for(Enumeration e = fonts.elements();e.hasMoreElements();) {
+ FontDescription fd = (FontDescription) e.nextElement();
+ if(fd.compareTo(f)) {
+ alreadyExists = true;
+ break;
+ } else {
+ i++;
+ }
+ }
+
+ if(!alreadyExists)
+ fonts.add(f);
+
+ return i;
+ }
+
+ /**
+ * Adds a ExtendedFormat record to the workbook
+ *
+ * @param f the font recrod to add
+ */
+ public int addExtendedFormat(Format fmt) throws IOException {
+
+ FontDescription fd = new FontDescription(fmt);
+ int ixfnt = addFont(fd);
+ ExtendedFormat xf = new ExtendedFormat(ixfnt, fmt);
+
+ boolean alreadyExists = false;
+ int i = 0;
+
+ for(Enumeration e = extendedFormats.elements();e.hasMoreElements();) {
+ ExtendedFormat currentXF = (ExtendedFormat) e.nextElement();
+ if(xf.compareTo(currentXF)) {
+ alreadyExists = true;
+ break;
+ } else if(!alreadyExists) {
+ i++;
+ }
+ }
+
+ if(!alreadyExists)
+ extendedFormats.add(xf);
+
+ return i;
+ }
+
+ /**
+ * Gets a worksheet at a particular index from mthe current workbook.
+ *
+ * @param index the index of the worksheet to retrieve
+ */
+ public Worksheet getWorksheet(int index) {
+
+ return ((Worksheet) worksheets.elementAt(index));
+ }
+
+ /**
+ * Returns a FontDescription indictated by the
+ * index parameter passed in to the method
+ *
+ * @param ixfnt index to the FontDescriptions, this is a 0 based index
+ * @return FontDescription indexed by ixfe
+ */
+ public FontDescription getFontDescription(int ixfnt) {
+
+ return (FontDescription) fonts.elementAt(ixfnt);
+ }
+
+ /**
+ * Returns a ExtendedFormat indictated by the
+ * index parameter passed in to the method
+ *
+ * @param ixfe index to the FontDescriptions, this is a 0 based index
+ * @return FontDescription indexed by ixfe
+ */
+ public ExtendedFormat getExtendedFormat(int ixfe) {
+
+ return (ExtendedFormat) extendedFormats.elementAt(ixfe);
+ }
+
+ /**
+ * Returns an enumeration of DefinedNames for this workbook
+ *
+ * @return Enumeration for the DefinedNames
+ */
+ public Enumeration getDefinedNames() {
+
+ return definedNames.elements();
+ }
+
+ /**
+ * Returns an enumeration of <code>Settings</code> for this workbook
+ *
+ * @return Enumeration of <code>Settings</code>
+ */
+ public BookSettings getSettings() {
+
+ Vector settingsVector = new Vector();
+ int index = 0;
+ for(Enumeration e = worksheets.elements();e.hasMoreElements();) {
+ Worksheet ws = (Worksheet) e.nextElement();
+ SheetSettings s = ws.getSettings();
+ s.setSheetName(getSheetName(index++));
+ settingsVector.add(s);
+ }
+ BookSettings bs = new BookSettings(settingsVector);
+ String activeSheetName = getSheetName(win1.getActiveSheet());
+ bs.setActiveSheet(activeSheetName);
+ return bs;
+ }
+
+ /**
+ * Returns a <code>Vector</code> containing all the worksheet Names
+ *
+ * @return a <code>Vector</code> containing all the worksheet Names
+ */
+ public Vector getWorksheetNames() {
+
+ Vector wsNames = new Vector();
+
+ for(int i = 0;i < boundsheets.size();i++) {
+ wsNames.add(getSheetName(i));
+ }
+
+ return wsNames;
+ }
+
+ /**
+ * Returns the name of the worksheet at the specified index
+ *
+ * @return a <code>String</code> containing the name of the worksheet
+ */
+ public String getSheetName(int index) {
+ BoundSheet bs = (BoundSheet) boundsheets.elementAt(index);
+
+ return bs.getSheetName();
+ }
+
+ /**
+ * Adds a <code>Worksheet</code> to the workbook.
+ *
+ * @return name the name of the <code>Worksheet</code> to be added
+ */
+ public void addWorksheet(String name) throws IOException {
+
+ BoundSheet bs = new BoundSheet(name);
+ boundsheets.add(bs);
+
+ Worksheet ws = new Worksheet();
+ worksheets.add(ws);
+ }
+
+ /**
+ * Adds a cell to the current worksheet.
+ *
+ * @return the name of the <code>Worksheet</code> to be added
+ */
+ public void addCell(int row,int col, Format fmt, String cellContents)
+ throws IOException {
+
+ Worksheet currentWS = (Worksheet) worksheets.elementAt(worksheets.size()-1);
+ int ixfe = addExtendedFormat(fmt);
+
+ String category = fmt.getCategory();
+
+ // Now the formatting is out of the way add the cell
+ Debug.log(Debug.TRACE,"Cell Format: " + fmt);
+ Debug.log(Debug.TRACE,"Row : " + row);
+ Debug.log(Debug.TRACE,"Col : " + col);
+ if(cellContents.startsWith("=")) {
+ try {
+ Formula f = new Formula(row, col, cellContents, ixfe, fmt, this);
+ currentWS.addCell(f);
+ if(category.equalsIgnoreCase(CELLTYPE_STRING)) {
+ StringValue sv = new StringValue(fmt.getValue());
+ currentWS.addCell(sv);
+ }
+ } catch(Exception e) {
+ Debug.log(Debug.TRACE, "Parsing Exception thrown : " + e.getMessage());
+ BoolErrCell errorCell = new BoolErrCell(row, col, ixfe, 0x2A, 1);
+ currentWS.addCell(errorCell);
+ }
+ } else if(category.equalsIgnoreCase(OfficeConstants.CELLTYPE_FLOAT)) {
+ try {
+ FloatNumber num = new FloatNumber(row, col, cellContents, ixfe);
+ currentWS.addCell(num);
+ } catch(Exception e) {
+ Debug.log(Debug.TRACE,"Error could not parse Float " + cellContents);
+ LabelCell lc = new LabelCell(row, col, cellContents, ixfe);
+ currentWS.addCell(lc);
+ }
+ } else {
+ if(cellContents.length()==0) {
+ Debug.log(Debug.TRACE, "Blank Cell");
+ BlankCell b = new BlankCell(row, col, ixfe);
+ currentWS.addCell(b);
+ } else {
+ Debug.log(Debug.TRACE, "Label Cell : " + cellContents);
+ LabelCell lc = new LabelCell(row, col, cellContents, ixfe);
+ currentWS.addCell(lc); // three because we assume the last three
+ // Records in any worksheet is the selection,
+ // window2 and eof Records
+ }
+ }
+ }
+
+ /**
+ * Will create a number of ColInfo records based on the column widths
+ * based in.
+ *
+ * @param columnRows <code>Vector</code> of <code>ColumnRowInfo</code>
+ */
+ public void addColInfo(Vector columnRows) throws IOException {
+
+ Worksheet currentWS = (Worksheet) worksheets.elementAt(worksheets.size()-1);
+
+ int nCols = 0;
+ int nRows = 0;
+
+ Debug.log(Debug.TRACE,"Workbook: addColInfo()");
+ for(Enumeration e = columnRows.elements();e.hasMoreElements();) {
+ ColumnRowInfo cri =(ColumnRowInfo) e.nextElement();
+ int ixfe = 0;
+ int size = cri.getSize();
+ int repeated = cri.getRepeated();
+ if(cri.isColumn()) {
+ Debug.log(Debug.TRACE,"Workbook: adding ColInfo width = " + size);
+ ColInfo newColInfo = new ColInfo( nCols,
+ nCols+repeated-1,
+ size, ixfe);
+ currentWS.addCol(newColInfo);
+ nCols += repeated;
+ } else if(cri.isRow()) {
+
+ Debug.log(Debug.TRACE,"Workbook: adding Row Height = " + size);
+ if(!cri.isDefaultSize()) {
+ for(int i=0;i<repeated;i++) {
+ Row newRow = new Row(nRows++, size, cri.isUserDefined());
+ currentWS.addRow(newRow);
+ }
+ } else {
+ // If it is the Default Row we don't need to add it
+ nRows += repeated;
+ }
+
+ }
+ }
+ }
+
+ /**
+ * Will create a number of ColInfo recrods based on the column widths
+ * based in.
+ *
+ * @param an integer list representing the column widths
+ */
+ public void addNameDefinition(NameDefinition nameDefinition) throws IOException {
+
+ DefinedName dn = new DefinedName(nameDefinition, this);
+ definedNames.add(dn);
+ }
+
+ /**
+ * Adds the <code>BookSettings</code> for this workbook.
+ *
+ * @param book the <code>BookSettings</code> to add
+ */
+ public void addSettings(BookSettings book) throws IOException {
+
+ int index = 0;
+ Vector sheetSettings = book.getSheetSettings();
+ String activeSheetName = book.getActiveSheet();
+
+ for(Enumeration e = worksheets.elements();e.hasMoreElements();) {
+ Worksheet ws = (Worksheet) e.nextElement();
+ String name = getSheetName(index++);
+ if(activeSheetName.equals(name)) {
+ win1.setActiveSheet(index-1);
+ }
+ for(Enumeration eSettings = sheetSettings.elements();eSettings.hasMoreElements();) {
+ SheetSettings s = (SheetSettings) eSettings.nextElement();
+ if(name.equals(s.getSheetName())) {
+ ws.addSettings(s);
+ }
+ }
+ }
+ }
+
+ /**
+ * Return the filename of the pxl document without the file extension
+ *
+ * @return filename without the file extension
+ */
+ public String getName() {
+
+ // We have to strip off the file extension
+ int end = fileName.lastIndexOf(".");
+ String name;
+ if( end >= 0) // check in case the filename is already stripped
+ name = fileName.substring(0, end);
+ else
+ name = fileName;
+
+ return name;
+ }
+
+ /**
+ * Returns the filename of the pxl document with the file extension
+ *
+ * @return filename with the file extension
+ */
+ public String getFileName() {
+
+ return fileName;
+ }
+
+}
diff --git a/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/Worksheet.java b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/Worksheet.java
new file mode 100644
index 000000000000..6ab57189f39f
--- /dev/null
+++ b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/Worksheet.java
@@ -0,0 +1,319 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxc.pexcel.records;
+
+import java.io.OutputStream;
+import java.io.InputStream;
+import java.io.IOException;
+import java.util.Vector;
+import java.util.Enumeration;
+import java.awt.Point;
+
+import org.openoffice.xmerge.util.Debug;
+import org.openoffice.xmerge.converter.xml.sxc.SheetSettings;
+import org.openoffice.xmerge.converter.xml.sxc.pexcel.PocketExcelConstants;
+
+
+/**
+ * This class is used by <code>PxlDocument</code> to maintain pexcel
+ * worksheets.
+ *
+ * @author Martin Maher
+ */
+public class Worksheet {
+
+ private String name;
+ private Workbook wb;
+ private Vector rows = new Vector();
+ private Vector colInfo = new Vector();
+ private Vector cells = new Vector();
+ private DefColWidth dcw = new DefColWidth();
+ private DefRowHeight drh = new DefRowHeight();
+ private Window2 win2 = new Window2();
+ private Selection sel = new Selection();
+ private Pane p = new Pane();
+ private BeginningOfFile bof;
+ private Eof eof;
+
+ /**
+ * Writes the current workbook to the <code>Outputstream</code>
+ *
+ * @param os The destination outputstream
+ */
+ public Worksheet(Workbook wb) {
+ this.wb = wb;
+ }
+
+ /**
+ * Default Contructor
+ *
+ * @param os The destination outputstream
+ */
+ public Worksheet() {
+ }
+
+ /**
+ * Writes the current workbook to the <code>Outputstream</code>
+ *
+ * @param os The destination outputstream
+ */
+ public void write(OutputStream os) throws IOException {
+
+ bof = new BeginningOfFile(false);
+ bof.write(os);
+ dcw.write(os);
+ for(Enumeration e = colInfo.elements();e.hasMoreElements();) {
+ ColInfo ci = (ColInfo) e.nextElement();
+ ci.write(os);
+ }
+ drh.write(os);
+ for(Enumeration e = rows.elements();e.hasMoreElements();) {
+ Row rw = (Row) e.nextElement();
+ rw.write(os);
+ }
+ for(Enumeration e = cells.elements();e.hasMoreElements();) {
+ BIFFRecord cv = (BIFFRecord) e.nextElement();
+ cv.write(os);
+ }
+ win2.write(os);
+ p.write(os);
+ sel.write(os);
+ eof = new Eof();
+ eof.write(os);
+ }
+
+ /**
+ * Reads a worksheet from the <code>InputStream</code> and contructs a
+ * workbook object from it
+ *
+ * @param is InputStream containing a Pocket Excel Data file.
+ */
+ public boolean read(InputStream is) throws IOException {
+
+ int b = is.read();
+
+ if (b==-1)
+ return false;
+
+ while(b!=-1) {
+ switch (b)
+ {
+ case PocketExcelConstants.BLANK_CELL:
+ Debug.log(Debug.TRACE,"Blank Cell (01h)");
+ BlankCell bc = new BlankCell(is);
+ cells.add(bc);
+ break;
+
+ case PocketExcelConstants.NUMBER_CELL:
+ Debug.log(Debug.TRACE,"NUMBER: Cell Value, Floating-Point Number (03h)");
+ FloatNumber fn = new FloatNumber(is);
+ cells.add(fn);
+ break;
+
+ case PocketExcelConstants.LABEL_CELL:
+ Debug.log(Debug.TRACE,"LABEL: Cell Value, String Constant (04h)");
+ LabelCell lc = new LabelCell(is);
+ cells.add(lc);
+ break;
+
+ case PocketExcelConstants.BOOLERR_CELL:
+ Debug.log(Debug.TRACE,"BOOLERR: Cell Value, Boolean or Error (05h)");
+ BoolErrCell bec = new BoolErrCell(is);
+ break;
+
+ case PocketExcelConstants.FORMULA_CELL:
+ Debug.log(Debug.TRACE,"FORMULA: Cell Formula (06h)");
+ Formula f = new Formula(is, wb);
+ cells.add(f);
+ break;
+
+ case PocketExcelConstants.FORMULA_STRING:
+ Debug.log(Debug.TRACE,"String Value of a Formula (07h)");
+ StringValue sv = new StringValue(is);
+ break;
+
+ case PocketExcelConstants.ROW_DESCRIPTION:
+ Debug.log(Debug.TRACE,"ROW: Describes a Row (08h)");
+ Row rw = new Row(is);
+ rows.add(rw);
+ break;
+
+ case PocketExcelConstants.BOF_RECORD:
+ Debug.log(Debug.TRACE,"BOF Record");
+ bof = new BeginningOfFile(is);
+ break;
+
+ case PocketExcelConstants.EOF_MARKER:
+ Debug.log(Debug.TRACE,"EOF Marker");
+ eof = new Eof();
+ return true;
+
+ case PocketExcelConstants.CURRENT_SELECTION:
+ Debug.log(Debug.TRACE,"SELECTION: Current Selection (1Dh)");
+ sel = new Selection(is);
+ break;
+
+ case PocketExcelConstants.NUMBER_FORMAT:
+ Debug.log(Debug.TRACE,"FORMAT: Number Format (1Eh)");
+ NumberFormat nf = new NumberFormat(is);
+ break;
+
+ case PocketExcelConstants.DEFAULT_ROW_HEIGHT:
+ Debug.log(Debug.TRACE,"DEFAULTROWHEIGHT: Default Row Height (25h)");
+ drh = new DefRowHeight(is);
+ break;
+
+ case PocketExcelConstants.SHEET_WINDOW_INFO:
+ Debug.log(Debug.TRACE,"WINDOW2: Sheet Window Information (3Eh) [PXL 2.0]");
+ win2 = new Window2(is);
+ break;
+
+ case PocketExcelConstants.PANE_INFO:
+ Debug.log(Debug.TRACE,"PANE: Number of Panes and their Position (41h) [PXL 2.0]");
+ p = new Pane(is);
+ break;
+
+ case PocketExcelConstants.DEF_COL_WIDTH:
+ Debug.log(Debug.TRACE,"DEFCOLWIDTH: Default Column Width (55h) [PXL 2.0]");
+ dcw = new DefColWidth(is);
+ break;
+
+ case PocketExcelConstants.COLINFO:
+ Debug.log(Debug.TRACE,"COLINFO: Column Formatting Information (7Dh) [PXL 2.0]");
+ ColInfo ci = new ColInfo(is);
+ colInfo.add(ci);
+ break;
+
+ default:
+ break;
+ }
+ b = is.read();
+
+ }
+ Debug.log(Debug.TRACE,"Leaving Worksheet:");
+
+ return true;
+ }
+
+ /**
+ * Returns an enumerator which will be used to access individual cells
+ *
+ * @return an enumerator to the worksheet cells
+ */
+ public Enumeration getCellEnumerator() throws IOException {
+ return (cells.elements());
+ }
+
+ /**
+ * Adds a cell to this worksheet. Current valdid celltypes are
+ * <code>FloatNumber</code>, <code>LabelCell</code> or <code>Formula</code>
+ *
+ * @param f the font recrod to add
+ */
+ public void addCell(BIFFRecord br) {
+ cells.add(br);
+ }
+
+ /**
+ * Adds a number of ColInfo Records to the worksheet base on a list of
+ * clumnwidths passed in
+ *
+ * @param list of column widths
+ */
+ public void addRow(Row r) {
+ rows.add(r);
+ }
+
+ /**
+ * Adds a number of ColInfo Records to the worksheet base on a list of
+ * clumnwidths passed in
+ *
+ * @param list of column widths
+ */
+ public void addCol(ColInfo c) {
+ colInfo.add(c);
+ }
+ /**
+ * Returns an <code>Enumeration</code> to the ColInfo's for this worksheet
+ *
+ * @return an <code>Enumeration</code> to the ColInfo's
+ */
+ public void addSettings(SheetSettings s) {
+
+ sel.setActiveCell(s.getCursor());
+ p.setLeft(s.getLeft());
+ p.setTop(s.getTop());
+ p.setPaneNumber(s.getPaneNumber());
+ Point split = s.getSplit();
+ if(split.getX()!=0 || split.getY()!=0) {
+ p.setSplitPoint(s.getSplitType(), split);
+ win2.setSplitType(s.getSplitType());
+ }
+ }
+
+ /**
+ * Returns an <code>Enumeration</code> to the ColInfo's for this worksheet
+ *
+ * @return an <code>Enumeration</code> to the ColInfo's
+ */
+ public Enumeration getColInfos() {
+
+ return (colInfo.elements());
+ }
+
+ /**
+ * Returns a <code>SheetSettings</code> object containing a collection of data
+ * contained in <code>Pane</code>, <code>Window2</code> and
+ * <code>Selection</code>
+ *
+ * @return an <code>SheetSettings</code>
+ */
+ public SheetSettings getSettings() {
+
+ SheetSettings s = new SheetSettings();
+ s.setCursor(sel.getActiveCell());
+ if(win2.isFrozen()) {
+ s.setFreeze(p.getFreezePoint());
+ } else if(win2.isSplit()) {
+ s.setSplit(p.getSplitPoint());
+ }
+ s.setPaneNumber(p.getPaneNumber());
+ s.setTopLeft(p.getTop(), p.getLeft());
+ return s;
+ }
+ /**
+ * Returns an <code>Enumeration</code> to the Rows for this worksheet
+ *
+ * @return an <code>Enumeration</code> to the Rows
+ */
+ public Enumeration getRows() {
+
+ return (rows.elements());
+ }
+
+}
diff --git a/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/FormulaCompiler.java b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/FormulaCompiler.java
new file mode 100644
index 000000000000..2e060ca0a148
--- /dev/null
+++ b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/FormulaCompiler.java
@@ -0,0 +1,271 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxc.pexcel.records.formula;
+
+import java.util.*;
+import org.openoffice.xmerge.util.Debug;
+
+/**
+ * FormulaCompiler converts Calc formula string into PocketXL bytes
+ * and PocketXL formula bytes into Calc Formula strings
+ *
+ * For converting from infix to Reverse Polish (or Postfix) notation the string is
+ * converted into a vector of Tokens and then re-ordered based on a modified version
+ * of the standard Infix to RPN conversion algorithms.
+ * <pre>
+ * Infix2Rpn(tokens)
+ * while have more tokens
+ * if token is operand
+ * push to stack
+ * else if token is function, argument separater, or open bracket
+ * push token
+ * extract tokens to matching close bracket into param
+ * Infix2Rpn(param)
+ * else if token is close bracket
+ * pop from stack into result until close bracket or function
+ * else
+ * while stack.top.priority >= token.priority
+ * add stack.pop to result
+ * push token onto stack
+ * </pre>
+ * For converting from RPN to Infix the following algorithm is applied:
+ * <pre>
+ * while have more tokens
+ * if token is operand
+ * push token to stack
+ * else if token is function or operator
+ * pop from stack number of args required by token
+ * apply token to params to make expr
+ * push expr to stack
+ * return stack.pop
+ * </pre>
+ */
+public class FormulaCompiler {
+ /**
+ * Constructs a FormulaCompiler object
+ */
+ public FormulaCompiler() {
+ }
+
+ private boolean isPercent(Token pt) {
+ return pt.getTokenID() == TokenConstants.TPERCENT;
+ }
+
+ private boolean isOpenBrace(Token pt) {
+ return pt.getTokenID() == TokenConstants.TPAREN;
+ }
+
+ private boolean isCloseBrace(Token pt) {
+ return pt.getValue().compareTo(")") == 0;
+ }
+
+ private boolean isParamDelimiter(Token pt) {
+ return pt.getTokenID() == TokenConstants.TARGSEP;
+ }
+
+ private boolean isBinaryOperator(Token pt) {
+ return false;
+ }
+
+ /**
+ * Re-order into Infix format
+ * @param tokens The tokens in RPN form
+ * @return The vector of tokens re-ordered in Infix notation
+ */
+ public Vector RPN2Infix(Vector tokens) {
+ Vector infixExpr = new Vector(15);
+ ListIterator iter = tokens.listIterator();
+ Stack evalStack = new Stack();
+ Stack args = new Stack();
+
+ while (iter.hasNext()) {
+ Token pt = (Token)iter.next();
+ if (pt.isOperand()) {
+ Vector expr = new Vector(5);
+ expr.add(pt);
+ evalStack.push(expr);
+ } else if (pt.isOperator() || pt.isFunction()) {
+ args.clear();
+ for (int i=0; i< pt.getNumArgs(); i++) {
+ args.push(evalStack.pop());
+ }
+ evalStack.push(makeExpression(pt, args));
+ }
+ }
+ return (Vector)evalStack.elementAt(0);
+ }
+
+ /**
+ * Convert the infix expression to RPN. Note that open brackets are saved onto the stack to preserve the users bracketing.
+ * <p>Also note that the open bracket following functions is not pushed onto the stack - it is always implied when
+ * writing out results
+ *
+ * @param tokens The vector of tokens in Infix form
+ *
+ * @return A vector of tokens for the expression in Reverse Polish Notation order
+ */
+ public Vector infix2RPN(Vector tokens) {
+ Vector rpnExpr = new Vector(15);
+ Stack evalStack = new Stack();
+ ListIterator iter = tokens.listIterator();
+ while (iter.hasNext()) {
+ Token pt = (Token)iter.next();
+
+ if (pt.isOperand()) { //Operands are output immediately
+ rpnExpr.add(pt);
+ } else if (pt.isFunction() || isParamDelimiter(pt) || isOpenBrace(pt)) { //Extract parameters after afunction or comma
+ evalStack.push(pt);
+ if (pt.isFunction()) {
+ iter.next();
+ }
+ Vector param = extractParameter(iter);
+ Debug.log(Debug.TRACE, "Extracted parameter " + param);
+ rpnExpr.addAll(infix2RPN(param));
+ } else if (isCloseBrace(pt)) { //Pop off stack till you meet a function or an open bracket
+ Token tmpTok = null;
+ boolean bPop = true;
+ while (bPop) {
+ if (evalStack.isEmpty()) {
+ bPop = false;
+ } else {
+ tmpTok = (Token)evalStack.pop();
+ //if (!(isOpenBrace(tmpTok) || isParamDelimiter(tmpTok))) { //Don't output brackets and commas
+ if (!isParamDelimiter(tmpTok)) { //Don't output commas
+ rpnExpr.add(tmpTok);
+ }
+ if (tmpTok.isFunction() || isOpenBrace(tmpTok)) {
+ bPop = false;
+ }
+ }
+ }
+ } else {
+ if (!evalStack.isEmpty()) {
+ while (!evalStack.isEmpty() &&
+ (((Token)evalStack.peek()).getTokenPriority() >=pt.getTokenPriority())) {
+ Token topTok = (Token)evalStack.peek();
+ if (topTok.isFunction() || isOpenBrace(topTok)) {
+ break;
+ }
+ rpnExpr.add(evalStack.pop());
+ }
+ }
+ evalStack.push(pt);
+ }
+ }
+
+ while (!evalStack.isEmpty()) {
+ Token topTok = (Token)evalStack.peek();
+ if (!(isOpenBrace(topTok) || isParamDelimiter(topTok))) { //Don't output brackets and commas
+ rpnExpr.add(evalStack.pop());
+ }
+ else
+ {
+ evalStack.pop();
+ }
+ }
+ return rpnExpr;
+ }
+
+ /**
+ * Extract a parameter or bracketed sub-expression
+ * @param iter an iterator into the list
+ * @return A complete sub-expression
+ */
+ protected Vector extractParameter(ListIterator iter) {
+ Vector param = new Vector(5);
+ int subExprCount = 0;
+
+ while (iter.hasNext()) {
+ Token pt = (Token)iter.next();
+ Debug.log(Debug.TRACE, "Token is " + pt + " and subExprCount is " + subExprCount);
+ if (isOpenBrace(pt)) {
+ subExprCount++;
+ param.add(pt);
+ } else if (isCloseBrace(pt)) {
+ if (subExprCount == 0) {
+ iter.previous();
+ return param;
+ } else {
+ subExprCount--;
+ param.add(pt);
+ }
+ } else if (isParamDelimiter(pt) && (subExprCount == 0)) {
+ iter.previous();
+ return param;
+ } else {
+ param.add(pt);
+ }
+ }
+ return param;
+ }
+
+ /**
+ * Given the operator and it's operators
+ * @param pt The operator token
+ * @param args The arguments for this operator
+ * @return A correctly ordered expression
+ */
+ protected Vector makeExpression(Token pt, Stack args) {
+ Vector tmp = new Vector(5);
+ TokenFactory tf = new TokenFactory();
+ if (pt.isOperator()) {
+ if (pt.getNumArgs()==2) { //Binary operator
+ tmp.addAll((Vector)args.pop());
+ tmp.add(pt);
+ tmp.addAll((Vector)args.pop());
+ } else if (pt.getNumArgs() == 1) {
+ if(isPercent(pt)) {
+ tmp.addAll((Vector)args.elementAt(0));
+ tmp.add(pt);
+ } else {
+ tmp.add(pt);
+ tmp.addAll((Vector)args.elementAt(0));
+ }
+ if (isOpenBrace(pt)) {
+ tmp.add(tf.getOperatorToken(")",1));
+ }
+ }
+ } else if (pt.isFunction()) {
+ tmp.add(pt);
+ tmp.add(tf.getOperatorToken("(",1));
+ if (!args.isEmpty()) {
+ Vector v = (Vector)args.pop();
+ tmp.addAll(v);
+ }
+ while (!args.isEmpty()) {
+ tmp.add(tf.getOperatorToken(",",1));
+ Vector v = (Vector)args.pop();
+ tmp.addAll(v);
+
+ }
+ tmp.add(tf.getOperatorToken(")",1));
+ }
+
+ return tmp;
+ }
+}
diff --git a/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/FormulaHelper.java b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/FormulaHelper.java
new file mode 100644
index 000000000000..208feb030f36
--- /dev/null
+++ b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/FormulaHelper.java
@@ -0,0 +1,152 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxc.pexcel.records.formula;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.Vector;
+import java.util.Enumeration;
+
+import org.openoffice.xmerge.converter.xml.sxc.pexcel.records.Workbook;
+
+/**
+ * This Helper class provides a simplified interface to conversion between PocketXL formula representation
+ * and Calc formula representation.<p>
+ * The class is used by {@link org.openoffice.xmerge.converter.xml.sxc.pexcel.Records.Formula}
+ */
+public class FormulaHelper {
+
+ private static FormulaParser parser;
+ private static FormulaCompiler compiler;
+ private static TokenEncoder encoder;
+ private static TokenDecoder decoder;
+ private boolean rangeType = false;
+ private boolean expressionType = false;
+
+ static {
+ parser = new FormulaParser();
+ compiler = new FormulaCompiler();
+ encoder = new TokenEncoder();
+ decoder = new TokenDecoder();
+ }
+
+ /**
+ * Sets the workbook cache so that global data such as
+ * <code>DefinedNames</code>, <code>Boundsheets</code> can be read
+ *
+ * @param wb Wrokbook object containing all the global data
+ */
+ public void setWorkbook(Workbook wb) {
+
+ encoder.setWorkbook(wb);
+ decoder.setWorkbook(wb);
+ parser.setWorkbook(wb);
+ }
+
+ /**
+ * Convertes a string representation of a calc formula into an array of PocketXL bytes
+ * @param formula The Formula String (e.g. 1+SUM(A1,B1))
+ *
+ * @throws UnsupportedFunctionException Thrown if a function in the formula is nto supported by Pocket Excel
+ * @throws FormulaParsingException Thrown when the formula is not well formed
+ *
+ */
+ public byte[] convertCalcToPXL(String formula) throws UnsupportedFunctionException, FormulaParsingException {
+
+ Vector parseTokens = parser.parse(formula);
+ Vector rpnTokens = compiler.infix2RPN(parseTokens);
+
+ ByteArrayOutputStream bytes = null;
+ try {
+ bytes = new ByteArrayOutputStream();
+ for (Enumeration e = rpnTokens.elements(); e.hasMoreElements();) {
+ Token t = (Token)e.nextElement();
+ bytes.write(encoder.getByte(t));
+ }
+ } catch (IOException e) {
+ }
+
+ return bytes.toByteArray();
+ }
+
+ /**
+ * Converts a PocketXL byte array into a Calc function string
+ * @param formula A byte array that contains the PocketXL bytes for a formula
+ *
+ */
+ public String convertPXLToCalc(byte[] formula) {
+
+ Vector parseTokens = decoder.getTokenVector(formula);
+ Vector infixTokens = compiler.RPN2Infix(parseTokens);
+
+ StringBuffer buff = new StringBuffer();
+ for (Enumeration e = infixTokens.elements();e.hasMoreElements();) {
+ Token t = (Token)e.nextElement();
+ buff.append(t.toString());
+ // If we are parsing a Name definition we need to know if it is of
+ // type range or expression
+ if(!t.isOperand()) {
+ expressionType = true;
+ }
+ }
+ if(!expressionType) {
+ rangeType = true;
+ }
+ return "=" + buff.toString();
+ }
+
+ /**
+ * Returns a boolean indicating whether or not the byte[] parsed is of
+ * type range. This means it contains only a cell reference and no
+ * operators. This is necessry because the syntax for range and expression
+ * types differs. This is only of interest when dealing with
+ * <code>DefinedNames</code> and not <code>Formula</code>
+ *
+ * @return a boolean true if of type range otherwise false
+ *
+ */
+ public boolean isRangeType() {
+
+ return rangeType;
+ }
+
+ /**
+ * Returns a boolean indicating whether or not the byte[] parsed is of
+ * type expression. This means it contains operators. This is necessry
+ * because the syntax for range and expression types differs. This is
+ * only of interest when dealing with <code>DefinedNames</code> and not
+ * <code>Formula</code>
+ *
+ * @return a boolean true if of type expression otherwise false
+ *
+ */
+ public boolean isExpressionType() {
+
+ return expressionType;
+ }
+}
diff --git a/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/FormulaParser.java b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/FormulaParser.java
new file mode 100644
index 000000000000..0ab40ec53fd2
--- /dev/null
+++ b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/FormulaParser.java
@@ -0,0 +1,561 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxc.pexcel.records.formula;
+
+
+import java.util.Vector;
+
+import org.openoffice.xmerge.converter.xml.sxc.pexcel.records.Workbook;
+import org.openoffice.xmerge.util.Debug;
+
+/**
+ * This is the Formula Parser based on an article written by Jack Crenshaw. It is a
+ * top down parser with some basic error handling. It handles
+ * +,-,*,/,>,<,>=,<=,=,<>, unary + and - as well as functions.
+ * The BNF notation for this parser is
+ * <pre>
+ * &lt;expression&gt; ::= &lt;unary op&gt; &lt;term&gt; [&lt;addop&gt;|&lt;logop&gt; &lt;term&gt;]
+ * &lt;term&gt; ::= &lt;factor&gt; [&lt;mulop&gt; &lt;factor&gt;]
+ * &lt;factor&gt; ::= &lt;number&gt;[%] | &lt;CellRef&gt; | &lt;QuoteString&gt; | &lt;expression&gt;
+ * </pre>
+ */
+public class FormulaParser {
+
+ private char look;
+ private String formulaStr;
+ private int index = 1;
+ private TokenFactory tokenFactory;
+ private Vector tokenVector;
+ private Workbook wb;
+
+ /**
+ * Default constructor
+ */
+ public FormulaParser() {
+
+ Debug.log(Debug.TRACE,"Creating a Formula Parser");
+ tokenFactory = new TokenFactory();
+ tokenVector = new Vector();
+ }
+
+ /**
+ *
+ */
+ public void setWorkbook(Workbook wb) {
+
+ this.wb = wb;
+ }
+
+ /**
+ * Parse method for parsing from a String to a byte[]
+ *
+ * @param formula A <code>String</code> representation of a formula
+ * starting with the '=' character
+ * @return A <code>Vector</code> containing the parsed <code>Token</code>s
+ */
+ public Vector parse(String formula) throws FormulaParsingException {
+
+ index = 1;
+ look = ' ';
+ tokenVector.clear();
+ if(formula.startsWith("=")) {
+ formulaStr = formula;
+ Debug.log(Debug.TRACE,"Creating a Formula Parser for " + formulaStr);
+ getChar();
+ expression();
+ } else {
+ throw new FormulaParsingException("No equals found!" + makeErrorString());
+ }
+ return tokenVector;
+ }
+
+ /**
+ * Identify + and - operators
+ *
+ * @param c The character which is to be identified
+ * @return A boolean returning the result of the comparison
+ */
+ private boolean isAddOp(char c) {
+ return (c == '-') || (c == '+');
+ }
+
+ /**
+ * Determine if the current character is a multiop
+ *
+ * @return A boolean returning the result of the comparison
+ */
+ private boolean isMultiOp() {
+ return look=='*' || look =='/' || look == '^' || look == '&';
+ }
+
+ /**
+ * Identify <, >, <=, >=, =, <> using the index to find the current character(s)
+ *
+ * @return A boolean returning the result of the comparison
+ */
+ private boolean isLogicalOp() {
+ if (!isLogicalOpChar(look)) {
+ return false;
+ } else if ((index+1) >= formulaStr.length()) {//logical operators in their own right : if at end then return true
+ return true;
+ } else if (!isLogicalOpChar(formulaStr.charAt(index))) { // we have >, < or = on their own
+ return true;
+ } else if ((look == '<') && ((formulaStr.charAt(index) == '>') || formulaStr.charAt(index) == '=')) { // <>, or <=
+ return true;
+ } else if ((look == '>') && (formulaStr.charAt(index) == '=')) { // >=
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Identify <, >, <=, >=, =, <>
+ *
+ * @param The <code>String</code> which is to be identified
+ * @return A boolean returning the result of the comparison
+ */
+ private boolean isLogicalOp(String op) {
+ return ((op.compareTo(">") == 0) ||
+ (op.compareTo("<") == 0) ||
+ (op.compareTo(">=") == 0) ||
+ (op.compareTo("<=") == 0) ||
+ (op.compareTo("=") == 0) ||
+ (op.compareTo("<>") == 0));
+ }
+
+
+ /**
+ * Identify characters that MAY be logical operator characters
+ *
+ * @param c The character which is to be identified
+ * @return A boolean returning the result of the comparison
+ */
+ private boolean isLogicalOpChar(char c) {
+ return (c == '>') || (c == '<') || (c == '=');
+ }
+
+ /**
+ * Identify special Cell Reference charaters
+ *
+ * @param c The character which is to be identified
+ * @return A boolean returning the result of the comparison
+ */
+ private boolean isCellRefSpecialChar(char c) {
+ return (c == ':') || (c == '$') || (c == '.');
+ }
+
+ /**
+ * Identify letters
+ *
+ * @param c The character which is to be identified
+ * @return A boolean returning the result of the comparison
+ */
+ private boolean isAlpha(char c) {
+ return(Character.isLetter(c));
+ }
+
+ /**
+ * Identify numbers
+ *
+ * @param c The character which is to be identified
+ * @return A boolean returning the result of the comparison
+ */
+ private boolean isDigit(char c) {
+ return(Character.isDigit(c));
+ }
+
+ /**
+ * Identify numbers
+ *
+ * @param c The character which is to be identified
+ * @return A boolean returning the result of the comparison
+ */
+ private boolean isPercent(char c) {
+ return (c == '%');
+ }
+
+ /**
+ * Identify letters or numbers
+ *
+ * @param c The character which is to be identified
+ * @return A boolean returning the result of the comparison
+ */
+ private boolean isAlphaNum(char c) {
+ return(isAlpha(c) || isDigit(c));
+ }
+
+ /**
+ * Identify valid Characters for cell references
+ *
+ * @param c The character which is to be identified
+ * @return A boolean returning the result of the comparison
+ */
+ private boolean isCellRefChar(char c) {
+ return(isAlpha(c) || isDigit(c) || isCellRefSpecialChar(c));
+ }
+
+ /**
+ * Test if current character is a match and move to next character
+ *
+ * @param c The character which is to be matched
+ */
+ private void match(char c) throws FormulaParsingException {
+
+ if(look==c) {
+ Debug.log(Debug.TRACE,"Operator Found : " + look);
+ getChar();
+ skipWhite();
+ }
+ else
+ throw new FormulaParsingException("Unexpected character '" + c + "'" + makeErrorString());
+ }
+
+ /**
+ * Test if current character is a match and move to next character
+ *
+ * @param symbol The <code>String</code> to be matched.
+ */
+ private void match(String symbol) throws FormulaParsingException {
+
+ int numChars = symbol.length();
+ boolean bContinue = true;
+ for (int i=0;i<numChars && bContinue; i++) {
+ if (look == symbol.charAt(i)) {
+ bContinue = getChar();
+ skipWhite();
+ } else {
+ throw new FormulaParsingException("Unexpected character '" + symbol + "'" + makeErrorString());
+ }
+ }
+ }
+
+ /**
+ * Skip over whitespaces (ie. spaces and tabs)
+ */
+ private void skipWhite() throws FormulaParsingException {
+
+ boolean success = true;
+
+ while(Character.isWhitespace(look) && success) {
+ success = getChar();
+ }
+ }
+
+ /**
+ * This is a factor for multiplication and division operators
+ */
+ private void factor() throws FormulaParsingException {
+ if(isAddOp(look)) { // handle unary addop
+ Character ch = new Character(look);
+ match(look);
+ tokenVector.add(tokenFactory.getOperatorToken(ch.toString(), 1));
+ }
+ if(look=='(') {
+ match('(');
+ tokenVector.add(tokenFactory.getOperatorToken("(", 1));
+ expression();
+ match(')');
+ tokenVector.add(tokenFactory.getOperatorToken(")", 1));
+ } else if(isDigit(look)){
+ getNum();
+ } else {
+ ident();
+ }
+ }
+
+ /**
+ * Pulls the next character from the <code>String</code>
+ *
+ * @return boolean false if the end if the statement
+ * is reached otherwise true
+ */
+ private boolean getChar() throws FormulaParsingException {
+
+ boolean success = true;
+
+ if(index<formulaStr.length()) {
+ look = formulaStr.charAt(index);
+ index++;
+ if(look==',')
+ success = false;
+ } else {
+ success = false;
+ }
+ return success;
+ }
+
+ /**
+ * Parses the number of arguments in a function
+ *
+ * @return The number of arguments
+ */
+ private int arguments() throws FormulaParsingException {
+ int numArgs;
+
+ skipWhite();
+ if(look==')')
+ numArgs = 0;
+ else
+ numArgs = 1;
+
+ while(look!=')') {
+ expression();
+ if(look==',') {
+ numArgs++;
+ match(',');
+ tokenVector.add(tokenFactory.getOperatorToken(",", 1));
+ }
+ }
+ return numArgs;
+ }
+
+ /**
+ * Test to see if we have come across a cell reference or a Name
+ * Definition.
+ */
+ private boolean isCellRef(String s) {
+ char c;
+ boolean result = false;
+
+ for(int i = 0;i<s.length();i++) {
+ c = s.charAt(i);
+ if(isCellRefSpecialChar(c)) {
+ result = true;
+ break;
+ }
+ }
+
+ // if it is a simple cell reference then there will not be a cell
+ // reference 'special char' so we should also look for a digit
+ if(!result) {
+ if(isDigit(s.charAt(1)) || isDigit(s.charAt(2))) {
+ result = true;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Test to see if we have come across a cell reference or a function and
+ * add the resulting toek nto the tokenVector.
+ */
+ private void ident() throws FormulaParsingException {
+
+ String cell = getTokenString();
+ if(look=='(') {
+ Debug.log(Debug.TRACE,"Found Function : " + cell);
+
+ int index = tokenVector.size();
+ match('(');
+ tokenVector.add(tokenFactory.getOperatorToken("(", 1));
+ int numArgs = arguments();
+ match(')');
+ tokenVector.add(tokenFactory.getOperatorToken(")", 1));
+ tokenVector.insertElementAt(tokenFactory.getFunctionToken(cell, numArgs), index);
+ } else {
+
+ if(cell.indexOf('.')!=-1) {
+ String cellRef = cell.substring(cell.indexOf('.') + 1, cell.length());
+ if(cellRef.indexOf(':')!=-1) {
+ tokenVector.add(tokenFactory.getOperandToken(cell, "3D_CELL_AREA_REFERENCE"));
+ } else {
+ tokenVector.add(tokenFactory.getOperandToken(cell, "3D_CELL_REFERENCE"));
+ }
+ } else if(cell.indexOf(':')!=-1) {
+ tokenVector.add(tokenFactory.getOperandToken(cell, "CELL_AREA_REFERENCE"));
+ } else if(isCellRef(cell)) {
+ tokenVector.add(tokenFactory.getOperandToken(cell, "CELL_REFERENCE"));
+ } else {
+ tokenVector.add(tokenFactory.getOperandToken(cell, "NAME"));
+ }
+ }
+ }
+
+ /**
+ * Will keep pulling valid logical operators from the formula and return
+ * the resultant <code>String</code>.
+ *
+ * @return a <code>String<code> representing a logical operator
+ */
+ private String getLogicalOperator() throws FormulaParsingException {
+ String op = new String();
+ boolean status;
+
+ do {
+ op += look;
+ status = getChar();
+ } while(isLogicalOpChar(look) && status);
+ skipWhite();
+ return op;
+ }
+
+ /**
+ * Keeps pulling characters from the statement until we get an
+ * operator and returns the resulting string.
+ *
+ * @return A <code>String</code>representing the next token
+ */
+ private String getTokenString() throws FormulaParsingException {
+
+ if(!isAlpha(look) && look!='$')
+ throw new FormulaParsingException("Expected Cell Reference" + makeErrorString());
+ else {
+ String cell = new String();
+ boolean status;
+ do {
+ cell += look;
+ status = getChar();
+ } while(isCellRefChar(look) && status);
+ skipWhite();
+ return cell;
+ }
+ }
+
+ /**
+ * Keeps pulling numbers from the statement and add the resulting integer
+ * token to the tokenVector.
+ */
+ private void getNum() throws FormulaParsingException {
+
+ Debug.log(Debug.TRACE,"getNum : ");
+ if(!isDigit(look))
+ throw new FormulaParsingException("Expected Integer" + makeErrorString());
+ else {
+ String num = new String();
+ boolean status;
+
+ do {
+ num += look;
+ status = getChar();
+ } while((isDigit(look) || ((look == '.') && isDigit(formulaStr.charAt(index)))) && status);
+ skipWhite();
+ tokenVector.add(tokenFactory.getOperandToken(num, "INTEGER"));
+ if(isPercent(look)) {
+ match(look);
+ tokenVector.add(tokenFactory.getOperatorToken("%", 1));
+ Debug.log(Debug.TRACE,"Added Percent token to Vector: ");
+ }
+ Debug.log(Debug.TRACE,"Number parsed : " + num);
+ }
+ }
+
+
+ /**
+ * Term will parse multiplication/division expressions
+ */
+ private void term() throws FormulaParsingException {
+ factor();
+ while(isMultiOp()) {
+ multiOp(Character.toString(look));
+ }
+ }
+
+ /**
+ * Expression is the entry point for the parser. It is the code
+ * that parses addition/subtraction expressions.
+ */
+ private void expression() throws FormulaParsingException {
+
+ if (look == '"') { //Extract a quoted string...
+ StringBuffer buff = new StringBuffer();
+ boolean success = true;
+ success = getChar();
+ while (look != '"' && success) {
+ buff.append(look);
+ success = getChar();
+ }
+
+ if (look != '"') { //We've reached the end of the string without getting a closing quote
+ throw new FormulaParsingException("Expected closing quote." + makeErrorString());
+ } else {
+ tokenVector.add(tokenFactory.getOperandToken(buff.toString(), "STRING"));
+ getChar(); //Move on to the next character
+ }
+ } else {
+ term();
+ }
+ while(isAddOp(look) || isLogicalOp()) {
+ if (isAddOp(look)) {
+ addOp(Character.toString(look));
+ } else if (isLogicalOp()) {
+ logicalOp();
+ }
+ }
+ }
+
+ /**
+ * Test to see if the next token (represented as a <code>String</code>) is
+ * the same as the String passed in. Move the index along to the end of
+ * that String and add that <code>Token</code> to the tokenVector. Then
+ * call <code>term</code> to parse the right hand side of the operator.
+ *
+ * @param op A <code>String</code> representing the operator
+ */
+ private void addOp(String op) throws FormulaParsingException {
+ match(op);
+ tokenVector.add(tokenFactory.getOperatorToken(op, 2));
+ term();
+ }
+
+ /**
+ * Test to see if the next token (represented as a <code>String</code>) is
+ * the same as the String passed in. Move the index along to the end of
+ * that String and add that <code>Token</code> to the tokenVector. Then
+ * call <code>factor</code> to parse the right hand side of the operator.
+ *
+ * @param op A <code>String</code> representing the operator
+ */
+ private void multiOp(String op) throws FormulaParsingException {
+ match(op);
+ tokenVector.add(tokenFactory.getOperatorToken(op, 2));
+ factor();
+ }
+
+ /**
+ * Pull a logical operator starting at the current index, add a token for
+ * that operator to the tokenVector and call <code>term<code> to parse the
+ * right hand side of the operator
+ */
+ private void logicalOp() throws FormulaParsingException {
+ String op = getLogicalOperator();
+ tokenVector.add(tokenFactory.getOperatorToken(op, 2));
+ term();
+ }
+
+ private String makeErrorString() {
+ StringBuffer buff = new StringBuffer();
+ for (int i=0; i<index-1; i++) {
+ buff.append(' ');
+ }
+
+ buff.append('^');
+ return "\n\t" + formulaStr + "\n\t" + buff.toString();
+ }
+ }
+
diff --git a/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/FormulaParsingException.java b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/FormulaParsingException.java
new file mode 100644
index 000000000000..e8465391e6ff
--- /dev/null
+++ b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/FormulaParsingException.java
@@ -0,0 +1,41 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxc.pexcel.records.formula;
+
+/*
+ * If the formula failed to be parsed properly this exception will be thrown
+ *
+ * Martin Maher
+ */
+
+public class FormulaParsingException extends Exception {
+
+ public FormulaParsingException(String message) {
+ super(message);
+ }
+ }
diff --git a/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/FunctionLookup.java b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/FunctionLookup.java
new file mode 100644
index 000000000000..42c06d88754a
--- /dev/null
+++ b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/FunctionLookup.java
@@ -0,0 +1,204 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxc.pexcel.records.formula;
+
+import java.util.HashMap;
+
+public class FunctionLookup extends SymbolLookup {
+
+ private HashMap stringToArgs = null;
+
+ /**
+ * The default constructor - invokes {@link #initialize() initialize()}
+ */
+ public FunctionLookup() {
+ initialize();
+ }
+
+ /**
+ * Initialize the lookup table for functions
+ */
+ public void initialize() {
+ if ((stringToID != null) || (idToString != null) || (stringToArgs !=null)) {
+ return;
+ }
+ stringToID = new HashMap();
+ idToString = new HashMap();
+ stringToArgs = new HashMap();
+
+ // Functions with Variable number of Arguments
+ // Math and Trig
+ addEntry("SUM", TokenConstants.TSUM, -1);
+ addEntry("MIN", TokenConstants.TMIN, -1);
+ addEntry("PRODUCT", TokenConstants.TPRODUCT, -1);
+ addEntry("LOG", TokenConstants.TLOG, -1);
+ addEntry("SUMIF", TokenConstants.TSUMIF, -1);
+ addEntry("TRUNC", TokenConstants.TRUNC, -1);
+ // Financial
+ addEntry("DDB", TokenConstants.TDDB, -1);
+ addEntry("FV", TokenConstants.TFV, -1);
+ addEntry("IRR", TokenConstants.TIRR, -1);
+ addEntry("NPER", TokenConstants.TNPER, -1);
+ addEntry("NPV", TokenConstants.TNPV, -1);
+ addEntry("PMT", TokenConstants.TPMT, -1);
+ addEntry("PV", TokenConstants.TPV, -1);
+ addEntry("RATE", TokenConstants.TRATE, -1);
+ // Statistical
+ addEntry("AVERAGE", TokenConstants.TAVERAGE, -1);
+ addEntry("COUNT", TokenConstants.TCOUNT, -1);
+ addEntry("COUNTA", TokenConstants.TCOUNTA, -1);
+ addEntry("MAX", TokenConstants.TMAX, -1 );
+ addEntry("MIN", TokenConstants.TMIN, -1);
+ addEntry("STDEV", TokenConstants.TSTDEV, -1 );
+ addEntry("STDEVP", TokenConstants.TSTDEVP, -1 );
+ addEntry("VAR", TokenConstants.TVAR, -1);
+ addEntry("VARP", TokenConstants.TVARP, -1);
+ // Lookup
+ addEntry("CHOOSE", TokenConstants.TCHOOSE, -1);
+ addEntry("HLOOKUP", TokenConstants.THLOOKUP, -1);
+ addEntry("INDEX", TokenConstants.TINDEX, -1);
+ addEntry("MATCH", TokenConstants.TMATCH, -1) ;
+ addEntry("VLOOKUP", TokenConstants.TVLOOKUP, -1);
+ // Text
+ addEntry("RIGHT", TokenConstants.TRIGHT, -1);
+ addEntry("SUBSTITUTE", TokenConstants.TSUBSTITUTE, -1);
+ addEntry("FIND", TokenConstants.TFIND, -1);
+ addEntry("LEFT", TokenConstants.TLEFT, -1);
+ // Logical
+ addEntry("AND", TokenConstants.TAND, -1 );
+ addEntry("IF", TokenConstants.TIF, -1) ;
+ addEntry("OR", TokenConstants.TOR, -1);
+
+ // Functions with Fixed number of Arguments
+ // Math and Trig
+ addEntry("ABS", TokenConstants.TABS, 1);
+ addEntry("ACOS", TokenConstants.TACOS, 1);
+ addEntry("ASIN", TokenConstants.TASIN, 1);
+ addEntry("ATAN", TokenConstants.TATAN, 1);
+ addEntry("ATAN2", TokenConstants.TATAN2, 1);
+ addEntry("COS", TokenConstants.TCOS, 1);
+ addEntry("COUNTIF", TokenConstants.TCOUNTIF, 1);
+ addEntry("DEGREES", TokenConstants.TDEGREES, 1);
+ addEntry("EXP", TokenConstants.TEXP, 1);
+ addEntry("FACT", TokenConstants.TFACT, 1);
+ addEntry("INT", TokenConstants.TINTE, 1);
+ addEntry("LN", TokenConstants.TLN, 1);
+ addEntry("LOG10", TokenConstants.TLOG10, 1);
+ addEntry("MOD", TokenConstants.TMOD, 1);
+ addEntry("PI", TokenConstants.TPI, 0);
+ addEntry("POWER", TokenConstants.TPOWERF, 2);
+ addEntry("RADIANS", TokenConstants.TRADIANS, 1);
+ addEntry("RAND", TokenConstants.TRAND, 1);
+ addEntry("ROUND", TokenConstants.TROUND, 1);
+ addEntry("SQRT", TokenConstants.TSQRT, 1);
+ addEntry("TAN", TokenConstants.TTAN, 1);
+ addEntry("SIN", TokenConstants.TSIN, 1);
+ // Financial
+ addEntry("SLN", TokenConstants.TSLN, 3);
+ addEntry("SYD", TokenConstants.TSYD, 4);
+ // Date and Time
+ addEntry("DATE", TokenConstants.TDATE, 3);
+ addEntry("DATEVALUE", TokenConstants.TDATEVALUE, 1);
+ addEntry("DAY", TokenConstants.TDAY, 1);
+ addEntry("HOUR", TokenConstants.THOUR, 1);
+ addEntry("MINUTE", TokenConstants.TMINUTE, 1 );
+ addEntry("MONTH", TokenConstants.TMONTH, 1);
+ addEntry("NOW", TokenConstants.TNOW, 0);
+ addEntry("SECOND", TokenConstants.TSECOND, 1);
+ addEntry("TIME", TokenConstants.TTIME, 3);
+ addEntry("TIMEVALUE", TokenConstants.TTIMEVALUE, 1);
+ addEntry("YEAR", TokenConstants.TYEAR, 1);
+ // Statistical
+ addEntry("COUNTBLANK", TokenConstants.TCOUNTBLANK, 1);
+ // lookup
+ addEntry("COLUMNS", TokenConstants.TCOLUMNS, 1);
+ addEntry("ROWS", TokenConstants.TROWS, 1);
+ // Database
+ addEntry("DAVERAGE", TokenConstants.TDAVAERAGE, 3);
+ addEntry("DCOUNT", TokenConstants.TDCOUNT, 3);
+ addEntry("DCOUNTA", TokenConstants.TDCOUNTA, 2);
+ addEntry("DGET", TokenConstants.TDGET, 3);
+ addEntry("DMAX", TokenConstants.TDMAX, 3);
+ addEntry("DMIN", TokenConstants.TDMIN, 3);
+ addEntry("DPRODUCT", TokenConstants.TDPRODUCT, 3);
+ addEntry("DSTDEV", TokenConstants.TDSTDEV, 3);
+ addEntry("DSTDEVP", TokenConstants.TDSTDEVP, 3) ;
+ addEntry("DSUM", TokenConstants.TDSUM, 3);
+ addEntry("DVAR", TokenConstants.TDVAR, 3);
+ addEntry("DVARP", TokenConstants.TDVARP, 3);
+ // Text
+ addEntry("EXACT", TokenConstants.TEXACT, 2);
+ addEntry("LEN", TokenConstants.TLEN, 1);
+ addEntry("LOWER", TokenConstants.TLOWER, 1);
+ addEntry("MID", TokenConstants.TMID, 3); // ??????
+ addEntry("PROPER", TokenConstants.TPROPER, 1);
+ addEntry("REPLACE", TokenConstants.TREPLACE, 4);
+ addEntry("REPT", TokenConstants.TREPT, 2);
+ addEntry("T", TokenConstants.TT, 1);
+ addEntry("TRIM", TokenConstants.TRIM, 1);
+ addEntry("UPPER", TokenConstants.TUPPER, 1);
+ addEntry("VALUE", TokenConstants.TVALUE, 1);
+ // Logical
+ addEntry("FALSE", TokenConstants.TFALSE, 0);
+ addEntry("NOT", TokenConstants.TNOT, 1);
+ addEntry("TRUE", TokenConstants.TTRUE, 0);
+ // Informational
+ addEntry("ERRORTYPE", TokenConstants.TERRORTYPE, 1);
+ addEntry("ISBLANK", TokenConstants.TISBLANK, 1);
+ addEntry("ISERR", TokenConstants.TISERR, 1);
+ addEntry("ISERROR", TokenConstants.TISERROR, 1);
+ addEntry("ISLOGICAL", TokenConstants.TISLOGICAL, 1);
+ addEntry("ISNA", TokenConstants.TISNA, 1);
+ addEntry("ISNONTEXT", TokenConstants.TISNONTEXT, 1);
+ addEntry("ISNUMBER", TokenConstants.TISNUMBER, 1);
+ addEntry("ISTEXT", TokenConstants.TISTEXT, 1);
+ addEntry("N", TokenConstants.TN, 1);
+ addEntry("NA", TokenConstants.TNA, 0);
+
+ }
+
+ /**
+ * Associate a function with an identifier and specifiy the number of arguments for that function
+ * @param symbol The function string that will act as the key in the lookup table
+ * @param id The identifier for the function
+ * @param args The number of arguments this function requires
+ */
+ public void addEntry(String symbol, int id, int args) {
+ addEntry(symbol, id);
+ stringToArgs.put(symbol, new Integer(args));
+ }
+
+ /**
+ * Retrieve the number of arguments for this function
+ * @param symbol The function name
+ * @return The number of arguments required by this function
+ */
+ public int getArgCountFromString(String symbol) {
+ return ((Integer)stringToArgs.get(symbol)).intValue();
+ }
+}
diff --git a/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/OperandLookup.java b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/OperandLookup.java
new file mode 100644
index 000000000000..6ad1876e5358
--- /dev/null
+++ b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/OperandLookup.java
@@ -0,0 +1,62 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxc.pexcel.records.formula;
+import java.util.HashMap;
+
+/**
+ * A lookup table containing information about operands
+ */
+public class OperandLookup extends SymbolLookup {
+
+ /**
+ * The default constructor - invokes {@link #initialize() initialize()}
+ */
+ public OperandLookup() {
+ initialize();
+ }
+
+ /**
+ * Initialize the lookup table for operands
+ */
+ public void initialize() {
+ if ((stringToID != null) || (idToString != null)) {
+ return;
+ }
+ stringToID = new HashMap();
+ idToString = new HashMap();
+ addEntry("CELL_REFERENCE", TokenConstants.TREF);
+ addEntry("CELL_AREA_REFERENCE", TokenConstants.TAREA);
+ addEntry("INTEGER", TokenConstants.TNUM);
+ addEntry("NUMBER", TokenConstants.TNUM);
+ addEntry("STRING", TokenConstants.TSTRING);
+ addEntry("NAME", TokenConstants.TNAME);
+ addEntry("3D_CELL_REFERENCE", TokenConstants.TREF3D);
+ addEntry("3D_CELL_AREA_REFERENCE", TokenConstants.TAREA3D);
+ }
+
+}
diff --git a/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/OperatorLookup.java b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/OperatorLookup.java
new file mode 100644
index 000000000000..de9ed23d8a24
--- /dev/null
+++ b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/OperatorLookup.java
@@ -0,0 +1,73 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxc.pexcel.records.formula;
+
+import java.util.HashMap;
+
+/**
+ * A lookup table containing information about operators
+ */
+public class OperatorLookup extends SymbolLookup {
+
+ /**
+ * The default constructor - invokes {@link #initialize() initialize()}
+ */
+ public OperatorLookup() {
+ initialize();
+ }
+
+ /**
+ * Initialize the lookup table for operators
+ */
+ public void initialize() {
+ if ((stringToID != null) || (idToString != null)) {
+ return;
+ }
+ stringToID = new HashMap();
+ idToString = new HashMap();
+ addEntry("UNARY_PLUS", TokenConstants.TUPLUS);
+ addEntry("UNARY_MINUS", TokenConstants.TUMINUS);
+ addEntry("%", TokenConstants.TPERCENT);
+ addEntry("+", TokenConstants.TADD);
+ addEntry("-", TokenConstants.TSUB);
+ addEntry("*", TokenConstants.TMUL);
+ addEntry("/", TokenConstants.TDIV);
+ addEntry(",", TokenConstants.TARGSEP);
+ addEntry("^", TokenConstants.TPOWER);
+ addEntry("&", TokenConstants.TCONCAT);
+ addEntry("(", TokenConstants.TPAREN);
+ addEntry(")", TokenConstants.TCLOSEPAREN);
+ addEntry("<", TokenConstants.TLESS);
+ addEntry(">", TokenConstants.TGREATER);
+ addEntry(">=", TokenConstants.TGTEQUALS);
+ addEntry("<=", TokenConstants.TLESSEQUALS);
+ addEntry("=", TokenConstants.TEQUALS);
+ addEntry("<>", TokenConstants.TNEQUALS);
+ }
+
+}
diff --git a/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/ParseToken.java b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/ParseToken.java
new file mode 100644
index 000000000000..053266c8008b
--- /dev/null
+++ b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/ParseToken.java
@@ -0,0 +1,42 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxc.pexcel.records.formula;
+
+public interface ParseToken
+{
+ public boolean isOperand();
+ public boolean isOperator();
+ public int getTokenType();
+
+ //GENERIC TOKENS (MOSTLY UNUSED
+ public static final int TOKEN_OPERATOR = 1;
+ public static final int TOKEN_OPERAND = 2;
+ public static final int TOKEN_FUNCTION_FIXED = 3;
+ public static final int TOKEN_FUNCTION_VARIABLE = 4;
+
+}
diff --git a/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/PrecedenceTable.java b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/PrecedenceTable.java
new file mode 100644
index 000000000000..551b77cf6e7f
--- /dev/null
+++ b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/PrecedenceTable.java
@@ -0,0 +1,85 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxc.pexcel.records.formula;
+
+import java.util.HashMap;
+
+/**
+ * This class defines the precedence applied to each operator when performing a conversion
+ * {@link org.openoffice.xmerge.converter.xml.sxc.pexcel.Records.formula.FormulaCompiler.infix2 from infix to RPN.}.
+ */
+public class PrecedenceTable {
+ public static final int DEFAULT_PRECEDENCE = 0;
+ public static final int EQNEQ_PRECEDENCE = 1; // =, <>
+ public static final int GTLTEQ_PRECEDENCE = 1; // >=, <=
+ public static final int GTLT_PRECEDENCE = 2; // >, <
+ public static final int ADDOP_PRECEDENCE = 4; // +, -
+ public static final int MULTOP_PRECEDENCE = 5; // *, /
+ public static final int FACTOR_PRECEDENCE = 6; // ^
+ public static final int CONCAT_PRECEDENCE = 6; // &
+ public static final int UNARY_PRECEDENCE = 7; // !, Unary +, Unary -
+ public static final int PAREN_PRECEDENCE = 8; // (, )
+ public static final int FUNCTION_PRECEDENCE = 8;
+ public static final int COMMA_PRECEDENCE = 8;
+
+ private static HashMap map;
+ static {
+ map = new HashMap();
+
+ map.put("%", new Integer(UNARY_PRECEDENCE));
+ map.put("+", new Integer(ADDOP_PRECEDENCE));
+ map.put("-", new Integer(ADDOP_PRECEDENCE));
+ map.put("*", new Integer(MULTOP_PRECEDENCE));
+ map.put("/", new Integer(MULTOP_PRECEDENCE));
+ map.put("(", new Integer(PAREN_PRECEDENCE));
+ map.put(")", new Integer(PAREN_PRECEDENCE));
+ map.put(",", new Integer(COMMA_PRECEDENCE));
+ map.put(">", new Integer(GTLT_PRECEDENCE));
+ map.put("<", new Integer(GTLT_PRECEDENCE));
+ map.put("=", new Integer(EQNEQ_PRECEDENCE));
+ map.put("&", new Integer(CONCAT_PRECEDENCE));
+ map.put("^", new Integer(FACTOR_PRECEDENCE));
+ map.put(">=", new Integer(GTLTEQ_PRECEDENCE));
+ map.put("<=", new Integer(GTLTEQ_PRECEDENCE));
+ map.put("<>", new Integer(EQNEQ_PRECEDENCE));
+ map.put("FUNCTION", new Integer(FUNCTION_PRECEDENCE));
+ }
+
+ /**
+ * Retrieve the precedence value for a given operator.
+ * @param op Look up the precedence for this operator
+ * @return an integer representing the integer value of the operator
+ */
+ public static int getPrecedence(String op) {
+ Object obj = map.get(op);
+ if (obj == null) {
+ return DEFAULT_PRECEDENCE;
+ }
+ return ((Integer)obj).intValue();
+ }
+}
diff --git a/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/SymbolLookup.java b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/SymbolLookup.java
new file mode 100644
index 000000000000..bf7722b973e4
--- /dev/null
+++ b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/SymbolLookup.java
@@ -0,0 +1,81 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxc.pexcel.records.formula;
+
+import java.util.HashMap;
+
+/**
+ * This interface defines the attributes of a lookup table for this plugin.
+ * Symbols will generally be either operators (_, -, *, etc) or funtion names.
+ */
+public abstract class SymbolLookup {
+
+ protected HashMap stringToID = null;
+ protected HashMap idToString = null;
+
+ /**
+ * Perform lookup table specific initialization. This would typically entail loading values into
+ * the lookup table. It is best to optimize this process so that data is loaded statically and shared
+ * across all instances of the lookup table.
+ */
+ abstract public void initialize();
+
+ /**
+ * Associate a symbol with a numeric value in the lookup table
+ * @param symbol The symbol that will act as the key in the lookup table
+ * @param value The value to be associated with a given symbol
+ */
+ public void addEntry(String symbol, int id) {
+ Integer iObj = new Integer(id);
+ stringToID.put(symbol, iObj);
+ idToString.put(iObj, symbol);
+ }
+
+ /**
+ * Retrieve the symbol associated with a given identifier
+ * @param id The identfier for which we need to retieve the symbol string
+ * @return The string associated with this identifier in the lookup table.
+ */
+ public String getStringFromID(int id) {
+ return (String)idToString.get(new Integer(id));
+ }
+
+ /**
+ * Retrieve the identifier associated with a given symbol
+ * @param symbol The symbol for which we need to retieve the identifier
+ * @throws UnsupportedFunctionException Thown when the symbol is not found in the lookup table
+ * @return The identifier associated with this string in the lookup table.
+ */
+ public int getIDFromString(String symbol) throws UnsupportedFunctionException {
+ Integer i = (Integer)stringToID.get(symbol);
+ if (i == null)
+ throw new UnsupportedFunctionException("Token '" + symbol + "' not supported by Pocket Excel");
+
+ return ((Integer)stringToID.get(symbol)).intValue();
+ }
+}
diff --git a/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/Token.java b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/Token.java
new file mode 100644
index 000000000000..48d35dcef5d1
--- /dev/null
+++ b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/Token.java
@@ -0,0 +1,151 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxc.pexcel.records.formula;
+
+
+/**
+ * A Token is the basic building block of any formula.
+ * A Token can be of four types (Operator, Operand, Function with fixed
+ * arguments and function with a variable number of arguments. Each type can
+ * have numerous id's. Thetypes are define in <code>ParseToken</code> and the
+ * id's are defined in <code>TokenConstants</code>. The other member variables
+ * are priority which is returned from the <code>PrecedenceTable</code>, the
+ * value which is the String equivalent of the token (eg. "+", "$A$12", "SUM")
+ * and the number of arguments which is only valid for operators and functions.
+ * Tokens should never be created directly and instead are created by the
+ * <code>TokenFactory</code>
+ */
+public class Token implements ParseToken {
+
+ private String value;
+ private int type; // operator, operand, function fixed, function variable
+ private int id; // cell reference, SUM, integer
+ private int priority;
+ private int numArgs=-1;
+
+ public Token(String op, int type, int id, int args) {
+ this.value = op;
+ this.type = type;
+ this.id = id;
+ this.numArgs = args;
+ if(type==ParseToken.TOKEN_FUNCTION_VARIABLE) {
+ priority = PrecedenceTable.getPrecedence("FUNCTION");
+ } else if(type==ParseToken.TOKEN_OPERATOR) {
+ priority = PrecedenceTable.getPrecedence(op);
+ } else {
+ priority = PrecedenceTable.getPrecedence("DEFAULT");
+ }
+ }
+
+ /**
+ * Checks if the current token is an operator
+ *
+ * @return A <code>boolean</code> result of the comaparison
+ */
+ public boolean isOperator() {
+ return type == ParseToken.TOKEN_OPERATOR;
+ }
+
+ /**
+ * Checks if the current token is an operand
+ *
+ * @return A <code>boolean</code> result of the comaparison
+ */
+ public boolean isOperand() {
+ return type == ParseToken.TOKEN_OPERAND;
+ }
+
+ /**
+ * Checks if the current token is a function
+ *
+ * @return A <code>boolean</code> result of the comaparison
+ */
+ public boolean isFunction() {
+ return (type==ParseToken.TOKEN_FUNCTION_FIXED) || (type==ParseToken.TOKEN_FUNCTION_VARIABLE);
+ }
+
+ /**
+ * Returns the token type. This can be one of four values (TOKEN_OPERATOR,
+ * TOKEN_OPERAND, TOKEN_FUNCTION_FIXED, TOKEN_FUNCTION_VARIABLE) defined in
+ * <code>ParseToken</code>
+ *
+ * @return A <code>boolean</code> result of the comparison
+ */
+ public int getTokenType() {
+
+ return type;
+ }
+
+ /**
+ * Returns the ID of this token. This ID is equivalent to the pexcel hex
+ * value and is defined in <code>ParseToken</code>
+ *
+ * @return Returns the id of this token
+ */
+ public int getTokenID() {
+
+ return id;
+ }
+
+ /**
+ * Returns the <code>String</code> equivalent of this token
+ *
+ * @return The <code>String</code> representing this Token
+ */
+ public String getValue() {
+ return value;
+ }
+
+ /**
+ * Returns the number of arguments if this token represents an operator or
+ * function. Otherwise returns -1.
+ *
+ * @return The number of arguments
+ */
+ public int getNumArgs() {
+ return numArgs;
+ }
+
+ /**
+ * Checks if the current token is an operator
+ *
+ * @return A <code>boolean</code> result of the comparison
+ */
+ public int getTokenPriority() {
+ return priority;
+ }
+
+ /**
+ * Returns the <code>String</code> equivalent of this token
+ *
+ * @return The <code>String</code> representing this Token
+ */
+ public String toString() {
+ return getValue();
+ }
+}
diff --git a/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/TokenConstants.java b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/TokenConstants.java
new file mode 100644
index 000000000000..1a636f9ae1f1
--- /dev/null
+++ b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/TokenConstants.java
@@ -0,0 +1,203 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxc.pexcel.records.formula;
+
+public interface TokenConstants {
+
+ // Unary Operator Tokens
+ public static final int TUPLUS = 0x12;
+ public static final int TUMINUS = 0x13;
+ public static final int TPERCENT = 0x14;
+ public static final int TPAREN = 0x15;
+ // Binary Operator Tokens
+ public static final int TADD = 0x03;
+ public static final int TSUB = 0x04;
+ public static final int TMUL = 0x05;
+ public static final int TDIV = 0x06;
+ public static final int TPOWER = 0x07;
+ public static final int TCONCAT = 0x08;
+
+ //Logical operators
+ public static final int TLESS = 0x09;
+ public static final int TLESSEQUALS = 0x0A;
+ public static final int TEQUALS = 0x0B;
+ public static final int TGTEQUALS = 0x0C;
+ public static final int TGREATER = 0x0D;
+ public static final int TNEQUALS = 0x0E;
+
+ // Function Operator Tokens
+ public static final int TFUNC = 0x41;
+ public static final int TFUNCVAR = 0x42;
+
+ // Constant Operand Tokens
+ public static final int TSTRING = 0x17;
+ public static final int TINT = 0x1E;
+ public static final int TNUM = 0x1F;
+ // Operand Tokens
+ public static final int TREF = 0x44;
+ public static final int TAREA = 0x25;
+ public static final int TNAME = 0x23;
+ public static final int TREF3D = 0x3A;
+ public static final int TAREA3D = 0x3B;
+
+ //
+ public static final int TARGSEP = 0x1001;
+ public static final int TCLOSEPAREN = 0x1002;
+
+ // Variable argument Functions
+ // Math and Trig
+ public static final int TSUM = 0x04;
+ public static final int TPRODUCT = 0xB7;
+ public static final int TSUMIF = 0x0159;
+ public static final int TLOG = 0x6D;
+ public static final int TRUNC = 0xC5;
+ // Financial
+ public static final int TDDB = 0x90;
+ public static final int TFV = 0x39;
+ public static final int TIRR = 0x3E;
+ public static final int TNPER = 0x3A;
+ public static final int TNPV = 0x0B;
+ public static final int TPMT = 0x3B;
+ public static final int TPV = 0x38;
+ public static final int TRATE = 0x3C;
+ // Statistical
+ public static final int TAVERAGE = 0x05;
+ public static final int TCOUNT = 0x00;
+ public static final int TCOUNTA = 0xA9;
+ public static final int TMAX = 0x07;
+ public static final int TMIN = 0x06;
+ public static final int TSTDEV = 0x0C;
+ public static final int TSTDEVP = 0xC1;
+ public static final int TVAR = 0x2E;
+ public static final int TVARP = 0xC2;
+ // Lookup
+ public static final int TCHOOSE = 0x64;
+ public static final int THLOOKUP = 0x65;
+ public static final int TINDEX = 0x1D;
+ public static final int TMATCH = 0x40;
+ public static final int TVLOOKUP = 0x66;
+ // Text
+ public static final int TRIGHT = 0x74;
+ public static final int TSUBSTITUTE = 0x78;
+ public static final int TFIND = 0x7c;
+ public static final int TLEFT = 0x73;
+ // Logical
+ public static final int TAND = 0x24; // 42
+ public static final int TIF = 0x01; // 42
+ public static final int TOR = 0x25; // 42
+
+ // Fixed argument Functions
+ // Math and Trig
+ public static final int TABS = 0x18;
+ public static final int TACOS = 0x63;
+ public static final int TASIN = 0x62;
+ public static final int TATAN = 0x12;
+ public static final int TATAN2 = 0x61;
+ public static final int TCOS = 0x10;
+ public static final int TSIN = 0x0F;
+
+ public static final int TCOUNTIF = 0x015A;
+ public static final int TDEGREES = 0x0157;
+ public static final int TEXP = 0x15;
+ public static final int TFACT = 0xB8;
+ public static final int TINTE = 0x19;
+ public static final int TLN = 0x16;
+
+ public static final int TLOG10 = 0x17;
+ public static final int TMOD = 0x27;
+ public static final int TPI = 0x13;
+
+ public static final int TPOWERF = 0x0151;
+ public static final int TRADIANS = 0x0156;
+ public static final int TRAND = 0x3F;
+ public static final int TROUND = 0x1B;
+ public static final int TSQRT = 0x14;
+ public static final int TTAN = 0x11;
+
+ public static final int TSLN = 0x8E;
+ public static final int TSYD = 0x8F;
+
+ // Date and Time
+ public static final int TDATE = 0x41;
+ public static final int TDATEVALUE = 0x8C;
+ public static final int TDAY = 0x43;
+ public static final int THOUR = 0x47;
+ public static final int TMINUTE = 0x48;
+ public static final int TMONTH = 0x44;
+ public static final int TNOW = 0x4A;
+ public static final int TSECOND = 0x49;
+ public static final int TTIME = 0x42;
+ public static final int TTIMEVALUE = 0x8D;
+ public static final int TYEAR = 0x45;
+ // Statistical
+ public static final int TCOUNTBLANK = 0x015B ;
+ // lookup
+ public static final int TCOLUMNS = 0x4D;
+ public static final int TROWS = 0x4C;
+ // Database
+ public static final int TDAVAERAGE = 0x2A;
+ public static final int TDCOUNT = 0x28;
+ public static final int TDCOUNTA = 0xC7;
+ public static final int TDGET = 0xEB;
+ public static final int TDMAX = 0x2C;
+ public static final int TDMIN = 0x2B;
+ public static final int TDPRODUCT = 0xBD;
+ public static final int TDSTDEV = 0x2D;
+ public static final int TDSTDEVP = 0xC3;
+ public static final int TDSUM = 0x29;
+ public static final int TDVAR = 0x2F;
+ public static final int TDVARP = 0xC4;
+ // Text
+ public static final int TEXACT = 0x75;
+ public static final int TLEN = 0x20;
+ public static final int TLOWER = 0x70;
+ public static final int TMID = 0x1F; // ??????
+ public static final int TPROPER = 0x72;
+ public static final int TREPLACE = 0x77;
+ public static final int TREPT = 0x1E;
+ public static final int TT = 0x82;
+ public static final int TRIM = 0x76;
+ public static final int TUPPER = 0x71;
+ public static final int TVALUE = 0x21;
+ // Logical
+ public static final int TFALSE = 0x23;
+ public static final int TNOT = 0x26;
+ public static final int TTRUE = 0x22;
+ // Informational
+ public static final int TERRORTYPE = 0x05;
+ public static final int TISBLANK = 0x81;
+ public static final int TISERR = 0x7E;
+ public static final int TISERROR = 0x03;
+ public static final int TISLOGICAL = 0xC6;
+ public static final int TISNA = 0x02;
+ public static final int TISNONTEXT = 0xBE;
+ public static final int TISNUMBER = 0x80;
+ public static final int TISTEXT = 0x7F;
+ public static final int TN = 0x83;
+ public static final int TNA = 0x0A;
+}
diff --git a/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/TokenDecoder.java b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/TokenDecoder.java
new file mode 100644
index 000000000000..e18c1d10cc04
--- /dev/null
+++ b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/TokenDecoder.java
@@ -0,0 +1,497 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxc.pexcel.records.formula;
+
+import java.io.*;
+import java.util.Vector;
+import java.util.Enumeration;
+
+import org.openoffice.xmerge.util.Debug;
+import org.openoffice.xmerge.util.EndianConverter;
+import org.openoffice.xmerge.converter.xml.sxc.pexcel.records.DefinedName;
+import org.openoffice.xmerge.converter.xml.sxc.pexcel.records.Workbook;
+
+/**
+ * The TokenDecoder decodes a byte[] to an equivalent <code>String</code>. The only
+ * public method apart from the default constructor is the getTokenVector method.
+ * This method takes an entire formula as a pexcel byte[] and decodes it into
+ * a series of <code>Token</code>s. It adds these to a <code>Vector</code> which
+ * is returned once all the tokens have been decoded. The Decoder supports
+ * the following tokens.<br><br>
+ *
+ * Operands Floating point's, Cell references (absolute and relative),
+ * cell ranges<br>
+ * Operators +,-,*,/,&lt;,&gt;.&lt;=,&gt;=,&lt;&gt;<br>
+ * Functions All pexcel fixed and varaible argument functions
+ *
+ */
+public class TokenDecoder {
+
+ private TokenFactory tf;
+ private FunctionLookup fl;
+ private OperatorLookup operatorLookup;
+ private OperandLookup operandLookup;
+ private Workbook wb;
+
+ /**
+ * Default Constructor initializes the <code>TokenFactory</code> for generating
+ * <code>Token</code> and the <code>SymbolLookup</code> for generating
+ * Strings from hex values.
+ */
+ public TokenDecoder() {
+ tf = new TokenFactory();
+ fl = new FunctionLookup();
+ operatorLookup = new OperatorLookup();
+ operandLookup = new OperandLookup();
+ }
+
+ /**
+ * Sets global workbook data needed for defined names
+ */
+ public void setWorkbook(Workbook wb) {
+
+ Debug.log(Debug.TRACE, "TokenDecoder : setWorkbook");
+ this.wb = wb;
+ }
+
+ /**
+ * Returns a <code>Vector</code> of <code>Token</code> decoded from a
+ * byte[]. The byte[] is first converted to a
+ * <code>ByteArrayInputStream</code> as this is the easiest way of reading
+ * bytes.
+ *
+ * @param formula A Pocket Excel Formula byte[]
+ * @return A <code>Vector</code> of deoded <code>Token</code>
+ */
+ public Vector getTokenVector(byte[] formula) {
+
+ Vector v = new Vector();
+
+ ByteArrayInputStream bis = new ByteArrayInputStream(formula);
+ int b = 0 ;
+ Token t;
+
+ while ((b = bis.read())!=-1)
+ {
+
+
+ switch (b) {
+
+ case TokenConstants.TAREA3D:
+ Debug.log(Debug.TRACE, "Decoded 3D Area Cell Reference: ");
+ v.add(read3DCellAreaRefToken(bis));
+ Debug.log(Debug.TRACE, "Decoded 3D Area Cell Reference: " + v.lastElement());
+ break;
+ case TokenConstants.TREF3D:
+ Debug.log(Debug.TRACE, "Decoded 3D Cell Reference: ");
+ v.add(read3DCellRefToken(bis));
+ Debug.log(Debug.TRACE, "Decoded 3D Cell Reference: " + v.lastElement());
+ break;
+ case TokenConstants.TREF :
+ v.add(readCellRefToken(bis));
+ Debug.log(Debug.TRACE, "Decoded Cell Reference: " + v.lastElement());
+ break;
+ case TokenConstants.TAREA :
+ v.add(readCellAreaRefToken(bis));
+ Debug.log(Debug.TRACE, "Decoded Cell Area Reference: " + v.lastElement());
+ break;
+ case TokenConstants.TNUM :
+ v.add(readNumToken(bis));
+ Debug.log(Debug.TRACE, "Decoded number : " + v.lastElement());
+ break;
+ case TokenConstants.TFUNCVAR :
+ v.add(readFunctionVarToken(bis));
+ Debug.log(Debug.TRACE, "Decoded variable argument function: " + v.lastElement());
+ break;
+ case TokenConstants.TFUNC :
+ v.add(readFunctionToken(bis));
+ Debug.log(Debug.TRACE, "Decoded function: " + v.lastElement());
+ break;
+ case TokenConstants.TSTRING :
+ v.add(readStringToken(bis));
+ Debug.log(Debug.TRACE, "Decoded string: " + v.lastElement());
+ break;
+ case TokenConstants.TNAME :
+ v.add(readNameToken(bis));
+ Debug.log(Debug.TRACE, "Decoded defined name: " + v.lastElement());
+ break;
+ case TokenConstants.TUPLUS:
+ case TokenConstants.TUMINUS:
+ case TokenConstants.TPERCENT:
+ v.add(readOperatorToken(b, 1));
+ Debug.log(Debug.TRACE, "Decoded Unary operator : " + v.lastElement());
+ break;
+ case TokenConstants.TADD :
+ case TokenConstants.TSUB :
+ case TokenConstants.TMUL :
+ case TokenConstants.TDIV :
+ case TokenConstants.TLESS :
+ case TokenConstants.TLESSEQUALS :
+ case TokenConstants.TEQUALS :
+ case TokenConstants.TGTEQUALS :
+ case TokenConstants.TGREATER :
+ case TokenConstants.TNEQUALS :
+ v.add(readOperatorToken(b, 2));
+ Debug.log(Debug.TRACE, "Decoded Binary operator : " + v.lastElement());
+ break;
+
+ default :
+ Debug.log(Debug.TRACE, "Unrecognized byte : " + b);
+ }
+ }
+ return v;
+ }
+
+ /**
+ * Converts a zero based integer to a char (eg. a=0, b=1).
+ * It assumes the integer is less than 26.
+ *
+ * @param i A 0 based index
+ * @return The equivalent character
+ */
+ private char int2Char(int i) {
+ return (char) ('A' + i);
+ }
+
+ /**
+ * Reads a Cell Reference token from the <code>ByteArrayInputStream</code>
+ *
+ * @param bis The <code>ByteArrayInputStream</code> from which we read the
+ * bytes.
+ * @return The decoded String <code>Token</code>
+ */
+ private Token readStringToken(ByteArrayInputStream bis) {
+
+ int len = ((int)bis.read())*2;
+ int options = (int)bis.read();
+ Debug.log(Debug.TRACE,"String length is " + len + " and Options Flag is " + options);
+ byte [] stringBytes = new byte[len];
+ int numRead =0;
+ if ((numRead = bis.read(stringBytes, 0, len)) != len) {
+ Debug.log(Debug.TRACE,"Expected " + len + " bytes. Could only read " + numRead + " bytes.");
+ //throw new IOException("Expected " + len + " bytes. Could only read " + numRead + " bytes.");
+ }
+ StringBuffer outputString = new StringBuffer();
+ outputString.append('"');
+ try {
+ Debug.log(Debug.TRACE,"Using LE encoding");
+ outputString.append(new String(stringBytes, "UTF-16LE"));
+ } catch (IOException eIO) {
+ outputString.append(new String(stringBytes)); //fall back to default encoding
+ }
+ outputString.append('"');
+
+ return (tf.getOperandToken(outputString.toString(), "STRING"));
+ }
+
+ /**
+ * Reads a Defined Name token from the <code>ByteArrayInputStream</code>
+ *
+ * @param bis The <code>ByteArrayInputStream</code> from which we read the
+ * bytes.
+ * @return The decoded Name <code>Token</code>
+ */
+ private Token readNameToken(ByteArrayInputStream bis) {
+ byte buffer[] = new byte[2];
+ buffer[0] = (byte) bis.read();
+ buffer[1] = (byte) bis.read();
+ int nameIndex = EndianConverter.readShort(buffer);
+ bis.skip(12); // the next 12 bytes are unused
+ Enumeration e = wb.getDefinedNames();
+ int i = 1;
+ while(i<nameIndex) {
+ e.nextElement();
+ i++;
+ }
+ Debug.log(Debug.TRACE,"Name index is " + nameIndex);
+ DefinedName dn = (DefinedName)e.nextElement();
+ Debug.log(Debug.TRACE,"DefinedName is " + dn.getName());
+ return (tf.getOperandToken(dn.getName(), "NAME"));
+ }
+
+ /**
+ * Reads a Cell Reference token from the <code>ByteArrayInputStream</code>
+ *
+ * @param bis The <code>ByteArrayInputStream</code> from which we read the
+ * bytes.
+ * @return The decoded Cell Reference <code>Token</code>
+ */
+ private Token readCellRefToken(ByteArrayInputStream bis) {
+
+ byte buffer[] = new byte[2];
+ String outputString = new String();
+
+ buffer[0] = (byte) bis.read();
+ buffer[1] = (byte) bis.read();
+ int formulaRow = EndianConverter.readShort(buffer);
+ int relativeFlags = (formulaRow & 0xC000)>>14;
+ formulaRow &= 0x3FFF;
+ int formulaCol = (byte) bis.read();
+
+ outputString = int2CellStr(formulaRow, formulaCol, relativeFlags);
+
+ return (tf.getOperandToken(outputString,"CELL_REFERENCE"));
+ }
+
+ /**
+ * Reads a Cell Reference token from the <code>ByteArrayInputStream</code>
+ *
+ * @param bis The <code>ByteArrayInputStream</code> from which we read the
+ * bytes.
+ * @return The decoded Cell Reference <code>Token</code>
+ */
+ private Token read3DCellRefToken(ByteArrayInputStream bis) {
+
+ byte buffer[] = new byte[2];
+ String outputString = new String();
+
+ bis.skip(10);
+
+ buffer[0] = (byte) bis.read();
+ buffer[1] = (byte) bis.read();
+ int Sheet1 = EndianConverter.readShort(buffer);
+ buffer[0] = (byte) bis.read();
+ buffer[1] = (byte) bis.read();
+ int Sheet2 = EndianConverter.readShort(buffer);
+
+ buffer[0] = (byte) bis.read();
+ buffer[1] = (byte) bis.read();
+ int formulaRow = EndianConverter.readShort(buffer);
+ int relativeFlags = (formulaRow & 0xC000)>>14;
+ formulaRow &= 0x3FFF;
+ int formulaCol = (byte) bis.read();
+ String cellRef = "." + int2CellStr(formulaRow, formulaCol, relativeFlags);
+ if(Sheet1 == Sheet2) {
+ outputString = "$" + wb.getSheetName(Sheet1) + cellRef;
+ } else {
+ outputString = "$" + wb.getSheetName(Sheet1) + cellRef + ":$" + wb.getSheetName(Sheet2) + cellRef;
+ }
+
+ return (tf.getOperandToken(outputString,"3D_CELL_REFERENCE"));
+ }
+
+ /**
+ * Reads a Cell Reference token from the <code>ByteArrayInputStream</code>
+ *
+ * @param bis The <code>ByteArrayInputStream</code> from which we read the
+ * bytes.
+ * @return The decoded Cell Reference <code>Token</code>
+ */
+ private Token read3DCellAreaRefToken(ByteArrayInputStream bis) {
+
+ byte buffer[] = new byte[2];
+ String outputString = new String();
+
+ bis.skip(10);
+
+ buffer[0] = (byte) bis.read();
+ buffer[1] = (byte) bis.read();
+ int Sheet1 = EndianConverter.readShort(buffer);
+ buffer[0] = (byte) bis.read();
+ buffer[1] = (byte) bis.read();
+ int Sheet2 = EndianConverter.readShort(buffer);
+
+ buffer[0] = (byte) bis.read();
+ buffer[1] = (byte) bis.read();
+ int formulaRow1 = EndianConverter.readShort(buffer);
+ int relativeFlags1 = (formulaRow1 & 0xC000)>>14;
+ formulaRow1 &= 0x3FFF;
+
+ buffer[0] = (byte) bis.read();
+ buffer[1] = (byte) bis.read();
+ int formulaRow2 = EndianConverter.readShort(buffer);
+ int relativeFlags2 = (formulaRow2 & 0xC000)>>14;
+ formulaRow2 &= 0x3FFF;
+
+ int formulaCol1 = (byte) bis.read();
+ int formulaCol2 = (byte) bis.read();
+
+ String cellRef1 = "." + int2CellStr(formulaRow1, formulaCol1, relativeFlags1);
+ String cellRef2 = int2CellStr(formulaRow2, formulaCol2, relativeFlags2);
+
+ if(Sheet1 == Sheet2) {
+ outputString = "$" + wb.getSheetName(Sheet1) + cellRef1 + ":" + cellRef2;
+ } else {
+ outputString = "$" + wb.getSheetName(Sheet1) + cellRef1 + ":$" + wb.getSheetName(Sheet2) + "." + cellRef2;
+ }
+
+ return (tf.getOperandToken(outputString,"3D_CELL_AREA_REFERENCE"));
+ }
+
+ /**
+ * Converts a row and col 0 based index to a spreadsheet cell reference.
+ * It also has a relativeFlags which indicates whether or not the
+ * Cell Reference is relative or absolute (Absolute is denoted with '$')
+ *
+ * 00 = absolute row, absolute col
+ * 01 = absolute row, relative col
+ * 10 = relative row, absolute col
+ * 11 = relative row, relative col
+ *
+ * @param row The cell reference 0 based index to the row
+ * @param col The cell reference 0 based index to the row
+ * @param relativeFlags Flags indicating addressing of row and column
+ * @return A <code>String</code> representing a cell reference
+ */
+ private String int2CellStr(int row, int col, int relativeFlags) {
+ String outputString = "";
+ int firstChar = (col + 1) / 26;
+
+ if((relativeFlags & 1) == 0) {
+ outputString += "$";
+ }
+
+ if(firstChar>0) {
+ int secondChar = (col + 1) % 26;
+ outputString += Character.toString(int2Char(firstChar - 1)) + Character.toString(int2Char(secondChar - 1));
+ } else {
+ outputString += Character.toString(int2Char(col));
+ }
+ if((relativeFlags & 2) == 0) {
+ outputString += "$";
+ }
+ outputString += Integer.toString(row+1);
+ return outputString;
+ }
+
+ /**
+ * Reads a Cell Area Reference (cell range) <code>Token</code> from
+ * the <code>ByteArrayInputStream</code>
+ *
+ * @param bis The <code>ByteArrayInputStream</code> from which we read the
+ * bytes.
+ * @return The equivalent Cell Area Reference (cell range)
+ * <code>Token</code>
+ */
+ private Token readCellAreaRefToken(ByteArrayInputStream bis) {
+ byte buffer[] = new byte[2];
+ int formulaRow1, formulaRow2;
+ int formulaCol1, formulaCol2;
+
+ String outputString = new String();
+
+ buffer[0] = (byte) bis.read();
+ buffer[1] = (byte) bis.read();
+ formulaRow1 = EndianConverter.readShort(buffer);
+ int relativeFlags1 = (formulaRow1 & 0xC000)>>14;
+ formulaRow1 &= 0x3FFF;
+ buffer[0] = (byte) bis.read();
+ buffer[1] = (byte) bis.read();
+ formulaRow2 = EndianConverter.readShort(buffer);
+ int relativeFlags2 = (formulaRow2 & 0xC000)>>14;
+ formulaRow2 &= 0x3FFF;
+
+ formulaCol1 = (byte) bis.read();
+ formulaCol2 = (byte) bis.read();
+
+ outputString = int2CellStr(formulaRow1, formulaCol1, relativeFlags1);
+ outputString += (":" + int2CellStr(formulaRow2, formulaCol2, relativeFlags2));
+
+ return (tf.getOperandToken(outputString,"CELL_AREA_REFERENCE"));
+ }
+
+
+ /**
+ * Reads a Number (floating point) token from the <code>ByteArrayInputStream</code>
+ *
+ * @param bis The <code>ByteArrayInputStream</code> from which we read the
+ * bytes.
+ * @return The decoded Integer <code>Token</code>
+ */
+ private Token readNumToken(ByteArrayInputStream bis) {
+
+ byte numBuffer[] = new byte[8];
+
+ for(int j=0;j<8;j++) {
+ numBuffer[j]=(byte) bis.read();
+ }
+
+ return (tf.getOperandToken(Double.toString(EndianConverter.readDouble(numBuffer)),"NUMBER"));
+ }
+
+ /**
+ * Read an Operator token from the <code>ByteArrayInputStream</code>
+ *
+ * @param b A Pocket Excel number representing an operator.
+ * @param args The number of arguments this operator takes.
+ * @return The decoded Operator <code>Token</code>
+ */
+ private Token readOperatorToken(int b, int args) {
+
+ Token t;
+
+ if(b==TokenConstants.TUPLUS) {
+ t = tf.getOperatorToken("+", args);
+ } else if(b==TokenConstants.TUMINUS) {
+ t = tf.getOperatorToken("-", args);
+ } else {
+ t = tf.getOperatorToken(operatorLookup.getStringFromID(b), args);
+ }
+ return t;
+ }
+
+ /**
+ * Read a Function token from the <code>ByteArrayInputStream</code>
+ * This function can have any number of arguments and this number is read
+ * in with the record
+ *
+ * @param bis The <code>ByteArrayInputStream</code> from which we read the
+ * bytes.
+ * @return The decoded variable argument Function <code>Token</code>
+ */
+ private Token readFunctionVarToken(ByteArrayInputStream bis) {
+
+ int numArgs = 0;
+ numArgs = bis.read();
+ byte buffer[] = new byte[2];
+ buffer[0] = (byte) bis.read();
+ buffer[1] = (byte) bis.read();
+ int functionID = EndianConverter.readShort(buffer);
+ return (tf.getFunctionToken(fl.getStringFromID(functionID),numArgs));
+ }
+
+ /**
+ * Read a Function token from the <code>ByteArrayInputStream</code>
+ * This function has a fixed number of arguments which it will get
+ * from <code>FunctionLookup</code>.
+ *
+ * @param bis The <code>ByteArrayInputStream</code> from which we read the
+ * bytes.
+ * @return The decoded fixed argument Function <code>Token</code>
+ */
+ private Token readFunctionToken(ByteArrayInputStream bis) {
+
+ byte buffer[] = new byte[2];
+ buffer[0] = (byte) bis.read();
+ buffer[1] = (byte) bis.read();
+ int functionID = EndianConverter.readShort(buffer);
+ String functionName = fl.getStringFromID(functionID);
+ return (tf.getFunctionToken(functionName,fl.getArgCountFromString(functionName)));
+ }
+
+}
diff --git a/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/TokenEncoder.java b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/TokenEncoder.java
new file mode 100644
index 000000000000..249e14ac620f
--- /dev/null
+++ b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/TokenEncoder.java
@@ -0,0 +1,559 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxc.pexcel.records.formula;
+
+import java.io.*;
+import java.util.Vector;
+import java.util.Enumeration;
+
+import org.openoffice.xmerge.util.Debug;
+import org.openoffice.xmerge.util.EndianConverter;
+import org.openoffice.xmerge.converter.xml.sxc.pexcel.records.Workbook;
+import org.openoffice.xmerge.converter.xml.sxc.pexcel.records.DefinedName;
+
+/**
+ * The TokenEncoder encodes a Token to an equivalent pexcel byte[]. The only
+ * public method apart from the default constructor is the getByte method.
+ * This method picks an encoder based onthe Token's type or id field and uses
+ * that encoder to return a byte[] which it returns. This Encoder supports
+ * Operands Floating point's, Cell references (absolute and relative),
+ * cell ranges
+ * Operators +,-,*,/,&lt;,&gt;.&lt;=,&gt;=,&lt;&gt;
+ * Functions All pexcel fixed and varaible argument functions
+ *
+ */
+public class TokenEncoder {
+
+ private FunctionLookup fl;
+ private String parseString;
+ private int index;
+ private Workbook wb;
+
+ /**
+ * Default Constructor
+ */
+ public TokenEncoder() {
+
+ parseString = new String();
+ fl = new FunctionLookup();
+ }
+
+ /**
+ * Sets global workbook data needed for defined names
+ */
+ public void setWorkbook(Workbook wb) {
+
+ this.wb = wb;
+ }
+
+
+ /**
+ * Return the byte[] equivalent of a <code>Token</code>. The various
+ * encoders return <code>Vector</code> of <code>Byte</code> instead
+ * of byte[] because the number of bytes returned varies with each
+ * <code>Token</code> encoded. After the encoding is finished the Vector
+ * in converted to a byte[].
+ *
+ * @param t The <code>Token</code> to be encoded
+ * @return An equivalent Pocket Excel byte[]
+ */
+ public byte[] getByte(Token t) throws IOException {
+
+ Vector tmpByteArray = null; // we use this cause we don't know till after
+ // the encoding takes place how big the byte [] will be
+ //index=0; // This class is declared static in
+ // FormulaHelper so better make sure our index is 0
+ if(t.getTokenType()==ParseToken.TOKEN_OPERATOR) {
+ tmpByteArray = operatorEncoder(t);
+ } else if (t.getTokenType()==ParseToken.TOKEN_FUNCTION_VARIABLE || t.getTokenType()==ParseToken.TOKEN_FUNCTION_FIXED){
+ tmpByteArray = functionEncoder(t);
+ } else { // Operands and functions
+ switch(t.getTokenID()) {
+ case TokenConstants.TNAME :
+ tmpByteArray = nameDefinitionEncoder(t);
+ break;
+ case TokenConstants.TREF3D :
+ tmpByteArray = threeDCellRefEncoder(t);
+ break;
+ case TokenConstants.TAREA3D:
+ tmpByteArray = threeDAreaRefEncoder(t);
+ break;
+ case TokenConstants.TREF :
+ tmpByteArray = cellRefEncoder(t);
+ break;
+ case TokenConstants.TAREA :
+ tmpByteArray = areaRefEncoder(t);
+ break;
+ case TokenConstants.TNUM :
+ tmpByteArray = numEncoder(t);
+ break;
+ case TokenConstants.TSTRING :
+ tmpByteArray = stringEncoder(t);
+ break;
+ default :
+ Debug.log(Debug.ERROR, "Encoder found unrecognized Token");
+ }
+ }
+
+ byte cellRefArray[] = new byte[tmpByteArray.size()];
+ int i = 0;
+ String s = new String();
+ for(Enumeration e = tmpByteArray.elements();e.hasMoreElements();) {
+ Byte tmpByte = (Byte) e.nextElement();
+ s = s + tmpByte + " ";
+ cellRefArray[i] = tmpByte.byteValue();
+ i++;
+ }
+ Debug.log(Debug.TRACE, "Encoding Token " + t.getValue() + " as [" + s + "]");
+ return cellRefArray;
+ }
+
+ /**
+ * An Operator Encoder.
+ *
+ * @param t <code>Token</code> to be encoded
+ * @return A <code>Vector</code> of pexcel <code>Byte</code>
+ */
+ private Vector operatorEncoder(Token t) {
+
+ Vector tmpByteArray = new Vector();
+ tmpByteArray.add(new Byte((byte)t.getTokenID()));
+ return tmpByteArray;
+ }
+
+
+ /**
+ * A String Encoder.
+ *
+ * @param t <code>Token</code> to be encoded
+ * @return A <code>Vector</code> of pexcel <code>Byte</code>
+ */
+ private Vector stringEncoder(Token t) throws IOException{
+
+ Vector tmpByteArray = new Vector();
+ tmpByteArray.add(new Byte((byte)t.getTokenID()));
+ tmpByteArray.add(new Byte((byte)(t.getValue().length())));
+ tmpByteArray.add(new Byte((byte)0x01));
+ byte [] stringBytes = t.getValue().getBytes("UTF-16LE");
+ for (int i=0; i<stringBytes.length; i++) {
+ tmpByteArray.add(new Byte(stringBytes[i]));
+ }
+ return tmpByteArray;
+ }
+
+
+ /**
+ * An Integer Encoder.
+ *
+ * @param t <code>Token</code> to be encoded
+ * @return A <code>Vector</code> of pexcel <code>Byte</code>
+ */
+ private Vector numEncoder(Token t) {
+
+ Vector tmpByteArray = new Vector();
+
+ double cellLong = (double) Double.parseDouble(t.getValue());
+ tmpByteArray.add(new Byte((byte)t.getTokenID()));
+ byte[] tempByte = EndianConverter.writeDouble(cellLong);
+ for(int byteIter=0;byteIter<tempByte.length;byteIter++) {
+ tmpByteArray.add(new Byte(tempByte[byteIter]));
+ }
+ return tmpByteArray;
+ }
+
+ /**
+ * Converts a char to an int. It is zero based
+ * so a=0, b=1 etc.
+ *
+ * @param ch the character to be converted
+ * @return -1 if not a character otherwise a 0 based index
+ */
+ private int char2int(char ch) {
+ if(!Character.isLetter(ch))
+ return -1;
+
+ ch = Character.toUpperCase(ch);
+ return ch-'A';
+ }
+
+ /**
+ * Identify letters
+ *
+ * @param c The character which is to be identified
+ * @return A boolean returning the result of the comparison
+ */
+ private boolean isAlpha(char c) {
+ return(Character.isLetter(c));
+ }
+
+ /**
+ * Identify numbers
+ *
+ * @param c The character which is to be identified
+ * @return A boolean returning the result of the comparison
+ */
+ private boolean isDigit(char c) {
+ return(Character.isDigit(c));
+ }
+
+ /**
+ * Identify letters or numbers
+ *
+ * @param c The character which is to be identified
+ * @return A boolean returning the result of the comparison
+ */
+ private boolean isAlphaNum(char c) {
+ return(isAlpha(c) || isDigit(c));
+ }
+
+ /**
+ * Parses a column reference and returns it's integer equivalent. (eg.
+ * A=0, D=3, BA=27)
+ *
+ * @return an 0 based index to a column
+ */
+ private int column() {
+ char ch = parseString.charAt(index);
+ String columnStr = new String();
+ int col = 0;
+
+ while(isAlpha(ch)) {
+ columnStr += ch;
+ index++;
+ ch = parseString.charAt(index);
+ }
+
+ if(columnStr.length()==1) {
+ col = char2int(columnStr.charAt(0));
+ } else if (columnStr.length()==2) {
+ col = char2int(columnStr.charAt(0)) + 1;
+ col = (col*26) + char2int(columnStr.charAt(1));
+ } else {
+ Debug.log(Debug.ERROR, "Invalid Column Reference " + columnStr );
+ }
+
+
+ return col;
+ }
+
+ /**
+ * Parses a column reference and returns it's integer equivalent. (eg.
+ * A=0, D=3, BA=27)
+ *
+ * @return an 0 based index to a column
+ */
+ private int row() {
+ char ch = parseString.charAt(index);
+ String rowStr = new String();
+ int row = 0;
+ boolean status = true;
+
+ do {
+ rowStr += ch;
+ index++;
+ if(index>=parseString.length()) {
+ status = false;
+ } else {
+ ch = parseString.charAt(index);
+ }
+ } while(isDigit(ch) && status);
+ return Integer.parseInt(rowStr)-1; // Pexcel uses a 0 based index
+ }
+
+ /**
+ * A Cell Reference Encoder (It supports absolute and relative addressing)
+ *
+ * @param t <code>Token</code> to be encoded
+ * @return A <code>Vector</code> of pexcel <code>Byte</code>
+ */
+ private byte[] encodeCellCoordinates(String cellCoordinates) {
+ int col = 0, row = 0;
+ int addressing = 0xC000;
+
+ index = 0;
+ parseString = cellCoordinates;
+ Debug.log(Debug.TRACE,"Encoding cell coordinates " + cellCoordinates);
+ if(cellCoordinates.charAt(index)=='$') {
+ addressing &= 0x8000;
+ index++;
+ }
+ col = column();
+ if(cellCoordinates.charAt(index)=='$') {
+ addressing &= 0x4000;
+ index++;
+ }
+ row = row(); // Pexcel uses a 0 based index
+ row |= addressing;
+ byte tokenBytes[] = new byte[3];
+ tokenBytes[0] = (byte)row;
+ tokenBytes[1] = (byte)(row>>8);
+ tokenBytes[2] = (byte)col;
+ return tokenBytes;
+ }
+
+ /**
+ * A name definition Encoder
+ *
+ * @param t <code>Token</code> to be encoded
+ * @return A <code>Vector</code> of pexcel <code>Byte</code>
+ */
+ private Vector nameDefinitionEncoder(Token t) {
+
+ Vector tmpByteArray = new Vector();
+
+ String nameString = t.getValue();
+ Debug.log(Debug.TRACE,"NameDefinitionEncoder : " + nameString);
+ tmpByteArray.add(new Byte((byte)t.getTokenID()));
+ Enumeration e = wb.getDefinedNames();
+ DefinedName dn;
+ String name;
+ int definedNameIndex = 0;
+ do {
+ dn = (DefinedName)e.nextElement();
+ name = dn.getName();
+ Debug.log(Debug.TRACE,"Name pulled from DefinedName : " + name);
+ definedNameIndex++;
+ } while(!nameString.equalsIgnoreCase(name) && e.hasMoreElements());
+
+ tmpByteArray.add(new Byte((byte)definedNameIndex));
+ tmpByteArray.add(new Byte((byte)0x00));
+
+ for(int i = 0;i < 12;i++) {
+ tmpByteArray.add(new Byte((byte)0x00));
+ }
+
+ return tmpByteArray;
+ }
+ /**
+ * A Cell Reference Encoder. It supports absolute and relative addressing
+ * but not sheetnames.
+ *
+ * @param t <code>Token</code> to be encoded
+ * @return A <code>Vector</code> of pexcel <code>Byte</code>
+ */
+ private Vector cellRefEncoder(Token t) {
+
+ Vector tmpByteArray = new Vector();
+
+ tmpByteArray.add(new Byte((byte)t.getTokenID()));
+ byte cellRefBytes[] = encodeCellCoordinates(t.getValue());
+ for(int i = 0;i < cellRefBytes.length;i++) {
+ tmpByteArray.add(new Byte(cellRefBytes[i]));
+ }
+ return tmpByteArray;
+ }
+
+ /**
+ * This function will find the sheetname index for a given String
+ *
+ * @param t <code>Token</code> to be encoded
+ * @return A <code>Vector</code> of pexcel <code>Byte</code>
+ */
+ private short findSheetIndex(String s) {
+
+ short sheetIndex = 0;
+ String savedName;
+ String sheetName;
+ if (s.startsWith("$")) {
+ sheetName = s.substring(1,s.length()); // Remove $
+ } else {
+ sheetName = s.substring(0,s.length());
+ }
+ Debug.log(Debug.TRACE,"Searching for Worksheet : " + sheetName);
+ Vector names = wb.getWorksheetNames();
+ Enumeration e = names.elements();
+ do {
+ savedName = (String) e.nextElement();
+ sheetIndex++;
+ } while(!savedName.equalsIgnoreCase(sheetName) && e.hasMoreElements());
+
+ Debug.log(Debug.TRACE,"Setting sheetindex to " + sheetIndex);
+ return (short)(sheetIndex-1);
+ }
+
+ /**
+ * A 3D Cell reference encoder
+ *
+ * @param t <code>Token</code> to be encoded
+ * @return A <code>Vector</code> of pexcel <code>Byte</code>
+ */
+ private Vector threeDCellRefEncoder(Token t) {
+
+ Vector tmpByteArray = new Vector();
+ parseString = t.getValue();
+ Debug.log(Debug.TRACE,"Encoding 3D Cell reference " + t);
+ tmpByteArray.add(new Byte((byte)t.getTokenID()));
+ tmpByteArray.add(new Byte((byte)0xFF));
+ tmpByteArray.add(new Byte((byte)0xFF));
+ for(int i = 0;i < 8;i++) {
+ tmpByteArray.add(new Byte((byte)0x00));
+ }
+
+ String sheetRef = parseString.substring(0, parseString.indexOf('.') + 1);
+ if (sheetRef.indexOf(':')!=-1) {
+ sheetRef = parseString.substring(0, parseString.indexOf(':'));
+ short sheetNum1 = findSheetIndex(sheetRef);
+ sheetRef = parseString.substring(parseString.indexOf(':') + 1, parseString.length());
+ short sheetNum2 = findSheetIndex(sheetRef);
+ tmpByteArray.add(new Byte((byte)sheetNum1));
+ tmpByteArray.add(new Byte((byte)0x00));
+ tmpByteArray.add(new Byte((byte)sheetNum2));
+ tmpByteArray.add(new Byte((byte)0x00));
+ } else {
+ sheetRef = parseString.substring(0, parseString.indexOf('.'));
+ short sheetNum = findSheetIndex(sheetRef);
+ tmpByteArray.add(new Byte((byte)sheetNum));
+ tmpByteArray.add(new Byte((byte)0x00));
+ tmpByteArray.add(new Byte((byte)sheetNum));
+ tmpByteArray.add(new Byte((byte)0x00));
+ }
+ String s = parseString.substring(parseString.indexOf('.') + 1, parseString.length());
+ Debug.log(Debug.TRACE,"Parsing : " + s);
+ byte cellRefBytes[] = encodeCellCoordinates(s);
+ for(int i = 0;i < cellRefBytes.length;i++) {
+ tmpByteArray.add(new Byte(cellRefBytes[i]));
+ }
+ return tmpByteArray;
+ }
+ /**
+ * A 3D Area Reference Encoder.
+ *
+ * @param t <code>Token</code> to be encoded
+ * @return A <code>Vector</code> of pexcel <code>Byte</code>
+ */
+ private Vector threeDAreaRefEncoder(Token t) {
+
+ Vector tmpByteArray = new Vector();
+ parseString = t.getValue();
+ Debug.log(Debug.TRACE,"Encoding 3D Area reference " + t);
+ tmpByteArray.add(new Byte((byte)t.getTokenID()));
+ tmpByteArray.add(new Byte((byte)0xFF));
+ tmpByteArray.add(new Byte((byte)0xFF));
+ for(int i = 0;i < 8;i++) {
+ tmpByteArray.add(new Byte((byte)0x00));
+ }
+
+ String param1= parseString.substring(0, parseString.indexOf(':'));
+ String cellRef1 = param1.substring(parseString.indexOf('.') + 1, param1.length());
+ String sheetRef1 = param1.substring(0, param1.indexOf('.'));
+ short sheetNum1 = findSheetIndex(sheetRef1);
+
+ String param2 = parseString.substring(parseString.indexOf(':') + 1, parseString.length());
+ Debug.log(Debug.TRACE,"param2: " + param2);
+ String cellRef2 = param2.substring(param2.indexOf('.') + 1, param2.length());
+ Debug.log(Debug.TRACE,"cellRef2: " + cellRef2);
+
+ if(param2.indexOf('.')==-1) {
+ tmpByteArray.add(new Byte((byte)sheetNum1));
+ tmpByteArray.add(new Byte((byte)0x00));
+ tmpByteArray.add(new Byte((byte)sheetNum1));
+ tmpByteArray.add(new Byte((byte)0x00));
+ } else {
+ String sheetRef2 = param2.substring(0, param2.indexOf('.'));
+ short sheetNum2 = findSheetIndex(sheetRef2);
+ tmpByteArray.add(new Byte((byte)sheetNum1));
+ tmpByteArray.add(new Byte((byte)0x00));
+ tmpByteArray.add(new Byte((byte)sheetNum2));
+ tmpByteArray.add(new Byte((byte)0x00));
+ }
+
+ byte cellRefBytes1[] = encodeCellCoordinates(cellRef1);
+ byte cellRefBytes2[] = encodeCellCoordinates(cellRef2);
+
+ tmpByteArray.add(new Byte(cellRefBytes1[0]));
+ tmpByteArray.add(new Byte(cellRefBytes1[1]));
+
+ tmpByteArray.add(new Byte(cellRefBytes2[0]));
+ tmpByteArray.add(new Byte(cellRefBytes2[1]));
+
+ tmpByteArray.add(new Byte(cellRefBytes1[2]));
+ tmpByteArray.add(new Byte(cellRefBytes2[2]));
+
+ return tmpByteArray;
+ }
+
+ /**
+ * A Cell Range Encoder.
+ *
+ * @param t <code>Token</code> to be encoded
+ * @return A <code>Vector</code> of pexcel <code>Byte</code>
+ */
+ private Vector areaRefEncoder(Token t) {
+
+ Vector tmpByteArray = new Vector();
+
+ tmpByteArray.add(new Byte((byte)t.getTokenID()));
+ String param = t.getValue();
+ String cellRef1 = new String();
+ String cellRef2 = new String();
+
+ if(param.indexOf(':')==-1) {
+ Debug.log(Debug.ERROR, "Invalid Cell Range, could not find :");
+ } else {
+ cellRef1 = param.substring(0, param.indexOf(':'));
+ cellRef2 = param.substring(param.indexOf(':') + 1, param.length());
+ }
+ byte cellRefBytes1[] = encodeCellCoordinates(cellRef1);
+ byte cellRefBytes2[] = encodeCellCoordinates(cellRef2);
+
+ tmpByteArray.add(new Byte(cellRefBytes1[0]));
+ tmpByteArray.add(new Byte(cellRefBytes1[1]));
+
+ tmpByteArray.add(new Byte(cellRefBytes2[0]));
+ tmpByteArray.add(new Byte(cellRefBytes2[1]));
+
+ tmpByteArray.add(new Byte(cellRefBytes1[2]));
+ tmpByteArray.add(new Byte(cellRefBytes2[2]));
+
+ return tmpByteArray;
+ }
+
+ /**
+ * A Function Encoder.
+ *
+ * @param t <code>Token</code> to be encoded
+ * @return A <code>Vector</code> of pexcel <code>Byte</code>
+ */
+ private Vector functionEncoder(Token t) {
+ Vector tmpByteArray = new Vector();
+
+ int id = t.getTokenID();
+ if(t.getTokenType()==ParseToken.TOKEN_FUNCTION_VARIABLE) {
+ tmpByteArray.add(new Byte((byte)TokenConstants.TFUNCVAR));
+ tmpByteArray.add(new Byte((byte)t.getNumArgs()));
+ } else {
+ tmpByteArray.add(new Byte((byte)TokenConstants.TFUNC));
+ }
+
+ tmpByteArray.add(new Byte((byte)id));
+ tmpByteArray.add(new Byte((byte)(id>>8)));
+ return tmpByteArray;
+ }
+
+
+}
diff --git a/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/TokenFactory.java b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/TokenFactory.java
new file mode 100644
index 000000000000..e745c7c0f970
--- /dev/null
+++ b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/TokenFactory.java
@@ -0,0 +1,118 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxc.pexcel.records.formula;
+
+import org.openoffice.xmerge.util.Debug;
+
+/**
+ * This is the Factory class responsible for creating a <code>Token</code>.
+ * It has three methods for returning three different types of Tokens
+ * (Operator, Operand and Function).
+ * This utility class is used by either the <code>FormulaParser</code> or the
+ * <code>FormulaDecoder</code>.
+ */
+public class TokenFactory {
+
+ private OperatorLookup operatorLookup;
+ private OperandLookup operandLookup;
+ private FunctionLookup fl;
+
+ /**
+ * Default Constructor
+ */
+ public TokenFactory() {
+ operatorLookup = new OperatorLookup();
+ operandLookup = new OperandLookup();
+ fl = new FunctionLookup();
+ }
+
+ /**
+ * The Factory method for creating function Tokens
+ *
+ * @return The created <code>Token</code>
+ */
+ public Token getFunctionToken(String s, int args) {
+ Token t = null;
+ // We will have to fix this later to include fixed function tokens
+ // Also will need to handle errors where functions names are incorrect???
+ Debug.log(Debug.TRACE,"TokenFactory creating function Token : " + s);
+ try {
+ t = new Token(s, ParseToken.TOKEN_FUNCTION_VARIABLE, fl.getIDFromString(s), args);
+ } catch (UnsupportedFunctionException eFn) {
+
+ Debug.log(Debug.ERROR, eFn.getMessage());
+ }
+ return t;
+ }
+
+ /**
+ * The Factory method for creating operator Tokens
+ *
+ * @return The created <code>Token</code>
+ */
+ public Token getOperatorToken(String s, int args) {
+
+ Token t = null;
+
+ Debug.log(Debug.TRACE,"TokenFactory creating operator Token : " + s);
+ try {
+ if(args==1) {
+ if(s.equals("+")) {
+ t = new Token(s, ParseToken.TOKEN_OPERATOR, operatorLookup.getIDFromString("UNARY_PLUS"), args);
+ } else if (s.equals("-")) {
+ t = new Token(s, ParseToken.TOKEN_OPERATOR, operatorLookup.getIDFromString("UNARY_MINUS"), args);
+ } else {
+ t = new Token(s, ParseToken.TOKEN_OPERATOR, operatorLookup.getIDFromString(s), args);
+ }
+ } else {
+ t = new Token(s, ParseToken.TOKEN_OPERATOR, operatorLookup.getIDFromString(s), args);
+ }
+ } catch (UnsupportedFunctionException eFn) {
+ Debug.log(Debug.ERROR, eFn.getMessage());
+ }
+ return t;
+ }
+
+ /**
+ * The Factory method for creating Operand Tokens
+ *
+ * @return The created <code>Token</code>
+ */
+ public Token getOperandToken(String s, String type) {
+ Token t = null;
+
+ Debug.log(Debug.TRACE,"TokenFactory creating operand (" + type + ") Token : " + s);
+ try {
+ t = new Token(s, ParseToken.TOKEN_OPERAND, operandLookup.getIDFromString(type), 0);
+ } catch (UnsupportedFunctionException eFn) {
+ Debug.log(Debug.ERROR, eFn.getMessage());
+ }
+
+ return t;
+ }
+}
diff --git a/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/UnsupportedFunctionException.java b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/UnsupportedFunctionException.java
new file mode 100644
index 000000000000..ca2794d3f73d
--- /dev/null
+++ b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/UnsupportedFunctionException.java
@@ -0,0 +1,40 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxc.pexcel.records.formula;
+
+/*
+ * Exception thrown when a function specified in a calc formula has no equivalent in Pocket Excel
+ *
+ * @author : Mike Hayes
+ */
+
+public class UnsupportedFunctionException extends Exception {
+ UnsupportedFunctionException(String message) {
+ super(message);
+ }
+}
diff --git a/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/package.html b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/package.html
new file mode 100644
index 000000000000..6239c2b5b625
--- /dev/null
+++ b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/package.html
@@ -0,0 +1,42 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+ <!--
+ #*************************************************************************
+ #
+ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+
+ Copyright 2000, 2010 Oracle and/or its affiliates.
+
+ OpenOffice.org - a multi-platform office productivity suite
+
+ This file is part of OpenOffice.org.
+
+ OpenOffice.org is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License version 3
+ only, as published by the Free Software Foundation.
+
+ OpenOffice.org is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License version 3 for more details
+ (a copy is included in the LICENSE file that accompanied this code).
+
+ You should have received a copy of the GNU Lesser General Public License
+ version 3 along with OpenOffice.org. If not, see
+ <http://www.openoffice.org/license.html>
+ for a copy of the LGPLv3 License.
+
+ #*************************************************************************
+ -->
+
+ <title>org.openoffice.xmerge.converter.xml.sxc.pexcel.records.formula package</title>
+
+</head>
+ <body bgcolor="white">
+
+<p> This package contains the classes necessary for converting pexcel formula
+to and from StarCalc Formula.</p>
+
+</body>
+</html>
diff --git a/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/package.html b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/package.html
new file mode 100644
index 000000000000..ef06a251cfaa
--- /dev/null
+++ b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/package.html
@@ -0,0 +1,47 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+ <!--
+ #*************************************************************************
+ #
+ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+
+ Copyright 2000, 2010 Oracle and/or its affiliates.
+
+ OpenOffice.org - a multi-platform office productivity suite
+
+ This file is part of OpenOffice.org.
+
+ OpenOffice.org is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License version 3
+ only, as published by the Free Software Foundation.
+
+ OpenOffice.org is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License version 3 for more details
+ (a copy is included in the LICENSE file that accompanied this code).
+
+ You should have received a copy of the GNU Lesser General Public License
+ version 3 along with OpenOffice.org. If not, see
+ <http://www.openoffice.org/license.html>
+ for a copy of the LGPLv3 License.
+
+ #*************************************************************************
+ -->
+
+ <title>org.openoffice.xmerge.converter.xml.sxc.pexcel.records package</title>
+
+</head>
+ <body bgcolor="white">
+
+<p> This package contains the objects that represent BIFF Records for the
+pocket excel format. Each one implements the BIFF Record abstract class which
+contains three basic functions (read, write and getBiffType). BIFF Records
+which are not used do not contain setter's or getter's for their member
+variables as some records have a large number of variables. It should be up
+to the implementer which attributes get set and which get set to default
+values.</p>
+
+</body>
+</html>
diff --git a/xmerge/source/pexcel/makefile.mk b/xmerge/source/pexcel/makefile.mk
new file mode 100644
index 000000000000..7f51a43e7530
--- /dev/null
+++ b/xmerge/source/pexcel/makefile.mk
@@ -0,0 +1,35 @@
+#*************************************************************************
+#
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# Copyright 2000, 2010 Oracle and/or its affiliates.
+#
+# OpenOffice.org - a multi-platform office productivity suite
+#
+# This file is part of OpenOffice.org.
+#
+# OpenOffice.org is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License version 3
+# only, as published by the Free Software Foundation.
+#
+# OpenOffice.org is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License version 3 for more details
+# (a copy is included in the LICENSE file that accompanied this code).
+#
+# You should have received a copy of the GNU Lesser General Public License
+# version 3 along with OpenOffice.org. If not, see
+# <http://www.openoffice.org/license.html>
+# for a copy of the LGPLv3 License.
+#
+#*************************************************************************
+
+TARGET=pexcel
+PRJ=../..
+PRJNAME=xmerge
+
+.INCLUDE : ant.mk
+.IF "$(L10N_framework)"==""
+ALLTAR: ANTBUILD
+.ENDIF
diff --git a/xmerge/source/pocketword/build.xml b/xmerge/source/pocketword/build.xml
new file mode 100644
index 000000000000..51b198c329af
--- /dev/null
+++ b/xmerge/source/pocketword/build.xml
@@ -0,0 +1,76 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ #*************************************************************************
+ #
+ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+
+ Copyright 2000, 2010 Oracle and/or its affiliates.
+
+ OpenOffice.org - a multi-platform office productivity suite
+
+ This file is part of OpenOffice.org.
+
+ OpenOffice.org is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License version 3
+ only, as published by the Free Software Foundation.
+
+ OpenOffice.org is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License version 3 for more details
+ (a copy is included in the LICENSE file that accompanied this code).
+
+ You should have received a copy of the GNU Lesser General Public License
+ version 3 along with OpenOffice.org. If not, see
+ <http://www.openoffice.org/license.html>
+ for a copy of the LGPLv3 License.
+
+ #*************************************************************************
+ -->
+
+<project name="pocketword" default="all" basedir=".">
+
+ <property file="../inc/antbuild.properties"/>
+
+ <path id="classpath">
+ <pathelement location="${build.dir}/xmerge.jar"/>
+ </path>
+
+
+ <target name="init" >
+ <mkdir dir="${target.dir}"/>
+ </target>
+
+ <!-- compile java sources in ${package} -->
+ <target name="compile" depends="init">
+ <javac srcdir="${src.dir}"
+ destdir="${target.dir}"
+ debug="${debug}"
+ deprecation="${deprecation}"
+ optimize="${optimize}">
+ <classpath refid="classpath"/>
+ </javac>
+ </target>
+
+ <!-- package to jar -->
+ <target name="jar" depends="compile">
+ <jar destfile="${target.jar}">
+ <fileset dir="${target.dir}"
+ includes="**/*.class" />
+ <metainf dir="${basedir}">
+ <filename name="converter.xml"/>
+ </metainf>
+ </jar>
+ </target>
+
+ <!-- clean up -->
+ <target name="clean">
+ <delete dir="${class.dir}"/>
+ <delete file="${target.jar}"/>
+ </target>
+
+ <target name="all" depends="jar">
+ </target>
+
+</project>
+
diff --git a/xmerge/source/pocketword/converter.xml b/xmerge/source/pocketword/converter.xml
new file mode 100644
index 000000000000..56fcebfba6b1
--- /dev/null
+++ b/xmerge/source/pocketword/converter.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+ #*************************************************************************
+ #
+ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+
+ Copyright 2000, 2010 Oracle and/or its affiliates.
+
+ OpenOffice.org - a multi-platform office productivity suite
+
+ This file is part of OpenOffice.org.
+
+ OpenOffice.org is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License version 3
+ only, as published by the Free Software Foundation.
+
+ OpenOffice.org is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License version 3 for more details
+ (a copy is included in the LICENSE file that accompanied this code).
+
+ You should have received a copy of the GNU Lesser General Public License
+ version 3 along with OpenOffice.org. If not, see
+ <http://www.openoffice.org/license.html>
+ for a copy of the LGPLv3 License.
+
+ #*************************************************************************
+ -->
+
+
+<converters>
+ <converter type="staroffice/sxw" version="1.1">
+ <converter-display-name>
+ Pocket Word
+ </converter-display-name>
+ <converter-description>
+ OpenOffice Writer XML to/from Pocket Word conversion.
+ </converter-description>
+ <converter-vendor>
+ OpenOffice.org
+ </converter-vendor>
+ <converter-class-impl>
+ org.openoffice.xmerge.converter.xml.sxw.pocketword.PluginFactoryImpl
+ </converter-class-impl>
+ <converter-target type="application/x-pocket-word"/>
+ </converter>
+</converters>
+
diff --git a/xmerge/source/pocketword/java/org/openoffice/xmerge/converter/xml/sxw/pocketword/ConverterCapabilitiesImpl.java b/xmerge/source/pocketword/java/org/openoffice/xmerge/converter/xml/sxw/pocketword/ConverterCapabilitiesImpl.java
new file mode 100644
index 000000000000..13437cc7bb7c
--- /dev/null
+++ b/xmerge/source/pocketword/java/org/openoffice/xmerge/converter/xml/sxw/pocketword/ConverterCapabilitiesImpl.java
@@ -0,0 +1,93 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxw.pocketword;
+
+import org.openoffice.xmerge.ConverterCapabilities;
+import org.openoffice.xmerge.converter.xml.OfficeConstants;
+
+/**
+ * <p>PocketWord implementation of <code>ConverterCapabilities</code> for
+ * the {@link
+ * org.openoffice.xmerge.converter.xml.sxw.pocketword.PluginFactoryImpl
+ * PluginFactoryImpl}.</p>
+ *
+ * <p>Used with StarWriter XML to/from PocketWord conversions. The
+ * <code>ConverterCapibilies</code> specify which &quot;Office&quot;
+ * <code>Document</code> tags and attributes are supported on the
+ * &quot;Device&quot; <code>Document</code> format.</p>
+ */
+public final class ConverterCapabilitiesImpl
+ implements ConverterCapabilities {
+
+ public boolean canConvertTag(String tag) {
+
+ if (OfficeConstants.TAG_OFFICE_DOCUMENT.equals(tag))
+ return true;
+ else if (OfficeConstants.TAG_OFFICE_DOCUMENT_CONTENT.equals(tag))
+ return true;
+ else if (OfficeConstants.TAG_OFFICE_BODY.equals(tag))
+ return true;
+ else if (OfficeConstants.TAG_PARAGRAPH.equals(tag))
+ return true;
+ else if (OfficeConstants.TAG_HEADING.equals(tag))
+ return true;
+ else if (OfficeConstants.TAG_ORDERED_LIST.equals(tag))
+ return true;
+ else if (OfficeConstants.TAG_UNORDERED_LIST.equals(tag))
+ return true;
+ else if (OfficeConstants.TAG_LIST_ITEM.equals(tag))
+ return true;
+ else if (OfficeConstants.TAG_LIST_HEADER.equals(tag))
+ return true;
+ else if (OfficeConstants.TAG_SPAN.equals(tag))
+ return true;
+ else if (OfficeConstants.TAG_HYPERLINK.equals(tag))
+ return true;
+ else if (OfficeConstants.TAG_LINE_BREAK.equals(tag))
+ return true;
+ else if (OfficeConstants.TAG_SPACE.equals(tag))
+ return true;
+ else if (OfficeConstants.TAG_TAB_STOP.equals(tag))
+ return true;
+
+ return false;
+ }
+
+ public boolean canConvertAttribute(String tag,
+ String attribute) {
+
+ if (OfficeConstants.TAG_SPACE.equals(tag)) {
+
+ if (OfficeConstants.ATTRIBUTE_SPACE_COUNT.equals(attribute))
+ return true;
+ }
+
+ return false;
+ }
+}
+
diff --git a/xmerge/source/pocketword/java/org/openoffice/xmerge/converter/xml/sxw/pocketword/DocumentDescriptor.java b/xmerge/source/pocketword/java/org/openoffice/xmerge/converter/xml/sxw/pocketword/DocumentDescriptor.java
new file mode 100644
index 000000000000..5e2f8a06e3a0
--- /dev/null
+++ b/xmerge/source/pocketword/java/org/openoffice/xmerge/converter/xml/sxw/pocketword/DocumentDescriptor.java
@@ -0,0 +1,235 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxw.pocketword;
+
+import org.openoffice.xmerge.util.EndianConverter;
+
+import java.io.ByteArrayOutputStream;
+import java.io.OutputStream;
+import java.io.IOException;
+
+import java.util.Vector;
+
+
+/**
+ * This class to represent the data structure stored by a Pocket Word file that
+ * describes that file.
+ *
+ * The data structure is of variable length, beginning at the end of the
+ * font declarations and ending 10 bytes before the first instance of 0xFF 0xFF
+ * marking a paragraph block.
+ *
+ * The variable length component arises from an 8 byte structure describing each
+ * paragraph in the document. These paragraph descriptors appear at the end
+ * of the Document Descriptor.
+ *
+ * @author Mark Murnane
+ * @version 1.1
+ */
+class DocumentDescriptor {
+ private short numParagraphs = 0;
+ private short length = 0;
+ private short numLines = 0;
+
+ private Vector paragraphDesc = null;
+
+ DocumentDescriptor() {
+ paragraphDesc = new Vector(0, 1);
+ }
+
+
+
+ /**
+ * Updates the <code>DocumentDescriptor</code> to include details of another
+ * paragraph in the document.
+ *
+ * @param len The number of characters in the paragraph.
+ * @param lines The number of lines on screen that the paragraph uses.
+ */
+ public void addParagraph(short len, short lines) {
+ ParagraphDescriptor pd = new ParagraphDescriptor(len, lines);
+
+ paragraphDesc.add(pd);
+ numParagraphs++;
+ numLines += lines;
+ length += pd.length;
+ }
+
+
+ /**
+ * Retrieve the <code>DocumentDescriptor's</code> data. Due to the variable
+ * length nature of the descriptor, certain fields can only be
+ * calculated/written after the addition of all paragraphs.
+ *
+ * @return Byte array containing the Pocket Word representation of this
+ * <code>DocumentDescriptor</code>.
+ */
+ public byte[] getDescriptor () {
+ ByteArrayOutputStream descStream = new ByteArrayOutputStream();
+
+ writeHeader(descStream);
+
+ /*
+ * This value seems to increment by 0x02 for each paragraph.
+ * For a single paragraph doc, the value is 0x08, 0x0A for two,
+ * 0x0C for three ...
+ */
+ try {
+ descStream.write(EndianConverter.writeShort((short)(6 +
+ (numParagraphs * 2))));
+
+ descStream.write(EndianConverter.writeShort(numParagraphs));
+ descStream.write(EndianConverter.writeShort((short)0));
+ descStream.write(EndianConverter.writeShort(numParagraphs));
+
+ descStream.write(EndianConverter.writeShort((short)0));
+ descStream.write(EndianConverter.writeShort((short)length));
+ descStream.write(EndianConverter.writeShort((short)0));
+
+ descStream.write(EndianConverter.writeShort(numLines));
+ descStream.write(new byte[] { 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00 } );
+
+ for (int i = 0; i < paragraphDesc.size(); i++) {
+ ParagraphDescriptor pd = (ParagraphDescriptor)paragraphDesc.elementAt(i);
+
+ descStream.write(pd.getDescriptor());
+ }
+
+ // Byte sequence marking the end of this DocumentDescriptor
+ descStream.write(EndianConverter.writeShort((short)0));
+ descStream.write(EndianConverter.writeShort((short)0x41));
+ }
+ catch (IOException ioe) {
+ // Should never happen as this is a memory based stream.
+ }
+
+ return descStream.toByteArray();
+ }
+
+
+ /*
+ * This method loads the intial fixed portion of the descriptor and the
+ * mid-section. The mid-section is variable but Pocket Word doesn't seem
+ * to mind default values.
+ */
+ private void writeHeader(OutputStream descStream) {
+
+ try {
+ descStream.write(new byte[] { 0x00, 0x00, 0x00, 0x00,
+ 0x07, 0x00, 0x06, 0x00,
+ 0x15, 0x00, 0x10, 0x00,
+ 0x01, 0x00, (byte)0xD0, 0x2F,
+ 0x00, 0x00, (byte)0xE0, 0x3D,
+ 0x00, 0x00, (byte)0xF0, 0x00,
+ 0x00, 0x00, (byte)0xA0, 0x05,
+ 0x00, 0x00, (byte)0xA0, 0x05,
+ 0x00, 0x00, (byte)0xA0, 0x05,
+ 0x00, 0x00, (byte)0xA0, 0x05,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x0A, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x04, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x0A, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x04, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x08, 0x00,
+ 0x07, 0x00, 0x10, 0x00,
+ 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x12, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x1F, 0x04, 0x00, 0x00 } );
+
+ /*
+ * The next four bytes are variable, but a pattern hasn't yet been
+ * established. Pocket Word seems to accept this constant value.
+ *
+ * The bytes are repeated after another 12 byte sequence which does
+ * not seem to change from one file to the next.
+ */
+ descStream.write(new byte[] { (byte)0xE2, 0x02, 0x00, 0x00 } );
+ descStream.write(new byte[] { 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x3D, 0x04, 0x00, 0x00 } );
+ descStream.write(new byte[] { (byte)0xE2, 0x02, 0x00, 0x00 } );
+
+ descStream.write(new byte[] { 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x40, 0x00, 0x08, 0x00 } );
+ }
+ catch (IOException ioe) {
+ /* Shouldn't happen with a ByteArrayOutputStream */
+ }
+ }
+
+
+ /**
+ * <code>ParagraphDescriptor</code> represents the data structure used to
+ * describe individual paragraphs within a <code>DocumentDescriptor.</code>
+ *
+ * It is used solely by the <code>DocumentDescriptor<code> class.
+ */
+ private class ParagraphDescriptor {
+ private short filler = 0;
+ private short lines = 0;
+ private short length = 0;
+ private short unknown = 0x23;
+
+ public ParagraphDescriptor(short len, short numLines) {
+ lines = numLines;
+ length = (short)(len + 1);
+ }
+
+ public byte[] getDescriptor() {
+ ByteArrayOutputStream desc = new ByteArrayOutputStream();
+
+ try {
+ desc.write(EndianConverter.writeShort(filler));
+ desc.write(EndianConverter.writeShort(lines));
+ desc.write(EndianConverter.writeShort(length));
+ desc.write(EndianConverter.writeShort(unknown));
+ }
+ catch (IOException ioe) {
+ /* Should never happen */
+ }
+
+ return desc.toByteArray();
+ }
+ }
+} \ No newline at end of file
diff --git a/xmerge/source/pocketword/java/org/openoffice/xmerge/converter/xml/sxw/pocketword/DocumentDeserializerImpl.java b/xmerge/source/pocketword/java/org/openoffice/xmerge/converter/xml/sxw/pocketword/DocumentDeserializerImpl.java
new file mode 100644
index 000000000000..6d7873cca96b
--- /dev/null
+++ b/xmerge/source/pocketword/java/org/openoffice/xmerge/converter/xml/sxw/pocketword/DocumentDeserializerImpl.java
@@ -0,0 +1,294 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxw.pocketword;
+
+import org.openoffice.xmerge.ConvertData;
+import org.openoffice.xmerge.ConvertException;
+import org.openoffice.xmerge.Document;
+import org.openoffice.xmerge.DocumentDeserializer;
+
+import org.openoffice.xmerge.converter.xml.OfficeConstants;
+import org.openoffice.xmerge.converter.xml.sxw.SxwDocument;
+
+import org.openoffice.xmerge.converter.xml.ParaStyle;
+import org.openoffice.xmerge.converter.xml.TextStyle;
+import org.openoffice.xmerge.converter.xml.StyleCatalog;
+
+import org.openoffice.xmerge.util.OfficeUtil;
+
+import java.io.IOException;
+
+import java.util.Enumeration;
+import java.util.Vector;
+
+import org.w3c.dom.NodeList;
+import org.w3c.dom.Node;
+import org.w3c.dom.Element;
+
+
+/**
+ * <p>Pocket Word implementation of <code>DocumentDeserializer</code>
+ * for the {@link
+ * org.openoffice.xmerge.converter.xml.sxw.pocketword.PluginFactoryImpl
+ * PluginFactoryImpl}.</p>
+ *
+ * <p>This converts a Pocket Word file to an OpenOffice Writer XML DOM.</p>
+ *
+ * @author Mark Murnane
+ * @version 1.1
+ */
+public final class DocumentDeserializerImpl
+ implements DocumentDeserializer, OfficeConstants {
+
+ private PocketWordDocument pswDoc = null;
+ private SxwDocument sxwDoc = null;
+ private String docName;
+
+ private StyleCatalog styleCat = null;
+
+
+ /**
+ * Initialises a new <code>DocumentDeserializerImpl</code> using the
+ * supplied <code>ConvertData</code>.</p>
+ *
+ * <p>The <code>Document</code> objects in the <code>ConvertData</code>
+ * should be {@link
+ * org.openoffice.xmerge.converter.xml.sxw.pocketword.PocketWordDocument
+ * PocketWordDocument} objects.</p>
+ *
+ * @param cd ConvertData containing a <code>PocketWordDocument</code>
+ * for conversion.
+ */
+ public DocumentDeserializerImpl(ConvertData cd) {
+ Enumeration e = cd.getDocumentEnumeration();
+
+ // A Pocket Word file is composed of one binary file
+ while (e.hasMoreElements()) {
+ pswDoc = (PocketWordDocument)e.nextElement();
+ }
+
+ docName = pswDoc.getName();
+ }
+
+
+ /**
+ * <p>Convert the data passed into the <code>DocumentDeserializer</code>
+ * constructor into the OpenOffice Writer <code>Document</code>
+ * format.</p>
+ *
+ * <p>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.</p>
+ *
+ * @return The resulting <code>Document</code> object from conversion.
+ *
+ * @throws ConvertException If any Convert error occurs.
+ * @throws IOException If any I/O error occurs.
+ */
+ public Document deserialize() throws IOException, ConvertException {
+ Enumeration pe = pswDoc.getParagraphEnumeration();
+
+ sxwDoc = new SxwDocument (docName);
+ sxwDoc.initContentDOM();
+
+ // Default to an initial 5 entries in the catalog.
+ styleCat = new StyleCatalog(5);
+
+ try {
+ buildDocument(pe);
+ }
+ catch (Exception e) {
+ e.printStackTrace();
+ throw new ConvertException("Error building OpenOffice Writer DOM: "
+ + e.toString());
+
+ }
+
+ return sxwDoc;
+ }
+
+
+ /**
+ * This method actually takes care of the conversion.
+ *
+ * @param data An Enumeration of all Paragraphs in the Pocket Word doc.
+ *
+ * @return The OpenOffice Writer XML representation of the data.
+ *
+ * @throws IOException If any I/O errors occur.
+ */
+ private void buildDocument(Enumeration data) throws IOException {
+
+ org.w3c.dom.Document doc = sxwDoc.getContentDOM();
+
+ /*
+ * There should be only one each of office:body and
+ * office:automatic-styles in each document.
+ */
+ Node bodyNode = doc.getElementsByTagName(TAG_OFFICE_BODY).item(0);
+
+ // Not every document has an automatic style tag
+ Node autoStylesNode = doc.getElementsByTagName(
+ TAG_OFFICE_AUTOMATIC_STYLES).item(0);
+ if (autoStylesNode == null) {
+ autoStylesNode = doc.createElement(TAG_OFFICE_AUTOMATIC_STYLES);
+ doc.insertBefore(autoStylesNode, bodyNode);
+ }
+
+
+ // Needed for naming new styles
+ int paraStyles = 1;
+ int textStyles = 1;
+
+ // Pocket Word has no concept of a list.
+ Element listNode = null;
+
+
+ // Down to business ...
+ while (data.hasMoreElements()) {
+ Paragraph p = (Paragraph)data.nextElement();
+ Element paraNode = doc.createElement(TAG_PARAGRAPH);
+
+ // Set paragraph style information here
+ ParaStyle pStyle = p.makeStyle();
+ if (pStyle == null) {
+ paraNode.setAttribute(ATTRIBUTE_TEXT_STYLE_NAME,
+ PocketWordConstants.DEFAULT_STYLE);
+ }
+ else {
+ // Create paragraph style
+ pStyle.setName(new String("PS" + paraStyles++));
+ paraNode.setAttribute(ATTRIBUTE_TEXT_STYLE_NAME, pStyle.getName());
+ styleCat.add(pStyle);
+ }
+
+
+ /*
+ * For each of the paragraphs, process each segment.
+ * There will always be at least one.
+ */
+ Enumeration paraData = p.getSegmentsEnumerator();
+ Vector textSpans = new Vector(0, 1);
+
+ do {
+ ParagraphTextSegment pts = (ParagraphTextSegment)paraData.nextElement();
+ Element span = doc.createElement(OfficeConstants.TAG_SPAN);
+
+ TextStyle ts = pts.getStyle();
+
+ if (ts != null) {
+ ts.setName(new String("TS" + textStyles++));
+ span.setAttribute(ATTRIBUTE_TEXT_STYLE_NAME, ts.getName());
+ styleCat.add(ts);
+ }
+ else {
+ span.setAttribute(ATTRIBUTE_TEXT_STYLE_NAME,
+ PocketWordConstants.DEFAULT_STYLE);
+ }
+
+ // If this isn't a blank paragraph
+ if (pts.getText() != null && !pts.getText().equals("")) {
+ Node[] children = OfficeUtil.parseText(pts.getText(), doc);
+
+ for (int j = 0; j < children.length; j++) {
+ span.appendChild(children[j]);
+ }
+ }
+
+ textSpans.add(span);
+
+ } while (paraData.hasMoreElements());
+
+
+ /*
+ * Special case for the first span. If it has no style, then
+ * it shouldn't be a span, so just add its children with style
+ * set as standard.
+ */
+ Element firstSpan = (Element)textSpans.elementAt(0);
+ String styleName = firstSpan.getAttribute(ATTRIBUTE_TEXT_STYLE_NAME);
+ if (styleName.equals(PocketWordConstants.DEFAULT_STYLE)) {
+ NodeList nl = firstSpan.getChildNodes();
+ int len = nl.getLength();
+
+ for (int i = 0; i < len; i++) {
+ /*
+ * Always take item 0 as the DOM tree event model will
+ * cause the NodeList to shrink as each Node is reparented.
+ *
+ * By taking the first item from the list, we essentially
+ * traverse the list in order.
+ */
+ paraNode.appendChild(nl.item(0));
+ }
+ }
+ else {
+ paraNode.appendChild(firstSpan);
+ }
+
+ // The rest are spans, so just add them
+ for (int i = 1; i < textSpans.size(); i++) {
+ paraNode.appendChild((Node)textSpans.elementAt(i));
+ }
+
+
+ /*
+ * Pocket Word doesn't support lists, but it does have bulleted
+ * paragraphs that are essentially the same thing.
+ *
+ * Unlike OpenOffice Writer, a blank paragraph can be bulleted
+ * as well. This will be handled by inserting a blank paragraph
+ * into the unordered list, but OpenOffice Writer will not display
+ * an item at that point in the list.
+ */
+ if (p.isBulleted()) {
+ if (listNode == null) {
+ listNode = doc.createElement(TAG_UNORDERED_LIST);
+ }
+ Element listItem = doc.createElement(TAG_LIST_ITEM);
+ listItem.appendChild(paraNode);
+ listNode.appendChild(listItem);
+ }
+ else {
+ if (listNode != null) {
+ bodyNode.appendChild(listNode);
+ listNode = null;
+ }
+ bodyNode.appendChild(paraNode);
+ }
+ } // End processing paragraphs
+
+
+ // Now write the style catalog to the document
+ NodeList nl = styleCat.writeNode(doc, "dummy").getChildNodes();
+ int nlLen = nl.getLength(); // nl.item reduces the length
+ for (int i = 0; i < nlLen; i++) {
+ autoStylesNode.appendChild(nl.item(0));
+ }
+ }
+}
diff --git a/xmerge/source/pocketword/java/org/openoffice/xmerge/converter/xml/sxw/pocketword/DocumentMergerImpl.java b/xmerge/source/pocketword/java/org/openoffice/xmerge/converter/xml/sxw/pocketword/DocumentMergerImpl.java
new file mode 100644
index 000000000000..e3d09b5c2bcc
--- /dev/null
+++ b/xmerge/source/pocketword/java/org/openoffice/xmerge/converter/xml/sxw/pocketword/DocumentMergerImpl.java
@@ -0,0 +1,97 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxw.pocketword;
+
+import org.w3c.dom.Document;
+
+import org.openoffice.xmerge.DocumentMerger;
+import org.openoffice.xmerge.MergeException;
+import org.openoffice.xmerge.ConverterCapabilities;
+import org.openoffice.xmerge.converter.xml.sxw.SxwDocument;
+import org.openoffice.xmerge.merger.DiffAlgorithm;
+import org.openoffice.xmerge.merger.Difference;
+import org.openoffice.xmerge.merger.NodeMergeAlgorithm;
+import org.openoffice.xmerge.merger.Iterator;
+import org.openoffice.xmerge.merger.diff.ParaNodeIterator;
+import org.openoffice.xmerge.merger.diff.IteratorLCSAlgorithm;
+import org.openoffice.xmerge.merger.merge.DocumentMerge;
+import org.openoffice.xmerge.merger.merge.CharacterBaseParagraphMerge;
+import org.openoffice.xmerge.util.Debug;
+
+
+/**
+ * PocketWord implementation of <code>DocumentMerger</code>
+ * for the {@link
+ * org.openoffice.xmerge.converter.xml.sxw.pocketword.PluginFactoryImpl
+ * PluginFactoryImpl}.</p>
+ */
+public class DocumentMergerImpl implements DocumentMerger {
+
+ private ConverterCapabilities cc_;
+ private org.openoffice.xmerge.Document orig = null;
+
+ public DocumentMergerImpl(org.openoffice.xmerge.Document doc, ConverterCapabilities cc) {
+ cc_ = cc;
+ this.orig = doc;
+ }
+
+ public void merge(org.openoffice.xmerge.Document modifiedDoc) throws MergeException {
+
+ SxwDocument wdoc1 = (SxwDocument) orig;
+ SxwDocument wdoc2 = (SxwDocument) modifiedDoc;
+
+ Document doc1 = wdoc1.getContentDOM();
+ Document doc2 = wdoc2.getContentDOM();
+
+ Iterator i1 = new ParaNodeIterator(cc_, doc1.getDocumentElement());
+ Iterator i2 = new ParaNodeIterator(cc_, doc2.getDocumentElement());
+
+ DiffAlgorithm diffAlgo = new IteratorLCSAlgorithm();
+
+ // find out the paragrah level diffs
+ Difference[] diffTable = diffAlgo.computeDiffs(i1, i2);
+
+ if (Debug.isFlagSet(Debug.INFO)) {
+ Debug.log(Debug.INFO, "Diff Result: ");
+
+ for (int i = 0; i < diffTable.length; i++) {
+ Debug.log(Debug.INFO, diffTable[i].debug());
+ }
+ }
+
+ // merge the paragraphs
+ NodeMergeAlgorithm charMerge = new CharacterBaseParagraphMerge();
+ DocumentMerge docMerge = new DocumentMerge(cc_, charMerge);
+
+ Iterator result = null;
+
+ docMerge.applyDifference(i1, i2, diffTable);
+ }
+}
+
+
diff --git a/xmerge/source/pocketword/java/org/openoffice/xmerge/converter/xml/sxw/pocketword/DocumentSerializerImpl.java b/xmerge/source/pocketword/java/org/openoffice/xmerge/converter/xml/sxw/pocketword/DocumentSerializerImpl.java
new file mode 100644
index 000000000000..08424a073803
--- /dev/null
+++ b/xmerge/source/pocketword/java/org/openoffice/xmerge/converter/xml/sxw/pocketword/DocumentSerializerImpl.java
@@ -0,0 +1,433 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxw.pocketword;
+
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.w3c.dom.NamedNodeMap;
+
+import org.openoffice.xmerge.ConvertData;
+import org.openoffice.xmerge.ConvertException;
+import org.openoffice.xmerge.Document;
+import org.openoffice.xmerge.DocumentSerializer;
+
+import org.openoffice.xmerge.converter.xml.OfficeConstants;
+import org.openoffice.xmerge.converter.xml.sxw.SxwDocument;
+
+import org.openoffice.xmerge.converter.xml.ParaStyle;
+import org.openoffice.xmerge.converter.xml.TextStyle;
+import org.openoffice.xmerge.converter.xml.StyleCatalog;
+
+import java.io.IOException;
+
+
+/**
+ * <p>Pocket Word implementation of <code>DocumentDeserializer</code>
+ * for use by {@link
+ * org.openoffice.xmerge.converter.xml.sxw.pocketword.PluginFactoryImpl
+ * PluginFactoryImpl}.</p>
+ *
+ * <p>This converts an OpenOffice Writer XML files to a Pocket Word file<.</p>
+ *
+ * @author Mark Murnane
+ * @version 1.1
+ */
+public final class DocumentSerializerImpl
+ implements DocumentSerializer, OfficeConstants {
+
+ private PocketWordDocument pswDoc;
+ private SxwDocument sxwDoc;
+
+ private StyleCatalog styleCat = null;
+
+ private boolean inList = false;
+
+
+ /**
+ * <p>Initialises a new <code>DocumentSerializerImpl</code> using the.<br>
+ * supplied <code>Document</code></p>
+ *
+ * <p>The supplied document should be an {@link
+ * org.openoffice.xmerge.converter.xml.sxw.SxwDocument SxwDocument}
+ * object.</p>
+ *
+ * @param document The <code>Document</code> to convert.
+ */
+ public DocumentSerializerImpl(Document doc) {
+ sxwDoc = (SxwDocument)doc;
+ pswDoc = new PocketWordDocument(sxwDoc.getName());
+ }
+
+
+ /**
+ * <p>Convert the data passed into the <code>DocumentSerializerImpl</code>
+ * constructor into Pocket Word format.</p>
+ *
+ * <p>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.</p>
+ *
+ * @return <code>ConvertData</code> object to pass back the
+ * converted data.
+ *
+ * @throws ConvertException If any conversion error occurs.
+ * @throws IOException If any I/O error occurs.
+ */
+ public ConvertData serialize() throws IOException, ConvertException {
+ ConvertData cd = new ConvertData();
+
+ org.w3c.dom.Document doc = sxwDoc.getContentDOM();
+
+ // Load any style info before traversing the document content tree
+ loadStyles();
+
+ NodeList list = doc.getElementsByTagName(TAG_OFFICE_BODY);
+
+ int len = list.getLength();
+ if (len > 0) {
+ Node node = list.item(0);
+ traverseBody(node);
+ }
+
+ cd.addDocument(pswDoc);
+
+ return cd;
+ }
+
+
+ /*
+ * Handles the loading of defined styles from the style.xml file as well
+ * as automatic styles from the content.xml file.
+ *
+ * Any change to a defined style, such as a short bold section, falls into
+ * the latter category.
+ */
+ private void loadStyles() {
+ org.w3c.dom.Document contentDom = sxwDoc.getContentDOM();
+ org.w3c.dom.Document styleDom = sxwDoc.getStyleDOM();
+
+ styleCat = new StyleCatalog(25);
+
+ NodeList nl = null;
+ String families[] = new String[] { PocketWordConstants.TEXT_STYLE_FAMILY,
+ PocketWordConstants.PARAGRAPH_STYLE_FAMILY,
+ PocketWordConstants.PARAGRAPH_STYLE_FAMILY };
+ Class classes[] = new Class[] { TextStyle.class,
+ ParaStyle.class,
+ TextStyle.class };
+
+ String[] styleTypes = new String[] { TAG_OFFICE_STYLES,
+ TAG_OFFICE_AUTOMATIC_STYLES,
+ TAG_OFFICE_MASTER_STYLES };
+
+ /*
+ * Documents converted from PSW -> SXW will not have a style.xml when
+ * being converted back to PSW. This would occur if a document was
+ * not modified within Writer between conversions.
+ *
+ * Any Writer modifications and saves create the style.xml and other
+ * portions of a complete Writer SXW file.
+ */
+ if (styleDom != null) {
+ // Process the Style XML tree
+ for (int i = 0; i < styleTypes.length; i++ ) {
+ nl = styleDom.getElementsByTagName(styleTypes[i]);
+ if (nl.getLength() != 0) {
+ styleCat.add(nl.item(0), families, classes, null, false);
+ }
+ }
+ }
+
+ /*
+ * Process the content XML for any other style info.
+ * Should only be automatic types here.
+ */
+ for (int i = 0; i < styleTypes.length; i++ ) {
+ nl = contentDom.getElementsByTagName(styleTypes[i]);
+ if (nl.getLength() != 0) {
+ styleCat.add(nl.item(0), families, classes, null, false);
+ }
+ }
+ }
+
+
+ /*
+ * Process the office:body tag.
+ */
+ private void traverseBody(Node node) throws IOException, ConvertException {
+
+ if (node.hasChildNodes()) {
+ NodeList nList = node.getChildNodes();
+ int len = nList.getLength();
+
+ for (int i = 0; i < len; i++) {
+ Node child = nList.item(i);
+
+ if (child.getNodeType() == Node.ELEMENT_NODE) {
+ String nodeName = child.getNodeName();
+
+ if (nodeName.equals(TAG_PARAGRAPH)
+ || nodeName.equals(TAG_HEADING)) {
+ traverseParagraph(child);
+ }
+
+ if (nodeName.equals(TAG_UNORDERED_LIST) ||
+ nodeName.equals(TAG_ORDERED_LIST)) {
+ traverseList(child);
+ }
+ }
+ }
+ }
+ }
+
+
+ /*
+ * Process a text:p tag
+ */
+ private void traverseParagraph(Node node) throws IOException, ConvertException {
+ String styleName = getAttribute(node, ATTRIBUTE_TEXT_STYLE_NAME);
+
+ ParaStyle pstyle = (ParaStyle)styleCat.lookup(styleName,
+ PocketWordConstants.PARAGRAPH_STYLE_FAMILY, null,
+ ParaStyle.class);
+ if (pstyle != null) {
+ pstyle = (ParaStyle)pstyle.getResolved();
+ }
+
+ TextStyle tstyle = (TextStyle)styleCat.lookup(styleName,
+ PocketWordConstants.PARAGRAPH_STYLE_FAMILY, null,
+ TextStyle.class);
+ if (pstyle != null) {
+ tstyle = (TextStyle)tstyle.getResolved();
+ }
+
+ try {
+ pswDoc.addParagraph(pstyle, inList);
+ }
+ catch (Exception e) {
+ throw new ConvertException(
+ "Error adding paragraph to PocketWordDocument.\n"
+ + e.toString());
+ }
+
+ traverseParagraphContents(node, tstyle);
+ }
+
+
+ /*
+ * Process the contents of a paragraph. This method handles situations
+ * where the paragraph contains multiple children, each representing a
+ * differently formatted piece of text.
+ */
+ private void traverseParagraphContents (Node node, TextStyle defTextStyle)
+ throws IOException, ConvertException {
+ // First up, get the style of this little bit
+ String styleName = getAttribute(node, ATTRIBUTE_TEXT_STYLE_NAME);
+ TextStyle tStyle = (TextStyle)styleCat.lookup(styleName,
+ PocketWordConstants.TEXT_STYLE_FAMILY, null,
+ TextStyle.class);
+
+ if (tStyle == null) {
+ tStyle = defTextStyle;
+ }
+
+ if (node.hasChildNodes()) {
+ NodeList nList = node.getChildNodes();
+ int len = nList.getLength();
+
+ for (int i = 0; i < len; i++) {
+
+ Node child = nList.item(i);
+ short nodeType = child.getNodeType();
+
+ switch (nodeType) {
+ case Node.TEXT_NODE:
+ String s = child.getNodeValue();
+ if (s.length() > 0) {
+ try {
+ pswDoc.addParagraphData(s, tStyle);
+ }
+ catch (Exception e) {
+ throw new ConvertException(
+ "Error adding data to paragraph in " +
+ "PocketWordDocument.\n" + e.toString());
+
+ }
+ }
+ break;
+
+ case Node.ELEMENT_NODE:
+ if (child.getNodeName().equals(TAG_SPACE)) {
+ StringBuffer sb = new StringBuffer("");
+ int count = 1;
+
+ NamedNodeMap map = child.getAttributes();
+
+ if (map.getLength() > 0) {
+ Node attr = map.getNamedItem(ATTRIBUTE_SPACE_COUNT);
+ count = Integer.parseInt(attr.getNodeValue().trim());
+ }
+
+ for ( ; count > 0; count--) {
+ sb.append(" ");
+ }
+
+ /*
+ * May want to look at style info for spaces. Could
+ * be important when calculating font metrics.
+ */
+ try {
+ pswDoc.addParagraphData(sb.toString(), tStyle);
+ }
+ catch (Exception e) {
+ throw new ConvertException(
+ "Error adding data to paragraph in " +
+ "PocketWordDocument.\n" + e.toString());
+
+ }
+ }
+ else if (child.getNodeName().equals(TAG_TAB_STOP)) {
+ try {
+ pswDoc.addParagraphData("\t", tStyle);
+ }
+ catch (Exception e) {
+ throw new ConvertException(
+ "Error adding data to paragraph in " +
+ "PocketWordDocument.\n" + e.toString());
+
+ }
+ }
+ else if (child.getNodeName().equals(TAG_LINE_BREAK)) {
+ /*
+ * Pocket Word does not support soft line breaks.
+ * They are just new paragraphs.
+ */
+ }
+ else if (child.getNodeName().equals(TAG_SPAN)) {
+ /*
+ * This is where the interesting ones, i.e. format
+ * changes occur.
+ */
+ traverseParagraphContents (child, defTextStyle);
+ }
+ else if (child.getNodeName().equals(TAG_HYPERLINK)) {
+ traverseParagraphContents (child, defTextStyle);
+ }
+ else {
+ // Should maybe have a default in here.
+ }
+ break;
+ default:
+ // Do nothing
+ }
+ }
+ }
+ else {
+ /*
+ * If the node has no children, then it is a blank paragraph, but
+ * they still require an entry in the Paragraph class to make sense.
+ */
+ pswDoc.addParagraphData("", tStyle);
+ }
+ }
+
+
+ /*
+ * Process a text:ordered-list or text:unordered-list tag. Pocket Word has
+ * no concept of a list so there is no need to differentiate between the
+ * two.
+ *
+ * Each item on the list contains a text:p node.
+ */
+ private void traverseList (Node node) throws IOException, ConvertException {
+ inList = true;
+
+ if (node.hasChildNodes()) {
+ NodeList nList = node.getChildNodes();
+ int len = nList.getLength();
+
+ for (int i = 0; i < len; i++) {
+ Node child = nList.item(i);
+
+ if (child.getNodeType() == Node.ELEMENT_NODE) {
+ String nodeName = child.getNodeName();
+
+ if (nodeName.equals(TAG_LIST_ITEM)) {
+ traverseListItem(child);
+ }
+ }
+ }
+ }
+
+ inList = false;
+ }
+
+
+ /*
+ * Process a text:list-item node. They usually contain have a single
+ * text:p child but can also have sections or other lists.
+ *
+ * For this case, only paragraphs are supported.
+ */
+ private void traverseListItem (Node node) throws IOException, ConvertException {
+ if (node.hasChildNodes()) {
+ NodeList nList = node.getChildNodes();
+ int len = nList.getLength();
+
+ for (int i = 0; i < len; i++) {
+ Node child = nList.item(i);
+
+ if (child.getNodeType() == Node.ELEMENT_NODE) {
+ String nodeName = child.getNodeName();
+
+ if (nodeName.equals(TAG_PARAGRAPH)) {
+ traverseParagraph(child);
+ }
+ }
+ }
+ }
+
+ }
+
+
+ /*
+ * Utility method to retrieve a Node attribute.
+ */
+ private String getAttribute (Node node, String attribute) {
+ NamedNodeMap attrNodes = node.getAttributes();
+
+ if (attrNodes != null) {
+ Node attr = attrNodes.getNamedItem(attribute);
+ if (attr != null) {
+ return attr.getNodeValue();
+ }
+ }
+
+ return null;
+ }
+}
diff --git a/xmerge/source/pocketword/java/org/openoffice/xmerge/converter/xml/sxw/pocketword/Paragraph.java b/xmerge/source/pocketword/java/org/openoffice/xmerge/converter/xml/sxw/pocketword/Paragraph.java
new file mode 100644
index 000000000000..0302a5d6efba
--- /dev/null
+++ b/xmerge/source/pocketword/java/org/openoffice/xmerge/converter/xml/sxw/pocketword/Paragraph.java
@@ -0,0 +1,858 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxw.pocketword;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+import java.util.Vector;
+import java.util.Enumeration;
+
+import java.awt.Color;
+
+import org.openoffice.xmerge.util.EndianConverter;
+import org.openoffice.xmerge.util.ColourConverter;
+import org.openoffice.xmerge.converter.xml.ParaStyle;
+import org.openoffice.xmerge.converter.xml.TextStyle;
+
+
+/**
+ * Represents a paragraph data structure within a Pocket Word document.
+ *
+ * @author Mark Murnane
+ * @version 1.1
+ */
+class Paragraph implements PocketWordConstants {
+ /*
+ * The data elements of a Paragraph.
+ *
+ * As the 'unknown' values are not calculated they are declared static.
+ * They are not declared final because they do have a calcuable value.
+ */
+ private static short unknown1 = 0x23;
+ private short dataWords = 0;
+ private short textLength = 0;
+ private short lengthWithFormatting = 0;
+ private short lines = 0;
+
+ private static final short marker = (short)0xFFFF;
+ private static int unknown2 = 0x22; // May be two short values
+
+ private short specialIndentation = 0;
+ private short leftIndentation = 0;
+ private short rightIndentation = 0;
+
+ private byte bullets = 0;
+ private byte alignment = 0;
+
+ private static int unknown3 = 0;
+
+ // Will always have at least these formatting settings in each paragraph
+ private short defaultFont = 2; // Courier New for the time being
+ private short defaultSize = 10;
+
+
+ /*
+ * Remaining elements assist in calculating correct values for the paragraph
+ * representation.
+ */
+
+ private Vector textSegments = null;
+
+ private Vector lineDescriptors = null;
+
+ private ParaStyle pStyle = null;
+
+ private boolean isLastParagraph = false;
+
+
+ /*
+ * Private class constructor used by all constructors. Ensures the proper
+ * initialisation of the Vector storing the paragraph's text.
+ */
+ private Paragraph () {
+ textSegments = new Vector(0, 1);
+ }
+
+
+ /**
+ * <p>Constructor for use when converting from SXW format to Pocket Word
+ * format.</p>
+ *
+ * @param style Paragraph style object describing the formatting style
+ * of this paragraph.
+ */
+ public Paragraph (ParaStyle style) {
+ this();
+
+ lineDescriptors = new Vector(0, 1);
+ pStyle = style;
+ }
+
+
+ /**
+ * <p>Constructor for use when converting from Pocket Word format to SXW
+ * format.</p>
+ *
+ * @param data Byte array containing byte data describing this paragraph
+ * from the Pocket Word file.
+ */
+ public Paragraph (byte[] data) {
+ this();
+
+ /*
+ * Read in all fixed data from the array
+ *
+ * unknown1 appears at data[0] and data[1]
+ */
+ dataWords = EndianConverter.readShort(new byte[] { data[2], data[3] } );
+ textLength = EndianConverter.readShort(new byte[] { data[4], data [5] } );
+ lengthWithFormatting = EndianConverter.readShort(
+ new byte[] { data[6], data[7] } );
+ lines = EndianConverter.readShort(new byte[] { data[8], data [9] } );
+
+ /*
+ * The marker appears at data[10] and data[11].
+ *
+ * The value of unknown2 is at data[12], data[13], data[14] and data[15].
+ */
+
+ specialIndentation = EndianConverter.readShort(new byte[] { data[16], data[17] } );
+ leftIndentation = EndianConverter.readShort(new byte[] { data[18], data [19] } );
+ rightIndentation = EndianConverter.readShort(new byte[] { data[20], data [21] } );
+
+ bullets = data[22];
+ alignment = data[23];
+
+ // The value of unknown3 is at data[24], data[25], data[26] and data[27].
+
+ /*
+ * The actual paragraph data is in the remainder of the byte sequence.
+ *
+ * Only the actual text seqence with the embedded formatting tags is
+ * relevant to the conversion from Pocket Word to SXW format.
+ */
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ bos.write(data, 28, lengthWithFormatting);
+ parseText(bos.toByteArray());
+ }
+
+
+ /*
+ * Processes the text portion of the raw paragraph data from the Pocket Word
+ * file. This data also includes formatting settings for the text in the
+ * paragraph.
+ *
+ * Formatting changes appear like XML/HTML tags. Formatted blocks are
+ * preceded by a sequence of bytes switching on a formatting change and
+ * followed by a sequence switching off that formatting change.
+ */
+ private void parseText (byte[] data) {
+
+ int totalLength = data.length;
+
+ StringBuffer sb = new StringBuffer("");
+
+ // Setup text style information
+ int mask = TextStyle.BOLD | TextStyle.ITALIC | TextStyle.UNDERLINE
+ | TextStyle.STRIKETHRU;
+
+
+ String fontName = null;
+ int fontSize = 0;
+ Color textColour = null;
+ Color backColour = null;
+ int modifiers = 0;
+
+ TextStyle ts = null;
+
+ int attrsSet = 0; // If this is 0, we have no extra style
+ boolean inSequence = false;
+ boolean sawText = false;
+
+ String s = new String(); // For debugging
+
+ // Start from the very beginning
+ for (int i = 0; i < totalLength; i++) {
+ // Will encounter at least two codes first
+ if ((byte)(data[i] & 0xF0) == FORMATTING_TAG) {
+ if (sawText) {
+ // Style change so dump previous segment and style info
+ addTextSegment(sb.toString(), ts);
+ sb = new StringBuffer("");
+ sawText = false;
+ }
+
+ switch (data[i]) {
+ case FONT_TAG:
+ int index = EndianConverter.readShort(
+ new byte[] { data[i + 1], data[i + 2] } );
+
+ /*
+ * Standard font.
+ *
+ * Should really be one, but as the only supported font
+ * currently is Courier New, want to leave it at Courier
+ * New for round trip conversions.
+ *
+ * Also need to account for the fact that Tahoma is the
+ * correct standard font.
+ */
+ if (fontName == null || fontName.equals("2")) {
+ if (index != 2 && index != 1) {
+ fontName = String.valueOf(index);
+ attrsSet++;
+ }
+ }
+ else {
+ // Font is set, but not the default
+ if (index == 2 || index == 1) {
+ fontName = "2";
+ attrsSet--;
+ }
+ else {
+ fontName = String.valueOf(index);
+ }
+ }
+ i += 2;
+ break;
+
+
+ case FONT_SIZE_TAG:
+ int size = EndianConverter.readShort(
+ new byte[] { data[i + 1], data[i + 2] } );
+
+ if (size == 0) {
+ // Flags the end of the last paragraph
+ isLastParagraph = true;
+ i += 2;
+ break;
+ }
+
+ // Standard size
+ if (fontSize == 0 || fontSize == 10) {
+ if (size != 10) {
+ fontSize = size;
+ attrsSet++;
+ }
+ }
+ else {
+ // Font size is set, but not to standard
+ if (size == 10) {
+ fontSize = 10;
+ attrsSet--;
+ }
+ else {
+ fontSize = size;
+ }
+ }
+ i += 2;
+ break;
+
+
+ case COLOUR_TAG:
+ if (data[i + 1] != 0) {
+ ColourConverter cc = new ColourConverter();
+ textColour = cc.convertToRGB(
+ EndianConverter.readShort(new byte[] { data[i + 1],
+ data[i + 2] } ));
+ attrsSet++;
+ }
+ else {
+ textColour = null;
+ attrsSet--;
+ }
+ i += 2;
+ break;
+
+
+ case FONT_WEIGHT_TAG:
+ if (data[i + 1] == FONT_WEIGHT_BOLD
+ || data[i + 1] == FONT_WEIGHT_THICK) {
+ modifiers |= TextStyle.BOLD;
+ attrsSet++;
+ }
+ else {
+ // Its a bit field so subtracting should work okay.
+ modifiers ^= TextStyle.BOLD;
+ attrsSet--;
+ }
+ i += 2;
+ break;
+
+
+ case ITALIC_TAG:
+ if (data[i + 1] == (byte)0x01) {
+ modifiers |= TextStyle.ITALIC;
+ attrsSet++;
+ }
+ else {
+ modifiers ^= TextStyle.ITALIC;
+ attrsSet--;
+ }
+ i++;
+ break;
+
+
+ case UNDERLINE_TAG:
+ if (data[i + 1] == (byte)0x01) {
+ modifiers |= TextStyle.UNDERLINE;
+ attrsSet++;
+ }
+ else {
+ modifiers ^= TextStyle.UNDERLINE;
+ attrsSet--;
+ }
+ i++;
+ break;
+
+
+ case STRIKETHROUGH_TAG:
+ if (data[i + 1] == (byte)0x01) {
+ modifiers |= TextStyle.STRIKETHRU;
+ attrsSet++;
+ }
+ else {
+ modifiers ^= TextStyle.STRIKETHRU;
+ attrsSet--;
+ }
+ i++;
+ break;
+
+ case HIGHLIGHT_TAG:
+ /*
+ * Highlighting is treated by OpenOffice as a
+ * background colour.
+ */
+ if (data[i + 1] == (byte)0x01) {
+ backColour = Color.yellow;
+ attrsSet++;
+ }
+ else {
+ backColour = null;
+ attrsSet--;
+ }
+ i++;
+ break;
+ }
+
+ inSequence = true;
+ continue;
+ }
+
+ if (inSequence) {
+ // Style information has been changed. Create new style here
+
+ inSequence = false;
+ if (attrsSet > 0) {
+ ts = new TextStyle(null, TEXT_STYLE_FAMILY, DEFAULT_STYLE,
+ mask, modifiers, fontSize, fontName, null);
+ ts.setColors(textColour, backColour);
+ }
+ else {
+ ts = null;
+ }
+ }
+
+ /*
+ * C4 xx seems to indicate a control code. C4 00 indicates the end
+ * of a paragraph; C4 04 indicates a tab space. Only these two
+ * have been seen so far.
+ */
+ if (data[i] == (byte)0xC4) {
+ /*
+ * Redundant nodes are sometimes added to the last paragraph
+ * because a new sequence is being processed when the flag is
+ * set.
+ *
+ * To avoid this, do nothing with the last paragraph unless no
+ * text has been added for it already. In that case, add the
+ * empty text segment being process to ensure that all
+ * paragraphs have at least one text segment.
+ */
+ if (data[i + 1] == (byte)0x00) {
+ if (isLastParagraph && textSegments.size() > 0) {
+ return;
+ }
+ addTextSegment(sb.toString(), ts);
+ return;
+ }
+ sb.append("\t");
+ sawText = true;
+ i++;
+ continue;
+ }
+
+ sb.append((char)data[i]);
+ sawText = true;
+ s = sb.toString();
+ }
+ }
+
+
+ /**
+ * <p>Adds details of a new text block to the <code>Paragraph</code> object.
+ * </p>
+ *
+ * @param text The text of the new block.
+ * @param style Text style object describing the formatting attached
+ * to this block of text.
+ */
+ public void addTextSegment(String text, TextStyle style) {
+ textLength += text.length();
+ textSegments.add(new ParagraphTextSegment(text, style));
+ }
+
+
+ /**
+ * <p>This method alters the state of the <code>Paragraph</code> object to
+ * indicate whether or not it is the final paragraph in the document.</p>
+ *
+ * <p>It is used during conversion from SXW format to Pocket Word format.
+ * In Pocket Word files, the last paragraph finishes with a different byte
+ * sequence to other paragraphs.</p>
+ *
+ * @param isLast true if the Paragraph is the last in the document,
+ * false otherwise.
+ */
+ public void setLastParagraph(boolean isLast) {
+ isLastParagraph = isLast;
+ }
+
+
+ /**
+ * <p>Complementary method to {@link #setLastParagraph(boolean)
+ * setLastParagraph}. Returns the terminal status of this
+ * <code>Paragraph</code> within the Pocket Word document.</p>
+ *
+ * @return true if the Paragraph is the last in the document; false otherwise.
+ */
+ public boolean getLastParagraph () {
+ return isLastParagraph;
+ }
+
+
+ /**
+ * <p>This method returns the Pocket Word representation of this
+ * <code>Paragraph</code> in Little Endian byte order.</p>
+ *
+ * <p>Used when converting from SXW format to Pocket Word format.</p>
+ *
+ * @return <code>byte</code> array containing the formatted representation
+ * of this Paragraph.
+ */
+ public byte[] getParagraphData() {
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+
+ postProcessText();
+
+ /*
+ * Need information about the paragraph segments in two places
+ * so calculate them first.
+ *
+ * The stream contains the text wrapped in any formatting sequences that
+ * are necessary.
+ */
+ ByteArrayOutputStream segs = new ByteArrayOutputStream();
+
+ try {
+ for (int i = 0; i < textSegments.size(); i++) {
+ ParagraphTextSegment pts = (ParagraphTextSegment)textSegments.elementAt(i);
+ segs.write(pts.getData());
+ }
+ }
+ catch (IOException ioe) {
+ // Should never happen in a memory based stream
+ }
+
+ /*
+ * Number of data words for this paragraph descriptor:
+ *
+ * 26 is the number of bytes prior to the start of the segment.
+ * 3 comes from the C4 00 00 termintating sequence.
+ */
+ dataWords = (short)(26 + segs.size() + 3 + 4);
+ if (isLastParagraph) {
+ dataWords += 6;
+ }
+ if (dataWords % 4 != 0) {
+ dataWords += (4 - (dataWords % 4));
+ }
+ dataWords /= 4;
+
+ /*
+ * The 8 bytes are made up of E6 ?0 00 and E5 ?0 00 at the start of the
+ * text along with the C4 00 that terminates it.
+ *
+ * In the event that the paragraph is the last one E6 00 00 is also
+ * present at the end of the text. Also, as we currently use a font
+ * other than the first in the index (Tahoma) E5 01 00 is also present.
+ *
+ * Make sure this is accurate when font specifications change
+ */
+ lengthWithFormatting = (short)(segs.size() + (isLastParagraph ? 14 : 8));
+
+ try {
+ bos.write(EndianConverter.writeShort(unknown1));
+ bos.write(EndianConverter.writeShort(dataWords));
+ bos.write(EndianConverter.writeShort((short)(textLength + 1)));
+ bos.write(EndianConverter.writeShort(lengthWithFormatting));
+ bos.write(EndianConverter.writeShort(lines));
+
+ bos.write(EndianConverter.writeShort(marker));
+ bos.write(EndianConverter.writeInt(unknown2));
+
+ bos.write(EndianConverter.writeShort(specialIndentation));
+ bos.write(EndianConverter.writeShort(leftIndentation));
+ bos.write(EndianConverter.writeShort(rightIndentation));
+
+ bos.write(bullets);
+
+ if (pStyle != null && pStyle.isAttributeSet(ParaStyle.TEXT_ALIGN)) {
+ switch (pStyle.getAttribute(ParaStyle.TEXT_ALIGN)) {
+
+ case ParaStyle.ALIGN_RIGHT:
+ bos.write(0x01);
+ break;
+
+ case ParaStyle.ALIGN_CENTER:
+ bos.write(0x02);
+ break;
+
+ default:
+ bos.write(0x00); // Left align in all other circumstances
+ break;
+ }
+ }
+ else {
+ bos.write(0x00);
+ }
+
+ bos.write(EndianConverter.writeInt(unknown3));
+
+
+ /*
+ * Write out font and size.
+ *
+ * If font support is added then this should change as the information
+ * will have to be calculated from a Font table.
+ */
+ bos.write(FONT_TAG);
+ bos.write(EndianConverter.writeShort(defaultFont));
+ bos.write(FONT_SIZE_TAG);
+ bos.write(EndianConverter.writeShort(defaultSize));
+
+ // Write out the text segments
+ bos.write(segs.toByteArray());
+
+ /*
+ * If this is the last paragraph in the document then we need to make
+ * sure that the paragraph text is terminated correctly with an E6 00 00
+ * before the C4 00 00.
+ */
+ if (isLastParagraph) {
+ if (defaultFont != 1) {
+ // Must always go back to the first font.
+ bos.write(FONT_TAG);
+ bos.write(EndianConverter.writeShort((short)0x01));
+ }
+ bos.write(FONT_SIZE_TAG);
+ bos.write(EndianConverter.writeShort((short)0x00));
+ }
+
+ bos.write(new byte[] { (byte)0xC4, 0x00, 0x00 } );
+
+ int padding = 0;
+ if (bos.size() % 4 != 0) {
+ padding = 4 - (bos.size() % 4);
+ }
+ for (int i = 0; i < padding; i++) {
+ bos.write(0x00);
+ }
+
+ // Third byte should match first byte after 0xFF 0xFF
+ bos.write(new byte[] { 0x42, 0x00, 0x22, 0x00} );
+
+ /*
+ * Meaning of last two bytes seems to be the number of words describing
+ * lines. This is calculated at 10 bytes per descriptor.
+ *
+ * May have two extra padding bytes that need to be accounted for too
+ * The division below may lose 2 bytes (integer result).
+ */
+ int wordsRemaining = (lineDescriptors.size() * 10) / 4;
+ if ((lineDescriptors.size() * 10) % 4 != 0) {
+ wordsRemaining++;
+ }
+ bos.write(EndianConverter.writeShort((short)wordsRemaining));
+
+
+ // Now write out the line descriptors
+ for (int i = 0; i < lineDescriptors.size(); i++) {
+ LineDescriptor ld = (LineDescriptor)lineDescriptors.elementAt(i);
+
+ bos.write(ld.getDescriptorInfo());
+ }
+
+
+ if (!isLastParagraph) {
+ /*
+ * There may be a need to pad this. Will be writing at
+ * either start of 4 byte block or 2 bytes into it.
+ */
+ if (bos.size() % 4 != 2) {
+ bos.write(EndianConverter.writeShort((short)0));
+ }
+ bos.write(EndianConverter.writeShort((short)0x41));
+ }
+ }
+ catch (IOException ioe) {
+ // Should never occur for a memory based stream
+ }
+
+ return bos.toByteArray();
+ }
+
+
+ /*
+ * This method handles the calculation of correct values for line lengths
+ * in each individual descriptor and the number of lines in the document.
+ *
+ * TODO: Update to take account of different font metrics.
+ */
+ private void postProcessText() {
+ /*
+ * The post-processing ...
+ *
+ * For each line, we need to add a line descriptor and increment
+ * the number of lines in the paragraph data structure.
+ *
+ * To do this, make sure that no sequence goes over the given screen
+ * width unless the last char is a whitespace character.
+ */
+
+ // In courier, can have no more than 29 chars per line
+
+ int chunkStart = 0;
+ StringBuffer sb = new StringBuffer("");
+
+ // Line Descriptor info should be eliminated each time
+ lineDescriptors = new Vector(1, 1);
+ lines = 0;
+
+ for (int i = 0; i < textSegments.size(); i++) {
+ ParagraphTextSegment pts = (ParagraphTextSegment)textSegments.elementAt(i);
+ sb.append(pts.getText());
+ }
+
+ if (sb.length() == 0) {
+ lines = 1;
+ lineDescriptors.add(new LineDescriptor((short)1, (short)0));
+ return;
+ }
+
+ while (chunkStart < sb.length()) {
+ String text = "";
+
+ try {
+ text = sb.substring(chunkStart, chunkStart + 30);
+ }
+ catch (StringIndexOutOfBoundsException sioobe) {
+ // We have less than one line left so just add it
+ text = sb.substring(chunkStart);
+ lineDescriptors.add(new LineDescriptor((short)(text.length() + 1), (short)(text.length() * 36)));
+ chunkStart += text.length();
+ lines++;
+ continue;
+ }
+
+ int lastWhitespace = -1;
+
+ for (int i = 29; i >= 0; i--) {
+ if (Character.isWhitespace(text.charAt(i))) {
+ lastWhitespace = i;
+ break;
+ }
+ }
+
+ if (lastWhitespace != -1) {
+ // The line can be split
+ lineDescriptors.add(new LineDescriptor((short)(lastWhitespace + 1), (short)(lastWhitespace * 36)));
+ chunkStart += lastWhitespace + 1;
+ lines++;
+ }
+ else {
+ // The line is completely occupied by a single word
+ lineDescriptors.add(new LineDescriptor((short)29, (short)(29 * 36)));
+ chunkStart += 29;
+ lines++;
+ }
+ }
+ }
+
+
+ /**
+ * <p>Returns the number of lines in the <code>Paragraph</code>.</p>
+ *
+ * @return The number of lines in the document.
+ */
+ public short getLines() {
+ postProcessText();
+
+ return lines;
+ }
+
+
+ /**
+ * <p>Toggles the flag indicating that the <code>Paragraph</code> is a
+ * bulleted paragraph.</p>
+ *
+ * @param isBulleted true to enable bulleting for this paragraph, false
+ * otherwise.
+ */
+ public void setBullets(boolean isBulleted) {
+ if (isBulleted) {
+ bullets = (byte)0xFF;
+ }
+ else {
+ bullets = 0;
+ }
+ }
+
+ /**
+ * <p>Returns the bulleting status of the <code>Paragraph</code>.</p>
+ *
+ * @return true if the paragraph is bulleted, false otherwise.
+ */
+ public boolean isBulleted() {
+ if (bullets != 0) {
+ return true;
+ }
+ return false;
+ }
+
+
+ /**
+ * <p>Returns the number of text characters in the <code>Paragraph</code>,
+ * excluding formatting.</p>
+ *
+ * @return The length of the paragraph.
+ */
+ public int getTextLength () {
+ return textLength;
+ }
+
+
+ /**
+ * <p>Returns an <code>Enumeration</code> over the individual text segments
+ * of the <code>Paragraph</code>.</p>
+ *
+ * @return An <code>Enumeration</code> of the text segments.
+ */
+ public Enumeration getSegmentsEnumerator () {
+ return textSegments.elements();
+ }
+
+
+ /**
+ * <p>Returns a paragraph style object that describes any of the paragraph
+ * level formatting used by this <code>Paragraph</code>.</p>
+ *
+ * @return Paragraph style object describing the <code>Paragraph</code>.
+ */
+ public ParaStyle makeStyle() {
+ int attrs[] = new int[] { ParaStyle.MARGIN_LEFT, ParaStyle.MARGIN_RIGHT,
+ ParaStyle.TEXT_ALIGN };
+ String values[] = new String[attrs.length];
+
+ /*
+ * Not interested in left or right indents just yet. Don't know
+ * how to calculate them.
+ */
+
+ switch (alignment) {
+ case 2:
+ values[2] = "center";
+ break;
+
+ case 1:
+ values[2] = "right";
+ break;
+
+ case 0:
+ default:
+ values[2] = "left";
+ return null; // Not interested if its the default.
+ }
+
+ return new ParaStyle(null, PARAGRAPH_STYLE_FAMILY, null, attrs,
+ values, null);
+ }
+
+
+ /*
+ * Class describing the data structures which appear following the text
+ * of a Paragraph. For each line on screen that the Paragraph uses, a
+ * LineDescriptor details how many characters are on the line and how much
+ * screen space they occupy.
+ *
+ * The screen space and character breaks are calculated during post-processing
+ * of the paragraph. See postProcessText().
+ *
+ * The unit of measurement used for screen space is currently unknown.
+ */
+ private class LineDescriptor {
+ private short characters = 0;
+ private int filler = 0;
+ private short screen_space = 0;
+ private short marker = 0;
+
+ private LineDescriptor(short chars, short space) {
+ characters = chars;
+ screen_space = space;
+ marker = (short)0x040C; // Not a constant. Depends on font used.
+ }
+
+
+ private byte[] getDescriptorInfo(){
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+
+ try {
+ bos.write(EndianConverter.writeShort(characters));
+ bos.write(EndianConverter.writeInt(filler));
+ bos.write(EndianConverter.writeShort(screen_space));
+ bos.write(EndianConverter.writeShort(marker));
+ }
+ catch (IOException ioe) {
+ // Should never happen in a memory based stream.
+ }
+
+ return bos.toByteArray();
+ }
+ }
+}
diff --git a/xmerge/source/pocketword/java/org/openoffice/xmerge/converter/xml/sxw/pocketword/ParagraphTextSegment.java b/xmerge/source/pocketword/java/org/openoffice/xmerge/converter/xml/sxw/pocketword/ParagraphTextSegment.java
new file mode 100644
index 000000000000..e17617f467c7
--- /dev/null
+++ b/xmerge/source/pocketword/java/org/openoffice/xmerge/converter/xml/sxw/pocketword/ParagraphTextSegment.java
@@ -0,0 +1,202 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxw.pocketword;
+
+import org.openoffice.xmerge.converter.xml.TextStyle;
+
+import org.openoffice.xmerge.util.EndianConverter;
+
+import org.openoffice.xmerge.util.ColourConverter;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+/**
+ * This class represents a portion of text with a particular formatting style.
+ * The style may differ from the default style of the paragraph of which it
+ * is part.
+ *
+ * @author Mark Murnane
+ * @version 1.1
+ */
+class ParagraphTextSegment implements PocketWordConstants {
+
+ private String pText;
+ private TextStyle pStyle;
+
+
+ /**
+ * <p>Initialise a new <code>ParagraphTextSegment</p>.
+ * <p>Both parameters may be <code>null</code>.</p>
+ *
+ * @param data The text of this segment.
+ * @param style The style describing this segment.
+ */
+ public ParagraphTextSegment (String data, TextStyle style) {
+ pText = data;
+ pStyle = style;
+ }
+
+ /**
+ * <p>Sets the text for this segment.</p>
+ *
+ * @param data The text of this segment.
+ */
+ public void setText (String data) {
+ pText = data;
+ }
+
+ /**
+ * <p>Gets the text for this segment.</p>
+ *
+ * @return The text of this segment.
+ */
+ public String getText () {
+ return pText;
+ }
+
+
+ /**
+ * <p>Sets the style for this segment.</p>
+ *
+ * @param data The style describing this segment.
+ */
+ public void setStyle (TextStyle style) {
+ pStyle = style;
+ }
+
+
+ /**
+ * <p>Gets the style for this segment.</p>
+ *
+ * @return The style describing this segment.
+ */
+ public TextStyle getStyle () {
+ return pStyle;
+ }
+
+
+ /**
+ * <p>Returns the string data for this text segment wrapped with the
+ * appropriate byte codes for the formatting settings used.</p>
+ *
+ * @return <code>byte</code> array containing formatted text in Pocket Word
+ * format.
+ */
+ public byte[] getData () {
+ ByteArrayOutputStream data = new ByteArrayOutputStream();
+
+ boolean colourSet = false;
+ boolean boldSet = false;
+ boolean italicSet = false;
+ boolean underlineSet = false;
+ boolean strikeSet = false;
+ boolean highlightSet = false;
+
+ // TODO: Font changes need to be worked out here
+
+ try {
+ if (pStyle != null) {
+ if (pStyle.getFontColor() != null) {
+ ColourConverter cc = new ColourConverter();
+ short colourCode = cc.convertFromRGB(pStyle.getFontColor());
+ if (colourCode != 0) { // not black
+ data.write(COLOUR_TAG);
+ data.write(EndianConverter.writeShort(colourCode));
+ colourSet = true;
+ }
+ }
+ if (pStyle.isSet(TextStyle.BOLD) && pStyle.getAttribute(TextStyle.BOLD)) {
+ data.write(new byte[] { FONT_WEIGHT_TAG, FONT_WEIGHT_BOLD, 0x00 } );
+ boldSet = true;
+ }
+ if (pStyle.isSet(TextStyle.ITALIC) && pStyle.getAttribute(TextStyle.ITALIC)) {
+ data.write(new byte[] { ITALIC_TAG, 0x01 } );
+ italicSet = true;
+ }
+ if (pStyle.isSet(TextStyle.UNDERLINE) && pStyle.getAttribute(TextStyle.UNDERLINE)) {
+ data.write(new byte[] { UNDERLINE_TAG, 0x01 } );
+ underlineSet = true;
+ }
+ if (pStyle.isSet(TextStyle.STRIKETHRU) && pStyle.getAttribute(TextStyle.STRIKETHRU)) {
+ data.write(new byte[] { STRIKETHROUGH_TAG, 0x01 } );
+ strikeSet = true;
+ }
+ if (pStyle.getBackgroundColor() != null) {
+ data.write(new byte[] { HIGHLIGHT_TAG, 0x01 } );
+ highlightSet = true;
+ }
+ }
+
+
+ // Now write out the data
+ if (!pText.equals("\t")) {
+ data.write(pText.getBytes());
+ }
+ else {
+ /*
+ * Tabs are a special case. They are represented by Pocket Word
+ * as the LE sequence 0xC4 0x04.
+ */
+ data.write(new byte[] { (byte)0xC4, 0x04 } );
+ }
+
+
+ // Now close out any of the settings changes
+ if (colourSet) {
+ /*
+ * Colours may change without changing back to black, but
+ * without knowing what the previous colour was, the only
+ * way to ensure correct conversion is to restore to black and
+ * let the next segment change the colour again.
+ */
+ data.write(new byte[] { COLOUR_TAG, 0x00, 0x00 } );
+ }
+ if (boldSet) {
+ data.write(new byte[] { FONT_WEIGHT_TAG, FONT_WEIGHT_NORMAL, 0x00 } );
+ }
+ if (italicSet) {
+ data.write(new byte[] { ITALIC_TAG, 0x00 } );
+ }
+ if (underlineSet) {
+ data.write(new byte[] { UNDERLINE_TAG, 0x00 } );
+ }
+ if (strikeSet) {
+ data.write(new byte[] { STRIKETHROUGH_TAG, 0x00 } );
+ }
+ if (highlightSet) {
+ data.write(new byte[] { HIGHLIGHT_TAG, 0x00 } );
+ }
+ }
+ catch (IOException ioe) {
+ // Should never occur in a memory based stream
+ }
+
+ return data.toByteArray();
+ }
+}
diff --git a/xmerge/source/pocketword/java/org/openoffice/xmerge/converter/xml/sxw/pocketword/PluginFactoryImpl.java b/xmerge/source/pocketword/java/org/openoffice/xmerge/converter/xml/sxw/pocketword/PluginFactoryImpl.java
new file mode 100644
index 000000000000..963e7f489726
--- /dev/null
+++ b/xmerge/source/pocketword/java/org/openoffice/xmerge/converter/xml/sxw/pocketword/PluginFactoryImpl.java
@@ -0,0 +1,164 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxw.pocketword;
+
+
+import java.io.InputStream;
+import java.io.IOException;
+
+import org.openoffice.xmerge.ConvertData;
+import org.openoffice.xmerge.Document;
+import org.openoffice.xmerge.DocumentDeserializer;
+import org.openoffice.xmerge.DocumentSerializer;
+import org.openoffice.xmerge.DocumentDeserializerFactory;
+import org.openoffice.xmerge.DocumentSerializerFactory;
+import org.openoffice.xmerge.DocumentMerger;
+import org.openoffice.xmerge.DocumentMergerFactory;
+import org.openoffice.xmerge.ConverterCapabilities;
+
+import org.openoffice.xmerge.util.registry.ConverterInfo;
+
+import org.openoffice.xmerge.converter.xml.sxw.SxwPluginFactory;
+
+
+/**
+ * Factory class used to create converters to/from the Pocket Word format.
+ *
+ * @author Mark Murnane
+ * @version 1.1
+ */
+public final class PluginFactoryImpl extends SxwPluginFactory
+ implements DocumentDeserializerFactory, DocumentSerializerFactory,
+ DocumentMergerFactory{
+
+ /**
+ * <p>Constructor that caches the <code>ConvertInfo</code> that
+ * corresponds to the registry information for this plug-in.</p>
+ *
+ * @param ci <code>ConvertInfo</code> object.
+ */
+ public PluginFactoryImpl (ConverterInfo ci) {
+ super(ci);
+ }
+
+ /** ConverterCapabilities object for this type of conversion. */
+ private final static ConverterCapabilities converterCap =
+ new ConverterCapabilitiesImpl();
+
+
+ /**
+ * <p>The <code>DocumentSerializer</code> is used to convert
+ * from the OpenOffice Writer <code>Document</code> format
+ * to the Pocket Word <code>Document</code> format.</p>
+ *
+ * <p>The <code>ConvertData</code> object is passed along to the
+ * created <code>DocumentSerializer</code> via its constructor.
+ * The <code>ConvertData</code> is read and converted when the
+ * the <code>DocumentSerializer</code> object's
+ * <code>serialize</code> method is called.</p>
+ *
+ * @param doc <code>Document</code> object that the created
+ * <code>DocumentSerializer</code> object uses
+ * as input.
+ *
+ * @return A <code>DocumentSerializer</code> object.
+ */
+ public DocumentSerializer createDocumentSerializer(Document doc) {
+ return new DocumentSerializerImpl(doc);
+ }
+
+
+ /**
+ * The <code>DocumentDeserializer</code> is used to convert
+ * from the Pocket Word <code>Document</code> format to
+ * the OpenOffice Writer <code>Document</code> format.</p>
+ *
+ * The <code>ConvertData</code> object is passed along to the
+ * created <code>DocumentDeserializer</code> via its constructor.
+ * The <code>ConvertData</code> is read and converted when the
+ * the <code>DocumentDeserializer</code> object's
+ * <code>deserialize</code> method is called.
+ * </p>
+ *
+ * @param cd <code>ConvertData</code> object that the created
+ * <code>DocumentDeserializer</code> object uses as
+ * input.
+ *
+ * @return A <code>DocumentDeserializer</code> object.
+ */
+ public DocumentDeserializer createDocumentDeserializer(ConvertData cd) {
+ return new DocumentDeserializerImpl(cd);
+ }
+
+
+ /**
+ * <p>Create a <code>Document</code> object that corresponds to
+ * the Pocket Word data passed in via the <code>InputStream</code>
+ * object.
+ *
+ * <p>This method will read from the given <code>InputStream</code>
+ * object. The returned <code>Document</code> object will contain
+ * the necessary data for the other objects created by the
+ * <code>PluginFactoryImpl</code> to process, like the
+ * <code>DocumentSerializerImpl</code> object and a
+ * <code>DocumentMerger</code> object.</p>
+ *
+ * @param name The <code>Document</code> name.
+ * @param is <code>InputStream</code> object corresponding
+ * to the <code>Document</code>.
+ *
+ * @return A <code>Document</code> object representing the
+ * Pocket Word format.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+
+ public Document createDeviceDocument(String name, InputStream is)
+ throws IOException {
+ PocketWordDocument pwd = new PocketWordDocument(name);
+ pwd.read(is);
+ return pwd;
+ }
+
+ /**
+ * Returns an instance of <code>DocumentMergerImpl</code>,
+ * which is an implementation of the <code>DocumentMerger</code>
+ * interface.
+ *
+ * @param doc <code>Document</code> to merge.
+ *
+ * @return A DocumentMergerImpl object.
+ */
+ public DocumentMerger createDocumentMerger(Document doc) {
+ ConverterCapabilities cc = converterCap;
+ DocumentMergerImpl merger = new DocumentMergerImpl(doc, cc);
+ return merger;
+
+ }
+
+}
diff --git a/xmerge/source/pocketword/java/org/openoffice/xmerge/converter/xml/sxw/pocketword/PocketWordConstants.java b/xmerge/source/pocketword/java/org/openoffice/xmerge/converter/xml/sxw/pocketword/PocketWordConstants.java
new file mode 100644
index 000000000000..207627398ca1
--- /dev/null
+++ b/xmerge/source/pocketword/java/org/openoffice/xmerge/converter/xml/sxw/pocketword/PocketWordConstants.java
@@ -0,0 +1,94 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxw.pocketword;
+
+
+/**
+ * Interface defining constants for Pocket Word attributes.
+ *
+ * @author Mark Murnane
+ * @version 1.1
+ */
+public interface PocketWordConstants {
+ /** File extension for Pocket Word files. */
+ public static final String FILE_EXTENSION = ".psw";
+
+ /** Name of the default style. */
+ public static final String DEFAULT_STYLE = "Standard";
+
+ /** Family name for Paragraph styles. */
+ public static final String PARAGRAPH_STYLE_FAMILY = "paragraph";
+
+ /** Family name for Text styles. */
+ public static final String TEXT_STYLE_FAMILY = "text";
+
+
+ /**
+ * Generic Pocket Word formatting code.
+ *
+ * Formatting codes are 0xEz, where z indicates the specific format code.
+ */
+ public static final byte FORMATTING_TAG = (byte)0xE0;
+
+ /** Font specification tag. The two bytes following inidicate which font. */
+ public static final byte FONT_TAG = (byte)0xE5;
+
+ /** Font size tag. The two bytes following specify font size in points. */
+ public static final byte FONT_SIZE_TAG = (byte)0xE6;
+
+ /** Colour tag. Two bytes following index a 4-bit colour table. */
+ public static final byte COLOUR_TAG = (byte)0xE7;
+
+ /** Font weight tag. Two bytes following indicate weighting of font. */
+ public static final byte FONT_WEIGHT_TAG = (byte)0xE8;
+
+ /** Normal font weight value. */
+ public static final byte FONT_WEIGHT_NORMAL = (byte)0x04;
+
+ /** Fine font weight value. */
+ public static final byte FONT_WEIGHT_FINE = (byte)0x01;
+
+ /** Bold font weight value. */
+ public static final byte FONT_WEIGHT_BOLD = (byte)0x07;
+
+ /** Thick font weight value. */
+ public static final byte FONT_WEIGHT_THICK = (byte)0x09;
+
+ /** Italic tag. Single byte following indicates whether italic is on. */
+ public static final byte ITALIC_TAG = (byte)0xE9;
+
+ /** Underline tag. Single byte following indicates whether underline is on. */
+ public static final byte UNDERLINE_TAG = (byte)0xEA;
+
+ /** Strikethrough tag. Single byte following indicates whether strikethrough is on. */
+ public static final byte STRIKETHROUGH_TAG = (byte)0XEB;
+
+ /** Highlighting tag. Single byte following indicates whether highlighting is on. */
+ public static final byte HIGHLIGHT_TAG = (byte)0xEC;
+
+}
diff --git a/xmerge/source/pocketword/java/org/openoffice/xmerge/converter/xml/sxw/pocketword/PocketWordDocument.java b/xmerge/source/pocketword/java/org/openoffice/xmerge/converter/xml/sxw/pocketword/PocketWordDocument.java
new file mode 100644
index 000000000000..bc77e0fa6988
--- /dev/null
+++ b/xmerge/source/pocketword/java/org/openoffice/xmerge/converter/xml/sxw/pocketword/PocketWordDocument.java
@@ -0,0 +1,404 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxw.pocketword;
+
+import org.openoffice.xmerge.Document;
+import org.openoffice.xmerge.converter.xml.ParaStyle;
+import org.openoffice.xmerge.converter.xml.TextStyle;
+
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+
+import java.util.Enumeration;
+import java.util.Vector;
+
+
+/**
+ * <p>Class representing a Pocket Word Document.</p>
+ *
+ * <p><code>PocketWordDocument</code> is used to create new Pocket Word documents
+ * and to read existing data to allow for conversion to OpenOffice Writer
+ * format.</p>
+ *
+ * @author Mark Murnane
+ * @version 1.1
+ */
+public class PocketWordDocument implements Document, PocketWordConstants {
+ private String docName;
+
+ private byte[] preamble;
+ private Vector fonts;
+ private DocumentDescriptor descriptor;
+ private Vector paragraphs;
+
+ private ParaStyle pStyle;
+ private Paragraph currentPara;
+
+ /*
+ * The trailer currently appears to be constant, but if its found to
+ * have a variable component, then this initialisation should be moved
+ * to an initTrailer() method.
+ *
+ * Padding is sometimes needed before the trailer to ensure the file
+ * ends on a 4-byte boundary, but this is handled in write().
+ */
+ private static final byte[] trailer = new byte[] { (byte)0x82, 0x00,
+ 0x09, 0x00,
+ 0x03, 0x00,
+ (byte)0x82, 0x00,
+ 0x00, 0x00,
+ 0x00, 0x00,
+ 0x00, 0x00,
+ 0x00, 0x00,
+ 0x00, 0x00 };
+
+
+ /**
+ * <p>Constructs a new Pocket Word Document.</p>
+ *
+ * <p>This new document does notcontain any information. Document data must
+ * either be added using appropriate methods, or an existing file can be
+ * {@link #read(InputStream) read} from an <code>InputStream</code>.</p>
+ *
+ * @param name The name of the <code>PocketWordDocument</code>.
+ */
+ public PocketWordDocument(String name) {
+
+ docName = trimDocumentName(name);
+
+ preamble = new byte[52];
+ fonts = new Vector(0, 1);
+ descriptor = new DocumentDescriptor();
+ paragraphs = new Vector(0, 1);
+ }
+
+
+ /**
+ * <p>This method reads <code>byte</code> data from the InputStream and
+ * extracts font and paragraph data from the file.</p>
+ *
+ * @param is InputStream containing a Pocket Word data file.
+ *
+ * @throws IOException In case of any I/O errors.
+ */
+ public void read(InputStream docData) throws IOException {
+
+ if (docData == null) {
+ throw new IOException ("No input stream to convert");
+ }
+
+ // The preamble may become important for font declarations.
+ int readValue = docData.read(preamble);
+ // #i33702# check for an empty InputStream.
+ if(readValue == -1) {
+ System.err.println("Error:invalid input stream");
+ return;
+ }
+
+ byte[] font = new byte[80];
+ int numfonts = 0;
+ do {
+ docData.read(font);
+
+ String name = new String(font, 0, 64, "UTF-16LE");
+ fonts.add(name.trim());
+
+ } while (!(font[76] == 5 && font[77] == 0
+ && font[78] == 1 && font[79] == 0));
+
+ /*
+ * TODO: The document descriptor data that follows the fonts ends with
+ * a variable section containing data for each of the paragraphs.
+ * It may be possible to use this information to calculate staring
+ * positions for each paragraph rather than iterating through the
+ * entire byte stream.
+ */
+
+ int value;
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ while ((value = docData.read()) != -1) {
+ bos.write(value);
+ }
+
+
+ byte[] contentData = bos.toByteArray();
+ int start = 0, end = 0;
+ boolean sawMarker = false;
+
+ for (int i = 0; i < contentData.length; i += 4) {
+ if (contentData[i + 2] == (byte)0xFF
+ && contentData[i + 3] == (byte)0xFF && !sawMarker) {
+ start = i - 8;
+ sawMarker = true;
+ continue;
+ }
+
+ if (contentData[i + 2] == (byte)0xFF
+ && contentData[i + 3] == (byte)0xFF && sawMarker) {
+ end = i - 8;
+ ByteArrayOutputStream paragraph = new ByteArrayOutputStream();
+ paragraph.write(contentData, start, end - start);
+ paragraphs.add(new Paragraph(paragraph.toByteArray()));
+
+ // Reset the markers
+ sawMarker = false;
+ i -= 4; // Skip back
+ }
+
+ }
+
+ /*
+ * Special case, the last paragraph
+ * If we got here, and the marker is set then we saw the start of the
+ * last paragraph, but no following paragraph
+ */
+ ByteArrayOutputStream paragraph = new ByteArrayOutputStream();
+ if (contentData[contentData.length - 19] == 0) {
+ paragraph.write(contentData, start, contentData.length - start - 20);
+ }
+ else {
+ paragraph.write(contentData, start, contentData.length - start - 18);
+ }
+ paragraphs.add(new Paragraph(paragraph.toByteArray()));
+ }
+
+
+ /*
+ * Utility method to make sure the document name is stripped of any file
+ * extensions before use.
+ */
+ private String trimDocumentName(String name) {
+ String temp = name.toLowerCase();
+
+ if (temp.endsWith(FILE_EXTENSION)) {
+ // strip the extension
+ int nlen = name.length();
+ int endIndex = nlen - FILE_EXTENSION.length();
+ name = name.substring(0,endIndex);
+ }
+
+ return name;
+ }
+
+
+ /**
+ * <p>Method to provide access to all of the <code>Paragraph</code> objects
+ * in the <code>Document</code>.</p>
+ *
+ * @return <code>Enumeration</code> over the paragraphs in the document.
+ */
+ public Enumeration getParagraphEnumeration() {
+ return paragraphs.elements();
+ }
+
+
+ /**
+ * <p>Returns the <code>Document</code> name with no file extension.</p>
+ *
+ * @return The <code>Document</code> name with no file extension.
+ */
+ public String getName() {
+ return docName;
+ }
+
+
+ /**
+ * <p>Returns the <code>Document</code> name with file extension.</p>
+ *
+ * @return The <code>Document</code> name with file extension.
+ */
+ public String getFileName() {
+ return new String(docName + FILE_EXTENSION);
+ }
+
+
+ /**
+ * <p>Writes out the <code>Document</code> content to the specified
+ * <code>OutputStream</code>.</p>
+ *
+ * <p>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.</p>
+ *
+ * @param os <code>OutputStream</code> to write out the
+ * <code>Document</code> content.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ public void write(OutputStream os) throws IOException {
+ DataOutputStream dos = new DataOutputStream(os);
+
+ initPreamble();
+ dos.write(preamble);
+
+ loadFonts();
+ for (int i = 0; i < fonts.size(); i++ ) {
+ ByteArrayOutputStream fontData = (ByteArrayOutputStream)fonts.elementAt(i);
+ dos.write(fontData.toByteArray());
+ }
+
+
+ for (int i = 0; i < paragraphs.size(); i++) {
+ Paragraph para = (Paragraph)paragraphs.elementAt(i);
+ descriptor.addParagraph((short)para.getTextLength(), para.getLines());
+ }
+ dos.write(descriptor.getDescriptor());
+
+ for (int i = 0; i < paragraphs.size(); i++ ) {
+ Paragraph para = (Paragraph)paragraphs.elementAt(i);
+
+ // Last paragraph has some extra data
+ if (i + 1 == paragraphs.size()) {
+ para.setLastParagraph(true);
+ }
+ dos.write(para.getParagraphData());
+ }
+
+
+ /*
+ * Before we write out the trailer, we need to make sure that it will
+ * lead to the file ending on a 4 byte boundary.
+ */
+ if (dos.size() % 4 == 0) {
+ dos.write((byte)0x00);
+ dos.write((byte)0x00);
+ }
+
+ dos.write(trailer);
+
+ dos.flush();
+ dos.close();
+ }
+
+
+ /**
+ * <p>This method adds a new paragraph element to the document. No string
+ * data is added to the paragraph.</p>
+ *
+ * <p><b>N.B.</b> The newly added paragraph becomes the current paragraph and
+ * is used as the target for all subsequent calls to addParagraphData().</p>
+ *
+ * @param style Paragraph Style object describing the formatting for
+ * the new paragraph. Can be null.
+ * @param listElement true if this paragraph is to be bulleted;
+ * false otherwise.
+ */
+ public void addParagraph(ParaStyle style, boolean listElement) {
+ /* For the moment, only support basic text entry in a single paragraph */
+ Paragraph para = new Paragraph(style);
+
+ paragraphs.add(para);
+
+ pStyle = style;
+ currentPara = para;
+
+ if (listElement) {
+ para.setBullets(true);
+ }
+ }
+
+
+ /**
+ * <p>This method adds text to the current paragraph.</p>
+ *
+ * <p>If no paragraphs exist within the document, it creates one.</p>
+ *
+ * @param data The string data for this segment.
+ * @param style Text Style object describing the formatting of this
+ * segment. Can be null.
+ */
+ public void addParagraphData(String data, TextStyle style) {
+ if (currentPara == null) {
+ addParagraph(null, false);
+ }
+ currentPara.addTextSegment(data, style);
+ }
+
+
+ /*
+ * Preamble is the portion before font specification which never
+ * seems to change from one file, or one saved version, to the next.
+ *
+ * Bytes 18h and 19h seem to contain the number of fonts and should
+ * be modified when all of the fonts have been specified.
+ * These bytes are the first two on the fourth line below.
+ */
+ private void initPreamble() {
+ preamble = new byte[] { 0x7B, 0x5C, 0x70, 0x77, 0x69, 0x15, 0x00, 0x00,
+ 0x01, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x2C, 0x00, 0x01, 0x00, 0x0A, 0x00, // Bytes 3-4 Font??
+ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Bytes 1-2 # Fonts
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00 };
+ }
+
+
+ /*
+ * This method writes the minimum font data that is used by the converter.
+ * Currently, all documents convert to 10 point Courier New. Tahoma is
+ * always mentioned in Pocket Word files, however, even if it is not used.
+ *
+ * TODO: Rewrite to allow for multiple fonts once font support issues
+ * have been resolved.
+ */
+ private void loadFonts() {
+ ByteArrayOutputStream fontData = new ByteArrayOutputStream();
+
+ try {
+ fontData.write(new String("Tahoma").getBytes("UTF-16LE"));
+ fontData.write(new byte[52]); // Rest of font name?
+ fontData.write(new byte[] { 0x02, 0x00, 0x01, 0x00 } );
+ fontData.write(new byte[] { 0x00, 0x00, 0x01, 0x00 } );
+ fontData.write(new byte[] { 0x00, 0x00, 0x00, 0x00 } );
+ fontData.write(new byte[] { 0x00, 0x00, 0x00, 0x00 } );
+
+ fonts.add(fontData);
+
+ fontData = new ByteArrayOutputStream();
+
+ fontData.write(new String("Courier New").getBytes("UTF-16LE"));
+ fontData.write(new byte[42]);
+ fontData.write(new byte[] { 0x14, 0x00, 0x04, 0x00 } );
+ fontData.write(new byte[] { 0x01, 0x00, 0x00, 0x00 } );
+ fontData.write(new byte[] { 0x00, 0x00, 0x15, 0x00 } );
+
+ // Next part indicates that this is the last font
+ fontData.write(new byte[] { 0x05, 0x00, 0x01, 0x00 } );
+
+ fonts.add(fontData);
+ }
+ catch (IOException ioe) {
+ // Shouldn't happen as this is a memory based stream
+ }
+ }
+}
diff --git a/xmerge/source/pocketword/java/org/openoffice/xmerge/converter/xml/sxw/pocketword/package.html b/xmerge/source/pocketword/java/org/openoffice/xmerge/converter/xml/sxw/pocketword/package.html
new file mode 100644
index 000000000000..e32357b85ef7
--- /dev/null
+++ b/xmerge/source/pocketword/java/org/openoffice/xmerge/converter/xml/sxw/pocketword/package.html
@@ -0,0 +1,58 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<!--
+ #*************************************************************************
+ #
+ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+
+ Copyright 2000, 2010 Oracle and/or its affiliates.
+
+ OpenOffice.org - a multi-platform office productivity suite
+
+ This file is part of OpenOffice.org.
+
+ OpenOffice.org is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License version 3
+ only, as published by the Free Software Foundation.
+
+ OpenOffice.org is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License version 3 for more details
+ (a copy is included in the LICENSE file that accompanied this code).
+
+ You should have received a copy of the GNU Lesser General Public License
+ version 3 along with OpenOffice.org. If not, see
+ <http://www.openoffice.org/license.html>
+ for a copy of the LGPLv3 License.
+
+ #*************************************************************************
+ -->
+<html>
+<head>
+<title>org.openoffice.xmerge.converter.xml.sxw.pocketword package</title>
+</head>
+
+<body bgcolor="white">
+
+<p>Plugin for the conversion of documents between StarWriter XML and
+ Pocket Word format.</p>
+<p>This plugin suports conversion of most features supported by Pocket Word.</p>
+<ul>
+ <li>Bold, Italic, Underline</li>
+ <li>Strikethrough</li>
+ <li>Highlight</li>
+ <li>Colours</li>
+ <li>Lists</li>
+ <li>Alignments</li>
+</ul>
+
+<p>Additionally, work on fonts is currently underway.</p>
+
+<p>This plugin is based on the Windows CE 3.0 version of Pocket Word.<br>
+ Testing was carried out using Pocket PC 2000 and Pocket PC 2002 devices.</p>
+
+<p>It follows the {@link org.openoffice.xmerge} framework
+for the conversion process.</p>
+
+</body>
+</html>
diff --git a/xmerge/source/pocketword/makefile.mk b/xmerge/source/pocketword/makefile.mk
new file mode 100644
index 000000000000..9db2d15000c6
--- /dev/null
+++ b/xmerge/source/pocketword/makefile.mk
@@ -0,0 +1,35 @@
+#*************************************************************************
+#
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# Copyright 2000, 2010 Oracle and/or its affiliates.
+#
+# OpenOffice.org - a multi-platform office productivity suite
+#
+# This file is part of OpenOffice.org.
+#
+# OpenOffice.org is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License version 3
+# only, as published by the Free Software Foundation.
+#
+# OpenOffice.org is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License version 3 for more details
+# (a copy is included in the LICENSE file that accompanied this code).
+#
+# You should have received a copy of the GNU Lesser General Public License
+# version 3 along with OpenOffice.org. If not, see
+# <http://www.openoffice.org/license.html>
+# for a copy of the LGPLv3 License.
+#
+#*************************************************************************
+
+TARGET=pocketword
+PRJ=../..
+PRJNAME=xmerge
+
+.INCLUDE : ant.mk
+.IF "$(L10N_framework)"==""
+ALLTAR: ANTBUILD
+.ENDIF
diff --git a/xmerge/source/regutil/makefile.mk b/xmerge/source/regutil/makefile.mk
new file mode 100644
index 000000000000..4886fe0057b0
--- /dev/null
+++ b/xmerge/source/regutil/makefile.mk
@@ -0,0 +1,48 @@
+#*************************************************************************
+#
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# Copyright 2000, 2010 Oracle and/or its affiliates.
+#
+# OpenOffice.org - a multi-platform office productivity suite
+#
+# This file is part of OpenOffice.org.
+#
+# OpenOffice.org is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License version 3
+# only, as published by the Free Software Foundation.
+#
+# OpenOffice.org is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License version 3 for more details
+# (a copy is included in the LICENSE file that accompanied this code).
+#
+# You should have received a copy of the GNU Lesser General Public License
+# version 3 along with OpenOffice.org. If not, see
+# <http://www.openoffice.org/license.html>
+# for a copy of the LGPLv3 License.
+#
+#*************************************************************************
+
+PRJ = ..$/..
+PRJNAME = xmerge
+TARGET = regutil
+ENABLE_EXCEPTIONS=TRUE
+LIBTARGET=NO
+
+# --- Settings -----------------------------------------------------
+.INCLUDE: settings.mk
+
+.IF "$(GUI)" == "WNT"
+
+OBJFILES=$(OBJ)$/regutil.obj
+APP1TARGETDEPN=makefile.mk
+APP1OBJS=$(OBJFILES)
+APP1TARGET=$(TARGET)
+APP1STDLIBS= Advapi32.lib
+
+.ENDIF
+
+# --- Targets ------------------------------------------------------
+.INCLUDE : target.mk
diff --git a/xmerge/source/regutil/regutil.cpp b/xmerge/source/regutil/regutil.cpp
new file mode 100644
index 000000000000..3703192d79b5
--- /dev/null
+++ b/xmerge/source/regutil/regutil.cpp
@@ -0,0 +1,102 @@
+/*
+ * Simple Application which calls the DllRegisterServer or DllUnregisterServer functions
+ * of the XMerge ActiveSync plugin.
+ */
+
+
+#include <stdio.h>
+#include <string.h>
+#include <windows.h>
+
+
+typedef HRESULT (STDAPICALLTYPE *DLLREGISTERSERVER)(void);
+typedef HRESULT (STDAPICALLTYPE *DLLUNREGISTERSERVER)(void);
+
+int main(int argc, char* argv[])
+{
+ BOOL bUninstall = FALSE;
+ int nPathIndex = 1;
+
+ if (argc < 2 || argc > 3)
+ {
+ printf("\nUsage: regutil [/u] <Full Path of XMergeSync.dll>\n\n");
+ return -1;
+ }
+
+
+ if (argc == 3)
+ {
+ if (strcmp("/u", argv[1]))
+ {
+ printf("\nUnrecognised option: %s\n", argv[1]);
+ return -1;
+ }
+
+ bUninstall = TRUE;
+ nPathIndex = 2;
+ }
+
+
+ // Dynamically load the library
+ HMODULE hmXMDll = LoadLibrary(argv[nPathIndex]);
+
+ if (hmXMDll == NULL)
+ {
+ printf("\nUnable to load the library %s\n", argv[nPathIndex]);
+ return -1;
+ }
+
+
+ // Get an offset to the either the DllRegisterServer or DllUnregisterServer functions
+ if (!bUninstall)
+ {
+ printf("\nRegistering %s ... ", argv[nPathIndex]);
+
+ DLLREGISTERSERVER DllRegisterServer = (DLLREGISTERSERVER)GetProcAddress(hmXMDll, "DllRegisterServer");
+
+ if (DllRegisterServer == NULL)
+ {
+ printf("failed.\n\nDllRegisterServer is not present in library.\n");
+ return -1;
+ }
+
+ // Now call the procedure ...
+ HRESULT regResult = DllRegisterServer() ;
+
+ if (regResult != S_OK)
+ {
+ printf("failed.\n");
+ return -1;
+ }
+ }
+ else
+ {
+ printf("\nUnregistering %s ... ", argv[nPathIndex]);
+
+ DLLUNREGISTERSERVER DllUnregisterServer = (DLLUNREGISTERSERVER)GetProcAddress(hmXMDll, "DllUnregisterServer");
+
+ if (DllUnregisterServer == NULL)
+ {
+ printf("failed.\n\nDllUnregisterServer is not present in library.\n");
+ return -1;
+ }
+
+ // Now call the procedure ...
+ HRESULT regResult = DllUnregisterServer() ;
+
+ if (regResult != S_OK)
+ {
+ printf("failed.\n");
+ return -1;
+ }
+
+ }
+
+ printf("done.\n");
+
+
+ // Clean up
+ FreeLibrary(hmXMDll);
+
+ return 0;
+} \ No newline at end of file
diff --git a/xmerge/source/regutil/regutil.dsp b/xmerge/source/regutil/regutil.dsp
new file mode 100644
index 000000000000..2c3689c047a5
--- /dev/null
+++ b/xmerge/source/regutil/regutil.dsp
@@ -0,0 +1,96 @@
+# Microsoft Developer Studio Project File - Name="regutil" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=regutil - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "regutil.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "regutil.mak" CFG="regutil - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "regutil - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "regutil - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "regutil - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD BASE RSC /l 0x1809 /d "NDEBUG"
+# ADD RSC /l 0x1809 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+
+!ELSEIF "$(CFG)" == "regutil - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "regutil___Win32_Debug"
+# PROP BASE Intermediate_Dir "regutil___Win32_Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "regutil___Win32_Debug"
+# PROP Intermediate_Dir "regutil___Win32_Debug"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
+# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
+# ADD BASE RSC /l 0x1809 /d "_DEBUG"
+# ADD RSC /l 0x1809 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+
+!ENDIF
+
+# Begin Target
+
+# Name "regutil - Win32 Release"
+# Name "regutil - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# End Group
+# End Target
+# End Project
diff --git a/xmerge/source/regutil/regutil.dsw b/xmerge/source/regutil/regutil.dsw
new file mode 100644
index 000000000000..4ad03e67bffc
--- /dev/null
+++ b/xmerge/source/regutil/regutil.dsw
@@ -0,0 +1,17 @@
+Microsoft Developer Studio Workspace File, Format Version 6.00
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/xmerge/source/wordsmith/build.xml b/xmerge/source/wordsmith/build.xml
new file mode 100644
index 000000000000..9a0c1aef7563
--- /dev/null
+++ b/xmerge/source/wordsmith/build.xml
@@ -0,0 +1,76 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ #*************************************************************************
+ #
+ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+
+ Copyright 2000, 2010 Oracle and/or its affiliates.
+
+ OpenOffice.org - a multi-platform office productivity suite
+
+ This file is part of OpenOffice.org.
+
+ OpenOffice.org is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License version 3
+ only, as published by the Free Software Foundation.
+
+ OpenOffice.org is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License version 3 for more details
+ (a copy is included in the LICENSE file that accompanied this code).
+
+ You should have received a copy of the GNU Lesser General Public License
+ version 3 along with OpenOffice.org. If not, see
+ <http://www.openoffice.org/license.html>
+ for a copy of the LGPLv3 License.
+
+ #*************************************************************************
+ -->
+
+<project name="wordsmith" default="all" basedir=".">
+
+ <property file="../inc/antbuild.properties"/>
+
+ <path id="classpath">
+ <pathelement location="${build.dir}/xmerge.jar"/>
+ </path>
+
+
+ <target name="init" >
+ <mkdir dir="${target.dir}"/>
+ </target>
+
+ <!-- compile java sources in ${package} -->
+ <target name="compile" depends="init">
+ <javac srcdir="${src.dir}"
+ destdir="${target.dir}"
+ debug="${debug}"
+ deprecation="${deprecation}"
+ optimize="${optimize}">
+ <classpath refid="classpath"/>
+ </javac>
+ </target>
+
+ <!-- package to jar -->
+ <target name="jar" depends="compile">
+ <jar destfile="${target.jar}">
+ <fileset dir="${target.dir}"
+ includes="**/*.class" />
+ <metainf dir="${basedir}">
+ <filename name="converter.xml"/>
+ </metainf>
+ </jar>
+ </target>
+
+ <!-- clean up -->
+ <target name="clean">
+ <delete dir="${class.dir}"/>
+ <delete file="${target.jar}"/>
+ </target>
+
+ <target name="all" depends="jar">
+ </target>
+
+</project>
+
diff --git a/xmerge/source/wordsmith/converter.xml b/xmerge/source/wordsmith/converter.xml
new file mode 100644
index 000000000000..9285730569db
--- /dev/null
+++ b/xmerge/source/wordsmith/converter.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0"?>
+<converters>
+ <converter type="staroffice/sxw" version="1.0">
+ <converter-display-name>
+ WordSmith
+ </converter-display-name>
+ <converter-description>
+ StarWriter XML to/from WordSmith conversion
+ </converter-description>
+ <converter-vendor>OpenOffice.org</converter-vendor>
+ <converter-class-impl>
+ org.openoffice.xmerge.converter.xml.sxw.wordsmith.PluginFactoryImpl
+ </converter-class-impl>
+ <converter-target type="application/x-wordsmith" />
+ </converter>
+</converters>
+
diff --git a/xmerge/source/wordsmith/java/org/openoffice/xmerge/converter/xml/sxw/wordsmith/ConverterCapabilitiesImpl.java b/xmerge/source/wordsmith/java/org/openoffice/xmerge/converter/xml/sxw/wordsmith/ConverterCapabilitiesImpl.java
new file mode 100644
index 000000000000..11e264a07cfb
--- /dev/null
+++ b/xmerge/source/wordsmith/java/org/openoffice/xmerge/converter/xml/sxw/wordsmith/ConverterCapabilitiesImpl.java
@@ -0,0 +1,93 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxw.wordsmith;
+
+import org.openoffice.xmerge.ConverterCapabilities;
+import org.openoffice.xmerge.converter.xml.OfficeConstants;
+
+/**
+ * <p>WordSmith implementation of <code>ConverterCapabilities</code> for
+ * the {@link
+ * org.openoffice.xmerge.converter.xml.sxw.wordsmith.PluginFactoryImpl
+ * PluginFactoryImpl}.</p>
+ *
+ * <p>Used with StarWriter XML to/from WordSmith conversions.
+ * The <code>ConverterCapibilies</code> specify which &quot;Office&quot;
+ * <code>Document</code> tags and attributes are supported on the
+ * &quot;Device&quot; <code>Document</code> format.</p>
+ */
+public final class ConverterCapabilitiesImpl
+ implements ConverterCapabilities {
+
+ public boolean canConvertTag(String tag) {
+
+ if (OfficeConstants.TAG_OFFICE_DOCUMENT.equals(tag))
+ return true;
+ else if (OfficeConstants.TAG_OFFICE_DOCUMENT_CONTENT.equals(tag))
+ return true;
+ else if (OfficeConstants.TAG_OFFICE_BODY.equals(tag))
+ return true;
+ else if (OfficeConstants.TAG_PARAGRAPH.equals(tag))
+ return true;
+ else if (OfficeConstants.TAG_HEADING.equals(tag))
+ return true;
+ else if (OfficeConstants.TAG_ORDERED_LIST.equals(tag))
+ return true;
+ else if (OfficeConstants.TAG_UNORDERED_LIST.equals(tag))
+ return true;
+ else if (OfficeConstants.TAG_LIST_ITEM.equals(tag))
+ return true;
+ else if (OfficeConstants.TAG_LIST_HEADER.equals(tag))
+ return true;
+ else if (OfficeConstants.TAG_SPAN.equals(tag))
+ return true;
+ else if (OfficeConstants.TAG_HYPERLINK.equals(tag))
+ return true;
+ else if (OfficeConstants.TAG_LINE_BREAK.equals(tag))
+ return true;
+ else if (OfficeConstants.TAG_SPACE.equals(tag))
+ return true;
+ else if (OfficeConstants.TAG_TAB_STOP.equals(tag))
+ return true;
+
+ return false;
+ }
+
+ public boolean canConvertAttribute(String tag,
+ String attribute) {
+
+ if (OfficeConstants.TAG_SPACE.equals(tag)) {
+
+ if (OfficeConstants.ATTRIBUTE_SPACE_COUNT.equals(attribute))
+ return true;
+ }
+
+ return false;
+ }
+}
+
diff --git a/xmerge/source/wordsmith/java/org/openoffice/xmerge/converter/xml/sxw/wordsmith/DOCConstants.java b/xmerge/source/wordsmith/java/org/openoffice/xmerge/converter/xml/sxw/wordsmith/DOCConstants.java
new file mode 100644
index 000000000000..415392933c2c
--- /dev/null
+++ b/xmerge/source/wordsmith/java/org/openoffice/xmerge/converter/xml/sxw/wordsmith/DOCConstants.java
@@ -0,0 +1,61 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxw.wordsmith;
+
+/**
+ * Constants used for encoding and decoding the WordSmith format.
+ *
+ * @author Herbie Ong, David Proulx
+ */
+interface DOCConstants {
+
+ /** Constant for uncompressed version. */
+ public static final short UNCOMPRESSED = 1;
+
+ /** Constant for compressed version. */
+ public static final short COMPRESSED = 2;
+
+ /** Constant used for spare fields. */
+ public static final int SPARE = 0;
+
+ /** WordSmith record size. */
+ public static final short TEXT_RECORD_SIZE = 4096;
+
+ /** Constant for encoding scheme. */
+ public static final String ENCODING = "8859_1";
+
+ /** Constant for TAB character. */
+ public final static char TAB_CHAR = '\t';
+
+ /** Constant for EOL character. */
+ public final static char EOL_CHAR = '\n';
+
+ /** Constant for SPACE character. */
+ public final static char SPACE_CHAR = ' ';
+}
+
diff --git a/xmerge/source/wordsmith/java/org/openoffice/xmerge/converter/xml/sxw/wordsmith/DocumentDeserializerImpl.java b/xmerge/source/wordsmith/java/org/openoffice/xmerge/converter/xml/sxw/wordsmith/DocumentDeserializerImpl.java
new file mode 100644
index 000000000000..29098b72cc17
--- /dev/null
+++ b/xmerge/source/wordsmith/java/org/openoffice/xmerge/converter/xml/sxw/wordsmith/DocumentDeserializerImpl.java
@@ -0,0 +1,565 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxw.wordsmith;
+
+import org.w3c.dom.*;
+
+import java.io.IOException;
+import java.util.Enumeration;
+
+import org.openoffice.xmerge.Document;
+import org.openoffice.xmerge.ConvertData;
+import org.openoffice.xmerge.ConvertException;
+import org.openoffice.xmerge.DocumentDeserializer;
+import org.openoffice.xmerge.converter.xml.OfficeConstants;
+import org.openoffice.xmerge.converter.palm.PalmDB;
+import org.openoffice.xmerge.converter.palm.Record;
+import org.openoffice.xmerge.converter.palm.PdbDecoder;
+import org.openoffice.xmerge.converter.palm.PalmDocument;
+import org.openoffice.xmerge.converter.xml.sxw.SxwDocument;
+
+import java.util.Vector;
+import java.io.ByteArrayInputStream;
+
+import org.openoffice.xmerge.converter.xml.*;
+import org.openoffice.xmerge.util.Debug;
+import org.openoffice.xmerge.util.XmlUtil;
+
+/**
+ * <p>WordSmith implementation of
+ * org.openoffice.xmerge.DocumentDeserializer
+ * for the {@link
+ * org.openoffice.xmerge.converter.xml.sxw.wordsmith.PluginFactoryImpl
+ * PluginFactoryImpl}.</p>
+ *
+ * The <code>deserialize</code> method uses a
+ * <code>DocDecoder</code> to read the WordSmith format into a
+ * <code>String</code> object, then it calls <code>buildDocument</code>
+ * to create a <code>SxwDocument</code> object from it.
+ *
+ * @author Herbie Ong, David Proulx
+ */
+public final class DocumentDeserializerImpl
+implements DOCConstants, OfficeConstants, DocumentDeserializer {
+
+ /** A Decoder object for decoding WordSmith format. */
+ private WSDecoder decoder = null;
+
+ WseFontTable fontTable = null;
+ WseColorTable colorTable = null;
+ StyleCatalog styleCat = null;
+ StyleCatalog oldStyleCat = null;
+
+ /** A <code>ConvertData</code> object assigned to this object. */
+ private ConvertData cd = null;
+
+
+ /**
+ * Constructor that assigns the given <code>ConvertData</code>
+ * to the object.
+ *
+ * @param cd A <code>ConvertData</code> object to read data for
+ * the conversion process by the deserialize method.
+ */
+ public DocumentDeserializerImpl(ConvertData cd) {
+ this.cd = cd;
+ }
+
+
+ /**
+ * Convert the given <code>ConvertData</code> into a
+ * <code>SxwDocument</code> object.
+ *
+ * @return Resulting <code>Document</code> object.
+ *
+ * @throws ConvertException If any conversion error occurs.
+ * @throws IOException If any I/O error occurs.
+ */
+ public Document deserialize() throws ConvertException,
+ IOException {
+ return deserialize(null, cd);
+ }
+
+
+ public Document deserialize(Document origDoc, ConvertData cd)
+ throws IOException {
+
+ Document doc = null;
+ PalmDocument palmDoc = null;
+ Enumeration e = cd.getDocumentEnumeration();
+
+ while(e.hasMoreElements()) {
+ palmDoc = (PalmDocument) e.nextElement();
+ PalmDB pdb = palmDoc.getPdb();
+ Record[] recs = pdb.getRecords();
+ decoder = new WSDecoder();
+ Wse[] b = decoder.parseDocument(recs);
+ String docName = palmDoc.getName();
+ doc = buildDocument(docName, b, origDoc);
+ }
+ return doc;
+ }
+
+
+ /**
+ * Temporary method to read existing <code>StyleCatalog</code>
+ * as a starting point.
+ *
+ * @param parentDoc The parent <code>Document</code>.
+ */
+ private void readStyleCatalog(Document parentDoc) {
+ Element rootNode = null;
+ try {
+ java.io.ByteArrayOutputStream bos = new java.io.ByteArrayOutputStream();
+ parentDoc.write(bos);
+ SxwDocument sxwDoc = new SxwDocument("old");
+ sxwDoc.read(new ByteArrayInputStream(bos.toByteArray()));
+ org.w3c.dom.Document domDoc = sxwDoc.getContentDOM();
+
+ String families[] = new String[3];
+ families[0] = "text";
+ families[1] = "paragraph";
+ families[2] = "paragraph";
+ Class classes[] = new Class[3];
+ classes[0] = TextStyle.class;
+ classes[1] = ParaStyle.class;
+ classes[2] = TextStyle.class;
+
+ NodeList nl = domDoc.getElementsByTagName(TAG_OFFICE_STYLES);
+ oldStyleCat.add(nl.item(0), families, classes, null, false);
+ nl = domDoc.getElementsByTagName(TAG_OFFICE_AUTOMATIC_STYLES);
+ oldStyleCat.add(nl.item(0), families, classes, null, false);
+ nl = domDoc.getElementsByTagName(TAG_OFFICE_MASTER_STYLES);
+ oldStyleCat.add(nl.item(0), families, classes, null, false);
+
+ } catch (Exception e) {
+ Debug.log(Debug.ERROR, "", e);
+ }
+
+ }
+
+
+ /**
+ * Given an array of paragraph <code>Style</code> objects, see if
+ * there is exactly one which matches the text formatting
+ * <code>Style</code> of <code>tStyle</code>.
+ *
+ * @param paraStyles An array of paragraph <code>Style</code>
+ * objects.
+ * @param tStyle Text <code>Style</code> to match.
+ *
+ * @return The paragraph <code>Style</code> that matches.
+ */
+ private ParaStyle matchParaByText(Style paraStyles[], TextStyle tStyle) {
+ int matchIndex = -1;
+ int matchCount = 0;
+ Style txtMatches[] = (Style[]) oldStyleCat.getMatching(tStyle);
+ if (txtMatches.length >= 1) {
+ for (int j = 0; j < txtMatches.length; j++) {
+ TextStyle t = (TextStyle)txtMatches[j];
+
+ if (!t.getFamily().equals("paragraph"))
+ continue;
+
+ for (int k = 0; k < paraStyles.length; k++) {
+ if (t.getName().equals(paraStyles[k].getName())) {
+ matchCount++;
+ matchIndex = k;
+ }
+ }
+ }
+ }
+ if (matchCount == 1)
+ return (ParaStyle)paraStyles[matchIndex];
+ else return null;
+ }
+
+
+ /**
+ * Take a <code>String</code> of text and turn it into a sequence
+ * of <code>Node</code> objects.
+ *
+ * @param text <code>String</code> of text.
+ * @param parentDoc Parent <code>Document</code>.
+ *
+ * @return Array of <code>Node</code> objects.
+ */
+ private Node[] parseText(String text, org.w3c.dom.Document parentDoc) {
+ Vector nodeVec = new Vector();
+
+ // Break up the text from the WordSmith text run into Open
+ // Office text runs. There may be more runs in OO because
+ // runs of 2 or more spaces map to nodes.
+ while ((text.indexOf(" ") != -1) || (text.indexOf("\t") != 1)) {
+
+ // Find the indices of tabs and multiple spaces, and
+ // figure out which of them occurs first in the string.
+ int spaceIndex = text.indexOf(" ");
+ int tabIndex = text.indexOf("\t");
+ if ((spaceIndex == -1) && (tabIndex == -1))
+ break; // DJP This should not be necessary. What is wrong
+ // with the while() stmt up above?
+ int closerIndex; // Index of the first of these
+ if (spaceIndex == -1)
+ closerIndex = tabIndex;
+ else if (tabIndex == -1)
+ closerIndex = spaceIndex;
+ else
+ closerIndex = (spaceIndex > tabIndex) ? tabIndex : spaceIndex;
+
+ // If there is any text prior to the first occurrence of a
+ // tab or spaces, create a text node from it, then chop it
+ // off the string we're working with.
+ if (closerIndex > 0) {
+ String beginningText = text.substring(0, closerIndex);
+ Text textNode = parentDoc.createTextNode(beginningText);
+ nodeVec.addElement(textNode);
+ log("<TEXT>");
+ log(beginningText);
+ log("</TEXT>");
+ }
+ text = text.substring(closerIndex);
+
+ // Handle either tab character or space sequence by creating
+ // an element for it, and then chopping out the text that
+ // represented it in "text".
+ if (closerIndex == tabIndex) {
+ Element tabNode = parentDoc.createElement(TAG_TAB_STOP);
+ nodeVec.add(tabNode);
+ text = text.substring(1); // tab is always a single character
+ log("<TAB/>");
+ } else {
+ // Compute length of space sequence.
+ int nrSpaces = 2;
+ while ((nrSpaces < text.length())
+ && text.substring(nrSpaces, nrSpaces + 1).equals(" "))
+ nrSpaces++;
+
+ Element spaceNode = parentDoc.createElement(TAG_SPACE);
+ spaceNode.setAttribute(ATTRIBUTE_SPACE_COUNT, new Integer(nrSpaces).toString());
+ nodeVec.add(spaceNode);
+ text = text.substring(nrSpaces);
+ log("<SPACE count=\"" + nrSpaces + "\" />");
+ }
+ }
+
+ // No more tabs or space sequences. If there's any remaining
+ // text create a text node for it.
+ if (text.length() > 0) {
+ Text textNode = parentDoc.createTextNode(text);
+ nodeVec.add(textNode);
+ log("<TEXT>");
+ log(text);
+ log("</TEXT>");
+ }
+
+ // Now create and populate an array to return the nodes in.
+ Node nodes[] = new Node[nodeVec.size()];
+ for (int i = 0; i < nodeVec.size(); i++)
+ nodes[i] = (Node)nodeVec.elementAt(i);
+ return nodes;
+ }
+
+
+ /**
+ * Parses the text content of a WordSmith format and builds a
+ * <code>SXWDocument</code>.
+ *
+ * @param docName <code>Document</code> name
+ * @param str Text content of WordSmith format
+ *
+ * @return Resulting <code>SXWDocument</code> object.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ private SxwDocument buildDocument(String docName, Wse[] data, Document origDoc)
+ throws IOException {
+
+ // create minimum office xml document.
+ SxwDocument sxwDoc = new SxwDocument(docName);
+ sxwDoc.initContentDOM();
+
+ org.w3c.dom.Document doc = sxwDoc.getContentDOM();
+
+ // Grab hold of the office:body tag,
+ // Assume there should be one.
+ // This is where top level paragraphs will append to.
+ NodeList list = doc.getElementsByTagName(TAG_OFFICE_BODY);
+ Node bodyNode = list.item(0);
+
+ styleCat = new StyleCatalog(50);
+ oldStyleCat = new StyleCatalog(50);
+ if (origDoc != null)
+ readStyleCatalog(origDoc);
+
+ Element currPara = null;
+ ParaStyle currParaStyle = null;
+ int newTextStyleNr = 0;
+ int newParaStyleNr = 0;
+
+ // Now write out the document body by running through
+ // the list of WordSmith elements and processing each one
+ // in turn.
+ for (int i = 0; i < data.length; i++) {
+
+ if (data[i].getClass() == WsePara.class) {
+
+ currPara = doc.createElement(TAG_PARAGRAPH);
+ log("</PARA>");
+ log("<PARA>");
+
+ WsePara p = (WsePara)data[i];
+
+ // Save info about the first text run, if there is one.
+ WseTextRun firstTextRun = null;
+
+ if ((data.length >= i + 2)
+ && (data[i+1].getClass() == WseTextRun.class))
+ firstTextRun = (WseTextRun)data[i+1];
+
+ Style matches[] = oldStyleCat.getMatching(p.makeStyle());
+
+ // See if we can find a unique match in the catalog
+ // of existing styles from the original document.
+ ParaStyle pStyle = null;
+ if (matches.length == 1) {
+ pStyle = (ParaStyle)matches[0];
+ log("using an existing style");
+ } else if ((matches.length > 1) && (firstTextRun != null)) {
+ pStyle = matchParaByText(matches, firstTextRun.makeStyle());
+ log("resolved a para by looking @ text");
+ }
+
+ // If nothing found so far, try looking in the catalog
+ // of newly-created styles.
+ // DJP FIXME: if we need to add two para styles with the
+ // same para formatting info but different default text
+ // styles, this won't work!
+ if (pStyle == null) {
+ log("had " + matches.length + " matches in old catalog");
+ matches = styleCat.getMatching(p.makeStyle());
+ if (matches.length == 0) {
+ pStyle = p.makeStyle();
+ String newName = new String("PPP" + ++newParaStyleNr);
+ pStyle.setName(newName);
+ styleCat.add(pStyle);
+ // DJP: write in the text format info here
+ log("created a new style");
+ } else if (matches.length == 1) {
+ pStyle = (ParaStyle)matches[0];
+ log("re-using a new style");
+ } else if (firstTextRun != null) {
+ pStyle = matchParaByText(matches, firstTextRun.makeStyle());
+ if (pStyle != null) {
+ log("resolved a (new) para by looking @ text");
+ } else
+ log("Hey this shouldn't happen! - nr of matches is "
+ + matches.length);
+ }
+ }
+
+ if (pStyle == null)
+ log("Unable to figure out a para style");
+
+ // Figured out a style to use. Specify the style in this
+ // paragraph's attributes.
+ currPara.setAttribute(ATTRIBUTE_TEXT_STYLE_NAME, pStyle.getName());
+
+ bodyNode.appendChild(currPara);
+ currParaStyle = pStyle;
+ } else if (data[i].getClass() == WseTextRun.class) {
+ WseTextRun tr = (WseTextRun)data[i];
+ TextStyle trStyle = null;
+ Node trNodes[] = parseText(tr.getText(), doc);
+
+ // First see if the formatting of this text run matches
+ // the default text formatting for this paragraph. If
+ // it does, then just make the text node(s) children of
+ // the current paragraph.
+ Style[] cps = new Style[1];
+ cps[0] = currParaStyle;
+ if (matchParaByText(cps, tr.makeStyle()) != null) {
+ for (int ii = 0; ii < trNodes.length; ii++) {
+ currPara.appendChild(trNodes[ii]);
+ }
+ continue;
+ }
+
+ // Check for existing, matching styles in the old style
+ // catalog. If exactly one is found, use it. Otherwise,
+ // check the new style catalog, and either use the style
+ // found or add this new one to it.
+ Style matches[] = oldStyleCat.getMatching(tr.makeStyle());
+ if (matches.length == 1)
+ trStyle = (TextStyle)matches[0];
+ else {
+ matches = styleCat.getMatching(tr.makeStyle());
+ if (matches.length == 0) {
+ trStyle = tr.makeStyle();
+ String newName = new String("TTT" + ++newTextStyleNr);
+ trStyle.setName(newName);
+ styleCat.add(trStyle);
+ } else if (matches.length == 1)
+ trStyle = (TextStyle)matches[0];
+ else
+ log("multiple text style matches from new catalog");
+ }
+
+ // Create a text span node, set the style attribute, make the
+ // text node(s) its children, and append it to current paragraph's
+ // list of children.
+ Element textSpanNode = doc.createElement(TAG_SPAN);
+ textSpanNode.setAttribute(ATTRIBUTE_TEXT_STYLE_NAME, trStyle.getName());
+ for (int ii = 0; ii < trNodes.length; ii++) {
+ textSpanNode.appendChild(trNodes[ii]);
+ }
+ currPara.appendChild(textSpanNode);
+ log("</SPAN>");
+ }
+
+ else if (data[i].getClass() == WseFontTable.class) {
+ fontTable = (WseFontTable)data[i];
+ }
+
+ else if (data[i].getClass() == WseColorTable.class) {
+ colorTable = (WseColorTable)data[i];
+ }
+ }
+
+
+ //NodeList r = doc.getElementsByTagName(TAG_OFFICE_DOCUMENT);
+ NodeList r = doc.getElementsByTagName(TAG_OFFICE_DOCUMENT_CONTENT);
+ Node rootNode = r.item(0);
+
+ // read the original document
+ org.w3c.dom.NodeList nl;
+ if (origDoc != null) {
+ java.io.ByteArrayOutputStream bos = new java.io.ByteArrayOutputStream();
+ origDoc.write(bos);
+ SxwDocument origSxwDoc = new SxwDocument("old");
+ origSxwDoc.read(new ByteArrayInputStream(bos.toByteArray()));
+ org.w3c.dom.Document origDomDoc = origSxwDoc.getContentDOM();
+
+ XmlUtil xu = new XmlUtil();
+ org.w3c.dom.DocumentFragment df;
+ org.w3c.dom.Node newNode;
+
+ // copy font declarations from original document to the new document
+ nl = origDomDoc.getElementsByTagName(TAG_OFFICE_FONT_DECLS);
+ df = doc.createDocumentFragment();
+ newNode = xu.deepClone(df, nl.item(0));
+ rootNode.insertBefore(newNode, bodyNode);
+
+ // copy style catalog from original document to the new document
+ nl = origDomDoc.getElementsByTagName(TAG_OFFICE_STYLES);
+ df = doc.createDocumentFragment();
+ newNode = xu.deepClone(df, nl.item(0));
+ rootNode.insertBefore(newNode, bodyNode);
+
+ nl = origDomDoc.getElementsByTagName(TAG_OFFICE_AUTOMATIC_STYLES);
+ df = doc.createDocumentFragment();
+ newNode = xu.deepClone(df, nl.item(0));
+ rootNode.insertBefore(newNode, bodyNode);
+
+ nl = origDomDoc.getElementsByTagName(TAG_OFFICE_MASTER_STYLES);
+ df = doc.createDocumentFragment();
+ newNode = xu.deepClone(df, nl.item(0));
+ rootNode.insertBefore(newNode, bodyNode);
+ }
+
+ // Original document not specified. We need to add font declarations.
+ // DJP: this might just be for debugging. Merger will probably put
+ // the "real" ones in.
+ // DJP: if really doing it this way, do it right: gather font names
+ // from style catalog(s).
+ else {
+ org.w3c.dom.Node declNode;
+
+ log("<FONT-DECLS/>");
+
+ declNode = doc.createElement(TAG_OFFICE_FONT_DECLS);
+ rootNode.insertBefore(declNode, bodyNode);
+ org.w3c.dom.Element fontNode;
+
+ fontNode = doc.createElement(TAG_STYLE_FONT_DECL);
+ fontNode.setAttribute(ATTRIBUTE_STYLE_NAME, "Arial");
+ fontNode.setAttribute(ATTRIBUTE_FO_FONT_FAMILY, "Arial");
+ fontNode.setAttribute(ATTRIBUTE_STYLE_FONT_PITCH, "variable");
+ declNode.appendChild(fontNode);
+
+ fontNode = doc.createElement(TAG_STYLE_FONT_DECL);
+ fontNode.setAttribute(ATTRIBUTE_STYLE_NAME, "Arioso");
+ fontNode.setAttribute(ATTRIBUTE_FO_FONT_FAMILY, "Arioso");
+ fontNode.setAttribute(ATTRIBUTE_STYLE_FONT_PITCH, "variable");
+ declNode.appendChild(fontNode);
+ }
+
+
+ // Now add any new styles we have created in this document.
+ nl = doc.getElementsByTagName(TAG_OFFICE_AUTOMATIC_STYLES);
+ Node autoStylesNode = nl.item(0);
+ if (autoStylesNode == null) {
+ autoStylesNode = doc.createElement(TAG_OFFICE_AUTOMATIC_STYLES);
+ log("<OFFICE-AUTOMATIC-STYLES/>");
+ rootNode.insertBefore(autoStylesNode, bodyNode);
+ }
+
+ Node newStyleCatNode = styleCat.writeNode(doc, "dummy");
+ nl = newStyleCatNode.getChildNodes();
+ int nNodes = nl.getLength();
+ for (int i = 0; i < nNodes; i++) {
+ autoStylesNode.appendChild(nl.item(0));
+ }
+
+ oldStyleCat.dumpCSV(true);
+ styleCat.dumpCSV(true);
+ return sxwDoc;
+ }
+
+
+ /**
+ * Sends message to the log object.
+ *
+ * @param str Debug message.
+ */
+ private void log(String str) {
+
+ Debug.log(Debug.TRACE, str);
+ }
+
+
+ /*
+ public static void main(String args[]) {
+
+ // DocumentDeserializerImpl d = new DocumentDeserializerImpl(new InputStream());
+
+ Node nodes[] = parseText("Tab here:\tThen some more text");
+ }
+*/
+}
+
diff --git a/xmerge/source/wordsmith/java/org/openoffice/xmerge/converter/xml/sxw/wordsmith/DocumentMergerImpl.java b/xmerge/source/wordsmith/java/org/openoffice/xmerge/converter/xml/sxw/wordsmith/DocumentMergerImpl.java
new file mode 100644
index 000000000000..b338c9adb6ff
--- /dev/null
+++ b/xmerge/source/wordsmith/java/org/openoffice/xmerge/converter/xml/sxw/wordsmith/DocumentMergerImpl.java
@@ -0,0 +1,99 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxw.wordsmith;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+import org.openoffice.xmerge.DocumentMerger;
+import org.openoffice.xmerge.MergeException;
+import org.openoffice.xmerge.ConverterCapabilities;
+import org.openoffice.xmerge.converter.xml.sxw.SxwDocument;
+import org.openoffice.xmerge.merger.DiffAlgorithm;
+import org.openoffice.xmerge.merger.Difference;
+import org.openoffice.xmerge.merger.NodeMergeAlgorithm;
+import org.openoffice.xmerge.merger.Iterator;
+import org.openoffice.xmerge.merger.DiffAlgorithm;
+import org.openoffice.xmerge.merger.diff.ParaNodeIterator;
+import org.openoffice.xmerge.merger.diff.IteratorLCSAlgorithm;
+import org.openoffice.xmerge.merger.merge.DocumentMerge;
+import org.openoffice.xmerge.merger.merge.CharacterBaseParagraphMerge;
+import org.openoffice.xmerge.util.Debug;
+
+
+/**
+ * Wordsmith implementation of <code>DocumentMerger</code>
+ * for the {@link
+ * org.openoffice.xmerge.converter.xml.sxw.wordsmith.PluginFactoryImpl
+ * PluginFactoryImpl}.</p>
+ */
+public class DocumentMergerImpl implements DocumentMerger {
+
+ private ConverterCapabilities cc_;
+ private org.openoffice.xmerge.Document orig = null;
+
+ public DocumentMergerImpl(org.openoffice.xmerge.Document doc, ConverterCapabilities cc) {
+ cc_ = cc;
+ this.orig = doc;
+ }
+
+ public void merge(org.openoffice.xmerge.Document modifiedDoc) throws MergeException {
+
+ SxwDocument wdoc1 = (SxwDocument) orig;
+ SxwDocument wdoc2 = (SxwDocument) modifiedDoc;
+
+ Document doc1 = wdoc1.getContentDOM();
+ Document doc2 = wdoc2.getContentDOM();
+
+ Iterator i1 = new ParaNodeIterator(cc_, doc1.getDocumentElement());
+ Iterator i2 = new ParaNodeIterator(cc_, doc2.getDocumentElement());
+
+ DiffAlgorithm diffAlgo = new IteratorLCSAlgorithm();
+
+ // find out the paragrah level diffs
+ Difference[] diffTable = diffAlgo.computeDiffs(i1, i2);
+
+ if (Debug.isFlagSet(Debug.INFO)) {
+ Debug.log(Debug.INFO, "Diff Result: ");
+
+ for (int i = 0; i < diffTable.length; i++) {
+ Debug.log(Debug.INFO, diffTable[i].debug());
+ }
+ }
+
+ // merge the paragraphs
+ NodeMergeAlgorithm charMerge = new CharacterBaseParagraphMerge();
+ DocumentMerge docMerge = new DocumentMerge(cc_, charMerge);
+
+ Iterator result = null;
+
+ docMerge.applyDifference(i1, i2, diffTable);
+ }
+}
+
+
diff --git a/xmerge/source/wordsmith/java/org/openoffice/xmerge/converter/xml/sxw/wordsmith/DocumentSerializerImpl.java b/xmerge/source/wordsmith/java/org/openoffice/xmerge/converter/xml/sxw/wordsmith/DocumentSerializerImpl.java
new file mode 100644
index 000000000000..bca91fa53415
--- /dev/null
+++ b/xmerge/source/wordsmith/java/org/openoffice/xmerge/converter/xml/sxw/wordsmith/DocumentSerializerImpl.java
@@ -0,0 +1,536 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxw.wordsmith;
+
+import org.w3c.dom.NodeList;
+import org.w3c.dom.Node;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Element;
+
+import java.io.IOException;
+
+import org.openoffice.xmerge.Document;
+import org.openoffice.xmerge.ConvertData;
+import org.openoffice.xmerge.ConvertException;
+import org.openoffice.xmerge.DocumentSerializer;
+import org.openoffice.xmerge.ConverterCapabilities;
+import org.openoffice.xmerge.converter.xml.OfficeConstants;
+import org.openoffice.xmerge.converter.xml.sxw.SxwDocument;
+import org.openoffice.xmerge.converter.palm.PalmDB;
+import org.openoffice.xmerge.converter.palm.PdbEncoder;
+import org.openoffice.xmerge.converter.palm.Record;
+import org.openoffice.xmerge.converter.palm.PdbUtil;
+import org.openoffice.xmerge.converter.palm.PalmDocument;
+import org.openoffice.xmerge.converter.xml.OfficeDocument;
+import org.openoffice.xmerge.util.*;
+import org.openoffice.xmerge.converter.xml.*;
+
+/**
+ * <p>WordSmith implementation of
+ * org.openoffice.xmerge.DocumentSerializer
+ * for the {@link
+ * org.openoffice.xmerge.converter.xml.sxw.wordsmith.PluginFactoryImpl
+ * PluginFactoryImpl}.</p>
+ *
+ * <p>The <code>serialize</code> method traverses the DOM
+ * document from the given <code>Document</code> object. It uses a
+ * <code>DocEncoder</code> object for the actual conversion of
+ * contents to the WordSmith format.</p>
+ *
+ * @author Herbie Ong, David Proulx
+ */
+
+// DJP: take out "implements OfficeConstants"
+public final class DocumentSerializerImpl
+implements OfficeConstants, DocumentSerializer {
+
+ /** A WSEncoder object for encoding to WordSmith. */
+ private WSEncoder encoder = null;
+
+ /** The <code>StyleCatalog</code>. */
+ private StyleCatalog styleCat = null;
+
+ private WseFontTable fontTable = new WseFontTable();
+ private WseColorTable colorTable = new WseColorTable();
+
+ /**
+ * The <code>SxwDocument</code> object that this converter
+ * processes.
+ */
+ private SxwDocument sxwDoc = null;
+
+ /**
+ * Constructor.
+ *
+ * @param doc The <code>Document</code> to convert.
+ */
+ public DocumentSerializerImpl(Document doc) {
+ sxwDoc = (SxwDocument) doc;
+ }
+
+
+ /**
+ * <p>Method to convert a <code>Document</code> into a
+ * <code>PalmDocument</code>.</p>
+ *
+ * <p>This method is not thread safe for performance reasons.
+ * This method should not be called from within two threads.
+ * It would be best to call this method only once per object
+ * instance.</p>
+ *
+ * <p>Note that the doc parameter needs to be an XML
+ * <code>Document</code>, else this method will throw a
+ * <code>ClassCastException</code>. I think this is a hack,
+ * but this is the only way to not modify most of the existing
+ * code right now.</p>
+ *
+ * @param doc Input should be an XML <code>Document</code>
+ * object
+ * @param os Output of <code>PalmDB</code> object
+ *
+ * @throws ConvertException If any conversion error occurs.
+ * @throws IOException If any I/O error occurs.
+ */
+ public ConvertData serialize()
+ throws IOException {
+
+
+ // get the server document name
+ String docName = sxwDoc.getName();
+
+ // get DOM document
+ org.w3c.dom.Document domDoc = sxwDoc.getContentDOM();
+
+ // Create WordSmith encoder object. Add WordSmith header,
+ // empty font table to it.
+ encoder = new WSEncoder();
+ encoder.addElement(fontTable);
+ encoder.addElement(colorTable);
+
+ // Read the styles into the style catalog
+ String families[] = new String[3];
+ families[0] = "text";
+ families[1] = "paragraph";
+ families[2] = "paragraph";
+ Class classes[] = new Class[3];
+ classes[0] = TextStyle.class;
+ classes[1] = ParaStyle.class;
+ classes[2] = TextStyle.class;
+ styleCat = new StyleCatalog(25);
+
+ // Parse the input document
+ // DJP todo: eliminate multiple calls to add() when it can
+ // recurse properly.
+ NodeList nl = domDoc.getElementsByTagName(TAG_OFFICE_STYLES);
+ styleCat.add(nl.item(0), families, classes, null, false);
+ nl = domDoc.getElementsByTagName(TAG_OFFICE_AUTOMATIC_STYLES);
+ styleCat.add(nl.item(0), families, classes, null, false);
+ nl = domDoc.getElementsByTagName(TAG_OFFICE_MASTER_STYLES);
+ styleCat.add(nl.item(0), families, classes, null, false);
+
+ // Traverse to the office:body element.
+ // There should only be one.
+ NodeList list = domDoc.getElementsByTagName(TAG_OFFICE_BODY);
+ int len = list.getLength();
+ if (len > 0) {
+ Node node = list.item(0);
+ traverseBody(node);
+ }
+
+ // create a PalmDB object and ConvertData object.
+ //
+ Record records[] = encoder.getRecords();
+
+ ConvertData cd = new ConvertData();
+ PalmDocument palmDoc = new PalmDocument(docName,
+ PdbUtil.intID("WrdS"), PdbUtil.intID("BDOC"), 0,
+ PalmDB.PDB_HEADER_ATTR_BACKUP, records);
+ cd.addDocument(palmDoc);
+ return cd;
+ }
+
+
+ /**
+ * This method traverses <i>office:body</i> element.
+ *
+ * @param node <i>office:body</i> <code>Node</code>.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ private void traverseBody(Node node) throws IOException {
+
+ if (node.hasChildNodes()) {
+
+ NodeList nodeList = node.getChildNodes();
+ int len = nodeList.getLength();
+
+ for (int i = 0; i < len; i++) {
+
+ Node child = nodeList.item(i);
+
+ if (child.getNodeType() == Node.ELEMENT_NODE) {
+ String nodeName = child.getNodeName();
+
+ if (nodeName.equals(TAG_PARAGRAPH) ||
+ nodeName.equals(TAG_HEADING)) {
+
+ traverseParagraph(child);
+
+ } else if (nodeName.equals(TAG_UNORDERED_LIST)) {
+
+ traverseList(child);
+
+ } else if (nodeName.equals(TAG_ORDERED_LIST)) {
+
+ traverseList(child);
+
+ } else {
+
+ Debug.log(Debug.INFO, "<OTHERS " /* + XmlDebug.nodeInfo(child) */ + " />");
+ }
+ }
+ }
+ }
+
+ }
+
+
+ /**
+ * This method traverses the <i>text:p</i> and <i>text:h</i>
+ * element <code>Node</code> objects.
+ *
+ * @param node A <i>text:p</i> or <i>text:h</i> <code>Node</code>.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ private void traverseParagraph(Node node) throws IOException {
+
+ String styleName = findAttribute(node, "text:style-name");
+ ParaStyle pstyle = (ParaStyle)styleCat.lookup(styleName, "paragraph",
+ null, ParaStyle.class);
+
+ // If the style does not exist in the style catalog for some reason,
+ // make up a default style and use it. We'll have to add this default
+ // style to the style catalog the first time it is used.
+ if (pstyle == null) {
+ styleName = "CONVERTER-DEFAULT";
+ pstyle = (ParaStyle)styleCat.lookup(styleName, "paragraph", null,
+ ParaStyle.class);
+ if (pstyle == null) {
+ pstyle = new ParaStyle(styleName, "paragraph", null,
+ (String [])null, null, styleCat);
+ styleCat.add(pstyle);
+ styleCat.add(new TextStyle(styleName, "paragraph", null,
+ 0, 0, 12, "Times-Roman", styleCat));
+ }
+ }
+
+ pstyle = (ParaStyle)pstyle.getResolved();
+ encoder.addElement(new WsePara(pstyle, styleCat));
+ TextStyle defParaTextStyle = (TextStyle)
+ styleCat.lookup(styleName, "paragraph", null, TextStyle.class);
+
+ traverseParaContents(node, defParaTextStyle);
+ }
+
+
+ /**
+ * This method traverses a paragraph content. Note that this
+ * method may recurse to call itself.
+ *
+ * @param node A paragraph or content <code>Node</code>
+ */
+ private void traverseParaContents(Node node, TextStyle defTextStyle) {
+
+ String styleName = findAttribute(node, "text:style-name");
+ TextStyle style = (TextStyle)
+ styleCat.lookup(styleName, "text", null, TextStyle.class);
+
+ if (node.hasChildNodes()) {
+ NodeList nodeList = node.getChildNodes();
+ int nChildren = nodeList.getLength();
+
+ for (int i = 0; i < nChildren; i++) {
+ Node child = nodeList.item(i);
+
+ if (child.getNodeType() == Node.TEXT_NODE) {
+
+ // this is for grabbing text nodes.
+ String s = child.getNodeValue();
+
+ if (s.length() > 0) {
+ if (style != null)
+ encoder.addElement(new WseTextRun(s, style, styleCat,
+ fontTable, colorTable));
+ else
+ encoder.addElement(new WseTextRun(s, defTextStyle,
+ styleCat, fontTable, colorTable));
+ }
+
+ } else if (child.getNodeType() == Node.ELEMENT_NODE) {
+
+ String childNodeName = child.getNodeName();
+
+ if (childNodeName.equals(TAG_SPACE)) {
+
+ // this is for text:s tags.
+ NamedNodeMap map = child.getAttributes();
+ Node attr = map.getNamedItem(ATTRIBUTE_SPACE_COUNT);
+ StringBuffer space = new StringBuffer(" ");
+ int count = 1;
+
+ if (attr != null) {
+ try {
+ String countStr = attr.getNodeValue();
+ count = Integer.parseInt(countStr.trim());
+ } catch (NumberFormatException e) {
+ Debug.log(Debug.ERROR, "Problem parsing space tag", e);
+ }
+ }
+
+ for (int j = 1; j < count; j++)
+ space.append(" ");
+
+ encoder.addElement(new WseTextRun(space.toString(),
+ defTextStyle,
+ styleCat, fontTable, colorTable));
+ Debug.log(Debug.INFO, "<SPACE count=\"" + count + "\" />");
+
+ } else if (childNodeName.equals(TAG_TAB_STOP)) {
+
+ // this is for text:tab-stop
+ encoder.addElement(new WseTextRun("\t", defTextStyle, styleCat,
+ fontTable, colorTable));
+
+ Debug.log(Debug.INFO, "<TAB/>");
+
+ } else if (childNodeName.equals(TAG_LINE_BREAK)) {
+
+ // this is for text:line-break
+ encoder.addElement(new WseTextRun("\n", defTextStyle,
+ styleCat, fontTable, colorTable));
+
+ Debug.log(Debug.INFO, "<LINE-BREAK/>");
+
+ } else if (childNodeName.equals(TAG_SPAN)) {
+
+ // this is for text:span
+ Debug.log(Debug.INFO, "<SPAN>");
+ traverseParaContents(child, defTextStyle);
+ Debug.log(Debug.INFO, "</SPAN>");
+
+ } else if (childNodeName.equals(TAG_HYPERLINK)) {
+
+ // this is for text:a
+ Debug.log(Debug.INFO, "<HYPERLINK>");
+ traverseParaContents(child, defTextStyle);
+ Debug.log(Debug.INFO, "<HYPERLINK/>");
+
+ } else if (childNodeName.equals(TAG_BOOKMARK) ||
+ childNodeName.equals(TAG_BOOKMARK_START)) {
+
+ Debug.log(Debug.INFO, "<BOOKMARK/>");
+
+ } else {
+
+ Debug.log(Debug.INFO, "<OTHERS " /* + XmlDebug.nodeInfo(child) */ + " />");
+ }
+
+ }
+
+ }
+ }
+ }
+
+
+ /**
+ * This method traverses list tags <i>text:unordered-list</i> and
+ * <i>text:ordered-list</i>. A list can only contain one optional
+ * <i>text:list-header</i> and one or more <i>text:list-item</i>
+ * elements.
+ *
+ * @param node A list <code>Node</code>.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ private void traverseList(Node node) throws IOException {
+
+ Debug.log(Debug.TRACE, "<LIST>");
+
+ if (node.hasChildNodes()) {
+
+ NodeList nodeList = node.getChildNodes();
+ int len = nodeList.getLength();
+
+ for (int i = 0; i < len; i++) {
+
+ Node child = nodeList.item(i);
+
+ if (child.getNodeType() == Node.ELEMENT_NODE) {
+
+ String nodeName = child.getNodeName();
+
+ if (nodeName.equals(TAG_LIST_ITEM)) {
+
+ traverseListItem(child);
+
+ } else if (nodeName.equals(TAG_LIST_HEADER)) {
+
+ traverseListHeader(child);
+
+ } else {
+
+ Debug.log(Debug.ERROR, "<INVALID-XML-BUG " + " />");
+ }
+ }
+ }
+ }
+
+ Debug.log(Debug.TRACE, "</LIST>");
+ }
+
+
+ /**
+ * This method traverses a <i>text:list-header</i> element.
+ * It contains one or more <i>text:p</i> elements.
+ *
+ * @param node A list header <code>Node</code>.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ private void traverseListHeader(Node node) throws IOException {
+
+ Debug.log(Debug.TRACE, "<LIST-HEADER>");
+
+ if (node.hasChildNodes()) {
+
+ NodeList nodeList = node.getChildNodes();
+ int len = nodeList.getLength();
+
+ for (int i = 0; i < len; i++) {
+
+ Node child = nodeList.item(i);
+
+ if (child.getNodeType() == Node.ELEMENT_NODE) {
+
+ String nodeName = child.getNodeName();
+
+ if (nodeName.equals(TAG_PARAGRAPH)) {
+
+ traverseParagraph(child);
+
+ } else {
+
+ Debug.log(Debug.TRACE, "<INVALID-XML-BUG " + " />");
+ }
+ }
+ }
+ }
+
+ Debug.log(Debug.TRACE, "</LIST-HEADER>");
+ }
+
+
+ /**
+ * This method will traverse a <i>text:list-item</i>.
+ * A list item may contain one or more of <i>text:p</i>,
+ * <i>text:h</i>, <i>text:section</i>,
+ * <i>text:ordered-list</i> and <i>text:unordered-list</i>.
+ *
+ * This method currently only implements grabbing <i>text:p</i>,
+ * <i>text:h</i>, <i>text:unordered-list</i> and
+ * <i>text:ordered-list</i>.
+ *
+ * @param Node <code>Node</code> to traverse.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ private void traverseListItem(Node node) throws IOException {
+
+ Debug.log(Debug.TRACE, "<LIST-ITEM>");
+
+ if (node.hasChildNodes()) {
+
+ NodeList nodeList = node.getChildNodes();
+ int len = nodeList.getLength();
+
+ for (int i = 0; i < len; i++) {
+
+ Node child = nodeList.item(i);
+
+ if (child.getNodeType() == Node.ELEMENT_NODE) {
+
+ String nodeName = child.getNodeName();
+
+ if (nodeName.equals(TAG_PARAGRAPH)) {
+
+ traverseParagraph(child);
+
+ } else if (nodeName.equals(TAG_UNORDERED_LIST)) {
+
+ traverseList(child);
+
+ } else if (nodeName.equals(TAG_ORDERED_LIST)) {
+
+ traverseList(child);
+
+ } else {
+
+ Debug.log(Debug.ERROR, "<INVALID-XML-BUG " + " />");
+ }
+ }
+ }
+ }
+
+ Debug.log(Debug.TRACE, "</LIST-ITEM>");
+ }
+
+
+ /**
+ * Look up a <code>Node</code> object's named attribute and return
+ * its value
+ *
+ * @param node The <code>Node</code>.
+ * @param name The attribute name.
+ *
+ * @return The value of the named attribute
+ */
+ private String findAttribute(Node node, String name) {
+ 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(name))
+ return attr.getNodeValue();
+ }
+ }
+ return null;
+ }
+}
+
diff --git a/xmerge/source/wordsmith/java/org/openoffice/xmerge/converter/xml/sxw/wordsmith/PluginFactoryImpl.java b/xmerge/source/wordsmith/java/org/openoffice/xmerge/converter/xml/sxw/wordsmith/PluginFactoryImpl.java
new file mode 100644
index 000000000000..d7e84d69f34c
--- /dev/null
+++ b/xmerge/source/wordsmith/java/org/openoffice/xmerge/converter/xml/sxw/wordsmith/PluginFactoryImpl.java
@@ -0,0 +1,149 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxw.wordsmith;
+
+import org.openoffice.xmerge.Document;
+import org.openoffice.xmerge.ConvertData;
+import org.openoffice.xmerge.DocumentMerger;
+import org.openoffice.xmerge.DocumentMergerFactory;
+import org.openoffice.xmerge.DocumentSerializer;
+import org.openoffice.xmerge.DocumentSerializerFactory;
+import org.openoffice.xmerge.DocumentDeserializer;
+import org.openoffice.xmerge.DocumentDeserializerFactory;
+import org.openoffice.xmerge.ConverterCapabilities;
+import org.openoffice.xmerge.converter.xml.sxw.SxwPluginFactory;
+import org.openoffice.xmerge.converter.palm.PalmDocument;
+import org.openoffice.xmerge.util.registry.ConverterInfo;
+
+import java.io.InputStream;
+import java.io.IOException;
+
+
+/**
+ * <p>WordSmith implementation of a <code>PluginFactory</code> that
+ * encapsulates conversion of StarWriter XML format to and from
+ * WordSmith format.</p>
+ *
+ * The superclass produces a particular
+ * {@link org.openoffice.xmerge.Document Document}
+ * object, i.e.
+ * {@link org.openoffice.xmerge.converter.xml.sxw.SxwDocument
+ * SxwDocument} that the converters in this class works with. Thus,
+ * this class only implements the methods that produces the converters,
+ * i.e. {@link
+ * org.openoffice.xmerge.DocumentSerializer
+ * DocumentSerializer} and {@link
+ * org.openoffice.xmerge.DocumentDeserializer
+ * DocumentDeserializer};
+ * as well as the {@link
+ * org.openoffice.xmerge.ConverterCapabilities
+ * ConverterCapabilities} object that is specific to this format
+ * conversion. That superclass also produces a {@link
+ * org.openoffice.xmerge.DocumentMerger DocumentMerger}
+ * object, i.e. {@link
+ * org.openoffice.xmerge.converter.xml.sxw.wordsmith.DocumentMergerImpl
+ * DocumentMergerImpl} which this class derives the functionality.</p>
+ *
+ * @author Herbie Ong, Dave Proulx
+ */
+public final class PluginFactoryImpl extends SxwPluginFactory
+ implements DocumentDeserializerFactory, DocumentSerializerFactory,
+ DocumentMergerFactory {
+
+ public PluginFactoryImpl(ConverterInfo ci) {
+ super(ci);
+ }
+
+ /** ConverterCapabilities object for this type of conversion. */
+ private final static ConverterCapabilities converterCap =
+ new ConverterCapabilitiesImpl();
+
+
+ /**
+ * Returns an instance of <code>DocumentSerializerImpl</code>, which is
+ * an implementation of <code>DocumentSerializer</code> interface.
+ *
+ * @param doc <code>Document</code> object to be converted/serialized.
+ *
+ * @return A <code>DocumentSerializerImpl</code> object.
+ */
+ public DocumentSerializer createDocumentSerializer(Document doc) {
+
+ return new DocumentSerializerImpl(doc);
+ }
+
+
+ /**
+ * Returns an instance of <code>DocumentDeserializerImpl</code>,
+ * which is an implementation of <code>DocumentDeserializer</code>
+ * interface.
+ *
+ * @param cd <code>ConvertData</code> object for reading data
+ * which will be converted back to a
+ * <code>Document</code> object.
+ *
+ * @return A <code>DocumentDeserializerImpl</code> object.
+ */
+ public DocumentDeserializer createDocumentDeserializer(ConvertData cd) {
+
+ return new DocumentDeserializerImpl(cd);
+ }
+
+ /**
+ * Returns an instance of <code>DocumentMergerImpl</code>,
+ * which is an implementation of the <code>DocumentMerger</code>
+ * interface.
+ *
+ * @param doc <code>Document</code> to merge.
+ *
+ * @return A DocumentMergerImpl object.
+ */
+ public DocumentMerger createDocumentMerger(Document doc) {
+
+ ConverterCapabilities cc = converterCap;
+ DocumentMergerImpl merger = new DocumentMergerImpl(doc, cc);
+ return merger;
+ }
+
+ /**
+ * Returns an instance of the DeviceDocument
+ * which is an implementation of the <code>DocumentMerger</code>
+ * interface.
+ *
+ * @param doc <code>Document</code> to merge.
+ *
+ * @return A Device Document object
+ */
+ public Document createDeviceDocument(String name, InputStream is)
+ throws IOException {
+
+ PalmDocument palmDoc = new PalmDocument(is);
+ return palmDoc;
+ }
+}
+
diff --git a/xmerge/source/wordsmith/java/org/openoffice/xmerge/converter/xml/sxw/wordsmith/WSDecoder.java b/xmerge/source/wordsmith/java/org/openoffice/xmerge/converter/xml/sxw/wordsmith/WSDecoder.java
new file mode 100644
index 000000000000..5ac9bc01c725
--- /dev/null
+++ b/xmerge/source/wordsmith/java/org/openoffice/xmerge/converter/xml/sxw/wordsmith/WSDecoder.java
@@ -0,0 +1,352 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxw.wordsmith;
+
+import java.io.ByteArrayInputStream;
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.io.FileInputStream;
+import java.io.UnsupportedEncodingException;
+import org.openoffice.xmerge.util.Debug;
+
+import org.openoffice.xmerge.converter.palm.*;
+import org.openoffice.xmerge.util.Resources;
+
+/**
+ * This class is used by {@link
+ * org.openoffice.xmerge.converter.xml.sxw.wordsmith.DocumentDeserializerImpl
+ * DocumentDeserializerImpl} to decode a WordSmith format. It currently
+ * decodes the text content into a single <code>String</code> object.
+ *
+ * @author Herbie Ong, David Proulx
+ */
+final class WSDecoder implements DOCConstants {
+
+ /** For decoding purposes. */
+ private final static int COUNT_BITS = 3;
+
+ /** Resources object for I18N. */
+ private Resources res = null;
+
+ /**
+ * Default constructor creates a header and
+ * a text buffer for holding all the text in
+ * the DOC db.
+ */
+ WSDecoder() {
+ res = Resources.getInstance();
+ }
+
+ /**
+ * Decode the text records into a single <code>byte</code> array.
+ *
+ * @param Record <code>Record</code> array holding WordSmith
+ * contents.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ byte[] parseRecords(Record[] recs) throws IOException {
+
+ // read the header record
+ HeaderInfo header = readHeader(recs[0].getBytes());
+ dumpHeader(header);
+ byte[][] byteArrays = new byte[recs.length - 1][];
+ for (int i = 0; i < recs.length - 1; i++) byteArrays[i] = null;
+
+ switch (header.version & ~4) { // DJP: "4" indicates OOB data is present.
+ // Add a constant to handle this, might also need code to handle it.
+
+ case COMPRESSED:
+ case 3: // DJP: determined this empirically. Are Herbie's constants wrong?
+ for (int i = 1; i < recs.length; i++) {
+ byteArrays[i-1] = decompress(recs[i].getBytes(),
+ header.textRecordSize);
+ Debug.log(Debug.INFO, "processing " + byteArrays[i-1].length + " bytes");
+ }
+
+ break;
+
+ case UNCOMPRESSED:
+ for (int i = 1; i < recs.length; i++) {
+ byteArrays[i-1] = recs[i].getBytes();
+ Debug.log(Debug.INFO, "processing " + byteArrays[i-1].length + " bytes");
+ }
+
+ break;
+
+ default:
+ throw new IOException(res.getString("UNKNOWN_DOC_VERSION"));
+
+ }
+
+ // Concatenate byteArrays[][] into a single byte array.
+ int length = 0;
+ for (int i = 0; i < recs.length - 1; i++)
+ length += byteArrays[i].length;
+ byte bigArray[] = new byte[length];
+ int offset = 0;
+ for (int i = 0; i < recs.length - 1; i++) {
+ System.arraycopy(byteArrays[i], 0, bigArray, offset,
+ byteArrays[i].length);
+ offset += byteArrays[i].length;
+ }
+ return bigArray;
+ }
+
+
+ /**
+ * Decode the text records into a <code>Wse</code> array.
+ *
+ * @param Record[] <code>Record</code> array holding DOC
+ * contents.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ Wse[] parseDocument(Record[] recs) throws IOException {
+
+ java.util.Vector v = new java.util.Vector(20, 20);
+ WseFontTable fontTable = null;
+ WseColorTable colorTable = null;
+
+ // rawData is the document data to be parsed.
+ byte rawData[] = parseRecords(recs);
+
+ // beginning of document has some header information, including
+ // optional font and color tables.
+ // DJP: maybe should add a new WSelement (docHeader) to hold
+ // header info.
+ // DJP: finish code here to parse header
+ if (rawData[0] != 2) throw new IOException();
+ int nParagraphs = util.intFrom4bytes(rawData, 2);
+ int nAtoms = util.intFrom4bytes(rawData, 6);
+ int nChars = util.intFrom4bytes(rawData, 10);
+ int miscSize = util.intFrom4bytes(rawData, 14);
+ int curIndex = 18;
+
+ while (curIndex < rawData.length) {
+ if (WsePara.isValid(rawData, curIndex)) {
+ v.add(new WsePara(rawData, curIndex));
+ curIndex = WsePara.computeNewIndex(rawData, curIndex);
+ } else if (WseTextRun.isValid(rawData, curIndex)) {
+ v.add(new WseTextRun(rawData, curIndex, fontTable, colorTable));
+ curIndex = WseTextRun.computeNewIndex(rawData, curIndex);
+ } else if (WseFontTable.isValid(rawData, curIndex)) {
+ fontTable = new WseFontTable(rawData, curIndex);
+ v.add(fontTable);
+ curIndex = WseFontTable.computeNewIndex(rawData, curIndex);
+ } else if (WseColorTable.isValid(rawData, curIndex)) {
+ colorTable = new WseColorTable(rawData, curIndex);
+ v.add(colorTable);
+ curIndex = WseColorTable.computeNewIndex(rawData, curIndex);
+ } else {
+ Debug.log(Debug.ERROR, "Unknown code " + rawData[curIndex]);
+ throw new IOException();
+ }
+ }
+
+ return (Wse[])v.toArray(new Wse[2]);
+ }
+
+
+ /**
+ * <p>Decompress the <code>byte</code> array.</p>
+ *
+ * <p>The resulting uncompressed <code>byte</code> array
+ * should be within <code>textRecordSize</code> length,
+ * definitely within twice the size it claims, else treat
+ * it as a problem with the encoding of that PDB and
+ * throw <code>IOException</code>.</p>
+ *
+ * @param bytes Compressed <code>byte</code> array
+ * @param textRecordSize Size of uncompressed <code>byte</code>
+ * array
+ *
+ * @throws IOException If <code>textRecordSize</codeL &lt;
+ * <code>cBytes.length</code>.
+ */
+ private byte[] decompress(byte[] cBytes, int textRecordSize)
+ throws IOException {
+
+ // create byte array for storing uncompressed bytes
+ // it should be within textRecordSize range, definitely
+ // within twice of textRecordSize! if not, then
+ // an ArrayIndexOutOfBoundsException will get thrown,
+ // and it should be converted into an IOException, and
+ // treat it as a conversion error.
+ byte[] uBytes = new byte[textRecordSize*2];
+
+ int up = 0;
+ int cp = 0;
+
+ try {
+
+ while (cp < cBytes.length) {
+
+ int c = cBytes[cp++] & 0xff;
+
+ // codes 1...8 mean copy that many bytes
+ if (c > 0 && c < 9) {
+
+ while (c-- > 0)
+ uBytes[up++] = cBytes[cp++];
+ }
+
+ // codes 0, 9...0x7F represent themselves
+ else if (c < 0x80) {
+ uBytes[up++] = (byte) c;
+ }
+
+ // codes 0xC0...0xFF represent "space + ascii char"
+ else if (c >= 0xC0) {
+ uBytes[up++] = (byte) ' ';
+ uBytes[up++] = (byte) (c ^ 0x80);
+ }
+
+ // codes 0x80...0xBf represent sequences
+ else {
+ c <<= 8;
+ c += cBytes[cp++] & 0xff;
+ int m = (c & 0x3fff) >> COUNT_BITS;
+ int n = c & ((1 << COUNT_BITS) - 1);
+ n += COUNT_BITS;
+ while (n-- > 0) {
+ uBytes[up] = uBytes[up - m];
+ up++;
+ }
+ }
+ }
+
+ } catch (ArrayIndexOutOfBoundsException e) {
+
+ throw new IOException(
+ res.getString("DOC_TEXT_RECORD_SIZE_EXCEEDED"));
+ }
+
+ // note that ubytes may be larger that the amount of
+ // uncompressed bytes, so trim it to another byte array
+ // with the exact size.
+ byte[] textBytes = new byte[up];
+ System.arraycopy(uBytes, 0, textBytes, 0, up);
+
+ return textBytes;
+ }
+
+
+ /**
+ * Read the header <code>byte</code> array.
+ *
+ * @param bytes <code>byte</code> array containing header
+ * record data.
+ *
+ * @return <code>HeaderInfo</code> object.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ private HeaderInfo readHeader(byte[] bytes) throws IOException {
+
+ HeaderInfo header = new HeaderInfo();
+
+ ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
+ DataInputStream dis = new DataInputStream(bis);
+
+ // Normally the first 2 bytes comprised of the version
+ // which should either be COMPRESSED or UNCOMPRESSED
+ // SmartDoc/Quickword would add a 0x01 to the first
+ // byte, thus their version would be 0x0101 for UNCOMPRESSED
+ // instead of 0x0001 and 0x0102 for UNCOMPRESSED instead of
+ // 0x0002.
+
+ dis.readByte();
+ header.version = dis.readByte();
+
+ // read extra 2 unused bytes
+ dis.readShort();
+
+ // Read the text length, this should be unsigned 4 bytes.
+ // We could store the read value into a long, but then
+ // our current buffer limit is the max positive of an int.
+ // That is a large enough limit, thus we shall stay with
+ // storing the value in an int. If it exceeds, then
+ // an IOException should be thrown.
+ header.textLen = dis.readInt();
+ if (header.textLen < 0) {
+ throw new IOException(res.getString("DOC_TEXT_LENGTH_EXCEEDED"));
+ }
+
+ // read the number of records - unsigned 2 bytes
+ header.textRecordCount = ((int) dis.readShort()) & 0x0000ffff;
+
+ // read the record size - unsigned 2 bytes
+ header.textRecordSize = ((int) dis.readShort()) & 0x0000ffff;
+
+ // read extra 4 unused bytes
+ dis.readInt();
+
+ return header;
+ }
+
+
+ /**
+ * Prints out header info into log.
+ * Used for debugging purposes only.
+ *
+ * @param header <code>HeaderInfo</code> structure.
+ */
+ private void dumpHeader(HeaderInfo header) {
+ /*
+ log("<DOC_INFO ");
+ log("version=\"" + header.version + "\" ");
+ log("text-length=\"" + header.textLen + "\" ");
+ log("number-of-records=\"" + header.textRecordCount + "\" ");
+ log("record-size=\"" + header.textRecordSize + "\" />\n");
+ */
+ }
+
+
+ /**
+ * Inner class to store DOC header information.
+ */
+ private class HeaderInfo {
+
+ /** length of text section */
+ int textLen = 0;
+
+ /** number of text records */
+ int textRecordCount = 0;
+
+ /**
+ * size of a text record. This is normally the same as
+ * TEXT_RECORD_SIZE, but some applications may modify this.
+ */
+ int textRecordSize = 0;
+
+ /** compression type */
+ int version = 0;
+ }
+}
+
diff --git a/xmerge/source/wordsmith/java/org/openoffice/xmerge/converter/xml/sxw/wordsmith/WSEncoder.java b/xmerge/source/wordsmith/java/org/openoffice/xmerge/converter/xml/sxw/wordsmith/WSEncoder.java
new file mode 100644
index 000000000000..15cf4ed36544
--- /dev/null
+++ b/xmerge/source/wordsmith/java/org/openoffice/xmerge/converter/xml/sxw/wordsmith/WSEncoder.java
@@ -0,0 +1,212 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxw.wordsmith;
+
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.*;
+import java.io.UnsupportedEncodingException;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Vector;
+
+import org.openoffice.xmerge.converter.palm.*;
+
+/**
+ * This class is used by {@link
+ * org.openoffice.xmerge.converter.xml.sxw.wordsmith.DocumentDeserializerImpl
+ * DocumentDeserializerImpl} to encode the WordSmith format.
+ *
+ * @author David Proulx
+ */
+
+// DJP: replace 4096 w/ a defined constant
+
+final class WSEncoder {
+
+ /* DJP: These should probably go somewhere else! */
+ /** Constant for uncompressed version. */
+ public static final short UNCOMPRESSED = 1;
+
+ /** Constant for compressed version. */
+ public static final short COMPRESSED = 2;
+
+ /** Constant used for spare fields. */
+ public static final int SPARE = 0;
+
+ /* WordSmith Header information. */
+ private short version;
+ private int textLen;
+ private short maxRecSize;
+ private int textRecCount = 0;
+
+
+ /* WordSmith document elements. */
+ WseHeader header = null;
+ WseFontTable ft = null;
+ WseColorTable ct = null;
+ private Vector elements; // paragraphs & text runs
+
+ /* Totals for the WordSmith document. */
+ int nrParagraphs = 0;
+ int nrAtoms = 0;
+ int nrChars = 0;
+
+
+ /**
+ * Default constructor creates a header and
+ * a text buffer for holding all the text in
+ * the WordSmith database.
+ */
+ WSEncoder() {
+ version = 1;
+ textLen = 0;
+ maxRecSize = 4096;
+ elements = new Vector();
+ }
+
+
+ /**
+ * This method adds a new element to the WordSmith document.
+ *
+ * @param elem WordSmith document element to add
+ */
+ void addElement(Wse elem) {
+ if (elem.getClass() == WseHeader.class)
+ header = (WseHeader)elem;
+ else if (elem.getClass() == WseFontTable.class)
+ ft = (WseFontTable)elem;
+ else if (elem.getClass() == WseColorTable.class)
+ ct = (WseColorTable)elem;
+ else
+ elements.addElement(elem);
+ }
+
+
+ /**
+ * This method encodes the information given to
+ * an array of palm Records in the WordSmith database format.
+ *
+ * @return <code>Record</code> array holding WordSmith contents.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ Record[] getRecords() throws IOException {
+
+ Vector allRecs = new Vector();
+ int nElements = elements.size();
+
+ // Count up the number of paragraphs, atoms, and characters.
+ int currElement = 0;
+ while (currElement < nElements) {
+ Wse e = (Wse)elements.elementAt(currElement++);
+ if (e.getClass() == WsePara.class)
+ nrParagraphs++;
+ if (e.getClass() == WseTextRun.class) {
+ nrAtoms++;
+ nrChars += ((WseTextRun)e).getText().length();
+ }
+ }
+
+ byte[] currRec = new byte[4096];
+ int currRecLen = 0;
+
+ // This code assumes that the WordSmith header, font table,
+ // and color table total less than 4096 bytes.
+ header = new WseHeader(nrParagraphs, nrAtoms, nrChars, ft, ct);
+ System.arraycopy(header.getBytes(), 0,
+ currRec, currRecLen, header.getByteCount());
+ currRecLen += header.getByteCount();
+
+ if (ft != null) {
+ System.arraycopy(ft.getBytes(), 0, currRec, currRecLen,
+ ft.getByteCount());
+ currRecLen += ft.getByteCount();
+ }
+ if (ct != null) {
+ System.arraycopy(ct.getBytes(), 0, currRec, currRecLen,
+ ct.getByteCount());
+ currRecLen += ct.getByteCount();
+ }
+
+ currElement = 0;
+ while (currElement < nElements) {
+ Wse e = (Wse)elements.elementAt(currElement++);
+ int length = e.getByteCount();
+ if ((length + currRecLen) <= 4096) {
+ System.arraycopy(e.getBytes(), 0, currRec, currRecLen, length);
+ currRecLen += length;
+ } else {
+ // Copy in enough to get to full size, then create a
+ // new Record and add it to the Vector.
+ int firstPartLen = 4096 - currRecLen;
+ System.arraycopy(e.getBytes(), 0, currRec, currRecLen,
+ firstPartLen);
+ Record r = new Record(currRec);
+ allRecs.addElement(r);
+
+ // Put the remainder at the beginning of the next record
+ currRecLen = 0;
+ System.arraycopy(e.getBytes(), firstPartLen, currRec,
+ currRecLen, length - firstPartLen);
+ currRecLen += length - firstPartLen;
+ }
+ }
+
+ // Processed all the elements. Write out any remaining partial record.
+ if (currRecLen > 0) {
+ byte[] partial = new byte[currRecLen];
+ System.arraycopy(currRec, 0, partial, 0, currRecLen);
+ Record rr = new Record(partial);
+ allRecs.addElement(rr);
+ }
+
+
+ // Record 0 is the WordSmith header. Do it last since it
+ // contains totals for the entire document. It goes
+ // before everything else.
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ DataOutputStream dos = new DataOutputStream(bos);
+ dos.writeShort(version);
+ dos.writeShort(0);
+ dos.writeInt(textLen);
+ dos.writeShort(allRecs.size());
+ dos.writeShort(maxRecSize);
+ dos.writeInt(0);
+ allRecs.insertElementAt(new Record(bos.toByteArray()), 0);
+
+ // Convert Vector of Records to an array and return it.
+ int nRecs = allRecs.size();
+ Record recs[] = new Record[nRecs];
+ for (int i = 0; i < nRecs; i++)
+ recs[i] = (Record)allRecs.elementAt(i);
+ return recs;
+ }
+
+}
+
diff --git a/xmerge/source/wordsmith/java/org/openoffice/xmerge/converter/xml/sxw/wordsmith/Wse.java b/xmerge/source/wordsmith/java/org/openoffice/xmerge/converter/xml/sxw/wordsmith/Wse.java
new file mode 100644
index 000000000000..4f1a7141f348
--- /dev/null
+++ b/xmerge/source/wordsmith/java/org/openoffice/xmerge/converter/xml/sxw/wordsmith/Wse.java
@@ -0,0 +1,100 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxw.wordsmith;
+
+import java.io.IOException;
+
+import org.w3c.dom.NodeList;
+import org.w3c.dom.Node;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Element;
+
+import org.openoffice.xmerge.Document;
+import org.openoffice.xmerge.ConverterCapabilities;
+import org.openoffice.xmerge.converter.xml.OfficeDocument;
+import org.openoffice.xmerge.converter.xml.sxw.SxwDocument;
+import org.openoffice.xmerge.converter.xml.*;
+
+
+/**
+ * This is the superclass for all elements in a WordSmith document.
+ * Elements can be paragraphs, text runs, font tables, or color tables.
+ *
+ * @author David Proulx
+ */
+abstract class Wse {
+
+ /**
+ * Return true if <code>dataArray[startIndex]</code> is the start
+ * of a valid element of this type.
+ *
+ * @param dataArray <code>byte</code> array.
+ * @param startIndex The start index.
+ *
+ * @return true if <code>dataArray[startIndex]</code> is the
+ * start of a valid element of this type, false otherwise.
+ */
+ static boolean isValid(byte dataArray[], int startIndex) {
+ return false;
+ }
+
+
+ /**
+ * Compute and return the index of the first <code>byte</code>
+ * following this element. It is assumed that the element
+ * starting at <code>dataArray[startIndex]</code> is valid.
+ *
+ * @param dataArray <code>byte</code> array.
+ * @param startIndex The start index.
+ *
+ * @return The index of the first <code>byte</code> following
+ * this element.
+ */
+ static int computeNewIndex(byte dataArray[], int startIndex) {
+ return 0;
+ }
+
+
+ /**
+ * Return the total number of bytes needed to represent this
+ * object.
+ *
+ * @return The total number of bytes needed to represent this
+ * object.
+ */
+ abstract int getByteCount();
+
+
+ /**
+ * Return an <code>byte</code> array representing this element.
+ *
+ * @return An <code>bytes</code> array representing this element.
+ */
+ abstract byte[] getBytes();
+}
+
diff --git a/xmerge/source/wordsmith/java/org/openoffice/xmerge/converter/xml/sxw/wordsmith/WseColorTable.java b/xmerge/source/wordsmith/java/org/openoffice/xmerge/converter/xml/sxw/wordsmith/WseColorTable.java
new file mode 100644
index 000000000000..bbb22952a24a
--- /dev/null
+++ b/xmerge/source/wordsmith/java/org/openoffice/xmerge/converter/xml/sxw/wordsmith/WseColorTable.java
@@ -0,0 +1,247 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxw.wordsmith;
+
+import java.io.IOException;
+import java.awt.Color;
+
+import org.w3c.dom.NodeList;
+import org.w3c.dom.Node;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Element;
+
+import org.openoffice.xmerge.Document;
+import org.openoffice.xmerge.ConverterCapabilities;
+import org.openoffice.xmerge.converter.xml.OfficeDocument;
+import org.openoffice.xmerge.converter.xml.sxw.SxwDocument;
+import org.openoffice.xmerge.converter.xml.*;
+
+/**
+ * This class represents a color table in a WordSmith document.
+ *
+ * @author David Proulx
+ */
+class WseColorTable extends Wse {
+
+ private Color fgColors[];
+ private Color bgColors[];
+
+ /**
+ * Constructor to use when going from DOM to WordSmith
+ */
+ public WseColorTable() {
+ fgColors = new Color[16];
+ bgColors = new Color[16];
+
+ // Always need these two!
+ fgColors[0] = Color.black;
+ bgColors[0] = Color.white;
+
+ }
+
+ /**
+ * Constructor to use when going from WordSmith to DOM.
+ *
+ * @param dataArray <code>byte</code> array.
+ * @param i The index.
+ */
+ public WseColorTable(byte dataArray[], int i) {
+ fgColors = new Color[16];
+ bgColors = new Color[16];
+
+ i += 2; // Skip leading "64" and table length field.
+ for (int k = 0; k < 16; k++) {
+ fgColors[k] = new Color(((int)dataArray[i+1]) & 0xFF,
+ ((int)dataArray[i+2]) & 0xFF,
+ ((int)dataArray[i+3]) & 0xFF);
+ i += 4;
+ }
+ for (int k = 0; k < 16; k++) {
+ bgColors[k] = new Color(((int)dataArray[i+1]) & 0xFF,
+ ((int)dataArray[i+2]) & 0xFF,
+ ((int)dataArray[i+3]) & 0xFF);
+ i += 4;
+ }
+
+ }
+
+
+ /**
+ * Compute the index of the first <code>byte</code> following the
+ * paragraph descriptor, assuming that
+ * <code>dataArray[startIndex]</code> is the beginning of a valid
+ * paragraph descriptor.
+ *
+ * @param dataArray <code>byte</code array.
+ * @param startIndex The start index.
+ *
+ * @return The index of the first <code>byte</code> following the
+ * paragraph description.
+ */
+ static int computeNewIndex(byte dataArray[], int startIndex) {
+ int tableLen = dataArray[startIndex + 1];
+ tableLen &= 0xFF; // eliminate problems with sign-extension
+ return startIndex + tableLen + 2;
+ }
+
+
+ /**
+ * Return true if <code>dataArray[startIndex]</code> is the start
+ * of a valid paragraph descriptor.
+ *
+ * @param dataArray <code>byte</code> array.
+ * @param startIndex Start index.
+ *
+ * @return true if <code>dataArray[startIndex]</code> is the start
+ * of a valid paragraph descriptor, false otherwise.
+ */
+ static boolean isValid(byte dataArray[], int startIndex) {
+ try {
+ if (dataArray[startIndex] != 64)
+ return false;
+ int len = dataArray[startIndex + 1];
+ len &= 0xFF; // eliminate problems with sign-extension
+ int temp = dataArray[startIndex + (int)len + 2]; // probe end of table
+ } catch (ArrayIndexOutOfBoundsException e) {
+ return false;
+ }
+ return true;
+ }
+
+
+ /**
+ * Return the number of bytes needed to represent this color table.
+ *
+ * @return The byte count.
+ */
+ int getByteCount() {
+ return (32 * 4) + 1 + 1;
+ }
+
+
+ /**
+ * Return a <code>byte</code> array representing this color table.
+ *
+ * @return <code>bytes</code> array representing this color table.
+ */
+ byte[] getBytes() {
+ byte[] b = new byte[(32 * 4) + 1 + 1];
+ b[0] = 0x40;
+ b[1] = (byte)128;
+ int i = 2;
+ // int indVal = 0xd8;
+ int indVal = 0;
+
+ for (int j = 0; j < 16; j++) {
+ b[i++] = (byte)indVal++;
+ if (fgColors[j] != null) {
+ b[i++] = (byte)fgColors[j].getRed();
+ b[i++] = (byte)fgColors[j].getGreen();
+ b[i++] = (byte)fgColors[j].getBlue();
+ } else {
+ b[i++] = (byte)0;
+ b[i++] = (byte)0;
+ b[i++] = (byte)0;
+ }
+ }
+
+ for (int j = 0; j < 16; j++) {
+ b[i++] = (byte)indVal++;
+ if (bgColors[j] != null) {
+ b[i++] = (byte)bgColors[j].getRed();
+ b[i++] = (byte)bgColors[j].getGreen();
+ b[i++] = (byte)bgColors[j].getBlue();
+ } else {
+ b[i++] = (byte)0xFF;
+ b[i++] = (byte)0xFF;
+ b[i++] = (byte)0xFF;
+ }
+ }
+
+ return b;
+ }
+
+
+ /**
+ * Return the index of the specified foreground or background
+ * <code>Color</code>. (If the color is not already in the table,
+ * it will be added.)
+ *
+ * Note that the implementation of this may include a "margin of
+ * error" to prevent the color table from being filled up too
+ * quickly.
+ *
+ * @param c The <code>Color</code>.
+ * @param foreground true if foreground color, false if background
+ * color
+ *
+ * @return The index of the specified foreground or background
+ * <code>Color</code>.
+ *
+ * DJP: how to handle table overflow?
+ */
+ int findColor(Color c, boolean foreground) {
+
+ Color colorArray[] = foreground ? fgColors : bgColors;
+
+ for (int i = 0; i < 16; i++) {
+ if (colorArray[i] != null) {
+ if (colorArray[i].equals(c))
+ return i;
+ }
+ else
+ break; // hit a null entry - no more colors in table!
+ }
+
+ // Color was not found in the table. Add it.
+ for (int i = 0; i < 16; i++) {
+ if (colorArray[i] == null) {
+ colorArray[i] = c;
+ return i;
+ }
+ }
+ return 0; // Default - we should never get here though.
+ }
+
+
+ /**
+ * Given an index, return the <code>Color</code> from the table.
+ *
+ * @param index The index
+ * @param foreground true if foreground color, false if background
+ * color
+ *
+ * @return The <code>Color</code> at the specified index.
+ */
+ Color getColor(int index, boolean foreground) {
+
+ Color colorArray[] = foreground ? fgColors : bgColors;
+ return colorArray[index];
+ }
+}
+
diff --git a/xmerge/source/wordsmith/java/org/openoffice/xmerge/converter/xml/sxw/wordsmith/WseFontTable.java b/xmerge/source/wordsmith/java/org/openoffice/xmerge/converter/xml/sxw/wordsmith/WseFontTable.java
new file mode 100644
index 000000000000..d7bc6edd8bc2
--- /dev/null
+++ b/xmerge/source/wordsmith/java/org/openoffice/xmerge/converter/xml/sxw/wordsmith/WseFontTable.java
@@ -0,0 +1,218 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxw.wordsmith;
+
+import java.io.IOException;
+
+import org.w3c.dom.Node;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Element;
+
+import org.openoffice.xmerge.Document;
+import org.openoffice.xmerge.ConverterCapabilities;
+import org.openoffice.xmerge.converter.xml.OfficeDocument;
+import org.openoffice.xmerge.converter.xml.sxw.SxwDocument;
+import org.openoffice.xmerge.converter.xml.*;
+
+/**
+ * <p>This class represents a font table in a WordSmith document.
+ * A font table is represented as follows:</p>
+ *
+ * <p><blockquote>
+ * binary "3"<br>
+ * two-byte length of the table of strings which follows<br>
+ * string table (null-terminated strings) representing font names
+ * </blockquote></p>
+ *
+ * @author David Proulx
+ */
+class WseFontTable extends Wse {
+
+ java.util.Vector fontNames = new java.util.Vector(10);
+
+
+ /**
+ * Constructor for use when going from DOM to WordSmith.
+ */
+ public WseFontTable() {
+ }
+
+
+ /**
+ * Constructor for use when going from WordSmith to DOM.
+ *
+ * @param dataArray <code>byte</code> array.
+ * @param i The index.
+ */
+ public WseFontTable(byte dataArray[], int i) {
+ i++;
+ int tableLen = ((dataArray[i] << 8) | (dataArray[i+1] & 0xFF));
+ i += 2;
+ while (tableLen > 0) {
+ int j = 0;
+ while (dataArray[i + j] != 0) j++;
+ fontNames.add(new String(dataArray, i, j));
+ tableLen -= (j + 1);
+ i += (j + 1);
+ }
+ }
+
+
+ /**
+ * Add a new font to the table.
+ *
+ * @param newFontName The new font name.
+ */
+ public void add(String newFontName) {
+ if (newFontName != null)
+ fontNames.add(newFontName);
+ }
+
+
+ /**
+ * Return a font name from the table, or null if invalid index.
+ *
+ * @param index The font name index.
+ *
+ * @return The font name.
+ */
+ public String getFontName(int index) {
+ try {
+ return (String)fontNames.elementAt(index);
+ } catch (ArrayIndexOutOfBoundsException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Return the index of a font name in the table, or -1 if not found.
+ *
+ * @param fontName The font name.
+ *
+ * @return The index of the font name, or -1 if not found.
+ */
+ public int getFontIndex(String fontName) {
+ int len = fontNames.size();
+ for (int i = 0; i < len; i++) {
+ String name = (String) fontNames.elementAt(i);
+ if (name.equals(fontName))
+ return i;
+ }
+ return -1;
+ }
+
+
+ /**
+ * Compute the index of the first <code>byte</code> following the
+ * paragraph descriptor, assuming that
+ * <code>dataArray[startIndex]</code> is the beginning of a valid
+ * paragraph descriptor.
+ *
+ * @param dataArray <code>byte</code> array.
+ * @param startIndex The start index.
+ *
+ * @return The index of the first <code>byte</code> following the
+ * paragraph description.
+ */
+ static int computeNewIndex(byte dataArray[], int startIndex) {
+ startIndex++; // Skip the leading "3"
+ int tableLen = ((dataArray[startIndex] << 8) | (dataArray[startIndex+1] & 0xFF));
+ tableLen &= 0xFFFF; // eliminate problems with sign-extension
+ return startIndex + tableLen + 2;
+ }
+
+
+ /**
+ * Return true if <code>dataArray[startIndex]</code> is the start of a
+ * valid paragraph descriptor.
+ *
+ * @param dataArray <code>byte</code> string.
+ * @param startIndex Start index.
+ *
+ * @return true if <code>dataArray[startIndex]</code> is the start
+ * of a valid paragraph descriptor, false otherwise.
+ */
+ static boolean isValid(byte dataArray[], int startIndex) {
+ try {
+ if (dataArray[startIndex] != 3)
+ return false;
+ int len = ((dataArray[startIndex+1] << 8)
+ | (dataArray[startIndex+2] & 0xFF));
+ len &= 0xFFFF; // eliminate problems with sign-extension
+
+ if (dataArray[startIndex + len + 2] != 0)
+ return false;
+ } catch (ArrayIndexOutOfBoundsException e) {
+ return false;
+ }
+ return true;
+ }
+
+
+ /**
+ * Return the number of bytes needed to represent this font table.
+ *
+ * @return The number of bytes needed to represent this font table.
+ */
+ int getByteCount() {
+
+ int length = 3; // leading "3" plus 2 bytes for length.
+ int nFonts = fontNames.size();
+ for (int i = 0; i < nFonts; i++) {
+ String name = (String)fontNames.elementAt(i);
+ length += name.length() + 1; // extra byte is for trailing "0"
+ }
+ return length;
+ }
+
+ /**
+ * Return a <code>byte</code> array representing this font table.
+ *
+ * @return An <code>byte</code> array representing this font table.
+ */
+ byte[] getBytes() {
+
+ int length = getByteCount();
+ int nFonts = fontNames.size();
+ byte b[] = new byte[length];
+ b[0] = 3;
+ length -= 3;
+ b[1] = (byte)(length >> 8);
+ b[2] = (byte)(length & 0xFF);
+ int indx = 3;
+ for (int i = 0; i < nFonts; i++) {
+ String name = (String)fontNames.elementAt(i);
+ byte bname[] = name.getBytes();
+ System.arraycopy(bname, 0, b, indx, bname.length);
+ indx += bname.length;
+ b[indx++] = 0;
+ }
+ return b;
+ }
+}
+
diff --git a/xmerge/source/wordsmith/java/org/openoffice/xmerge/converter/xml/sxw/wordsmith/WseHeader.java b/xmerge/source/wordsmith/java/org/openoffice/xmerge/converter/xml/sxw/wordsmith/WseHeader.java
new file mode 100644
index 000000000000..c80e03eca043
--- /dev/null
+++ b/xmerge/source/wordsmith/java/org/openoffice/xmerge/converter/xml/sxw/wordsmith/WseHeader.java
@@ -0,0 +1,145 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxw.wordsmith;
+
+import java.io.IOException;
+import java.io.DataOutputStream;
+import java.io.ByteArrayOutputStream;
+
+/**
+ * This class represents a WordSmith document header.
+ *
+ * @author David Proulx
+ */
+class WseHeader extends Wse {
+
+ private int nParagraphs = 0;
+ private int nAtoms = 0;
+ private int nChars = 0;
+ private int miscSize = 0;
+
+ /**
+ * Constructor for use when going from DOM to WordSmith.
+ *
+ * @param nPara The number of paragraphs.
+ * @param nAtoms The number of atoms.
+ * @param nChars The number of characters.
+ * @param ft The font table.
+ * @param ct The color table.
+ */
+ public WseHeader(int nPara, int nAtoms, int nChars, WseFontTable ft,
+ WseColorTable ct) {
+ nParagraphs = nPara;
+ this.nAtoms = nAtoms;
+ this.nChars = nChars;
+ if (ft != null) miscSize += ft.getByteCount();
+ if (ct != null) miscSize += ct.getByteCount();
+ }
+
+
+ /**
+ * Constructor for use when going from WordSmith to DOM.
+ *
+ * @param dataArray <code>byte</code> array.
+ * @param i Index.
+ */
+ public WseHeader(byte dataArray[], int i) {
+ // DJP: write this!
+ }
+
+ /**
+ * Return true if <code>dataArray[startIndex]</code> is the start
+ * of a document header.
+ *
+ * @param dataArray <code>byte</code> array.
+ * @param startIndex The index.
+ *
+ * @return true if <code>dataArray[startIndex]</code> is the start
+ * of a document header, false otherwise.
+ */
+ static boolean isValid(byte dataArray[], int startIndex) {
+ return ((dataArray[startIndex] == 2)
+ && (dataArray[startIndex + 1] == 4));
+ }
+
+
+ /**
+ * Compute and return the index of the first <code>byte</code>
+ * following this element. It is assumed that the element
+ * starting at <code>dataArray[startIndex]</code> is valid.
+ *
+ * @param dataArray <code>byte</code> array.
+ * @param startIndex The start index.
+ *
+ * @return The first <code>byte</code> following this element.
+ */
+ static int computeNewIndex(byte dataArray[], int startIndex) {
+ return startIndex + 18;
+ }
+
+
+ /**
+ * Return the total number of bytes needed to represent this.
+ *
+ * @return The total number of bytes needed to represent this.
+ */
+ int getByteCount() {
+ return 18;
+ }
+
+
+ /**
+ * Return a <code>byte</code> array representing this element.
+ *
+ * @return A <code>byte</code> array representing this element.
+ */
+ byte[] getBytes() {
+ DataOutputStream os; // Used for storing the data
+ ByteArrayOutputStream bs = null; // Used for storing the data
+
+ try {
+ bs = new ByteArrayOutputStream();
+ os = new DataOutputStream(bs);
+ os.write(2); // binary doc indicator
+ os.write(4); // binary header indicator
+
+ os.writeInt(nParagraphs);
+ os.writeInt(nAtoms);
+ os.writeInt(nChars);
+ os.writeInt(miscSize);
+
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
+ if (bs != null) {
+ return bs.toByteArray();
+ } else return null;
+ }
+}
+
diff --git a/xmerge/source/wordsmith/java/org/openoffice/xmerge/converter/xml/sxw/wordsmith/WsePara.java b/xmerge/source/wordsmith/java/org/openoffice/xmerge/converter/xml/sxw/wordsmith/WsePara.java
new file mode 100644
index 000000000000..36b21e21b931
--- /dev/null
+++ b/xmerge/source/wordsmith/java/org/openoffice/xmerge/converter/xml/sxw/wordsmith/WsePara.java
@@ -0,0 +1,299 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxw.wordsmith;
+
+import java.io.IOException;
+
+import org.w3c.dom.NodeList;
+import org.w3c.dom.Node;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Element;
+
+import org.openoffice.xmerge.Document;
+import org.openoffice.xmerge.ConverterCapabilities;
+import org.openoffice.xmerge.converter.xml.OfficeDocument;
+import org.openoffice.xmerge.converter.xml.sxw.SxwDocument;
+import org.openoffice.xmerge.converter.xml.*;
+
+
+/**
+ * This class represents a paragraph in a WordSmith document.
+ * (A paragraph is "5" followed by 12 bytes of attributes.)
+ *
+ * @author David Proulx
+ */
+class WsePara extends Wse {
+
+ private byte spaceBefore = 0;
+ private byte spaceAfter = 0;
+ private byte leftIndent = 0;
+ private byte firstIndent = 0;
+ private byte rightIndent = 0;
+ private byte misc = 0;
+ private byte style = 0;
+ private byte lineSpace = 0;
+ private byte outline = 0;
+ private byte reserved = 0;
+
+ private static final byte LS_EXACTLY = (byte)0xC0;
+ private static final byte LS_ATLEAST = (byte)0x80;
+ private static final byte LS_MULTIPLE = (byte)0x40;
+ private static final byte LS_VALUEMASK = (byte)0x3F;
+
+ private static final byte ALIGN_RIGHT = (byte)2;
+ private static final byte ALIGN_LEFT = (byte)0;
+ private static final byte ALIGN_CENTER = (byte)1;
+ private static final byte ALIGN_JUST = (byte)3;
+
+ private StyleCatalog sc = null;
+
+
+ /**
+ * Constructor for use when going from DOM to WordSmith.
+ *
+ * @param p The paragraph style.
+ * @param sc The <code>StyleCatalog</code>.
+ */
+ public WsePara(ParaStyle p, StyleCatalog sc) {
+ this.sc = sc;
+ ParaStyle ps = (ParaStyle)p.getResolved();
+
+ if (ps.isAttributeSet(ParaStyle.MARGIN_LEFT)) {
+ double temp = ps.getAttribute(ParaStyle.MARGIN_LEFT) * 1.6 / 100;
+ leftIndent = (byte) temp;
+ if ((temp - leftIndent) > 0.5) leftIndent++;
+ }
+
+ if (ps.isAttributeSet(ParaStyle.MARGIN_RIGHT)) {
+ double temp = ps.getAttribute(ParaStyle.MARGIN_RIGHT) * 1.6 / 100;
+ rightIndent = (byte) temp;
+ if ((temp - rightIndent) > 0.5) rightIndent++;
+ }
+
+ if (ps.isAttributeSet(ParaStyle.TEXT_INDENT)) {
+ double temp = ps.getAttribute(ParaStyle.TEXT_INDENT) * 1.6 / 100;
+ firstIndent = (byte) temp;
+ if ((temp - firstIndent) > 0.5) firstIndent++;
+ }
+
+ if (ps.isAttributeSet(ParaStyle.MARGIN_TOP)) {
+ double temp = ps.getAttribute(ParaStyle.MARGIN_TOP) * 1.6 / 100;
+ spaceBefore = (byte) temp;
+ if ((temp - spaceBefore) > 0.5) spaceBefore++;
+ }
+
+ if (ps.isAttributeSet(ParaStyle.MARGIN_BOTTOM)) {
+ double temp = ps.getAttribute(ParaStyle.MARGIN_BOTTOM) * 1.6 / 100;
+ spaceAfter = (byte) temp;
+ if ((temp - spaceAfter) > 0.5) spaceAfter++;
+ }
+
+ if (ps.isAttributeSet(ParaStyle.LINE_HEIGHT)) {
+ int lh = ps.getAttribute(ParaStyle.LINE_HEIGHT);
+ if ((lh & ~ParaStyle.LH_VALUEMASK) == 0)
+ lineSpace = (byte)(LS_MULTIPLE | (lh * 2));
+ else if ((lh & ParaStyle.LH_PCT) != 0) {
+ lh = (lh & ParaStyle.LH_VALUEMASK) / 100;
+ lineSpace = (byte)(LS_MULTIPLE | (lh * 2));
+ }
+ // DJP: handle other cases....
+ }
+
+ if (ps.isAttributeSet(ParaStyle.TEXT_ALIGN)) {
+
+ int val = ps.getAttribute(ParaStyle.TEXT_ALIGN);
+
+ switch (val) {
+ case ParaStyle.ALIGN_RIGHT:
+ misc = ALIGN_RIGHT;
+ break;
+ case ParaStyle.ALIGN_LEFT:
+ misc = ALIGN_LEFT;
+ break;
+ case ParaStyle.ALIGN_CENTER:
+ misc = ALIGN_CENTER;
+ break;
+ case ParaStyle.ALIGN_JUST:
+ misc = ALIGN_JUST;
+ break;
+ }
+ }
+
+ }
+
+
+ /**
+ * Constructor for use when going from WordSmith to DOM.
+ * Assumes <code>dataArray[startIndex]</code> is the first
+ * <code>byte</code> of a valid WordSmith paragraph descriptor.
+ *
+ * @param dataArray <code>byte</code> array.
+ * @param startIndex The start index.
+ */
+ public WsePara(byte dataArray[], int startIndex) {
+ spaceBefore = dataArray[startIndex + 1];
+ spaceAfter = dataArray[startIndex + 2];
+ leftIndent = dataArray[startIndex + 3];
+ firstIndent = dataArray[startIndex + 4];
+ rightIndent = dataArray[startIndex + 5];
+ misc = dataArray[startIndex + 6];
+ style = dataArray[startIndex + 7];
+ lineSpace = dataArray[startIndex + 8];
+ outline = dataArray[startIndex + 9];
+ }
+
+
+ /**
+ * Compute the index of the first <code>byte</code> following the
+ * paragraph descriptor, assuming that
+ * <code>dataArray[startIndex]</code> is the beginning of a valid
+ * paragraph descriptor.
+ *
+ * @param dataArray <code>byte</code> array.
+ * @param startIndex The start index.
+ *
+ * @return The index of the first <code>byte</code> following the
+ * paragraph description.
+ */
+ static int computeNewIndex(byte dataArray[], int startIndex) {
+ return startIndex + 13;
+ }
+
+
+ /**
+ * Return true if <code>dataArray[startIndex]</code> is the start
+ * of a valid paragraph descriptor.
+ *
+ * @param dataArray <code>byte</code> array.
+ * @param startIndex The start index.
+ *
+ * @return true if <code>dataArray[startIndex]</code> is the start
+ * of a valid paragraph descriptor, false otherwise.
+ */
+ static boolean isValid(byte dataArray[], int startIndex) {
+ return (dataArray[startIndex] == 5);
+ }
+
+ /**
+ * Return the number of bytes needed to represent this paragraph.
+ *
+ * @return The number of bytes needed to represent this paragraph.
+ */
+ int getByteCount() {
+ return 13;
+ }
+
+ /**
+ * Return an <code>byte</code> array representing this paragraph.
+ *
+ * @return An <code>byte</code> array representing this paragraph.
+ */
+ byte[] getBytes() {
+ byte b[] = new byte[13];
+
+ b[0] = 5;
+ b[1] = spaceBefore;
+ b[2] = spaceAfter;
+ b[3] = leftIndent;
+ b[4] = firstIndent;
+ b[5] = rightIndent;
+ b[6] = misc;
+ b[7] = style;
+ b[8] = lineSpace;
+ b[9] = outline;
+ b[10] = reserved;
+ b[11] = 0;
+ b[12] = 0;
+
+ return b;
+ }
+
+ /**
+ * Return a <code>ParaStyle</code> that reflects the formatting of
+ * this run.
+ *
+ * @return A <code>ParaStyle</code> that reflects the formatting
+ * of this run.
+ */
+ ParaStyle makeStyle() {
+ /* Csaba: Commented out the LINE_HEIGHT syle, because there was no
+ incoming data for that style. It was resulting a zero line
+ height in the xml document, ie. the doc looked empty.
+ */
+ int attrs[] = { ParaStyle.MARGIN_LEFT, ParaStyle.MARGIN_RIGHT,
+ ParaStyle.TEXT_INDENT, //ParaStyle.LINE_HEIGHT,
+ ParaStyle.MARGIN_TOP, ParaStyle.MARGIN_BOTTOM,
+ ParaStyle.TEXT_ALIGN };
+ String values[] = new String[attrs.length];
+ double temp;
+
+ temp = leftIndent / 1.6;
+ values[0] = (new Double(temp)).toString() + "mm";
+
+ temp = rightIndent / 1.6;
+ values[1] = (new Double(temp)).toString() + "mm";
+
+ temp = firstIndent / 1.6;
+ values[2] = (new Double(temp)).toString() + "mm";
+
+/* if ((lineSpace & LS_MULTIPLE) != 0) {
+ temp = (lineSpace & LS_VALUEMASK) / 2;
+ temp *= 100;
+ values[3] = (new Double(temp)).toString() + "%";
+ } else {
+ values[3] = (new Double(temp)).toString() + "mm";
+ // DJP: handle other cases
+ }
+*/
+ temp = spaceBefore / 1.6;
+// values[4] = (new Double(temp)).toString() + "mm";
+ values[3] = (new Double(temp)).toString() + "mm";
+
+ temp = spaceAfter / 1.6;
+// values[5] = (new Double(temp)).toString() + "mm";
+ values[4] = (new Double(temp)).toString() + "mm";
+
+ switch (misc) {
+
+// case ALIGN_RIGHT: values[6] = "right"; break;
+// case ALIGN_LEFT: values[6] = "left"; break;
+// case ALIGN_CENTER:values[6] = "center"; break;
+// case ALIGN_JUST: values[6] = "justified"; break;
+
+ case ALIGN_RIGHT: values[5] = "right"; break;
+ case ALIGN_LEFT: values[5] = "left"; break;
+ case ALIGN_CENTER:values[5] = "center"; break;
+ case ALIGN_JUST: values[5] = "justified"; break;
+ }
+ ParaStyle x = new ParaStyle(null, "paragraph", null, attrs,
+ values, sc);
+
+ return x;
+ }
+}
+
diff --git a/xmerge/source/wordsmith/java/org/openoffice/xmerge/converter/xml/sxw/wordsmith/WseTextRun.java b/xmerge/source/wordsmith/java/org/openoffice/xmerge/converter/xml/sxw/wordsmith/WseTextRun.java
new file mode 100644
index 000000000000..7a4bb325e051
--- /dev/null
+++ b/xmerge/source/wordsmith/java/org/openoffice/xmerge/converter/xml/sxw/wordsmith/WseTextRun.java
@@ -0,0 +1,324 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxw.wordsmith;
+
+import org.openoffice.xmerge.converter.xml.TextStyle;
+import org.openoffice.xmerge.converter.xml.StyleCatalog;
+import java.awt.Color;
+
+/**
+ * <p>This class represents a text run (aka text atom) in a WordSmith
+ * document.</p>
+ *
+ * <p>WordSmith represents a text run as follows:</p>
+ *
+ * <p><ul><li>
+ * 1 byte Value of "1", indicating beginning of a text atom
+ * </li><li>
+ * 2 bytes Length of text (does not include attributes, this length field,
+ * etc)
+ * </li><li>
+ * 1 byte Font index - Index in the font table of font to be used
+ * </li><li>
+ * 1 byte Font size (DJP: get details of representation)
+ * </li><li>
+ * 1 byte Color index - Index in the color table of font color to be used
+ * </li><li>
+ * 1 byte Modifiers - bit flags for bold, italic, etc
+ * </li><li>
+ * n bytes Text - the actual text
+ * </li></ul></p>
+ *
+ * @author David Proulx
+ */
+class WseTextRun extends Wse {
+
+ /** Font specifier. This is an index into the font table. */
+ private byte fontIndex = 0;
+ private String fontName = null;
+
+ /** Size of the font. */
+ private byte fontSize = 0;
+
+ /**
+ * Color of the font. This is an index into the color table.
+ * High nibble is background color index, low nibble is font color
+ * index.
+ */
+ private byte colorIndex = 0;
+
+ /**
+ * Reference to color table for color lookups.
+ */
+ private WseColorTable ct;
+
+ /**
+ * The modifiers for the text run. (Mostly) Bitwise flags. The "_TOKEN"
+ * values are not yet implemented in this converter. They may not even
+ * be implemented in WordSmith yet.
+ */
+ private byte modifiers = 0;
+ final public static int BOLD = 0x01;
+ final public static int ITALIC = 0x02;
+ final public static int UNDERLINE = 0x04;
+ final public static int STRIKETHRU = 0x08;
+ final public static int SUPERSCRIPT = 0x10;
+ final public static int SUBSCRIPT = 0x20;
+ final public static int LINK = 0x40;
+ final public static int CUSTOM_TOKEN = 0x80;
+ final public static int IMAGE_TOKEN = 0x80;
+ final public static int BOOKMARK_TOKEN = 0x81;
+ final public static int ANNOTATION_TOKEN = 0x82;
+ final public static int LINK_TOKEN = 0x83;
+
+ /** The actual text. */
+ private String text;
+
+ StyleCatalog sc;
+
+
+ /**
+ * Constructor for use when going from DOM to WordSmith.
+ *
+ * @param txt The text.
+ * @param t The text style.
+ * @param sc The <code>StyleCatalog</code>.
+ * @param ft The font table.
+ * @param ct The color Table.
+ */
+ public WseTextRun(String txt, TextStyle t, StyleCatalog sc,
+ WseFontTable ft, WseColorTable ct) {
+
+ this.sc = sc;
+ this.ct = ct;
+
+ TextStyle ts = (TextStyle)t.getResolved();
+
+ if (ts.isSet(TextStyle.BOLD) && ts.getAttribute(TextStyle.BOLD))
+ modifiers |= BOLD;
+ if (ts.isSet(TextStyle.ITALIC) && ts.getAttribute(TextStyle.ITALIC))
+ modifiers |= ITALIC;
+ if (ts.isSet(TextStyle.UNDERLINE) && ts.getAttribute(TextStyle.UNDERLINE))
+ modifiers |= UNDERLINE;
+ if (ts.isSet(TextStyle.STRIKETHRU) && ts.getAttribute(TextStyle.STRIKETHRU))
+ modifiers |= STRIKETHRU;
+ if (ts.isSet(TextStyle.SUPERSCRIPT) && ts.getAttribute(TextStyle.SUPERSCRIPT))
+ modifiers |= SUPERSCRIPT;
+ if (ts.isSet(TextStyle.SUBSCRIPT) && ts.getAttribute(TextStyle.SUBSCRIPT))
+ modifiers |= SUBSCRIPT;
+
+ fontSize = (byte)(ts.getFontSize() * 2);
+ fontName = ts.getFontName();
+ fontIndex = (byte)ft.getFontIndex(fontName);
+ if (fontIndex == -1) {
+ ft.add(fontName);
+ fontIndex = (byte)ft.getFontIndex(fontName);
+ }
+
+ // Figure out the color index.
+ Color c = t.getFontColor();
+ if (c == null)
+ c = Color.black;
+ colorIndex = (byte)ct.findColor(c, true);
+ c = t.getBackgroundColor();
+ if (c == null)
+ c = Color.white;
+ colorIndex |= (byte)(ct.findColor(c, false) << 4);
+
+ text = txt;
+ }
+
+
+ /**
+ * Standard constructor for use when going from WordSmith to DOM.
+ *
+ * @param dataArray <code>byte</code> array.
+ * @param startIndex The start index.
+ * @param ft The font table.
+ * @param ct The color table.
+ */
+ public WseTextRun(byte dataArray[], int startIndex, WseFontTable ft,
+ WseColorTable ct) {
+
+ this.ct = ct;
+
+ startIndex++; // Skip the leading "1"
+
+ int textLen = ((dataArray[startIndex] << 8)
+ | (dataArray[startIndex+1] & 0xFF));
+ startIndex += 2;
+
+ fontIndex = dataArray[startIndex++];
+ if (ft != null)
+ fontName = ft.getFontName(fontIndex);
+
+ fontSize = dataArray[startIndex++];
+
+ colorIndex = dataArray[startIndex++];
+ modifiers = dataArray[startIndex++];
+
+ text = new String(dataArray, startIndex, textLen);
+ startIndex += textLen; // skip the text
+ }
+
+
+ /**
+ * Given a <code>byte</code> sequence, assumed to be a text run,
+ * compute the index of the first byte past the text run.
+ *
+ * @param dataArray <code>byte</code> array.
+ * @param startIndex The start index
+ *
+ * @return The index of the first <code>byte</code> past the
+ * text run.
+ */
+ public static int computeNewIndex(byte dataArray[], int startIndex) {
+
+ startIndex++; // Skip the leading "1"
+
+ int textLen = ((dataArray[startIndex] << 8)
+ | (dataArray[startIndex+1] & 0xFF));
+ startIndex += 2;
+
+ startIndex += 4; // skip attributes
+ // text = new String(dataArray, startIndex, textLen);
+ startIndex += textLen; // skip the text
+ return startIndex;
+ }
+
+
+ /**
+ * Return true if the sequence starting at
+ * <code>dataArray[startIndex]</code> is a valid text run.
+ *
+ * @param dataArray <code>byte</code> array.
+ * @param startIndex The start index.
+ *
+ * @return true if the sequence starting at
+ * <code>dataArray[startIndex]</code> is a valid
+ * text run, false otherwise.
+ */
+ public static boolean isValid(byte dataArray[], int startIndex) {
+ return (dataArray[startIndex] == 1);
+ }
+
+ /**
+ * Return the number of bytes needed to represent this text run.
+ *
+ * @return The number of bytes needed to represent this text run.
+ */
+ int getByteCount() {
+ return text.length() + 7;
+ }
+
+
+ /**
+ * Return an <code>byte</code> array representing this text run.
+ *
+ * @return An <code>byte</code> array representing this text run.
+ */
+ byte[] getBytes() {
+ short textLen = (short)text.length();
+ byte b[] = new byte[textLen + 7];
+ b[0] = 1;
+ b[1] = (byte)(textLen >> 8);
+ b[2] = (byte)(textLen & 0xFF);
+ b[3] = fontIndex;
+ b[4] = fontSize;
+ b[5] = colorIndex;
+ b[6] = modifiers;
+ byte[] txtBytes = text.getBytes();
+ System.arraycopy(txtBytes, 0, b, 7, textLen);
+ return b;
+ }
+
+
+ /**
+ * Return the text of this run.
+ *
+ * @return The text of this run.
+ */
+ public String getText() {
+ return text;
+ }
+
+
+ /**
+ * Return a <code>TextStyle</code> that reflects the formatting
+ * of this run.
+ *
+ * @return A <code>TextStyle</code> that reflects the formatting
+ * of this run.
+ */
+ public TextStyle makeStyle() {
+ int mod = 0;
+ if ((modifiers & BOLD) != 0) mod |= TextStyle.BOLD;
+ if ((modifiers & ITALIC) != 0) mod |= TextStyle.ITALIC;
+ if ((modifiers & UNDERLINE) != 0) mod |= TextStyle.UNDERLINE;
+ if ((modifiers & STRIKETHRU) != 0)
+ mod |= TextStyle.STRIKETHRU;
+ if ((modifiers & SUPERSCRIPT) != 0) mod |= TextStyle.SUPERSCRIPT;
+ if ((modifiers & SUBSCRIPT) != 0) mod |= TextStyle.SUBSCRIPT;
+
+ int mask = TextStyle.BOLD | TextStyle.ITALIC
+ | TextStyle.UNDERLINE
+ | TextStyle.STRIKETHRU | TextStyle.SUPERSCRIPT
+ | TextStyle.SUBSCRIPT;
+
+ TextStyle x = new TextStyle(null, "text", null, mask,
+ mod, (int)(fontSize/2), fontName, sc);
+
+ // If color table is available, set the colors.
+ if (ct != null) {
+ Color fc = ct.getColor(colorIndex & 0xF, true);
+ Color bc = ct.getColor(colorIndex >> 4, false);
+ x.setColors(fc, bc);
+ }
+
+ return x;
+ }
+
+
+ /**
+ * Display debug information.
+ */
+ public void dump() {
+ System.out.print("TEXT RUN: fontIndex = " + fontIndex
+ + " fontsize = " + fontSize
+ + " colorIndex = " + colorIndex
+ + " ");
+ if ((modifiers & BOLD) != 0) System.out.print("BOLD,");
+ if ((modifiers & ITALIC) != 0) System.out.print("ITALIC,");
+ if ((modifiers & UNDERLINE) != 0) System.out.print("UNDERLINE,");
+ if ((modifiers & STRIKETHRU) != 0) System.out.print("STRIKETHRU,");
+ if ((modifiers & SUPERSCRIPT) != 0) System.out.print("SUPERSCRIPT,");
+ if ((modifiers & SUBSCRIPT) != 0) System.out.print("SUBSCRIPT,");
+ System.out.println("\n" + text);
+ }
+}
+
diff --git a/xmerge/source/wordsmith/java/org/openoffice/xmerge/converter/xml/sxw/wordsmith/textRecord.java b/xmerge/source/wordsmith/java/org/openoffice/xmerge/converter/xml/sxw/wordsmith/textRecord.java
new file mode 100644
index 000000000000..01276ce79a94
--- /dev/null
+++ b/xmerge/source/wordsmith/java/org/openoffice/xmerge/converter/xml/sxw/wordsmith/textRecord.java
@@ -0,0 +1,115 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxw.wordsmith;
+
+import org.openoffice.xmerge.util.Debug;
+import java.io.IOException;
+import java.io.DataOutputStream;
+import java.io.ByteArrayOutputStream;
+
+/**
+ * This class represents a single text record in a WordSmith document.
+ * A record is composed of one or more "WordSmith elements", which
+ * include: WordSmith header, font table, color table, paragraphs,
+ * and text runs.
+ *
+ * @author David Proulx
+ */
+
+class textRecord {
+
+ java.util.Vector elements;
+
+
+ /**
+ * Default constructor
+ */
+ textRecord() {
+ elements = new java.util.Vector(10);
+ }
+
+
+ /**
+ * Add an element
+ *
+ * @param elem The element to add
+ */
+ void addElement(Wse elem) {
+ elements.add(elem);
+ }
+
+
+ /**
+ * Return the number of bytes needed to represent the current
+ * contents of this text record.
+ *
+ * @return The number of bytes needed to represent the current
+ * contents of this text record.
+ */
+ int getByteCount() {
+ int totalBytes = 0;
+ int nElements = elements.size();
+ for (int i = 0; i < nElements; i++) {
+ Wse e = (Wse)elements.elementAt(i);
+ totalBytes += e.getByteCount();
+ }
+ return totalBytes;
+ }
+
+
+ /**
+ * Return the contents of this record as a <code>byte</code> array.
+ *
+ * @return the contents of this record as a <code>byte</code> array.
+ */
+ byte[] getBytes() {
+ DataOutputStream os = null; // Used for storing the data
+ ByteArrayOutputStream bs = null; // Used for storing the data
+ byte ftBytes[] = null;
+ byte ctBytes[] = null;
+
+ try {
+ bs = new ByteArrayOutputStream();
+ os = new DataOutputStream(bs);
+ int nElements = elements.size();
+ for (int i = 0; i < nElements; i++) {
+ Wse e = (Wse)elements.get(i);
+ os.write(e.getBytes());
+ }
+
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
+ if (bs != null)
+ return bs.toByteArray();
+ else
+ return null;
+ }
+}
+
diff --git a/xmerge/source/wordsmith/java/org/openoffice/xmerge/converter/xml/sxw/wordsmith/util.java b/xmerge/source/wordsmith/java/org/openoffice/xmerge/converter/xml/sxw/wordsmith/util.java
new file mode 100644
index 000000000000..9dcb178197da
--- /dev/null
+++ b/xmerge/source/wordsmith/java/org/openoffice/xmerge/converter/xml/sxw/wordsmith/util.java
@@ -0,0 +1,68 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxw.wordsmith;
+
+/**
+ * WordSmith utility class.
+ *
+ * @author David Proulx
+ */
+class util {
+
+ /**
+ * Convert 2 bytes to an integer.
+ *
+ * @param data <code>byte</code> data to convert.
+ * @param index Index to convert.
+ *
+ * @return Converted integer.
+ */
+ static int intFrom2bytes(byte[] data, int index) {
+ return (((data[index] & 0xFF) << 8)
+ | (data[index+1] & 0xFF));
+
+ }
+
+
+ /**
+ * Convert 4 bytes to an integer.
+ *
+ * @param data <code>byte</code> data to convert.
+ * @param index Index to convert.
+ *
+ * @return Converted integer.
+ */
+ static int intFrom4bytes(byte[] data, int index) {
+ return (((data[index] & 0xFF) << 24)
+ | ((data[index + 1] & 0xFF) << 16)
+ | ((data[index + 2] & 0xFF) << 8)
+ | (data[index+3] & 0xFF));
+
+ }
+}
+
diff --git a/xmerge/source/wordsmith/makefile.mk b/xmerge/source/wordsmith/makefile.mk
new file mode 100644
index 000000000000..9edb4e758878
--- /dev/null
+++ b/xmerge/source/wordsmith/makefile.mk
@@ -0,0 +1,33 @@
+#*************************************************************************
+#
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# Copyright 2000, 2010 Oracle and/or its affiliates.
+#
+# OpenOffice.org - a multi-platform office productivity suite
+#
+# This file is part of OpenOffice.org.
+#
+# OpenOffice.org is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License version 3
+# only, as published by the Free Software Foundation.
+#
+# OpenOffice.org is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License version 3 for more details
+# (a copy is included in the LICENSE file that accompanied this code).
+#
+# You should have received a copy of the GNU Lesser General Public License
+# version 3 along with OpenOffice.org. If not, see
+# <http://www.openoffice.org/license.html>
+# for a copy of the LGPLv3 License.
+#
+#*************************************************************************
+
+TARGET=wordsmith
+PRJ=../..
+PRJNAME=xmerge
+
+.INCLUDE : ant.mk
+ALLTAR: ANTBUILD
diff --git a/xmerge/source/xmerge/build.xml b/xmerge/source/xmerge/build.xml
new file mode 100644
index 000000000000..8c46b46ea747
--- /dev/null
+++ b/xmerge/source/xmerge/build.xml
@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ #*************************************************************************
+ #
+ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+
+ Copyright 2000, 2010 Oracle and/or its affiliates.
+
+ OpenOffice.org - a multi-platform office productivity suite
+
+ This file is part of OpenOffice.org.
+
+ OpenOffice.org is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License version 3
+ only, as published by the Free Software Foundation.
+
+ OpenOffice.org is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License version 3 for more details
+ (a copy is included in the LICENSE file that accompanied this code).
+
+ You should have received a copy of the GNU Lesser General Public License
+ version 3 along with OpenOffice.org. If not, see
+ <http://www.openoffice.org/license.html>
+ for a copy of the LGPLv3 License.
+
+ #*************************************************************************
+ -->
+
+<project name="xmerge" default="all" basedir=".">
+
+ <property file="../inc/antbuild.properties"/>
+
+ <property environment="env"/>
+ <property name="env.XML_APIS_JAR" value="${solar.jar}/xml-apis.jar"/>
+ <property name="env.XERCES_JAR" value="${solar.jar}/xercesImpl.jar"/>
+
+ <path id="classpath">
+ <pathelement location="${env.XML_APIS_JAR}"/>
+ <pathelement location="${env.XERCES_JAR}"/>
+ <pathelement location="${solar.jar}/unoil.jar"/>
+ <pathelement location="${solar.jar}/ridl.jar"/>
+ <pathelement location="${solar.jar}/jurt.jar"/>
+ <pathelement location="${solar.jar}/juh.jar"/>
+ </path>
+
+
+ <target name="init" >
+ <mkdir dir="${target.dir}"/>
+ </target>
+
+ <!-- compile java sources in ${package} -->
+ <target name="compile" depends="init">
+ <javac srcdir="${src.dir}"
+ destdir="${target.dir}"
+ debug="${debug}"
+ deprecation="${deprecation}"
+ optimize="${optimize}">
+ <classpath refid="classpath"/>
+ </javac>
+ </target>
+
+ <!-- package to jar -->
+ <target name="jar" depends="compile">
+ <jar destfile="${target.jar}">
+ <fileset dir="${target.dir}"
+ includes="**/*.class" />
+ <fileset dir="${src.dir}"
+ includes="**/*.properties" />
+ <manifest>
+ <attribute name="Main-Class" value="org.openoffice.xmerge.test.Driver"/>
+ <attribute name="Specification-Title" value="OpenOffice XMerge Framework"/>
+ <attribute name="Specification-Vendor" value="OpenOffice.org"/>
+ <attribute name="Specification-Version" value="0.6.0"/>
+ <attribute name="Implementation-Version" value="#IMPL-VERSION#"/>
+ <attribute name="Class-Path" value="xml-apis.jar xercesImpl.jar serializer.jar"/>
+ </manifest>
+ </jar>
+ </target>
+
+ <!-- clean up -->
+ <target name="clean">
+ <delete dir="${class.dir}"/>
+ <delete file="${target.jar}"/>
+ </target>
+
+ <target name="all" depends="jar">
+ </target>
+
+</project>
+
diff --git a/xmerge/source/xmerge/converter.dtd b/xmerge/source/xmerge/converter.dtd
new file mode 100644
index 000000000000..a73ce946fa56
--- /dev/null
+++ b/xmerge/source/xmerge/converter.dtd
@@ -0,0 +1,96 @@
+<!--
+ #*************************************************************************
+ #
+ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+
+ Copyright 2000, 2010 Oracle and/or its affiliates.
+
+ OpenOffice.org - a multi-platform office productivity suite
+
+ This file is part of OpenOffice.org.
+
+ OpenOffice.org is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License version 3
+ only, as published by the Free Software Foundation.
+
+ OpenOffice.org is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License version 3 for more details
+ (a copy is included in the LICENSE file that accompanied this code).
+
+ You should have received a copy of the GNU Lesser General Public License
+ version 3 along with OpenOffice.org. If not, see
+ <http://www.openoffice.org/license.html>
+ for a copy of the LGPLv3 License.
+
+ #*************************************************************************
+ -->
+
+<!-- converter.dtd
+
+ Author: Brian Cameron
+
+ This DTD file is provided for documentation and development
+ purposes, the converter does not actually validate the
+ converter.xml files that it processes. Plug-ins will not
+ work properly, though, if the converter.xml does not
+ conform to this DTD specification. -->
+
+<!-- The root node, converters, must contain one or more
+ converter nodes, each corresponds to a converter plug-in. -->
+
+<!ELEMENT converters (converter)+>
+
+<!-- The converter node must contain two elements:
+ type - The convert-from mime-type.
+ version - The version of the plug-in.
+
+ Each converter node must contain these child nodes:
+ converter-display-name - Name of the converter
+ converter-class-impl - The PluginFactory implementation for
+ the plugin
+ converter-targets - Can be one or more of these nodes. Each
+ contains only a "type" element. This
+ "type" element specifies the convert-to
+ mime-type.
+
+ Each converter node may contain these child nodes:
+ converter-description - Descriptive description of the plug-in.
+ converter-vendor - Plug-in vendor name
+ converter-xslt-serialize - The URL of the xsl stylesheet for
+ serialization. This stylesheet must
+ exist if the xslt plugin implementation
+ is to be used. It is assumed that the
+ plug-in specified via converter-class-impl
+ will make use of this value.
+ converter-xslt-deserialize - The URL of the xsl stylesheet for
+ deserialization. This stylesheet must
+ exist if the xslt plugin implementation
+ is to be used. It is assumed that the
+ plug-in specified via converter-class-impl
+ will make use of this value.
+ -->
+
+<!ELEMENT converter (converter-display-name,
+ converter-description?,
+ converter-vendor?,
+ converter-class-impl,
+ converter-xslt-serialize?,
+ converter-xslt-deserialize?,
+ converter-target+)>
+
+<!ATTLIST converter type CDATA #REQUIRED>
+<!ATTLIST converter version CDATA #REQUIRED>
+
+<!ELEMENT converter-display-name (#PCDATA)>
+<!ELEMENT converter-description (#PCDATA)>
+<!ELEMENT converter-vendor (#PCDATA)>
+<!ELEMENT converter-class-impl (#PCDATA)>
+<!ELEMENT converter-xslt-serialize (#PCDATA)>
+<!ELEMENT converter-xslt-deserialize (#PCDATA)>
+
+<!ELEMENT converter-target EMPTY>
+
+<!ATTLIST converter-target type CDATA #REQUIRED>
+
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 000000000000..59b6db6aa84c
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/Convert.java
@@ -0,0 +1,327 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge;
+
+import java.io.InputStream;
+import java.io.IOException;
+import java.util.Enumeration;
+
+import org.openoffice.xmerge.util.registry.ConverterInfo;
+
+/**
+ * The <code>Convert</code> class manages a conversion from one
+ * mime-type to another. The <code>ConvertFactory</code> is
+ * responsible for returning the appropriate <code>Convert</code>
+ * class for a specified conversion. This class is responsible
+ * for all interactions with the <code>PluginFactory</code>
+ * implementation.
+ *
+ * @see ConverterFactory
+ * @see PluginFactory
+ * @see org.openoffice.xmerge.util.registry.ConverterInfo
+ *
+ * @author Martin Maher
+ */
+public class Convert implements Cloneable {
+
+ /**
+ * ConvertInfo that corresponds to the from-mime/to-mime
+ * conversion.
+ */
+ private ConverterInfo ci;
+
+ /**
+ * true if converting to the Office format, false if converting
+ * to the device format.
+ */
+ private boolean toOffice;
+
+ /**
+ * Holds the convert input data.
+ */
+ private ConvertData inputCD = new ConvertData();
+
+
+ /**
+ * Construct a Convert class with specified <code>ConvertInfo</code>
+ * registry information.
+ *
+ * @param ci A <code>ConvertInfo</code> object containing
+ * registry information corresponding to a
+ * specific plug-in.
+ * @param toOffice true if converting to the Office format,
+ * false if converting to the device format.
+ */
+ public Convert(ConverterInfo ci, boolean toOffice) {
+ this.ci = ci;
+ this.toOffice = toOffice;
+ }
+
+
+ /**
+ * Adds an <code>InputStream</code> to be used as input by the
+ * <code>Convert</code> class. It is possible that many files
+ * need to be converted into a single output <code>Documetn</code>,
+ * 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</code>.
+ * @param is <code>InputStream</code> 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 == true) {
+ inputDoc = ci.getPluginFactory().createDeviceDocument(name, is);
+ } else {
+ inputDoc = ci.getPluginFactory().createOfficeDocument(name, is);
+ }
+ inputCD.addDocument(inputDoc);
+ }
+
+ /**
+ * Adds an <code>InputStream</code> to be used as input by the
+ * <code>Convert</code> class. It is possible that many files
+ * need to be converted into a single output <code>Documetn</code>,
+ * 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</code>.
+ * @param is <code>InputStream</code> to be used as input.
+ * @param isZip <code>boolean</code> 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 == true) {
+ inputDoc = ci.getPluginFactory().createDeviceDocument(name, is);
+ } else {
+ inputDoc = ci.getPluginFactory().createOfficeDocument(name, is, isZip);
+ }
+ inputCD.addDocument(inputDoc);
+ }
+
+
+ /**
+ * Returns a <code>DocumentMerger</code> for the given <code>Document</code>.
+ *
+ * @param origDoc The <code>Document</code> were later changes will be merged to
+ *
+ * @return The <code>DocumentMerger</code> 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</code> method to accept input for the next
+ * conversion.
+ */
+ public void reset() {
+ inputCD.reset();
+ }
+
+
+ /**
+ * Clones a Convert object so another Convert object can
+ * do the same conversion. <code>InputStream<code> objects passed
+ * in via calls to the <code>addInputStream</code> method are not
+ * copied.
+ *
+ * @return The cloned <code>Convert</code> object.
+ */
+ 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</code>
+ * method to the output format specified by this <code>Convert</code>
+ * 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();
+
+ Enumeration e = inputCD.getDocumentEnumeration();
+
+ Document doc = (Document) e.nextElement();
+ DocumentSerializer ser = myDocSerializerFactory.createDocumentSerializer(doc);
+ dataOut = ser.serialize();
+
+ return dataOut;
+ }
+ }
+
+ /**
+ * NEW (HJ):
+ * Convert the input specified in calls to the <code>addInputStream</code>
+ * method to the output format specified by this <code>Convert</code>
+ * class.
+ * The (de)serializer may use the URLs to resolve links and choose name(s)
+ * for destination document(s).
+ *
+ * @return The output data.
+ *
+ * @param sFromURL URL of the source document (may be null if unknown)
+ * @param sToURL URL of the destination document (may be null if unknown)
+ *
+ * @throws ConvertException If any conversion error occurs.
+ * @throws IOException If any I/O error occurs.
+ */
+ public ConvertData convert(String sFromURL, String sToURL) 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 officeDoc = deser instanceof DocumentSerializer2 ?
+ ((DocumentDeserializer2) deser).deserialize(sFromURL,sToURL) :
+ deser.deserialize();
+
+
+ dataOut.addDocument(officeDoc);
+ return dataOut;
+
+ } else {
+
+ // From Office format to device format
+ //
+ DocumentSerializerFactory myDocSerializerFactory =
+ ci.getDocSerializerFactory();
+
+ Enumeration e = inputCD.getDocumentEnumeration();
+
+ Document doc = (Document) e.nextElement();
+ DocumentSerializer ser = myDocSerializerFactory.createDocumentSerializer(doc);
+ dataOut = ser instanceof DocumentSerializer2 ?
+ ((DocumentSerializer2) ser).serialize(sFromURL,sToURL) :
+ ser.serialize();
+
+ return dataOut;
+ }
+ }
+
+ /**
+ * Returns the appropriate &quot;Office&quot; <code>Document</code>
+ * object for this plug-in.
+ *
+ * @param name The name of the <code>Document</code> to create.
+ * @param is The <code>InputStream</code> corresponding to the
+ * <code>Document</code> to create.
+ *
+ * @return The appropriate &quot;Office&quot; <code>Document</code>
+ * 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));
+ }
+
+
+ /**
+ * Returns the appropriate &quot;Device&quot; <code>Document</code>
+ * object for this plug-in.
+ *
+ * @param name The name of the <code>Document</code> to create.
+ * @param is The <code>InputStream</code> corresponding to the
+ * <code>Document</code> to create.
+ *
+ * @return The appropriate &quot;Device&quot; <code>Document</code>
+ * object for this plug-in.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ public Document getDeviceDocument(String name, InputStream is)
+ throws IOException {
+ return(ci.getPluginFactory().createDeviceDocument(name, is));
+ }
+}
+
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 000000000000..b2da0e3f3e4c
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/ConvertData.java
@@ -0,0 +1,117 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge;
+
+import java.util.Vector;
+import java.util.Enumeration;
+
+/**
+ * <p><code>ConvertData</code> is used as a container for passing
+ * <code>Document</code> objects in and out of the <code>Convert</code>
+ * class. The <code>ConvertData</code> contains a <code>String</code>
+ * name and a <code>Vector</code> of <code>Document</code> objects.</p>
+ *
+ * @author Martin Maher
+ */
+public class ConvertData {
+
+ /**
+ * Vector of <code>Document</code> objects.
+ */
+ private Vector v = new Vector();
+
+ /**
+ * Name of the <code>ConvertData</code> object.
+ */
+ private String name;
+
+
+ /**
+ * Resets ConvertData. This empties all <code>Document</code>
+ * objects from this class. This allows reuse of a
+ * <code>ConvertData</code>.
+ */
+ public void reset() {
+ name = null;
+ v.removeAllElements();
+ }
+
+ /**
+ * Returns the <code>Document</code> name.
+ *
+ * @return The <code>Document</code> name.
+ */
+ public String getName() {
+ return name;
+ }
+
+
+ /**
+ * Sets the <code>Document</code> name.
+ *
+ * @param docName The name of the <code>Document</code>.
+ */
+ public void setName(String docName) {
+ name = docName;
+ }
+
+
+ /**
+ * Adds a <code>Document</code> to the vector.
+ *
+ * @param doc The <code>Document</code> to add.
+ */
+ public void addDocument(Document doc) {
+ v.add(doc);
+ }
+
+
+ /**
+ * Gets an <code>Enumeration</code> to access the <code>Vector</code>
+ * of <code>Document</code> objects.
+ *
+ * @return The <code>Enumeration</code> to access the
+ * <code>Vector</code> of <code>Document</code> objects.
+ */
+ public Enumeration getDocumentEnumeration() {
+ Enumeration enumerate = v.elements();
+ return (enumerate);
+ }
+
+
+ /**
+ * Gets the number of <code>Document</code> objects currently stored
+ *
+ * @return The number of <code>Document</code> 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 000000000000..5065ca20ca10
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/ConvertException.java
@@ -0,0 +1,45 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge;
+
+/**
+ * This <code>Exception</code> 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</code>.
+ */
+ public ConvertException(String message) {
+ super(message);
+ }
+}
+
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 000000000000..b26e0d5559b8
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/ConverterCapabilities.java
@@ -0,0 +1,67 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge;
+
+/**
+ * <p>A <code>ConverterCapabilities</code> object is used by
+ * <code>DocumentMerger</code> implementations. The
+ * <code>ConverterCapabilities</code> indicates which
+ * &quot;Office&quot; XML tags are supported by the
+ * &quot;Device&quot; format.</p>
+ *
+ * @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 true if the device format supports the
+ * tag, 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 true if the device format supports the
+ * attribute, false otherwise.
+ */
+ boolean canConvertAttribute(String tag, String attribute);
+}
+
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 000000000000..b6afe0d42bfa
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/ConverterFactory.java
@@ -0,0 +1,124 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+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</code> objects, which
+ * are used to do a conversion. The <code>ConvertFactory</code> does
+ * this via the <code>ConvertInfoMgr</code> which maintains a list of
+ * which <code>Convert</code> objects are available and their
+ * capabilities.
+ *
+ * @see Convert
+ * @see org.openoffice.xmerge.util.registry.ConverterInfoMgr
+ *
+ * @author Martin Maher
+ */
+public class ConverterFactory {
+
+ /**
+ * Confirms whether or not a particular conversion can be done
+ * based on the Mime types of the files to be converted to and
+ * from.
+ *
+ * @param mimeTypeIn The mime input type.
+ * @param mimeTypeOut The mime output type.
+ *
+ * @return true if the conversion is possible, false otherwise.
+ */
+ public boolean canConvert(String mimeTypeIn, String mimeTypeOut) {
+
+ ConverterInfo foundInfo = null;
+
+ // findConverterInfo expects the second paramenter to be the
+ // destination MimeType
+ if (foundInfo.isValidOfficeType(mimeTypeOut))
+ foundInfo = ConverterInfoMgr.findConverterInfo(mimeTypeIn, mimeTypeOut);
+ else
+ foundInfo = ConverterInfoMgr.findConverterInfo(mimeTypeOut, mimeTypeIn);
+
+ if (foundInfo != null)
+ return true;
+ else
+ return false;
+ }
+
+
+ /**
+ * Returns the <code>Convert</code> object that converts
+ * the specified device/office mime type conversion. If there
+ * are multiple <code>Converter</code> 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</code> object that supports
+ * the specified conversion.
+ */
+ public Convert getConverter(String mimeTypeIn, String mimeTypeOut) {
+
+ ConverterInfo foundInfo = null;
+ boolean toOffice;
+
+ toOffice = foundInfo.isValidOfficeType(mimeTypeOut);
+
+ // findConverterInfo expects the second paramenter 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</code> object that is described
+ * by the <code>ConverterInfo</code> parameter.
+ *
+ * @param ci The <code>ConverterInfo</code> describing the converter.
+ *
+ * @param toOffice true to convert to office, false to convert to device.
+ *
+ * @return The <code>Convert</code> 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 000000000000..786050a42a0e
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/Document.java
@@ -0,0 +1,99 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge;
+
+import java.io.OutputStream;
+import java.io.InputStream;
+import java.io.IOException;
+
+/**
+ * <p>A <code>Document</code> represents any <code>Document</code>
+ * to be converted and the resulting <code>Document</code> from any
+ * conversion.</p>
+ *
+ * <p>It is created by the <code>PluginFactory</code> object's {@link
+ * org.openoffice.xmerge.PluginFactory#createOfficeDocument
+ * createOfficeDocument} method or the {@link
+ * org.openoffice.xmerge.PluginFactory#createDeviceDocument
+ * createDeviceDocument} method.</p>
+ *
+ * @author Herbie Ong
+ * @see org.openoffice.xmerge.PluginFactory
+ */
+public interface Document {
+
+ /**
+ * <p>Writes out the <code>Document</code> content to the specified
+ * <code>OutputStream</code>.</p>
+ *
+ * <p>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.</p>
+ *
+ * @param os <code>OutputStream</code> to write out the
+ * <code>Document</code> content.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ public void write(OutputStream os) throws IOException;
+
+
+ /**
+ * <p>Reads the content from the <code>InputStream</code> into
+ * the <code>Document</code>.</p>
+ *
+ * <p>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.</p>
+ *
+ * @param is <code>InputStream</code> to read in the
+ * <code>Document</code> content.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ public void read(InputStream is) throws IOException;
+
+
+ /**
+ * Returns the <code>Document</code> name with no file extension.
+ *
+ * @return The <code>Document</code> name with no file extension.
+ */
+ public String getName();
+
+
+ /**
+ * Returns the <code>Document</code> name with file extension.
+ *
+ * @return The <code>Document</code> name with file extension.
+ */
+ public String getFileName();
+}
+
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 000000000000..4c26453a982b
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/DocumentDeserializer.java
@@ -0,0 +1,65 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge;
+
+import java.io.IOException;
+
+/**
+ * <p>A <code>DocumentDeserializer</code> represents a converter that
+ * converts &quot;Device&quot; <code>Document</code> objects into the
+ * &quot;Office&quot; <code>Document</code> format.</p>
+ *
+ * <p>The <code>DocumentDeserializer</code> object is created by
+ * the </code>PluginFactory</code> {@link
+ * org.openoffice.xmerge.DocumentDeserializerFactory#createDocumentDeserializer
+ * createDocumentDeserializer} method. When it is constructed, a
+ * <code>ConvertData</code> object is passed in to be used as input.</p>
+ *
+ * @author Herbie Ong
+ * @see org.openoffice.xmerge.PluginFactory
+ * @see org.openoffice.xmerge.DocumentDeserializerFactory
+ */
+public interface DocumentDeserializer {
+
+ /**
+ * <p>Convert the data passed into the <code>DocumentDeserializer</code>
+ * constructor into the &quot;Office&quot; <code>Document</code>
+ * format.</p>
+ *
+ * <p>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.</p>
+ *
+ * @return The resulting <code>Document</code> object from conversion.
+ *
+ * @throws ConvertException If any Convert error occurs.
+ * @throws IOException If any I/O error occurs.
+ */
+ public Document deserialize() throws ConvertException, IOException;
+}
+
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 000000000000..417144b7ac49
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/DocumentDeserializer2.java
@@ -0,0 +1,71 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge;
+
+import java.io.IOException;
+
+/**
+ * <p>A <code>DocumentDeserializer</code> represents a converter that
+ * converts &quot;Device&quot; <code>Document</code> objects into the
+ * &quot;Office&quot; <code>Document</code> format.</p>
+ *
+ * <p>The <code>PluginFactory</code> {@link
+ * org.openoffice.xmerge.DocumentDeserializerFactory#createDocumentDeserializer
+ * createDocumentDeserializer} method creates a <code>DocumentDeserializer</code>,
+ * which may or may not implement <code>DocumentDeserializer2</code>.
+ * When it is constructed, a
+ * <code>ConvertData</code> object is passed in to be used as input.</p>
+ *
+ * @author Henrik Just
+ * @see org.openoffice.xmerge.PluginFactory
+ * @see org.openoffice.xmerge.DocumentDeserializerFactory
+ */
+public interface DocumentDeserializer2 extends DocumentSerializer {
+
+ /**
+ * <p>Convert the data passed into the <code>DocumentDeserializer2</code>
+ * constructor into the &quot;Office&quot; <code>Document</code>
+ * format. The URL's passed may be used to resolve links and to choose the
+ * name of the output office document.</p>
+ *
+ * <p>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.</p>
+ *
+ * @return The resulting <code>Document</code> 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.
+ */
+ public Document deserialize(String deviceURL, String officeURL) throws
+ ConvertException, IOException;
+}
+
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 000000000000..315ebc0cf051
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/DocumentDeserializerFactory.java
@@ -0,0 +1,65 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge;
+
+/**
+ * <p>A <code>DocumentDeserializer</code> object is used to convert
+ * from the &quot;Device&quot; <code>Documetn</code> format to the
+ * &quot;Office&quot; <code>Document</code> format.</p>
+ *
+ * <p>All plug-in implementations of the <code>PluginFactory</code>
+ * interface that also support deserialization must also
+ * implement this interface.</p>
+ *
+ * @see PluginFactory
+ * @see DocumentDeserializer
+ */
+public interface DocumentDeserializerFactory {
+
+ /**
+ * The <code>DocumentDeserializer</code> is used to convert
+ * from the &quot;Device&quot; <code>Document</code> format to
+ * the &quot;Office&quot; <code>Document</code> format.</p>
+ *
+ * The <code>ConvertData</code> object is passed along to the
+ * created <code>DocumentDeserializer</code> via its constructor.
+ * The <code>ConvertData</code> is read and converted when the
+ * the <code>DocumentDeserializer</code> object's
+ * <code>deserialize</code> method is called.
+ * </p>
+ *
+ * @param cd <code>ConvertData</code> object that the created
+ * <code>DocumentDeserializer</code> object uses as
+ * input.
+ *
+ * @return A <code>DocumentDeserializer</code> object.
+ */
+
+ public DocumentDeserializer createDocumentDeserializer(ConvertData cd);
+}
+
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 000000000000..3f29b2dad7f2
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/DocumentMerger.java
@@ -0,0 +1,93 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge;
+
+/**
+ * <p>A <code>DocumentMerger</code> can merge changes from a modified
+ * &quot;Device&quot; <code>Document</code> to the assigned original
+ * &quot;Office&quot; <code>Document</code>.</p>
+ *
+ * <p>Merge is useful when an <code>OfficeDocument</code>
+ * is converted to a &quot;Device&quot; <code>Document</code> format,
+ * and the &quot;Device&quot; <code>Document</code> version is modified.
+ * Those changes can be merged back into the original
+ * <code>OfficeDocument</code> with the merger. The merger is capable
+ * of doing this even if the &quot;Device&quot; format is lossy in
+ * comparison to the <code>OfficeDocument</code> format.</p>
+ *
+ * <p>The <code>ConverterCapabilities</code> object is what the
+ * DocumentMerger utilizes to know how the &quot;Office&quot;
+ * <code>Document</code> tags are supported in the &quot;Device&quot;
+ * format.</p>
+ *
+ * <p>The <code>DocumentMerger</code> object is created by a
+ * the <code>DocumentMergerFactory</code> {@link
+ * org.openoffice.xmerge.DocumentMergerFactory#createDocumentMerger
+ * createDocumenMerger} method. When it is constructed, the
+ * &quot;Original Office&quot; <code>Document</code> object is
+ * passed in to be used as input.</p>
+ *
+ * @author Herbie Ong
+ * @see org.openoffice.xmerge.PluginFactory
+ * @see org.openoffice.xmerge.DocumentMergerFactory
+ * @see org.openoffice.xmerge.ConverterCapabilities
+ */
+public interface DocumentMerger {
+
+ /**
+ * <p>This method will find the changes that had happened
+ * in the <code>modifiedDoc</code> <code>Document</code>
+ * object given the designated original <code>Document</code>.</p>
+ *
+ * <p>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</code>
+ * into the assigned original <code>Document</code> object, thus
+ * it also will try to preserve items that were originally in
+ * the original <code>Document</code>, but never got transferred
+ * during the
+ * {@link org.openoffice.xmerge.DocumentSerializer#serialize
+ * serialize} process/method call. After this method call, the
+ * original <code>Document</code> object will contain the changes
+ * applied.</p>
+ *
+ * <p>This method may or may not be thread-safe.
+ * Also, it is expected that the user uses only one instance
+ * of a <code>DocumentMerger</code> object per merge process.
+ * Create another <code>DocumentMerger</code> object for another
+ * merge process.</p>
+ *
+ * @param modifiedDoc device <code>Document</code> object.
+ *
+ * @throws MergeException If any merge error occurs.
+ */
+ public 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 000000000000..3daa41db4b99
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/DocumentMergerFactory.java
@@ -0,0 +1,63 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge;
+
+/**
+ * <p>All plug-in implementations of the <code>PluginFactory</code>
+ * interface that also support merging must also implement
+ * this interface.</p>
+ *
+ * <p>Merge is useful when an <code>OfficeDocument</code>
+ * is converted to a &quot;Device&quot; <code>Document</code> format,
+ * and the &quot;Device&quot; <code>Document</code> version is modified.
+ * Those changes can be merged back into the original
+ * <code>OfficeDocument</code> with the merger. The merger is capable
+ * of doing this even if the &quot;Device&quot; format is lossy in
+ * comparison to the <code>OfficeDocument</code> format.</p>
+ *
+ * @see PluginFactory
+ * @see DocumentMerger
+ * @see ConverterCapabilities
+ *
+ */
+public interface DocumentMergerFactory {
+
+ /**
+ * <p>Create a <code>DocumentMerger</code> object given a
+ * <code>Document</code> object.</p>
+ *
+ * @param doc <code>Document</code> object that the created
+ * <code>DocumentMerger</code> object uses as a base
+ * <code>Document</code> for merging changes into.
+ *
+ * @return A <code>DocumentMerger</code> object or null if none
+ * exists.
+ */
+ public DocumentMerger createDocumentMerger(Document doc);
+}
+
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 000000000000..d46e5baca765
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/DocumentSerializer.java
@@ -0,0 +1,67 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge;
+
+import java.io.IOException;
+
+/**
+ * <p>A <code>DocumentSerializer</code> represents a converter that
+ * converts a &quot;Office&quot; <code>Document</code> to a
+ * &quot;Device&quot; <code>Document</code> format.</p>
+ *
+ * <p>The <code>DocumentSerializer</code> object is created by a
+ * the <code>PluginFactory</code> {@link
+ * org.openoffice.xmerge.DocumentSerializerFactory#createDocumentSerializer
+ * createDocumentSerializer} method. When it is constructed, a
+ * &quot;Office&quot; <code>Document</code> object is passed in to
+ * be used as input.</p>
+ *
+ * @author Herbie Ong
+ * @see org.openoffice.xmerge.PluginFactory
+ * @see org.openoffice.xmerge.DocumentSerializerFactory
+ */
+public interface DocumentSerializer {
+
+ /**
+ * <p>Convert the data passed into the <code>DocumentSerializer</code>
+ * constructor into the &quot;Device&quot; <code>Document</code>
+ * format.</p>
+ *
+ * <p>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.</p>
+ *
+ * @return <code>ConvertData</code> object to pass back the
+ * converted data.
+ *
+ * @throws ConvertException If any conversion error occurs.
+ * @throws IOException If any I/O error occurs.
+ */
+ public 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 000000000000..dd3ee25460a6
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/DocumentSerializer2.java
@@ -0,0 +1,73 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge;
+
+import java.io.IOException;
+
+/**
+ * <p>A <code>DocumentSerializer2</code> represents a converter that
+ * converts a &quot;Office&quot; <code>Document</code> to a
+ * &quot;Device&quot; <code>Document</code> format.</p>
+ *
+ * <p>The <code>PluginFactory</code> {@link
+ * org.openoffice.xmerge.DocumentSerializerFactory#createDocumentSerializer
+ * createDocumentSerializer} method creates a <code>DocumentSerializer</code>,
+ * which may or may not implement <code>DocumentSerializer2</code>.
+ * When it is constructed, a
+ * &quot;Office&quot; <code>Document</code> object is passed in to
+ * be used as input.</p>
+ *
+ * @author Henrik Just
+ * @see org.openoffice.xmerge.PluginFactory
+ * @see org.openoffice.xmerge.DocumentSerializerFactory
+ */
+public interface DocumentSerializer2 extends DocumentSerializer {
+
+ /**
+ * <p>Convert the data passed into the <code>DocumentSerializer2</code>
+ * constructor into the &quot;Device&quot; <code>Document</code>
+ * format. The URL's passed may be used to resolve links and to name
+ * the output device document(s).</p>
+ *
+ * <p>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.</p>
+ *
+ * @return <code>ConvertData</code> 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.
+ */
+ public ConvertData serialize(String officeURL, String deviceURL) throws
+ ConvertException, IOException;
+}
+
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 000000000000..6d6f47078b5e
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/DocumentSerializerFactory.java
@@ -0,0 +1,63 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge;
+
+/**
+ * <p>A <code>DocumentSerializer</code> object is used to convert
+ * from the &quot;Office&quot; <code>Document</code> format to the
+ * &quot;Device&quot; <code>Document</code> format.</p>
+ *
+ * <p>All plug-in implementations of the <code>PluginFactory</code>
+ * interface that also support serialization must also
+ * implement this interface.</p>
+ *
+ * @see PluginFactory
+ * @see DocumentSerializer
+ */
+public interface DocumentSerializerFactory {
+
+ /**
+ * <p>The <code>DocumentSerializer</code> is used to convert
+ * from the &quot;Office&quot; <code>Document</code> format
+ * to the &quot;Device&quot; <code>Document</code> format.</p>
+ *
+ * The <code>ConvertData</code> object is passed along to the
+ * created <code>DocumentSerializer</code> via its constructor.
+ * The <code>ConvertData</code> is read and converted when the
+ * the <code>DocumentSerializer</code> object's
+ * <code>serialize</code> method is called.
+ *
+ * @param doc <code>Document</code> object that the created
+ * <code>DocumentSerializer</code> object uses
+ * as input.
+ *
+ * @return A <code>DocumentSerializer</code> object.
+ */
+ public 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 000000000000..8c649c8fa6cf
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/MergeException.java
@@ -0,0 +1,45 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge;
+
+/**
+ * This <code>Exception</code> 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</code>.
+ */
+ public MergeException(String message) {
+ super(message);
+ }
+}
+
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 000000000000..de7baba4683f
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/PluginFactory.java
@@ -0,0 +1,193 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge;
+
+import org.openoffice.xmerge.util.registry.ConverterInfo;
+import java.io.InputStream;
+import java.io.IOException;
+
+/**
+ * <p>A <code>PluginFactory</code> encapsulates the
+ * conversions from one <code>Document</code> format to another.
+ * It provides conversions in both directions. Refer to the
+ * <a href="package-summary.html#package_description">
+ * package description</a> for its usage.</p>
+ *
+ * <p>Conversion from the &quot;Office&quot; <code>Document</code>
+ * format to a &quot;Device&quot; <code>Document</code> format may
+ * be lossy, i.e. some information may be lost. If a plug-in
+ * implements the <code>DocumentMergerFactory</code> interface,
+ * then there is the possibility for merging the changes done on the
+ * &quot;Device&quot; <code>Document</code> back to the original
+ * &quot;Office&quot; <code>Document</code> via the
+ * <code>DocumentMerger</code> interface.</p>
+ *
+ * <p>Plug-ins that convert from the &quot;Device&quot;
+ * <code>Document</code> format to the &quot;Office&quot;
+ * <code>Document</code> format must implement the
+ * <code>DocumentDeserializerFactory</code> interface. Plug-ins
+ * that convert from the &quot;Office&quot; <code>Document</code>
+ * format to the &quot;Device&quot; format must implement the
+ * <code>DocumentSerializerFactory</code> interface.
+ *
+ * <p>All plug-ins should have an associated Plugin 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</code> object. The <code>ConverterInfoMgr</code>
+ * manages a registry of all <code>ConverterInfo</code> objects. For
+ * more information about this XML file, refer to
+ * <a href="converter/xml/sxc/package-summary.html">
+ * org.openoffice.xmerge.util.registry</a>.</p>
+ *
+ * @author Herbie Ong
+ * @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</code> object.
+ */
+ private ConverterInfo ciCache;
+
+
+ /**
+ * Constructor that caches the <code>ConvertInfo</code> that
+ * corresponds to the registry information for this plug-in.
+ *
+ * @param ci <code>ConvertInfo</code> object.
+ */
+ public PluginFactory(ConverterInfo ci) {
+ ciCache=ci;
+ }
+
+
+ /**
+ * Returns the <code>ConvertInfo</code> that corresponds to this
+ * plug-in.
+ *
+ * @return The <code>ConvertInfo</code> that corresponds to this
+ * plug-in.
+ */
+ public ConverterInfo getConverterInfo () {
+ return ciCache;
+ }
+
+
+ /**
+ * <p>Create a <code>Document</code> object that corresponds to
+ * the Office data passed in via the <code>InputStream</code>
+ * object. This abstract method must be implemented for each
+ * plug-in.</p>
+ *
+ * <p>This method will read from the given <code>InputStream</code>
+ * object. The returned <code>Document</code> object will contain
+ * the necessary data for the other objects created by the
+ * <code>PluginFactory</code> to process, like a
+ * <code>DocumentSerializer</code> object and a
+ * <code>DocumentMerger</code> object.</p>
+ *
+ * @param name The <code>Document</code> name.
+ * @param is <code>InputStream</code> object corresponding
+ * to the <code>Document</code>.
+ *
+ * @return A <code>Document</code> object representing the
+ * particular <code>Document</code> format for the
+ * <code>PluginFactory</code>.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ public abstract Document createOfficeDocument(String name, InputStream is)
+ throws IOException;
+
+
+ /**
+ * <p>Create a <code>Document</code> object that corresponds to
+ * the Office data passed in via the <code>InputStream</code>
+ * object. This abstract method must be implemented for each
+ * plug-in.</p>
+ *
+ * <p>This method will read from the given <code>InputStream</code>
+ * object. The returned <code>Document</code> object will contain
+ * the necessary data for the other objects created by the
+ * <code>PluginFactory</code> to process, like a
+ * <code>DocumentSerializer</code> object and a
+ * <code>DocumentMerger</code> object.</p>
+ *
+ * @param name The <code>Document</code> name.
+ * @param is <code>InputStream</code> object corresponding
+ * to the <code>Document</code>.
+ * @param isZip <code>boolean</code> to show that the created office
+ * document is to be zipped.
+ *
+ * @return A <code>Document</code> object representing the
+ * particular <code>Document</code> format for the
+ * <code>PluginFactory</code>.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ public abstract Document createOfficeDocument(String name, InputStream is,boolean isZip)
+ throws IOException;
+
+
+ /**
+ * <p>Create a <code>Document</code> object that corresponds to
+ * the device data passed in via the <code>InputStream</code>
+ * object. This abstract method must be implemented for each
+ * plug-in.</p>
+ *
+ * <p>This method will read from the given <code>InputStream</code>
+ * object. The returned <code>Document</code> object will contain
+ * the necessary data for the other objects created by the
+ * <code>PluginFactory</code> to process, like a
+ * <code>DocumentSerializer</code> object and a
+ * <code>DocumentMerger</code> object.</p>
+ *
+ * @param name The <code>Document</code> name.
+ * @param is <code>InputStream</code> object corresponding
+ * to the <code>Document</code>.
+ *
+ * @return A <code>Document</code> object representing the
+ * particular <code>Document</code> format for the
+ * <code>PluginFactory</code>.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ public abstract Document createDeviceDocument(String name, InputStream is)
+ throws IOException;
+}
+
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 000000000000..b639d95a8116
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/Version.java
@@ -0,0 +1,88 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+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.
+ *
+ * @author Herbie Ong
+ */
+public final class Version {
+
+ private static Package pkg;
+
+ private static Version version;
+
+ static {
+
+ version = new Version();
+ 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());
+ }
+}
+
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 000000000000..f7df881b1061
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/dom/DOMDocument.java
@@ -0,0 +1,412 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+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.Element;
+import org.w3c.dom.Document;
+import org.xml.sax.SAXException;
+
+import org.openoffice.xmerge.util.Resources;
+import org.openoffice.xmerge.util.Debug;
+
+/**
+ * An implementation of <code>Document</code> for
+ * StarOffice documents.
+ */
+public class DOMDocument
+ implements org.openoffice.xmerge.Document {
+
+ /** Factory for <code>DocumentBuilder</code> objects. */
+ private static DocumentBuilderFactory factory =
+ DocumentBuilderFactory.newInstance();
+
+ /** DOM <code>Document</code> of content.xml. */
+ private Document contentDoc = null;
+
+ private String documentName = null;
+ private String fileName = null;
+ private String fileExt = null;
+
+ /** Resources object. */
+ private Resources res = null;
+
+
+ /**
+ * Default constructor.
+ *
+ * @param name <code>Document</code> name.
+ * @param ext <code>Document</code> extension.
+ */
+ public DOMDocument(String name,String ext)
+ {
+ this(name,ext,true, false);
+ }
+
+ /**
+ * Returns the file extension of the <code>Document</code>
+ * represented.
+ *
+ * @return file extension of the <code>Document</code>.
+ */
+ protected String getFileExtension() {
+ return fileExt;
+ }
+
+
+ /**
+ * Constructor with arguments to set <code>namespaceAware</code>
+ * and <code>validating</code> flags.
+ *
+ * @param name <code>Document</code> name (may or may not
+ * contain extension).
+ * @param ext <code>Document</code> extension.
+ * @param namespaceAware Value for <code>namespaceAware</code> flag.
+ * @param validating Value for <code>validating</code> flag.
+ */
+ public DOMDocument(String name, String ext,boolean namespaceAware, boolean validating) {
+
+ res = Resources.getInstance();
+ 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</code>
+ * name.
+ *
+ * @param name Full <code>Document</code> name with extension.
+ *
+ * @return Name of <code>Document</code> 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</code> object of the document content
+ * file. Note that a content DOM is not created when the constructor
+ * is called. So, either the <code>read</code> method or the
+ * <code>initContentDOM</code> method will need to be called ahead
+ * on this object before calling this method.
+ *
+ * @return DOM <code>Document</code> object.
+ */
+ public Document getContentDOM() {
+
+ return contentDoc;
+ }
+
+ /**
+ * Sets the Content of the <code>Document</code> to the contents of the
+ * supplied <code>Node</code> list.
+ *
+ * @return DOM <code>Document</code> object.
+ */
+ public void setContentDOM( Node newDom) {
+ contentDoc=(Document)newDom;
+ }
+
+
+ /**
+ * Return the name of the <code>Document</code>.
+ *
+ * @return The name of <code>Document</code>.
+ */
+ public String getName() {
+
+ return documentName;
+ }
+
+
+ /**
+ * Return the file name of the <code>Document</code>, possibly
+ * with the standard extension.
+ *
+ * @return The file name of <code>Document</code>.
+ */
+ public String getFileName() {
+
+ return fileName;
+ }
+
+
+ /**
+ * Read the Office <code>Document</code> from the specified
+ * <code>InputStream</code>.
+ *
+ * @param is Office document <code>InputStream</code>.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ public void read(InputStream is) throws IOException {
+ Debug.log(Debug.INFO, "reading file");
+ DocumentBuilder builder = null;
+ try {
+ builder = factory.newDocumentBuilder();
+ } catch (ParserConfigurationException ex) {
+ System.out.println("Error:"+ ex);
+ //throw new OfficeDocumentException(ex);
+ }
+ try {
+
+ contentDoc= builder.parse(is);
+
+
+ } catch (SAXException ex) {
+ System.out.println("Error:"+ ex);
+ //throw new OfficeDocumentException(ex);
+ }
+ }
+
+
+ /**
+ * Write out content to the supplied <code>OutputStream</code>.
+ *
+ * @param os XML <code>OutputStream</code>.
+ *
+ * @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);
+ }
+
+
+ /**
+ * <p>Write out a <code>org.w3c.dom.Document</code> object into a
+ * <code>byte</code> array.</p>
+ *
+ * <p>TODO: remove dependency on com.sun.xml.tree.XmlDocument
+ * package!</p>
+ *
+ * @param Document DOM <code>Document</code> object.
+ *
+ * @return <code>byte</code> array of DOM <code>Document</code>
+ * 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 dont 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
+ throw new IOException("No appropriate API (JAXP/Xerces) to serialize XML document: " + domImpl);
+ }
+ }
+ }
+ catch (ClassNotFoundException cnfe) {
+ throw new IOException(cnfe.toString());
+ }
+ catch (Exception e) {
+ // We may get some other errors, but the bottom line is that
+ // the steps being executed no longer work
+ throw new IOException(e.toString());
+ }
+
+ byte bytes[] = baos.toByteArray();
+
+ return bytes;
+ }
+
+
+ /**
+ * Initializes a new DOM <code>Document</code> with the content
+ * containing minimum XML tags.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ public final void initContentDOM() throws IOException {
+ contentDoc = createDOM("");
+
+ }
+
+ /**
+ * <p>Creates a new DOM <code>Document</code> containing minimum
+ * OpenOffice XML tags.</p>
+ *
+ * <p>This method uses the subclass
+ * <code>getOfficeClassAttribute</code> method to get the
+ * attribute for <i>office:class</i>.</p>
+ *
+ * @param rootName root name of <code>Document</code>.
+ *
+ * @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) {
+ System.out.println("Error:"+ ex);
+
+
+ }
+
+ Element root = (Element) doc.createElement(rootName);
+ doc.appendChild(root);
+
+
+ return doc;
+ }
+
+}
+
+
+
+
diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/dom/package.html b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/dom/package.html
new file mode 100644
index 000000000000..0198fdd4576f
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/dom/package.html
@@ -0,0 +1,55 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+ <!--
+ #*************************************************************************
+ #
+ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+
+ Copyright 2000, 2010 Oracle and/or its affiliates.
+
+ OpenOffice.org - a multi-platform office productivity suite
+
+ This file is part of OpenOffice.org.
+
+ OpenOffice.org is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License version 3
+ only, as published by the Free Software Foundation.
+
+ OpenOffice.org is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License version 3 for more details
+ (a copy is included in the LICENSE file that accompanied this code).
+
+ You should have received a copy of the GNU Lesser General Public License
+ version 3 along with OpenOffice.org. If not, see
+ <http://www.openoffice.org/license.html>
+ for a copy of the LGPLv3 License.
+
+ #*************************************************************************
+ -->
+
+ <title>org.openoffice.xmerge.converter.palm package</title>
+
+</head>
+ <body bgcolor="white">
+<p>Provides classes for converting basic document types to/from a <code>
+DOMDocument</code> object, which can be used by the framework. </p>
+<p>This package provides classes that handle the writing of data to an <code>
+ OutputStream</code> object for the {@link org.openoffice.xmerge.DocumentSerializer
+DocumentSerializer} interface for; as well as the reading of data from an
+<code>InputStream</code> 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.
+ </p>
+<a name="streamformat">
+<h2></h2>
+</a>
+<p></p>
+<h2>Important Note</h2>
+<p>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.</p>
+</body>
+</html>
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 000000000000..11286ee824ce
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm/PalmDB.java
@@ -0,0 +1,469 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+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;
+import java.io.UnsupportedEncodingException;
+
+/**
+ * <p>This class contains data for a single Palm database for use during
+ * a conversion process.</p>
+ *
+ * <p>It contains zero or more <code>Record</code> objects stored in an
+ * array. The index of the <code>Record</code> object in the array is
+ * the <code>Record</code> id or number for that specific <code>Record</code> object.
+ * Note that this class does not check for maximum number of Records
+ * allowable in an actual PDB.</p>
+ *
+ * <p>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).</p>
+ *
+ * <p>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</code> or <code>byte</code> array are converted to an exact
+ * <code>NAME_LENGTH</code> byte array. If the length of the name is less
+ * than <code>NAME_LENGTH</code>, it is padded with '\0' characters. If it
+ * is more, it gets truncated. The last character in the resulting byte
+ * array is always a '\0' character. The resulting byte array is stored in
+ * <code>bName</code>, and a corresponding String object <code>sName</code>
+ * that contains characters without the '\0' characters.</p>
+ *
+ * <p>The {@link #write 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</code>
+ * object.</p>
+ *
+ * <p>The {@link #read 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</code>
+ * object.</p>
+ *
+ * @author Akhil Arora, Herbie Ong
+ * @see PalmDocument
+ * @see Record
+ */
+
+public final class PalmDB {
+
+ /* Backup attribute for a PDB. This corresponds to dmHdrAttrBackup. */
+ public final static short PDB_HEADER_ATTR_BACKUP = 0x0008;
+
+ /** Number of bytes for the name field in the PDB. */
+ public final static int NAME_LENGTH = 32;
+
+ /** List of <code>Record</code> 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, 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</code> object with
+ * <code>Record</code> objects. <code>recs.length</code>
+ * can be zero for an empty PDB.
+ *
+ * @param name Suggested PDB name in a <code>String</code>.
+ * @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</code> objects.
+ *
+ * @throws UnsupportedEncodingException If <code>name</code> is
+ * not properly encoded.
+ * @throws NullPointerException If <code>recs</code> is 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</code>
+ * objects. <code>recs.length</code> can be zero for an
+ * empty PDB.
+ *
+ * @param name Suggested PDB name in a <code>byte</code>
+ * 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</code> objects.
+ *
+ * @throws UnsupportedEncodingException If <code>name</code> is
+ * not properly encoded.
+ * @throws NullPointerException If recs is 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</code> 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.
+ */
+ public 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</code>
+ * representation. and also by the <code>read</code> method.
+ *
+ * TODO: Note that this method assumes that the <code>byte</code>
+ * array parameter contains one character per <code>byte</code>,
+ * else it would truncate improperly.
+ *
+ * @param bytes PDB name in <code>byte</code> 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</code> object.
+ *
+ * @return Number of <code>Record</code> objects.
+ */
+ public int getRecordCount() {
+
+ return records.length;
+ }
+
+
+ /**
+ * Return the specific <code>Record</code> object associated
+ * with the <code>Record</code> number.
+ *
+ * @param index <code>Record</code> index number.
+ *
+ * @return The <code>Record</code> 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</code> objects.
+ *
+ * @return The array of <code>Record</code> 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</code> array of exact length of 32 bytes.
+ *
+ * @return The PDB name in <code>byte</code> array of
+ * length 32.
+ */
+ public byte[] getPDBNameBytes() {
+
+ return bName;
+ }
+
+
+ /**
+ * Write out the number of Records followed by what
+ * will be written out by each <code>Record</code> object.
+ *
+ * @param os The <code>OutputStream</code> to write the
+ * object.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ public void write(OutputStream os) throws IOException {
+
+ DataOutputStream out = new DataOutputStream(os);
+
+ // write out PDB name
+ out.write(bName);
+
+ // write out 2 bytes for number of records
+ out.writeShort(records.length);
+
+ // let each Record object write out its own info.
+ for (int i = 0; i < records.length; i++)
+ records[i].write(out);
+ }
+
+ /**
+ * Read the necessary data to create a PDB from
+ * the <code>InputStream</code>.
+ *
+ * @param is The <code>InputStream</code> to read data
+ * in order to restore the object.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ public void read(InputStream is) throws IOException {
+
+ DataInputStream in = new DataInputStream(is);
+
+ // read in the PDB name.
+ byte[] bytes = new byte[NAME_LENGTH];
+ in.readFully(bytes);
+ store(bytes);
+
+ // read in number of records
+ int nrec = in.readUnsignedShort();
+ records = new Record[nrec];
+
+ // read in the Record infos
+ for (int i = 0; i < nrec; i++) {
+
+ records[i] = new Record();
+ records[i].read(in);
+ }
+ }
+
+ /**
+ * Override equals method of <code>Object</code>.
+ *
+ * Two <code>PalmDB</code> 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> <code>Object</code> to
+ * compare.
+ *
+ * @return true if <code>obj</code> is equal to this, otherwise
+ * false.
+ */
+ 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;
+ }
+}
+
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 000000000000..668bfdb7f155
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm/PalmDocument.java
@@ -0,0 +1,177 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+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;
+
+/**
+ * <p> A <code>PalmDocument</code> is palm implementaion of the
+ * <code>Docuemnt</code> interface.</p>
+ *
+ * <p>This implementation allows the Palm device format to be
+ * read via an <code>InputStream</code> and written via an
+ * <code>OutputStream</code>.</p>
+ *
+ * @author Martin Maher
+ */
+
+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</code>
+ * from an <code>InputStream</code>.
+ *
+ * @param is <code>InputStream</code> 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</code> with
+ * <code>Record</code> objects. <code>recs.length</code>
+ * can be zero for an empty PDB.
+ *
+ * @param name Suggested PDB name in <code>String</code>.
+ * @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</code> objects.
+ *
+ * @throws NullPointerException If <code>recs</code> is 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</code>.
+ *
+ * @param is <code>InputStream</code> 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 = 0;
+ 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</code> to an <code>OutputStream</code>.
+ *
+ * @param is The <code>OutputStream</code> 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</code> contained in this object.
+ *
+ * @return The <code>PalmDB</code>.
+ */
+ public PalmDB getPdb() {
+ return pdb;
+ }
+
+
+ /**
+ * Sets the <code>PalmDocument</code> to a new <code>PalmDB</code>
+ * value.
+ *
+ * @param pdb The new <code>PalmDB</code> 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</code>.
+ */
+ public String getFileName() {
+ return fileName + ".pdb";
+ }
+
+
+ /**
+ * Returns the <code>Document</code> name.
+ *
+ * @return The <code>Document</code> name.
+ */
+ public String getName() {
+ return fileName;
+ }
+}
+
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 000000000000..68e7c66beb11
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm/PdbDecoder.java
@@ -0,0 +1,233 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.palm;
+
+import java.io.RandomAccessFile;
+import java.io.IOException;
+import java.io.ByteArrayInputStream;
+import java.io.DataInputStream;
+
+/**
+ * <p>Provides functionality to decode a PDB formatted file into
+ * a <code>PalmDB</code> object given an <code>InputStream</code>.
+ * This class is only used by the <code>PalmDB</code> object.</p>
+ *
+ * <p>Sample usage:</p>
+ *
+ * <blockquote><pre><code>
+ * PdbDecoder decoder = new PdbDecoder("sample.pdb");
+ * PalmDB palmDB = decoder.parse();
+ * </code></pre></blockquote>
+ *
+ * <p>This decoder has the following assumptions on the PDB file:</p>
+ *
+ * <p><ol>
+ * <li>There is only one RecordList section in the PDB.</li>
+ * <li>The <code>Record</code> indices in the RecordList are sorted in
+ * order, i.e. the first <code>Record</code> index refers to
+ * <code>Record</code> 0, and so forth.</li>
+ * <li>The raw <code>Record</code> in the <code>Record</code> section
+ * are sorted as well in order, i.e. first <code>Record</code>
+ * comes ahead of second <code>Record</code>, etc.</li>
+ * </ol></p>
+ *
+ * <p>Other decoders assume these as well.</p>
+ *
+ * @author Herbie Ong
+ * @see PalmDB
+ * @see Record
+ */
+public final class PdbDecoder {
+
+
+ /**
+ * <p>This method decodes a PDB file into a <code>PalmDB</code>
+ * object.</p>
+ *
+ * <p>First, the header data is read using the <code>PdbHeader</code>
+ * <code>read</code> method. Next, the RecordList section is
+ * read and the <code>Record</code> offsets are stored for use when
+ * parsing the Records. Based on these offsets, the bytes
+ * corresponding to each <code>Record</code> are read and each is
+ * stored in a <code>Record</code> object. Lastly, the data is
+ * used to create a <code>PalmDB</code> object.</p>
+ *
+ * @param fileName PDB file name.
+ *
+ * @throws IOException If I/O error occurs.
+ */
+ public PalmDB parse(String fileName) throws IOException {
+
+ RandomAccessFile file = new RandomAccessFile(fileName, "r");
+
+ // read the PDB header
+ PdbHeader header = new PdbHeader();
+ header.read(file);
+
+ 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] = file.readInt();
+
+ // read in attributes (1 byte) + unique id (3 bytes)
+ // take away the unique id, store the attributes
+
+ int attr = file.readInt();
+ recAttrs[i] = (byte) (attr >>> 24);
+ }
+
+
+ // read the records
+
+ int len = 0;
+ byte[] bytes = null;
+
+ int lastIndex = header.numRecords - 1;
+
+ for (int i = 0; i < lastIndex; i++) {
+
+ file.seek(recOffset[i]);
+ len = recOffset[i+1] - recOffset[i];
+ bytes = new byte[len];
+ file.readFully(bytes);
+ recArray[i] = new Record(bytes, recAttrs[i]);
+ }
+
+ // last record
+ file.seek(recOffset[lastIndex]);
+ len = (int) file.length() - recOffset[lastIndex];
+ bytes = new byte[len];
+ file.readFully(bytes);
+ recArray[lastIndex] = new Record(bytes, recAttrs[lastIndex]);
+
+ }
+
+ file.close();
+
+ // create PalmDB and return it
+ PalmDB pdb = new PalmDB(header.pdbName, header.creatorID,
+ header.typeID, header.version, header.attribute, recArray);
+
+ return pdb;
+ }
+
+ /**
+ * <p>This method decodes a PDB file into a <code>PalmDB</code>
+ * object.</p>
+ *
+ * <p>First, the header data is read using the <code>PdbHeader</code>
+ * <code>read</code> method. Next, the RecordList section is
+ * read and the <code>Record</code> offsets are stored for use when
+ * parsing the Records. Based on these offsets, the bytes
+ * corresponding to each <code>Record</code> are read and each is
+ * stored in a <code>Record</code> object. Lastly, the data is
+ * used to create a <code>PalmDB</code> object.</p>
+ *
+ * @param b <code>byte[]</code> 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 len = 0;
+ byte[] bytes = null;
+
+ int lastIndex = header.numRecords - 1;
+
+ for (int i = 0; i < lastIndex; i++) {
+
+ //dis.seek(recOffset[i]);
+ dis.reset();
+ dis.skip(recOffset[i]);
+ len = recOffset[i+1] - recOffset[i];
+ bytes = new byte[len];
+ dis.readFully(bytes);
+ recArray[i] = new Record(bytes, recAttrs[i]);
+ }
+
+ // last record
+
+ dis.reset();
+ len = (int) dis.available() - recOffset[lastIndex];
+ dis.skip(recOffset[lastIndex]);
+ 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 000000000000..46433e88ec2e
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm/PdbEncoder.java
@@ -0,0 +1,196 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+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;
+
+/**
+ * <p>Provides functionality to encode a <code>PalmDB</code> object
+ * into a PDB formatted file given a file <code>OutputStream</code>.
+ * This class is only used by the <code>PalmDB</code> object.</p>
+ *
+ * <p>One needs to create one <code>PdbEncoder</code> object per
+ * <code>PalmDB</code> object to be encoded. This class keeps
+ * the PDB header data and functionality in the <code>PdbHeader</code>
+ * class.</p>
+ *
+ * <p>Sample usage:</p>
+ *
+ * <blockquote><pre><code>
+ * PdbEncoder encoder = new PdbEncoder(palmDB, "STRW", "data");
+ * encoder.write(new FileOutputStream("sample.pdb"));
+ * </code></pre></blockquote>
+ *
+ * @author Herbie Ong
+ * @see PalmDB
+ * @see Record
+ */
+public final class PdbEncoder {
+
+ /** PDB header. */
+ private PdbHeader header = null;
+
+ /** the PalmDB object. */
+ private PalmDB db = null;
+
+ /**
+ * The pattern for unique_id=0x00BABE(start).
+ */
+ private final static int START_UNIQUE_ID = 0x00BABE;
+
+
+ /**
+ * Constructor.
+ *
+ * @param db The <code>PalmDB</code> 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();
+ }
+
+
+ /**
+ * <p>Write out a PDB into the given <code>OutputStream</code>.</p>
+ *
+ * <p>First, write out the header data by using the
+ * <code>PdbHeader</code> <code>write</code> method. Next,
+ * calculate the RecordList section and write it out.
+ * Lastly, write out the bytes corresponding to each
+ * <code>Record</code>.</p>
+ *
+ * <p>The RecordList section contains a list of
+ * <code>Record</code> index info, where each <code>Record</code>
+ * index info contains:</p>
+ *
+ * <p><ul>
+ * <li>4 bytes local offset of the <code>Record</code> from the
+ * top of the PDB.</li>
+ * <li>1 byte of <code>Record</code> attribute.</li>
+ * <li>3 bytes unique <code>Record</code> ID.</li>
+ * </ul></p>
+ *
+ * <p>There should be a total of <code>header.numRecords</code>
+ * of <code>Record</code> index info</p>.
+ *
+ * @param os <code>OutputStream</code> 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 = (((int) 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();
+ }
+}
+
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 000000000000..2f9d389e80cc
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm/PdbHeader.java
@@ -0,0 +1,162 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.palm;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+
+/**
+ * <p>Class used only internally by <code>PdbEncoder</code> and
+ * <code>PdbDecoder</code> to store, read and write a PDB header.</p>
+ *
+ * <p>Note that fields are intended to be accessible only at the
+ * package level.</p>
+ *
+ * <p>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</code> and <code>write</code> methods should
+ * handle them properly.</p>
+ *
+ * @author Herbie Ong
+ * @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. */
+ long lastBackupDate = 0;
+
+ /**
+ * Incremented every time a <code>Record</code> is
+ * added, deleted or modified. Palm UInt32.
+ */
+ long modificationNumber = 0;
+
+ /** Optional field. Palm UInt32. Unsignedness should be irrelevant. */
+ int appInfoID = 0;
+
+ /** Optional field. Palm UInt32. Unsignedness should be irrelevant. */
+ 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;
+
+ /** ??? */
+ int uniqueIDSeed = 0;
+
+ /** See numRecords. 4 bytes. */
+ int nextRecordListID = 0;
+
+ /**
+ * Number of Records stored in the database header.
+ * If all the <code>Record</code> entries cannot fit in the header,
+ * then <code>nextRecordList</code> has the local ID of a
+ * RecordList that contains the next set of <code>Record</code>.
+ * 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 di A <code>DataInput</code> 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 = ((long) in.readInt()) & 0xffffffffL;
+ modificationDate = ((long) in.readInt()) & 0xffffffffL;
+ lastBackupDate = ((long) in.readInt()) & 0xffffffffL;
+ modificationNumber = ((long) 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</code> 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);
+ }
+}
+
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 000000000000..d0714d677960
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm/PdbUtil.java
@@ -0,0 +1,105 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.palm;
+
+/**
+ * Contains common static methods and constants for use within the package.
+ *
+ * @author Herbie Ong
+ */
+public final class PdbUtil {
+
+ /** Difference in seconds from Jan 01, 1904 to Jan 01, 1970. */
+ final static long TIME_DIFF = 2082844800;
+
+ /** Encoding scheme used. */
+ final static String ENCODING = "8859_1";
+
+ /** Size of a PDB header in bytes. */
+ final static int HEADER_SIZE = 78;
+
+
+ /**
+ * <p>This method converts a 4 letter string into the Palm ID
+ * integer.</p>
+ *
+ * <p>It is normally used to convert the Palm creator ID string into
+ * the integer version of it. Also use for data types, etc.</p>
+ *
+ * @param s Four character <code>String</code>.
+ *
+ * @return Palm ID representing the <code>String</code>.
+ *
+ * @throws ArrayIndexOutOfBoundsException If <code>String</code>
+ * parameter contains less than four characters.
+ */
+ public static int intID(String s) {
+
+ int id = -1;
+ int temp = 0;
+
+ // grab the first char and put it in the high bits
+ // note that we only want 8 lower bits of it.
+ temp = (int) s.charAt(0);
+ id = temp << 24;
+
+ // grab the second char and add it in.
+ temp = ((int) s.charAt(1)) & 0x00ff;
+ id += temp << 16;
+
+ // grab the second char and add it in.
+ temp = ((int) s.charAt(2)) & 0x00ff;
+ id += temp << 8;
+
+ // grab the last char and add it in
+ id += ((int) s.charAt(3)) & 0x00ff;
+
+ return id;
+ }
+
+
+ /**
+ * This method converts an integer into a <code>String</code>
+ * given the Palm ID format.
+ *
+ * @param i Palm ID.
+ *
+ * @return <code>String</code> representation.
+ */
+ public static String stringID(int i) {
+
+ char ch[] = new char[4];
+ ch[0] = (char) (i >>> 24);
+ ch[1] = (char) ((i >> 16) & 0x00ff);
+ ch[2] = (char) ((i >> 8) & 0x00ff);
+ ch[3] = (char) (i & 0x00ff);
+
+ return new String(ch);
+ }
+}
+
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 000000000000..23690792bdbf
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm/Record.java
@@ -0,0 +1,216 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+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;
+
+/**
+ * <p>Contains the raw bytes for a <code>Record</code> in a PDB.</p>
+ *
+ * <p>Note that it is not associated with a <code>Record</code> number
+ * or ID.</p>
+ *
+ * @author Akhil Arora, Herbie Ong
+ * @see PalmDocument
+ * @see PalmDB
+ */
+public final class Record {
+
+ /** <code>Record</code> <code>byte</code> array. */
+ private byte[] data;
+
+ /** <code>Record</code> attributes. */
+ private byte attributes = 0;
+
+
+ /**
+ * Default constructor.
+ */
+ public Record() {
+
+ data = new byte[0];
+ }
+
+
+ /**
+ * <p>Constructor to create a <code>Record</code> filled with
+ * bytes.</p>
+ *
+ * <p>Note that this does not check for 64k <code>Record</code>
+ * sizes. User of this class must check for that.</p>
+ *
+ * @param d <code>byte</code> array contents for this object.
+ */
+ public Record(byte[] d) {
+
+ this(d, (byte) 0);
+ }
+
+
+ /**
+ * <p>Constructor to create a <code>Record</code> filled with
+ * bytes and assign <code>Record</code> attributes.</p>
+ *
+ * <p>Note that this does not check for 64k <code>Record</code>
+ * sizes. User of this class must check for that.</p>
+ *
+ * @param d <code>byte</code> array contents for this object.
+ * @param attrs <code>Record</code> 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</code>.
+ *
+ * @return Contents in <code>byte</code> array
+ */
+ public byte[] getBytes() {
+
+ return data;
+ }
+
+
+ /**
+ * <p>This method returns the <code>Record</code> attributes.</p>
+ *
+ * <blockquote><pre>
+ * <code>Record</code> attributes consists of (from high to low bit)
+ *
+ * delete (1) - dirty (1) - busy (1) - secret (1) - category (4)
+ * </pre></blockquote>
+ *
+ * @return <code>Record</code> attribute.
+ */
+ public byte getAttributes() {
+
+ return attributes;
+ }
+
+
+ /**
+ * Write out the <code>Record</code> attributes and
+ * <code>Record</code> length followed by the data in this
+ * <code>Record</code> object.
+ *
+ * @param out The <code>OutputStream</code> 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</code>.
+ *
+ * @param in The <code>InputStream</code> to read data from
+ * in order to restore the <code>object</code>.
+ *
+ * @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);
+ }
+
+
+ /**
+ * <p>Override equals method of <code>Object</code>.</p>
+ *
+ * <p>Two <code>Record</code> objects are equal if they contain
+ * the same bytes in the array and the same attributes.</p>
+ *
+ * <p>This is used primarily for testing purposes only for now.</p>
+ *
+ * @param obj A <code>Record</code> object to compare with
+ *
+ * @return true if obj is equal, otherwise false.
+ */
+ public boolean equals(Object obj) {
+
+ boolean bool = false;
+
+ if (obj instanceof Record) {
+
+ Record rec = (Record) obj;
+
+ checkLabel: {
+
+ if (rec.getAttributes() != attributes) {
+
+ break checkLabel;
+ }
+
+ if (rec.getSize() == data.length) {
+
+ for (int i = 0; i < data.length; i++) {
+
+ if (data[i] != rec.data[i]) {
+ break checkLabel;
+ }
+ }
+
+ bool = true;
+ }
+ }
+ }
+ return bool;
+ }
+}
+
diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm/package.html b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm/package.html
new file mode 100644
index 000000000000..f2628bb0b235
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm/package.html
@@ -0,0 +1,142 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<!--
+ #*************************************************************************
+ #
+ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+
+ Copyright 2000, 2010 Oracle and/or its affiliates.
+
+ OpenOffice.org - a multi-platform office productivity suite
+
+ This file is part of OpenOffice.org.
+
+ OpenOffice.org is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License version 3
+ only, as published by the Free Software Foundation.
+
+ OpenOffice.org is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License version 3 for more details
+ (a copy is included in the LICENSE file that accompanied this code).
+
+ You should have received a copy of the GNU Lesser General Public License
+ version 3 along with OpenOffice.org. If not, see
+ <http://www.openoffice.org/license.html>
+ for a copy of the LGPLv3 License.
+
+ #*************************************************************************
+ -->
+<html>
+<head>
+<title>org.openoffice.xmerge.converter.palm package</title>
+</head>
+
+<body bgcolor="white">
+
+<p>Provides classes for converting Palm database data to/from a
+<code>PalmDocument</code> object, which can be used by the framework.
+
+<p>This package provides classes that handle the writing of data to
+an <code>OutputStream</code> object for the
+{@link org.openoffice.xmerge.DocumentSerializer DocumentSerializer}
+interface for; as well as the reading of data from an <code>InputStream</code>
+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.</p>
+
+<a name="streamformat">
+<h2>Palm database converter specific I/O stream format</h2>
+</a>
+
+<p>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 ...</p>
+
+<pre>
+ 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
+</pre>
+
+<p>Note that each PDB section is appended by another if there is more
+than one.</p>
+
+<p>Since the <code>PalmDocument</code> class takes care of the writing
+and reading of this format through its <code>write</code> and
+<code>read</code> methods, respectively, this format shall also be
+referred to as the <b>PalmDocument stream format</b>.</p>
+
+<h2>Usage of the classes for the specified I/O stream</h2>
+
+<p>When converting from a server document to device document(s), the
+framework requires writing the device document(s) to an
+<code>OutputStream</code> object via the <code>DocumentSerializer</code>
+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</code> . Thus, if there is more
+than one worksheet in the document, more than one <code>PalmDocument</code>
+will be produced by the <code>DocumentSerializer</code>.</p>
+
+<p>A <code>DocumentSerializer</code> creates a <code>ConvertData</code> object,
+which contains all of the <code>PalmDocuments</code>. The
+{@link org.openoffice.xmerge.converter.palm.PalmDocument#write write}
+method to write to the given <code>OutputStream</code>. The <code>PalmDocument</code>
+object will take care of writing the data in the
+<a href=#streamformat>specified format</a>.</p>
+
+<p>A <code>DocumentDeserializer</code> can use the <code>PalmDocument</code> object's
+{@link org.openoffice.xmerge.converter.palm.PalmDocument#read read}
+method to fill in all the <code>PalmDocument</code> object's data.</p>
+
+<h2>PDB file encoding/decoding</h2>
+
+<p>The <code>PalmDocument</code> object's read and write functions are provided
+by the <code>PdbDecoder</code> and <code>PdbEncoder</code> objects. The
+<code>PdbEncoder</code> class provides the functionality of encoding a
+<code>PalmDB</code> object into an <code>InputStream</code>, while the
+<code>PdbDecoder</code> class provides the functionality of decoding a
+PDB file into an <code>OutputStream</code>.</p>
+
+<p>Refer to the class description of each for usage.</p>
+
+<h2>Important Note</h2>
+
+<p>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.</p>
+
+<h2>TODO list</h2>
+
+<p><ol>
+<li>Merge the PalmDB, PdbDecoder and PdbEncoder classes into the
+ PalmDocument class.</li>
+<li>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.</li>
+<li>The current PdbDecoder only returns a PalmDB object. There are other
+ information that we may want to expose from the PDB decoding process.</li>
+<li>Investigate on different language encoding on the Palm and how that
+ affects the PDB name.</li>
+</ol></p>
+
+</body>
+</html>
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 000000000000..ac82675b229d
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/EmbeddedBinaryObject.java
@@ -0,0 +1,127 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+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. */
+ protected 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</code> array containing the object's data.
+ */
+ public byte[] getBinaryData() {
+
+ if (objData == null) {
+ // See if we came from a Zip file
+ if (zipFile != null) {
+ objData = zipFile.getNamedBytes(objName);
+ }
+ }
+
+ return objData;
+ }
+
+
+ /**
+ * Sets the data for this object.
+ *
+ * @param data A <code>byte</code> 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</code> instance representing the file
+ * the data is to be written to.
+ */
+ void write(OfficeZip zip) {
+ if (hasChanged) {
+ zip.setNamedBytes(objName, objData);
+ }
+ }
+
+
+ /**
+ * Package private method that constructs the manifest.xml entries for this
+ * embedded object.
+ *
+ * @return Document <code>Document</code> containing the manifest entries.
+ */
+ 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);
+ }
+
+}
+
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 000000000000..11240b4bceac
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/EmbeddedObject.java
@@ -0,0 +1,116 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+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.
+ *
+ * <b>N.B.</b>The name referes to the name as found in the
+ * <code>META-INF/manifest.xml</code> 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</code> 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</code> 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.
+ *
+ * @return Document <code>Document</code> containing the manifest entries.
+ */
+ 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 000000000000..6e5f123ded53
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/EmbeddedXMLObject.java
@@ -0,0 +1,295 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+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:
+ *
+ * Formulae created with Math (application/vnd.sun.xml.math)
+ * Charts created with Chart (application/vnd.sun.xml.chart)
+ * Spreadsheets created with Calc (application/vnd.sun.xml.calc)
+ * Text created with Writer (application/vnd.sun.xml.writer)
+ * Drawings created with Draw (application/vnd.sun.xml.draw)
+ * Presentations created with Impress (application/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;
+ protected Document contentDOM = null;
+ protected Document settingsDOM = null;
+ protected 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 represenation 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 represenation 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 styles 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 represenation 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(new String(objName + "/" + name));
+ if (data != null) {
+ return OfficeDocument.parse(builder, data);
+ }
+ else {
+ return null;
+ }
+
+ }
+ catch (SAXException se) {
+ throw se;
+ }
+ catch (IOException ioe) {
+ throw ioe;
+ }
+ 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</code> instance representing the file
+ * the data is to be written to.
+ */
+ void write(OfficeZip zip) throws IOException {
+ if (hasChanged == true) {
+ if (contentDOM != null) {
+ zip.setNamedBytes(new String(objName + "/content.xml"),
+ OfficeDocument.docToBytes(contentDOM));
+ }
+ if (settingsDOM != null) {
+ zip.setNamedBytes(new String(objName + "/settings.xml"),
+ OfficeDocument.docToBytes(settingsDOM));
+ }
+ if (stylesDOM != null) {
+ zip.setNamedBytes(new String(objName + "/styles.xml"),
+ OfficeDocument.docToBytes(stylesDOM));
+ }
+ }
+ }
+
+ /**
+ * Package private method that constructs the manifest.xml entries for this
+ * embedded object.
+ *
+ * @param manifestDoc <code>Document</code> containing the manifest entries.
+ */
+ 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,
+ new String(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,
+ new String(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,
+ new String(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,
+ new String(objName + "/"));
+
+ root.appendChild(objectNode);
+ }
+
+}
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 000000000000..afa889cb9e3f
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/OfficeConstants.java
@@ -0,0 +1,439 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml;
+
+/**
+ * This interface contains constants for StarOffice XML tags,
+ * attributes (StarCalc cell types, etc.).
+ *
+ * @author Herbie Ong, Paul Rank, Martin Maher
+ */
+public interface OfficeConstants {
+
+ /** Element tag for <i>office:document</i>, this is the root tag. */
+ public final static String TAG_OFFICE_DOCUMENT = "office:document";
+
+ /**
+ * Element tag for <i>office:document-content</i>, this is the root
+ * tag in content.xml.
+ */
+ public final static String TAG_OFFICE_DOCUMENT_CONTENT = "office:document-content";
+
+ /**
+ * Element tag for <i>office:document-settings</i>, this is the root
+ * tag in content.xml.
+ */
+ public final static String TAG_OFFICE_DOCUMENT_SETTINGS= "office:document-settings";
+
+ /**
+ * Element tag for <i>office:document-meta</i>, this is the root
+ * tag in content.xml.
+ */
+ public final static String TAG_OFFICE_DOCUMENT_META= "office:document-meta";
+
+ /**
+ * Element tag for <i>office:document-styles</i>, this is the root tag
+ * in styles.xml.
+ */
+ public final static String TAG_OFFICE_DOCUMENT_STYLES = "office:document-styles";
+
+ /**
+ * Attribute tag for <i>office:class</i> of element
+ * <i>office:document</i>.
+ */
+ public final static String ATTRIBUTE_OFFICE_CLASS = "office:class";
+
+ /** Element tag for <i>office:styles</i>. */
+ public final static String TAG_OFFICE_STYLES = "office:styles";
+
+ /** Element tag for <i>office:meta</i>. */
+ public final static String TAG_OFFICE_META = "office:meta";
+
+ /** Element tag for <i>office:automatic-styles</i>. */
+ public final static String TAG_OFFICE_AUTOMATIC_STYLES = "office:automatic-styles";
+
+ /** Element tag for <i>office:master-styles</i>. */
+ public final static String TAG_OFFICE_MASTER_STYLES = "office:master-styles";
+
+ /** Element tag for <i>office:body</i>. */
+ public final static String TAG_OFFICE_BODY = "office:body";
+
+ /** Element tag for <i>office:settings</i>. */
+ public final static String TAG_OFFICE_SETTINGS = "office:settings";
+
+ //Adding
+
+ /** Element tag for <i>text:variable-set</i>. */
+ public final static String TAG_TEXT_VARIABLE_SET = "text:variable-set";
+
+ /** Element tag for <i>text:variable-get</i>. */
+ public final static String TAG_TEXT_VARIABLE_GET = "text:variable-get";
+/** Element tag for <i>text:expression</i>. */
+ public final static String TAG_TEXT_EXPRESSION = "text:expression";
+
+/** Element tag for <i>text:user-field-get</i>. */
+ public final static String TAG_TEXT_USER_FIELD_GET = "text:user-field-get";
+
+/** Element tag for <i>text:page-variable-get</i>. */
+ public final static String TAG_TEXT_PAGE_VARIABLE_GET = "text:page-variable-get";
+/** Element tag for <i>text:sequence</i>. */
+ public final static String TAG_TEXT_SEQUENCE = "text:sequence";
+
+ /** Element tag for <i>text:text-input</i>. */
+ public final static String TAG_TEXT_VARIABLE_INPUT = "text:variable-input";
+ /** Element tag for <i>text:time</i>. */
+ public final static String TAG_TEXT_TIME = "text:time";
+
+ /** Element tag for <i>text:page-count</i>. */
+ public final static String TAG_TEXT_PAGE_COUNT = "text:page-count";
+ /** Element tag for <i>text:page-number</i>. */
+ public final static String TAG_TEXT_PAGE_NUMBER = "text:page-number";
+ /** Element tag for <i>text:author-initials</i>. */
+ public final static String TAG_TEXT_AUTHOR_INITIALS = "text:author-initials";
+ /** Element tag for <i>text:subject</i>. */
+ public final static String TAG_TEXT_SUBJECT = "text:subject";
+ /** Element tag for <i>text:title</i>. */
+ public final static String TAG_TEXT_TITLE = "text:title";
+ /** Element tag for <i>text:creation-time</i>. */
+ public final static String TAG_TEXT_CREATION_TIME = "text:creation-time";
+
+ /** Element tag for <i>text:date</i>. */
+ public final static String TAG_TEXT_DATE = "text:date";
+ /** Element tag for <i>text:text-input</i>. */
+ public final static String TAG_TEXT_TEXT_INPUT = "text:text-input";
+
+
+//end adding
+
+ /** Element tag for <i>office:font-decls</i>. */
+ public final static String TAG_OFFICE_FONT_DECLS = "office:font-decls";
+
+ /** Element tag for <i>style:font-decl</i>. */
+ public final static String TAG_STYLE_FONT_DECL = "style:font-decl";
+
+ /** Attribute tag for <i>style:name</i> of element <i>style:name</i>. */
+ public final static String ATTRIBUTE_STYLE_NAME = "style:name";
+
+ /**
+ * Attribute tag for <i>style:font-pitch</i> of element
+ * <i>style:font-pitch</i>.
+ */
+ public final static String ATTRIBUTE_STYLE_FONT_PITCH = "style:font-pitch";
+
+ /**
+ * Attribute tag for <i>fo:font-family</i> of element
+ * <i>fo:font-family</i>.
+ */
+ public final static String ATTRIBUTE_FO_FONT_FAMILY = "fo:font-family";
+
+ /**
+ * Attribute tag for <i>fo:font-family</i> of element
+ * <i>fo:font-family</i>.
+ */
+ public final static String ATTRIBUTE_FO_FONT_FAMILY_GENERIC = "fo:font-family-generic";
+
+ /** Element tag for <i>text:p</i>. */
+ public final static String TAG_PARAGRAPH = "text:p";
+
+ /** Element tag for <i>text:</i>. */
+ public final static String TAG_TEXT = "text:";
+
+ /** Element tag for <i>text:h</i>. */
+ public final static String TAG_HEADING = "text:h";
+
+ /** Element tag for <i>text:s</i>. */
+ public final static String TAG_SPACE = "text:s";
+
+ /** Element tag for <i>text:tab-stop</i>. */
+ public final static String TAG_TAB_STOP = "text:tab-stop";
+
+ /** Element tag for <i>text:line-break</i>. */
+ public final static String TAG_LINE_BREAK = "text:line-break";
+
+ /** Element tag for <i>text:span</i>. */
+ public final static String TAG_SPAN = "text:span";
+
+ /** Element tag for <i>text:a</i>. */
+ public final static String TAG_HYPERLINK = "text:a";
+
+ /** Element tag for <i>text:bookmark</i>. */
+ public final static String TAG_BOOKMARK = "text:bookmark";
+
+ /** Element tag for <i>text:bookmark-start</i>. */
+ public final static String TAG_BOOKMARK_START = "text:bookmark-start";
+
+ /** Element tag for <i>text:unordered-list</i>. */
+ public final static String TAG_UNORDERED_LIST = "text:unordered-list";
+
+ /** Element tag for <i>text:ordered-list</i>. */
+ public final static String TAG_ORDERED_LIST = "text:ordered-list";
+
+ /** Element tag for <i>text:list-header</i>. */
+ public final static String TAG_LIST_HEADER = "text:list-header";
+
+ /** Element tag for <i>text:list-item</i>. */
+ public final static String TAG_LIST_ITEM = "text:list-item";
+
+ /** Attribute tag for <i>text:c</i> of element <i>text:s</i>. */
+ public final static String ATTRIBUTE_SPACE_COUNT = "text:c";
+
+ /**
+ * Attribute tag for <i>text:style-name</i> of element
+ * <i>text:style-name</i>.
+ */
+ public final static String ATTRIBUTE_TEXT_STYLE_NAME = "text:style-name";
+
+ /** Element tag for <i>table:table</i>. */
+ public final static String TAG_TABLE = "table:table";
+
+ /** Element tag for <i>table:named-expression</i>. */
+ public final static String TAG_NAMED_EXPRESSIONS = "table:named-expressions";
+
+ /** Element tag for <i>table:named-range</i>. */
+ public final static String TAG_TABLE_NAMED_RANGE= "table:named-range";
+
+ /** Element tag for <i>table:named-expression</i>. */
+ public final static String TAG_TABLE_NAMED_EXPRESSION= "table:named-expression";
+
+ /**
+ * Attribute tag for <i>table:name</i> of element
+ * <i>table:table</i>.
+ */
+ public final static String ATTRIBUTE_TABLE_NAME = "table:name";
+
+ /**
+ * Attribute tag for <i>table:expression</i> of element
+ * <i>table:named-range</i>.
+ */
+ public final static String ATTRIBUTE_TABLE_EXPRESSION = "table:expression";
+
+ /**
+ * Attribute tag for <i>table:base-cell-address</i> of element
+ * <i>table:named-range</i>.
+ */
+ public final static String ATTRIBUTE_TABLE_BASE_CELL_ADDRESS = "table:base-cell-address";
+
+ /**
+ * Attribute tag for <i>table:cell-range-address</i> of element
+ * <i>table:named-range</i>.
+ */
+ public final static String ATTRIBUTE_TABLE_CELL_RANGE_ADDRESS = "table:cell-range-address";
+
+ /** Element tag for <i>table:table-row</i>. */
+ public final static String TAG_TABLE_ROW = "table:table-row";
+
+ /** Element tag for <i>table:table-column</i>. */
+ public final static String TAG_TABLE_COLUMN = "table:table-column";
+
+ /**
+ * Attribute tag for <i>table:default-cell-style-name</i>
+ * of element <i>table:table-column</i>.
+ */
+ public final static String ATTRIBUTE_DEFAULT_CELL_STYLE = "table:default-cell-style-name";
+
+ /** Element tag for <i>table:scenario</i>. */
+ public final static String TAG_TABLE_SCENARIO = "table:scenario";
+
+ /** Element tag for <i>table:table-cell</i>. */
+ public final static String TAG_TABLE_CELL = "table:table-cell";
+
+ /**
+ * Attribute tag for <i>table:value-type</i> of element
+ * <i>table:table-cell</i>.
+ */
+ public final static String ATTRIBUTE_TABLE_VALUE_TYPE = "table:value-type";
+
+ /**
+ * Attribute tag for <i>table:number-columns-repeated</i>
+ * of element <i>table:table-cell</i>.
+ */
+ public final static String ATTRIBUTE_TABLE_NUM_COLUMNS_REPEATED =
+ "table:number-columns-repeated";
+
+ /**
+ * Attribute tag for <i>table:number-rows-repeated</i>
+ * of element <i>table:table-row</i>.
+ */
+ public final static String ATTRIBUTE_TABLE_NUM_ROWS_REPEATED =
+ "table:number-rows-repeated";
+
+ /**
+ * Attribute tag for <i>table:formula</i> of element
+ * <i>table:table-cell</i>.
+ */
+ public final static String ATTRIBUTE_TABLE_FORMULA = "table:formula";
+
+ /**
+ * Attribute tag for <i>table:value</i> of element
+ * <i>table:table-cell</i>.
+ */
+ public final static String ATTRIBUTE_TABLE_VALUE = "table:value";
+
+ /**
+ * Attribute tag for <i>table:date-value</i> of element
+ * <i>table:table-cell</i>.
+ */
+ public final static String ATTRIBUTE_TABLE_DATE_VALUE = "table:date-value";
+
+ /**
+ * Attribute tag for <i>table:time-value</i> of element
+ * <i>table:table-cell</i>.
+ */
+ public final static String ATTRIBUTE_TABLE_TIME_VALUE = "table:time-value";
+
+ /**
+ * Attribute tag for <i>table:string-value</i> of element
+ * <i>table:table-cell</i>.
+ */
+ public final static String ATTRIBUTE_TABLE_STRING_VALUE =
+ "table:string-value";
+
+ /**
+ * Attribute tag for <i>table:time-boolean-value</i> of element
+ * <i>table:table-cell</i>.
+ */
+ public final static String ATTRIBUTE_TABLE_BOOLEAN_VALUE =
+ "table:boolean-value";
+
+ /** Attribute tag for <i>table:style-name</i> of table elements. */
+ public final static String ATTRIBUTE_TABLE_STYLE_NAME = "table:style-name";
+
+ /**
+ * Attribute tag for <i>table:currency</i> of element
+ * <i>table:table-cell</i>.
+ */
+ public final static String ATTRIBUTE_TABLE_CURRENCY = "table:currency";
+
+ /** The cell contains data of type <i>string</i>. */
+ public final static String CELLTYPE_STRING = "string";
+
+ /** The cell contains data of type <i>float</i>. */
+ public final static String CELLTYPE_FLOAT = "float";
+
+ /** The cell contains data of type <i>time</i>. */
+ public final static String CELLTYPE_TIME = "time";
+
+ /** The cell contains data of type <i>date</i>. */
+ public final static String CELLTYPE_DATE = "date";
+
+ /** The cell contains data of type <i>currency</i>. */
+ public final static String CELLTYPE_CURRENCY = "currency";
+
+ /** The cell contains data of type <i>boolean</i>. */
+ public final static String CELLTYPE_BOOLEAN = "boolean";
+
+ /** The cell contains data of type <i>percent</i>. */
+ public final static String CELLTYPE_PERCENT = "percentage";
+
+ /** StarWriter XML file extension. */
+ public final static String SXW_FILE_EXTENSION = ".sxw";
+
+ /** StarWriter XML <i>office:class</i> value. */
+ public final static String SXW_TYPE = "text";
+
+ /** StarCalc XML file extension. */
+ public final static String SXC_FILE_EXTENSION = ".sxc";
+
+ /** StarCalc XML <i>office:class</i> value. */
+ public final static String SXC_TYPE = "spreadsheet";
+
+ /** Element tag for <i>manifest:manifest</i>entry in Manifest XML */
+ public final static String TAG_MANIFEST_ROOT = "manifest:manifest";
+
+ /** Element tag for <i>manifest:file-entry</i> entry in Manifest XML. */
+ public final static String TAG_MANIFEST_FILE = "manifest:file-entry";
+
+ /**
+ * Attribute tag for <i>manifest:media-type</i> of element
+ * <i>manifest:file-entry</i>.
+ */
+ public final static String ATTRIBUTE_MANIFEST_FILE_TYPE = "manifest:media-type";
+
+ /**
+ * Attribute tag for <i>manifest:full-path</i> of element
+ * <i>manifest:file-entry</i>.
+ */
+ public final static String ATTRIBUTE_MANIFEST_FILE_PATH = "manifest:full-path";
+
+ // Tags and Elements for the settings.xml
+
+ /** Element tag for <i>config:config-item</i>. */
+ public final static String TAG_CONFIG_ITEM = "config:config-item";
+
+ /** Element tag for <i>config:config-item-set</i>. */
+ public final static String TAG_CONFIG_ITEM_SET = "config:config-item-set";
+
+ /** Element tag for <i>config:config-item-map-indexed</i>. */
+ public final static String TAG_CONFIG_ITEM_MAP_INDEXED = "config:config-item-map-indexed";
+
+ /** Element tag for <i>config:config-item-map-named</i>. */
+ public final static String TAG_CONFIG_ITEM_MAP_NAMED = "config:config-item-map-named";
+
+ /** Element tag for <i>config:config-item-map-entry</i>. */
+ public final static String TAG_CONFIG_ITEM_MAP_ENTRY= "config:config-item-map-entry";
+
+ /**
+ * Attribute tag for <i>config:name</i> of element
+ * <i>config:config-item</i>.
+ */
+ public final static String ATTRIBUTE_CONFIG_NAME = "config:name";
+
+ /**
+ * Attribute tag for <i>config:type</i> of element
+ * <i>config:config-item</i>.
+ */
+ public final static String ATTRIBUTE_CONFIG_TYPE = "config:type";
+
+
+ /** StarWriter XML MIME type. */
+ public final static String SXW_MIME_TYPE = "application/vnd.sun.xml.writer";
+
+ /** StarWriter XML Template MIME type. */
+ public final static String STW_MIME_TYPE = "application/vnd.sun.xml.writer.template";
+
+ /** StarCalc XML MIME type. */
+ public final static String SXC_MIME_TYPE = "application/vnd.sun.xml.calc";
+
+ /** StarCalc XML Template MIME type. */
+ public final static String STC_MIME_TYPE = "application/vnd.sun.xml.calc.template";
+
+ /** StarImpress XML MIME type. */
+ public final static String SXI_MIME_TYPE = "application/vnd.sun.xml.impress";
+
+ /** StarImpress XML Template MIME type. */
+ public final static String STI_MIME_TYPE = "application/vnd.sun.xml.impress.template";
+
+ /** StarDraw XML MIME type. */
+ public final static String SXD_MIME_TYPE = "application/vnd.sun.xml.draw";
+
+ /** StarMath XML MIME type. */
+ public final static String SXM_MIME_TYPE = "application/vnd.sun.xml.math";
+
+ /** StarWriter Global XML MIME Type */
+ public final static String SXG_MIME_TYPE = "application/vnd.sun.xml.writer.global";
+}
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 000000000000..d3372be5a757
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/OfficeDocument.java
@@ -0,0 +1,1265 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+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.Resources;
+import org.openoffice.xmerge.util.Debug;
+
+/**
+ * An implementation of <code>Document</code> for
+ * StarOffice documents.
+ */
+public abstract class OfficeDocument
+ implements org.openoffice.xmerge.Document,
+ OfficeConstants {
+
+ /** Factory for <code>DocumentBuilder</code> objects. */
+ private static DocumentBuilderFactory factory =
+ DocumentBuilderFactory.newInstance();
+
+ /** DOM <code>Document</code> of content.xml. */
+ private Document contentDoc = null;
+
+ /** DOM <code>Document</code> of meta.xml. */
+ private Document metaDoc = null;
+
+ /** DOM <code>Document</code> of settings.xml. */
+ private Document settingsDoc = null;
+
+ /** DOM <code>Document</code> of content.xml. */
+ private Document styleDoc = null;
+
+ /** DOM <code>Docuemtn</code> of META-INF/manifest.xml. */
+ private Document manifestDoc = null;
+
+ private String documentName = null;
+ private String fileName = null;
+
+ /** Resources object. */
+ private Resources res = null;
+
+ /**
+ * <code>OfficeZip</code> object to store zip contents from
+ * read <code>InputStream</code>. 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</code> name.
+ */
+ public OfficeDocument(String name)
+ {
+ this(name, true, false);
+ }
+
+
+ /**
+ * Constructor with arguments to set <code>namespaceAware</code>
+ * and <code>validating</code> flags.
+ *
+ * @param name <code>Document</code> name (may or may not
+ * contain extension).
+ * @param namespaceAware Value for <code>namespaceAware</code> flag.
+ * @param validating Value for <code>validating</code> flag.
+ */
+ public OfficeDocument(String name, boolean namespaceAware, boolean validating) {
+
+ res = Resources.getInstance();
+ factory.setValidating(validating);
+ factory.setNamespaceAware(namespaceAware);
+ this.documentName = trimDocumentName(name);
+ this.fileName = documentName + getFileExtension();
+ }
+
+
+ /**
+ * Removes the file extension from the <code>Document</code>
+ * name.
+ *
+ * @param name Full <code>Document</code> name with extension.
+ *
+ * @return Name of <code>Document</code> 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</code> object of the content.xml
+ * file. Note that a content DOM is not created when the constructor
+ * is called. So, either the <code>read</code> method or the
+ * <code>initContentDOM</code> method will need to be called ahead
+ * on this object before calling this method.
+ *
+ * @return DOM <code>Document</code> object.
+ */
+ public Document getContentDOM() {
+
+ return contentDoc;
+ }
+
+ /**
+ * Return a DOM <code>Document</code> object of the meta.xml
+ * file. Note that a content DOM is not created when the constructor
+ * is called. So, either the <code>read</code> method or the
+ * <code>initContentDOM</code> method will need to be called ahead
+ * on this object before calling this method.
+ *
+ * @return DOM <code>Document</code> object.
+ */
+ public Document getMetaDOM() {
+
+ return metaDoc;
+ }
+
+
+ /**
+ * Return a DOM <code>Document</code> object of the settings.xml
+ * file. Note that a content DOM is not created when the constructor
+ * is called. So, either the <code>read</code> method or the
+ * <code>initContentDOM</code> method will need to be called ahead
+ * on this object before calling this method.
+ *
+ * @return DOM <code>Document</code> object.
+ */
+ public Document getSettingsDOM() {
+
+ return settingsDoc;
+ }
+
+
+ /**
+ * Sets the content tree of the document.
+ *
+ * @param newDom <code>Node</code> containing the new content tree.
+ */
+ public void setContentDOM( Node newDom) {
+ contentDoc = (Document)newDom;
+ }
+
+
+ /**
+ * Sets the meta tree of the document.
+ *
+ * @param newDom <code>Node</code> containing the new meta tree.
+ */
+ public void setMetaDOM (Node newDom) {
+ metaDoc = (Document)newDom;
+ }
+
+
+ /**
+ * Sets the settings tree of the document.
+ *
+ * @param newDom <code>Node</code> containing the new settings tree.
+ */
+ public void setSettingsDOM (Node newDom) {
+ settingsDoc = (Document)newDom;
+ }
+
+
+ /**
+ * Sets the style tree of the document.
+ *
+ * @param newDom <code>Node</code> containing the new style tree.
+ */
+ public void setStyleDOM (Node newDom) {
+ styleDoc = (Document)newDom;
+ }
+
+
+ /**
+ * Return a DOM <code>Document</code> object of the style.xml file.
+ * Note that this may return 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</code>, a
+ * <code>read</code> method may or may not build a style DOM. When
+ * creating a new style DOM, call the <code>initStyleDOM</code> method
+ * first.
+ *
+ * @return DOM <code>Document</code> object.
+ */
+ public Document getStyleDOM() {
+
+ return styleDoc;
+ }
+
+
+ /**
+ * Return the name of the <code>Document</code>.
+ *
+ * @return The name of <code>Document</code>.
+ */
+ public String getName() {
+
+ return documentName;
+ }
+
+
+ /**
+ * Return the file name of the <code>Document</code>, possibly
+ * with the standard extension.
+ *
+ * @return The file name of <code>Document</code>.
+ */
+ public String getFileName() {
+
+ return fileName;
+ }
+
+
+ /**
+ * Returns the file extension for this type of
+ * <code>Document</code>.
+ *
+ * @return The file extension of <code>Document</code>.
+ */
+ protected abstract String getFileExtension();
+
+
+ /**
+ * Returns all the embedded objects (graphics, formulae, etc.) present in
+ * this document.
+ *
+ * @return An <code>Iterator</code> of <code>EmbeddedObject</code> objects.
+ */
+ public 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);
+
+ // Dont 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));
+ }
+ }
+ }
+
+ return embeddedObjects.values().iterator();
+ }
+
+ /**
+ * Returns the embedded object corresponding to the name provided.
+ * The name should be stripped of any preceding path characters, such as
+ * '/', '.' or '#'.
+ *
+ * @param name The name of the embedded object to retrieve.
+ *
+ * @return An <code>EmbeddedObject</code> instance representing the named
+ * object.
+ */
+ public EmbeddedObject getEmbeddedObject(String name) {
+ if (name == null) {
+ return null;
+ }
+
+ if (embeddedObjects == null) {
+ getEmbeddedObjects();
+ }
+
+ if (embeddedObjects.containsKey(name)) {
+ return (EmbeddedObject)embeddedObjects.get(name);
+ }
+ else {
+ return null;
+ }
+ }
+
+
+ /**
+ * Adds a new embedded object to the document.
+ *
+ * @param embObj An instance of <code>EmbeddedObject</code>.
+ */
+ public void addEmbeddedObject(EmbeddedObject embObj) {
+ if (embObj == null) {
+ return;
+ }
+
+ if (embeddedObjects == null) {
+ embeddedObjects = new HashMap();
+ }
+
+ embeddedObjects.put(embObj.getName(), embObj);
+ }
+
+
+ /**
+ * Read the Office <code>Document</code> from the given
+ * <code>InputStream</code>.
+ *
+ * @param is Office document <code>InputStream</code>.
+ *
+ * @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</code> from the given
+ * <code>InputStream</code>.
+ *
+ * @param is Office document <code>InputStream</code>.
+ * @param isZip <code>boolean</code> 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{
+ //System.out.println("\nParsing Input stream, validating?: "+builder.isValidating());
+ //contentDoc= builder.parse((InputStream)is);
+
+ Reader r = secondHack(is);
+ InputSource ins = new InputSource(r);
+ org.w3c.dom.Document newDoc = builder.parse(ins);
+ //org.w3c.dom.Document newDoc = builder.parse((InputStream)is);
+ Element rootElement=newDoc.getDocumentElement();
+
+ NodeList nodeList;
+ Node tmpNode;
+ Node rootNode = (Node)rootElement;
+ if (newDoc !=null){
+ /*content*/
+ contentDoc = createDOM(TAG_OFFICE_DOCUMENT_CONTENT);
+ rootElement=contentDoc.getDocumentElement();
+ rootNode = (Node)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 = (Node)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 = (Node)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 = (Node)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</code> array into a DOM
+ * <code>Document</code> object using the
+ * <code>DocumentBuilder</code> object.
+ *
+ * @param builder <code>DocumentBuilder</code> object for parsing.
+ * @param bytes <code>byte</code> array for parsing.
+ *
+ * @return Resulting DOM <code>Document</code> 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</code>.
+ *
+ * @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();
+ while (embObjs.hasNext()) {
+ EmbeddedObject obj = (EmbeddedObject)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</code>.
+ * @param isZip <code>boolean</code>
+ *
+ * @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();
+ DocumentType docType =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() == SXC_MIME_TYPE)
+ rootElement.setAttribute("office:class","spreadsheet" );
+ else if(getDocumentMimeType() == SXW_MIME_TYPE)
+ rootElement.setAttribute("office:class","text" );
+ rootElement.setAttribute("office:version","1.0");
+
+
+ NodeList nodeList;
+ Node tmpNode;
+ Node rootNode = (Node)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);
+ //System.out.println(new String(contentBytes));
+ os.write(contentBytes);
+ }
+ catch(Exception exc){
+ System.out.println("\nException in OfficeDocument.write():" +exc);
+ }
+ //byte contentBytes[] = docToBytes(contentDoc);
+ }
+ }
+
+
+ /**
+ * <p>Write out a <code>org.w3c.dom.Document</code> object into a
+ * <code>byte</code> array.</p>
+ *
+ * <p>TODO: remove dependency on com.sun.xml.tree.XmlDocument
+ * package!</p>
+ *
+ * @param Document DOM <code>Document</code> object.
+ *
+ * @return <code>byte</code> array of DOM <code>Document</code>
+ * 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
+ throw new IOException("No appropriate API (JAXP/Xerces) to serialize XML document: " + domImpl);
+ }
+ }
+ }
+ catch (ClassNotFoundException cnfe) {
+ throw new IOException(cnfe.toString());
+ }
+ catch (Exception e) {
+ // We may get some other errors, but the bottom line is that
+ // the steps being executed no longer work
+ throw new IOException(e.toString());
+ }
+
+ byte bytes[] = baos.toByteArray();
+
+ return bytes;
+ }
+
+
+ /**
+ * Initializes a new DOM <code>Document</code> 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</code> 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);
+ }
+
+ /**
+ * <p>Creates a new DOM <code>Document</code> containing minimum
+ * OpenOffice XML tags.</p>
+ *
+ * <p>This method uses the subclass
+ * <code>getOfficeClassAttribute</code> method to get the
+ * attribute for <i>office:class</i>.</p>
+ *
+ * @param rootName root name of <code>Document</code>.
+ *
+ * @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 = (Element) 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;
+ }
+
+
+ /**
+ * <p>Creates a new DOM <code>Document</code> containing minimum
+ * OpenOffice XML tags.</p>
+ *
+ * <p>This method uses the subclass
+ * <code>getOfficeClassAttribute</code> method to get the
+ * attribute for <i>office:class</i>.</p>
+ *
+ * @param rootName root name of <code>Document</code>.
+ *
+ * @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 = (Element) 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 <i>office:class</i> attribute value.
+ *
+ * @return The attribute value.
+ */
+ protected abstract String getOfficeClassAttribute();
+
+
+ /**
+ * <p>Hacked code to filter <!DOCTYPE> tag before
+ * sending stream to parser.</p>
+ *
+ * <p>This hacked code needs to be changed later on.</p>
+ *
+ * <p>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.</p>
+ *
+ * <p>This is a simple hack that assumes the whole <!DOCTYPE>
+ * 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.</p>
+ * FIX (HJ): Removed requirement for DOCTYPE to be in one line
+ * FIX (HJ): No longer removes newlines
+ *
+ * @param is <code>InputStream</code> to be filtered.
+ *
+ * @return Reader value without the <!DOCTYPE> 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 = null;
+
+ while ((str = br.readLine()) != null) {
+
+ int sIndex = str.indexOf("<!DOCTYPE");
+
+ if (sIndex > -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;
+ }
+
+ /**
+ * <p>Transform the InputStream to a Reader Stream.</p>
+ *
+ * <p>This hacked code needs to be changed later on.</p>
+ *
+ * <p>Issue: the new oasis input file stream means
+ * that the old input stream fails. see #i33702# </p>
+ *
+ * @param is <code>InputStream</code> to be filtered.
+ *
+ * @return Reader value of the 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 = 0;
+ 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("</office:document>");
+ sBuf.delete(sIndex, sBuf.length());
+ sBuf.append("</office:document>");
+ 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 <manifest:manifest> 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 000000000000..2c8ae71f2af3
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/OfficeDocumentException.java
@@ -0,0 +1,130 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+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</code>.
+ *
+ * @author Herbie Ong
+ */
+
+public final class OfficeDocumentException extends IOException {
+
+ StringBuffer message = null;
+
+
+ /**
+ * Constructor, capturing additional information from the
+ * <code>SAXException</code>.
+ *
+ * @param e The <code>SAXException</code>.
+ */
+ public OfficeDocumentException(SAXException e) {
+ super(e.toString());
+ 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());
+ }
+ }
+
+
+ /**
+ * 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 Exception.
+ */
+ public OfficeDocumentException(Exception e) {
+ super(e.getMessage());
+ }
+
+
+ /**
+ * Returns the message value for the <code>Exception</code>.
+ *
+ * @return The message value for the <code>Exception</code>.
+ */
+ public String getMessage() {
+ return message.toString() + super.getMessage();
+ }
+}
+
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 000000000000..9752650533a1
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/OfficeZip.java
@@ -0,0 +1,458 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+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.OfficeDocument
+ * OfficeDocument} to handle reading and writing
+ * from a ZIP file, as well as storing ZIP entries.
+ *
+ * @author Herbie Ong
+ */
+class OfficeZip {
+
+ /** File name of the XML file in a zipped document. */
+ private final static String CONTENTXML = "content.xml";
+
+ private final static String STYLEXML = "styles.xml";
+ private final static String METAXML = "meta.xml";
+ private final static String SETTINGSXML = "settings.xml";
+ private final static String MANIFESTXML = "META-INF/manifest.xml";
+
+ private final static int BUFFERSIZE = 1024;
+
+ private List entryList = null;
+
+ 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();
+ }
+
+
+ /**
+ * <p>Read each zip entry in the <code>InputStream</code> object
+ * and store in entryList both the <code>ZipEntry</code> object
+ * as well as the bits of each entry. Call this method before
+ * calling the <code>getContentXMLBytes</code> method or the
+ * <code>getStyleXMLBytes</code> method.</p>
+ *
+ * <p>Keep track of the CONTENTXML and STYLEXML using
+ * contentIndex and styleIndex, respectively.</p>
+ *
+ * @param is <code>InputStream</code> object to read.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ void read(InputStream is) throws IOException {
+
+ ZipInputStream zis = new ZipInputStream(is);
+ ZipEntry ze = null;
+ 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 = 0;
+ 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</code> array. It returns null if there is no
+ * CONTENTXML in this zip file.
+ *
+ * @return CONTENTXML in a <code>byte</code> array.
+ */
+ byte[] getContentXMLBytes() {
+
+ return getEntryBytes(contentIndex);
+ }
+
+
+ /**
+ * This method returns the STYLEXML file in a
+ * <code>byte</code> array. It returns null if there is
+ * no STYLEXML in this zip file.
+ *
+ * @return STYLEXML in a <code>byte</code> array.
+ */
+ byte[] getStyleXMLBytes() {
+
+ return getEntryBytes(styleIndex);
+ }
+
+ /**
+ * This method returns the METAXML file in a
+ * <code>byte</code> array. It returns null if there is
+ * no METAXML in this zip file.
+ *
+ * @return METAXML in a <code>byte</code> array.
+ */
+ byte[] getMetaXMLBytes() {
+ return getEntryBytes(metaIndex);
+ }
+
+ /**
+ * This method returns the SETTINGSXML file in a
+ * <code>byte</code> array. It returns null if there is
+ * no SETTINGSXML in this zip file.
+ *
+ * @return SETTINGSXML in a <code>byte</code> array.
+ */
+ byte[] getSettingsXMLBytes() {
+ return getEntryBytes(settingsIndex);
+ }
+
+ /**
+ * This method returns the MANIFESTXML file in a <code>byte</code> array.
+ * It returns null if there is no MANIFESTXML in this zip file.
+ *
+ * @return MANIFESTXML in a <code>byte</code> 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</code> array or
+ * <code>null</code> 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 = (Entry)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 defferred to 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 = (Entry)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</code> method and the
+ * <code>getStyleXMLBytes</code> method to return the
+ * <code>byte</code> array from the corresponding
+ * <code>entry</code> in the <code>entryList</code>.
+ *
+ * @param index Index of <code>Entry</code> object in
+ * <code>entryList</code>.
+ *
+ * @return <code>byte</code> array associated in that
+ * <code>Entry</code> object or null, if there is
+ * not such <code>Entry</code>.
+ */
+ private byte[] getEntryBytes(int index) {
+
+ byte[] bytes = null;
+
+ if (index > -1) {
+ Entry entry = (Entry) entryList.get(index);
+ bytes = entry.bytes;
+ }
+ return bytes;
+ }
+
+
+ /**
+ * Set or replace the <code>byte</code> array for the
+ * CONTENTXML file.
+ *
+ * @param bytes <code>byte</code> array for the
+ * CONTENTXML file.
+ */
+ void setContentXMLBytes(byte bytes[]) {
+
+ contentIndex = setEntryBytes(contentIndex, bytes, CONTENTXML);
+ }
+
+
+ /**
+ * Set or replace the <code>byte</code> array for the
+ * STYLEXML file.
+ *
+ * @param bytes <code>byte</code> array for the
+ * STYLEXML file.
+ */
+ void setStyleXMLBytes(byte bytes[]) {
+
+ styleIndex = setEntryBytes(styleIndex, bytes, STYLEXML);
+ }
+
+
+ /**
+ * Set or replace the <code>byte</code> array for the
+ * METAXML file.
+ *
+ * @param bytes <code>byte</code> array for the
+ * METAXML file.
+ */
+ void setMetaXMLBytes(byte bytes[]) {
+
+ metaIndex = setEntryBytes(metaIndex, bytes, METAXML);
+ }
+
+
+ /**
+ * Set or replace the <code>byte</code> array for the
+ * SETTINGSXML file.
+ *
+ * @param bytes <code>byte</code> array for the
+ * SETTINGSXML file.
+ */
+ void setSettingsXMLBytes(byte bytes[]) {
+
+ settingsIndex = setEntryBytes(settingsIndex, bytes, SETTINGSXML);
+ }
+
+
+ /**
+ * Set or replace the <code>byte</code> array for the MANIFESTXML file.
+ *
+ * @param bytes <code>byte</code> array for the MANIFESTXML file.
+ */
+ void setManifestXMLBytes(byte bytes[]) {
+ manifestIndex = setEntryBytes(manifestIndex, bytes, MANIFESTXML);
+ }
+
+ /**
+ * <p>Used by the <code>setContentXMLBytes</code> method and
+ * the <code>setStyleXMLBytes</code> to either replace an
+ * existing <code>Entry</code>, or create a new entry in
+ * <code>entryList</code>.</p>
+ *
+ * <p>If there is an <code>Entry</code> object within
+ * entryList that corresponds to the index, replace the
+ * <code>ZipEntry</code> info.</p>
+ *
+ * @param index Index of <code>Entry</code> to modify.
+ * @param bytes <code>Entry</code> value.
+ * @param name Name of <code>Entry</code>.
+ *
+ * @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 = (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</code>
+ * object.
+ *
+ * @param os <code>OutputStream</code> 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 = (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</code> object based on the given params.
+ *
+ * @param name Name for the <code>ZipEntry</code>.
+ * @param bytes <code>byte</code> array for <code>ZipEntry</code>.
+ * @param method ZIP method to be used for <code>ZipEntry</code>.
+ *
+ * @return A <code>ZipEntry</code> 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</code> info and its corresponding bytes.
+ * These are stored in entryList.
+ */
+ private class Entry {
+
+ ZipEntry zipEntry = null;
+ byte bytes[] = null;
+
+ Entry(ZipEntry zipEntry, byte bytes[]) {
+ this.zipEntry = zipEntry;
+ this.bytes = bytes;
+ }
+ }
+}
+
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 000000000000..662a542d0e7b
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/ParaStyle.java
@@ -0,0 +1,601 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+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 {
+ int I(String val) {
+ return 0;
+ }
+}
+
+ /*
+ * This algorithm expects only values in millimeters, e.g. "20.3mm".
+ */
+class horizSize extends conversionAlgorithm {
+ 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 - can be either millimeters or
+ * a percentage.
+ */
+class lineHeight extends conversionAlgorithm {
+ 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 {
+ 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;
+ }
+}
+
+
+/**
+ * <p>This class represents a paragraph <code>Style</code>.</p>
+ *
+ * <p><table border="1" cellpadding="1"><tr><td>
+ * Attribute </td><td>Value
+ * </td></tr><tr><td>
+ * MARGIN_LEFT </td><td>mm * 100
+ * </td></tr><tr><td>
+ * MARGIN_RIGHT </td><td>mm * 100
+ * </td></tr><tr><td>
+ * MARGIN_TOP </td><td>mm * 100 (space on top of paragraph)
+ * </td></tr><tr><td>
+ * MARGIN_BOTTOM </td><td>mm * 100
+ * </td></tr><tr><td>
+ * TEXT_INDENT </td><td>mm * 100 (first line indent)
+ * </td></tr><tr><td>
+ * LINE_HEIGHT </td><td>mm * 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.
+ * </td></tr><tr><td>
+ * TEXT_ALIGN </td><td>ALIGN_RIGHT, ALIGN_CENTER, ALIGN_JUST, ALIGN_LEFT
+ * </td></tr></table></p>
+ *
+ * @author David Proulx
+ */
+public class ParaStyle extends Style implements Cloneable {
+
+ /** The left margin property. */
+ public static final int MARGIN_LEFT = 0;
+ /** The right margin property. */
+ public static final int MARGIN_RIGHT = 1;
+ /** The top margin property. */
+ public static final int MARGIN_TOP = 2;
+ /** The bottom margin property. */
+ public static final int MARGIN_BOTTOM = 3;
+ /** Indent left property. */
+ public static final int TEXT_INDENT = 4;
+ /** Indent right property. */
+ public static final int LINE_HEIGHT = 5;
+ /** Align text property. */
+ public static final int TEXT_ALIGN = 6;
+ // This must always be one more than highest property
+ /** Total number of properties. */
+ protected static final int NR_PROPERTIES = 7;
+
+ /**
+ * Array of flags indicating which attributes are set for this
+ * paragraph <code>Style</code>.
+ */
+ protected boolean isSet[] = new boolean[NR_PROPERTIES];
+ /** Array of attribute values for this paragraph <code>tyle</code>. */
+ protected int value[] = new int[NR_PROPERTIES];
+ /** Array of attribute names for this paragraph <code>Style</code>. */
+ protected 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</code>. */
+ protected 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 minimum value. */
+ public static final int LH_ATLEAST = 0x20000000;
+ /** Line height mask. */
+ public 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 <i>style:style</i> <code>Node</code> which, which
+ * is assumed to have <i>family</i> attribute of
+ * <i>paragraph</i>.
+ * @param sc The <code>StyleCatalog</code>, which is used for
+ * looking up ancestor <code>Style</code> 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 name = child.getNodeName();
+ if (name.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</code>. Can be null.
+ * @param family Family of the <code>Style</code> - usually
+ * <i>paragraph</i>, <i>text</i>, etc. Can be null.
+ * @param parent Name of the parent <code>Style</code>, or null
+ * if none.
+ * @param attribs Array of attributes to set.
+ * @param values Array of values to set.
+ * @param sc The <code>StyleCatalog</code>, which is used for
+ * looking up ancestor <code>Style</code> 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</code>. Can be null.
+ * @param family Family of the <code>Style</code> - usually
+ * <i>paragraph</i>, <i>text</i>, etc. Can be null.
+ * @param parent Name of the parent <code>Style</code>, or
+ * null if none.
+ * @param attribs Array of attributes indices to set.
+ * @param values Array of values to set.
+ * @param sc The <code>StyleCatalog</code>, which is used for
+ * looking up ancestor <code>Style</code> 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 true if attribute can be ignored, 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</code>.
+ *
+ * @param attr The attribute to set.
+ * @param value The attribute value to set.
+ */
+ public 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);
+ }
+
+
+ /**
+ * Check whether an attribute is set in this <code>Style</code>.
+ *
+ * @param attrIndex The attribute index to check.
+ *
+ * @return true if the attribute at specified index is set,
+ * false otherwise.
+ */
+ public boolean isAttributeSet(int attrIndex) {
+ return isSet[attrIndex];
+ }
+
+
+ /**
+ * Get the value of an integer attribute.
+ *
+ * @param attrIndex Index of the attribute.
+ *
+ * @return Value of the attribute, 0 if not set.
+ */
+ public int getAttribute(int attrIndex) {
+ if (isSet[attrIndex])
+ return value[attrIndex];
+ else return 0;
+ }
+
+
+ /**
+ * Set an attribute for this paragraph <code>Style</code>.
+ *
+ * @param attr The attribute index to set.
+ * @apram value The attribute value to set.
+ */
+ public 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</code> in use.
+ *
+ * @return The fully-resolved copy of the <code>Style</code> in use.
+ */
+ 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</code> 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</code> with the specified elements.
+ *
+ * @parentDoc Parent <code>Document</code> of the
+ * <code>Node</code> to create.
+ * @param name Name of the <code>Node</code>.
+ *
+ * @return The created <code>Node</code>.
+ */
+ public Node createNode(org.w3c.dom.Document parentDoc, String name) {
+ Element node = parentDoc.createElement(name);
+ writeAttributes(node);
+ return node;
+ }
+
+
+ /**
+ * Return true if <code>style</code> is a subset of the
+ * <code>Style</code>.
+ *
+ * @param style <code>Style</code> to check.
+ *
+ * @return true if <code>style</code> is a subset, false
+ * otherwise.
+ */
+ 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 (!isSet[i]) return false;
+
+ 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</code> attributes to the given
+ * <code>Node</code>. This may involve writing child
+ * <code>Node</code> objects as well.
+ *
+ * @param node The <code>Node</code> to add <code>Style</code>
+ * attributes.
+ */
+ public void writeAttributes(Element node) {
+ for (int i = 0; i <= TEXT_INDENT; i++) {
+ if (isSet[i]) {
+ double temp = value[i] / 100.0;
+ String stringVal = (new Double(temp)).toString() + "mm";
+ node.setAttribute(attrName[i], stringVal);
+ }
+ }
+
+ if (isSet[LINE_HEIGHT]) {
+ String stringVal;
+ if ((value[LINE_HEIGHT] & LH_PCT) != 0)
+ stringVal = (new Integer(value[LINE_HEIGHT] & LH_VALUEMASK)).toString() + "%";
+ else {
+ double temp = (value[LINE_HEIGHT] & LH_VALUEMASK) / 100.0;
+ stringVal = (new Double(temp)).toString() + "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);
+ }
+ }
+}
+
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 000000000000..cc1e1d3d530c
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/Style.java
@@ -0,0 +1,227 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml;
+
+import org.w3c.dom.Node;
+import org.w3c.dom.NamedNodeMap;
+
+/**
+ * An object of class <code>Style</code> represents a <i>style</i>
+ * in an OpenOffice document. In practice subclasses of this
+ * <code>Style</code>, such as <code>TextStyle</code>,
+ * <code>ParaStyle</code> are used.
+ *
+ * @author David Proulx
+ * @see <a href="TextStyle.html">TextStyle</a>,
+ * <a href="ParaStyle.html">ParaStyle</a>
+ */
+public class Style {
+
+ /** Name of the <code>Style</code>. */
+ protected String name = null;
+ /** Family of the <code>Style</code>. */
+ protected String family = null;
+ /** Parent of the <code>Style</code>. */
+ protected String parent = null;
+
+ /**
+ * A reference to the <code>StyleCatalog</code> to be used for
+ * looking up ancestor <code>Style</code> objects.
+ */
+ protected StyleCatalog sc;
+
+
+ /**
+ * Constructor for use when going from DOM to client device format.
+ *
+ * @param node A <i>style:style</i> or <i>style:default-style</i>
+ * <code>Node</code> from the document being parsed.
+ * No checking of <code>Node</code> is done, so if it
+ * is not of the proper type the results will be
+ * unpredictable.
+ * @param sc The <code>StyleCatalog</code>, which is used for
+ * looking up ancestor <code>Style</code> 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</code>. Can be null.
+ * @param family Family of the <code>Style</code> - usually
+ * <i>paragraph</i>, <i>text</i>, etc. Can be null.
+ * @param parent Name of the parent <code>Style</code>, or null if none.
+ * @param sc The <code>StyleCatalog</code>, which is used for
+ * looking up ancestor <code>Style</code> 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</code> to be used when looking up the
+ * <code>Style</code> parent.
+ *
+ * @param sc The <code>StyleCatalog</code>, which is used for
+ * looking up ancestor <code>Style</code> objects.
+ */
+ public void setCatalog(StyleCatalog sc) {
+ this.sc = sc;
+ }
+
+
+ /**
+ * Returns the name of this <code>Style</code>.
+ *
+ * @return The name of this <code>Style</code>.
+ */
+ public String getName() {
+ return name;
+ }
+
+
+ /**
+ * Sets the name of this <code>Style</code>.
+ *
+ * @param newName The new name of this <code>Style</code>.
+ */
+ public void setName(String newName) {
+ name = newName;
+ }
+
+
+ /**
+ * Return the family of this <code>Style</code>.
+ *
+ * @return The family of this <code>Style</code>.
+ */
+ public String getFamily() {
+ return family;
+ }
+
+ /**
+ * Return the name of the parent of this <code>Style</code>.
+ *
+ * @return The parent of this <code>Style</code>.
+ */
+ public String getParent() {
+ return parent;
+ }
+
+
+ /**
+ * Return a <code>Style</code> object corresponding to this one, but with
+ * all of the inherited information from parent <code>Style</code>
+ * 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</code> object in which to look up
+ * ancestors.
+ */
+ public Style getResolved() {
+ return new Style(name, family, parent, sc);
+ }
+
+
+ /**
+ * Write a <code>Node</code> in <code>parentDoc</code>
+ * representing this <code>Style</code>. Note that the
+ * <code>Node</code> is returned unconnected.
+ *
+ * @param parentDoc Document to which new <code>Node</code> will
+ * belong.
+ * @param name Name to use for new <code>Node</code>.
+ */
+ public Node createNode(org.w3c.dom.Document parentDoc, String name) {
+ // DJP: write this! Should call writeAttributes()
+ return null;
+ }
+
+
+ /**
+ * Write this <code>Style</code> object's attributes to the given
+ * <code>Node</code>. This may involve writing child
+ * <code>Node</code> objects as well. This is similar to the
+ * <code>writeNode</code> method, but the <code>Node</code>
+ * already exists, and this does <b>not</b> write the name,
+ * family, and parent attributes, which are assumed to already
+ * exist in the <code>Node</code>.
+ *
+ * @param node The <code>Node</code> to add style attributes.
+ */
+ public void writeAttributes(Node node) {
+ }
+
+
+ /**
+ * Return true if <code>Style</code> is a subset of this one. Note
+ * that this will return true even if <code>Style</code> is less
+ * specific than this <code>Style</code>, so long as it does not
+ * contradict this <code>Style</code> in any way.
+ *
+ * This always returns true since only subclasses of
+ * <code>Style</code> contain any actual <code>Style</code>
+ * information.
+ *
+ * @param style The <code>Style</code> to check
+ *
+ * @return true if the <code>Style</code> is a subset, false otherwise.
+ */
+ public boolean isSubset(Style style) {
+ return true;
+ }
+}
+
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 000000000000..c783d366a68b
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/StyleCatalog.java
@@ -0,0 +1,390 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+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.*;
+import java.util.Vector;
+import java.lang.reflect.Constructor;
+
+
+/**
+ * A <code>StyleCatalog</code> holds a collection of <code>Style</code>
+ * objects. It is intended for use when parsing or building a DOM
+ * document.
+ *
+ * Each entry in the <code>StyleCatalog</code> represents a
+ * <code>Style</code>, and is an object which is a subclass of
+ * <code>Style</code>.
+ *
+ * @author David Proulx
+ * @see <a href="Style.html">Style</a>
+ */
+public class StyleCatalog {
+
+ private Vector styles; // The actual styles
+
+ /**
+ * Constructor
+ *
+ * @param initialEntries Expected number of entries to set
+ * for efficiency purposes.
+ */
+ public StyleCatalog(int initialEntries) {
+ styles = new Vector(initialEntries);
+ }
+
+
+ /**
+ * <p>Parse the <code>Document</code> starting from <code>node</code>
+ * and working downward, and add all styles found, so long as their
+ * family name is listed in <code>families</code>. For each
+ * family name in <code>families</code> there must be a corresponding
+ * element in <code>classes</code>, which specifies the class type
+ * to use for that family. All of these classes must be
+ * subclasses of <code>Style</code>. There can be multiple
+ * classes specified for a particular family.</p>
+ *
+ * <p>If <code>defaultClass</code> is non-null, then all styles that
+ * are found will be added. Any <code>Style</code> whose family is
+ * not listed in <code>families</code> will be added using defaultClass,
+ * which, of course, must be a subclass of <code>Style</code>.
+ * If <code>alwaysCreateDefault</code> is true, then a class
+ * of type <code>defaultClass</code> will always be created,
+ * regardless of whether there was also a match in
+ * <code>families</code>.</p>
+ *
+ * <p>DJP Todo: make it recursive so that <code>node</code> can be
+ * higher up in the <code>Document</code> tree.</p>
+ *
+ * @param node The node to be searched for
+ * <code>Style</code> objects.
+ * @param families An array of <code>Style</code> families
+ * to add.
+ * @param classes An array of class types corresponding
+ * to the families array.
+ * @param defaultClass All <code>Style</code> objects that are
+ * found are added to this class.
+ * @param alwaysCreateDefault A class of type <code>defaultClass</code>
+ * will always be created, regardless of
+ * whether there is a match in the
+ * families array.
+ */
+ public void add(Node node, String families[], Class classes[],
+ Class defaultClass, boolean alwaysCreateDefault) {
+
+ if (node == null)
+ return;
+
+ if (families == null)
+ families = new String[0];
+ if (classes == null)
+ classes = new Class[0];
+ if (node.hasChildNodes()) {
+ NodeList children = node.getChildNodes();
+ int len = children.getLength();
+
+ for (int i = 0; i < len; i++) {
+ boolean found = false;
+ Node child = children.item(i);
+ String name = child.getNodeName();
+ if (name.equals("style:default-style") || name.equals("style:style")) {
+ String familyName = getFamilyName(child);
+ if (familyName == null) {
+ Debug.log(Debug.ERROR, "familyName is null!");
+ continue;
+ }
+
+ for (int j = 0; j < families.length; j++) {
+ if (families[j].equals(familyName)) {
+ Class styleClass = classes[j];
+ callConstructor(classes[j], child);
+ found = true;
+ }
+ }
+ if ((!found || alwaysCreateDefault) && (defaultClass != null))
+ callConstructor(defaultClass, child);
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Call the constructor of class <code>cls</code> with parameters
+ * <code>node</code>, and add the resulting <code>Style</code> to
+ * the catalog.
+ *
+ * @param cls The class whose constructor will be called.
+ * @param node The constructed class will be added to this node.
+ */
+ private void callConstructor(Class cls, Node node) {
+ Class params[] = new Class[2];
+ params[0] = Node.class;
+ params[1] = this.getClass();
+ try {
+ Constructor c = cls.getConstructor(params);
+ Object p[] = new Object[2];
+ p[0] = node;
+ p[1] = this;
+ styles.add(c.newInstance(p));
+ } catch (Exception e) {
+ Debug.log(Debug.ERROR, "Exception when calling constructor", e);
+ }
+ }
+
+
+ /**
+ * Add a <code>Style</code> to the catalog.
+ *
+ * @param s The <code>Style</code> to add.
+ */
+ public void add(Style s) {
+ styles.addElement(s);
+ }
+
+
+ /**
+ * Return the first <code>Style</code> matching the specified names.
+ *
+ * @param name Name to match, null is considered
+ * <i>always match</i>.
+ * @param family Family to match, null is considered
+ * <i>always match</i>.
+ * @param parent Parent to match, null is considered
+ * <i>always match</i>.
+ * @param styleClass styleClass to match, null is considered
+ * <i>always match</i>.
+ *
+ * @return <code>Style</code> value if all parameters match,
+ * null otherwise
+ */
+ public Style lookup(String name, String family, String parent,
+ Class styleClass) {
+ int nStyles = styles.size();
+ for (int i = 0; i < nStyles; i++) {
+ Style s = (Style)styles.elementAt(i);
+ if ((name != null) && (s.getName() != null)
+ && (!s.getName().equals(name)))
+ continue;
+ if ((family != null) && (s.getFamily() != null)
+ && (!s.getFamily().equals(family)))
+ continue;
+ if ((parent != null) && (s.getParent() != null)
+ && (!s.getParent().equals(parent)))
+ continue;
+ if ((styleClass != null) && (s.getClass() != styleClass))
+ continue;
+ if (s.getName() == null) continue; // DJP: workaround for "null name" problem
+ return s;
+ }
+ return null; // none found
+ }
+
+
+ /**
+ * Given a <code>Style</code> <code>s<code> return all
+ * <code>Style</code> objects that match.
+ *
+ * @param s <code>Style</code> to match.
+ *
+ * @return An array of <code>Style</code> objects that match, an
+ * empty array if none match.
+ */
+ public Style[] getMatching(Style s) {
+
+ // Run through and count the matching styles so we know how big of
+ // an array to allocate.
+ int matchCount = 0;
+ int nStyles = styles.size();
+ for (int j = 0; j < nStyles; j++) {
+ Style p = ((Style)styles.elementAt(j)).getResolved();
+ if (p.isSubset(s)) matchCount++;
+ }
+
+ // Now allocate the array, and run through again, populating it.
+ Style[] matchArray = new Style[matchCount];
+ matchCount = 0;
+ for (int j = 0; j < nStyles; j++) {
+ Style p = ((Style)styles.elementAt(j)).getResolved();
+ if (p.isSubset(s)) matchArray[matchCount++] = p;
+ }
+ return matchArray;
+ }
+
+
+ /**
+ * Given a <code>Style</code> <code>s</code>, return the
+ * <code>style</code> that is the closest match. Not currently
+ * implemented.
+ *
+ * @param s <code>Style</code> to match.
+ *
+ * @return The <code>Style</code> that most closely matches.
+ */
+ public Style getBestMatch(Style s) {
+ // DJP: is this needed?
+ // DJP ToDo: implement this
+ return null;
+ }
+
+
+ /**
+ * <p>Create a <code>Node</code> named <code>name</code> in
+ * <code>Document</code> <code>parentDoc</code>, and write the
+ * entire <code>StyleCatalog</code> to it.</p>
+ *
+ * <p>Note that the resulting node is returned, but is not connected
+ * into the document. Placing the output node in the document is
+ * left to the caller.</p>
+ *
+ * @param parentDoc The <code>Document</code> to add the
+ * <code>Node</code>.
+ * @param name The name of the <code>Node</code> to add.
+ *
+ * @return The <code>Element</code> that was created.
+ */
+ public Element writeNode(org.w3c.dom.Document parentDoc, String name) {
+ Element rootNode = parentDoc.createElement(name);
+
+ int len = styles.size();
+ for (int j = 0; j < len; j++) {
+ Style s = (Style)styles.get(j);
+
+ Element styleNode = parentDoc.createElement("style:style");
+
+ if (s.getName() != null)
+ styleNode.setAttribute("style:name", s.getName());
+ if (s.getParent() != null)
+ styleNode.setAttribute("style:parent-style-name", s.getParent());
+ if (s.getFamily() != null)
+ styleNode.setAttribute("style:family", s.getFamily());
+
+ Element propertiesNode = (Element) s.createNode(parentDoc, "style:properties");
+ // if (propertiesNode.getFirstChild() != null)
+ // DJP: only add node if has children OR attributes
+ if (propertiesNode != null)
+ styleNode.appendChild(propertiesNode);
+
+ rootNode.appendChild(styleNode);
+ }
+
+ return rootNode;
+ }
+
+
+ /**
+ * Dump the <code>Style</code> table in Comma Separated Value (CSV)
+ * format
+ *
+ * @param para If true, dump in paragraph <code>Style</code>,
+ * otherwise dump in text style.
+ */
+ public void dumpCSV(boolean para) {
+ if (!para) {
+ TextStyle.dumpHdr();
+ int nStyles = styles.size();
+ for (int i = 0; i < nStyles; i++) {
+ Style s = (Style)styles.get(i);
+ if (s.getClass().equals(TextStyle.class))
+ ((TextStyle)s).dumpCSV();
+ }
+ } else {
+ ParaStyle.dumpHdr();
+ int nStyles = styles.size();
+ for (int i = 0; i < nStyles; i++) {
+ Style s = (Style)styles.get(i);
+ if (s.getClass().equals(ParaStyle.class))
+ ((ParaStyle)s).dumpCSV();
+ }
+ }
+
+ }
+
+
+ /**
+ * Check whether a given node represents a <code>Style</code>
+ * that should be added to the catalog, and if so, return the
+ * class type for it. If <code>Style</code> should not be added,
+ * or if node is not a <code>Style</code>, return null.
+ *
+ * @param node The <code>Node</code> to be checked.
+ * @param families An array of <code>Style</code> families.
+ * @param classes An array of class types corresponding to the
+ * families array.
+ * @param defaultClass The default class.
+ *
+ * @return The class that is appropriate for this node.
+ */
+ private Class getClass(Node node, String[] families, Class[] classes,
+ Class defaultClass) {
+ NamedNodeMap attributes = node.getAttributes();
+ if (attributes != null) {
+ int len = attributes.getLength();
+ for (int i = 0; i < len; i++) {
+ Node attr = attributes.item(i);
+ if (attr.getNodeName().equals("style:family")) {
+ String familyName = attr.getNodeValue();
+ for (int j = 0; j < families.length; j++) {
+ if (families[j].equals(familyName))
+ return classes[j];
+ }
+ return defaultClass;
+ }
+ }
+ }
+ return null;
+ }
+
+
+ /**
+ * Find the family attribute of a <code>Style</code> <code>Node</code>.
+ *
+ * @param node The <code>Node</code> to check.
+ *
+ * @return The family attribute, or null if one does not
+ * exist.
+ */
+ private String getFamilyName(Node node) {
+ NamedNodeMap attributes = node.getAttributes();
+ if (attributes != null) {
+ int len = attributes.getLength();
+ for (int i = 0; i < len; i++) {
+ Node attr = attributes.item(i);
+ if (attr.getNodeName().equals("style:family")) {
+ return attr.getNodeValue();
+ }
+ }
+ }
+ return null;
+ }
+}
+
diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/TextStyle.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/TextStyle.java
new file mode 100644
index 000000000000..91926310776c
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/TextStyle.java
@@ -0,0 +1,679 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// DJP ToDo: need way of specifying fg/bg colors on ws->DOM
+
+package org.openoffice.xmerge.converter.xml;
+
+import java.awt.Color;
+
+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;
+
+/**
+ * Represents a text <code>Style</code> in an OpenOffice document.
+ *
+ * @author David Proulx
+ */
+public class TextStyle extends Style implements Cloneable {
+
+ final protected static int FIRST_ATTR = 0x01;
+ /** Indicates <i>bold</i> text. */
+ final public static int BOLD = 0x01;
+ /** Indicates <i>italic</i> text. */
+ final public static int ITALIC = 0x02;
+ /** Indicates <i>underlined</i> text. */
+ final public static int UNDERLINE = 0x04;
+ /** Indicates <i>strike-through</i> in the text. */
+ final public static int STRIKETHRU = 0x08;
+ /** Indicates <i>superscripted</i> text. */
+ final public static int SUPERSCRIPT = 0x10;
+ /** Indicates <i>subscripted</i> text. */
+ final public static int SUBSCRIPT = 0x20;
+ /** Indicates the last attribute. */
+ final protected static int LAST_ATTR = 0x20;
+
+ /** Values of text attributes. */
+ protected int values = 0;
+ /** Bitwise mask of text attributes. */
+ protected int mask = 0;
+
+ /** Font size in points. */
+ protected int sizeInPoints = 0;
+ /** Font name. */
+ protected String fontName = null;
+ /** Font <code>Color</code>. */
+ protected Color fontColor = null;
+ /** Background <code>Color</code>. */
+ protected Color bgColor = null;
+
+ /**
+ * Constructor for use when going from DOM to client device format.
+ *
+ * @param Node The <i>style:style</i> <code>Node</code> containing
+ * the <code>Style</code>. (This <code>Node</code> is
+ * assumed have a <i>family</i> attribute of <i>text</i>).
+ * @param sc The <code>StyleCatalog</code>, which is used for
+ * looking up ancestor <code>Style</code> objects.
+ */
+ public TextStyle(Node node, StyleCatalog sc) {
+ super(node, sc);
+
+ // Run through the attributes of this node, saving
+ // the ones we're interested in.
+ NamedNodeMap attrNodes = node.getAttributes();
+ if (attrNodes != null) {
+ int len = attrNodes.getLength();
+ for (int i = 0; i < len; i++) {
+ Node attr = attrNodes.item(i);
+ handleAttribute(attr.getNodeName(), attr.getNodeValue());
+ }
+ }
+
+ // 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 name = child.getNodeName();
+ if (name.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);
+ handleAttribute(attr.getNodeName(),
+ attr.getNodeValue());
+ }
+ }
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Constructor for use when going from client device format to DOM
+ *
+ * @param name Name of text <code>Style</code>. Can be null.
+ * @param family Family of text <code>Style</code> (usually
+ * <i>text</i>). Can be null.
+ * @param parent Name of parent text <code>Style</code>, or null
+ * for none.
+ * @param mask Bitwise mask of text attributes that this text
+ * <code>Style</code> will specify. Can be any
+ * combination of the following, or'ed together:
+ * {@link #BOLD}, {@link #ITALIC}, {@link #UNDERLINE},
+ * {@link #STRIKETHRU}, {@link #SUPERSCRIPT},
+ * {@link #SUBSCRIPT}. This parameter determines what
+ * attributes this <code>Style</code> will specify.
+ * When an attribute is specified in a
+ * <code>Style</code>, its value can be either
+ * <i>on</i> or <i>off</i>. The on/off value for
+ * each attribute is controlled by the
+ * <code>values</code> parameter.
+ * @param values Values of text attributes that this text
+ * <code>Style</code> will be setting. Any of the
+ * attributes ({@link #BOLD}, etc) listed for
+ * <code>mask</code> can be used for this.
+ * @param fontSize Font size in points.
+ * @param fontName Name of font.
+ * @param sc The <code>StyleCatalog</code>, which is used for
+ * looking up ancestor <code>Style</code> objects.
+ */
+ public TextStyle(String name, String family, String parent,
+ int mask, int values, int fontSize, String fontName, StyleCatalog sc) {
+ super(name, family, parent, sc);
+ this.mask = mask;
+ this.values = values;
+ this.sizeInPoints = fontSize;
+ this.fontName = fontName;
+ }
+
+
+ /**
+ * Parse a color specification of the form <i>#rrggbb</i>
+ *
+ * @param value <code>Color</code> specification to parse.
+ *
+ * @return The <code>Color</code> associated the value.
+ */
+ private Color parseColorString(String value) {
+ // Assume color value is of form #rrggbb
+ String r = value.substring(1, 3);
+ String g = value.substring(3, 5);
+ String b = value.substring(5, 7);
+ int red = 0;
+ int green = 0;
+ int blue = 0;
+ try {
+ red = Integer.parseInt(r, 16);
+ green = Integer.parseInt(g, 16);
+ blue = Integer.parseInt(b, 16);
+ } catch (NumberFormatException e) {
+ Debug.log(Debug.ERROR, "Problem parsing a color string", e);
+ }
+ return new Color(red, green, blue);
+ }
+
+
+ /**
+ * Set an attribute.
+ *
+ * @param attr The attribute to set.
+ * @param value The attribute value to set.
+ */
+ private void handleAttribute(String attr, String value) {
+
+ if (attr.equals("fo:font-weight")) {
+ if (value.equals("bold")) turnAttributesOn(BOLD);
+ else if (value.equals("normal")) turnAttributesOff(BOLD);
+ }
+
+ else if (attr.equals("fo:font-style")) {
+ if (value.equals("italic")) turnAttributesOn(ITALIC);
+ else if (value.equals("oblique")) turnAttributesOn(ITALIC);
+ else if (value.equals("normal")) turnAttributesOff(ITALIC);
+ }
+
+ else if (attr.equals("style:text-underline")) {
+ if (value.equals("none"))
+ turnAttributesOff(UNDERLINE);
+ else
+ turnAttributesOn(UNDERLINE);
+ }
+
+ else if (attr.equals("style:text-crossing-out")) {
+ if (value.equals("none"))
+ turnAttributesOff(STRIKETHRU);
+ else
+ turnAttributesOn(STRIKETHRU);
+ }
+
+ else if (attr.equals("style:text-position")) {
+ if (value.startsWith("super "))
+ turnAttributesOn(SUPERSCRIPT);
+ else if (value.startsWith("sub "))
+ turnAttributesOn(SUBSCRIPT);
+ else if (value.startsWith("0% "))
+ turnAttributesOff(SUPERSCRIPT | SUBSCRIPT);
+ else {
+ String firstPart = value.substring(0, value.indexOf(" "));
+ if (firstPart.endsWith("%")) {
+ firstPart = firstPart.substring(0, value.indexOf("%"));
+ int amount;
+ try {
+ amount = Integer.parseInt(firstPart);
+ } catch (NumberFormatException e) {
+ amount = 0;
+ Debug.log(Debug.ERROR, "Problem with style:text-position tag", e);
+ }
+ if (amount < 0) turnAttributesOn(SUBSCRIPT);
+ else if (amount > 0) turnAttributesOn(SUPERSCRIPT);
+ }
+ }
+ }
+
+ else if (attr.equals("fo:font-size")) {
+ if (value.endsWith("pt")) {
+ String num = value.substring(0, value.length() - 2);
+ sizeInPoints = Integer.parseInt(num);
+ }
+ }
+
+ else if (attr.equals("style:font-name"))
+ fontName = value;
+
+ else if (attr.equals("fo:color"))
+ fontColor = parseColorString(value);
+
+ else if (attr.equals("style:text-background-color"))
+ bgColor = parseColorString(value);
+
+ else if (isIgnored(attr)) {}
+
+ else {
+ Debug.log(Debug.INFO, "TextStyle Unhandled: " + attr + "=" + value);
+ }
+ }
+
+
+ /**
+ * Return true if text <code>attribute</code> is set in this
+ * <code>Style</code>. An attribute that is set may have a
+ * value of <i>on</i> or <i>off</i>.
+ *
+ * @param attribute The attribute to check ({@link #BOLD},
+ * {@link #ITALIC}, etc.).
+ *
+ * @return true if text <code>attribute</code> is set in this
+ * <code>Style</code>, false otherwise.
+ */
+ public boolean isSet(int attribute) {
+ return (!((mask & attribute) == 0));
+ }
+
+
+ /**
+ * Return true if the <code>attribute</code> is set to <i>on</i>
+ *
+ * @param attribute Attribute to check ({@link #BOLD},
+ * {@link #ITALIC}, etc.)
+ *
+ * @return true if <code>attribute</code> is set to <i>on</i>,
+ * otherwise false.
+ */
+ public boolean getAttribute(int attribute) {
+ if ((mask & attribute) == 0)
+ return false;
+ return (!((values & attribute) == 0));
+ }
+
+
+ /**
+ * Return the font size for this <code>Style</code>.
+ *
+ * @return The font size in points
+ */
+ public int getFontSize() {
+ return sizeInPoints;
+ }
+
+
+ /**
+ * Return the name of the font for this <code>Style</code>.
+ *
+ * @return Name of font, or null if no font is specified by
+ * this <code>Style</code>.
+ */
+ public String getFontName() {
+ return fontName;
+ }
+
+
+ /**
+ * Return the font <code>Color</code> for this <code>Style</code>.
+ * Can be null if none was specified.
+ *
+ * @return <code>Color</code> value for this <code>Style</code>.
+ * Can be null.
+ */
+ public Color getFontColor() {
+ return fontColor;
+ }
+
+
+ /**
+ * Return the background <code>Color</code> for this
+ * <code>Style</code>. Can be null if none was specified.
+ *
+ * @return Background <code>Color</code> value for this
+ * <code>Style</code>. Can be null.
+ */
+ public Color getBackgroundColor() {
+ return bgColor;
+ }
+
+
+ /**
+ * Set the font and/or background <code>Color</code> for this
+ * <code>Style</code>.
+ *
+ * @param fontColor The font <code>Color</code> to set.
+ * @param backgroundColor The background <code>Color</code> to set.
+ */
+ public void setColors(Color fontColor, Color backgroundColor) {
+ if (fontColor != null)
+ this.fontColor = fontColor;
+ if (backgroundColor != null)
+ this.bgColor = backgroundColor;
+ }
+
+
+ /**
+ * Return a <code>Style</code> object corresponding to this one,
+ * but with all of the inherited information from parent
+ * <code>Style</code> 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 The <code>StyleCatalog</code> in which to look up
+ * ancestors.
+ */
+ public Style getResolved() {
+ // Create a new object to return, which is a clone of this one.
+ TextStyle resolved = null;
+ try {
+ resolved = (TextStyle)this.clone();
+ } catch (Exception e) {
+ Debug.log(Debug.ERROR, "Can't clone", e);
+ }
+
+ // Look up the parentStyle. (If there is no style catalog
+ // specified, we can't do any lookups.)
+ TextStyle parentStyle = null;
+ if (sc != null) {
+ if (parent != null) {
+ parentStyle = (TextStyle)sc.lookup(parent, family, null,
+ this.getClass());
+ if (parentStyle == null)
+ Debug.log(Debug.ERROR, "parent style lookup of "
+ + parent + " failed!");
+ else
+ parentStyle = (TextStyle)parentStyle.getResolved();
+
+ } else if (!name.equals("DEFAULT_STYLE")) {
+ parentStyle = (TextStyle)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 = (TextStyle)parentStyle.getResolved();
+
+ if ((sizeInPoints == 0) && (parentStyle.sizeInPoints != 0))
+ resolved.sizeInPoints = parentStyle.sizeInPoints;
+ if ((fontName == null) && (parentStyle.fontName != null))
+ resolved.fontName = parentStyle.fontName;
+ if ((fontColor == null) && (parentStyle.fontColor != null))
+ resolved.fontColor = parentStyle.fontColor;
+ if ((bgColor == null) && (parentStyle.bgColor != null))
+ resolved.bgColor = parentStyle.bgColor;
+ for (int m = BOLD; m <= SUBSCRIPT; m = m << 1) {
+ if (((mask & m) == 0) && ((parentStyle.mask & m) != 0)) {
+ resolved.mask |= m;
+ resolved.values |= (parentStyle.mask & m);
+ }
+ }
+
+ }
+ return resolved;
+ }
+
+
+ /**
+ * Set one or more text attributes to <i>on</i>.
+ *
+ * @param flags Flag values to set <i>on</i>.
+ */
+ private void turnAttributesOn(int flags) {
+ mask |= flags;
+ values |= flags;
+ }
+
+
+ /**
+ * Set one or more text attributes to <i>off</i>.
+ *
+ * @param flags The flag values to set <i>off</i>.
+ */
+ private void turnAttributesOff(int flags) {
+ mask |= flags;
+ values &= ~flags;
+ }
+
+
+ /**
+ * Private function to return the value as an element in
+ * a Comma Separated Value (CSV) format.
+ *
+ * @param 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("Font") + toCSV("Size")
+ + toCSV("Bold") + toCSV("Italic") + toCSV("Underline")
+ + toCSV("Strikethru") + toCSV("Superscript") + toLastCSV("Subscript"));
+ }
+
+
+ /**
+ * Dump this <code>Style</code> as a Comma Separated Value (CSV) line.
+ */
+ public void dumpCSV() {
+ String attributes = "";
+ for (int bitVal = 0x01; bitVal <= 0x20; bitVal = bitVal << 1) {
+ if ((bitVal & mask) != 0) {
+ attributes += toCSV(((bitVal & values) != 0) ? "yes" : "no");
+ } else attributes += toCSV(null); // unspecified
+ }
+ System.out.println(toCSV(name) + toCSV(family) + toCSV(parent)
+ + toCSV(fontName) + toCSV("" + sizeInPoints) + attributes + toLastCSV(null));
+ }
+
+
+ /**
+ * Create a new <code>Node</code> in the <code>Document</code>, and
+ * write this <code>Style</code> to it.
+ *
+ * @param parentDoc Parent <code>Document</code> of the
+ * <code>Node</code> to create.
+ * @param name Name to use for the new <code>Node</code> (e.g.
+ * <i>style:style</i>)
+ *
+ * @return Created <code>Node</code>.
+ */
+ public Node createNode(org.w3c.dom.Document parentDoc, String name) {
+ Element node = parentDoc.createElement(name);
+ writeAttributes(node);
+ return node;
+ }
+
+
+ /**
+ * Return true if <code>style</code> specifies as much or less
+ * than this <code>Style</code>, and nothing it specifies
+ * contradicts this <code>Style</code>.
+ *
+ * @param style The <code>Style</code> to check.
+ *
+ * @return true if <code>style</code> is a subset, false
+ * otherwise.
+ */
+ public boolean isSubset(Style style) {
+ if (style.getClass() != this.getClass())
+ return false;
+ TextStyle tStyle = (TextStyle)style;
+
+ if (tStyle.values != values)
+ return false;
+
+ if (tStyle.sizeInPoints != 0) {
+ if (sizeInPoints != tStyle.sizeInPoints)
+ return false;
+ }
+
+ if (tStyle.fontName != null) {
+ if (fontName == null)
+ return false;
+ if (!fontName.equals(tStyle.fontName))
+ return false;
+ }
+
+ if (tStyle.fontColor != null) {
+ if (fontColor == null)
+ return false;
+ if (!fontColor.equals(tStyle.fontColor))
+ return false;
+ }
+
+ if (tStyle.bgColor != null) {
+ if (bgColor == null)
+ return false;
+ if (!bgColor.equals(tStyle.bgColor))
+ return false;
+ }
+
+ return true;
+ }
+
+
+ /**
+ * Write this <code>Style</code> object's attributes to a
+ * <code>Node</code> in the <code>Document</code>.
+ *
+ * @param node The <code>Node</code> to add <code>Style</code>
+ * attributes.
+ */
+ public void writeAttributes(Element node) {
+
+ if ((mask & BOLD) != 0)
+ if ((values & BOLD) != 0)
+ node.setAttribute("fo:font-weight", "bold");
+
+ if ((mask & ITALIC) != 0)
+ if ((values & ITALIC) != 0)
+ node.setAttribute("fo:font-style", "italic");
+
+ if ((mask & UNDERLINE) != 0)
+ if ((values & UNDERLINE) != 0)
+ node.setAttribute("style:text-underline", "single");
+
+ if ((mask & STRIKETHRU) != 0)
+ if ((values & STRIKETHRU) != 0)
+ node.setAttribute("style:text-crossing-out", "single-line");
+
+ if ((mask & SUPERSCRIPT) != 0)
+ if ((values & SUPERSCRIPT) != 0)
+ node.setAttribute("style:text-position", "super 58%");
+
+ if ((mask & SUBSCRIPT) != 0)
+ if ((values & SUBSCRIPT) != 0)
+ node.setAttribute("style:text-position", "sub 58%");
+
+ if (sizeInPoints != 0) {
+ Integer fs = new Integer(sizeInPoints);
+ node.setAttribute("fo:font-size", fs.toString() + "pt");
+ }
+
+ if (fontName != null)
+ node.setAttribute("style:font-name", fontName);
+
+ if (fontColor != null)
+ node.setAttribute("fo:color", buildColorString(fontColor));
+
+ if (bgColor != null)
+ node.setAttribute("style:text-background-color",
+ buildColorString(bgColor));
+ }
+
+
+ /**
+ * Given a <code>Color</code>, return a string of the form
+ * <i>#rrggbb</i>.
+ *
+ * @param c The <code>Color</code> value.
+ *
+ * @return The <code>Color</code> value in the form <i>#rrggbb</i>.
+ */
+ private String buildColorString(Color c) {
+ int v[] = new int[3];
+ v[0] = c.getRed();
+ v[1] = c.getGreen();
+ v[2] = c.getBlue();
+ String colorString = new String("#");
+ for (int i = 0; i <= 2; i++) {
+ String xx = Integer.toHexString(v[i]);
+ if (xx.length() < 2)
+ xx = "0" + xx;
+ colorString += xx;
+ }
+ return colorString;
+ }
+
+
+ private static String[] ignored = {
+ "style:text-autospace", "style:text-underline-color",
+ "fo:margin-left", "fo:margin-right", "fo:text-indent",
+ "fo:margin-top", "fo:margin-bottom", "text:line-number",
+ "text:number-lines", "style:country-asian",
+ "style:font-size-asian", "style:font-name-complex",
+ "style:language-complex", "style:country-complex",
+ "style:font-size-complex", "style:punctuation-wrap",
+ "fo:language", "fo:country",
+ "style:font-name-asian", "style:language-asian",
+ "style:line-break", "fo:keep-with-next"
+ };
+
+
+ /*
+ * This code checks whether an attribute is one that we
+ * intentionally ignore.
+ *
+ * @param attribute The attribute to check.
+ *
+ * @return true if <code>attribute</code> can be ignored,
+ * otherwise false.
+ */
+ private boolean isIgnored(String attribute) {
+ for (int i = 0; i < ignored.length; i++) {
+ if (ignored[i].equals(attribute))
+ return true;
+ }
+ return false;
+ }
+}
+
diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/package.html b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/package.html
new file mode 100644
index 000000000000..9d4d0f5bd5cf
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/package.html
@@ -0,0 +1,41 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<!--
+ #*************************************************************************
+ #
+ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+
+ Copyright 2000, 2010 Oracle and/or its affiliates.
+
+ OpenOffice.org - a multi-platform office productivity suite
+
+ This file is part of OpenOffice.org.
+
+ OpenOffice.org is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License version 3
+ only, as published by the Free Software Foundation.
+
+ OpenOffice.org is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License version 3 for more details
+ (a copy is included in the LICENSE file that accompanied this code).
+
+ You should have received a copy of the GNU Lesser General Public License
+ version 3 along with OpenOffice.org. If not, see
+ <http://www.openoffice.org/license.html>
+ for a copy of the LGPLv3 License.
+
+ #*************************************************************************
+ -->
+<html>
+<head>
+<title>org.openoffice.xmerge.util package</title>
+</head>
+
+<body bgcolor="white">
+
+<p><code>Document</code> and <code>PluginFactory</code> implementations
+for XML based formats.
+
+</body>
+</html>
diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/BookSettings.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/BookSettings.java
new file mode 100644
index 000000000000..9c1ae2768524
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/BookSettings.java
@@ -0,0 +1,228 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxc;
+
+import java.util.Vector;
+import java.util.Enumeration;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.NodeList;
+import org.w3c.dom.Node;
+import org.w3c.dom.Element;
+
+import org.openoffice.xmerge.converter.xml.OfficeConstants;
+import org.openoffice.xmerge.util.Debug;
+import org.openoffice.xmerge.util.XmlUtil;
+
+/**
+ * This is a class representing the different attributes for a worksheet
+ * contained in settings.xml.
+ *
+ * @author Martin Maher
+ */
+public class BookSettings implements OfficeConstants {
+
+ /** A w3c <code>Document</code>. */
+ private org.w3c.dom.Document settings = null;
+
+ private boolean hasColumnRowHeaders = true;
+ private String activeSheet = new String();
+ private Vector worksheetSettings = new Vector();
+
+ /**
+ * Default Constructor for a <code>BookSettings</code>
+ *
+ * @param dimension if it's a row the height, a column the width
+ * @param repeated
+ */
+ public BookSettings(Node root) {
+ readNode(root);
+ }
+
+ /**
+ * Default Constructor for a <code>BookSettings</code>
+ *
+ * @param worksheetSettings if it's a row the height, a column the width
+ */
+ public BookSettings(Vector worksheetSettings) {
+ this.worksheetSettings = worksheetSettings;
+ }
+
+ /**
+ *
+ */
+ public void setColumnRowHeaders(boolean hasColumnRowHeaders) {
+ this.hasColumnRowHeaders = hasColumnRowHeaders;
+ }
+
+ /**
+ *
+ */
+ public boolean hasColumnRowHeaders() {
+ return hasColumnRowHeaders;
+ }
+
+ /**
+ * Gets the <code>Vector</code> of <code>SheetSettings</code>
+ *
+ * @return <code>Vector</code> of <code>SheetSettings</code>
+ */
+ public Vector getSheetSettings() {
+ return worksheetSettings;
+ }
+
+ /**
+ * Gets the active sheet name
+ *
+ * @return the active sheet name
+ */
+ public String getActiveSheet() {
+
+ return activeSheet;
+ }
+
+ /**
+ * Sets the active sheet name
+ *
+ * @param activeSheet the active sheet name
+ */
+ public void setActiveSheet(String activeSheet) {
+
+ this.activeSheet = activeSheet;
+ }
+
+
+ /**
+ * Adds an XML entry for a particular setting
+ *
+ * @param root the root node at which to add the xml entry
+ * @param attriute the name of the attribute to add
+ * @param type the attribute type (int, short etc)
+ * @param value the value of the attribute
+ */
+ private void addConfigItem(Node root, String attribute, String type, String value) {
+
+ Element configItem = settings.createElement(TAG_CONFIG_ITEM);
+ configItem.setAttribute(ATTRIBUTE_CONFIG_NAME, attribute);
+ configItem.setAttribute(ATTRIBUTE_CONFIG_TYPE, type);
+
+ configItem.appendChild(settings.createTextNode(value));
+
+ root.appendChild(configItem);
+ }
+
+ /**
+ * Writes out a settings.xml entry for this BookSettings object
+ *
+ * @param settings a <code>Document</code> object representing the settings.xml
+ * @param root the root xml node to add to
+ */
+ public void writeNode(org.w3c.dom.Document settings, Node root) {
+
+ this.settings = settings;
+ Element configItemMapNamed = (Element) settings.createElement(TAG_CONFIG_ITEM_MAP_NAMED);
+ configItemMapNamed.setAttribute(ATTRIBUTE_CONFIG_NAME, "Tables");
+ for(Enumeration e = worksheetSettings.elements();e.hasMoreElements();) {
+ SheetSettings s = (SheetSettings) e.nextElement();
+ s.writeNode(settings, configItemMapNamed);
+ }
+ addConfigItem(root, "ActiveTable", "string", activeSheet);
+ String booleanValue = Boolean.toString(hasColumnRowHeaders);
+ addConfigItem(root, "HasColumnRowHeaders", "boolean", booleanValue);
+ root.appendChild(configItemMapNamed);
+ }
+
+ /**
+ * Sets a variable based on a String value read from XML
+ *
+ * @param name xml name of the attribute to set
+ * @param value String value fo the attribute
+ */
+ public void addAttribute(String name, String value) {
+
+ if(name.equals("ActiveTable")) {
+ activeSheet = value;
+ } else if(name.equals("HasColumnRowHeaders")) {
+ Boolean b = Boolean.valueOf(value);
+ hasColumnRowHeaders = b.booleanValue();
+ }
+ }
+
+ /**
+ * Reads document settings from xml and inits SheetSettings variables
+ *
+ * @param root XML Node to read from
+ */
+ public void readNode(Node root) {
+
+ if (root.hasChildNodes()) {
+
+ NodeList nodeList = root.getChildNodes();
+ int len = nodeList.getLength();
+ for (int i = 0; i < len; i++) {
+ Node child = nodeList.item(i);
+
+ if (child.getNodeType() == Node.ELEMENT_NODE) {
+ String nodeName = child.getNodeName();
+
+ if (nodeName.equals(TAG_CONFIG_ITEM)) {
+
+ NamedNodeMap cellAtt = child.getAttributes();
+
+ Node configNameNode =
+ cellAtt.getNamedItem(ATTRIBUTE_CONFIG_NAME);
+
+ String name = configNameNode.getNodeValue();
+ NodeList nodeList2 = child.getChildNodes();
+ int len2 = nodeList2.getLength();
+ String s = "";
+ for (int j = 0; j < len2; j++) {
+ Node child2 = nodeList2.item(j);
+ if (child2.getNodeType() == Node.TEXT_NODE) {
+ s = child2.getNodeValue();
+ }
+ }
+ addAttribute(name, s);
+
+ } else if (nodeName.equals(TAG_CONFIG_ITEM_MAP_NAMED)) {
+
+ readNode(child);
+
+ } else if (nodeName.equals(TAG_CONFIG_ITEM_MAP_ENTRY)) {
+
+ SheetSettings s = new SheetSettings(child);
+ worksheetSettings.add(s);
+
+ } else {
+
+ Debug.log(Debug.TRACE, "<OTHERS " + XmlUtil.getNodeInfo(child) + " />");
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/CellStyle.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/CellStyle.java
new file mode 100644
index 000000000000..2e3e34b6d620
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/CellStyle.java
@@ -0,0 +1,510 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxc;
+
+import java.awt.Color;
+
+import org.w3c.dom.NodeList;
+import org.w3c.dom.Node;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Element;
+
+import org.openoffice.xmerge.converter.xml.Style;
+import org.openoffice.xmerge.converter.xml.StyleCatalog;
+import org.openoffice.xmerge.util.Debug;
+
+/**
+ * Represents a text <code>Style</code> in an OpenOffice document.
+ *
+ * @author Martin Maher
+ */
+public class CellStyle extends Style implements Cloneable {
+
+ private Format fmt = new Format();
+
+ /**
+ * Constructor for use when going from DOM to client device format.
+ *
+ * @param Node The <i>style:style</i> <code>Node</code> containing
+ * the <code>Style</code>. (This <code>Node</code> is
+ * assumed have a <i>family</i> attribute of <i>text</i>).
+ * @param sc The <code>StyleCatalog</code>, which is used for
+ * looking up ancestor <code>Style</code> objects.
+ */
+ public CellStyle(Node node, StyleCatalog sc) {
+ super(node, sc);
+
+ // Run through the attributes of this node, saving
+ // the ones we're interested in.
+ NamedNodeMap attrNodes = node.getAttributes();
+ if (attrNodes != null) {
+ int len = attrNodes.getLength();
+ for (int i = 0; i < len; i++) {
+ Node attr = attrNodes.item(i);
+ handleAttribute(attr.getNodeName(), attr.getNodeValue());
+ }
+ }
+
+ // 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 name = child.getNodeName();
+ if (name.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);
+ handleAttribute(attr.getNodeName(),
+ attr.getNodeValue());
+ }
+ }
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Constructor for use when going from client device format to DOM
+ *
+ * @param name Name of cell <code>Style</code>. Can be null.
+ * @param family Family of text <code>Style</code> (usually
+ * <i>text</i>). Can be null.
+ * @param parent Name of parent text <code>Style</code>, or null
+ * for none.
+ * @param fmt size in points.
+ * @param sc The <code>StyleCatalog</code>, which is used for
+ * looking up ancestor <code>Style</code> objects.
+ */
+ public CellStyle(String name, String family, String parent,Format fmt, StyleCatalog sc) {
+ super(name, family, parent, sc);
+ this.fmt = fmt;
+ }
+
+ /**
+ * Returns the <code>Format</code> object for this particular style
+ *
+ * @return the <code>Format</code> object
+ */
+ public Format getFormat() {
+ return fmt;
+ }
+
+ /**
+ * Parse a color specification of the form <i>#rrggbb</i>
+ *
+ * @param value <code>Color</code> specification to parse.
+ *
+ * @return The <code>Color</code> associated the value.
+ */
+ private Color parseColorString(String value) {
+ // Assume color value is of form #rrggbb
+ String r = value.substring(1, 3);
+ String g = value.substring(3, 5);
+ String b = value.substring(5, 7);
+ int red = 0;
+ int green = 0;
+ int blue = 0;
+ try {
+ red = Integer.parseInt(r, 16);
+ green = Integer.parseInt(g, 16);
+ blue = Integer.parseInt(b, 16);
+ } catch (NumberFormatException e) {
+ Debug.log(Debug.ERROR, "Problem parsing a color string", e);
+ }
+ return new Color(red, green, blue, 0);
+ }
+
+
+ /**
+ * Set an attribute.
+ *
+ * @param attr The attribute to set.
+ * @param value The attribute value to set.
+ */
+ private void handleAttribute(String attr, String value) {
+
+ if (attr.equals("fo:font-weight")) {
+ fmt.setAttribute(Format.BOLD, value.equals("bold"));
+ }
+
+ else if (attr.equals("fo:font-style")) {
+ if (value.equals("italic") || value.equals("oblique"))
+ fmt.setAttribute(Format.ITALIC, true);
+ else if (value.equals("normal"))
+ fmt.setAttribute(Format.ITALIC, false);
+ }
+
+ else if (attr.equals("style:text-underline")) {
+ fmt.setAttribute(Format.UNDERLINE, !value.equals("none"));
+ }
+
+ else if (attr.equals("style:text-crossing-out")) {
+ fmt.setAttribute(Format.STRIKETHRU, !value.equals("none"));
+ }
+
+ else if (attr.equals("style:text-position")) {
+ if (value.startsWith("super "))
+ fmt.setAttribute(Format.SUPERSCRIPT, true);
+ else if (value.startsWith("sub "))
+ fmt.setAttribute(Format.SUBSCRIPT, true);
+ else if (value.startsWith("0% "))
+ fmt.setAttribute(Format.SUPERSCRIPT | Format.SUBSCRIPT, false);
+ else {
+ String firstPart = value.substring(0, value.indexOf(" "));
+ if (firstPart.endsWith("%")) {
+ firstPart = firstPart.substring(0, value.indexOf("%"));
+ int amount;
+ try {
+ amount = Integer.parseInt(firstPart);
+ } catch (NumberFormatException e) {
+ amount = 0;
+ Debug.log(Debug.ERROR, "Problem with style:text-position tag", e);
+ }
+ if (amount < 0) fmt.setAttribute(Format.SUBSCRIPT, true);
+ else if (amount > 0) fmt.setAttribute(Format.SUPERSCRIPT, false);
+ }
+ }
+ }
+
+ else if (attr.equals("fo:font-size")) {
+ if (value.endsWith("pt")) {
+ String num = value.substring(0, value.length() - 2);
+ fmt.setFontSize(Integer.parseInt(num));
+ }
+ }
+
+ else if (attr.equals("style:font-name"))
+ fmt.setFontName(value);
+
+ else if (attr.equals("fo:color"))
+ fmt.setForeground(parseColorString(value));
+
+ else if (attr.equals("fo:background-color"))
+ fmt.setBackground(parseColorString(value));
+
+ else if (attr.equals("fo:text-align")) {
+ if(value.equals("center")) {
+ fmt.setAlign(Format.CENTER_ALIGN);
+ } else if(value.equals("end")) {
+ fmt.setAlign(Format.RIGHT_ALIGN);
+ } else if(value.equals("start")) {
+ fmt.setAlign(Format.LEFT_ALIGN);
+ }
+ }
+
+ else if (attr.equals("fo:vertical-align")) {
+ if(value.equals("top")) {
+ fmt.setVertAlign(Format.TOP_ALIGN);
+ } else if(value.equals("middle")) {
+ fmt.setVertAlign(Format.MIDDLE_ALIGN);
+ } else if(value.equals("bottom")) {
+ fmt.setVertAlign(Format.BOTTOM_ALIGN);
+ }
+ }
+
+ else if (attr.equals("fo:border")) {
+ fmt.setAttribute(Format.TOP_BORDER, !value.equals("none"));
+ fmt.setAttribute(Format.BOTTOM_BORDER, !value.equals("none"));
+ fmt.setAttribute(Format.LEFT_BORDER, !value.equals("none"));
+ fmt.setAttribute(Format.RIGHT_BORDER, !value.equals("none"));
+ }
+ else if (attr.equals("fo:border-top")) {
+ fmt.setAttribute(Format.TOP_BORDER, !value.equals("none"));
+ }
+ else if (attr.equals("fo:border-bottom")) {
+ fmt.setAttribute(Format.BOTTOM_BORDER, !value.equals("none"));
+ }
+ else if (attr.equals("fo:border-left")) {
+ fmt.setAttribute(Format.LEFT_BORDER, !value.equals("none"));
+ }
+ else if (attr.equals("fo:border-right")) {
+ fmt.setAttribute(Format.RIGHT_BORDER, !value.equals("none"));
+ }
+ else if (attr.equals("fo:wrap-option")) {
+ fmt.setAttribute(Format.WORD_WRAP, value.equals("wrap"));
+ }
+
+ else if (isIgnored(attr)) {}
+
+ else {
+ Debug.log(Debug.INFO, "CellStyle Unhandled: " + attr + "=" + value);
+ }
+ }
+
+
+ /**
+ * Return a <code>Style</code> object corresponding to this one,
+ * but with all of the inherited information from parent
+ * <code>Style</code> 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 The <code>StyleCatalog</code> in which to look up
+ * ancestors.
+ */
+ public Style getResolved() {
+ // Create a new object to return, which is a clone of this one.
+ CellStyle resolved = null;
+ try {
+ resolved = (CellStyle)this.clone();
+ } catch (Exception e) {
+ Debug.log(Debug.ERROR, "Can't clone", e);
+ }
+
+ // Look up the parentStyle. (If there is no style catalog
+ // specified, we can't do any lookups.)
+ CellStyle parentStyle = null;
+ if (sc != null) {
+ if (parent != null) {
+ parentStyle = (CellStyle)sc.lookup(parent, family, null,
+ this.getClass());
+ if (parentStyle == null)
+ Debug.log(Debug.ERROR, "parent style lookup of "
+ + parent + " failed!");
+ else
+ parentStyle = (CellStyle)parentStyle.getResolved();
+
+ } else if (!name.equals("DEFAULT_STYLE")) {
+ parentStyle = (CellStyle)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 = (CellStyle)parentStyle.getResolved();
+ Format parentFormat = parentStyle.getFormat();
+ Format resolvedFormat = resolved.getFormat();
+
+ if ((fmt.getAlign() == Format.LEFT_ALIGN) && (parentFormat.getAlign() != Format.LEFT_ALIGN))
+ resolvedFormat.setAlign(parentFormat.getAlign());
+ if ((fmt.getVertAlign() == Format.BOTTOM_ALIGN) && (parentFormat.getVertAlign() != Format.BOTTOM_ALIGN))
+ resolvedFormat.setVertAlign(parentFormat.getVertAlign());
+ if ((fmt.getFontSize() == 0) && (parentFormat.getFontSize() != 0))
+ resolvedFormat.setFontSize(parentFormat.getFontSize());
+ if ((fmt.getFontName() == null) && (parentFormat.getFontName() != null))
+ resolvedFormat.setFontName(parentFormat.getFontName());
+ if ((fmt.getForeground() == null) && (parentFormat.getForeground() != null))
+ resolvedFormat.setForeground(parentFormat.getForeground());
+ if ((fmt.getBackground() == null) && (parentFormat.getBackground() != null))
+ resolvedFormat.setBackground(parentFormat.getBackground());
+ for (int m = Format.BOLD; m <= Format.SUBSCRIPT; m = m << 1) {
+ if ((fmt.getAttribute(m)) && (parentFormat.getAttribute(m))) {
+ resolvedFormat.setAttribute(m, parentFormat.getAttribute(m));
+ }
+ }
+
+ }
+ return resolved;
+ }
+
+
+ /**
+ * Create a new <code>Node</code> in the <code>Document</code>, and
+ * write this <code>Style</code> to it.
+ *
+ * @param parentDoc Parent <code>Document</code> of the
+ * <code>Node</code> to create.
+ * @param name Name to use for the new <code>Node</code> (e.g.
+ * <i>style:style</i>)
+ *
+ * @return Created <code>Node</code>.
+ */
+ public Node createNode(org.w3c.dom.Document parentDoc, String name) {
+ Element node = parentDoc.createElement(name);
+ writeAttributes(node);
+ return node;
+ }
+
+
+ /**
+ * Return true if <code>style</code> specifies as much or less
+ * than this <code>Style</code>, and nothing it specifies
+ * contradicts this <code>Style</code>.
+ *
+ * @param style The <code>Style</code> to check.
+ *
+ * @return true if <code>style</code> is a subset, false
+ * otherwise.
+ */
+ public boolean isSubset(Style style) {
+ if (style.getClass() != this.getClass())
+ return false;
+ CellStyle tStyle = (CellStyle)style;
+
+ Format rhs = tStyle.getFormat();
+
+ if(!fmt.isSubset(rhs))
+ return false;
+
+ return true;
+ }
+
+
+ /**
+ * Write this <code>Style</code> object's attributes to a
+ * <code>Node</code> in the <code>Document</code>.
+ *
+ * @param node The <code>Node</code> to add <code>Style</code>
+ * attributes.
+ */
+ public void writeAttributes(Element node) {
+
+ if (fmt.getAlign()==Format.RIGHT_ALIGN)
+ node.setAttribute("fo:text-align", "end");
+
+ if (fmt.getAlign()==Format.LEFT_ALIGN)
+ node.setAttribute("fo:text-align", "start");
+
+ if (fmt.getAlign()==Format.CENTER_ALIGN)
+ node.setAttribute("fo:text-align", "center");
+
+ if (fmt.getVertAlign()==Format.TOP_ALIGN)
+ node.setAttribute("fo:vertical-align", "top");
+
+ if (fmt.getVertAlign()==Format.MIDDLE_ALIGN)
+ node.setAttribute("fo:vertical-align", "middle");
+
+ if (fmt.getVertAlign()==Format.BOTTOM_ALIGN)
+ node.setAttribute("fo:vertical-align", "bottom");
+
+ if (fmt.getAttribute(Format.BOLD))
+ node.setAttribute("fo:font-weight", "bold");
+
+ if (fmt.getAttribute(Format.ITALIC))
+ node.setAttribute("fo:font-style", "italic");
+
+ if (fmt.getAttribute(Format.UNDERLINE))
+ node.setAttribute("style:text-underline", "single");
+
+ if (fmt.getAttribute(Format.STRIKETHRU))
+ node.setAttribute("style:text-crossing-out", "single-line");
+
+ if (fmt.getAttribute(Format.SUPERSCRIPT))
+ node.setAttribute("style:text-position", "super 58%");
+
+ if (fmt.getAttribute(Format.SUBSCRIPT))
+ node.setAttribute("style:text-position", "sub 58%");
+
+ if (fmt.getFontSize() != 0) {
+ Integer fs = new Integer(fmt.getFontSize());
+ node.setAttribute("fo:font-size", fs.toString() + "pt");
+ }
+
+ if (fmt.getFontName() != null)
+ node.setAttribute("style:font-name", fmt.getFontName());
+
+ if (fmt.getForeground() != null)
+ node.setAttribute("fo:color", buildColorString(fmt.getForeground()));
+
+ if (fmt.getBackground() != null)
+ node.setAttribute("fo:background-color",
+ buildColorString(fmt.getBackground()));
+
+ if (fmt.getAttribute(Format.TOP_BORDER))
+ node.setAttribute("fo:border-top", "0.0008inch solid #000000");
+
+ if (fmt.getAttribute(Format.BOTTOM_BORDER))
+ node.setAttribute("fo:border-bottom", "0.0008inch solid #000000");
+
+ if (fmt.getAttribute(Format.RIGHT_BORDER))
+ node.setAttribute("fo:border-right", "0.0008inch solid #000000");
+
+ if (fmt.getAttribute(Format.LEFT_BORDER))
+ node.setAttribute("fo:border-left", "0.0008inch solid #000000");
+
+ if (fmt.getAttribute(Format.WORD_WRAP))
+ node.setAttribute("fo:wrap-option", "wrap");
+
+ }
+
+
+ /**
+ * Given a <code>Color</code>, return a string of the form
+ * <i>#rrggbb</i>.
+ *
+ * @param c The <code>Color</code> value.
+ *
+ * @return The <code>Color</code> value in the form <i>#rrggbb</i>.
+ */
+ private String buildColorString(Color c) {
+ int v[] = new int[3];
+ v[0] = c.getRed();
+ v[1] = c.getGreen();
+ v[2] = c.getBlue();
+ String colorString = new String("#");
+ for (int i = 0; i <= 2; i++) {
+ String xx = Integer.toHexString(v[i]);
+ if (xx.length() < 2)
+ xx = "0" + xx;
+ colorString += xx;
+ }
+ return colorString;
+ }
+
+
+ private static String[] ignored = {
+ "style:text-autospace", "style:text-underline-color",
+ "fo:margin-left", "fo:margin-right", "fo:text-indent",
+ "fo:margin-top", "fo:margin-bottom", "text:line-number",
+ "text:number-lines", "style:country-asian",
+ "style:font-size-asian", "style:font-name-complex",
+ "style:language-complex", "style:country-complex",
+ "style:font-size-complex", "style:punctuation-wrap",
+ "fo:language", "fo:country",
+ "style:font-name-asian", "style:language-asian",
+ "style:line-break", "fo:keep-with-next"
+ };
+
+
+ /*
+ * This code checks whether an attribute is one that we
+ * intentionally ignore.
+ *
+ * @param attribute The attribute to check.
+ *
+ * @return true if <code>attribute</code> can be ignored,
+ * otherwise false.
+ */
+ private boolean isIgnored(String attribute) {
+ for (int i = 0; i < ignored.length; i++) {
+ if (ignored[i].equals(attribute))
+ return true;
+ }
+ return false;
+ }
+}
+
diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/ColumnRowInfo.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/ColumnRowInfo.java
new file mode 100644
index 000000000000..14c1dbfc8e77
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/ColumnRowInfo.java
@@ -0,0 +1,195 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxc;
+
+/**
+ * This is a class to define a table-column structure. This can then be
+ * used by plugins to write or read their own column types.
+ *
+ * @author Martin Maher
+ */
+public class ColumnRowInfo {
+
+ final public static int COLUMN = 0x01;
+ final public static int ROW = 0x02;
+
+ final private static int DEFAULTROWSIZE_MIN = 250;
+ final private static int DEFAULTROWSIZE_MAX = 260;
+
+ private int type;
+ private int dimension = 0;
+ private int repeated = 1;
+ private boolean userDefined = true;
+ private Format fmt = new Format();
+
+ /**
+ * Constructor for a <code>ColumnRowInfo</code>
+ *
+ * @param dimension if it's a row the height, a column the width
+ * @param repeated
+ */
+ public ColumnRowInfo(int type) {
+
+ this.type = type;
+ }
+
+ /**
+ * Constructor for a <code>ColumnRowInfo</code>
+ *
+ * @param dimension if it's a row the height, a column the width
+ * @param repeated how many times it is repeated
+ * @param type whether Row or column record
+ */
+ public ColumnRowInfo(int dimension, int repeated, int type) {
+
+ this.dimension = dimension;
+ this.repeated = repeated;
+ this.type = type;
+ }
+
+ /**
+ * Constructor that includes userDefined field
+ *
+ * @param userDefined whether the record is manually set
+ */
+ public ColumnRowInfo(int dimension, int repeated, int type, boolean userDefined) {
+
+ this(dimension, repeated, type);
+ this.userDefined = userDefined;
+ }
+
+ /**
+ * sets the definition
+ *
+ * @param newDefinition sets the definition
+ */
+ public void setFormat(Format fmt) {
+
+ this.fmt = fmt;
+ }
+
+ /**
+ * returns Name of the definition
+ *
+ * @return the name which identifies the definition
+ */
+ public Format getFormat() {
+
+ return fmt;
+ }
+
+ /**
+ * returns Name of the definition
+ *
+ * @return the name which identifies the definition
+ */
+ public int getSize() {
+
+ return dimension;
+ }
+
+ /**
+ * sets the definition
+ *
+ * @param newDefinition sets the definition
+ */
+ public void setSize(int dimension) {
+
+ this.dimension = dimension;
+ }
+ /**
+ * Returns the definition itself
+ *
+ * @return the definition
+ */
+ public int getRepeated() {
+
+ return repeated;
+ }
+
+ /**
+ * Returns the base Cell address
+ *
+ * @return the base cell address
+ */
+ public void setRepeated(int repeated) {
+
+ this.repeated = repeated;
+ }
+
+ /**
+ * Returns the definition itself
+ *
+ * @return the definition
+ */
+ public boolean isRow() {
+
+ if(type==ROW)
+ return true;
+ else
+ return false;
+ }
+
+ /**
+ * Returns the base Cell address
+ *
+ * @return the base cell address
+ */
+ public boolean isColumn() {
+
+ if(type==COLUMN)
+ return true;
+ else
+ return false;
+ }
+
+ /**
+ * Test if the row height as been set manually
+ *
+ * @return true if user defined otherwise false
+ */
+ public boolean isUserDefined() {
+
+ return userDefined;
+ }
+
+ /**
+ * Test if the row height is default
+ *
+ * @return true if default otherwise false
+ */
+ public boolean isDefaultSize() {
+
+ if( type==ROW &&
+ dimension>DEFAULTROWSIZE_MIN &&
+ dimension<DEFAULTROWSIZE_MAX)
+ return true;
+ else
+ return false;
+ }
+}
diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/ColumnStyle.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/ColumnStyle.java
new file mode 100644
index 000000000000..76c742b57496
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/ColumnStyle.java
@@ -0,0 +1,300 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxc;
+
+import org.w3c.dom.NodeList;
+import org.w3c.dom.Node;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Element;
+
+import org.openoffice.xmerge.converter.xml.Style;
+import org.openoffice.xmerge.converter.xml.StyleCatalog;
+import org.openoffice.xmerge.util.Debug;
+import org.openoffice.xmerge.util.TwipsConverter;
+
+/**
+ * Represents a text <code>Style</code> in an OpenOffice document.
+ *
+ * @author Martin Maher
+ */
+public class ColumnStyle extends Style implements Cloneable {
+
+ private int colWidth = 0;
+ /**
+ * Constructor for use when going from DOM to client device format.
+ *
+ * @param Node The <i>style:style</i> <code>Node</code> containing
+ * the <code>Style</code>. (This <code>Node</code> is
+ * assumed have a <i>family</i> attribute of <i>text</i>).
+ * @param sc The <code>StyleCatalog</code>, which is used for
+ * looking up ancestor <code>Style</code> objects.
+ */
+ public ColumnStyle(Node node, StyleCatalog sc) {
+ super(node, sc);
+
+ // Run through the attributes of this node, saving
+ // the ones we're interested in.
+ NamedNodeMap attrNodes = node.getAttributes();
+ if (attrNodes != null) {
+ int len = attrNodes.getLength();
+ for (int i = 0; i < len; i++) {
+ Node attr = attrNodes.item(i);
+ handleAttribute(attr.getNodeName(), attr.getNodeValue());
+ }
+ }
+
+ // 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 name = child.getNodeName();
+ if (name.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);
+ handleAttribute(attr.getNodeName(),
+ attr.getNodeValue());
+ }
+ }
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Constructor for use when going from client device format to DOM
+ *
+ * @param name Name of text <code>Style</code>. Can be null.
+ * @param family Family of text <code>Style</code> (usually
+ * <i>text</i>). Can be null.
+ * @param parent Name of parent text <code>Style</code>, or null
+ * for none.
+ * @param mask the width of this column
+ * @param sc The <code>StyleCatalog</code>, which is used for
+ * looking up ancestor <code>Style</code> objects.
+ */
+ public ColumnStyle(String name, String family, String parent,int colWidth, StyleCatalog sc) {
+ super(name, family, parent, sc);
+ this.colWidth = colWidth;
+ }
+
+ /**
+ * Returns the width of this column
+ *
+ * @return the <code>Format</code> object
+ */
+ public int getColWidth() {
+ return colWidth;
+ }
+
+ /**
+ * Sets the width of this column
+ *
+ * @return the <code>Format</code> object
+ */
+ public void setColWidth(int colWidth) {
+
+ this.colWidth = colWidth;
+ }
+
+ /**
+ * Parse a colwidth in the form "1.234cm" to twips
+ *
+ * @param value <code>String</code> specification to parse.
+ *
+ * @return The twips equivalent.
+ */
+ private int parseColWidth(String value) {
+
+ int width = 255; // Default value
+
+ if(value.indexOf("cm")!=-1) {
+ float widthCM = Float.parseFloat(value.substring(0,value.indexOf("c")));
+ width = TwipsConverter.cm2twips(widthCM);
+ } else if(value.indexOf("inch")!=-1) {
+ float widthInch = Float.parseFloat(value.substring(0,value.indexOf("i")));
+ width = TwipsConverter.inches2twips(widthInch);
+ }
+
+ return (width);
+ }
+
+
+ /**
+ * Set an attribute.
+ *
+ * @param attr The attribute to set.
+ * @param value The attribute value to set.
+ */
+ private void handleAttribute(String attr, String value) {
+
+ if (attr.equals("style:column-width")) {
+ colWidth = parseColWidth(value);
+ }
+ else {
+ Debug.log(Debug.INFO, "ColumnStyle Unhandled: " + attr + "=" + value);
+ }
+ }
+
+
+ /**
+ * Return a <code>Style</code> object corresponding to this one,
+ * but with all of the inherited information from parent
+ * <code>Style</code> 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 The <code>StyleCatalog</code> in which to look up
+ * ancestors.
+ */
+ public Style getResolved() {
+ // Create a new object to return, which is a clone of this one.
+ ColumnStyle resolved = null;
+ try {
+ resolved = (ColumnStyle)this.clone();
+ } catch (Exception e) {
+ Debug.log(Debug.ERROR, "Can't clone", e);
+ }
+
+ // Look up the parentStyle. (If there is no style catalog
+ // specified, we can't do any lookups.)
+ ColumnStyle parentStyle = null;
+ if (sc != null) {
+ if (parent != null) {
+ parentStyle = (ColumnStyle)sc.lookup(parent, family, null,
+ this.getClass());
+ if (parentStyle == null)
+ Debug.log(Debug.ERROR, "parent style lookup of "
+ + parent + " failed!");
+ else
+ parentStyle = (ColumnStyle)parentStyle.getResolved();
+
+ } else if (!name.equals("DEFAULT_STYLE")) {
+ parentStyle = (ColumnStyle)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 = (ColumnStyle)parentStyle.getResolved();
+
+ if ((colWidth == 0) && (parentStyle.getColWidth() != 0))
+ resolved.setColWidth(parentStyle.getColWidth());
+ }
+ return resolved;
+ }
+
+
+ /**
+ * Create a new <code>Node</code> in the <code>Document</code>, and
+ * write this <code>Style</code> to it.
+ *
+ * @param parentDoc Parent <code>Document</code> of the
+ * <code>Node</code> to create.
+ * @param name Name to use for the new <code>Node</code> (e.g.
+ * <i>style:style</i>)
+ *
+ * @return Created <code>Node</code>.
+ */
+ public Node createNode(org.w3c.dom.Document parentDoc, String name) {
+ Element node = parentDoc.createElement(name);
+ writeAttributes(node);
+ return node;
+ }
+
+
+ /**
+ * Return true if <code>style</code> specifies as much or less
+ * than this <code>Style</code>, and nothing it specifies
+ * contradicts this <code>Style</code>.
+ *
+ * @param style The <code>Style</code> to check.
+ *
+ * @return true if <code>style</code> is a subset, false
+ * otherwise.
+ */
+ public boolean isSubset(Style style) {
+ if (style.getClass() != this.getClass())
+ return false;
+ ColumnStyle tStyle = (ColumnStyle)style;
+
+ if(colWidth!=tStyle.getColWidth())
+ return false;
+
+ return true;
+ }
+
+
+ /**
+ * Write this <code>Style</code> object's attributes to a
+ * <code>Node</code> in the <code>Document</code>.
+ *
+ * @param node The <code>Node</code> to add <code>Style</code>
+ * attributes.
+ */
+ public void writeAttributes(Element node) {
+
+ if(colWidth!=0) {
+ String width = TwipsConverter.twips2cm(colWidth) + "cm";
+ node.setAttribute("style:column-width", width);
+ }
+ }
+
+
+ private static String[] ignored = {
+ "fo:break-before", "fo:keep-with-next"
+ };
+
+
+ /*
+ * This code checks whether an attribute is one that we
+ * intentionally ignore.
+ *
+ * @param attribute The attribute to check.
+ *
+ * @return true if <code>attribute</code> can be ignored,
+ * otherwise false.
+ */
+ private boolean isIgnored(String attribute) {
+ for (int i = 0; i < ignored.length; i++) {
+ if (ignored[i].equals(attribute))
+ return true;
+ }
+ return false;
+ }
+}
+
diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/DocumentMergerImpl.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/DocumentMergerImpl.java
new file mode 100644
index 000000000000..2fa5f22303b2
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/DocumentMergerImpl.java
@@ -0,0 +1,198 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxc;
+
+import org.w3c.dom.Node;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+
+import org.openoffice.xmerge.Document;
+import org.openoffice.xmerge.DocumentMerger;
+import org.openoffice.xmerge.MergeException;
+import org.openoffice.xmerge.ConverterCapabilities;
+import org.openoffice.xmerge.converter.xml.OfficeConstants;
+import org.openoffice.xmerge.merger.DiffAlgorithm;
+import org.openoffice.xmerge.merger.Difference;
+import org.openoffice.xmerge.merger.Iterator;
+import org.openoffice.xmerge.merger.NodeMergeAlgorithm;
+import org.openoffice.xmerge.merger.diff.IteratorRowCompare;
+import org.openoffice.xmerge.merger.diff.RowIterator;
+import org.openoffice.xmerge.merger.merge.SheetMerge;
+import org.openoffice.xmerge.merger.merge.PositionBaseRowMerge;
+import org.openoffice.xmerge.merger.MergeAlgorithm;
+import org.openoffice.xmerge.util.XmlUtil;
+import org.openoffice.xmerge.util.Debug;
+
+
+/**
+ * Generic small device implementation of <code>DocumentMerger</code> for
+ * the {@link
+ * org.openoffice.xmerge.converter.xml.sxc.SxcPluginFactory
+ * SxcPluginFactory}. Used with SXC <code>Document</code> objects.</p>
+ */
+public class DocumentMergerImpl implements DocumentMerger {
+
+ private ConverterCapabilities cc_;
+ private org.openoffice.xmerge.Document orig = null;
+
+ /**
+ * Constructor
+ *
+ * @param doc The original &quot;Office&quot; <code>Document</code>
+ * to merge.
+ * @param cc The <code>ConverterCapabilities</code>.
+ */
+ public DocumentMergerImpl(org.openoffice.xmerge.Document doc, ConverterCapabilities cc) {
+ cc_ = cc;
+ this.orig = doc;
+ }
+
+ public void merge(Document modifiedDoc) throws MergeException {
+
+ SxcDocument sdoc1 = (SxcDocument)orig;
+ SxcDocument sdoc2 = (SxcDocument)modifiedDoc;
+
+ org.w3c.dom.Document doc1 = sdoc1.getContentDOM();
+ org.w3c.dom.Document doc2 = sdoc2.getContentDOM();
+
+ Element elem1 = doc1.getDocumentElement();
+ Element elem2 = doc2.getDocumentElement();
+
+ // get table name
+ NodeList workSheetList1 =
+ elem1.getElementsByTagName(OfficeConstants.TAG_TABLE);
+ NodeList workSheetList2 =
+ elem2.getElementsByTagName(OfficeConstants.TAG_TABLE);
+
+ int numOfWorkSheet = workSheetList1.getLength();
+
+ for (int i=0; i < numOfWorkSheet; i++) {
+ Node workSheet = workSheetList1.item(i);
+
+ // try to match the workSheet
+ Node matchingWorkSheet = matchWorkSheet(workSheet, workSheetList2);
+
+ if (matchingWorkSheet != null) {
+
+ // need to put it into a row Iterator
+ // use a straight comparsion algorithm then do a merge on it
+ Iterator i1 = new RowIterator(cc_, workSheet);
+ Iterator i2 = new RowIterator(cc_, matchingWorkSheet);
+
+ // find out the diff
+ DiffAlgorithm diffAlgo = new IteratorRowCompare();
+
+ // find out the paragrah level diffs
+ Difference[] diffResult = diffAlgo.computeDiffs(i1, i2);
+
+ if (Debug.isFlagSet(Debug.INFO)) {
+ Debug.log(Debug.INFO, "Diff Result: ");
+
+ for (int j = 0; j < diffResult.length; j++) {
+ Debug.log(Debug.INFO, diffResult[j].debug());
+ }
+ }
+
+ // merge back the result
+ NodeMergeAlgorithm rowMerger = new PositionBaseRowMerge(cc_);
+ MergeAlgorithm merger = new SheetMerge(cc_, rowMerger);
+
+ Iterator result = null;
+
+ merger.applyDifference(i1, i2, diffResult);
+ }
+ }
+
+ numOfWorkSheet = workSheetList2.getLength();
+
+ // for those workSheet from target don't have a matching one
+ // in the original workSheet list, we add it
+
+ // find out the office body node first
+ NodeList officeBodyList =
+ elem1.getElementsByTagName(OfficeConstants.TAG_OFFICE_BODY);
+
+ Node officeBody = officeBodyList.item(0);
+
+ // for each WorkSheets, try to see whether we have it or not
+ for (int j=0; j < numOfWorkSheet; j++) {
+ Node workSheet= workSheetList2.item(j);
+
+ // try to match the workSheet
+ //
+ Node matchingWorkSheet = matchWorkSheet(workSheet, workSheetList1);
+
+ // add the new WorkSheet to the original document iff match not
+ // found
+ //
+ if (matchingWorkSheet == null) {
+ Node cloneNode = XmlUtil.deepClone(officeBody, workSheet);
+ officeBody.appendChild(cloneNode);
+ }
+ }
+ }
+
+ /**
+ * Try to find a WorkSheet from the modified WorkSheetList that
+ * has a matching table name from the original WorkSheet.
+ *
+ * @param orgSheet The original WorkSheet.
+ * @param modSheetList The modified WorkSheet.
+ *
+ * @return The Node in modSheetList that matches the orgSheet.
+ */
+ private Node matchWorkSheet(Node orgSheet, NodeList modSheetList) {
+
+ Node matchSheet = null;
+
+ String orgTableName = ((Element)orgSheet).getAttribute(
+ OfficeConstants.ATTRIBUTE_TABLE_NAME);
+
+ if (orgTableName == null)
+ return null;
+
+ int numOfWorkSheet = modSheetList.getLength();
+
+ String modTableName;
+
+ for (int i=0; i < numOfWorkSheet; i++) {
+ modTableName = ((Element)modSheetList.item(i)).getAttribute(
+ OfficeConstants.ATTRIBUTE_TABLE_NAME);
+ if (modTableName == null)
+ continue;
+
+ if (orgTableName.equals(modTableName)) {
+ matchSheet = modSheetList.item(i);
+ break;
+ }
+ }
+
+ return matchSheet;
+ }
+}
+
diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/Format.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/Format.java
new file mode 100644
index 000000000000..2bb836a7303d
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/Format.java
@@ -0,0 +1,475 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxc;
+
+import java.awt.Color;
+
+/**
+ * This class specifies the format for a given spreadsheet cell.
+ *
+ * @author Mark Murnane
+ * @author Martin Maher (Extended Style Support)
+ */
+public class Format implements Cloneable {
+
+ /** Horizontal Alignment Constants. */
+ final public static int RIGHT_ALIGN = 0x01;
+ final public static int CENTER_ALIGN = 0x02;
+ final public static int LEFT_ALIGN = 0x03;
+ final public static int JUST_ALIGN = 0x04;
+
+ /** Vertical Alignment Constants. */
+ final public static int TOP_ALIGN = 0x01;
+ final public static int MIDDLE_ALIGN = 0x02;
+ final public static int BOTTOM_ALIGN = 0x03;
+
+ /** Indicates <i>bold</i> text. */
+ final public static int BOLD = 0x01;
+ /** Indicates <i>italic</i> text. */
+ final public static int ITALIC = 0x02;
+ /** Indicates <i>underlined</i> text. */
+ final public static int UNDERLINE = 0x04;
+ /** Indicates <i>strike-through</i> in the text. */
+ final public static int STRIKETHRU = 0x08;
+ /** Indicates <i>superscripted</i> text. */
+ final public static int SUPERSCRIPT = 0x10;
+ /** Indicates <i>subscripted</i> text. */
+ final public static int SUBSCRIPT = 0x20;
+
+ final public static int LEFT_BORDER = 0x40;
+ final public static int RIGHT_BORDER = 0x80;
+ final public static int TOP_BORDER = 0x100;
+ final public static int BOTTOM_BORDER = 0x200;
+
+ final public static int WORD_WRAP = 0x400;
+
+ private int align;
+ private int vertAlign;
+ private String category;
+ private String value;
+ private String formatSpecifier;
+ private int decimalPlaces;
+
+ /** Font name. */
+ private String fontName;
+ /** Font size in points. */
+ protected int sizeInPoints;
+
+ private Color foreground, background;
+
+ /** Values of text attributes. */
+ protected int attributes = 0;
+ /** Bitwise mask of text attributes. */
+ protected int mask = 0;
+
+ /**
+ * Constructor for creating a new <code>Format</code>.
+ */
+ public Format() {
+ clearFormatting();
+ }
+
+ /**
+ * Constructor that creates a new <code>Format</code> object
+ * by setting all the format attributes.
+ *
+ */
+ public Format(int attributes, int fontSize, String fontName) {
+
+ this.attributes = attributes;
+ sizeInPoints = fontSize;
+ this.fontName = fontName;
+ }
+
+ /**
+ * Constructor for creating a new <code>Format</code> object
+ * based on an existing one.
+ *
+ * @param fmt <code>Format</code> to copy.
+ */
+ public Format(Format fmt) {
+ category = fmt.getCategory();
+ value = fmt.getValue();
+ formatSpecifier = fmt.getFormatSpecifier();
+ decimalPlaces = fmt.getDecimalPlaces();
+
+ attributes = fmt.attributes;
+ mask = fmt.mask;
+
+ fontName = fmt.getFontName();
+ align = fmt.getAlign();
+ vertAlign = fmt.getVertAlign();
+ foreground = fmt.getForeground();
+ background = fmt.getBackground();
+ sizeInPoints = fmt.sizeInPoints;
+ }
+
+
+ /**
+ * Reset this <code>Format</code> description.
+ */
+ public void clearFormatting() {
+ category = "";
+ value = "";
+ formatSpecifier = "";
+ decimalPlaces = 0;
+ attributes = 0;
+ mask = 0;
+ sizeInPoints = 10;
+ align = LEFT_ALIGN;
+ vertAlign = BOTTOM_ALIGN;
+ fontName = "";
+ foreground = null;
+ background = null;
+ }
+
+ /**
+ * Set one or more text attributes to <i>on</i>.
+ *
+ * @param flags Flag attributes to set <i>on</i>.
+ */
+ public void setAttribute(int flags, boolean toggle) {
+ mask |= flags;
+ if(toggle) {
+ attributes |= flags;
+ } else {
+ attributes &= ~flags;
+ }
+ }
+
+ /**
+ * Return true if the <code>attribute</code> is set to <i>on</i>
+ *
+ * @param attribute Attribute to check ({@link #BOLD},
+ * {@link #ITALIC}, etc.)
+ *
+ * @return true if <code>attribute</code> is set to <i>on</i>,
+ * otherwise false.
+ */
+ public boolean getAttribute(int attribute) {
+ if ((mask & attribute) == 0)
+ return false;
+ return (!((attributes & attribute) == 0));
+ }
+
+ /**
+ * Return true if text <code>attribute</code> is set in this
+ * <code>Style</code>.An attribute that is set may have a
+ * value of <i>on</i> or <i>off</i>.
+ *
+ * @param attribute The attribute to check ({@link #BOLD},
+ * {@link #ITALIC}, etc.).
+ *
+ * @return true if text <code>attribute</code> is set in this
+ * <code>Style</code>, false otherwise.
+ */
+ public boolean isSet(int attribute) {
+ return (!((mask & attribute) == 0));
+ }
+
+
+ /**
+ * Set the formatting category of this object, ie number, date,
+ * currency.The <code>OfficeConstants</code> class contains string
+ * constants for the category types.
+ *
+ * @see org.openoffice.xmerge.converter.xml.OfficeConstants
+ *
+ * @param newCategory The name of the category to be set.
+ */
+ public void setCategory(String newCategory) {
+ category = newCategory;
+ }
+
+ /**
+ * Return the formatting category of the object.
+ *
+ * @see org.openoffice.xmerge.converter.xml.OfficeConstants
+ *
+ * @return The formatting category of the object.
+ */
+ public String getCategory() {
+ return category;
+ }
+
+ /**
+ * In the case of Formula returns the value of the formula.
+ *
+ * @return The value of the formula
+ */
+ public String getValue() {
+ return value;
+ }
+
+ /**
+ * In the case of formula the contents are set as the formula string and
+ * the value of the formula is a formatting attribute.
+ *
+ * @param newValue the formuala value
+ */
+ public void setValue(String newValue) {
+ value = newValue;
+ }
+
+
+ /**
+ * Set the <code>Format</code> specifier for this category.
+ *
+ * @param formatString The new <code>Format</code> specifier.
+ */
+ public void setFormatSpecifier(String formatString) {
+ formatSpecifier = formatString;
+ }
+
+
+ /**
+ * Get the <code>Format</code> specifier for this category.
+ *
+ * @return <code>Format</code> specifier for this category.
+ */
+ public String getFormatSpecifier() {
+ return formatSpecifier;
+ }
+
+
+ /**
+ * Set the precision of the number to be displayed.
+ *
+ * @param precision The number of decimal places to display.
+ */
+ public void setDecimalPlaces(int precision) {
+ decimalPlaces = precision;
+ }
+
+
+ /**
+ * Get the number of decimal places displayed.
+ *
+ * @return Number of decimal places.
+ */
+ public int getDecimalPlaces() {
+ return decimalPlaces;
+ }
+
+
+ /**
+ * Set the font used for this cell.
+ *
+ * @param fontName The name of the font.
+ */
+ public void setFontName(String fontName) {
+ this.fontName = fontName;
+ }
+
+
+ /**
+ * Get the font used for this cell.
+ *
+ * @return The font name.
+ */
+ public String getFontName() {
+ return fontName;
+ }
+
+ /**
+ * Set the font used for this cell.
+ *
+ * @param fontName The name of the font.
+ */
+ public void setFontSize(int fontSize) {
+ sizeInPoints = fontSize;
+ }
+
+
+ /**
+ * Get the font used for this cell.
+ *
+ * @return The font name.
+ */
+ public int getFontSize() {
+ return sizeInPoints;
+ }
+
+ /**
+ * Set the alignmen used for this cell.
+ *
+ * @param fontName The name of the font.
+ */
+ public void setVertAlign(int vertAlign) {
+ this.vertAlign = vertAlign;
+ }
+
+
+ /**
+ * Get the alignment used for this cell.
+ *
+ * @return The font name.
+ */
+ public int getVertAlign() {
+ return vertAlign;
+ }
+
+ /**
+ * Set the alignmen used for this cell.
+ *
+ * @param fontName The name of the font.
+ */
+ public void setAlign(int align) {
+ this.align = align;
+ }
+
+
+ /**
+ * Get the alignment used for this cell.
+ *
+ * @return The font name.
+ */
+ public int getAlign() {
+ return align;
+ }
+ /**
+ * Set the Foreground <code>Color</code> for this cell.
+ *
+ * @param color A <code>Color</code> object representing the
+ * foreground color.
+ */
+ public void setForeground(Color c) {
+ if(c!=null)
+ foreground = new Color(c.getRGB());
+ }
+
+
+ /**
+ * Get the Foreground <code>Color</code> for this cell.
+ *
+ * @return Foreground <code>Color</code> value.
+ */
+ public Color getForeground() {
+ return foreground;
+ }
+
+
+ /**
+ * Set the Background <code>Color</code> for this cell
+ *
+ * @param color A <code>Color</code> object representing
+ * the background color.
+ */
+ public void setBackground(Color c) {
+ if(c!=null)
+ background = new Color(c.getRGB());
+ }
+
+
+ /**
+ * Get the Foreground <code>Color</code> for this cell
+ *
+ * @return Background <code>Color</code> value
+ */
+ public Color getBackground() {
+ return background;
+ }
+
+ /**
+ * Get the Foreground <code>Color</code> for this cell
+ *
+ * @return Background <code>Color</code> value
+ */
+ public String toString() {
+ return new String("Value : " + getValue() + " Category : " + getCategory());
+ }
+
+ /**
+ * Tests if the current <code>Format</code> object has default attribute
+ * values.
+ *
+ * @return true if it contains default value
+ */
+ public boolean isDefault() {
+
+ Format rhs = new Format();
+
+ if (rhs.attributes!= attributes)
+ return false;
+
+ if (foreground!=rhs.foreground)
+ return false;
+
+ if (background!=rhs.background)
+ return false;
+
+ if (rhs.align!= align)
+ return false;
+
+ if (rhs.vertAlign!= vertAlign)
+ return false;
+
+ return true;
+ }
+
+ /**
+ * Return true if <code>style</code> specifies as much or less
+ * than this <code>Style</code>, and nothing it specifies
+ * contradicts this <code>Style</code>.
+ *
+ * @param style The <code>Style</code> to check.
+ *
+ * @return true if <code>style</code> is a subset, false
+ * otherwise.
+ */
+ public boolean isSubset(Format rhs) {
+ if (rhs.getClass() != this.getClass())
+ return false;
+
+ if (rhs.attributes!= attributes)
+ return false;
+
+ if (rhs.sizeInPoints != 0) {
+ if (sizeInPoints != rhs.sizeInPoints)
+ return false;
+ }
+
+ if (fontName!=rhs.fontName)
+ return false;
+
+ if (foreground!=rhs.foreground)
+ return false;
+
+ if (background!=rhs.background)
+ return false;
+
+ if (rhs.align!= align)
+ return false;
+
+ if (rhs.vertAlign!= vertAlign)
+ return false;
+
+ return true;
+ }
+}
+
diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/NameDefinition.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/NameDefinition.java
new file mode 100644
index 000000000000..de83543fd86e
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/NameDefinition.java
@@ -0,0 +1,215 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxc;
+
+import org.w3c.dom.Node;
+import org.w3c.dom.Element;
+import org.w3c.dom.NamedNodeMap;
+
+import org.openoffice.xmerge.converter.xml.OfficeConstants;
+import org.openoffice.xmerge.util.Debug;
+import org.openoffice.xmerge.util.XmlUtil;
+
+/**
+ * This is a class to define a Name Definition structure. This can then be
+ * used by plugins to write or read their own definition types.
+ *
+ * @author Martin Maher
+ */
+public class NameDefinition implements OfficeConstants {
+
+ private String name; // name which identifies the definition
+ private String definition; // the definition itself
+ private String baseCellAddress; // the basecelladdress
+ private boolean rangeType = false; // true if definition of type range
+ private boolean expressionType = false; // true if definition of type expression
+
+ /**
+ * Default Constructor for a <code>NameDefinition</code>
+ *
+ */
+ public NameDefinition() {
+
+ }
+
+ /**
+ * Constructor that takes a <code>Node</code> to build a
+ * <code>NameDefinition</code>
+ *
+ * @param root XML Node to read from
+ */
+ public NameDefinition(Node root) {
+ readNode(root);
+ }
+
+ /**
+ * Default Constructor for a <code>NameDefinition</code>
+ *
+ */
+ public NameDefinition(String name, String definition, String
+ baseCellAddress, boolean rangeType, boolean expressionType ) {
+ this.name = name;
+ this.definition = definition;
+ this.baseCellAddress = baseCellAddress;
+ this.rangeType = rangeType;
+ this.expressionType = expressionType;
+ }
+
+ /**
+ * returns Name of the definition
+ *
+ * @return the name which identifies the definition
+ */
+ public String getName() {
+
+ return name;
+ }
+ /**
+ * sets the definition
+ *
+ * @param newDefinition sets the definition
+ */
+ public void setDefinition(String newDefinition) {
+
+ definition = newDefinition;
+ }
+ /**
+ * Returns the definition itself
+ *
+ * @return the definition
+ */
+ public String getDefinition() {
+
+ return definition;
+ }
+
+ /**
+ * Returns the base Cell address
+ *
+ * @return the base cell address
+ */
+ public String getBaseCellAddress() {
+
+ return baseCellAddress;
+ }
+
+ /**
+ * Tests if definition is of type expression
+ *
+ * @return whether or not this name definition is of type expression
+ */
+ public boolean isExpressionType() {
+ return expressionType;
+ }
+
+ /**
+ * Tests if definition is of type range
+ *
+ * @return whether or not this name definition is of type range
+ */
+ public boolean isRangeType() {
+ return rangeType;
+ }
+
+ /**
+ * Writes out a content.xml entry for this NameDefinition object
+ *
+ * @param settings a <code>Document</code> object representing the settings.xml
+ * @param root the root xml node to add to
+ */
+ public void writeNode(org.w3c.dom.Document doc, Node root) {
+
+ if(isRangeType()) {
+
+ Debug.log(Debug.TRACE, "Found Range Name : " + getName());
+ Element namedRangeElement = (Element) doc.createElement(TAG_TABLE_NAMED_RANGE);
+ namedRangeElement.setAttribute(ATTRIBUTE_TABLE_NAME, getName());
+ namedRangeElement.setAttribute(ATTRIBUTE_TABLE_BASE_CELL_ADDRESS, getBaseCellAddress());
+ namedRangeElement.setAttribute(ATTRIBUTE_TABLE_CELL_RANGE_ADDRESS, getDefinition());
+ root.appendChild(namedRangeElement);
+ } else if (isExpressionType()) {
+
+ Debug.log(Debug.TRACE, "Found Expression Name : " + getName());
+ Element namedExpressionElement = (Element) doc.createElement(TAG_TABLE_NAMED_EXPRESSION);
+ namedExpressionElement.setAttribute(ATTRIBUTE_TABLE_NAME, getName());
+ namedExpressionElement.setAttribute(ATTRIBUTE_TABLE_BASE_CELL_ADDRESS,getBaseCellAddress());
+ namedExpressionElement.setAttribute(ATTRIBUTE_TABLE_EXPRESSION, getDefinition());
+ root.appendChild(namedExpressionElement);
+ } else {
+
+ Debug.log(Debug.TRACE, "Unknown Name Definition : " + getName());
+ }
+ }
+
+ /**
+ * Reads document settings from xml and inits Settings variables
+ *
+ * @param root XML Node to read from
+ */
+ public void readNode(Node root) {
+
+ String nodeName = root.getNodeName();
+ NamedNodeMap cellAtt = root.getAttributes();
+
+ if (nodeName.equals(TAG_TABLE_NAMED_RANGE)) {
+
+ Node tableNameNode =
+ cellAtt.getNamedItem(ATTRIBUTE_TABLE_NAME);
+ Node tableBaseCellAddress =
+ cellAtt.getNamedItem(ATTRIBUTE_TABLE_BASE_CELL_ADDRESS);
+ Node tableCellRangeAddress =
+ cellAtt.getNamedItem(ATTRIBUTE_TABLE_CELL_RANGE_ADDRESS);
+ Debug.log(Debug.TRACE,"Named-range : " + tableNameNode.getNodeValue());
+ // Create a named-range name definition
+ name = tableNameNode.getNodeValue();
+ definition = tableCellRangeAddress.getNodeValue();
+ baseCellAddress = tableBaseCellAddress.getNodeValue();
+ expressionType = true;
+ rangeType = false;
+
+ } else if (nodeName.equals(TAG_TABLE_NAMED_EXPRESSION)) {
+
+ Node tableNameNode =
+ cellAtt.getNamedItem(ATTRIBUTE_TABLE_NAME);
+ Node tableBaseCellAddress =
+ cellAtt.getNamedItem(ATTRIBUTE_TABLE_BASE_CELL_ADDRESS);
+ Node tableExpression=
+ cellAtt.getNamedItem(ATTRIBUTE_TABLE_EXPRESSION);
+ Debug.log(Debug.TRACE,"Named-expression: " + tableNameNode.getNodeValue());
+ // Create a named-range name definition
+ name = tableNameNode.getNodeValue();
+ definition = tableExpression.getNodeValue();
+ baseCellAddress = tableBaseCellAddress.getNodeValue();
+ expressionType = false;
+ rangeType = true;
+ } else {
+ Debug.log(Debug.TRACE, "<OTHERS " + XmlUtil.getNodeInfo(root) + " />");
+ }
+ }
+
+}
diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/RowStyle.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/RowStyle.java
new file mode 100644
index 000000000000..2b4ce04a13f0
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/RowStyle.java
@@ -0,0 +1,300 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxc;
+
+import org.w3c.dom.NodeList;
+import org.w3c.dom.Node;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Element;
+
+import org.openoffice.xmerge.converter.xml.Style;
+import org.openoffice.xmerge.converter.xml.StyleCatalog;
+import org.openoffice.xmerge.util.Debug;
+import org.openoffice.xmerge.util.TwipsConverter;
+
+/**
+ * Represents a text <code>Style</code> in an OpenOffice document.
+ *
+ * @author Martin Maher
+ */
+public class RowStyle extends Style implements Cloneable {
+
+ private int rowHeight = 255;
+ /**
+ * Constructor for use when going from DOM to client device format.
+ *
+ * @param Node The <i>style:style</i> <code>Node</code> containing
+ * the <code>Style</code>. (This <code>Node</code> is
+ * assumed have a <i>family</i> attribute of <i>text</i>).
+ * @param sc The <code>StyleCatalog</code>, which is used for
+ * looking up ancestor <code>Style</code> objects.
+ */
+ public RowStyle(Node node, StyleCatalog sc) {
+ super(node, sc);
+
+ // Run through the attributes of this node, saving
+ // the ones we're interested in.
+ NamedNodeMap attrNodes = node.getAttributes();
+ if (attrNodes != null) {
+ int len = attrNodes.getLength();
+ for (int i = 0; i < len; i++) {
+ Node attr = attrNodes.item(i);
+ handleAttribute(attr.getNodeName(), attr.getNodeValue());
+ }
+ }
+
+ // 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 name = child.getNodeName();
+ if (name.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);
+ handleAttribute(attr.getNodeName(),
+ attr.getNodeValue());
+ }
+ }
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Constructor for use when going from client device format to DOM
+ *
+ * @param name Name of text <code>Style</code>. Can be null.
+ * @param family Family of text <code>Style</code> (usually
+ * <i>text</i>). Can be null.
+ * @param parent Name of parent text <code>Style</code>, or null
+ * for none.
+ * @param mask The height of this row
+ * @param sc The <code>StyleCatalog</code>, which is used for
+ * looking up ancestor <code>Style</code> objects.
+ */
+ public RowStyle(String name, String family, String parent,int rowHeight, StyleCatalog sc) {
+ super(name, family, parent, sc);
+ this.rowHeight=rowHeight;
+ }
+
+ /**
+ * Returns the height of this row
+ *
+ * @return the <code>Format</code> object
+ */
+ public int getRowHeight() {
+ return rowHeight;
+ }
+
+ /**
+ * Sets the height of this row
+ *
+ * @return the <code>Format</code> object
+ */
+ public void setRowHeight(int RowHeight) {
+
+ this.rowHeight = rowHeight;
+ }
+ /**
+ * Parse a colheight in the form "1.234cm" to twips
+ *
+ * @param value <code>String</code> specification to parse.
+ *
+ * @return The twips equivalent.
+ */
+ private int parseRowHeight(String value) {
+
+ int height = 255; // Default value
+
+ if(value.indexOf("cm")!=-1) {
+ float heightCM = Float.parseFloat(value.substring(0,value.indexOf("c")));
+ height = TwipsConverter.cm2twips(heightCM);
+ } else if(value.indexOf("inch")!=-1) {
+ float heightInch = Float.parseFloat(value.substring(0,value.indexOf("i")));
+ height = TwipsConverter.inches2twips(heightInch);
+ }
+
+ return (height);
+
+ }
+
+
+ /**
+ * Set an attribute.
+ *
+ * @param attr The attribute to set.
+ * @param value The attribute value to set.
+ */
+ private void handleAttribute(String attr, String value) {
+
+ if (attr.equals("style:row-height")) {
+ rowHeight = parseRowHeight(value);
+ }
+ else {
+ Debug.log(Debug.INFO, "RowStyle Unhandled: " + attr + "=" + value);
+ }
+ }
+
+
+ /**
+ * Return a <code>Style</code> object corresponding to this one,
+ * but with all of the inherited information from parent
+ * <code>Style</code> 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 The <code>StyleCatalog</code> in which to look up
+ * ancestors.
+ */
+ public Style getResolved() {
+ // Create a new object to return, which is a clone of this one.
+ RowStyle resolved = null;
+ try {
+ resolved = (RowStyle)this.clone();
+ } catch (Exception e) {
+ Debug.log(Debug.ERROR, "Can't clone", e);
+ }
+
+ // Look up the parentStyle. (If there is no style catalog
+ // specified, we can't do any lookups.)
+ RowStyle parentStyle = null;
+ if (sc != null) {
+ if (parent != null) {
+ parentStyle = (RowStyle)sc.lookup(parent, family, null,
+ this.getClass());
+ if (parentStyle == null)
+ Debug.log(Debug.ERROR, "parent style lookup of "
+ + parent + " failed!");
+ else
+ parentStyle = (RowStyle)parentStyle.getResolved();
+
+ } else if (!name.equals("DEFAULT_STYLE")) {
+ parentStyle = (RowStyle)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 = (RowStyle)parentStyle.getResolved();
+
+ if ((rowHeight == 0) && (parentStyle.getRowHeight() != 0))
+ resolved.setRowHeight(parentStyle.getRowHeight());
+ }
+ return resolved;
+ }
+
+
+ /**
+ * Create a new <code>Node</code> in the <code>Document</code>, and
+ * write this <code>Style</code> to it.
+ *
+ * @param parentDoc Parent <code>Document</code> of the
+ * <code>Node</code> to create.
+ * @param name Name to use for the new <code>Node</code> (e.g.
+ * <i>style:style</i>)
+ *
+ * @return Created <code>Node</code>.
+ */
+ public Node createNode(org.w3c.dom.Document parentDoc, String name) {
+ Element node = parentDoc.createElement(name);
+ writeAttributes(node);
+ return node;
+ }
+
+
+ /**
+ * Return true if <code>style</code> specifies as much or less
+ * than this <code>Style</code>, and nothing it specifies
+ * contradicts this <code>Style</code>.
+ *
+ * @param style The <code>Style</code> to check.
+ *
+ * @return true if <code>style</code> is a subset, false
+ * otherwise.
+ */
+ public boolean isSubset(Style style) {
+ if (style.getClass() != this.getClass())
+ return false;
+ RowStyle tStyle = (RowStyle)style;
+
+ if(rowHeight!=tStyle.getRowHeight())
+ return false;
+
+ return true;
+ }
+
+
+ /**
+ * Write this <code>Style</code> object's attributes to a
+ * <code>Node</code> in the <code>Document</code>.
+ *
+ * @param node The <code>Node</code> to add <code>Style</code>
+ * attributes.
+ */
+ public void writeAttributes(Element node) {
+
+ if(rowHeight!=0) {
+ String height = TwipsConverter.twips2cm(rowHeight) + "cm";
+ node.setAttribute("style:row-height", height);
+ }
+ }
+
+
+ private static String[] ignored = {
+ "fo:break-before", "fo:keep-with-next"
+ };
+
+
+ /*
+ * This code checks whether an attribute is one that we
+ * intentionally ignore.
+ *
+ * @param attribute The attribute to check.
+ *
+ * @return true if <code>attribute</code> can be ignored,
+ * otherwise false.
+ */
+ private boolean isIgnored(String attribute) {
+ for (int i = 0; i < ignored.length; i++) {
+ if (ignored[i].equals(attribute))
+ return true;
+ }
+ return false;
+ }
+}
+
diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/SheetSettings.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/SheetSettings.java
new file mode 100644
index 000000000000..4258e1a5e035
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/SheetSettings.java
@@ -0,0 +1,373 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxc;
+
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.NodeList;
+import org.w3c.dom.Node;
+import org.w3c.dom.Element;
+import java.awt.Point;
+
+import org.openoffice.xmerge.converter.xml.OfficeConstants;
+
+/**
+ * This is a class representing the different attributes for a worksheet
+ * contained in settings.xml.
+ *
+ * @author Martin Maher
+ */
+public class SheetSettings implements OfficeConstants {
+
+ /** A w3c <code>Document</code>. */
+ private org.w3c.dom.Document settings = null;
+
+ private String sheetName;
+ private int cursorX = 0;
+ private int cursorY = 0;
+ private int splitTypeX;
+ private int splitTypeY;
+ private int splitPointX = 0;
+ private int splitPointY = 0;
+ private int posLeft = 0;
+ private int posRight = 0;
+ private int posBottom = 0;
+ private int posTop = 0;
+ private int paneNumber = 2;
+
+ final public static int NONE = 0x00;
+ final public static int SPLIT = 0x01;
+ final public static int FREEZE = 0x02;
+
+
+ /**
+ * Default Constructor for a <code>ColumnRowInfo</code>
+ *
+ */
+ public SheetSettings() {
+ }
+
+ /**
+ * Constructor that takes a <code>Node</code> to build a <code>SheetSettings</code>
+ *
+ * @param root XML Node to read from
+ */
+ public SheetSettings(Node root) {
+ readNode(root);
+ }
+
+ /**
+ * Constructor for a <code>ColumnRowInfo</code>
+ *
+ * @param dimension if it's a row the height, a column the width
+ * @param repeated
+ */
+ public SheetSettings(String name) {
+ sheetName = name;
+ }
+
+ /**
+ * sets the position of the acitve cell
+ *
+ * @param activeCell the current curor position
+ */
+ public void setCursor(Point activeCell) {
+
+ cursorX = (int) activeCell.getX();
+ cursorY = (int) activeCell.getY();
+ }
+
+ /**
+ * Gets the position of the acitve cell
+ *
+ * @return The position as a <code>Point</code>
+ */
+ public Point getCursor() {
+
+ return (new Point(cursorX, cursorY));
+ }
+
+ /**
+ * Sets the position of the freeze
+ *
+ * @param splitPoint the point at where the split occurs
+ */
+ public void setFreeze(Point splitPoint) {
+
+ splitTypeX = FREEZE;
+ splitTypeY = FREEZE;
+ splitPointX = (int) splitPoint.getX();
+ splitPointY = (int) splitPoint.getY();
+ }
+
+ /**
+ * Sets the position of the split
+ *
+ * @param splitPoint the point at where the split occurs
+ */
+ public void setSplit(Point splitPoint) {
+
+ splitTypeX = SPLIT;
+ splitTypeY = SPLIT;
+ splitPointX = (int) splitPoint.getX();
+ splitPointY = (int) splitPoint.getY();
+ }
+
+ /**
+ * sets the position and type of the split
+ *
+ * @return The position as a <code>Point</code> where the split occurs
+ */
+ public Point getSplit() {
+
+ return (new Point(splitPointX, splitPointY));
+ }
+
+ /**
+ * sets the position and type of the split
+ *
+ * @return The position as a <code>Point</code> where the split occurs
+ */
+ public Point getSplitType() {
+
+ return (new Point(splitTypeX, splitTypeY));
+ }
+
+ /**
+ * Sets the top row visible in the lower pane and the leftmost column
+ * visibile in the right pane.
+ *
+ * @param top The top row visible in the lower pane
+ * @param left The leftmost column visibile in the right pane
+ */
+ public void setTopLeft(int top, int left) {
+
+ posLeft = left;
+ posTop = top;
+ }
+
+ /**
+ * Gets the the leftmost column visibile in the right pane.
+ *
+ * @return the 0-based index to the column
+ */
+ public int getLeft() {
+
+ return posLeft;
+ }
+ /**
+ * Sets the top row visible in the lower pane and the leftmost column
+ * visibile in the right pane.
+ *
+ * @param top The top row visible in the lower pane
+ * @param left The leftmost column visibile in the right pane
+ */
+ public int getTop() {
+
+ return posTop;
+ }
+
+ /**
+ * Gets the active Panel
+ * 0 - Bottom Right, 1 - Top Right
+ * 2 - Bottom Left, 3 - Top Left
+ *
+ * @return int representing the active panel
+ */
+ public int getPaneNumber() {
+
+ return paneNumber;
+ }
+
+ /**
+ * Sets the sheetname this settings object applies to
+ *
+ * @param sheetName the name of the worksheet
+ */
+ public void setSheetName(String sheetName) {
+
+ this.sheetName = sheetName;
+
+ }
+
+ /**
+ * Sets the active pane number
+ * 0 - Bottom Right, 1 - Top Right
+ * 2 - Bottom Left, 3 - Top Left
+ *
+ * @param paneNumber the pane number
+ */
+ public void setPaneNumber(int paneNumber) {
+
+ this.paneNumber = paneNumber;
+ }
+
+ /**
+ * Gets the name of the worksheet these <code>Settings</code> apply to
+ *
+ * @return the name of the worksheet
+ */
+ public String getSheetName() {
+
+ return sheetName;
+ }
+
+ /**
+ * Adds an XML entry for a particular setting
+ *
+ * @param root the root node at which to add the xml entry
+ * @param attriute the name of the attribute to add
+ * @param type the attribute type (int, short etc)
+ * @param value the value of the attribute
+ */
+ private void addConfigItem(Node root, String attribute, String type, String value) {
+
+ Element configItem = settings.createElement(TAG_CONFIG_ITEM);
+ configItem.setAttribute(ATTRIBUTE_CONFIG_NAME, attribute);
+ configItem.setAttribute(ATTRIBUTE_CONFIG_TYPE, type);
+
+ configItem.appendChild(settings.createTextNode(value));
+
+ root.appendChild(configItem);
+ }
+
+ /**
+ * Writes out a settings.xml entry for this SheetSettings object
+ *
+ * @param settings a <code>Document</code> object representing the settings.xml
+ * @param root the root xml node to add to
+ */
+ public void writeNode(org.w3c.dom.Document settings, Node root) {
+
+ this.settings = settings;
+ Element configItemMapEntry = (Element) settings.createElement(TAG_CONFIG_ITEM_MAP_ENTRY);
+ configItemMapEntry.setAttribute(ATTRIBUTE_CONFIG_NAME, getSheetName());
+ addConfigItem(configItemMapEntry, "CursorPositionX", "int", Integer.toString(cursorX));
+ addConfigItem(configItemMapEntry, "CursorPositionY", "int", Integer.toString(cursorY));
+
+ String splitMode = Integer.toString(splitTypeX);
+ if(splitPointX==0) {
+ splitMode = "0";
+ }
+ addConfigItem(configItemMapEntry, "HorizontalSplitMode", "short", splitMode);
+
+ splitMode = Integer.toString(splitTypeY);
+ if(splitPointY==0) {
+ splitMode = "0";
+ }
+ addConfigItem(configItemMapEntry, "VerticalSplitMode", "short", splitMode);
+
+ addConfigItem(configItemMapEntry, "HorizontalSplitPosition", "int", Integer.toString(splitPointX));
+ addConfigItem(configItemMapEntry, "VerticalSplitPosition", "int", Integer.toString(splitPointY));
+ addConfigItem(configItemMapEntry, "ActiveSplitRange", "short", Integer.toString(paneNumber));
+
+ addConfigItem(configItemMapEntry, "PositionLeft", "int", "0");
+ addConfigItem(configItemMapEntry, "PositionRight", "int", Integer.toString(posLeft));
+ addConfigItem(configItemMapEntry, "PositionTop", "int", "0");
+ addConfigItem(configItemMapEntry, "PositionBottom", "int", Integer.toString(posTop));
+ root.appendChild(configItemMapEntry);
+ }
+
+ /**
+ * Sets a variable based on a String value read from XML
+ *
+ * @param name xml name of the attribute to set
+ * @param value String value fo the attribute
+ */
+ public void addAttribute(String name, String value) {
+
+ if(name.equals("CursorPositionX")) {
+ cursorX = Integer.parseInt(value);
+ } else if(name.equals("CursorPositionY")) {
+ cursorY = Integer.parseInt(value);
+
+ } else if(name.equals("HorizontalSplitPosition")) {
+ splitPointX = Integer.parseInt(value);
+ } else if(name.equals("VerticalSplitPosition")) {
+ splitPointY = Integer.parseInt(value);
+ } else if(name.equals("ActiveSplitRange")) {
+ paneNumber = Integer.parseInt(value);
+
+ } else if(name.equals("PositionRight")) {
+ posLeft = Integer.parseInt(value);
+ } else if(name.equals("PositionBottom")) {
+ posTop = Integer.parseInt(value);
+
+ } else if(name.equals("HorizontalSplitMode")) {
+ splitTypeX = Integer.parseInt(value);
+ } else if(name.equals("VerticalSplitMode")) {
+ splitTypeY = Integer.parseInt(value);
+ }
+ }
+
+ /**
+ * Reads document settings from xml and inits SheetSettings variables
+ *
+ * @param root XML Node to read from
+ */
+ public void readNode(Node root) {
+
+ NamedNodeMap sheetAtt = root.getAttributes();
+
+ Node sheetNameNode = sheetAtt.getNamedItem(ATTRIBUTE_CONFIG_NAME);
+
+ sheetName = sheetNameNode.getNodeValue();
+
+ if (root.hasChildNodes()) {
+
+ NodeList nodeList = root.getChildNodes();
+ int len = nodeList.getLength();
+ for (int i = 0; i < len; i++) {
+ Node child = nodeList.item(i);
+
+ if (child.getNodeType() == Node.ELEMENT_NODE) {
+ String nodeName = child.getNodeName();
+
+ if (nodeName.equals(TAG_CONFIG_ITEM)) {
+
+ NamedNodeMap cellAtt = child.getAttributes();
+
+ Node configNameNode =
+ cellAtt.getNamedItem(ATTRIBUTE_CONFIG_NAME);
+
+ String name = configNameNode.getNodeValue();
+ NodeList nodeList2 = child.getChildNodes();
+ int len2 = nodeList2.getLength();
+ String s = "";
+ for (int j = 0; j < len2; j++) {
+ Node child2 = nodeList2.item(j);
+ if (child2.getNodeType() == Node.TEXT_NODE) {
+ s = child2.getNodeValue();
+ }
+ }
+ addAttribute(name, s);
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/SpreadsheetDecoder.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/SpreadsheetDecoder.java
new file mode 100644
index 000000000000..169f54a65845
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/SpreadsheetDecoder.java
@@ -0,0 +1,180 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxc;
+
+import java.io.IOException;
+import java.util.Enumeration;
+
+import org.openoffice.xmerge.converter.xml.sxc.Format;
+import org.openoffice.xmerge.ConvertData;
+
+/**
+ * This class is a abstract class for encoding a &quot;Device&quot;
+ * <code>Document</code> format into an alternative spreadsheet format.
+ *
+ * @author Mark Murnane
+ */
+public abstract class SpreadsheetDecoder {
+
+ /**
+ * Constructor for creating new <code>SpreadsheetDecoder</code>.
+ */
+ public SpreadsheetDecoder(String name, String password) throws IOException {
+ }
+
+ /**
+ * Returns the total number of sheets in the WorkBook.
+ *
+ * @return The number of sheets in the WorkBook.
+ */
+ public abstract int getNumberOfSheets();
+
+ /**
+ * Returns an Enumeration to a Vector of <code>NameDefinition</code>.
+ *
+ * @return The Enumeration
+ */
+ public abstract Enumeration getNameDefinitions();
+
+ /**
+ * Returns an <code>BookSettings</code>
+ *
+ * @return The Enumeration
+ */
+ public abstract BookSettings getSettings();
+
+ /**
+ * Returns an Enumeration to a Vector of <code>ColumnRowInfo</code>.
+ *
+ * @return The Enumeration
+ */
+ public abstract Enumeration getColumnRowInfos();
+
+ /**
+ * Returns the number of populated rows in the current WorkSheet.
+ *
+ * @return the number of populated rows in the current WorkSheet.
+ */
+ public abstract int getNumberOfRows();
+
+
+ /**
+ * Returns the number of populated columns in the current WorkSheet.
+ *
+ * @return The number of populated columns in the current WorkSheet.
+ */
+ public abstract int getNumberOfColumns();
+
+
+ /**
+ * Returns the name of the current WorkSheet.
+ *
+ * @return Name of the current WorkSheet.
+ */
+ public abstract String getSheetName();
+
+
+ /**
+ * Returns the number of the active column.
+ *
+ * @return The number of the active column.
+ */
+ public abstract int getColNumber();
+
+
+ /**
+ * Returns the number of the active row.
+ *
+ * @return The number of the active row.
+ */
+ public abstract int getRowNumber();
+
+
+ /**
+ * Sets the active WorkSheet.
+ *
+ * @param sheetIndex The index of the sheet to be made active.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ public abstract void setWorksheet(int sheetIndex) throws IOException;
+
+
+ /**
+ * Move on the next populated cell in the current WorkSheet.
+ *
+ * @return true if successful, false otherwise.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ public abstract boolean goToNextCell() throws IOException;
+
+
+ /**
+ * Return the contents of the active cell.
+ *
+ * @return The cell contents.
+ */
+ public abstract String getCellContents();
+
+ /**
+ * Return the value of the active cell. Used in the case of Formula where
+ * the cell contents and the cell value are not the same thing.
+ *
+ * @return The cell value.
+ */
+ public abstract String getCellValue();
+
+ /**
+ * Return the data type of the active cell.
+ *
+ * @return The cell data type.
+ */
+ public abstract String getCellDataType();
+
+
+ /**
+ * Return a <code>Format</code> object describing the active cells
+ * formatting.
+ *
+ * @return <code>Format</code> object for the cell.
+ */
+ public abstract Format getCellFormat();
+
+
+ /**
+ * Add the contents of a <code>ConvertData</code> to the workbook.
+ *
+ * @param cd The <code>ConvertData</code> containing the
+ * content.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ public abstract void addDeviceContent(ConvertData cd) throws IOException;
+}
+
diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/SpreadsheetEncoder.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/SpreadsheetEncoder.java
new file mode 100644
index 000000000000..fc965bcd88b1
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/SpreadsheetEncoder.java
@@ -0,0 +1,129 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxc;
+
+import java.io.IOException;
+import java.util.Vector;
+
+/**
+ * <p>This class is a abstract class for encoding an SXC into an
+ * alternative spreadsheet format.</p>
+ *
+ * <p>TODO - Add appropriate exceptions to each of the methods.</p>
+ *
+ * @author Mark Murnane
+ */
+public abstract class SpreadsheetEncoder {
+
+
+ /**
+ * Creates new SpreadsheetEncoder.
+ *
+ * @param name The name of the WorkBook to be created.
+ * @param password An optional password for the WorkBook.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ public SpreadsheetEncoder(String name, String password) throws IOException { };
+
+
+ /**
+ * Create a new WorkSheet within the WorkBook.
+ *
+ * @param sheetName The name of the WorkSheet.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ public abstract void createWorksheet(String sheetName) throws IOException;
+
+
+ /**
+ * Set a cell's formatting options via a separately create
+ * <code>Format</code> object.
+ *
+ * @param row The row number of the cell to be changed
+ * @param column The column number of the cell to be changed
+ * @param fmt Object containing formatting settings for this cell.
+ */
+ public abstract void setCellFormat(int row, int column, Format fmt);
+
+
+ /**
+ * Add a cell to the current WorkSheet.
+ *
+ * @param row The row number of the cell
+ * @param column The column number of the cell
+ * @param fmt The <code>Format</code> object describing the
+ * appearance of this cell.
+ * @param cellContents The text or formula of the cell's contents.
+ */
+ public abstract void addCell(int row, int column,
+ Format fmt, String cellContents) throws IOException;
+
+
+ /**
+ * Get the number of sheets in the WorkBook.
+ *
+ * @return The number of sheets in the WorkBook.
+ */
+ public abstract int getNumberOfSheets();
+
+
+ /**
+ * Get the names of the sheets in the WorkBook.
+ *
+ * @param sheet The required sheet.
+ */
+ public abstract String getSheetName(int sheet);
+
+
+ /**
+ * Set the width of the columns in the WorkBook.
+ *
+ * @param columnWidths An <code>IntArrayList</code> of column
+ * widths.
+ */
+ public abstract void setColumnRows(Vector columnRows) throws IOException;
+
+ /**
+ * Set the width of the columns in the WorkBook.
+ *
+ * @param columnWidths An <code>IntArrayList</code> of column
+ * widths.
+ */
+ public abstract void setNameDefinition(NameDefinition nd) throws IOException;
+
+ /**
+ * Set the width of the columns in the WorkBook.
+ *
+ * @param columnWidths An <code>IntArrayList</code> of column
+ * widths.
+ */
+ public abstract void addSettings(BookSettings s) throws IOException;
+}
+
diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/SxcConstants.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/SxcConstants.java
new file mode 100644
index 000000000000..32fd85fa071a
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/SxcConstants.java
@@ -0,0 +1,49 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxc;
+
+
+/**
+ * Interface defining constants for Sxc attributes.
+ *
+ * @author Martin Maher
+ */
+public interface SxcConstants {
+
+ /** Family name for column styles. */
+ public static final String COLUMN_STYLE_FAMILY = "table-column";
+
+ /** Family name for row styles. */
+ public static final String ROW_STYLE_FAMILY = "table-row";
+
+ /** Family name for table-cell styles. */
+ public static final String TABLE_CELL_STYLE_FAMILY = "table-cell";
+
+ /** Name of the default style. */
+ public static final String DEFAULT_STYLE = "Default";
+}
diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/SxcDocument.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/SxcDocument.java
new file mode 100644
index 000000000000..5561ef3c9d9c
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/SxcDocument.java
@@ -0,0 +1,92 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxc;
+
+import org.openoffice.xmerge.converter.xml.OfficeDocument;
+import org.openoffice.xmerge.converter.xml.OfficeConstants;
+
+/**
+ * This class is an implementation of <code>OfficeDocument</code> for
+ * the SXC format.
+ */
+public class SxcDocument extends OfficeDocument {
+
+ /**
+ * Constructor with arguments to set <code>name</code>.
+ *
+ * @param name The name of the <code>Document</code>
+ */
+ public SxcDocument(String name) {
+ super(name);
+ }
+
+
+ /**
+ * Constructor with arguments to set <code>name</code>, the
+ * <code>namespaceAware</code> flag, and the <code>validating</code>
+ * flag.
+ *
+ * @param name The name of the <code>Document</code>.
+ * @param namespaceAware The value of the <code>namespaceAware</code>
+ * flag.
+ * @param validating The value of the <code>validating</code> flag.
+ */
+ public SxcDocument(String name, boolean namespaceAware, boolean validating) {
+
+ super(name, namespaceAware, validating);
+ }
+
+ /**
+ * Returns the Office file extension for the SXC format.
+ *
+ * @return The Office file extension for the SXC format.
+ */
+ protected String getFileExtension() {
+ return OfficeConstants.SXC_FILE_EXTENSION;
+ }
+
+ /**
+ * Returns the Office attribute for the SXC format.
+ *
+ * @return The Office attribute for the SXC format.
+ */
+ protected String getOfficeClassAttribute() {
+ return OfficeConstants.SXC_TYPE;
+ }
+
+ /**
+ * Method to return the MIME type of the document.
+ *
+ * @return String The document's MIME type.
+ */
+ protected final String getDocumentMimeType() {
+ return OfficeConstants.SXC_MIME_TYPE;
+ }
+
+}
+
diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/SxcDocumentDeserializer.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/SxcDocumentDeserializer.java
new file mode 100644
index 000000000000..2eb507d09b7b
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/SxcDocumentDeserializer.java
@@ -0,0 +1,792 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxc;
+
+import org.w3c.dom.NodeList;
+import org.w3c.dom.Node;
+import org.w3c.dom.Element;
+
+import java.io.IOException;
+import java.util.Enumeration;
+
+import org.openoffice.xmerge.Document;
+import org.openoffice.xmerge.ConvertData;
+import org.openoffice.xmerge.ConvertException;
+import org.openoffice.xmerge.DocumentDeserializer;
+import org.openoffice.xmerge.converter.xml.OfficeConstants;
+import org.openoffice.xmerge.converter.xml.sxc.SxcDocument;
+import org.openoffice.xmerge.converter.xml.sxc.BookSettings;
+import org.openoffice.xmerge.converter.xml.sxc.NameDefinition;
+import org.openoffice.xmerge.converter.xml.sxc.CellStyle;
+import org.openoffice.xmerge.converter.xml.Style;
+import org.openoffice.xmerge.converter.xml.StyleCatalog;
+import org.openoffice.xmerge.util.Debug;
+
+/**
+ * <p>General spreadsheet implementation of <code>DocumentDeserializer</code>
+ * for the {@link
+ * org.openoffice.xmerge.converter.xml.sxc.SxcPluginFactory
+ * SxcPluginFactory}. Used with SXC <code>Document</code> objects.</p>
+ *
+ * <p>The <code>deserialize</code> method uses a <code>DocDecoder</code>
+ * to read the device spreadsheet format into a <code>String</code>
+ * object, then it calls <code>buildDocument</code> to create a
+ * <code>SxcDocument</code> object from it.</p>
+ *
+ * @author Paul Rank
+ * @author Mark Murnane
+ * @author Martin Maher
+ */
+public abstract class SxcDocumentDeserializer implements OfficeConstants,
+ DocumentDeserializer {
+
+ /**
+ * A <code>SpreadsheetDecoder</code> object for decoding from
+ * device formats.
+ */
+ private SpreadsheetDecoder decoder = null;
+
+ /** A w3c <code>Document</code>. */
+ private org.w3c.dom.Document settings = null;
+
+ /** A w3c <code>Document</code>. */
+ private org.w3c.dom.Document doc = null;
+
+ /** An <code>ConvertData</code> object assigned to this object. */
+ private ConvertData cd = null;
+
+ /** A style catalog for the workbook */
+ private StyleCatalog styleCat = null;
+
+ private int textStyles = 1;
+ private int colStyles = 1;
+ private int rowStyles = 1;
+
+ /**
+ * Constructor.
+ *
+ * @param cd <code>ConvertData</code> consisting of a
+ * device content object.
+ */
+ public SxcDocumentDeserializer(ConvertData cd) {
+ this.cd = cd;
+ }
+
+
+ /**
+ * This abstract method will be implemented by concrete subclasses
+ * and will return an application-specific Decoder.
+ *
+ * @param workbook The WorkBook to read.
+ * @param password The WorkBook password.
+ *
+ * @return The appropriate <code>SpreadSheetDecoder</code>.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ public abstract SpreadsheetDecoder createDecoder(String workbook, String[] worksheetNames, String password)
+ throws IOException;
+
+
+ /**
+ * <p>This method will return the name of the WorkBook from the
+ * <code>ConvertData</code>. Allows for situations where the
+ * WorkBook name differs from the Device Content name.</p>
+ *
+ * <p>Implemented in the Deserializer as the Decoder's constructor requires
+ * a name.</p>
+ *
+ * @param cd The <code>ConvertData</code> containing the Device
+ * content.
+ *
+ * @return The WorkBook name.
+ */
+ protected abstract String getWorkbookName(ConvertData cd) throws IOException;
+
+
+ /**
+ * This method will return the name of the WorkSheet from the
+ * <code>ConvertData</code>.
+ *
+ * @param cd The <code>ConvertData</code> containing the Device
+ * content.
+ *
+ * @return The WorkSheet names.
+ */
+ protected abstract String[] getWorksheetNames(ConvertData cd) throws IOException;
+
+
+ /**
+ * <p>Method to convert a set of &quot;Device&quot;
+ * <code>Document</code> objects into a <code>SxcDocument</code>
+ * object and returns it as a <code>Document</code>.</p>
+ *
+ * <p>This method is not thread safe for performance reasons.
+ * This method should not be called from within two threads.
+ * It would be best to call this method only once per object
+ * instance.</p>
+ *
+ * @return document An <code>SxcDocument</code> consisting
+ * of the data converted from the input
+ * stream.
+ *
+ * @throws ConvertException If any conversion error occurs.
+ * @throws IOException If any I/O error occurs.
+ */
+ public Document deserialize() throws ConvertException,
+ IOException {
+
+ // Get the name of the WorkBook from the ConvertData.
+ String[] worksheetNames = getWorksheetNames(cd);
+ String workbookName = getWorkbookName(cd);
+
+ // Create a document
+ SxcDocument sxcDoc = new SxcDocument(workbookName);
+ sxcDoc.initContentDOM();
+ sxcDoc.initSettingsDOM();
+
+ // Default to an initial 5 entries in the catalog.
+ styleCat = new StyleCatalog(5);
+
+ doc = sxcDoc.getContentDOM();
+ settings = sxcDoc.getSettingsDOM();
+ initFontTable();
+ // Little fact for the curious reader: workbookName should
+ // be the name of the StarCalc file minus the file extension suffix.
+
+ // Create a Decoder to decode the DeviceContent to a spreadsheet document
+ // TODO - we aren't using a password in StarCalc, so we can
+ // use any value for password here. If StarCalc XML supports
+ // passwords in the future, we should try to get the correct
+ // password value here.
+ //
+ decoder = createDecoder(workbookName, worksheetNames, "password");
+
+ Debug.log(Debug.TRACE, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
+ Debug.log(Debug.TRACE, "<DEBUGLOG>");
+
+ decoder.addDeviceContent(cd);
+ decode();
+
+ Debug.log(Debug.TRACE, "</DEBUGLOG>");
+
+ return sxcDoc;
+ }
+
+ /**
+ * This initializes a font table so we can imclude some basic font
+ * support for spreadsheets.
+ *
+ */
+ private void initFontTable() {
+
+ String fontTable[]= new String[] { "Tahoma", "Tahoma", "swiss", "variable",
+ "Courier New", "&apos;Courier New&apos;", "modern", "fixed"};
+ // Traverse to the office:body element.
+ // There should only be one.
+ NodeList list = doc.getElementsByTagName(TAG_OFFICE_FONT_DECLS);
+ Node root = list.item(0);
+
+ for(int i=0;i<fontTable.length;) {
+
+ // Create an element node for the table
+ Element tableElement = (Element) doc.createElement(TAG_STYLE_FONT_DECL);
+
+ tableElement.setAttribute(ATTRIBUTE_STYLE_NAME, fontTable[i++]);
+ tableElement.setAttribute(ATTRIBUTE_FO_FONT_FAMILY, fontTable[i++]);
+ tableElement.setAttribute(ATTRIBUTE_FO_FONT_FAMILY_GENERIC, fontTable[i++]);
+ tableElement.setAttribute(ATTRIBUTE_STYLE_FONT_PITCH, fontTable[i++]);
+
+ root.appendChild(tableElement);
+ }
+
+ }
+
+ /**
+ * Outer level method used to decode a WorkBook
+ * into a <code>Document</code>.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ protected void decode() throws IOException {
+
+ // Get number of worksheets
+ int numSheets = decoder.getNumberOfSheets();
+ // #i33702# - check for an Empty InputStream.
+ if(numSheets == 0)
+ {
+ System.err.println("Error decoding invalid Input stream");
+ return;
+ }
+
+ // Traverse to the office:body element.
+ // There should only be one.
+ NodeList list = doc.getElementsByTagName(TAG_OFFICE_BODY);
+ Node node = list.item(0);
+
+ for (int i = 0; i < numSheets; i++) {
+
+ // Set the decoder to the correct worksheet
+ decoder.setWorksheet(i);
+
+ int len = list.getLength();
+
+ if (len > 0) {
+
+ // Process the spreadsheet
+ processTable(node);
+ }
+ }
+
+ // Add the Defined Name table if there is one
+ Enumeration nameDefinitionTable = decoder.getNameDefinitions();
+ if(nameDefinitionTable.hasMoreElements()) {
+ processNameDefinition(node, nameDefinitionTable);
+ }
+
+ // add settings
+ NodeList settingsList = settings.getElementsByTagName(TAG_OFFICE_SETTINGS);
+ Node settingsNode = settingsList.item(0);;
+ processSettings(settingsNode);
+
+ }
+
+
+
+ /**
+ * This method process the settings portion
+ * of the <code>Document</code>.
+ *
+ * @param root The root <code>Node</code> of the
+ * <code>Document</code> we are building. This
+ * <code>Node</code> should be a TAG_OFFICE_SETTINGS
+ * tag.
+ */
+ protected void processSettings(Node root) {
+
+ Element configItemSetEntry = (Element) settings.createElement(TAG_CONFIG_ITEM_SET);
+ configItemSetEntry.setAttribute(ATTRIBUTE_CONFIG_NAME, "view-settings");
+ Element configItemMapIndexed = (Element) settings.createElement(TAG_CONFIG_ITEM_MAP_INDEXED);
+ configItemMapIndexed.setAttribute(ATTRIBUTE_CONFIG_NAME, "Views");
+ Element configItemMapEntry = (Element) settings.createElement(TAG_CONFIG_ITEM_MAP_ENTRY);
+ BookSettings bs = (BookSettings) decoder.getSettings();
+ bs.writeNode(settings, configItemMapEntry);
+
+ configItemMapIndexed.appendChild(configItemMapEntry);
+ configItemSetEntry.appendChild(configItemMapIndexed);
+ root.appendChild(configItemSetEntry);
+ }
+
+ /**
+ * This method process a Name Definition Table and generates a portion
+ * of the <code>Document</code>.
+ *
+ * @param root The root <code>Node</code> of the
+ * <code>Document</code> we are building. This
+ * <code>Node</code> should be a TAG_OFFICE_BODY
+ * tag.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ protected void processNameDefinition(Node root, Enumeration eNameDefinitions) throws IOException {
+
+ Debug.log(Debug.TRACE, "<NAMED-EXPRESSIONS>");
+
+ Element namedExpressionsElement = (Element) doc.createElement(TAG_NAMED_EXPRESSIONS);
+
+ while(eNameDefinitions.hasMoreElements()) {
+
+ NameDefinition tableEntry = (NameDefinition) eNameDefinitions.nextElement();
+ tableEntry.writeNode(doc, namedExpressionsElement);
+ }
+
+ root.appendChild(namedExpressionsElement);
+
+ Debug.log(Debug.TRACE, "</NAMED-EXPRESSIONS>");
+ }
+
+ /**
+ * This method process a WorkSheet and generates a portion
+ * of the <code>Document</code>. A spreadsheet is represented
+ * as a table Node in StarOffice XML format.
+ *
+ * @param root The root <code>Node</code> of the
+ * <code>Document</code> we are building. This
+ * <code>Node</code> should be a TAG_OFFICE_BODY
+ * tag.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ protected void processTable(Node root) throws IOException {
+
+ Debug.log(Debug.TRACE, "<TABLE>");
+
+ // Create an element node for the table
+ Element tableElement = (Element) doc.createElement(TAG_TABLE);
+
+ // Get the sheet name
+ String sheetName = decoder.getSheetName();
+
+ // Set the table name attribute
+ tableElement.setAttribute(ATTRIBUTE_TABLE_NAME, sheetName);
+
+ // TODO - style currently hardcoded - get real value
+ // Set table style-name attribute
+ tableElement.setAttribute(ATTRIBUTE_TABLE_STYLE_NAME, "Default");
+
+ // Append the table element to the root node
+ root.appendChild(tableElement);
+
+ Debug.log(Debug.TRACE, "<SheetName>" + sheetName + "</SheetName>");
+
+ // add the various different table-columns
+ processColumns(tableElement);
+
+ // Get each cell and add to doc
+ processCells(tableElement);
+
+ Debug.log(Debug.TRACE, "</TABLE>");
+ }
+
+ /**
+ * <p>This method process the cells in a <code>Document</code>
+ * and generates a portion of the <code>Document</code>.</p>
+ *
+ * <p>This method assumes that records are sorted by
+ * row and then column.</p>
+ *
+ * @param root The <code>Node</code> of the <code>Document</code>
+ * we are building that we will append our cell
+ * <code>Node</code> objects. This <code>Node</code>
+ * should be a TAG_TABLE tag.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ protected void processColumns(Node root) throws IOException {
+
+ for(Enumeration e = decoder.getColumnRowInfos();e.hasMoreElements();) {
+
+ ColumnRowInfo ci = (ColumnRowInfo) e.nextElement();
+ if(ci.isColumn()) {
+ ColumnStyle cStyle = new ColumnStyle("Default",SxcConstants.COLUMN_STYLE_FAMILY,
+ SxcConstants.DEFAULT_STYLE, ci.getSize(), null);
+
+ Style result[] = (Style[]) styleCat.getMatching(cStyle);
+ String styleName;
+ if(result.length==0) {
+
+ cStyle.setName("co" + colStyles++);
+ styleName = cStyle.getName();
+ Debug.log(Debug.TRACE,"No existing style found, adding " + styleName);
+ styleCat.add(cStyle);
+ } else {
+ ColumnStyle existingStyle = (ColumnStyle) result[0];
+ styleName = existingStyle.getName();
+ Debug.log(Debug.TRACE,"Existing style found : " + styleName);
+ }
+
+ // Create an element node for the new row
+ Element colElement = (Element) doc.createElement(TAG_TABLE_COLUMN);
+ colElement.setAttribute(ATTRIBUTE_TABLE_STYLE_NAME, styleName);
+ if(ci.getRepeated()!=1) {
+ String repeatStr = String.valueOf(ci.getRepeated());
+ colElement.setAttribute(ATTRIBUTE_TABLE_NUM_COLUMNS_REPEATED, repeatStr);
+ }
+ root.appendChild(colElement);
+ }
+ }
+ }
+
+ /**
+ * <p>This method process the cells in a <code>Document</code>
+ * and generates a portion of the <code>Document</code>.</p>
+ *
+ * <p>This method assumes that records are sorted by
+ * row and then column.</p>
+ *
+ * @param root The <code>Node</code> of the <code>Document</code>
+ * we are building that we will append our cell
+ * <code>Node</code> objects. This <code>Node</code>
+ * should be a TAG_TABLE tag.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ protected void processCells(Node root) throws IOException {
+
+ // The current row element
+ Element rowElement = null;
+
+ // The current cell element
+ Element cellElement = null;
+
+ // The row number - we may not have any rows (empty sheet)
+ // so set to zero.
+ int row = 0;
+
+ // The column number - This is the expected column number of
+ // the next cell we are reading.
+ int col = 1;
+
+ // The number of columns in the spreadsheet
+ int lastColumn = decoder.getNumberOfColumns();
+
+ //
+ Node autoStylesNode = null;
+
+ // Loop over all cells in the spreadsheet
+ while (decoder.goToNextCell()) {
+
+ // Get the row number
+ int newRow = decoder.getRowNumber();
+
+ // Is the cell in a new row, or part of the current row?
+ if (newRow != row) {
+
+ // Make sure that all the cells in the previous row
+ // have been entered.
+ if (col <= lastColumn && rowElement != null) {
+ int numSkippedCells = lastColumn - col + 1;
+ addEmptyCells(numSkippedCells, rowElement);
+ }
+
+ // log an end row - if we already have a row
+ if (row != 0) {
+ Debug.log(Debug.TRACE, "</tr>");
+ }
+
+ // How far is the new row from the last row?
+ int deltaRows = newRow - row;
+
+ // Check if we have skipped any rows
+ if (deltaRows > 1) {
+ // Add in empty rows
+ addEmptyRows(deltaRows-1, root, lastColumn);
+ }
+
+ // Re-initialize column (since we are in a new row)
+ col = 1;
+
+ // Create an element node for the new row
+ rowElement = (Element) doc.createElement(TAG_TABLE_ROW);
+
+
+ for(Enumeration e = decoder.getColumnRowInfos();e.hasMoreElements();) {
+ ColumnRowInfo cri = (ColumnRowInfo) e.nextElement();
+ if(cri.isRow() && cri.getRepeated()==newRow-1) {
+ // We have the correct Row BIFFRecord for this row
+ RowStyle rStyle = new RowStyle("Default",SxcConstants.ROW_STYLE_FAMILY,
+ SxcConstants.DEFAULT_STYLE, cri.getSize(), null);
+
+ Style result[] = (Style[]) styleCat.getMatching(rStyle);
+ String styleName;
+ if(result.length==0) {
+
+ rStyle.setName("ro" + rowStyles++);
+ styleName = rStyle.getName();
+ Debug.log(Debug.TRACE,"No existing style found, adding " + styleName);
+ styleCat.add(rStyle);
+ } else {
+ RowStyle existingStyle = (RowStyle) result[0];
+ styleName = existingStyle.getName();
+ Debug.log(Debug.TRACE,"Existing style found : " + styleName);
+ }
+ rowElement.setAttribute(ATTRIBUTE_TABLE_STYLE_NAME, styleName);
+ // For now we will not use the repeat column attribute
+ }
+ }
+
+ // Append the row element to the root node
+ root.appendChild(rowElement);
+
+ // Update row number
+ row = newRow;
+
+ Debug.log(Debug.TRACE, "<tr>");
+ }
+
+ // Get the column number of the current cell
+ int newCol = decoder.getColNumber();
+
+ // Check to see if some columns were skipped
+ if (newCol != col) {
+
+ // How many columns have we skipped?
+ int numColsSkipped = newCol - col;
+
+ addEmptyCells(numColsSkipped, rowElement);
+
+ // Update the column number to account for the
+ // skipped cells
+ col = newCol;
+ }
+
+ // Lets start dealing with the cell data
+ Debug.log(Debug.TRACE, "<td>");
+
+ // Get the cell's contents
+ String cellContents = decoder.getCellContents();
+
+ // Get the type of the data in the cell
+ String cellType = decoder.getCellDataType();
+
+ // Get the cell format
+ Format fmt = decoder.getCellFormat();
+
+ // Create an element node for the cell
+ cellElement = (Element) doc.createElement(TAG_TABLE_CELL);
+
+ Node bodyNode = doc.getElementsByTagName(TAG_OFFICE_BODY).item(0);
+
+ // Not every document has an automatic style tag
+ autoStylesNode = doc.getElementsByTagName(
+ TAG_OFFICE_AUTOMATIC_STYLES).item(0);
+
+ if (autoStylesNode == null) {
+ autoStylesNode = doc.createElement(TAG_OFFICE_AUTOMATIC_STYLES);
+ doc.insertBefore(autoStylesNode, bodyNode);
+ }
+
+ CellStyle tStyle = new
+ CellStyle( "Default",SxcConstants.TABLE_CELL_STYLE_FAMILY,
+ SxcConstants.DEFAULT_STYLE, fmt, null);
+ String styleName;
+ Style result[] = (Style[]) styleCat.getMatching(tStyle);
+ if(result.length==0) {
+
+ tStyle.setName("ce" + textStyles++);
+ styleName = tStyle.getName();
+ Debug.log(Debug.TRACE,"No existing style found, adding " + styleName);
+ styleCat.add(tStyle);
+ } else {
+ CellStyle existingStyle = (CellStyle) result[0];
+ styleName = existingStyle.getName();
+ Debug.log(Debug.TRACE,"Existing style found : " + styleName);
+ }
+
+ cellElement.setAttribute(ATTRIBUTE_TABLE_STYLE_NAME, styleName);
+
+ // Store the cell data into the appropriate attributes
+ processCellData(cellElement, cellType, cellContents);
+
+ // Append the cell element to the row node
+ rowElement.appendChild(cellElement);
+
+ // Append the cellContents as a text node
+ Element textElement = (Element) doc.createElement(TAG_PARAGRAPH);
+ cellElement.appendChild(textElement);
+ textElement.appendChild(doc.createTextNode(cellContents));
+
+ Debug.log(Debug.TRACE, cellContents);
+ Debug.log(Debug.TRACE, "</td>");
+
+ // Increment to the column number of the next expected cell
+ col++;
+ }
+
+ // Make sure that the last row is padded correctly
+ if (col <= lastColumn && rowElement != null) {
+ int numSkippedCells = lastColumn - col + 1;
+ addEmptyCells(numSkippedCells, rowElement);
+ }
+
+ // Now write the style catalog to the document
+ if(autoStylesNode!=null) {
+ Debug.log(Debug.TRACE,"Well the autostyle node was found!!!");
+ NodeList nl = styleCat.writeNode(doc, "dummy").getChildNodes();
+ int nlLen = nl.getLength(); // nl.item reduces the length
+ for (int i = 0; i < nlLen; i++) {
+ autoStylesNode.appendChild(nl.item(0));
+ }
+ }
+
+ if (row != 0) {
+
+ // The sheet does have rows, so write out a /tr
+ Debug.log(Debug.TRACE, "</tr>");
+ }
+ }
+
+
+ /**
+ * This method will add empty rows to the <code>Document</code>.
+ * It is called when the conversion process encounters
+ * a row (or rows) that do not contain any data in its cells.
+ *
+ * @param numEmptyRows The number of empty rows that we
+ * need to add to the <code>Document</code>.
+ * @param root The <code>Node</code> of the
+ * <code>Document</code> we are building
+ * that we will append our empty row
+ * <code>Node</code> objects. This
+ * <code>Node</code> should be a TAG_TABLE
+ * tag.
+ * @param numEmptyCells The number of empty cells in the
+ * empty row.
+ */
+ protected void addEmptyRows(int numEmptyRows, Node root, int numEmptyCells) {
+
+ // Create an element node for the row
+ Element rowElement = (Element) doc.createElement(TAG_TABLE_ROW);
+
+ // TODO - style currently hardcoded - get real value
+ // Set row style-name attribute
+ rowElement.setAttribute(ATTRIBUTE_TABLE_STYLE_NAME, "Default");
+
+ // Set cell number-rows-repeated attribute
+ rowElement.setAttribute(ATTRIBUTE_TABLE_NUM_ROWS_REPEATED,
+ Integer.toString(numEmptyRows));
+
+ // Append the row element to the root node
+ root.appendChild(rowElement);
+
+ // Open Office requires the empty row to have an empty cell (or cells)
+ addEmptyCells(numEmptyCells, rowElement);
+
+ // Write empty rows to the log
+ for (int i = 0; i < numEmptyRows; i++) {
+ Debug.log(Debug.TRACE, "<tr />");
+ }
+
+ }
+
+
+ /**
+ * This method will add empty cells to the <code>Document</code>.
+ * It is called when the conversion process encounters a row
+ * that contains some cells without data.
+ *
+ * @param numColsSkipped The number of empty cells
+ * that we need to add to the
+ * current row.
+ * @param row The <code>Node</code> of the
+ * <code>Document</code> we
+ * are building that we will
+ * append our empty cell
+ * <code>Node</code> objects.
+ * This <code>Node</code> should
+ * be a TAG_TABLE_ROW tag.
+ */
+ protected void addEmptyCells(int numColsSkipped, Node row) {
+
+ // Create an empty cellElement
+ Element cellElement = (Element) doc.createElement(TAG_TABLE_CELL);
+
+ // TODO - style currently hardcoded - get real value
+ // Set cell style-name attribute
+ cellElement.setAttribute(ATTRIBUTE_TABLE_STYLE_NAME, "Default");
+
+ // If we skipped more than 1 cell, we must set the
+ // appropriate attribute
+ if (numColsSkipped > 1) {
+
+ // Set cell number-columns-repeated attribute
+ cellElement.setAttribute(ATTRIBUTE_TABLE_NUM_COLUMNS_REPEATED,
+ Integer.toString(numColsSkipped));
+ }
+
+ // Append the empty cell element to the row node
+ row.appendChild(cellElement);
+
+ // Write empty cells to the log
+ for (int i = 0; i < numColsSkipped; i++) {
+ Debug.log(Debug.TRACE, "<td />");
+ }
+ }
+
+
+ /**
+ * This method process the data in a cell and sets
+ * the appropriate attributes on the cell <code>Element</code>.
+ *
+ * @param cellElement A TAG_TABLE_CELL <code>Element</code>
+ * that we will be adding attributes to
+ * based on the type of data in the cell.
+ * @param type The type of data contained in the cell.
+ * @param contents The contents of the data contained in
+ * the cell.
+ */
+ protected void processCellData(Element cellElement, String type,
+ String contents) {
+
+ // Set cell value-type attribute
+ cellElement.setAttribute(ATTRIBUTE_TABLE_VALUE_TYPE, type);
+
+ // Does the cell contain a formula?
+ if (contents.startsWith("=")) {
+
+ cellElement.setAttribute(ATTRIBUTE_TABLE_FORMULA, contents);
+
+ cellElement.setAttribute(ATTRIBUTE_TABLE_VALUE, decoder.getCellValue());
+ // String data does not require any additional attributes
+ } else if (!type.equals(CELLTYPE_STRING)) {
+
+ if (type.equals(CELLTYPE_TIME)) {
+
+ // Data returned in StarOffice XML format, so store in
+ // attribute
+ cellElement.setAttribute(ATTRIBUTE_TABLE_TIME_VALUE,
+ contents);
+
+ } else if (type.equals(CELLTYPE_DATE)) {
+
+ // Data returned in StarOffice XML format, so store in
+ // attribute
+ cellElement.setAttribute(ATTRIBUTE_TABLE_DATE_VALUE,
+ contents);
+
+ } else if (type.equals(CELLTYPE_BOOLEAN)) {
+
+ // StarOffice XML format requires stored boolean value
+ // to be in lower case
+ cellElement.setAttribute(ATTRIBUTE_TABLE_BOOLEAN_VALUE,
+ contents.toLowerCase());
+
+ } else if (type.equals(CELLTYPE_CURRENCY)) {
+ // TODO - StarOffice XML format requires a correct style to
+ // display currencies correctly. Need to implement styles.
+ // TODO - USD is for US currencies. Need to pick up
+ // the correct currency location from the source file.
+ cellElement.setAttribute(ATTRIBUTE_TABLE_CURRENCY, "USD");
+
+ // Data comes stripped of currency symbols
+ cellElement.setAttribute(ATTRIBUTE_TABLE_VALUE, contents);
+
+ } else if (type.equals(CELLTYPE_PERCENT)) {
+ // Data comes stripped of percent signs
+ cellElement.setAttribute(ATTRIBUTE_TABLE_VALUE, contents);
+
+ } else {
+ // Remaining data types use table-value attribute
+
+ cellElement.setAttribute(ATTRIBUTE_TABLE_VALUE, contents);
+ }
+ }
+ }
+
+}
+
diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/SxcDocumentSerializer.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/SxcDocumentSerializer.java
new file mode 100644
index 000000000000..b0cfc09893bc
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/SxcDocumentSerializer.java
@@ -0,0 +1,993 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxc;
+
+import java.awt.Color;
+
+import org.w3c.dom.NodeList;
+import org.w3c.dom.Node;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Element;
+
+import java.io.IOException;
+import java.util.Vector;
+import java.util.Enumeration;
+
+import org.openoffice.xmerge.Document;
+import org.openoffice.xmerge.ConvertData;
+import org.openoffice.xmerge.ConvertException;
+import org.openoffice.xmerge.DocumentSerializer;
+
+import org.openoffice.xmerge.converter.xml.OfficeConstants;
+import org.openoffice.xmerge.converter.xml.sxc.SxcDocument;
+import org.openoffice.xmerge.converter.xml.sxc.CellStyle;
+import org.openoffice.xmerge.converter.xml.StyleCatalog;
+
+import org.openoffice.xmerge.util.Debug;
+import org.openoffice.xmerge.util.XmlUtil;
+
+/**
+ * <p>General spreadsheet implementation of <code>DocumentSerializer</code>
+ * for the {@link
+ * org.openoffice.xmerge.converter.xml.sxc.SxcPluginFactory
+ * SxcPluginFactory}. Used with SXC <code>Document</code> objects.</p>
+ *
+ * <p>The <code>serialize</code> method traverses the DOM
+ * <code>Document</code> from the given <code>Document</code> object.
+ * It uses a <code>DocEncoder</code> object for the actual conversion
+ * of contents to the device spreadsheet format.</p>
+ *
+ * @author Paul Rank
+ * @author Mark Murnane
+ */
+public abstract class SxcDocumentSerializer implements OfficeConstants,
+ DocumentSerializer {
+
+ /** The cell foreground <code>Color</code>. */
+ private Color foreground = Color.black;
+
+ /** The cell background <code>Color</code>. */
+ private Color background = Color.white;
+
+ /** The cell format. */
+ private long format = 0;
+
+ /** <code>Format</code> object describing the cell. */
+ private Format fmt = null;
+
+ /** The row number. */
+ private int rowID = 1;
+
+ /** The column number. */
+ private int colID = 1;
+
+ /** The number of times the current row is repeated. */
+ private int rowsRepeated = 1;
+
+ /** The number of times the current column is repeated. */
+ private int colsRepeated = 1;
+
+ /** The number of times the current column is repeated. */
+ private StyleCatalog styleCat = null;
+ /**
+ * An array of column widths of the current worksheet. Width is
+ * measured in number of characters.
+ */
+ private Vector ColumnRowList;
+
+ /** Width, in characters, of the current cell display data. */
+ private int displayWidth = 0;
+
+ /**
+ * A <code>SpreadsheetEncoder</code> object for encoding to
+ * appropriate format.
+ */
+ protected SpreadsheetEncoder encoder = null;
+
+ /** <code>SxcDocument</code> object that this converter processes. */
+ protected SxcDocument sxcDoc = null;
+
+
+ /**
+ * Constructor.
+ *
+ * @param document Input <code>SxcDocument</code>
+ * <code>Document</code>.
+ */
+ public SxcDocumentSerializer(Document document) {
+ fmt = new Format();
+ sxcDoc = (SxcDocument) document;
+ }
+
+
+ /**
+ * <p>Method to convert a DOM <code>Document</code> into
+ * &quot;Device&quot; <code>Document</code> objects.</p>
+ *
+ * <p>This method is not thread safe for performance reasons.
+ * This method should not be called from within two threads.
+ * It would be best to call this method only once per object
+ * instance.</p>
+ *
+ * @return <code>ConvertData</code> containing &quot;Device&quot;
+ * <code>Document</code> objects.
+ *
+ * @throws ConvertException If any conversion error occurs.
+ * @throws IOException If any I/O error occurs.
+ */
+ public abstract ConvertData serialize() throws ConvertException,
+ IOException;
+
+
+ /**
+ * This method traverses <i>office:settings</i> <code>Element</code>.
+ *
+ * @param node <i>office:settings</i> <code>Node</code>.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ public void traverseSettings(Node node) throws IOException {
+ if (node.hasChildNodes()) {
+
+ NodeList nodeList = node.getChildNodes();
+ int len = nodeList.getLength();
+ for (int i = 0; i < len; i++) {
+ Node child = nodeList.item(i);
+
+ if (child.getNodeType() == Node.ELEMENT_NODE) {
+ String nodeName = child.getNodeName();
+
+ if (nodeName.equals(TAG_CONFIG_ITEM_SET)) {
+
+ traverseSettings(child);
+
+ } else if (nodeName.equals(TAG_CONFIG_ITEM_MAP_INDEXED)) {
+
+ traverseSettings(child);
+
+ } else if (nodeName.equals(TAG_CONFIG_ITEM_MAP_ENTRY)) {
+
+ BookSettings bs = new BookSettings(child);
+ encoder.addSettings(bs);
+
+ } else {
+
+ Debug.log(Debug.TRACE, "<OTHERS " + XmlUtil.getNodeInfo(child) + " />");
+ }
+ }
+ }
+ }
+ }
+
+ /*
+ * Handles the loading of defined styles from the style.xml file as well
+ * as automatic styles from the content.xml file.
+ *
+ * Any change to a defined style, such as a short bold section, falls into
+ * the latter category.
+ */
+ protected void loadStyles(SxcDocument sxcDoc) {
+
+ styleCat = new StyleCatalog(25);
+ NodeList nl = null;
+ String families[] = new String[] { SxcConstants.COLUMN_STYLE_FAMILY,
+ SxcConstants.ROW_STYLE_FAMILY,
+ SxcConstants.TABLE_CELL_STYLE_FAMILY };
+ Class classes[] = new Class[] { ColumnStyle.class,
+ RowStyle.class,
+ CellStyle.class};
+ /*
+ * Process the content XML for any other style info.
+ */
+ org.w3c.dom.Document contentDom = sxcDoc.getContentDOM();
+ nl = contentDom.getElementsByTagName(TAG_OFFICE_AUTOMATIC_STYLES);
+ if (nl.getLength() != 0) {
+ styleCat.add(nl.item(0), families, classes, null, false);
+ }
+
+ org.w3c.dom.Document stylesDom = sxcDoc.getStyleDOM();
+ nl = stylesDom.getElementsByTagName(TAG_OFFICE_STYLES);
+ if (nl.getLength() != 0) {
+ styleCat.add(nl.item(0), families, classes, null, false);
+ }
+ }
+
+ /**
+ * This method traverses <i>office:body</i> <code>Element</code>.
+ *
+ * @param node <i>office:body</i> <code>Node</code>.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ protected void traverseBody(Node node) throws IOException {
+
+ Debug.log(Debug.TRACE, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
+ Debug.log(Debug.TRACE, "<DEBUGLOG>");
+
+ if (node.hasChildNodes()) {
+
+ NodeList nodeList = node.getChildNodes();
+ int len = nodeList.getLength();
+
+ for (int i = 0; i < len; i++) {
+ Node searchNode = nodeList.item(i);
+ if (searchNode.getNodeType() == Node.ELEMENT_NODE) {
+
+ String nodeName = searchNode.getNodeName();
+
+ if (nodeName.equals(TAG_NAMED_EXPRESSIONS)) {
+
+ traverseNamedExpressions(searchNode);
+
+ } else {
+
+ Debug.log(Debug.TRACE, "Skipping " + XmlUtil.getNodeInfo(searchNode) + " />");
+ }
+ }
+ }
+
+ for (int i = 0; i < len; i++) {
+ Node child = nodeList.item(i);
+
+ if (child.getNodeType() == Node.ELEMENT_NODE) {
+ String nodeName = child.getNodeName();
+
+ if (nodeName.equals(TAG_TABLE)) {
+
+ traverseTable(child);
+
+ } else {
+
+ Debug.log(Debug.TRACE, "<OTHERS " + XmlUtil.getNodeInfo(child) + " />");
+ }
+ }
+ }
+ }
+
+ Debug.log(Debug.TRACE, "</DEBUGLOG>");
+ }
+
+
+ /**
+ * This method traverses the <i>table:table</i> element
+ * <code>Node</code>.
+ *
+ * @param node A <i>table:table</i> <code>Node</code>.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ protected void traverseNamedExpressions(Node node) throws IOException {
+
+ Debug.log(Debug.TRACE, "<NAMED:EXPRESSIONS>");
+
+ NamedNodeMap att = node.getAttributes();
+
+ if (node.hasChildNodes()) {
+
+ NodeList nodeList = node.getChildNodes();
+ int len = nodeList.getLength();
+
+ for (int i = 0; i < len; i++) {
+ Node child = nodeList.item(i);
+
+ if (child.getNodeType() == Node.ELEMENT_NODE) {
+ NameDefinition nd = new NameDefinition(child);
+ encoder.setNameDefinition(nd);
+ }
+ }
+ }
+
+ Debug.log(Debug.TRACE, "</NAMED:EXPRESSIONS>");
+ }
+
+ /**
+ * This method traverses the <i>table:table</i> element
+ * <code>Node</code>.
+ *
+ * @param node A <i>table:table</i> <code>Node</code>.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ protected void traverseTable(Node node) throws IOException {
+
+ Debug.log(Debug.TRACE, "<TABLE>");
+
+ ColumnRowList = new Vector();
+
+ // Get table attributes
+ // TODO - extract style from attribute
+
+ NamedNodeMap att = node.getAttributes();
+
+ String tableName =
+ att.getNamedItem(ATTRIBUTE_TABLE_NAME).getNodeValue();
+
+ rowID = 1;
+
+ encoder.createWorksheet(tableName);
+
+ if (node.hasChildNodes()) {
+
+ NodeList nodeList = node.getChildNodes();
+ int len = nodeList.getLength();
+
+ for (int i = 0; i < len; i++) {
+ Node child = nodeList.item(i);
+
+ if (child.getNodeType() == Node.ELEMENT_NODE) {
+ String nodeName = child.getNodeName();
+
+ if (nodeName.equals(TAG_TABLE_ROW)) {
+ // TODO - handle all the possible rows
+ // spelled out in the entities
+
+ traverseTableRow(child);
+
+ } else if (nodeName.equals(TAG_TABLE_COLUMN)) {
+
+ traverseTableColumn(child);
+
+ } else if (nodeName.equals(TAG_TABLE_SCENARIO)) {
+
+ // TODO
+
+ } else {
+
+ Debug.log(Debug.TRACE, "<OTHERS " + XmlUtil.getNodeInfo(child) + " />");
+ }
+ }
+ }
+ }
+
+ // Add column width info to the current sheet
+ encoder.setColumnRows(ColumnRowList);
+
+ Debug.log(Debug.TRACE, "</TABLE>");
+ }
+
+ /**
+ * This method traverses the <i>table:table-row</i> element
+ * <code>Node</code>.
+ *
+ * @param node A <i>table:table-row</i> <code>Node</code>.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ protected void traverseTableRow(Node node) throws IOException {
+
+ // Get the attributes of the row
+ NamedNodeMap cellAtt = node.getAttributes();
+
+ if (cellAtt != null) {
+
+ Node rowStyle =
+ cellAtt.getNamedItem(ATTRIBUTE_TABLE_STYLE_NAME);
+
+ Node tableNumRowRepeatingNode = cellAtt.getNamedItem(ATTRIBUTE_TABLE_NUM_ROWS_REPEATED);
+ int repeatedRows = 1;
+
+ if(tableNumRowRepeatingNode!=null) {
+ String repeatStr = tableNumRowRepeatingNode.getNodeValue();
+ Debug.log(Debug.TRACE, "traverseTableRow() repeated-rows : " + repeatStr);
+ repeatedRows = Integer.parseInt(repeatStr);
+ }
+
+ String styleName = new String("");
+
+ if ( rowStyle != null) {
+ styleName = rowStyle.getNodeValue();
+ }
+ if(styleName.equalsIgnoreCase("Default") || styleName.length()==0) {
+
+ Debug.log(Debug.TRACE, "No defined Row Style Attribute was found");
+
+ } else {
+
+ RowStyle rStyle = ( RowStyle)styleCat.lookup(styleName,
+ SxcConstants.ROW_STYLE_FAMILY, null,
+ RowStyle.class);
+
+ int rowHeight = rStyle.getRowHeight();
+
+ Debug.log(Debug.TRACE, "traverseTableRow() Row Height : " + rowHeight);
+ ColumnRowInfo ri = new ColumnRowInfo( rowHeight,
+ repeatedRows,
+ ColumnRowInfo.ROW,
+ rowHeight!=0);
+ ColumnRowList.add(ri);
+ }
+
+ // Get the attribute representing the number of rows repeated
+ Node rowsRepeatedNode =
+ cellAtt.getNamedItem(ATTRIBUTE_TABLE_NUM_ROWS_REPEATED);
+
+ // There is a number of rows repeated attribute:
+ if (rowsRepeatedNode != null) {
+
+ // Get the number of times the row is repeated
+ String rowsRepeatedString = rowsRepeatedNode.getNodeValue();
+
+ Integer rowsRepeatedInt = new Integer(rowsRepeatedString);
+
+ rowsRepeated = rowsRepeatedInt.intValue();
+
+ } else {
+
+ // The row is not repeated
+ rowsRepeated = 1;
+ }
+ }
+
+ Debug.log(Debug.TRACE, "<TR>");
+
+ if (node.hasChildNodes()) {
+
+ NodeList nodeList = node.getChildNodes();
+ int len = nodeList.getLength();
+
+ for (int i = 0; i < len; i++) {
+ Node child = nodeList.item(i);
+
+ if (child.getNodeType() == Node.ELEMENT_NODE) {
+ String nodeName = child.getNodeName();
+
+ if (nodeName.equals(TAG_TABLE_CELL)) {
+
+ traverseCell(child);
+
+ } else {
+
+ Debug.log(Debug.TRACE, "<OTHERS " + XmlUtil.getNodeInfo(child) + " />");
+ }
+ }
+ }
+ }
+
+ // Increase the row counter by the number of rows which are repeated
+ rowID += rowsRepeated;
+
+ // Re-initialize number of rows repeated before processing the next
+ // row data.
+ rowsRepeated = 1;
+
+ // When starting a new row, set the column counter back to the
+ // first column.
+ colID = 1;
+
+ // Re-initialize number of columns repeated before processing
+ // the next row data.
+ colsRepeated = 1;
+
+ Debug.log(Debug.TRACE, "</TR>");
+ }
+
+
+ /**
+ * This method traverses the <i>table:table-column</i>
+ * <code>Node</code>. Not yet implemented.
+ *
+ * @param node A <i>table:table-column</i> <code>Node</code>.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ protected void traverseTableColumn(Node node) throws IOException {
+
+ Debug.log(Debug.TRACE, "traverseColumn() : ");
+ NamedNodeMap cellAtt = node.getAttributes();
+ Node tableStyleNode = cellAtt.getNamedItem(ATTRIBUTE_TABLE_STYLE_NAME);
+ Node tableNumColRepeatingNode = cellAtt.getNamedItem(ATTRIBUTE_TABLE_NUM_COLUMNS_REPEATED);
+ Node tableDefaultCellStyle = cellAtt.getNamedItem(ATTRIBUTE_DEFAULT_CELL_STYLE);
+
+ int repeatedColumns = 1;
+ int columnWidth = 0;
+ ColumnRowInfo col = new ColumnRowInfo(ColumnRowInfo.COLUMN);
+
+ if(tableNumColRepeatingNode!=null) {
+ Debug.log(Debug.TRACE, "traverseColumn() repeated-cols : " + tableNumColRepeatingNode.getNodeValue());
+ repeatedColumns = Integer.parseInt(tableNumColRepeatingNode.getNodeValue());
+ col.setRepeated(repeatedColumns);
+ }
+
+ String cellStyleName = new String("");
+
+ if(tableDefaultCellStyle!=null) {
+ cellStyleName = tableDefaultCellStyle.getNodeValue();
+
+ Debug.log(Debug.TRACE, "traverseColumn() default-cell-style : " + cellStyleName);
+ }
+
+ if(cellStyleName.equalsIgnoreCase("Default") || cellStyleName.length()==0) {
+
+ Debug.log(Debug.TRACE, "No default cell Style Attribute was found");
+
+ } else {
+
+ CellStyle cellStyle = (CellStyle)styleCat.lookup(cellStyleName,
+ SxcConstants.TABLE_CELL_STYLE_FAMILY, null,
+ CellStyle.class);
+ Format defaultFmt = new Format(cellStyle.getFormat());
+ col.setFormat(defaultFmt);
+ }
+
+ String styleName = new String("");
+
+ if(tableStyleNode!=null) {
+ styleName = tableStyleNode.getNodeValue();
+ }
+
+ if(styleName.equalsIgnoreCase("Default") || styleName.length()==0) {
+
+ Debug.log(Debug.TRACE, "No defined Style Attribute was found");
+
+ } else {
+
+ ColumnStyle cStyle = (ColumnStyle)styleCat.lookup(styleName,
+ SxcConstants.COLUMN_STYLE_FAMILY, null,
+ ColumnStyle.class);
+
+ columnWidth = cStyle.getColWidth();
+ col.setSize(columnWidth);
+ Debug.log(Debug.TRACE, "traverseColumn() Column Width : " + columnWidth);
+
+ }
+ ColumnRowList.add(col);
+ }
+
+ /**
+ * This method traverses a <i>table:table-cell</i> element
+ * <code>Node</code>.
+ *
+ * @param node a <i>table:table-cell</i> <code>Node</code>.
+ *
+ * @throws IOException if any I/O error occurs.
+ */
+ protected void traverseCell(Node node) throws IOException {
+
+ NamedNodeMap cellAtt = node.getAttributes();
+
+ int debug_i=0;
+ Node debug_attrib = null;
+ fmt.clearFormatting();
+ if (cellAtt == null || cellAtt.item(0) == null)
+ {
+ Debug.log(Debug.INFO, "No Cell Attributes\n");
+ // return;
+ }
+ else
+ {
+ while ((debug_attrib = cellAtt.item(debug_i++)) != null)
+ {
+ Debug.log(Debug.INFO, "Cell Attribute " + debug_i +
+ ": " + debug_attrib.getNodeName() + " : " +
+ debug_attrib.getNodeValue() + "\n");
+ }
+ }
+
+ // Get the type of data in the cell
+ Node tableValueTypeNode =
+ cellAtt.getNamedItem(ATTRIBUTE_TABLE_VALUE_TYPE);
+
+ // Get the number of columns this cell is repeated
+ Node colsRepeatedNode =
+ cellAtt.getNamedItem(ATTRIBUTE_TABLE_NUM_COLUMNS_REPEATED);
+
+ // Get the style type
+ Node tableStyleNode =
+ cellAtt.getNamedItem(ATTRIBUTE_TABLE_STYLE_NAME);
+
+ String styleName = new String("");
+
+ if(tableStyleNode!=null) {
+ styleName = tableStyleNode.getNodeValue();
+ }
+
+ if(styleName.equalsIgnoreCase("Default")) {
+
+ Debug.log(Debug.TRACE, "No defined Style Attribute was found");
+
+ } else if(styleName.length()!=0) {
+
+ CellStyle cStyle = (CellStyle)styleCat.lookup(styleName,
+ SxcConstants.TABLE_CELL_STYLE_FAMILY, null,
+ CellStyle.class);
+
+ Format definedFormat = cStyle.getFormat();
+ fmt = new Format(definedFormat);
+ }
+
+ // There is a number of cols repeated attribute
+ if (colsRepeatedNode != null) {
+
+ // Get the number of times the cell is repeated
+ String colsRepeatedString = colsRepeatedNode.getNodeValue();
+
+ Integer colsRepeatedInt = new Integer(colsRepeatedString);
+ colsRepeated = colsRepeatedInt.intValue();
+ } else {
+
+ // The cell is not repeated
+ colsRepeated = 1;
+ }
+
+
+ // if there is no style we need to check to see if there is a default
+ // cell style defined in the table-column's
+
+ if (fmt.isDefault() && styleName.length()==0) {
+ int index = 1;
+ for(Enumeration e = ColumnRowList.elements();e.hasMoreElements();) {
+ ColumnRowInfo cri = (ColumnRowInfo) e.nextElement();
+ if(cri.isColumn()) {
+ if(colID>=index && colID<(index+cri.getRepeated())) {
+ fmt = new Format(cri.getFormat());
+ }
+ index += cri.getRepeated();
+ }
+ }
+ }
+
+
+ // for (int j = 0; j < colsRepeated; j++) {
+
+
+ if (tableValueTypeNode != null) {
+
+ // Make sure we initialize to 0 the width of the current cell
+ displayWidth = 0;
+
+ String cellType =
+ tableValueTypeNode.getNodeValue();
+
+ if (cellType.equalsIgnoreCase(CELLTYPE_STRING)) {
+
+ // has text:p tag
+ fmt.setCategory(CELLTYPE_STRING);
+ Node tableStringValueNode = cellAtt.getNamedItem(ATTRIBUTE_TABLE_STRING_VALUE);
+ Debug.log(Debug.TRACE,"Cell Type String : " + tableStringValueNode);
+ if(tableStringValueNode != null) {
+ fmt.setValue(tableStringValueNode.getNodeValue());
+ }
+
+ } else if (cellType.equalsIgnoreCase(CELLTYPE_FLOAT)) {
+
+ // has table:value attribute
+ // has text:p tag
+
+ // Determine the number of decimal places StarCalc
+ // is displaying for this floating point output.
+ fmt.setCategory(CELLTYPE_FLOAT);
+ fmt.setDecimalPlaces(getDecimalPlaces(node));
+ Node tableValueNode = cellAtt.getNamedItem(ATTRIBUTE_TABLE_VALUE);
+ fmt.setValue(tableValueNode.getNodeValue());
+
+
+ } else if (cellType.equalsIgnoreCase(CELLTYPE_TIME)) {
+
+ // has table:time-value attribute
+ // has text:p tag - which is the value we convert
+
+ fmt.setCategory(CELLTYPE_TIME);
+ Node tableTimeNode = cellAtt.getNamedItem(ATTRIBUTE_TABLE_TIME_VALUE);
+ fmt.setValue(tableTimeNode.getNodeValue());
+
+ } else if (cellType.equalsIgnoreCase(CELLTYPE_DATE)) {
+
+ // has table:date-value attribute
+ // has text:p tag - which is the value we convert
+
+ fmt.setCategory(CELLTYPE_DATE);
+ Node tableDateNode = cellAtt.getNamedItem(ATTRIBUTE_TABLE_DATE_VALUE);
+ fmt.setValue(tableDateNode.getNodeValue());
+
+ } else if (cellType.equalsIgnoreCase(CELLTYPE_CURRENCY)) {
+
+ // has table:currency
+ // has table:value attribute
+ // has text:p tag
+
+ fmt.setCategory(CELLTYPE_CURRENCY);
+ fmt.setDecimalPlaces(getDecimalPlaces(node));
+ Node tableValueNode = cellAtt.getNamedItem(ATTRIBUTE_TABLE_VALUE);
+ fmt.setValue(tableValueNode.getNodeValue());
+
+ } else if (cellType.equalsIgnoreCase(CELLTYPE_BOOLEAN)) {
+
+ // has table:boolean-value attribute
+ // has text:p tag - which is the value we convert
+
+ fmt.setCategory(CELLTYPE_BOOLEAN);
+ Node tableBooleanNode = cellAtt.getNamedItem(ATTRIBUTE_TABLE_BOOLEAN_VALUE);
+ fmt.setValue(tableBooleanNode.getNodeValue());
+
+ } else if (cellType.equalsIgnoreCase(CELLTYPE_PERCENT)) {
+
+ // has table:value attribute
+ // has text:p tag
+
+ fmt.setCategory(CELLTYPE_PERCENT);
+ fmt.setDecimalPlaces(getDecimalPlaces(node));
+ Node tableValueNode = cellAtt.getNamedItem(ATTRIBUTE_TABLE_VALUE);
+ fmt.setValue(tableValueNode.getNodeValue());
+
+ } else {
+
+ Debug.log(Debug.TRACE,"No defined value type" + cellType);
+ // Should never get here
+
+ }
+ }
+
+ Node tableFormulaNode = cellAtt.getNamedItem(ATTRIBUTE_TABLE_FORMULA);
+
+ if(tableFormulaNode != null)
+ {
+ if(tableValueTypeNode == null) { // If there is no value-type Node we must assume string-value
+ fmt.setCategory(CELLTYPE_STRING);
+ Node tableStringValueNode = cellAtt.getNamedItem(ATTRIBUTE_TABLE_STRING_VALUE);
+ fmt.setValue(tableStringValueNode.getNodeValue());
+ }
+ String cellFormula = tableFormulaNode.getNodeValue();
+ addCell(cellFormula);
+ } else {
+
+ // Text node, Date node, or Time node
+ //
+ Debug.log(Debug.INFO,
+ "TextNode, DateNode, TimeNode or BooleanNode\n");
+ // This handles the case where we have style information but no content
+ if (node.hasChildNodes()) {
+ NodeList childList = node.getChildNodes();
+ int len = childList.getLength();
+
+ for (int i = 0; i < len; i++) {
+ Node child = childList.item(i);
+ if (child.getNodeType() == Node.ELEMENT_NODE) {
+ String childName = child.getNodeName();
+ if (childName.equals(TAG_PARAGRAPH)) {
+ traverseParagraph(child);
+ }
+ }
+ }
+ } else if(!fmt.isDefault()) {
+ addCell("");
+ }
+ }
+
+ // Clear out format for current cell after it is written
+ format = 0;
+
+ // Increase the column counter by the number of times the
+ // last cell was repeated.
+ colID += colsRepeated;
+
+ // Re-initialize the number of columns repeated before processing
+ // the next cell data.
+ colsRepeated = 1;
+
+ }
+
+
+ /**
+ * This method traverses the <i>text:p</i> element <code>Node</code>.
+ *
+ * @param node A <i>text:p</i> <code>Node</code>.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ protected void traverseParagraph(Node node) throws IOException {
+
+ NamedNodeMap cellAtt = node.getAttributes();
+
+ int debug_i=0;
+ Node debug_attrib = null;
+ if (cellAtt == null || cellAtt.item(0) == null)
+ {
+ Debug.log(Debug.INFO, "No Paragraph Attributes\n");
+ }
+ else
+ {
+ while ((debug_attrib = cellAtt.item(debug_i++)) != null)
+ {
+ Debug.log(Debug.INFO, "Paragraph Attribute " + debug_i +
+ ": " + debug_attrib.getNodeName() + " : " +
+ debug_attrib.getNodeValue() + "\n");
+ }
+ }
+
+ if (node.hasChildNodes()) {
+
+ NodeList nodeList = node.getChildNodes();
+
+ int len = nodeList.getLength();
+
+ StringBuffer buffer = new StringBuffer();
+
+ for (int i = 0; i < len; i++) {
+
+ Node child = nodeList.item(i);
+
+ // TODO: need to handle space/tabs/newline nodes later
+ short nodeType = child.getNodeType();
+
+ switch (nodeType) {
+
+ case Node.TEXT_NODE:
+ buffer.append(child.getNodeValue());
+ break;
+
+ case Node.ENTITY_REFERENCE_NODE:
+
+ NodeList nodeList2 = child.getChildNodes();
+ int len2 = nodeList2.getLength();
+
+ for (int j = 0; j < len2; j++) {
+ Node child2 = nodeList2.item(j);
+
+ if (child2.getNodeType() == Node.TEXT_NODE) {
+ buffer.append(child2.getNodeValue());
+ }
+ }
+
+ break;
+ }
+ }
+
+ String s = buffer.toString();
+ // displayWidth = calculateContentWidth(s);
+ addCell(s);
+
+ }
+ }
+
+
+ /**
+ * This method will take the input cell value and add
+ * it to the spreadsheet <code>Document</code> we are currently
+ * encoding. This method correctly handles cells that are
+ * repeated in either the row, cell, or both directions.
+ *
+ * @param cellValue The contents of the cell we want to add
+ * to the spreadsheet <code>Document</code>.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ protected void addCell(String cellValue) throws IOException {
+
+ int col = colID;
+ int row = rowID;
+
+ for (int i = 0; i < rowsRepeated; i++) {
+
+ // Log the columns when there are rowsRepeated.
+ if (i > 0) {
+ Debug.log(Debug.TRACE, "</TR>");
+ Debug.log(Debug.TRACE, "<TR>");
+ }
+
+ col = colID;
+
+ for (int j = 0; j < colsRepeated; j++) {
+
+ Debug.log(Debug.TRACE, "<TD>");
+
+
+ // Add the cell data to the encoded spreadsheet document
+ encoder.addCell(row, col, fmt, cellValue);
+
+ Debug.log(Debug.TRACE, cellValue);
+ Debug.log(Debug.TRACE, "</TD>");
+
+ col++;
+ }
+
+ row++;
+
+ }
+
+ }
+
+
+
+ /**
+ * This method takes a <i>table:table-cell</i> <code>Node</code>
+ * and traverses down to the <i>text:p</i> tag. The value is
+ * extracted from the <i>text:p</i> tag and the number of decimal
+ * places is calculated.
+ *
+ * @param node A <i>table:table-cell</i> <code>Node</code>.
+ *
+ * @return The number of decimal places in the display
+ * string of the data in the input <code>Node</code>.
+ */
+ protected int getDecimalPlaces(Node node) {
+
+ int decimals = 0;
+
+ Element element = null;
+
+ // cast org.w3c.dom.Node to org.w3c.dom.Element
+ if (node instanceof Element) {
+ element = (Element) node;
+ } else {
+ return decimals;
+ }
+
+ // Traverse to the text:p element, there should only be one.
+ NodeList list = element.getElementsByTagName(TAG_PARAGRAPH);
+
+ if (list.getLength() != 1) {
+ return decimals;
+ }
+
+ Node paragraph = list.item(0);
+
+ if (paragraph.hasChildNodes()) {
+
+ NodeList nodeList = paragraph.getChildNodes();
+
+ int len = nodeList.getLength();
+
+ for (int j = 0; j < len; j++) {
+
+ Node child = nodeList.item(j);
+
+ if (child.getNodeType() == Node.TEXT_NODE) {
+
+ String s = child.getNodeValue();
+
+ // displayWidth = calculateContentWidth(s);
+
+ int k = s.lastIndexOf(".");
+ if (k > 0) {
+ s = s.substring(k+1);
+ decimals = s.length();
+ }
+ }
+ }
+ }
+
+ return decimals;
+ }
+
+ /*
+ * Utility method to retrieve a Node attribute.
+ */
+ private String getAttribute (Node node, String attribute) {
+ NamedNodeMap attrNodes = node.getAttributes();
+
+ if (attrNodes != null) {
+ Node attr = attrNodes.getNamedItem(attribute);
+ if (attr != null) {
+ return attr.getNodeValue();
+ }
+ }
+ return null;
+ }
+
+}
+
diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/SxcPluginFactory.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/SxcPluginFactory.java
new file mode 100644
index 000000000000..401bdff1f533
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/SxcPluginFactory.java
@@ -0,0 +1,82 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxc;
+
+import java.io.InputStream;
+import java.io.IOException;
+
+import org.openoffice.xmerge.util.registry.ConverterInfo;
+import org.openoffice.xmerge.PluginFactory;
+import org.openoffice.xmerge.Document;
+import org.openoffice.xmerge.DocumentMergerFactory;
+
+
+/**
+ * General implementation of the <code>PluginFactory</code> interface
+ * for SXC <code>Document</code> objects.
+ *
+ * @see org.openoffice.xmerge.DocumentDeserializer
+ * @see org.openoffice.xmerge.DocumentMerger
+ * @see org.openoffice.xmerge.DocumentSerializer
+ */
+public abstract class SxcPluginFactory
+ extends PluginFactory implements DocumentMergerFactory {
+
+
+ /**
+ * Constructor that caches the <code>ConvertInfo</code> that
+ * corresponds to the registry information for this plug-in.
+ *
+ * @param ci <code>ConvertInfo</code> object.
+ */
+ public SxcPluginFactory(ConverterInfo ci) {
+ super(ci);
+ }
+
+
+ public Document createOfficeDocument(String name, InputStream is)
+ throws IOException {
+
+ // read zipped XML stream
+ //
+ SxcDocument doc = new SxcDocument(name);
+ doc.read(is);
+ return doc;
+ }
+
+ public Document createOfficeDocument(String name, InputStream is,boolean isZip)
+ throws IOException {
+
+ // read zipped XML stream
+ //
+ SxcDocument doc = new SxcDocument(name);
+ doc.read(is,isZip);
+ return doc;
+ }
+}
+
diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/package.html b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/package.html
new file mode 100644
index 000000000000..d350ea262303
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxc/package.html
@@ -0,0 +1,40 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<!--
+ #*************************************************************************
+ #
+ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+
+ Copyright 2000, 2010 Oracle and/or its affiliates.
+
+ OpenOffice.org - a multi-platform office productivity suite
+
+ This file is part of OpenOffice.org.
+
+ OpenOffice.org is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License version 3
+ only, as published by the Free Software Foundation.
+
+ OpenOffice.org is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License version 3 for more details
+ (a copy is included in the LICENSE file that accompanied this code).
+
+ You should have received a copy of the GNU Lesser General Public License
+ version 3 along with OpenOffice.org. If not, see
+ <http://www.openoffice.org/license.html>
+ for a copy of the LGPLv3 License.
+
+ #*************************************************************************
+ -->
+<html>
+<head>
+<title>org.openoffice.xmerge.converter.xml.sxc package</title>
+</head>
+
+<body bgcolor="white">
+<p>Provides base implementation of StarCalc XML conversion to and from
+different &quot;Device&quot; <code>Document</code> formats.</p>
+
+</body>
+</html>
diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxw/SxwDocument.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxw/SxwDocument.java
new file mode 100644
index 000000000000..0485c4a435c0
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxw/SxwDocument.java
@@ -0,0 +1,94 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxw;
+
+import org.openoffice.xmerge.converter.xml.OfficeDocument;
+import org.openoffice.xmerge.converter.xml.OfficeConstants;
+
+/**
+ * This class is an implementation of <code>OfficeDocument</code> for
+ * the SXW format.
+ */
+public class SxwDocument extends OfficeDocument {
+
+
+ /**
+ * Constructor with arguments to set <code>name</code>.
+ *
+ * @param name The name of the <code>Document</code>
+ */
+ public SxwDocument(String name) {
+ super(name);
+ }
+
+
+ /**
+ * Constructor with arguments to set <code>name</code>, the
+ * <code>namespaceAware</code> flag, and the <code>validating</code>
+ * flag.
+ *
+ * @param name The name of the <code>Document</code>.
+ * @param namespaceAware The value of the namespaceAware flag.
+ * @param validating The value of the validating flag.
+ */
+ public SxwDocument(String name, boolean namespaceAware, boolean validating) {
+
+ super(name, namespaceAware, validating);
+ }
+
+
+ /**
+ * Returns the Office file extension for the SXW format.
+ *
+ * @return The Office file extension for the SXW format.
+ */
+ protected String getFileExtension() {
+ return OfficeConstants.SXW_FILE_EXTENSION;
+ }
+
+
+ /**
+ * Returns the Office attribute for the SXW format.
+ *
+ * @return The Office attribute for the SXW format.
+ */
+ protected String getOfficeClassAttribute() {
+ return OfficeConstants.SXW_TYPE;
+ }
+
+ /**
+ * Method to return the MIME type of the document.
+ *
+ * @return String The document's MIME type.
+ */
+ protected final String getDocumentMimeType() {
+ return OfficeConstants.SXW_MIME_TYPE;
+ }
+
+}
+
diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxw/SxwPluginFactory.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxw/SxwPluginFactory.java
new file mode 100644
index 000000000000..a1f53bfd9ede
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxw/SxwPluginFactory.java
@@ -0,0 +1,76 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxw;
+
+import java.io.InputStream;
+import java.io.IOException;
+
+import org.openoffice.xmerge.PluginFactory;
+import org.openoffice.xmerge.Document;
+import org.openoffice.xmerge.util.registry.ConverterInfo;
+
+/**
+ * General implementation of the <code>PluginFactory</code> interface
+ * for SXW documents.
+ *
+ * @see org.openoffice.xmerge.DocumentDeserializer
+ * @see org.openoffice.xmerge.DocumentMerger
+ * @see org.openoffice.xmerge.DocumentSerializer
+ */
+public abstract class SxwPluginFactory extends PluginFactory {
+
+ /**
+ * Constructor that caches the <code>ConvertInfo</code> that
+ * corresponds to the registry information for this plug-in.
+ *
+ * @param ci <code>ConvertInfo</code> object.
+ */
+ public SxwPluginFactory (ConverterInfo ci) {
+ super(ci);
+ }
+
+
+ public Document createOfficeDocument(String name, InputStream is)
+ throws IOException {
+
+ // read zipped XML stream
+ SxwDocument doc = new SxwDocument(name);
+ doc.read(is);
+ return doc;
+ }
+
+ public Document createOfficeDocument(String name, InputStream is,boolean isZip)
+ throws IOException {
+
+ // read XML stream
+ SxwDocument doc = new SxwDocument(name);
+ doc.read(is,isZip);
+ return doc;
+ }
+}
+
diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxw/package.html b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxw/package.html
new file mode 100644
index 000000000000..a9ced174ff5a
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/sxw/package.html
@@ -0,0 +1,40 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<!--
+ #*************************************************************************
+ #
+ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+
+ Copyright 2000, 2010 Oracle and/or its affiliates.
+
+ OpenOffice.org - a multi-platform office productivity suite
+
+ This file is part of OpenOffice.org.
+
+ OpenOffice.org is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License version 3
+ only, as published by the Free Software Foundation.
+
+ OpenOffice.org is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License version 3 for more details
+ (a copy is included in the LICENSE file that accompanied this code).
+
+ You should have received a copy of the GNU Lesser General Public License
+ version 3 along with OpenOffice.org. If not, see
+ <http://www.openoffice.org/license.html>
+ for a copy of the LGPLv3 License.
+
+ #*************************************************************************
+ -->
+<html>
+<head>
+<title>org.openoffice.xmerge.converter.xml.sxw package</title>
+</head>
+
+<body bgcolor="white">
+<p>Provides base implementation of StarWriter XML conversion to and from
+different &quot;Device&quot; <code>Document</code> formats.</p>
+
+</body>
+</html>
diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/xslt/ConverterCapabilitiesImpl.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/xslt/ConverterCapabilitiesImpl.java
new file mode 100644
index 000000000000..5f6e4ac38ce2
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/xslt/ConverterCapabilitiesImpl.java
@@ -0,0 +1,93 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.xslt;
+
+import org.openoffice.xmerge.ConverterCapabilities;
+import org.openoffice.xmerge.converter.xml.OfficeConstants;
+
+/**
+ * <p>Xslt implementation of <code>ConverterCapabilities</code> for
+ * the {@link
+ * org.openoffice.xmerge.converter.xml.xslt.PluginFactoryImpl
+ * PluginFactoryImpl}.</p>
+ *
+ * <p>Used with StarWriter XML to/from XSLT supported formats conversions. The
+ * <code>ConverterCapibilies</code> specify which &quot;Office&quot;
+ * <code>Document</code> tags and attributes are supported on the
+ * &quot;Device&quot; <code>Document</code> format.</p>
+ */
+public final class ConverterCapabilitiesImpl
+ implements ConverterCapabilities {
+
+ public boolean canConvertTag(String tag) {
+
+ if (OfficeConstants.TAG_OFFICE_DOCUMENT.equals(tag))
+ return true;
+ else if (OfficeConstants.TAG_OFFICE_DOCUMENT_CONTENT.equals(tag))
+ return true;
+ else if (OfficeConstants.TAG_OFFICE_BODY.equals(tag))
+ return true;
+ else if (OfficeConstants.TAG_PARAGRAPH.equals(tag))
+ return true;
+ else if (OfficeConstants.TAG_HEADING.equals(tag))
+ return true;
+ else if (OfficeConstants.TAG_ORDERED_LIST.equals(tag))
+ return true;
+ else if (OfficeConstants.TAG_UNORDERED_LIST.equals(tag))
+ return true;
+ else if (OfficeConstants.TAG_LIST_ITEM.equals(tag))
+ return true;
+ else if (OfficeConstants.TAG_LIST_HEADER.equals(tag))
+ return true;
+ else if (OfficeConstants.TAG_SPAN.equals(tag))
+ return true;
+ else if (OfficeConstants.TAG_HYPERLINK.equals(tag))
+ return true;
+ else if (OfficeConstants.TAG_LINE_BREAK.equals(tag))
+ return true;
+ else if (OfficeConstants.TAG_SPACE.equals(tag))
+ return true;
+ else if (OfficeConstants.TAG_TAB_STOP.equals(tag))
+ return true;
+
+ return false;
+ }
+
+ public boolean canConvertAttribute(String tag,
+ String attribute) {
+
+ if (OfficeConstants.TAG_SPACE.equals(tag)) {
+
+ if (OfficeConstants.ATTRIBUTE_SPACE_COUNT.equals(attribute))
+ return true;
+ }
+
+ return false;
+ }
+}
+
diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/xslt/DocumentDeserializerImpl.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/xslt/DocumentDeserializerImpl.java
new file mode 100644
index 000000000000..e118cc690ea0
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/xslt/DocumentDeserializerImpl.java
@@ -0,0 +1,250 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.xslt;
+
+import java.io.InputStream;
+import java.io.IOException;
+import java.util.Enumeration;
+import java.io.ByteArrayOutputStream;
+import java.io.ByteArrayInputStream;
+
+
+
+
+import org.openoffice.xmerge.Document;
+import org.openoffice.xmerge.ConvertData;
+import org.openoffice.xmerge.ConvertException;
+import org.openoffice.xmerge.DocumentDeserializer;
+import org.openoffice.xmerge.converter.dom.DOMDocument;
+//import org.openoffice.xmerge.converter.xml.sxw.SxwDocument;
+import org.openoffice.xmerge.converter.xml.xslt.GenericOfficeDocument;
+import org.openoffice.xmerge.util.Debug;
+import org.openoffice.xmerge.util.registry.ConverterInfo;
+
+// Imported TraX classes
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.dom.DOMSource;
+//import javax.xml.transform.dom.DOMResult;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerConfigurationException;
+import javax.xml.transform.stream.StreamResult;
+import javax.xml.transform.stream.StreamSource;
+import javax.xml.transform.URIResolver;
+import javax.xml.transform.Source;
+
+
+//
+//import org.apache.xalan.serialize.Serializer;
+//import org.apache.xalan.serialize.SerializerFactory;
+//import org.apache.xalan.templates.OutputProperties;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+
+// Imported java classes
+import java.io.FileNotFoundException;
+
+
+/**
+ * <p>Xslt implementation of
+ * org.openoffice.xmerge.DocumentSerializer
+ * for the {@link
+ * org.openoffice.xmerge.converter.xml.xslt.PluginFactoryImpl
+ * PluginFactoryImpl}.</p>
+ *
+ * <p>The <code>serialize</code> method transforms the DOM
+ * document from the given <code>Document</code> object by
+ * means of a supplied Xsl Stylesheet.</p>
+ *
+ * @author Aidan Butler
+ */
+public final class DocumentDeserializerImpl
+ implements DocumentDeserializer,URIResolver {
+
+ /** A <code>ConvertData</code> object assigned to this object. */
+ private InputStream is = null;
+ private ConvertData cd = null;
+ private PluginFactoryImpl pluginFactory = null;
+
+ /**
+ * Constructor that assigns the given <code>ConvertData</code>
+ * to this object.
+ *
+ * @param pf A <code>PluginFactoryImpl</code> object.
+ *
+ * @param cd A <code>ConvertData</code> object to read data for
+ * the conversion process by the <code>deserialize</code>
+ * method.
+ */
+ public DocumentDeserializerImpl(PluginFactoryImpl pf,ConvertData cd) {
+ this.cd = cd;
+ pluginFactory = pf;
+ }
+
+
+
+ /*
+ * This method performs the xslt transformation on the supplied <code>
+ * Document</code> and returns a <code>ByteArrayOutputStream</code> object.
+ *
+ * Xslt transformation code
+ *
+ * @return baos A <code>ByteArrayOutputStream</code> object containing
+ * the result of the Xslt transformation.
+ * @throws TransformerException,TransformerConfigurationException
+ * , FileNotFoundException,IOException
+ *
+ */
+ public Document deserialize() throws ConvertException, IOException {
+ log("\nFound the XSLT deserializer");
+ Enumeration enumerate = cd.getDocumentEnumeration();
+ org.w3c.dom.Document domDoc=null;
+ DOMDocument docOut=null;
+ GenericOfficeDocument doc = null;
+ ByteArrayOutputStream baos =null;
+ GenericOfficeDocument sxwDoc = new GenericOfficeDocument("output");
+ while (enumerate.hasMoreElements()) {
+ docOut = (DOMDocument) enumerate.nextElement();
+ }
+ domDoc = docOut.getContentDOM();
+ try{
+ baos = transform(domDoc);
+ sxwDoc.initContentDOM();
+ DocumentBuilderFactory dFactory = DocumentBuilderFactory.newInstance();
+ dFactory.setNamespaceAware(true);
+ DocumentBuilder dBuilder = dFactory.newDocumentBuilder();
+ sxwDoc.setContentDOM(dBuilder.parse(new ByteArrayInputStream(baos.toByteArray())));
+
+ }
+ catch(Exception e){
+ System.out.println("The following error occurred:"+e);
+ }
+ return sxwDoc;
+ }
+
+ public Source resolve(String href,String base)
+ throws TransformerException{
+ //System.out.println("\nhref "+href+"\nbase "+base);
+ if (href !=null){
+ if(href.equals("javax.xml.transform.dom.DOMSource")|| href.equals(""))
+ return null;
+ try{
+ ConverterInfo ci = pluginFactory.getConverterInfo();
+ String newhRef ="jar:"+ci.getJarName()+"!/"+href;
+ //System.out.println("\n Looking For "+ newhRef);
+ StreamSource sheetFile= new StreamSource(newhRef);
+ return sheetFile;
+ }
+ catch (Exception e){
+ System.out.println("\nException in Xslt Resolver " +e);
+ return null;
+ }
+ }
+ else
+ return null;
+ }
+
+ /*
+ * This method performs the xslt transformation on the supplied Dom Tree.
+ *
+ * Xslt transformation code
+ *
+ * @throws TransformerException,TransformerConfigurationException
+ * , FileNotFoundException,IOException
+ *
+ */
+ private ByteArrayOutputStream transform(org.w3c.dom.Document xmlDoc)
+ throws TransformerException,TransformerConfigurationException
+ , FileNotFoundException,IOException{
+
+ log("\nTransforming...");
+ ConverterInfo ci = pluginFactory.getConverterInfo();
+ ByteArrayOutputStream baos= new ByteArrayOutputStream();
+ try{
+ DocumentBuilderFactory dFactory = DocumentBuilderFactory.newInstance();
+ dFactory.setNamespaceAware(true);
+ DocumentBuilder dBuilder = dFactory.newDocumentBuilder();
+
+ String teststr = ci.getXsltDeserial();
+ teststr= teststr.substring(0,6);
+ org.w3c.dom.Document xslDoc=null;
+ if ((teststr.equals("http:/"))||(teststr.equals("file:/"))
+ ||(teststr.equals("jar://"))){
+ log(ci.getXsltDeserial());
+ xslDoc= dBuilder.parse(ci.getXsltDeserial());
+
+ }
+ else{
+ log(ci.getJarName()+"!/"+ci.getXsltDeserial());
+ xslDoc = dBuilder.parse(
+ "jar:"+ci.getJarName()+"!/"+ci.getXsltDeserial());
+ }
+
+
+ DOMSource xslDomSource = new DOMSource(xslDoc);
+ DOMSource xmlDomSource = new DOMSource(xmlDoc);
+
+ //call the tranformer using the XSL, Source and Result dom.
+ TransformerFactory tFactory = TransformerFactory.newInstance();
+ tFactory.setURIResolver(this);
+ Transformer transformer = tFactory.newTransformer(xslDomSource);
+ transformer.transform(xmlDomSource,new StreamResult(baos));
+ /*
+ // Serialize for output to standard out
+ Serializer serializer = SerializerFactory.getSerializer
+ (OutputProperties.getDefaultMethodProperties("xml"));
+ serializer.setOutputStream(System.out);
+ serializer.asDOMSerializer().serialize(xmlDomResult.getNode());
+ */
+
+ log("\n** Transform Complete ***");
+
+ }
+ catch (StackOverflowError sOE){
+ System.out.println("\nERROR : Stack Overflow Error During Transformation\n Try increasing the stack size by passing the -Xss1m option to the JRE.");
+ throw sOE;
+ }
+ catch(Exception e){
+ System.out.println("An error occured in the transformation : "+e);
+ }
+ return baos;
+ }
+
+ /**
+ * Sends message to the log object.
+ *
+ * @param str Debug message.
+ */
+ private void log(String str) {
+
+ Debug.log(Debug.TRACE, str);
+ }
+
+}
+
diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/xslt/DocumentMergerImpl.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/xslt/DocumentMergerImpl.java
new file mode 100644
index 000000000000..6416d0d531a0
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/xslt/DocumentMergerImpl.java
@@ -0,0 +1,97 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.xslt;
+
+import org.w3c.dom.Document;
+
+import org.openoffice.xmerge.DocumentMerger;
+import org.openoffice.xmerge.MergeException;
+import org.openoffice.xmerge.ConverterCapabilities;
+import org.openoffice.xmerge.converter.xml.xslt.GenericOfficeDocument;
+import org.openoffice.xmerge.merger.DiffAlgorithm;
+import org.openoffice.xmerge.merger.Difference;
+import org.openoffice.xmerge.merger.NodeMergeAlgorithm;
+import org.openoffice.xmerge.merger.Iterator;
+import org.openoffice.xmerge.merger.diff.ParaNodeIterator;
+import org.openoffice.xmerge.merger.diff.IteratorLCSAlgorithm;
+import org.openoffice.xmerge.merger.merge.DocumentMerge;
+import org.openoffice.xmerge.merger.merge.CharacterBaseParagraphMerge;
+import org.openoffice.xmerge.util.Debug;
+
+
+/**
+ * Xslt implementation of <code>DocumentMerger</code>
+ * for the {@link
+ * org.openoffice.xmerge.converter.xml.xslt.PluginFactoryImpl
+ * PluginFactoryImpl}.</p>
+ */
+public class DocumentMergerImpl implements DocumentMerger {
+
+ private ConverterCapabilities cc_;
+ private org.openoffice.xmerge.Document orig = null;
+
+ public DocumentMergerImpl(org.openoffice.xmerge.Document doc, ConverterCapabilities cc) {
+ cc_ = cc;
+ this.orig = doc;
+ }
+
+ public void merge(org.openoffice.xmerge.Document modifiedDoc) throws MergeException {
+
+ GenericOfficeDocument wdoc1 = (GenericOfficeDocument) orig;
+ GenericOfficeDocument wdoc2 = (GenericOfficeDocument) modifiedDoc;
+
+ Document doc1 = wdoc1.getContentDOM();
+ Document doc2 = wdoc2.getContentDOM();
+
+ Iterator i1 = new ParaNodeIterator(cc_, doc1.getDocumentElement());
+ Iterator i2 = new ParaNodeIterator(cc_, doc2.getDocumentElement());
+
+ DiffAlgorithm diffAlgo = new IteratorLCSAlgorithm();
+
+ // find out the paragrah level diffs
+ Difference[] diffTable = diffAlgo.computeDiffs(i1, i2);
+
+ if (Debug.isFlagSet(Debug.INFO)) {
+ Debug.log(Debug.INFO, "Diff Result: ");
+
+ for (int i = 0; i < diffTable.length; i++) {
+ Debug.log(Debug.INFO, diffTable[i].debug());
+ }
+ }
+
+ // merge the paragraphs
+ NodeMergeAlgorithm charMerge = new CharacterBaseParagraphMerge();
+ DocumentMerge docMerge = new DocumentMerge(cc_, charMerge);
+
+ Iterator result = null;
+
+ docMerge.applyDifference(i1, i2, diffTable);
+ }
+}
+
+
diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/xslt/DocumentSerializerImpl.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/xslt/DocumentSerializerImpl.java
new file mode 100644
index 000000000000..5bf8d4983da1
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/xslt/DocumentSerializerImpl.java
@@ -0,0 +1,297 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.xslt;
+
+import org.w3c.dom.NodeList;
+import org.w3c.dom.Node;
+import org.w3c.dom.Element;
+import org.w3c.dom.*;
+
+import java.io.IOException;
+import java.io.ByteArrayOutputStream;
+import java.io.ByteArrayInputStream;
+
+import org.openoffice.xmerge.Document;
+import org.openoffice.xmerge.ConvertData;
+import org.openoffice.xmerge.ConvertException;
+import org.openoffice.xmerge.DocumentSerializer;
+import org.openoffice.xmerge.converter.xml.xslt.GenericOfficeDocument;
+import org.openoffice.xmerge.converter.dom.DOMDocument;
+import org.openoffice.xmerge.util.registry.ConverterInfo;
+import org.openoffice.xmerge.converter.xml.OfficeConstants;
+
+// Imported TraX classes
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.stream.StreamSource;
+import javax.xml.transform.stream.StreamResult;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerConfigurationException;
+import javax.xml.transform.URIResolver;
+import javax.xml.transform.Source;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+
+// Imported java classes
+import java.io.FileNotFoundException;
+
+/**
+ * <p>Xslt implementation of
+ * org.openoffice.xmerge.DocumentSerializer
+ * for the {@link
+ * org.openoffice.xmerge.converter.xml.xslt.PluginFactoryImpl
+ * PluginFactoryImpl}.</p>
+ *
+ * <p>The <code>serialize</code> method transforms the DOM
+ * document from the given <code>Document</code> object by
+ * means of a supplied Xsl Stylesheet.</p>
+ *
+ * @author Aidan Butler
+ */
+
+
+public final class DocumentSerializerImpl
+ implements DocumentSerializer,OfficeConstants,URIResolver {
+
+
+ /** SXW <code>Document</code> object that this converter processes. */
+ private GenericOfficeDocument sxwDoc = null;
+
+ private PluginFactoryImpl pluginFactory = null;
+
+ /**
+ * Constructor.
+ *
+ * @param pf A <code>PluginFactoryImpl</code>
+ * @param doc A SXW <code>Document</code> to be converted.
+ */
+ public DocumentSerializerImpl(PluginFactoryImpl pf,Document doc) {
+ pluginFactory=pf;
+ sxwDoc = (GenericOfficeDocument) doc;
+ }
+
+
+ /**
+ * Method to convert a <code>Document</code> with an xsl stylesheet.
+ * It creates a <code>Document</code> object, which is then transformed
+ * with the Xslt processer. A <code>ConvertData </code> object is
+ * constructed and returned.
+ *
+ * @return cd A <code>ConvertData</code> object.
+ * @throws ConvertException If any I/O error occurs.
+ * @throws IOException If any I/O error occurs.
+ */
+ public ConvertData serialize() throws ConvertException, IOException {
+ String docName = sxwDoc.getName();
+ org.w3c.dom.Document domDoc = sxwDoc.getContentDOM();
+ org.w3c.dom.Document metaDoc = sxwDoc.getMetaDOM();
+ org.w3c.dom.Document styleDoc = sxwDoc.getStyleDOM();
+ ByteArrayOutputStream baos= new ByteArrayOutputStream();
+ ConvertData cd = new ConvertData();
+ Node offnode = (Node)domDoc.getDocumentElement();
+ if (!(offnode.getNodeName()).equals("office:document")){
+ try{
+ DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
+ DocumentBuilder builder= builderFactory.newDocumentBuilder();
+ DOMImplementation domImpl = builder.getDOMImplementation();
+ DocumentType docType =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",docType);
+
+
+ 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" );
+ rootElement.setAttribute("office:class","text" );
+ rootElement.setAttribute("office:version","1.0");
+
+
+ NodeList nodeList;
+ Node tmpNode;
+ Node rootNode = (Node)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 (domDoc !=null){
+ nodeList= domDoc.getElementsByTagName(TAG_OFFICE_AUTOMATIC_STYLES);
+ if (nodeList.getLength()>0){
+ tmpNode = newDoc.importNode(nodeList.item(0),true);
+ rootNode.appendChild(tmpNode);
+ }
+ nodeList= domDoc.getElementsByTagName(TAG_OFFICE_BODY);
+ if (nodeList.getLength()>0){
+ tmpNode = newDoc.importNode(nodeList.item(0),true);
+ rootNode.appendChild(tmpNode);
+ }
+ }
+ domDoc=newDoc;
+ }catch(Exception e){
+ System.out.println("\nAn Exception occurred with Xslt Serializer"+e);
+ }
+
+ }
+
+ try{
+ baos=transform(domDoc);
+ }
+ catch (Exception e){
+ System.out.println("\n Error with Xslt\n");
+ }
+
+ String ext = pluginFactory.getDeviceFileExtension();
+ DOMDocument resultDomDoc=(DOMDocument)pluginFactory.createDeviceDocument(docName,new ByteArrayInputStream(baos.toByteArray()));
+ cd.addDocument (resultDomDoc);
+ return cd;
+ }
+
+ public Source resolve(String href,String base)
+ throws TransformerException{
+ //System.out.println("\nhref "+href+"\nbase "+base);
+ if (href !=null){
+ if(href.equals("javax.xml.transform.dom.DOMSource")|| href.equals(""))
+ return null;
+ try{
+ ConverterInfo ci = pluginFactory.getConverterInfo();
+ String newhRef ="jar:"+ci.getJarName()+"!/"+href;
+ //System.out.println("\n Looking For "+ newhRef);
+ StreamSource sheetFile= new StreamSource(newhRef);
+ return sheetFile;
+ }
+ catch (Exception e){
+ System.out.println("\nException in Xslt Resolver " +e);
+ return null;
+ }
+ }
+ else
+ return null;
+ }
+
+
+ /*
+ * This method performs the sxl transformation on the supplied <code>
+ * Document</code> and returns a <code>DOMResult</code> object.
+ *
+ * Xslt transformation code
+ *
+ * @return baos A <code>ByteArrayOutputStream</code> object containing
+ * the result of the Xslt transformation.
+ * @throws TransformerException,TransformerConfigurationException
+ * , FileNotFoundException,IOException
+ *
+ */
+
+
+ private ByteArrayOutputStream transform(org.w3c.dom.Document domDoc)
+ throws TransformerException,TransformerConfigurationException
+ , FileNotFoundException,IOException{
+ //System.out.println("\nTransforming...");
+ ConverterInfo ci = pluginFactory.getConverterInfo();
+ //DOMResult xmlDomResult = new DOMResult();
+ ByteArrayOutputStream baos= new ByteArrayOutputStream();
+ try{
+
+ DocumentBuilderFactory dFactory = DocumentBuilderFactory.newInstance();
+ dFactory.setNamespaceAware(true);
+
+ DocumentBuilder dBuilder = dFactory.newDocumentBuilder();
+ String teststr = ci.getXsltSerial();
+
+ teststr= teststr.substring(0,6);
+ org.w3c.dom.Document xslDoc=null;
+ if ((teststr.equals("http:/"))||(teststr.equals("file:/"))
+ ||(teststr.equals("jar://"))){
+ System.out.println(ci.getXsltSerial());
+ xslDoc= dBuilder.parse(ci.getXsltSerial());
+
+ }
+ else{
+ //System.out.println(ci.getJarName()+"!/"+ci.getXsltSerial());
+ xslDoc = dBuilder.parse(
+ "jar:"+ci.getJarName()+"!/"+ci.getXsltSerial());
+ }
+
+ DOMSource xslDomSource = new DOMSource(xslDoc);
+ DOMSource xmlDomSource = new DOMSource(domDoc);
+
+ //call the tranformer using the XSL, Source and Result.
+ TransformerFactory tFactory = TransformerFactory.newInstance();
+ tFactory.setURIResolver(this);
+ Transformer transformer = tFactory.newTransformer(xslDomSource);
+
+ transformer.transform(xmlDomSource, new StreamResult(baos));
+
+ /*
+ transformer.transform(xmlDomSource, xmlDomResult); //Removed this impl because the DocType was not being written out
+
+ // Serialize for output to standard out
+ Serializer serializer = SerializerFactory.getSerializer
+ (OutputProperties.getDefaultMethodProperties("xml"));
+ //serializer.setOutputStream(System.out);
+ serializer.setOutputStream(baos);
+ serializer.asDOMSerializer().serialize(xmlDomResult.getNode());
+ //serializer.asDOMSerializer().serialize(xmlDomSource.getNode());
+
+
+ //System.out.println("\n** Transform Complete ***");
+ */
+ }
+ catch(Exception e){
+ System.out.println("An error occured in the transformation : "+e);
+ }
+ return baos;
+ }
+
+
+}
+
diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/xslt/GenericOfficeDocument.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/xslt/GenericOfficeDocument.java
new file mode 100644
index 000000000000..d0ecb2c943ac
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/xslt/GenericOfficeDocument.java
@@ -0,0 +1,93 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.xslt;
+
+import org.openoffice.xmerge.converter.xml.OfficeDocument;
+
+/**
+ * This class is an implementation of <code>OfficeDocument</code> for
+ * the generic office format.
+ */
+public class GenericOfficeDocument extends OfficeDocument {
+
+ /**
+ * Constructor with arguments to set <code>name</code>.
+ *
+ * @param name The name of the <code>Document</code>
+ */
+ public GenericOfficeDocument(String name) {
+ super(name);
+ }
+
+
+ /**
+ * Constructor with arguments to set <code>name</code>, the
+ * <code>namespaceAware</code> flag, and the <code>validating</code>
+ * flag.
+ *
+ * @param name The name of the <code>Document</code>.
+ * @param namespaceAware The value of the <code>namespaceAware</code>
+ * flag.
+ * @param validating The value of the <code>validating</code> flag.
+ */
+ public GenericOfficeDocument(String name, boolean namespaceAware, boolean validating) {
+
+ super(name, namespaceAware, validating);
+ }
+
+ /**
+ * Returns the Office file extension for the generic format.
+ *
+ * @return The Office file extension for the generic format.
+ */
+ protected String getFileExtension() {
+ return "";
+ }
+
+ /**
+ * Returns the Office attribute for the generic format.
+ *
+ * @return The Office attribute for the generic format.
+ */
+ protected String getOfficeClassAttribute() {
+
+ return "";
+ }
+
+ /**
+ * Method to return the MIME type of the document.
+ *
+ * @return String The document's MIME type.
+ */
+ protected String getDocumentMimeType() {
+ /* TODO: Determine the MIME-type from the input. */
+ return "";
+ }
+
+}
+
diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/xslt/PluginFactoryImpl.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/xslt/PluginFactoryImpl.java
new file mode 100644
index 000000000000..36872751e999
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/xslt/PluginFactoryImpl.java
@@ -0,0 +1,202 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.xslt;
+
+import org.openoffice.xmerge.Document;
+import org.openoffice.xmerge.ConvertData;
+import org.openoffice.xmerge.DocumentSerializer;
+import org.openoffice.xmerge.DocumentSerializerFactory;
+import org.openoffice.xmerge.DocumentDeserializer;
+import org.openoffice.xmerge.DocumentDeserializerFactory;
+import org.openoffice.xmerge.PluginFactory;
+import org.openoffice.xmerge.converter.dom.DOMDocument;
+//import org.openoffice.xmerge.converter.xml.sxw.SxwDocument;
+//import org.openoffice.xmerge.converter.xml.OfficeDocument;
+import org.openoffice.xmerge.converter.xml.xslt.GenericOfficeDocument;
+import org.openoffice.xmerge.util.registry.ConverterInfo;
+import org.openoffice.xmerge.DocumentMerger;
+import org.openoffice.xmerge.DocumentMergerFactory;
+import org.openoffice.xmerge.ConverterCapabilities;
+
+import java.io.InputStream;
+import java.util.Enumeration;
+import java.io.IOException;
+import java.util.Properties;
+
+/**
+ * <p>Xslt implementation of the <code>PluginFactory</code>.
+ * This encapsulates conversion of StarWriter XML format to and from
+ * a supported format.</p>
+ *
+ * <p>The superclass produces a particular
+ * {@link org.openoffice.xmerge.Document Document}
+ * object, i.e. {@link
+ * org.openoffice.xmerge.converter.xml.sxw.SxwDocument
+ * SxwDocument} that the converters in this class work with. Thus,
+ * this class only implements the methods that produces the converters,
+ * i.e. {@link
+ * org.openoffice.xmerge.DocumentSerializer
+ * DocumentSerializer} and {@link
+ * org.openoffice.xmerge.DocumentDeserializer
+ * DocumentDeserializer}</p>
+ *
+ * @author Aidan Butler
+ */
+public final class PluginFactoryImpl extends PluginFactory
+ implements DocumentDeserializerFactory, DocumentSerializerFactory, DocumentMergerFactory
+{
+
+ public PluginFactoryImpl (ConverterInfo ci) {
+ super(ci);
+ }
+
+ /** ConverterCapabilities object for this type of conversion. */
+ private final static ConverterCapabilities converterCap =
+ new ConverterCapabilitiesImpl();
+
+
+ /**
+ * Returns an instance of <code>DocumentSerializerImpl</code>,
+ * which is an implementation of the <code>DocumentSerializer</code>
+ * interface.
+ *
+ * @param doc <code>Document</code> object to be
+ * converted/serialized.
+ *
+ * @return A <code>DocumentSerializerImpl</code> object.
+ */
+ public DocumentSerializer createDocumentSerializer(Document doc) {
+ return new DocumentSerializerImpl(this,doc);
+ }
+
+
+ /**
+ * Returns an instance of <code>DocumentDeserializerImpl</code>,
+ * which is an implementation of the <code>DocumentDeserializer</code>
+ * interface.
+ *
+ * @param cd <code>ConvertData</code> object.
+ *
+ * @return A DocumentDeserializerImpl object.
+ */
+ public DocumentDeserializer createDocumentDeserializer(ConvertData cd) {
+
+ return new DocumentDeserializerImpl(this,cd);
+ }
+
+ public org.openoffice.xmerge.Document createDeviceDocument(java.lang.String str, java.io.InputStream inputStream) throws java.io.IOException {
+ String ext = this.getDeviceFileExtension();
+ DOMDocument domDoc = new DOMDocument(str,ext);
+ domDoc.read(inputStream);
+ return domDoc;
+ }
+
+
+ public Document createOfficeDocument(String name, InputStream is)
+ throws IOException {
+
+ // read zipped XML stream
+ GenericOfficeDocument doc = new GenericOfficeDocument(name);
+ doc.read(is);
+ return doc;
+ }
+
+ public Document createOfficeDocument(String name, InputStream is,boolean isZip)
+ throws IOException {
+
+ // read zipped XML stream
+ GenericOfficeDocument doc = new GenericOfficeDocument(name);
+ doc.read(is,isZip);
+ return doc;
+ }
+
+ /**
+ * Returns a <code>String</code> containing the file extension of a
+ * <code>Document</code>. This method uses a properties file to determine
+ * a mapping from the device mime in the <code>ConverterInfo</code> to a
+ * particular file extension. If a mapping is not specified, the default
+ * is ".txt".
+ *
+ * @return <code>String</code>.
+ */
+
+
+ public String getDeviceFileExtension(){
+ Class c = this.getClass();
+ InputStream is = c.getResourceAsStream("XsltPlugin.properties");
+ Properties props = new Properties();
+ String ext= ".txt";
+ String mimeType = null;
+ ConverterInfo ci = this.getConverterInfo();
+ Enumeration enumerate = ci.getDeviceMime();
+ while (enumerate.hasMoreElements()) {
+ mimeType= (String) enumerate.nextElement();
+ }
+ try {
+ props.load(is);
+
+ String info = props.getProperty(mimeType);
+ if (info != null) {
+ ext = info;
+ }
+ } catch (Exception e) {
+
+ // It is okay for the property file to not exist.
+ //
+ }
+ return ext;
+ }
+
+ /**
+ * Returns an instance of <code>DocumentMergerImpl</code>,
+ * which is an implementation of the <code>DocumentMerger</code>
+ * interface.
+ *
+ * @param doc <code>Document</code> to merge.
+ *
+ * @return A DocumentMergerImpl object.
+ */
+ public DocumentMerger createDocumentMerger(Document doc) {
+ ConverterCapabilities cc = converterCap;
+ DocumentMergerImpl merger = new DocumentMergerImpl(doc, cc);
+ return merger;
+
+ }
+
+}
+
+
+
+
+
+
+
+
+
+
+
diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/xslt/XsltPlugin.properties b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/xslt/XsltPlugin.properties
new file mode 100644
index 000000000000..aeb6fdaba443
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/xslt/XsltPlugin.properties
@@ -0,0 +1,37 @@
+#*************************************************************************
+#
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# Copyright 2000, 2010 Oracle and/or its affiliates.
+#
+# OpenOffice.org - a multi-platform office productivity suite
+#
+# This file is part of OpenOffice.org.
+#
+# OpenOffice.org is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License version 3
+# only, as published by the Free Software Foundation.
+#
+# OpenOffice.org is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License version 3 for more details
+# (a copy is included in the LICENSE file that accompanied this code).
+#
+# You should have received a copy of the GNU Lesser General Public License
+# version 3 along with OpenOffice.org. If not, see
+# <http://www.openoffice.org/license.html>
+# for a copy of the LGPLv3 License.
+#
+#*************************************************************************
+# x-no-translate
+
+
+#
+# XsltPlugin.properties
+#
+
+#This file allows users to specify the mime-type to file extension mappings
+
+# e.g text/html=.html
+text/html=.html
diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/xslt/package.html b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/xslt/package.html
new file mode 100644
index 000000000000..30c71b15655f
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/xml/xslt/package.html
@@ -0,0 +1,67 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
+<!--
+ #*************************************************************************
+ #
+ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+
+ Copyright 2000, 2010 Oracle and/or its affiliates.
+
+ OpenOffice.org - a multi-platform office productivity suite
+
+ This file is part of OpenOffice.org.
+
+ OpenOffice.org is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License version 3
+ only, as published by the Free Software Foundation.
+
+ OpenOffice.org is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License version 3 for more details
+ (a copy is included in the LICENSE file that accompanied this code).
+
+ You should have received a copy of the GNU Lesser General Public License
+ version 3 along with OpenOffice.org. If not, see
+ <http://www.openoffice.org/license.html>
+ for a copy of the LGPLv3 License.
+
+ #*************************************************************************
+ -->
+<HTML>
+<HEAD>
+ <TITLE>org.openoffice.xmerge.converter.xml.xslt package</TITLE>
+</HEAD>
+<BODY>
+<P>Provides the tools for doing the conversion of StarWriter XML to
+and from supported formats, through the use of an XSLT
+transformation.</P>
+<P>It follows the {@link org.openoffice.xmerge}
+framework for the conversion process.</P>
+<P>This converter does not currently support merge.</P>
+<P><FONT FACE="Times New Roman, serif"><FONT SIZE=5><B>XSLT
+Transformation</B></FONT></FONT></P>
+<p>The converter makes use
+of one or more XSLT style sheets, which are used in the
+DocumentSerializer and DocumentDeserializer, to perform the actual
+translations. The location of these stylesheets is extracted from the {@link org.openoffice.xmerge.util.registry.ConverterInfo ConverterInfo} data structure, and are specified using the optional converter-xslt-serialize and converter-xsltdeserialize tags in a plugins converter.xml file. Please refer to the SDK document for more information about how to implement a Plugin Configuration XML File for a specific plugin.
+A sample OpenOffice to Html stylesheet and Html to
+Openffice stylesheet, has been provided as a sample implementation.
+The converter also makes use of an XsltPlugin.properties file, which may be edited by the user to provide MIME-TYPE to file extension mappings. This file is used by the {@link org.openoffice.xmerge.converter.xml.xslt.PluginFactoryImpl getDeviceFileExtension} method.
+</p>
+
+<H2>TODO list</H2>
+
+<p><ol>
+<li>Expand XSLT style sheets to support more office/html
+ capabilities</li>
+<li>Add support for certain character codes, such as &amp;nbsp
+ which currently causes the transformer to break.</li>
+<li>Change the DocumentDeserializer transformer, so that the DOMResult is serialized using the xalan serializer and create an SxwDocument from the result</li>
+</ol></p>
+
+@see org.openoffice.xmerge.util.registry
+
+</BODY>
+</HTML>
+
+
diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/merger/DiffAlgorithm.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/merger/DiffAlgorithm.java
new file mode 100644
index 000000000000..76158a7053c0
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/merger/DiffAlgorithm.java
@@ -0,0 +1,51 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.merger;
+
+/**
+ * This is the difference algorithm interface. It is an interface so
+ * that different algorithms may be plugged-in to actually compute
+ * the differences.
+ *
+ * NOTE: this code may not be thread safe.
+ */
+public interface DiffAlgorithm {
+
+ /**
+ * Returns a <code>Difference</code> array. This method finds out
+ * the difference between two sequences.
+ *
+ * @param orgSeq The original sequence of object.
+ * @param modSeq The modified (or changed) sequence to
+ * compare against with the origial.
+ *
+ * @return A <code>Difference</code> array.
+ */
+ public Difference[] computeDiffs(Iterator orgSeq, Iterator modSeq);
+}
+
diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/merger/Difference.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/merger/Difference.java
new file mode 100644
index 000000000000..31977b36f377
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/merger/Difference.java
@@ -0,0 +1,242 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.merger;
+
+
+/**
+ * This is the <code>Difference</code> basic unit. Used by the
+ * <code>DiffAlgorithm</code> as a set of difference between two
+ * <code>Iterators</code> (the original and modified
+ * <code>Iterators</code>).
+ *
+ * @author smak
+ */
+public final class Difference {
+
+ /**
+ * Add operation.
+ */
+ public static final int ADD = 1;
+
+ /**
+ * Delete operation.
+ */
+ public static final int DELETE = 2;
+
+ /**
+ * Change operation.
+ */
+ public static final int CHANGE = 3;
+
+ /**
+ * Unchange operation (i.e. no change).
+ */
+ public static final int UNCHANGE = 4;
+
+ /**
+ * The action of the diff - either {@link #ADD} or {@link #DELETE}.
+ */
+ private int operation;
+
+ /**
+ * <p>The position of the content that should be operated on (original
+ * iterator).</p>
+ *
+ * <p>For ADD, the orgPosition is the position of the original sequence
+ * where the diff will insert (the element count is starting from 0, and
+ * always insert before the element). The modPosition is the position
+ * of the diff in the modified sequence (also starting from 0).</p>
+ *
+ * <blockquote><pre>
+ * example:
+ *
+ * diff - &lt;B D&gt;and &lt;A B C D E F&gt;
+ * note: &lt;B D&gt;is original sequence and &lt;A B C D E F&gt;
+ * is the modified one.
+ *
+ * and here is the position of those sequence:
+ * &lt;B D&gt; &lt;A B C D E F&gt;
+ * 0 1 0 1 2 3 4 5
+ *
+ * result:
+ * &lt;diff orgPos=0 modPos=0 operation=ADD&gt; &lt;-- element A
+ * &lt;diff orgPos=1 modPos=2 operation=ADD&gt; &lt;-- element C
+ * &lt;diff orgPos=2 modPos=4 operation=ADD&gt; &lt;-- element E
+ * &lt;diff orgPos=2 modPos=5 operation=ADD&gt; &lt;-- element F
+ *
+ * </pre> </blockquote>
+ * <p>One can notice the add operation is inserted before the position.
+ * Hence, in order to append an element, we will have a position of
+ * original sequence length + 1 to denote an append.</p>
+ *
+ * <p>For DELETE, orgPosition is the position that the element
+ * will be deleted (starting from 0) and modPosition is the position
+ * where the deleted element should be (consider as an ADD).</p>
+ *
+ * <p>The modPosition is less useful and it is difficult to understand
+ * how the position is calculated. One can just skip this piece of
+ * information. It is useful if one wants to reverse the role
+ * of original sequence and modified sequence and find out the diff
+ * easily (just change add to delete and delete to add for operation
+ * and swap the orgPosition and modPosition).</p>
+ *
+ * <blockquote><pre>
+ * example:
+ *
+ * diff - &lt;A B C D E F&gt; and &lt; B D&gt;
+ * note: &lt;A B C D E F&gt; is original sequence and &lt;B D&gt;
+ * is the modified one.
+ *
+ * and here is the position of those sequence:
+ * &lt;A B C D E F&gt; &lt;B D&gt;
+ * 0 1 2 3 4 5 0 1
+ *
+ * result:
+ * &lt;diff orgPos=0 modPos=0 operation=DELETE&gt; &lt;-- element A
+ * &lt;diff orgPos=2 modPos=1 operation=DELETE&gt; &lt;-- element C
+ * &lt;diff orgPos=4 modPos=2 operation=DELETE&gt; &lt;-- element E
+ * &lt;diff orgPos=5 modPos=2 operation=DELETE&gt; &lt;-- element F
+ * </pre></blockquote>
+ */
+ private int orgPosition;
+
+ /**
+ * The position of the content that should be operated (modified iterator).
+ * For explanation and examples, see {@link #orgPosition}.
+ */
+ private int modPosition;
+
+
+ /**
+ * Constructor. This is the standard way to create a
+ * <code>Difference</code> object.
+ *
+ * @param operation Either {@link #ADD} or {@link #DELETE}.
+ * @param orgPosition The position in the original (first)
+ * <code>Iterator</code>.
+ * @param modPosition The position in the modified (second)
+ * <code>Iterator</code>.
+ */
+ public Difference(int operation, int orgPosition,
+ int modPosition) {
+ this.operation = operation;
+ this.orgPosition = orgPosition;
+ this.modPosition = modPosition;
+ }
+
+
+ /**
+ * Get the operation of the <code>Difference</code>.
+ *
+ * @return the operation of the <code>Difference</code>,
+ * either {@link #ADD} or {@link #DELETE}
+ */
+ public int getOperation() {
+ return operation;
+ }
+
+ /**
+ * Get the original <code>Iterator</code> position.
+ *
+ * @return The position in the original (first) <code>Iterator</code>
+ */
+ public int getOrgPosition() {
+ return orgPosition;
+ }
+
+ /**
+ * Get the modified <code>Iterator</code> position.
+ *
+ * @return The position in the modified (second) <code>Iterator</code>
+ */
+ public int getModPosition() {
+ return modPosition;
+ }
+
+
+ /**
+ * Two <code>Difference</code> objects will equal if and only if
+ * all operation, orgPosition, modPosition and content are equal.
+ *
+ * @param obj Object to compare.
+ *
+ * @return true if equal, false otherwise.
+ */
+ public boolean equals(Object obj) {
+ if (obj instanceof Difference) {
+ Difference diff = (Difference) obj;
+ if ((operation == diff.operation) &&
+ (orgPosition == diff.orgPosition) &&
+ (modPosition == diff.modPosition)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Display debug information.
+ *
+ * @return Debug string.
+ */
+ public String debug() {
+
+ String opStr = "";
+
+ switch (operation) {
+ case ADD:
+ opStr = "add";
+ break;
+ case DELETE:
+ opStr = "del";
+ break;
+ case CHANGE:
+ opStr = "chg";
+ break;
+ case UNCHANGE:
+ opStr = "uch";
+ break;
+ default:
+ break;
+ }
+ return "<diff orgPos=" + orgPosition + " modPos=" + modPosition +
+ " op=" + opStr + ">";
+ }
+
+ /**
+ * Returns position and operation values as a single string.
+ *
+ * @return orgPosition, modPosition and operation as a single string.
+ */
+ public String toString() {
+
+ return orgPosition + " " + modPosition + " " + operation;
+ }
+}
+
diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/merger/Iterator.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/merger/Iterator.java
new file mode 100644
index 000000000000..5ebfa7b2f499
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/merger/Iterator.java
@@ -0,0 +1,123 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.merger;
+
+/**
+ * This is an interface used by the {@link
+ * org.openoffice.xmerge.merger.DiffAlgorithm
+ * DiffAlgorithm} and {@link
+ * org.openoffice.xmerge.merger.MergeAlgorithm
+ * MergeAlgorithm} to access a <code>Document</code>.
+ *
+ * @author smak
+ */
+public interface Iterator {
+
+
+ /**
+ * Move to next element in the sequence.
+ *
+ * @return The <code>Object</code> of the next element in the sequence.
+ * If there is no next element, then return null.
+ */
+ public Object next();
+
+
+ /**
+ * Move to previous element in the sequence.
+ *
+ * @return The <code>Object</code> of the previous element in the sequence.
+ * If there is no previous element, then return null.
+ */
+ public Object previous();
+
+
+ /**
+ * Move to the beginning of the sequence.
+ *
+ * @return The <code>Object</code> of the first element in the sequence.
+ * If it is empty, then return null.
+ */
+ public Object start();
+
+
+ /**
+ * Move to the end of the sequence.
+ *
+ * @return The <code>Object</code> of the last element in the sequence.
+ * If it is empty, then return null.
+ */
+ public Object end();
+
+
+ /**
+ * Return the current element <code>Object</code> content.
+ *
+ * @return The <code>Object</code> at current position.
+ */
+ public Object currentElement();
+
+
+ /**
+ * Return the total element count in the sequence.
+ *
+ * @return The total element count.
+ */
+ public int elementCount();
+
+
+ /**
+ * A method to allow the difference algorithm to test whether the
+ * <code>obj1</code> and <code>obj2</code> in the
+ * <code>Iterator</code> are considered equal. As not every
+ * <code>Object</code> in the <code>Iterator</code> can implement its
+ * own equal method, with this equivalent method, we can allow
+ * flexibility for the <code>Iterator</code> to choose a custom way
+ * to compare two objects. Two objects can even be compared based on
+ * the position in the <code>Iterator</code> rather than by
+ * the content via this option.
+ *
+ * @param obj1 The first <code>Object</code>.
+ * @param obj2 The second <code>Object</code>.
+ *
+ * @return true if equal, false otherwise.
+ */
+ public boolean equivalent(Object obj1, Object obj2);
+
+
+ /**
+ * <p>A method to force the <code>Iterator</code> to transverse the tree
+ * again to refresh the content.</p>
+ *
+ * <p>It is used mainly for <code>Iterator</code> objects which take a snap
+ * shot instead of dynamically transversing the tree. The current
+ * position will be set to the beginning.</p>
+ */
+ public void refresh();
+}
+
diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/merger/MergeAlgorithm.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/merger/MergeAlgorithm.java
new file mode 100644
index 000000000000..b1d4d5b510fd
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/merger/MergeAlgorithm.java
@@ -0,0 +1,61 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.merger;
+
+import org.openoffice.xmerge.MergeException;
+import org.openoffice.xmerge.merger.Iterator;
+import org.openoffice.xmerge.merger.Difference;
+
+/**
+ * This is the <code>MergeAlgorithm</code> interface. It is an
+ * interface so that different merge algorithms may be plugged-in
+ * to actually merge the diffs back to an original document.
+ *
+ * @author smak
+ */
+public interface MergeAlgorithm {
+
+ /**
+ * This method is to merge the difference to an <code>Iterator</code>.
+ * The original <code>Iterator</code> will be modified after the call.
+ *
+ * @param objSeq The original sequence which the difference
+ * will be applied. It will be modified.
+ * @param modSeq The modified sequence where the difference
+ * content will be extracted.
+ * @param differences The <code>Difference</code> array.
+ *
+ * @return An <code>Iterator</code> which is the modified original
+ * <code>Iterator</code> Sequence. Same as the first parameter.
+ *
+ * @throws MergeException If an error occurs during the merge.
+ */
+ public void applyDifference(Iterator orgSeq, Iterator modSeq,
+ Difference[] differences) throws MergeException;
+}
+
diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/merger/NodeMergeAlgorithm.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/merger/NodeMergeAlgorithm.java
new file mode 100644
index 000000000000..9337816c64ab
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/merger/NodeMergeAlgorithm.java
@@ -0,0 +1,52 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.merger;
+
+import org.w3c.dom.Node;
+
+/**
+ * This is an interface for a {@link
+ * org.openoffice.xmerge.merger.MergeAlgorithm
+ * MergeAlgorithm} to merge two <code>Node</code> objects. It is an
+ * interface so that different merge algorithms may be plugged-in.
+ *
+ * @author smak
+ */
+public interface NodeMergeAlgorithm {
+
+ /**
+ * This method is used to merge two given <code>Node</code>
+ * objects. Note: the original <code>Node</code> may be modified.
+ *
+ * @param originalNode The original <code>Node</code>.
+ * @param modifyNode The <code>Node</code> to be merged. It may
+ * be modified.
+ */
+ public void merge(Node orginialNode, Node modifyNode);
+}
+
diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/merger/diff/CellNodeIterator.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/merger/diff/CellNodeIterator.java
new file mode 100644
index 000000000000..95fddea14cb9
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/merger/diff/CellNodeIterator.java
@@ -0,0 +1,114 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.merger.diff;
+
+import org.w3c.dom.Node;
+import org.w3c.dom.Element;
+
+import org.openoffice.xmerge.ConverterCapabilities;
+import org.openoffice.xmerge.converter.xml.OfficeConstants;
+import org.openoffice.xmerge.util.Resources;
+
+
+/**
+ * <p>This is an implementations of the <code>Iterator</code> interface.
+ * It will traverse the tree and find cell <code>Node</code> sequences.</p>
+ *
+ * <p>Note: Once the XML Tree is parsed, then the <code>Iterator</code>
+ * will be a snap shot of that tree. That means even the tree is
+ * modified later, than the cached paragraph <code>Node</code> list will
+ * not be updated accordingly. For this reason and for performance reasons
+ * this <code>Iterator</code> does not support any operation methods such
+ * as insert, remove or replace. The main purpose of this
+ * <code>Iterator</code> is to be used with difference, not with merge.</p>
+ *
+ * @author smak
+ */
+public final class CellNodeIterator extends NodeIterator {
+
+ private Resources res = Resources.getInstance();
+
+ // can be expanded to an array in the future, not necessary right now
+ private static final String SUPPORTED_TAG1 = OfficeConstants.TAG_TABLE_CELL;
+
+ /**
+ * The standard constructor.
+ *
+ * @param cc The <code>ConverterCapabilities</code>.
+ * @param node The initial root <code>Node</code>.
+ */
+ public CellNodeIterator(ConverterCapabilities cc, Node node) {
+ super(cc, node);
+ }
+
+
+ /**
+ * Overwrite the parent <code>nodeSupported</code> method. Only cell
+ * <code>Node</code> objects are supported.
+ *
+ * @param node The <code>Node</code> to check.
+ *
+ * @return true if the <code>Node</code> is supported, false otherwise.
+ */
+ protected boolean nodeSupported(Node node) {
+
+ // can use an array later to check all possible tags for
+ // future expansion
+ if (node.getNodeType() == Node.ELEMENT_NODE &&
+ node.getNodeName().equals(SUPPORTED_TAG1)) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+
+ protected boolean childrenEqual(Node node1, Node node2) {
+
+ boolean equal = false;
+
+ if (node1.hasChildNodes() && node2.hasChildNodes()) {
+ Element cell1 = (Element)node1;
+ Element cell2 = (Element)node2;
+
+ // only need compare the first <text:p> children node, don't want
+ // to compare any non-supported features
+ // TODO: need to confirm whether all the text string is the
+ // first <text:p>, though I checked with the openoffice 619 build
+ Node paraNode1 = cell1.getElementsByTagName(
+ OfficeConstants.TAG_PARAGRAPH).item(0);
+ Node paraNode2 = cell2.getElementsByTagName(
+ OfficeConstants.TAG_PARAGRAPH).item(0);
+
+ equal = super.compareNode(paraNode1, paraNode2);
+ }
+
+ return equal;
+ }
+}
+
diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/merger/diff/CharArrayLCSAlgorithm.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/merger/diff/CharArrayLCSAlgorithm.java
new file mode 100644
index 000000000000..9026303ca3d3
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/merger/diff/CharArrayLCSAlgorithm.java
@@ -0,0 +1,234 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.merger.diff;
+
+import java.util.Vector;
+import org.openoffice.xmerge.merger.Difference;
+
+/**
+ * <p>This is an implementations of <code>DiffAlgorithm</code> interface
+ * which will difference char arrays.</p>
+ *
+ * <p>It also use Longest Common Subsequence (LCS). The algorithm is based
+ * on the book "Introduction to Algorithms" by Thomas H.Cormen,
+ * Charles E.Leiserson, and Ronald L.Riverst (MIT Press 1990) page 314.</p>
+ *
+ * @author smak
+ */
+public class CharArrayLCSAlgorithm {
+
+ /**
+ * Return an <code>Difference</code> array. This method finds out
+ * the difference between two sequences.
+ *
+ * @param orgSeq The original sequence.
+ * @param modSeq The modified (or changed) sequence to
+ * compare against the origial.
+ *
+ * @return A <code>Difference</code> array.
+ */
+ public Difference[] computeDiffs(char[] orgSeq, char[] modSeq) {
+
+ int orgSeqlen = orgSeq.length;
+ int modSeqlen = modSeq.length;
+
+ int[][] diffTable;
+
+ // Diff table is used to keep track which element is the same or not
+ // in those 2 sequences
+ diffTable = createDiffTable(orgSeq, modSeq);
+
+ // debug purpose...
+ // printDiffTable(diffTable);
+
+ Vector diffResult = new Vector();
+
+ generateResult(diffTable, orgSeqlen, modSeqlen, diffResult);
+
+ // don't need anymore if Difference do not contain content information
+ /* fillInDiffContent(diffResult, orgSeq, modSeq); */
+
+ Difference[] diffArray = new Difference[0];
+
+ // convert the vector to array, it has to do in here as
+ // generateResult is called recursively
+ if (diffResult.size() > 0) {
+ diffArray = new Difference[diffResult.size()];
+ diffResult.copyInto(diffArray);
+ }
+
+ diffTable = null;
+ diffResult = null;
+
+ return diffArray;
+ }
+
+
+ /**
+ * Debug function Used to print out the nicely formatted
+ * difference table.
+ *
+ * @param diffTable The difference table to display.
+ */
+ private void printDiffTable(int[][] diffTable) {
+
+ for (int i = 0; i < diffTable.length; i++) {
+ for (int j = 0; j < diffTable[i].length; j++) {
+ System.out.print(" " + diffTable[i][j] + " ");
+ }
+ System.out.println();
+ }
+ }
+
+
+ /**
+ * Create the difference table.
+ * The difference table is used internal to keep track what
+ * elements are common or different in the two sequences.
+ *
+ * @param orgSeq The original sequence to be used as a base.
+ * @param modSeq The modified sequence to compare.
+ *
+ * @return A difference table as a two-dimensional array of
+ * integers.
+ */
+ private int[][] createDiffTable(char[] orgSeq, char[] modSeq) {
+ int orgSeqlen = orgSeq.length + 1;
+ int modSeqlen = modSeq.length + 1;
+ int[][] diffTable;
+
+ // initialize the diffTable (it need to be 1 row/col bigger
+ // than the original str)
+ diffTable = new int[orgSeqlen][];
+ for (int i = 0; i < orgSeqlen; i++) {
+ diffTable[i] = new int[modSeqlen];
+ }
+
+ // compute the diff Table using LCS algorithm, refer to the book
+ // mentioned at the top of the program
+ for (int i = 1; i < orgSeqlen; i++) {
+ for (int j = 1; j < modSeqlen; j++) {
+
+ if (orgSeq[i-1] == modSeq[j-1]) {
+ diffTable[i][j] = diffTable[i-1][j-1]+1;
+ } else {
+ if (diffTable[i-1][j] >= diffTable[i][j-1]) {
+ diffTable[i][j] = diffTable[i-1][j];
+ } else {
+ diffTable[i][j] = diffTable[i][j-1];
+ }
+ }
+ }
+ }
+
+ return diffTable;
+ }
+
+
+ /**
+ * Generate the <code>Difference</code> result vector.
+ * This method will be called recursively to backtrack the difference
+ * table to get the difference result (and also the LCS).
+ *
+ * @param diffTable The difference table containing the
+ * <code>Difference</code> result.
+ * @param i The nth element in original sequence to
+ * compare. This method is called recursively
+ * with i and j decreased until 0.
+ * @param j The nth element in modified sequence to
+ * compare.
+ * @param diffVector A vector to output the <code>Difference</code>
+ * result. Can not use a return variable as it
+ * is a recursive method. The vector will contain
+ * <code>Difference</code> objects with operation
+ * and positions filled in.
+ */
+ private void generateResult(int[][] diffTable,
+ int i, int j, Vector diffVector) {
+
+ // handle the first element
+ if (i == 0 || j == 0) {
+ if (i == 0 && j == 0) {
+ // return
+ } else if (j == 0) {
+ for (int cnt = 0; cnt < i; cnt++) {
+ Difference diff =
+ new Difference(Difference.DELETE, cnt, j);
+ diffVector.add(diff);
+ }
+ } else {
+ for (int cnt = 0; cnt < j; cnt++) {
+ Difference diff =
+ new Difference(Difference.ADD, i, cnt);
+ diffVector.add(diff);
+ }
+ }
+ return;
+ }
+
+ // for the detail of this algorithm, refer to the book mentioned on
+ // the top and page 317 and 318.
+ if ((diffTable[i-1][j-1] == diffTable[i][j] -1) &&
+ (diffTable[i-1][j-1] == diffTable[i-1][j]) &&
+ (diffTable[i-1][j-1] == diffTable[i][j-1])) {
+
+ // the element of ith and jth in org and mod sequence is the same
+ generateResult(diffTable, i-1, j-1, diffVector);
+ } else {
+ if (diffTable[i-1][j] > diffTable[i][j-1]) {
+
+ // recursively call first, then add the result so that
+ // the beginning of the diffs will be stored first
+ generateResult(diffTable, i-1, j, diffVector);
+
+ Difference diff =
+ new Difference(Difference.DELETE, i-1, j);
+ diffVector.add(diff);
+ } else if (diffTable[i-1][j] < diffTable[i][j-1]) {
+
+ // recursively call first, then add the result so that
+ // the beginning of the diffs will be stored first
+ generateResult(diffTable, i, j-1, diffVector);
+
+ Difference diff =
+ new Difference(Difference.ADD, i, j-1);
+ diffVector.add(diff);
+ } else { // diffTable[i-1][j] == diffTable[i][j-1]
+ // recursively call first, then add the result so that
+ // the beginning of the diffs will be stored first
+ generateResult(diffTable, i-1, j-1, diffVector);
+
+ Difference diff =
+ new Difference(Difference.CHANGE, i-1, j-1);
+ diffVector.add(diff);
+
+ }
+ }
+ }
+}
+
diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/merger/diff/CharacterParser.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/merger/diff/CharacterParser.java
new file mode 100644
index 000000000000..1a047d130a03
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/merger/diff/CharacterParser.java
@@ -0,0 +1,142 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.merger.diff;
+
+import org.w3c.dom.Node;
+
+import org.openoffice.xmerge.converter.xml.OfficeConstants;
+
+import java.util.Vector;
+import java.util.List;
+
+
+/**
+ * <p>This is a parser to return a character array for difference purpose.
+ * It will use depth first search to traverse all the characters inside the
+ * text <code>Node</code> under a given <code>Node</code> (most likely to be
+ * a paragraph <code>Node</code>).</p>
+ *
+ * <p>Note: Once the XML Tree is parsed, then the <code>Iterator</code> will be
+ * a snap shot of that tree. That means even the tree is modified later, than
+ * the cached paragraph <code>Node</code> list will not be updated accordingly.
+ * For this reason and for performance reasons this <code>Iterator</code> does
+ * not support any operation methods such as insert, remove or replace. The
+ * main purpose of this <code>Iterator</code> is to be used with difference,
+ * not with merge.</p>
+ *
+ * @author smak
+ */
+public class CharacterParser {
+
+ private TextNodeIterator textNodes;
+ private int currentPosition = 0;
+ private List nodeList_ = null;
+ private char[] charArray;
+
+
+ /**
+ * Standard constructor.
+ *
+ * @param node The initial root <code>Node</code>.
+ */
+ public CharacterParser(Node node) {
+ textNodes = new TextNodeIterator(node);
+ nodeList_ = new Vector();
+
+ parseNodes();
+ }
+
+
+ /**
+ * Returns the <code>Node</code> pointer with the given character position.
+ *
+ * @return The <code>Node</code> pointer with the given character position.
+ */
+ public List getNodeList() {
+ // will go through the nodeList to find the corresponding node
+ return nodeList_;
+ }
+
+ /**
+ * Returns the character array representation of the text.
+ *
+ * @return The character array representation of the text.
+ */
+ public char[] getCharArray() {
+ return charArray;
+ }
+
+ private void parseNodes() {
+
+ StringBuffer strBuf = new StringBuffer();
+
+ /* create the character array by iterate the textnode iterator */
+ Node currentNode = (Node)(textNodes.start());
+ for (;
+ currentNode != null;
+ currentNode = (Node)(textNodes.next())) {
+
+ // add the text value into the array
+ String textValue = null;
+ String nodeName = currentNode.getNodeName();
+
+ // TODO: Space node have a count attribute which is not handled!
+ if (currentNode.getNodeType() == Node.TEXT_NODE) {
+ textValue = currentNode.getNodeValue();
+ } else if (nodeName.equals(OfficeConstants.TAG_SPACE)) {
+ textValue = " ";
+ } else if (nodeName.equals(OfficeConstants.TAG_TAB_STOP)) {
+ textValue = "\t";
+ }
+
+ if (textValue != null) {
+ strBuf.append(textValue);
+ addNewNodeEntry(textValue.length(), currentNode);
+ }
+ }
+
+ charArray = strBuf.toString().toCharArray();
+ }
+
+
+ /**
+ * Adds a new <code>Node</code> entry.
+ *
+ * @param textLen The text length.
+ * @param node The <code>Node</code>.
+ */
+ private void addNewNodeEntry(int textLen, Node node) {
+
+ TextNodeEntry nodeEntry = new TextNodeEntry(currentPosition,
+ currentPosition + textLen - 1, node);
+ currentPosition = currentPosition + textLen;
+
+ nodeList_.add(nodeEntry);
+ }
+}
+
diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/merger/diff/IteratorLCSAlgorithm.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/merger/diff/IteratorLCSAlgorithm.java
new file mode 100644
index 000000000000..ae90274bfaf1
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/merger/diff/IteratorLCSAlgorithm.java
@@ -0,0 +1,236 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.merger.diff;
+
+import java.util.Vector;
+import org.openoffice.xmerge.merger.DiffAlgorithm;
+import org.openoffice.xmerge.merger.Difference;
+import org.openoffice.xmerge.merger.Iterator;
+import org.openoffice.xmerge.util.Debug;
+
+/**
+ * This is one of the implementations of <code>DiffAlgorithm</code> interface.
+ * Using Longest Common Subsequence (LCS). The algorithm here is based
+ * on the book "Introduction to Algorithms" by Thomas H.Cormen,
+ * Charles E.Leiserson and Ronald L.Riverst (MIT Press 1990) page 314.
+ *
+ * @author smak
+ */
+public class IteratorLCSAlgorithm implements DiffAlgorithm {
+
+ public Difference[] computeDiffs(Iterator orgSeq, Iterator modSeq) {
+
+ int orgSeqlen = orgSeq.elementCount();
+ int modSeqlen = modSeq.elementCount();
+
+ int[][] diffTable;
+
+ // Diff table is used to keep track which element is the same or not
+ // in those 2 sequences
+ diffTable = createDiffTable(orgSeq, modSeq);
+
+ // debug purpose...
+ if (Debug.isFlagSet(Debug.INFO)) {
+ printDiffTable(diffTable);
+ }
+
+ Vector diffResult = new Vector();
+
+ generateResult(diffTable, orgSeqlen, modSeqlen, diffResult);
+
+ Difference[] diffArray = new Difference[0];
+
+ // convert the vector to array, it has to do in here as
+ // generateResult is called recursively
+ if (diffResult.size() > 0) {
+ diffArray = new Difference[diffResult.size()];
+ diffResult.copyInto(diffArray);
+ }
+
+ diffTable = null;
+ diffResult = null;
+
+ return diffArray;
+ }
+
+
+ /**
+ * Debug function used to print out the nicely formatted
+ * difference table.
+ *
+ * @param diffTable The difference table to display.
+ */
+ private void printDiffTable(int[][] diffTable) {
+
+ String tmpString = "";
+
+ for (int i = 0; i < diffTable.length; i++) {
+ for (int j = 0; j < diffTable[i].length; j++) {
+ tmpString = tmpString + " " + diffTable[i][j] + " ";
+ }
+ Debug.log(Debug.INFO, tmpString);
+ tmpString = "";
+ }
+ }
+
+ /**
+ * Create the difference table.
+ * The difference table is used internal to keep track what
+ * elements are common or different in the two sequences.
+ *
+ * @param orgSeq The original sequence to be used as a base.
+ * @param modSeq The modified sequence to compare.
+ *
+ * @return A difference table as a two-dimensional array of
+ * integers.
+ */
+ private int[][] createDiffTable(Iterator orgSeq, Iterator modSeq) {
+ int orgSeqlen = orgSeq.elementCount() + 1;
+ int modSeqlen = modSeq.elementCount() + 1;
+ int[][] diffTable;
+
+ // initialize the diffTable
+ diffTable = new int[orgSeqlen][];
+ for (int i = 0; i < orgSeqlen; i++) {
+ diffTable[i] = new int[modSeqlen];
+ }
+
+ // compute the diff Table using LCS algorithm, refer to the book
+ // mentioned at the top of the program
+
+ int i, j;
+
+ Object orgSeqObject, modSeqObject;
+
+ for (orgSeqObject = orgSeq.start(), i = 1;
+ orgSeqObject != null;
+ orgSeqObject = orgSeq.next(), i++) {
+
+ for (modSeqObject = modSeq.start(), j = 1;
+ modSeqObject != null;
+ modSeqObject = modSeq.next(), j++) {
+
+ if (orgSeq.equivalent(orgSeqObject, modSeqObject)) {
+ diffTable[i][j] = diffTable[i-1][j-1]+1;
+ } else {
+ if (diffTable[i-1][j] >= diffTable[i][j-1]) {
+ diffTable[i][j] = diffTable[i-1][j];
+ } else {
+ diffTable[i][j] = diffTable[i][j-1];
+ }
+ }
+ }
+ }
+
+ return diffTable;
+ }
+
+
+ /**
+ * Generate the <code>Difference</code> object result vector.
+ * This method will be called recursively to backtrack the difference
+ * table to get the difference result (and also the LCS).
+ *
+ * @param diffTable The difference table containing the
+ * <code>Difference</code> result.
+ * @param i The nth element in original sequence to
+ * compare. This method is called recursively
+ * with i and j decreased until 0.
+ * @param j The nth element in modified sequence to
+ * compare.
+ * @param diffVector A vector to output the <code>Difference</code>
+ * result. Can not use a return variable as it
+ * is a recursive method. The vector will contain
+ * <code>Difference</code> objects with operation
+ * and positions fill in.
+ */
+ private void generateResult(int[][] diffTable,
+ int i, int j, Vector diffVector) {
+
+ // handle the first element
+ if (i == 0 && j == 0) {
+ return;
+
+ } else if (j == 0) {
+ for (int cnt = 0; cnt < i; cnt++) {
+ Difference diff =
+ new Difference(Difference.DELETE, cnt, j);
+ diffVector.add(diff);
+ }
+ return;
+
+ } else if (i == 0) {
+ for (int cnt = 0; cnt < j; cnt++) {
+ Difference diff =
+ new Difference(Difference.ADD, i, cnt);
+ diffVector.add(diff);
+ }
+ return;
+ }
+
+ // for the detail of this algorithm, refer to the book mentioned on
+ // the top and page 317 and 318.
+ if ((diffTable[i-1][j-1] == diffTable[i][j] -1) &&
+ (diffTable[i-1][j-1] == diffTable[i-1][j]) &&
+ (diffTable[i-1][j-1] == diffTable[i][j-1])) {
+
+ // the element of ith and jth in org and mod sequence is the same
+ generateResult(diffTable, i-1, j-1, diffVector);
+ } else {
+ if (diffTable[i-1][j] > diffTable[i][j-1]) {
+
+ // recursively call first, then add the result so that
+ // the beginning of the diffs will be stored first
+ generateResult(diffTable, i-1, j, diffVector);
+
+ Difference diff =
+ new Difference(Difference.DELETE, i-1, j);
+ diffVector.add(diff);
+ } else if (diffTable[i-1][j] < diffTable[i][j-1]) {
+
+ // recursively call first, then add the result so that
+ // the beginning of the diffs will be stored first
+ generateResult(diffTable, i, j-1, diffVector);
+
+ Difference diff =
+ new Difference(Difference.ADD, i, j-1);
+ diffVector.add(diff);
+ } else { // diffTable[i-1][j] == diffTable[i][j-1]
+ // recursively call first, then add the result so that
+ // the beginning of the diffs will be stored first
+ generateResult(diffTable, i-1, j-1, diffVector);
+
+ Difference diff =
+ new Difference(Difference.CHANGE, i-1, j-1);
+ diffVector.add(diff);
+
+ }
+ }
+ }
+}
+
diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/merger/diff/IteratorRowCompare.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/merger/diff/IteratorRowCompare.java
new file mode 100644
index 000000000000..fa6642432838
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/merger/diff/IteratorRowCompare.java
@@ -0,0 +1,243 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.merger.diff;
+
+import org.w3c.dom.Node;
+import org.w3c.dom.Element;
+
+import java.util.Vector;
+import org.openoffice.xmerge.merger.DiffAlgorithm;
+import org.openoffice.xmerge.merger.Difference;
+import org.openoffice.xmerge.merger.Iterator;
+import org.openoffice.xmerge.converter.xml.OfficeConstants;
+
+/**
+ * <p>A very simple and direct difference algorithm for row
+ * <code>Node</code> objects in a spreadsheet. Basically, it will
+ * compare objects in sequence and does not look ahead (unlike LCS).</p>
+ *
+ * <p><ol><li>
+ * If two objects are the same, skip to next one.
+ * </li><li>
+ * Otherwise check whether the row repeated attribute is the same.
+ * </li><li>
+ * If the row repeated attribute is the same, then compare two rows
+ * and mark it as <i>change</i> if those rows are different.
+ * </li><li>
+ * If the row repeated attribute is different, then split the rows and
+ * continue to compare.
+ * </li><li>
+ * If there are more objects in the modseq than the original sequence,
+ * then all of the extra ones in the modified sequence are marked as add.
+ * </li><li>
+ * If there are more objects in the original sequence than the modified
+ * sequence, then all the extra one in the modified sequence are marked
+ * as delete.
+ * </li></ol></p>
+ *
+ * <p>NOTE: The algorithm will have potential side effect to split rows.</p>
+ *
+ * @author smak
+ */
+
+public class IteratorRowCompare implements DiffAlgorithm {
+
+ /**
+ * Compute the differences of the given two sequences.
+ * Refer to the class description.
+ *
+ * Return an array of <code>Difference</code> objects. This method finds
+ * out the difference between two sequences.
+ *
+ * @param orgSeq The original sequence.
+ * @param modSeq The modified (or changed) sequence to
+ * compare against with the origial.
+ *
+ * @return An array of Difference objects.
+ */
+ public Difference[] computeDiffs(Iterator orgSeq, Iterator modSeq) {
+
+ int orgSeqlen = orgSeq.elementCount();
+ int modSeqlen = modSeq.elementCount();
+
+ Vector diffVector = new Vector();
+
+ // i and j are counters to keep track the current position in the
+ // iterator
+ int i = 0;
+ int j = 0;
+ Object orgSeqObject = orgSeq.start();
+ Object modSeqObject = modSeq.start();
+ Element orgRow, modRow;
+ boolean different = false;
+ boolean orgSplited = false;
+ boolean modSplited = false;
+
+ while (orgSeqObject != null) {
+
+ different = true;
+
+ if (modSeqObject == null) {
+ // no more modsequence, all the remaining org sequence objs
+ // should consider as a delete.
+ Difference diff = new Difference(Difference.DELETE, i, j);
+ diffVector.add(diff);
+ orgSeqObject = orgSeq.next();
+
+ } else {
+ if (!orgSeq.equivalent(orgSeqObject, modSeqObject)) {
+
+ orgRow = (Element)orgSeqObject;
+ modRow = (Element)modSeqObject;
+
+ // check whether the original Row with multiple row
+ // if so, need to split one out for merge
+ String orgRowRepeated = orgRow.getAttribute(
+ OfficeConstants.ATTRIBUTE_TABLE_NUM_ROWS_REPEATED);
+ String modRowRepeated = modRow.getAttribute(
+ OfficeConstants.ATTRIBUTE_TABLE_NUM_ROWS_REPEATED);
+
+
+ int orgRowNum = 1;
+ int modRowNum = 1;
+
+ if (orgRowRepeated.length() > 0) {
+ orgRowNum =
+ Integer.valueOf(orgRowRepeated).intValue();
+ }
+ if (modRowRepeated.length() > 0) {
+ modRowNum =
+ Integer.valueOf(modRowRepeated).intValue();
+ }
+
+ // try to find out the common number of repeated Rows
+ if (orgRowNum == modRowNum) {
+ orgSeqObject = orgSeq.next();
+ modSeqObject = modSeq.next();
+
+ // cut the original row into two halves, first half
+ // have the repeated attribute = modify row attr
+ } else if (orgRowNum > modRowNum) {
+ Element orgSplitRow = splitRepeatedRow(
+ orgRow, modRowNum,
+ orgRowNum - modRowNum);
+ // it may equal after the split!
+ if (orgSeq.equivalent(orgSplitRow, modRow)) {
+ different = false;
+ }
+ orgSplited = true;
+ modSeqObject = modSeq.next();
+
+ // cut the modified Row into two halves, first half
+ // have the repeated attribute = original Row attr
+ } else {
+ Element modSplitRow = splitRepeatedRow(
+ modRow, orgRowNum,
+ modRowNum - orgRowNum);
+
+ // check whether rows are equal after the split
+ if (modSeq.equivalent(orgRow, modSplitRow)) {
+ different = false;
+ }
+ modSplited = true;
+ orgSeqObject = orgSeq.next();
+ }
+
+ if (different) {
+ Difference diff = new Difference(Difference.CHANGE,
+ i, j);
+ diffVector.add(diff);
+ }
+
+ } else {
+ // Rows are equivalent, move on to next one.
+ orgSeqObject = orgSeq.next();
+ modSeqObject = modSeq.next();
+ } // end if-else
+ j++;
+ } // end if-else
+ i++;
+ } // end while loop
+
+ // any extra objects in modify sequence should consider as an add
+ // to the original sequence
+ for (; modSeqObject != null; modSeqObject = modSeq.next(), j++) {
+ Difference diff = new Difference(Difference.ADD, i, j);
+ diffVector.add(diff);
+ }
+
+ // need to refresh the iterator if we split the rows
+ if (orgSplited) {
+ orgSeq.refresh();
+ }
+
+ if (modSplited) {
+ modSeq.refresh();
+ }
+
+
+ // convert the vector to array
+ Difference[] diffArray = new Difference[diffVector.size()];
+ diffVector.copyInto(diffArray);
+
+ return diffArray;
+ }
+
+
+ private Element splitRepeatedRow(Element orgRow, int splitNum, int orgNum) {
+ // NOTE: should we really want to do deep clone?
+ // in most the case, it is an empty Row, but the
+ // specification didn't forbid any node to use multiple
+ // column attributes. i.e. the node can contain text
+ // nodes or other things under it.
+ Element splitRow = (Element)(orgRow.cloneNode(true));
+
+ if (splitNum > 1) {
+ splitRow.setAttribute(
+ OfficeConstants.ATTRIBUTE_TABLE_NUM_ROWS_REPEATED,
+ String.valueOf(splitNum));
+ } else if (splitNum == 1) {
+ splitRow.removeAttribute(
+ OfficeConstants.ATTRIBUTE_TABLE_NUM_ROWS_REPEATED);
+ }
+ if (orgNum > 1) {
+ orgRow.setAttribute(
+ OfficeConstants.ATTRIBUTE_TABLE_NUM_ROWS_REPEATED,
+ String.valueOf(orgNum));
+ } else if (orgNum == 1) {
+ orgRow.removeAttribute(
+ OfficeConstants.ATTRIBUTE_TABLE_NUM_ROWS_REPEATED);
+ }
+
+ Node parentNode = orgRow.getParentNode();
+ parentNode.insertBefore(splitRow, orgRow);
+
+ return splitRow;
+ }
+}
+
diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/merger/diff/NodeIterator.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/merger/diff/NodeIterator.java
new file mode 100644
index 000000000000..308affeb130a
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/merger/diff/NodeIterator.java
@@ -0,0 +1,384 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.merger.diff;
+
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.w3c.dom.NamedNodeMap;
+
+import org.openoffice.xmerge.ConverterCapabilities;
+import org.openoffice.xmerge.merger.Iterator;
+import org.openoffice.xmerge.util.Debug;
+import org.openoffice.xmerge.util.Resources;
+
+import java.util.Vector;
+import java.util.List;
+
+
+/**
+ * <p>This is an implementation of the <code>Iterator</code> interface.
+ * It will traverse the tree and find <code>Node</code> sequences.</p>
+ *
+ * <p>Note: Once the XML Tree is parsed, then the <code>Iterator</code> will
+ * be a snap shot of that tree. That means even the tree is modified later,
+ * than the cached paragraph <code>Node</code> list will not be updated
+ * accordingly. For this reason and for performance reasons this
+ * <code>Iterator</code> does not support any operation methods such as
+ * insert, remove or replace. The main purpose of this
+ * <code>Iterator</code> is to be used with difference, not with merge.</p>
+ *
+ * @author smak
+ */
+public abstract class NodeIterator implements Iterator {
+
+ private List nodeList = null;
+ private int currentPosition = 0;
+ private Node root;
+ private ConverterCapabilities cc_ = null;
+
+
+ /**
+ * Standard constructor.
+ *
+ * @param cc The <code>ConverterCapabilities</code>.
+ * @param node The initial root <code>Node</code>.
+ */
+ public NodeIterator(ConverterCapabilities cc, Node node) {
+ cc_ = cc;
+ nodeList = new Vector();
+ root = node;
+ markTree(node);
+ }
+
+
+ public Object next() {
+ if (currentPosition < nodeList.size() - 1) {
+ currentPosition++;
+ return currentElement();
+ } else {
+ return null;
+ }
+ }
+
+
+ public Object previous() {
+ if (currentPosition > 0) {
+ currentPosition--;
+ return currentElement();
+ } else {
+ return null;
+ }
+ }
+
+
+ public Object start() {
+ currentPosition = 0;
+ return currentElement();
+ }
+
+
+ public Object end() {
+ int size = nodeList.size();
+
+ if (size > 0) {
+ currentPosition = size - 1;
+ return currentElement();
+ } else {
+ return null;
+ }
+ }
+
+
+ public Object currentElement() {
+
+ if (currentPosition < 0 || currentPosition >= nodeList.size()) {
+ return null;
+ }
+
+ return nodeList.get(currentPosition);
+ }
+
+
+ public int elementCount() {
+ return nodeList.size();
+ }
+
+
+ public boolean equivalent(Object obj1, Object obj2) {
+ boolean equal = false;
+ String errMsg = null;
+ if (!(obj1 instanceof Node && obj2 instanceof Node)) {
+ errMsg = Resources.getInstance().getString("NOT_NODE_ERROR");
+ Debug.log(Debug.ERROR, errMsg);
+ } else {
+ Node node1 = (Node)obj1;
+ Node node2 = (Node)obj2;
+
+ equal = compareNode(node1, node2);
+ }
+ return equal;
+ }
+
+
+ public void refresh() {
+ nodeList = new Vector();
+ markTree(root);
+ currentPosition = 0;
+ }
+
+
+ /**
+ * Used to compare two <code>Node</code> objects (type/name/value)
+ * and all their children <code>Node</code> objects.
+ *
+ * @param node1 The first <code>Node</code> to compare.
+ * @param node2 The second <code>Node</code> to compare.
+ *
+ * @return true if <code>Node</code> is equal, false otherwise.
+ */
+ protected boolean compareNode(Node node1, Node node2) {
+ boolean equal = false;
+
+ nodeCheck: {
+
+ if (node1 == null || node2 == null) {
+ break nodeCheck;
+ }
+
+ // nodevalue is short
+ if (node1.getNodeType() != node2.getNodeType()) {
+ break nodeCheck;
+ }
+
+ // nodeName will not be null
+ if (!node1.getNodeName().equals(node2.getNodeName())) {
+ break nodeCheck;
+ }
+
+ // nodeValue can be null for a lot of type of cells
+ if (node1.getNodeValue() == null && node2.getNodeValue() == null) {
+ // empty
+ } else if (node1.getNodeValue() == null ||
+ node2.getNodeValue() == null) {
+ break nodeCheck;
+ } else if (!node1.getNodeValue().equals(node2.getNodeValue())) {
+ break nodeCheck;
+ }
+
+ // try to compare attributes
+ if (!attributesEqual(node1, node2)) {
+ break nodeCheck;
+ }
+
+ // don't need to compare if both node do not have children
+ if (!node1.hasChildNodes() && !node2.hasChildNodes()) {
+ equal = true;
+ break nodeCheck;
+ // don't need to compare if one node has children but not the other
+ } else if (!node1.hasChildNodes() || !node2.hasChildNodes()) {
+ equal = false;
+ break nodeCheck;
+ // need to compare if both node has children
+ } else if (!childrenEqual(node1, node2)) {
+ break nodeCheck;
+ }
+
+ equal = true;
+ }
+
+ return equal;
+ }
+
+
+ /**
+ * Compare the children of two <code>Node</code> objects. This
+ * method can be intentionally overridden by any class that
+ * extend from <code>NodeIterator</code> so that it can have
+ * its own children comparison if necessary.
+ *
+ * @param node1 The first <code>Node</code> to compare.
+ * @param node2 The second <code>Node</code> to compare.
+ *
+ * @return true if children are equal, false otherwise.
+ */
+ protected boolean childrenEqual(Node node1, Node node2) {
+
+ boolean equal = false;
+
+ childrenCheck: {
+ NodeList node1Children = node1.getChildNodes();
+ NodeList node2Children = node2.getChildNodes();
+
+ if (node1Children == null || node2Children == null) {
+ break childrenCheck;
+ }
+
+ if (node1Children.getLength() != node2Children.getLength()) {
+ break childrenCheck;
+ }
+
+ // compare all the childrens
+ equal = true;
+
+ for (int i = 0; i < node1Children.getLength(); i++) {
+ if (!compareNode(node1Children.item(i),
+ node2Children.item(i))) {
+ equal = false;
+ break childrenCheck;
+ }
+ }
+ }
+
+ return equal;
+ }
+
+
+ /**
+ * Compare attributes of two <code>Node</code> objects. This
+ * method can be intentionally overridden by any class that
+ * extends from <code>NodeIterator</code> so that it can have
+ * its own attribute comparison.
+ *
+ * @param node1 The first <code>Node</code> to compare.
+ * @param node2 The second <code>Node</code> to compare.
+ *
+ * @return true if attributes are equal, false otherwise.
+ */
+ protected boolean attributesEqual(Node node1, Node node2) {
+
+ boolean equal = false;
+ String nodeName = node1.getNodeName();
+ NamedNodeMap attrNode[] = new NamedNodeMap[2];
+ attrNode[0] = node1.getAttributes();
+ attrNode[1] = node2.getAttributes();
+
+ // attribute node will be null if node is not an element node
+ // and attribute nodes are equal if both are not element node
+ if (attrNode[0] == null || attrNode[1] == null) {
+ if (attrNode[0] == null && attrNode[1] == null) {
+ equal = true;
+ }
+ return equal;
+ }
+
+ // compare the attributes from node1 vs node2 and node2 vs node1
+ // though it's a little inefficient for the duplication of comparison
+ // as the number of attributes is not so many, it should not be
+ // a big problem.
+ int len [] = new int[2];
+ int src, dst;
+
+ attrCheck: {
+ for (int i = 0; i < 2; i++) {
+
+ if (i == 0) {
+ src = 0;
+ dst = 1;
+ } else {
+ src = 1;
+ dst = 0;
+ }
+
+ len[src] = attrNode[src].getLength();
+
+ for (int j = 0; j < len[src]; j++) {
+ Node srcAttr = attrNode[src].item(j);
+ String srcAttrName = srcAttr.getNodeName();
+
+ // copy the supported attrs
+ if (cc_ == null ||
+ cc_.canConvertAttribute(nodeName, srcAttrName)) {
+
+ // check whether the attribute exist in dst node
+ Node dstAttr = attrNode[dst].getNamedItem(srcAttrName);
+
+ if (dstAttr == null) {
+ Debug.log(Debug.INFO,
+ "[NodeIterator] Attr not exist in dst - "
+ + srcAttrName);
+ break attrCheck;
+ }
+
+ // then compare the attribute values
+ if (!srcAttr.getNodeValue().equals(
+ dstAttr.getNodeValue())) {
+ Debug.log(Debug.INFO,
+ "[NodeIterator] Attr diff src: " +
+ srcAttr.getNodeValue() + " dst: "+
+ dstAttr.getNodeValue());
+ break attrCheck;
+ }
+ } // end if cc_ loop
+ } // end for j loop
+ } // end for i loop
+
+ // the whole checking is done smoothly and all attributes are equal
+ equal = true;
+ }
+
+ return equal;
+ }
+
+
+ /**
+ * Check whether a <code>Node</code> is supported. This method
+ * can be intentionally overridden by any class that extends from
+ * <code>NodeIterator</code> so that it can specify which
+ * <code>Node</code> to support.
+ *
+ * @param node <code>Node</code> to check.
+ *
+ * @return true if <code>Node</code> is supported, false otherwise.
+ */
+ protected abstract boolean nodeSupported(Node node);
+
+ // doing a depth first search for the tree and mark all supported nodes
+ private void markTree(Node node) {
+
+ // if this is a supported node, then we add it to our cache table
+ if (nodeSupported(node)) {
+ nodeList.add(node);
+ } else {
+ // or we go through all children nodes recursively
+ // (can be optimized in future)
+ String nodeName = node.getNodeName();
+ if ( cc_ == null || cc_.canConvertTag(nodeName)) {
+ NodeList nodeList = node.getChildNodes();
+ int nodeListLength = nodeList.getLength();
+ for (int i = 0; i < nodeListLength; i++) {
+ markTree(nodeList.item(i));
+ }
+ }
+ else {
+ Debug.log(Debug.INFO, " [NodeIterator::markTree] Skipping node "
+ + nodeName);
+ }
+ }
+ }
+}
+
diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/merger/diff/ObjectArrayIterator.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/merger/diff/ObjectArrayIterator.java
new file mode 100644
index 000000000000..d52b53fd78a7
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/merger/diff/ObjectArrayIterator.java
@@ -0,0 +1,210 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.merger.diff;
+
+import org.openoffice.xmerge.merger.Iterator;
+
+/**
+ * <p>This is an implementation of the <code>Iterator</code> interface.
+ * It is based upon a simple <code>Object</code> array.</p>
+ *
+ * <p>Note: this class is not thread safe for performance reasons.</p>
+ *
+ * @author smak
+ */
+public final class ObjectArrayIterator implements Iterator {
+
+
+ /**
+ * The <code>Object</code> array.
+ */
+ private Object [] objArray;
+ private int currentPosition;
+
+
+ /**
+ * Private default constructor.
+ */
+ private ObjectArrayIterator() {
+ // do not allow user new a ObjectArrayIterator without argument
+ }
+
+
+ /**
+ * Standard constructor.
+ *
+ * @param objArray The <code>Object</code> array.
+ */
+ public ObjectArrayIterator(Object [] objArray) {
+ if (objArray != null) {
+ this.objArray = new Object[objArray.length];
+ System.arraycopy(objArray, 0, this.objArray, 0, objArray.length);
+ currentPosition = 0;
+ } else {
+ this.objArray = new Object[0];
+ }
+ }
+
+
+ public Object next() {
+ if (currentPosition < objArray.length - 1) {
+ currentPosition++;
+ return currentElement();
+ } else {
+ return null;
+ }
+
+ }
+
+
+ public Object previous() {
+ if (currentPosition > 0) {
+ currentPosition--;
+ return currentElement();
+ } else {
+ return null;
+ }
+ }
+
+
+ public Object start() {
+ currentPosition = 0;
+ return currentElement();
+ }
+
+
+ public Object end() {
+ if (objArray.length > 0) {
+ currentPosition = objArray.length - 1;
+ }
+ return currentElement();
+ }
+
+
+ public Object currentElement() {
+ if (objArray.length > 0) {
+ return objArray[currentPosition];
+ } else {
+ return null;
+ }
+ }
+
+
+ /**
+ * Replace current <code>Object</code>.
+ *
+ * @param object <code>Object</code> to replace.
+ */
+ public void replace(Object object) {
+ objArray[currentPosition] = object;
+ }
+
+
+ /**
+ * Insert <code>Object</code> after current <code>Object</code>.
+ *
+ * @param object <code>Object</code> to insert.
+ */
+ public void insert(Object object) {
+ Object [] objArray2 = new Object[objArray.length+1];
+
+ // copy the array content up before the currentposition
+ if (currentPosition > 0) {
+ System.arraycopy(objArray, 0, objArray2, 0, currentPosition);
+ }
+
+ objArray2[currentPosition] = object;
+
+ // copy the array content up after the currentposition
+ System.arraycopy(objArray, currentPosition, objArray2,
+ currentPosition + 1, objArray.length - currentPosition);
+
+ objArray = objArray2;
+ currentPosition++;
+ }
+
+ /**
+ * Append <code>Object</code> after current <code>Object</code>.
+ *
+ * @param object <code>Object</code> to append.
+ */
+ public void append(Object object) {
+ Object [] objArray2 = new Object[objArray.length + 1];
+
+ int newPosition = currentPosition + 1;
+
+ // copy the array content up to the currentposition
+ System.arraycopy(objArray, 0, objArray2, 0, newPosition);
+
+ objArray2[newPosition] = object;
+
+ // copy the array content up after the currentposition
+ if (currentPosition < objArray.length - 1) {
+ System.arraycopy(objArray, newPosition, objArray2,
+ newPosition + 1, objArray.length - newPosition);
+ }
+
+ objArray = objArray2;
+ }
+
+ /**
+ * Remove current <code>Object</code>.
+ */
+ public void remove() {
+ Object [] objArray2 = new Object[objArray.length - 1];
+
+ // copy the array content up before the currentposition
+ if (currentPosition > 0) {
+ System.arraycopy(objArray, 0, objArray2, 0, currentPosition);
+ }
+
+ // copy the array content up after the currentposition
+ if (currentPosition < objArray.length - 1) {
+ System.arraycopy(objArray, currentPosition + 1, objArray2,
+ currentPosition, objArray.length - currentPosition - 1);
+ }
+
+ objArray = objArray2;
+
+ if (currentPosition == objArray.length)
+ currentPosition--;
+ }
+
+ public int elementCount() {
+ return objArray.length;
+ }
+
+ public boolean equivalent(Object obj1, Object obj2) {
+ return obj1.equals(obj2);
+ }
+
+ public void refresh() {
+ // do nothing
+ }
+}
+
diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/merger/diff/ParaNodeIterator.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/merger/diff/ParaNodeIterator.java
new file mode 100644
index 000000000000..2e16275e0e44
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/merger/diff/ParaNodeIterator.java
@@ -0,0 +1,90 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.merger.diff;
+
+import org.w3c.dom.Node;
+
+import org.openoffice.xmerge.ConverterCapabilities;
+import org.openoffice.xmerge.converter.xml.OfficeConstants;
+
+
+/**
+ * <p>This is an implementation of the <code>Iterator</code> interface.
+ * It will traverse the tree and find the Paragraph/Heading <code>Node</code>
+ * sequences.</p>
+ *
+ * <p>Note: Once the XML Tree is parsed, then the <code>Iterator</code> will
+ * be a snap shot of that tree. That means even the tree is modified later,
+ * than the cached paragraph <code>Node</code> list will not be updated
+ * accordingly. For this reason and for performance reasons this
+ * <code>Iterator</code> does not support any operation methods such as
+ * insert, remove or replace. The main purpose of this
+ * <code>Iterator</code> is to be used with difference, not with merge.</p>
+ *
+ * @author smak
+ */
+public final class ParaNodeIterator extends NodeIterator {
+
+ // can be expanded to an array in the future, not necessary right now
+ private static final String SUPPORTED_TAG1 = OfficeConstants.TAG_PARAGRAPH;
+ private static final String SUPPORTED_TAG2 = OfficeConstants.TAG_HEADING;
+
+ /**
+ * Standard constructor.
+ *
+ * @param cc The <code>ConverterCapabilities</code>.
+ * @param node The initial root <code>Node</code>.
+ */
+ public ParaNodeIterator(ConverterCapabilities cc, Node node) {
+ // not using convertercapabilities unless it's needed in future.
+ super(cc, node);
+ }
+
+
+ /**
+ * Overwrite the parent <code>nodeSupported</code> method.
+ *
+ * @param node <code>Node</code> to check.
+ *
+ * @return true if the <code>Node</code> is supported, false
+ * otherwise.
+ */
+ protected boolean nodeSupported(Node node) {
+
+ // can use an array later to check all possible tags for
+ // future expansion
+ if (node.getNodeType() == Node.ELEMENT_NODE &&
+ (node.getNodeName().equals(SUPPORTED_TAG1) ||
+ node.getNodeName().equals(SUPPORTED_TAG2))) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+}
+
diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/merger/diff/RowIterator.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/merger/diff/RowIterator.java
new file mode 100644
index 000000000000..0e514209e2f0
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/merger/diff/RowIterator.java
@@ -0,0 +1,81 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.merger.diff;
+
+import org.w3c.dom.Node;
+
+import org.openoffice.xmerge.ConverterCapabilities;
+import org.openoffice.xmerge.converter.xml.OfficeConstants;
+import org.openoffice.xmerge.util.Resources;
+
+
+/**
+ * This is an implementation of the <code>Iterator</code> interface and extends
+ * <code>NodeIterator</code>. It will traverse the tree and find row sequences.
+ *
+ * @author smak
+ */
+public final class RowIterator extends NodeIterator {
+
+ private Resources res = Resources.getInstance();
+
+ // TODO: should compare the ConverterCapabilities supported feature only!
+ // otherwise even though one with a chart, one without, will still be
+ // considered to be not equivalent.
+
+ /**
+ * Standard constructor.
+ *
+ * @param cc The <code>ConverterCapabilities</code>.
+ * @param node The initial root <code>Node</code>.
+ */
+ public RowIterator(ConverterCapabilities cc, Node node) {
+ super(cc, node);
+ }
+
+ /**
+ * Overwrite the parent <code>nodeSupported</code> method. Only
+ * row <code>Node</code> objects are supported.
+ *
+ * @param node <code>Node</code> to check.
+ *
+ * @return true if the <code>Node</code> is supported, false otherwise.
+ */
+ protected boolean nodeSupported(Node node) {
+
+ // can use an array later to check all possible tags for
+ // future expansion
+ if (node.getNodeType() == Node.ELEMENT_NODE &&
+ node.getNodeName().equals(OfficeConstants.TAG_TABLE_ROW)) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+}
+
diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/merger/diff/TextNodeEntry.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/merger/diff/TextNodeEntry.java
new file mode 100644
index 000000000000..8840585b2b92
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/merger/diff/TextNodeEntry.java
@@ -0,0 +1,88 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.merger.diff;
+
+import org.w3c.dom.Node;
+
+/**
+ * A small class to hold the start/end character position and the
+ * <code>Node</code> pointer in a text <code>Node</code>. It is
+ * mainly used for character parser to make a list of text
+ * <code>Node</code> cache entries.
+ *
+ * @author smak
+ */
+public class TextNodeEntry {
+
+ private int startChar_;
+ private int endChar_;
+ private Node node_;
+
+ /**
+ * Constructor
+ *
+ * @param startChar The start character position.
+ * @param endChar The end character position.
+ * @param node The text <code>Node</code>.
+ */
+ public TextNodeEntry(int startChar, int endChar, Node node) {
+ startChar_ = startChar;
+ endChar_ = endChar;
+ node_ = node;
+ }
+
+ /**
+ * Returns the start character.
+ *
+ * @return The start character.
+ */
+ public int startChar() {
+ return startChar_;
+ }
+
+
+ /**
+ * Returns the end character.
+ *
+ * @return The end character.
+ */
+ public int endChar() {
+ return endChar_;
+ }
+
+
+ /**
+ * Returns the <code>Node</code>.
+ *
+ * @return The <code>Node</code>.
+ */
+ public Node node() {
+ return node_;
+ }
+}
+
diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/merger/diff/TextNodeIterator.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/merger/diff/TextNodeIterator.java
new file mode 100644
index 000000000000..b1da7bcdcdaf
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/merger/diff/TextNodeIterator.java
@@ -0,0 +1,84 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.merger.diff;
+
+import org.w3c.dom.Node;
+
+import org.openoffice.xmerge.converter.xml.OfficeConstants;
+
+
+/**
+ * <p>This is an implementation of the <code>Iterator</code> interface.
+ * It will traverse the tree and find text/space/tab <code>Node</code>
+ * sequences.</p>
+ *
+ * <p>Note: Once the XML Tree is parsed, then the <code>Iterator</code>
+ * will be a snap shot of that tree. That means even the tree is modified
+ * later, than the cached paragraph <code>Node</code> list will not be
+ * updated accordingly. For this reason and for performance reasons
+ * this <code>Iterator</code> does not support any operation methods
+ * such as insert, remove or replace. The main purpose of this
+ * <code>Iterator</code> is to be used with difference, not with merge.</p>
+ *
+ * @author smak
+ */
+public final class TextNodeIterator extends NodeIterator {
+
+ /**
+ * Standard constructor.
+ *
+ * @param initial The initial root <code>Node</code>.
+ */
+ public TextNodeIterator(Node node) {
+ super(null, node);
+ }
+
+ /**
+ * Overwrite the parent <code>nodeSupported</code> method. Only text
+ * <code>Node</code> objects are supported.
+ *
+ * @param node <code>Node</code> to check.
+ *
+ * @return true if the <code>Node</code> is supported, false
+ * otherwise.
+ */
+ protected boolean nodeSupported(Node node) {
+
+ // can use an array later to check all possible tags for
+ // future expansion
+ if (node.getNodeType() == Node.TEXT_NODE ||
+ node.getNodeName().equals(OfficeConstants.TAG_SPACE) ||
+ node.getNodeName().equals(OfficeConstants.TAG_TAB_STOP) ||
+ node.getNodeName().equals(OfficeConstants.TAG_LINE_BREAK)) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+}
+
diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/merger/diff/package.html b/xmerge/source/xmerge/java/org/openoffice/xmerge/merger/diff/package.html
new file mode 100644
index 000000000000..f9d1b12a5f39
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/merger/diff/package.html
@@ -0,0 +1,43 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<!--
+ #*************************************************************************
+ #
+ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+
+ Copyright 2000, 2010 Oracle and/or its affiliates.
+
+ OpenOffice.org - a multi-platform office productivity suite
+
+ This file is part of OpenOffice.org.
+
+ OpenOffice.org is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License version 3
+ only, as published by the Free Software Foundation.
+
+ OpenOffice.org is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License version 3 for more details
+ (a copy is included in the LICENSE file that accompanied this code).
+
+ You should have received a copy of the GNU Lesser General Public License
+ version 3 along with OpenOffice.org. If not, see
+ <http://www.openoffice.org/license.html>
+ for a copy of the LGPLv3 License.
+
+ #*************************************************************************
+ -->
+<html>
+<head>
+<title>org.openoffice.xmerge.merger.diff package</title>
+</head>
+
+<body bgcolor="white">
+<p>Provides implementations for the {@link
+org.openoffice.xmerge.merger.Iterator Iterator}
+interface and related support classes. These are used by the {@link
+org.openoffice.xmerge.merger.DiffAlgorithm
+DiffAlgorithm} interface.</p>
+
+</body>
+</html>
diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/merger/merge/CharacterBaseParagraphMerge.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/merger/merge/CharacterBaseParagraphMerge.java
new file mode 100644
index 000000000000..adcd483dd44a
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/merger/merge/CharacterBaseParagraphMerge.java
@@ -0,0 +1,310 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.merger.merge;
+
+import java.util.List;
+import org.w3c.dom.Node;
+import org.openoffice.xmerge.merger.Difference;
+import org.openoffice.xmerge.merger.NodeMergeAlgorithm;
+import org.openoffice.xmerge.merger.diff.CharacterParser;
+import org.openoffice.xmerge.merger.diff.CharArrayLCSAlgorithm;
+import org.openoffice.xmerge.merger.diff.TextNodeEntry;
+import org.openoffice.xmerge.util.Debug;
+
+/**
+ * This is an implementation of the <code>NodeMergeAlgorithm</code>
+ * interface. It is used to merge two paragraph <code>Node</code>
+ * objects based on character comparisons.
+ *
+ * @author smak
+ */
+public final class CharacterBaseParagraphMerge
+ implements NodeMergeAlgorithm {
+
+
+ private class cacheCharArray {
+ public cacheCharArray(int cacheSize) {
+ }
+ }
+
+
+ /**
+ * Merge two paragraph <code>Node</code> by using Longest Common
+ * Subsequence (LCS) character algorithm defined in {@link
+ * org.openoffice.xmerge.merger.diff.CharArrayLCSAlgorithm
+ * CharArrayLCSAlgorithm}
+ *
+ * @param orgPara The original paragraph <code>Node</code>.
+ * @param modPara The modified paragraph <code>Node</code>.
+ */
+ public void merge(Node orgPara, Node modPara) {
+ CharacterParser orgParser = new CharacterParser(orgPara);
+ CharacterParser modParser = new CharacterParser(modPara);
+
+ char[] orgCharArray = orgParser.getCharArray();
+ char[] modCharArray = modParser.getCharArray();
+
+ CharArrayLCSAlgorithm diffAlgo = new CharArrayLCSAlgorithm();
+
+ Difference[] diffResult = diffAlgo.computeDiffs(orgCharArray,
+ modCharArray);
+ // debug use
+ System.out.println("Diff Result: ");
+ for (int i = 0; i < diffResult.length; i++) {
+ Debug.log(Debug.INFO, diffResult[i].debug());
+ }
+
+ applyDifference(orgParser, modParser, diffResult);
+ }
+
+
+ private void applyDifference(CharacterParser orgParser,
+ CharacterParser modParser,
+ Difference[] diffs) {
+
+ List orgNodeList = orgParser.getNodeList();
+ List modNodeList = modParser.getNodeList();
+ int diffCount = 0;
+ int modNodeListCnt = 0;
+ int numNode = orgNodeList.size();
+
+ for (int i = 0; i < numNode; i++) {
+
+ int extraChar = 0;
+ int orgDiffCount = diffCount;
+ TextNodeEntry orgTextNode = (TextNodeEntry)(orgNodeList.get(i));
+
+ Debug.log(Debug.INFO, "checking node " + (i + 1) + " of " + numNode);
+
+ // check any difference in this node and estimate the new char num
+ for (; diffCount < diffs.length; diffCount++) {
+
+ Debug.log(Debug.INFO, " checking diff " + (diffCount + 1) +
+ " of " + diffs.length);
+ Debug.log(Debug.INFO, " OrgPosision <" +
+ diffs[diffCount].getOrgPosition() + "> diffCount <" +
+ diffCount + "> orgDiffCount <" + orgDiffCount + ">");
+
+ // don't need to check and diffs beyond the current node text
+ // range except the last node
+ if (diffs[diffCount].getOrgPosition() > orgTextNode.endChar() &&
+ i < numNode - 1) {
+ Debug.log(Debug.INFO, " breaking!");
+ break;
+ }
+
+ if (diffs[diffCount].getOrgPosition()
+ >= orgTextNode.startChar()) {
+ if (diffs[diffCount].getOperation() == Difference.DELETE) {
+ extraChar--;
+ } else if (diffs[diffCount].getOperation()
+ == Difference.ADD) {
+ extraChar++;
+ }
+
+ }
+ }
+
+ Debug.log(Debug.INFO, " final diffCount <" + diffCount +
+ "> final orgDiffCount <" + orgDiffCount + ">");
+
+ // will only try to merge if there is a difference in this node
+ if (diffCount > orgDiffCount) {
+
+ Debug.log(Debug.INFO, " There is a difference, doing merge");
+ Debug.log(Debug.INFO, " TextNode name <" +
+ orgTextNode.node().getNodeName() + ">");
+ Debug.log(Debug.INFO, " TextNode value <" +
+ orgTextNode.node().getNodeValue() + ">");
+ Debug.log(Debug.INFO, " TextNode start char <" +
+ orgTextNode.startChar() + "> TextNode end char <" +
+ orgTextNode.endChar() + ">");
+ Debug.log(Debug.INFO, " extraChar value <" + extraChar + ">");
+
+ coreMerge(orgDiffCount, diffCount, diffs, orgParser,
+ modParser, orgTextNode, extraChar);
+ }
+ }
+ }
+
+ private void coreMerge(int startDiffNum, int endDiffNum, Difference[] diffs,
+ CharacterParser orgParser, CharacterParser modParser,
+ TextNodeEntry orgTextNode, int extraChar) {
+
+ Node orgNode = orgTextNode.node();
+ char[] modTextArray = modParser.getCharArray();
+ String tmpString;
+
+ // Handle situation where getNodeValue returns null
+ //
+ if (orgNode.getNodeValue() != null)
+ tmpString = orgNode.getNodeValue();
+ else
+ tmpString = "";
+
+ char[] orgNodeText = tmpString.toCharArray();
+ char[] newNodeText;
+
+ if (orgNodeText.length + extraChar > 0)
+ newNodeText = new char[orgNodeText.length + extraChar];
+ else
+ newNodeText = new char[0];
+
+ int orgTextPosition = orgTextNode.startChar(); // used for block copy
+ int newTextPosition = 0; // used for block copy
+ int unChangedTextLength = 0;
+
+ char[] cacheCharArray = new char[endDiffNum - startDiffNum];
+ int cacheLength = 0;
+ int lastDiffOperation = Difference.UNCHANGE;
+ int lastDiffPosition = -1;
+
+ // starting to diff
+ //
+ for (int j = startDiffNum; j < endDiffNum; j++) {
+
+ // copy any contents before the diff
+ //
+ if (diffs[j].getOrgPosition() > orgTextPosition) {
+ // need to flush first
+ if (cacheLength > 0) {
+ System.arraycopy(cacheCharArray, 0,
+ newNodeText, newTextPosition, cacheLength);
+ newTextPosition += cacheLength;
+
+ // reset the markers
+ lastDiffPosition = -1;
+ lastDiffOperation = Difference.UNCHANGE;
+ cacheLength = 0;
+ }
+
+ // find out the length how many characters are
+ // untouched by the diff
+ unChangedTextLength = diffs[j].getOrgPosition() -
+ orgTextPosition;
+ System.arraycopy(orgNodeText,
+ orgTextPosition - orgTextNode.startChar(),
+ newNodeText, newTextPosition,
+ unChangedTextLength);
+ orgTextPosition += unChangedTextLength;
+ newTextPosition += unChangedTextLength;
+ }
+
+ // for any deleted characters, just skip without copy
+ // but still need to take care the cached characters
+ //
+ if (diffs[j].getOperation() == Difference.DELETE) {
+ orgTextPosition++;
+
+ // flush out the cache and copy the content to new Text
+ if (cacheLength > 0) {
+ System.arraycopy(cacheCharArray, 0,
+ newNodeText, newTextPosition, cacheLength);
+ newTextPosition += cacheLength;
+
+ // reset the markers
+ lastDiffPosition = -1;
+ lastDiffOperation = Difference.UNCHANGE;
+ cacheLength = 0;
+ }
+
+ continue;
+
+
+ // check whether we should flush the cache.
+ // For changed diffs, only continuous changes can be cached
+ // For Add diffs, only same insertion point can be cached
+ // and for both changed/add diffs, need to have same operation
+ // as last cached diffs.
+
+ } else {
+ if (lastDiffOperation != diffs[j].getOperation() ||
+ (diffs[j].getOperation() == Difference.CHANGE &&
+ diffs[j].getOrgPosition() != lastDiffPosition + 1) ||
+ (diffs[j].getOperation() == Difference.ADD &&
+ diffs[j].getOrgPosition() != lastDiffPosition)) {
+
+ // flush the cache
+ if (cacheLength > 0) {
+ System.arraycopy(cacheCharArray, 0, newNodeText,
+ newTextPosition, cacheLength);
+ newTextPosition += cacheLength;
+
+ // reset the markers
+ lastDiffPosition = -1;
+ lastDiffOperation = Difference.UNCHANGE;
+ cacheLength = 0;
+ }
+ }
+
+ // add the diffs to the cache, now the diffs will be either
+ // a new 'changed' char or is an adjacent following change of
+ // last difference
+ cacheCharArray[cacheLength] =
+ modTextArray[diffs[j].getModPosition()];
+ cacheLength++;
+ lastDiffOperation = diffs[j].getOperation();
+ lastDiffPosition = diffs[j].getOrgPosition();
+
+ // need to increment the original text position
+ // after we cached it
+ if (lastDiffOperation == Difference.CHANGE) {
+ orgTextPosition++;
+ }
+ }
+ }
+
+ // flush any contents remaining in the cache
+ if (cacheLength > 0) {
+ System.arraycopy(cacheCharArray, 0, newNodeText,
+ newTextPosition, cacheLength);
+ newTextPosition += cacheLength;
+ // no need to reset any cache-related info as this is a last flush
+ }
+
+ // copy any contents after all the diffs
+ int orgStartPosition = orgTextNode.startChar();
+ if (orgNodeText.length + orgStartPosition > orgTextPosition) {
+ unChangedTextLength = orgNodeText.length + orgStartPosition
+ - orgTextPosition;
+ System.arraycopy(orgNodeText, orgTextPosition - orgStartPosition,
+ newNodeText, newTextPosition,
+ unChangedTextLength);
+ }
+
+ // set the text to the original node if there are any diffs processed.
+ // can't use newNodeText.length to check as even it is empty, we may
+ // process a whole bunch of deletion already (i.e. the whole
+ // orgNodeText deleted).
+ if (endDiffNum > startDiffNum) {
+ String newString = new String(newNodeText);
+ orgNode.setNodeValue(newString);
+ }
+ }
+}
+
diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/merger/merge/DocumentMerge.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/merger/merge/DocumentMerge.java
new file mode 100644
index 000000000000..5c293000a964
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/merger/merge/DocumentMerge.java
@@ -0,0 +1,247 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.merger.merge;
+
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+import org.openoffice.xmerge.ConverterCapabilities;
+import org.openoffice.xmerge.MergeException;
+import org.openoffice.xmerge.merger.MergeAlgorithm;
+import org.openoffice.xmerge.merger.NodeMergeAlgorithm;
+import org.openoffice.xmerge.merger.Iterator;
+import org.openoffice.xmerge.merger.Difference;
+import org.openoffice.xmerge.util.XmlUtil;
+
+/**
+ * This is an implementation of the <code>MergeAlgorithm</code> interface.
+ * This class will merge two <code>Document</code> classes. It utilizes the
+ * appropriate class which implements {@link
+ * org.openoffice.xmerge.merger.NodeMergeAlgorithm
+ * NodeMergeAlgorithm} to perform the merge.
+ *
+ * @author smak
+ */
+public class DocumentMerge implements MergeAlgorithm {
+
+ private NodeMergeAlgorithm subDocumentMerge = null;
+
+ /** The capabilities of this converter. */
+ protected ConverterCapabilities cc_;
+
+
+ /**
+ * Constructor
+ *
+ * @param cc The <code>ConverterCapabilities</code>.
+ * @param merge The <code>NodeMergeAlgorithm</code>.
+ */
+ public DocumentMerge(ConverterCapabilities cc, NodeMergeAlgorithm merge) {
+ cc_ = cc;
+ subDocumentMerge = merge;
+ }
+
+
+ public void applyDifference(Iterator orgSeq, Iterator modSeq,
+ Difference[] differences) throws MergeException {
+
+
+ // a quick test whether the differences array is in ascending order
+ int currentPosition = -1;
+ boolean haveDeleteOperation = false;
+
+ for (int i = 0; i < differences.length; i++) {
+ if (differences[i].getOrgPosition() > currentPosition) {
+ currentPosition = differences[i].getOrgPosition();
+ if (differences[i].getOperation() == Difference.DELETE) {
+ haveDeleteOperation = true;
+ } else {
+ haveDeleteOperation = false;
+ }
+ } else if (differences[i].getOrgPosition() == currentPosition) {
+ if (differences[i].getOperation() == Difference.DELETE) {
+ haveDeleteOperation = true;
+ } else if (differences[i].getOperation() == Difference.ADD &&
+ haveDeleteOperation == true) {
+ throw new MergeException(
+ "Differences array is not sorted. Delete before Add");
+ }
+ } else {
+ throw new MergeException("Differences array need to be sorted.");
+ }
+ }
+
+ // reset sequence counters
+ orgSeq.start();
+ int orgSeqCounter = 0;
+
+ modSeq.start();
+ int modSeqCounter = 0;
+
+ // check for each diff unit in the diff array to apply the diff
+ for (int i = 0; i < differences.length; i++) {
+
+ Difference currentDiff = differences[i];
+
+ int operation = currentDiff.getOperation();
+
+ Object currentElement;
+
+ switch (operation) {
+
+ case Difference.DELETE:
+ // loop through the original sequence up to the expected
+ // position. note that we use delta (see above comment)
+ // also. we will just continue the counter without reset it.
+ for (;
+ orgSeqCounter < currentDiff.getOrgPosition();
+ orgSeqCounter++, orgSeq.next()) {
+ // empty
+ }
+
+ // remove the Node. note that it will NOT affect the
+ // iterator sequence as ParaNodeIterator is a static one.
+ removeNode((Node)(orgSeq.currentElement()));
+
+ break;
+
+ // if it's an add operation, then get content from original seq
+ case Difference.ADD:
+ // loop through the modified sequence up to the expected
+ // position to get the content. As we don't need to modify
+ // the sequence. we don't need to use delta to do adjustment.
+ for (;
+ modSeqCounter < currentDiff.getModPosition();
+ modSeqCounter++, modSeq.next()) {
+ // empty
+ }
+
+ currentElement = orgSeq.currentElement();
+
+ for (;
+ orgSeqCounter < currentDiff.getOrgPosition();
+ orgSeqCounter++, currentElement = orgSeq.next()) {
+ // empty
+ }
+
+ if (orgSeqCounter > orgSeq.elementCount() - 1) {
+ // append the element to the end of the original sequence
+ appendNode((Node)(orgSeq.currentElement()),
+ (Node)(modSeq.currentElement()));
+ } else {
+ // insert the element BEFORE the current element
+ insertNode((Node)(orgSeq.currentElement()),
+ (Node)(modSeq.currentElement()));
+ }
+
+ break;
+
+ case Difference.CHANGE:
+ for (;
+ modSeqCounter < currentDiff.getModPosition();
+ modSeqCounter++, modSeq.next()) {
+ // empty
+ }
+
+ currentElement = orgSeq.currentElement();
+
+ for (;
+ orgSeqCounter < currentDiff.getOrgPosition();
+ orgSeqCounter++, currentElement = orgSeq.next()) {
+ // empty
+ }
+
+ if (subDocumentMerge == null) {
+ // use a simple replace if no row merge algorithm supply
+ replaceElement((Element)orgSeq.currentElement(),
+ (Element)modSeq.currentElement());
+ } else {
+ subDocumentMerge.merge((Element)orgSeq.currentElement(),
+ (Element)modSeq.currentElement());
+
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+
+
+ /**
+ * Removes the specified <code>Node</code>.
+ *
+ * @param node <code>Node</code> to remove.
+ */
+ protected void removeNode(Node node) {
+
+ Node parent = node.getParentNode();
+ parent.removeChild(node);
+ }
+
+ /**
+ * Appends <code>Node</code> after the specified <code>Node</code>.
+ *
+ * @param oldNode <code>Node</code> to append after.
+ * @param newNode <code>Node</code> to append.
+ */
+ protected void appendNode(Node oldNode, Node newNode) {
+ Node clonedNode = XmlUtil.deepClone(oldNode, newNode);
+ Node parent = oldNode.getParentNode();
+ parent.appendChild(clonedNode);
+ }
+
+
+ /**
+ * Insert <code>Node</code> before the specified <code>Node</code>.
+ *
+ * @param oldNode <code>Node</code> to insert before.
+ * @param newNode <code>Node</code> to insert.
+ */
+ protected void insertNode(Node oldNode, Node newNode) {
+ Node clonedNode = XmlUtil.deepClone(oldNode, newNode);
+ Node parent = oldNode.getParentNode();
+ parent.insertBefore(clonedNode, oldNode);
+ }
+
+
+ /**
+ * Replace <code>Element</code>.
+ *
+ * @param currElem <code>Element</code> to be replaced.
+ * @param newElem <code>Element</code> to replace.
+ */
+ protected void replaceElement(Element currElem, Element newElem) {
+
+ Node clonedNode = XmlUtil.deepClone(currElem, newElem);
+ Node parent = currElem.getParentNode();
+ parent.replaceChild(clonedNode, currElem);
+ }
+}
+
diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/merger/merge/PositionBaseRowMerge.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/merger/merge/PositionBaseRowMerge.java
new file mode 100644
index 000000000000..4d912d1c8a56
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/merger/merge/PositionBaseRowMerge.java
@@ -0,0 +1,260 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.merger.merge;
+
+import org.w3c.dom.Node;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+import org.w3c.dom.NamedNodeMap;
+
+import org.openoffice.xmerge.ConverterCapabilities;
+import org.openoffice.xmerge.merger.Iterator;
+import org.openoffice.xmerge.merger.NodeMergeAlgorithm;
+import org.openoffice.xmerge.merger.diff.CellNodeIterator;
+import org.openoffice.xmerge.converter.xml.OfficeConstants;
+import org.openoffice.xmerge.util.XmlUtil;
+
+
+/**
+ * This is an implementation of the <code>NodeMergeAlgorithm</code>
+ * interface. It is used to merge two rows using a positional
+ * comparison base method.
+ */
+public final class PositionBaseRowMerge implements NodeMergeAlgorithm {
+
+ /** The capabilities of this converter. */
+ private ConverterCapabilities cc_;
+
+
+ /**
+ * Constructor.
+ *
+ * @param cc The <code>ConverterCapabilities</code>.
+ */
+ public PositionBaseRowMerge(ConverterCapabilities cc) {
+ cc_ = cc;
+ }
+
+
+ public void merge(Node orgRow, Node modRow) {
+
+ Iterator orgCells = new CellNodeIterator(cc_, orgRow);
+ Iterator modCells = new CellNodeIterator(cc_, modRow);
+
+ mergeCellSequences(orgCells, modCells);
+ }
+
+
+ // used to compare the cell 1 by 1
+ private void mergeCellSequences(Iterator orgSeq, Iterator modSeq) {
+
+ boolean needMerge = true;
+ Element orgCell, modCell;
+
+ Object orgSeqObject = orgSeq.start();
+ Object modSeqObject = modSeq.start();
+
+ while (orgSeqObject != null) {
+
+
+ needMerge = true;
+
+ if (modSeqObject == null) {
+ // no corresponding cell in the target, empty out the cell
+ SheetUtil.emptyCell(cc_, (Node)orgSeqObject);
+ orgSeqObject = orgSeq.next();
+
+ } else {
+
+ // compare the cell directly
+ if (!orgSeq.equivalent(orgSeqObject, modSeqObject)) {
+
+ orgCell = (Element)orgSeqObject;
+ modCell = (Element)modSeqObject;
+
+ // check whether the original cell with multiple column
+ // if so, need to split one out for merge
+ String orgColRepeated = orgCell.getAttribute(
+ OfficeConstants.ATTRIBUTE_TABLE_NUM_COLUMNS_REPEATED);
+ String modColRepeated = modCell.getAttribute(
+ OfficeConstants.ATTRIBUTE_TABLE_NUM_COLUMNS_REPEATED);
+
+ int orgColNum = 1;
+ int modColNum = 1;
+
+ if (orgColRepeated.length() > 0) {
+ orgColNum =
+ Integer.valueOf(orgColRepeated).intValue();
+ }
+ if (modColRepeated.length() > 0) {
+ modColNum =
+ Integer.valueOf(modColRepeated).intValue();
+ }
+
+ // try to find out the common number of repeated cols
+ if (orgColNum == modColNum) {
+ orgSeqObject = orgSeq.next();
+ modSeqObject = modSeq.next();
+
+ // cut the original cell into 2 half, first half
+ // have the repeated attribute = modify cell attr
+ } else if (orgColNum > modColNum) {
+ Element orgSplitCell = splitColRepeatedCell(
+ orgCell, modColNum,
+ orgColNum - modColNum);
+ // it may equal after the split!
+ if (orgSeq.equivalent(orgSplitCell, modCell)) {
+ needMerge = false;
+ }
+ orgCell = orgSplitCell;
+ modSeqObject = modSeq.next();
+
+ // cut the modified cell into 2 half, first half
+ // have the repeated attribute = original cell attr
+ } else {
+ Element modSplitCell = splitColRepeatedCell(
+ modCell, orgColNum,
+ modColNum - orgColNum);
+ // it may equal after the split!
+ if (modSeq.equivalent(orgCell, modSplitCell)) {
+ needMerge = false;
+ }
+ modCell = modSplitCell;
+ orgSeqObject = orgSeq.next();
+ }
+
+ if (needMerge) {
+ mergeCells(orgCell, modCell);
+ }
+
+ } else {
+ // cells are equivalent, move on to next one.
+ orgSeqObject = orgSeq.next();
+ modSeqObject = modSeq.next();
+ } // end if-else
+ } // end if-else
+ } // end while loop
+
+ // get the one of the original cell, so that the cloned node
+ // can base it to find the document node
+ orgCell = (Element)orgSeq.start();
+
+ // add any extra cells to the original cell sequence.
+ for (; modSeqObject != null; modSeqObject = modSeq.next()) {
+ Node clonedNode = XmlUtil.deepClone(orgCell, (Node)modSeqObject);
+ Node parent = orgCell.getParentNode();
+ parent.appendChild(clonedNode);
+ }
+ }
+
+
+ private Element splitColRepeatedCell(Element orgCell,
+ int splitNum, int orgNum) {
+ // NOTE: should we really want to do deep clone?
+ // in most the case, it is an empty cell, but the
+ // specification didn't forbid any node to use multiple
+ // column attributes. i.e. the node can contain text
+ // nodes or other things under it.
+ Element splitCell = (Element)(orgCell.cloneNode(true));
+
+ if (splitNum > 1) {
+ splitCell.setAttribute(
+ OfficeConstants.ATTRIBUTE_TABLE_NUM_COLUMNS_REPEATED,
+ String.valueOf(splitNum));
+ } else if (splitNum == 1) {
+ splitCell.removeAttribute(
+ OfficeConstants.ATTRIBUTE_TABLE_NUM_COLUMNS_REPEATED);
+ }
+ if (orgNum > 1) {
+ orgCell.setAttribute(
+ OfficeConstants.ATTRIBUTE_TABLE_NUM_COLUMNS_REPEATED,
+ String.valueOf(orgNum));
+ } else if (orgNum == 1) {
+ orgCell.removeAttribute(
+ OfficeConstants.ATTRIBUTE_TABLE_NUM_COLUMNS_REPEATED);
+ }
+
+ Node parentNode = orgCell.getParentNode();
+ parentNode.insertBefore(splitCell, orgCell);
+
+ return splitCell;
+ }
+
+
+ private void mergeCells(Element orgCell, Element modCell) {
+
+ // remove all the supported attributes and possible text child for
+ // string cells
+ SheetUtil.emptyCell(cc_, orgCell);
+
+ // copy all the supported attributes and possible text child from
+ // the modified cell
+ NamedNodeMap attrNodes = modCell.getAttributes();
+
+ if (attrNodes != null) {
+
+ // copy the first text:p node. As it's not necessary only string
+ // type cell can have a text:p section.
+ NodeList paraNodes =
+ modCell.getElementsByTagName(OfficeConstants.TAG_PARAGRAPH);
+
+ Node firstParaNode = paraNodes.item(0);
+
+ // try to clone the node
+ if (firstParaNode != null) {
+
+ Node clonedNode = XmlUtil.deepClone(orgCell, firstParaNode);
+
+ // insert as the first child of the original cell
+ Node firstChild = orgCell.getFirstChild();
+ if (firstChild != null) {
+ orgCell.insertBefore(clonedNode, firstChild);
+ } else {
+ orgCell.appendChild(clonedNode);
+ }
+ }
+
+ // check all the attributes and copy those we supported in
+ // converter
+ // NOTE: for attribute list, refer to section 4.7.2 in specification
+ int len = attrNodes.getLength();
+
+ for (int i = 0; i < len; i++) {
+ Node attr = attrNodes.item(i);
+
+ // copy the supported attrs
+ if (cc_.canConvertAttribute(OfficeConstants.TAG_TABLE_CELL,
+ attr.getNodeName())) {
+ orgCell.setAttribute(attr.getNodeName(),
+ attr.getNodeValue());
+ }
+ }
+ }
+ }
+}
+
diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/merger/merge/SheetMerge.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/merger/merge/SheetMerge.java
new file mode 100644
index 000000000000..edb95cfd9cb2
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/merger/merge/SheetMerge.java
@@ -0,0 +1,89 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.merger.merge;
+
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+import org.openoffice.xmerge.ConverterCapabilities;
+import org.openoffice.xmerge.merger.NodeMergeAlgorithm;
+
+/**
+ * This class extends the <code>DocumentMerge</code> class.
+ * This class will merge two spreadsheet documents.
+ * The main difference between this implementation and
+ * <code>DocumentMerge</code>
+ * is that this merge will try to maintain unsupported features by
+ * examing the cell <code>node</code> objects one by one when it
+ * removes a node from the original <code>Iterator</code>.
+ *
+ * @author smak
+ */
+public final class SheetMerge extends DocumentMerge {
+
+ /**
+ * Constructor.
+ *
+ * @param cc The <code>ConverterCapabilities</code>.
+ * @param merge The <code>NodeMergeAlgorithm</code>.
+ */
+ public SheetMerge(ConverterCapabilities cc, NodeMergeAlgorithm merge) {
+ super(cc, merge);
+ }
+
+
+ /**
+ * Remove specified <code>Node</code>.
+ *
+ * @param node <code>Node</code> to remove.
+ */
+ protected void removeNode(Node node) {
+
+ clearRow(node);
+ }
+
+
+ /**
+ * Clear the row corresponding to the <code>Node</code>
+ *
+ * @param node <code>Node</code> containing the row to clear.
+ */
+ private void clearRow(Node node) {
+ NodeList children = node.getChildNodes();
+ int numOfChildren = children.getLength();
+
+ // clear all the cells under the row node but maintain any unsupported
+ // features
+ // TODO: we can actually check anything left after the clear up.
+ // if there is nothing left, then we can even delete the cell nodes
+ for (int i = 0; i < numOfChildren; i++) {
+ SheetUtil.emptyCell(cc_, children.item(i));
+ }
+ }
+}
+
diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/merger/merge/SheetUtil.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/merger/merge/SheetUtil.java
new file mode 100644
index 000000000000..0329434105b8
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/merger/merge/SheetUtil.java
@@ -0,0 +1,107 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.merger.merge;
+
+import org.w3c.dom.Node;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+import org.w3c.dom.NamedNodeMap;
+
+import org.openoffice.xmerge.ConverterCapabilities;
+import org.openoffice.xmerge.converter.xml.OfficeConstants;
+
+
+/**
+ * Utility methods to handle sheet XML tree.
+ */
+public class SheetUtil {
+
+ /**
+ * <p>Empty the content of a cell value. This includes the following:
+ * </p>
+ *
+ * <p><ul><li>
+ * Remove all of the supported attributes.
+ * </li><li>
+ * Remove the first <i>text:p</i> <code>Node</code> for most of the cells.
+ * </li></ul></p>
+ *
+ * @param cc The <code>ConverterCapabilities</code>.
+ * @param node The <code>Node</code>.
+ */
+ public static void emptyCell(ConverterCapabilities cc, Node node) {
+
+ NamedNodeMap attrNodes = node.getAttributes();
+
+ if (attrNodes != null) {
+
+ // empty the first text:p node.
+ // Note: it's not necessary only string type cell contain text:p
+ // basically, all different type of cell will contain one
+ Element cell = (Element)node;
+
+ // get the paragraph node list
+ NodeList paraNodes =
+ cell.getElementsByTagName(OfficeConstants.TAG_PARAGRAPH);
+
+ Node firstParaNode = paraNodes.item(0);
+
+ // remove the first paragraph element node
+ if (firstParaNode != null) {
+ Node parent = firstParaNode.getParentNode();
+ parent.removeChild(firstParaNode);
+ }
+
+ // check all the attributes and remove those we supported in
+ // converter
+ // NOTE: for attribute list, refer to section 4.7.2 in specification
+ int len = attrNodes.getLength();
+
+ for (int i = 0; i < len; ) {
+ Node attr = attrNodes.item(i);
+
+ // when we hit the end of the attribute nodes, return
+ // it may happen sooner as we keep on removing nodes
+ if (attr == null) {
+ break;
+ }
+ // remove the supported attr except columns repeated attribute
+ if (cc.canConvertAttribute(OfficeConstants.TAG_TABLE_CELL,
+ attr.getNodeName()) &&
+ !attr.getNodeName().equals(
+ OfficeConstants.ATTRIBUTE_TABLE_NUM_COLUMNS_REPEATED)) {
+
+ attrNodes.removeNamedItem(attr.getNodeName());
+ } else {
+ i++;
+ }
+ }
+ }
+ }
+}
+
diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/merger/merge/package.html b/xmerge/source/xmerge/java/org/openoffice/xmerge/merger/merge/package.html
new file mode 100644
index 000000000000..d54b7c37a0ef
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/merger/merge/package.html
@@ -0,0 +1,43 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<!--
+ #*************************************************************************
+ #
+ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+
+ Copyright 2000, 2010 Oracle and/or its affiliates.
+
+ OpenOffice.org - a multi-platform office productivity suite
+
+ This file is part of OpenOffice.org.
+
+ OpenOffice.org is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License version 3
+ only, as published by the Free Software Foundation.
+
+ OpenOffice.org is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License version 3 for more details
+ (a copy is included in the LICENSE file that accompanied this code).
+
+ You should have received a copy of the GNU Lesser General Public License
+ version 3 along with OpenOffice.org. If not, see
+ <http://www.openoffice.org/license.html>
+ for a copy of the LGPLv3 License.
+
+ #*************************************************************************
+ -->
+<html>
+<head>
+<title>org.openoffice.xmerge.merger.diff package</title>
+</head>
+
+<body bgcolor="white">
+<p>Provides implementations for the {@link
+org.openoffice.xmerge.merger.MergeAlgorithm
+MergeAlgorithm} interface, the {@link
+org.openoffice.xmerge.merger.NodeMergeAlgorithm
+NodeMergeAlgorithm} interface, and related support classes.</p>
+
+</body>
+</html>
diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/merger/package.html b/xmerge/source/xmerge/java/org/openoffice/xmerge/merger/package.html
new file mode 100644
index 000000000000..e5cd65c3f357
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/merger/package.html
@@ -0,0 +1,75 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<!--
+ #*************************************************************************
+ #
+ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+
+ Copyright 2000, 2010 Oracle and/or its affiliates.
+
+ OpenOffice.org - a multi-platform office productivity suite
+
+ This file is part of OpenOffice.org.
+
+ OpenOffice.org is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License version 3
+ only, as published by the Free Software Foundation.
+
+ OpenOffice.org is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License version 3 for more details
+ (a copy is included in the LICENSE file that accompanied this code).
+
+ You should have received a copy of the GNU Lesser General Public License
+ version 3 along with OpenOffice.org. If not, see
+ <http://www.openoffice.org/license.html>
+ for a copy of the LGPLv3 License.
+
+ #*************************************************************************
+ -->
+<html>
+<head>
+<title>org.openoffice.xmerge.merger package</title>
+</head>
+
+<body bgcolor="white">
+<p>The <code>DiffAlgorithm</code> and <code>MergeAlgorithm</code>
+are used to provide the merge capabilities of this project.</p>
+
+<p>Merge is useful when an <code>OfficeDocument</code>
+is converted to a &quot;Device&quot; <code>Document</code> format,
+and the &quot;Device&quot; <code>Document</code> version is modified.
+Those changes can be merged back into the original
+<code>OfficeDocument</code> with the merger. The merger is capable
+of doing this even if the &quot;Device&quot; format is lossy in
+comparison to the <code>OfficeDocument</code> format.</p>
+
+<p>The <code>DiffAlgorithm</code> generates a list of
+<code>Difference</code> objects that represent the
+differences between two <code>OfficeDocument</code> objects.
+It is assumed that one is the original <code>OfficeDocument</code>
+object and the other is a &quot;lossy&quot; version of the same
+<code>Document</code> with edits to be merged. Typically the
+&quot;lossy&quot; version is created by converting a &quot;Device&quot
+<code>Document</code> back into an <code>OfficeDocument</code>.
+
+<p>The <code>MergeAlgorithm</code> takes the <code>Difference</code>
+objects as input, and creates a merged <code>OfficeDocument</code>.
+A merged <code>OfficeDocument</code> has the following features:</p>
+
+<p><ul>
+<li>Tags in the <code>OfficeDocument</code> that are not
+ supported in the device format are not altered or removed.
+<li>Changes made to the device format are merged back into
+ the <code>OfficeDocument</code> in the location determined by
+ the <code>DiffAlgorithm</code>.
+</ul></p>
+
+<p>Each converter provides an implementation of the
+{@link org.openoffice.xmerge.ConverterCapabilities
+ConverterCapabilities} which specifies which
+<code>OfficeDocument</code> tags are supported for the
+device format.</p>
+
+</body>
+</html>
diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/package.html b/xmerge/source/xmerge/java/org/openoffice/xmerge/package.html
new file mode 100644
index 000000000000..ea56e3b6c118
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/package.html
@@ -0,0 +1,113 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<!--
+ #*************************************************************************
+ #
+ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+
+ Copyright 2000, 2010 Oracle and/or its affiliates.
+
+ OpenOffice.org - a multi-platform office productivity suite
+
+ This file is part of OpenOffice.org.
+
+ OpenOffice.org is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License version 3
+ only, as published by the Free Software Foundation.
+
+ OpenOffice.org is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License version 3 for more details
+ (a copy is included in the LICENSE file that accompanied this code).
+
+ You should have received a copy of the GNU Lesser General Public License
+ version 3 along with OpenOffice.org. If not, see
+ <http://www.openoffice.org/license.html>
+ for a copy of the LGPLv3 License.
+
+ #*************************************************************************
+ -->
+<html>
+<head>
+<title>org.openoffice.xmerge package</title>
+</head>
+
+<body bgcolor="white">
+
+<p>Provides interfaces for converting between two <code>Document</code>
+formats, and supports a &quot;merge&quot; interface for merging back
+changes from a &quot;lossy&quot; format back into a rich format.</p>
+
+<p>The {@link org.openoffice.xmerge.Convert
+Convert} object encapsulates the conversion of one format to/from another
+format. The user requests a <code>Convert</code> object via the
+<code>ConverterFactory</code>.</p>
+
+<p>The <code>Convert</code> class encapsulates a specific plug-in.
+A plug-in can support deserialization (convert from &quot;Device&quot;
+to &quot;Office&quot;) and/or serialization (convert from
+&quot;Office&quot; to &quot;Device&quot;). If a plug-in supports
+both deserialization and serialization, then it can also support
+&quot;merge&quot;.</p>
+
+<p>To support conversions where a single input <code>Document</code> can
+create multiple output <code>Document</code> objects, data is passed in
+and out of the conversion functions via a <code>ConvertData</code> object.
+This <code>ConvertData</code> can contain one or more <code>Document</code>
+objects. It is assumed that the client will know when to pass multiple
+files into a specific plug-in, and that the plug-in will know how to
+handle the multiple files.</p>
+
+<p>Merging is useful when converting from a rich <code>Document</code>
+format to a more lossy format. Then the user may modify the
+<code>Document</code> in the lossy format, and &quot;merge&quot; those
+changes back into the original &quot;rich&quot; <code>Document</code>.
+Each merge implementation provides a <code>ConverterCapabilities</code>
+implementation so that the merge logic knows what changes from the
+&quot;lossy&quot; format to merge into the original &quot;rich&quot;
+<code>Document</code>.</p>
+
+<p>Each plug-in must be registed via the singleton ConverterInfoMgr
+object via its {@link
+org.openoffice.xmerge.util.registry.ConverterInfoMgr#addPlugIn
+addPlugIn} method.</p>
+
+<h2>Providing implementations</h2>
+
+<p>The plug-in implementation must include the <code>getDeviceDocument</code>
+and <code>getOfficeDocument</code> methods. These functions need to return
+the appropriate type of <code>Document</code> for the plug-in. It may be
+necessary to create a new implementation of the <code>Document</code>
+interface if one does not exist that meets the needs of the plug-in.</p>
+
+<p>Currently, base implementations for working with StarWriter XML
+<code>Document</code> objects are available via the
+<a href="converter/xml/sxc/package-summary.html#package_description">
+org.openoffice.xmerge.xml.sxw</a>
+package, and StarCalc XML <code>Document</code> objects via the
+<a href="converter/xml/sxw/package-summary.html#package_description">
+org.openoffice.xmerge.xml.sxc</a>
+package.</p>
+
+<h2>TODO/IDEAS list</h2>
+
+<p><ol>
+<li>An idea is to combine the <code>ConvertData</code> and the
+ <code>Convert</code> classes, so that a <code>ConvertData</code>
+ knows what it can convert into and whether or not it can merge.
+ Then a user would call convert/merge methods on the
+ <code>ConvertData</code> class, which returns a
+ <code>ConvertData</code> object that likewise knows what it can
+ convert/merge into.</li>
+<li><code>DocumentSerialize</code> constructors and the
+ <code>DocumentDeserializer.deserializer</code> method could pass
+ in a <code>ConvertData</code> object rather than assuming
+ a single <code>Document</code> will represent a &quot;rich&quot;
+ <code>Document</code>.</li>
+<li>May need to add a <code>PluginFactory.setProperties</code>
+ method for adding properties specific to each converter.</li>
+</ol></p>
+
+</body>
+</html>
+
diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/test/ConverterInfoList.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/test/ConverterInfoList.java
new file mode 100644
index 000000000000..f9742c48a743
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/test/ConverterInfoList.java
@@ -0,0 +1,105 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.test;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.BufferedInputStream;
+import java.util.Properties;
+import java.util.Vector;
+import java.util.Enumeration;
+
+/**
+ * Loads a properties file so that registry knows which plug-ins
+ * it needs to load.
+ *
+ * @author: Martin Maher
+ */
+public class ConverterInfoList {
+
+ private static String defaultPropsFile = "ConverterInfoList.properties";
+
+ private Vector jars;
+ private Properties props = null;
+
+
+ /**
+ * This constructor loads and reads the default properties file.
+ * The default property file name is:
+ * &quot;ConverterInfoList.properties&quot;.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ public ConverterInfoList() throws IOException {
+ this(defaultPropsFile);
+ }
+
+ /**
+ * This constructor loads and reads the properties file.
+ *
+ * @param propsFile The properties file to load.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ public ConverterInfoList(String propsFile) throws IOException {
+
+ Class c = this.getClass();
+ InputStream is = c.getResourceAsStream(propsFile);
+ BufferedInputStream bis = new BufferedInputStream(is);
+ props = new Properties();
+ props.load(bis);
+ bis.close();
+
+ int i = 1;
+ String jarFileName = new String();
+ jars = new Vector();
+
+ while ((jarFileName = props.getProperty("jarname" + i)) != null) {
+ jars.add(jarFileName);
+ i++;
+ }
+ }
+
+
+ /**
+ * Returns a <code>Vector</code> containing a list of
+ * <code>String</code> objects. Each <code>String</code>
+ * describes a plug-in to be loaded into the registry.
+ *
+ *
+ * @return A <code>Vector</code> containing a list of
+ * <code>String</code> objects. Each
+ * <code>String</code> describes a plug-in to be
+ * loaded into the registry.
+ */
+ public Enumeration getJarFileEnum() {
+
+ return jars.elements();
+ }
+}
+
diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/test/ConverterInfoList.properties b/xmerge/source/xmerge/java/org/openoffice/xmerge/test/ConverterInfoList.properties
new file mode 100644
index 000000000000..a342273c67b9
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/test/ConverterInfoList.properties
@@ -0,0 +1,37 @@
+#*************************************************************************
+#
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# Copyright 2000, 2010 Oracle and/or its affiliates.
+#
+# OpenOffice.org - a multi-platform office productivity suite
+#
+# This file is part of OpenOffice.org.
+#
+# OpenOffice.org is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License version 3
+# only, as published by the Free Software Foundation.
+#
+# OpenOffice.org is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License version 3 for more details
+# (a copy is included in the LICENSE file that accompanied this code).
+#
+# You should have received a copy of the GNU Lesser General Public License
+# version 3 along with OpenOffice.org. If not, see
+# <http://www.openoffice.org/license.html>
+# for a copy of the LGPLv3 License.
+#
+#*************************************************************************
+# x-no-translate
+
+#
+# Jarfiles to be loaded
+#
+jarname1=file:///jarDirectory/htmlsoff.jar
+
+#
+# Pocket Word plugin
+#
+jarname2=file:///jarDirectory/pocketword.jar
diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/test/Driver.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/test/Driver.java
new file mode 100644
index 000000000000..5855727364ef
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/test/Driver.java
@@ -0,0 +1,318 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.test;
+
+import java.util.Vector;
+import java.util.Enumeration;
+import java.io.FileOutputStream;
+import java.io.FileInputStream;
+import java.io.File;
+
+import org.openoffice.xmerge.Convert;
+import org.openoffice.xmerge.Document;
+import org.openoffice.xmerge.ConvertData;
+import org.openoffice.xmerge.ConverterFactory;
+import org.openoffice.xmerge.test.ConverterInfoList;
+import org.openoffice.xmerge.util.registry.ConverterInfoMgr;
+import org.openoffice.xmerge.util.registry.ConverterInfoReader;
+import org.openoffice.xmerge.DocumentMerger;
+
+/**
+ * This class is a command-line driver for the converter framework.
+ * It is expected that this code will be later called by the device
+ * server. It does some basic validation of the command-line
+ * parameters.
+ */
+public final class Driver {
+
+ /** Command-line parameter. */
+ private String fromMime = null;
+
+ /** Command-line parameter. */
+ private String toMime = null;
+
+ /** mergeFile name. */
+ private String mergeFile = null;
+
+ /** Command-line parmeter. */
+ private Vector deviceFiles = new Vector();
+
+ /** Command-line parmeter shortcuts. */
+ private String mimeTypes[] = {
+ "sxc", "staroffice/sxc",
+ "sxw","staroffice/sxw"
+ };
+
+
+ /**
+ * Main.
+ *
+ * @param args The argument passed on the command line.
+ */
+ public static void main(String args[]) {
+
+ // Register jarfiles
+ //
+ String propFile = "ConverterInfoList.properties";
+ ConverterInfoList cil = null;
+ try {
+ cil = new ConverterInfoList(propFile);
+ } catch (Exception e) {
+ System.out.println("\nCannot not load " + propFile +
+ " property file");
+ }
+
+ Enumeration jarInfoEnumeration;
+ ConverterInfoReader cir;
+
+ Enumeration jarFileEnum = cil.getJarFileEnum();
+ while (jarFileEnum.hasMoreElements()) {
+ String jarName = (String) jarFileEnum.nextElement();
+ try {
+ cir = new ConverterInfoReader(jarName, false);
+ jarInfoEnumeration = cir.getConverterInfoEnumeration();
+ ConverterInfoMgr.addPlugIn(jarInfoEnumeration);
+ } catch (Exception e) {
+ System.out.println("\nCannot not load <" + jarName +
+ "> from the <" + propFile + "> property file");
+ }
+ }
+
+ try {
+
+ Driver app = new Driver();
+ app.parseCommandLine(args);
+ app.doConversion();
+ } catch (IllegalArgumentException ex) {
+
+ String msg = ex.getMessage();
+ if (msg != null) System.out.println("\n" + msg);
+ showUsage();
+
+ } catch (Exception ex) {
+
+ String msg = ex.getMessage();
+ if (msg != null) System.out.println("\n" + msg);
+ ex.printStackTrace();
+ }
+ }
+
+
+ /**
+ * Gets a <code>Convert</code> object using the
+ * <code>ConverterFactory</code> and does the conversion using
+ * this object.
+ *
+ * @throws IllegalArgumentException If an argument is invalid.
+ */
+ private void doConversion() throws IllegalArgumentException {
+
+ ConverterFactory cf = new ConverterFactory();
+ Convert myConvert = cf.getConverter(fromMime, toMime);
+ String processFile = null;
+
+ if (myConvert == null) {
+ System.out.println("\nNo plug-in exists to convert from <" +
+ fromMime + "> to <" + toMime + ">");
+ throw new IllegalArgumentException();
+ }
+
+ try {
+ Enumeration dfEnum = deviceFiles.elements();
+ while (dfEnum.hasMoreElements()) {
+ processFile = (String)dfEnum.nextElement();
+ File f = new File(processFile);
+
+ // Make sure the input file actually exists before using it
+ if (!f.exists()) {
+ System.out.println(processFile + " does not exist!");
+ System.exit(0);
+ }
+ FileInputStream fis = new FileInputStream(f);
+ myConvert.addInputStream(f.getName(), fis);
+ }
+ } catch (Exception addExcept) {
+ System.out.println("\nFile <" + processFile + "> is not in <" +
+ fromMime + "> format");
+ throw new IllegalArgumentException();
+ }
+
+ ConvertData dataOut = null;
+
+ try {
+ dataOut = myConvert.convert();
+ } catch (Exception convertExcept) {
+ System.out.println("\nThere was an error in the conversion");
+ convertExcept.printStackTrace();
+ }
+
+ if (dataOut != null ) {
+
+ if (mergeFile == null) {
+ Enumeration docEnum = dataOut.getDocumentEnumeration();
+ while (docEnum.hasMoreElements()) {
+ Document docOut = (Document)docEnum.nextElement();
+ String fileName = docOut.getFileName();
+ try {
+ FileOutputStream fos = new FileOutputStream(fileName);
+ docOut.write(fos);
+ fos.flush();
+ fos.close();
+ } catch (Exception writeExcept) {
+ System.out.println("\nThere was an writing out file <" +
+ fileName + ">");
+ writeExcept.printStackTrace();
+ }
+ }
+ } else {
+ try {
+ FileInputStream mergeIS = new FileInputStream(mergeFile);
+ Document mergeDoc = myConvert.getOfficeDocument(mergeFile, mergeIS);
+ DocumentMerger merger = myConvert.getDocumentMerger(mergeDoc);
+ Enumeration mergeDocEnum = dataOut.getDocumentEnumeration();
+ Document convertedFile = (Document)mergeDocEnum.nextElement();
+
+ merger.merge(convertedFile);
+ mergeIS.close();
+
+ FileOutputStream fos = new FileOutputStream(mergeFile);
+ mergeDoc.write(fos);
+ fos.flush();
+ fos.close();
+ } catch (Exception mergeExcept) {
+ System.out.println("\nThere was an error in the merge");
+ mergeExcept.printStackTrace();
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Display usage.
+ */
+ private static void showUsage() {
+
+ System.out.println("\nUsage:");
+ System.out.println("\n java org.openoffice.xmerge.test.Driver <args>");
+ System.out.println("\n where <args> is as follows:");
+ System.out.println(" -from <MIMETYPE> -to <MIMETYPE> [ -merge <OrigDoc ] <document>\n");
+ }
+
+
+ /**
+ * Parse command-line arguments.
+ *
+ * @param args Array of command line arguments.
+ *
+ * @throws IllegalArgumentException If an argument is invalid.
+ */
+ private void parseCommandLine(String args[])
+ throws IllegalArgumentException {
+
+ if (args.length == 0) {
+ throw new IllegalArgumentException();
+ }
+
+ for (int i = 0; i < args.length; i++) {
+ String arg = args[i];
+
+ if ("-to".equals(arg)) {
+ toMime = extractArg(i, args);
+ for (int j = 0; j < mimeTypes.length; j+=2) {
+ if(mimeTypes[j].equals(extractArg(i, args)))
+ toMime = mimeTypes[j+1];
+ }
+ i++;
+ } else if ("-from".equals(arg)) {
+ fromMime = extractArg(i, args);
+ for (int j = 0; j < mimeTypes.length; j+=2) {
+ if(mimeTypes[j].equals(extractArg(i, args)))
+ fromMime = mimeTypes[j+1];
+ }
+ i++;
+ } else if ("-merge".equals(arg)) {
+ mergeFile = extractArg(i, args);
+ if (!isZip(mergeFile)) {
+ throw new
+ IllegalArgumentException("Arg " + i +
+ ": expected zip, got " +
+ mergeFile);
+ }
+ i++;
+ } else {
+ deviceFiles.add(arg);
+ }
+ }
+
+ System.out.println("\nConverting from " + fromMime + " to " + toMime +
+ ((mergeFile != null) ? " with merge " : " "));
+ }
+
+
+ /**
+ * Extract the next argument from the array, while checking to see
+ * that the array size is not exceeded. Throw a friendly error
+ * message in case the arg is missing.
+ *
+ * @param i Argument index.
+ * @param args Array of command line arguments.
+ *
+ * @return The argument with the specified index.
+ *
+ * @throws IllegalArgumentException If an argument is invalid.
+ */
+ private String extractArg(int i, String args[])
+ throws IllegalArgumentException {
+
+ if (i+1 < args.length)
+ return args[i+1];
+ else throw new
+ IllegalArgumentException("Arg " + i +
+ ": expected arg for " + args[i]);
+ }
+
+
+ /**
+ * Simple validation for Office ZIP files.
+ *
+ * @param zipName The name of the ZIP file.
+ *
+ * @return true if zipName is valid, false otherwise.
+ */
+ private boolean isZip(String zipName) {
+
+ String str = zipName.toLowerCase();
+ if (str.endsWith("sxw") || zipName.endsWith("sxc")) {
+ return true;
+ }
+
+ return false;
+ }
+}
+
diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/util/ActiveSyncDriver.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/util/ActiveSyncDriver.java
new file mode 100644
index 000000000000..fb7941a15ae0
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/util/ActiveSyncDriver.java
@@ -0,0 +1,144 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.util;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.FileInputStream;
+import java.util.StringTokenizer;
+
+import org.openoffice.xmerge.Convert;
+import org.openoffice.xmerge.Document;
+import org.openoffice.xmerge.ConvertData;
+import org.openoffice.xmerge.ConverterFactory;
+import org.openoffice.xmerge.util.registry.ConverterInfoMgr;
+import org.openoffice.xmerge.util.registry.ConverterInfoReader;
+
+public class ActiveSyncDriver {
+ public static void main(String[] args) {
+ if (args.length != 4) {
+ return;
+ }
+
+ ActiveSyncDriver asd = new ActiveSyncDriver();
+
+ try {
+ // At the moment can't really signal back to the calling DLL
+ asd.Convert(args[0], args[1], args[2], args[3]);
+ }
+ catch (Exception e) {
+ return;
+ }
+ }
+
+
+ private boolean Convert(String srcMime, String dstMime, String srcFile, String dstFile) throws Exception {
+ /*
+ * The classpath passed in by XMergeSync.dll should contain all of the
+ * jar files, but at the least it will contain xmerge.jar, so strip off
+ * the xmerge.jar portion and use the remainder to provide a root for
+ * the Pocket Word and Pocket Excel plugins.
+ */
+ String ooClassDir = null;
+ String strClassPath = System.getProperty("java.class.path");
+
+ StringTokenizer st = new StringTokenizer(strClassPath, ";");
+
+ // There should be at least one element, but just in case
+ while (st.hasMoreTokens()) {
+ String s = st.nextToken();
+
+ if (s.endsWith("xmerge.jar")) {
+ ooClassDir = s.substring(0, s.indexOf("xmerge.jar"));
+ }
+ }
+
+ if (ooClassDir == null) {
+ return true;
+ }
+
+
+ /*
+ * The XMergeSync.dll should will have checked for the presence of the
+ * jars at the same location already.
+ *
+ * Because they can be installed separately, though, the MIME types need
+ * to be check to see which one to load.
+ */
+ File pluginJar = null;
+ if (srcMime.equals("staroffice/sxw") || srcMime.equals("application/x-pocket-word"))
+ {
+ pluginJar = new File(ooClassDir + "pocketWord.jar");
+ }
+ else if (srcMime.equals("staroffice/sxc") || srcMime.equals("application/x-pocket-excel"))
+ {
+ pluginJar = new File(ooClassDir + "pexcel.jar");
+ }
+
+ ConverterInfoReader cirPlugin = new ConverterInfoReader(pluginJar.toURL().toString(), false);
+
+ ConverterInfoMgr.addPlugIn(cirPlugin.getConverterInfoEnumeration());
+
+ ConverterFactory cf = new ConverterFactory();
+ Convert conv = cf.getConverter(srcMime, dstMime);
+
+ if (conv == null) {
+ return false;
+ }
+
+ // Everything is registered so do the conversion
+ FileInputStream fis = new FileInputStream(srcFile);
+ FileOutputStream fos = new FileOutputStream(dstFile);
+
+ conv.addInputStream(srcFile, fis);
+
+ ConvertData dataOut;
+ try {
+ dataOut = conv.convert();
+ }
+ catch (Exception e) {
+ return false;
+ }
+
+ if (dataOut == null) {
+ return false;
+ }
+
+ // Get the document and write it out.
+ Document doc = (Document)dataOut.getDocumentEnumeration().nextElement();
+ if (doc == null) {
+ return false;
+ }
+
+ doc.write(fos);
+ fos.flush();
+ fos.close();
+
+ return true;
+ }
+}
diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/util/ColourConverter.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/util/ColourConverter.java
new file mode 100644
index 000000000000..33ef294d4ae8
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/util/ColourConverter.java
@@ -0,0 +1,446 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.util;
+
+
+import java.awt.Color;
+
+/**
+ * Utility class mapping RGB colour specifications to the colour indices used
+ * in the Pocket PC. The original converter was written for use with Pocket
+ * Word it was later put into the utils so Pocket excel could use this code
+ * also. For this reason the defualt values are those used by Pocket Word but
+ * a colour table can be passed in through the constructor to map the 16
+ * values to a colour table.
+ *
+ * These colour indices are based on the Windows VGA 16 colour palette, which
+ * later was used as the basis for the named colours in the HTML 3.2
+ * specification.
+ *
+ * In Pocket Word's case, the match to the VGA 16 palette is not exact as it
+ * swaps Grey and Silver, with Silver being the darker colour (i.e. having the
+ * lower RGB value).
+ */
+
+public class ColourConverter {
+
+ /** Colour table index for Black */
+ private static final short BLACK = 0;
+
+ /** Colour table index for Silver */
+ private static final short SILVER = 1;
+
+ /** Colour table index for Grey */
+ private static final short GREY = 2;
+
+ /** Colour table index for White */
+ private static final short WHITE = 3;
+
+ /** Colour table index for Red */
+ private static final short RED = 4;
+
+ /** Colour table index for Lime */
+ private static final short LIME = 5;
+
+ /** Colour table index for Blue */
+ private static final short BLUE = 6;
+
+ /** Colour table index for Aqua */
+ private static final short AQUA = 7;
+
+ /** Colour table index for Fuchsia */
+ private static final short FUCHSIA = 8;
+
+ /** Colour table index for Yellow */
+ private static final short YELLOW = 9;
+
+ /** Colour table index for Maroon */
+ private static final short MAROON = 10;
+
+ /** Colour table index for Green */
+ private static final short GREEN = 11;
+
+ /** Colour table index for Navy */
+ private static final short NAVY = 12;
+
+ /** Colour table index for Teal */
+ private static final short TEAL = 13;
+
+ /** Colour table index for Purple */
+ private static final short PURPLE = 14;
+
+ /** Colour table index for Olive */
+ public static final short OLIVE = 15;
+
+ private short tableLookup[] = null;
+
+ /**
+ * Default constructor used in the case where a lookup table is not
+ * required
+ */
+ public ColourConverter() {
+
+ }
+
+ /**
+ * Constructor that passes in the colour lookup table. This is required in
+ * cases where the 16 colour values are something other than there default
+ * values (e.g. in the case of pocket Excel)
+ *
+ * @param short[] a 16 bit array mapping the 16 colours to there values
+ */
+ public ColourConverter(short lookup[]) {
+
+ tableLookup = lookup;
+ }
+
+ /**
+ * Uses the colour table it it exists to translate default values to
+ * values in the colorTable
+ */
+ private short colourLookup(short colour) {
+
+ if(tableLookup!=null) {
+ return tableLookup[colour];
+ } else {
+ return colour;
+ }
+ }
+
+ /**
+ * Uses the colour table it it exists to translate default values to
+ * values in the colorTable
+ */
+ private short indexLookup(short index) {
+
+ short result = 0;
+
+ if(tableLookup!=null) {
+ for(short i = 0;i < tableLookup.length;i++) {
+ if(tableLookup[i]==index)
+ result = i;
+ }
+ } else {
+ result = index;
+ }
+
+ return result;
+ }
+ /**
+ * This method maps a Pocket Word colour index value to an RGB value as
+ * used by OpenOffice.
+ *
+ * @param index The index into Pocket Word's colour table.
+ *
+ * @return A Color object representing the RGB value of the Pocket Word
+ * colour.
+ */
+ public Color convertToRGB (short colour) {
+
+ short index = indexLookup(colour);
+
+ int r = 0;
+ int g = 0;
+ int b = 0;
+
+ switch (index) {
+ case SILVER:
+ r = g = b = 128;
+ break;
+
+ case GREY:
+ r = g = b = 192;
+ break;
+
+ case WHITE:
+ r = g = b = 255;
+ break;
+
+ case RED:
+ r = 255;
+ break;
+
+ case LIME:
+ g = 255;
+ break;
+
+ case BLUE:
+ b = 255;
+ break;
+
+ case AQUA:
+ g = b = 255;
+ break;
+
+ case FUCHSIA:
+ r = b = 255;
+ break;
+
+ case YELLOW:
+ r = g = 255;
+ break;
+
+ case MAROON:
+ r = 128;
+ break;
+
+ case GREEN:
+ g = 128;
+ break;
+
+ case NAVY:
+ b = 128;
+ break;
+
+ case TEAL:
+ b = g = 128;
+ break;
+
+ case PURPLE:
+ r = b = 128;
+ break;
+
+ case OLIVE:
+ r = g = 128;
+ break;
+
+ case BLACK:
+ default:
+ r = g = b = 0;
+ break;
+ }
+
+ return new Color(r, g, b);
+ }
+
+
+ /**
+ * This method approximates an RGB value (as used by Writer) to one of the
+ * 16 available colours
+ *
+ * Most of the supported colours have their components set to either 0, 128
+ * or 255. The exception is 'Grey' which is 0xC0C0C0.
+ *
+ * @param colour Color object representing the RGB value of the colour.
+ *
+ * @return Index into the Pocket Word colour table which represents the
+ * closest match to the specified colour.
+ */
+ public short convertFromRGB (Color colour) {
+ int matchedRGB = 0;
+ short indexColour = 0;
+ int reducedMap[] = new int[] { 0, 0, 128 };
+
+ int red = colour.getRed();
+ int green = colour.getGreen();
+ int blue = colour.getBlue();
+
+ // We need to convert the pale colors to their base color rather than
+ // white so we modify the rgb values if the colour is sufficently
+ // white
+ if(red>0xC0 && green>0xC0 && blue>0xC0) {
+
+ if(red!=0xFF)
+ red = getClosest(red, reducedMap);
+ if(green!=0xFF)
+ green = getClosest(green, reducedMap);
+ if(blue!=0xFF)
+ blue = getClosest(blue, reducedMap);
+ }
+
+ /*
+ * Need to derive an RGB value that has been rounded to match the ones
+ * Pocket Word knows about.
+ */
+ matchedRGB += getClosest(red) << 16;
+ matchedRGB += getClosest(green) << 8;
+ matchedRGB += getClosest(blue);
+
+ /*
+ * The colour map used by Pocket Word doesn't have any combinations of
+ * values beyond 0 and any other value. A value of 255 in any RGB
+ * code indicates a dominant colour. Other colours are only modifiers
+ * to the principal colour(s). Thus, for this conversion, modifiers
+ * can be dropped.
+ */
+ if ((matchedRGB & 0xFF0000) == 0xFF0000 || (matchedRGB & 0xFF00) == 0xFF00
+ || (matchedRGB & 0xFF) == 0xFF) {
+ if ((matchedRGB & 0xFF0000) == 0x800000) {
+ matchedRGB ^= 0x800000;
+ }
+ if ((matchedRGB & 0xFF00) == 0x8000) {
+ matchedRGB ^= 0x8000;
+ }
+ if ((matchedRGB & 0xFF) == 0x80) {
+ matchedRGB ^= 0x80;
+ }
+ }
+
+
+ /*
+ * And now for the actual matching ...
+ *
+ * Colours are based on the Windows VGA 16 palette. One difference
+ * though is that Pocket Word seems to switch the RGB codes for Grey
+ * and Silver. In Pocket Word Silver is the darker colour leaving Grey
+ * is closest to White.
+ *
+ * Shades of grey will be converted to either Silver or White, where
+ * Grey may be a more appropraite colour. This is handled specially
+ * only for Silver and White matches.
+ */
+ switch (matchedRGB) {
+ case 0x000000:
+ indexColour = BLACK;
+ break;
+
+ case 0x808080:
+ if (!isGrey(colour)) {
+ indexColour = SILVER;
+ }
+ else {
+ indexColour = GREY;
+ }
+ break;
+
+ case 0xFFFFFF:
+ if (!isGrey(colour)) {
+ indexColour = WHITE;
+ }
+ else {
+ indexColour = GREY;
+ }
+ break;
+
+ case 0xFF0000:
+ indexColour = RED;
+ break;
+
+ case 0x00FF00:
+ indexColour = LIME;
+ break;
+
+ case 0x0000FF:
+ indexColour = BLUE;
+ break;
+
+ case 0x00FFFF:
+ indexColour = AQUA;
+ break;
+
+ case 0xFF00FF:
+ indexColour = FUCHSIA;
+ break;
+
+ case 0xFFFF00:
+ indexColour = YELLOW;
+ break;
+
+ case 0x800000:
+ indexColour = MAROON;
+ break;
+
+ case 0x008000:
+ indexColour = GREEN;
+ break;
+
+ case 0x000080:
+ indexColour = NAVY;
+ break;
+
+ case 0x008080:
+ indexColour = TEAL;
+ break;
+
+ case 0x800080:
+ indexColour = PURPLE;
+ break;
+
+ case 0x808000:
+ indexColour = OLIVE;
+ break;
+
+ default: // Just in case!
+ indexColour = BLACK;
+ break;
+ }
+
+ return colourLookup(indexColour);
+ }
+
+
+ /*
+ * Default implementation, checks for the closest of value to 0, 128 or 255.
+ */
+ private int getClosest(int value) {
+ int points[] = new int[] { 0, 128, 255 };
+
+ return getClosest(value, points);
+ }
+
+
+ /*
+ * Utility method that returns the closest of the three points to the value
+ * supplied.
+ */
+ private int getClosest(int value, int[] points) {
+
+ if (value == points[0] || value == points[1] || value == points[2]) {
+ return value;
+ }
+
+ if (value < points[1]) {
+ int x = value - points[0];
+ return (Math.round((float)x / (points[1] - points[0])) == 1 ? points[1] : points[0]);
+ }
+ else {
+ int x = value - points[1];
+ return (Math.round((float)x / (points[2] - points[1])) >= 1 ? points[2] : points[1]);
+ }
+ }
+
+
+ /*
+ * Checks to see if the supplied colour can be considered to be grey.
+ */
+ private boolean isGrey(Color c) {
+ int matchedRGB = 0;
+ int points[] = new int[] { 128, 192, 255 };
+
+ matchedRGB += getClosest(c.getRed(), points) << 16;
+ matchedRGB += getClosest(c.getGreen(), points) << 8;
+ matchedRGB += getClosest(c.getBlue(), points);
+
+ if (matchedRGB == 0xC0C0C0) {
+ return true;
+ }
+
+ return false;
+ }
+}
+
diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/util/Debug.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/util/Debug.java
new file mode 100644
index 000000000000..8b9f06eb4e86
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/util/Debug.java
@@ -0,0 +1,339 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.util;
+
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.io.FileWriter;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.io.Writer;
+import java.text.DateFormat;
+import java.util.Date;
+import java.util.Calendar;
+import java.util.Properties;
+
+/**
+ * This class is used for logging debug messages.
+ * Currently, there are three types of logging: {@link #INFO},
+ * {@link #TRACE} & {@link #ERROR}. Use the Debug.properties
+ * file to set or unset each type. Also use Debug.properties
+ * to set the writer to either <code>System.out</code>,
+ * <code>System.err</code>, or to a file.
+ *
+ * @author Herbie Ong
+ */
+public final class Debug {
+
+ /** Informational messages. */
+ public final static int INFO = 0x0001;
+ /** Error messages. */
+ public final static int ERROR = 0x0002;
+ /** Trace messages. */
+ public final static int TRACE = 0x0004;
+
+ /** To set a flag. */
+ public final static boolean SET = true;
+ /** To unset a flag. */
+ public final static boolean UNSET = false;
+
+ private static int flags = 0;
+ private static PrintWriter writer = null;
+
+ static {
+
+ try {
+
+ Class c = new Debug().getClass();
+ InputStream is = c.getResourceAsStream("Debug.properties");
+ Properties props = new Properties();
+ props.load(is);
+
+ String info = props.getProperty("debug.info", "false");
+ info = info.toLowerCase();
+
+ if (info.equals("true")) {
+ setFlags(Debug.INFO, Debug.SET);
+ }
+
+ String trace = props.getProperty("debug.trace", "false");
+ trace = trace.toLowerCase();
+
+ if (trace.equals("true")) {
+ setFlags(Debug.TRACE, Debug.SET);
+ }
+
+ String error = props.getProperty("debug.error", "false");
+ error = error.toLowerCase();
+
+ if (error.equals("true")) {
+ setFlags(Debug.ERROR, Debug.SET);
+ }
+
+ String w = props.getProperty("debug.output", "System.out");
+ setOutput(w);
+
+ } catch (Throwable ex) {
+
+ ex.printStackTrace(System.err);
+ }
+ }
+
+
+ /**
+ * Private constructor so as not to allow any instances
+ * of this class. This serves as a singleton class.
+ */
+ private Debug() {
+ }
+
+
+ /**
+ * Set the output to the specified argument.
+ * This method is only used internally to prevent
+ * invalid string parameters.
+ *
+ * @param str Output specifier.
+ */
+ private static void setOutput(String str) {
+
+ if (writer == null) {
+
+ if (str.equals("System.out")) {
+
+ setOutput(System.out);
+
+ } else if (str.equals("System.err")) {
+
+ setOutput(System.err);
+
+ } else {
+
+ try {
+
+ setOutput(new FileWriter(str));
+
+ } catch (IOException e) {
+
+ e.printStackTrace(System.err);
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Set the output to an <code>OutputStream</code> object.
+ *
+ * @param stream OutputStream object.
+ */
+ private static void setOutput(OutputStream stream) {
+
+ setOutput(new OutputStreamWriter(stream));
+ }
+
+
+ /**
+ * Set the <code>Writer</code> object to manage the output.
+ *
+ * @param w <code>Writer</code> object to write out.
+ */
+ private static void setOutput(Writer w) {
+
+ if (writer != null) {
+
+ writer.close();
+ }
+
+ writer = new PrintWriter(new BufferedWriter(w), true);
+ }
+
+
+ /**
+ * <p>
+ * This method sets the levels for debugging logs.
+ * Example calls:
+ * </p>
+ *
+ * <blockquote><pre><code>
+ * Debug.setFlags( Debug.INFO, Debug.SET )
+ * Debug.setFlags( Debug.TRACE, Debug.SET )
+ * Debug.setFlags( Debug.INFO | Debug.TRACE, Debug.SET )
+ * Debug.setFlags( Debug.ERROR, Debug.UNSET )
+ * </code></pre></blockquote>
+ *
+ * @param f Debug flag
+ * @param set Use Debug.SET to set, and Debug.UNSET to unset
+ * the given flag.
+ */
+ private static void setFlags(int f, boolean set) {
+
+ if (set) {
+ flags |= f;
+ } else {
+ flags &= ~f;
+ }
+ }
+
+
+ /**
+ * Prints out information regarding platform.
+ */
+ public static void logSystemInfo() {
+
+ if (writer != null) {
+
+ writer.println();
+ writer.println("Platform Information:");
+ writer.println("OS : " + System.getProperty("os.name"));
+ writer.println("Version : " + System.getProperty("os.version"));
+ writer.println("Platform : " + System.getProperty("os.arch"));
+ writer.println("JDK Version : " + System.getProperty("java.version"));
+ writer.println("JDK Vendor : " + System.getProperty("java.vendor"));
+ writer.println();
+ }
+ }
+
+
+ /**
+ * Prints out timestamp.
+ */
+ public static void logTime() {
+
+ if (writer != null) {
+
+ Date time = Calendar.getInstance().getTime();
+ DateFormat dt = DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL);
+ writer.println(dt.format(time));
+ }
+ }
+
+
+ /**
+ * Checks if flag is set.
+ *
+ * @return true if info logging is on, otherwise false
+ */
+ public static boolean isFlagSet(int f) {
+
+ return ((flags & f) != 0);
+ }
+
+
+ /**
+ * <p>Log message based on the flag type.</p>
+ *
+ * <p>Example 1:</p>
+ *
+ * <blockquote><pre><code>
+ * Debug.log(Debug.INFO, "info string here");
+ * </code></pre></blockquote>
+ *
+ * <p>This logs the message during runtime if
+ * <code>debug.info</code> in the properties file is
+ * set to true.</p>
+ *
+ * <p>Example 2:</p>
+ *
+ * <blockquote><pre><code>
+ * Debug.log(Debug.INFO | Debug.TRACE, "info string here");
+ * </code></pre></blockquote>
+ *
+ * <p>This logs the message during runtime if debug.info or debug.trace
+ * in the properties file is set to true.</p>
+ *
+ * @param int Log type, one of the Debug constants
+ * {@link #INFO}, {@link #TRACE}, {@link #ERROR}
+ * or a combination of which or'ed together.
+ * @param msg The message.
+ */
+ public static void log(int flag, String msg) {
+
+ if (isFlagSet(flag)) {
+
+ if (writer != null) {
+
+ writer.println(msg);
+ }
+ }
+ }
+
+
+ /**
+ * Log message based on flag type plus print out stack trace
+ * of the exception passed in. Refer to the other log method
+ * for description.
+ *
+ * @param int Log type, one of the Debug constants
+ * {@link #INFO}, {@link #TRACE}, {@link #ERROR}
+ * or a combination of which or'ed together.
+ * @param msg The message.
+ * @param e Throwable object.
+ */
+ public static void log(int flag, String msg, Throwable e) {
+
+ if (isFlagSet(flag)) {
+
+ if (writer != null) {
+
+ writer.println(msg);
+ if (e != null)
+ e.printStackTrace(writer);
+ }
+ }
+ }
+
+
+ /**
+ * Converts the given bytes to a <code>String</code> of
+ * Hex digits.
+ *
+ * @param bytes <code>byte</code> array.
+ *
+ * @return Hex representation in a <code>String</code>.
+ */
+ public static String byteArrayToHexString(byte bytes[]) {
+
+ StringBuffer buff = new StringBuffer();
+
+ for (int i = 0; i < bytes.length; i++) {
+
+ int ch = ((int) bytes[i] & 0xff);
+ String str = Integer.toHexString(ch);
+ if (str.length() < 2)
+ buff.append('0');
+ buff.append(str);
+ buff.append(' ');
+ }
+
+ return buff.toString();
+ }
+}
+
diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/util/Debug.properties b/xmerge/source/xmerge/java/org/openoffice/xmerge/util/Debug.properties
new file mode 100644
index 000000000000..925392b86cdd
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/util/Debug.properties
@@ -0,0 +1,39 @@
+#*************************************************************************
+#
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# Copyright 2000, 2010 Oracle and/or its affiliates.
+#
+# OpenOffice.org - a multi-platform office productivity suite
+#
+# This file is part of OpenOffice.org.
+#
+# OpenOffice.org is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License version 3
+# only, as published by the Free Software Foundation.
+#
+# OpenOffice.org is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License version 3 for more details
+# (a copy is included in the LICENSE file that accompanied this code).
+#
+# You should have received a copy of the GNU Lesser General Public License
+# version 3 along with OpenOffice.org. If not, see
+# <http://www.openoffice.org/license.html>
+# for a copy of the LGPLv3 License.
+#
+#*************************************************************************
+# x-no-translate
+
+
+#
+# debug logging information and settings.
+#
+
+debug.info=false
+debug.trace=false
+debug.error=false
+debug.output=System.err
+
+
diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/util/EndianConverter.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/util/EndianConverter.java
new file mode 100644
index 000000000000..c41a428dd0c2
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/util/EndianConverter.java
@@ -0,0 +1,178 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.util;
+
+
+/**
+ * <p>Helper class providing static methods to convert data to/from
+ * Network Byte Order (Big Endian).</p>
+ *
+ * <p>With the introduction of <code>java.nio.ByteOrder</code> and
+ * <code>java.nio.ByteBuffer</code> in Java 1.4, it may no longer be
+ * necessary to use this class in the future.</p>
+ *
+ * @author Mark Murnane
+ * @version 1.1
+ */
+public class EndianConverter {
+
+ /**
+ * <p>Convert a <code>short</code> to a Little Endian representation.</p>
+ *
+ * @param value The <code>short</code> to be converted.
+ *
+ * @return Two element <code>byte</code> array containing the converted
+ * value.
+ */
+ public static byte[] writeShort (short value) {
+ byte[] leShort = new byte[2];
+
+ leShort[0] = (byte) value;
+ leShort[1] = (byte) (value >>> 8);
+
+ return leShort;
+ }
+
+
+ /**
+ * <p>Convert an integer to a Little Endian representation.</p>
+ *
+ * @param value The <code>int</code> to be converted.
+ *
+ * @return Four element <code>byte</code> array containing the converted
+ * value.
+ */
+ public static byte[] writeInt (int value) {
+ byte[] leInt = new byte[4];
+
+ leInt[0] = (byte) value;
+ leInt[1] = (byte) (value >>> 8);
+ leInt[2] = (byte) (value >>> 16);
+ leInt[3] = (byte) (value >>> 24);
+
+ return leInt;
+ }
+
+ /**
+ * <p>Converts a <code>double</code> to a Little Endian representation
+ * of a float in IEEE-754 format.
+ *
+ * <p>An array with more than eight elements can be used, but only the first
+ * eight elements will be read.</p>
+ *
+ * @param value <code>double</code> containing the value to be converted
+ *
+ * @return <code>byte</code> array containing the LE representation of a IEEE-754 float
+ */
+ public static byte[] writeDouble(double value) {
+
+ long myDouble = Double.doubleToLongBits(value);
+ byte[] leDouble = new byte[8];
+
+ leDouble[0] = (byte) (myDouble >>> 0);
+ leDouble[1] = (byte) (myDouble >>> 8);
+ leDouble[2] = (byte) (myDouble >>> 16);
+ leDouble[3] = (byte) (myDouble >>> 24);
+ leDouble[4] = (byte) (myDouble >>> 32);
+ leDouble[5] = (byte) (myDouble >>> 40);
+ leDouble[6] = (byte) (myDouble >>> 48);
+ leDouble[7] = (byte) (myDouble >>> 56);
+
+ return leDouble;
+ }
+
+ /**
+ * <p>Convert a Little Endian representation of a short to a Java
+ * <code>short</code> (Network Byte Order).</p>
+ *
+ * <p>An array with more than two elements can be used, but only the first
+ * two elements will be read.</p>
+ *
+ * @param value <code>byte</code> array containing the LE representation
+ * of the value.
+ *
+ * @return <code>short</code> containing the converted value.
+ */
+ public static short readShort (byte[] value) {
+ int high, low;
+
+ high = value[1] & 0xFF;
+ low = value[0] & 0xFF;
+
+ return (short)(high << 8 | low);
+ }
+
+
+ /**
+ * <p>Convert a Little Endian representation of an integer to a Java
+ * <code>int</code> (Network Byte Order).</p>
+ *
+ * <p>An array with more than four elements can be used, but only the first
+ * four elements will be read.</p>
+ *
+ * @param value <code>byte</code> array containing the LE representation
+ * of the value.
+ *
+ * @return <code>int</code> containing the converted value.
+ */
+ public static int readInt(byte[] value) {
+ int number = 0;
+
+ for (int i = 0; i < 4; i++) {
+ number |= (value[i] & 0xFF) << ( i * 8);
+ }
+
+ return number;
+ }
+
+ /**
+ * <p>Convert a Little Endian representation of a float in IEEE-754 Little
+ * Endian to a Java <code>double</code> (Network Byte Order).</p>
+ *
+ * <p>An array with more than eight elements can be used, but only the first
+ * eight elements will be read.</p>
+ *
+ * @param value <code>byte</code> array containing the LE representation
+ * of a IEEE-754 float.
+ *
+ * @return <code>double</code> containing the converted value.
+ */
+ public static double readDouble(byte[] value) {
+
+ long lvalue = ( ((long)(value[7]) << 56) +
+ ((long)(value[6]&0xFF) << 48) +
+ ((long)(value[5]&0xFF) << 40) +
+ ((long)(value[4]&0xFF) << 32) +
+ ((long)(value[3]&0xFF) << 24) +
+ ((long)(value[2]&0xFF) << 16) +
+ ((long)(value[1]&0xFF) << 8) +
+ (long)(value[0]&0xFF));
+
+ return Double.longBitsToDouble(lvalue);
+ }
+}
diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/util/IntArrayList.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/util/IntArrayList.java
new file mode 100644
index 000000000000..a317fa2997e1
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/util/IntArrayList.java
@@ -0,0 +1,147 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.util;
+
+import java.util.ArrayList;
+import java.lang.Integer;
+
+/**
+ * This is a convenience class used to create an
+ * <code>ArrayList</code> of integers.
+ */
+public class IntArrayList {
+
+ /** The list to hold our integers. */
+ private ArrayList list;
+
+ /**
+ * Constructor.
+ * Creates the list with 0 length.
+ */
+ public IntArrayList() {
+ list = new ArrayList();
+ }
+
+
+ /**
+ * Constructor.
+ *
+ * @param initialCapacity Initial capacity of the list.
+ */
+ public IntArrayList(int initialCapacity) {
+ list = new ArrayList(initialCapacity);
+ }
+
+
+ /**
+ * This method ensures that the list is large enough for
+ * <code>minCapacity</code> elements.
+ *
+ * @param minCapacity The minimum capacity of the list.
+ */
+ public void ensureCapacity(int minCapacity) {
+
+ list.ensureCapacity(minCapacity);
+ }
+
+
+ /**
+ * This method ensures that the list is large enough for
+ * <code>minCapacity</code> elements. It also fills in the
+ * new slots in the list with the integer value input as
+ * <code>fillValue</code>.
+ *
+ * @param minCapacity The minimum capacity of the list.
+ * @param fillValue This method adds in a integer for each
+ * slot that was added to ensure that the
+ * list meets the minimum capacity.
+ * <code>fillValue</code> is the value
+ * used as the initial value of these
+ * added elements.
+ */
+ public void ensureCapacityAndFill(int minCapacity, int fillValue) {
+
+ list.ensureCapacity(minCapacity);
+
+ int needToAdd = minCapacity - list.size();
+ if (needToAdd > 0) {
+ for (int i = 0; i < needToAdd; i++) {
+ list.add(new Integer(fillValue));
+ }
+ }
+ }
+
+
+ /**
+ * This method sets an element of the list to the input
+ * integer value.
+ *
+ * @param index The index in the list of the element
+ * we wish to set.
+ * @param value The integer value that we assign to the
+ * selected element of the list.
+ */
+ public void set(int index, int value) {
+ list.set(index, new Integer(value));
+ }
+
+
+ /**
+ * This method appends an element to the list.
+ *
+ * @param value The integer value that we assign to the
+ * element that we are appending to the list.
+ */
+ public void add(int value) {
+ list.add(new Integer(value));
+ }
+
+
+ /**
+ * This method gets the integer value stored in element index.
+ *
+ * @param index The index in the list of the element
+ * we wish to get the value from.
+ *
+ * @return The value of the data stored in element index.
+ */
+ public int get(int index) {
+ return ((Integer)list.get(index)).intValue();
+ }
+
+
+ /**
+ * This method gets the size of the list.
+ *
+ * @return The size of the list.
+ */
+ public int size() {
+ return list.size();
+ }
+}
+
diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/util/OfficeUtil.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/util/OfficeUtil.java
new file mode 100644
index 000000000000..64a37037c406
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/util/OfficeUtil.java
@@ -0,0 +1,135 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.util;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.Text;
+
+import org.openoffice.xmerge.converter.xml.OfficeConstants;
+
+import java.util.Vector;
+
+
+/**
+ * Class providing utility methods for OpenOffice plugins.
+ *
+ * @author Mark Murnane
+ * @version 1.1
+ */
+public class OfficeUtil implements OfficeConstants {
+
+ /**
+ * <p>Method to replace whitespace character within text with appropriate
+ * OpenOffice tags.</p>
+ *
+ * @param text The text to parse for whitespace.
+ *
+ * @return <code>Node</code> array containing OpenOffice XML nodes
+ * representing the text.
+ */
+ public static Node[] parseText(String text, Document parentDoc) {
+ Vector nodeVec = new Vector();
+
+ /*
+ * Break up the text from the text run into Open
+ * Office text runs. There may be more runs in OO because
+ * runs of 2 or more spaces map to nodes.
+ */
+ while ((text.indexOf(" ") != -1) || (text.indexOf("\t") != 1)) {
+
+ /*
+ * Find the indices of tabs and multiple spaces, and
+ * figure out which of them occurs first in the string.
+ */
+ int spaceIndex = text.indexOf(" ");
+ int tabIndex = text.indexOf("\t");
+ if ((spaceIndex == -1) && (tabIndex == -1))
+ break; // DJP This should not be necessary. What is wrong
+ // with the while() stmt up above?
+ int closerIndex; // Index of the first of these
+ if (spaceIndex == -1)
+ closerIndex = tabIndex;
+ else if (tabIndex == -1)
+ closerIndex = spaceIndex;
+ else
+ closerIndex = (spaceIndex > tabIndex) ? tabIndex : spaceIndex;
+
+ /*
+ * If there is any text prior to the first occurrence of a
+ * tab or spaces, create a text node from it, then chop it
+ * off the string we're working with.
+ */
+ if (closerIndex > 0) {
+ String beginningText = text.substring(0, closerIndex);
+ Text textNode = parentDoc.createTextNode(beginningText);
+ nodeVec.addElement(textNode);
+ }
+ text = text.substring(closerIndex);
+
+ /*
+ * Handle either tab character or space sequence by creating
+ * an element for it, and then chopping out the text that
+ * represented it in "text".
+ */
+ if (closerIndex == tabIndex) {
+ Element tabNode = parentDoc.createElement(TAG_TAB_STOP);
+ nodeVec.add(tabNode);
+ text = text.substring(1); // tab is always a single character
+ } else {
+ // Compute length of space sequence.
+ int nrSpaces = 2;
+ while ((nrSpaces < text.length())
+ && text.substring(nrSpaces, nrSpaces + 1).equals(" "))
+ nrSpaces++;
+
+ Element spaceNode = parentDoc.createElement(TAG_SPACE);
+ spaceNode.setAttribute(ATTRIBUTE_SPACE_COUNT,
+ new Integer(nrSpaces).toString());
+ nodeVec.add(spaceNode);
+ text = text.substring(nrSpaces);
+ }
+ }
+
+ /*
+ * No more tabs or space sequences. If there's any remaining
+ * text create a text node for it.
+ */
+ if (text.length() > 0) {
+ Text textNode = parentDoc.createTextNode(text);
+ nodeVec.add(textNode);
+ }
+
+ // Now create and populate an array to return the nodes in.
+ Node nodes[] = new Node[nodeVec.size()];
+ for (int i = 0; i < nodeVec.size(); i++)
+ nodes[i] = (Node)nodeVec.elementAt(i);
+ return nodes;
+ }
+} \ No newline at end of file
diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/util/Resources.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/util/Resources.java
new file mode 100644
index 000000000000..44db518b3389
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/util/Resources.java
@@ -0,0 +1,99 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.util;
+
+import java.util.ResourceBundle;
+
+/**
+ * <p>Provides a singleton resource class for converter messages.</p>
+ *
+ * <p>By default, this class will search for a
+ * <code>ResourceBundle</code> class file or properties file based
+ * on the default locale.</p>
+ *
+ * <p>A properties file resources.properties will be provided.</p>
+ *
+ * <p>Note that if the resource bundle object is not loaded, the
+ * construction of the singleton object will throw a
+ * <code>MissingResourceException</code>, which is a
+ * <code>RuntimeException</code>, thus I opted to not explicitly
+ * declare it. If it does throw <code>MissingResourceException</code>,
+ * it may be due to a packaging problem.</p>
+ *
+ * @author Herbie Ong
+ */
+public final class Resources
+{
+ private ResourceBundle rb = null;
+
+ private static Resources instance = null;
+
+
+ /**
+ * This method returns the singleton instance
+ * of this class.
+ *
+ * @return The singleton <code>Resources</code>
+ * instance.
+ */
+ public synchronized static Resources getInstance()
+ {
+ if (instance == null)
+ {
+ instance = new Resources();
+ }
+
+ return instance;
+ }
+
+
+ /**
+ * Default constructor is only accessible within this class.
+ * Load the resource bundle that contains the resource
+ * <code>String</code> values.
+ */
+ private Resources()
+ {
+ rb = ResourceBundle.getBundle("org.openoffice.xmerge.util.resources");
+ }
+
+
+ /**
+ * This method returns the corresponding <code>String</code> given
+ * the key.
+ *
+ * @param key Key string for getting the message
+ * <code>String</code>.
+ * @return Message <code>String</code> corresponding to the key.
+ */
+ public String getString(String key)
+ {
+ return rb.getString(key);
+ }
+}
+
diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/util/TwipsConverter.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/util/TwipsConverter.java
new file mode 100644
index 000000000000..fe3931a5aadf
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/util/TwipsConverter.java
@@ -0,0 +1,99 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.util;
+
+
+/**
+ * <p>Helper class providing static methods to convert data to/from
+ * twips</p>
+ *
+ * @author Martin Maher
+ */
+public class TwipsConverter {
+
+ /**
+ * <p>Convert from twips to cm's</p>
+ *
+ * @param value The <code>short</code> to be converted.
+ *
+ * @return float containing the converted
+ */
+ public static float twips2cm(int value) {
+
+ float inches = (float) value/1440;
+ float cm = (float) inches*(float)2.54;
+
+ return cm;
+ }
+
+
+
+ /**
+ * <p>Convert from cm's to twips</p>
+ *
+ * @param value <code>byte</code> array containing the LE representation
+ * of the value.
+ *
+ * @return int containing the converted value.
+ */
+ public static int cm2twips(float value) {
+
+ int twips = (int) ((value/2.54)*1440);
+
+ return twips;
+ }
+
+ /**
+ * <p>Convert from twips to cm's</p>
+ *
+ * @param value The <code>short</code> to be converted.
+ *
+ * @return float containing the converted
+ */
+ public static float twips2inches(int value) {
+
+ return (float) value/1440;
+ }
+
+
+
+ /**
+ * <p>Convert from cm's to twips</p>
+ *
+ * @param value <code>byte</code> array containing the LE representation
+ * of the value.
+ *
+ * @return int containing the converted value.
+ */
+ public static int inches2twips(float value) {
+
+ return (int) (value*1440);
+ }
+
+
+}
diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/util/XmlUtil.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/util/XmlUtil.java
new file mode 100644
index 000000000000..9b3ec402b2e8
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/util/XmlUtil.java
@@ -0,0 +1,189 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.util;
+
+import org.w3c.dom.Node;
+import org.w3c.dom.Document;
+import org.w3c.dom.NodeList;
+import org.w3c.dom.Element;
+import org.w3c.dom.NamedNodeMap;
+
+/**
+ * Class containing static util methods for handling XML trees.
+ *
+ * @author smak
+ */
+public final class XmlUtil {
+
+
+ /**
+ * Perform a deep clone of certain <code>Node</code> which
+ * will base on the document <code>Node</code> of the old
+ * <code>Node</code>.
+ *
+ * @param oldNode The <code>Document</code> of this
+ * <code>Node</code> is used to clone
+ * the <code>Node</code>
+ * @param newNode The <code>Node</code> to clone.
+ *
+ * @return The cloned <code>Node</code>.
+ */
+ public static Node deepClone(Node oldNode, Node newNode) {
+ Document docNode = oldNode.getOwnerDocument();
+
+ // clone the starting node
+ Node clonedNode = cloneNode(docNode, newNode);
+
+ // then clone the sub-tree recursively
+ cloneTree(docNode, clonedNode, newNode);
+
+ return clonedNode;
+ }
+
+
+ /**
+ * Clone the sub-tree under certain given <code>Node</code>
+ *
+ * @param docNode The <code>Document</code> used to clone
+ * the <code>Node</code>.
+ * @param oldNode The <code>Node</code> to clone.
+ * @param newNode The destination <code>Node</code>.
+ */
+ private static void cloneTree(Document docNode, Node oldNode, Node newNode) {
+
+ NodeList nodeList = newNode.getChildNodes();
+ int nodeListLen = nodeList.getLength();
+
+ for (int i = 0; i < nodeListLen; i++) {
+ Node newClonedChild = cloneNode(docNode, nodeList.item(i));
+ if (newClonedChild != null) {
+ oldNode.appendChild(newClonedChild);
+ cloneTree(docNode, newClonedChild, nodeList.item(i));
+ }
+ }
+ }
+
+
+ /**
+ * Clone a <code>Node</code> (either text or element).
+ *
+ * @param docNode The <code>Document</code> used to
+ * clone the <code>Node</code>.
+ * @param newNode The <code>Node</code> to clone.
+ *
+ * @return The cloned <code>Node</code>.
+ */
+ private static Node cloneNode(Document docNode, Node newNode) {
+
+ Node clonedNode = null;
+
+ // only support text node and element node (will copy the attributes)
+ switch (newNode.getNodeType()) {
+ case Node.TEXT_NODE:
+ String textStr = newNode.getNodeValue();
+ clonedNode = docNode.createTextNode(textStr);
+ break;
+ case Node.ELEMENT_NODE:
+ Element oldElem = (Element)newNode;
+ String tagName = newNode.getNodeName();
+ Element newElem = (docNode.createElement(tagName));
+
+ // copy the attributes
+ NamedNodeMap attrs = oldElem.getAttributes();
+
+ for (int i = 0; i < attrs.getLength(); i++) {
+ newElem.setAttribute(attrs.item(i).getNodeName(),
+ attrs.item(i).getNodeValue());
+ }
+ clonedNode = newElem;
+ break;
+ }
+ return clonedNode;
+ }
+
+
+ /**
+ * Returns the name and type of an XML DOM <code>Node</code>.
+ *
+ * @param node <code>Node</code> to query.
+ *
+ * @return Name and type of XML DOM <code>Node</code>.
+ */
+ public static String getNodeInfo(Node node) {
+
+ String str = null;
+ switch (node.getNodeType()) {
+
+ case Node.ELEMENT_NODE:
+ str = "ELEMENT";
+ break;
+ case Node.ATTRIBUTE_NODE:
+ str = "ATTRIBUTE";
+ break;
+ case Node.TEXT_NODE:
+ str = "TEXT";
+ break;
+ case Node.CDATA_SECTION_NODE:
+ str = "CDATA_SECTION";
+ break;
+ case Node.ENTITY_REFERENCE_NODE:
+ str = "ENTITY_REFERENCE";
+ break;
+ case Node.ENTITY_NODE:
+ str = "ENTITY";
+ break;
+ case Node.PROCESSING_INSTRUCTION_NODE:
+ str = "PROCESSING_INSTRUCTION";
+ break;
+ case Node.COMMENT_NODE:
+ str = "COMMENT";
+ break;
+ case Node.DOCUMENT_NODE:
+ str = "DOCUMENT";
+ break;
+ case Node.DOCUMENT_TYPE_NODE:
+ str = "DOCUMENT_TYPE";
+ break;
+ case Node.DOCUMENT_FRAGMENT_NODE:
+ str = "DOCUMENT_FRAGMENT";
+ break;
+ case Node.NOTATION_NODE:
+ str = "NOTATION";
+ break;
+ }
+
+ StringBuffer buffer = new StringBuffer("name=\"");
+ buffer.append(node.getNodeName());
+ buffer.append("\" type=\"");
+ buffer.append(str);
+ buffer.append("\"");
+
+ return buffer.toString();
+ }
+}
+
diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/util/package.html b/xmerge/source/xmerge/java/org/openoffice/xmerge/util/package.html
new file mode 100644
index 000000000000..1caffdbe41d4
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/util/package.html
@@ -0,0 +1,39 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<!--
+ #*************************************************************************
+ #
+ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+
+ Copyright 2000, 2010 Oracle and/or its affiliates.
+
+ OpenOffice.org - a multi-platform office productivity suite
+
+ This file is part of OpenOffice.org.
+
+ OpenOffice.org is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License version 3
+ only, as published by the Free Software Foundation.
+
+ OpenOffice.org is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License version 3 for more details
+ (a copy is included in the LICENSE file that accompanied this code).
+
+ You should have received a copy of the GNU Lesser General Public License
+ version 3 along with OpenOffice.org. If not, see
+ <http://www.openoffice.org/license.html>
+ for a copy of the LGPLv3 License.
+
+ #*************************************************************************
+ -->
+<html>
+<head>
+<title>org.openoffice.xmerge.util package</title>
+</head>
+
+<body bgcolor="white">
+<p>Provides general purpose utilities.</p>
+
+</body>
+</html>
diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/util/registry/ConverterInfo.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/util/registry/ConverterInfo.java
new file mode 100644
index 000000000000..359bcbfeb222
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/util/registry/ConverterInfo.java
@@ -0,0 +1,436 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.util.registry;
+
+import java.util.Vector;
+import java.util.Enumeration;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.lang.reflect.Constructor;
+import org.openoffice.xmerge.PluginFactory;
+import org.openoffice.xmerge.DocumentSerializerFactory;
+import org.openoffice.xmerge.DocumentDeserializerFactory;
+import org.openoffice.xmerge.DocumentMergerFactory;
+
+/**
+ * Class for storing the information about a converter plugin.
+ *
+ * @author Brian Cameron
+ */
+public class ConverterInfo {
+
+ /**
+ * Keep track of the valid Office mime types
+ */
+ private static String[] validOfficeTypes;
+ public static String SxwType = "staroffice/sxw";
+ public static String SxcType = "staroffice/sxc";
+
+
+ static {
+ // This needs to be updated to reflect all valid office types.
+ //
+ validOfficeTypes = new String[2];
+ validOfficeTypes[0] = SxwType;
+ validOfficeTypes[1] = SxcType;
+ }
+
+ private String piJarName;
+ private String piOfficeMime;
+ private Vector piDeviceMime;
+ private String piDisplayName;
+ private String piDescription;
+ private String piVersion;
+ private String piVendor;
+ private String piClassImpl;
+ private String piXsltSerial;
+ private String piXsltDeserial;
+ private boolean piCanSerialize = false;
+ private boolean piCanDeserialize = false;
+ private boolean piCanMerge = false;
+ private ClassLoader piClassLoader = null;
+ private PluginFactory piPluginFactory;
+
+
+ /**
+ * The constructor builds a ConverterInfo structure.
+ *
+ * @param jarName The URL of the jarfile.
+ * @param officeMime The office mime-type.
+ * @param deviceMime The device mime-type.
+ * @param displayName The display name.
+ * @param description The description.
+ * @param version The version.
+ * @param vendor The vendor name.
+ * @param impl The implementation class name of
+ * PluginFactory.
+ * @param xsltSerial The url of the serializer xsl stylesheet
+ * @param xsltDeserial The url of the deserializer xsl stylesheet
+ *
+ * @throws RegistryException If <code>ci</code> cannot
+ * be loaded.
+ */
+ public ConverterInfo(String jarName, String officeMime,
+ Vector deviceMime, String displayName, String description,
+ String version, String vendor, String impl,String xsltSerial,
+ String xsltDeserial)
+ throws RegistryException {
+
+ if (isValidOfficeType(officeMime.trim()) == false) {
+ RegistryException re = new RegistryException(
+ "Invalid office type");
+ throw re;
+ }
+
+ piJarName = jarName.trim();
+ piOfficeMime = officeMime.trim();
+ piDeviceMime = deviceMime;
+ piDisplayName = displayName.trim();
+ piDescription = description.trim();
+ piVersion = version.trim();
+ piVendor = vendor.trim();
+ piXsltSerial = xsltSerial.trim();
+ piXsltDeserial= xsltDeserial.trim();
+ piClassImpl = impl.trim();
+ piClassLoader = this.getClass().getClassLoader();
+
+ // Get instance of the PluginFactory.
+ //
+ try {
+ URL jarURL = new URL(jarName);
+ URLClassLoader loader = new URLClassLoader(new URL[] { jarURL },
+ piClassLoader);
+ Class clas = loader.loadClass(piClassImpl);
+ Class[] argumentTypes = { org.openoffice.xmerge.util.registry.ConverterInfo.class };
+ Constructor construct = clas.getConstructor(argumentTypes);
+
+ Object[] arguments = { this };
+ piPluginFactory = ( PluginFactory ) construct.newInstance(arguments);
+
+ // See which interfaces the plug-in PluginFactory supports.
+ //
+ Class[] cl = piPluginFactory.getClass().getInterfaces();
+ for (int i=0; i < cl.length; i++) {
+
+ if (cl[i].getName().equals("org.openoffice.xmerge.DocumentSerializerFactory")) {
+ piCanSerialize = true;
+ }
+ if (cl[i].getName().equals("org.openoffice.xmerge.DocumentDeserializerFactory")) {
+ piCanDeserialize = true;
+ }
+ if (cl[i].getName().equals("org.openoffice.xmerge.DocumentMergerFactory")) {
+ piCanMerge = true;
+ }
+ }
+
+ } catch (Exception e) {
+ RegistryException re = new RegistryException(
+ "Class implementation of the plug-in cannot be loaded.");
+ throw re;
+ }
+ }
+
+ /**
+ * The constructor builds a ConverterInfo structure.
+ *
+ * @param jarName The URL of the jarfile.
+ * @param officeMime The office mime-type.
+ * @param deviceMime The device mime-type.
+ * @param displayName The display name.
+ * @param description The description.
+ * @param version The version.
+ * @param vendor The vendor name.
+ * @param impl The implementation class name of
+ * PluginFactory.
+ *
+ * @throws RegistryException If <code>ci</code> cannot
+ * be loaded.
+ */
+
+
+ public ConverterInfo(String jarName, String officeMime,
+ Vector deviceMime, String displayName, String description,
+ String version, String vendor, String impl)
+ throws RegistryException {
+
+ if (isValidOfficeType(officeMime.trim()) == false) {
+ RegistryException re = new RegistryException(
+ "Invalid office type");
+ throw re;
+ }
+
+ piJarName = jarName.trim();
+ piOfficeMime = officeMime.trim();
+ piDeviceMime = deviceMime;
+ piDisplayName = displayName.trim();
+ piDescription = description.trim();
+ piVersion = version.trim();
+ piVendor = vendor.trim();
+ piClassImpl = impl.trim();
+ piClassLoader = this.getClass().getClassLoader();
+
+ // Get instance of the PluginFactory.
+ //
+ try {
+ URL jarURL = new URL(jarName);
+ URLClassLoader loader = new URLClassLoader(new URL[] { jarURL },
+ piClassLoader);
+ Class clas = loader.loadClass(piClassImpl);
+ Class[] argumentTypes = { org.openoffice.xmerge.util.registry.ConverterInfo.class };
+ Constructor construct = clas.getConstructor(argumentTypes);
+
+ Object[] arguments = { this };
+ piPluginFactory = ( PluginFactory ) construct.newInstance(arguments);
+
+ // See which interfaces the plug-in PluginFactory supports.
+ //
+ Class[] cl = piPluginFactory.getClass().getInterfaces();
+ for (int i=0; i < cl.length; i++) {
+
+ if (cl[i].getName().equals("org.openoffice.xmerge.DocumentSerializerFactory")) {
+ piCanSerialize = true;
+ }
+ if (cl[i].getName().equals("org.openoffice.xmerge.DocumentDeserializerFactory")) {
+ piCanDeserialize = true;
+ }
+ if (cl[i].getName().equals("org.openoffice.xmerge.DocumentMergerFactory")) {
+ piCanMerge = true;
+ }
+ }
+
+ } catch (Exception e) {
+ RegistryException re = new RegistryException(
+ "Class implementation of the plug-in cannot be loaded.");
+ throw re;
+ }
+ }
+
+
+
+
+ /**
+ * Create a default constructor so we can use isValidOfficeType
+ * without having to actually have a valid ConverterInfo.
+ */
+ private ConverterInfo() {
+ }
+
+
+ /**
+ * Returns an instance of the DocumentDeserializerFactory interface.
+ *
+ * @return instance of the DocumentDeserializer for this ConverterInfo.
+ */
+ public DocumentSerializerFactory getDocSerializerFactory() {
+ return (DocumentSerializerFactory)piPluginFactory;
+ }
+
+
+ /**
+ * Returns an instance of the DocumentSerializerFactory interface.
+ *
+ * @return instance of the DocumentSerializer for this ConverterInfo.
+ */
+ public DocumentDeserializerFactory getDocDeserializerFactory() {
+ return (DocumentDeserializerFactory)piPluginFactory;
+ }
+
+
+ /**
+ * Returns an instance of the DocumentMergerFactory interface.
+ *
+ * @return instance of the DocumentMergerFactory for this ConverterInfo.
+ */
+ public DocumentMergerFactory getDocMergerFactory() {
+ return (DocumentMergerFactory)piPluginFactory;
+ }
+
+
+ /**
+ * Returns the jar file name.
+ *
+ * @return The jar file name, null if none exists.
+ */
+ public String getJarName() {
+ return piJarName;
+ }
+
+
+ /**
+ * Returns the office mime-type.
+ *
+ * @return The office mime-type, null if none exists.
+ */
+ public String getOfficeMime() {
+ return piOfficeMime;
+ }
+
+
+ /**
+ * Returns an <code>Enumeration</code> of <code>String</code>
+ * objects indicating the device mime-type.
+ *
+ * @return An <code>Enumeration</code> of <code>String</code>
+ * objects indicating the device mime-type.
+ */
+ public Enumeration getDeviceMime() {
+ return(piDeviceMime.elements());
+ }
+
+
+ /**
+ * Returns the display name.
+ *
+ * @return The display name, null if none exists.
+ */
+ public String getDisplayName() {
+ return piDisplayName;
+ }
+
+
+ /**
+ * Returns the description.
+ *
+ * @return The description, null if none exists.
+ */
+ public String getDescription() {
+ return piDescription;
+ }
+
+
+ /**
+ * Returns the version.
+ *
+ * @return The version, null if none exists.
+ */
+ public String getVersion() {
+ return piVersion;
+ }
+
+
+ /**
+ * Returns the vendor name.
+ *
+ * @return The vendor name, null if none exists.
+ */
+ public String getVendor() {
+ return piVendor;
+ }
+
+
+ /**
+ * Returns the implementation class name of PluginFactory.
+ *
+ * @return The implementation class name of PluginFactory,
+ * null if none exists.
+ */
+ public String getClassImpl() {
+ return piClassImpl;
+ }
+
+
+ /**
+ * Returns the PluginFactory instance for this plug-in.
+ *
+ * @return The PluginFactory instance for this plug-in.
+ */
+ public PluginFactory getPluginFactory() {
+ return piPluginFactory;
+ }
+
+
+ /**
+ * Returns true if this plug-in has a serializier, false otherwise.
+ *
+ * @return true if this plug-in has a serializier, false otherwise.
+ */
+ public boolean canSerialize() {
+ return piCanSerialize;
+ }
+
+
+ /**
+ * Returns true if this plug-in has a deserializier, false otherwise.
+ *
+ * @return true if this plug-in has a deserializier, false otherwise.
+ */
+ public boolean canDeserialize() {
+ return piCanDeserialize;
+ }
+
+
+ /**
+ * Returns true if this plug-in has a merger, false otherwise.
+ *
+ * @return true if this plug-in has a merger, false otherwise.
+ */
+ public boolean canMerge() {
+ return piCanMerge;
+ }
+
+
+ /**
+ * Returns true if the officeMime is a valid Office mime type.
+ *
+ * @return true if the officeMime is a valid Office mime type.
+ */
+ public static boolean isValidOfficeType(String officeMime) {
+
+ boolean rc = false;
+ for (int i=0; i < validOfficeTypes.length; i++) {
+ if (officeMime.equals(validOfficeTypes[i])) {
+ rc = true;
+ }
+ }
+
+ return rc;
+ }
+
+ /**
+ * Returns a <code>String</code> containing the Xslt stylesheet url that
+ * is to be used by the Xslt Plugin Serializer.
+ *
+ * @return <code>String</code>
+ */
+
+ public String getXsltSerial() {
+ return piXsltSerial;
+ }
+
+ /**
+ * Returns a <code>String</code> containing the xslt stylesheet url that
+ * is to be used by the Xslt Plugin Deserializer.
+ *
+ * @return <code>String</code>
+ */
+
+ public String getXsltDeserial() {
+ return piXsltDeserial;
+ }
+}
+
diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/util/registry/ConverterInfoMgr.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/util/registry/ConverterInfoMgr.java
new file mode 100644
index 000000000000..0993924c129f
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/util/registry/ConverterInfoMgr.java
@@ -0,0 +1,536 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.util.registry;
+
+import java.util.*;
+import java.io.*;
+
+/**
+ * Manages the converter plug-ins that are currently active.
+ * This class allows plug-ins to be added or removed dynamically.
+ * This class is a singleton (static) class, so that only one
+ * manager can exist at a time. It is final, so it may not be
+ * subclassed.
+ *
+ * @author: Brian Cameron
+ */
+public final class ConverterInfoMgr {
+
+ private static Vector converterInfoList;
+
+ /**
+ * Constructor
+ */
+ static {
+ converterInfoList = new Vector();
+ }
+
+
+ /**
+ * Adds a converter plug-in to the registry. The
+ * <code>ConverterInfo</code> must have a unique DisplayName
+ * and must have non-null values for DisplayName, ClassImpl,
+ * OfficeMime, and DeviceMime.
+ *
+ * @param ConverterInfo A <code>ConverterInfo</code> object
+ * describing a plug-in.
+ *
+ * @throws RegistryException If the <code>ConverterInfo</code>
+ * is not valid.
+ */
+ public static void addPlugIn(ConverterInfo ci) throws RegistryException {
+
+ ConverterInfo converterInfo;
+
+ // Validate
+ //
+ if (ci.getDisplayName() == null) {
+ RegistryException re = new RegistryException(
+ "Converter must have valid name.");
+ throw re;
+ }
+ if (ci.getClassImpl() == null) {
+ RegistryException re = new RegistryException(
+ "Converter must have valid class implementation specified.");
+ throw re;
+ }
+ if (ci.getOfficeMime() == null) {
+ RegistryException re = new RegistryException(
+ "Converter must have valid office mime specified.");
+ throw re;
+ }
+ if (! ci.getDeviceMime().hasMoreElements()) {
+ RegistryException re = new RegistryException(
+ "Converter must have valid device mime specified.");
+ throw re;
+ }
+
+ // Verify there is no converter with the same Display Name in
+ // the registry.
+ //
+ Enumeration ciEnum = converterInfoList.elements();
+ while (ciEnum.hasMoreElements()) {
+ converterInfo = (ConverterInfo)ciEnum.nextElement();
+ if (ci.getDisplayName().equals(converterInfo.getDisplayName())) {
+ RegistryException re = new RegistryException(
+ "Converter with specified display name already exists.");
+ throw re;
+ }
+ }
+
+ // Since this is a adding to a static Vector, make sure this
+ // add method call is synchronized.
+ //
+ synchronized (converterInfoList) {
+ converterInfoList.add(ci);
+ }
+ }
+
+
+ /**
+ * Adds a <code>Vector</code> of converter plug-ins to the registry.
+ * Each <code>ConverterInfo</code> in the <code>Vector</code> must have
+ * a unique DisplayName and must have non-null values for DisplayName,
+ * ClassImpl, OfficeMime, and DeviceMime.
+ *
+ * @param ciVectory A <code>Vector</code> of <code>ConverterInfo</code>
+ * objects describing one or more plug-in(s).
+ *
+ * @throws RegistryException If a <code>ConverterInfo</code> in the
+ * <code>Vector</code> is not valid.
+ */
+ public static void addPlugIn(Enumeration jarEnum) throws RegistryException {
+
+ while (jarEnum.hasMoreElements()) {
+ ConverterInfo converterInfo = (ConverterInfo)jarEnum.nextElement();
+ addPlugIn(converterInfo);
+ }
+ }
+
+
+ /**
+ * Returns an <code>Enumeration</code> of registered
+ * <code>ConverterInfo</code> objects.
+ *
+ * @return An <code>Enumeration</code> containing the currently registered
+ * <code>ConverterInfo</code> objects, an empty
+ * <code>Vector</code> if none exist.
+ */
+ public static Enumeration getConverterInfoEnumeration() {
+ return (converterInfoList.elements());
+ }
+
+
+ /**
+ * Removes any <code>ConverterInfo</code> object from the registry
+ * that have the specified jar name value.
+ *
+ * @param jar The name of the jarfile.
+ *
+ * @return True if a <code>ConverterInfo</code> object was
+ * removed, false otherwise.
+ */
+ public static boolean removeByJar(String jar) {
+
+ ConverterInfo converterInfo;
+ boolean rc = false;
+
+ // FIX (HJ): Has to use an iterator, since we are removing items
+ /*Enumeration ciEnum = converterInfoList.elements();
+ while (ciEnum.hasMoreElements())
+ {
+ converterInfo = (ConverterInfo)ciEnum.nextElement();
+ if (jar.equals(converterInfo.getJarName())) {
+ converterInfoList.remove(converterInfo);
+ rc = true;
+ }
+ }*/
+
+ Iterator ciIter = converterInfoList.iterator();
+ while (ciIter.hasNext())
+ {
+ converterInfo = (ConverterInfo)ciIter.next();
+ if (jar.equals(converterInfo.getJarName())) {
+ ciIter.remove();
+ rc = true;
+ }
+ }
+ return rc;
+ }
+
+
+ /**
+ * Removes any <code>ConverterInfo</code> object from the registry
+ * that have the specified display name value.
+ *
+ * @param name The display name.
+ *
+ * @return True if a <code>ConverterInfo</code> object was
+ * removed, false otherwise.
+ */
+ public static boolean removeByName(String name) {
+
+ ConverterInfo converterInfo;
+ boolean rc = false;
+
+ Enumeration ciEnum = converterInfoList.elements();
+ while (ciEnum.hasMoreElements())
+ {
+ converterInfo = (ConverterInfo)ciEnum.nextElement();
+ if (name.equals(converterInfo.getDisplayName())) {
+ converterInfoList.remove(converterInfo);
+ rc = true;
+ }
+ }
+ return rc;
+ }
+
+
+ /**
+ * Returns the <code>ConverterInfo</code> object that supports
+ * the specified device/office mime type conversion. If there
+ * are multiple <code>ConverterInfo</code> objects registered
+ * that support this conversion, only the first is returned.
+ *
+ * @param deviceMime The device mime.
+ * @param officeMime The office mime.
+ *
+ * @return The first plug-in that supports the specified
+ * conversion.
+ */
+ public static ConverterInfo findConverterInfo(String deviceMime, String officeMime) {
+
+ ConverterInfo converterInfo;
+
+ if (deviceMime == null ||
+ ConverterInfo.isValidOfficeType(officeMime) == false) {
+ return null;
+ }
+
+ // Loop over elements comparing with deviceFromMime
+ //
+ Enumeration ciEnum = converterInfoList.elements();
+ while (ciEnum.hasMoreElements()) {
+
+ converterInfo = (ConverterInfo)ciEnum.nextElement();
+ String toDeviceInfo = (String)converterInfo.getOfficeMime();
+ Enumeration fromEnum = converterInfo.getDeviceMime();
+
+ // Loop over the deviceMime types.
+ //
+ while (fromEnum.hasMoreElements()) {
+ String fromDeviceInfo = (String)fromEnum.nextElement();
+ if (deviceMime.trim().equals(fromDeviceInfo) &&
+ officeMime.trim().equals(toDeviceInfo)) {
+ return (converterInfo);
+ }
+ }
+ }
+ return null;
+ }
+
+
+ /**
+ * Returns an array of two <code>ConverterInfo</code> objects that
+ * can be chained to perform the specified mime type conversion.
+ * If there are multiple <code>ConverterInfo</code> objects that
+ * support this conversion, only the first is returned.
+ *
+ * @param deviceMimeFrom The device from mime.
+ * @param deviceMimeTo The device to mime.
+ *
+ * @return An array of two <code>ConverterInfo</code> objects
+ * that can be chained to perform the specified
+ * conversion.
+ */
+ public static ConverterInfo[] findConverterInfoChain(String deviceFromMime, String deviceToMime) {
+
+ if (deviceFromMime == null || deviceToMime == null) {
+ return null;
+ }
+
+ ConverterInfo[] converterInfo = new ConverterInfo[2];
+
+ // Loop over elements comparing with deviceFromMime
+ //
+ Enumeration cifEnum = converterInfoList.elements();
+ while (cifEnum.hasMoreElements()) {
+
+ converterInfo[0] = (ConverterInfo)cifEnum.nextElement();
+ String fromOfficeInfo = converterInfo[0].getOfficeMime();
+ Enumeration fromEnum = converterInfo[0].getDeviceMime();
+
+ // Loop over the deviceMime types looking for a deviceFromMime
+ // match.
+ //
+ while (fromEnum.hasMoreElements()) {
+ String fromDeviceInfo = (String)fromEnum.nextElement();
+
+ if (deviceFromMime.trim().equals(fromDeviceInfo)) {
+
+ // Found a a match for deviceFrom. Now loop over the
+ // elements comparing with deviceToMime
+ //
+ Enumeration citEnum = converterInfoList.elements();
+ while (citEnum.hasMoreElements()) {
+
+ converterInfo[1] = (ConverterInfo)citEnum.nextElement();
+ String toOfficeInfo = converterInfo[1].getOfficeMime();
+ Enumeration toEnum = converterInfo[1].getDeviceMime();
+
+ // Loop over deviceMime types looking for a
+ // deviceToMime match.
+ //
+ while (toEnum.hasMoreElements()) {
+ String toDeviceInfo = (String)toEnum.nextElement();
+ if (deviceToMime.trim().equals(toDeviceInfo) &&
+ fromOfficeInfo.equals(toOfficeInfo)) {
+
+ // Found a match
+ //
+ return (converterInfo);
+ }
+ }
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+
+ /**
+ * main to let the user specify what plug-ins to register from
+ * jarfiles and to display the currently registered plug-ins.
+ *
+ * @param args Not used.
+ */
+ public static void main(String args[]) {
+
+ ConverterInfoReader cir = null;
+ boolean validate = false;
+ InputStreamReader isr = new InputStreamReader(System.in);
+ BufferedReader br = new BufferedReader(isr);
+ char c = ' ';
+
+ boolean exitFlag = false;
+ while (exitFlag == false) {
+
+ System.out.println("\nMenu:");
+ System.out.println("(L)oad plug-ins from a jar file");
+ System.out.println("(D)isplay name unload");
+ System.out.println("(J)ar name unload");
+ System.out.println("(F)ind ConverterInfo");
+ System.out.println("(C)ind ConverterInfo chain");
+ System.out.println("(V)iew plug-ins");
+ System.out.println("(T)oggle Validation");
+ System.out.println("(Q)uit\n");
+
+ try {
+ c = br.readLine().toUpperCase().trim().charAt(0);
+ } catch(Exception e) {
+ System.out.println("Invalid entry");
+ System.out.println("Error msg: " + e.getMessage());
+ continue;
+ }
+
+ System.out.println("");
+
+ // Quit
+ //
+ if (c == 'Q') {
+ exitFlag = true;
+
+ // Load by Jarfile
+ //
+ } else if (c == 'L') {
+
+ System.out.println("Enter path to jarfile: ");
+ try {
+ String jarname = br.readLine().trim();
+ cir = new ConverterInfoReader(jarname,validate);
+ } catch (RegistryException e) {
+ System.out.println("Cannot load plug-in ConverterFactory implementation.");
+ System.out.println("Error msg: " + e.getMessage());
+ } catch (Exception e) {
+ System.out.println("Error adding data to registry");
+ System.out.println("Error msg: " + e.getMessage());
+ }
+
+ if (cir != null) {
+ Enumeration jarInfoEnum = cir.getConverterInfoEnumeration();
+ try {
+ ConverterInfoMgr.addPlugIn(jarInfoEnum);
+ } catch (Exception e) {
+ System.out.println("Error adding data to registry");
+ System.out.println("Error msg: " + e.getMessage());
+ }
+ }
+
+ // Unload by Display Name or Jarfile
+ //
+ } else if (c == 'T') {
+ if (validate== true){
+ System.out.println("Validation switched off");
+ validate=false;
+ }else{
+ System.out.println("Validation switched on");
+ validate=true;
+ }
+ } else if (c == 'D' || c == 'J') {
+
+ if (c == 'D') {
+ System.out.println("Enter display name: ");
+ } else {
+ System.out.println("Enter path to jarfile: ");
+ }
+
+ try
+ {
+ String name = br.readLine().trim();
+ boolean rc = false;
+
+ if (c == 'D') {
+ rc = ConverterInfoMgr.removeByName(name);
+ } else {
+ rc = ConverterInfoMgr.removeByJar(name);
+ }
+
+ if (rc == true) {
+ System.out.println("Remove successful.");
+ } else {
+ System.out.println("Remove failed.");
+ }
+
+ } catch (Exception e) {
+ System.out.println("Error removing value from registry");
+ System.out.println("Error msg: " + e.getMessage());
+ }
+
+ // Find Office Mime
+ //
+ } else if (c == 'F' || c == 'C') {
+
+ String findMimeOne = null;
+ String findMimeTwo = null;
+
+ if (c == 'F') {
+ System.out.println("Enter device mime: ");
+ } else {
+ System.out.println("Enter device from mime: ");
+ }
+
+ try {
+ findMimeOne = br.readLine().trim();
+ } catch (Exception e) {
+ System.out.println("Error adding data to registry");
+ System.out.println("Error msg: " + e.getMessage());
+ }
+
+ if (c == 'F') {
+ System.out.println("Enter office mime: ");
+ } else {
+ System.out.println("Enter device to mime: ");
+ }
+
+ try {
+ findMimeTwo = br.readLine().trim();
+ } catch (Exception e) {
+ System.out.println("Error adding data to registry");
+ System.out.println("Error msg: " + e.getMessage());
+ }
+
+ if (c == 'F') {
+ ConverterInfo foundInfo = ConverterInfoMgr.findConverterInfo(findMimeOne, findMimeTwo);
+ if (foundInfo != null) {
+ System.out.println(" Found ConverterInfo");
+ System.out.println(" DisplayName : " + foundInfo.getDisplayName());
+ } else {
+ System.out.println(" Did not find ConverterInfo");
+ }
+ } else {
+ ConverterInfo[] foundInfo = ConverterInfoMgr.findConverterInfoChain(findMimeOne,
+ findMimeTwo);
+ if (foundInfo[0] != null && foundInfo[1] != null ) {
+ System.out.println(" Found ConverterInfo Chain");
+ System.out.println(" DisplayName : " + foundInfo[0].getDisplayName());
+ System.out.println(" DisplayName : " + foundInfo[1].getDisplayName());
+ } else {
+ System.out.println(" Did not find ConverterInfo");
+ }
+ }
+
+ // View
+ //
+ } else if (c == 'V') {
+
+ Enumeration ciEnum = ConverterInfoMgr.getConverterInfoEnumeration();
+
+ int ciCnt = 0;
+ while (ciEnum.hasMoreElements())
+ {
+ System.out.println("");
+ System.out.println(" Displaying converter number " + ciCnt);
+ ConverterInfo converterInfo = (ConverterInfo)ciEnum.nextElement();
+ System.out.println(" DisplayName : " + converterInfo.getDisplayName());
+ System.out.println(" JarFile : " + converterInfo.getJarName());
+ System.out.println(" Description : " + converterInfo.getDescription());
+ System.out.println(" Version : " + converterInfo.getVersion());
+ System.out.println(" OfficeMime : " + converterInfo.getOfficeMime());
+ Enumeration fromEnum = converterInfo.getDeviceMime();
+ int feCnt = 1;
+ while (fromEnum.hasMoreElements())
+ {
+ System.out.println(" DeviceMime : (#" + feCnt + ") : " +
+ (String)fromEnum.nextElement());
+ feCnt++;
+ }
+ if (feCnt == 1) {
+ System.out.println(" DeviceMime : None specified");
+ }
+
+ System.out.println(" Vendor : " + converterInfo.getVendor());
+ System.out.println(" ClassImpl : " + converterInfo.getClassImpl());
+ System.out.println(" XsltSerial : " + converterInfo.getXsltSerial());
+ System.out.println(" XsltDeserial : " + converterInfo.getXsltDeserial());
+ System.out.println(" Serialize : " + converterInfo.canSerialize());
+ System.out.println(" Deserialize : " + converterInfo.canDeserialize());
+ System.out.println(" Merge : " + converterInfo.canMerge());
+ ciCnt++;
+ }
+
+ if (ciCnt == 0) {
+ System.out.println("No converters registered");
+ }
+ } else {
+ System.out.println("Invalid input");
+ }
+ }
+ }
+}
+
diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/util/registry/ConverterInfoReader.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/util/registry/ConverterInfoReader.java
new file mode 100644
index 000000000000..238fd59f9608
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/util/registry/ConverterInfoReader.java
@@ -0,0 +1,279 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.util.registry;
+
+import java.io.*;
+import java.util.*;
+import java.util.jar.*;
+import org.xml.sax.*;
+import org.w3c.dom.*;
+import javax.xml.parsers.*;
+import java.net.URL;
+import java.net.JarURLConnection;
+
+/**
+ * The <code>ConverterInfoReader</code> pulls a META-INF/converter.xml
+ * file out of a jar file and parses it, providing access to this
+ * information in a <code>Vector</code> of <code>ConverterInfo</code>
+ * objects.
+ *
+ * @author Brian Cameron
+ */
+public class ConverterInfoReader {
+
+ private final static String TAG_CONVERTER = "converter";
+ private final static String ATTRIB_OFFICE_TYPE = "type";
+ private final static String ATTRIB_VERSION = "version";
+ private final static String TAG_NAME = "converter-display-name";
+ private final static String TAG_DESC = "converter-description";
+ private final static String TAG_VENDOR = "converter-vendor";
+ private final static String TAG_CLASS_IMPL = "converter-class-impl";
+ private final static String TAG_TARGET = "converter-target";
+ private final static String ATTRIB_DEVICE_TYPE = "type";
+ private final static String TAG_XSLT_DESERIAL = "converter-xslt-deserialize";
+ private final static String TAG_XSLT_SERIAL = "converter-xslt-serialize";
+ private String jarfilename;
+ private Document document;
+ private Vector converterInfoList;
+
+
+ /**
+ * Constructor. A jar file is passed in. The jar file is
+ * parsed and the <code>Vector</code> of <code>ConverterInfo</code>
+ * objects is built.
+ *
+ * @param jar The URL of the jar file to process.
+ * @param shouldvalidate Boolean to enable or disable xml validation.
+ *
+ * @throws IOException If the jar file cannot
+ * be read or if the
+ * META-INF/converter.xml
+ * can not be read in the
+ * jar file.
+ * @throws ParserConfigurationException If the DocumentBuilder
+ * can not be built.
+ * @throws org.xml.sax.SAXException If the converter.xml
+ * file can not be parsed.
+ * @throws RegistryException If the ConverterFactory
+ * implementation of a
+ * plug-in cannot be loaded.
+ */
+ public ConverterInfoReader(String jar,boolean shouldvalidate) throws IOException,
+ ParserConfigurationException, org.xml.sax.SAXException,
+ RegistryException {
+
+ InputStream istream;
+ InputSource isource;
+ DocumentBuilderFactory builderFactory;
+ DocumentBuilder builder;
+ JarURLConnection jarConnection;
+ JarEntry jarentry;
+ JarFile jarfile;
+ URL url;
+
+ converterInfoList = new Vector();
+ jarfilename = jar;
+
+ // Get Jar via URL
+ //
+ url = new URL("jar:" + jar + "!/META-INF/converter.xml");
+ jarConnection = (JarURLConnection)url.openConnection();
+ jarentry = jarConnection.getJarEntry();
+ jarfile = jarConnection.getJarFile();
+
+ // Build the InputSource
+ //
+ istream = jarfile.getInputStream(jarentry);
+ isource = new InputSource(istream);
+
+ // Get the DOM builder and build the document.
+ //
+ builderFactory = DocumentBuilderFactory.newInstance();
+
+ //DTD validation
+ if (shouldvalidate){
+ System.out.println("Validating xml...");
+ builderFactory.setValidating(true);
+ }
+ //
+ builder = builderFactory.newDocumentBuilder();
+ document = builder.parse(isource);
+
+ // Parse the document.
+ //
+ parseDocument();
+ }
+
+
+ /**
+ * Loops over the <i>converter</i> <code>Node</code> in the converter.xml
+ * file and processes them.
+ *
+ * @throws RegistryException If the plug-in associated with a
+ * specific <i>converter</i> <code>Node</code>
+ * cannot be loaded.
+ */
+ private void parseDocument() throws RegistryException {
+
+ Node converterNode;
+ NodeList converterNodes = document.getElementsByTagName(TAG_CONVERTER);
+
+ for (int i=0; i < converterNodes.getLength(); i++) {
+ converterNode = converterNodes.item(i);
+ if (converterNode.getNodeType() == Node.ELEMENT_NODE) {
+ parseConverterNode((Element)converterNode);
+ }
+ }
+ }
+
+
+ /**
+ * Parses a <i>converter</i> node, pulling the information out of
+ * the <code>Node</code> and placing it in a <code>ConverterInfo</code>
+ * object, and adds that object to a <code>Vector</code> of
+ * <code>ConverterInfo</code> objects.
+ *
+ * @param e The <code>Element</code> corresponding to the
+ * <i>converter</i> XML tag.
+ *
+ *
+ * @throws RegistryException If the plug-in cannot be loaded.
+ */
+ private void parseConverterNode(Element e) throws RegistryException {
+
+ Element detailElement;
+ Node detailNode;
+ String elementTagName;
+ String officeMime = null;
+ Vector deviceMime = new Vector();
+ String name = null;
+ String desc = null;
+ String version = null;
+ String vendor = null;
+ String classImpl = null;
+ String xsltSerial = null;
+ String xsltDeserial= null;
+ String temp;
+
+ temp = e.getAttribute(ATTRIB_OFFICE_TYPE);
+ if (temp.length() != 0) {
+ officeMime = temp;
+ }
+
+ temp = e.getAttribute(ATTRIB_VERSION);
+ if (temp.length() != 0) {
+ version = temp;
+ }
+
+ NodeList detailNodes = e.getChildNodes();
+ for (int i=0; i < detailNodes.getLength(); i++) {
+
+ detailNode = detailNodes.item(i);
+ if (detailNode.getNodeType() == Node.ELEMENT_NODE) {
+
+ detailElement = (Element)detailNode;
+ elementTagName = detailElement.getTagName();
+
+ if (TAG_NAME.equalsIgnoreCase(elementTagName)) {
+ name = getTextValue(detailElement);
+ } else if (TAG_DESC.equalsIgnoreCase(elementTagName)) {
+ desc = getTextValue(detailElement);
+ } else if (TAG_VENDOR.equalsIgnoreCase(elementTagName)) {
+ vendor = getTextValue(detailElement);
+ } else if (TAG_XSLT_SERIAL.equalsIgnoreCase(elementTagName)) {
+ xsltSerial = getTextValue(detailElement);
+ } else if (TAG_XSLT_DESERIAL.equalsIgnoreCase(elementTagName)) {
+ xsltDeserial = getTextValue(detailElement);
+ } else if (TAG_CLASS_IMPL.equalsIgnoreCase(elementTagName)) {
+ classImpl = getTextValue(detailElement);
+ } else if (TAG_TARGET.equalsIgnoreCase(elementTagName)) {
+
+ temp = detailElement.getAttribute(ATTRIB_DEVICE_TYPE);
+ if (temp.length() != 0) {
+ deviceMime.add(temp);
+ }
+ }
+ }
+ }
+ ConverterInfo converterInfo;
+ if ((xsltSerial==null) || (xsltDeserial==null)){
+ converterInfo = new ConverterInfo(jarfilename,
+ officeMime, deviceMime, name,
+ desc, version, vendor,classImpl);
+ }
+ else{
+ converterInfo = new ConverterInfo(jarfilename,
+ officeMime, deviceMime, name,
+ desc, version, vendor,classImpl,
+ xsltSerial,xsltDeserial);
+ }
+ /*ConverterInfo converterInfo = new ConverterInfo(jarfilename,
+ officeMime, deviceMime, name, desc, version, vendor,
+ classImpl);*/
+ converterInfoList.add(converterInfo);
+ }
+
+
+ /**
+ * Helper function to get the text value of an
+ * <code>Element</code>.
+ *
+ * @param e The <code>Element</code> to process.
+ *
+ * @return The text value of the <code>Element</code>.
+ */
+ private String getTextValue(Element e) {
+
+ NodeList tempNodes = e.getChildNodes();
+ String text = null;
+ Node tempNode;
+
+ for (int j=0; j < tempNodes.getLength(); j++) {
+ tempNode = tempNodes.item(j);
+ if (tempNode.getNodeType() == Node.TEXT_NODE) {
+ text = tempNode.getNodeValue().trim();
+ break;
+ }
+ }
+
+ return text;
+ }
+
+
+ /**
+ * Returns an <code>Enumeration</code> of <code>ConverterInfo</code>
+ * objects.
+ *
+ * @return An <code>Enumeration</code> of <code>ConverterInfo</code>
+ * objects.
+ */
+ public Enumeration getConverterInfoEnumeration() {
+ return (converterInfoList.elements());
+ }
+}
+
diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/util/registry/RegistryException.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/util/registry/RegistryException.java
new file mode 100644
index 000000000000..ea370d386c1c
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/util/registry/RegistryException.java
@@ -0,0 +1,47 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.util.registry;
+
+/**
+ * This <code>Exception</code> is thrown by converter registry
+ * algorithms.
+ */
+public class RegistryException extends Exception {
+
+
+ /**
+ * Exception thrown by merge algorithms.
+ *
+ * @param message Message to be included in the
+ * <code>Exception</code>.
+ */
+ public RegistryException(String message) {
+ super(message);
+ }
+}
+
diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/util/registry/build.xml b/xmerge/source/xmerge/java/org/openoffice/xmerge/util/registry/build.xml
new file mode 100644
index 000000000000..525546d2f7fc
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/util/registry/build.xml
@@ -0,0 +1,135 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ #*************************************************************************
+ #
+ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+
+ Copyright 2000, 2010 Oracle and/or its affiliates.
+
+ OpenOffice.org - a multi-platform office productivity suite
+
+ This file is part of OpenOffice.org.
+
+ OpenOffice.org is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License version 3
+ only, as published by the Free Software Foundation.
+
+ OpenOffice.org is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License version 3 for more details
+ (a copy is included in the LICENSE file that accompanied this code).
+
+ You should have received a copy of the GNU Lesser General Public License
+ version 3 along with OpenOffice.org. If not, see
+ <http://www.openoffice.org/license.html>
+ for a copy of the LGPLv3 License.
+
+ #*************************************************************************
+ -->
+<project name="xmrg_jooxu_registry" default="main" basedir=".">
+
+ <!-- ================================================================= -->
+ <!-- settings -->
+ <!-- ================================================================= -->
+
+ <!-- project prefix, used for targets and build.lst -->
+ <property name="prj.prefix" value="xmrg"/>
+
+ <!-- name of this sub target used in recursive builds -->
+ <property name="target" value="xmrg_jooxu_registry"/>
+
+ <!-- relative path to project directory -->
+ <property name="prj" value="../../../../../.."/>
+
+ <!-- start of java source code package structure -->
+ <property name="java.dir" value="${prj}/java"/>
+
+ <!-- path component for current java package -->
+ <property name="package" value="org/openoffice/xmerge/util/registry"/>
+
+ <!-- define how to handle CLASSPATH environment -->
+ <property name="build.sysclasspath" value="ignore"/>
+
+ <property environment="env"/>
+ <property name="env.XML_APIS_JAR" value="${solar.jar}/xml-apis.jar"/>
+ <property name="env.XERCES_JAR" value="${solar.jar}/xercesImpl.jar"/>
+
+ <!-- classpath settings for javac tasks -->
+ <path id="classpath">
+ <pathelement location="${build.class}"/>
+ <pathelement location="${env.XML_APIS_JAR}"/>
+ <pathelement location="${env.XERCES_JAR}"/>
+ </path>
+
+ <!-- set whether we want to compile with or without deprecation -->
+ <property name="deprecation" value="on"/>
+
+ <!-- ================================================================= -->
+ <!-- solar build environment targets -->
+ <!-- ================================================================= -->
+
+ <target name="build_dir" unless="build.dir">
+ <property name="build.dir" value="${out}"/>
+ </target>
+
+ <target name="solar" depends="build_dir" if="solar.update">
+ <property name="solar.properties"
+ value="${solar.bin}/solar.properties"/>
+ </target>
+
+ <target name="init" depends="solar">
+ <property name="build.compiler" value="classic"/>
+ <property file="${solar.properties}"/>
+ <property file="${build.dir}/class/solar.properties"/>
+ </target>
+
+ <target name="info">
+ <echo message="--------------------"/>
+ <echo message="${target}"/>
+ <echo message="--------------------"/>
+ </target>
+
+
+ <!-- ================================================================= -->
+ <!-- custom targets -->
+ <!-- ================================================================= -->
+
+ <!-- the main target, called in recursive builds -->
+ <target name="main" depends="info,prepare,compile"/>
+
+ <!-- prepare output directories -->
+ <target name="prepare" depends="init" if="build.class">
+ <mkdir dir="${build.dir}"/>
+ <mkdir dir="${build.class}"/>
+ </target>
+
+ <!-- compile java sources in ${package} -->
+ <target name="compile" depends="prepare" if="build.class">
+ <javac srcdir="${java.dir}"
+ destdir="${build.class}"
+ debug="${debug}"
+ deprecation="${deprecation}"
+ optimize="${optimize}">
+ <classpath refid="classpath"/>
+ <include name="${package}/ConverterInfo.java"/>
+ <include name="${package}/ConverterInfoMgr.java"/>
+ <include name="${package}/ConverterInfoReader.java"/>
+ <include name="${package}/RegistryException.java"/>
+ <include name="${package}/UnoBridgeConverterInfo.java"/>
+ </javac>
+ </target>
+
+ <!-- clean up -->
+ <target name="clean" depends="prepare">
+ <delete includeEmptyDirs="true">
+ <fileset dir="${build.class}">
+ <patternset>
+ <include name="${package}/*.class"/>
+ </patternset>
+ </fileset>
+ </delete>
+ </target>
+
+</project>
+
diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/util/registry/package.html b/xmerge/source/xmerge/java/org/openoffice/xmerge/util/registry/package.html
new file mode 100644
index 000000000000..b6af6262cc5c
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/util/registry/package.html
@@ -0,0 +1,82 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<!--
+ #*************************************************************************
+ #
+ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+
+ Copyright 2000, 2010 Oracle and/or its affiliates.
+
+ OpenOffice.org - a multi-platform office productivity suite
+
+ This file is part of OpenOffice.org.
+
+ OpenOffice.org is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License version 3
+ only, as published by the Free Software Foundation.
+
+ OpenOffice.org is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License version 3 for more details
+ (a copy is included in the LICENSE file that accompanied this code).
+
+ You should have received a copy of the GNU Lesser General Public License
+ version 3 along with OpenOffice.org. If not, see
+ <http://www.openoffice.org/license.html>
+ for a copy of the LGPLv3 License.
+
+ #*************************************************************************
+ -->
+<html>
+<head>
+<title>org.openoffice.xmerge.util.registry package</title>
+</head>
+
+<body bgcolor="white">
+
+<p>Provides an interface for plug-in registration. Each plug-in must
+have a corresponding Plugin Configuration XML File which is named
+converter.xml. If the plug-in is stored in a jarfile, this
+converter.xml file is typically stored in the following location in
+the jarfile:</p>
+
+<blockquote>
+ META-INF/converter.xml
+</blockquote>
+
+<p>The Plugin Configuration XML File must validate against the
+converter.dtd file provided with this package. Since a jarfile
+can contain multiple plug-ins, this DTD supports specifying multiple
+plug-ins per jarfile. Please refer to the SDK document for more
+information about how to implement a Plugin Configuration XML File
+for a specific plugin.</p>
+
+<p>All information in the Plugin Configuratino XML File is bundled
+into one or more <code>ConverterInfo</code> object. The
+<code>ConverterInfoReader</code> object is used to build a
+<code>Vector</code> of <code>ConverterInfo</code> objects from a
+jarfile.</p>
+
+<p>The <code>ConverterInfoMgr</code> manages the registry of
+<code>ConverterInfo</code>. It is a singleton class, so that only one
+registry manager will ever exist. It is the client program's
+responsibility to register <code>ConverterInfo</code> objects that
+correspond to the plug-ins that are to be used.</p>
+
+<h2>TODO/IDEAS list</h2>
+
+<p><ol>
+<li>The <code>ConverterInfo</code> object could contain
+ <code>org.w3c.dom.Document</code> fragments that are accessed in a
+ generic fashion rather than get/set methods for each item in the DTD.
+ This would provide a more flexible approach, especially for adding
+ custom tags to a specific Plugin Configuration XML file (tags that
+ are only used by its associated plug-in).
+<li><code>ConverterInfo</code> should allow the merge/serialize/deserialize
+ logic to be included in separate plug-ins, if desired.</li>
+<li><code>ConverterInfoMgr</code> could use the Java Activation
+ Framework (JAF) to manage registration.</li>
+</ol></p>
+
+</body>
+</html>
diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/util/resources.properties b/xmerge/source/xmerge/java/org/openoffice/xmerge/util/resources.properties
new file mode 100644
index 000000000000..99e6ccae2645
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/util/resources.properties
@@ -0,0 +1,69 @@
+#*************************************************************************
+#
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# Copyright 2000, 2010 Oracle and/or its affiliates.
+#
+# OpenOffice.org - a multi-platform office productivity suite
+#
+# This file is part of OpenOffice.org.
+#
+# OpenOffice.org is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License version 3
+# only, as published by the Free Software Foundation.
+#
+# OpenOffice.org is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License version 3 for more details
+# (a copy is included in the LICENSE file that accompanied this code).
+#
+# You should have received a copy of the GNU Lesser General Public License
+# version 3 along with OpenOffice.org. If not, see
+# <http://www.openoffice.org/license.html>
+# for a copy of the LGPLv3 License.
+#
+#*************************************************************************
+# x-no-translate
+
+
+#
+# resources.properties
+#
+# resources for org.openoffice.xmerge.converter package.
+#
+NULL_MIME_EXCEPTION=Cannot specify null MIME types
+EMPTY_MIME_EXCEPTION=Cannot specify empty MIME types
+CANNOT_LOAD_CLASS=Unable to load class
+CANNOT_INST_CLASS=Unable to instantiate class
+NOT_AN_INSTANCE= is not an instance of
+CANNOT_FIND_REGISTERED=Cannot find registered class
+PARSE_ERROR=Parse Error
+LINE=Line
+COLUMN=Column
+PUBLIC_ID=PublicId
+SYSTEM_ID=SystemId
+INVALID_LOG_LEVEL=Invalid log level specified
+OPERATION_NOT_SUPPORTED=Operation not supported
+TEMPLATE_FILE_LOAD_ERROR=Error in loading template file -
+
+#
+# diff/merge algorithm erro messages
+#
+EMPTY_NODE_EXCEPTION=Current Node is empty
+NOT_LEAFNODE_EXCEPTION=Current Node is not a leaf node
+ROOTNODE_EXCEPTION=Cannot perform insert/append/remove on root node
+NOT_TEXTNODE_EXCEPTION=The target Node is not a TEXT_NODE, it is -
+NULL_NODE_EXCEPTION=The initial Xmldocument node is null
+CELL_NODE_EXCEPTION1=Cell node do not have only 1 child <text:p> nodes, will skip the merge of this node.Num of PARA child nodes:
+CELL_NODE_EXCEPTION2=Cell node have a non Element child nodes -
+CELL_NODE_EXCEPTION2=There is a child node under an expected empty cell node.
+NOT_ELEM_NODE_ERROR=The compared nodes are not a Element Node
+NOT_PARA_NODE_ERROR=The compared nodes are not a Paragraph or Heading node -
+NOT_NODE_ERROR=The compared nodes are not a Node
+#
+# SXW to/from DOC conversion error messages.
+#
+UNKNOWN_DOC_VERSION=Unknown DOC version.
+DOC_TEXT_LENGTH_EXCEEDED=DOC text length exceeds maximum value.
+DOC_TEXT_RECORD_SIZE_EXCEEDED=DOC text record exceeds size limit.
diff --git a/xmerge/source/xmerge/makefile.mk b/xmerge/source/xmerge/makefile.mk
new file mode 100644
index 000000000000..8ff18ad94d5d
--- /dev/null
+++ b/xmerge/source/xmerge/makefile.mk
@@ -0,0 +1,34 @@
+#*************************************************************************
+#
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# Copyright 2000, 2010 Oracle and/or its affiliates.
+#
+# OpenOffice.org - a multi-platform office productivity suite
+#
+# This file is part of OpenOffice.org.
+#
+# OpenOffice.org is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License version 3
+# only, as published by the Free Software Foundation.
+#
+# OpenOffice.org is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License version 3 for more details
+# (a copy is included in the LICENSE file that accompanied this code).
+#
+# You should have received a copy of the GNU Lesser General Public License
+# version 3 along with OpenOffice.org. If not, see
+# <http://www.openoffice.org/license.html>
+# for a copy of the LGPLv3 License.
+#
+#*************************************************************************
+
+TARGET=xmerge
+PRJ=../..
+
+.INCLUDE : ant.mk
+.IF "$(L10N_framework)"==""
+ALLTAR: ANTBUILD
+.ENDIF
diff --git a/xmerge/util/build.xml b/xmerge/util/build.xml
new file mode 100644
index 000000000000..f15ad3acff08
--- /dev/null
+++ b/xmerge/util/build.xml
@@ -0,0 +1,94 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+
+ Copyright 2000, 2010 Oracle and/or its affiliates.
+
+ OpenOffice.org - a multi-platform office productivity suite
+
+ This file is part of OpenOffice.org.
+
+ OpenOffice.org is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License version 3
+ only, as published by the Free Software Foundation.
+
+ OpenOffice.org is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License version 3 for more details
+ (a copy is included in the LICENSE file that accompanied this code).
+
+ You should have received a copy of the GNU Lesser General Public License
+ version 3 along with OpenOffice.org. If not, see
+ <http://www.openoffice.org/license.html>
+ for a copy of the LGPLv3 License.
+
+-->
+<project name="xmrg_util" default="main" basedir=".">
+
+ <property file="../source/inc/antbuild.properties"/>
+
+ <property name="javadoc.dir" location="${build.dir}/javadoc"/>
+
+ <property environment="env"/>
+ <property name="env.XML_APIS_JAR" value="${solar.jar}/xml-apis.jar"/>
+ <property name="env.XERCES_JAR" value="${solar.jar}/xercesImpl.jar"/>
+
+ <path id="classpath">
+ <pathelement location="${env.XML_APIS_JAR}"/>
+ <pathelement location="${env.XERCES_JAR}"/>
+ <pathelement location="${solar.jar}/unoil.jar"/>
+ <pathelement location="${solar.jar}/ridl.jar"/>
+ <pathelement location="${solar.jar}/jurt.jar"/>
+ <pathelement location="${solar.jar}/juh.jar"/>
+ <pathelement location="${build.dir}/xmerge.jar"/>
+ </path>
+
+ <target name="init">
+ <mkdir dir="${javadoc.dir}"/>
+ </target>
+
+ <!-- build javadoc -->
+ <target name="javadoc" depends="init">
+ <javadoc destdir="${javadoc.dir}"
+ verbose="false"
+ author="false"
+ nodeprecated="true"
+ nodeprecatedlist="true"
+ use="true"
+ Doctitle="OpenOffice XMerge API"
+ windowtitle="OpenOffice XMerge API"
+ classpathref="classpath">
+ <fileset dir="../source/bridge" defaultexcludes="yes">
+ <include name="**/*.java"/>
+ </fileset>
+ <fileset dir="../source/xmerge" defaultexcludes="yes">
+ <include name="**/*.java"/>
+ </fileset>
+ <fileset dir="../source/aportisdoc" defaultexcludes="yes">
+ <include name="**/*.java"/>
+ </fileset>
+ <fileset dir="../source/pexcel" defaultexcludes="yes">
+ <include name="**/*.java"/>
+ </fileset>
+ <fileset dir="../source/pocketword" defaultexcludes="yes">
+ <include name="**/*.java"/>
+ </fileset>
+ <link offline="true" href="http://java.sun.com/j2se/1.3/docs/api" packagelistLoc="${solar.doc}/jdk13"/>
+ <bottom><![CDATA[<i>Copyright &#169 2002 OpenOffice.org</i>]]></bottom>
+ <header><![CDATA[<b>OpenOffice.org<br>XMerge API</b>]]></header>
+ </javadoc>
+ </target>
+
+ <target name="main" depends="javadoc">
+ </target>
+
+ <target name="all" depends="javadoc">
+ </target>
+
+ <target name="clean">
+ <delete file="${javadoc.dir}"/>
+ </target>
+
+</project>
+
diff --git a/xmerge/util/makefile.mk b/xmerge/util/makefile.mk
new file mode 100644
index 000000000000..54ed16e3ef8e
--- /dev/null
+++ b/xmerge/util/makefile.mk
@@ -0,0 +1,34 @@
+#***************************************************************************
+#
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# Copyright 2000, 2010 Oracle and/or its affiliates.
+#
+# OpenOffice.org - a multi-platform office productivity suite
+#
+# This file is part of OpenOffice.org.
+#
+# OpenOffice.org is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License version 3
+# only, as published by the Free Software Foundation.
+#
+# OpenOffice.org is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License version 3 for more details
+# (a copy is included in the LICENSE file that accompanied this code).
+#
+# You should have received a copy of the GNU Lesser General Public License
+# version 3 along with OpenOffice.org. If not, see
+# <http://www.openoffice.org/license.html>
+# for a copy of the LGPLv3 License.
+#
+#***************************************************************************
+
+TARGET=xmrg_util
+PRJ=..
+
+.INCLUDE : ant.mk
+.IF "$(L10N_framework)"==""
+ALLTAR: ANTBUILD
+.ENDIF
diff --git a/xmerge/util/minicalc.mf b/xmerge/util/minicalc.mf
new file mode 100644
index 000000000000..1f0a0e35e276
--- /dev/null
+++ b/xmerge/util/minicalc.mf
@@ -0,0 +1,3 @@
+Manifest-Version: 1.0
+Class-Path: jmc.jar
+
diff --git a/xmerge/util/xmerge.mf b/xmerge/util/xmerge.mf
new file mode 100644
index 000000000000..89d942f17b5c
--- /dev/null
+++ b/xmerge/util/xmerge.mf
@@ -0,0 +1,8 @@
+Manifest-Version: 1.0
+Main-Class: org.openoffice.xmerge.test.Driver
+Class-Path: xml-apis.jar xercesImpl.jar serializer.jar
+Specification-Title: OpenOffice XMerge Framework
+Specification-Vendor: OpenOffice.org
+Specification-Version: 0.6.0
+Implementation-Version: #IMPL-VERSION#
+
diff --git a/xmerge/workben/XmlDiff.java b/xmerge/workben/XmlDiff.java
new file mode 100644
index 000000000000..e41dbbb6b9b0
--- /dev/null
+++ b/xmerge/workben/XmlDiff.java
@@ -0,0 +1,458 @@
+/************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+import java.io.FileWriter;
+import java.io.InputStream;
+import java.io.FileInputStream;
+import java.io.BufferedInputStream;
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.io.FileNotFoundException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+import java.io.PrintWriter;
+import java.util.Vector;
+import java.util.Properties;
+
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.w3c.dom.Node;
+import org.w3c.dom.Document;
+import org.w3c.dom.NodeList;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
+/**
+ * This class will diff 2 Xml files.
+ *
+ * @author Stephen Mak
+ */
+
+public final class XmlDiff {
+
+ private static final String PROPSFILE = "XmlDiff.properties";
+ private static final String FILE1 = "XmlDiff.file1";
+ private static final String FILE2 = "XmlDiff.file2";
+ private static final String OUTPUT= "XmlDiff.output";
+ private static final String IGNORE_TAGS= "XmlDiff.tags";
+
+ private Properties props_ = null;
+ private static PrintWriter writer_ = null;
+ private String[] tags_ = null;
+ private String file1_ = null;
+ private String file2_ = null;
+
+ /**
+ * Constructor. Load the properties file.
+ */
+
+ public XmlDiff() throws IOException {
+
+ Class c = this.getClass();
+ InputStream is = c.getResourceAsStream(PROPSFILE);
+ BufferedInputStream bis = new BufferedInputStream(is);
+ props_ = new Properties();
+ props_.load(bis);
+ bis.close();
+
+ String file1 = props_.getProperty(FILE1, "");
+ String file2 = props_.getProperty(FILE2, "");
+ String tagsString = props_.getProperty(IGNORE_TAGS, "");
+ String output = props_.getProperty("debug.output", "System.out");
+ setOutput(output);
+ tags_ = parseTags(tagsString);
+ }
+
+ /**
+ * diff 2 xml, but overwrite the property file's file1/2 setting with
+ * the input argument
+ */
+ public boolean diff(String file1, String file2) throws IOException {
+ file1_ = file1;
+ file2_ = file2;
+ return diff();
+ }
+
+ public boolean diff() throws IOException {
+
+ boolean result = false;
+
+ writer_.println("parsing "+ file1_ + "...");
+ // parse the Xml file
+ Document doc1 = parseXml(file1_);
+
+ writer_.println("parsing "+ file1_ + "...");
+ Document doc2 = parseXml(file2_);
+
+ if (doc1 != null && doc2 != null) {
+ writer_.println("diffing "+ file1_ + " & " + file2_ + "...");
+ result = compareNode(doc1, doc2);
+ }
+ return result;
+ }
+
+ private void diffLog(String errMsg, Node node1, Node node2) {
+
+ String node1Str = "";
+ String node2Str = "";
+
+ if (node1 != null) {
+ node1Str = "[Type]:" + nodeInfo(node1) +
+ " [Name]:" + node1.getNodeName();
+ if (node1.getNodeValue() != null)
+ node1Str += " [Value]:" + node1.getNodeValue();
+ }
+
+ if (node2 != null) {
+ node2Str = "[Type]:" + nodeInfo(node2) +
+ " [Name]:" + node2.getNodeName();
+ if (node2.getNodeValue() != null)
+ node2Str += " [Value]:" + node2.getNodeValue();
+ }
+
+ writer_.println(errMsg);
+ writer_.println(" Node1 - " + node1Str);
+ writer_.println(" Node2 - " + node2Str);
+ }
+
+ private String nodeInfo(Node node) {
+
+ String str = null;
+ switch (node.getNodeType()) {
+
+ case Node.ELEMENT_NODE:
+ str = "ELEMENT";
+ break;
+ case Node.ATTRIBUTE_NODE:
+ str = "ATTRIBUTE";
+ break;
+ case Node.TEXT_NODE:
+ str = "TEXT";
+ break;
+ case Node.CDATA_SECTION_NODE:
+ str = "CDATA_SECTION";
+ break;
+ case Node.ENTITY_REFERENCE_NODE:
+ str = "ENTITY_REFERENCE";
+ break;
+ case Node.ENTITY_NODE:
+ str = "ENTITY";
+ break;
+ case Node.PROCESSING_INSTRUCTION_NODE:
+ str = "PROCESSING_INSTRUCTION";
+ break;
+ case Node.COMMENT_NODE:
+ str = "COMMENT";
+ break;
+ case Node.DOCUMENT_NODE:
+ str = "DOCUMENT";
+ break;
+ case Node.DOCUMENT_TYPE_NODE:
+ str = "DOCUMENT_TYPE";
+ break;
+ case Node.DOCUMENT_FRAGMENT_NODE:
+ str = "DOCUMENT_FRAGMENT";
+ break;
+ case Node.NOTATION_NODE:
+ str = "NOTATION";
+ break;
+ }
+ return str;
+ }
+
+ private boolean ignoreTag(String nodeName) {
+
+
+ if (tags_ != null) {
+ for (int i = 0; i < tags_.length; i++) {
+ if (tags_[i].equals(nodeName))
+ return true;
+ }
+ }
+ return false;
+ }
+
+ // for future use if we want to compare attributes
+ private boolean attributesEqual(Node node1, Node node2) {
+ return true;
+ }
+
+ private boolean compareNode(Node node1, Node node2) {
+ boolean equal = false;
+
+ while (true) {
+
+ if (node1 == null && node2 == null) {
+ equal = true;
+ break;
+ } else if (node1 == null || node2 == null) {
+ diffLog("DIFF: one of the node is null", node1, node2);
+ break;
+ }
+
+ if (node1.getNodeType() != node2.getNodeType()) {
+ diffLog("DIFF: nodetype is different", node1, node2);
+ break;
+ }
+
+ if (node1.getNodeName() == null && node2.getNodeName() == null) {
+ // empty
+ } else if (node1.getNodeName() == null ||
+ node2.getNodeName() == null) {
+ diffLog("DIFF: one of the nodeName is null", node1, node2);
+ break;
+ } else if (!node1.getNodeName().equals(node2.getNodeName())) {
+ diffLog("DIFF: nodeName is different", node1, node2);
+ break;
+ }
+
+ if (ignoreTag(node1.getNodeName())) {
+ diffLog("DIFF: Some tag(s) is ignored", node1, node2);
+ equal = true;
+ break;
+ }
+
+ if (node1.getNodeValue() == null && node2.getNodeValue() == null) {
+ // empty
+ } else if (node1.getNodeValue() == null ||
+ node2.getNodeValue() == null) {
+ diffLog("DIFF: one of the nodevalue is null", node1, node2);
+ break;
+ } else if (!node1.getNodeValue().equals(node2.getNodeValue())) {
+ diffLog("DIFF: nodeValue is different", node1, node2);
+ break;
+ }
+
+ // try to compare attributes if necessary
+ if (!attributesEqual(node1, node2))
+ break;
+
+ NodeList node1Children = node1.getChildNodes();
+ NodeList node2Children = node2.getChildNodes();
+
+ // number of children have to be the same
+ if (node1Children == null && node2Children == null) {
+ equal = true;
+ break;
+ }
+
+ if (node1Children == null || node2Children == null) {
+ diffLog("DIFF: one node's children is null", node1, node2);
+ break;
+ }
+
+ if (node1Children.getLength() != node2Children.getLength()) {
+ diffLog("DIFF: num of children is different", node1, node2);
+ break;
+ }
+
+ // compare all the childrens
+ equal = true;
+
+ for (int i = 0; i < node1Children.getLength(); i++) {
+ if (!compareNode(node1Children.item(i),
+ node2Children.item(i))) {
+ equal = false;
+ break;
+ }
+ }
+ break;
+ }
+
+ return equal;
+ }
+
+ private Document parseXml (String filename) throws IOException {
+
+ Document w3cDocument = null;
+
+ FileInputStream fis;
+
+ try {
+ fis = new FileInputStream(filename);
+ } catch (FileNotFoundException ex) {
+ ex.printStackTrace(writer_);
+ writer_.println(ex.getMessage());
+ return w3cDocument;
+ }
+
+ /** factory for DocumentBuilder objects */
+ DocumentBuilderFactory factory = null;
+ factory = DocumentBuilderFactory.newInstance();
+ factory.setNamespaceAware(true);
+ factory.setValidating(false);
+
+ /** DocumentBuilder object */
+ DocumentBuilder builder = null;
+
+ try {
+ builder = factory.newDocumentBuilder();
+ } catch (ParserConfigurationException ex) {
+ ex.printStackTrace(writer_);
+ writer_.println(ex.getMessage());
+ return null;
+ }
+
+
+ builder.setErrorHandler(
+ new org.xml.sax.ErrorHandler() {
+ // ignore fatal errors (an exception is guaranteed)
+ public void fatalError(SAXParseException e)
+ throws SAXException {
+ throw e;
+ }
+
+ public void error(SAXParseException e)
+ throws SAXParseException {
+ // make sure validation error is thrown.
+ throw e;
+ }
+
+ public void warning(SAXParseException e)
+ throws SAXParseException {
+ }
+ }
+ );
+
+ try {
+ w3cDocument = builder.parse(fis);
+ w3cDocument.getDocumentElement().normalize();
+ } catch (SAXException ex) {
+ ex.printStackTrace(writer_);
+ writer_.println(ex.getMessage());
+ return w3cDocument;
+ }
+
+ return w3cDocument;
+ }
+
+ private String [] parseTags(String tagsString) {
+ Vector tagsVector = new Vector();
+ if (tagsString.length() == 0)
+ return null;
+
+ int start = 0;
+ int end = 0;
+ // break the tag string into a vector of strings by words
+ for (end = tagsString.indexOf(" ", start);
+ end != -1 ;
+ start = end + 1, end = tagsString.indexOf(" ", start)) {
+ tagsVector.add(tagsString.substring(start,end));
+ }
+
+ tagsVector.add(tagsString.substring(start,tagsString.length()));
+
+ // convert the vector to array
+ String[] tags= new String[tagsVector.size()];
+ tagsVector.copyInto(tags);
+
+ return tags;
+ }
+
+
+ /**
+ * Set the output to the specified argument.
+ * This method is only used internally to prevent
+ * invalid string parameter.
+ *
+ * @param str output specifier
+ */
+ private static void setOutput(String str) {
+
+ if (writer_ == null) {
+
+ if (str.equals("System.out")) {
+
+ setOutput(System.out);
+
+ } else if (str.equals("System.err")) {
+
+ setOutput(System.err);
+
+ } else {
+
+ try {
+
+ setOutput(new FileWriter(str));
+
+ } catch (IOException e) {
+
+ e.printStackTrace(System.err);
+ }
+ }
+ }
+ }
+
+ /**
+ * Set the output to an OutputStream object.
+ *
+ * @param stream OutputStream object
+ */
+
+ private static void setOutput(OutputStream stream) {
+
+ setOutput(new OutputStreamWriter(stream));
+ }
+
+ /**
+ * Set the Writer object to manage the output.
+ *
+ * @param w Writer object to write out
+ */
+
+ private static void setOutput(Writer w) {
+
+ if (writer_ != null) {
+
+ writer_.close();
+ }
+
+ writer_ = new PrintWriter(new BufferedWriter(w), true);
+ }
+
+ public static void main(String args[]) throws IOException {
+
+ if (args.length != 0 && args.length != 2) {
+ System.out.println("Usage: XmlDiff [<file1> <file2>].");
+ return;
+ }
+
+ XmlDiff xmldiff = new XmlDiff();
+
+ boolean same = false;
+ if (args.length == 2) {
+ same = xmldiff.diff(args[0], args[1]);
+ } else {
+ same = xmldiff.diff();
+ }
+
+ System.out.println("Diff result: " + same);
+ }
+}
+
diff --git a/xmerge/workben/XmlDiff.properties b/xmerge/workben/XmlDiff.properties
new file mode 100644
index 000000000000..34483a5bd230
--- /dev/null
+++ b/xmerge/workben/XmlDiff.properties
@@ -0,0 +1,40 @@
+#*************************************************************************
+#
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# Copyright 2000, 2010 Oracle and/or its affiliates.
+#
+# OpenOffice.org - a multi-platform office productivity suite
+#
+# This file is part of OpenOffice.org.
+#
+# OpenOffice.org is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License version 3
+# only, as published by the Free Software Foundation.
+#
+# OpenOffice.org is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License version 3 for more details
+# (a copy is included in the LICENSE file that accompanied this code).
+#
+# You should have received a copy of the GNU Lesser General Public License
+# version 3 along with OpenOffice.org. If not, see
+# <http://www.openoffice.org/license.html>
+# for a copy of the LGPLv3 License.
+#
+#*************************************************************************
+# x-no-translate
+
+
+#
+# This properties file provides info for XmlDiff program
+# XmlDiff.file1 is the first input XML file
+# XmlDiff.file2 is the second input XML file
+# XmlDiff.output is where the output (err/message) go
+# XmlDiff.tags are what tagname should ignore (and the subtree under it)
+#
+XmlDiff.file1=test1.xml
+XmlDiff.file2=test2.xml
+XmlDiff.output=System.err
+XmlDiff.tags=
diff --git a/xmerge/workben/build.xml b/xmerge/workben/build.xml
new file mode 100644
index 000000000000..ed8da0ccb444
--- /dev/null
+++ b/xmerge/workben/build.xml
@@ -0,0 +1,128 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+
+ Copyright 2000, 2010 Oracle and/or its affiliates.
+
+ OpenOffice.org - a multi-platform office productivity suite
+
+ This file is part of OpenOffice.org.
+
+ OpenOffice.org is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License version 3
+ only, as published by the Free Software Foundation.
+
+ OpenOffice.org is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License version 3 for more details
+ (a copy is included in the LICENSE file that accompanied this code).
+
+ You should have received a copy of the GNU Lesser General Public License
+ version 3 along with OpenOffice.org. If not, see
+ <http://www.openoffice.org/license.html>
+ for a copy of the LGPLv3 License.
+
+-->
+<project name="xmrg_workben" default="main" basedir=".">
+
+ <!-- ================================================================= -->
+ <!-- settings -->
+ <!-- ================================================================= -->
+
+ <!-- project prefix, used for targets and build.lst -->
+ <property name="prj.prefix" value="xmrg"/>
+
+ <!-- name of this sub target used in recursive builds -->
+ <property name="target" value="xmrg_workben"/>
+
+ <!-- relative path to project directory -->
+ <property name="prj" value=".."/>
+
+ <!-- start of java source code package structure -->
+ <property name="java.dir" value="${prj}/workben"/>
+
+ <!-- path component for current java package -->
+ <property name="package" value="."/>
+
+ <!-- define how to handle CLASSPATH environment -->
+ <property name="build.sysclasspath" value="ignore"/>
+
+ <property environment="env"/>
+ <property name="env.XML_APIS_JAR" value="${solar.jar}/xml-apis.jar"/>
+ <property name="env.XERCES_JAR" value="${solar.jar}/xercesImpl.jar"/>
+
+ <!-- classpath settings for javac tasks -->
+ <path id="classpath">
+ <pathelement location="${build.class}"/>
+ <pathelement location="${env.XML_APIS_JAR}"/>
+ <pathelement location="${env.XERCES_JAR}"/>
+ </path>
+
+ <!-- set wether we want to compile with or without deprecation -->
+ <property name="deprecation" value="on"/>
+
+ <!-- ================================================================= -->
+ <!-- solar build environment targets -->
+ <!-- ================================================================= -->
+
+ <target name="build_dir" unless="build.dir">
+ <property name="build.dir" value="${out}"/>
+ </target>
+
+ <target name="solar" depends="build_dir" if="solar.update">
+ <property name="solar.properties"
+ value="${solar.bin}/solar.properties"/>
+ </target>
+
+ <target name="init" depends="solar">
+ <property name="build.compiler" value="classic"/>
+ <property file="${solar.properties}"/>
+ <property file="${build.dir}/class/solar.properties"/>
+ </target>
+
+ <target name="info">
+ <echo message="--------------------"/>
+ <echo message="${target}"/>
+ <echo message="--------------------"/>
+ </target>
+
+
+ <!-- ================================================================= -->
+ <!-- custom targets -->
+ <!-- ================================================================= -->
+
+ <!-- the main target, called in recursive builds -->
+ <target name="main" depends="info,prepare,compile"/>
+
+ <!-- prepare output directories -->
+ <target name="prepare" depends="init" if="build.class">
+ <mkdir dir="${build.dir}"/>
+ <mkdir dir="${build.class}"/>
+ </target>
+
+ <!-- compile java sources in ${package} and sub packages -->
+ <target name="compile" depends="prepare" if="build.class">
+ <javac srcdir="${java.dir}"
+ destdir="${build.class}"
+ debug="${debug}"
+ deprecation="${deprecation}"
+ optimize="${optimize}">
+ <classpath refid="classpath"/>
+ <include name="XmlDiff.java"/>
+ </javac>
+ </target>
+
+ <!-- clean up -->
+ <target name="clean" depends="prepare">
+ <delete includeEmptyDirs="true">
+ <fileset dir="${build.class}">
+ <patternset>
+ <include name="${package}/**/*.class"/>
+ </patternset>
+ </fileset>
+ </delete>
+ </target>
+
+</project>
diff --git a/xmerge/workben/jstyle.pl b/xmerge/workben/jstyle.pl
new file mode 100644
index 000000000000..3c300c29a227
--- /dev/null
+++ b/xmerge/workben/jstyle.pl
@@ -0,0 +1,541 @@
+#!/bin/sh -- # This comment tells perl not to loop!
+#
+#***************************************************************************
+#
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# Copyright 2000, 2010 Oracle and/or its affiliates.
+#
+# OpenOffice.org - a multi-platform office productivity suite
+#
+# This file is part of OpenOffice.org.
+#
+# OpenOffice.org is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License version 3
+# only, as published by the Free Software Foundation.
+#
+# OpenOffice.org is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License version 3 for more details
+# (a copy is included in the LICENSE file that accompanied this code).
+#
+# You should have received a copy of the GNU Lesser General Public License
+# version 3 along with OpenOffice.org. If not, see
+# <http://www.openoffice.org/license.html>
+# for a copy of the LGPLv3 License.
+#
+#***************************************************************************
+
+
+eval 'exec perl -S $0 "$@"'
+if 0;
+#
+# @(#)jstyle 1.2 98/01/08
+#
+# jstyle - check for some common stylistic errors.
+#
+# jstyle is a sort of "lint" for Java coding style.
+#
+# There's a lot this can't check for, like proper
+# indentation of continuation lines. There's also
+# a lot more this could check for.
+#
+# A note to the non perl literate:
+#
+# perl regular expressions are pretty much like egrep
+# regular expressions, with the following special symbols
+#
+# \s any space character
+# \S any non-space character
+# \w any "word" character [a-zA-Z0-9_]
+# \W any non-word character
+# \d a digit [0-9]
+# \D a non-digit
+# \b word boundary (between \w and \W)
+# \B non-word boundary
+#
+#require "getopts.pl";
+# XXX - because some versions of perl can not find the lib directory,
+# we just include this here.
+;# getopts.pl - a better getopt.pl
+
+;# Usage:
+;# do Getopts("a:bc"); # -a takes arg. -b & -c not. Sets opt_* as a
+;# # side effect.
+
+sub Getopts {
+ local($argumentative) = @_;
+ local(@args,$_,$first,$rest);
+ local($[) = 0;
+ local($errs) = 0;
+
+ @args = split( / */, $argumentative );
+ while(($_ = $ARGV[0]) =~ /^-(.)(.*)/) {
+ ($first,$rest) = ($1,$2);
+ $pos = index($argumentative,$first);
+ if($pos >= $[) {
+ if($args[$pos+1] eq ":") {
+ shift(@ARGV);
+ if($rest eq "") {
+ $rest = shift(@ARGV);
+ }
+ eval "\$opt_$first = \$rest;";
+ }
+ else {
+ eval "\$opt_$first = 1";
+ if($rest eq "") {
+ shift(@ARGV);
+ }
+ else {
+ $ARGV[0] = "-$rest";
+ }
+ }
+ }
+ else {
+ print STDERR "Unknown option: $first\n";
+ ++$errs;
+ if($rest ne "") {
+ $ARGV[0] = "-$rest";
+ }
+ else {
+ shift(@ARGV);
+ }
+ }
+ }
+ $errs == 0;
+}
+
+1;
+# end of getopts.pl
+
+$usage =
+"usage: jstyle [-c] [-h] [-p] [-s] [-t] [-v] [-C] file ...
+ -c check continuation line indenting
+ -h perform heuristic checks that are sometimes wrong
+ -p perform some of the more picky checks
+ -s check for spaces vs. tabs
+ -t insist on indenting by tabs
+ -v verbose
+ -C don't check anything in header block comments
+ -S print out overall statistics
+";
+
+if (!&Getopts("chpstvCS")) {
+ print $usage;
+ exit 1;
+}
+
+$check_continuation = $opt_c;
+$heuristic = $opt_h;
+$picky = $opt_p;
+$spaces = $opt_s;
+$tabs = $opt_t;
+$verbose = $opt_v;
+$ignore_hdr_comment = $opt_C;
+$statistics = $opt_S;
+
+if ($verbose) {
+ $fmt = "%s: %d: %s\n%s\n";
+} else {
+ $fmt = "%s: %d: %s\n";
+}
+
+# Note, following must be in single quotes so that \s and \w work right.
+$typename = '(int|char|boolean|byte|short|long|float|double)';
+
+if ($#ARGV >= 0) {
+ foreach $arg (@ARGV) {
+ if (!open(STDIN, $arg)) {
+ printf "%s: can not open\n", $arg;
+ } else {
+ &jstyle($arg);
+ close STDIN;
+ }
+ }
+} else {
+ &jstyle("<stdin>");
+}
+
+if ($statistics != 0) {
+ foreach $key (sort(keys %errcount)) {
+ printf "%6d %s\n", $errcount{$key}, $key;
+ }
+ printf " -----\n";
+ printf "%6d Total warnings\n", $tot_errcount;
+ printf "%6d Lines of code\n", $totlines;
+}
+
+sub err {
+ if ($statistics == 0) {
+ printf $fmt, $filename, $., $_[0], $line;
+ } else {
+ $msg = $_[0];
+ $msg =~ s/ \([0-9][0-9]*\)$//;
+ $errcount{$msg} += 1;
+ $tot_errcount += 1;
+ }
+}
+
+sub jstyle {
+
+$in_comment = 0;
+$in_header_comment = 0;
+$in_continuation = 0;
+$in_class = 0;
+$in_declaration = 0;
+$note_level = 0;
+$nextok = 0;
+$nocheck = 0;
+$expect_continuation = 0;
+$prev = '';
+
+$filename = $_[0];
+
+line: while (<STDIN>) {
+ ++$totlines;
+ s/\r?\n$//; # strip return and newline
+
+ # save the original line, then remove all text from within
+ # double or single quotes, we do not want to check such text.
+
+ $line = $_;
+ s/"[^"]*"/\"\"/g;
+ s/'.'/''/g;
+
+ # an /* END JSTYLED */ comment ends a no-check block.
+ if ($nocheck) {
+ if (/\/\* *END *JSTYLED *\*\//) {
+ $nocheck = 0;
+ } else {
+ next line;
+ }
+ }
+
+ # a /*JSTYLED*/ comment indicates that the next line is ok.
+ if ($nextok) {
+ if ($okmsg) {
+ do err($okmsg);
+ }
+ $nextok = 0;
+ $okmsg = 0;
+ if (/\/\* *JSTYLED.*\*\//) {
+ /^.*\/\* *JSTYLED *(.*) *\*\/.*$/;
+ $okmsg = $1;
+ $nextok = 1;
+ }
+ $prev = $line;
+ next line;
+ }
+
+ # check length of line.
+ # first, a quick check to see if there is any chance of being too long.
+ if ($line =~ tr/\t/\t/ * 7 + length($line) > 100) {
+ # yes, there is a chance.
+ # replace tabs with spaces and check again.
+ $eline = $line;
+ 1 while $eline =~
+ s/\t+/' ' x (length($&) * 8 - length($`) % 8)/e;
+ $l = length($eline);
+ if (length($eline) > 100) {
+ do err("line > 100 characters ($l)");
+ }
+ }
+# this is the fastest way to check line length,
+# but it doesnt work with perl 3.0.
+# if ($line =~ tr/\t/\t/ * 7 + length($line) > 80) {
+# $pos = $oldp = $p = 0;
+# while (($p = index($line, "\t", $p)) >= 0) {
+# $pos = ($pos + $p - $oldp + 8) & ~7;
+# $oldp = ++$p;
+# }
+# $pos += length($line) - $oldp;
+# if ($pos > 80) {
+# do err("line > 80 characters");
+# }
+# }
+
+ # remember whether we expect to be inside a continuation line.
+ $in_continuation = $expect_continuation;
+
+ # check for proper continuation line. blank lines
+ # in the middle of the
+ # continuation do not count.
+ # XXX - only check within functions.
+ if ($check_continuation && $expect_continuation && $in_class &&
+ !/^\s*$/) {
+ # continuation line must start with whitespace of
+ # previous line, plus either 4 spaces or a tab, but
+ # do not check lines that start with a string constant
+ # since they are often shifted to the left to make them
+ # fit on the line.
+ if (!/^$continuation_indent \S/ &&
+ !/^$continuation_indent\t\S/ && !/^\s*"/) {
+ do err("continuation line improperly indented");
+ }
+ $expect_continuation = 0;
+ }
+
+ # a /* BEGIN JSTYLED */ comment starts a no-check block.
+ if (/\/\* *BEGIN *JSTYLED *\*\//) {
+ $nocheck = 1;
+ }
+
+ # a /*JSTYLED*/ comment indicates that the next line is ok.
+ if (/\/\* *JSTYLED.*\*\//) {
+ /^.*\/\* *JSTYLED *(.*) *\*\/.*$/;
+ $okmsg = $1;
+ $nextok = 1;
+ }
+ if (/\/\/ *JSTYLED/) {
+ /^.*\/\/ *JSTYLED *(.*)$/;
+ $okmsg = $1;
+ $nextok = 1;
+ }
+
+ # is this the beginning or ending of a class?
+ if (/^(public\s+)*\w(class|interface)\s/) {
+ $in_class = 1;
+ $in_declaration = 1;
+ $prev = $line;
+ next line;
+ }
+ if (/^}\s*(\/\*.*\*\/\s*)*$/) {
+ $in_class = 0;
+ $prev = $line;
+ next line;
+ }
+
+ if (!$spaces) {
+ # strip trailing spaces
+ s/\s*$//;
+ }
+
+ # does this looks like the start of a block comment?
+ if (/^\s*\/\*(\*|)$/) {
+ if (!/^(\t| )*\/\*(\*|)$/) {
+ do err("block comment not indented properly");
+ }
+ $in_comment = 1;
+ s/\/\*(\*|)/ /;
+ $comment_prefix = $_;
+ if ($comment_prefix eq " ") {
+ $in_header_comment = 1;
+ }
+ $prev = $line;
+ next line;
+ }
+ if (/^\s*\/\*./ && !/^\s*\/\*\*$/ && !/^\s*\/\*.*\*\//) {
+ do err("improper first line of block comment");
+ # it's a bad one, but it still is one.
+ # avoid ripple effect of not recognizing this.
+ if (!/^(\t| )*\/\*(\*|)/) {
+ do err("block comment not indented properly");
+ }
+ $in_comment = 1;
+ s/\/\*.*/ /;
+ $comment_prefix = $_;
+ if ($comment_prefix eq " ") {
+ $in_header_comment = 1;
+ }
+ $prev = $line;
+ next line;
+ }
+ # are we still in the block comment?
+ if ($in_comment && !/^$comment_prefix\*/) {
+ # assume out of comment
+ $in_comment = 0;
+ $in_header_comment = 0;
+ }
+
+ if ($in_header_comment && $ignore_hdr_comment) {
+ $prev = $line;
+ next line;
+ }
+
+ # check for errors that might occur in comments and in code.
+
+ # allow spaces to be used to draw pictures in header comments.
+ if ($spaces && /[^ ] / && !/".* .*"/ && !$in_header_comment) {
+ do err("spaces instead of tabs");
+ }
+ if ($tabs && /^ / && !/^ \*[ \t\/]/ && !/^ \*$/ &&
+ (!/^ \w/ || $in_class != 0)) {
+ do err("indent by spaces instead of tabs");
+ }
+ if (!$in_comment && (/^(\t )* {1,3}\S/ || /^(\t )* {5,7}\S/) &&
+ !(/^\s*[-+|&\/?:=]/ || ($prev =~ /,\s*$/))) {
+ do err("indent not a multiple of 4");
+ }
+ if ($spaces && /\s$/) {
+ do err("space or tab at end of line");
+ }
+if (0) {
+ if (/^[\t]+ [^ \t\*]/ || /^[\t]+ \S/ || /^[\t]+ \S/) {
+ do err("continuation line not indented by 4 spaces");
+ }
+}
+ if (/[^ \t(]\/\*/ && !/\w\(\/\*.*\*\/\);/) {
+ do err("comment preceded by non-blank");
+ }
+ if ($spaces && /\t[ ]+\t/) {
+ do err("spaces between tabs");
+ }
+ if ($spaces && / [\t]+ /) {
+ do err("tabs between spaces");
+ }
+
+ if ($in_comment) { # still in comment
+ $prev = $line;
+ next line;
+ }
+
+ if ((/\/\*\S/ && !/\/\*\*/) || /\/\*\*\S/) {
+ do err("missing blank after open comment");
+ }
+ if (/\S\*\//) {
+ do err("missing blank before close comment");
+ }
+ # allow // at beginnging of line, often used to comment out code
+ if (/.\/\/\S/) { # C++ comments
+ do err("missing blank after start comment");
+ }
+ # check for unterminated single line comments.
+ if (/\S.*\/\*/ && !/\S.*\/\*.*\*\//) {
+ do err("unterminated single line comment");
+ }
+
+ # delete any comments and check everything else.
+ s/\/\*.*\*\///g;
+ s/\/\/.*$//; # C++ comments
+
+ # delete any trailing whitespace; we have already checked for that.
+ s/\s*$//;
+
+ # following checks do not apply to text in comments.
+
+ # if it looks like an operator at the end of the line, and it is
+ # not really the end of a comment (...*/), and it is not really
+ # a label (done:), and it is not a case label (case FOO:),
+ # or we are not in a function definition (ANSI C style) and the
+ # operator is a "," (to avoid hitting "int\nfoo(\n\tint i,\n\tint j)"),
+ # or we are in a function and the operator is a
+ # "*" (to avoid hitting on "char*\nfunc()").
+ if ((/[-+|&\/?:=]$/ && !/\*\/$/ && !/^\s*\w*:$/ &&
+ !/^\s\s*case\s\s*\w*:$/) ||
+ /,$/ ||
+ ($in_class && /\*$/)) {
+ $expect_continuation = 1;
+ if (!$in_continuation) {
+ /^(\s*)\S/;
+ $continuation_indent = $1;
+ }
+ }
+ if (/[^<>\s][!<>=]=/ || /[^<>][!<>=]=\S/ ||
+ (/[^->]>[^=>\s]/ && !/[^->]>$/) || (/[^<]<[^=<\s]/ && !/[^<]<$/) ||
+ /[^<\s]<[^<]/ || /[^->\s]>[^>]/) {
+ do err("missing space around relational operator");
+ }
+ if (/\S>>=/ || /\S<<=/ || />>=\S/ || /<<=\S/ || /\S[-+*\/&|^%]=/ ||
+ (/[^-+*\/&|^%!<>=\s]=[^=]/ && !/[^-+*\/&|^%!<>=\s]=$/) ||
+ (/[^!<>=]=[^=\s]/ && !/[^!<>=]=$/)) {
+ do err("missing space around assignment operator");
+ }
+ if (/[,;]\S/ && !/\bfor \(;;\)/) {
+ do err("comma or semicolon followed by non-blank");
+ }
+ # allow "for" statements to have empty "while" clauses
+ if (/\s[,;]/ && !/^[\t]+;$/ && !/^\s*for \([^;]*; ;[^;]*\)/) {
+ do err("comma or semicolon preceded by blank");
+ }
+if (0) {
+ if (/^\s*(&&|\|\|)/) {
+ do err("improper boolean continuation");
+ }
+}
+ if ($picky && /\S *(&&|\|\|)/ || /(&&|\|\|) *\S/) {
+ do err("more than one space around boolean operator");
+ }
+ if (/\b(for|if|while|switch|return|case|catch|synchronized)\(/) {
+ do err("missing space between keyword and paren");
+ }
+ if (/(\b(for|if|while|switch|return|catch|synchronized)\b.*){2,}/) {
+ # multiple "case" allowed
+ do err("more than one keyword on line");
+ }
+ if (/\b(for|if|while|switch|return|case|catch|synchronized)\s\s+\(/ &&
+ !/^#if\s+\(/) {
+ do err("extra space between keyword and paren");
+ }
+ # try to detect "func (x)" but not "if (x)" or
+ # "int (*func)();"
+ if (/\w\s\(/) {
+ $s = $_;
+ # strip off all keywords on the line
+ s/\b(for|if|while|switch|return|case|catch|synchronized)\s\(/XXX(/g;
+ #s/\b($typename|void)\s+\(+/XXX(/og;
+ if (/\w\s\(/) {
+ do err("extra space between function name and left paren");
+ }
+ $_ = $s;
+ }
+ if (/\(\s/) {
+ do err("whitespace after left paren");
+ }
+ # allow "for" statements to have empty "continue" clauses
+ if (/\s\)/ && !/^\s*for \([^;]*;[^;]*; \)/) {
+ do err("whitespace before right paren");
+ }
+ if (/^\s*\(void\)[^ ]/) {
+ do err("missing space after (void) cast");
+ }
+ if (/\S{/ && !/{{/) {
+ do err("missing space before left brace");
+ }
+ if ($in_class && /^\s+{/ && ($prev =~ /\)\s*$/)) {
+ do err("left brace starting a line");
+ }
+ if (/}(else|while)/) {
+ do err("missing space after right brace");
+ }
+ if (/}\s\s+(else|while)/) {
+ do err("extra space after right brace");
+ }
+ if (/\b$typename\*/o) {
+ do err("missing space between type name and *");
+ }
+ if ($heuristic) {
+ # cannot check this everywhere due to "struct {\n...\n} foo;"
+ if ($in_class && !$in_declaration &&
+ /}./ && !/}\s+=/ && !/{.*}[;,]$/ && !/}(\s|)*$/ &&
+ !/} (else|while)/ && !/}}/) {
+ do err("possible bad text following right brace");
+ }
+ # cannot check this because sub-blocks in
+ # the middle of code are ok
+ if ($in_class && /^\s+{/) {
+ do err("possible left brace starting a line");
+ }
+ }
+ if (/^\s*else\W/) {
+ if ($prev =~ /^\s*}$/) {
+ $str = "else and right brace should be on same line";
+ if ($statistics == 0) {
+ printf $fmt, $filename, $., $str, $prev;
+ if ($verbose) {
+ printf "%s\n", $line;
+ }
+ } else {
+ $errcount{$str} += 1;
+ $tot_errcount += 1;
+ }
+ }
+ }
+ $prev = $line;
+}
+
+if ($picky && $prev eq "") {
+ do err("last line in file is blank");
+}
+
+}
diff --git a/xmerge/workben/makefile.mk b/xmerge/workben/makefile.mk
new file mode 100644
index 000000000000..b3acd7240f57
--- /dev/null
+++ b/xmerge/workben/makefile.mk
@@ -0,0 +1,32 @@
+#***************************************************************************
+#
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# Copyright 2000, 2010 Oracle and/or its affiliates.
+#
+# OpenOffice.org - a multi-platform office productivity suite
+#
+# This file is part of OpenOffice.org.
+#
+# OpenOffice.org is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License version 3
+# only, as published by the Free Software Foundation.
+#
+# OpenOffice.org is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License version 3 for more details
+# (a copy is included in the LICENSE file that accompanied this code).
+#
+# You should have received a copy of the GNU Lesser General Public License
+# version 3 along with OpenOffice.org. If not, see
+# <http://www.openoffice.org/license.html>
+# for a copy of the LGPLv3 License.
+#
+#***************************************************************************
+
+TARGET=xmrg_workben
+PRJ=..
+
+.INCLUDE : ant.mk
+ALLTAR: ANTBUILD