Line data Source code
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"
21 : #include "OOXMLFastTokenHandler.hxx"
22 : #include "ooxmlLoggers.hxx"
23 : #include <iostream>
24 :
25 : #include <com/sun/star/embed/XHierarchicalStorageAccess.hpp>
26 : #include <com/sun/star/uri/UriReferenceFactory.hpp>
27 : #include <com/sun/star/xml/sax/Parser.hpp>
28 :
29 : //#define DEBUG_STREAM
30 :
31 : namespace writerfilter {
32 : namespace ooxml
33 : {
34 :
35 : using namespace ::std;
36 :
37 904 : OOXMLStreamImpl::OOXMLStreamImpl
38 : (uno::Reference<uno::XComponentContext> xContext,
39 : uno::Reference<io::XInputStream> xStorageStream,
40 : StreamType_t nType, bool bRepairStorage)
41 904 : : mxContext(xContext), mxStorageStream(xStorageStream), mnStreamType(nType)
42 : {
43 : mxStorage.set
44 : (comphelper::OStorageHelper::GetStorageOfFormatFromInputStream
45 904 : (OFOPXML_STORAGE_FORMAT_STRING, mxStorageStream, xContext, bRepairStorage));
46 904 : mxRelationshipAccess.set(mxStorage, uno::UNO_QUERY_THROW);
47 :
48 904 : init();
49 904 : }
50 :
51 19197 : OOXMLStreamImpl::OOXMLStreamImpl
52 : (OOXMLStreamImpl & rOOXMLStream, StreamType_t nStreamType)
53 : : mxContext(rOOXMLStream.mxContext),
54 : mxStorageStream(rOOXMLStream.mxStorageStream),
55 : mxStorage(rOOXMLStream.mxStorage),
56 : mnStreamType(nStreamType),
57 19203 : msPath(rOOXMLStream.msPath)
58 : {
59 19197 : mxRelationshipAccess.set(rOOXMLStream.mxDocumentStream, uno::UNO_QUERY_THROW);
60 :
61 19197 : init();
62 19191 : }
63 :
64 822 : OOXMLStreamImpl::OOXMLStreamImpl
65 : (OOXMLStreamImpl & rOOXMLStream, const OUString & rId)
66 : : mxContext(rOOXMLStream.mxContext),
67 : mxStorageStream(rOOXMLStream.mxStorageStream),
68 : mxStorage(rOOXMLStream.mxStorage),
69 : mnStreamType(UNKNOWN),
70 : msId(rId),
71 822 : msPath(rOOXMLStream.msPath)
72 : {
73 822 : mxRelationshipAccess.set(rOOXMLStream.mxDocumentStream, uno::UNO_QUERY_THROW);
74 :
75 822 : init();
76 822 : }
77 :
78 41834 : OOXMLStreamImpl::~OOXMLStreamImpl()
79 : {
80 : #ifdef DEBUG_STREAM
81 : debug_logger->endElement("stream");
82 : #endif
83 41834 : }
84 :
85 1088 : const OUString & OOXMLStreamImpl::getTarget() const
86 : {
87 1088 : return msTarget;
88 : }
89 :
90 21516 : bool OOXMLStreamImpl::lcl_getTarget(uno::Reference<embed::XRelationshipAccess>
91 : xRelationshipAccess,
92 : StreamType_t nStreamType,
93 : const OUString & rId,
94 : OUString & rDocumentTarget)
95 : {
96 21516 : static OUString sId("Id");
97 21516 : static OUString sTarget("Target");
98 21516 : static OUString sTargetMode("TargetMode");
99 21516 : static OUString sExternal("External");
100 21516 : if (maIdCache.empty())
101 : {
102 : // Cache is empty? Then let's build it!
103 20954 : uno::Sequence< uno::Sequence<beans::StringPair> >aSeqs = xRelationshipAccess->getAllRelationships();
104 2415471 : for (sal_Int32 i = 0; i < aSeqs.getLength(); ++i)
105 : {
106 2394517 : const uno::Sequence<beans::StringPair>& rSeq = aSeqs[i];
107 2394517 : OUString aId;
108 4789034 : OUString aTarget;
109 2394517 : bool bExternal = false;
110 9999966 : for (sal_Int32 j = 0; j < rSeq.getLength(); ++j)
111 : {
112 7605449 : const beans::StringPair& rPair = rSeq[j];
113 7605449 : if (rPair.First == sId)
114 2394517 : aId = rPair.Second;
115 5210932 : else if (rPair.First == sTarget)
116 2394509 : aTarget = rPair.Second;
117 2816423 : else if (rPair.First == sTargetMode && rPair.Second == sExternal)
118 421906 : bExternal = true;
119 : }
120 : // Only cache external targets, internal ones are more complex (see below)
121 2394517 : if (bExternal)
122 421906 : maIdCache[aId] = aTarget;
123 2415471 : }
124 : }
125 :
126 21516 : if (maIdCache.find(rId) != maIdCache.end())
127 : {
128 593 : rDocumentTarget = maIdCache[rId];
129 593 : return true;
130 : }
131 :
132 20923 : bool bFound = false;
133 20923 : static uno::Reference< com::sun::star::uri::XUriReferenceFactory > xFac = ::com::sun::star::uri::UriReferenceFactory::create( mxContext );
134 : // use '/' to representent the root of the zip package ( and provide a 'file' scheme to
135 : // keep the XUriReference implementation happy )
136 : // add mspath to represent the 'source' of this stream
137 20923 : uno::Reference< com::sun::star::uri::XUriReference > xBase = xFac->parse( OUString( "file:///" ) + msPath );
138 :
139 20923 : static OUString sType("Type");
140 20923 : static OUString sDocumentType("http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument");
141 20923 : static OUString sStylesType("http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles");
142 20923 : static OUString sNumberingType("http://schemas.openxmlformats.org/officeDocument/2006/relationships/numbering");
143 20923 : static OUString sFonttableType("http://schemas.openxmlformats.org/officeDocument/2006/relationships/fontTable");
144 20923 : static OUString sFootnotesType("http://schemas.openxmlformats.org/officeDocument/2006/relationships/footnotes");
145 20923 : static OUString sEndnotesType("http://schemas.openxmlformats.org/officeDocument/2006/relationships/endnotes");
146 20923 : static OUString sCommentsType("http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments");
147 20923 : static OUString sThemeType("http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme");
148 20923 : static OUString sCustomType("http://schemas.openxmlformats.org/officeDocument/2006/relationships/customXml");
149 20923 : static OUString sCustomPropsType("http://schemas.openxmlformats.org/officeDocument/2006/relationships/customXmlProps");
150 20923 : static OUString sActiveXType("http://schemas.openxmlformats.org/officeDocument/2006/relationships/control");
151 20923 : static OUString sActiveXBinType("http://schemas.microsoft.com/office/2006/relationships/activeXControlBinary");
152 20923 : static OUString sGlossaryType("http://schemas.openxmlformats.org/officeDocument/2006/relationships/glossaryDocument");
153 20923 : static OUString sWebSettings("http://schemas.openxmlformats.org/officeDocument/2006/relationships/webSettings");
154 20923 : static OUString sSettingsType("http://schemas.openxmlformats.org/officeDocument/2006/relationships/settings");
155 20923 : static OUString sChartType("http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart");
156 20923 : static OUString sEmbeddingsType("http://schemas.openxmlformats.org/officeDocument/2006/relationships/package");
157 20923 : static OUString sFooterType("http://schemas.openxmlformats.org/officeDocument/2006/relationships/footer");
158 20923 : static OUString sHeaderType("http://schemas.openxmlformats.org/officeDocument/2006/relationships/header");
159 20923 : static OUString sOleObjectType("http://schemas.openxmlformats.org/officeDocument/2006/relationships/oleObject");
160 : // OOXML strict
161 20923 : static OUString sDocumentTypeStrict("http://purl.oclc.org/ooxml/officeDocument/relationships/officeDocument");
162 20923 : static OUString sStylesTypeStrict("http://purl.oclc.org/ooxml/officeDocument/relationships/styles");
163 20923 : static OUString sNumberingTypeStrict("http://purl.oclc.org/ooxml/officeDocument/relationships/numbering");
164 20923 : static OUString sFonttableTypeStrict("http://purl.oclc.org/ooxml/officeDocument/relationships/fontTable");
165 20923 : static OUString sFootnotesTypeStrict("http://purl.oclc.org/ooxml/officeDocument/relationships/footnotes");
166 20923 : static OUString sEndnotesTypeStrict("http://purl.oclc.org/ooxml/officeDocument/relationships/endnotes");
167 20923 : static OUString sCommentsTypeStrict("http://purl.oclc.org/ooxml/officeDocument/relationships/comments");
168 20923 : static OUString sThemeTypeStrict("http://purl.oclc.org/ooxml/officeDocument/relationships/theme");
169 20923 : static OUString sCustomTypeStrict("http://purl.oclc.org/ooxml/officeDocument/relationships/customXml");
170 20923 : static OUString sCustomPropsTypeStrict("http://purl.oclc.org/ooxml/officeDocument/relationships/customXmlProps");
171 20923 : static OUString sActiveXTypeStrict("http://purl.oclc.org/ooxml/officeDocument/relationships/control");
172 20923 : static OUString sGlossaryTypeStrict("http://purl.oclc.org/ooxml/officeDocument/relationships/glossaryDocument");
173 20923 : static OUString sWebSettingsStrict("http://purl.oclc.org/ooxml/officeDocument/relationships/webSettings");
174 20923 : static OUString sSettingsTypeStrict("http://purl.oclc.org/ooxml/officeDocument/relationships/settings");
175 20923 : static OUString sChartTypeStrict("http://purl.oclc.org/ooxml/officeDocument/relationships/chart");
176 20923 : static OUString sEmbeddingsTypeStrict("http://purl.oclc.org/ooxml/officeDocument/relationships/package");
177 20923 : static OUString sFootersTypeStrict("http://purl.oclc.org/ooxml/officeDocument/relationships/footer");
178 20923 : static OUString sHeaderTypeStrict("http://purl.oclc.org/ooxml/officeDocument/relationships/header");
179 20923 : static OUString sOleObjectTypeStrict("http://purl.oclc.org/ooxml/officeDocument/relationships/oleObject");
180 20923 : static OUString sVBAProjectType("http://schemas.microsoft.com/office/2006/relationships/vbaProject");
181 :
182 41846 : OUString sStreamType;
183 41846 : OUString sStreamTypeStrict;
184 :
185 20923 : switch (nStreamType)
186 : {
187 : case VBAPROJECT:
188 904 : sStreamType = sVBAProjectType;
189 904 : sStreamTypeStrict = sVBAProjectType;
190 904 : break;
191 : case DOCUMENT:
192 904 : sStreamType = sDocumentType;
193 904 : sStreamTypeStrict = sDocumentTypeStrict;
194 904 : break;
195 : case STYLES:
196 1779 : sStreamType = sStylesType;
197 1779 : sStreamTypeStrict = sStylesTypeStrict;
198 1779 : break;
199 : case NUMBERING:
200 1745 : sStreamType = sNumberingType;
201 1745 : sStreamTypeStrict = sNumberingTypeStrict;
202 1745 : break;
203 : case FONTTABLE:
204 1779 : sStreamType = sFonttableType;
205 1779 : sStreamTypeStrict = sFonttableTypeStrict;
206 1779 : break;
207 : case FOOTNOTES:
208 24 : sStreamType = sFootnotesType;
209 24 : sStreamTypeStrict = sFootnotesTypeStrict;
210 24 : break;
211 : case ENDNOTES:
212 6 : sStreamType = sEndnotesType;
213 6 : sStreamTypeStrict = sEndnotesTypeStrict;
214 6 : break;
215 : case COMMENTS:
216 11 : sStreamType = sCommentsType;
217 11 : sStreamTypeStrict = sCommentsTypeStrict;
218 11 : break;
219 : case THEME:
220 3490 : sStreamType = sThemeType;
221 3490 : sStreamTypeStrict = sThemeTypeStrict;
222 3490 : break;
223 : case CUSTOMXML:
224 520 : sStreamType = sCustomType;
225 520 : sStreamTypeStrict = sCustomTypeStrict;
226 520 : break;
227 : case CUSTOMXMLPROPS:
228 260 : sStreamType = sCustomPropsType;
229 260 : sStreamTypeStrict = sCustomPropsTypeStrict;
230 260 : break;
231 : case ACTIVEX:
232 2778 : sStreamType = sActiveXType;
233 2778 : sStreamTypeStrict = sActiveXTypeStrict;
234 2778 : break;
235 : case ACTIVEXBIN:
236 1389 : sStreamType = sActiveXBinType;
237 1389 : sStreamTypeStrict = sActiveXBinType;
238 1389 : break;
239 : case SETTINGS:
240 1779 : sStreamType = sSettingsType;
241 1779 : sStreamTypeStrict = sSettingsTypeStrict;
242 1779 : break;
243 : case GLOSSARY:
244 1779 : sStreamType = sGlossaryType;
245 1779 : sStreamTypeStrict = sGlossaryTypeStrict;
246 1779 : break;
247 : case WEBSETTINGS:
248 34 : sStreamType = sWebSettings;
249 34 : sStreamTypeStrict = sWebSettingsStrict;
250 34 : break;
251 : case CHARTS:
252 56 : sStreamType = sChartType;
253 56 : sStreamTypeStrict = sChartTypeStrict;
254 56 : break;
255 : case EMBEDDINGS:
256 56 : sStreamType = sEmbeddingsType;
257 56 : sStreamTypeStrict = sEmbeddingsTypeStrict;
258 56 : break;
259 : case FOOTER:
260 419 : sStreamType = sFooterType;
261 419 : sStreamTypeStrict = sFootersTypeStrict;
262 419 : break;
263 : case HEADER:
264 389 : sStreamType = sHeaderType;
265 389 : sStreamTypeStrict = sHeaderTypeStrict;
266 389 : break;
267 : default:
268 822 : break;
269 : }
270 :
271 20923 : if (xRelationshipAccess.is())
272 : {
273 : uno::Sequence< uno::Sequence< beans::StringPair > >aSeqs =
274 20923 : xRelationshipAccess->getAllRelationships();
275 :
276 1234752 : for (sal_Int32 j = 0; j < aSeqs.getLength(); j++)
277 : {
278 1226109 : const uno::Sequence< beans::StringPair > &rSeq = aSeqs[j];
279 :
280 1226109 : bool bExternalTarget = false;
281 1226109 : OUString sMyTarget;
282 5117631 : for (sal_Int32 i = 0; i < rSeq.getLength(); i++)
283 : {
284 3891522 : const beans::StringPair &rPair = rSeq[i];
285 :
286 5744350 : if (rPair.First.compareTo(sType) == 0 &&
287 1825519 : ( rPair.Second.compareTo(sStreamType) == 0 ||
288 599410 : rPair.Second.compareTo(sStreamTypeStrict) == 0))
289 626719 : bFound = true;
290 3864200 : else if(rPair.First.compareTo(sType) == 0 &&
291 1198661 : ((rPair.Second.compareTo(sOleObjectType) == 0 ||
292 599391 : rPair.Second.compareTo(sOleObjectTypeStrict) == 0) &&
293 : nStreamType == EMBEDDINGS))
294 : {
295 7 : bFound = true;
296 : }
297 4490905 : else if (rPair.First.compareTo(sId) == 0 &&
298 1226109 : rPair.Second.compareTo(rId) == 0)
299 822 : bFound = true;
300 3263974 : else if (rPair.First.compareTo(sTarget) == 0)
301 : {
302 : // checking item[n].xml or activex[n].xml is not visited already.
303 1226102 : if(customTarget != rPair.Second && (sStreamType == sCustomType || sStreamType == sActiveXType || sStreamType == sChartType || sStreamType == sFooterType || sStreamType == sHeaderType))
304 : {
305 1156484 : bFound = false;
306 : }
307 : else
308 : {
309 69618 : sMyTarget = rPair.Second;
310 : }
311 : }
312 2251074 : else if (rPair.First.compareTo(sTargetMode) == 0 &&
313 213202 : rPair.Second.compareTo(sExternal) == 0)
314 213202 : bExternalTarget = true;
315 :
316 : }
317 :
318 1226109 : if (bFound)
319 : {
320 12280 : if (bExternalTarget)
321 6 : rDocumentTarget = sMyTarget;
322 : else
323 : {
324 : // 'Target' is a relative Uri, so a 'Target=/path'
325 : // with a base Uri of file://base/foo will resolve to
326 : // file://base/word. We need something more than some
327 : // simple string concatination here to handle that.
328 12274 : uno::Reference< com::sun::star::uri::XUriReference > xPart = xFac->parse( sMyTarget );
329 24548 : uno::Reference< com::sun::star::uri::XUriReference > xAbs = xFac->makeAbsolute( xBase, xPart, sal_True, com::sun::star::uri::RelativeUriExcessParentSegments_RETAIN );
330 12274 : rDocumentTarget = xAbs->getPath();
331 : // path will start with the fragment separator. need to
332 : // remove that
333 12274 : rDocumentTarget = rDocumentTarget.copy( 1 );
334 12274 : if(sStreamType == sEmbeddingsType)
335 12323 : embeddingsTarget = rDocumentTarget;
336 : }
337 :
338 12280 : break;
339 : }
340 1234752 : }
341 : }
342 :
343 41846 : return bFound;
344 : }
345 :
346 593 : OUString OOXMLStreamImpl::getTargetForId(const OUString & rId)
347 : {
348 593 : OUString sTarget;
349 :
350 : uno::Reference<embed::XRelationshipAccess> xRelationshipAccess
351 1186 : (mxDocumentStream, uno::UNO_QUERY_THROW);
352 :
353 593 : if (lcl_getTarget(xRelationshipAccess, UNKNOWN, rId, sTarget))
354 593 : return sTarget;
355 :
356 593 : return OUString();
357 : }
358 :
359 20923 : void OOXMLStreamImpl::init()
360 : {
361 : bool bFound = lcl_getTarget(mxRelationshipAccess,
362 20923 : mnStreamType, msId, msTarget);
363 : #ifdef DEBUG_STREAM
364 : debug_logger->startElement("stream");
365 : debug_logger->attribute("target", msTarget);
366 : #endif
367 :
368 20923 : if (bFound)
369 : {
370 12280 : sal_Int32 nLastIndex = msTarget.lastIndexOf('/');
371 12280 : if (nLastIndex >= 0)
372 12277 : msPath = msTarget.copy(0, nLastIndex + 1);
373 :
374 : uno::Reference<embed::XHierarchicalStorageAccess>
375 12280 : xHierarchicalStorageAccess(mxStorage, uno::UNO_QUERY);
376 :
377 12280 : if (xHierarchicalStorageAccess.is())
378 : {
379 12280 : uno::Any aAny(xHierarchicalStorageAccess->
380 : openStreamElementByHierarchicalName
381 12280 : (msTarget, embed::ElementModes::SEEKABLEREAD));
382 12274 : aAny >>= mxDocumentStream;
383 : // Non-cached ID lookup works by accessing mxDocumentStream as an embed::XRelationshipAccess.
384 : // So when it changes, we should empty the cache.
385 12274 : maIdCache.clear();
386 12280 : }
387 : }
388 20917 : }
389 :
390 20075 : uno::Reference<io::XInputStream> OOXMLStreamImpl::getDocumentStream()
391 : {
392 20075 : uno::Reference<io::XInputStream> xResult;
393 :
394 20075 : if (mxDocumentStream.is())
395 11432 : xResult = mxDocumentStream->getInputStream();
396 :
397 20075 : return xResult;
398 : }
399 :
400 : // Giving access to mxDocumentStream. It is needed by resolving custom xml to get list of customxml's used in document.
401 6077 : uno::Reference<io::XStream> OOXMLStreamImpl::accessDocumentStream()
402 : {
403 6077 : return mxDocumentStream;
404 : }
405 :
406 1088 : uno::Reference<io::XInputStream> OOXMLStreamImpl::getStorageStream()
407 : {
408 1088 : return mxStorageStream;
409 : }
410 :
411 0 : uno::Reference<xml::sax::XParser> OOXMLStreamImpl::getParser()
412 : {
413 0 : uno::Reference<xml::sax::XParser> xParser = xml::sax::Parser::create(mxContext);
414 0 : return xParser;
415 : }
416 :
417 15006 : uno::Reference<uno::XComponentContext> OOXMLStreamImpl::getContext()
418 : {
419 15006 : return mxContext;
420 : }
421 :
422 : uno::Reference <xml::sax::XFastTokenHandler>
423 12119 : OOXMLStreamImpl::getFastTokenHandler
424 : (uno::Reference<uno::XComponentContext> xContext)
425 : {
426 12119 : if (! mxFastTokenHandler.is())
427 12119 : mxFastTokenHandler.set(new OOXMLFastTokenHandler(xContext));
428 :
429 12119 : return mxFastTokenHandler;
430 : }
431 :
432 : OOXMLStream::Pointer_t
433 904 : OOXMLDocumentFactory::createStream
434 : (uno::Reference<uno::XComponentContext> xContext,
435 : uno::Reference<io::XInputStream> rStream,
436 : bool bRepairStorage,
437 : OOXMLStream::StreamType_t nStreamType)
438 : {
439 : OOXMLStreamImpl * pStream = new OOXMLStreamImpl(xContext, rStream,
440 904 : nStreamType, bRepairStorage);
441 904 : return OOXMLStream::Pointer_t(pStream);
442 : }
443 :
444 : OOXMLStream::Pointer_t
445 19197 : OOXMLDocumentFactory::createStream
446 : (OOXMLStream::Pointer_t pStream, OOXMLStream::StreamType_t nStreamType)
447 : {
448 19197 : OOXMLStream::Pointer_t pRet;
449 19197 : if (OOXMLStreamImpl* pImpl = dynamic_cast<OOXMLStreamImpl *>(pStream.get()))
450 19203 : pRet.reset(new OOXMLStreamImpl(*pImpl, nStreamType));
451 19191 : return pRet;
452 : }
453 :
454 : OOXMLStream::Pointer_t
455 822 : OOXMLDocumentFactory::createStream
456 : (OOXMLStream::Pointer_t pStream, const OUString & rId)
457 : {
458 822 : OOXMLStream::Pointer_t pRet;
459 822 : if (OOXMLStreamImpl* pImpl = dynamic_cast<OOXMLStreamImpl *>(pStream.get()))
460 822 : pRet.reset(new OOXMLStreamImpl(*pImpl, rId));
461 822 : return pRet;
462 : }
463 :
464 42 : }}
465 :
466 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|