LibreOffice Module writerfilter (master) 1
OOXMLStreamImpl.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20#include "OOXMLStreamImpl.hxx"
22
23#include <com/sun/star/embed/XHierarchicalStorageAccess.hpp>
24#include <com/sun/star/uri/UriReferenceFactory.hpp>
26#include <utility>
27
28namespace writerfilter::ooxml
29{
30
31using namespace com::sun::star;
32
34(uno::Reference<uno::XComponentContext> const & xContext,
35 uno::Reference<io::XInputStream> xStorageStream,
36 StreamType_t nType, bool bRepairStorage)
37: mxContext(xContext), mxStorageStream(std::move(xStorageStream)), mnStreamType(nType)
38{
39 mxStorage.set
41 (OFOPXML_STORAGE_FORMAT_STRING, mxStorageStream, xContext, bRepairStorage));
42 mxRelationshipAccess.set(mxStorage, uno::UNO_QUERY_THROW);
43
44 init();
45}
46
47OOXMLStreamImpl::OOXMLStreamImpl
48(OOXMLStreamImpl const & rOOXMLStream, StreamType_t nStreamType)
49: mxContext(rOOXMLStream.mxContext),
50 mxStorageStream(rOOXMLStream.mxStorageStream),
51 mxStorage(rOOXMLStream.mxStorage),
52 mnStreamType(nStreamType),
53 msPath(rOOXMLStream.msPath)
54{
55 mxRelationshipAccess.set(rOOXMLStream.mxDocumentStream, uno::UNO_QUERY_THROW);
56
57 init();
58}
59
61(OOXMLStreamImpl const & rOOXMLStream, OUString sId)
62: mxContext(rOOXMLStream.mxContext),
63 mxStorageStream(rOOXMLStream.mxStorageStream),
64 mxStorage(rOOXMLStream.mxStorage),
65 mnStreamType(UNKNOWN),
66 msId(std::move(sId)),
67 msPath(rOOXMLStream.msPath)
68{
69 mxRelationshipAccess.set(rOOXMLStream.mxDocumentStream, uno::UNO_QUERY_THROW);
70
71 init();
72}
73
75{
76}
77
78const OUString & OOXMLStreamImpl::getTarget() const
79{
80 return msTarget;
81}
82
84 xRelationshipAccess,
85 StreamType_t nStreamType,
86 const OUString & rId,
87 OUString & rDocumentTarget)
88{
89 static const char sId[] = "Id";
90 static const char sTarget[] = "Target";
91 static const char sTargetMode[] = "TargetMode";
92 static const char sExternal[] = "External";
93 if (maIdCache.empty())
94 {
95 // Cache is empty? Then let's build it!
96 const uno::Sequence< uno::Sequence<beans::StringPair> >aSeqs = xRelationshipAccess->getAllRelationships();
97 for (const uno::Sequence<beans::StringPair>& rSeq : aSeqs)
98 {
99 OUString aId;
100 OUString aTarget;
101 bool bExternal = false;
102 for (const beans::StringPair& rPair : rSeq)
103 {
104 if (rPair.First == sId)
105 aId = rPair.Second;
106 else if (rPair.First == sTarget)
107 aTarget = rPair.Second;
108 else if (rPair.First == sTargetMode && rPair.Second == sExternal)
109 bExternal = true;
110 }
111 // Only cache external targets, internal ones are more complex (see below)
112 if (bExternal || aTarget.startsWith("#"))
113 maIdCache[aId] = aTarget;
114 }
115 }
116
117 if (maIdCache.find(rId) != maIdCache.end())
118 {
119 rDocumentTarget = maIdCache[rId];
120 return true;
121 }
122
123 bool bFound = false;
124 static uno::Reference<uri::XUriReferenceFactory> xFac = uri::UriReferenceFactory::create(mxContext);
125 // use '/' to representent the root of the zip package ( and provide a 'file' scheme to
126 // keep the XUriReference implementation happy )
127 // add mspath to represent the 'source' of this stream
128 uno::Reference<uri::XUriReference> xBase = xFac->parse("file:///" + msPath);
129
130 static const char sType[] = "Type";
131 static constexpr OUStringLiteral sDocumentType = u"http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument";
132 static constexpr OUStringLiteral sStylesType = u"http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles";
133 static constexpr OUStringLiteral sNumberingType = u"http://schemas.openxmlformats.org/officeDocument/2006/relationships/numbering";
134 static constexpr OUStringLiteral sFonttableType = u"http://schemas.openxmlformats.org/officeDocument/2006/relationships/fontTable";
135 static constexpr OUStringLiteral sFootnotesType = u"http://schemas.openxmlformats.org/officeDocument/2006/relationships/footnotes";
136 static constexpr OUStringLiteral sEndnotesType = u"http://schemas.openxmlformats.org/officeDocument/2006/relationships/endnotes";
137 static constexpr OUStringLiteral sCommentsType = u"http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments";
138 static constexpr OUStringLiteral sThemeType = u"http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme";
139 static constexpr OUStringLiteral sCustomType = u"http://schemas.openxmlformats.org/officeDocument/2006/relationships/customXml";
140 static constexpr OUStringLiteral sCustomPropsType = u"http://schemas.openxmlformats.org/officeDocument/2006/relationships/customXmlProps";
141 static constexpr OUStringLiteral sGlossaryType = u"http://schemas.openxmlformats.org/officeDocument/2006/relationships/glossaryDocument";
142 static constexpr OUStringLiteral sWebSettings = u"http://schemas.openxmlformats.org/officeDocument/2006/relationships/webSettings";
143 static constexpr OUStringLiteral sSettingsType = u"http://schemas.openxmlformats.org/officeDocument/2006/relationships/settings";
144 static constexpr OUStringLiteral sChartType = u"http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart";
145 static constexpr OUStringLiteral sEmbeddingsType = u"http://schemas.openxmlformats.org/officeDocument/2006/relationships/package";
146 static constexpr OUStringLiteral sFooterType = u"http://schemas.openxmlformats.org/officeDocument/2006/relationships/footer";
147 static constexpr OUStringLiteral sHeaderType = u"http://schemas.openxmlformats.org/officeDocument/2006/relationships/header";
148 static constexpr OUStringLiteral sOleObjectType = u"http://schemas.openxmlformats.org/officeDocument/2006/relationships/oleObject";
149 static constexpr OUStringLiteral sCommentsExtendedType = u"http://schemas.microsoft.com/office/2011/relationships/commentsExtended";
150 // OOXML strict
151 static constexpr OUStringLiteral sDocumentTypeStrict = u"http://purl.oclc.org/ooxml/officeDocument/relationships/officeDocument";
152 static constexpr OUStringLiteral sStylesTypeStrict = u"http://purl.oclc.org/ooxml/officeDocument/relationships/styles";
153 static constexpr OUStringLiteral sNumberingTypeStrict = u"http://purl.oclc.org/ooxml/officeDocument/relationships/numbering";
154 static constexpr OUStringLiteral sFonttableTypeStrict = u"http://purl.oclc.org/ooxml/officeDocument/relationships/fontTable";
155 static constexpr OUStringLiteral sFootnotesTypeStrict = u"http://purl.oclc.org/ooxml/officeDocument/relationships/footnotes";
156 static constexpr OUStringLiteral sEndnotesTypeStrict = u"http://purl.oclc.org/ooxml/officeDocument/relationships/endnotes";
157 static constexpr OUStringLiteral sCommentsTypeStrict = u"http://purl.oclc.org/ooxml/officeDocument/relationships/comments";
158 static constexpr OUStringLiteral sThemeTypeStrict = u"http://purl.oclc.org/ooxml/officeDocument/relationships/theme";
159 static constexpr OUStringLiteral sCustomTypeStrict = u"http://purl.oclc.org/ooxml/officeDocument/relationships/customXml";
160 static constexpr OUStringLiteral sCustomPropsTypeStrict = u"http://purl.oclc.org/ooxml/officeDocument/relationships/customXmlProps";
161 static constexpr OUStringLiteral sGlossaryTypeStrict = u"http://purl.oclc.org/ooxml/officeDocument/relationships/glossaryDocument";
162 static constexpr OUStringLiteral sWebSettingsStrict = u"http://purl.oclc.org/ooxml/officeDocument/relationships/webSettings";
163 static constexpr OUStringLiteral sSettingsTypeStrict = u"http://purl.oclc.org/ooxml/officeDocument/relationships/settings";
164 static constexpr OUStringLiteral sChartTypeStrict = u"http://purl.oclc.org/ooxml/officeDocument/relationships/chart";
165 static constexpr OUStringLiteral sEmbeddingsTypeStrict = u"http://purl.oclc.org/ooxml/officeDocument/relationships/package";
166 static constexpr OUStringLiteral sFootersTypeStrict = u"http://purl.oclc.org/ooxml/officeDocument/relationships/footer";
167 static constexpr OUStringLiteral sHeaderTypeStrict = u"http://purl.oclc.org/ooxml/officeDocument/relationships/header";
168 static constexpr OUStringLiteral sOleObjectTypeStrict = u"http://purl.oclc.org/ooxml/officeDocument/relationships/oleObject";
169 static constexpr OUStringLiteral sVBAProjectType = u"http://schemas.microsoft.com/office/2006/relationships/vbaProject";
170 static constexpr OUStringLiteral sVBADataType = u"http://schemas.microsoft.com/office/2006/relationships/wordVbaData";
171
172 OUString sStreamType;
173 OUString sStreamTypeStrict;
174
175 switch (nStreamType)
176 {
177 case VBAPROJECT:
178 sStreamType = sVBAProjectType;
179 sStreamTypeStrict = sVBAProjectType;
180 break;
181 case VBADATA:
182 sStreamType = sVBADataType;
183 sStreamTypeStrict = sVBADataType;
184 break;
185 case DOCUMENT:
186 sStreamType = sDocumentType;
187 sStreamTypeStrict = sDocumentTypeStrict;
188 break;
189 case STYLES:
190 sStreamType = sStylesType;
191 sStreamTypeStrict = sStylesTypeStrict;
192 break;
193 case NUMBERING:
194 sStreamType = sNumberingType;
195 sStreamTypeStrict = sNumberingTypeStrict;
196 break;
197 case FONTTABLE:
198 sStreamType = sFonttableType;
199 sStreamTypeStrict = sFonttableTypeStrict;
200 break;
201 case FOOTNOTES:
202 sStreamType = sFootnotesType;
203 sStreamTypeStrict = sFootnotesTypeStrict;
204 break;
205 case ENDNOTES:
206 sStreamType = sEndnotesType;
207 sStreamTypeStrict = sEndnotesTypeStrict;
208 break;
209 case COMMENTS:
210 sStreamType = sCommentsType;
211 sStreamTypeStrict = sCommentsTypeStrict;
212 break;
213 case THEME:
214 sStreamType = sThemeType;
215 sStreamTypeStrict = sThemeTypeStrict;
216 break;
217 case CUSTOMXML:
218 sStreamType = sCustomType;
219 sStreamTypeStrict = sCustomTypeStrict;
220 break;
221 case CUSTOMXMLPROPS:
222 sStreamType = sCustomPropsType;
223 sStreamTypeStrict = sCustomPropsTypeStrict;
224 break;
225 case SETTINGS:
226 sStreamType = sSettingsType;
227 sStreamTypeStrict = sSettingsTypeStrict;
228 break;
229 case GLOSSARY:
230 sStreamType = sGlossaryType;
231 sStreamTypeStrict = sGlossaryTypeStrict;
232 break;
233 case WEBSETTINGS:
234 sStreamType = sWebSettings;
235 sStreamTypeStrict = sWebSettingsStrict;
236 break;
237 case CHARTS:
238 sStreamType = sChartType;
239 sStreamTypeStrict = sChartTypeStrict;
240 break;
241 case EMBEDDINGS:
242 sStreamType = sEmbeddingsType;
243 sStreamTypeStrict = sEmbeddingsTypeStrict;
244 break;
245 case FOOTER:
246 sStreamType = sFooterType;
247 sStreamTypeStrict = sFootersTypeStrict;
248 break;
249 case HEADER:
250 sStreamType = sHeaderType;
251 sStreamTypeStrict = sHeaderTypeStrict;
252 break;
254 sStreamType = sCommentsExtendedType;
255 sStreamTypeStrict = sCommentsExtendedType;
256 break;
257 default:
258 break;
259 }
260
261 if (xRelationshipAccess.is())
262 {
264 xRelationshipAccess->getAllRelationships();
265
266 for (const uno::Sequence< beans::StringPair > &rSeq : aSeqs)
267 {
268 bool bExternalTarget = false;
269 OUString sMyTarget;
270 for (const beans::StringPair &rPair : rSeq)
271 {
272 if (rPair.First == sType &&
273 ( rPair.Second == sStreamType ||
274 rPair.Second == sStreamTypeStrict ))
275 bFound = true;
276 else if(rPair.First == sType &&
277 ((rPair.Second == sOleObjectType ||
278 rPair.Second == sOleObjectTypeStrict) &&
279 nStreamType == EMBEDDINGS))
280 {
281 bFound = true;
282 }
283 else if (rPair.First == sId &&
284 rPair.Second == rId)
285 bFound = true;
286 else if (rPair.First == sTarget)
287 {
288 // checking item[n].xml is not visited already.
289 if(customTarget != rPair.Second && (sStreamType == sCustomType || sStreamType == sChartType || sStreamType == sFooterType || sStreamType == sHeaderType))
290 {
291 bFound = false;
292 }
293 else
294 {
295 sMyTarget = rPair.Second;
296 }
297 }
298 else if (rPair.First == sTargetMode &&
299 rPair.Second == sExternal)
300 bExternalTarget = true;
301 }
302
303 if (bFound)
304 {
305 if (bExternalTarget)
306 rDocumentTarget = sMyTarget;
307 else
308 {
309 // 'Target' is a relative Uri, so a 'Target=/path'
310 // with a base Uri of file://base/foo will resolve to
311 // file://base/word. We need something more than some
312 // simple string concatenation here to handle that.
313 uno::Reference<uri::XUriReference> xPart = xFac->parse(sMyTarget);
314 uno::Reference<uri::XUriReference> xAbs = xFac->makeAbsolute(xBase, xPart, true, uri::RelativeUriExcessParentSegments_RETAIN);
315 if (!xAbs)
316 {
317 //it was invalid gibberish
318 bFound = false;
319 }
320 else
321 {
322 rDocumentTarget = xAbs->getPath();
323 // path will start with the fragment separator. need to
324 // remove that
325 rDocumentTarget = rDocumentTarget.copy( 1 );
326 if(sStreamType == sEmbeddingsType)
327 embeddingsTarget = rDocumentTarget;
328 }
329 }
330
331 break;
332 }
333 }
334 }
335
336 return bFound;
337}
338
339OUString OOXMLStreamImpl::getTargetForId(const OUString & rId)
340{
341 OUString sTarget;
342
344 (mxDocumentStream, uno::UNO_QUERY_THROW);
345
346 if (lcl_getTarget(xRelationshipAccess, UNKNOWN, rId, sTarget))
347 return sTarget;
348
349 return OUString();
350}
351
353{
356
357 if (!bFound)
358 return;
359
360 sal_Int32 nLastIndex = msTarget.lastIndexOf('/');
361 if (nLastIndex >= 0)
362 msPath = msTarget.copy(0, nLastIndex + 1);
363
365 xHierarchicalStorageAccess(mxStorage, uno::UNO_QUERY);
366
367 if (xHierarchicalStorageAccess.is())
368 {
369 uno::Any aAny(xHierarchicalStorageAccess->
370 openStreamElementByHierarchicalName
371 (msTarget, embed::ElementModes::SEEKABLEREAD));
372 aAny >>= mxDocumentStream;
373 // Non-cached ID lookup works by accessing mxDocumentStream as an embed::XRelationshipAccess.
374 // So when it changes, we should empty the cache.
375 maIdCache.clear();
376 }
377}
378
380{
382
383 if (mxDocumentStream.is())
384 xResult = mxDocumentStream->getInputStream();
385
386 return xResult;
387}
388
390{
391 return mxContext;
392}
393
395{
396 if (! mxFastTokenHandler.is())
398
399 return mxFastTokenHandler;
400}
401
406 bool bRepairStorage)
407{
408 OOXMLStreamImpl * pStream = new OOXMLStreamImpl(xContext, rStream,
409 OOXMLStream::DOCUMENT, bRepairStorage);
410 return OOXMLStream::Pointer_t(pStream);
411}
412
415(const OOXMLStream::Pointer_t& pStream, OOXMLStream::StreamType_t nStreamType)
416{
418
419 if (nStreamType != OOXMLStream::VBADATA)
420 {
421 if (OOXMLStreamImpl* pImpl = dynamic_cast<OOXMLStreamImpl *>(pStream.get()))
422 pRet = new OOXMLStreamImpl(*pImpl, nStreamType);
423 }
424 else
425 {
426 // VBADATA is not a relation of the document, but of the VBAPROJECT stream.
427 if (OOXMLStreamImpl* pImpl = dynamic_cast<OOXMLStreamImpl *>(pStream.get()))
428 {
430 pRet = new OOXMLStreamImpl(aProject, OOXMLStream::VBADATA);
431 }
432 }
433
434 return pRet;
435}
436
439(const OOXMLStream::Pointer_t& pStream, const OUString & rId)
440{
442 if (OOXMLStreamImpl* pImpl = dynamic_cast<OOXMLStreamImpl *>(pStream.get()))
443 pRet = new OOXMLStreamImpl(*pImpl, rId);
444 return pRet;
445}
446
447}
448
449/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
OptionalString sType
OUString customTarget
OUString embeddingsTarget
FILE * init(int, char **)
static css::uno::Reference< css::embed::XStorage > GetStorageOfFormatFromInputStream(const OUString &aFormat, const css::uno::Reference< css::io::XInputStream > &xStream, const css::uno::Reference< css::uno::XComponentContext > &rxContext=css::uno::Reference< css::uno::XComponentContext >(), bool bRepairStorage=false)
T * get() const
static OOXMLStream::Pointer_t createStream(const css::uno::Reference< css::uno::XComponentContext > &rContext, const css::uno::Reference< css::io::XInputStream > &rStream, bool bRepairStorage)
css::uno::Reference< css::embed::XRelationshipAccess > mxRelationshipAccess
bool lcl_getTarget(const css::uno::Reference< css::embed::XRelationshipAccess > &xRelationshipAccess, StreamType_t nStreamType, const OUString &rId, OUString &rDocumentTarget)
css::uno::Reference< css::io::XStream > mxDocumentStream
OOXMLStreamImpl(OOXMLStreamImpl const &rStream, StreamType_t nType)
virtual css::uno::Reference< css::io::XInputStream > getDocumentStream() override
virtual css::uno::Reference< css::uno::XComponentContext > getContext() override
Returns component context for this stream.
virtual const OUString & getTarget() const override
css::uno::Reference< css::xml::sax::XFastTokenHandler > mxFastTokenHandler
std::map< OUString, OUString > maIdCache
Cache holding an Id <-> Target map of external relations.
css::uno::Reference< css::uno::XComponentContext > mxContext
css::uno::Reference< css::embed::XStorage > mxStorage
virtual css::uno::Reference< css::xml::sax::XFastTokenHandler > getFastTokenHandler() override
virtual OUString getTargetForId(const OUString &rId) override
Returns target URL from relationships for a given id.
tools::SvRef< OOXMLStream > Pointer_t
uno::Reference< uno::XComponentContext > mxContext
float u
UNKNOWN
Reference< XNameContainer > mxStorage
QPRO_FUNC_TYPE nType
OUString sId