summaryrefslogtreecommitdiffstats
path: root/writerfilter/source/ooxml/OOXMLStreamImpl.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'writerfilter/source/ooxml/OOXMLStreamImpl.cxx')
-rw-r--r--writerfilter/source/ooxml/OOXMLStreamImpl.cxx448
1 files changed, 448 insertions, 0 deletions
diff --git a/writerfilter/source/ooxml/OOXMLStreamImpl.cxx b/writerfilter/source/ooxml/OOXMLStreamImpl.cxx
new file mode 100644
index 000000000..1cfd48139
--- /dev/null
+++ b/writerfilter/source/ooxml/OOXMLStreamImpl.cxx
@@ -0,0 +1,448 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "OOXMLStreamImpl.hxx"
+#include <oox/core/fasttokenhandler.hxx>
+
+#include <com/sun/star/embed/XHierarchicalStorageAccess.hpp>
+#include <com/sun/star/uri/UriReferenceFactory.hpp>
+#include <comphelper/storagehelper.hxx>
+
+namespace writerfilter::ooxml
+{
+
+using namespace com::sun::star;
+
+OOXMLStreamImpl::OOXMLStreamImpl
+(uno::Reference<uno::XComponentContext> const & xContext,
+ uno::Reference<io::XInputStream> const & xStorageStream,
+ StreamType_t nType, bool bRepairStorage)
+: mxContext(xContext), mxStorageStream(xStorageStream), mnStreamType(nType)
+{
+ mxStorage.set
+ (comphelper::OStorageHelper::GetStorageOfFormatFromInputStream
+ (OFOPXML_STORAGE_FORMAT_STRING, mxStorageStream, xContext, bRepairStorage));
+ mxRelationshipAccess.set(mxStorage, uno::UNO_QUERY_THROW);
+
+ init();
+}
+
+OOXMLStreamImpl::OOXMLStreamImpl
+(OOXMLStreamImpl const & rOOXMLStream, StreamType_t nStreamType)
+: mxContext(rOOXMLStream.mxContext),
+ mxStorageStream(rOOXMLStream.mxStorageStream),
+ mxStorage(rOOXMLStream.mxStorage),
+ mnStreamType(nStreamType),
+ msPath(rOOXMLStream.msPath)
+{
+ mxRelationshipAccess.set(rOOXMLStream.mxDocumentStream, uno::UNO_QUERY_THROW);
+
+ init();
+}
+
+OOXMLStreamImpl::OOXMLStreamImpl
+(OOXMLStreamImpl const & rOOXMLStream, const OUString & rId)
+: mxContext(rOOXMLStream.mxContext),
+ mxStorageStream(rOOXMLStream.mxStorageStream),
+ mxStorage(rOOXMLStream.mxStorage),
+ mnStreamType(UNKNOWN),
+ msId(rId),
+ msPath(rOOXMLStream.msPath)
+{
+ mxRelationshipAccess.set(rOOXMLStream.mxDocumentStream, uno::UNO_QUERY_THROW);
+
+ init();
+}
+
+OOXMLStreamImpl::~OOXMLStreamImpl()
+{
+}
+
+const OUString & OOXMLStreamImpl::getTarget() const
+{
+ return msTarget;
+}
+
+bool OOXMLStreamImpl::lcl_getTarget(const uno::Reference<embed::XRelationshipAccess>&
+ xRelationshipAccess,
+ StreamType_t nStreamType,
+ const OUString & rId,
+ OUString & rDocumentTarget)
+{
+ static const char sId[] = "Id";
+ static const char sTarget[] = "Target";
+ static const char sTargetMode[] = "TargetMode";
+ static const char sExternal[] = "External";
+ if (maIdCache.empty())
+ {
+ // Cache is empty? Then let's build it!
+ const uno::Sequence< uno::Sequence<beans::StringPair> >aSeqs = xRelationshipAccess->getAllRelationships();
+ for (const uno::Sequence<beans::StringPair>& rSeq : aSeqs)
+ {
+ OUString aId;
+ OUString aTarget;
+ bool bExternal = false;
+ for (const beans::StringPair& rPair : rSeq)
+ {
+ if (rPair.First == sId)
+ aId = rPair.Second;
+ else if (rPair.First == sTarget)
+ aTarget = rPair.Second;
+ else if (rPair.First == sTargetMode && rPair.Second == sExternal)
+ bExternal = true;
+ }
+ // Only cache external targets, internal ones are more complex (see below)
+ if (bExternal || aTarget.startsWith("#"))
+ maIdCache[aId] = aTarget;
+ }
+ }
+
+ if (maIdCache.find(rId) != maIdCache.end())
+ {
+ rDocumentTarget = maIdCache[rId];
+ return true;
+ }
+
+ bool bFound = false;
+ static uno::Reference<uri::XUriReferenceFactory> xFac = uri::UriReferenceFactory::create(mxContext);
+ // use '/' to representent the root of the zip package ( and provide a 'file' scheme to
+ // keep the XUriReference implementation happy )
+ // add mspath to represent the 'source' of this stream
+ uno::Reference<uri::XUriReference> xBase = xFac->parse("file:///" + msPath);
+
+ static const char sType[] = "Type";
+ static const OUStringLiteral sDocumentType = u"http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument";
+ static const OUStringLiteral sStylesType = u"http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles";
+ static const OUStringLiteral sNumberingType = u"http://schemas.openxmlformats.org/officeDocument/2006/relationships/numbering";
+ static const OUStringLiteral sFonttableType = u"http://schemas.openxmlformats.org/officeDocument/2006/relationships/fontTable";
+ static const OUStringLiteral sFootnotesType = u"http://schemas.openxmlformats.org/officeDocument/2006/relationships/footnotes";
+ static const OUStringLiteral sEndnotesType = u"http://schemas.openxmlformats.org/officeDocument/2006/relationships/endnotes";
+ static const OUStringLiteral sCommentsType = u"http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments";
+ static const OUStringLiteral sThemeType = u"http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme";
+ static const OUStringLiteral sCustomType = u"http://schemas.openxmlformats.org/officeDocument/2006/relationships/customXml";
+ static const OUStringLiteral sCustomPropsType = u"http://schemas.openxmlformats.org/officeDocument/2006/relationships/customXmlProps";
+ static const OUStringLiteral sGlossaryType = u"http://schemas.openxmlformats.org/officeDocument/2006/relationships/glossaryDocument";
+ static const OUStringLiteral sWebSettings = u"http://schemas.openxmlformats.org/officeDocument/2006/relationships/webSettings";
+ static const OUStringLiteral sSettingsType = u"http://schemas.openxmlformats.org/officeDocument/2006/relationships/settings";
+ static const OUStringLiteral sChartType = u"http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart";
+ static const OUStringLiteral sEmbeddingsType = u"http://schemas.openxmlformats.org/officeDocument/2006/relationships/package";
+ static const OUStringLiteral sFooterType = u"http://schemas.openxmlformats.org/officeDocument/2006/relationships/footer";
+ static const OUStringLiteral sHeaderType = u"http://schemas.openxmlformats.org/officeDocument/2006/relationships/header";
+ static const OUStringLiteral sOleObjectType = u"http://schemas.openxmlformats.org/officeDocument/2006/relationships/oleObject";
+ static const OUStringLiteral sCommentsExtendedType = u"http://schemas.microsoft.com/office/2011/relationships/commentsExtended";
+ // OOXML strict
+ static const OUStringLiteral sDocumentTypeStrict = u"http://purl.oclc.org/ooxml/officeDocument/relationships/officeDocument";
+ static const OUStringLiteral sStylesTypeStrict = u"http://purl.oclc.org/ooxml/officeDocument/relationships/styles";
+ static const OUStringLiteral sNumberingTypeStrict = u"http://purl.oclc.org/ooxml/officeDocument/relationships/numbering";
+ static const OUStringLiteral sFonttableTypeStrict = u"http://purl.oclc.org/ooxml/officeDocument/relationships/fontTable";
+ static const OUStringLiteral sFootnotesTypeStrict = u"http://purl.oclc.org/ooxml/officeDocument/relationships/footnotes";
+ static const OUStringLiteral sEndnotesTypeStrict = u"http://purl.oclc.org/ooxml/officeDocument/relationships/endnotes";
+ static const OUStringLiteral sCommentsTypeStrict = u"http://purl.oclc.org/ooxml/officeDocument/relationships/comments";
+ static const OUStringLiteral sThemeTypeStrict = u"http://purl.oclc.org/ooxml/officeDocument/relationships/theme";
+ static const OUStringLiteral sCustomTypeStrict = u"http://purl.oclc.org/ooxml/officeDocument/relationships/customXml";
+ static const OUStringLiteral sCustomPropsTypeStrict = u"http://purl.oclc.org/ooxml/officeDocument/relationships/customXmlProps";
+ static const OUStringLiteral sGlossaryTypeStrict = u"http://purl.oclc.org/ooxml/officeDocument/relationships/glossaryDocument";
+ static const OUStringLiteral sWebSettingsStrict = u"http://purl.oclc.org/ooxml/officeDocument/relationships/webSettings";
+ static const OUStringLiteral sSettingsTypeStrict = u"http://purl.oclc.org/ooxml/officeDocument/relationships/settings";
+ static const OUStringLiteral sChartTypeStrict = u"http://purl.oclc.org/ooxml/officeDocument/relationships/chart";
+ static const OUStringLiteral sEmbeddingsTypeStrict = u"http://purl.oclc.org/ooxml/officeDocument/relationships/package";
+ static const OUStringLiteral sFootersTypeStrict = u"http://purl.oclc.org/ooxml/officeDocument/relationships/footer";
+ static const OUStringLiteral sHeaderTypeStrict = u"http://purl.oclc.org/ooxml/officeDocument/relationships/header";
+ static const OUStringLiteral sOleObjectTypeStrict = u"http://purl.oclc.org/ooxml/officeDocument/relationships/oleObject";
+ static const OUStringLiteral sVBAProjectType = u"http://schemas.microsoft.com/office/2006/relationships/vbaProject";
+ static const OUStringLiteral sVBADataType = u"http://schemas.microsoft.com/office/2006/relationships/wordVbaData";
+
+ OUString sStreamType;
+ OUString sStreamTypeStrict;
+
+ switch (nStreamType)
+ {
+ case VBAPROJECT:
+ sStreamType = sVBAProjectType;
+ sStreamTypeStrict = sVBAProjectType;
+ break;
+ case VBADATA:
+ sStreamType = sVBADataType;
+ sStreamTypeStrict = sVBADataType;
+ break;
+ case DOCUMENT:
+ sStreamType = sDocumentType;
+ sStreamTypeStrict = sDocumentTypeStrict;
+ break;
+ case STYLES:
+ sStreamType = sStylesType;
+ sStreamTypeStrict = sStylesTypeStrict;
+ break;
+ case NUMBERING:
+ sStreamType = sNumberingType;
+ sStreamTypeStrict = sNumberingTypeStrict;
+ break;
+ case FONTTABLE:
+ sStreamType = sFonttableType;
+ sStreamTypeStrict = sFonttableTypeStrict;
+ break;
+ case FOOTNOTES:
+ sStreamType = sFootnotesType;
+ sStreamTypeStrict = sFootnotesTypeStrict;
+ break;
+ case ENDNOTES:
+ sStreamType = sEndnotesType;
+ sStreamTypeStrict = sEndnotesTypeStrict;
+ break;
+ case COMMENTS:
+ sStreamType = sCommentsType;
+ sStreamTypeStrict = sCommentsTypeStrict;
+ break;
+ case THEME:
+ sStreamType = sThemeType;
+ sStreamTypeStrict = sThemeTypeStrict;
+ break;
+ case CUSTOMXML:
+ sStreamType = sCustomType;
+ sStreamTypeStrict = sCustomTypeStrict;
+ break;
+ case CUSTOMXMLPROPS:
+ sStreamType = sCustomPropsType;
+ sStreamTypeStrict = sCustomPropsTypeStrict;
+ break;
+ case SETTINGS:
+ sStreamType = sSettingsType;
+ sStreamTypeStrict = sSettingsTypeStrict;
+ break;
+ case GLOSSARY:
+ sStreamType = sGlossaryType;
+ sStreamTypeStrict = sGlossaryTypeStrict;
+ break;
+ case WEBSETTINGS:
+ sStreamType = sWebSettings;
+ sStreamTypeStrict = sWebSettingsStrict;
+ break;
+ case CHARTS:
+ sStreamType = sChartType;
+ sStreamTypeStrict = sChartTypeStrict;
+ break;
+ case EMBEDDINGS:
+ sStreamType = sEmbeddingsType;
+ sStreamTypeStrict = sEmbeddingsTypeStrict;
+ break;
+ case FOOTER:
+ sStreamType = sFooterType;
+ sStreamTypeStrict = sFootersTypeStrict;
+ break;
+ case HEADER:
+ sStreamType = sHeaderType;
+ sStreamTypeStrict = sHeaderTypeStrict;
+ break;
+ case COMMENTS_EXTENDED:
+ sStreamType = sCommentsExtendedType;
+ sStreamTypeStrict = sCommentsExtendedType;
+ break;
+ default:
+ break;
+ }
+
+ if (xRelationshipAccess.is())
+ {
+ const uno::Sequence< uno::Sequence< beans::StringPair > >aSeqs =
+ xRelationshipAccess->getAllRelationships();
+
+ for (const uno::Sequence< beans::StringPair > &rSeq : aSeqs)
+ {
+ bool bExternalTarget = false;
+ OUString sMyTarget;
+ for (const beans::StringPair &rPair : rSeq)
+ {
+ if (rPair.First == sType &&
+ ( rPair.Second == sStreamType ||
+ rPair.Second == sStreamTypeStrict ))
+ bFound = true;
+ else if(rPair.First == sType &&
+ ((rPair.Second == sOleObjectType ||
+ rPair.Second == sOleObjectTypeStrict) &&
+ nStreamType == EMBEDDINGS))
+ {
+ bFound = true;
+ }
+ else if (rPair.First == sId &&
+ rPair.Second == rId)
+ bFound = true;
+ else if (rPair.First == sTarget)
+ {
+ // checking item[n].xml is not visited already.
+ if(customTarget != rPair.Second && (sStreamType == sCustomType || sStreamType == sChartType || sStreamType == sFooterType || sStreamType == sHeaderType))
+ {
+ bFound = false;
+ }
+ else
+ {
+ sMyTarget = rPair.Second;
+ }
+ }
+ else if (rPair.First == sTargetMode &&
+ rPair.Second == sExternal)
+ bExternalTarget = true;
+ }
+
+ if (bFound)
+ {
+ if (bExternalTarget)
+ rDocumentTarget = sMyTarget;
+ else
+ {
+ // 'Target' is a relative Uri, so a 'Target=/path'
+ // with a base Uri of file://base/foo will resolve to
+ // file://base/word. We need something more than some
+ // simple string concatenation here to handle that.
+ uno::Reference<uri::XUriReference> xPart = xFac->parse(sMyTarget);
+ uno::Reference<uri::XUriReference> xAbs = xFac->makeAbsolute(xBase, xPart, true, uri::RelativeUriExcessParentSegments_RETAIN);
+ if (!xAbs)
+ {
+ //it was invalid gibberish
+ bFound = false;
+ }
+ else
+ {
+ rDocumentTarget = xAbs->getPath();
+ // path will start with the fragment separator. need to
+ // remove that
+ rDocumentTarget = rDocumentTarget.copy( 1 );
+ if(sStreamType == sEmbeddingsType)
+ embeddingsTarget = rDocumentTarget;
+ }
+ }
+
+ break;
+ }
+ }
+ }
+
+ return bFound;
+}
+
+OUString OOXMLStreamImpl::getTargetForId(const OUString & rId)
+{
+ OUString sTarget;
+
+ uno::Reference<embed::XRelationshipAccess> xRelationshipAccess
+ (mxDocumentStream, uno::UNO_QUERY_THROW);
+
+ if (lcl_getTarget(xRelationshipAccess, UNKNOWN, rId, sTarget))
+ return sTarget;
+
+ return OUString();
+}
+
+void OOXMLStreamImpl::init()
+{
+ bool bFound = lcl_getTarget(mxRelationshipAccess,
+ mnStreamType, msId, msTarget);
+
+ if (!bFound)
+ return;
+
+ sal_Int32 nLastIndex = msTarget.lastIndexOf('/');
+ if (nLastIndex >= 0)
+ msPath = msTarget.copy(0, nLastIndex + 1);
+
+ uno::Reference<embed::XHierarchicalStorageAccess>
+ xHierarchicalStorageAccess(mxStorage, uno::UNO_QUERY);
+
+ if (xHierarchicalStorageAccess.is())
+ {
+ uno::Any aAny(xHierarchicalStorageAccess->
+ openStreamElementByHierarchicalName
+ (msTarget, embed::ElementModes::SEEKABLEREAD));
+ aAny >>= mxDocumentStream;
+ // Non-cached ID lookup works by accessing mxDocumentStream as an embed::XRelationshipAccess.
+ // So when it changes, we should empty the cache.
+ maIdCache.clear();
+ }
+}
+
+uno::Reference<io::XInputStream> OOXMLStreamImpl::getDocumentStream()
+{
+ uno::Reference<io::XInputStream> xResult;
+
+ if (mxDocumentStream.is())
+ xResult = mxDocumentStream->getInputStream();
+
+ return xResult;
+}
+
+uno::Reference<uno::XComponentContext> OOXMLStreamImpl::getContext()
+{
+ return mxContext;
+}
+
+uno::Reference <xml::sax::XFastTokenHandler> OOXMLStreamImpl::getFastTokenHandler()
+{
+ if (! mxFastTokenHandler.is())
+ mxFastTokenHandler.set(new oox::core::FastTokenHandler());
+
+ return mxFastTokenHandler;
+}
+
+OOXMLStream::Pointer_t
+OOXMLDocumentFactory::createStream
+(const uno::Reference<uno::XComponentContext>& xContext,
+ const uno::Reference<io::XInputStream>& rStream,
+ bool bRepairStorage)
+{
+ OOXMLStreamImpl * pStream = new OOXMLStreamImpl(xContext, rStream,
+ OOXMLStream::DOCUMENT, bRepairStorage);
+ return OOXMLStream::Pointer_t(pStream);
+}
+
+OOXMLStream::Pointer_t
+OOXMLDocumentFactory::createStream
+(const OOXMLStream::Pointer_t& pStream, OOXMLStream::StreamType_t nStreamType)
+{
+ OOXMLStream::Pointer_t pRet;
+
+ if (nStreamType != OOXMLStream::VBADATA)
+ {
+ if (OOXMLStreamImpl* pImpl = dynamic_cast<OOXMLStreamImpl *>(pStream.get()))
+ pRet = 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()))
+ {
+ OOXMLStreamImpl aProject(*pImpl, OOXMLStream::VBAPROJECT);
+ pRet = new OOXMLStreamImpl(aProject, OOXMLStream::VBADATA);
+ }
+ }
+
+ return pRet;
+}
+
+OOXMLStream::Pointer_t
+OOXMLDocumentFactory::createStream
+(const OOXMLStream::Pointer_t& pStream, const OUString & rId)
+{
+ OOXMLStream::Pointer_t pRet;
+ if (OOXMLStreamImpl* pImpl = dynamic_cast<OOXMLStreamImpl *>(pStream.get()))
+ pRet = new OOXMLStreamImpl(*pImpl, rId);
+ return pRet;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */