Kaydet (Commit) 0129c2cd authored tarafından Miklos Vajna's avatar Miklos Vajna

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.

Change-Id: I4085e4dba24475e6fd555e5f34fe7ad0f305c57d
Reviewed-on: https://gerrit.libreoffice.org/38504Reviewed-by: 's avatarMiklos Vajna <vmiklos@collabora.co.uk>
Tested-by: 's avatarJenkins <ci@libreoffice.org>
üst 57bdb067
......@@ -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.
......
......@@ -163,14 +163,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" );
......
......@@ -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" );
......
......@@ -1287,51 +1287,30 @@ void DocxExport::WriteVBA()
m_pFilter->addRelation(m_pDocumentFS->getOutputStream(), "http://schemas.microsoft.com/office/2006/relationships/vbaProject", "vbaProject.bin");
}
uno::Reference<beans::XPropertySet> xPropertySet(m_pDoc->GetDocShell()->GetBaseModel(), uno::UNO_QUERY);
if (!xPropertySet.is())
OUString aDataName("_MS_VBA_Macros_XML");
if (!xDocumentStorage.is() || !xDocumentStorage->hasByName(aDataName))
return;
uno::Reference<beans::XPropertySetInfo> xPropertySetInfo = xPropertySet->getPropertySetInfo();
if (!xPropertySetInfo->hasPropertyByName(UNO_NAME_MISC_OBJ_INTEROPGRABBAG))
return;
uno::Sequence<beans::PropertyValue> aGrabBag;
xPropertySet->getPropertyValue(UNO_NAME_MISC_OBJ_INTEROPGRABBAG) >>= aGrabBag;
uno::Sequence<beans::PropertyValue> aVBA;
for (const auto& rProperty : aGrabBag)
uno::Reference<io::XStream> xDataStream(xDocumentStorage->openStreamElement(aDataName, nOpenMode), uno::UNO_QUERY);
if (xDataStream.is())
{
if (rProperty.Name == "OOXVBA")
rProperty.Value >>= aVBA;
}
if (!aVBA.hasElements())
return;
// Then the data stream, which wants to work with an already set
// xProjectStream.
std::unique_ptr<SvStream> pIn(utl::UcbStreamHelper::CreateStream(xDataStream));
for (const auto& rProperty : aVBA)
{
if (rProperty.Name == "DataStream")
{
// Then the data stream, which wants to work with an already set
// xProjectStream.
uno::Reference<io::XStream> xInputStream;
rProperty.Value >>= xInputStream;
if (!xInputStream.is())
return;
std::unique_ptr<SvStream> pIn(utl::UcbStreamHelper::CreateStream(xInputStream));
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");
}
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");
}
}
......
......@@ -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 };
FOOTNOTES, ENDNOTES, COMMENTS, THEME, CUSTOMXML, CUSTOMXMLPROPS, ACTIVEX, ACTIVEXBIN, GLOSSARY, CHARTS, EMBEDDINGS, SETTINGS, VBAPROJECT, FOOTER, HEADER, VBADATA };
typedef std::shared_ptr<OOXMLStream> Pointer_t;
virtual ~OOXMLStream() {}
......@@ -229,7 +229,6 @@ public:
virtual css::uno::Sequence<css::uno::Reference<css::xml::dom::XDocument> > getActiveXDomList( ) = 0;
virtual css::uno::Sequence<css::uno::Reference<css::io::XInputStream> > getActiveXBinList() = 0;
virtual css::uno::Sequence<css::beans::PropertyValue > getEmbeddingsList() = 0;
virtual css::uno::Sequence<css::beans::PropertyValue > getVBA() = 0;
};
......
......@@ -236,9 +236,6 @@ sal_Bool WriterFilter::filter(const uno::Sequence< beans::PropertyValue >& aDesc
// Adding the saved embedding document to document's grab bag
aGrabBagProperties["OOXEmbeddings"] <<= pDocument->getEmbeddingsList();
if (pDocument->getVBA().hasElements())
aGrabBagProperties["OOXVBA"] <<= pDocument->getVBA();
putPropertiesToDocumentGrabBag(aGrabBagProperties);
writerfilter::ooxml::OOXMLStream::Pointer_t pVBAProjectStream(writerfilter::ooxml::OOXMLDocumentFactory::createStream(pDocStream, writerfilter::ooxml::OOXMLStream::VBAPROJECT));
......@@ -257,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();
......
......@@ -39,7 +39,6 @@
#include <svx/dialogs.hrc>
#include <comphelper/sequence.hxx>
#include <unotools/mediadescriptor.hxx>
#include <comphelper/propertysequence.hxx>
#include <iostream>
#include "sfx2/objsh.hxx"
......@@ -497,9 +496,6 @@ void OOXMLDocumentImpl::resolve(Stream & rStream)
resolveActiveXStream(rStream);
if (!mbIsSubstream)
preserveVBA();
resolveFastSubStream(rStream, OOXMLStream::FONTTABLE);
resolveFastSubStream(rStream, OOXMLStream::STYLES);
resolveFastSubStream(rStream, OOXMLStream::NUMBERING);
......@@ -811,71 +807,6 @@ void OOXMLDocumentImpl::resolveEmbeddingsStream(const OOXMLStream::Pointer_t& pS
mxEmbeddingsList = comphelper::containerToSequence(aEmbeddings);
}
namespace
{
/// Returns the target string for rType in xRelationshipAccess.
OUString getTypeTarget(const uno::Reference<embed::XRelationshipAccess>& xRelationshipAccess, const OUString& rType)
{
uno::Sequence< uno::Sequence<beans::StringPair> > aRelations = xRelationshipAccess->getAllRelationships();
for (const auto& rRelation : aRelations)
{
OUString aType;
OUString aTarget;
for (const auto& rPair : rRelation)
{
if (rPair.First == "Type")
aType = rPair.Second;
else if (rPair.First == "Target")
aTarget = rPair.Second;
}
if (aType == rType)
return aTarget;
}
return OUString();
}
}
void OOXMLDocumentImpl::preserveVBA()
{
auto pOOXMLStream = dynamic_cast<OOXMLStreamImpl*>(mpStream.get());
if (!pOOXMLStream)
return;
uno::Reference<embed::XRelationshipAccess> xRelationshipAccess(pOOXMLStream->accessDocumentStream(), uno::UNO_QUERY);
if (!xRelationshipAccess.is())
return;
OUString aVBAStreamName = getTypeTarget(xRelationshipAccess, "http://schemas.microsoft.com/office/2006/relationships/vbaProject");
if (aVBAStreamName.isEmpty())
return;
uno::Reference<embed::XHierarchicalStorageAccess> xStorage(pOOXMLStream->getStorage(), uno::UNO_QUERY);
if (!xStorage.is())
return;
OUString aPath = pOOXMLStream->getPath();
uno::Reference<io::XStream> xStream(xStorage->openStreamElementByHierarchicalName(aPath + aVBAStreamName, embed::ElementModes::SEEKABLEREAD), uno::UNO_QUERY);
if (!xStream.is())
return;
xRelationshipAccess.set(xStream, uno::UNO_QUERY);
uno::Reference<io::XStream> xDataStream;
if (xRelationshipAccess.is())
{
// Check if there is a vbaData.xml for the vbaProject.bin.
OUString aVBAData = getTypeTarget(xRelationshipAccess, "http://schemas.microsoft.com/office/2006/relationships/wordVbaData");
if (!aVBAData.isEmpty())
xDataStream.set(xStorage->openStreamElementByHierarchicalName(aPath + aVBAData, embed::ElementModes::SEEKABLEREAD), uno::UNO_QUERY);
}
maVBA = comphelper::InitPropertySequence(
{
{"DataStream", uno::makeAny(xDataStream)}
});
}
void OOXMLDocumentImpl::resolveActiveXStream(Stream & rStream)
{
// Resolving all ActiveX[n].xml files from ActiveX folder.
......@@ -1015,11 +946,6 @@ uno::Sequence<beans::PropertyValue > OOXMLDocumentImpl::getEmbeddingsList( )
return mxEmbeddingsList;
}
uno::Sequence<beans::PropertyValue> OOXMLDocumentImpl::getVBA()
{
return maVBA;
}
OOXMLDocument *
OOXMLDocumentFactory::createDocument
(const OOXMLStream::Pointer_t& pStream,
......
......@@ -54,8 +54,6 @@ class OOXMLDocumentImpl : public OOXMLDocument
css::uno::Reference<css::io::XInputStream> mxEmbeddings;
css::uno::Sequence < css::beans::PropertyValue > mxEmbeddingsList;
std::vector<css::beans::PropertyValue> aEmbeddings;
/// List of VBA-related streams.
css::uno::Sequence<css::beans::PropertyValue> maVBA;
bool mbIsSubstream;
bool mbSkipImages;
/// How many paragraphs equal to 1 percent?
......@@ -94,7 +92,6 @@ protected:
void resolveActiveXStream(Stream & rStream);
void resolveGlossaryStream(Stream & rStream);
void resolveEmbeddingsStream(const OOXMLStream::Pointer_t& pStream);
void preserveVBA();
public:
OOXMLDocumentImpl(OOXMLStream::Pointer_t const & pStream, const css::uno::Reference<css::task::XStatusIndicator>& xStatusIndicator, bool bSkipImages, const css::uno::Sequence<css::beans::PropertyValue>& rDescriptor);
virtual ~OOXMLDocumentImpl() override;
......@@ -140,7 +137,6 @@ public:
virtual css::uno::Reference<css::xml::dom::XDocument> getGlossaryDocDom() override;
virtual css::uno::Sequence<css::uno::Sequence< css::uno::Any> > getGlossaryDomList() override;
virtual css::uno::Sequence<css::beans::PropertyValue > getEmbeddingsList() override;
virtual css::uno::Sequence<css::beans::PropertyValue> getVBA() override;
void incrementProgress();
bool IsSkipImages() { return mbSkipImages; };
......
......@@ -172,6 +172,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;
......@@ -182,6 +183,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;
......@@ -416,8 +421,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;
}
......
......@@ -80,9 +80,6 @@ public:
// Giving access to mxDocumentStream. It is needed by resolving custom xml to get list of customxml's used in document.
const css::uno::Reference<css::io::XStream>& accessDocumentStream() { return mxDocumentStream;}
const css::uno::Reference<css::embed::XStorage>& getStorage() { return mxStorage; }
const OUString& getPath() { return msPath; }
};
}}
#endif // INCLUDED_WRITERFILTER_SOURCE_OOXML_OOXMLSTREAMIMPL_HXX
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment