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 <sal/config.h>
21 :
22 : #include <boost/noncopyable.hpp>
23 : #include <cppuhelper/compbase6.hxx>
24 : #include <com/sun/star/lang/XServiceInfo.hpp>
25 : #include <com/sun/star/document/XDocumentProperties.hpp>
26 : #include <com/sun/star/lang/XInitialization.hpp>
27 : #include <com/sun/star/util/XCloneable.hpp>
28 : #include <com/sun/star/util/XModifiable.hpp>
29 : #include <com/sun/star/xml/sax/XSAXSerializable.hpp>
30 :
31 : #include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
32 : #include <com/sun/star/lang/EventObject.hpp>
33 : #include <com/sun/star/beans/XPropertySet.hpp>
34 : #include <com/sun/star/beans/XPropertySetInfo.hpp>
35 : #include <com/sun/star/beans/PropertyAttribute.hpp>
36 : #include <com/sun/star/task/ErrorCodeIOException.hpp>
37 : #include <com/sun/star/embed/XStorage.hpp>
38 : #include <com/sun/star/embed/XTransactedObject.hpp>
39 : #include <com/sun/star/embed/ElementModes.hpp>
40 : #include <com/sun/star/io/XActiveDataControl.hpp>
41 : #include <com/sun/star/io/XActiveDataSource.hpp>
42 : #include <com/sun/star/io/XStream.hpp>
43 : #include <com/sun/star/document/XImporter.hpp>
44 : #include <com/sun/star/document/XExporter.hpp>
45 : #include <com/sun/star/document/XFilter.hpp>
46 : #include <com/sun/star/xml/sax/Parser.hpp>
47 : #include <com/sun/star/xml/sax/Writer.hpp>
48 : #include <com/sun/star/xml/dom/XDocument.hpp>
49 : #include <com/sun/star/xml/dom/XElement.hpp>
50 : #include <com/sun/star/xml/dom/DocumentBuilder.hpp>
51 : #include <com/sun/star/xml/dom/XSAXDocumentBuilder.hpp>
52 : #include <com/sun/star/xml/dom/NodeType.hpp>
53 : #include <com/sun/star/xml/xpath/XPathAPI.hpp>
54 : #include <com/sun/star/util/Date.hpp>
55 : #include <com/sun/star/util/Time.hpp>
56 : #include <com/sun/star/util/DateWithTimezone.hpp>
57 : #include <com/sun/star/util/DateTimeWithTimezone.hpp>
58 : #include <com/sun/star/util/Duration.hpp>
59 :
60 : #include <rtl/ref.hxx>
61 : #include <rtl/ustrbuf.hxx>
62 : #include <tools/debug.hxx>
63 : #include <tools/datetime.hxx>
64 : #include <osl/mutex.hxx>
65 : #include <cppuhelper/basemutex.hxx>
66 : #include <cppuhelper/interfacecontainer.hxx>
67 : #include <comphelper/storagehelper.hxx>
68 : #include <unotools/mediadescriptor.hxx>
69 : #include <comphelper/sequence.hxx>
70 : #include <sot/storage.hxx>
71 : #include <sfx2/docfile.hxx>
72 : #include <sax/tools/converter.hxx>
73 : #include <i18nlangtag/languagetag.hxx>
74 :
75 : #include <utility>
76 : #include <vector>
77 : #include <map>
78 : #include <cstring>
79 : #include <limits>
80 :
81 :
82 : #include <cppuhelper/implbase1.hxx>
83 : #include <cppuhelper/supportsservice.hxx>
84 : #include <com/sun/star/document/XCompatWriterDocProperties.hpp>
85 : #include <com/sun/star/beans/PropertyBag.hpp>
86 :
87 : /**
88 : * This file contains the implementation of the service
89 : * com.sun.star.document.DocumentProperties.
90 : * This service enables access to the meta-data stored in documents.
91 : * Currently, this service only handles documents in ODF format.
92 : *
93 : * The implementation uses an XML DOM to store the properties.
94 : * This approach was taken because it allows for preserving arbitrary XML data
95 : * in loaded documents, which will be stored unmodified when saving the
96 : * document again.
97 : *
98 : * Upon access, some properties are directly read from and updated in the DOM.
99 : * Exception: it seems impossible to get notified upon addition of a property
100 : * to a com.sun.star.beans.PropertyBag, which is used for storing user-defined
101 : * properties; because of this, user-defined properties are updated in the
102 : * XML DOM only when storing the document.
103 : * Exception 2: when setting certain properties which correspond to attributes
104 : * in the XML DOM, we want to remove the corresponding XML element. Detecting
105 : * this condition can get messy, so we store all such properties as members,
106 : * and update the DOM tree only when storing the document (in
107 : * <method>updateUserDefinedAndAttributes</method>).
108 : *
109 : */
110 :
111 : /// anonymous implementation namespace
112 : namespace {
113 :
114 : /// a list of attribute-lists, where attribute means name and content
115 : typedef std::vector<std::vector<std::pair<const char*, OUString> > >
116 : AttrVector;
117 :
118 : typedef ::cppu::WeakComponentImplHelper6<
119 : css::lang::XServiceInfo,
120 : css::document::XDocumentProperties,
121 : css::lang::XInitialization,
122 : css::util::XCloneable,
123 : css::util::XModifiable,
124 : css::xml::sax::XSAXSerializable>
125 : SfxDocumentMetaData_Base;
126 :
127 : class SfxDocumentMetaData:
128 : private ::cppu::BaseMutex,
129 : public SfxDocumentMetaData_Base,
130 : private boost::noncopyable
131 : {
132 : public:
133 : explicit SfxDocumentMetaData(
134 : css::uno::Reference< css::uno::XComponentContext > const & context);
135 :
136 : // ::com::sun::star::lang::XServiceInfo:
137 : virtual OUString SAL_CALL getImplementationName()
138 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
139 : virtual sal_Bool SAL_CALL supportsService(
140 : const OUString & ServiceName) throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
141 : virtual css::uno::Sequence< OUString > SAL_CALL
142 : getSupportedServiceNames() throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
143 :
144 : // ::com::sun::star::lang::XComponent:
145 : virtual void SAL_CALL dispose() throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
146 :
147 : // ::com::sun::star::document::XDocumentProperties:
148 : virtual OUString SAL_CALL getAuthor()
149 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
150 : virtual void SAL_CALL setAuthor(const OUString & the_value)
151 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
152 : virtual OUString SAL_CALL getGenerator()
153 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
154 : virtual void SAL_CALL setGenerator(const OUString & the_value)
155 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
156 : virtual css::util::DateTime SAL_CALL getCreationDate()
157 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
158 : virtual void SAL_CALL setCreationDate(const css::util::DateTime & the_value)
159 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
160 : virtual OUString SAL_CALL getTitle()
161 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
162 : virtual void SAL_CALL setTitle(const OUString & the_value)
163 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
164 : virtual OUString SAL_CALL getSubject()
165 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
166 : virtual void SAL_CALL setSubject(const OUString & the_value)
167 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
168 : virtual OUString SAL_CALL getDescription()
169 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
170 : virtual void SAL_CALL setDescription(const OUString & the_value)
171 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
172 : virtual css::uno::Sequence< OUString > SAL_CALL getKeywords()
173 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
174 : virtual void SAL_CALL setKeywords(
175 : const css::uno::Sequence< OUString > & the_value)
176 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
177 : virtual css::lang::Locale SAL_CALL getLanguage()
178 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
179 : virtual void SAL_CALL setLanguage(const css::lang::Locale & the_value)
180 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
181 : virtual OUString SAL_CALL getModifiedBy()
182 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
183 : virtual void SAL_CALL setModifiedBy(const OUString & the_value)
184 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
185 : virtual css::util::DateTime SAL_CALL getModificationDate()
186 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
187 : virtual void SAL_CALL setModificationDate(
188 : const css::util::DateTime & the_value)
189 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
190 : virtual OUString SAL_CALL getPrintedBy()
191 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
192 : virtual void SAL_CALL setPrintedBy(const OUString & the_value)
193 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
194 : virtual css::util::DateTime SAL_CALL getPrintDate()
195 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
196 : virtual void SAL_CALL setPrintDate(const css::util::DateTime & the_value)
197 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
198 : virtual OUString SAL_CALL getTemplateName()
199 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
200 : virtual void SAL_CALL setTemplateName(const OUString & the_value)
201 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
202 : virtual OUString SAL_CALL getTemplateURL()
203 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
204 : virtual void SAL_CALL setTemplateURL(const OUString & the_value)
205 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
206 : virtual css::util::DateTime SAL_CALL getTemplateDate()
207 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
208 : virtual void SAL_CALL setTemplateDate(const css::util::DateTime & the_value)
209 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
210 : virtual OUString SAL_CALL getAutoloadURL()
211 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
212 : virtual void SAL_CALL setAutoloadURL(const OUString & the_value)
213 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
214 : virtual ::sal_Int32 SAL_CALL getAutoloadSecs()
215 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
216 : virtual void SAL_CALL setAutoloadSecs(::sal_Int32 the_value)
217 : throw (css::uno::RuntimeException, css::lang::IllegalArgumentException, std::exception) SAL_OVERRIDE;
218 : virtual OUString SAL_CALL getDefaultTarget()
219 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
220 : virtual void SAL_CALL setDefaultTarget(const OUString & the_value)
221 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
222 : virtual css::uno::Sequence< css::beans::NamedValue > SAL_CALL
223 : getDocumentStatistics() throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
224 : virtual void SAL_CALL setDocumentStatistics(
225 : const css::uno::Sequence< css::beans::NamedValue > & the_value)
226 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
227 : virtual ::sal_Int16 SAL_CALL getEditingCycles()
228 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
229 : virtual void SAL_CALL setEditingCycles(::sal_Int16 the_value)
230 : throw (css::uno::RuntimeException, css::lang::IllegalArgumentException, std::exception) SAL_OVERRIDE;
231 : virtual ::sal_Int32 SAL_CALL getEditingDuration()
232 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
233 : virtual void SAL_CALL setEditingDuration(::sal_Int32 the_value)
234 : throw (css::uno::RuntimeException, css::lang::IllegalArgumentException, std::exception) SAL_OVERRIDE;
235 : virtual void SAL_CALL resetUserData(const OUString & the_value)
236 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
237 : virtual css::uno::Reference< css::beans::XPropertyContainer > SAL_CALL
238 : getUserDefinedProperties() throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
239 : virtual void SAL_CALL loadFromStorage(
240 : const css::uno::Reference< css::embed::XStorage > & Storage,
241 : const css::uno::Sequence< css::beans::PropertyValue > & Medium)
242 : throw (css::uno::RuntimeException, css::lang::IllegalArgumentException,
243 : css::io::WrongFormatException,
244 : css::lang::WrappedTargetException, css::io::IOException, std::exception) SAL_OVERRIDE;
245 : virtual void SAL_CALL loadFromMedium(const OUString & URL,
246 : const css::uno::Sequence< css::beans::PropertyValue > & Medium)
247 : throw (css::uno::RuntimeException,
248 : css::io::WrongFormatException,
249 : css::lang::WrappedTargetException, css::io::IOException, std::exception) SAL_OVERRIDE;
250 : virtual void SAL_CALL storeToStorage(
251 : const css::uno::Reference< css::embed::XStorage > & Storage,
252 : const css::uno::Sequence< css::beans::PropertyValue > & Medium)
253 : throw (css::uno::RuntimeException, css::lang::IllegalArgumentException,
254 : css::lang::WrappedTargetException, css::io::IOException, std::exception) SAL_OVERRIDE;
255 : virtual void SAL_CALL storeToMedium(const OUString & URL,
256 : const css::uno::Sequence< css::beans::PropertyValue > & Medium)
257 : throw (css::uno::RuntimeException,
258 : css::lang::WrappedTargetException, css::io::IOException, std::exception) SAL_OVERRIDE;
259 :
260 : // ::com::sun::star::lang::XInitialization:
261 : virtual void SAL_CALL initialize(
262 : const css::uno::Sequence< css::uno::Any > & aArguments)
263 : throw (css::uno::RuntimeException, css::uno::Exception, std::exception) SAL_OVERRIDE;
264 :
265 : // ::com::sun::star::util::XCloneable:
266 : virtual css::uno::Reference<css::util::XCloneable> SAL_CALL createClone()
267 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
268 :
269 : // ::com::sun::star::util::XModifiable:
270 : virtual sal_Bool SAL_CALL isModified( )
271 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
272 : virtual void SAL_CALL setModified( sal_Bool bModified )
273 : throw (css::beans::PropertyVetoException, css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
274 :
275 : // ::com::sun::star::util::XModifyBroadcaster:
276 : virtual void SAL_CALL addModifyListener(
277 : const css::uno::Reference< css::util::XModifyListener > & xListener)
278 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
279 : virtual void SAL_CALL removeModifyListener(
280 : const css::uno::Reference< css::util::XModifyListener > & xListener)
281 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
282 :
283 : // ::com::sun::star::xml::sax::XSAXSerializable
284 : virtual void SAL_CALL serialize(
285 : const css::uno::Reference<css::xml::sax::XDocumentHandler>& i_xHandler,
286 : const css::uno::Sequence< css::beans::StringPair >& i_rNamespaces)
287 : throw (css::uno::RuntimeException, css::xml::sax::SAXException, std::exception) SAL_OVERRIDE;
288 :
289 : protected:
290 9754 : virtual ~SfxDocumentMetaData() {}
291 685 : virtual SfxDocumentMetaData* createMe( css::uno::Reference< css::uno::XComponentContext > const & context ) { return new SfxDocumentMetaData( context ); };
292 : const css::uno::Reference< css::uno::XComponentContext > m_xContext;
293 :
294 : /// for notification
295 : ::cppu::OInterfaceContainerHelper m_NotifyListeners;
296 : /// flag: false means not initialized yet, or disposed
297 : bool m_isInitialized;
298 : /// flag
299 : bool m_isModified;
300 : /// meta-data DOM tree
301 : css::uno::Reference< css::xml::dom::XDocument > m_xDoc;
302 : /// meta-data super node in the meta-data DOM tree
303 : css::uno::Reference< css::xml::dom::XNode> m_xParent;
304 : /// standard meta data (single occurrence)
305 : std::map< OUString, css::uno::Reference<css::xml::dom::XNode> >
306 : m_meta;
307 : /// standard meta data (multiple occurrences)
308 : std::map< OUString,
309 : std::vector<css::uno::Reference<css::xml::dom::XNode> > > m_metaList;
310 : /// user-defined meta data (meta:user-defined) @ATTENTION may be null!
311 : css::uno::Reference<css::beans::XPropertyContainer> m_xUserDefined;
312 : // now for some meta-data attributes; these are not updated directly in the
313 : // DOM because updates (detecting "empty" elements) would be quite messy
314 : OUString m_TemplateName;
315 : OUString m_TemplateURL;
316 : css::util::DateTime m_TemplateDate;
317 : OUString m_AutoloadURL;
318 : sal_Int32 m_AutoloadSecs;
319 : OUString m_DefaultTarget;
320 :
321 : /// check if we are initialized properly
322 : void SAL_CALL checkInit() const;
323 : /// initialize state from given DOM tree
324 : void SAL_CALL init(css::uno::Reference<css::xml::dom::XDocument> i_xDom);
325 : /// update element in DOM tree
326 : void SAL_CALL updateElement(const char *i_name,
327 : std::vector<std::pair<const char *, OUString> >* i_pAttrs = 0);
328 : /// update user-defined meta data and attributes in DOM tree
329 : void SAL_CALL updateUserDefinedAndAttributes();
330 : /// create empty DOM tree (XDocument)
331 : css::uno::Reference<css::xml::dom::XDocument> SAL_CALL createDOM() const;
332 : /// extract base URL (necessary for converting relative links)
333 : css::uno::Reference<css::beans::XPropertySet> SAL_CALL getURLProperties(
334 : const css::uno::Sequence<css::beans::PropertyValue> & i_rMedium) const;
335 : /// get text of standard meta data element
336 : OUString SAL_CALL getMetaText(const char* i_name) const;
337 : /// set text of standard meta data element iff not equal to existing text
338 : bool SAL_CALL setMetaText(const char* i_name,
339 : const OUString & i_rValue);
340 : /// set text of standard meta data element iff not equal to existing text
341 : void SAL_CALL setMetaTextAndNotify(const char* i_name,
342 : const OUString & i_rValue);
343 : /// get text of standard meta data element's attribute
344 : OUString SAL_CALL getMetaAttr(const char* i_name,
345 : const char* i_attr) const;
346 : /// get text of a list of standard meta data elements (multiple occ.)
347 : css::uno::Sequence< OUString > SAL_CALL getMetaList(
348 : const char* i_name) const;
349 : /// set text of a list of standard meta data elements (multiple occ.)
350 : bool SAL_CALL setMetaList(const char* i_name,
351 : const css::uno::Sequence< OUString > & i_rValue,
352 : AttrVector const* = 0);
353 : void createUserDefined();
354 : };
355 :
356 : typedef ::cppu::ImplInheritanceHelper1< SfxDocumentMetaData, css::document::XCompatWriterDocProperties > CompatWriterDocPropsImpl_BASE;
357 :
358 0 : class CompatWriterDocPropsImpl : public CompatWriterDocPropsImpl_BASE
359 : {
360 : OUString msManager;
361 : OUString msCategory;
362 : OUString msCompany;
363 : protected:
364 0 : virtual SfxDocumentMetaData* createMe( css::uno::Reference< css::uno::XComponentContext > const & context ) SAL_OVERRIDE { return new CompatWriterDocPropsImpl( context ); };
365 : public:
366 0 : CompatWriterDocPropsImpl( css::uno::Reference< css::uno::XComponentContext > const & context) : CompatWriterDocPropsImpl_BASE( context ) {}
367 : // XCompatWriterDocPropsImpl
368 0 : virtual OUString SAL_CALL getManager() throw (::com::sun::star::uno::RuntimeException, std::exception) SAL_OVERRIDE { return msManager; }
369 0 : virtual void SAL_CALL setManager( const OUString& _manager ) throw (::com::sun::star::uno::RuntimeException, std::exception) SAL_OVERRIDE { msManager = _manager; }
370 0 : virtual OUString SAL_CALL getCategory() throw (::com::sun::star::uno::RuntimeException, std::exception) SAL_OVERRIDE { return msCategory; }
371 0 : virtual void SAL_CALL setCategory( const OUString& _category ) throw (::com::sun::star::uno::RuntimeException, std::exception) SAL_OVERRIDE { msCategory = _category; }
372 0 : virtual OUString SAL_CALL getCompany() throw (::com::sun::star::uno::RuntimeException, std::exception) SAL_OVERRIDE { return msCompany; }
373 0 : virtual void SAL_CALL setCompany( const OUString& _company ) throw (::com::sun::star::uno::RuntimeException, std::exception) SAL_OVERRIDE { msCompany = _company; }
374 :
375 : // XServiceInfo
376 0 : virtual OUString SAL_CALL getImplementationName( ) throw (::com::sun::star::uno::RuntimeException, std::exception) SAL_OVERRIDE
377 : {
378 0 : return OUString("CompatWriterDocPropsImpl");
379 : }
380 :
381 0 : virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) throw (::com::sun::star::uno::RuntimeException, std::exception) SAL_OVERRIDE
382 : {
383 0 : return cppu::supportsService(this, ServiceName);
384 : }
385 :
386 0 : virtual ::com::sun::star::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) throw (::com::sun::star::uno::RuntimeException, std::exception) SAL_OVERRIDE
387 : {
388 0 : css::uno::Sequence< OUString > aServiceNames(1);
389 0 : aServiceNames[ 0 ] = "com.sun.star.writer.DocumentProperties";
390 0 : return aServiceNames;
391 : }
392 : };
393 :
394 61 : bool operator== (const css::util::DateTime &i_rLeft,
395 : const css::util::DateTime &i_rRight)
396 : {
397 61 : return i_rLeft.Year == i_rRight.Year
398 60 : && i_rLeft.Month == i_rRight.Month
399 60 : && i_rLeft.Day == i_rRight.Day
400 60 : && i_rLeft.Hours == i_rRight.Hours
401 60 : && i_rLeft.Minutes == i_rRight.Minutes
402 60 : && i_rLeft.Seconds == i_rRight.Seconds
403 60 : && i_rLeft.NanoSeconds == i_rRight.NanoSeconds
404 121 : && i_rLeft.IsUTC == i_rRight.IsUTC;
405 : }
406 :
407 : // NB: keep these two arrays in sync!
408 : const char* s_stdStatAttrs[] = {
409 : "meta:page-count",
410 : "meta:table-count",
411 : "meta:draw-count",
412 : "meta:image-count",
413 : "meta:object-count",
414 : "meta:ole-object-count",
415 : "meta:paragraph-count",
416 : "meta:word-count",
417 : "meta:character-count",
418 : "meta:row-count",
419 : "meta:frame-count",
420 : "meta:sentence-count",
421 : "meta:syllable-count",
422 : "meta:non-whitespace-character-count",
423 : "meta:cell-count",
424 : 0
425 : };
426 :
427 : // NB: keep these two arrays in sync!
428 : const char* s_stdStats[] = {
429 : "PageCount",
430 : "TableCount",
431 : "DrawCount",
432 : "ImageCount",
433 : "ObjectCount",
434 : "OLEObjectCount",
435 : "ParagraphCount",
436 : "WordCount",
437 : "CharacterCount",
438 : "RowCount",
439 : "FrameCount",
440 : "SentenceCount",
441 : "SyllableCount",
442 : "NonWhitespaceCharacterCount",
443 : "CellCount",
444 : 0
445 : };
446 :
447 : const char* s_stdMeta[] = {
448 : "meta:generator", // string
449 : "dc:title", // string
450 : "dc:description", // string
451 : "dc:subject", // string
452 : "meta:initial-creator", // string
453 : "dc:creator", // string
454 : "meta:printed-by", // string
455 : "meta:creation-date", // dateTime
456 : "dc:date", // dateTime
457 : "meta:print-date", // dateTime
458 : "meta:template", // XLink
459 : "meta:auto-reload",
460 : "meta:hyperlink-behaviour",
461 : "dc:language", // language
462 : "meta:editing-cycles", // nonNegativeInteger
463 : "meta:editing-duration", // duration
464 : "meta:document-statistic", // ... // note: statistic is singular, no s!
465 : 0
466 : };
467 :
468 : const char* s_stdMetaList[] = {
469 : "meta:keyword", // string*
470 : "meta:user-defined", // ...*
471 : 0
472 : };
473 :
474 : const char* s_nsXLink = "http://www.w3.org/1999/xlink";
475 : const char* s_nsDC = "http://purl.org/dc/elements/1.1/";
476 : const char* s_nsODF = "urn:oasis:names:tc:opendocument:xmlns:office:1.0";
477 : const char* s_nsODFMeta = "urn:oasis:names:tc:opendocument:xmlns:meta:1.0";
478 : // const char* s_nsOOo = "http://openoffice.org/2004/office"; // not used (yet?)
479 :
480 : static const char s_meta [] = "meta.xml";
481 :
482 1 : bool isValidDate(const css::util::Date & i_rDate)
483 : {
484 1 : return i_rDate.Month > 0;
485 : }
486 :
487 6519 : bool isValidDateTime(const css::util::DateTime & i_rDateTime)
488 : {
489 6519 : return i_rDateTime.Month > 0;
490 : }
491 :
492 : std::pair< OUString, OUString > SAL_CALL
493 255070 : getQualifier(const char* i_name) {
494 255070 : OUString nm = OUString::createFromAscii(i_name);
495 255070 : sal_Int32 ix = nm.indexOf(static_cast<sal_Unicode> (':'));
496 255070 : if (ix == -1) {
497 0 : return std::make_pair(OUString(), nm);
498 : } else {
499 255070 : return std::make_pair(nm.copy(0,ix), nm.copy(ix+1));
500 255070 : }
501 : }
502 :
503 : // get namespace for standard qualified names
504 : // NB: only call this with statically known strings!
505 153004 : OUString SAL_CALL getNameSpace(const char* i_qname) throw ()
506 : {
507 : DBG_ASSERT(i_qname, "SfxDocumentMetaData: getNameSpace: argument is null");
508 153004 : const char * ns = "";
509 153004 : OUString n = getQualifier(i_qname).first;
510 153004 : if ( n == "xlink" ) ns = s_nsXLink;
511 153004 : if ( n == "dc" ) ns = s_nsDC;
512 153004 : if ( n == "office" ) ns = s_nsODF;
513 153004 : if ( n == "meta" ) ns = s_nsODFMeta;
514 : DBG_ASSERT(*ns, "SfxDocumentMetaData: unknown namespace prefix");
515 153004 : return OUString::createFromAscii(ns);
516 : }
517 :
518 : bool SAL_CALL
519 4 : textToDateOrDateTime(css::util::Date & io_rd, css::util::DateTime & io_rdt,
520 : bool & o_rIsDateTime, boost::optional<sal_Int16> & o_rTimeZone,
521 : const OUString& i_text) throw ()
522 : {
523 4 : if (::sax::Converter::parseDateOrDateTime(
524 : &io_rd, io_rdt, o_rIsDateTime, &o_rTimeZone, i_text)) {
525 4 : return true;
526 : } else {
527 : SAL_WARN_IF(!i_text.isEmpty(), "sfx.doc", "Invalid date: " << i_text);
528 0 : return false;
529 : }
530 : }
531 :
532 : // convert string to date/time
533 : bool SAL_CALL
534 13029 : textToDateTime(css::util::DateTime & io_rdt, const OUString& i_text) throw ()
535 : {
536 13029 : if (::sax::Converter::parseDateTime(io_rdt, 0, i_text)) {
537 1686 : return true;
538 : } else {
539 : SAL_WARN_IF(!i_text.isEmpty(), "sfx.doc", "Invalid date: " << i_text);
540 11343 : return false;
541 : }
542 : }
543 :
544 : // convert string to date/time with default return value
545 : css::util::DateTime SAL_CALL
546 13029 : textToDateTimeDefault(const OUString& i_text) throw ()
547 : {
548 13029 : css::util::DateTime dt;
549 13029 : static_cast<void> (textToDateTime(dt, i_text));
550 : // on conversion error: return default value (unchanged)
551 13029 : return dt;
552 : }
553 :
554 : // convert date to string
555 : OUString SAL_CALL
556 1 : dateToText(css::util::Date const& i_rd,
557 : sal_Int16 const*const pTimeZone = 0) throw ()
558 : {
559 1 : if (isValidDate(i_rd)) {
560 1 : OUStringBuffer buf;
561 1 : ::sax::Converter::convertDate(buf, i_rd, pTimeZone);
562 1 : return buf.makeStringAndClear();
563 : } else {
564 0 : return OUString();
565 : }
566 : }
567 :
568 :
569 : // convert date/time to string
570 : OUString SAL_CALL
571 5485 : dateTimeToText(css::util::DateTime const& i_rdt,
572 : sal_Int16 const*const pTimeZone = 0) throw ()
573 : {
574 5485 : if (isValidDateTime(i_rdt)) {
575 4871 : OUStringBuffer buf;
576 4871 : ::sax::Converter::convertDateTime(buf, i_rdt, pTimeZone, true);
577 4871 : return buf.makeStringAndClear();
578 : } else {
579 614 : return OUString();
580 : }
581 : }
582 :
583 : // convert string to duration
584 : bool
585 11181 : textToDuration(css::util::Duration& io_rDur, OUString const& i_rText)
586 : throw ()
587 : {
588 11181 : if (::sax::Converter::convertDuration(io_rDur, i_rText)) {
589 670 : return true;
590 : } else {
591 : SAL_WARN_IF(!i_rText.isEmpty(), "sfx.doc", "Invalid duration: " << i_rText);
592 10511 : return false;
593 : }
594 : }
595 :
596 11179 : sal_Int32 textToDuration(OUString const& i_rText) throw ()
597 : {
598 11179 : css::util::Duration d;
599 11179 : if (textToDuration(d, i_rText)) {
600 : // #i107372#: approximate years/months
601 668 : const sal_Int32 days( (d.Years * 365) + (d.Months * 30) + d.Days );
602 668 : return (days * (24*3600))
603 668 : + (d.Hours * 3600) + (d.Minutes * 60) + d.Seconds;
604 : } else {
605 10511 : return 0; // default
606 : }
607 : }
608 :
609 : // convert duration to string
610 1894 : OUString durationToText(css::util::Duration const& i_rDur) throw ()
611 : {
612 1894 : OUStringBuffer buf;
613 1894 : ::sax::Converter::convertDuration(buf, i_rDur);
614 1894 : return buf.makeStringAndClear();
615 : }
616 :
617 : // convert duration to string
618 1892 : OUString SAL_CALL durationToText(sal_Int32 i_value) throw ()
619 : {
620 1892 : css::util::Duration ud;
621 1892 : ud.Days = static_cast<sal_Int16>(i_value / (24 * 3600));
622 1892 : ud.Hours = static_cast<sal_Int16>((i_value % (24 * 3600)) / 3600);
623 1892 : ud.Minutes = static_cast<sal_Int16>((i_value % 3600) / 60);
624 1892 : ud.Seconds = static_cast<sal_Int16>(i_value % 60);
625 1892 : ud.NanoSeconds = 0;
626 1892 : return durationToText(ud);
627 : }
628 :
629 : // extract base URL (necessary for converting relative links)
630 : css::uno::Reference< css::beans::XPropertySet > SAL_CALL
631 7 : SfxDocumentMetaData::getURLProperties(
632 : const css::uno::Sequence< css::beans::PropertyValue > & i_rMedium) const
633 : {
634 7 : css::uno::Reference< css::beans::XPropertyBag> xPropArg = css::beans::PropertyBag::createDefault( m_xContext );
635 : try {
636 7 : css::uno::Any baseUri;
637 30 : for (sal_Int32 i = 0; i < i_rMedium.getLength(); ++i) {
638 23 : if (i_rMedium[i].Name == "DocumentBaseURL") {
639 0 : baseUri = i_rMedium[i].Value;
640 23 : } else if (i_rMedium[i].Name == "URL") {
641 7 : if (!baseUri.hasValue()) {
642 7 : baseUri = i_rMedium[i].Value;
643 : }
644 16 : } else if (i_rMedium[i].Name == "HierarchicalDocumentName") {
645 0 : xPropArg->addProperty(
646 : OUString("StreamRelPath"),
647 : css::beans::PropertyAttribute::MAYBEVOID,
648 0 : i_rMedium[i].Value);
649 : }
650 : }
651 7 : if (baseUri.hasValue()) {
652 7 : xPropArg->addProperty(
653 : "BaseURI", css::beans::PropertyAttribute::MAYBEVOID,
654 7 : baseUri);
655 : }
656 7 : xPropArg->addProperty(OUString("StreamName"),
657 : css::beans::PropertyAttribute::MAYBEVOID,
658 7 : css::uno::makeAny(OUString(s_meta)));
659 0 : } catch (const css::uno::Exception &) {
660 : // ignore
661 : }
662 : return css::uno::Reference< css::beans::XPropertySet>(xPropArg,
663 7 : css::uno::UNO_QUERY_THROW);
664 : }
665 :
666 : // return the text of the (hopefully unique, i.e., normalize first!) text
667 : // node _below_ the given node
668 : OUString SAL_CALL
669 14715 : getNodeText(css::uno::Reference<css::xml::dom::XNode> i_xNode)
670 : throw (css::uno::RuntimeException)
671 : {
672 14715 : if (!i_xNode.is()) throw css::uno::RuntimeException(
673 0 : OUString("SfxDocumentMetaData::getNodeText: argument is null"), i_xNode);
674 29430 : for (css::uno::Reference<css::xml::dom::XNode> c = i_xNode->getFirstChild();
675 : c.is();
676 0 : c = c->getNextSibling()) {
677 14531 : if (c->getNodeType() == css::xml::dom::NodeType_TEXT_NODE) {
678 : try {
679 14531 : return c->getNodeValue();
680 0 : } catch (const css::xml::dom::DOMException &) { // too big?
681 0 : return OUString();
682 : }
683 : }
684 184 : }
685 184 : return OUString();
686 : }
687 :
688 : OUString SAL_CALL
689 19319 : SfxDocumentMetaData::getMetaText(const char* i_name) const
690 : // throw (css::uno::RuntimeException)
691 : {
692 19319 : checkInit();
693 :
694 19319 : const OUString name( OUString::createFromAscii(i_name) );
695 : DBG_ASSERT(m_meta.find(name) != m_meta.end(),
696 : "SfxDocumentMetaData::getMetaText: not found");
697 38638 : css::uno::Reference<css::xml::dom::XNode> xNode = m_meta.find(name)->second;
698 38638 : return (xNode.is()) ? getNodeText(xNode) : OUString();
699 : }
700 :
701 : bool SAL_CALL
702 17931 : SfxDocumentMetaData::setMetaText(const char* i_name,
703 : const OUString & i_rValue)
704 : // throw (css::uno::RuntimeException)
705 : {
706 17931 : checkInit();
707 :
708 17931 : const OUString name( OUString::createFromAscii(i_name) );
709 : DBG_ASSERT(m_meta.find(name) != m_meta.end(),
710 : "SfxDocumentMetaData::setMetaText: not found");
711 35862 : css::uno::Reference<css::xml::dom::XNode> xNode = m_meta.find(name)->second;
712 :
713 : try {
714 17931 : if (i_rValue.isEmpty()) {
715 2228 : if (xNode.is()) { // delete
716 22 : m_xParent->removeChild(xNode);
717 22 : xNode.clear();
718 22 : m_meta[name] = xNode;
719 22 : return true;
720 : } else {
721 2206 : return false;
722 : }
723 : } else {
724 15703 : if (xNode.is()) { // update
725 1466 : for (css::uno::Reference<css::xml::dom::XNode> c =
726 733 : xNode->getFirstChild();
727 : c.is();
728 0 : c = c->getNextSibling()) {
729 732 : if (c->getNodeType() == css::xml::dom::NodeType_TEXT_NODE) {
730 732 : if (!c->getNodeValue().equals(i_rValue)) {
731 182 : c->setNodeValue(i_rValue);
732 182 : return true;
733 : } else {
734 550 : return false;
735 : }
736 : }
737 1 : }
738 : } else { // insert
739 14970 : xNode.set(m_xDoc->createElementNS(getNameSpace(i_name), name),
740 14970 : css::uno::UNO_QUERY_THROW);
741 14970 : m_xParent->appendChild(xNode);
742 14970 : m_meta[name] = xNode;
743 : }
744 : css::uno::Reference<css::xml::dom::XNode> xTextNode(
745 14971 : m_xDoc->createTextNode(i_rValue), css::uno::UNO_QUERY_THROW);
746 14971 : xNode->appendChild(xTextNode);
747 14971 : return true;
748 : }
749 0 : } catch (const css::xml::dom::DOMException & e) {
750 0 : css::uno::Any a(e);
751 : throw css::lang::WrappedTargetRuntimeException(
752 : OUString("SfxDocumentMetaData::setMetaText: DOM exception"),
753 0 : css::uno::Reference<css::uno::XInterface>(*this), a);
754 17931 : }
755 : }
756 :
757 : void SAL_CALL
758 17899 : SfxDocumentMetaData::setMetaTextAndNotify(const char* i_name,
759 : const OUString & i_rValue)
760 : // throw (css::uno::RuntimeException)
761 : {
762 17899 : ::osl::ClearableMutexGuard g(m_aMutex);
763 17899 : if (setMetaText(i_name, i_rValue)) {
764 15152 : g.clear();
765 15152 : setModified(true);
766 17899 : }
767 17899 : }
768 :
769 : OUString SAL_CALL
770 191316 : SfxDocumentMetaData::getMetaAttr(const char* i_name, const char* i_attr) const
771 : // throw (css::uno::RuntimeException)
772 : {
773 191316 : OUString name = OUString::createFromAscii(i_name);
774 : DBG_ASSERT(m_meta.find(name) != m_meta.end(),
775 : "SfxDocumentMetaData::getMetaAttr: not found");
776 382632 : css::uno::Reference<css::xml::dom::XNode> xNode = m_meta.find(name)->second;
777 191316 : if (xNode.is()) {
778 : css::uno::Reference<css::xml::dom::XElement> xElem(xNode,
779 102066 : css::uno::UNO_QUERY_THROW);
780 102066 : return xElem->getAttributeNS(getNameSpace(i_attr),
781 102066 : getQualifier(i_attr).second);
782 : } else {
783 89250 : return OUString();
784 191316 : }
785 : }
786 :
787 : css::uno::Sequence< OUString> SAL_CALL
788 787 : SfxDocumentMetaData::getMetaList(const char* i_name) const
789 : // throw (css::uno::RuntimeException)
790 : {
791 787 : checkInit();
792 787 : OUString name = OUString::createFromAscii(i_name);
793 : DBG_ASSERT(m_metaList.find(name) != m_metaList.end(),
794 : "SfxDocumentMetaData::getMetaList: not found");
795 : std::vector<css::uno::Reference<css::xml::dom::XNode> > const & vec =
796 787 : m_metaList.find(name)->second;
797 787 : css::uno::Sequence< OUString> ret(vec.size());
798 808 : for (size_t i = 0; i < vec.size(); ++i) {
799 21 : ret[i] = getNodeText(vec.at(i));
800 : }
801 787 : return ret;
802 : }
803 :
804 : bool SAL_CALL
805 1219 : SfxDocumentMetaData::setMetaList(const char* i_name,
806 : const css::uno::Sequence< OUString> & i_rValue,
807 : AttrVector const* i_pAttrs)
808 : // throw (css::uno::RuntimeException)
809 : {
810 1219 : checkInit();
811 : DBG_ASSERT((i_pAttrs == 0) ||
812 : (static_cast<size_t>(i_rValue.getLength()) == i_pAttrs->size()),
813 : "SfxDocumentMetaData::setMetaList: invalid args");
814 :
815 : try {
816 1219 : OUString name = OUString::createFromAscii(i_name);
817 : DBG_ASSERT(m_metaList.find(name) != m_metaList.end(),
818 : "SfxDocumentMetaData::setMetaList: not found");
819 : std::vector<css::uno::Reference<css::xml::dom::XNode> > & vec =
820 1219 : m_metaList[name];
821 :
822 : // if nothing changed, do nothing
823 : // alas, this does not check for permutations, or attributes...
824 1219 : if ((0 == i_pAttrs)) {
825 185 : if (static_cast<size_t>(i_rValue.getLength()) == vec.size()) {
826 172 : bool isEqual(true);
827 172 : for (sal_Int32 i = 0; i < i_rValue.getLength(); ++i) {
828 1 : css::uno::Reference<css::xml::dom::XNode> xNode(vec.at(i));
829 1 : if (xNode.is()) {
830 1 : OUString val = getNodeText(xNode);
831 1 : if (!val.equals(i_rValue[i])) {
832 1 : isEqual = false;
833 1 : break;
834 0 : }
835 : }
836 0 : }
837 172 : if (isEqual) return false;
838 : }
839 : }
840 :
841 : // remove old meta data nodes
842 : {
843 : std::vector<css::uno::Reference<css::xml::dom::XNode> >
844 1048 : ::reverse_iterator it(vec.rbegin());
845 : try {
846 1276 : for ( ;it != vec.rend(); ++it)
847 : {
848 228 : m_xParent->removeChild(*it);
849 : }
850 : }
851 0 : catch (...)
852 : {
853 : // Clean up already removed nodes
854 0 : vec.erase(it.base(), vec.end());
855 0 : throw;
856 : }
857 1048 : vec.clear();
858 : }
859 :
860 : // insert new meta data nodes into DOM tree
861 4041 : for (sal_Int32 i = 0; i < i_rValue.getLength(); ++i) {
862 : css::uno::Reference<css::xml::dom::XElement> xElem(
863 2993 : m_xDoc->createElementNS(getNameSpace(i_name), name),
864 2993 : css::uno::UNO_QUERY_THROW);
865 : css::uno::Reference<css::xml::dom::XNode> xNode(xElem,
866 5986 : css::uno::UNO_QUERY_THROW);
867 : css::uno::Reference<css::xml::dom::XNode> xTextNode(
868 5986 : m_xDoc->createTextNode(i_rValue[i]), css::uno::UNO_QUERY_THROW);
869 : // set attributes
870 2993 : if (i_pAttrs != 0) {
871 24675 : for (std::vector<std::pair<const char*, OUString> >
872 2956 : ::const_iterator it = (*i_pAttrs)[i].begin();
873 16450 : it != (*i_pAttrs)[i].end(); ++it) {
874 10538 : xElem->setAttributeNS(getNameSpace(it->first),
875 5269 : OUString::createFromAscii(it->first),
876 15807 : it->second);
877 : }
878 : }
879 2993 : xNode->appendChild(xTextNode);
880 2993 : m_xParent->appendChild(xNode);
881 2993 : vec.push_back(xNode);
882 2993 : }
883 :
884 1048 : return true;
885 0 : } catch (const css::xml::dom::DOMException & e) {
886 0 : css::uno::Any a(e);
887 : throw css::lang::WrappedTargetRuntimeException(
888 : OUString("SfxDocumentMetaData::setMetaList: DOM exception"),
889 0 : css::uno::Reference<css::uno::XInterface>(*this), a);
890 : }
891 : }
892 :
893 : // convert property list to string list and attribute list
894 : std::pair<css::uno::Sequence< OUString>, AttrVector> SAL_CALL
895 1034 : propsToStrings(css::uno::Reference<css::beans::XPropertySet> const & i_xPropSet)
896 : {
897 1034 : ::std::vector< OUString > values;
898 2068 : AttrVector attrs;
899 :
900 : css::uno::Reference<css::beans::XPropertySetInfo> xSetInfo
901 2068 : = i_xPropSet->getPropertySetInfo();
902 2068 : css::uno::Sequence<css::beans::Property> props = xSetInfo->getProperties();
903 :
904 3990 : for (sal_Int32 i = 0; i < props.getLength(); ++i) {
905 2956 : if (props[i].Attributes & css::beans::PropertyAttribute::TRANSIENT) {
906 0 : continue;
907 : }
908 2956 : const OUString name = props[i].Name;
909 5912 : css::uno::Any any;
910 : try {
911 2956 : any = i_xPropSet->getPropertyValue(name);
912 0 : } catch (const css::uno::Exception &) {
913 : // ignore
914 : }
915 2956 : const css::uno::Type & type = any.getValueType();
916 5912 : std::vector<std::pair<const char*, OUString> > as;
917 : as.push_back(std::make_pair(static_cast<const char*>("meta:name"),
918 2956 : name));
919 2956 : const char* vt = "meta:value-type";
920 :
921 : // convert according to type
922 2956 : if (type == ::cppu::UnoType<bool>::get()) {
923 1812 : bool b = false;
924 1812 : any >>= b;
925 1812 : OUStringBuffer buf;
926 1812 : ::sax::Converter::convertBool(buf, b);
927 1812 : values.push_back(buf.makeStringAndClear());
928 : as.push_back(std::make_pair(vt,
929 1812 : OUString("boolean")));
930 1144 : } else if (type == ::cppu::UnoType< OUString>::get()) {
931 674 : OUString s;
932 674 : any >>= s;
933 674 : values.push_back(s);
934 : // #i90847# OOo 2.x does stupid things if value-type="string";
935 : // fortunately string is default anyway, so we can just omit it
936 : // #i107502#: however, OOo 2.x only reads 4 user-defined without @value-type
937 : // => best backward compatibility: first 4 without @value-type, rest with
938 674 : if (4 <= i)
939 : {
940 : as.push_back(std::make_pair(vt,
941 31 : OUString("string")));
942 674 : }
943 470 : } else if (type == ::cppu::UnoType<css::util::DateTime>::get()) {
944 3 : css::util::DateTime dt;
945 3 : any >>= dt;
946 3 : values.push_back(dateTimeToText(dt));
947 : as.push_back(std::make_pair(vt,
948 3 : OUString("date")));
949 467 : } else if (type == ::cppu::UnoType<css::util::Date>::get()) {
950 1 : css::util::Date d;
951 1 : any >>= d;
952 1 : values.push_back(dateToText(d));
953 : as.push_back(std::make_pair(vt,
954 1 : OUString("date")));
955 466 : } else if (type == ::cppu::UnoType<css::util::DateTimeWithTimezone>::get()) {
956 0 : css::util::DateTimeWithTimezone dttz;
957 0 : any >>= dttz;
958 0 : values.push_back(dateTimeToText(dttz.DateTimeInTZ, &dttz.Timezone));
959 : as.push_back(std::make_pair(vt,
960 0 : OUString("date")));
961 466 : } else if (type == ::cppu::UnoType<css::util::DateWithTimezone>::get()) {
962 0 : css::util::DateWithTimezone dtz;
963 0 : any >>= dtz;
964 0 : values.push_back(dateToText(dtz.DateInTZ, &dtz.Timezone));
965 : as.push_back(std::make_pair(vt,
966 0 : OUString("date")));
967 466 : } else if (type == ::cppu::UnoType<css::util::Time>::get()) {
968 : // #i97029#: replaced by Duration
969 : // Time is supported for backward compatibility with OOo 3.x, x<=2
970 1 : css::util::Time ut;
971 1 : any >>= ut;
972 1 : css::util::Duration ud;
973 1 : ud.Hours = ut.Hours;
974 1 : ud.Minutes = ut.Minutes;
975 1 : ud.Seconds = ut.Seconds;
976 1 : ud.NanoSeconds = ut.NanoSeconds;
977 1 : values.push_back(durationToText(ud));
978 : as.push_back(std::make_pair(vt,
979 1 : OUString("time")));
980 465 : } else if (type == ::cppu::UnoType<css::util::Duration>::get()) {
981 1 : css::util::Duration ud;
982 1 : any >>= ud;
983 1 : values.push_back(durationToText(ud));
984 : as.push_back(std::make_pair(vt,
985 1 : OUString("time")));
986 464 : } else if (::cppu::UnoType<double>::get().isAssignableFrom(type)) {
987 : // support not just double, but anything that can be converted
988 464 : double d = 0;
989 464 : any >>= d;
990 464 : OUStringBuffer buf;
991 464 : ::sax::Converter::convertDouble(buf, d);
992 464 : values.push_back(buf.makeStringAndClear());
993 : as.push_back(std::make_pair(vt,
994 464 : OUString("float")));
995 : } else {
996 : SAL_WARN("sfx.doc", "Unsupported property type: " << any.getValueTypeName() );
997 0 : continue;
998 : }
999 2956 : attrs.push_back(as);
1000 2956 : }
1001 :
1002 2068 : return std::make_pair(comphelper::containerToSequence(values), attrs);
1003 : }
1004 :
1005 : // remove the given element from the DOM, and iff i_pAttrs != 0 insert new one
1006 : void SAL_CALL
1007 8753 : SfxDocumentMetaData::updateElement(const char *i_name,
1008 : std::vector<std::pair<const char *, OUString> >* i_pAttrs)
1009 : {
1010 8753 : OUString name = OUString::createFromAscii(i_name);
1011 : try {
1012 : // remove old element
1013 : css::uno::Reference<css::xml::dom::XNode> xNode =
1014 8753 : m_meta.find(name)->second;
1015 8753 : if (xNode.is()) {
1016 3756 : m_xParent->removeChild(xNode);
1017 3756 : xNode.clear();
1018 : }
1019 : // add new element
1020 8753 : if (0 != i_pAttrs) {
1021 : css::uno::Reference<css::xml::dom::XElement> xElem(
1022 6118 : m_xDoc->createElementNS(getNameSpace(i_name), name),
1023 6118 : css::uno::UNO_QUERY_THROW);
1024 6118 : xNode.set(xElem, css::uno::UNO_QUERY_THROW);
1025 : // set attributes
1026 83118 : for (std::vector<std::pair<const char *, OUString> >
1027 6118 : ::const_iterator it = i_pAttrs->begin();
1028 55412 : it != i_pAttrs->end(); ++it) {
1029 43176 : xElem->setAttributeNS(getNameSpace(it->first),
1030 43176 : OUString::createFromAscii(it->first), it->second);
1031 : }
1032 6118 : m_xParent->appendChild(xNode);
1033 : }
1034 8753 : m_meta[name] = xNode;
1035 0 : } catch (const css::xml::dom::DOMException & e) {
1036 0 : css::uno::Any a(e);
1037 : throw css::lang::WrappedTargetRuntimeException(
1038 : OUString("SfxDocumentMetaData::updateElement: DOM exception"),
1039 0 : css::uno::Reference<css::uno::XInterface>(*this), a);
1040 8753 : }
1041 8753 : }
1042 :
1043 : // update user-defined meta data in DOM tree
1044 1034 : void SAL_CALL SfxDocumentMetaData::updateUserDefinedAndAttributes()
1045 : {
1046 1034 : createUserDefined();
1047 : const css::uno::Reference<css::beans::XPropertySet> xPSet(m_xUserDefined,
1048 1034 : css::uno::UNO_QUERY_THROW);
1049 : const std::pair<css::uno::Sequence< OUString>, AttrVector>
1050 2068 : udStringsAttrs( propsToStrings(xPSet) );
1051 : (void) setMetaList("meta:user-defined", udStringsAttrs.first,
1052 1034 : &udStringsAttrs.second);
1053 :
1054 : // update elements with attributes
1055 2068 : std::vector<std::pair<const char *, OUString> > attributes;
1056 2637 : if (!m_TemplateName.isEmpty() || !m_TemplateURL.isEmpty()
1057 1603 : || isValidDateTime(m_TemplateDate)) {
1058 : attributes.push_back(std::make_pair(
1059 : static_cast<const char*>("xlink:type"),
1060 465 : OUString("simple")));
1061 : attributes.push_back(std::make_pair(
1062 : static_cast<const char*>("xlink:actuate"),
1063 465 : OUString("onRequest")));
1064 : attributes.push_back(std::make_pair(
1065 465 : static_cast<const char*>("xlink:title"), m_TemplateName));
1066 : attributes.push_back(std::make_pair(
1067 465 : static_cast<const char*>("xlink:href" ), m_TemplateURL ));
1068 465 : if (isValidDateTime(m_TemplateDate)) {
1069 : attributes.push_back(std::make_pair(
1070 : static_cast<const char*>("meta:date" ),
1071 3 : dateTimeToText(m_TemplateDate)));
1072 : }
1073 465 : updateElement("meta:template", &attributes);
1074 : } else {
1075 569 : updateElement("meta:template");
1076 : }
1077 1034 : attributes.clear();
1078 :
1079 1034 : if (!m_AutoloadURL.isEmpty() || (0 != m_AutoloadSecs)) {
1080 : attributes.push_back(std::make_pair(
1081 1 : static_cast<const char*>("xlink:href" ), m_AutoloadURL ));
1082 : attributes.push_back(std::make_pair(
1083 : static_cast<const char*>("meta:delay" ),
1084 1 : durationToText(m_AutoloadSecs)));
1085 1 : updateElement("meta:auto-reload", &attributes);
1086 : } else {
1087 1033 : updateElement("meta:auto-reload");
1088 : }
1089 1034 : attributes.clear();
1090 :
1091 1034 : if (!m_DefaultTarget.isEmpty()) {
1092 : attributes.push_back(std::make_pair(
1093 : static_cast<const char*>("office:target-frame-name"),
1094 1 : m_DefaultTarget));
1095 : // xlink:show: _blank -> new, any other value -> replace
1096 1 : const sal_Char* show = m_DefaultTarget == "_blank" ? "new" : "replace";
1097 : attributes.push_back(std::make_pair(
1098 : static_cast<const char*>("xlink:show"),
1099 1 : OUString::createFromAscii(show)));
1100 1 : updateElement("meta:hyperlink-behaviour", &attributes);
1101 : } else {
1102 1033 : updateElement("meta:hyperlink-behaviour");
1103 : }
1104 2068 : attributes.clear();
1105 1034 : }
1106 :
1107 : // create empty DOM tree (XDocument)
1108 : css::uno::Reference<css::xml::dom::XDocument> SAL_CALL
1109 9795 : SfxDocumentMetaData::createDOM() const // throw (css::uno::RuntimeException)
1110 : {
1111 9795 : css::uno::Reference<css::lang::XMultiComponentFactory> xMsf ( m_xContext->getServiceManager());
1112 19590 : css::uno::Reference<css::xml::dom::XDocumentBuilder> xBuilder( css::xml::dom::DocumentBuilder::create(m_xContext) );
1113 9795 : css::uno::Reference<css::xml::dom::XDocument> xDoc = xBuilder->newDocument();
1114 9795 : if (!xDoc.is()) throw css::uno::RuntimeException(
1115 : OUString("SfxDocumentMetaData::createDOM: "
1116 : "cannot create new document"),
1117 0 : *const_cast<SfxDocumentMetaData*>(this));
1118 19590 : return xDoc;
1119 : }
1120 :
1121 : void SAL_CALL
1122 110778 : SfxDocumentMetaData::checkInit() const // throw (css::uno::RuntimeException)
1123 : {
1124 110778 : if (!m_isInitialized) {
1125 : throw css::uno::RuntimeException(OUString(
1126 : "SfxDocumentMetaData::checkInit: not initialized"),
1127 0 : *const_cast<SfxDocumentMetaData*>(this));
1128 : }
1129 : DBG_ASSERT((m_xDoc.is() && m_xParent.is() ),
1130 : "SfxDocumentMetaData::checkInit: reference is null");
1131 110778 : }
1132 :
1133 : // initialize state from DOM tree
1134 10436 : void SAL_CALL SfxDocumentMetaData::init(
1135 : css::uno::Reference<css::xml::dom::XDocument> i_xDoc)
1136 : {
1137 10436 : if (!i_xDoc.is()) throw css::uno::RuntimeException(
1138 0 : OUString("SfxDocumentMetaData::init: no DOM tree given"), *this);
1139 :
1140 10436 : css::uno::Reference<css::xml::xpath::XXPathAPI> xPath = css::xml::xpath::XPathAPI::create(m_xContext);
1141 :
1142 10436 : m_isInitialized = false;
1143 10436 : m_xDoc = i_xDoc;
1144 :
1145 : // select nodes for standard meta data stuff
1146 10436 : xPath->registerNS(OUString("xlink"),
1147 10436 : OUString::createFromAscii(s_nsXLink));
1148 10436 : xPath->registerNS(OUString("dc"),
1149 10436 : OUString::createFromAscii(s_nsDC));
1150 10436 : xPath->registerNS(OUString("office"),
1151 10436 : OUString::createFromAscii(s_nsODF));
1152 10436 : xPath->registerNS(OUString("meta"),
1153 10436 : OUString::createFromAscii(s_nsODFMeta));
1154 : // NB: we do not handle the single-XML-file ODF variant, which would
1155 : // have the root element office:document.
1156 : // The root of such documents must be converted in the importer!
1157 : OUString prefix(
1158 20872 : "/child::office:document-meta/child::office:meta");
1159 : css::uno::Reference<css::xml::dom::XNode> xDocNode(
1160 20872 : m_xDoc, css::uno::UNO_QUERY_THROW);
1161 10436 : m_xParent.clear();
1162 : try {
1163 10436 : m_xParent = xPath->selectSingleNode(xDocNode, prefix);
1164 9110 : } catch (const com::sun::star::uno::Exception &) {
1165 : }
1166 :
1167 10436 : if (!m_xParent.is()) {
1168 : // all this create/append stuff may throw DOMException
1169 : try {
1170 9126 : css::uno::Reference<css::xml::dom::XElement> xRElem;
1171 : css::uno::Reference<css::xml::dom::XNode> xNode(
1172 18252 : i_xDoc->getFirstChild());
1173 18252 : while (xNode.is()) {
1174 16 : if (css::xml::dom::NodeType_ELEMENT_NODE ==xNode->getNodeType())
1175 : {
1176 16 : if ( xNode->getNamespaceURI().equalsAscii(s_nsODF) && xNode->getLocalName() == "document-meta" )
1177 : {
1178 16 : xRElem.set(xNode, css::uno::UNO_QUERY_THROW);
1179 16 : break;
1180 : }
1181 : else
1182 : {
1183 : OSL_TRACE("SfxDocumentMetaData::init(): "
1184 : "deleting unexpected root element: %s",
1185 : OUStringToOString(xNode->getLocalName(),
1186 : RTL_TEXTENCODING_UTF8).getStr());
1187 0 : i_xDoc->removeChild(xNode);
1188 0 : xNode = i_xDoc->getFirstChild(); // start over
1189 : }
1190 : } else {
1191 0 : xNode = xNode->getNextSibling();
1192 : }
1193 : }
1194 9126 : if (!xRElem.is()) {
1195 27330 : xRElem = i_xDoc->createElementNS(
1196 : OUString::createFromAscii(s_nsODF),
1197 18220 : OUString("office:document-meta"));
1198 : css::uno::Reference<css::xml::dom::XNode> xRNode(xRElem,
1199 9110 : css::uno::UNO_QUERY_THROW);
1200 9110 : i_xDoc->appendChild(xRNode);
1201 : }
1202 9126 : xRElem->setAttributeNS(OUString::createFromAscii(s_nsODF),
1203 : OUString("office:version"),
1204 9126 : OUString("1.0"));
1205 : // does not exist, otherwise m_xParent would not be null
1206 : css::uno::Reference<css::xml::dom::XNode> xParent (
1207 9126 : i_xDoc->createElementNS(
1208 : OUString::createFromAscii(s_nsODF),
1209 9126 : OUString("office:meta")),
1210 18252 : css::uno::UNO_QUERY_THROW);
1211 9126 : xRElem->appendChild(xParent);
1212 18252 : m_xParent = xParent;
1213 0 : } catch (const css::xml::dom::DOMException & e) {
1214 0 : css::uno::Any a(e);
1215 : throw css::lang::WrappedTargetRuntimeException(
1216 : OUString("SfxDocumentMetaData::init: DOM exception"),
1217 0 : css::uno::Reference<css::uno::XInterface>(*this), a);
1218 : }
1219 : }
1220 :
1221 :
1222 : // select nodes for elements of which we only handle one occurrence
1223 187848 : for (const char **pName = s_stdMeta; *pName != 0; ++pName) {
1224 177412 : OUString name = OUString::createFromAscii(*pName);
1225 : // NB: If a document contains more than one occurrence of a
1226 : // meta-data element, we arbitrarily pick one of them here.
1227 : // We do not remove the others, i.e., when we write the
1228 : // document, it will contain the duplicates unchanged.
1229 : // The ODF spec says that handling multiple occurrences is
1230 : // application-specific.
1231 : css::uno::Reference<css::xml::dom::XNode> xNode =
1232 354824 : xPath->selectSingleNode(m_xParent, "child::" + name);
1233 : // Do not create an empty element if it is missing;
1234 : // for certain elements, such as dateTime, this would be invalid
1235 177412 : m_meta[name] = xNode;
1236 177412 : }
1237 :
1238 : // select nodes for elements of which we handle all occurrences
1239 31308 : for (const char **pName = s_stdMetaList; *pName != 0; ++pName) {
1240 20872 : OUString name = OUString::createFromAscii(*pName);
1241 : css::uno::Reference<css::xml::dom::XNodeList> nodes =
1242 41744 : xPath->selectNodeList(m_xParent, "child::" + name);
1243 41744 : std::vector<css::uno::Reference<css::xml::dom::XNode> > v;
1244 24182 : for (sal_Int32 i = 0; i < nodes->getLength(); ++i) {
1245 3310 : v.push_back(nodes->item(i));
1246 : }
1247 20872 : m_metaList[name] = v;
1248 20872 : }
1249 :
1250 : // initialize members corresponding to attributes from DOM nodes
1251 10436 : m_TemplateName = getMetaAttr("meta:template", "xlink:title");
1252 10436 : m_TemplateURL = getMetaAttr("meta:template", "xlink:href");
1253 : m_TemplateDate =
1254 10436 : textToDateTimeDefault(getMetaAttr("meta:template", "meta:date"));
1255 10436 : m_AutoloadURL = getMetaAttr("meta:auto-reload", "xlink:href");
1256 : m_AutoloadSecs =
1257 10436 : textToDuration(getMetaAttr("meta:auto-reload", "meta:delay"));
1258 20872 : m_DefaultTarget =
1259 10436 : getMetaAttr("meta:hyperlink-behaviour", "office:target-frame-name");
1260 :
1261 :
1262 : std::vector<css::uno::Reference<css::xml::dom::XNode> > & vec =
1263 10436 : m_metaList[OUString("meta:user-defined")];
1264 10436 : m_xUserDefined.clear(); // #i105826#: reset (may be re-initialization)
1265 10436 : if ( !vec.empty() )
1266 : {
1267 553 : createUserDefined();
1268 : }
1269 :
1270 : // user-defined meta data: initialize PropertySet from DOM nodes
1271 41178 : for (std::vector<css::uno::Reference<css::xml::dom::XNode> >::iterator
1272 37888 : it = vec.begin(); it != vec.end(); ++it) {
1273 3290 : css::uno::Reference<css::xml::dom::XElement> xElem(*it,
1274 3290 : css::uno::UNO_QUERY_THROW);
1275 6580 : css::uno::Any any;
1276 3290 : OUString name = xElem->getAttributeNS(
1277 : OUString::createFromAscii(s_nsODFMeta),
1278 6580 : OUString("name"));
1279 3290 : OUString type = xElem->getAttributeNS(
1280 : OUString::createFromAscii(s_nsODFMeta),
1281 6580 : OUString("value-type"));
1282 6580 : OUString text = getNodeText(*it);
1283 3290 : if ( type == "float" ) {
1284 : double d;
1285 494 : if (::sax::Converter::convertDouble(d, text)) {
1286 494 : any <<= d;
1287 : } else {
1288 : SAL_WARN("sfx.doc", "Invalid float: " << text);
1289 0 : continue;
1290 : }
1291 2796 : } else if ( type == "date" ) {
1292 : bool isDateTime;
1293 4 : css::util::Date d;
1294 4 : css::util::DateTime dt;
1295 4 : boost::optional<sal_Int16> nTimeZone;
1296 4 : if (textToDateOrDateTime(d, dt, isDateTime, nTimeZone, text)) {
1297 4 : if (isDateTime) {
1298 3 : if (nTimeZone.is_initialized()) {
1299 0 : any <<= css::util::DateTimeWithTimezone(dt,
1300 0 : nTimeZone.get());
1301 : } else {
1302 3 : any <<= dt;
1303 : }
1304 : } else {
1305 1 : if (nTimeZone.is_initialized()) {
1306 0 : any <<= css::util::DateWithTimezone(d, nTimeZone.get());
1307 : } else {
1308 1 : any <<= d;
1309 : }
1310 : }
1311 : } else {
1312 : SAL_WARN("sfx.doc", "Invalid date: " << text);
1313 0 : continue;
1314 4 : }
1315 2792 : } else if ( type == "time" ) {
1316 2 : css::util::Duration ud;
1317 2 : if (textToDuration(ud, text)) {
1318 2 : any <<= ud;
1319 : } else {
1320 : SAL_WARN("sfx.doc", "Invalid time: " << text);
1321 0 : continue;
1322 : }
1323 2790 : } else if ( type == "boolean" ) {
1324 : bool b;
1325 1920 : if (::sax::Converter::convertBool(b, text)) {
1326 1920 : any <<= b;
1327 : } else {
1328 : SAL_WARN("sfx.doc", "Invalid boolean: " << text);
1329 0 : continue;
1330 : }
1331 870 : } else if ( type == "string" || true) { // default
1332 870 : any <<= text;
1333 : }
1334 : try {
1335 3290 : m_xUserDefined->addProperty(name,
1336 3290 : css::beans::PropertyAttribute::REMOVABLE, any);
1337 0 : } catch (const css::beans::PropertyExistException &) {
1338 : SAL_WARN("sfx.doc", "Duplicate: " << name);
1339 : // ignore; duplicate
1340 0 : } catch (const css::beans::IllegalTypeException &) {
1341 : OSL_TRACE("SfxDocumentMetaData: illegal type: %s",
1342 : OUStringToOString(name, RTL_TEXTENCODING_UTF8).getStr());
1343 0 : } catch (const css::lang::IllegalArgumentException &) {
1344 : OSL_TRACE("SfxDocumentMetaData: illegal arg: %s",
1345 : OUStringToOString(name, RTL_TEXTENCODING_UTF8).getStr());
1346 : }
1347 3290 : }
1348 :
1349 10436 : m_isModified = false;
1350 20872 : m_isInitialized = true;
1351 10436 : }
1352 :
1353 :
1354 :
1355 4898 : SfxDocumentMetaData::SfxDocumentMetaData(
1356 : css::uno::Reference< css::uno::XComponentContext > const & context)
1357 : : BaseMutex()
1358 : , SfxDocumentMetaData_Base(m_aMutex)
1359 : , m_xContext(context)
1360 : , m_NotifyListeners(m_aMutex)
1361 : , m_isInitialized(false)
1362 : , m_isModified(false)
1363 4898 : , m_AutoloadSecs(0)
1364 : {
1365 : DBG_ASSERT(context.is(), "SfxDocumentMetaData: context is null");
1366 : DBG_ASSERT(context->getServiceManager().is(),
1367 : "SfxDocumentMetaData: context has no service manager");
1368 4898 : init(createDOM());
1369 4898 : }
1370 :
1371 : // com.sun.star.uno.XServiceInfo:
1372 : OUString SAL_CALL
1373 1 : SfxDocumentMetaData::getImplementationName() throw (css::uno::RuntimeException, std::exception)
1374 : {
1375 1 : return OUString("SfxDocumentMetaData");
1376 : }
1377 :
1378 : sal_Bool SAL_CALL
1379 0 : SfxDocumentMetaData::supportsService(OUString const & serviceName)
1380 : throw (css::uno::RuntimeException, std::exception)
1381 : {
1382 0 : return cppu::supportsService(this, serviceName);
1383 : }
1384 :
1385 : css::uno::Sequence< OUString > SAL_CALL
1386 1 : SfxDocumentMetaData::getSupportedServiceNames()
1387 : throw (css::uno::RuntimeException, std::exception)
1388 : {
1389 1 : css::uno::Sequence< OUString > s(1);
1390 1 : s[0] = "com.sun.star.document.DocumentProperties";
1391 1 : return s;
1392 : }
1393 :
1394 :
1395 : // ::com::sun::star::lang::XComponent:
1396 4877 : void SAL_CALL SfxDocumentMetaData::dispose() throw (css::uno::RuntimeException, std::exception)
1397 : {
1398 4877 : ::osl::MutexGuard g(m_aMutex);
1399 4877 : if (!m_isInitialized) {
1400 4877 : return;
1401 : }
1402 4877 : WeakComponentImplHelperBase::dispose(); // superclass
1403 : m_NotifyListeners.disposeAndClear(css::lang::EventObject(
1404 4877 : static_cast< ::cppu::OWeakObject* >(this)));
1405 4877 : m_isInitialized = false;
1406 4877 : m_meta.clear();
1407 4877 : m_metaList.clear();
1408 4877 : m_xParent.clear();
1409 4877 : m_xDoc.clear();
1410 4877 : m_xUserDefined.clear();
1411 : }
1412 :
1413 :
1414 : // ::com::sun::star::document::XDocumentProperties:
1415 : OUString SAL_CALL
1416 3563 : SfxDocumentMetaData::getAuthor() throw (css::uno::RuntimeException, std::exception)
1417 : {
1418 3563 : ::osl::MutexGuard g(m_aMutex);
1419 3563 : return getMetaText("meta:initial-creator");
1420 : }
1421 :
1422 2329 : void SAL_CALL SfxDocumentMetaData::setAuthor(const OUString & the_value)
1423 : throw (css::uno::RuntimeException, std::exception)
1424 : {
1425 2329 : setMetaTextAndNotify("meta:initial-creator", the_value);
1426 2329 : }
1427 :
1428 :
1429 : OUString SAL_CALL
1430 3996 : SfxDocumentMetaData::getGenerator() throw (css::uno::RuntimeException, std::exception)
1431 : {
1432 3996 : ::osl::MutexGuard g(m_aMutex);
1433 3996 : return getMetaText("meta:generator");
1434 : }
1435 :
1436 : void SAL_CALL
1437 2721 : SfxDocumentMetaData::setGenerator(const OUString & the_value)
1438 : throw (css::uno::RuntimeException, std::exception)
1439 : {
1440 2721 : setMetaTextAndNotify("meta:generator", the_value);
1441 2721 : }
1442 :
1443 : css::util::DateTime SAL_CALL
1444 908 : SfxDocumentMetaData::getCreationDate() throw (css::uno::RuntimeException, std::exception)
1445 : {
1446 908 : ::osl::MutexGuard g(m_aMutex);
1447 908 : return textToDateTimeDefault(getMetaText("meta:creation-date"));
1448 : }
1449 :
1450 : void SAL_CALL
1451 2689 : SfxDocumentMetaData::setCreationDate(const css::util::DateTime & the_value)
1452 : throw (css::uno::RuntimeException, std::exception)
1453 : {
1454 2689 : setMetaTextAndNotify("meta:creation-date", dateTimeToText(the_value));
1455 2689 : }
1456 :
1457 : OUString SAL_CALL
1458 1825 : SfxDocumentMetaData::getTitle() throw (css::uno::RuntimeException, std::exception)
1459 : {
1460 1825 : ::osl::MutexGuard g(m_aMutex);
1461 1825 : return getMetaText("dc:title");
1462 : }
1463 :
1464 443 : void SAL_CALL SfxDocumentMetaData::setTitle(const OUString & the_value)
1465 : throw (css::uno::RuntimeException, std::exception)
1466 : {
1467 443 : setMetaTextAndNotify("dc:title", the_value);
1468 443 : }
1469 :
1470 : OUString SAL_CALL
1471 851 : SfxDocumentMetaData::getSubject() throw (css::uno::RuntimeException, std::exception)
1472 : {
1473 851 : ::osl::MutexGuard g(m_aMutex);
1474 851 : return getMetaText("dc:subject");
1475 : }
1476 :
1477 : void SAL_CALL
1478 225 : SfxDocumentMetaData::setSubject(const OUString & the_value)
1479 : throw (css::uno::RuntimeException, std::exception)
1480 : {
1481 225 : setMetaTextAndNotify("dc:subject", the_value);
1482 225 : }
1483 :
1484 : OUString SAL_CALL
1485 787 : SfxDocumentMetaData::getDescription() throw (css::uno::RuntimeException, std::exception)
1486 : {
1487 787 : ::osl::MutexGuard g(m_aMutex);
1488 787 : return getMetaText("dc:description");
1489 : }
1490 :
1491 : void SAL_CALL
1492 172 : SfxDocumentMetaData::setDescription(const OUString & the_value)
1493 : throw (css::uno::RuntimeException, std::exception)
1494 : {
1495 172 : setMetaTextAndNotify("dc:description", the_value);
1496 172 : }
1497 :
1498 : css::uno::Sequence< OUString >
1499 787 : SAL_CALL SfxDocumentMetaData::getKeywords() throw (css::uno::RuntimeException, std::exception)
1500 : {
1501 787 : ::osl::MutexGuard g(m_aMutex);
1502 787 : return getMetaList("meta:keyword");
1503 : }
1504 :
1505 : void SAL_CALL
1506 185 : SfxDocumentMetaData::setKeywords(
1507 : const css::uno::Sequence< OUString > & the_value)
1508 : throw (css::uno::RuntimeException, std::exception)
1509 : {
1510 185 : ::osl::ClearableMutexGuard g(m_aMutex);
1511 185 : if (setMetaList("meta:keyword", the_value)) {
1512 14 : g.clear();
1513 14 : setModified(true);
1514 185 : }
1515 185 : }
1516 :
1517 : css::lang::Locale SAL_CALL
1518 620 : SfxDocumentMetaData::getLanguage() throw (css::uno::RuntimeException, std::exception)
1519 : {
1520 620 : ::osl::MutexGuard g(m_aMutex);
1521 620 : css::lang::Locale loc( LanguageTag( getMetaText("dc:language")).getLocale( false));
1522 620 : return loc;
1523 : }
1524 :
1525 : void SAL_CALL
1526 685 : SfxDocumentMetaData::setLanguage(const css::lang::Locale & the_value)
1527 : throw (css::uno::RuntimeException, std::exception)
1528 : {
1529 685 : OUString text( LanguageTag::convertToBcp47( the_value, false));
1530 685 : setMetaTextAndNotify("dc:language", text);
1531 685 : }
1532 :
1533 : OUString SAL_CALL
1534 3538 : SfxDocumentMetaData::getModifiedBy() throw (css::uno::RuntimeException, std::exception)
1535 : {
1536 3538 : ::osl::MutexGuard g(m_aMutex);
1537 3538 : return getMetaText("dc:creator");
1538 : }
1539 :
1540 : void SAL_CALL
1541 1773 : SfxDocumentMetaData::setModifiedBy(const OUString & the_value)
1542 : throw (css::uno::RuntimeException, std::exception)
1543 : {
1544 1773 : setMetaTextAndNotify("dc:creator", the_value);
1545 1773 : }
1546 :
1547 : css::util::DateTime SAL_CALL
1548 885 : SfxDocumentMetaData::getModificationDate() throw (css::uno::RuntimeException, std::exception)
1549 : {
1550 885 : ::osl::MutexGuard g(m_aMutex);
1551 885 : return textToDateTimeDefault(getMetaText("dc:date"));
1552 : }
1553 :
1554 : void SAL_CALL
1555 2088 : SfxDocumentMetaData::setModificationDate(const css::util::DateTime & the_value)
1556 : throw (css::uno::RuntimeException, std::exception)
1557 : {
1558 2088 : setMetaTextAndNotify("dc:date", dateTimeToText(the_value));
1559 2088 : }
1560 :
1561 : OUString SAL_CALL
1562 60 : SfxDocumentMetaData::getPrintedBy() throw (css::uno::RuntimeException, std::exception)
1563 : {
1564 60 : ::osl::MutexGuard g(m_aMutex);
1565 60 : return getMetaText("meta:printed-by");
1566 : }
1567 :
1568 : void SAL_CALL
1569 267 : SfxDocumentMetaData::setPrintedBy(const OUString & the_value)
1570 : throw (css::uno::RuntimeException, std::exception)
1571 : {
1572 267 : setMetaTextAndNotify("meta:printed-by", the_value);
1573 267 : }
1574 :
1575 : css::util::DateTime SAL_CALL
1576 800 : SfxDocumentMetaData::getPrintDate() throw (css::uno::RuntimeException, std::exception)
1577 : {
1578 800 : ::osl::MutexGuard g(m_aMutex);
1579 800 : return textToDateTimeDefault(getMetaText("meta:print-date"));
1580 : }
1581 :
1582 : void SAL_CALL
1583 690 : SfxDocumentMetaData::setPrintDate(const css::util::DateTime & the_value)
1584 : throw (css::uno::RuntimeException, std::exception)
1585 : {
1586 690 : setMetaTextAndNotify("meta:print-date", dateTimeToText(the_value));
1587 690 : }
1588 :
1589 : OUString SAL_CALL
1590 1029 : SfxDocumentMetaData::getTemplateName() throw (css::uno::RuntimeException, std::exception)
1591 : {
1592 1029 : ::osl::MutexGuard g(m_aMutex);
1593 1029 : checkInit();
1594 1029 : return m_TemplateName;
1595 : }
1596 :
1597 : void SAL_CALL
1598 1603 : SfxDocumentMetaData::setTemplateName(const OUString & the_value)
1599 : throw (css::uno::RuntimeException, std::exception)
1600 : {
1601 1603 : ::osl::ClearableMutexGuard g(m_aMutex);
1602 1603 : checkInit();
1603 1603 : if (m_TemplateName != the_value) {
1604 1484 : m_TemplateName = the_value;
1605 1484 : g.clear();
1606 1484 : setModified(true);
1607 1603 : }
1608 1603 : }
1609 :
1610 : OUString SAL_CALL
1611 1178 : SfxDocumentMetaData::getTemplateURL() throw (css::uno::RuntimeException, std::exception)
1612 : {
1613 1178 : ::osl::MutexGuard g(m_aMutex);
1614 1178 : checkInit();
1615 1178 : return m_TemplateURL;
1616 : }
1617 :
1618 : void SAL_CALL
1619 795 : SfxDocumentMetaData::setTemplateURL(const OUString & the_value)
1620 : throw (css::uno::RuntimeException, std::exception)
1621 : {
1622 795 : ::osl::ClearableMutexGuard g(m_aMutex);
1623 795 : checkInit();
1624 795 : if (m_TemplateURL != the_value) {
1625 10 : m_TemplateURL = the_value;
1626 10 : g.clear();
1627 10 : setModified(true);
1628 795 : }
1629 795 : }
1630 :
1631 : css::util::DateTime SAL_CALL
1632 58 : SfxDocumentMetaData::getTemplateDate() throw (css::uno::RuntimeException, std::exception)
1633 : {
1634 58 : ::osl::MutexGuard g(m_aMutex);
1635 58 : checkInit();
1636 58 : return m_TemplateDate;
1637 : }
1638 :
1639 : void SAL_CALL
1640 61 : SfxDocumentMetaData::setTemplateDate(const css::util::DateTime & the_value)
1641 : throw (css::uno::RuntimeException, std::exception)
1642 : {
1643 61 : ::osl::ClearableMutexGuard g(m_aMutex);
1644 61 : checkInit();
1645 61 : if (!(m_TemplateDate == the_value)) {
1646 1 : m_TemplateDate = the_value;
1647 1 : g.clear();
1648 1 : setModified(true);
1649 61 : }
1650 61 : }
1651 :
1652 : OUString SAL_CALL
1653 6018 : SfxDocumentMetaData::getAutoloadURL() throw (css::uno::RuntimeException, std::exception)
1654 : {
1655 6018 : ::osl::MutexGuard g(m_aMutex);
1656 6018 : checkInit();
1657 6018 : return m_AutoloadURL;
1658 : }
1659 :
1660 : void SAL_CALL
1661 698 : SfxDocumentMetaData::setAutoloadURL(const OUString & the_value)
1662 : throw (css::uno::RuntimeException, std::exception)
1663 : {
1664 698 : ::osl::ClearableMutexGuard g(m_aMutex);
1665 698 : checkInit();
1666 698 : if (m_AutoloadURL != the_value) {
1667 2 : m_AutoloadURL = the_value;
1668 2 : g.clear();
1669 2 : setModified(true);
1670 698 : }
1671 698 : }
1672 :
1673 : ::sal_Int32 SAL_CALL
1674 5393 : SfxDocumentMetaData::getAutoloadSecs() throw (css::uno::RuntimeException, std::exception)
1675 : {
1676 5393 : ::osl::MutexGuard g(m_aMutex);
1677 5393 : checkInit();
1678 5393 : return m_AutoloadSecs;
1679 : }
1680 :
1681 : void SAL_CALL
1682 57 : SfxDocumentMetaData::setAutoloadSecs(::sal_Int32 the_value)
1683 : throw (css::uno::RuntimeException, css::lang::IllegalArgumentException, std::exception)
1684 : {
1685 57 : if (the_value < 0) throw css::lang::IllegalArgumentException(
1686 : OUString("SfxDocumentMetaData::setAutoloadSecs: argument is negative"),
1687 0 : *this, 0);
1688 57 : ::osl::ClearableMutexGuard g(m_aMutex);
1689 57 : checkInit();
1690 57 : if (m_AutoloadSecs != the_value) {
1691 1 : m_AutoloadSecs = the_value;
1692 1 : g.clear();
1693 1 : setModified(true);
1694 57 : }
1695 57 : }
1696 :
1697 : OUString SAL_CALL
1698 75 : SfxDocumentMetaData::getDefaultTarget() throw (css::uno::RuntimeException, std::exception)
1699 : {
1700 75 : ::osl::MutexGuard g(m_aMutex);
1701 75 : checkInit();
1702 75 : return m_DefaultTarget;
1703 : }
1704 :
1705 : void SAL_CALL
1706 57 : SfxDocumentMetaData::setDefaultTarget(const OUString & the_value)
1707 : throw (css::uno::RuntimeException, std::exception)
1708 : {
1709 57 : ::osl::ClearableMutexGuard g(m_aMutex);
1710 57 : checkInit();
1711 57 : if (m_DefaultTarget != the_value) {
1712 0 : m_DefaultTarget = the_value;
1713 0 : g.clear();
1714 0 : setModified(true);
1715 57 : }
1716 57 : }
1717 :
1718 : css::uno::Sequence< css::beans::NamedValue > SAL_CALL
1719 8580 : SfxDocumentMetaData::getDocumentStatistics() throw (css::uno::RuntimeException, std::exception)
1720 : {
1721 8580 : ::osl::MutexGuard g(m_aMutex);
1722 8580 : checkInit();
1723 17160 : ::std::vector<css::beans::NamedValue> stats;
1724 137280 : for (size_t i = 0; s_stdStats[i] != 0; ++i) {
1725 128700 : const char * aName = s_stdStatAttrs[i];
1726 128700 : OUString text = getMetaAttr("meta:document-statistic", aName);
1727 128700 : if (text.isEmpty()) continue;
1728 39604 : css::beans::NamedValue stat;
1729 19802 : stat.Name = OUString::createFromAscii(s_stdStats[i]);
1730 : sal_Int32 val;
1731 39604 : css::uno::Any any;
1732 19802 : if (!::sax::Converter::convertNumber(val, text, 0,
1733 19802 : std::numeric_limits<sal_Int32>::max()) || (val < 0)) {
1734 0 : val = 0;
1735 : SAL_WARN("sfx.doc", "Invalid number: " << text);
1736 : }
1737 19802 : any <<= val;
1738 19802 : stat.Value = any;
1739 19802 : stats.push_back(stat);
1740 19802 : }
1741 :
1742 17160 : return ::comphelper::containerToSequence(stats);
1743 : }
1744 :
1745 : void SAL_CALL
1746 5651 : SfxDocumentMetaData::setDocumentStatistics(
1747 : const css::uno::Sequence< css::beans::NamedValue > & the_value)
1748 : throw (css::uno::RuntimeException, std::exception)
1749 : {
1750 5651 : ::osl::ClearableMutexGuard g(m_aMutex);
1751 5651 : checkInit();
1752 11302 : std::vector<std::pair<const char *, OUString> > attributes;
1753 25372 : for (sal_Int32 i = 0; i < the_value.getLength(); ++i) {
1754 19721 : const OUString name = the_value[i].Name;
1755 : // inefficently search for matching attribute
1756 114886 : for (size_t j = 0; s_stdStats[j] != 0; ++j) {
1757 114886 : if (name.equalsAscii(s_stdStats[j])) {
1758 19721 : const css::uno::Any any = the_value[i].Value;
1759 19721 : sal_Int32 val = 0;
1760 19721 : if (any >>= val) {
1761 19721 : OUStringBuffer buf;
1762 19721 : ::sax::Converter::convertNumber(buf, val);
1763 : attributes.push_back(std::make_pair(s_stdStatAttrs[j],
1764 19721 : buf.makeStringAndClear()));
1765 : } else {
1766 : SAL_WARN("sfx.doc", "Invalid statistic: " << name);
1767 : }
1768 19721 : break;
1769 : }
1770 : }
1771 19721 : }
1772 5651 : updateElement("meta:document-statistic", &attributes);
1773 5651 : g.clear();
1774 11302 : setModified(true);
1775 5651 : }
1776 :
1777 : ::sal_Int16 SAL_CALL
1778 743 : SfxDocumentMetaData::getEditingCycles() throw (css::uno::RuntimeException, std::exception)
1779 : {
1780 743 : ::osl::MutexGuard g(m_aMutex);
1781 1486 : OUString text = getMetaText("meta:editing-cycles");
1782 : sal_Int32 ret;
1783 743 : if (::sax::Converter::convertNumber(ret, text,
1784 743 : 0, std::numeric_limits<sal_Int16>::max())) {
1785 743 : return static_cast<sal_Int16>(ret);
1786 : } else {
1787 0 : return 0;
1788 743 : }
1789 : }
1790 :
1791 : void SAL_CALL
1792 1930 : SfxDocumentMetaData::setEditingCycles(::sal_Int16 the_value)
1793 : throw (css::uno::RuntimeException, css::lang::IllegalArgumentException, std::exception)
1794 : {
1795 1930 : if (the_value < 0) throw css::lang::IllegalArgumentException(
1796 : OUString("SfxDocumentMetaData::setEditingCycles: argument is negative"),
1797 0 : *this, 0);
1798 1930 : OUStringBuffer buf;
1799 1930 : ::sax::Converter::convertNumber(buf, the_value);
1800 1930 : setMetaTextAndNotify("meta:editing-cycles", buf.makeStringAndClear());
1801 1930 : }
1802 :
1803 : ::sal_Int32 SAL_CALL
1804 743 : SfxDocumentMetaData::getEditingDuration() throw (css::uno::RuntimeException, std::exception)
1805 : {
1806 743 : ::osl::MutexGuard g(m_aMutex);
1807 743 : return textToDuration(getMetaText("meta:editing-duration"));
1808 : }
1809 :
1810 : void SAL_CALL
1811 1887 : SfxDocumentMetaData::setEditingDuration(::sal_Int32 the_value)
1812 : throw (css::uno::RuntimeException, css::lang::IllegalArgumentException, std::exception)
1813 : {
1814 1887 : if (the_value < 0) throw css::lang::IllegalArgumentException(
1815 : OUString("SfxDocumentMetaData::setEditingDuration: argument is negative"),
1816 0 : *this, 0);
1817 1887 : setMetaTextAndNotify("meta:editing-duration", durationToText(the_value));
1818 1887 : }
1819 :
1820 : void SAL_CALL
1821 4 : SfxDocumentMetaData::resetUserData(const OUString & the_value)
1822 : throw (css::uno::RuntimeException, std::exception)
1823 : {
1824 4 : ::osl::ClearableMutexGuard g(m_aMutex);
1825 :
1826 4 : bool bModified( false );
1827 4 : bModified |= setMetaText("meta:initial-creator", the_value);
1828 4 : ::DateTime now( ::DateTime::SYSTEM );
1829 4 : css::util::DateTime uDT(now.GetUNODateTime());
1830 4 : bModified |= setMetaText("meta:creation-date", dateTimeToText(uDT));
1831 4 : bModified |= setMetaText("dc:creator", OUString());
1832 4 : bModified |= setMetaText("meta:printed-by", OUString());
1833 4 : bModified |= setMetaText("dc:date", dateTimeToText(css::util::DateTime()));
1834 : bModified |= setMetaText("meta:print-date",
1835 4 : dateTimeToText(css::util::DateTime()));
1836 4 : bModified |= setMetaText("meta:editing-duration", durationToText(0));
1837 : bModified |= setMetaText("meta:editing-cycles",
1838 4 : OUString("1"));
1839 :
1840 4 : if (bModified) {
1841 4 : g.clear();
1842 4 : setModified(true);
1843 4 : }
1844 4 : }
1845 :
1846 :
1847 : css::uno::Reference< css::beans::XPropertyContainer > SAL_CALL
1848 12916 : SfxDocumentMetaData::getUserDefinedProperties()
1849 : throw (css::uno::RuntimeException, std::exception)
1850 : {
1851 12916 : ::osl::MutexGuard g(m_aMutex);
1852 12916 : checkInit();
1853 12916 : createUserDefined();
1854 12916 : return m_xUserDefined;
1855 : }
1856 :
1857 :
1858 : void SAL_CALL
1859 4 : SfxDocumentMetaData::loadFromStorage(
1860 : const css::uno::Reference< css::embed::XStorage > & xStorage,
1861 : const css::uno::Sequence< css::beans::PropertyValue > & Medium)
1862 : throw (css::uno::RuntimeException, css::lang::IllegalArgumentException,
1863 : css::io::WrongFormatException,
1864 : css::lang::WrappedTargetException, css::io::IOException, std::exception)
1865 : {
1866 4 : if (!xStorage.is()) throw css::lang::IllegalArgumentException(
1867 0 : OUString("SfxDocumentMetaData::loadFromStorage: argument is null"), *this, 0);
1868 4 : ::osl::MutexGuard g(m_aMutex);
1869 :
1870 : // open meta data file
1871 : css::uno::Reference<css::io::XStream> xStream(
1872 4 : xStorage->openStreamElement(
1873 : OUString(s_meta),
1874 8 : css::embed::ElementModes::READ) );
1875 4 : if (!xStream.is()) throw css::uno::RuntimeException();
1876 : css::uno::Reference<css::io::XInputStream> xInStream =
1877 8 : xStream->getInputStream();
1878 4 : if (!xInStream.is()) throw css::uno::RuntimeException();
1879 :
1880 : // create DOM parser service
1881 : css::uno::Reference<css::lang::XMultiComponentFactory> xMsf (
1882 8 : m_xContext->getServiceManager());
1883 8 : css::uno::Reference<css::xml::sax::XParser> xParser = css::xml::sax::Parser::create(m_xContext);
1884 8 : css::xml::sax::InputSource input;
1885 4 : input.aInputStream = xInStream;
1886 :
1887 4 : sal_uInt64 version = SotStorage::GetVersion( xStorage );
1888 : // Oasis is also the default (0)
1889 4 : bool bOasis = ( version > SOFFICE_FILEFORMAT_60 || version == 0 );
1890 : const sal_Char *pServiceName = bOasis
1891 : ? "com.sun.star.document.XMLOasisMetaImporter"
1892 4 : : "com.sun.star.document.XMLMetaImporter";
1893 :
1894 : // set base URL
1895 : css::uno::Reference<css::beans::XPropertySet> xPropArg =
1896 8 : getURLProperties(Medium);
1897 : try {
1898 4 : xPropArg->getPropertyValue("BaseURI")
1899 4 : >>= input.sSystemId;
1900 4 : input.sSystemId += OUStringLiteral("/") + s_meta;
1901 0 : } catch (const css::uno::Exception &) {
1902 0 : input.sSystemId = s_meta;
1903 : }
1904 8 : css::uno::Sequence< css::uno::Any > args(1);
1905 4 : args[0] <<= xPropArg;
1906 :
1907 : css::uno::Reference<css::xml::sax::XDocumentHandler> xDocHandler (
1908 4 : xMsf->createInstanceWithArgumentsAndContext(
1909 4 : OUString::createFromAscii(pServiceName), args, m_xContext),
1910 8 : css::uno::UNO_QUERY_THROW);
1911 4 : if (!xDocHandler.is()) throw css::uno::RuntimeException(
1912 : OUString("SfxDocumentMetaData::loadFromStorage:"
1913 0 : " cannot create XMLOasisMetaImporter service"), *this);
1914 : css::uno::Reference<css::document::XImporter> xImp (xDocHandler,
1915 8 : css::uno::UNO_QUERY_THROW);
1916 4 : xImp->setTargetDocument(css::uno::Reference<css::lang::XComponent>(this));
1917 4 : xParser->setDocumentHandler(xDocHandler);
1918 : try {
1919 4 : xParser->parseStream(input);
1920 0 : } catch (const css::xml::sax::SAXException &) {
1921 : throw css::io::WrongFormatException(OUString(
1922 : "SfxDocumentMetaData::loadFromStorage:"
1923 0 : " XML parsing exception"), *this);
1924 : }
1925 : // NB: the implementation of XMLOasisMetaImporter calls initialize
1926 8 : checkInit();
1927 4 : }
1928 :
1929 : void SAL_CALL
1930 3 : SfxDocumentMetaData::storeToStorage(
1931 : const css::uno::Reference< css::embed::XStorage > & xStorage,
1932 : const css::uno::Sequence< css::beans::PropertyValue > & Medium)
1933 : throw (css::uno::RuntimeException, css::lang::IllegalArgumentException,
1934 : css::lang::WrappedTargetException, css::io::IOException, std::exception)
1935 : {
1936 3 : if (!xStorage.is()) throw css::lang::IllegalArgumentException(
1937 : OUString("SfxDocumentMetaData::storeToStorage:"
1938 0 : " argument is null"), *this, 0);
1939 3 : ::osl::MutexGuard g(m_aMutex);
1940 3 : checkInit();
1941 :
1942 : // update user-defined meta data in DOM tree
1943 : // updateUserDefinedAndAttributes(); // this will be done in serialize!
1944 :
1945 : // write into storage
1946 : css::uno::Reference<css::io::XStream> xStream =
1947 3 : xStorage->openStreamElement(OUString(s_meta),
1948 : css::embed::ElementModes::WRITE
1949 6 : | css::embed::ElementModes::TRUNCATE);
1950 3 : if (!xStream.is()) throw css::uno::RuntimeException();
1951 : css::uno::Reference< css::beans::XPropertySet > xStreamProps(xStream,
1952 6 : css::uno::UNO_QUERY_THROW);
1953 3 : xStreamProps->setPropertyValue(
1954 : OUString("MediaType"),
1955 3 : css::uno::makeAny(OUString("text/xml")));
1956 3 : xStreamProps->setPropertyValue(
1957 : OUString("Compressed"),
1958 3 : css::uno::makeAny(false));
1959 3 : xStreamProps->setPropertyValue(
1960 : OUString("UseCommonStoragePasswordEncryption"),
1961 3 : css::uno::makeAny(false));
1962 : css::uno::Reference<css::io::XOutputStream> xOutStream =
1963 6 : xStream->getOutputStream();
1964 3 : if (!xOutStream.is()) throw css::uno::RuntimeException();
1965 : css::uno::Reference<css::lang::XMultiComponentFactory> xMsf (
1966 6 : m_xContext->getServiceManager());
1967 : css::uno::Reference<css::xml::sax::XWriter> xSaxWriter(
1968 6 : css::xml::sax::Writer::create(m_xContext));
1969 3 : xSaxWriter->setOutputStream(xOutStream);
1970 :
1971 3 : const sal_uInt64 version = SotStorage::GetVersion( xStorage );
1972 : // Oasis is also the default (0)
1973 3 : const bool bOasis = ( version > SOFFICE_FILEFORMAT_60 || version == 0 );
1974 : const sal_Char *pServiceName = bOasis
1975 : ? "com.sun.star.document.XMLOasisMetaExporter"
1976 3 : : "com.sun.star.document.XMLMetaExporter";
1977 :
1978 : // set base URL
1979 : css::uno::Reference<css::beans::XPropertySet> xPropArg =
1980 6 : getURLProperties(Medium);
1981 6 : css::uno::Sequence< css::uno::Any > args(2);
1982 3 : args[0] <<= xSaxWriter;
1983 3 : args[1] <<= xPropArg;
1984 :
1985 : css::uno::Reference<css::document::XExporter> xExp(
1986 3 : xMsf->createInstanceWithArgumentsAndContext(
1987 3 : OUString::createFromAscii(pServiceName), args, m_xContext),
1988 6 : css::uno::UNO_QUERY_THROW);
1989 3 : xExp->setSourceDocument(css::uno::Reference<css::lang::XComponent>(this));
1990 : css::uno::Reference<css::document::XFilter> xFilter(xExp,
1991 6 : css::uno::UNO_QUERY_THROW);
1992 3 : if (xFilter->filter(css::uno::Sequence< css::beans::PropertyValue >())) {
1993 : css::uno::Reference<css::embed::XTransactedObject> xTransaction(
1994 3 : xStorage, css::uno::UNO_QUERY);
1995 3 : if (xTransaction.is()) {
1996 3 : xTransaction->commit();
1997 3 : }
1998 : } else {
1999 : throw css::io::IOException(OUString(
2000 0 : "SfxDocumentMetaData::storeToStorage: cannot filter"), *this);
2001 3 : }
2002 3 : }
2003 :
2004 : void SAL_CALL
2005 10 : SfxDocumentMetaData::loadFromMedium(const OUString & URL,
2006 : const css::uno::Sequence< css::beans::PropertyValue > & Medium)
2007 : throw (css::uno::RuntimeException, css::io::WrongFormatException,
2008 : css::lang::WrappedTargetException, css::io::IOException, std::exception)
2009 : {
2010 10 : css::uno::Reference<css::io::XInputStream> xIn;
2011 20 : utl::MediaDescriptor md(Medium);
2012 : // if we have an URL parameter, it replaces the one in the media descriptor
2013 10 : if (!URL.isEmpty()) {
2014 9 : md[ utl::MediaDescriptor::PROP_URL() ] <<= URL;
2015 9 : md[ utl::MediaDescriptor::PROP_READONLY() ] <<= true;
2016 : }
2017 10 : if (md.addInputStream()) {
2018 4 : md[ utl::MediaDescriptor::PROP_INPUTSTREAM() ] >>= xIn;
2019 : }
2020 20 : css::uno::Reference<css::embed::XStorage> xStorage;
2021 : try {
2022 10 : if (xIn.is()) {
2023 8 : xStorage = ::comphelper::OStorageHelper::GetStorageFromInputStream(
2024 4 : xIn, m_xContext);
2025 : } else { // fallback to url parameter
2026 6 : xStorage = ::comphelper::OStorageHelper::GetStorageFromURL(
2027 0 : URL, css::embed::ElementModes::READ, m_xContext);
2028 : }
2029 0 : } catch (const css::uno::RuntimeException &) {
2030 0 : throw;
2031 0 : } catch (const css::io::IOException &) {
2032 0 : throw;
2033 12 : } catch (const css::uno::Exception & e) {
2034 : throw css::lang::WrappedTargetException(
2035 : OUString("SfxDocumentMetaData::loadFromMedium: exception"),
2036 : css::uno::Reference<css::uno::XInterface>(*this),
2037 6 : css::uno::makeAny(e));
2038 : }
2039 4 : if (!xStorage.is()) {
2040 : throw css::uno::RuntimeException(OUString(
2041 : "SfxDocumentMetaData::loadFromMedium: cannot get Storage"),
2042 0 : *this);
2043 : }
2044 14 : loadFromStorage(xStorage, md.getAsConstPropertyValueList());
2045 4 : }
2046 :
2047 : void SAL_CALL
2048 3 : SfxDocumentMetaData::storeToMedium(const OUString & URL,
2049 : const css::uno::Sequence< css::beans::PropertyValue > & Medium)
2050 : throw (css::uno::RuntimeException,
2051 : css::lang::WrappedTargetException, css::io::IOException, std::exception)
2052 : {
2053 3 : utl::MediaDescriptor md(Medium);
2054 3 : if (!URL.isEmpty()) {
2055 2 : md[ utl::MediaDescriptor::PROP_URL() ] <<= URL;
2056 : }
2057 6 : SfxMedium aMedium(md.getAsConstPropertyValueList());
2058 : css::uno::Reference<css::embed::XStorage> xStorage
2059 6 : = aMedium.GetOutputStorage();
2060 :
2061 :
2062 3 : if (!xStorage.is()) {
2063 : throw css::uno::RuntimeException(OUString(
2064 : "SfxDocumentMetaData::storeToMedium: cannot get Storage"),
2065 0 : *this);
2066 : }
2067 : // set MIME type of the storage
2068 : utl::MediaDescriptor::const_iterator iter
2069 3 : = md.find(utl::MediaDescriptor::PROP_MEDIATYPE());
2070 3 : if (iter != md.end()) {
2071 : css::uno::Reference< css::beans::XPropertySet > xProps(xStorage,
2072 3 : css::uno::UNO_QUERY_THROW);
2073 3 : xProps->setPropertyValue(
2074 3 : utl::MediaDescriptor::PROP_MEDIATYPE(),
2075 6 : iter->second);
2076 : }
2077 3 : storeToStorage(xStorage, md.getAsConstPropertyValueList());
2078 :
2079 :
2080 3 : const bool bOk = aMedium.Commit();
2081 3 : aMedium.Close();
2082 3 : if ( !bOk ) {
2083 0 : sal_uInt32 nError = aMedium.GetError();
2084 0 : if ( nError == ERRCODE_NONE ) {
2085 0 : nError = ERRCODE_IO_GENERAL;
2086 : }
2087 :
2088 : throw css::task::ErrorCodeIOException(
2089 0 : ("SfxDocumentMetaData::storeToMedium <" + URL + "> Commit failed: "
2090 0 : "0x" + OUString::number(nError, 16)),
2091 0 : css::uno::Reference< css::uno::XInterface >(), nError);
2092 :
2093 3 : }
2094 3 : }
2095 :
2096 : // ::com::sun::star::lang::XInitialization:
2097 : void SAL_CALL
2098 4853 : SfxDocumentMetaData::initialize(
2099 : const css::uno::Sequence< ::com::sun::star::uno::Any > & aArguments)
2100 : throw (css::uno::RuntimeException, css::uno::Exception, std::exception)
2101 : {
2102 : // possible arguments:
2103 : // - no argument: default initialization (empty DOM)
2104 : // - 1 argument, XDocument: initialize with given DOM and empty base URL
2105 : // NB: links in document must be absolute
2106 :
2107 4853 : ::osl::MutexGuard g(m_aMutex);
2108 9706 : css::uno::Reference<css::xml::dom::XDocument> xDoc;
2109 :
2110 5494 : for (sal_Int32 i = 0; i < aArguments.getLength(); ++i) {
2111 641 : const css::uno::Any any = aArguments[i];
2112 641 : if (any >>= xDoc) {
2113 641 : if (!xDoc.is()) {
2114 : throw css::lang::IllegalArgumentException(
2115 : OUString("SfxDocumentMetaData::"
2116 : "initialize: argument is null"),
2117 0 : *this, static_cast<sal_Int16>(i));
2118 : }
2119 : } else {
2120 : throw css::lang::IllegalArgumentException(
2121 : OUString("SfxDocumentMetaData::"
2122 : "initialize: argument must be XDocument"),
2123 0 : *this, static_cast<sal_Int16>(i));
2124 : }
2125 641 : }
2126 :
2127 4853 : if (!xDoc.is()) {
2128 : // For a new document, we create a new DOM tree here.
2129 4212 : xDoc = createDOM();
2130 : }
2131 :
2132 9706 : init(xDoc);
2133 4853 : }
2134 :
2135 : // ::com::sun::star::util::XCloneable:
2136 : css::uno::Reference<css::util::XCloneable> SAL_CALL
2137 685 : SfxDocumentMetaData::createClone()
2138 : throw (css::uno::RuntimeException, std::exception)
2139 : {
2140 685 : ::osl::MutexGuard g(m_aMutex);
2141 685 : checkInit();
2142 :
2143 685 : SfxDocumentMetaData *pNew = createMe(m_xContext);
2144 :
2145 : // NB: do not copy the modification listeners, only DOM
2146 1370 : css::uno::Reference<css::xml::dom::XDocument> xDoc = createDOM();
2147 : try {
2148 685 : updateUserDefinedAndAttributes();
2149 : // deep copy of root node
2150 : css::uno::Reference<css::xml::dom::XNode> xRoot(
2151 685 : m_xDoc->getDocumentElement(), css::uno::UNO_QUERY_THROW);
2152 : css::uno::Reference<css::xml::dom::XNode> xRootNew(
2153 1370 : xDoc->importNode(xRoot, true));
2154 685 : xDoc->appendChild(xRootNew);
2155 1370 : pNew->init(xDoc);
2156 0 : } catch (const css::uno::RuntimeException &) {
2157 0 : throw;
2158 0 : } catch (const css::uno::Exception & e) {
2159 0 : css::uno::Any a(e);
2160 : throw css::lang::WrappedTargetRuntimeException(
2161 : OUString("SfxDocumentMetaData::createClone: exception"),
2162 0 : css::uno::Reference<css::uno::XInterface>(*this), a);
2163 : }
2164 1370 : return css::uno::Reference<css::util::XCloneable> (pNew);
2165 : }
2166 :
2167 : // ::com::sun::star::util::XModifiable:
2168 0 : sal_Bool SAL_CALL SfxDocumentMetaData::isModified( )
2169 : throw (css::uno::RuntimeException, std::exception)
2170 : {
2171 0 : ::osl::MutexGuard g(m_aMutex);
2172 0 : checkInit();
2173 : css::uno::Reference<css::util::XModifiable> xMB(m_xUserDefined,
2174 0 : css::uno::UNO_QUERY);
2175 0 : return m_isModified || (xMB.is() && xMB->isModified());
2176 : }
2177 :
2178 22319 : void SAL_CALL SfxDocumentMetaData::setModified( sal_Bool bModified )
2179 : throw (css::beans::PropertyVetoException, css::uno::RuntimeException, std::exception)
2180 : {
2181 22319 : css::uno::Reference<css::util::XModifiable> xMB;
2182 : { // do not lock mutex while notifying (#i93514#) to prevent deadlock
2183 22319 : ::osl::MutexGuard g(m_aMutex);
2184 22319 : checkInit();
2185 22319 : m_isModified = bModified;
2186 22319 : if ( !bModified && m_xUserDefined.is() )
2187 : {
2188 0 : xMB.set(m_xUserDefined, css::uno::UNO_QUERY);
2189 : DBG_ASSERT(xMB.is(),
2190 : "SfxDocumentMetaData::setModified: PropertyBag not Modifiable?");
2191 22319 : }
2192 : }
2193 22319 : if (bModified) {
2194 : try {
2195 22319 : css::uno::Reference<css::uno::XInterface> xThis(*this);
2196 44638 : css::lang::EventObject event(xThis);
2197 : m_NotifyListeners.notifyEach(&css::util::XModifyListener::modified,
2198 44638 : event);
2199 0 : } catch (const css::uno::RuntimeException &) {
2200 0 : throw;
2201 0 : } catch (const css::uno::Exception & e) {
2202 : // ignore
2203 : SAL_WARN("sfx.doc", "setModified: exception: " << e.Message);
2204 : }
2205 : } else {
2206 0 : if (xMB.is()) {
2207 0 : xMB->setModified(false);
2208 : }
2209 22319 : }
2210 22319 : }
2211 :
2212 : // ::com::sun::star::util::XModifyBroadcaster:
2213 3992 : void SAL_CALL SfxDocumentMetaData::addModifyListener(
2214 : const css::uno::Reference< css::util::XModifyListener > & xListener)
2215 : throw (css::uno::RuntimeException, std::exception)
2216 : {
2217 3992 : ::osl::MutexGuard g(m_aMutex);
2218 3992 : checkInit();
2219 3992 : m_NotifyListeners.addInterface(xListener);
2220 : css::uno::Reference<css::util::XModifyBroadcaster> xMB(m_xUserDefined,
2221 7984 : css::uno::UNO_QUERY);
2222 3992 : if (xMB.is()) {
2223 1 : xMB->addModifyListener(xListener);
2224 3992 : }
2225 3992 : }
2226 :
2227 1 : void SAL_CALL SfxDocumentMetaData::removeModifyListener(
2228 : const css::uno::Reference< css::util::XModifyListener > & xListener)
2229 : throw (css::uno::RuntimeException, std::exception)
2230 : {
2231 1 : ::osl::MutexGuard g(m_aMutex);
2232 1 : checkInit();
2233 1 : m_NotifyListeners.removeInterface(xListener);
2234 : css::uno::Reference<css::util::XModifyBroadcaster> xMB(m_xUserDefined,
2235 2 : css::uno::UNO_QUERY);
2236 1 : if (xMB.is()) {
2237 1 : xMB->removeModifyListener(xListener);
2238 1 : }
2239 1 : }
2240 :
2241 : // ::com::sun::star::xml::sax::XSAXSerializable
2242 349 : void SAL_CALL SfxDocumentMetaData::serialize(
2243 : const css::uno::Reference<css::xml::sax::XDocumentHandler>& i_xHandler,
2244 : const css::uno::Sequence< css::beans::StringPair >& i_rNamespaces)
2245 : throw (css::uno::RuntimeException, css::xml::sax::SAXException, std::exception)
2246 : {
2247 349 : ::osl::MutexGuard g(m_aMutex);
2248 349 : checkInit();
2249 349 : updateUserDefinedAndAttributes();
2250 : css::uno::Reference<css::xml::sax::XSAXSerializable> xSAXable(m_xDoc,
2251 698 : css::uno::UNO_QUERY_THROW);
2252 698 : xSAXable->serialize(i_xHandler, i_rNamespaces);
2253 349 : }
2254 :
2255 14503 : void SfxDocumentMetaData::createUserDefined()
2256 : {
2257 : // user-defined meta data: create PropertyBag which only accepts property
2258 : // values of allowed types
2259 14503 : if ( !m_xUserDefined.is() )
2260 : {
2261 2838 : css::uno::Sequence<css::uno::Type> types(13);
2262 2838 : types[ 0] = ::cppu::UnoType<bool>::get();
2263 2838 : types[ 1] = ::cppu::UnoType< OUString>::get();
2264 2838 : types[ 2] = ::cppu::UnoType<css::util::DateTime>::get();
2265 2838 : types[ 3] = ::cppu::UnoType<css::util::Date>::get();
2266 2838 : types[ 4] = ::cppu::UnoType<css::util::DateTimeWithTimezone>::get();
2267 2838 : types[ 5] = ::cppu::UnoType<css::util::DateWithTimezone>::get();
2268 2838 : types[ 6] = ::cppu::UnoType<css::util::Duration>::get();
2269 2838 : types[ 7] = ::cppu::UnoType<float>::get();
2270 2838 : types[ 8] = ::cppu::UnoType<double>::get();
2271 2838 : types[ 9] = ::cppu::UnoType<sal_Int16>::get();
2272 2838 : types[10] = ::cppu::UnoType<sal_Int32>::get();
2273 2838 : types[11] = ::cppu::UnoType<sal_Int64>::get();
2274 : // Time is supported for backward compatibility with OOo 3.x, x<=2
2275 2838 : types[12] = ::cppu::UnoType<css::util::Time>::get();
2276 : // #i94175#: ODF allows empty user-defined property names!
2277 : m_xUserDefined.set(
2278 : css::beans::PropertyBag::createWithTypes( m_xContext, types, sal_True/*AllowEmptyPropertyName*/, sal_False/*AutomaticAddition*/ ),
2279 2838 : css::uno::UNO_QUERY_THROW);
2280 :
2281 : const css::uno::Reference<css::util::XModifyBroadcaster> xMB(
2282 5676 : m_xUserDefined, css::uno::UNO_QUERY);
2283 2838 : if (xMB.is())
2284 : {
2285 : const css::uno::Sequence<css::uno::Reference<css::uno::XInterface> >
2286 2838 : listeners(m_NotifyListeners.getElements());
2287 4970 : for (css::uno::Reference< css::uno::XInterface > const * iter = listeners.begin(); iter != listeners.end(); ++iter) {
2288 2132 : xMB->addModifyListener(
2289 : css::uno::Reference< css::util::XModifyListener >(*iter,
2290 2132 : css::uno::UNO_QUERY));
2291 2838 : }
2292 2838 : }
2293 : }
2294 14503 : }
2295 :
2296 : } // closing anonymous implementation namespace
2297 :
2298 : extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * SAL_CALL
2299 0 : CompatWriterDocPropsImpl_get_implementation(
2300 : css::uno::XComponentContext *context,
2301 : css::uno::Sequence<css::uno::Any> const &)
2302 : {
2303 0 : return cppu::acquire(new CompatWriterDocPropsImpl(context));
2304 : }
2305 :
2306 : extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * SAL_CALL
2307 4213 : SfxDocumentMetaData_get_implementation(
2308 : css::uno::XComponentContext *context,
2309 : css::uno::Sequence<css::uno::Any> const &)
2310 : {
2311 4213 : return cppu::acquire(new SfxDocumentMetaData(context));
2312 : }
2313 :
2314 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|