/src/libreoffice/sfx2/source/doc/DocumentMetadataAccess.cxx
Line | Count | Source |
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 | | |
21 | | #include <sfx2/DocumentMetadataAccess.hxx> |
22 | | |
23 | | #include <com/sun/star/lang/WrappedTargetRuntimeException.hpp> |
24 | | #include <com/sun/star/beans/XPropertySet.hpp> |
25 | | #include <com/sun/star/embed/ElementModes.hpp> |
26 | | #include <com/sun/star/embed/XStorage.hpp> |
27 | | #include <com/sun/star/embed/XTransactedObject.hpp> |
28 | | #include <com/sun/star/frame/XTransientDocumentsDocumentContentIdentifierFactory.hpp> |
29 | | #include <com/sun/star/task/ErrorCodeIOException.hpp> |
30 | | #include <com/sun/star/ucb/InteractiveAugmentedIOException.hpp> |
31 | | #include <com/sun/star/rdf/FileFormat.hpp> |
32 | | #include <com/sun/star/rdf/ParseException.hpp> |
33 | | #include <com/sun/star/rdf/RepositoryException.hpp> |
34 | | #include <com/sun/star/rdf/URIs.hpp> |
35 | | #include <com/sun/star/rdf/Statement.hpp> |
36 | | #include <com/sun/star/rdf/URI.hpp> |
37 | | #include <com/sun/star/rdf/Repository.hpp> |
38 | | |
39 | | #include <rtl/ref.hxx> |
40 | | #include <rtl/ustrbuf.hxx> |
41 | | #include <rtl/uri.hxx> |
42 | | #include <rtl/bootstrap.hxx> |
43 | | #include <sal/log.hxx> |
44 | | |
45 | | #include <comphelper/interaction.hxx> |
46 | | #include <unotools/mediadescriptor.hxx> |
47 | | #include <comphelper/sequence.hxx> |
48 | | #include <comphelper/sequenceashashmap.hxx> |
49 | | #include <comphelper/storagehelper.hxx> |
50 | | #include <cppuhelper/exc_hlp.hxx> |
51 | | #include <o3tl/string_view.hxx> |
52 | | |
53 | | #include <sfx2/docfile.hxx> |
54 | | #include <sfx2/XmlIdRegistry.hxx> |
55 | | #include <sfx2/objsh.hxx> |
56 | | #include <comphelper/diagnose_ex.hxx> |
57 | | |
58 | | #include <libxml/tree.h> |
59 | | |
60 | | #include <utility> |
61 | | #include <vector> |
62 | | #include <set> |
63 | | #include <string_view> |
64 | | |
65 | | #include <com/sun/star/uri/XUriReference.hpp> |
66 | | #include <com/sun/star/uri/UriReferenceFactory.hpp> |
67 | | |
68 | | |
69 | | /* |
70 | | Note: in the context of this implementation, all rdf.QueryExceptions and |
71 | | rdf.RepositoryExceptions are RuntimeExceptions, and will be reported as such. |
72 | | |
73 | | This implementation assumes that it is only used with ODF documents, not mere |
74 | | ODF packages. In other words, we enforce that metadata files must not be |
75 | | called reserved names. |
76 | | */ |
77 | | |
78 | | using namespace ::com::sun::star; |
79 | | |
80 | | namespace sfx2 { |
81 | | |
82 | | |
83 | | bool isValidNCName(std::u16string_view i_rIdref) |
84 | 6.14k | { |
85 | 6.14k | const OString id( |
86 | 6.14k | OUStringToOString(i_rIdref, RTL_TEXTENCODING_UTF8) ); |
87 | 6.14k | return !(xmlValidateNCName( |
88 | 6.14k | reinterpret_cast<const unsigned char*>(id.getStr()), 0)); |
89 | 6.14k | } |
90 | | |
91 | | |
92 | | constexpr OUString s_content = u"content.xml"_ustr; |
93 | | constexpr OUString s_styles = u"styles.xml"_ustr; |
94 | | constexpr OUString s_manifest = u"manifest.rdf"_ustr; |
95 | | const char s_odfmime [] = "application/vnd.oasis.opendocument."; |
96 | | |
97 | | |
98 | | static bool isContentFile(std::u16string_view i_rPath) |
99 | 5.76k | { |
100 | 5.76k | return i_rPath == s_content; |
101 | 5.76k | } |
102 | | |
103 | | static bool isStylesFile (std::u16string_view i_rPath) |
104 | 14 | { |
105 | 14 | return i_rPath == s_styles; |
106 | 14 | } |
107 | | |
108 | | bool isValidXmlId(std::u16string_view i_rStreamName, |
109 | | std::u16string_view i_rIdref) |
110 | 6.14k | { |
111 | 6.14k | return isValidNCName(i_rIdref) |
112 | 5.76k | && (isContentFile(i_rStreamName) || isStylesFile(i_rStreamName)); |
113 | 6.14k | } |
114 | | |
115 | | static bool isReservedFile(std::u16string_view i_rPath) |
116 | 0 | { |
117 | 0 | return isContentFile(i_rPath) || isStylesFile(i_rPath) || i_rPath == u"meta.xml" || i_rPath == u"settings.xml"; |
118 | 0 | } |
119 | | |
120 | | |
121 | | uno::Reference<rdf::XURI> createBaseURI( |
122 | | uno::Reference<uno::XComponentContext> const & i_xContext, |
123 | | uno::Reference<frame::XModel> const & i_xModel, |
124 | | OUString const & i_rPkgURI, std::u16string_view i_rSubDocument) |
125 | 6.33k | { |
126 | 6.33k | if (!i_xContext.is() || (!i_xModel.is() && i_rPkgURI.isEmpty())) { |
127 | 0 | throw uno::RuntimeException(); |
128 | 0 | } |
129 | | |
130 | 6.33k | OUString pkgURI(i_rPkgURI); |
131 | | |
132 | | // tdf#123293 chicken/egg problem when loading from stream: there is no URI, |
133 | | // and also the model doesn't have a storage yet, so we need to get the |
134 | | // tdoc URI without a storage... |
135 | 6.33k | if (pkgURI.isEmpty()) |
136 | 6.33k | { |
137 | 6.33k | assert(i_xModel.is()); |
138 | 6.33k | uno::Reference<frame::XTransientDocumentsDocumentContentIdentifierFactory> |
139 | 6.33k | const xTDDCIF( |
140 | 6.33k | i_xContext->getServiceManager()->createInstanceWithContext( |
141 | 6.33k | u"com.sun.star.ucb.TransientDocumentsContentProvider"_ustr, |
142 | 6.33k | i_xContext), |
143 | 6.33k | uno::UNO_QUERY_THROW); |
144 | 6.33k | uno::Reference<ucb::XContentIdentifier> const xContentId( |
145 | 6.33k | xTDDCIF->createDocumentContentIdentifier(i_xModel)); |
146 | 6.33k | SAL_WARN_IF(!xContentId.is(), "sfx", "createBaseURI: cannot create ContentIdentifier"); |
147 | 6.33k | if (!xContentId.is()) |
148 | 0 | { |
149 | 0 | throw uno::RuntimeException(u"createBaseURI: cannot create ContentIdentifier"_ustr); |
150 | 0 | } |
151 | 6.33k | pkgURI = xContentId->getContentIdentifier(); |
152 | 6.33k | assert(!pkgURI.isEmpty()); |
153 | 6.33k | if (!pkgURI.isEmpty() && !pkgURI.endsWith("/")) |
154 | 6.33k | { |
155 | 6.33k | pkgURI += "/"; |
156 | 6.33k | } |
157 | 6.33k | } |
158 | | |
159 | | // #i108078# workaround non-hierarchical vnd.sun.star.expand URIs |
160 | | // this really should be done somewhere else, not here. |
161 | 6.33k | if (pkgURI.startsWithIgnoreAsciiCase("vnd.sun.star.expand:", &pkgURI)) |
162 | 0 | { |
163 | | // expand it here (makeAbsolute requires hierarchical URI) |
164 | 0 | if (!pkgURI.isEmpty()) { |
165 | 0 | pkgURI = ::rtl::Uri::decode( |
166 | 0 | pkgURI, rtl_UriDecodeStrict, RTL_TEXTENCODING_UTF8); |
167 | 0 | if (pkgURI.isEmpty()) { |
168 | 0 | throw uno::RuntimeException(); |
169 | 0 | } |
170 | 0 | ::rtl::Bootstrap::expandMacros(pkgURI); |
171 | 0 | } |
172 | 0 | } |
173 | | |
174 | 6.33k | const uno::Reference<uri::XUriReferenceFactory> xUriFactory = |
175 | 6.33k | uri::UriReferenceFactory::create( i_xContext); |
176 | 6.33k | uno::Reference< uri::XUriReference > xBaseURI; |
177 | | |
178 | 6.33k | const uno::Reference< uri::XUriReference > xPkgURI( |
179 | 6.33k | xUriFactory->parse(pkgURI), uno::UNO_SET_THROW ); |
180 | 6.33k | xPkgURI->clearFragment(); |
181 | | |
182 | | // need to know whether the storage is a FileSystemStorage |
183 | | // XServiceInfo would be better, but it is not implemented |
184 | | // if ( pkgURI.getLength() && ::utl::UCBContentHelper::IsFolder(pkgURI) ) |
185 | 6.33k | if (true) { |
186 | 6.33k | xBaseURI.set( xPkgURI, uno::UNO_SET_THROW ); |
187 | 6.33k | } |
188 | 6.33k | OUStringBuffer buf(64); |
189 | 6.33k | if (!xBaseURI->getUriReference().endsWith("/")) |
190 | 0 | { |
191 | 0 | const sal_Int32 count( xBaseURI->getPathSegmentCount() ); |
192 | 0 | if (count > 0) |
193 | 0 | { |
194 | 0 | buf.append(xBaseURI->getPathSegment(count - 1)); |
195 | 0 | } |
196 | 0 | buf.append('/'); |
197 | 0 | } |
198 | 6.33k | if (!i_rSubDocument.empty()) |
199 | 0 | { |
200 | 0 | buf.append(OUString::Concat(i_rSubDocument) + "/"); |
201 | 0 | } |
202 | 6.33k | if (!buf.isEmpty()) |
203 | 0 | { |
204 | 0 | const uno::Reference< uri::XUriReference > xPathURI( |
205 | 0 | xUriFactory->parse(buf.makeStringAndClear()), uno::UNO_SET_THROW ); |
206 | 0 | xBaseURI.set( |
207 | 0 | xUriFactory->makeAbsolute(xBaseURI, xPathURI, |
208 | 0 | true, uri::RelativeUriExcessParentSegments_ERROR), |
209 | 0 | uno::UNO_SET_THROW); |
210 | 0 | } |
211 | | |
212 | 6.33k | return rdf::URI::create(i_xContext, xBaseURI->getUriReference()); |
213 | 6.33k | } |
214 | | |
215 | | |
216 | | struct DocumentMetadataAccess_Impl |
217 | | { |
218 | | // note: these are all initialized in constructor, and loadFromStorage |
219 | | const uno::Reference<uno::XComponentContext> m_xContext; |
220 | | const SfxObjectShell & m_rXmlIdRegistrySupplier; |
221 | | uno::Reference<rdf::XURI> m_xBaseURI; |
222 | | uno::Reference<rdf::XRepository> m_xRepository; |
223 | | uno::Reference<rdf::XNamedGraph> m_xManifest; |
224 | | DocumentMetadataAccess_Impl( |
225 | | uno::Reference<uno::XComponentContext> i_xContext, |
226 | | SfxObjectShell const & i_rRegistrySupplier) |
227 | 6.33k | : m_xContext(std::move(i_xContext)) |
228 | 6.33k | , m_rXmlIdRegistrySupplier(i_rRegistrySupplier) |
229 | 6.33k | { |
230 | 6.33k | OSL_ENSURE(m_xContext.is(), "context null"); |
231 | 6.33k | } |
232 | | }; |
233 | | |
234 | | // this is... a hack. |
235 | | template<sal_Int16 Constant> |
236 | | static uno::Reference<rdf::XURI> const & |
237 | | getURI(uno::Reference< uno::XComponentContext > const & i_xContext) |
238 | 39.1k | { |
239 | 39.1k | static uno::Reference< rdf::XURI > xURI( |
240 | 39.1k | rdf::URI::createKnown(i_xContext, Constant), uno::UNO_SET_THROW); |
241 | 39.1k | return xURI; |
242 | 39.1k | } DocumentMetadataAccess.cxx:com::sun::star::uno::Reference<com::sun::star::rdf::XURI> const& sfx2::getURI<(short)2008>(com::sun::star::uno::Reference<com::sun::star::uno::XComponentContext> const&) Line | Count | Source | 238 | 6.33k | { | 239 | 6.33k | static uno::Reference< rdf::XURI > xURI( | 240 | 6.33k | rdf::URI::createKnown(i_xContext, Constant), uno::UNO_SET_THROW); | 241 | 6.33k | return xURI; | 242 | 6.33k | } |
DocumentMetadataAccess.cxx:com::sun::star::uno::Reference<com::sun::star::rdf::XURI> const& sfx2::getURI<(short)2000>(com::sun::star::uno::Reference<com::sun::star::uno::XComponentContext> const&) Line | Count | Source | 238 | 7.44k | { | 239 | 7.44k | static uno::Reference< rdf::XURI > xURI( | 240 | 7.44k | rdf::URI::createKnown(i_xContext, Constant), uno::UNO_SET_THROW); | 241 | 7.44k | return xURI; | 242 | 7.44k | } |
DocumentMetadataAccess.cxx:com::sun::star::uno::Reference<com::sun::star::rdf::XURI> const& sfx2::getURI<(short)1000>(com::sun::star::uno::Reference<com::sun::star::uno::XComponentContext> const&) Line | Count | Source | 238 | 6.33k | { | 239 | 6.33k | static uno::Reference< rdf::XURI > xURI( | 240 | 6.33k | rdf::URI::createKnown(i_xContext, Constant), uno::UNO_SET_THROW); | 241 | 6.33k | return xURI; | 242 | 6.33k | } |
DocumentMetadataAccess.cxx:com::sun::star::uno::Reference<com::sun::star::rdf::XURI> const& sfx2::getURI<(short)2103>(com::sun::star::uno::Reference<com::sun::star::uno::XComponentContext> const&) Line | Count | Source | 238 | 6.33k | { | 239 | 6.33k | static uno::Reference< rdf::XURI > xURI( | 240 | 6.33k | rdf::URI::createKnown(i_xContext, Constant), uno::UNO_SET_THROW); | 241 | 6.33k | return xURI; | 242 | 6.33k | } |
DocumentMetadataAccess.cxx:com::sun::star::uno::Reference<com::sun::star::rdf::XURI> const& sfx2::getURI<(short)2104>(com::sun::star::uno::Reference<com::sun::star::uno::XComponentContext> const&) Line | Count | Source | 238 | 6.33k | { | 239 | 6.33k | static uno::Reference< rdf::XURI > xURI( | 240 | 6.33k | rdf::URI::createKnown(i_xContext, Constant), uno::UNO_SET_THROW); | 241 | 6.33k | return xURI; | 242 | 6.33k | } |
DocumentMetadataAccess.cxx:com::sun::star::uno::Reference<com::sun::star::rdf::XURI> const& sfx2::getURI<(short)2007>(com::sun::star::uno::Reference<com::sun::star::uno::XComponentContext> const&) Line | Count | Source | 238 | 6.33k | { | 239 | 6.33k | static uno::Reference< rdf::XURI > xURI( | 240 | 6.33k | rdf::URI::createKnown(i_xContext, Constant), uno::UNO_SET_THROW); | 241 | 6.33k | return xURI; | 242 | 6.33k | } |
|
243 | | |
244 | | |
245 | | /** would storing the file to a XStorage succeed? */ |
246 | | static bool isFileNameValid(std::u16string_view i_rFileName) |
247 | 0 | { |
248 | 0 | if (i_rFileName.empty()) return false; |
249 | 0 | if (i_rFileName[0] == '/') return false; // no absolute paths! |
250 | 0 | sal_Int32 idx(0); |
251 | 0 | do { |
252 | 0 | const OUString segment( |
253 | 0 | o3tl::getToken(i_rFileName, 0, u'/', idx) ); |
254 | 0 | if (segment.isEmpty() || // no empty segments |
255 | 0 | segment == "." || // no . segments |
256 | 0 | segment == ".." || // no .. segments |
257 | 0 | !::comphelper::OStorageHelper::IsValidZipEntryFileName( |
258 | 0 | segment, false)) // no invalid characters |
259 | 0 | return false; |
260 | 0 | } while (idx >= 0); |
261 | 0 | return true; |
262 | 0 | } |
263 | | |
264 | | /** split a uri hierarchy into first segment and rest */ |
265 | | static bool |
266 | | splitPath(OUString const & i_rPath, |
267 | | OUString & o_rDir, OUString& o_rRest) |
268 | 6.33k | { |
269 | 6.33k | const sal_Int32 idx(i_rPath.indexOf(u'/')); |
270 | 6.33k | if (idx < 0 || idx >= i_rPath.getLength()) { |
271 | 6.33k | o_rDir.clear(); |
272 | 6.33k | o_rRest = i_rPath; |
273 | 6.33k | return true; |
274 | 6.33k | } else if (idx == 0 || idx == i_rPath.getLength() - 1) { |
275 | | // input must not start or end with '/' |
276 | 0 | return false; |
277 | 0 | } else { |
278 | 0 | o_rDir = i_rPath.copy(0, idx); |
279 | 0 | o_rRest = i_rPath.copy(idx+1); |
280 | 0 | return true; |
281 | 0 | } |
282 | 6.33k | } |
283 | | |
284 | | static bool |
285 | | splitXmlId(std::u16string_view i_XmlId, |
286 | | OUString & o_StreamName, OUString& o_Idref ) |
287 | 0 | { |
288 | 0 | const size_t idx(i_XmlId.find(u'#')); |
289 | 0 | if (idx == std::u16string_view::npos) |
290 | 0 | return false; |
291 | 0 | o_StreamName = i_XmlId.substr(0, idx); |
292 | 0 | o_Idref = i_XmlId.substr(idx+1); |
293 | 0 | return isValidXmlId(o_StreamName, o_Idref); |
294 | 0 | } |
295 | | |
296 | | |
297 | | static uno::Reference<rdf::XURI> |
298 | | getURIForStream(struct DocumentMetadataAccess_Impl const & i_rImpl, |
299 | | OUString const& i_rPath) |
300 | 6.33k | { |
301 | 6.33k | const uno::Reference<rdf::XURI> xURI( |
302 | 6.33k | rdf::URI::createNS( i_rImpl.m_xContext, |
303 | 6.33k | i_rImpl.m_xBaseURI->getStringValue(), i_rPath), |
304 | 6.33k | uno::UNO_SET_THROW); |
305 | 6.33k | return xURI; |
306 | 6.33k | } |
307 | | |
308 | | /** add statements declaring i_xResource to be a file of type i_xType with |
309 | | path i_rPath to manifest, with optional additional types i_pTypes */ |
310 | | static void |
311 | | addFile(struct DocumentMetadataAccess_Impl const & i_rImpl, |
312 | | uno::Reference<rdf::XURI> const& i_xType, |
313 | | OUString const & i_rPath, |
314 | | const uno::Sequence < uno::Reference< rdf::XURI > > * i_pTypes) |
315 | 0 | { |
316 | 0 | try { |
317 | 0 | const uno::Reference<rdf::XURI> xURI( getURIForStream( |
318 | 0 | i_rImpl, i_rPath) ); |
319 | |
|
320 | 0 | i_rImpl.m_xManifest->addStatement(i_rImpl.m_xBaseURI, |
321 | 0 | getURI<rdf::URIs::PKG_HASPART>(i_rImpl.m_xContext), |
322 | 0 | xURI); |
323 | 0 | i_rImpl.m_xManifest->addStatement(xURI, |
324 | 0 | getURI<rdf::URIs::RDF_TYPE>(i_rImpl.m_xContext), |
325 | 0 | i_xType); |
326 | 0 | if (i_pTypes) { |
327 | 0 | for (const auto& rType : *i_pTypes) { |
328 | 0 | i_rImpl.m_xManifest->addStatement(xURI, |
329 | 0 | getURI<rdf::URIs::RDF_TYPE>(i_rImpl.m_xContext), |
330 | 0 | rType); |
331 | 0 | } |
332 | 0 | } |
333 | 0 | } catch (const uno::RuntimeException &) { |
334 | 0 | throw; |
335 | 0 | } catch (const uno::Exception &) { |
336 | 0 | css::uno::Any anyEx = cppu::getCaughtException(); |
337 | 0 | throw lang::WrappedTargetRuntimeException( |
338 | 0 | u"addFile: exception"_ustr, /*this*/nullptr, anyEx); |
339 | 0 | } |
340 | 0 | } |
341 | | |
342 | | /** add content.xml or styles.xml to manifest */ |
343 | | static bool |
344 | | addContentOrStylesFileImpl(struct DocumentMetadataAccess_Impl const & i_rImpl, |
345 | | const OUString & i_rPath) |
346 | 0 | { |
347 | 0 | uno::Reference<rdf::XURI> xType; |
348 | 0 | if (isContentFile(i_rPath)) { |
349 | 0 | xType.set(getURI<rdf::URIs::ODF_CONTENTFILE>(i_rImpl.m_xContext)); |
350 | 0 | } else if (isStylesFile(i_rPath)) { |
351 | 0 | xType.set(getURI<rdf::URIs::ODF_STYLESFILE>(i_rImpl.m_xContext)); |
352 | 0 | } else { |
353 | 0 | return false; |
354 | 0 | } |
355 | 0 | addFile(i_rImpl, xType, i_rPath, nullptr); |
356 | 0 | return true; |
357 | 0 | } |
358 | | |
359 | | /** add metadata file to manifest */ |
360 | | static void |
361 | | addMetadataFileImpl(struct DocumentMetadataAccess_Impl const & i_rImpl, |
362 | | const OUString & i_rPath, |
363 | | const uno::Sequence < uno::Reference< rdf::XURI > > & i_rTypes) |
364 | 0 | { |
365 | 0 | addFile(i_rImpl, |
366 | 0 | getURI<rdf::URIs::PKG_METADATAFILE>(i_rImpl.m_xContext), |
367 | 0 | i_rPath, &i_rTypes); |
368 | 0 | } |
369 | | |
370 | | /** remove a file from the manifest */ |
371 | | static void |
372 | | removeFile(struct DocumentMetadataAccess_Impl const & i_rImpl, |
373 | | uno::Reference<rdf::XURI> const& i_xPart) |
374 | 0 | { |
375 | 0 | if (!i_xPart.is()) throw uno::RuntimeException(); |
376 | 0 | try { |
377 | 0 | i_rImpl.m_xManifest->removeStatements(i_rImpl.m_xBaseURI, |
378 | 0 | getURI<rdf::URIs::PKG_HASPART>(i_rImpl.m_xContext), |
379 | 0 | i_xPart); |
380 | 0 | i_rImpl.m_xManifest->removeStatements(i_xPart, |
381 | 0 | getURI<rdf::URIs::RDF_TYPE>(i_rImpl.m_xContext), nullptr); |
382 | 0 | } catch (const uno::RuntimeException &) { |
383 | 0 | throw; |
384 | 0 | } catch (const uno::Exception &) { |
385 | 0 | css::uno::Any anyEx = cppu::getCaughtException(); |
386 | 0 | throw lang::WrappedTargetRuntimeException( |
387 | 0 | u"removeFile: exception"_ustr, |
388 | 0 | nullptr, anyEx); |
389 | 0 | } |
390 | 0 | } |
391 | | |
392 | | static ::std::vector< uno::Reference< rdf::XURI > > |
393 | | getAllParts(struct DocumentMetadataAccess_Impl const & i_rImpl) |
394 | 6.33k | { |
395 | 6.33k | ::std::vector< uno::Reference< rdf::XURI > > ret; |
396 | 6.33k | try { |
397 | 6.33k | const uno::Reference<container::XEnumeration> xEnum( |
398 | 6.33k | i_rImpl.m_xManifest->getStatements( i_rImpl.m_xBaseURI, |
399 | 6.33k | getURI<rdf::URIs::PKG_HASPART>(i_rImpl.m_xContext), nullptr), |
400 | 6.33k | uno::UNO_SET_THROW); |
401 | 6.33k | while (xEnum->hasMoreElements()) { |
402 | 0 | rdf::Statement stmt; |
403 | 0 | if (!(xEnum->nextElement() >>= stmt)) { |
404 | 0 | throw uno::RuntimeException(); |
405 | 0 | } |
406 | 0 | const uno::Reference<rdf::XURI> xPart(stmt.Object, |
407 | 0 | uno::UNO_QUERY); |
408 | 0 | if (!xPart.is()) continue; |
409 | 0 | ret.push_back(xPart); |
410 | 0 | } |
411 | 6.33k | return ret; |
412 | 6.33k | } catch (const uno::RuntimeException &) { |
413 | 0 | throw; |
414 | 0 | } catch (const uno::Exception &) { |
415 | 0 | css::uno::Any anyEx = cppu::getCaughtException(); |
416 | 0 | throw lang::WrappedTargetRuntimeException( |
417 | 0 | u"getAllParts: exception"_ustr, |
418 | 0 | nullptr, anyEx); |
419 | 0 | } |
420 | 6.33k | } |
421 | | |
422 | | static bool |
423 | | isPartOfType(struct DocumentMetadataAccess_Impl const & i_rImpl, |
424 | | uno::Reference<rdf::XURI> const & i_xPart, |
425 | | uno::Reference<rdf::XURI> const & i_xType) |
426 | 0 | { |
427 | 0 | if (!i_xPart.is() || !i_xType.is()) throw uno::RuntimeException(); |
428 | 0 | try { |
429 | 0 | const uno::Reference<container::XEnumeration> xEnum( |
430 | 0 | i_rImpl.m_xManifest->getStatements(i_xPart, |
431 | 0 | getURI<rdf::URIs::RDF_TYPE>(i_rImpl.m_xContext), |
432 | 0 | i_xType), |
433 | 0 | uno::UNO_SET_THROW); |
434 | 0 | return xEnum->hasMoreElements(); |
435 | 0 | } catch (const uno::RuntimeException &) { |
436 | 0 | throw; |
437 | 0 | } catch (const uno::Exception &) { |
438 | 0 | css::uno::Any anyEx = cppu::getCaughtException(); |
439 | 0 | throw lang::WrappedTargetRuntimeException( |
440 | 0 | u"isPartOfType: exception"_ustr, |
441 | 0 | nullptr, anyEx); |
442 | 0 | } |
443 | 0 | } |
444 | | |
445 | | static ::std::vector<uno::Reference<rdf::XURI>> |
446 | | getAllParts(struct DocumentMetadataAccess_Impl const& i_rImpl, |
447 | | const uno::Reference<rdf::XURI>& i_xType) |
448 | 1.11k | { |
449 | 1.11k | ::std::vector<uno::Reference<rdf::XURI>> ret; |
450 | 1.11k | try |
451 | 1.11k | { |
452 | 1.11k | const uno::Reference<container::XEnumeration> xEnum( |
453 | 1.11k | i_rImpl.m_xManifest->getStatements(i_rImpl.m_xBaseURI, |
454 | 1.11k | getURI<rdf::URIs::PKG_HASPART>(i_rImpl.m_xContext), |
455 | 1.11k | nullptr), |
456 | 1.11k | uno::UNO_SET_THROW); |
457 | 1.11k | while (xEnum->hasMoreElements()) |
458 | 0 | { |
459 | 0 | rdf::Statement stmt; |
460 | 0 | if (!(xEnum->nextElement() >>= stmt)) |
461 | 0 | { |
462 | 0 | throw uno::RuntimeException(); |
463 | 0 | } |
464 | 0 | const uno::Reference<rdf::XURI> xPart(stmt.Object, uno::UNO_QUERY); |
465 | 0 | if (!xPart.is()) |
466 | 0 | continue; |
467 | | |
468 | 0 | const uno::Reference<container::XEnumeration> xEnum2( |
469 | 0 | i_rImpl.m_xManifest->getStatements( |
470 | 0 | xPart, getURI<rdf::URIs::RDF_TYPE>(i_rImpl.m_xContext), i_xType), |
471 | 0 | uno::UNO_SET_THROW); |
472 | 0 | if (xEnum2->hasMoreElements()) |
473 | 0 | ret.emplace_back(xPart); |
474 | 0 | } |
475 | 1.11k | return ret; |
476 | 1.11k | } |
477 | 1.11k | catch (const uno::RuntimeException&) |
478 | 1.11k | { |
479 | 0 | throw; |
480 | 0 | } |
481 | 1.11k | catch (const uno::Exception& e) |
482 | 1.11k | { |
483 | 0 | throw lang::WrappedTargetRuntimeException(u"getAllParts: exception"_ustr, nullptr, |
484 | 0 | uno::Any(e)); |
485 | 0 | } |
486 | 1.11k | } |
487 | | |
488 | | static ucb::InteractiveAugmentedIOException |
489 | | mkException( OUString const & i_rMessage, |
490 | | ucb::IOErrorCode const i_ErrorCode, |
491 | | OUString const & i_rUri, OUString const & i_rResource) |
492 | 6.33k | { |
493 | 6.33k | const beans::PropertyValue uriProp(u"Uri"_ustr, |
494 | 6.33k | -1, uno::Any(i_rUri), static_cast<beans::PropertyState>(0)); |
495 | 6.33k | const beans::PropertyValue rnProp( |
496 | 6.33k | u"ResourceName"_ustr, |
497 | 6.33k | -1, uno::Any(i_rResource), static_cast<beans::PropertyState>(0)); |
498 | 6.33k | return ucb::InteractiveAugmentedIOException(i_rMessage, {}, |
499 | 6.33k | task::InteractionClassification_ERROR, i_ErrorCode, |
500 | 6.33k | { uno::Any(uriProp), uno::Any(rnProp) }); |
501 | 6.33k | } |
502 | | |
503 | | /** error handling policy. |
504 | | <p>If a handler is given, ask it how to proceed: |
505 | | <ul><li>(default:) cancel import, raise exception</li> |
506 | | <li>ignore the error and continue</li> |
507 | | <li>retry the action that led to the error</li></ul></p> |
508 | | N.B.: must not be called before DMA is fully initialized! |
509 | | @returns true iff caller should retry |
510 | | */ |
511 | | static bool |
512 | | handleError( ucb::InteractiveAugmentedIOException const & i_rException, |
513 | | const uno::Reference<task::XInteractionHandler> & i_xHandler) |
514 | 0 | { |
515 | 0 | if (!i_xHandler.is()) { |
516 | 0 | throw lang::WrappedTargetException( |
517 | 0 | u"DocumentMetadataAccess::loadMetadataFromStorage: exception"_ustr, |
518 | 0 | /* *this*/ nullptr, uno::Any(i_rException)); |
519 | 0 | } |
520 | | |
521 | 0 | ::rtl::Reference< ::comphelper::OInteractionRequest > pRequest( |
522 | 0 | new ::comphelper::OInteractionRequest(uno::Any(i_rException)) ); |
523 | 0 | ::rtl::Reference< ::comphelper::OInteractionRetry > pRetry( |
524 | 0 | new ::comphelper::OInteractionRetry ); |
525 | 0 | ::rtl::Reference< ::comphelper::OInteractionApprove > pApprove( |
526 | 0 | new ::comphelper::OInteractionApprove ); |
527 | 0 | ::rtl::Reference< ::comphelper::OInteractionAbort > pAbort( |
528 | 0 | new ::comphelper::OInteractionAbort ); |
529 | |
|
530 | 0 | pRequest->addContinuation( pApprove ); |
531 | 0 | pRequest->addContinuation( pAbort ); |
532 | | // actually call the handler |
533 | 0 | i_xHandler->handle( pRequest ); |
534 | 0 | if (pRetry->wasSelected()) { |
535 | 0 | return true; |
536 | 0 | } else if (pApprove->wasSelected()) { |
537 | 0 | return false; |
538 | 0 | } else { |
539 | 0 | OSL_ENSURE(pAbort->wasSelected(), "no continuation selected?"); |
540 | 0 | throw lang::WrappedTargetException( |
541 | 0 | u"DocumentMetadataAccess::loadMetadataFromStorage: exception"_ustr, |
542 | 0 | /* *this*/ nullptr, uno::Any(i_rException)); |
543 | 0 | } |
544 | 0 | } |
545 | | |
546 | | /** check if storage has content.xml/styles.xml; |
547 | | e.g. ODB files seem to only have content.xml */ |
548 | | static void |
549 | | collectFilesFromStorage(uno::Reference<embed::XStorage> const& i_xStorage, |
550 | | std::set< OUString > & o_rFiles) |
551 | 6.33k | { |
552 | 6.33k | try { |
553 | 6.33k | if (i_xStorage->hasByName(s_content) && |
554 | 0 | i_xStorage->isStreamElement(s_content)) |
555 | 0 | { |
556 | 0 | o_rFiles.insert(s_content); |
557 | 0 | } |
558 | 6.33k | if (i_xStorage->hasByName(s_styles) && |
559 | 0 | i_xStorage->isStreamElement(s_styles)) |
560 | 0 | { |
561 | 0 | o_rFiles.insert(s_styles); |
562 | 0 | } |
563 | 6.33k | } catch (const uno::Exception &) { |
564 | 0 | TOOLS_WARN_EXCEPTION("sfx", "collectFilesFromStorage"); |
565 | 0 | } |
566 | 6.33k | } |
567 | | |
568 | | /** import a metadata file into repository */ |
569 | | static void |
570 | | readStream(struct DocumentMetadataAccess_Impl & i_rImpl, |
571 | | uno::Reference< embed::XStorage > const & i_xStorage, |
572 | | OUString const & i_rPath, |
573 | | OUString const & i_rBaseURI) |
574 | 6.33k | { |
575 | 6.33k | try { |
576 | 6.33k | OUString dir; |
577 | 6.33k | OUString rest; |
578 | 6.33k | if (!splitPath(i_rPath, dir, rest)) throw uno::RuntimeException(); |
579 | 6.33k | if (dir.isEmpty()) { |
580 | 6.33k | if (!i_xStorage->isStreamElement(i_rPath)) { |
581 | 0 | throw mkException( |
582 | 0 | u"readStream: is not a stream"_ustr, |
583 | 0 | ucb::IOErrorCode_NO_FILE, i_rBaseURI + i_rPath, i_rPath); |
584 | 0 | } |
585 | 6.33k | const uno::Reference<io::XStream> xStream( |
586 | 6.33k | i_xStorage->openStreamElement(i_rPath, |
587 | 6.33k | embed::ElementModes::READ), uno::UNO_SET_THROW); |
588 | 6.33k | const uno::Reference<io::XInputStream> xInStream( |
589 | 6.33k | xStream->getInputStream(), uno::UNO_SET_THROW ); |
590 | 6.33k | const uno::Reference<rdf::XURI> xBaseURI( |
591 | 6.33k | rdf::URI::create(i_rImpl.m_xContext, i_rBaseURI)); |
592 | 6.33k | const uno::Reference<rdf::XURI> xURI( |
593 | 6.33k | rdf::URI::createNS(i_rImpl.m_xContext, |
594 | 6.33k | i_rBaseURI, i_rPath)); |
595 | 6.33k | i_rImpl.m_xRepository->importGraph(rdf::FileFormat::RDF_XML, |
596 | 6.33k | xInStream, xURI, xBaseURI); |
597 | 6.33k | } else { |
598 | 0 | if (!i_xStorage->isStorageElement(dir)) { |
599 | 0 | throw mkException( |
600 | 0 | u"readStream: is not a directory"_ustr, |
601 | 0 | ucb::IOErrorCode_NO_DIRECTORY, i_rBaseURI + dir, dir); |
602 | 0 | } |
603 | 0 | const uno::Reference<embed::XStorage> xDir( |
604 | 0 | i_xStorage->openStorageElement(dir, |
605 | 0 | embed::ElementModes::READ)); |
606 | 0 | const uno::Reference< beans::XPropertySet > xDirProps(xDir, |
607 | 0 | uno::UNO_QUERY_THROW); |
608 | 0 | try { |
609 | 0 | OUString mimeType; |
610 | 0 | xDirProps->getPropertyValue( |
611 | 0 | utl::MediaDescriptor::PROP_MEDIATYPE ) |
612 | 0 | >>= mimeType; |
613 | 0 | if (mimeType.startsWith(s_odfmime)) { |
614 | 0 | SAL_WARN("sfx", "readStream: refusing to recurse into embedded document"); |
615 | 0 | return; |
616 | 0 | } |
617 | 0 | } catch (const uno::Exception &) { } |
618 | 0 | readStream(i_rImpl, xDir, rest, i_rBaseURI+dir+"/" ); |
619 | 0 | } |
620 | 6.33k | } catch (const container::NoSuchElementException & e) { |
621 | 6.33k | throw mkException(e.Message, ucb::IOErrorCode_NOT_EXISTING_PATH, |
622 | 6.33k | i_rBaseURI + i_rPath, i_rPath); |
623 | 6.33k | } catch (const io::IOException & e) { |
624 | 0 | throw mkException(e.Message, ucb::IOErrorCode_CANT_READ, |
625 | 0 | i_rBaseURI + i_rPath, i_rPath); |
626 | 0 | } catch (const rdf::ParseException & e) { |
627 | 0 | throw mkException(e.Message, ucb::IOErrorCode_WRONG_FORMAT, |
628 | 0 | i_rBaseURI + i_rPath, i_rPath); |
629 | 0 | } |
630 | 6.33k | } |
631 | | |
632 | | /** import a metadata file into repository */ |
633 | | static void |
634 | | importFile(struct DocumentMetadataAccess_Impl & i_rImpl, |
635 | | uno::Reference<embed::XStorage> const & i_xStorage, |
636 | | OUString const & i_rBaseURI, |
637 | | uno::Reference<task::XInteractionHandler> const & i_xHandler, |
638 | | const OUString& i_rPath) |
639 | 0 | { |
640 | 0 | retry: |
641 | 0 | try { |
642 | 0 | readStream(i_rImpl, i_xStorage, i_rPath, i_rBaseURI); |
643 | 0 | } catch (const ucb::InteractiveAugmentedIOException & e) { |
644 | 0 | if (handleError(e, i_xHandler)) goto retry; |
645 | 0 | } catch (const uno::RuntimeException &) { |
646 | 0 | throw; |
647 | 0 | } catch (const uno::Exception &) { |
648 | 0 | css::uno::Any anyEx = cppu::getCaughtException(); |
649 | 0 | throw lang::WrappedTargetRuntimeException( |
650 | 0 | u"importFile: exception"_ustr, |
651 | 0 | nullptr, anyEx); |
652 | 0 | } |
653 | 0 | } |
654 | | |
655 | | /** actually write a metadata file to the storage */ |
656 | | static void |
657 | | exportStream(struct DocumentMetadataAccess_Impl const & i_rImpl, |
658 | | uno::Reference< embed::XStorage > const & i_xStorage, |
659 | | uno::Reference<rdf::XURI> const & i_xGraphName, |
660 | | OUString const & i_rFileName, |
661 | | OUString const & i_rBaseURI) |
662 | 0 | { |
663 | 0 | const uno::Reference<io::XStream> xStream( |
664 | 0 | i_xStorage->openStreamElement(i_rFileName, |
665 | 0 | embed::ElementModes::WRITE | embed::ElementModes::TRUNCATE), |
666 | 0 | uno::UNO_SET_THROW); |
667 | 0 | const uno::Reference< beans::XPropertySet > xStreamProps(xStream, |
668 | 0 | uno::UNO_QUERY); |
669 | 0 | if (xStreamProps.is()) { // this is NOT supported in FileSystemStorage |
670 | 0 | xStreamProps->setPropertyValue( |
671 | 0 | u"MediaType"_ustr, |
672 | 0 | uno::Any(u"application/rdf+xml"_ustr)); |
673 | 0 | } |
674 | 0 | const uno::Reference<io::XOutputStream> xOutStream( |
675 | 0 | xStream->getOutputStream(), uno::UNO_SET_THROW ); |
676 | 0 | const uno::Reference<rdf::XURI> xBaseURI( |
677 | 0 | rdf::URI::create(i_rImpl.m_xContext, i_rBaseURI)); |
678 | 0 | i_rImpl.m_xRepository->exportGraph(rdf::FileFormat::RDF_XML, |
679 | 0 | xOutStream, i_xGraphName, xBaseURI); |
680 | 0 | } |
681 | | |
682 | | /** write a metadata file to the storage */ |
683 | | static void |
684 | | writeStream(struct DocumentMetadataAccess_Impl & i_rImpl, |
685 | | uno::Reference< embed::XStorage > const & i_xStorage, |
686 | | uno::Reference<rdf::XURI> const & i_xGraphName, |
687 | | OUString const & i_rPath, |
688 | | OUString const & i_rBaseURI) |
689 | 0 | { |
690 | 0 | OUString dir; |
691 | 0 | OUString rest; |
692 | 0 | if (!splitPath(i_rPath, dir, rest)) throw uno::RuntimeException(); |
693 | 0 | try { |
694 | 0 | if (dir.isEmpty()) { |
695 | 0 | exportStream(i_rImpl, i_xStorage, i_xGraphName, i_rPath, |
696 | 0 | i_rBaseURI); |
697 | 0 | } else { |
698 | 0 | const uno::Reference<embed::XStorage> xDir( |
699 | 0 | i_xStorage->openStorageElement(dir, |
700 | 0 | embed::ElementModes::WRITE)); |
701 | 0 | const uno::Reference< beans::XPropertySet > xDirProps(xDir, |
702 | 0 | uno::UNO_QUERY_THROW); |
703 | 0 | try { |
704 | 0 | OUString mimeType; |
705 | 0 | xDirProps->getPropertyValue( |
706 | 0 | utl::MediaDescriptor::PROP_MEDIATYPE ) |
707 | 0 | >>= mimeType; |
708 | 0 | if (mimeType.startsWith(s_odfmime)) { |
709 | 0 | SAL_WARN("sfx", "writeStream: refusing to recurse into embedded document"); |
710 | 0 | return; |
711 | 0 | } |
712 | 0 | } catch (const uno::Exception &) { } |
713 | 0 | writeStream(i_rImpl, xDir, i_xGraphName, rest, i_rBaseURI+dir+"/"); |
714 | 0 | uno::Reference<embed::XTransactedObject> const xTransaction( |
715 | 0 | xDir, uno::UNO_QUERY); |
716 | 0 | if (xTransaction.is()) { |
717 | 0 | xTransaction->commit(); |
718 | 0 | } |
719 | 0 | } |
720 | 0 | } catch (const uno::RuntimeException &) { |
721 | 0 | throw; |
722 | 0 | } catch (const io::IOException &) { |
723 | 0 | throw; |
724 | 0 | } |
725 | 0 | } |
726 | | |
727 | | static void |
728 | | initLoading(struct DocumentMetadataAccess_Impl & i_rImpl, |
729 | | const uno::Reference< embed::XStorage > & i_xStorage, |
730 | | const uno::Reference<rdf::XURI> & i_xBaseURI, |
731 | | const uno::Reference<task::XInteractionHandler> & i_xHandler) |
732 | 6.33k | { |
733 | 6.33k | retry: |
734 | | // clear old data |
735 | 6.33k | i_rImpl.m_xManifest.clear(); |
736 | | // init BaseURI |
737 | 6.33k | i_rImpl.m_xBaseURI = i_xBaseURI; |
738 | | |
739 | | // create repository |
740 | 6.33k | i_rImpl.m_xRepository.clear(); |
741 | 6.33k | i_rImpl.m_xRepository.set(rdf::Repository::create(i_rImpl.m_xContext), |
742 | 6.33k | uno::UNO_SET_THROW); |
743 | | |
744 | | // try to delay raising errors until after initialization is done |
745 | 6.33k | uno::Any rterr; |
746 | 6.33k | ucb::InteractiveAugmentedIOException iaioe; |
747 | 6.33k | bool err(false); |
748 | | |
749 | 6.33k | const uno::Reference <rdf::XURI> xManifest( |
750 | 6.33k | getURIForStream(i_rImpl, s_manifest)); |
751 | 6.33k | try { |
752 | 6.33k | readStream(i_rImpl, i_xStorage, s_manifest, i_xBaseURI->getStringValue()); |
753 | 6.33k | } catch (const ucb::InteractiveAugmentedIOException & e) { |
754 | | // no manifest.rdf: this is not an error in ODF < 1.2 |
755 | 6.33k | if (ucb::IOErrorCode_NOT_EXISTING_PATH != e.Code) { |
756 | 0 | iaioe = e; |
757 | 0 | err = true; |
758 | 0 | } |
759 | 6.33k | } catch (const uno::Exception & e) { |
760 | 0 | rterr <<= e; |
761 | 0 | } |
762 | | |
763 | | // init manifest graph |
764 | 6.33k | const uno::Reference<rdf::XNamedGraph> xManifestGraph( |
765 | 6.33k | i_rImpl.m_xRepository->getGraph(xManifest)); |
766 | 6.33k | i_rImpl.m_xManifest.set(xManifestGraph.is() ? xManifestGraph : |
767 | 6.33k | i_rImpl.m_xRepository->createGraph(xManifest), uno::UNO_SET_THROW); |
768 | | |
769 | | // document statement |
770 | 6.33k | i_rImpl.m_xManifest->addStatement(i_rImpl.m_xBaseURI, |
771 | 6.33k | getURI<rdf::URIs::RDF_TYPE>(i_rImpl.m_xContext), |
772 | 6.33k | getURI<rdf::URIs::PKG_DOCUMENT>(i_rImpl.m_xContext)); |
773 | | |
774 | 6.33k | OSL_ENSURE(i_rImpl.m_xBaseURI.is(), "base URI is null"); |
775 | 6.33k | OSL_ENSURE(i_rImpl.m_xRepository.is(), "repository is null"); |
776 | 6.33k | OSL_ENSURE(i_rImpl.m_xManifest.is(), "manifest is null"); |
777 | | |
778 | 6.33k | if (rterr.hasValue()) { |
779 | 0 | throw lang::WrappedTargetRuntimeException( |
780 | 0 | u"DocumentMetadataAccess::loadMetadataFromStorage: " |
781 | 0 | "exception"_ustr, nullptr, rterr); |
782 | 0 | } |
783 | | |
784 | 6.33k | if (err && handleError(iaioe, i_xHandler)) |
785 | 0 | goto retry; |
786 | 6.33k | } |
787 | | |
788 | | /** init Impl struct */ |
789 | | static void init(struct DocumentMetadataAccess_Impl & i_rImpl) |
790 | 0 | { |
791 | 0 | try { |
792 | |
|
793 | 0 | i_rImpl.m_xManifest.set(i_rImpl.m_xRepository->createGraph( |
794 | 0 | getURIForStream(i_rImpl, s_manifest)), |
795 | 0 | uno::UNO_SET_THROW); |
796 | | |
797 | | // insert the document statement |
798 | 0 | i_rImpl.m_xManifest->addStatement(i_rImpl.m_xBaseURI, |
799 | 0 | getURI<rdf::URIs::RDF_TYPE>(i_rImpl.m_xContext), |
800 | 0 | getURI<rdf::URIs::PKG_DOCUMENT>(i_rImpl.m_xContext)); |
801 | 0 | } catch (const uno::Exception &) { |
802 | 0 | css::uno::Any anyEx = cppu::getCaughtException(); |
803 | 0 | throw lang::WrappedTargetRuntimeException( |
804 | 0 | u"init: unexpected exception"_ustr, nullptr, |
805 | 0 | anyEx); |
806 | 0 | } |
807 | | |
808 | | // add top-level content files |
809 | 0 | if (!addContentOrStylesFileImpl(i_rImpl, s_content)) { |
810 | 0 | throw uno::RuntimeException(); |
811 | 0 | } |
812 | 0 | if (!addContentOrStylesFileImpl(i_rImpl, s_styles)) { |
813 | 0 | throw uno::RuntimeException(); |
814 | 0 | } |
815 | 0 | } |
816 | | |
817 | | |
818 | | DocumentMetadataAccess::DocumentMetadataAccess( |
819 | | uno::Reference< uno::XComponentContext > const & i_xContext, |
820 | | const SfxObjectShell & i_rRegistrySupplier) |
821 | 6.33k | : m_pImpl(new DocumentMetadataAccess_Impl(i_xContext, i_rRegistrySupplier)) |
822 | 6.33k | { |
823 | | // no initialization: must call loadFrom... |
824 | 6.33k | } |
825 | | |
826 | | DocumentMetadataAccess::DocumentMetadataAccess( |
827 | | uno::Reference< uno::XComponentContext > const & i_xContext, |
828 | | const SfxObjectShell & i_rRegistrySupplier, |
829 | | OUString const & i_rURI) |
830 | 0 | : m_pImpl(new DocumentMetadataAccess_Impl(i_xContext, i_rRegistrySupplier)) |
831 | 0 | { |
832 | 0 | OSL_ENSURE(!i_rURI.isEmpty(), "DMA::DMA: no URI given!"); |
833 | 0 | OSL_ENSURE(i_rURI.endsWith("/"), "DMA::DMA: URI without / given!"); |
834 | 0 | if (!i_rURI.endsWith("/")) throw uno::RuntimeException(); |
835 | 0 | m_pImpl->m_xBaseURI.set(rdf::URI::create(m_pImpl->m_xContext, i_rURI)); |
836 | 0 | m_pImpl->m_xRepository.set(rdf::Repository::create(m_pImpl->m_xContext), |
837 | 0 | uno::UNO_SET_THROW); |
838 | | |
839 | | // init repository |
840 | 0 | init(*m_pImpl); |
841 | |
|
842 | 0 | OSL_ENSURE(m_pImpl->m_xBaseURI.is(), "base URI is null"); |
843 | 0 | OSL_ENSURE(m_pImpl->m_xRepository.is(), "repository is null"); |
844 | 0 | OSL_ENSURE(m_pImpl->m_xManifest.is(), "manifest is null"); |
845 | 0 | } |
846 | | |
847 | | DocumentMetadataAccess::~DocumentMetadataAccess() |
848 | 6.33k | { |
849 | 6.33k | } |
850 | | |
851 | | // css::rdf::XRepositorySupplier: |
852 | | uno::Reference< rdf::XRepository > SAL_CALL |
853 | | DocumentMetadataAccess::getRDFRepository() |
854 | 24 | { |
855 | 24 | OSL_ENSURE(m_pImpl->m_xRepository.is(), "repository not initialized"); |
856 | 24 | return m_pImpl->m_xRepository; |
857 | 24 | } |
858 | | |
859 | | // css::rdf::XNode: |
860 | | OUString SAL_CALL |
861 | | DocumentMetadataAccess::getStringValue() |
862 | 0 | { |
863 | 0 | return m_pImpl->m_xBaseURI->getStringValue(); |
864 | 0 | } |
865 | | |
866 | | // css::rdf::XURI: |
867 | | OUString SAL_CALL |
868 | | DocumentMetadataAccess::getNamespace() |
869 | 0 | { |
870 | 0 | return m_pImpl->m_xBaseURI->getNamespace(); |
871 | 0 | } |
872 | | |
873 | | OUString SAL_CALL |
874 | | DocumentMetadataAccess::getLocalName() |
875 | 0 | { |
876 | 0 | return m_pImpl->m_xBaseURI->getLocalName(); |
877 | 0 | } |
878 | | |
879 | | // css::rdf::XDocumentMetadataAccess: |
880 | | uno::Reference< rdf::XMetadatable > SAL_CALL |
881 | | DocumentMetadataAccess::getElementByMetadataReference( |
882 | | const css::beans::StringPair & i_rReference) |
883 | 0 | { |
884 | 0 | const IXmlIdRegistry * pReg( |
885 | 0 | m_pImpl->m_rXmlIdRegistrySupplier.GetXmlIdRegistry() ); |
886 | 0 | if (!pReg) { |
887 | 0 | throw uno::RuntimeException( |
888 | 0 | u"DocumentMetadataAccess::getElementByXmlId: no registry"_ustr, *this); |
889 | 0 | } |
890 | 0 | return pReg->GetElementByMetadataReference(i_rReference); |
891 | 0 | } |
892 | | |
893 | | uno::Reference< rdf::XMetadatable > SAL_CALL |
894 | | DocumentMetadataAccess::getElementByURI( |
895 | | const uno::Reference< rdf::XURI > & i_xURI ) |
896 | 0 | { |
897 | 0 | if (!i_xURI.is()) { |
898 | 0 | throw lang::IllegalArgumentException( |
899 | 0 | u"DocumentMetadataAccess::getElementByURI: URI is null"_ustr, *this, 0); |
900 | 0 | } |
901 | | |
902 | 0 | const OUString baseURI( m_pImpl->m_xBaseURI->getStringValue() ); |
903 | 0 | const OUString name( i_xURI->getStringValue() ); |
904 | 0 | if (!name.match(baseURI)) { |
905 | 0 | return nullptr; |
906 | 0 | } |
907 | 0 | OUString path; |
908 | 0 | OUString idref; |
909 | 0 | if (!splitXmlId(name.subView(baseURI.getLength()), path, idref)) { |
910 | 0 | return nullptr; |
911 | 0 | } |
912 | | |
913 | 0 | return getElementByMetadataReference( beans::StringPair(path, idref) ); |
914 | 0 | } |
915 | | |
916 | | uno::Sequence<uno::Reference<rdf::XURI>> SAL_CALL |
917 | | DocumentMetadataAccess::getMetadataGraphsWithType(const uno::Reference<rdf::XURI>& i_xType) |
918 | 1.11k | { |
919 | 1.11k | if (!i_xType.is()) |
920 | 0 | { |
921 | 0 | throw lang::IllegalArgumentException(u"DocumentMetadataAccess::getMetadataGraphsWithType: " |
922 | 0 | "type is null"_ustr, |
923 | 0 | *this, 0); |
924 | 0 | } |
925 | | |
926 | 1.11k | return ::comphelper::containerToSequence(getAllParts(*m_pImpl, i_xType)); |
927 | 1.11k | } |
928 | | |
929 | | uno::Reference<rdf::XURI> SAL_CALL |
930 | | DocumentMetadataAccess::addMetadataFile(const OUString & i_rFileName, |
931 | | const uno::Sequence < uno::Reference< rdf::XURI > > & i_rTypes) |
932 | 0 | { |
933 | 0 | if (!isFileNameValid(i_rFileName)) { |
934 | 0 | throw lang::IllegalArgumentException( |
935 | 0 | u"DocumentMetadataAccess::addMetadataFile: invalid FileName"_ustr, |
936 | 0 | *this, 0); |
937 | 0 | } |
938 | 0 | if (isReservedFile(i_rFileName)) { |
939 | 0 | throw lang::IllegalArgumentException( |
940 | 0 | u"DocumentMetadataAccess::addMetadataFile:" |
941 | 0 | "invalid FileName: reserved"_ustr, *this, 0); |
942 | 0 | } |
943 | 0 | if (std::any_of(i_rTypes.begin(), i_rTypes.end(), |
944 | 0 | [](const uno::Reference< rdf::XURI >& rType) { return !rType.is(); })) { |
945 | 0 | throw lang::IllegalArgumentException( |
946 | 0 | u"DocumentMetadataAccess::addMetadataFile: " |
947 | 0 | "null type"_ustr, *this, 2); |
948 | 0 | } |
949 | | |
950 | 0 | const uno::Reference<rdf::XURI> xGraphName( |
951 | 0 | getURIForStream(*m_pImpl, i_rFileName) ); |
952 | |
|
953 | 0 | try { |
954 | 0 | m_pImpl->m_xRepository->createGraph(xGraphName); |
955 | 0 | } catch (const rdf::RepositoryException &) { |
956 | 0 | css::uno::Any anyEx = cppu::getCaughtException(); |
957 | 0 | throw lang::WrappedTargetRuntimeException( |
958 | 0 | u"DocumentMetadataAccess::addMetadataFile: exception"_ustr, |
959 | 0 | *this, anyEx); |
960 | | // note: all other exceptions are propagated |
961 | 0 | } |
962 | | |
963 | 0 | addMetadataFileImpl(*m_pImpl, i_rFileName, i_rTypes); |
964 | 0 | return xGraphName; |
965 | 0 | } |
966 | | |
967 | | uno::Reference<rdf::XURI> SAL_CALL |
968 | | DocumentMetadataAccess::importMetadataFile(::sal_Int16 i_Format, |
969 | | const uno::Reference< io::XInputStream > & i_xInStream, |
970 | | const OUString & i_rFileName, |
971 | | const uno::Reference< rdf::XURI > & i_xBaseURI, |
972 | | const uno::Sequence < uno::Reference< rdf::XURI > > & i_rTypes) |
973 | 0 | { |
974 | 0 | if (!isFileNameValid(i_rFileName)) { |
975 | 0 | throw lang::IllegalArgumentException( |
976 | 0 | u"DocumentMetadataAccess::importMetadataFile: invalid FileName"_ustr, |
977 | 0 | *this, 0); |
978 | 0 | } |
979 | 0 | if (isReservedFile(i_rFileName)) { |
980 | 0 | throw lang::IllegalArgumentException( |
981 | 0 | u"DocumentMetadataAccess::importMetadataFile:" |
982 | 0 | "invalid FileName: reserved"_ustr, *this, 0); |
983 | 0 | } |
984 | 0 | if (std::any_of(i_rTypes.begin(), i_rTypes.end(), |
985 | 0 | [](const uno::Reference< rdf::XURI >& rType) { return !rType.is(); })) { |
986 | 0 | throw lang::IllegalArgumentException( |
987 | 0 | u"DocumentMetadataAccess::importMetadataFile: null type"_ustr, |
988 | 0 | *this, 5); |
989 | 0 | } |
990 | | |
991 | 0 | const uno::Reference<rdf::XURI> xGraphName( |
992 | 0 | getURIForStream(*m_pImpl, i_rFileName) ); |
993 | |
|
994 | 0 | try { |
995 | 0 | m_pImpl->m_xRepository->importGraph( |
996 | 0 | i_Format, i_xInStream, xGraphName, i_xBaseURI); |
997 | 0 | } catch (const rdf::RepositoryException &) { |
998 | 0 | css::uno::Any anyEx = cppu::getCaughtException(); |
999 | 0 | throw lang::WrappedTargetRuntimeException( |
1000 | 0 | u"DocumentMetadataAccess::importMetadataFile: " |
1001 | 0 | "RepositoryException"_ustr, *this, anyEx); |
1002 | | // note: all other exceptions are propagated |
1003 | 0 | } |
1004 | | |
1005 | | // add to manifest |
1006 | 0 | addMetadataFileImpl(*m_pImpl, i_rFileName, i_rTypes); |
1007 | 0 | return xGraphName; |
1008 | 0 | } |
1009 | | |
1010 | | void SAL_CALL |
1011 | | DocumentMetadataAccess::removeMetadataFile( |
1012 | | const uno::Reference< rdf::XURI > & i_xGraphName) |
1013 | 0 | { |
1014 | 0 | try { |
1015 | 0 | m_pImpl->m_xRepository->destroyGraph(i_xGraphName); |
1016 | 0 | } catch (const rdf::RepositoryException &) { |
1017 | 0 | css::uno::Any anyEx = cppu::getCaughtException(); |
1018 | 0 | throw lang::WrappedTargetRuntimeException( |
1019 | 0 | u"DocumentMetadataAccess::removeMetadataFile: " |
1020 | 0 | "RepositoryException"_ustr, *this, anyEx); |
1021 | | // note: all other exceptions are propagated |
1022 | 0 | } |
1023 | | |
1024 | | // remove file from manifest |
1025 | 0 | removeFile(*m_pImpl, i_xGraphName); |
1026 | 0 | } |
1027 | | |
1028 | | void SAL_CALL |
1029 | | DocumentMetadataAccess::addContentOrStylesFile( |
1030 | | const OUString & i_rFileName) |
1031 | 0 | { |
1032 | 0 | if (!isFileNameValid(i_rFileName)) { |
1033 | 0 | throw lang::IllegalArgumentException( |
1034 | 0 | u"DocumentMetadataAccess::addContentOrStylesFile: " |
1035 | 0 | "invalid FileName"_ustr, *this, 0); |
1036 | 0 | } |
1037 | | |
1038 | 0 | if (!addContentOrStylesFileImpl(*m_pImpl, i_rFileName)) { |
1039 | 0 | throw lang::IllegalArgumentException( |
1040 | 0 | u"DocumentMetadataAccess::addContentOrStylesFile: " |
1041 | 0 | "invalid FileName: must end with content.xml or styles.xml"_ustr, |
1042 | 0 | *this, 0); |
1043 | 0 | } |
1044 | 0 | } |
1045 | | |
1046 | | void SAL_CALL |
1047 | | DocumentMetadataAccess::removeContentOrStylesFile( |
1048 | | const OUString & i_rFileName) |
1049 | 0 | { |
1050 | 0 | if (!isFileNameValid(i_rFileName)) { |
1051 | 0 | throw lang::IllegalArgumentException( |
1052 | 0 | u"DocumentMetadataAccess::removeContentOrStylesFile: " |
1053 | 0 | "invalid FileName"_ustr, *this, 0); |
1054 | 0 | } |
1055 | | |
1056 | 0 | try { |
1057 | 0 | const uno::Reference<rdf::XURI> xPart( |
1058 | 0 | getURIForStream(*m_pImpl, i_rFileName) ); |
1059 | 0 | const uno::Reference<container::XEnumeration> xEnum( |
1060 | 0 | m_pImpl->m_xManifest->getStatements( m_pImpl->m_xBaseURI, |
1061 | 0 | getURI<rdf::URIs::PKG_HASPART>(m_pImpl->m_xContext), |
1062 | 0 | xPart), |
1063 | 0 | uno::UNO_SET_THROW); |
1064 | 0 | if (!xEnum->hasMoreElements()) { |
1065 | 0 | throw container::NoSuchElementException( |
1066 | 0 | "DocumentMetadataAccess::removeContentOrStylesFile: " |
1067 | 0 | "cannot find stream in manifest graph: " + i_rFileName, |
1068 | 0 | *this); |
1069 | 0 | } |
1070 | | |
1071 | | // remove file from manifest |
1072 | 0 | removeFile(*m_pImpl, xPart); |
1073 | |
|
1074 | 0 | } catch (const uno::RuntimeException &) { |
1075 | 0 | throw; |
1076 | 0 | } catch (const uno::Exception &) { |
1077 | 0 | css::uno::Any anyEx = cppu::getCaughtException(); |
1078 | 0 | throw lang::WrappedTargetRuntimeException( |
1079 | 0 | u"DocumentMetadataAccess::removeContentOrStylesFile: exception"_ustr, |
1080 | 0 | *this, anyEx); |
1081 | 0 | } |
1082 | 0 | } |
1083 | | |
1084 | | void SAL_CALL DocumentMetadataAccess::loadMetadataFromStorage( |
1085 | | const uno::Reference< embed::XStorage > & i_xStorage, |
1086 | | const uno::Reference<rdf::XURI> & i_xBaseURI, |
1087 | | const uno::Reference<task::XInteractionHandler> & i_xHandler) |
1088 | 6.33k | { |
1089 | 6.33k | if (!i_xStorage.is()) { |
1090 | 0 | throw lang::IllegalArgumentException( |
1091 | 0 | u"DocumentMetadataAccess::loadMetadataFromStorage: " |
1092 | 0 | "storage is null"_ustr, *this, 0); |
1093 | 0 | } |
1094 | 6.33k | if (!i_xBaseURI.is()) { |
1095 | 0 | throw lang::IllegalArgumentException( |
1096 | 0 | u"DocumentMetadataAccess::loadMetadataFromStorage: " |
1097 | 0 | "base URI is null"_ustr, *this, 1); |
1098 | 0 | } |
1099 | 6.33k | const OUString baseURI( i_xBaseURI->getStringValue()); |
1100 | 6.33k | if (baseURI.indexOf('#') >= 0) { |
1101 | 0 | throw lang::IllegalArgumentException( |
1102 | 0 | u"DocumentMetadataAccess::loadMetadataFromStorage: " |
1103 | 0 | "base URI not absolute"_ustr, *this, 1); |
1104 | 0 | } |
1105 | 6.33k | if (!baseURI.endsWith("/")) { |
1106 | 0 | throw lang::IllegalArgumentException( |
1107 | 0 | u"DocumentMetadataAccess::loadMetadataFromStorage: " |
1108 | 0 | "base URI does not end with slash"_ustr, *this, 1); |
1109 | 0 | } |
1110 | | |
1111 | 6.33k | initLoading(*m_pImpl, i_xStorage, i_xBaseURI, i_xHandler); |
1112 | | |
1113 | 6.33k | std::set< OUString > StgFiles; |
1114 | 6.33k | collectFilesFromStorage(i_xStorage, StgFiles); |
1115 | | |
1116 | 6.33k | std::vector< OUString > MfstMetadataFiles; |
1117 | | |
1118 | 6.33k | try { |
1119 | 6.33k | const ::std::vector< uno::Reference< rdf::XURI > > parts( |
1120 | 6.33k | getAllParts(*m_pImpl) ); |
1121 | 6.33k | const uno::Reference<rdf::XURI>& xContentFile( |
1122 | 6.33k | getURI<rdf::URIs::ODF_CONTENTFILE>(m_pImpl->m_xContext)); |
1123 | 6.33k | const uno::Reference<rdf::XURI>& xStylesFile( |
1124 | 6.33k | getURI<rdf::URIs::ODF_STYLESFILE>(m_pImpl->m_xContext)); |
1125 | 6.33k | const uno::Reference<rdf::XURI>& xMetadataFile( |
1126 | 6.33k | getURI<rdf::URIs::PKG_METADATAFILE>(m_pImpl->m_xContext)); |
1127 | 6.33k | const sal_Int32 len( baseURI.getLength() ); |
1128 | 6.33k | for (const auto& rxPart : parts) { |
1129 | 0 | const OUString name(rxPart->getStringValue()); |
1130 | 0 | if (!name.match(baseURI)) { |
1131 | 0 | SAL_WARN("sfx", "loadMetadataFromStorage: graph not in document: " << name); |
1132 | 0 | continue; |
1133 | 0 | } |
1134 | 0 | const OUString relName( name.copy(len) ); |
1135 | 0 | if (relName == s_manifest) { |
1136 | 0 | SAL_WARN("sfx", "loadMetadataFromStorage: found ourselves a recursive manifest!"); |
1137 | 0 | continue; |
1138 | 0 | } |
1139 | | // remove found items from StgFiles |
1140 | 0 | StgFiles.erase(relName); |
1141 | 0 | if (isContentFile(relName)) { |
1142 | 0 | if (!isPartOfType(*m_pImpl, rxPart, xContentFile)) { |
1143 | 0 | const uno::Reference <rdf::XURI> xName( |
1144 | 0 | getURIForStream(*m_pImpl, relName) ); |
1145 | | // add missing type statement |
1146 | 0 | m_pImpl->m_xManifest->addStatement(xName, |
1147 | 0 | getURI<rdf::URIs::RDF_TYPE>(m_pImpl->m_xContext), |
1148 | 0 | xContentFile); |
1149 | 0 | } |
1150 | 0 | } else if (isStylesFile(relName)) { |
1151 | 0 | if (!isPartOfType(*m_pImpl, rxPart, xStylesFile)) { |
1152 | 0 | const uno::Reference <rdf::XURI> xName( |
1153 | 0 | getURIForStream(*m_pImpl, relName) ); |
1154 | | // add missing type statement |
1155 | 0 | m_pImpl->m_xManifest->addStatement(xName, |
1156 | 0 | getURI<rdf::URIs::RDF_TYPE>(m_pImpl->m_xContext), |
1157 | 0 | xStylesFile); |
1158 | 0 | } |
1159 | 0 | } else if (isReservedFile(relName)) { |
1160 | 0 | SAL_WARN("sfx", "loadMetadataFromStorage: reserved file name in manifest"); |
1161 | 0 | } else { |
1162 | 0 | if (isPartOfType(*m_pImpl, rxPart, xMetadataFile)) { |
1163 | 0 | MfstMetadataFiles.push_back(relName); |
1164 | 0 | } |
1165 | | // do not add statement for MetadataFile; it could be |
1166 | | // something else! just ignore it... |
1167 | 0 | } |
1168 | 0 | } |
1169 | 6.33k | } catch (const uno::RuntimeException &) { |
1170 | 0 | throw; |
1171 | 0 | } catch (const uno::Exception &) { |
1172 | 0 | css::uno::Any anyEx = cppu::getCaughtException(); |
1173 | 0 | throw lang::WrappedTargetRuntimeException( |
1174 | 0 | u"DocumentMetadataAccess::loadMetadataFromStorage: " |
1175 | 0 | "exception"_ustr, *this, anyEx); |
1176 | 0 | } |
1177 | | |
1178 | 6.33k | for (const auto& aStgFile : StgFiles) |
1179 | 0 | addContentOrStylesFileImpl(*m_pImpl, aStgFile); |
1180 | | |
1181 | 6.33k | for (const auto& aMfstMetadataFile : MfstMetadataFiles) |
1182 | 0 | importFile(*m_pImpl, i_xStorage, baseURI, i_xHandler, aMfstMetadataFile); |
1183 | 6.33k | } |
1184 | | |
1185 | | void SAL_CALL DocumentMetadataAccess::storeMetadataToStorage( |
1186 | | const uno::Reference< embed::XStorage > & i_xStorage) |
1187 | 0 | { |
1188 | 0 | if (!i_xStorage.is()) { |
1189 | 0 | throw lang::IllegalArgumentException( |
1190 | 0 | u"DocumentMetadataAccess::storeMetadataToStorage: " |
1191 | 0 | "storage is null"_ustr, *this, 0); |
1192 | 0 | } |
1193 | | |
1194 | | // export manifest |
1195 | 0 | const uno::Reference <rdf::XURI> xManifest( |
1196 | 0 | getURIForStream(*m_pImpl, s_manifest) ); |
1197 | 0 | const OUString baseURI( m_pImpl->m_xBaseURI->getStringValue() ); |
1198 | 0 | try { |
1199 | 0 | writeStream(*m_pImpl, i_xStorage, xManifest, s_manifest, baseURI); |
1200 | 0 | } catch (const uno::RuntimeException &) { |
1201 | 0 | throw; |
1202 | 0 | } catch (const io::IOException &) { |
1203 | 0 | css::uno::Any anyEx = cppu::getCaughtException(); |
1204 | 0 | throw lang::WrappedTargetException( |
1205 | 0 | u"storeMetadataToStorage: IO exception"_ustr, *this, anyEx); |
1206 | 0 | } catch (const uno::Exception &) { |
1207 | 0 | css::uno::Any anyEx = cppu::getCaughtException(); |
1208 | 0 | throw lang::WrappedTargetRuntimeException( |
1209 | 0 | u"storeMetadataToStorage: exception"_ustr, *this, anyEx); |
1210 | 0 | } |
1211 | | |
1212 | | // export metadata streams |
1213 | 0 | try { |
1214 | 0 | const uno::Sequence<uno::Reference<rdf::XURI> > graphs( |
1215 | 0 | m_pImpl->m_xRepository->getGraphNames()); |
1216 | 0 | const sal_Int32 len( baseURI.getLength() ); |
1217 | 0 | for (const uno::Reference<rdf::XURI>& xName : graphs) { |
1218 | 0 | const OUString name(xName->getStringValue()); |
1219 | 0 | if (!name.match(baseURI)) { |
1220 | 0 | SAL_WARN("sfx", "storeMetadataToStorage: graph not in document: " << name); |
1221 | 0 | continue; |
1222 | 0 | } |
1223 | 0 | const OUString relName( name.copy(len) ); |
1224 | 0 | if (relName == s_manifest) { |
1225 | 0 | continue; |
1226 | 0 | } |
1227 | 0 | if (!isFileNameValid(relName) || isReservedFile(relName)) { |
1228 | 0 | SAL_WARN("sfx", "storeMetadataToStorage: invalid file name: " << relName); |
1229 | 0 | continue; |
1230 | 0 | } |
1231 | 0 | try { |
1232 | 0 | writeStream(*m_pImpl, i_xStorage, xName, relName, baseURI); |
1233 | 0 | } catch (const uno::RuntimeException &) { |
1234 | 0 | throw; |
1235 | 0 | } catch (const io::IOException &) { |
1236 | 0 | css::uno::Any anyEx = cppu::getCaughtException(); |
1237 | 0 | throw lang::WrappedTargetException( |
1238 | 0 | u"storeMetadataToStorage: IO exception"_ustr, |
1239 | 0 | *this, anyEx); |
1240 | 0 | } catch (const uno::Exception &) { |
1241 | 0 | css::uno::Any anyEx = cppu::getCaughtException(); |
1242 | 0 | throw lang::WrappedTargetRuntimeException( |
1243 | 0 | u"storeMetadataToStorage: exception"_ustr, |
1244 | 0 | *this, anyEx); |
1245 | 0 | } |
1246 | 0 | } |
1247 | 0 | } catch (const rdf::RepositoryException &) { |
1248 | 0 | css::uno::Any anyEx = cppu::getCaughtException(); |
1249 | 0 | throw lang::WrappedTargetRuntimeException( |
1250 | 0 | u"storeMetadataToStorage: exception"_ustr, *this, anyEx); |
1251 | 0 | } |
1252 | 0 | } |
1253 | | |
1254 | | void SAL_CALL |
1255 | | DocumentMetadataAccess::loadMetadataFromMedium( |
1256 | | const uno::Sequence< beans::PropertyValue > & i_rMedium) |
1257 | 0 | { |
1258 | 0 | uno::Reference<io::XInputStream> xIn; |
1259 | 0 | comphelper::SequenceAsHashMap md(i_rMedium); |
1260 | 0 | OUString URL; |
1261 | 0 | md[ utl::MediaDescriptor::PROP_URL ] >>= URL; |
1262 | 0 | OUString BaseURL; |
1263 | 0 | md[ utl::MediaDescriptor::PROP_DOCUMENTBASEURL ] >>= BaseURL; |
1264 | 0 | if (utl::MediaDescriptor::addInputStream(md)) { |
1265 | 0 | md[ utl::MediaDescriptor::PROP_INPUTSTREAM ] >>= xIn; |
1266 | 0 | } |
1267 | 0 | if (!xIn.is() && URL.isEmpty()) { |
1268 | 0 | throw lang::IllegalArgumentException( |
1269 | 0 | u"DocumentMetadataAccess::loadMetadataFromMedium: " |
1270 | 0 | "invalid medium: no URL, no input stream"_ustr, *this, 0); |
1271 | 0 | } |
1272 | 0 | uno::Reference<embed::XStorage> xStorage; |
1273 | 0 | try { |
1274 | 0 | if (xIn.is()) { |
1275 | 0 | xStorage = ::comphelper::OStorageHelper::GetStorageFromInputStream( |
1276 | 0 | xIn, m_pImpl->m_xContext); |
1277 | 0 | } else { // fallback to url |
1278 | 0 | xStorage = ::comphelper::OStorageHelper::GetStorageFromURL2( |
1279 | 0 | URL, embed::ElementModes::READ, m_pImpl->m_xContext); |
1280 | 0 | } |
1281 | 0 | } catch (const uno::RuntimeException &) { |
1282 | 0 | throw; |
1283 | 0 | } catch (const io::IOException &) { |
1284 | 0 | throw; |
1285 | 0 | } catch (const uno::Exception &) { |
1286 | 0 | css::uno::Any anyEx = cppu::getCaughtException(); |
1287 | 0 | throw lang::WrappedTargetException( |
1288 | 0 | u"DocumentMetadataAccess::loadMetadataFromMedium: " |
1289 | 0 | "exception"_ustr, *this, anyEx); |
1290 | 0 | } |
1291 | 0 | if (!xStorage.is()) { |
1292 | 0 | throw uno::RuntimeException( |
1293 | 0 | u"DocumentMetadataAccess::loadMetadataFromMedium: " |
1294 | 0 | "cannot get Storage"_ustr, *this); |
1295 | 0 | } |
1296 | 0 | uno::Reference<rdf::XURI> xBaseURI; |
1297 | 0 | try { |
1298 | 0 | xBaseURI = createBaseURI(m_pImpl->m_xContext, nullptr, BaseURL); |
1299 | 0 | } catch (const uno::Exception &) { |
1300 | | // fall back to URL |
1301 | 0 | try { |
1302 | 0 | xBaseURI = createBaseURI(m_pImpl->m_xContext, nullptr, URL); |
1303 | 0 | } catch (const uno::Exception &) { |
1304 | 0 | OSL_FAIL("cannot create base URI"); |
1305 | 0 | } |
1306 | 0 | } |
1307 | 0 | uno::Reference<task::XInteractionHandler> xIH; |
1308 | 0 | md[ utl::MediaDescriptor::PROP_INTERACTIONHANDLER ] >>= xIH; |
1309 | 0 | loadMetadataFromStorage(xStorage, xBaseURI, xIH); |
1310 | 0 | } |
1311 | | |
1312 | | void SAL_CALL |
1313 | | DocumentMetadataAccess::storeMetadataToMedium( |
1314 | | const uno::Sequence< beans::PropertyValue > & i_rMedium) |
1315 | 0 | { |
1316 | 0 | comphelper::SequenceAsHashMap md(i_rMedium); |
1317 | 0 | OUString URL; |
1318 | 0 | md[ utl::MediaDescriptor::PROP_URL ] >>= URL; |
1319 | 0 | if (URL.isEmpty()) { |
1320 | 0 | throw lang::IllegalArgumentException( |
1321 | 0 | u"DocumentMetadataAccess::storeMetadataToMedium: " |
1322 | 0 | "invalid medium: no URL"_ustr, *this, 0); |
1323 | 0 | } |
1324 | | |
1325 | 0 | SfxMedium aMedium(i_rMedium); |
1326 | 0 | uno::Reference<embed::XStorage> xStorage(aMedium.GetOutputStorage()); |
1327 | |
|
1328 | 0 | bool sfx(false); |
1329 | 0 | if (xStorage.is()) { |
1330 | 0 | sfx = true; |
1331 | 0 | } else { |
1332 | 0 | xStorage = ::comphelper::OStorageHelper::GetStorageFromURL2( |
1333 | 0 | URL, embed::ElementModes::WRITE, m_pImpl->m_xContext); |
1334 | 0 | } |
1335 | |
|
1336 | 0 | if (!xStorage.is()) { |
1337 | 0 | throw uno::RuntimeException( |
1338 | 0 | u"DocumentMetadataAccess::storeMetadataToMedium: " |
1339 | 0 | "cannot get Storage"_ustr, *this); |
1340 | 0 | } |
1341 | | // set MIME type of the storage |
1342 | 0 | auto iter = md.find(utl::MediaDescriptor::PROP_MEDIATYPE); |
1343 | 0 | if (iter != md.end()) { |
1344 | 0 | uno::Reference< beans::XPropertySet > xProps(xStorage, |
1345 | 0 | uno::UNO_QUERY_THROW); |
1346 | 0 | try { |
1347 | | // this is NOT supported in FileSystemStorage |
1348 | 0 | xProps->setPropertyValue( |
1349 | 0 | utl::MediaDescriptor::PROP_MEDIATYPE, |
1350 | 0 | iter->second); |
1351 | 0 | } catch (const uno::Exception &) { } |
1352 | 0 | } |
1353 | 0 | storeMetadataToStorage(xStorage); |
1354 | |
|
1355 | 0 | if (!sfx) |
1356 | 0 | return; |
1357 | | |
1358 | 0 | const bool bOk = aMedium.Commit(); |
1359 | 0 | aMedium.Close(); |
1360 | 0 | if ( !bOk ) { |
1361 | 0 | ErrCodeMsg nError = aMedium.GetErrorIgnoreWarning(); |
1362 | 0 | if ( nError == ERRCODE_NONE ) { |
1363 | 0 | nError = ERRCODE_IO_GENERAL; |
1364 | 0 | } |
1365 | 0 | task::ErrorCodeIOException ex( |
1366 | 0 | "DocumentMetadataAccess::storeMetadataToMedium Commit failed: " + nError.toString(), |
1367 | 0 | uno::Reference< uno::XInterface >(), sal_uInt32(nError.GetCode())); |
1368 | 0 | throw lang::WrappedTargetException(OUString(), *this, |
1369 | 0 | uno::Any(ex)); |
1370 | 0 | } |
1371 | 0 | } |
1372 | | |
1373 | | } // namespace sfx2 |
1374 | | |
1375 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |