Coverage Report

Created: 2025-07-07 10:01

/src/libreoffice/embeddedobj/source/commonembedding/persistence.cxx
Line
Count
Source (jump to first uncovered line)
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 <commonembobj.hxx>
21
#include <com/sun/star/embed/Aspects.hpp>
22
#include <com/sun/star/document/XStorageBasedDocument.hpp>
23
#include <com/sun/star/embed/EmbedStates.hpp>
24
#include <com/sun/star/embed/EntryInitModes.hpp>
25
#include <com/sun/star/embed/StorageWrappedTargetException.hpp>
26
#include <com/sun/star/embed/WrongStateException.hpp>
27
#include <com/sun/star/embed/XStorage.hpp>
28
#include <com/sun/star/embed/XOptimizedStorage.hpp>
29
#include <com/sun/star/embed/ElementModes.hpp>
30
#include <com/sun/star/embed/EmbedUpdateModes.hpp>
31
#include <com/sun/star/embed/StorageFactory.hpp>
32
#include <com/sun/star/io/IOException.hpp>
33
#include <com/sun/star/io/TempFile.hpp>
34
#include <com/sun/star/frame/XModel.hpp>
35
#include <com/sun/star/frame/XStorable.hpp>
36
#include <com/sun/star/frame/XLoadable.hpp>
37
#include <com/sun/star/frame/XModule.hpp>
38
#include <com/sun/star/lang/NoSupportException.hpp>
39
#include <com/sun/star/lang/XSingleServiceFactory.hpp>
40
#include <com/sun/star/lang/DisposedException.hpp>
41
#include <com/sun/star/util/XModifiable.hpp>
42
43
#include <com/sun/star/container/XNameAccess.hpp>
44
#include <com/sun/star/container/XChild.hpp>
45
#include <com/sun/star/util/XCloseable.hpp>
46
#include <com/sun/star/beans/XPropertySet.hpp>
47
#include <com/sun/star/beans/IllegalTypeException.hpp>
48
#include <com/sun/star/chart2/XChartDocument.hpp>
49
50
#include <com/sun/star/ucb/SimpleFileAccess.hpp>
51
52
#include <comphelper/fileformat.h>
53
#include <comphelper/storagehelper.hxx>
54
#include <comphelper/mimeconfighelper.hxx>
55
#include <comphelper/namedvaluecollection.hxx>
56
#include <comphelper/propertyvalue.hxx>
57
#include <comphelper/configuration.hxx>
58
#include <tools/urlobj.hxx>
59
#include <unotools/mediadescriptor.hxx>
60
#include <unotools/securityoptions.hxx>
61
62
#include <comphelper/diagnose_ex.hxx>
63
#include <sal/log.hxx>
64
#include "persistence.hxx"
65
66
using namespace ::com::sun::star;
67
68
69
uno::Sequence< beans::PropertyValue > GetValuableArgs_Impl( const uno::Sequence< beans::PropertyValue >& aMedDescr,
70
                                                            bool bCanUseDocumentBaseURL )
71
0
{
72
0
    uno::Sequence< beans::PropertyValue > aResult;
73
0
    sal_Int32 nResLen = 0;
74
75
0
    for ( beans::PropertyValue const & prop : aMedDescr )
76
0
    {
77
0
        if ( prop.Name == "ComponentData" || prop.Name == "DocumentTitle"
78
0
          || prop.Name == "InteractionHandler" || prop.Name == "JumpMark"
79
          // || prop.Name == "Password" // makes no sense for embedded objects
80
0
          || prop.Name == "Preview" || prop.Name == "ReadOnly"
81
0
          || prop.Name == "StartPresentation" || prop.Name == "RepairPackage"
82
0
          || prop.Name == "StatusIndicator" || prop.Name == "ViewData"
83
0
          || prop.Name == "ViewId" || prop.Name == "MacroExecutionMode"
84
0
          || prop.Name == "UpdateDocMode" || prop.Name == "Referer"
85
0
          || (prop.Name == "DocumentBaseURL" && bCanUseDocumentBaseURL) )
86
0
        {
87
0
            aResult.realloc( ++nResLen );
88
0
            aResult.getArray()[nResLen-1] = prop;
89
0
        }
90
0
    }
91
92
0
    return aResult;
93
0
}
94
95
96
static uno::Sequence< beans::PropertyValue > addAsTemplate( const uno::Sequence< beans::PropertyValue >& aOrig )
97
0
{
98
0
    bool bAsTemplateSet = false;
99
0
    sal_Int32 nLength = aOrig.getLength();
100
0
    uno::Sequence< beans::PropertyValue > aResult( aOrig );
101
102
0
    for ( sal_Int32 nInd = 0; nInd < nLength; nInd++ )
103
0
    {
104
0
        if ( aResult[nInd].Name == "AsTemplate" )
105
0
        {
106
0
            aResult.getArray()[nInd].Value <<= true;
107
0
            bAsTemplateSet = true;
108
0
        }
109
0
    }
110
111
0
    if ( !bAsTemplateSet )
112
0
    {
113
0
        aResult.realloc( nLength + 1 );
114
0
        auto pResult = aResult.getArray();
115
0
        pResult[nLength].Name = "AsTemplate";
116
0
        pResult[nLength].Value <<= true;
117
0
    }
118
119
0
    return aResult;
120
0
}
121
122
123
static uno::Reference< io::XInputStream > createTempInpStreamFromStor(
124
                                                            const uno::Reference< embed::XStorage >& xStorage,
125
                                                            const uno::Reference< uno::XComponentContext >& xContext )
126
0
{
127
0
    SAL_WARN_IF( !xStorage.is(), "embeddedobj.common", "The storage can not be empty!" );
128
129
0
    uno::Reference< io::XInputStream > xResult;
130
131
0
    uno::Reference < io::XStream > xTempStream( io::TempFile::create(xContext), uno::UNO_QUERY_THROW );
132
133
0
    uno::Reference < lang::XSingleServiceFactory > xStorageFactory( embed::StorageFactory::create(xContext) );
134
135
0
    uno::Sequence< uno::Any > aArgs{ uno::Any(xTempStream),
136
0
                                     uno::Any(embed::ElementModes::READWRITE) };
137
0
    uno::Reference< embed::XStorage > xTempStorage( xStorageFactory->createInstanceWithArguments( aArgs ),
138
0
                                                    uno::UNO_QUERY_THROW );
139
140
0
    try
141
0
    {
142
0
        xStorage->copyToStorage( xTempStorage );
143
0
    } catch( const uno::Exception& )
144
0
    {
145
0
        css::uno::Any anyEx = cppu::getCaughtException();
146
0
        throw embed::StorageWrappedTargetException(
147
0
                    u"Can't copy storage!"_ustr,
148
0
                    uno::Reference< uno::XInterface >(),
149
0
                    anyEx );
150
0
    }
151
152
0
    try {
153
0
        if ( xTempStorage.is() )
154
0
            xTempStorage->dispose();
155
0
    }
156
0
    catch ( const uno::Exception& )
157
0
    {
158
0
    }
159
160
0
    try {
161
0
        uno::Reference< io::XOutputStream > xTempOut = xTempStream->getOutputStream();
162
0
        if ( xTempOut.is() )
163
0
            xTempOut->closeOutput();
164
0
    }
165
0
    catch ( const uno::Exception& )
166
0
    {
167
0
    }
168
169
0
    xResult = xTempStream->getInputStream();
170
171
0
    return xResult;
172
173
0
}
174
175
176
static void TransferMediaType( const uno::Reference< embed::XStorage >& i_rSource, const uno::Reference< embed::XStorage >& i_rTarget )
177
0
{
178
0
    try
179
0
    {
180
0
        const uno::Reference< beans::XPropertySet > xSourceProps( i_rSource, uno::UNO_QUERY_THROW );
181
0
        const uno::Reference< beans::XPropertySet > xTargetProps( i_rTarget, uno::UNO_QUERY_THROW );
182
0
        static constexpr OUString sMediaTypePropName( u"MediaType"_ustr );
183
0
        xTargetProps->setPropertyValue( sMediaTypePropName, xSourceProps->getPropertyValue( sMediaTypePropName ) );
184
0
    }
185
0
    catch( const uno::Exception& )
186
0
    {
187
0
        DBG_UNHANDLED_EXCEPTION("embeddedobj.common");
188
0
    }
189
0
}
190
191
192
static uno::Reference< util::XCloseable > CreateDocument( const uno::Reference< uno::XComponentContext >& _rxContext,
193
    const OUString& _rDocumentServiceName, bool _bEmbeddedScriptSupport, const bool i_bDocumentRecoverySupport )
194
0
{
195
0
    static constexpr OUStringLiteral sEmbeddedObject = u"EmbeddedObject";
196
0
    static constexpr OUStringLiteral sEmbeddedScriptSupport = u"EmbeddedScriptSupport";
197
0
    static constexpr OUStringLiteral sDocumentRecoverySupport = u"DocumentRecoverySupport";
198
0
    ::comphelper::NamedValueCollection aArguments;
199
0
    aArguments.put( sEmbeddedObject, true );
200
0
    aArguments.put( sEmbeddedScriptSupport, _bEmbeddedScriptSupport );
201
0
    aArguments.put( sDocumentRecoverySupport, i_bDocumentRecoverySupport );
202
203
0
    uno::Reference< uno::XInterface > xDocument;
204
0
    try
205
0
    {
206
0
        xDocument = _rxContext->getServiceManager()->createInstanceWithArgumentsAndContext(
207
0
                        _rDocumentServiceName, aArguments.getWrappedPropertyValues(), _rxContext );
208
0
    }
209
0
    catch( const uno::Exception& )
210
0
    {
211
        // if an embedded object implementation does not support XInitialization,
212
        // the default factory from cppuhelper will throw an
213
        // IllegalArgumentException when we try to create the instance with arguments.
214
        // Okay, so we fall back to creating the instance without any arguments.
215
0
        OSL_FAIL("Consider implementing interface XInitialization to avoid duplicate construction");
216
0
        xDocument = _rxContext->getServiceManager()->createInstanceWithContext( _rDocumentServiceName, _rxContext );
217
0
    }
218
219
0
    SAL_WARN_IF(!xDocument.is(), "embeddedobj.common", "Service " << _rDocumentServiceName << " is not available?");
220
0
    return uno::Reference< util::XCloseable >( xDocument, uno::UNO_QUERY );
221
0
}
222
223
224
static void SetDocToEmbedded( const uno::Reference< frame::XModel >& rDocument, const OUString& aModuleName )
225
0
{
226
0
    if (!rDocument.is())
227
0
        return;
228
229
0
    uno::Sequence< beans::PropertyValue > aSeq{ comphelper::makePropertyValue(u"SetEmbedded"_ustr, true) };
230
0
    rDocument->attachResource( OUString(), aSeq );
231
232
0
    if ( !aModuleName.isEmpty() )
233
0
    {
234
0
        try
235
0
        {
236
0
            uno::Reference< frame::XModule > xModule( rDocument, uno::UNO_QUERY_THROW );
237
0
            xModule->setIdentifier( aModuleName );
238
0
        }
239
0
        catch( const uno::Exception& )
240
0
        {}
241
0
    }
242
0
}
243
244
245
void OCommonEmbeddedObject::SwitchOwnPersistence( const uno::Reference< embed::XStorage >& xNewParentStorage,
246
                                                  const uno::Reference< embed::XStorage >& xNewObjectStorage,
247
                                                  const OUString& aNewName )
248
0
{
249
0
    if ( xNewParentStorage == m_xParentStorage && aNewName == m_aEntryName )
250
0
    {
251
0
        SAL_WARN_IF( xNewObjectStorage != m_xObjectStorage, "embeddedobj.common", "The storage must be the same!" );
252
0
        return;
253
0
    }
254
255
0
    auto xOldObjectStorage = m_xObjectStorage;
256
0
    m_xObjectStorage = xNewObjectStorage;
257
0
    m_xParentStorage = xNewParentStorage;
258
0
    m_aEntryName = aNewName;
259
260
    // the linked document should not be switched
261
0
    if ( !m_bIsLinkURL )
262
0
    {
263
0
        uno::Reference< document::XStorageBasedDocument > xDoc( m_xDocHolder->GetComponent(), uno::UNO_QUERY );
264
0
        if ( xDoc.is() )
265
0
            SwitchDocToStorage_Impl( xDoc, m_xObjectStorage );
266
0
    }
267
268
0
    try {
269
0
        if ( xOldObjectStorage.is() )
270
0
            xOldObjectStorage->dispose();
271
0
    }
272
0
    catch ( const uno::Exception& )
273
0
    {
274
0
    }
275
0
}
276
277
278
void OCommonEmbeddedObject::SwitchOwnPersistence( const uno::Reference< embed::XStorage >& xNewParentStorage,
279
                                                  const OUString& aNewName )
280
0
{
281
0
    if ( xNewParentStorage == m_xParentStorage && aNewName == m_aEntryName )
282
0
        return;
283
284
0
    sal_Int32 nStorageMode = m_bReadOnly ? embed::ElementModes::READ : embed::ElementModes::READWRITE;
285
286
0
    uno::Reference< embed::XStorage > xNewOwnStorage = xNewParentStorage->openStorageElement( aNewName, nStorageMode );
287
0
    SAL_WARN_IF( !xNewOwnStorage.is(), "embeddedobj.common", "The method can not return empty reference!" );
288
289
0
    SwitchOwnPersistence( xNewParentStorage, xNewOwnStorage, aNewName );
290
0
}
291
292
293
void OCommonEmbeddedObject::EmbedAndReparentDoc_Impl( const uno::Reference< util::XCloseable >& i_rxDocument ) const
294
0
{
295
0
    SetDocToEmbedded( uno::Reference< frame::XModel >( i_rxDocument, uno::UNO_QUERY ), m_aModuleName );
296
297
0
    try
298
0
    {
299
0
        uno::Reference < container::XChild > xChild( i_rxDocument, uno::UNO_QUERY );
300
0
        if ( xChild.is() )
301
0
            xChild->setParent( m_xParent );
302
0
    }
303
0
    catch( const lang::NoSupportException & )
304
0
    {
305
0
        SAL_WARN( "embeddedobj.common", "OCommonEmbeddedObject::EmbedAndReparentDoc: cannot set parent at document!" );
306
0
    }
307
0
}
308
309
310
uno::Reference< util::XCloseable > OCommonEmbeddedObject::InitNewDocument_Impl()
311
0
{
312
0
    uno::Reference< util::XCloseable > xDocument( CreateDocument( m_xContext, GetDocumentServiceName(),
313
0
                                                m_bEmbeddedScriptSupport, m_bDocumentRecoverySupport ) );
314
315
0
    uno::Reference< frame::XModel > xModel( xDocument, uno::UNO_QUERY );
316
0
    uno::Reference< frame::XLoadable > xLoadable( xModel, uno::UNO_QUERY_THROW );
317
318
0
    try
319
0
    {
320
        // set the document mode to embedded as the first action on document!!!
321
0
        EmbedAndReparentDoc_Impl( xDocument );
322
323
        // if we have a storage to recover the document from, do not use initNew, but instead load from that storage
324
0
        bool bInitNew = true;
325
0
        if ( m_xRecoveryStorage.is() )
326
0
        {
327
0
            uno::Reference< document::XStorageBasedDocument > xDoc( xLoadable, uno::UNO_QUERY );
328
0
            SAL_WARN_IF( !xDoc.is(), "embeddedobj.common", "OCommonEmbeddedObject::InitNewDocument_Impl: cannot recover from a storage when the document is not storage based!" );
329
0
            if ( xDoc.is() )
330
0
            {
331
0
                ::comphelper::NamedValueCollection aLoadArgs;
332
0
                FillDefaultLoadArgs_Impl( m_xRecoveryStorage, aLoadArgs );
333
334
0
                xDoc->loadFromStorage( m_xRecoveryStorage, aLoadArgs.getPropertyValues() );
335
0
                SwitchDocToStorage_Impl( xDoc, m_xObjectStorage );
336
0
                bInitNew = false;
337
0
            }
338
0
        }
339
340
0
        if ( bInitNew )
341
0
        {
342
            // init document as a new
343
0
            xLoadable->initNew();
344
0
        }
345
0
        xModel->attachResource( xModel->getURL(), m_aDocMediaDescriptor );
346
0
    }
347
0
    catch( const uno::Exception& )
348
0
    {
349
0
        if ( xDocument.is() )
350
0
        {
351
0
            try
352
0
            {
353
0
                xDocument->close( true );
354
0
            }
355
0
            catch( const uno::Exception& )
356
0
            {
357
0
            }
358
0
        }
359
360
0
        throw; // TODO
361
0
    }
362
363
0
    return xDocument;
364
0
}
365
366
bool OCommonEmbeddedObject::getAllowLinkUpdate() const
367
0
{
368
    // assume we can update if we can't determine a parent
369
0
    bool bAllowLinkUpdate(true);
370
371
0
    try
372
0
    {
373
0
        uno::Reference<container::XChild> xParent(m_xParent, uno::UNO_QUERY);
374
0
        while (xParent)
375
0
        {
376
0
            uno::Reference<container::XChild> xGrandParent(xParent->getParent(), uno::UNO_QUERY);
377
0
            if (!xGrandParent)
378
0
                break;
379
0
            xParent = std::move(xGrandParent);
380
0
        }
381
382
0
        uno::Reference<beans::XPropertySet> xPropSet(xParent, uno::UNO_QUERY);
383
0
        if (xPropSet.is())
384
0
        {
385
0
            uno::Any aAny = xPropSet->getPropertyValue(u"AllowLinkUpdate"_ustr);
386
0
            aAny >>= bAllowLinkUpdate;
387
0
        }
388
0
    }
389
0
    catch (const uno::Exception&)
390
0
    {
391
0
    }
392
393
0
    SAL_WARN_IF(!bAllowLinkUpdate, "embeddedobj.common", "getAllowLinkUpdate is false");
394
395
0
    return bAllowLinkUpdate;
396
0
}
397
398
uno::Reference< util::XCloseable > OCommonEmbeddedObject::LoadLink_Impl()
399
0
{
400
0
    if (!getAllowLinkUpdate())
401
0
        return nullptr;
402
403
0
    sal_Int32 nLen = m_bLinkHasPassword ? 3 : 2;
404
0
    uno::Sequence< beans::PropertyValue > aArgs( m_aDocMediaDescriptor.getLength() + nLen );
405
0
    auto pArgs = aArgs.getArray();
406
407
0
    OUString sURL;
408
0
    if (m_aLinkTempFile.is())
409
0
        sURL = m_aLinkTempFile->getUri();
410
0
    else
411
0
        sURL = m_aLinkURL;
412
0
    if (INetURLObject(sURL).IsExoticProtocol())
413
0
    {
414
0
        SAL_WARN("embeddedobj.common", "Ignore exotic protocol: " << pArgs[0].Value);
415
0
        return nullptr;
416
0
    }
417
418
0
    pArgs[0].Name = "URL";
419
0
    pArgs[0].Value <<= sURL;
420
421
0
    pArgs[1].Name = "FilterName";
422
0
    pArgs[1].Value <<= m_aLinkFilterName;
423
424
0
    if ( m_bLinkHasPassword )
425
0
    {
426
0
        pArgs[2].Name = "Password";
427
0
        pArgs[2].Value <<= m_aLinkPassword;
428
0
    }
429
430
0
    for ( sal_Int32 nInd = 0; nInd < m_aDocMediaDescriptor.getLength(); nInd++ )
431
0
    {
432
        // return early if this document is not trusted to open links
433
0
        if (m_aDocMediaDescriptor[nInd].Name == utl::MediaDescriptor::PROP_REFERRER)
434
0
        {
435
0
            OUString referer;
436
0
            m_aDocMediaDescriptor[nInd].Value >>= referer;
437
0
            if (SvtSecurityOptions::isUntrustedReferer(referer))
438
0
                return nullptr;
439
0
        }
440
0
        pArgs[nInd+nLen].Name = m_aDocMediaDescriptor[nInd].Name;
441
0
        pArgs[nInd+nLen].Value = m_aDocMediaDescriptor[nInd].Value;
442
0
    }
443
444
0
    uno::Reference< util::XCloseable > xDocument( CreateDocument( m_xContext, GetDocumentServiceName(),
445
0
                                                m_bEmbeddedScriptSupport, m_bDocumentRecoverySupport ) );
446
0
    uno::Reference< frame::XLoadable > xLoadable( xDocument, uno::UNO_QUERY_THROW );
447
448
0
    try
449
0
    {
450
0
        handleLinkedOLE(CopyBackToOLELink::CopyLinkToTemp);
451
452
        // the document is not really an embedded one, it is a link
453
0
        EmbedAndReparentDoc_Impl( xDocument );
454
455
        // load the document
456
0
        xLoadable->load( aArgs );
457
458
0
        if ( !m_bLinkHasPassword )
459
0
        {
460
            // check if there is a password to cache
461
0
            uno::Reference< frame::XModel > xModel( xLoadable, uno::UNO_QUERY_THROW );
462
0
            const uno::Sequence< beans::PropertyValue > aProps = xModel->getArgs();
463
0
            for ( beans::PropertyValue const & prop : aProps )
464
0
                if ( prop.Name == "Password" && ( prop.Value >>= m_aLinkPassword ) )
465
0
                {
466
0
                    m_bLinkHasPassword = true;
467
0
                    break;
468
0
                }
469
0
        }
470
0
    }
471
0
    catch( const uno::Exception& )
472
0
    {
473
0
        if ( xDocument.is() )
474
0
        {
475
0
            try
476
0
            {
477
0
                xDocument->close( true );
478
0
            }
479
0
            catch( const uno::Exception& )
480
0
            {
481
0
            }
482
0
        }
483
484
0
        throw; // TODO
485
0
    }
486
487
0
    return xDocument;
488
489
0
}
490
491
OUString OCommonEmbeddedObject::GetFilterName( sal_Int32 nVersion ) const
492
0
{
493
0
    OUString aFilterName = GetPresetFilterName();
494
0
    if ( aFilterName.isEmpty() )
495
0
    {
496
0
        OUString sDocumentServiceName = GetDocumentServiceName();
497
0
        if (comphelper::IsFuzzing() && nVersion == SOFFICE_FILEFORMAT_CURRENT &&
498
0
            sDocumentServiceName == "com.sun.star.chart2.ChartDocument")
499
0
        {
500
0
            return u"chart8"_ustr;
501
0
        }
502
0
        try {
503
0
            ::comphelper::MimeConfigurationHelper aHelper( m_xContext );
504
0
            aFilterName = aHelper.GetDefaultFilterFromServiceName(sDocumentServiceName, nVersion);
505
506
            // If no filter is found, fall back to the FileFormatVersion=6200 filter, Base only has that.
507
0
            if (aFilterName.isEmpty() && nVersion == SOFFICE_FILEFORMAT_CURRENT)
508
0
                aFilterName = aHelper.GetDefaultFilterFromServiceName(GetDocumentServiceName(), SOFFICE_FILEFORMAT_60);
509
0
        } catch( const uno::Exception& )
510
0
        {}
511
0
    }
512
513
0
    return aFilterName;
514
0
}
515
516
517
void OCommonEmbeddedObject::FillDefaultLoadArgs_Impl( const uno::Reference< embed::XStorage >& i_rxStorage,
518
        ::comphelper::NamedValueCollection& o_rLoadArgs ) const
519
0
{
520
0
    o_rLoadArgs.put( u"DocumentBaseURL"_ustr, GetBaseURL_Impl() );
521
0
    o_rLoadArgs.put( u"HierarchicalDocumentName"_ustr, m_aEntryName );
522
0
    o_rLoadArgs.put( u"ReadOnly"_ustr, m_bReadOnly );
523
524
0
    OUString aFilterName = GetFilterName( ::comphelper::OStorageHelper::GetXStorageFormat( i_rxStorage ) );
525
0
    SAL_WARN_IF( aFilterName.isEmpty(), "embeddedobj.common", "OCommonEmbeddedObject::FillDefaultLoadArgs_Impl: Wrong document service name!" );
526
0
    if ( aFilterName.isEmpty() )
527
0
        throw io::IOException();    // TODO: error message/code
528
529
0
    o_rLoadArgs.put( u"FilterName"_ustr, aFilterName );
530
0
}
531
532
533
uno::Reference< util::XCloseable > OCommonEmbeddedObject::LoadDocumentFromStorage_Impl()
534
0
{
535
0
    ENSURE_OR_THROW( m_xObjectStorage.is(), "no object storage" );
536
537
0
    const uno::Reference< embed::XStorage > xSourceStorage( m_xRecoveryStorage.is() ? m_xRecoveryStorage : m_xObjectStorage );
538
539
0
    uno::Reference< util::XCloseable > xDocument( CreateDocument( m_xContext, GetDocumentServiceName(),
540
0
                                                m_bEmbeddedScriptSupport, m_bDocumentRecoverySupport ) );
541
542
    //#i103460# ODF: take the size given from the parent frame as default
543
0
    uno::Reference< chart2::XChartDocument > xChart( xDocument, uno::UNO_QUERY );
544
0
    if( xChart.is() )
545
0
    {
546
0
        uno::Reference< embed::XVisualObject > xChartVisualObject( xChart, uno::UNO_QUERY );
547
0
        if( xChartVisualObject.is() )
548
0
            xChartVisualObject->setVisualAreaSize( embed::Aspects::MSOLE_CONTENT, m_aDefaultSizeForChart_In_100TH_MM );
549
0
    }
550
551
0
    uno::Reference< frame::XLoadable > xLoadable( xDocument, uno::UNO_QUERY );
552
0
    uno::Reference< document::XStorageBasedDocument > xDoc( xDocument, uno::UNO_QUERY );
553
0
    if ( !xDoc.is() && !xLoadable.is() )
554
0
        throw uno::RuntimeException();
555
556
0
    ::comphelper::NamedValueCollection aLoadArgs;
557
0
    FillDefaultLoadArgs_Impl( xSourceStorage, aLoadArgs );
558
559
0
    uno::Reference< io::XInputStream > xTempInpStream;
560
0
    if ( !xDoc.is() )
561
0
    {
562
0
        xTempInpStream = createTempInpStreamFromStor( xSourceStorage, m_xContext );
563
0
        if ( !xTempInpStream.is() )
564
0
            throw uno::RuntimeException();
565
566
0
        OUString aTempFileURL;
567
0
        try
568
0
        {
569
            // no need to let the file stay after the stream is removed since the embedded document
570
            // can not be stored directly
571
0
            uno::Reference< beans::XPropertySet > xTempStreamProps( xTempInpStream, uno::UNO_QUERY_THROW );
572
0
            xTempStreamProps->getPropertyValue(u"Uri"_ustr) >>= aTempFileURL;
573
0
        }
574
0
        catch( const uno::Exception& )
575
0
        {
576
0
        }
577
578
0
        SAL_WARN_IF( aTempFileURL.isEmpty(), "embeddedobj.common", "Couldn't retrieve temporary file URL!" );
579
580
0
        aLoadArgs.put( u"URL"_ustr, aTempFileURL );
581
0
        aLoadArgs.put( u"InputStream"_ustr, xTempInpStream );
582
0
    }
583
584
585
0
    aLoadArgs.merge( m_aDocMediaDescriptor, true );
586
587
0
    try
588
0
    {
589
        // set the document mode to embedded as the first step!!!
590
0
        EmbedAndReparentDoc_Impl( xDocument );
591
592
0
        if (m_bReadOnly)
593
0
        {
594
0
            aLoadArgs.put(u"ReadOnly"_ustr, true);
595
0
        }
596
597
0
        if ( xDoc.is() )
598
0
        {
599
0
            xDoc->loadFromStorage( xSourceStorage, aLoadArgs.getPropertyValues() );
600
0
            if ( xSourceStorage != m_xObjectStorage )
601
0
                SwitchDocToStorage_Impl( xDoc, m_xObjectStorage );
602
0
        }
603
0
        else
604
0
            xLoadable->load( aLoadArgs.getPropertyValues() );
605
0
    }
606
0
    catch( const uno::Exception& )
607
0
    {
608
0
        if ( xDocument.is() )
609
0
        {
610
0
            try
611
0
            {
612
0
                xDocument->close( true );
613
0
            }
614
0
            catch( const uno::Exception& )
615
0
            {
616
0
                DBG_UNHANDLED_EXCEPTION("embeddedobj.common");
617
0
            }
618
0
        }
619
620
0
        throw; // TODO
621
0
    }
622
623
0
    return xDocument;
624
0
}
625
626
627
uno::Reference< io::XInputStream > OCommonEmbeddedObject::StoreDocumentToTempStream_Impl(
628
                                                                            sal_Int32 nStorageFormat,
629
                                                                            const OUString& aBaseURL,
630
                                                                            const OUString& aHierarchName )
631
0
{
632
0
    uno::Reference < io::XOutputStream > xTempOut(
633
0
                io::TempFile::create(m_xContext),
634
0
                uno::UNO_QUERY_THROW );
635
0
    uno::Reference< io::XInputStream > aResult( xTempOut, uno::UNO_QUERY_THROW );
636
637
0
    uno::Reference< frame::XStorable > xStorable;
638
0
    {
639
0
        osl::MutexGuard aGuard( m_aMutex );
640
0
        if ( m_xDocHolder.is() )
641
0
            xStorable.set( m_xDocHolder->GetComponent(), uno::UNO_QUERY );
642
0
    }
643
644
0
    if( !xStorable.is() )
645
0
        throw uno::RuntimeException(u"No storage is provided for storing!"_ustr); // TODO:
646
647
0
    OUString aFilterName = GetFilterName( nStorageFormat );
648
649
0
    SAL_WARN_IF( aFilterName.isEmpty(), "embeddedobj.common", "Wrong document service name!" );
650
0
    if ( aFilterName.isEmpty() )
651
0
        throw io::IOException(u"No filter name provided / Wrong document service name"_ustr); // TODO:
652
653
0
    uno::Sequence< beans::PropertyValue > aArgs{
654
0
        comphelper::makePropertyValue(u"FilterName"_ustr, aFilterName),
655
0
        comphelper::makePropertyValue(u"OutputStream"_ustr, xTempOut),
656
0
        comphelper::makePropertyValue(u"DocumentBaseURL"_ustr, aBaseURL),
657
0
        comphelper::makePropertyValue(u"HierarchicalDocumentName"_ustr, aHierarchName)
658
0
    };
659
660
0
    xStorable->storeToURL( u"private:stream"_ustr, aArgs );
661
0
    try
662
0
    {
663
0
        xTempOut->closeOutput();
664
0
    }
665
0
    catch( const uno::Exception& )
666
0
    {
667
0
        SAL_WARN( "embeddedobj.common", "Looks like stream was closed already" );
668
0
    }
669
670
0
    return aResult;
671
0
}
672
673
674
void OCommonEmbeddedObject::SaveObject_Impl()
675
0
{
676
0
    if ( !m_xClientSite.is() )
677
0
        return;
678
679
0
    try
680
0
    {
681
        // check whether the component is modified,
682
        // if not there is no need for storing
683
0
        uno::Reference< util::XModifiable > xModifiable( m_xDocHolder->GetComponent(), uno::UNO_QUERY );
684
0
        if ( xModifiable.is() && !xModifiable->isModified() )
685
0
            return;
686
0
    }
687
0
    catch( const uno::Exception& )
688
0
    {}
689
690
0
    try {
691
0
        m_xClientSite->saveObject();
692
0
    }
693
0
    catch( const uno::Exception& )
694
0
    {
695
0
        SAL_WARN( "embeddedobj.common", "The object was not stored!" );
696
0
    }
697
0
}
698
699
700
OUString OCommonEmbeddedObject::GetBaseURL_Impl() const
701
0
{
702
0
    OUString aBaseURL;
703
704
0
    if ( m_xClientSite.is() )
705
0
    {
706
0
        try
707
0
        {
708
0
            uno::Reference< frame::XModel > xParentModel( m_xClientSite->getComponent(), uno::UNO_QUERY_THROW );
709
0
            const uno::Sequence< beans::PropertyValue > aModelProps = xParentModel->getArgs();
710
0
            for ( beans::PropertyValue const & prop : aModelProps )
711
0
                if ( prop.Name == "DocumentBaseURL" )
712
0
                {
713
0
                    prop.Value >>= aBaseURL;
714
0
                    break;
715
0
                }
716
0
        }
717
0
        catch( const uno::Exception& )
718
0
        {}
719
0
    }
720
721
0
    if ( aBaseURL.isEmpty() )
722
0
    {
723
0
        for ( beans::PropertyValue const & prop : m_aDocMediaDescriptor )
724
0
            if ( prop.Name == "DocumentBaseURL" )
725
0
            {
726
0
                prop.Value >>= aBaseURL;
727
0
                break;
728
0
            }
729
0
    }
730
731
0
    if ( aBaseURL.isEmpty() )
732
0
        aBaseURL = m_aDefaultParentBaseURL;
733
734
0
    return aBaseURL;
735
0
}
736
737
738
OUString OCommonEmbeddedObject::GetBaseURLFrom_Impl(
739
                    const uno::Sequence< beans::PropertyValue >& lArguments,
740
                    const uno::Sequence< beans::PropertyValue >& lObjArgs )
741
0
{
742
0
    OUString aBaseURL;
743
744
0
    for ( beans::PropertyValue const & prop : lArguments )
745
0
        if ( prop.Name == "DocumentBaseURL" )
746
0
        {
747
0
            prop.Value >>= aBaseURL;
748
0
            break;
749
0
        }
750
751
0
    if ( aBaseURL.isEmpty() )
752
0
    {
753
0
        for ( beans::PropertyValue const & prop : lObjArgs )
754
0
            if ( prop.Name == "DefaultParentBaseURL" )
755
0
            {
756
0
                prop.Value >>= aBaseURL;
757
0
                break;
758
0
            }
759
0
    }
760
761
0
    return aBaseURL;
762
0
}
763
764
765
void OCommonEmbeddedObject::SwitchDocToStorage_Impl( const uno::Reference< document::XStorageBasedDocument >& xDoc, const uno::Reference< embed::XStorage >& xStorage )
766
0
{
767
0
    xDoc->switchToStorage( xStorage );
768
769
0
    uno::Reference< util::XModifiable > xModif( xDoc, uno::UNO_QUERY );
770
0
    if ( xModif.is() )
771
0
        xModif->setModified( false );
772
773
0
    if ( m_xRecoveryStorage.is() )
774
0
        m_xRecoveryStorage.clear();
775
0
}
776
777
namespace {
778
779
beans::PropertyValue getStringPropertyValue(const uno::Sequence<beans::PropertyValue>& rProps,
780
                                            const OUString& rName)
781
0
{
782
0
    OUString aStr;
783
784
0
    for (beans::PropertyValue const & prop : rProps)
785
0
    {
786
0
        if (prop.Name == rName)
787
0
        {
788
0
            prop.Value >>= aStr;
789
0
            break;
790
0
        }
791
0
    }
792
793
0
    return comphelper::makePropertyValue(rName, aStr);
794
0
}
795
796
}
797
798
void OCommonEmbeddedObject::StoreDocToStorage_Impl(
799
    const uno::Reference<embed::XStorage>& xStorage,
800
    const uno::Sequence<beans::PropertyValue>& rMediaArgs,
801
    const uno::Sequence<beans::PropertyValue>& rObjArgs,
802
    sal_Int32 nStorageFormat,
803
    const OUString& aHierarchName,
804
    bool bAttachToTheStorage )
805
0
{
806
0
    SAL_WARN_IF( !xStorage.is(), "embeddedobj.common", "No storage is provided for storing!" );
807
808
0
    if ( !xStorage.is() )
809
0
        throw uno::RuntimeException(); // TODO:
810
811
0
    uno::Reference< document::XStorageBasedDocument > xDoc;
812
0
    {
813
0
        osl::MutexGuard aGuard( m_aMutex );
814
0
        if ( m_xDocHolder.is() )
815
0
            xDoc.set( m_xDocHolder->GetComponent(), uno::UNO_QUERY );
816
0
    }
817
818
0
    OUString aBaseURL = GetBaseURLFrom_Impl(rMediaArgs, rObjArgs);
819
820
0
    if ( xDoc.is() )
821
0
    {
822
0
        OUString aFilterName = GetFilterName( nStorageFormat );
823
824
        // No filter found? Try the older format, e.g. Base has only that.
825
0
        if (aFilterName.isEmpty() && nStorageFormat == SOFFICE_FILEFORMAT_CURRENT)
826
0
            aFilterName = GetFilterName( SOFFICE_FILEFORMAT_60 );
827
828
0
        SAL_WARN_IF( aFilterName.isEmpty(), "embeddedobj.common", "Wrong document service name!" );
829
0
        if ( aFilterName.isEmpty() )
830
0
            throw io::IOException(); // TODO:
831
832
0
        uno::Sequence<beans::PropertyValue> aArgs{
833
0
            comphelper::makePropertyValue(u"FilterName"_ustr, aFilterName),
834
0
            comphelper::makePropertyValue(u"HierarchicalDocumentName"_ustr, aHierarchName),
835
0
            comphelper::makePropertyValue(u"DocumentBaseURL"_ustr, aBaseURL),
836
0
            getStringPropertyValue(rObjArgs, u"SourceShellID"_ustr),
837
0
            getStringPropertyValue(rObjArgs, u"DestinationShellID"_ustr),
838
0
        };
839
840
0
        xDoc->storeToStorage( xStorage, aArgs );
841
0
        if ( bAttachToTheStorage )
842
0
            SwitchDocToStorage_Impl( xDoc, xStorage );
843
0
    }
844
0
    else
845
0
    {
846
        // store document to temporary stream based on temporary file
847
0
        uno::Reference < io::XInputStream > xTempIn = StoreDocumentToTempStream_Impl( nStorageFormat, aBaseURL, aHierarchName );
848
849
0
        SAL_WARN_IF( !xTempIn.is(), "embeddedobj.common", "The stream reference can not be empty!" );
850
851
        // open storage based on document temporary file for reading
852
0
        uno::Reference < lang::XSingleServiceFactory > xStorageFactory = embed::StorageFactory::create(m_xContext);
853
854
0
        uno::Sequence< uno::Any > aArgs{ uno::Any(xTempIn) };
855
0
        uno::Reference< embed::XStorage > xTempStorage( xStorageFactory->createInstanceWithArguments( aArgs ),
856
0
                                                            uno::UNO_QUERY_THROW );
857
858
        // object storage must be committed automatically
859
0
        xTempStorage->copyToStorage( xStorage );
860
0
    }
861
0
}
862
863
864
uno::Reference< util::XCloseable > OCommonEmbeddedObject::CreateDocFromMediaDescr_Impl(
865
                                        const uno::Sequence< beans::PropertyValue >& aMedDescr )
866
0
{
867
0
    uno::Reference< util::XCloseable > xDocument( CreateDocument( m_xContext, GetDocumentServiceName(),
868
0
                                                m_bEmbeddedScriptSupport, m_bDocumentRecoverySupport ) );
869
870
0
    uno::Reference< frame::XLoadable > xLoadable( xDocument, uno::UNO_QUERY_THROW );
871
872
0
    try
873
0
    {
874
        // set the document mode to embedded as the first action on the document!!!
875
0
        EmbedAndReparentDoc_Impl( xDocument );
876
877
0
        xLoadable->load( addAsTemplate( aMedDescr ) );
878
0
    }
879
0
    catch( const uno::Exception& )
880
0
    {
881
0
        if ( xDocument.is() )
882
0
        {
883
0
            try
884
0
            {
885
0
                xDocument->close( true );
886
0
            }
887
0
            catch( const uno::Exception& )
888
0
            {
889
0
            }
890
0
        }
891
892
0
        throw; // TODO
893
0
    }
894
895
0
    return xDocument;
896
0
}
897
898
899
uno::Reference< util::XCloseable > OCommonEmbeddedObject::CreateTempDocFromLink_Impl()
900
0
{
901
0
    uno::Reference< util::XCloseable > xResult;
902
903
0
    SAL_WARN_IF( !m_bIsLinkURL, "embeddedobj.common", "The object is not a linked one!" );
904
905
0
    uno::Sequence< beans::PropertyValue > aTempMediaDescr;
906
907
0
    sal_Int32 nStorageFormat = SOFFICE_FILEFORMAT_CURRENT;
908
0
    try {
909
0
        nStorageFormat = ::comphelper::OStorageHelper::GetXStorageFormat( m_xParentStorage );
910
0
    }
911
0
    catch ( const beans::IllegalTypeException& )
912
0
    {
913
        // the container just has an unknown type, use current file format
914
0
    }
915
0
    catch ( const uno::Exception& )
916
0
    {
917
0
        SAL_WARN( "embeddedobj.common", "Can not retrieve storage media type!" );
918
0
    }
919
920
0
    if ( m_xDocHolder->GetComponent().is() )
921
0
    {
922
0
        aTempMediaDescr.realloc( 4 );
923
924
        // TODO/LATER: may be private:stream should be used as target URL
925
0
        OUString aTempFileURL;
926
0
        uno::Reference< io::XInputStream > xTempStream = StoreDocumentToTempStream_Impl( SOFFICE_FILEFORMAT_CURRENT,
927
0
                                                                                         OUString(),
928
0
                                                                                         OUString() );
929
0
        try
930
0
        {
931
            // no need to let the file stay after the stream is removed since the embedded document
932
            // can not be stored directly
933
0
            uno::Reference< beans::XPropertySet > xTempStreamProps( xTempStream, uno::UNO_QUERY_THROW );
934
0
            xTempStreamProps->getPropertyValue(u"Uri"_ustr) >>= aTempFileURL;
935
0
        }
936
0
        catch( const uno::Exception& )
937
0
        {
938
0
        }
939
940
0
        SAL_WARN_IF( aTempFileURL.isEmpty(), "embeddedobj.common", "Couldn't retrieve temporary file URL!" );
941
942
0
        aTempMediaDescr
943
0
            = { comphelper::makePropertyValue(u"URL"_ustr, aTempFileURL),
944
0
                comphelper::makePropertyValue(u"InputStream"_ustr, xTempStream),
945
0
                comphelper::makePropertyValue(u"FilterName"_ustr, GetFilterName( nStorageFormat )),
946
0
                comphelper::makePropertyValue(u"AsTemplate"_ustr, true) };
947
0
    }
948
0
    else
949
0
    {
950
0
        aTempMediaDescr = { comphelper::makePropertyValue(
951
0
                                u"URL"_ustr,
952
                                // tdf#141529 use URL of the linked TempFile if it exists
953
0
                                m_aLinkTempFile.is() ? m_aLinkTempFile->getUri() : m_aLinkURL),
954
0
                            comphelper::makePropertyValue(u"FilterName"_ustr, m_aLinkFilterName) };
955
0
    }
956
957
0
    xResult = CreateDocFromMediaDescr_Impl( aTempMediaDescr );
958
959
0
    return xResult;
960
0
}
961
962
963
void SAL_CALL OCommonEmbeddedObject::setPersistentEntry(
964
                    const uno::Reference< embed::XStorage >& xStorage,
965
                    const OUString& sEntName,
966
                    sal_Int32 nEntryConnectionMode,
967
                    const uno::Sequence< beans::PropertyValue >& lArguments,
968
                    const uno::Sequence< beans::PropertyValue >& lObjArgs )
969
0
{
970
    // the type of the object must be already set
971
    // a kind of typedetection should be done in the factory
972
973
0
    ::osl::MutexGuard aGuard( m_aMutex );
974
0
    if ( m_bDisposed )
975
0
        throw lang::DisposedException(); // TODO
976
977
0
    if ( !xStorage.is() )
978
0
        throw lang::IllegalArgumentException( u"No parent storage is provided!"_ustr,
979
0
                                            static_cast< ::cppu::OWeakObject* >(this),
980
0
                                            1 );
981
982
0
    if ( sEntName.isEmpty() )
983
0
        throw lang::IllegalArgumentException( u"Empty element name is provided!"_ustr,
984
0
                                            static_cast< ::cppu::OWeakObject* >(this),
985
0
                                            2 );
986
987
    // May be LOADED should be forbidden here ???
988
0
    if ( ( m_nObjectState != -1 || nEntryConnectionMode == embed::EntryInitModes::NO_INIT )
989
0
      && ( m_nObjectState == -1 || nEntryConnectionMode != embed::EntryInitModes::NO_INIT ) )
990
0
    {
991
        // if the object is not loaded
992
        // it can not get persistent representation without initialization
993
994
        // if the object is loaded
995
        // it can switch persistent representation only without initialization
996
997
0
        throw embed::WrongStateException(
998
0
                    u"Can't change persistent representation of activated object!"_ustr,
999
0
                     static_cast< ::cppu::OWeakObject* >(this) );
1000
0
    }
1001
1002
0
    if ( m_bWaitSaveCompleted )
1003
0
    {
1004
0
        if ( nEntryConnectionMode != embed::EntryInitModes::NO_INIT )
1005
0
            throw embed::WrongStateException(
1006
0
                        u"The object waits for saveCompleted() call!"_ustr,
1007
0
                        static_cast< ::cppu::OWeakObject* >(this) );
1008
        // saveCompleted is expected, handle it accordingly
1009
0
        if ( m_xNewParentStorage == xStorage && m_aNewEntryName == sEntName )
1010
0
        {
1011
0
            saveCompleted( true );
1012
0
            return;
1013
0
        }
1014
1015
        // if a completely different entry is provided, switch first back to the old persistence in saveCompleted
1016
        // and then switch to the target persistence
1017
0
        bool bSwitchFurther = ( m_xParentStorage != xStorage || m_aEntryName != sEntName );
1018
0
        saveCompleted( false );
1019
0
        if ( !bSwitchFurther )
1020
0
            return;
1021
0
    }
1022
1023
    // for now support of this interface is required to allow breaking of links and converting them to normal embedded
1024
    // objects, so the persist name must be handled correctly ( althowgh no real persist entry is used )
1025
    // OSL_ENSURE( !m_bIsLinkURL, "This method implementation must not be used for links!" );
1026
0
    if ( m_bIsLinkURL )
1027
0
    {
1028
0
        m_aEntryName = sEntName;
1029
0
        return;
1030
0
    }
1031
1032
0
    uno::Reference< container::XNameAccess > xNameAccess( xStorage, uno::UNO_QUERY_THROW );
1033
1034
    // detect entry existence
1035
0
    bool bElExists = xNameAccess->hasByName( sEntName );
1036
1037
0
    m_aDocMediaDescriptor = GetValuableArgs_Impl( lArguments,
1038
0
                                                  nEntryConnectionMode != embed::EntryInitModes::MEDIA_DESCRIPTOR_INIT );
1039
1040
0
    m_bReadOnly = false;
1041
0
    for ( beans::PropertyValue const & prop : lArguments )
1042
0
        if ( prop.Name == "ReadOnly" )
1043
0
            prop.Value >>= m_bReadOnly;
1044
1045
    // TODO: use lObjArgs for StoreVisualReplacement
1046
0
    for ( beans::PropertyValue const & prop : lObjArgs )
1047
0
        if ( prop.Name == "OutplaceDispatchInterceptor" )
1048
0
        {
1049
0
            uno::Reference< frame::XDispatchProviderInterceptor > xDispatchInterceptor;
1050
0
            if ( prop.Value >>= xDispatchInterceptor )
1051
0
                m_xDocHolder->SetOutplaceDispatchInterceptor( xDispatchInterceptor );
1052
0
        }
1053
0
        else if ( prop.Name == "DefaultParentBaseURL" )
1054
0
        {
1055
0
            prop.Value >>= m_aDefaultParentBaseURL;
1056
0
        }
1057
0
        else if ( prop.Name == "Parent" )
1058
0
        {
1059
0
            prop.Value >>= m_xParent;
1060
0
        }
1061
0
        else if ( prop.Name == "IndividualMiscStatus" )
1062
0
        {
1063
0
            sal_Int64 nMiscStatus=0;
1064
0
            prop.Value >>= nMiscStatus;
1065
0
            m_nMiscStatus |= nMiscStatus;
1066
0
        }
1067
0
        else if ( prop.Name == "CloneFrom" )
1068
0
        {
1069
0
            uno::Reference < embed::XEmbeddedObject > xObj;
1070
0
            prop.Value >>= xObj;
1071
0
            if ( xObj.is() )
1072
0
            {
1073
0
                m_bHasClonedSize = true;
1074
0
                m_aClonedSize = xObj->getVisualAreaSize( embed::Aspects::MSOLE_CONTENT );
1075
0
                m_nClonedMapUnit = xObj->getMapUnit( embed::Aspects::MSOLE_CONTENT );
1076
0
            }
1077
0
        }
1078
0
        else if ( prop.Name == "OutplaceFrameProperties" )
1079
0
        {
1080
0
            uno::Sequence< uno::Any > aOutFrameProps;
1081
0
            uno::Sequence< beans::NamedValue > aOutFramePropsTyped;
1082
0
            if ( prop.Value >>= aOutFrameProps )
1083
0
            {
1084
0
                m_xDocHolder->SetOutplaceFrameProperties( aOutFrameProps );
1085
0
            }
1086
0
            else if ( prop.Value >>= aOutFramePropsTyped )
1087
0
            {
1088
0
                aOutFrameProps.realloc( aOutFramePropsTyped.getLength() );
1089
0
                uno::Any* pProp = aOutFrameProps.getArray();
1090
0
                for (   const beans::NamedValue* pTypedProp = aOutFramePropsTyped.getConstArray();
1091
0
                        pTypedProp != aOutFramePropsTyped.getConstArray() + aOutFramePropsTyped.getLength();
1092
0
                        ++pTypedProp, ++pProp
1093
0
                    )
1094
0
                {
1095
0
                    *pProp <<= *pTypedProp;
1096
0
                }
1097
0
                m_xDocHolder->SetOutplaceFrameProperties( aOutFrameProps );
1098
0
            }
1099
0
            else
1100
0
                SAL_WARN( "embeddedobj.common", "OCommonEmbeddedObject::setPersistentEntry: illegal type for argument 'OutplaceFrameProperties'!" );
1101
0
        }
1102
0
        else if ( prop.Name == "ModuleName" )
1103
0
        {
1104
0
            prop.Value >>= m_aModuleName;
1105
0
        }
1106
0
        else if ( prop.Name == "EmbeddedScriptSupport" )
1107
0
        {
1108
0
            OSL_VERIFY( prop.Value >>= m_bEmbeddedScriptSupport );
1109
0
        }
1110
0
        else if ( prop.Name == "DocumentRecoverySupport" )
1111
0
        {
1112
0
            OSL_VERIFY( prop.Value >>= m_bDocumentRecoverySupport );
1113
0
        }
1114
0
        else if ( prop.Name == "RecoveryStorage" )
1115
0
        {
1116
0
            OSL_VERIFY( prop.Value >>= m_xRecoveryStorage );
1117
0
        }
1118
1119
1120
0
    sal_Int32 nStorageMode = m_bReadOnly ? embed::ElementModes::READ : embed::ElementModes::READWRITE;
1121
1122
0
    SwitchOwnPersistence( xStorage, sEntName );
1123
1124
0
    if ( nEntryConnectionMode == embed::EntryInitModes::DEFAULT_INIT )
1125
0
    {
1126
0
        if ( bElExists )
1127
0
        {
1128
            // the initialization from existing storage allows to leave object in loaded state
1129
0
            m_nObjectState = embed::EmbedStates::LOADED;
1130
0
        }
1131
0
        else
1132
0
        {
1133
0
            m_xDocHolder->SetComponent( InitNewDocument_Impl(), m_bReadOnly );
1134
0
            if ( !m_xDocHolder->GetComponent().is() )
1135
0
                throw io::IOException(); // TODO: can not create document
1136
1137
0
            m_nObjectState = embed::EmbedStates::RUNNING;
1138
0
        }
1139
0
    }
1140
0
    else
1141
0
    {
1142
0
        if ( ( nStorageMode & embed::ElementModes::READWRITE ) != embed::ElementModes::READWRITE )
1143
0
            throw io::IOException();
1144
1145
0
        if ( nEntryConnectionMode == embed::EntryInitModes::NO_INIT )
1146
0
        {
1147
            // the document just already changed its storage to store to
1148
            // the links to OOo documents for now ignore this call
1149
            // TODO: OOo links will have persistence so it will be switched here
1150
0
        }
1151
0
        else if ( nEntryConnectionMode == embed::EntryInitModes::TRUNCATE_INIT )
1152
0
        {
1153
0
            if ( m_xRecoveryStorage.is() )
1154
0
                TransferMediaType( m_xRecoveryStorage, m_xObjectStorage );
1155
1156
            // TODO:
1157
0
            m_xDocHolder->SetComponent( InitNewDocument_Impl(), m_bReadOnly );
1158
1159
0
            if ( !m_xDocHolder->GetComponent().is() )
1160
0
                throw io::IOException(); // TODO: can not create document
1161
1162
0
            m_nObjectState = embed::EmbedStates::RUNNING;
1163
0
        }
1164
0
        else if ( nEntryConnectionMode == embed::EntryInitModes::MEDIA_DESCRIPTOR_INIT )
1165
0
        {
1166
0
            m_xDocHolder->SetComponent( CreateDocFromMediaDescr_Impl( lArguments ), m_bReadOnly );
1167
0
            m_nObjectState = embed::EmbedStates::RUNNING;
1168
0
        }
1169
        //else if ( nEntryConnectionMode == embed::EntryInitModes::TRANSFERABLE_INIT )
1170
        //{
1171
            //TODO:
1172
        //}
1173
0
        else
1174
0
            throw lang::IllegalArgumentException( u"Wrong connection mode is provided!"_ustr,
1175
0
                                        static_cast< ::cppu::OWeakObject* >(this),
1176
0
                                        3 );
1177
0
    }
1178
0
}
1179
1180
1181
void SAL_CALL OCommonEmbeddedObject::storeToEntry( const uno::Reference< embed::XStorage >& xStorage,
1182
                            const OUString& sEntName,
1183
                            const uno::Sequence< beans::PropertyValue >& lArguments,
1184
                            const uno::Sequence< beans::PropertyValue >& lObjArgs )
1185
0
{
1186
0
    ::osl::ResettableMutexGuard aGuard( m_aMutex );
1187
0
    if ( m_bDisposed )
1188
0
        throw lang::DisposedException(); // TODO
1189
1190
0
    if ( m_nObjectState == -1 )
1191
0
    {
1192
        // the object is still not loaded
1193
0
        throw embed::WrongStateException( u"Can't store object without persistence!"_ustr,
1194
0
                                        static_cast< ::cppu::OWeakObject* >(this) );
1195
0
    }
1196
1197
0
    if ( m_bWaitSaveCompleted )
1198
0
        throw embed::WrongStateException(
1199
0
                    u"The object waits for saveCompleted() call!"_ustr,
1200
0
                    static_cast< ::cppu::OWeakObject* >(this) );
1201
1202
    // for now support of this interface is required to allow breaking of links and converting them to normal embedded
1203
    // objects, so the persist name must be handled correctly ( althowgh no real persist entry is used )
1204
    // OSL_ENSURE( !m_bIsLinkURL, "This method implementation must not be used for links!" );
1205
0
    if ( m_bIsLinkURL )
1206
0
        return;
1207
1208
0
    OSL_ENSURE( m_xParentStorage.is() && m_xObjectStorage.is(), "The object has no valid persistence!" );
1209
1210
0
    sal_Int32 nTargetStorageFormat = SOFFICE_FILEFORMAT_CURRENT;
1211
0
    sal_Int32 nOriginalStorageFormat = SOFFICE_FILEFORMAT_CURRENT;
1212
0
    try {
1213
0
        nTargetStorageFormat = ::comphelper::OStorageHelper::GetXStorageFormat( xStorage );
1214
0
    }
1215
0
    catch ( const beans::IllegalTypeException& )
1216
0
    {
1217
        // the container just has an unknown type, use current file format
1218
0
    }
1219
0
    catch ( const uno::Exception& )
1220
0
    {
1221
0
        SAL_WARN( "embeddedobj.common", "Can not retrieve target storage media type!" );
1222
0
    }
1223
0
    if (nTargetStorageFormat == SOFFICE_FILEFORMAT_60)
1224
0
    {
1225
0
        SAL_INFO("embeddedobj.common", "fdo#78159: Storing OOoXML as ODF");
1226
0
        nTargetStorageFormat = SOFFICE_FILEFORMAT_CURRENT;
1227
        // setting MediaType is done later anyway, no need to do it here
1228
0
    }
1229
1230
0
    try
1231
0
    {
1232
0
        nOriginalStorageFormat = ::comphelper::OStorageHelper::GetXStorageFormat( m_xParentStorage );
1233
0
    }
1234
0
    catch ( const beans::IllegalTypeException& )
1235
0
    {
1236
        // the container just has an unknown type, use current file format
1237
0
    }
1238
0
    catch ( const uno::Exception& )
1239
0
    {
1240
0
        SAL_WARN( "embeddedobj.common", "Can not retrieve own storage media type!" );
1241
0
    }
1242
1243
0
    bool bTryOptimization = false;
1244
0
    for ( beans::PropertyValue const & prop : lObjArgs )
1245
0
    {
1246
        // StoreVisualReplacement and VisualReplacement args have no sense here
1247
0
        if ( prop.Name == "CanTryOptimization" )
1248
0
            prop.Value >>= bTryOptimization;
1249
0
    }
1250
1251
0
    bool bSwitchBackToLoaded = false;
1252
1253
    // Storing to different format can be done only in running state.
1254
0
    if ( m_nObjectState == embed::EmbedStates::LOADED )
1255
0
    {
1256
        // TODO/LATER: copying is not legal for documents with relative links.
1257
0
        if ( nTargetStorageFormat == nOriginalStorageFormat )
1258
0
        {
1259
0
            bool bOptimizationWorks = false;
1260
0
            if ( bTryOptimization )
1261
0
            {
1262
0
                try
1263
0
                {
1264
                    // try to use optimized copying
1265
0
                    uno::Reference< embed::XOptimizedStorage > xSource( m_xParentStorage, uno::UNO_QUERY_THROW );
1266
0
                    uno::Reference< embed::XOptimizedStorage > xTarget( xStorage, uno::UNO_QUERY_THROW );
1267
0
                    xSource->copyElementDirectlyTo( m_aEntryName, xTarget, sEntName );
1268
0
                    bOptimizationWorks = true;
1269
0
                }
1270
0
                catch( const uno::Exception& )
1271
0
                {
1272
0
                }
1273
0
            }
1274
1275
0
            if ( !bOptimizationWorks )
1276
0
                m_xParentStorage->copyElementTo( m_aEntryName, xStorage, sEntName );
1277
0
        }
1278
0
        else
1279
0
        {
1280
0
            changeState( embed::EmbedStates::RUNNING );
1281
0
            bSwitchBackToLoaded = true;
1282
0
        }
1283
0
    }
1284
1285
0
    if ( m_nObjectState == embed::EmbedStates::LOADED )
1286
0
        return;
1287
1288
0
    uno::Reference< embed::XStorage > xSubStorage =
1289
0
                xStorage->openStorageElement( sEntName, embed::ElementModes::READWRITE );
1290
1291
0
    if ( !xSubStorage.is() )
1292
0
        throw uno::RuntimeException(); //TODO
1293
1294
0
    aGuard.clear();
1295
    // TODO/LATER: support hierarchical name for embedded objects in embedded objects
1296
0
    StoreDocToStorage_Impl(
1297
0
        xSubStorage, lArguments, lObjArgs, nTargetStorageFormat, sEntName, false );
1298
0
    aGuard.reset();
1299
1300
0
    if ( bSwitchBackToLoaded )
1301
0
        changeState( embed::EmbedStates::LOADED );
1302
1303
    // TODO: should the listener notification be done?
1304
0
}
1305
1306
1307
void SAL_CALL OCommonEmbeddedObject::storeAsEntry( const uno::Reference< embed::XStorage >& xStorage,
1308
                            const OUString& sEntName,
1309
                            const uno::Sequence< beans::PropertyValue >& lArguments,
1310
                            const uno::Sequence< beans::PropertyValue >& lObjArgs )
1311
0
{
1312
0
    ::osl::ResettableMutexGuard aGuard( m_aMutex );
1313
0
    if ( m_bDisposed )
1314
0
        throw lang::DisposedException(); // TODO
1315
1316
0
    bool AutoSaveEvent = false;
1317
0
    utl::MediaDescriptor lArgs(lObjArgs);
1318
0
    lArgs[utl::MediaDescriptor::PROP_AUTOSAVEEVENT] >>= AutoSaveEvent;
1319
1320
0
    if ( m_nObjectState == -1 )
1321
0
    {
1322
        // the object is still not loaded
1323
0
        throw embed::WrongStateException( u"Can't store object without persistence!"_ustr,
1324
0
                                        static_cast< ::cppu::OWeakObject* >(this) );
1325
0
    }
1326
1327
0
    if ( m_bWaitSaveCompleted )
1328
0
        throw embed::WrongStateException(
1329
0
                    u"The object waits for saveCompleted() call!"_ustr,
1330
0
                    static_cast< ::cppu::OWeakObject* >(this) );
1331
1332
    // for now support of this interface is required to allow breaking of links and converting them to normal embedded
1333
    // objects, so the persist name must be handled correctly ( althowgh no real persist entry is used )
1334
    // OSL_ENSURE( !m_bIsLinkURL, "This method implementation must not be used for links!" );
1335
0
    if ( m_bIsLinkURL )
1336
0
    {
1337
0
        m_aNewEntryName = sEntName;
1338
1339
0
        if ( !AutoSaveEvent )
1340
0
            handleLinkedOLE(CopyBackToOLELink::CopyTempToLink);
1341
1342
0
        return;
1343
0
    }
1344
1345
0
    OSL_ENSURE( m_xParentStorage.is() && m_xObjectStorage.is(), "The object has no valid persistence!" );
1346
1347
0
    sal_Int32 nTargetStorageFormat = SOFFICE_FILEFORMAT_CURRENT;
1348
0
    sal_Int32 nOriginalStorageFormat = SOFFICE_FILEFORMAT_CURRENT;
1349
0
    try {
1350
0
        nTargetStorageFormat = ::comphelper::OStorageHelper::GetXStorageFormat( xStorage );
1351
0
    }
1352
0
    catch ( const beans::IllegalTypeException& )
1353
0
    {
1354
        // the container just has an unknown type, use current file format
1355
0
    }
1356
0
    catch ( const uno::Exception& )
1357
0
    {
1358
0
        SAL_WARN( "embeddedobj.common", "Can not retrieve target storage media type!" );
1359
0
    }
1360
0
    if (nTargetStorageFormat == SOFFICE_FILEFORMAT_60)
1361
0
    {
1362
0
        SAL_INFO("embeddedobj.common", "fdo#78159: Storing OOoXML as ODF");
1363
0
        nTargetStorageFormat = SOFFICE_FILEFORMAT_CURRENT;
1364
        // setting MediaType is done later anyway, no need to do it here
1365
0
    }
1366
1367
0
    try
1368
0
    {
1369
0
        nOriginalStorageFormat = ::comphelper::OStorageHelper::GetXStorageFormat( m_xParentStorage );
1370
0
    }
1371
0
    catch ( const beans::IllegalTypeException& )
1372
0
    {
1373
        // the container just has an unknown type, use current file format
1374
0
    }
1375
0
    catch ( const uno::Exception& )
1376
0
    {
1377
0
        SAL_WARN( "embeddedobj.common", "Can not retrieve own storage media type!" );
1378
0
    }
1379
1380
0
    PostEvent_Impl( u"OnSaveAs"_ustr );
1381
1382
0
    bool bTryOptimization = false;
1383
0
    for ( beans::PropertyValue const & prop : lObjArgs )
1384
0
    {
1385
        // StoreVisualReplacement and VisualReplacement args have no sense here
1386
0
        if ( prop.Name == "CanTryOptimization" )
1387
0
            prop.Value >>= bTryOptimization;
1388
0
    }
1389
1390
0
    bool bSwitchBackToLoaded = false;
1391
1392
    // Storing to different format can be done only in running state.
1393
0
    if ( m_nObjectState == embed::EmbedStates::LOADED )
1394
0
    {
1395
        // TODO/LATER: copying is not legal for documents with relative links.
1396
0
        if ( nTargetStorageFormat == nOriginalStorageFormat )
1397
0
        {
1398
0
            bool bOptimizationWorks = false;
1399
0
            if ( bTryOptimization )
1400
0
            {
1401
0
                try
1402
0
                {
1403
                    // try to use optimized copying
1404
0
                    uno::Reference< embed::XOptimizedStorage > xSource( m_xParentStorage, uno::UNO_QUERY_THROW );
1405
0
                    uno::Reference< embed::XOptimizedStorage > xTarget( xStorage, uno::UNO_QUERY_THROW );
1406
0
                    xSource->copyElementDirectlyTo( m_aEntryName, xTarget, sEntName );
1407
0
                    bOptimizationWorks = true;
1408
0
                }
1409
0
                catch( const uno::Exception& )
1410
0
                {
1411
0
                }
1412
0
            }
1413
1414
0
            if ( !bOptimizationWorks )
1415
0
                m_xParentStorage->copyElementTo( m_aEntryName, xStorage, sEntName );
1416
0
        }
1417
0
        else
1418
0
        {
1419
0
            changeState( embed::EmbedStates::RUNNING );
1420
0
            bSwitchBackToLoaded = true;
1421
0
        }
1422
0
    }
1423
1424
0
    uno::Reference< embed::XStorage > xSubStorage =
1425
0
                xStorage->openStorageElement( sEntName, embed::ElementModes::READWRITE );
1426
1427
0
    if ( !xSubStorage.is() )
1428
0
        throw uno::RuntimeException(); //TODO
1429
1430
0
    if ( m_nObjectState != embed::EmbedStates::LOADED )
1431
0
    {
1432
0
        aGuard.clear();
1433
        // TODO/LATER: support hierarchical name for embedded objects in embedded objects
1434
0
        StoreDocToStorage_Impl(
1435
0
            xSubStorage, lArguments, lObjArgs, nTargetStorageFormat, sEntName, false );
1436
0
        aGuard.reset();
1437
1438
0
        if ( bSwitchBackToLoaded )
1439
0
            changeState( embed::EmbedStates::LOADED );
1440
0
    }
1441
1442
0
    m_bWaitSaveCompleted = true;
1443
0
    m_xNewObjectStorage = std::move(xSubStorage);
1444
0
    m_xNewParentStorage = xStorage;
1445
0
    m_aNewEntryName = sEntName;
1446
0
    m_aNewDocMediaDescriptor = GetValuableArgs_Impl( lArguments, true );
1447
1448
    // TODO: register listeners for storages above, in case they are disposed
1449
    //       an exception will be thrown on saveCompleted( true )
1450
1451
    // TODO: should the listener notification be done here or in saveCompleted?
1452
0
}
1453
1454
1455
void SAL_CALL OCommonEmbeddedObject::saveCompleted( sal_Bool bUseNew )
1456
0
{
1457
0
    ::osl::MutexGuard aGuard( m_aMutex );
1458
0
    if ( m_bDisposed )
1459
0
        throw lang::DisposedException(); // TODO
1460
1461
0
    if ( m_nObjectState == -1 )
1462
0
    {
1463
        // the object is still not loaded
1464
0
        throw embed::WrongStateException( u"Can't store object without persistence!"_ustr,
1465
0
                                        static_cast< ::cppu::OWeakObject* >(this) );
1466
0
    }
1467
1468
    // for now support of this interface is required to allow breaking of links and converting them to normal embedded
1469
    // objects, so the persist name must be handled correctly ( althowgh no real persist entry is used )
1470
    // OSL_ENSURE( !m_bIsLinkURL, "This method implementation must not be used for links!" );
1471
0
    if ( m_bIsLinkURL )
1472
0
    {
1473
0
        if ( bUseNew )
1474
0
            m_aEntryName = m_aNewEntryName;
1475
0
        m_aNewEntryName.clear();
1476
0
        return;
1477
0
    }
1478
1479
    // it is allowed to call saveCompleted( false ) for nonstored objects
1480
0
    if ( !m_bWaitSaveCompleted && !bUseNew )
1481
0
        return;
1482
1483
0
    SAL_WARN_IF( !m_bWaitSaveCompleted, "embeddedobj.common", "Unexpected saveCompleted() call!" );
1484
0
    if ( !m_bWaitSaveCompleted )
1485
0
        throw io::IOException(); // TODO: illegal call
1486
1487
0
    OSL_ENSURE( m_xNewObjectStorage.is() && m_xNewParentStorage.is() , "Internal object information is broken!" );
1488
0
    if ( !m_xNewObjectStorage.is() || !m_xNewParentStorage.is() )
1489
0
        throw uno::RuntimeException(); // TODO: broken internal information
1490
1491
0
    if ( bUseNew )
1492
0
    {
1493
0
        SwitchOwnPersistence( m_xNewParentStorage, m_xNewObjectStorage, m_aNewEntryName );
1494
0
        m_aDocMediaDescriptor = m_aNewDocMediaDescriptor;
1495
1496
0
        uno::Reference< util::XModifiable > xModif( m_xDocHolder->GetComponent(), uno::UNO_QUERY );
1497
0
        if ( xModif.is() )
1498
0
            xModif->setModified( false );
1499
1500
0
        PostEvent_Impl( u"OnSaveAsDone"_ustr);
1501
0
    }
1502
0
    else
1503
0
    {
1504
0
        try {
1505
0
            m_xNewObjectStorage->dispose();
1506
0
        }
1507
0
        catch ( const uno::Exception& )
1508
0
        {
1509
0
        }
1510
0
    }
1511
1512
0
    m_xNewObjectStorage.clear();
1513
0
    m_xNewParentStorage.clear();
1514
0
    m_aNewEntryName.clear();
1515
0
    m_aNewDocMediaDescriptor.realloc( 0 );
1516
0
    m_bWaitSaveCompleted = false;
1517
1518
0
    if ( bUseNew )
1519
0
    {
1520
        // TODO: notify listeners
1521
1522
0
        if ( m_nUpdateMode == embed::EmbedUpdateModes::ALWAYS_UPDATE )
1523
0
        {
1524
            // TODO: update visual representation
1525
0
        }
1526
0
    }
1527
0
}
1528
1529
1530
sal_Bool SAL_CALL OCommonEmbeddedObject::hasEntry()
1531
0
{
1532
0
    ::osl::MutexGuard aGuard( m_aMutex );
1533
0
    if ( m_bDisposed )
1534
0
        throw lang::DisposedException(); // TODO
1535
1536
0
    if ( m_bWaitSaveCompleted )
1537
0
        throw embed::WrongStateException(
1538
0
                    u"The object waits for saveCompleted() call!"_ustr,
1539
0
                    static_cast< ::cppu::OWeakObject* >(this) );
1540
1541
0
    if ( m_xObjectStorage.is() )
1542
0
        return true;
1543
1544
0
    return false;
1545
0
}
1546
1547
1548
OUString SAL_CALL OCommonEmbeddedObject::getEntryName()
1549
0
{
1550
0
    ::osl::MutexGuard aGuard( m_aMutex );
1551
0
    if ( m_bDisposed )
1552
0
        throw lang::DisposedException(); // TODO
1553
1554
0
    if ( m_nObjectState == -1 )
1555
0
    {
1556
        // the object is still not loaded
1557
0
        throw embed::WrongStateException( u"The object persistence is not initialized!"_ustr,
1558
0
                                        static_cast< ::cppu::OWeakObject* >(this) );
1559
0
    }
1560
1561
0
    if ( m_bWaitSaveCompleted )
1562
0
        throw embed::WrongStateException(
1563
0
                    u"The object waits for saveCompleted() call!"_ustr,
1564
0
                    static_cast< ::cppu::OWeakObject* >(this) );
1565
1566
0
    return m_aEntryName;
1567
0
}
1568
1569
1570
void SAL_CALL OCommonEmbeddedObject::storeOwn()
1571
0
{
1572
    // during switching from Activated to Running and from Running to Loaded states the object will
1573
    // ask container to store the object, the container has to make decision
1574
    // to do so or not
1575
1576
0
    ::osl::ResettableMutexGuard aGuard( m_aMutex );
1577
0
    if ( m_bDisposed )
1578
0
        throw lang::DisposedException(); // TODO
1579
1580
0
    if ( m_nObjectState == -1 )
1581
0
    {
1582
        // the object is still not loaded
1583
0
        throw embed::WrongStateException( u"Can't store object without persistence!"_ustr,
1584
0
                                    static_cast< ::cppu::OWeakObject* >(this) );
1585
0
    }
1586
1587
0
    if ( m_bWaitSaveCompleted )
1588
0
        throw embed::WrongStateException(
1589
0
                    u"The object waits for saveCompleted() call!"_ustr,
1590
0
                    static_cast< ::cppu::OWeakObject* >(this) );
1591
1592
0
    if ( m_bReadOnly )
1593
0
        throw io::IOException(); // TODO: access denied
1594
1595
    // nothing to do, if the object is in loaded state
1596
0
    if ( m_nObjectState == embed::EmbedStates::LOADED )
1597
0
        return;
1598
1599
0
    PostEvent_Impl( u"OnSave"_ustr );
1600
1601
0
    SAL_WARN_IF( !m_xDocHolder->GetComponent().is(), "embeddedobj.common", "If an object is activated or in running state it must have a document!" );
1602
0
    if ( !m_xDocHolder->GetComponent().is() )
1603
0
        throw uno::RuntimeException();
1604
1605
0
    if ( m_bIsLinkURL )
1606
0
    {
1607
        // TODO: just store the document to its location
1608
0
        uno::Reference< frame::XStorable > xStorable( m_xDocHolder->GetComponent(), uno::UNO_QUERY_THROW );
1609
1610
        // free the main mutex for the storing time
1611
0
        aGuard.clear();
1612
1613
0
        xStorable->store();
1614
1615
0
        aGuard.reset();
1616
0
    }
1617
0
    else
1618
0
    {
1619
0
        OSL_ENSURE( m_xParentStorage.is() && m_xObjectStorage.is(), "The object has no valid persistence!" );
1620
1621
0
        if ( !m_xObjectStorage.is() )
1622
0
            throw io::IOException(); //TODO: access denied
1623
1624
0
        sal_Int32 nStorageFormat = SOFFICE_FILEFORMAT_CURRENT;
1625
0
        try {
1626
0
            nStorageFormat = ::comphelper::OStorageHelper::GetXStorageFormat( m_xParentStorage );
1627
0
        }
1628
0
        catch ( const beans::IllegalTypeException& )
1629
0
        {
1630
            // the container just has an unknown type, use current file format
1631
0
        }
1632
0
        catch ( const uno::Exception& )
1633
0
        {
1634
0
            SAL_WARN( "embeddedobj.common", "Can not retrieve storage media type!" );
1635
0
        }
1636
0
        if (nStorageFormat == SOFFICE_FILEFORMAT_60)
1637
0
        {
1638
0
            SAL_INFO("embeddedobj.common", "fdo#78159: Storing OOoXML as ODF");
1639
0
            nStorageFormat = SOFFICE_FILEFORMAT_CURRENT;
1640
            // setting MediaType is done later anyway, no need to do it here
1641
0
        }
1642
1643
0
        aGuard.clear();
1644
0
        uno::Sequence<beans::PropertyValue> aEmpty;
1645
0
        uno::Sequence<beans::PropertyValue> aMediaArgs{ comphelper::makePropertyValue(
1646
0
            u"DocumentBaseURL"_ustr, GetBaseURL_Impl()) };
1647
0
        StoreDocToStorage_Impl( m_xObjectStorage, aMediaArgs, aEmpty, nStorageFormat, m_aEntryName, true );
1648
0
        aGuard.reset();
1649
0
    }
1650
1651
0
    uno::Reference< util::XModifiable > xModif( m_xDocHolder->GetComponent(), uno::UNO_QUERY );
1652
0
    if ( xModif.is() )
1653
0
        xModif->setModified( false );
1654
1655
0
    PostEvent_Impl( u"OnSaveDone"_ustr );
1656
0
}
1657
1658
1659
sal_Bool SAL_CALL OCommonEmbeddedObject::isReadonly()
1660
0
{
1661
0
    ::osl::MutexGuard aGuard( m_aMutex );
1662
0
    if ( m_bDisposed )
1663
0
        throw lang::DisposedException(); // TODO
1664
1665
0
    if ( m_nObjectState == -1 )
1666
0
    {
1667
        // the object is still not loaded
1668
0
        throw embed::WrongStateException( u"The object persistence is not initialized!"_ustr,
1669
0
                                        static_cast< ::cppu::OWeakObject* >(this) );
1670
0
    }
1671
1672
0
    if ( m_bWaitSaveCompleted )
1673
0
        throw embed::WrongStateException(
1674
0
                    u"The object waits for saveCompleted() call!"_ustr,
1675
0
                    static_cast< ::cppu::OWeakObject* >(this) );
1676
1677
0
    return m_bReadOnly;
1678
0
}
1679
1680
1681
void SAL_CALL OCommonEmbeddedObject::reload(
1682
                const uno::Sequence< beans::PropertyValue >& lArguments,
1683
                const uno::Sequence< beans::PropertyValue >& lObjArgs )
1684
0
{
1685
    // TODO: use lObjArgs
1686
    // for now this method is used only to switch readonly state
1687
1688
0
    ::osl::MutexGuard aGuard( m_aMutex );
1689
0
    if ( m_bDisposed )
1690
0
        throw lang::DisposedException(); // TODO
1691
1692
0
    if ( m_nObjectState == -1 )
1693
0
    {
1694
        // the object is still not loaded
1695
0
        throw embed::WrongStateException( u"The object persistence is not initialized!"_ustr,
1696
0
                                        static_cast< ::cppu::OWeakObject* >(this) );
1697
0
    }
1698
1699
0
    if ( m_nObjectState != embed::EmbedStates::LOADED )
1700
0
    {
1701
        // the object is still not loaded
1702
0
        throw embed::WrongStateException(
1703
0
                                u"The object must be in loaded state to be reloaded!"_ustr,
1704
0
                                static_cast< ::cppu::OWeakObject* >(this) );
1705
0
    }
1706
1707
0
    if ( m_bWaitSaveCompleted )
1708
0
        throw embed::WrongStateException(
1709
0
                    u"The object waits for saveCompleted() call!"_ustr,
1710
0
                    static_cast< ::cppu::OWeakObject* >(this) );
1711
1712
0
    if ( m_bIsLinkURL )
1713
0
    {
1714
        // reload of the link
1715
0
        OUString aOldLinkFilter = m_aLinkFilterName;
1716
1717
0
        OUString aNewLinkFilter;
1718
0
        for ( beans::PropertyValue const & prop : lArguments )
1719
0
        {
1720
0
            if ( prop.Name == "URL" )
1721
0
            {
1722
                // the new URL
1723
0
                prop.Value >>= m_aLinkURL;
1724
0
                m_aLinkFilterName.clear();
1725
0
            }
1726
0
            else if ( prop.Name == "FilterName" )
1727
0
            {
1728
0
                prop.Value >>= aNewLinkFilter;
1729
0
                m_aLinkFilterName.clear();
1730
0
            }
1731
0
        }
1732
1733
0
        ::comphelper::MimeConfigurationHelper aHelper( m_xContext );
1734
0
        if ( m_aLinkFilterName.isEmpty() )
1735
0
        {
1736
0
            if ( !aNewLinkFilter.isEmpty() )
1737
0
                m_aLinkFilterName = aNewLinkFilter;
1738
0
            else
1739
0
            {
1740
0
                uno::Sequence< beans::PropertyValue > aArgs{ comphelper::makePropertyValue(
1741
0
                    u"URL"_ustr, m_aLinkURL) };
1742
0
                m_aLinkFilterName = aHelper.UpdateMediaDescriptorWithFilterName( aArgs, false );
1743
0
            }
1744
0
        }
1745
1746
0
        if ( aOldLinkFilter != m_aLinkFilterName )
1747
0
        {
1748
0
            uno::Sequence< beans::NamedValue > aObject = aHelper.GetObjectPropsByFilter( m_aLinkFilterName );
1749
1750
            // TODO/LATER: probably the document holder could be cleaned explicitly as in the destructor
1751
0
            m_xDocHolder.clear();
1752
1753
0
            LinkInit_Impl( aObject, lArguments, lObjArgs );
1754
0
        }
1755
0
    }
1756
1757
0
    m_aDocMediaDescriptor = GetValuableArgs_Impl( lArguments, true );
1758
1759
    // TODO: use lObjArgs for StoreVisualReplacement
1760
0
    for ( beans::PropertyValue const & prop : lObjArgs )
1761
0
        if ( prop.Name == "OutplaceDispatchInterceptor" )
1762
0
        {
1763
0
            uno::Reference< frame::XDispatchProviderInterceptor > xDispatchInterceptor;
1764
0
            if ( prop.Value >>= xDispatchInterceptor )
1765
0
                m_xDocHolder->SetOutplaceDispatchInterceptor( xDispatchInterceptor );
1766
1767
0
            break;
1768
0
        }
1769
1770
    // TODO:
1771
    // when document allows reloading through API the object can be reloaded not only in loaded state
1772
1773
0
    bool bOldReadOnlyValue = m_bReadOnly;
1774
1775
0
    m_bReadOnly = false;
1776
0
    for ( beans::PropertyValue const & prop : lArguments )
1777
0
        if ( prop.Name == "ReadOnly" )
1778
0
            prop.Value >>= m_bReadOnly;
1779
1780
0
    if ( bOldReadOnlyValue == m_bReadOnly || m_bIsLinkURL )
1781
0
        return;
1782
1783
    // close own storage
1784
0
    try {
1785
0
        if ( m_xObjectStorage.is() )
1786
0
            m_xObjectStorage->dispose();
1787
0
    }
1788
0
    catch ( const uno::Exception& )
1789
0
    {
1790
0
    }
1791
1792
0
    sal_Int32 nStorageMode = m_bReadOnly ? embed::ElementModes::READ : embed::ElementModes::READWRITE;
1793
0
    m_xObjectStorage = m_xParentStorage->openStorageElement( m_aEntryName, nStorageMode );
1794
0
}
1795
1796
sal_Bool SAL_CALL OCommonEmbeddedObject::isStored()
1797
0
{
1798
0
    if (!m_xObjectStorage.is())
1799
0
        return false;
1800
1801
0
    return m_xObjectStorage->getElementNames().hasElements();
1802
0
}
1803
1804
1805
void SAL_CALL OCommonEmbeddedObject::breakLink( const uno::Reference< embed::XStorage >& xStorage,
1806
                                                const OUString& sEntName )
1807
0
{
1808
0
    ::osl::ResettableMutexGuard aGuard( m_aMutex );
1809
0
    if ( m_bDisposed )
1810
0
        throw lang::DisposedException(); // TODO
1811
1812
0
    if (!m_bIsLinkURL || m_nObjectState == -1)
1813
0
    {
1814
        // it must be a linked initialized object
1815
0
        throw embed::WrongStateException(
1816
0
                    u"The object is not a valid linked object!"_ustr,
1817
0
                    static_cast< ::cppu::OWeakObject* >(this) );
1818
0
    }
1819
    // the current implementation of OOo links does not implement this method since it does not implement
1820
    // all the set of interfaces required for OOo embedded object ( XEmbedPersist is not supported ).
1821
1822
0
    if ( !xStorage.is() )
1823
0
        throw lang::IllegalArgumentException( u"No parent storage is provided!"_ustr,
1824
0
                                            static_cast< ::cppu::OWeakObject* >(this),
1825
0
                                            1 );
1826
1827
0
    if ( sEntName.isEmpty() )
1828
0
        throw lang::IllegalArgumentException( u"Empty element name is provided!"_ustr,
1829
0
                                            static_cast< ::cppu::OWeakObject* >(this),
1830
0
                                            2 );
1831
1832
0
    if ( m_bWaitSaveCompleted )
1833
0
        throw embed::WrongStateException(
1834
0
                    u"The object waits for saveCompleted() call!"_ustr,
1835
0
                    static_cast< ::cppu::OWeakObject* >(this) );
1836
1837
0
    uno::Reference< container::XNameAccess > xNameAccess( xStorage, uno::UNO_QUERY_THROW );
1838
1839
0
    m_bReadOnly = false;
1840
1841
0
    if ( m_xParentStorage != xStorage || m_aEntryName != sEntName )
1842
0
        SwitchOwnPersistence( xStorage, sEntName );
1843
1844
    // for linked object it means that it becomes embedded object
1845
    // the document must switch it's persistence also
1846
1847
    // TODO/LATER: handle the case when temp doc can not be created
1848
    // the document is a new embedded object so it must be marked as modified
1849
0
    uno::Reference< util::XCloseable > xDocument = CreateTempDocFromLink_Impl();
1850
0
    try
1851
0
    {
1852
0
        if(m_xDocHolder.is() && m_xDocHolder->GetComponent().is())
1853
0
        {
1854
            // tdf#141528 m_xDocHolder->GetComponent() may be not set, so add it
1855
            // to the try path to not get thrown out of the local context to the next
1856
            // higher try...catch on the stack. To make breakLink work it is
1857
            // *necessary* to execute the code below that resets the linked state,
1858
            // esp. the *.clear stuff and resetting m_bIsLink.
1859
0
            uno::Reference< util::XModifiable > xModif( m_xDocHolder->GetComponent(), uno::UNO_QUERY_THROW );
1860
1861
            // all other locations in this file check for xModif.is(), so do it here, too
1862
0
            if ( xModif.is() )
1863
0
                xModif->setModified( true );
1864
0
        }
1865
0
    }
1866
0
    catch( const uno::Exception& )
1867
0
    {}
1868
1869
0
    m_xDocHolder->SetComponent( xDocument, m_bReadOnly );
1870
0
    SAL_WARN_IF( !m_xDocHolder->GetComponent().is(), "embeddedobj.common", "If document can't be created, an exception must be thrown!" );
1871
1872
0
    if ( m_nObjectState == embed::EmbedStates::LOADED )
1873
0
    {
1874
        // the state is changed and can not be switched to loaded state back without saving
1875
0
        m_nObjectState = embed::EmbedStates::RUNNING;
1876
0
        StateChangeNotification_Impl( false, embed::EmbedStates::LOADED, m_nObjectState, aGuard );
1877
0
    }
1878
0
    else if ( m_nObjectState == embed::EmbedStates::ACTIVE )
1879
0
        m_xDocHolder->Show();
1880
1881
    // tdf#141529 reset all stuff involved in linked state, including
1882
    // the OLE content copied to the temp file
1883
0
    m_bIsLinkURL = false;
1884
0
    m_aLinkTempFile.clear();
1885
0
    m_aLinkFilterName.clear();
1886
0
    m_aLinkURL.clear();
1887
0
}
1888
1889
1890
sal_Bool SAL_CALL  OCommonEmbeddedObject::isLink()
1891
0
{
1892
0
    ::osl::MutexGuard aGuard( m_aMutex );
1893
0
    if ( m_bDisposed )
1894
0
        throw lang::DisposedException(); // TODO
1895
1896
0
    return m_bIsLinkURL;
1897
0
}
1898
1899
1900
OUString SAL_CALL OCommonEmbeddedObject::getLinkURL()
1901
0
{
1902
0
    ::osl::MutexGuard aGuard( m_aMutex );
1903
0
    if ( m_bDisposed )
1904
0
        throw lang::DisposedException(); // TODO
1905
1906
0
    if ( !m_bIsLinkURL )
1907
0
        throw embed::WrongStateException(
1908
0
                    u"The object is not a link object!"_ustr,
1909
0
                    static_cast< ::cppu::OWeakObject* >(this) );
1910
1911
0
    return m_aLinkURL;
1912
0
}
1913
1914
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */