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 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
];
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
)
110 else if (rPair
.First
== sTarget
)
111 aTarget
= rPair
.Second
;
112 else if (rPair
.First
== sTargetMode
&& rPair
.Second
== sExternal
)
115 // Only cache external targets, internal ones are more complex (see below)
117 maIdCache
[aId
] = aTarget
;
121 if (maIdCache
.find(rId
) != maIdCache
.end())
123 rDocumentTarget
= maIdCache
[rId
];
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";
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
;
181 sStreamType
= sVBAProjectType
;
182 sStreamTypeStrict
= sVBAProjectType
;
185 sStreamType
= sVBADataType
;
186 sStreamTypeStrict
= sVBADataType
;
189 sStreamType
= sDocumentType
;
190 sStreamTypeStrict
= sDocumentTypeStrict
;
193 sStreamType
= sStylesType
;
194 sStreamTypeStrict
= sStylesTypeStrict
;
197 sStreamType
= sNumberingType
;
198 sStreamTypeStrict
= sNumberingTypeStrict
;
201 sStreamType
= sFonttableType
;
202 sStreamTypeStrict
= sFonttableTypeStrict
;
205 sStreamType
= sFootnotesType
;
206 sStreamTypeStrict
= sFootnotesTypeStrict
;
209 sStreamType
= sEndnotesType
;
210 sStreamTypeStrict
= sEndnotesTypeStrict
;
213 sStreamType
= sCommentsType
;
214 sStreamTypeStrict
= sCommentsTypeStrict
;
217 sStreamType
= sThemeType
;
218 sStreamTypeStrict
= sThemeTypeStrict
;
221 sStreamType
= sCustomType
;
222 sStreamTypeStrict
= sCustomTypeStrict
;
225 sStreamType
= sCustomPropsType
;
226 sStreamTypeStrict
= sCustomPropsTypeStrict
;
229 sStreamType
= sSettingsType
;
230 sStreamTypeStrict
= sSettingsTypeStrict
;
233 sStreamType
= sGlossaryType
;
234 sStreamTypeStrict
= sGlossaryTypeStrict
;
237 sStreamType
= sWebSettings
;
238 sStreamTypeStrict
= sWebSettingsStrict
;
241 sStreamType
= sChartType
;
242 sStreamTypeStrict
= sChartTypeStrict
;
245 sStreamType
= sEmbeddingsType
;
246 sStreamTypeStrict
= sEmbeddingsTypeStrict
;
249 sStreamType
= sFooterType
;
250 sStreamTypeStrict
= sFootersTypeStrict
;
253 sStreamType
= sHeaderType
;
254 sStreamTypeStrict
= sHeaderTypeStrict
;
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;
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
))
279 else if(rPair
.First
== sType
&&
280 ((rPair
.Second
== sOleObjectType
||
281 rPair
.Second
== sOleObjectTypeStrict
) &&
282 nStreamType
== EMBEDDINGS
))
286 else if (rPair
.First
== sId
&&
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
))
298 sMyTarget
= rPair
.Second
;
301 else if (rPair
.First
== sTargetMode
&&
302 rPair
.Second
== sExternal
)
303 bExternalTarget
= true;
310 rDocumentTarget
= sMyTarget
;
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
);
321 //it was invalid gibberish
326 rDocumentTarget
= xAbs
->getPath();
327 // path will start with the fragment separator. need to
329 rDocumentTarget
= rDocumentTarget
.copy( 1 );
330 if(sStreamType
== sEmbeddingsType
)
331 embeddingsTarget
= rDocumentTarget
;
343 OUString
OOXMLStreamImpl::getTargetForId(const OUString
& rId
)
347 uno::Reference
<embed::XRelationshipAccess
> xRelationshipAccess
348 (mxDocumentStream
, uno::UNO_QUERY_THROW
);
350 if (lcl_getTarget(xRelationshipAccess
, UNKNOWN
, rId
, sTarget
))
356 void OOXMLStreamImpl::init()
358 bool bFound
= lcl_getTarget(mxRelationshipAccess
,
359 mnStreamType
, msId
, msTarget
);
363 sal_Int32 nLastIndex
= msTarget
.lastIndexOf('/');
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.
383 uno::Reference
<io::XInputStream
> OOXMLStreamImpl::getDocumentStream()
385 uno::Reference
<io::XInputStream
> xResult
;
387 if (mxDocumentStream
.is())
388 xResult
= mxDocumentStream
->getInputStream();
393 uno::Reference
<uno::XComponentContext
> OOXMLStreamImpl::getContext()
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
,
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
);
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
);
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
);
453 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */