Coverage Report

Created: 2026-02-14 09:37

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