1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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>
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
{
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
)
42 (comphelper::OStorageHelper::GetStorageOfFormatFromInputStream
43 (OFOPXML_STORAGE_FORMAT_STRING
, mxStorageStream
, xContext
, bRepairStorage
));
44 mxRelationshipAccess
.set(mxStorage
, uno::UNO_QUERY_THROW
);
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
);
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
),
69 msPath(rOOXMLStream
.msPath
)
71 mxRelationshipAccess
.set(rOOXMLStream
.mxDocumentStream
, uno::UNO_QUERY_THROW
);
76 OOXMLStreamImpl::~OOXMLStreamImpl()
80 const OUString
& OOXMLStreamImpl::getTarget() const
85 bool OOXMLStreamImpl::lcl_getTarget(const uno::Reference
<embed::XRelationshipAccess
>&
87 StreamType_t nStreamType
,
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
)
103 bool bExternal
= false;
104 for (const beans::StringPair
& rPair
: rSeq
)
106 if (rPair
.First
== sId
)
108 else if (rPair
.First
== sTarget
)
109 aTarget
= rPair
.Second
;
110 else if (rPair
.First
== sTargetMode
&& rPair
.Second
== sExternal
)
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
];
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";
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
;
179 sStreamType
= sVBAProjectType
;
180 sStreamTypeStrict
= sVBAProjectType
;
183 sStreamType
= sVBADataType
;
184 sStreamTypeStrict
= sVBADataType
;
187 sStreamType
= sDocumentType
;
188 sStreamTypeStrict
= sDocumentTypeStrict
;
191 sStreamType
= sStylesType
;
192 sStreamTypeStrict
= sStylesTypeStrict
;
195 sStreamType
= sNumberingType
;
196 sStreamTypeStrict
= sNumberingTypeStrict
;
199 sStreamType
= sFonttableType
;
200 sStreamTypeStrict
= sFonttableTypeStrict
;
203 sStreamType
= sFootnotesType
;
204 sStreamTypeStrict
= sFootnotesTypeStrict
;
207 sStreamType
= sEndnotesType
;
208 sStreamTypeStrict
= sEndnotesTypeStrict
;
211 sStreamType
= sCommentsType
;
212 sStreamTypeStrict
= sCommentsTypeStrict
;
215 sStreamType
= sThemeType
;
216 sStreamTypeStrict
= sThemeTypeStrict
;
219 sStreamType
= sCustomType
;
220 sStreamTypeStrict
= sCustomTypeStrict
;
223 sStreamType
= sCustomPropsType
;
224 sStreamTypeStrict
= sCustomPropsTypeStrict
;
227 sStreamType
= sSettingsType
;
228 sStreamTypeStrict
= sSettingsTypeStrict
;
231 sStreamType
= sGlossaryType
;
232 sStreamTypeStrict
= sGlossaryTypeStrict
;
235 sStreamType
= sWebSettings
;
236 sStreamTypeStrict
= sWebSettingsStrict
;
239 sStreamType
= sChartType
;
240 sStreamTypeStrict
= sChartTypeStrict
;
243 sStreamType
= sEmbeddingsType
;
244 sStreamTypeStrict
= sEmbeddingsTypeStrict
;
247 sStreamType
= sFooterType
;
248 sStreamTypeStrict
= sFootersTypeStrict
;
251 sStreamType
= sHeaderType
;
252 sStreamTypeStrict
= sHeaderTypeStrict
;
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;
267 for (const beans::StringPair
&rPair
: rSeq
)
269 if (rPair
.First
== sType
&&
270 ( rPair
.Second
== sStreamType
||
271 rPair
.Second
== sStreamTypeStrict
))
273 else if(rPair
.First
== sType
&&
274 ((rPair
.Second
== sOleObjectType
||
275 rPair
.Second
== sOleObjectTypeStrict
) &&
276 nStreamType
== EMBEDDINGS
))
280 else if (rPair
.First
== sId
&&
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
))
292 sMyTarget
= rPair
.Second
;
295 else if (rPair
.First
== sTargetMode
&&
296 rPair
.Second
== sExternal
)
297 bExternalTarget
= true;
303 rDocumentTarget
= sMyTarget
;
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
);
314 //it was invalid gibberish
319 rDocumentTarget
= xAbs
->getPath();
320 // path will start with the fragment separator. need to
322 rDocumentTarget
= rDocumentTarget
.copy( 1 );
323 if(sStreamType
== sEmbeddingsType
)
324 embeddingsTarget
= rDocumentTarget
;
336 OUString
OOXMLStreamImpl::getTargetForId(const OUString
& rId
)
340 uno::Reference
<embed::XRelationshipAccess
> xRelationshipAccess
341 (mxDocumentStream
, uno::UNO_QUERY_THROW
);
343 if (lcl_getTarget(xRelationshipAccess
, UNKNOWN
, rId
, sTarget
))
349 void OOXMLStreamImpl::init()
351 bool bFound
= lcl_getTarget(mxRelationshipAccess
,
352 mnStreamType
, msId
, msTarget
);
356 sal_Int32 nLastIndex
= msTarget
.lastIndexOf('/');
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.
376 uno::Reference
<io::XInputStream
> OOXMLStreamImpl::getDocumentStream()
378 uno::Reference
<io::XInputStream
> xResult
;
380 if (mxDocumentStream
.is())
381 xResult
= mxDocumentStream
->getInputStream();
386 uno::Reference
<uno::XComponentContext
> OOXMLStreamImpl::getContext()
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
,
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
);
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
);
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
);
446 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */