Version 6.4.0.3, tag libreoffice-6.4.0.3
[LibreOffice.git] / writerfilter / source / ooxml / OOXMLStreamImpl.cxx
blob2b773e02cf5efc70b3397a4b849be2bdfddbd4b1
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "OOXMLStreamImpl.hxx"
21 #include <oox/core/fasttokenhandler.hxx>
22 #include <iostream>
24 #include <com/sun/star/embed/XHierarchicalStorageAccess.hpp>
25 #include <com/sun/star/uri/UriReferenceFactory.hpp>
26 #include <com/sun/star/xml/sax/Parser.hpp>
27 #include <comphelper/storagehelper.hxx>
29 namespace writerfilter {
30 namespace ooxml
33 using namespace com::sun::star;
35 OOXMLStreamImpl::OOXMLStreamImpl
36 (uno::Reference<uno::XComponentContext> const & xContext,
37 uno::Reference<io::XInputStream> const & xStorageStream,
38 StreamType_t nType, bool bRepairStorage)
39 : mxContext(xContext), mxStorageStream(xStorageStream), mnStreamType(nType)
41 mxStorage.set
42 (comphelper::OStorageHelper::GetStorageOfFormatFromInputStream
43 (OFOPXML_STORAGE_FORMAT_STRING, mxStorageStream, xContext, bRepairStorage));
44 mxRelationshipAccess.set(mxStorage, uno::UNO_QUERY_THROW);
46 init();
49 OOXMLStreamImpl::OOXMLStreamImpl
50 (OOXMLStreamImpl const & rOOXMLStream, StreamType_t nStreamType)
51 : mxContext(rOOXMLStream.mxContext),
52 mxStorageStream(rOOXMLStream.mxStorageStream),
53 mxStorage(rOOXMLStream.mxStorage),
54 mnStreamType(nStreamType),
55 msPath(rOOXMLStream.msPath)
57 mxRelationshipAccess.set(rOOXMLStream.mxDocumentStream, uno::UNO_QUERY_THROW);
59 init();
62 OOXMLStreamImpl::OOXMLStreamImpl
63 (OOXMLStreamImpl const & rOOXMLStream, const OUString & rId)
64 : mxContext(rOOXMLStream.mxContext),
65 mxStorageStream(rOOXMLStream.mxStorageStream),
66 mxStorage(rOOXMLStream.mxStorage),
67 mnStreamType(UNKNOWN),
68 msId(rId),
69 msPath(rOOXMLStream.msPath)
71 mxRelationshipAccess.set(rOOXMLStream.mxDocumentStream, uno::UNO_QUERY_THROW);
73 init();
76 OOXMLStreamImpl::~OOXMLStreamImpl()
80 const OUString & OOXMLStreamImpl::getTarget() const
82 return msTarget;
85 bool OOXMLStreamImpl::lcl_getTarget(const uno::Reference<embed::XRelationshipAccess>&
86 xRelationshipAccess,
87 StreamType_t nStreamType,
88 const OUString & rId,
89 OUString & rDocumentTarget)
91 static const char sId[] = "Id";
92 static const char sTarget[] = "Target";
93 static const char sTargetMode[] = "TargetMode";
94 static const char sExternal[] = "External";
95 if (maIdCache.empty())
97 // Cache is empty? Then let's build it!
98 const uno::Sequence< uno::Sequence<beans::StringPair> >aSeqs = xRelationshipAccess->getAllRelationships();
99 for (const uno::Sequence<beans::StringPair>& rSeq : aSeqs)
101 OUString aId;
102 OUString aTarget;
103 bool bExternal = false;
104 for (const beans::StringPair& rPair : rSeq)
106 if (rPair.First == sId)
107 aId = rPair.Second;
108 else if (rPair.First == sTarget)
109 aTarget = rPair.Second;
110 else if (rPair.First == sTargetMode && rPair.Second == sExternal)
111 bExternal = true;
113 // Only cache external targets, internal ones are more complex (see below)
114 if (bExternal || aTarget.startsWith("#"))
115 maIdCache[aId] = aTarget;
119 if (maIdCache.find(rId) != maIdCache.end())
121 rDocumentTarget = maIdCache[rId];
122 return true;
125 bool bFound = false;
126 static uno::Reference<uri::XUriReferenceFactory> xFac = uri::UriReferenceFactory::create(mxContext);
127 // use '/' to representent the root of the zip package ( and provide a 'file' scheme to
128 // keep the XUriReference implementation happy )
129 // add mspath to represent the 'source' of this stream
130 uno::Reference<uri::XUriReference> xBase = xFac->parse("file:///" + msPath);
132 static const char sType[] = "Type";
133 static const char sDocumentType[] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument";
134 static const char sStylesType[] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles";
135 static const char sNumberingType[] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/numbering";
136 static const char sFonttableType[] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/fontTable";
137 static const char sFootnotesType[] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/footnotes";
138 static const char sEndnotesType[] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/endnotes";
139 static const char sCommentsType[] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments";
140 static const char sThemeType[] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme";
141 static const char sCustomType[] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/customXml";
142 static const char sCustomPropsType[] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/customXmlProps";
143 static const char sGlossaryType[] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/glossaryDocument";
144 static const char sWebSettings[] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/webSettings";
145 static const char sSettingsType[] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/settings";
146 static const char sChartType[] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart";
147 static const char sEmbeddingsType[] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/package";
148 static const char sFooterType[] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/footer";
149 static const char sHeaderType[] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/header";
150 static const char sOleObjectType[] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/oleObject";
151 // OOXML strict
152 static const char sDocumentTypeStrict[] = "http://purl.oclc.org/ooxml/officeDocument/relationships/officeDocument";
153 static const char sStylesTypeStrict[] = "http://purl.oclc.org/ooxml/officeDocument/relationships/styles";
154 static const char sNumberingTypeStrict[] = "http://purl.oclc.org/ooxml/officeDocument/relationships/numbering";
155 static const char sFonttableTypeStrict[] = "http://purl.oclc.org/ooxml/officeDocument/relationships/fontTable";
156 static const char sFootnotesTypeStrict[] = "http://purl.oclc.org/ooxml/officeDocument/relationships/footnotes";
157 static const char sEndnotesTypeStrict[] = "http://purl.oclc.org/ooxml/officeDocument/relationships/endnotes";
158 static const char sCommentsTypeStrict[] = "http://purl.oclc.org/ooxml/officeDocument/relationships/comments";
159 static const char sThemeTypeStrict[] = "http://purl.oclc.org/ooxml/officeDocument/relationships/theme";
160 static const char sCustomTypeStrict[] = "http://purl.oclc.org/ooxml/officeDocument/relationships/customXml";
161 static const char sCustomPropsTypeStrict[] = "http://purl.oclc.org/ooxml/officeDocument/relationships/customXmlProps";
162 static const char sGlossaryTypeStrict[] = "http://purl.oclc.org/ooxml/officeDocument/relationships/glossaryDocument";
163 static const char sWebSettingsStrict[] = "http://purl.oclc.org/ooxml/officeDocument/relationships/webSettings";
164 static const char sSettingsTypeStrict[] = "http://purl.oclc.org/ooxml/officeDocument/relationships/settings";
165 static const char sChartTypeStrict[] = "http://purl.oclc.org/ooxml/officeDocument/relationships/chart";
166 static const char sEmbeddingsTypeStrict[] = "http://purl.oclc.org/ooxml/officeDocument/relationships/package";
167 static const char sFootersTypeStrict[] = "http://purl.oclc.org/ooxml/officeDocument/relationships/footer";
168 static const char sHeaderTypeStrict[] = "http://purl.oclc.org/ooxml/officeDocument/relationships/header";
169 static const char sOleObjectTypeStrict[] = "http://purl.oclc.org/ooxml/officeDocument/relationships/oleObject";
170 static const char sVBAProjectType[] = "http://schemas.microsoft.com/office/2006/relationships/vbaProject";
171 static const char sVBADataType[] = "http://schemas.microsoft.com/office/2006/relationships/wordVbaData";
173 OUString sStreamType;
174 OUString sStreamTypeStrict;
176 switch (nStreamType)
178 case VBAPROJECT:
179 sStreamType = sVBAProjectType;
180 sStreamTypeStrict = sVBAProjectType;
181 break;
182 case VBADATA:
183 sStreamType = sVBADataType;
184 sStreamTypeStrict = sVBADataType;
185 break;
186 case DOCUMENT:
187 sStreamType = sDocumentType;
188 sStreamTypeStrict = sDocumentTypeStrict;
189 break;
190 case STYLES:
191 sStreamType = sStylesType;
192 sStreamTypeStrict = sStylesTypeStrict;
193 break;
194 case NUMBERING:
195 sStreamType = sNumberingType;
196 sStreamTypeStrict = sNumberingTypeStrict;
197 break;
198 case FONTTABLE:
199 sStreamType = sFonttableType;
200 sStreamTypeStrict = sFonttableTypeStrict;
201 break;
202 case FOOTNOTES:
203 sStreamType = sFootnotesType;
204 sStreamTypeStrict = sFootnotesTypeStrict;
205 break;
206 case ENDNOTES:
207 sStreamType = sEndnotesType;
208 sStreamTypeStrict = sEndnotesTypeStrict;
209 break;
210 case COMMENTS:
211 sStreamType = sCommentsType;
212 sStreamTypeStrict = sCommentsTypeStrict;
213 break;
214 case THEME:
215 sStreamType = sThemeType;
216 sStreamTypeStrict = sThemeTypeStrict;
217 break;
218 case CUSTOMXML:
219 sStreamType = sCustomType;
220 sStreamTypeStrict = sCustomTypeStrict;
221 break;
222 case CUSTOMXMLPROPS:
223 sStreamType = sCustomPropsType;
224 sStreamTypeStrict = sCustomPropsTypeStrict;
225 break;
226 case SETTINGS:
227 sStreamType = sSettingsType;
228 sStreamTypeStrict = sSettingsTypeStrict;
229 break;
230 case GLOSSARY:
231 sStreamType = sGlossaryType;
232 sStreamTypeStrict = sGlossaryTypeStrict;
233 break;
234 case WEBSETTINGS:
235 sStreamType = sWebSettings;
236 sStreamTypeStrict = sWebSettingsStrict;
237 break;
238 case CHARTS:
239 sStreamType = sChartType;
240 sStreamTypeStrict = sChartTypeStrict;
241 break;
242 case EMBEDDINGS:
243 sStreamType = sEmbeddingsType;
244 sStreamTypeStrict = sEmbeddingsTypeStrict;
245 break;
246 case FOOTER:
247 sStreamType = sFooterType;
248 sStreamTypeStrict = sFootersTypeStrict;
249 break;
250 case HEADER:
251 sStreamType = sHeaderType;
252 sStreamTypeStrict = sHeaderTypeStrict;
253 break;
254 default:
255 break;
258 if (xRelationshipAccess.is())
260 const uno::Sequence< uno::Sequence< beans::StringPair > >aSeqs =
261 xRelationshipAccess->getAllRelationships();
263 for (const uno::Sequence< beans::StringPair > &rSeq : aSeqs)
265 bool bExternalTarget = false;
266 OUString sMyTarget;
267 for (const beans::StringPair &rPair : rSeq)
269 if (rPair.First == sType &&
270 ( rPair.Second == sStreamType ||
271 rPair.Second == sStreamTypeStrict ))
272 bFound = true;
273 else if(rPair.First == sType &&
274 ((rPair.Second == sOleObjectType ||
275 rPair.Second == sOleObjectTypeStrict) &&
276 nStreamType == EMBEDDINGS))
278 bFound = true;
280 else if (rPair.First == sId &&
281 rPair.Second == rId)
282 bFound = true;
283 else if (rPair.First == sTarget)
285 // checking item[n].xml is not visited already.
286 if(customTarget != rPair.Second && (sStreamType == sCustomType || sStreamType == sChartType || sStreamType == sFooterType || sStreamType == sHeaderType))
288 bFound = false;
290 else
292 sMyTarget = rPair.Second;
295 else if (rPair.First == sTargetMode &&
296 rPair.Second == sExternal)
297 bExternalTarget = true;
300 if (bFound)
302 if (bExternalTarget)
303 rDocumentTarget = sMyTarget;
304 else
306 // 'Target' is a relative Uri, so a 'Target=/path'
307 // with a base Uri of file://base/foo will resolve to
308 // file://base/word. We need something more than some
309 // simple string concatenation here to handle that.
310 uno::Reference<uri::XUriReference> xPart = xFac->parse(sMyTarget);
311 uno::Reference<uri::XUriReference> xAbs = xFac->makeAbsolute(xBase, xPart, true, uri::RelativeUriExcessParentSegments_RETAIN);
312 if (!xAbs)
314 //it was invalid gibberish
315 bFound = false;
317 else
319 rDocumentTarget = xAbs->getPath();
320 // path will start with the fragment separator. need to
321 // remove that
322 rDocumentTarget = rDocumentTarget.copy( 1 );
323 if(sStreamType == sEmbeddingsType)
324 embeddingsTarget = rDocumentTarget;
328 break;
333 return bFound;
336 OUString OOXMLStreamImpl::getTargetForId(const OUString & rId)
338 OUString sTarget;
340 uno::Reference<embed::XRelationshipAccess> xRelationshipAccess
341 (mxDocumentStream, uno::UNO_QUERY_THROW);
343 if (lcl_getTarget(xRelationshipAccess, UNKNOWN, rId, sTarget))
344 return sTarget;
346 return OUString();
349 void OOXMLStreamImpl::init()
351 bool bFound = lcl_getTarget(mxRelationshipAccess,
352 mnStreamType, msId, msTarget);
354 if (bFound)
356 sal_Int32 nLastIndex = msTarget.lastIndexOf('/');
357 if (nLastIndex >= 0)
358 msPath = msTarget.copy(0, nLastIndex + 1);
360 uno::Reference<embed::XHierarchicalStorageAccess>
361 xHierarchicalStorageAccess(mxStorage, uno::UNO_QUERY);
363 if (xHierarchicalStorageAccess.is())
365 uno::Any aAny(xHierarchicalStorageAccess->
366 openStreamElementByHierarchicalName
367 (msTarget, embed::ElementModes::SEEKABLEREAD));
368 aAny >>= mxDocumentStream;
369 // Non-cached ID lookup works by accessing mxDocumentStream as an embed::XRelationshipAccess.
370 // So when it changes, we should empty the cache.
371 maIdCache.clear();
376 uno::Reference<io::XInputStream> OOXMLStreamImpl::getDocumentStream()
378 uno::Reference<io::XInputStream> xResult;
380 if (mxDocumentStream.is())
381 xResult = mxDocumentStream->getInputStream();
383 return xResult;
386 uno::Reference<uno::XComponentContext> OOXMLStreamImpl::getContext()
388 return mxContext;
391 uno::Reference <xml::sax::XFastTokenHandler> OOXMLStreamImpl::getFastTokenHandler()
393 if (! mxFastTokenHandler.is())
394 mxFastTokenHandler.set(new oox::core::FastTokenHandler());
396 return mxFastTokenHandler;
399 OOXMLStream::Pointer_t
400 OOXMLDocumentFactory::createStream
401 (const uno::Reference<uno::XComponentContext>& xContext,
402 const uno::Reference<io::XInputStream>& rStream,
403 bool bRepairStorage)
405 OOXMLStreamImpl * pStream = new OOXMLStreamImpl(xContext, rStream,
406 OOXMLStream::DOCUMENT, bRepairStorage);
407 return OOXMLStream::Pointer_t(pStream);
410 OOXMLStream::Pointer_t
411 OOXMLDocumentFactory::createStream
412 (const OOXMLStream::Pointer_t& pStream, OOXMLStream::StreamType_t nStreamType)
414 OOXMLStream::Pointer_t pRet;
416 if (nStreamType != OOXMLStream::VBADATA)
418 if (OOXMLStreamImpl* pImpl = dynamic_cast<OOXMLStreamImpl *>(pStream.get()))
419 pRet = new OOXMLStreamImpl(*pImpl, nStreamType);
421 else
423 // VBADATA is not a relation of the document, but of the VBAPROJECT stream.
424 if (OOXMLStreamImpl* pImpl = dynamic_cast<OOXMLStreamImpl *>(pStream.get()))
426 std::unique_ptr<OOXMLStreamImpl> pProject(new OOXMLStreamImpl(*pImpl, OOXMLStream::VBAPROJECT));
427 pRet = new OOXMLStreamImpl(*pProject, OOXMLStream::VBADATA);
431 return pRet;
434 OOXMLStream::Pointer_t
435 OOXMLDocumentFactory::createStream
436 (const OOXMLStream::Pointer_t& pStream, const OUString & rId)
438 OOXMLStream::Pointer_t pRet;
439 if (OOXMLStreamImpl* pImpl = dynamic_cast<OOXMLStreamImpl *>(pStream.get()))
440 pRet = new OOXMLStreamImpl(*pImpl, rId);
441 return pRet;
446 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */