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 0 : OOXMLStreamImpl::OOXMLStreamImpl
38 : (uno::Reference<uno::XComponentContext> xContext,
39 : uno::Reference<io::XInputStream> xStorageStream,
40 : StreamType_t nType, bool bRepairStorage)
41 0 : : mxContext(xContext), mxStorageStream(xStorageStream), mnStreamType(nType)
42 : {
43 : mxStorage.set
44 : (comphelper::OStorageHelper::GetStorageOfFormatFromInputStream
45 0 : (OFOPXML_STORAGE_FORMAT_STRING, mxStorageStream, xContext, bRepairStorage));
46 0 : mxRelationshipAccess.set(mxStorage, uno::UNO_QUERY_THROW);
47 :
48 0 : init();
49 0 : }
50 :
51 0 : OOXMLStreamImpl::OOXMLStreamImpl
52 : (OOXMLStreamImpl & rOOXMLStream, StreamType_t nStreamType)
53 : : mxContext(rOOXMLStream.mxContext),
54 : mxStorageStream(rOOXMLStream.mxStorageStream),
55 : mxStorage(rOOXMLStream.mxStorage),
56 : mnStreamType(nStreamType),
57 0 : msPath(rOOXMLStream.msPath)
58 : {
59 0 : mxRelationshipAccess.set(rOOXMLStream.mxDocumentStream, uno::UNO_QUERY_THROW);
60 :
61 0 : init();
62 0 : }
63 :
64 0 : 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 0 : msPath(rOOXMLStream.msPath)
72 : {
73 0 : mxRelationshipAccess.set(rOOXMLStream.mxDocumentStream, uno::UNO_QUERY_THROW);
74 :
75 0 : init();
76 0 : }
77 :
78 0 : OOXMLStreamImpl::~OOXMLStreamImpl()
79 : {
80 : #ifdef DEBUG_STREAM
81 : debug_logger->endElement("stream");
82 : #endif
83 0 : }
84 :
85 0 : const OUString & OOXMLStreamImpl::getTarget() const
86 : {
87 0 : return msTarget;
88 : }
89 :
90 0 : bool OOXMLStreamImpl::lcl_getTarget(uno::Reference<embed::XRelationshipAccess>
91 : xRelationshipAccess,
92 : StreamType_t nStreamType,
93 : const OUString & rId,
94 : OUString & rDocumentTarget)
95 : {
96 0 : static OUString sId("Id");
97 0 : static OUString sTarget("Target");
98 0 : static OUString sTargetMode("TargetMode");
99 0 : static OUString sExternal("External");
100 0 : if (maIdCache.empty())
101 : {
102 : // Cache is empty? Then let's build it!
103 0 : uno::Sequence< uno::Sequence<beans::StringPair> >aSeqs = xRelationshipAccess->getAllRelationships();
104 0 : for (sal_Int32 i = 0; i < aSeqs.getLength(); ++i)
105 : {
106 0 : const uno::Sequence<beans::StringPair>& rSeq = aSeqs[i];
107 0 : OUString aId;
108 0 : OUString aTarget;
109 0 : bool bExternal = false;
110 0 : for (sal_Int32 j = 0; j < rSeq.getLength(); ++j)
111 : {
112 0 : const beans::StringPair& rPair = rSeq[j];
113 0 : if (rPair.First == sId)
114 0 : aId = rPair.Second;
115 0 : else if (rPair.First == sTarget)
116 0 : aTarget = rPair.Second;
117 0 : else if (rPair.First == sTargetMode && rPair.Second == sExternal)
118 0 : bExternal = true;
119 : }
120 : // Only cache external targets, internal ones are more complex (see below)
121 0 : if (bExternal)
122 0 : maIdCache[aId] = aTarget;
123 0 : }
124 : }
125 :
126 0 : if (maIdCache.find(rId) != maIdCache.end())
127 : {
128 0 : rDocumentTarget = maIdCache[rId];
129 0 : return true;
130 : }
131 :
132 0 : bool bFound = false;
133 0 : 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 0 : uno::Reference< com::sun::star::uri::XUriReference > xBase = xFac->parse( OUString( "file:///" ) + msPath );
138 :
139 0 : static OUString sType("Type");
140 0 : static OUString sDocumentType("http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument");
141 0 : static OUString sStylesType("http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles");
142 0 : static OUString sNumberingType("http://schemas.openxmlformats.org/officeDocument/2006/relationships/numbering");
143 0 : static OUString sFonttableType("http://schemas.openxmlformats.org/officeDocument/2006/relationships/fontTable");
144 0 : static OUString sFootnotesType("http://schemas.openxmlformats.org/officeDocument/2006/relationships/footnotes");
145 0 : static OUString sEndnotesType("http://schemas.openxmlformats.org/officeDocument/2006/relationships/endnotes");
146 0 : static OUString sCommentsType("http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments");
147 0 : static OUString sThemeType("http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme");
148 0 : static OUString sCustomType("http://schemas.openxmlformats.org/officeDocument/2006/relationships/customXml");
149 0 : static OUString sCustomPropsType("http://schemas.openxmlformats.org/officeDocument/2006/relationships/customXmlProps");
150 0 : static OUString sActiveXType("http://schemas.openxmlformats.org/officeDocument/2006/relationships/control");
151 0 : static OUString sActiveXBinType("http://schemas.microsoft.com/office/2006/relationships/activeXControlBinary");
152 0 : static OUString sGlossaryType("http://schemas.openxmlformats.org/officeDocument/2006/relationships/glossaryDocument");
153 0 : static OUString sWebSettings("http://schemas.openxmlformats.org/officeDocument/2006/relationships/webSettings");
154 0 : static OUString sSettingsType("http://schemas.openxmlformats.org/officeDocument/2006/relationships/settings");
155 0 : static OUString sChartType("http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart");
156 0 : static OUString sEmbeddingsType("http://schemas.openxmlformats.org/officeDocument/2006/relationships/package");
157 0 : static OUString sFooterType("http://schemas.openxmlformats.org/officeDocument/2006/relationships/footer");
158 0 : static OUString sHeaderType("http://schemas.openxmlformats.org/officeDocument/2006/relationships/header");
159 0 : static OUString sOleObjectType("http://schemas.openxmlformats.org/officeDocument/2006/relationships/oleObject");
160 : // OOXML strict
161 0 : static OUString sDocumentTypeStrict("http://purl.oclc.org/ooxml/officeDocument/relationships/officeDocument");
162 0 : static OUString sStylesTypeStrict("http://purl.oclc.org/ooxml/officeDocument/relationships/styles");
163 0 : static OUString sNumberingTypeStrict("http://purl.oclc.org/ooxml/officeDocument/relationships/numbering");
164 0 : static OUString sFonttableTypeStrict("http://purl.oclc.org/ooxml/officeDocument/relationships/fontTable");
165 0 : static OUString sFootnotesTypeStrict("http://purl.oclc.org/ooxml/officeDocument/relationships/footnotes");
166 0 : static OUString sEndnotesTypeStrict("http://purl.oclc.org/ooxml/officeDocument/relationships/endnotes");
167 0 : static OUString sCommentsTypeStrict("http://purl.oclc.org/ooxml/officeDocument/relationships/comments");
168 0 : static OUString sThemeTypeStrict("http://purl.oclc.org/ooxml/officeDocument/relationships/theme");
169 0 : static OUString sCustomTypeStrict("http://purl.oclc.org/ooxml/officeDocument/relationships/customXml");
170 0 : static OUString sCustomPropsTypeStrict("http://purl.oclc.org/ooxml/officeDocument/relationships/customXmlProps");
171 0 : static OUString sActiveXTypeStrict("http://purl.oclc.org/ooxml/officeDocument/relationships/control");
172 0 : static OUString sGlossaryTypeStrict("http://purl.oclc.org/ooxml/officeDocument/relationships/glossaryDocument");
173 0 : static OUString sWebSettingsStrict("http://purl.oclc.org/ooxml/officeDocument/relationships/webSettings");
174 0 : static OUString sSettingsTypeStrict("http://purl.oclc.org/ooxml/officeDocument/relationships/settings");
175 0 : static OUString sChartTypeStrict("http://purl.oclc.org/ooxml/officeDocument/relationships/chart");
176 0 : static OUString sEmbeddingsTypeStrict("http://purl.oclc.org/ooxml/officeDocument/relationships/package");
177 0 : static OUString sFootersTypeStrict("http://purl.oclc.org/ooxml/officeDocument/relationships/footer");
178 0 : static OUString sHeaderTypeStrict("http://purl.oclc.org/ooxml/officeDocument/relationships/header");
179 0 : static OUString sOleObjectTypeStrict("http://purl.oclc.org/ooxml/officeDocument/relationships/oleObject");
180 0 : static OUString sVBAProjectType("http://schemas.microsoft.com/office/2006/relationships/vbaProject");
181 :
182 0 : OUString sStreamType;
183 0 : OUString sStreamTypeStrict;
184 :
185 0 : switch (nStreamType)
186 : {
187 : case VBAPROJECT:
188 0 : sStreamType = sVBAProjectType;
189 0 : sStreamTypeStrict = sVBAProjectType;
190 0 : break;
191 : case DOCUMENT:
192 0 : sStreamType = sDocumentType;
193 0 : sStreamTypeStrict = sDocumentTypeStrict;
194 0 : break;
195 : case STYLES:
196 0 : sStreamType = sStylesType;
197 0 : sStreamTypeStrict = sStylesTypeStrict;
198 0 : break;
199 : case NUMBERING:
200 0 : sStreamType = sNumberingType;
201 0 : sStreamTypeStrict = sNumberingTypeStrict;
202 0 : break;
203 : case FONTTABLE:
204 0 : sStreamType = sFonttableType;
205 0 : sStreamTypeStrict = sFonttableTypeStrict;
206 0 : break;
207 : case FOOTNOTES:
208 0 : sStreamType = sFootnotesType;
209 0 : sStreamTypeStrict = sFootnotesTypeStrict;
210 0 : break;
211 : case ENDNOTES:
212 0 : sStreamType = sEndnotesType;
213 0 : sStreamTypeStrict = sEndnotesTypeStrict;
214 0 : break;
215 : case COMMENTS:
216 0 : sStreamType = sCommentsType;
217 0 : sStreamTypeStrict = sCommentsTypeStrict;
218 0 : break;
219 : case THEME:
220 0 : sStreamType = sThemeType;
221 0 : sStreamTypeStrict = sThemeTypeStrict;
222 0 : break;
223 : case CUSTOMXML:
224 0 : sStreamType = sCustomType;
225 0 : sStreamTypeStrict = sCustomTypeStrict;
226 0 : break;
227 : case CUSTOMXMLPROPS:
228 0 : sStreamType = sCustomPropsType;
229 0 : sStreamTypeStrict = sCustomPropsTypeStrict;
230 0 : break;
231 : case ACTIVEX:
232 0 : sStreamType = sActiveXType;
233 0 : sStreamTypeStrict = sActiveXTypeStrict;
234 0 : break;
235 : case ACTIVEXBIN:
236 0 : sStreamType = sActiveXBinType;
237 0 : sStreamTypeStrict = sActiveXBinType;
238 0 : break;
239 : case SETTINGS:
240 0 : sStreamType = sSettingsType;
241 0 : sStreamTypeStrict = sSettingsTypeStrict;
242 0 : break;
243 : case GLOSSARY:
244 0 : sStreamType = sGlossaryType;
245 0 : sStreamTypeStrict = sGlossaryTypeStrict;
246 0 : break;
247 : case WEBSETTINGS:
248 0 : sStreamType = sWebSettings;
249 0 : sStreamTypeStrict = sWebSettingsStrict;
250 0 : break;
251 : case CHARTS:
252 0 : sStreamType = sChartType;
253 0 : sStreamTypeStrict = sChartTypeStrict;
254 0 : break;
255 : case EMBEDDINGS:
256 0 : sStreamType = sEmbeddingsType;
257 0 : sStreamTypeStrict = sEmbeddingsTypeStrict;
258 0 : break;
259 : case FOOTER:
260 0 : sStreamType = sFooterType;
261 0 : sStreamTypeStrict = sFootersTypeStrict;
262 0 : break;
263 : case HEADER:
264 0 : sStreamType = sHeaderType;
265 0 : sStreamTypeStrict = sHeaderTypeStrict;
266 0 : break;
267 : default:
268 0 : break;
269 : }
270 :
271 0 : if (xRelationshipAccess.is())
272 : {
273 : uno::Sequence< uno::Sequence< beans::StringPair > >aSeqs =
274 0 : xRelationshipAccess->getAllRelationships();
275 :
276 0 : for (sal_Int32 j = 0; j < aSeqs.getLength(); j++)
277 : {
278 0 : const uno::Sequence< beans::StringPair > &rSeq = aSeqs[j];
279 :
280 0 : bool bExternalTarget = false;
281 0 : OUString sMyTarget;
282 0 : for (sal_Int32 i = 0; i < rSeq.getLength(); i++)
283 : {
284 0 : const beans::StringPair &rPair = rSeq[i];
285 :
286 0 : if (rPair.First.compareTo(sType) == 0 &&
287 0 : ( rPair.Second.compareTo(sStreamType) == 0 ||
288 0 : rPair.Second.compareTo(sStreamTypeStrict) == 0))
289 0 : bFound = true;
290 0 : else if(rPair.First.compareTo(sType) == 0 &&
291 0 : ((rPair.Second.compareTo(sOleObjectType) == 0 ||
292 0 : rPair.Second.compareTo(sOleObjectTypeStrict) == 0) &&
293 : nStreamType == EMBEDDINGS))
294 : {
295 0 : bFound = true;
296 : }
297 0 : else if (rPair.First.compareTo(sId) == 0 &&
298 0 : rPair.Second.compareTo(rId) == 0)
299 0 : bFound = true;
300 0 : else if (rPair.First.compareTo(sTarget) == 0)
301 : {
302 : // checking item[n].xml or activex[n].xml is not visited already.
303 0 : if(customTarget != rPair.Second && (sStreamType == sCustomType || sStreamType == sActiveXType || sStreamType == sChartType || sStreamType == sFooterType || sStreamType == sHeaderType))
304 : {
305 0 : bFound = false;
306 : }
307 : else
308 : {
309 0 : sMyTarget = rPair.Second;
310 : }
311 : }
312 0 : else if (rPair.First.compareTo(sTargetMode) == 0 &&
313 0 : rPair.Second.compareTo(sExternal) == 0)
314 0 : bExternalTarget = true;
315 :
316 : }
317 :
318 0 : if (bFound)
319 : {
320 0 : if (bExternalTarget)
321 0 : 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 0 : uno::Reference< com::sun::star::uri::XUriReference > xPart = xFac->parse( sMyTarget );
329 0 : uno::Reference< com::sun::star::uri::XUriReference > xAbs = xFac->makeAbsolute( xBase, xPart, sal_True, com::sun::star::uri::RelativeUriExcessParentSegments_RETAIN );
330 0 : rDocumentTarget = xAbs->getPath();
331 : // path will start with the fragment separator. need to
332 : // remove that
333 0 : rDocumentTarget = rDocumentTarget.copy( 1 );
334 0 : if(sStreamType == sEmbeddingsType)
335 0 : embeddingsTarget = rDocumentTarget;
336 : }
337 :
338 0 : break;
339 : }
340 0 : }
341 : }
342 :
343 0 : return bFound;
344 : }
345 :
346 0 : OUString OOXMLStreamImpl::getTargetForId(const OUString & rId)
347 : {
348 0 : OUString sTarget;
349 :
350 : uno::Reference<embed::XRelationshipAccess> xRelationshipAccess
351 0 : (mxDocumentStream, uno::UNO_QUERY_THROW);
352 :
353 0 : if (lcl_getTarget(xRelationshipAccess, UNKNOWN, rId, sTarget))
354 0 : return sTarget;
355 :
356 0 : return OUString();
357 : }
358 :
359 0 : void OOXMLStreamImpl::init()
360 : {
361 : bool bFound = lcl_getTarget(mxRelationshipAccess,
362 0 : mnStreamType, msId, msTarget);
363 : #ifdef DEBUG_STREAM
364 : debug_logger->startElement("stream");
365 : debug_logger->attribute("target", msTarget);
366 : #endif
367 :
368 0 : if (bFound)
369 : {
370 0 : sal_Int32 nLastIndex = msTarget.lastIndexOf('/');
371 0 : if (nLastIndex >= 0)
372 0 : msPath = msTarget.copy(0, nLastIndex + 1);
373 :
374 : uno::Reference<embed::XHierarchicalStorageAccess>
375 0 : xHierarchicalStorageAccess(mxStorage, uno::UNO_QUERY);
376 :
377 0 : if (xHierarchicalStorageAccess.is())
378 : {
379 0 : uno::Any aAny(xHierarchicalStorageAccess->
380 : openStreamElementByHierarchicalName
381 0 : (msTarget, embed::ElementModes::SEEKABLEREAD));
382 0 : 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 0 : maIdCache.clear();
386 0 : }
387 : }
388 0 : }
389 :
390 0 : uno::Reference<io::XInputStream> OOXMLStreamImpl::getDocumentStream()
391 : {
392 0 : uno::Reference<io::XInputStream> xResult;
393 :
394 0 : if (mxDocumentStream.is())
395 0 : xResult = mxDocumentStream->getInputStream();
396 :
397 0 : 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 0 : uno::Reference<io::XStream> OOXMLStreamImpl::accessDocumentStream()
402 : {
403 0 : return mxDocumentStream;
404 : }
405 :
406 0 : uno::Reference<io::XInputStream> OOXMLStreamImpl::getStorageStream()
407 : {
408 0 : 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 0 : uno::Reference<uno::XComponentContext> OOXMLStreamImpl::getContext()
418 : {
419 0 : return mxContext;
420 : }
421 :
422 : uno::Reference <xml::sax::XFastTokenHandler>
423 0 : OOXMLStreamImpl::getFastTokenHandler
424 : (uno::Reference<uno::XComponentContext> xContext)
425 : {
426 0 : if (! mxFastTokenHandler.is())
427 0 : mxFastTokenHandler.set(new OOXMLFastTokenHandler(xContext));
428 :
429 0 : return mxFastTokenHandler;
430 : }
431 :
432 : OOXMLStream::Pointer_t
433 0 : 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 0 : nStreamType, bRepairStorage);
441 0 : return OOXMLStream::Pointer_t(pStream);
442 : }
443 :
444 : OOXMLStream::Pointer_t
445 0 : OOXMLDocumentFactory::createStream
446 : (OOXMLStream::Pointer_t pStream, OOXMLStream::StreamType_t nStreamType)
447 : {
448 0 : OOXMLStream::Pointer_t pRet;
449 0 : if (OOXMLStreamImpl* pImpl = dynamic_cast<OOXMLStreamImpl *>(pStream.get()))
450 0 : pRet.reset(new OOXMLStreamImpl(*pImpl, nStreamType));
451 0 : return pRet;
452 : }
453 :
454 : OOXMLStream::Pointer_t
455 0 : OOXMLDocumentFactory::createStream
456 : (OOXMLStream::Pointer_t pStream, const OUString & rId)
457 : {
458 0 : OOXMLStream::Pointer_t pRet;
459 0 : if (OOXMLStreamImpl* pImpl = dynamic_cast<OOXMLStreamImpl *>(pStream.get()))
460 0 : pRet.reset(new OOXMLStreamImpl(*pImpl, rId));
461 0 : return pRet;
462 : }
463 :
464 0 : }}
465 :
466 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|