diff options
author | Miklos Vajna <vmiklos@collabora.co.uk> | 2017-06-02 18:41:38 +0200 |
---|---|---|
committer | Andras Timar <andras.timar@collabora.com> | 2017-06-23 16:59:20 +0200 |
commit | 748ebf9573096d31a59cdbf5d1e65340d1d55cfa (patch) | |
tree | 0d71abae026686dc4fd9160a0b17244e98394eb4 | |
parent | de2d6e773212c983dc190d1d29d005de87df6ffd (diff) |
Related: tdf#108269 DOCM filter: preserve VBA stream
This is a combination of 3 commits (initial support, then two refactor
commits to not duplicate code.)
1st commit:
This means 2 new streams when roundtripping DOCM files that actually
have macros: word/vbaProject.bin and word/vbaData.xml (+ the relation
pointing to the second from the first).
Reviewed-on: https://gerrit.libreoffice.org/38360
Tested-by: Jenkins <ci@libreoffice.org>
Reviewed-by: Miklos Vajna <vmiklos@collabora.co.uk>
(cherry picked from commit 8a59b30bb1af55f7afd8b98e4b60234f98d84c76)
Conflicts:
sw/qa/extras/ooxmlexport/ooxmlexport9.cxx
Change-Id: Iba24eea4c5bca8f743a53027c71ed2aae48f1934
2nd commit:
Related: tdf#108269 DOCM filter: reuse oox code for VBA preservation
With this, the project stream import is shared between DOCM and XLSM.
Change-Id: I8fbffefc5acf28adea4875fa6bc4148a99b5ebef
Reviewed-on: https://gerrit.libreoffice.org/38495
Reviewed-by: Miklos Vajna <vmiklos@collabora.co.uk>
Tested-by: Jenkins <ci@libreoffice.org>
(cherry picked from commit e4adb8d9e77bab353dda26375e11a6b7a456368f)
3rd commit:
Related: tdf#108269 DOCM filter: reuse oox code for VBA data preservation
Which means the DOCM-specific code to roundtrip VBA things (project,
data) can be removed. The oox part has to be extended a bit, as at least
for this DOCM bugdoc there is an XML relation of the binary data, while
existing shared code assumed the full VBA project is just a single OLE
blob.
Reviewed-on: https://gerrit.libreoffice.org/38504
Reviewed-by: Miklos Vajna <vmiklos@collabora.co.uk>
Tested-by: Jenkins <ci@libreoffice.org>
(cherry picked from commit 0129c2cd9dd95355412b194c595f4b986403ba1e)
Conflicts:
writerfilter/inc/ooxml/OOXMLDocument.hxx
writerfilter/source/ooxml/OOXMLDocumentImpl.hxx
Change-Id: I4085e4dba24475e6fd555e5f34fe7ad0f305c57d
Reviewed-on: https://gerrit.libreoffice.org/38558
Reviewed-by: Andras Timar <andras.timar@collabora.com>
Tested-by: Andras Timar <andras.timar@collabora.com>
-rw-r--r-- | include/oox/ole/vbaproject.hxx | 4 | ||||
-rw-r--r-- | oox/source/core/filterdetect.cxx | 9 | ||||
-rw-r--r-- | oox/source/ole/vbaproject.cxx | 14 | ||||
-rw-r--r-- | sw/qa/extras/ooxmlexport/data/tdf108269.docm | bin | 0 -> 20187 bytes | |||
-rw-r--r-- | sw/qa/extras/ooxmlexport/ooxmlexport9.cxx | 12 | ||||
-rw-r--r-- | sw/source/filter/ww8/docxexport.cxx | 63 | ||||
-rw-r--r-- | sw/source/filter/ww8/docxexport.hxx | 3 | ||||
-rw-r--r-- | writerfilter/inc/ooxml/OOXMLDocument.hxx | 2 | ||||
-rw-r--r-- | writerfilter/source/filter/WriterFilter.cxx | 8 | ||||
-rw-r--r-- | writerfilter/source/ooxml/OOXMLStreamImpl.cxx | 23 |
10 files changed, 127 insertions, 11 deletions
diff --git a/include/oox/ole/vbaproject.hxx b/include/oox/ole/vbaproject.hxx index c29a8eaa2ce0..e48d19a87959 100644 --- a/include/oox/ole/vbaproject.hxx +++ b/include/oox/ole/vbaproject.hxx @@ -37,6 +37,7 @@ namespace com { namespace sun { namespace star { namespace script { namespace vba { class XVBAMacroResolver; } } namespace uno { class XComponentContext; } namespace uno { class XInterface; } + namespace io { class XInputStream; } } } } namespace oox { @@ -130,6 +131,9 @@ public: bool importVbaProject( StorageBase& rVbaPrjStrg ); + /// Imports VBA data for a VBA project, e.g. word/vbaData.xml. + void importVbaData(const css::uno::Reference<css::io::XInputStream>& xInputStream); + /** Reads vba module related information from the project streams */ void readVbaModules( StorageBase& rVbaPrjStrg ); /** Imports (and creates) vba modules and user forms from the vba project records previously read. diff --git a/oox/source/core/filterdetect.cxx b/oox/source/core/filterdetect.cxx index 8812e0c30c25..88d3926a2656 100644 --- a/oox/source/core/filterdetect.cxx +++ b/oox/source/core/filterdetect.cxx @@ -172,14 +172,7 @@ void FilterDetectDocHandler::parseRelationship( const AttributeList& rAttribs ) OUString FilterDetectDocHandler::getFilterNameFromContentType( const OUString& rContentType, const OUString& rFileName ) { - bool bDocm = false; - OUString aDocmExtension = ".docm"; - if (rFileName.getLength() >= aDocmExtension.getLength()) - { - OUString aExtension = rFileName.copy(rFileName.getLength() - aDocmExtension.getLength()); - // The file name ends with .docm, ignoring case. - bDocm = aExtension.equalsIgnoreAsciiCase(aDocmExtension); - } + bool bDocm = rFileName.endsWithIgnoreAsciiCase(".docm"); if( rContentType == "application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml" && !bDocm ) return OUString( "writer_MS_Word_2007" ); diff --git a/oox/source/ole/vbaproject.cxx b/oox/source/ole/vbaproject.cxx index b520d652f8d6..029d946892bd 100644 --- a/oox/source/ole/vbaproject.cxx +++ b/oox/source/ole/vbaproject.cxx @@ -32,6 +32,7 @@ #include <com/sun/star/uno/XComponentContext.hpp> #include <comphelper/configurationhelper.hxx> #include <comphelper/string.hxx> +#include <comphelper/storagehelper.hxx> #include <osl/diagnose.h> #include <rtl/tencinfo.h> #include <rtl/ustrbuf.h> @@ -49,6 +50,7 @@ namespace oox { namespace ole { +using namespace ::com::sun::star; using namespace ::com::sun::star::container; using namespace ::com::sun::star::document; using namespace ::com::sun::star::embed; @@ -182,6 +184,18 @@ void VbaProject::importVbaProject( StorageBase& rVbaPrjStrg, const GraphicHelper } } +void VbaProject::importVbaData(const uno::Reference<io::XInputStream>& xInputStream) +{ + uno::Reference<document::XStorageBasedDocument> xStorageBasedDoc(mxDocModel, uno::UNO_QUERY); + uno::Reference<embed::XStorage> xDocStorage(xStorageBasedDoc->getDocumentStorage(), uno::UNO_QUERY); + { + const sal_Int32 nOpenMode = ElementModes::SEEKABLE | ElementModes::WRITE | ElementModes::TRUNCATE; + uno::Reference<io::XOutputStream> xDocStream(xDocStorage->openStreamElement("_MS_VBA_Macros_XML", nOpenMode), uno::UNO_QUERY); + comphelper::OStorageHelper::CopyInputToOutput(xInputStream, xDocStream); + } + uno::Reference<embed::XTransactedObject>(xDocStorage, uno::UNO_QUERY)->commit(); +} + void VbaProject::registerMacroAttacher( const VbaMacroAttacherRef& rxAttacher ) { OSL_ENSURE( rxAttacher.get(), "VbaProject::registerMacroAttacher - unexpected empty reference" ); diff --git a/sw/qa/extras/ooxmlexport/data/tdf108269.docm b/sw/qa/extras/ooxmlexport/data/tdf108269.docm Binary files differnew file mode 100644 index 000000000000..44e943531d30 --- /dev/null +++ b/sw/qa/extras/ooxmlexport/data/tdf108269.docm diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport9.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport9.cxx index ba0e5a207d21..aa73ed26ddad 100644 --- a/sw/qa/extras/ooxmlexport/ooxmlexport9.cxx +++ b/sw/qa/extras/ooxmlexport/ooxmlexport9.cxx @@ -90,6 +90,18 @@ DECLARE_SW_ROUNDTRIP_TEST(testBadDocm, "bad.docm", nullptr, DocmTest) CPPUNIT_ASSERT_EQUAL(OUString("MS Word 2007 XML VBA"), pTextDoc->GetDocShell()->GetMedium()->GetFilter()->GetName()); } +DECLARE_SW_ROUNDTRIP_TEST(testTdf108269, "tdf108269.docm", nullptr, DocmTest) +{ + if (!mbExported) + return; + + uno::Reference<packages::zip::XZipFileAccess2> xNameAccess = packages::zip::ZipFileAccess::createWithURL(comphelper::getComponentContext(m_xSFactory), maTempFile.GetURL()); + // This failed: VBA streams were not roundtripped via the doc-level + // grab-bag. + CPPUNIT_ASSERT(xNameAccess->hasByName("word/vbaProject.bin")); + CPPUNIT_ASSERT(xNameAccess->hasByName("word/vbaData.xml")); +} + DECLARE_OOXMLEXPORT_TEST(testTdf95031, "tdf95031.docx") { // This was 494, in-numbering paragraph's automating spacing was handled as visible spacing, while it should not. diff --git a/sw/source/filter/ww8/docxexport.cxx b/sw/source/filter/ww8/docxexport.cxx index b7cda742afb9..48b6e300ff92 100644 --- a/sw/source/filter/ww8/docxexport.cxx +++ b/sw/source/filter/ww8/docxexport.cxx @@ -24,6 +24,7 @@ #include <com/sun/star/document/XDocumentPropertiesSupplier.hpp> #include <com/sun/star/document/XDocumentProperties.hpp> +#include <com/sun/star/document/XStorageBasedDocument.hpp> #include <com/sun/star/drawing/XShape.hpp> #include <com/sun/star/i18n/ScriptType.hpp> #include <com/sun/star/frame/XModel.hpp> @@ -75,6 +76,7 @@ #include <comphelper/string.hxx> #include <rtl/ustrbuf.hxx> #include <vcl/font.hxx> +#include <unotools/ucbstreamhelper.hxx> using namespace sax_fastparser; using namespace ::comphelper; @@ -462,6 +464,8 @@ void DocxExport::ExportDocument_Impl() WriteEmbeddings(); + WriteVBA(); + m_aLinkedTextboxesHelper.clear(); //final cleanup delete m_pStyles; m_pStyles = nullptr; @@ -1247,6 +1251,65 @@ void DocxExport::WriteActiveX() } } +void DocxExport::WriteVBA() +{ + uno::Reference<document::XStorageBasedDocument> xStorageBasedDocument(m_pDoc->GetDocShell()->GetBaseModel(), uno::UNO_QUERY); + if (!xStorageBasedDocument.is()) + return; + + uno::Reference<embed::XStorage> xDocumentStorage(xStorageBasedDocument->getDocumentStorage(), uno::UNO_QUERY); + OUString aMacrosName("_MS_VBA_Macros"); + if (!xDocumentStorage.is() || !xDocumentStorage->hasByName(aMacrosName)) + return; + + const sal_Int32 nOpenMode = embed::ElementModes::READ; + uno::Reference<io::XStream> xMacrosStream(xDocumentStorage->openStreamElement(aMacrosName, nOpenMode), uno::UNO_QUERY); + uno::Reference<io::XOutputStream> xProjectStream; + if (xMacrosStream.is()) + { + // First handle the the project stream, this sets xProjectStream. + std::unique_ptr<SvStream> pIn(utl::UcbStreamHelper::CreateStream(xMacrosStream)); + + xProjectStream = GetFilter().openFragmentStream("word/vbaProject.bin", "application/vnd.ms-office.vbaProject"); + uno::Reference<io::XStream> xOutputStream(xProjectStream, uno::UNO_QUERY); + if (!xOutputStream.is()) + return; + std::unique_ptr<SvStream> pOut(utl::UcbStreamHelper::CreateStream(xOutputStream)); + + // Write the stream. + pOut->WriteStream(*pIn); + + // Write the relationship. + m_pFilter->addRelation(m_pDocumentFS->getOutputStream(), "http://schemas.microsoft.com/office/2006/relationships/vbaProject", "vbaProject.bin"); + } + + OUString aDataName("_MS_VBA_Macros_XML"); + if (!xDocumentStorage.is() || !xDocumentStorage->hasByName(aDataName)) + return; + + uno::Reference<io::XStream> xDataStream(xDocumentStorage->openStreamElement(aDataName, nOpenMode), uno::UNO_QUERY); + if (xDataStream.is()) + { + // Then the data stream, which wants to work with an already set + // xProjectStream. + std::unique_ptr<SvStream> pIn(utl::UcbStreamHelper::CreateStream(xDataStream)); + + uno::Reference<io::XStream> xOutputStream(GetFilter().openFragmentStream("word/vbaData.xml", "application/vnd.ms-word.vbaData+xml"), uno::UNO_QUERY); + if (!xOutputStream.is()) + return; + std::unique_ptr<SvStream> pOut(utl::UcbStreamHelper::CreateStream(xOutputStream)); + + // Write the stream. + pOut->WriteStream(*pIn); + + // Write the relationship. + if (!xProjectStream.is()) + return; + + m_pFilter->addRelation(xProjectStream, "http://schemas.microsoft.com/office/2006/relationships/wordVbaData", "vbaData.xml"); + } +} + void DocxExport::WriteEmbeddings() { uno::Reference< beans::XPropertySet > xPropSet( m_pDoc->GetDocShell()->GetBaseModel(), uno::UNO_QUERY_THROW ); diff --git a/sw/source/filter/ww8/docxexport.hxx b/sw/source/filter/ww8/docxexport.hxx index 65c9f9283730..3623c5718eeb 100644 --- a/sw/source/filter/ww8/docxexport.hxx +++ b/sw/source/filter/ww8/docxexport.hxx @@ -244,6 +244,9 @@ private: /// Write word/embeddings/Worksheet[n].xlsx void WriteEmbeddings(); + /// Writes word/vbaProject.bin. + void WriteVBA(); + /// return true if Page Layout is set as Mirrored bool isMirroredMargin(); diff --git a/writerfilter/inc/ooxml/OOXMLDocument.hxx b/writerfilter/inc/ooxml/OOXMLDocument.hxx index af060387d9a7..1b33336c8996 100644 --- a/writerfilter/inc/ooxml/OOXMLDocument.hxx +++ b/writerfilter/inc/ooxml/OOXMLDocument.hxx @@ -75,7 +75,7 @@ class OOXMLStream { public: enum StreamType_t { UNKNOWN, DOCUMENT, STYLES, WEBSETTINGS, FONTTABLE, NUMBERING, - FOOTNOTES, ENDNOTES, COMMENTS, THEME, CUSTOMXML, CUSTOMXMLPROPS, ACTIVEX, ACTIVEXBIN, GLOSSARY, CHARTS, EMBEDDINGS, SETTINGS, VBAPROJECT, FOOTER, HEADER, SIGNATURE }; + FOOTNOTES, ENDNOTES, COMMENTS, THEME, CUSTOMXML, CUSTOMXMLPROPS, ACTIVEX, ACTIVEXBIN, GLOSSARY, CHARTS, EMBEDDINGS, SETTINGS, VBAPROJECT, FOOTER, HEADER, SIGNATURE, VBADATA }; typedef std::shared_ptr<OOXMLStream> Pointer_t; virtual ~OOXMLStream() {} diff --git a/writerfilter/source/filter/WriterFilter.cxx b/writerfilter/source/filter/WriterFilter.cxx index b50a8f49743f..4a1ce7762e3c 100644 --- a/writerfilter/source/filter/WriterFilter.cxx +++ b/writerfilter/source/filter/WriterFilter.cxx @@ -254,6 +254,14 @@ sal_Bool WriterFilter::filter(const uno::Sequence< beans::PropertyValue >& aDesc oox::GraphicHelper gHelper(m_xContext, xFrame, xVbaPrjStrg); aVbaProject.importVbaProject(*xVbaPrjStrg, gHelper); + + writerfilter::ooxml::OOXMLStream::Pointer_t pVBADataStream(writerfilter::ooxml::OOXMLDocumentFactory::createStream(pDocStream, writerfilter::ooxml::OOXMLStream::VBADATA)); + if (pVBADataStream) + { + uno::Reference<io::XInputStream> xDataStream = pVBADataStream->getDocumentStream(); + if (xDataStream.is()) + aVbaProject.importVbaData(xDataStream); + } } pStream.reset(); diff --git a/writerfilter/source/ooxml/OOXMLStreamImpl.cxx b/writerfilter/source/ooxml/OOXMLStreamImpl.cxx index 16d7ae31100b..fe26b58cbe93 100644 --- a/writerfilter/source/ooxml/OOXMLStreamImpl.cxx +++ b/writerfilter/source/ooxml/OOXMLStreamImpl.cxx @@ -173,6 +173,7 @@ bool OOXMLStreamImpl::lcl_getTarget(const uno::Reference<embed::XRelationshipAcc static const char sHeaderTypeStrict[] = "http://purl.oclc.org/ooxml/officeDocument/relationships/header"; static const char sOleObjectTypeStrict[] = "http://purl.oclc.org/ooxml/officeDocument/relationships/oleObject"; static const char sVBAProjectType[] = "http://schemas.microsoft.com/office/2006/relationships/vbaProject"; + static const char sVBADataType[] = "http://schemas.microsoft.com/office/2006/relationships/wordVbaData"; OUString sStreamType; OUString sStreamTypeStrict; @@ -183,6 +184,10 @@ bool OOXMLStreamImpl::lcl_getTarget(const uno::Reference<embed::XRelationshipAcc sStreamType = sVBAProjectType; sStreamTypeStrict = sVBAProjectType; break; + case VBADATA: + sStreamType = sVBADataType; + sStreamTypeStrict = sVBADataType; + break; case DOCUMENT: sStreamType = sDocumentType; sStreamTypeStrict = sDocumentTypeStrict; @@ -420,8 +425,22 @@ OOXMLDocumentFactory::createStream (const OOXMLStream::Pointer_t& pStream, OOXMLStream::StreamType_t nStreamType) { OOXMLStream::Pointer_t pRet; - if (OOXMLStreamImpl* pImpl = dynamic_cast<OOXMLStreamImpl *>(pStream.get())) - pRet.reset(new OOXMLStreamImpl(*pImpl, nStreamType)); + + if (nStreamType != OOXMLStream::VBADATA) + { + if (OOXMLStreamImpl* pImpl = dynamic_cast<OOXMLStreamImpl *>(pStream.get())) + pRet.reset(new OOXMLStreamImpl(*pImpl, nStreamType)); + } + else + { + // VBADATA is not a relation of the document, but of the VBAPROJECT stream. + if (OOXMLStreamImpl* pImpl = dynamic_cast<OOXMLStreamImpl *>(pStream.get())) + { + std::unique_ptr<OOXMLStreamImpl> pProject(new OOXMLStreamImpl(*pImpl, OOXMLStream::VBAPROJECT)); + pRet.reset(new OOXMLStreamImpl(*pProject, OOXMLStream::VBADATA)); + } + } + return pRet; } |