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