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