lok: vcl: fix multiple floatwin removal case more robustly.
[LibreOffice.git] / writerfilter / source / ooxml / OOXMLStreamImpl.cxx
blobe4e53acc8f1f1294572d914522bfa97181c0d63e
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 uno::Sequence< uno::Sequence<beans::StringPair> >aSeqs = xRelationshipAccess->getAllRelationships();
99 for (sal_Int32 i = 0; i < aSeqs.getLength(); ++i)
101 const uno::Sequence<beans::StringPair>& rSeq = aSeqs[i];
102 OUString aId;
103 OUString aTarget;
104 bool bExternal = false;
105 for (sal_Int32 j = 0; j < rSeq.getLength(); ++j)
107 const beans::StringPair& rPair = rSeq[j];
108 if (rPair.First == sId)
109 aId = rPair.Second;
110 else if (rPair.First == sTarget)
111 aTarget = rPair.Second;
112 else if (rPair.First == sTargetMode && rPair.Second == sExternal)
113 bExternal = true;
115 // Only cache external targets, internal ones are more complex (see below)
116 if (bExternal)
117 maIdCache[aId] = aTarget;
121 if (maIdCache.find(rId) != maIdCache.end())
123 rDocumentTarget = maIdCache[rId];
124 return true;
127 bool bFound = false;
128 static uno::Reference<uri::XUriReferenceFactory> xFac = uri::UriReferenceFactory::create(mxContext);
129 // use '/' to representent the root of the zip package ( and provide a 'file' scheme to
130 // keep the XUriReference implementation happy )
131 // add mspath to represent the 'source' of this stream
132 uno::Reference<uri::XUriReference> xBase = xFac->parse("file:///" + msPath);
134 static const char sType[] = "Type";
135 static const char sDocumentType[] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument";
136 static const char sStylesType[] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles";
137 static const char sNumberingType[] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/numbering";
138 static const char sFonttableType[] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/fontTable";
139 static const char sFootnotesType[] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/footnotes";
140 static const char sEndnotesType[] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/endnotes";
141 static const char sCommentsType[] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments";
142 static const char sThemeType[] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme";
143 static const char sCustomType[] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/customXml";
144 static const char sCustomPropsType[] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/customXmlProps";
145 static const char sGlossaryType[] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/glossaryDocument";
146 static const char sWebSettings[] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/webSettings";
147 static const char sSettingsType[] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/settings";
148 static const char sChartType[] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart";
149 static const char sEmbeddingsType[] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/package";
150 static const char sFooterType[] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/footer";
151 static const char sHeaderType[] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/header";
152 static const char sOleObjectType[] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/oleObject";
153 // OOXML strict
154 static const char sDocumentTypeStrict[] = "http://purl.oclc.org/ooxml/officeDocument/relationships/officeDocument";
155 static const char sStylesTypeStrict[] = "http://purl.oclc.org/ooxml/officeDocument/relationships/styles";
156 static const char sNumberingTypeStrict[] = "http://purl.oclc.org/ooxml/officeDocument/relationships/numbering";
157 static const char sFonttableTypeStrict[] = "http://purl.oclc.org/ooxml/officeDocument/relationships/fontTable";
158 static const char sFootnotesTypeStrict[] = "http://purl.oclc.org/ooxml/officeDocument/relationships/footnotes";
159 static const char sEndnotesTypeStrict[] = "http://purl.oclc.org/ooxml/officeDocument/relationships/endnotes";
160 static const char sCommentsTypeStrict[] = "http://purl.oclc.org/ooxml/officeDocument/relationships/comments";
161 static const char sThemeTypeStrict[] = "http://purl.oclc.org/ooxml/officeDocument/relationships/theme";
162 static const char sCustomTypeStrict[] = "http://purl.oclc.org/ooxml/officeDocument/relationships/customXml";
163 static const char sCustomPropsTypeStrict[] = "http://purl.oclc.org/ooxml/officeDocument/relationships/customXmlProps";
164 static const char sGlossaryTypeStrict[] = "http://purl.oclc.org/ooxml/officeDocument/relationships/glossaryDocument";
165 static const char sWebSettingsStrict[] = "http://purl.oclc.org/ooxml/officeDocument/relationships/webSettings";
166 static const char sSettingsTypeStrict[] = "http://purl.oclc.org/ooxml/officeDocument/relationships/settings";
167 static const char sChartTypeStrict[] = "http://purl.oclc.org/ooxml/officeDocument/relationships/chart";
168 static const char sEmbeddingsTypeStrict[] = "http://purl.oclc.org/ooxml/officeDocument/relationships/package";
169 static const char sFootersTypeStrict[] = "http://purl.oclc.org/ooxml/officeDocument/relationships/footer";
170 static const char sHeaderTypeStrict[] = "http://purl.oclc.org/ooxml/officeDocument/relationships/header";
171 static const char sOleObjectTypeStrict[] = "http://purl.oclc.org/ooxml/officeDocument/relationships/oleObject";
172 static const char sVBAProjectType[] = "http://schemas.microsoft.com/office/2006/relationships/vbaProject";
173 static const char sVBADataType[] = "http://schemas.microsoft.com/office/2006/relationships/wordVbaData";
175 OUString sStreamType;
176 OUString sStreamTypeStrict;
178 switch (nStreamType)
180 case VBAPROJECT:
181 sStreamType = sVBAProjectType;
182 sStreamTypeStrict = sVBAProjectType;
183 break;
184 case VBADATA:
185 sStreamType = sVBADataType;
186 sStreamTypeStrict = sVBADataType;
187 break;
188 case DOCUMENT:
189 sStreamType = sDocumentType;
190 sStreamTypeStrict = sDocumentTypeStrict;
191 break;
192 case STYLES:
193 sStreamType = sStylesType;
194 sStreamTypeStrict = sStylesTypeStrict;
195 break;
196 case NUMBERING:
197 sStreamType = sNumberingType;
198 sStreamTypeStrict = sNumberingTypeStrict;
199 break;
200 case FONTTABLE:
201 sStreamType = sFonttableType;
202 sStreamTypeStrict = sFonttableTypeStrict;
203 break;
204 case FOOTNOTES:
205 sStreamType = sFootnotesType;
206 sStreamTypeStrict = sFootnotesTypeStrict;
207 break;
208 case ENDNOTES:
209 sStreamType = sEndnotesType;
210 sStreamTypeStrict = sEndnotesTypeStrict;
211 break;
212 case COMMENTS:
213 sStreamType = sCommentsType;
214 sStreamTypeStrict = sCommentsTypeStrict;
215 break;
216 case THEME:
217 sStreamType = sThemeType;
218 sStreamTypeStrict = sThemeTypeStrict;
219 break;
220 case CUSTOMXML:
221 sStreamType = sCustomType;
222 sStreamTypeStrict = sCustomTypeStrict;
223 break;
224 case CUSTOMXMLPROPS:
225 sStreamType = sCustomPropsType;
226 sStreamTypeStrict = sCustomPropsTypeStrict;
227 break;
228 case SETTINGS:
229 sStreamType = sSettingsType;
230 sStreamTypeStrict = sSettingsTypeStrict;
231 break;
232 case GLOSSARY:
233 sStreamType = sGlossaryType;
234 sStreamTypeStrict = sGlossaryTypeStrict;
235 break;
236 case WEBSETTINGS:
237 sStreamType = sWebSettings;
238 sStreamTypeStrict = sWebSettingsStrict;
239 break;
240 case CHARTS:
241 sStreamType = sChartType;
242 sStreamTypeStrict = sChartTypeStrict;
243 break;
244 case EMBEDDINGS:
245 sStreamType = sEmbeddingsType;
246 sStreamTypeStrict = sEmbeddingsTypeStrict;
247 break;
248 case FOOTER:
249 sStreamType = sFooterType;
250 sStreamTypeStrict = sFootersTypeStrict;
251 break;
252 case HEADER:
253 sStreamType = sHeaderType;
254 sStreamTypeStrict = sHeaderTypeStrict;
255 break;
256 default:
257 break;
260 if (xRelationshipAccess.is())
262 uno::Sequence< uno::Sequence< beans::StringPair > >aSeqs =
263 xRelationshipAccess->getAllRelationships();
265 for (sal_Int32 j = 0; j < aSeqs.getLength(); j++)
267 const uno::Sequence< beans::StringPair > &rSeq = aSeqs[j];
269 bool bExternalTarget = false;
270 OUString sMyTarget;
271 for (sal_Int32 i = 0; i < rSeq.getLength(); i++)
273 const beans::StringPair &rPair = rSeq[i];
275 if (rPair.First == sType &&
276 ( rPair.Second == sStreamType ||
277 rPair.Second == sStreamTypeStrict ))
278 bFound = true;
279 else if(rPair.First == sType &&
280 ((rPair.Second == sOleObjectType ||
281 rPair.Second == sOleObjectTypeStrict) &&
282 nStreamType == EMBEDDINGS))
284 bFound = true;
286 else if (rPair.First == sId &&
287 rPair.Second == rId)
288 bFound = true;
289 else if (rPair.First == sTarget)
291 // checking item[n].xml is not visited already.
292 if(customTarget != rPair.Second && (sStreamType == sCustomType || sStreamType == sChartType || sStreamType == sFooterType || sStreamType == sHeaderType))
294 bFound = false;
296 else
298 sMyTarget = rPair.Second;
301 else if (rPair.First == sTargetMode &&
302 rPair.Second == sExternal)
303 bExternalTarget = true;
307 if (bFound)
309 if (bExternalTarget)
310 rDocumentTarget = sMyTarget;
311 else
313 // 'Target' is a relative Uri, so a 'Target=/path'
314 // with a base Uri of file://base/foo will resolve to
315 // file://base/word. We need something more than some
316 // simple string concatenation here to handle that.
317 uno::Reference<uri::XUriReference> xPart = xFac->parse(sMyTarget);
318 uno::Reference<uri::XUriReference> xAbs = xFac->makeAbsolute(xBase, xPart, true, uri::RelativeUriExcessParentSegments_RETAIN);
319 if (!xAbs)
321 //it was invalid gibberish
322 bFound = false;
324 else
326 rDocumentTarget = xAbs->getPath();
327 // path will start with the fragment separator. need to
328 // remove that
329 rDocumentTarget = rDocumentTarget.copy( 1 );
330 if(sStreamType == sEmbeddingsType)
331 embeddingsTarget = rDocumentTarget;
335 break;
340 return bFound;
343 OUString OOXMLStreamImpl::getTargetForId(const OUString & rId)
345 OUString sTarget;
347 uno::Reference<embed::XRelationshipAccess> xRelationshipAccess
348 (mxDocumentStream, uno::UNO_QUERY_THROW);
350 if (lcl_getTarget(xRelationshipAccess, UNKNOWN, rId, sTarget))
351 return sTarget;
353 return OUString();
356 void OOXMLStreamImpl::init()
358 bool bFound = lcl_getTarget(mxRelationshipAccess,
359 mnStreamType, msId, msTarget);
361 if (bFound)
363 sal_Int32 nLastIndex = msTarget.lastIndexOf('/');
364 if (nLastIndex >= 0)
365 msPath = msTarget.copy(0, nLastIndex + 1);
367 uno::Reference<embed::XHierarchicalStorageAccess>
368 xHierarchicalStorageAccess(mxStorage, uno::UNO_QUERY);
370 if (xHierarchicalStorageAccess.is())
372 uno::Any aAny(xHierarchicalStorageAccess->
373 openStreamElementByHierarchicalName
374 (msTarget, embed::ElementModes::SEEKABLEREAD));
375 aAny >>= mxDocumentStream;
376 // Non-cached ID lookup works by accessing mxDocumentStream as an embed::XRelationshipAccess.
377 // So when it changes, we should empty the cache.
378 maIdCache.clear();
383 uno::Reference<io::XInputStream> OOXMLStreamImpl::getDocumentStream()
385 uno::Reference<io::XInputStream> xResult;
387 if (mxDocumentStream.is())
388 xResult = mxDocumentStream->getInputStream();
390 return xResult;
393 uno::Reference<uno::XComponentContext> OOXMLStreamImpl::getContext()
395 return mxContext;
398 uno::Reference <xml::sax::XFastTokenHandler> OOXMLStreamImpl::getFastTokenHandler()
400 if (! mxFastTokenHandler.is())
401 mxFastTokenHandler.set(new oox::core::FastTokenHandler());
403 return mxFastTokenHandler;
406 OOXMLStream::Pointer_t
407 OOXMLDocumentFactory::createStream
408 (const uno::Reference<uno::XComponentContext>& xContext,
409 const uno::Reference<io::XInputStream>& rStream,
410 bool bRepairStorage)
412 OOXMLStreamImpl * pStream = new OOXMLStreamImpl(xContext, rStream,
413 OOXMLStream::DOCUMENT, bRepairStorage);
414 return OOXMLStream::Pointer_t(pStream);
417 OOXMLStream::Pointer_t
418 OOXMLDocumentFactory::createStream
419 (const OOXMLStream::Pointer_t& pStream, OOXMLStream::StreamType_t nStreamType)
421 OOXMLStream::Pointer_t pRet;
423 if (nStreamType != OOXMLStream::VBADATA)
425 if (OOXMLStreamImpl* pImpl = dynamic_cast<OOXMLStreamImpl *>(pStream.get()))
426 pRet = new OOXMLStreamImpl(*pImpl, nStreamType);
428 else
430 // VBADATA is not a relation of the document, but of the VBAPROJECT stream.
431 if (OOXMLStreamImpl* pImpl = dynamic_cast<OOXMLStreamImpl *>(pStream.get()))
433 std::unique_ptr<OOXMLStreamImpl> pProject(new OOXMLStreamImpl(*pImpl, OOXMLStream::VBAPROJECT));
434 pRet = new OOXMLStreamImpl(*pProject, OOXMLStream::VBADATA);
438 return pRet;
441 OOXMLStream::Pointer_t
442 OOXMLDocumentFactory::createStream
443 (const OOXMLStream::Pointer_t& pStream, const OUString & rId)
445 OOXMLStream::Pointer_t pRet;
446 if (OOXMLStreamImpl* pImpl = dynamic_cast<OOXMLStreamImpl *>(pStream.get()))
447 pRet = new OOXMLStreamImpl(*pImpl, rId);
448 return pRet;
453 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */