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