Coverage Report

Created: 2026-10-14 09:33

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/embeddedobj/source/msole/olepersist.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 <oleembobj.hxx>
21
#include "olepersist.hxx"
22
#include <com/sun/star/embed/EmbedStates.hpp>
23
#include <com/sun/star/embed/EmbedVerbs.hpp>
24
#include <com/sun/star/embed/EntryInitModes.hpp>
25
#include <com/sun/star/embed/WrongStateException.hpp>
26
#include <com/sun/star/embed/XStorage.hpp>
27
#include <com/sun/star/embed/XTransactedObject.hpp>
28
#include <com/sun/star/embed/ElementModes.hpp>
29
#include <com/sun/star/embed/EmbedUpdateModes.hpp>
30
#include <com/sun/star/embed/Aspects.hpp>
31
#include <com/sun/star/embed/XOptimizedStorage.hpp>
32
#include <com/sun/star/lang/XComponent.hpp>
33
#include <com/sun/star/lang/DisposedException.hpp>
34
#include <com/sun/star/container/XNameAccess.hpp>
35
#include <com/sun/star/container/XNameContainer.hpp>
36
#include <com/sun/star/io/TempFile.hpp>
37
#include <com/sun/star/io/XSeekable.hpp>
38
#include <com/sun/star/io/XTruncate.hpp>
39
#include <com/sun/star/beans/XPropertySet.hpp>
40
#include <com/sun/star/packages/WrongPasswordException.hpp>
41
#include <com/sun/star/ucb/SimpleFileAccess.hpp>
42
#include <com/sun/star/io/IOException.hpp>
43
44
#include <comphelper/storagehelper.hxx>
45
#include <comphelper/mimeconfighelper.hxx>
46
#include <comphelper/classids.hxx>
47
#include <osl/diagnose.h>
48
#include <osl/thread.hxx>
49
#include <rtl/ref.hxx>
50
#include <sal/log.hxx>
51
52
#include <closepreventer.hxx>
53
54
#if defined(_WIN32)
55
#include "olecomponent.hxx"
56
#endif
57
58
using namespace ::com::sun::star;
59
using namespace ::comphelper;
60
61
62
bool KillFile_Impl( const OUString& aURL, const uno::Reference< uno::XComponentContext >& xContext )
63
0
{
64
0
    if ( !xContext.is() )
65
0
        return false;
66
67
0
    bool bRet = false;
68
69
0
    try
70
0
    {
71
0
        uno::Reference < ucb::XSimpleFileAccess3 > xAccess(
72
0
                ucb::SimpleFileAccess::create( xContext ) );
73
74
0
        xAccess->kill( aURL );
75
0
        bRet = true;
76
0
    }
77
0
    catch( const uno::Exception& )
78
0
    {
79
0
    }
80
81
0
    return bRet;
82
0
}
83
84
85
OUString GetNewTempFileURL_Impl( const uno::Reference< uno::XComponentContext >& xContext )
86
0
{
87
0
    SAL_WARN_IF( !xContext.is(), "embeddedobj.ole", "No factory is provided!" );
88
89
0
    OUString aResult;
90
91
0
    uno::Reference < io::XTempFile > xTempFile(
92
0
            io::TempFile::create(xContext),
93
0
            uno::UNO_SET_THROW );
94
95
0
    try {
96
0
        xTempFile->setRemoveFile( false );
97
0
        aResult = xTempFile->getUri();
98
0
    }
99
0
    catch ( const uno::Exception& )
100
0
    {
101
0
    }
102
103
0
    if ( aResult.isEmpty() )
104
0
        throw uno::RuntimeException(u"Cannot create tempfile."_ustr);
105
106
0
    return aResult;
107
0
}
108
109
110
OUString GetNewFilledTempFile_Impl( const uno::Reference< io::XInputStream >& xInStream,
111
                                      const uno::Reference< uno::XComponentContext >& xContext )
112
0
{
113
0
    OSL_ENSURE( xInStream.is() && xContext.is(), "Wrong parameters are provided!" );
114
115
0
    OUString aResult = GetNewTempFileURL_Impl( xContext );
116
117
0
    if ( !aResult.isEmpty() )
118
0
    {
119
0
        try {
120
0
            uno::Reference < ucb::XSimpleFileAccess3 > xTempAccess(
121
0
                    ucb::SimpleFileAccess::create( xContext ) );
122
123
0
            uno::Reference< io::XOutputStream > xTempOutStream = xTempAccess->openFileWrite( aResult );
124
0
            if ( !xTempOutStream.is() )
125
0
                throw io::IOException(); // TODO:
126
            // copy stream contents to the file
127
0
            ::comphelper::OStorageHelper::CopyInputToOutput( xInStream, xTempOutStream );
128
0
            xTempOutStream->closeOutput();
129
0
            xTempOutStream.clear();
130
0
        }
131
0
        catch( const packages::WrongPasswordException& )
132
0
        {
133
0
            KillFile_Impl( aResult, xContext );
134
0
            throw io::IOException(); //TODO:
135
0
        }
136
0
        catch( const io::IOException& )
137
0
        {
138
0
            KillFile_Impl( aResult, xContext );
139
0
            throw;
140
0
        }
141
0
        catch( const uno::RuntimeException& )
142
0
        {
143
0
            KillFile_Impl( aResult, xContext );
144
0
            throw;
145
0
        }
146
0
        catch( const uno::Exception& )
147
0
        {
148
0
            KillFile_Impl( aResult, xContext );
149
0
            aResult.clear();
150
0
        }
151
0
    }
152
153
0
    return aResult;
154
0
}
155
#ifdef _WIN32
156
/// @throws io::IOException
157
/// @throws uno::RuntimeException
158
static OUString GetNewFilledTempFile_Impl( const uno::Reference< embed::XOptimizedStorage >& xParentStorage, const OUString& aEntryName, const uno::Reference< uno::XComponentContext >& xContext )
159
{
160
    OUString aResult;
161
162
    try
163
    {
164
        uno::Reference < io::XTempFile > xTempFile(
165
                io::TempFile::create(xContext),
166
                uno::UNO_SET_THROW );
167
168
        xParentStorage->copyStreamElementData( aEntryName, xTempFile );
169
170
        xTempFile->setRemoveFile( false );
171
        aResult = xTempFile->getUri();
172
    }
173
    catch( const uno::RuntimeException& )
174
    {
175
        throw;
176
    }
177
    catch( const uno::Exception& )
178
    {
179
    }
180
181
    if ( aResult.isEmpty() )
182
        throw io::IOException();
183
184
    return aResult;
185
}
186
187
188
static void SetStreamMediaType_Impl( const uno::Reference< io::XStream >& xStream, const OUString& aMediaType )
189
{
190
    uno::Reference< beans::XPropertySet > xPropSet( xStream, uno::UNO_QUERY_THROW );
191
    xPropSet->setPropertyValue("MediaType", uno::Any( aMediaType ) );
192
}
193
#endif
194
195
static void LetCommonStoragePassBeUsed_Impl( const uno::Reference< io::XStream >& xStream )
196
0
{
197
0
    uno::Reference< beans::XPropertySet > xPropSet( xStream, uno::UNO_QUERY_THROW );
198
0
    xPropSet->setPropertyValue(u"UseCommonStoragePasswordEncryption"_ustr,
199
0
                                uno::Any( true ) );
200
0
}
201
#ifdef _WIN32
202
203
void VerbExecutionController::StartControlExecution()
204
{
205
    osl::MutexGuard aGuard( m_aVerbExecutionMutex );
206
207
    // the class is used to detect STAMPIT object, that can never be active
208
    if ( !m_bVerbExecutionInProgress && !m_bWasEverActive )
209
    {
210
        m_bVerbExecutionInProgress = true;
211
        m_nVerbExecutionThreadIdentifier = osl::Thread::getCurrentIdentifier();
212
        m_bChangedOnVerbExecution = false;
213
    }
214
}
215
216
217
bool VerbExecutionController::EndControlExecution_WasModified()
218
{
219
    osl::MutexGuard aGuard( m_aVerbExecutionMutex );
220
221
    bool bResult = false;
222
    if ( m_bVerbExecutionInProgress && m_nVerbExecutionThreadIdentifier == osl::Thread::getCurrentIdentifier() )
223
    {
224
        bResult = m_bChangedOnVerbExecution;
225
        m_bVerbExecutionInProgress = false;
226
    }
227
228
    return bResult;
229
}
230
231
232
void VerbExecutionController::ModificationNotificationIsDone()
233
{
234
    osl::MutexGuard aGuard( m_aVerbExecutionMutex );
235
236
    if ( m_bVerbExecutionInProgress && osl::Thread::getCurrentIdentifier() == m_nVerbExecutionThreadIdentifier )
237
        m_bChangedOnVerbExecution = true;
238
}
239
#endif
240
241
void VerbExecutionController::LockNotification()
242
0
{
243
0
    osl::MutexGuard aGuard( m_aVerbExecutionMutex );
244
0
    if ( m_nNotificationLock < SAL_MAX_INT32 )
245
0
        m_nNotificationLock++;
246
0
}
247
248
249
void VerbExecutionController::UnlockNotification()
250
0
{
251
0
    osl::MutexGuard aGuard( m_aVerbExecutionMutex );
252
0
    if ( m_nNotificationLock > 0 )
253
0
        m_nNotificationLock--;
254
0
}
255
256
257
uno::Reference< io::XStream > OleEmbeddedObject::GetNewFilledTempStream_Impl( const uno::Reference< io::XInputStream >& xInStream )
258
0
{
259
0
    SAL_WARN_IF( !xInStream.is(), "embeddedobj.ole", "Wrong parameter is provided!" );
260
261
0
    uno::Reference < io::XStream > xTempFile(
262
0
            io::TempFile::create(m_xContext),
263
0
            uno::UNO_QUERY_THROW );
264
265
0
    uno::Reference< io::XOutputStream > xTempOutStream = xTempFile->getOutputStream();
266
0
    if ( !xTempOutStream.is() )
267
0
        throw io::IOException(); // TODO:
268
0
    ::comphelper::OStorageHelper::CopyInputToOutput( xInStream, xTempOutStream );
269
0
    xTempOutStream->flush();
270
0
    return xTempFile;
271
0
}
272
273
274
uno::Reference< io::XStream > OleEmbeddedObject::TryToGetAcceptableFormat_Impl( const uno::Reference< io::XStream >& xStream )
275
0
{
276
    // TODO/LATER: Actually this should be done by a centralized component ( may be a graphical filter )
277
0
    if ( !m_xContext.is() )
278
0
        throw uno::RuntimeException();
279
280
0
    uno::Reference< io::XInputStream > xInStream = xStream->getInputStream();
281
0
    if ( !xInStream.is() )
282
0
        throw uno::RuntimeException();
283
284
0
    uno::Reference< io::XSeekable > xSeek( xStream, uno::UNO_QUERY_THROW );
285
0
    xSeek->seek( 0 );
286
287
0
    uno::Sequence< sal_Int8 > aData( 8 );
288
0
    sal_Int32 nRead = xInStream->readBytes( aData, 8 );
289
0
    xSeek->seek( 0 );
290
291
0
    if ( ( nRead >= 2 && aData[0] == 'B' && aData[1] == 'M' )
292
0
      || ( nRead >= 4 && aData[0] == 1 && aData[1] == 0 && aData[2] == 9 && aData[3] == 0 ) )
293
0
    {
294
        // it should be a bitmap or a Metafile
295
0
        return xStream;
296
0
    }
297
298
299
0
    sal_uInt32 nHeaderOffset = 0;
300
0
    if ( ( nRead >= 8 && aData[0] == -1 && aData[1] == -1 && aData[2] == -1 && aData[3] == -1 )
301
0
      && ( aData[4] == 2 || aData[4] == 3 || aData[4] == 14 ) && aData[5] == 0 && aData[6] == 0 && aData[7] == 0 )
302
0
    {
303
0
        nHeaderOffset = 40;
304
0
        xSeek->seek( 8 );
305
306
        // TargetDevice might be used in future, currently the cache has specified NULL
307
0
        uno::Sequence< sal_Int8 > aHeadData( 4 );
308
0
        nRead = xInStream->readBytes( aHeadData, 4 );
309
0
        sal_uInt32 nLen = 0;
310
0
        if ( nRead == 4 && aHeadData.getLength() == 4 )
311
0
            nLen = ( ( ( static_cast<sal_uInt32>(aHeadData[3]) * 0x100 + static_cast<sal_uInt32>(aHeadData[2]) ) * 0x100 ) + static_cast<sal_uInt32>(aHeadData[1]) ) * 0x100 + static_cast<sal_uInt32>(aHeadData[0]);
312
0
        if ( nLen > 4 )
313
0
        {
314
0
            xInStream->skipBytes( nLen - 4 );
315
0
            nHeaderOffset += nLen - 4;
316
0
        }
317
318
0
    }
319
0
    else if ( nRead > 4 )
320
0
    {
321
        // check whether the first bytes represent the size
322
0
        sal_uInt32 nSize = 0;
323
0
        for ( sal_Int32 nInd = 3; nInd >= 0; nInd-- )
324
0
            nSize = ( nSize << 8 ) + static_cast<sal_uInt8>(aData[nInd]);
325
326
0
        if ( nSize == xSeek->getLength() - 4 )
327
0
            nHeaderOffset = 4;
328
0
    }
329
330
0
    if ( nHeaderOffset )
331
0
    {
332
        // this is either a bitmap or a metafile clipboard format, retrieve the pure stream
333
0
        uno::Reference < io::XStream > xResult(
334
0
            io::TempFile::create(m_xContext),
335
0
            uno::UNO_QUERY_THROW );
336
0
        uno::Reference < io::XSeekable > xResultSeek( xResult, uno::UNO_QUERY_THROW );
337
0
        uno::Reference < io::XOutputStream > xResultOut = xResult->getOutputStream();
338
0
        uno::Reference < io::XInputStream > xResultIn = xResult->getInputStream();
339
0
        if ( !xResultOut.is() || !xResultIn.is() )
340
0
            throw uno::RuntimeException();
341
342
0
        xSeek->seek( nHeaderOffset ); // header size for these formats
343
0
        ::comphelper::OStorageHelper::CopyInputToOutput( xInStream, xResultOut );
344
0
        xResultOut->closeOutput();
345
0
        xResultSeek->seek( 0 );
346
0
        xSeek->seek( 0 );
347
348
0
        return xResult;
349
0
    }
350
351
0
    return uno::Reference< io::XStream >();
352
0
}
353
354
355
void OleEmbeddedObject::InsertVisualCache_Impl( const uno::Reference< io::XStream >& xTargetStream,
356
                                                const uno::Reference< io::XStream >& xCachedVisualRepresentation,
357
                                                osl::ResettableMutexGuard& rGuard )
358
0
{
359
0
    OSL_ENSURE( xTargetStream.is() && xCachedVisualRepresentation.is(), "Invalid arguments!" );
360
361
0
    if ( !xTargetStream.is() || !xCachedVisualRepresentation.is() )
362
0
        throw uno::RuntimeException();
363
364
0
    uno::Sequence< uno::Any > aArgs{ uno::Any(xTargetStream),
365
0
                                     uno::Any(true) }; // do not create copy
366
367
0
    uno::Reference< container::XNameContainer > xNameContainer(
368
0
            m_xContext->getServiceManager()->createInstanceWithArgumentsAndContext(
369
0
                    u"com.sun.star.embed.OLESimpleStorage"_ustr,
370
0
                    aArgs, m_xContext ),
371
0
            uno::UNO_QUERY_THROW );
372
373
0
    uno::Reference< io::XSeekable > xCachedSeek( xCachedVisualRepresentation, uno::UNO_QUERY_THROW );
374
0
    xCachedSeek->seek( 0 );
375
376
0
    uno::Reference < io::XStream > xTempFile(
377
0
            io::TempFile::create(m_xContext),
378
0
            uno::UNO_QUERY_THROW );
379
380
0
    uno::Reference< io::XSeekable > xTempSeek( xTempFile, uno::UNO_QUERY_THROW );
381
0
    uno::Reference< io::XOutputStream > xTempOutStream = xTempFile->getOutputStream();
382
0
    if ( !xTempOutStream.is() )
383
0
        throw io::IOException(); // TODO:
384
385
    // the OlePres stream must have additional header
386
    // TODO/LATER: might need to be extended in future (actually makes sense only for SO7 format)
387
0
    uno::Reference< io::XInputStream > xInCacheStream = xCachedVisualRepresentation->getInputStream();
388
0
    if ( !xInCacheStream.is() )
389
0
        throw uno::RuntimeException();
390
391
    // write 0xFFFFFFFF at the beginning
392
0
    uno::Sequence< sal_Int8 > aData( 4 );
393
0
    auto pData = aData.getArray();
394
0
    * reinterpret_cast<sal_uInt32*>(pData) = 0xFFFFFFFF;
395
396
0
    xTempOutStream->writeBytes( aData );
397
398
    // write clipboard format
399
0
    uno::Sequence< sal_Int8 > aSigData( 2 );
400
0
    xInCacheStream->readBytes( aSigData, 2 );
401
0
    if ( aSigData.getLength() < 2 )
402
0
        throw io::IOException();
403
404
0
    if ( aSigData[0] == 'B' && aSigData[1] == 'M' )
405
0
    {
406
        // it's a bitmap
407
0
        pData[0] = 0x02; pData[1] = 0; pData[2] = 0; pData[3] = 0;
408
0
    }
409
0
    else
410
0
    {
411
        // treat it as a metafile
412
0
        pData[0] = 0x03; pData[1] = 0; pData[2] = 0; pData[3] = 0;
413
0
    }
414
0
    xTempOutStream->writeBytes( aData );
415
416
    // write job related information
417
0
    pData[0] = 0x04; pData[1] = 0; pData[2] = 0; pData[3] = 0;
418
0
    xTempOutStream->writeBytes( aData );
419
420
    // write aspect
421
0
    pData[0] = 0x01; pData[1] = 0; pData[2] = 0; pData[3] = 0;
422
0
    xTempOutStream->writeBytes( aData );
423
424
    // write l-index
425
0
    * reinterpret_cast<sal_uInt32*>(pData) = 0xFFFFFFFF;
426
0
    xTempOutStream->writeBytes( aData );
427
428
    // write adv. flags
429
0
    pData[0] = 0x02; pData[1] = 0; pData[2] = 0; pData[3] = 0;
430
0
    xTempOutStream->writeBytes( aData );
431
432
    // write compression
433
0
    * reinterpret_cast<sal_uInt32*>(pData) = 0x0;
434
0
    xTempOutStream->writeBytes( aData );
435
436
    // get the size
437
0
    awt::Size aSize = getVisualAreaSize_impl(embed::Aspects::MSOLE_CONTENT, rGuard);
438
0
    sal_Int32 nIndex = 0;
439
440
    // write width
441
0
    for ( nIndex = 0; nIndex < 4; nIndex++ )
442
0
    {
443
0
        pData[nIndex] = static_cast<sal_Int8>( aSize.Width % 0x100 );
444
0
        aSize.Width /= 0x100;
445
0
    }
446
0
    xTempOutStream->writeBytes( aData );
447
448
    // write height
449
0
    for ( nIndex = 0; nIndex < 4; nIndex++ )
450
0
    {
451
0
        pData[nIndex] = static_cast<sal_Int8>( aSize.Height % 0x100 );
452
0
        aSize.Height /= 0x100;
453
0
    }
454
0
    xTempOutStream->writeBytes( aData );
455
456
    // write garbage, it will be overwritten by the size
457
0
    xTempOutStream->writeBytes( aData );
458
459
    // write first bytes that was used to detect the type
460
0
    xTempOutStream->writeBytes( aSigData );
461
462
    // write the rest of the stream
463
0
    ::comphelper::OStorageHelper::CopyInputToOutput( xInCacheStream, xTempOutStream );
464
465
    // write the size of the stream
466
0
    sal_Int64 nLength = xTempSeek->getLength() - 40;
467
0
    if ( nLength < 0 || nLength >= 0xFFFFFFFF )
468
0
    {
469
0
        SAL_WARN( "embeddedobj.ole", "Length is not acceptable!" );
470
0
        return;
471
0
    }
472
0
    for ( sal_Int32 nInd = 0; nInd < 4; nInd++ )
473
0
    {
474
0
        pData[nInd] = static_cast<sal_Int8>( static_cast<sal_uInt64>(nLength) % 0x100 );
475
0
        nLength /= 0x100;
476
0
    }
477
0
    xTempSeek->seek( 36 );
478
0
    xTempOutStream->writeBytes( aData );
479
480
0
    xTempOutStream->flush();
481
482
0
    xTempSeek->seek( 0 );
483
0
    if ( xCachedSeek.is() )
484
0
        xCachedSeek->seek( 0 );
485
486
    // insert the result file as replacement image
487
0
    OUString aCacheName = u"\002OlePres000"_ustr;
488
0
    if ( xNameContainer->hasByName( aCacheName ) )
489
0
        xNameContainer->replaceByName( aCacheName, uno::Any( xTempFile ) );
490
0
    else
491
0
        xNameContainer->insertByName( aCacheName, uno::Any( xTempFile ) );
492
493
0
    uno::Reference< embed::XTransactedObject > xTransacted( xNameContainer, uno::UNO_QUERY_THROW );
494
0
    xTransacted->commit();
495
0
}
496
497
498
void OleEmbeddedObject::RemoveVisualCache_Impl( const uno::Reference< io::XStream >& xTargetStream )
499
0
{
500
0
    OSL_ENSURE( xTargetStream.is(), "Invalid argument!" );
501
0
    if ( !xTargetStream.is() )
502
0
        throw uno::RuntimeException();
503
504
0
    uno::Sequence< uno::Any > aArgs{ uno::Any(xTargetStream),
505
0
                                     uno::Any(true) }; // do not create copy
506
0
    uno::Reference< container::XNameContainer > xNameContainer(
507
0
            m_xContext->getServiceManager()->createInstanceWithArgumentsAndContext(
508
0
                    u"com.sun.star.embed.OLESimpleStorage"_ustr,
509
0
                    aArgs, m_xContext ),
510
0
            uno::UNO_QUERY_THROW );
511
512
0
    for ( sal_uInt8 nInd = 0; nInd < 10; nInd++ )
513
0
    {
514
0
        OUString aStreamName =  "\002OlePres00" + OUString::number( nInd );
515
0
        if ( xNameContainer->hasByName( aStreamName ) )
516
0
            xNameContainer->removeByName( aStreamName );
517
0
    }
518
519
0
    uno::Reference< embed::XTransactedObject > xTransacted( xNameContainer, uno::UNO_QUERY_THROW );
520
0
    xTransacted->commit();
521
0
}
522
523
524
void OleEmbeddedObject::SetVisReplInStream( bool bExists )
525
0
{
526
0
    m_bVisReplInitialized = true;
527
0
    m_bVisReplInStream = bExists;
528
0
}
529
530
531
bool OleEmbeddedObject::HasVisReplInStream()
532
0
{
533
0
    if ( !m_bVisReplInitialized )
534
0
    {
535
0
        if ( m_xCachedVisualRepresentation.is() )
536
0
            SetVisReplInStream( true );
537
0
        else
538
0
        {
539
0
            SAL_INFO( "embeddedobj.ole", "embeddedobj (mv76033) OleEmbeddedObject::HasVisualReplInStream, analyzing" );
540
541
0
            uno::Reference< io::XInputStream > xStream;
542
543
0
            OSL_ENSURE( !m_pOleComponent || !m_aTempURL.isEmpty(), "The temporary file must exist if there is a component!" );
544
0
            if ( !m_aTempURL.isEmpty() )
545
0
            {
546
0
                try
547
0
                {
548
                    // open temporary file for reading
549
0
                    uno::Reference < ucb::XSimpleFileAccess3 > xTempAccess(
550
0
                            ucb::SimpleFileAccess::create( m_xContext ) );
551
552
0
                    xStream = xTempAccess->openFileRead( m_aTempURL );
553
0
                }
554
0
                catch( const uno::Exception& )
555
0
                {}
556
0
            }
557
558
0
            if ( !xStream.is() )
559
0
                xStream = m_xObjectStream->getInputStream();
560
561
0
            if ( xStream.is() )
562
0
            {
563
0
                bool bExists = false;
564
565
0
                uno::Sequence< uno::Any > aArgs{ uno::Any(xStream),
566
0
                                                 uno::Any(true) }; // do not create copy
567
0
                uno::Reference< container::XNameContainer > xNameContainer(
568
0
                        m_xContext->getServiceManager()->createInstanceWithArgumentsAndContext(
569
0
                                u"com.sun.star.embed.OLESimpleStorage"_ustr,
570
0
                                aArgs, m_xContext ),
571
0
                        uno::UNO_QUERY );
572
573
0
                if ( xNameContainer.is() )
574
0
                {
575
0
                    for ( sal_uInt8 nInd = 0; nInd < 10 && !bExists; nInd++ )
576
0
                    {
577
0
                        OUString aStreamName = "\002OlePres00" + OUString::number( nInd );
578
0
                        try
579
0
                        {
580
0
                            bExists = xNameContainer->hasByName( aStreamName );
581
0
                        }
582
0
                        catch( const uno::Exception& )
583
0
                        {}
584
0
                    }
585
0
                }
586
587
0
                SetVisReplInStream( bExists );
588
0
            }
589
0
        }
590
0
    }
591
592
0
    return m_bVisReplInStream;
593
0
}
594
595
596
uno::Reference< io::XStream > OleEmbeddedObject::TryToRetrieveCachedVisualRepresentation_Impl(
597
        const uno::Reference< io::XStream >& xStream,
598
        osl::ResettableMutexGuard& rGuard,
599
        bool bAllowToRepair50 )
600
    noexcept
601
0
{
602
0
    uno::Reference< io::XStream > xResult;
603
604
0
    if ( xStream.is() )
605
0
    {
606
0
        SAL_INFO( "embeddedobj.ole", "embeddedobj (mv76033) OleEmbeddedObject::TryToRetrieveCachedVisualRepresentation, retrieving" );
607
608
0
        uno::Reference< container::XNameContainer > xNameContainer;
609
0
        uno::Sequence< uno::Any > aArgs{ uno::Any(xStream),
610
0
                                         uno::Any(true) }; // do not create copy
611
0
        try
612
0
        {
613
0
            xNameContainer.set(
614
0
                m_xContext->getServiceManager()->createInstanceWithArgumentsAndContext(
615
0
                        u"com.sun.star.embed.OLESimpleStorage"_ustr,
616
0
                        aArgs, m_xContext ),
617
0
                uno::UNO_QUERY );
618
0
        }
619
0
        catch( const uno::Exception& )
620
0
        {}
621
622
0
        if ( xNameContainer.is() )
623
0
        {
624
0
            for ( sal_uInt8 nInd = 0; nInd < 10; nInd++ )
625
0
            {
626
0
                OUString aStreamName =  "\002OlePres00" + OUString::number( nInd );
627
0
                uno::Reference< io::XStream > xCachedCopyStream;
628
0
                try
629
0
                {
630
0
                    if ( ( xNameContainer->getByName( aStreamName ) >>= xCachedCopyStream ) && xCachedCopyStream.is() )
631
0
                    {
632
0
                        xResult = TryToGetAcceptableFormat_Impl( xCachedCopyStream );
633
0
                        if ( xResult.is() )
634
0
                            break;
635
0
                    }
636
0
                }
637
0
                catch( const uno::Exception& )
638
0
                {}
639
640
0
                if ( nInd == 0 )
641
0
                {
642
                    // to be compatible with the old versions Ole10Native is checked after OlePress000
643
0
                    aStreamName = "\001Ole10Native";
644
0
                    try
645
0
                    {
646
0
                        if ( ( xNameContainer->getByName( aStreamName ) >>= xCachedCopyStream ) && xCachedCopyStream.is() )
647
0
                        {
648
0
                            xResult = TryToGetAcceptableFormat_Impl( xCachedCopyStream );
649
0
                            if ( xResult.is() )
650
0
                                break;
651
0
                        }
652
0
                    }
653
0
                    catch( const uno::Exception& )
654
0
                    {}
655
0
                }
656
0
            }
657
658
0
            try
659
0
            {
660
0
                if ( bAllowToRepair50 && !xResult.is() )
661
0
                {
662
0
                    OUString aOrigContName( u"Ole-Object"_ustr );
663
0
                    if ( xNameContainer->hasByName( aOrigContName ) )
664
0
                    {
665
0
                        uno::Reference< embed::XClassifiedObject > xClassified( xNameContainer, uno::UNO_QUERY_THROW );
666
0
                        if ( MimeConfigurationHelper::ClassIDsEqual( xClassified->getClassID(), MimeConfigurationHelper::GetSequenceClassID( SO3_OUT_CLASSID ) ) )
667
0
                        {
668
                            // this is an OLE object wrongly stored in 5.0 format
669
                            // this object must be repaired since SO7 has done it
670
671
0
                            uno::Reference< io::XOutputStream > xOutputStream = xStream->getOutputStream();
672
0
                            uno::Reference< io::XTruncate > xTruncate( xOutputStream, uno::UNO_QUERY_THROW );
673
674
0
                            uno::Reference< io::XInputStream > xOrigInputStream;
675
0
                            if ( ( xNameContainer->getByName( aOrigContName ) >>= xOrigInputStream )
676
0
                              && xOrigInputStream.is() )
677
0
                            {
678
                                // the provided input stream must be based on temporary medium and must be independent
679
                                // from the stream the storage is based on
680
0
                                uno::Reference< io::XSeekable > xOrigSeekable( xOrigInputStream, uno::UNO_QUERY );
681
0
                                if ( xOrigSeekable.is() )
682
0
                                    xOrigSeekable->seek( 0 );
683
684
0
                                uno::Reference< lang::XComponent > xNameContDisp( xNameContainer, uno::UNO_QUERY_THROW );
685
0
                                xNameContDisp->dispose(); // free the original stream
686
687
0
                                xTruncate->truncate();
688
0
                                ::comphelper::OStorageHelper::CopyInputToOutput( xOrigInputStream, xOutputStream );
689
0
                                xOutputStream->flush();
690
691
0
                                if ( xStream == m_xObjectStream )
692
0
                                {
693
0
                                    if ( !m_aTempURL.isEmpty() )
694
0
                                    {
695
                                        // this is the own stream, so the temporary URL must be cleaned if it exists
696
0
                                        KillFile_Impl( m_aTempURL, m_xContext );
697
0
                                        m_aTempURL.clear();
698
0
                                    }
699
700
#ifdef _WIN32
701
                                    // retry to create the component after recovering
702
                                    GetRidOfComponent(&rGuard);
703
704
                                    try
705
                                    {
706
                                        CreateOleComponentAndLoad_Impl();
707
                                        m_aClassID = m_pOleComponent->GetCLSID(); // was not set during construction
708
                                    }
709
                                    catch( const uno::Exception& )
710
                                    {
711
                                        GetRidOfComponent(&rGuard);
712
                                    }
713
#endif
714
0
                                }
715
716
0
                                xResult = TryToRetrieveCachedVisualRepresentation_Impl( xStream, rGuard );
717
0
                            }
718
0
                        }
719
0
                    }
720
0
                }
721
0
            }
722
0
            catch( const uno::Exception& )
723
0
            {}
724
0
        }
725
0
    }
726
727
0
    return xResult;
728
0
}
729
730
731
void OleEmbeddedObject::SwitchOwnPersistence( const uno::Reference< embed::XStorage >& xNewParentStorage,
732
                                              const uno::Reference< io::XStream >& xNewObjectStream,
733
                                              const OUString& aNewName )
734
30
{
735
30
    if ( xNewParentStorage == m_xParentStorage && aNewName == m_aEntryName )
736
0
    {
737
0
        SAL_WARN_IF( xNewObjectStream != m_xObjectStream, "embeddedobj.ole", "The streams must be the same!" );
738
0
        return;
739
0
    }
740
741
30
    uno::Reference<io::XSeekable> xNewSeekable(xNewObjectStream, uno::UNO_QUERY);
742
30
    if (xNewSeekable.is() && xNewSeekable->getLength() == 0)
743
30
    {
744
30
        uno::Reference<io::XSeekable> xOldSeekable(m_xObjectStream, uno::UNO_QUERY);
745
30
        if (xOldSeekable.is() && xOldSeekable->getLength() > 0)
746
0
        {
747
0
            SAL_WARN("embeddedobj.ole", "OleEmbeddedObject::SwitchOwnPersistence(stream version): "
748
0
                                        "empty new stream, reusing old one");
749
0
            uno::Reference<io::XInputStream> xInput = m_xObjectStream->getInputStream();
750
0
            uno::Reference<io::XOutputStream> xOutput = xNewObjectStream->getOutputStream();
751
0
            xOldSeekable->seek(0);
752
0
            comphelper::OStorageHelper::CopyInputToOutput(xInput, xOutput);
753
0
            xNewSeekable->seek(0);
754
0
        }
755
30
    }
756
757
30
    try {
758
30
        uno::Reference< lang::XComponent > xComponent( m_xObjectStream, uno::UNO_QUERY );
759
30
        OSL_ENSURE( !m_xObjectStream.is() || xComponent.is(), "Wrong stream implementation!" );
760
30
        if ( xComponent.is() )
761
0
            xComponent->dispose();
762
30
    }
763
30
    catch ( const uno::Exception& )
764
30
    {
765
0
    }
766
767
30
    m_xObjectStream = xNewObjectStream;
768
30
    m_xParentStorage = xNewParentStorage;
769
30
    m_aEntryName = aNewName;
770
30
}
771
772
773
void OleEmbeddedObject::SwitchOwnPersistence( const uno::Reference< embed::XStorage >& xNewParentStorage,
774
                                              const OUString& aNewName )
775
30
{
776
30
    if ( xNewParentStorage == m_xParentStorage && aNewName == m_aEntryName )
777
0
        return;
778
779
30
    sal_Int32 nStreamMode = m_bReadOnly ? embed::ElementModes::READ : embed::ElementModes::READWRITE;
780
781
30
    uno::Reference< io::XStream > xNewOwnStream = xNewParentStorage->openStreamElement( aNewName, nStreamMode );
782
783
30
    uno::Reference<io::XSeekable> xNewSeekable (xNewOwnStream, uno::UNO_QUERY);
784
30
    if (xNewSeekable.is() && xNewSeekable->getLength() == 0)
785
30
    {
786
30
        uno::Reference<io::XSeekable> xOldSeekable(m_xObjectStream, uno::UNO_QUERY);
787
30
        if (xOldSeekable.is() && xOldSeekable->getLength() > 0)
788
0
        {
789
0
            SAL_WARN("embeddedobj.ole", "OleEmbeddedObject::SwitchOwnPersistence: empty new stream, reusing old one");
790
0
            uno::Reference<io::XInputStream> xInput = m_xObjectStream->getInputStream();
791
0
            uno::Reference<io::XOutputStream> xOutput = xNewOwnStream->getOutputStream();
792
0
            comphelper::OStorageHelper::CopyInputToOutput(xInput, xOutput);
793
0
            xNewSeekable->seek(0);
794
0
        }
795
30
    }
796
797
30
    SAL_WARN_IF( !xNewOwnStream.is(), "embeddedobj.ole", "The method can not return empty reference!" );
798
799
30
    SwitchOwnPersistence( xNewParentStorage, xNewOwnStream, aNewName );
800
30
}
801
802
#ifdef _WIN32
803
804
bool OleEmbeddedObject::SaveObject_Impl()
805
{
806
    bool bResult = false;
807
808
    if ( m_xClientSite.is() )
809
    {
810
        try
811
        {
812
            m_xClientSite->saveObject();
813
            bResult = true;
814
        }
815
        catch( const uno::Exception& )
816
        {
817
        }
818
    }
819
820
    return bResult;
821
}
822
823
824
bool OleEmbeddedObject::OnShowWindow_Impl( bool bShow )
825
{
826
    osl::ResettableMutexGuard aGuard(m_aMutex);
827
828
    bool bResult = false;
829
830
    SAL_WARN_IF( m_nObjectState == -1, "embeddedobj.ole", "The object has no persistence!" );
831
    SAL_WARN_IF( m_nObjectState == embed::EmbedStates::LOADED, "embeddedobj.ole", "The object get OnShowWindow in loaded state!" );
832
    if ( m_nObjectState == -1 || m_nObjectState == embed::EmbedStates::LOADED )
833
        return false;
834
835
    // the object is either activated or deactivated
836
    sal_Int32 nOldState = m_nObjectState;
837
    if ( bShow && m_nObjectState == embed::EmbedStates::RUNNING )
838
    {
839
        m_nObjectState = embed::EmbedStates::ACTIVE;
840
        m_aVerbExecutionController.ObjectIsActive();
841
842
        StateChangeNotification_Impl( false, nOldState, m_nObjectState, aGuard );
843
    }
844
    else if ( !bShow && m_nObjectState == embed::EmbedStates::ACTIVE )
845
    {
846
        m_nObjectState = embed::EmbedStates::RUNNING;
847
        StateChangeNotification_Impl( false, nOldState, m_nObjectState, aGuard );
848
    }
849
850
    if ( m_xClientSite.is() )
851
    {
852
        try
853
        {
854
            ExecUnlocked([p = m_xClientSite, bShow] { p->visibilityChanged(bShow); }, aGuard);
855
            bResult = true;
856
        }
857
        catch( const uno::Exception& )
858
        {
859
        }
860
    }
861
862
    return bResult;
863
}
864
865
866
void OleEmbeddedObject::OnIconChanged_Impl()
867
{
868
    // TODO/LATER: currently this notification seems to be impossible
869
    // MakeEventListenerNotification_Impl( OUString( "OnIconChanged" ) );
870
}
871
872
873
void OleEmbeddedObject::OnViewChanged_Impl()
874
{
875
    osl::ResettableMutexGuard aGuard(m_aMutex);
876
    if ( m_bDisposed )
877
        throw lang::DisposedException();
878
879
    // For performance reasons the notification currently is ignored, STAMPIT object is the exception,
880
    // it can never be active and never call SaveObject, so it is the only way to detect that it is changed
881
882
    // ==== the STAMPIT related solution =============================
883
    // the following variable is used to detect whether the object was modified during verb execution
884
    m_aVerbExecutionController.ModificationNotificationIsDone();
885
886
    // The following things are controlled by VerbExecutionController:
887
    // - if the verb execution is in progress and the view is changed the object will be stored
888
    // after the execution, so there is no need to send the notification.
889
    // - the STAMPIT object can never be active.
890
    if (m_aVerbExecutionController.CanDoNotification() &&
891
            m_pOleComponent && m_nUpdateMode == embed::EmbedUpdateModes::ALWAYS_UPDATE &&
892
            (MimeConfigurationHelper::ClassIDsEqual(m_aClassID, MimeConfigurationHelper::GetSequenceClassID(0x852ee1c9, 0x9058, 0x44ba, 0x8c, 0x6c, 0x0c, 0x5f, 0xc6, 0x6b, 0xdb, 0x8d)) ||
893
             MimeConfigurationHelper::ClassIDsEqual(m_aClassID, MimeConfigurationHelper::GetSequenceClassID(0xcf1b4491, 0xbea3, 0x4c9f, 0xa7, 0x0f, 0x22, 0x1b, 0x1e, 0xca, 0xef, 0x3e)))
894
       )
895
    {
896
        // The view is changed while the object is in running state, save the new object
897
        m_xCachedVisualRepresentation.clear();
898
        SaveObject_Impl();
899
        MakeEventListenerNotification_Impl( "OnVisAreaChanged", aGuard );
900
    }
901
902
}
903
904
905
void OleEmbeddedObject::OnClosed_Impl()
906
{
907
    osl::ResettableMutexGuard aGuard(m_aMutex);
908
    if ( m_bDisposed )
909
        throw lang::DisposedException();
910
911
    if ( m_nObjectState != embed::EmbedStates::LOADED )
912
    {
913
        sal_Int32 nOldState = m_nObjectState;
914
        m_nObjectState = embed::EmbedStates::LOADED;
915
        StateChangeNotification_Impl( false, nOldState, m_nObjectState, aGuard );
916
    }
917
}
918
919
920
OUString OleEmbeddedObject::CreateTempURLEmpty_Impl()
921
{
922
    SAL_WARN_IF( !m_aTempURL.isEmpty(), "embeddedobj.ole", "The object has already the temporary file!" );
923
    m_aTempURL = GetNewTempFileURL_Impl( m_xContext );
924
925
    return m_aTempURL;
926
}
927
928
929
OUString OleEmbeddedObject::GetTempURL_Impl()
930
{
931
    if ( m_aTempURL.isEmpty() )
932
    {
933
        SAL_INFO( "embeddedobj.ole", "embeddedobj (mv76033) OleEmbeddedObject::GetTempURL_Impl, tempfile creation" );
934
935
        // if there is no temporary file, it will be created from the own entry
936
        uno::Reference< embed::XOptimizedStorage > xOptParStorage( m_xParentStorage, uno::UNO_QUERY );
937
        if ( xOptParStorage.is() )
938
        {
939
            m_aTempURL = GetNewFilledTempFile_Impl( xOptParStorage, m_aEntryName, m_xContext );
940
        }
941
        else if ( m_xObjectStream.is() )
942
        {
943
            // load object from the stream
944
            uno::Reference< io::XInputStream > xInStream = m_xObjectStream->getInputStream();
945
            if ( !xInStream.is() )
946
                throw io::IOException(); // TODO: access denied
947
948
            m_aTempURL = GetNewFilledTempFile_Impl( xInStream, m_xContext );
949
        }
950
    }
951
952
    return m_aTempURL;
953
}
954
955
956
void OleEmbeddedObject::CreateOleComponent_Impl(
957
    rtl::Reference<OleComponent> const & pOleComponent )
958
{
959
    if ( !m_pOleComponent )
960
    {
961
        m_pOleComponent = pOleComponent ? pOleComponent : new OleComponent( m_xContext, this );
962
963
        if ( !m_xClosePreventer.is() )
964
            m_xClosePreventer = new OClosePreventer;
965
966
        m_pOleComponent->addCloseListener( m_xClosePreventer );
967
    }
968
}
969
970
971
void OleEmbeddedObject::CreateOleComponentAndLoad_Impl(
972
    rtl::Reference<OleComponent> const & pOleComponent )
973
{
974
    if ( !m_pOleComponent )
975
    {
976
        if ( !m_xObjectStream.is() )
977
            throw uno::RuntimeException();
978
979
        CreateOleComponent_Impl( pOleComponent );
980
981
        // after the loading the object can appear as a link
982
        // will be detected later by olecomponent
983
984
        GetTempURL_Impl();
985
        if ( m_aTempURL.isEmpty() )
986
            throw uno::RuntimeException(); // TODO
987
988
        m_pOleComponent->LoadEmbeddedObject( m_aTempURL );
989
    }
990
}
991
992
993
void OleEmbeddedObject::CreateOleComponentFromClipboard_Impl( OleComponent* pOleComponent )
994
{
995
    if ( !m_pOleComponent )
996
    {
997
        if ( !m_xObjectStream.is() )
998
            throw uno::RuntimeException();
999
1000
        CreateOleComponent_Impl( pOleComponent );
1001
1002
        // after the loading the object can appear as a link
1003
        // will be detected later by olecomponent
1004
        m_pOleComponent->CreateObjectFromClipboard();
1005
    }
1006
}
1007
1008
1009
uno::Reference< io::XOutputStream > OleEmbeddedObject::GetStreamForSaving()
1010
{
1011
    if ( !m_xObjectStream.is() )
1012
        throw uno::RuntimeException(); //TODO:
1013
1014
    uno::Reference< io::XOutputStream > xOutStream = m_xObjectStream->getOutputStream();
1015
    if ( !xOutStream.is() )
1016
        throw io::IOException(); //TODO: access denied
1017
1018
    uno::Reference< io::XTruncate > xTruncate( xOutStream, uno::UNO_QUERY_THROW );
1019
    xTruncate->truncate();
1020
1021
    return xOutStream;
1022
}
1023
1024
1025
void OleEmbeddedObject::StoreObjectToStream(uno::Reference<io::XOutputStream> const& xOutStream,
1026
                                            osl::ResettableMutexGuard& rGuard)
1027
{
1028
    // this method should be used only on windows
1029
    if ( m_pOleComponent )
1030
        ExecUnlocked([this] { m_pOleComponent->StoreOwnTmpIfNecessary(); }, rGuard);
1031
1032
    // now all the changes should be in temporary location
1033
    if ( m_aTempURL.isEmpty() )
1034
        throw uno::RuntimeException();
1035
1036
    // open temporary file for reading
1037
    uno::Reference < ucb::XSimpleFileAccess3 > xTempAccess(
1038
            ucb::SimpleFileAccess::create( m_xContext ) );
1039
1040
    uno::Reference< io::XInputStream > xTempInStream = xTempAccess->openFileRead( m_aTempURL );
1041
    SAL_WARN_IF( !xTempInStream.is(), "embeddedobj.ole", "The object's temporary file can not be reopened for reading!" );
1042
1043
    // TODO: use bStoreVisReplace
1044
1045
    if ( !xTempInStream.is() )
1046
    {
1047
        throw io::IOException(); // TODO:
1048
    }
1049
1050
    // write all the contents to XOutStream
1051
    uno::Reference< io::XTruncate > xTrunc( xOutStream, uno::UNO_QUERY_THROW );
1052
    xTrunc->truncate();
1053
1054
    ::comphelper::OStorageHelper::CopyInputToOutput( xTempInStream, xOutStream );
1055
1056
    // TODO: should the view replacement be in the stream ???
1057
    //       probably it must be specified on storing
1058
}
1059
#endif
1060
1061
void OleEmbeddedObject::StoreToLocation_Impl(
1062
                            const uno::Reference< embed::XStorage >& xStorage,
1063
                            const OUString& sEntName,
1064
                            const uno::Sequence< beans::PropertyValue >& lObjArgs,
1065
                            bool bSaveAs, osl::ResettableMutexGuard& rGuard)
1066
0
{
1067
0
#ifndef _WIN32
1068
0
    (void)rGuard;
1069
0
#endif
1070
    // TODO: use lObjArgs
1071
    // TODO: exchange StoreVisualReplacement by SO file format version?
1072
1073
0
    if ( m_nObjectState == -1 )
1074
0
    {
1075
        // the object is still not loaded
1076
0
        throw embed::WrongStateException( u"Can't store object without persistence!"_ustr,
1077
0
                                        static_cast< ::cppu::OWeakObject* >(this) );
1078
0
    }
1079
1080
0
    if ( m_bWaitSaveCompleted )
1081
0
        throw embed::WrongStateException(
1082
0
                    u"The object waits for saveCompleted() call!"_ustr,
1083
0
                    static_cast< ::cppu::OWeakObject* >(this) );
1084
1085
0
    OSL_ENSURE( m_xParentStorage.is() && m_xObjectStream.is(), "The object has no valid persistence!" );
1086
1087
0
    bool bVisReplIsStored = false;
1088
1089
0
    bool bTryOptimization = false;
1090
0
    bool bStoreVis = m_bStoreVisRepl;
1091
0
    uno::Reference< io::XStream > xCachedVisualRepresentation;
1092
0
    for ( beans::PropertyValue const & prop : lObjArgs )
1093
0
    {
1094
0
        if ( prop.Name == "StoreVisualReplacement" )
1095
0
            prop.Value >>= bStoreVis;
1096
0
        else if ( prop.Name == "VisualReplacement" )
1097
0
            prop.Value >>= xCachedVisualRepresentation;
1098
0
        else if ( prop.Name == "CanTryOptimization" )
1099
0
            prop.Value >>= bTryOptimization;
1100
0
    }
1101
1102
    // ignore visual representation provided from outside if it should not be stored
1103
0
    if ( !bStoreVis )
1104
0
        xCachedVisualRepresentation.clear();
1105
1106
0
    if ( bStoreVis && !HasVisReplInStream() && !xCachedVisualRepresentation.is() )
1107
0
        throw io::IOException(); // TODO: there is no cached visual representation and nothing is provided from outside
1108
1109
    // if the representation is provided from outside it should be copied to a local stream
1110
0
    bool bNeedLocalCache = xCachedVisualRepresentation.is();
1111
1112
0
    uno::Reference< io::XStream > xTargetStream;
1113
1114
0
    bool bStoreLoaded = false;
1115
0
    if ( m_nObjectState == embed::EmbedStates::LOADED
1116
#ifdef _WIN32
1117
        // if the object was NOT modified after storing it can be just copied
1118
        // as if it was in loaded state
1119
        || (m_pOleComponent && !ExecUnlocked([p = m_pOleComponent] { return p->IsDirty(); }, rGuard))
1120
#endif
1121
0
    )
1122
0
    {
1123
0
        bool bOptimizedCopyingDone = false;
1124
1125
0
        if ( bTryOptimization && bStoreVis == HasVisReplInStream() )
1126
0
        {
1127
0
            try
1128
0
            {
1129
0
                uno::Reference< embed::XOptimizedStorage > xSourceOptStor( m_xParentStorage, uno::UNO_QUERY_THROW );
1130
0
                uno::Reference< embed::XOptimizedStorage > xTargetOptStor( xStorage, uno::UNO_QUERY_THROW );
1131
0
                xSourceOptStor->copyElementDirectlyTo( m_aEntryName, xTargetOptStor, sEntName );
1132
0
                bOptimizedCopyingDone = true;
1133
0
            }
1134
0
            catch( const uno::Exception& )
1135
0
            {
1136
0
            }
1137
0
        }
1138
1139
0
        if ( !bOptimizedCopyingDone )
1140
0
        {
1141
            // if optimized copying fails a normal one should be tried
1142
0
            m_xParentStorage->copyElementTo( m_aEntryName, xStorage, sEntName );
1143
0
        }
1144
1145
        // the locally retrieved representation is always preferable
1146
        // since the object is in loaded state the representation is unchanged
1147
0
        if ( m_xCachedVisualRepresentation.is() )
1148
0
        {
1149
0
            xCachedVisualRepresentation = m_xCachedVisualRepresentation;
1150
0
            bNeedLocalCache = false;
1151
0
        }
1152
1153
0
        bVisReplIsStored = HasVisReplInStream();
1154
0
        bStoreLoaded = true;
1155
0
    }
1156
#ifdef _WIN32
1157
    else if ( m_pOleComponent )
1158
    {
1159
        xTargetStream =
1160
                xStorage->openStreamElement( sEntName, embed::ElementModes::READWRITE );
1161
        if ( !xTargetStream.is() )
1162
            throw io::IOException(); //TODO: access denied
1163
1164
        SetStreamMediaType_Impl( xTargetStream, "application/vnd.sun.star.oleobject" );
1165
        uno::Reference< io::XOutputStream > xOutStream = xTargetStream->getOutputStream();
1166
        if ( !xOutStream.is() )
1167
            throw io::IOException(); //TODO: access denied
1168
1169
        StoreObjectToStream(xOutStream, rGuard);
1170
        bVisReplIsStored = true;
1171
1172
        if ( bSaveAs )
1173
        {
1174
            // no need to do it on StoreTo since in this case the replacement is in the stream
1175
            // and there is no need to cache it even if it is thrown away because the object
1176
            // is not changed by StoreTo action
1177
1178
            uno::Reference< io::XStream > xTmpCVRepresentation =
1179
                        TryToRetrieveCachedVisualRepresentation_Impl( xTargetStream, rGuard );
1180
1181
            // the locally retrieved representation is always preferable
1182
            if ( xTmpCVRepresentation.is() )
1183
            {
1184
                xCachedVisualRepresentation = xTmpCVRepresentation;
1185
                bNeedLocalCache = false;
1186
            }
1187
        }
1188
    }
1189
#endif
1190
0
    else if (true) // loplugin:flatten
1191
0
    {
1192
0
        throw io::IOException(); // TODO
1193
0
    }
1194
1195
0
    if ( !xTargetStream.is() )
1196
0
    {
1197
0
        xTargetStream =
1198
0
            xStorage->openStreamElement( sEntName, embed::ElementModes::READWRITE );
1199
0
        if ( !xTargetStream.is() )
1200
0
            throw io::IOException(); //TODO: access denied
1201
0
    }
1202
1203
0
    LetCommonStoragePassBeUsed_Impl( xTargetStream );
1204
1205
0
    if ( bStoreVis != bVisReplIsStored )
1206
0
    {
1207
0
        if ( bStoreVis )
1208
0
        {
1209
0
            if ( !xCachedVisualRepresentation.is() )
1210
0
                xCachedVisualRepresentation = TryToRetrieveCachedVisualRepresentation_Impl( xTargetStream, rGuard );
1211
1212
0
            SAL_WARN_IF( !xCachedVisualRepresentation.is(), "embeddedobj.ole", "No representation is available!" );
1213
1214
            // the following copying will be done in case it is SaveAs anyway
1215
            // if it is not SaveAs the seekable access is not required currently
1216
            // TODO/LATER: may be required in future
1217
0
            if ( bSaveAs )
1218
0
            {
1219
0
                uno::Reference< io::XSeekable > xCachedSeek( xCachedVisualRepresentation, uno::UNO_QUERY );
1220
0
                if ( !xCachedSeek.is() )
1221
0
                {
1222
0
                    xCachedVisualRepresentation
1223
0
                        = GetNewFilledTempStream_Impl( xCachedVisualRepresentation->getInputStream() );
1224
0
                    bNeedLocalCache = false;
1225
0
                }
1226
0
            }
1227
1228
0
            InsertVisualCache_Impl(xTargetStream, xCachedVisualRepresentation, rGuard);
1229
0
        }
1230
0
        else
1231
0
        {
1232
            // the removed representation could be cached by this method
1233
0
            if ( !xCachedVisualRepresentation.is() )
1234
0
                xCachedVisualRepresentation = TryToRetrieveCachedVisualRepresentation_Impl( xTargetStream, rGuard );
1235
1236
0
            if (!m_bStreamReadOnly)
1237
0
                RemoveVisualCache_Impl(xTargetStream);
1238
0
        }
1239
0
    }
1240
1241
0
    if ( bSaveAs )
1242
0
    {
1243
0
        m_bWaitSaveCompleted = true;
1244
0
        m_xNewObjectStream = std::move(xTargetStream);
1245
0
        m_xNewParentStorage = xStorage;
1246
0
        m_aNewEntryName = sEntName;
1247
0
        m_bNewVisReplInStream = bStoreVis;
1248
0
        m_bStoreLoaded = bStoreLoaded;
1249
1250
0
        if ( xCachedVisualRepresentation.is() )
1251
0
        {
1252
0
            if ( bNeedLocalCache )
1253
0
                m_xNewCachedVisRepl = GetNewFilledTempStream_Impl( xCachedVisualRepresentation->getInputStream() );
1254
0
            else
1255
0
                m_xNewCachedVisRepl = std::move(xCachedVisualRepresentation);
1256
0
        }
1257
1258
        // TODO: register listeners for storages above, in case they are disposed
1259
        //       an exception will be thrown on saveCompleted( true )
1260
0
    }
1261
0
    else
1262
0
    {
1263
0
        uno::Reference< lang::XComponent > xComp( xTargetStream, uno::UNO_QUERY );
1264
0
        if ( xComp.is() )
1265
0
        {
1266
0
            try {
1267
0
                xComp->dispose();
1268
0
            } catch( const uno::Exception& )
1269
0
            {
1270
0
            }
1271
0
        }
1272
0
    }
1273
0
}
1274
1275
1276
void SAL_CALL OleEmbeddedObject::setPersistentEntry(
1277
                    const uno::Reference< embed::XStorage >& xStorage,
1278
                    const OUString& sEntName,
1279
                    sal_Int32 nEntryConnectionMode,
1280
                    const uno::Sequence< beans::PropertyValue >& lArguments,
1281
                    const uno::Sequence< beans::PropertyValue >& lObjArgs )
1282
30
{
1283
    // begin wrapping related part ====================
1284
30
    uno::Reference< embed::XEmbedPersist > xWrappedObject( m_xWrappedObject, uno::UNO_QUERY );
1285
30
    if ( xWrappedObject.is() )
1286
0
    {
1287
        // the object was converted to OOo embedded object, the current implementation is now only a wrapper
1288
0
        xWrappedObject->setPersistentEntry( xStorage, sEntName, nEntryConnectionMode, lArguments, lObjArgs );
1289
0
        return;
1290
0
    }
1291
    // end wrapping related part ====================
1292
1293
    // TODO: use lObjArgs
1294
1295
    // the type of the object must be already set
1296
    // a kind of typedetection should be done in the factory;
1297
    // the only exception is object initialized from a stream,
1298
    // the class ID will be detected from the stream
1299
1300
30
    osl::ResettableMutexGuard aGuard( m_aMutex );
1301
30
    if ( m_bDisposed )
1302
0
        throw lang::DisposedException(); // TODO
1303
1304
30
    if ( !xStorage.is() )
1305
0
        throw lang::IllegalArgumentException( u"No parent storage is provided!"_ustr,
1306
0
                                            static_cast< ::cppu::OWeakObject* >(this),
1307
0
                                            1 );
1308
1309
30
    if ( sEntName.isEmpty() )
1310
0
        throw lang::IllegalArgumentException( u"Empty element name is provided!"_ustr,
1311
0
                                            static_cast< ::cppu::OWeakObject* >(this),
1312
0
                                            2 );
1313
1314
    // May be LOADED should be forbidden here ???
1315
30
    if ( ( m_nObjectState != -1 || nEntryConnectionMode == embed::EntryInitModes::NO_INIT )
1316
0
      && ( m_nObjectState == -1 || nEntryConnectionMode != embed::EntryInitModes::NO_INIT ) )
1317
0
    {
1318
        // if the object is not loaded
1319
        // it can not get persistent representation without initialization
1320
1321
        // if the object is loaded
1322
        // it can switch persistent representation only without initialization
1323
1324
0
        throw embed::WrongStateException(
1325
0
                    u"Can't change persistent representation of activated object!"_ustr,
1326
0
                    static_cast< ::cppu::OWeakObject* >(this) );
1327
0
    }
1328
1329
30
    if ( m_bWaitSaveCompleted )
1330
0
    {
1331
0
        if ( nEntryConnectionMode != embed::EntryInitModes::NO_INIT )
1332
0
            throw embed::WrongStateException(
1333
0
                        u"The object waits for saveCompleted() call!"_ustr,
1334
0
                        static_cast< ::cppu::OWeakObject* >(this) );
1335
0
        saveCompleted( m_xParentStorage != xStorage || m_aEntryName != sEntName );
1336
0
    }
1337
1338
30
    uno::Reference< container::XNameAccess > xNameAccess( xStorage, uno::UNO_QUERY_THROW );
1339
1340
    // detect entry existence
1341
30
    bool bElExists = xNameAccess->hasByName( sEntName );
1342
1343
30
    m_bReadOnly = false;
1344
30
    for ( beans::PropertyValue const & prop : lArguments )
1345
0
        if ( prop.Name == "ReadOnly" )
1346
0
            prop.Value >>= m_bReadOnly;
1347
1348
#ifdef _WIN32
1349
    sal_Int32 nStorageMode = m_bReadOnly ? embed::ElementModes::READ : embed::ElementModes::READWRITE;
1350
#endif
1351
1352
30
    SwitchOwnPersistence( xStorage, sEntName );
1353
1354
30
    for ( beans::PropertyValue const & prop : lObjArgs )
1355
60
        if ( prop.Name == "StoreVisualReplacement" )
1356
0
            prop.Value >>= m_bStoreVisRepl;
1357
1358
#ifdef _WIN32
1359
    if ( nEntryConnectionMode == embed::EntryInitModes::DEFAULT_INIT )
1360
    {
1361
        if ( m_bFromClipboard )
1362
        {
1363
            // the object should be initialized from clipboard
1364
            // impossibility to initialize the object means error here
1365
            CreateOleComponentFromClipboard_Impl();
1366
            m_aClassID = m_pOleComponent->GetCLSID(); // was not set during construction
1367
            m_pOleComponent->RunObject();
1368
            m_nObjectState = embed::EmbedStates::RUNNING;
1369
        }
1370
        else if ( bElExists )
1371
        {
1372
            // load object from the stream
1373
            // after the loading the object can appear as a link
1374
            // will be detected by olecomponent
1375
            try
1376
            {
1377
                CreateOleComponentAndLoad_Impl();
1378
                m_aClassID = m_pOleComponent->GetCLSID(); // was not set during construction
1379
            }
1380
            catch( const uno::Exception& )
1381
            {
1382
                // TODO/LATER: detect classID of the object if possible
1383
                // means that the object inprocess server could not be successfully instantiated
1384
                GetRidOfComponent(&aGuard);
1385
            }
1386
1387
            m_nObjectState = embed::EmbedStates::LOADED;
1388
        }
1389
        else
1390
        {
1391
            // create a new object
1392
            CreateOleComponent_Impl();
1393
            m_pOleComponent->CreateNewEmbeddedObject( m_aClassID );
1394
            m_pOleComponent->RunObject();
1395
            m_nObjectState = embed::EmbedStates::RUNNING;
1396
        }
1397
    }
1398
    else
1399
    {
1400
        if ( ( nStorageMode & embed::ElementModes::READWRITE ) != embed::ElementModes::READWRITE )
1401
            throw io::IOException();
1402
1403
        if ( nEntryConnectionMode == embed::EntryInitModes::NO_INIT )
1404
        {
1405
            // the document just already changed its stream to store to;
1406
            // the links to OLE documents switch their persistence in the same way
1407
            // as normal embedded objects
1408
        }
1409
        else if ( nEntryConnectionMode == embed::EntryInitModes::TRUNCATE_INIT )
1410
        {
1411
            // create a new object, that will be stored in specified stream
1412
            CreateOleComponent_Impl();
1413
1414
            m_pOleComponent->CreateNewEmbeddedObject( m_aClassID );
1415
            m_pOleComponent->RunObject();
1416
            m_nObjectState = embed::EmbedStates::RUNNING;
1417
        }
1418
        else if ( nEntryConnectionMode == embed::EntryInitModes::MEDIA_DESCRIPTOR_INIT )
1419
        {
1420
            // use URL ( may be content or stream later ) from MediaDescriptor to initialize object
1421
            OUString aURL;
1422
            for ( beans::PropertyValue const & prop : lArguments )
1423
                if ( prop.Name == "URL" )
1424
                    prop.Value >>= aURL;
1425
1426
            if ( aURL.isEmpty() )
1427
                throw lang::IllegalArgumentException(
1428
                                    "Empty URL is provided in the media descriptor!",
1429
                                    static_cast< ::cppu::OWeakObject* >(this),
1430
                                    4 );
1431
1432
            CreateOleComponent_Impl();
1433
1434
            // TODO: the m_bIsLink value must be set already
1435
            if ( !m_bIsLink )
1436
                m_pOleComponent->CreateObjectFromFile( aURL );
1437
            else
1438
                m_pOleComponent->CreateLinkFromFile( aURL );
1439
1440
            m_pOleComponent->RunObject();
1441
            m_aClassID = m_pOleComponent->GetCLSID(); // was not set during construction
1442
1443
            m_nObjectState = embed::EmbedStates::RUNNING;
1444
        }
1445
        //else if ( nEntryConnectionMode == embed::EntryInitModes::TRANSFERABLE_INIT )
1446
        //{
1447
            //TODO:
1448
        //}
1449
        else
1450
            throw lang::IllegalArgumentException( "Wrong connection mode is provided!",
1451
                                        static_cast< ::cppu::OWeakObject* >(this),
1452
                                        3 );
1453
    }
1454
#else
1455
    // On Unix the OLE object can not do anything except storing itself somewhere
1456
30
    if ( nEntryConnectionMode == embed::EntryInitModes::DEFAULT_INIT && bElExists )
1457
0
    {
1458
        // TODO/LATER: detect classID of the object
1459
        // can be a real problem for the links
1460
1461
0
        m_nObjectState = embed::EmbedStates::LOADED;
1462
0
    }
1463
30
    else if ( nEntryConnectionMode == embed::EntryInitModes::NO_INIT )
1464
0
    {
1465
        // do nothing, the object has already switched it's persistence
1466
0
    }
1467
30
    else
1468
30
        throw lang::IllegalArgumentException( u"Wrong connection mode is provided!"_ustr,
1469
30
                                    static_cast< ::cppu::OWeakObject* >(this),
1470
30
                                    3 );
1471
1472
30
#endif
1473
30
}
1474
1475
1476
void SAL_CALL OleEmbeddedObject::storeToEntry( const uno::Reference< embed::XStorage >& xStorage,
1477
                            const OUString& sEntName,
1478
                            const uno::Sequence< beans::PropertyValue >& lArguments,
1479
                            const uno::Sequence< beans::PropertyValue >& lObjArgs )
1480
0
{
1481
    // begin wrapping related part ====================
1482
0
    uno::Reference< embed::XEmbedPersist > xWrappedObject( m_xWrappedObject, uno::UNO_QUERY );
1483
0
    if ( xWrappedObject.is() )
1484
0
    {
1485
        // the object was converted to OOo embedded object, the current implementation is now only a wrapper
1486
0
        xWrappedObject->storeToEntry( xStorage, sEntName, lArguments, lObjArgs );
1487
0
        return;
1488
0
    }
1489
    // end wrapping related part ====================
1490
1491
0
    ::osl::ResettableMutexGuard aGuard( m_aMutex );
1492
0
    if ( m_bDisposed )
1493
0
        throw lang::DisposedException(); // TODO
1494
1495
0
    VerbExecutionControllerGuard aVerbGuard( m_aVerbExecutionController );
1496
1497
0
    StoreToLocation_Impl( xStorage, sEntName, lObjArgs, false, aGuard );
1498
1499
    // TODO: should the listener notification be done?
1500
0
}
1501
1502
1503
void SAL_CALL OleEmbeddedObject::storeAsEntry( const uno::Reference< embed::XStorage >& xStorage,
1504
                            const OUString& sEntName,
1505
                            const uno::Sequence< beans::PropertyValue >& lArguments,
1506
                            const uno::Sequence< beans::PropertyValue >& lObjArgs )
1507
0
{
1508
    // begin wrapping related part ====================
1509
0
    uno::Reference< embed::XEmbedPersist > xWrappedObject( m_xWrappedObject, uno::UNO_QUERY );
1510
0
    if ( xWrappedObject.is() )
1511
0
    {
1512
        // the object was converted to OOo embedded object, the current implementation is now only a wrapper
1513
0
        xWrappedObject->storeAsEntry( xStorage, sEntName, lArguments, lObjArgs );
1514
0
        return;
1515
0
    }
1516
    // end wrapping related part ====================
1517
1518
0
    ::osl::ResettableMutexGuard aGuard( m_aMutex );
1519
0
    if ( m_bDisposed )
1520
0
        throw lang::DisposedException(); // TODO
1521
1522
0
    VerbExecutionControllerGuard aVerbGuard( m_aVerbExecutionController );
1523
1524
0
    StoreToLocation_Impl( xStorage, sEntName, lObjArgs, true, aGuard );
1525
1526
    // TODO: should the listener notification be done here or in saveCompleted?
1527
0
}
1528
1529
1530
void SAL_CALL OleEmbeddedObject::saveCompleted( sal_Bool bUseNew )
1531
0
{
1532
    // begin wrapping related part ====================
1533
0
    uno::Reference< embed::XEmbedPersist > xWrappedObject( m_xWrappedObject, uno::UNO_QUERY );
1534
0
    if ( xWrappedObject.is() )
1535
0
    {
1536
        // the object was converted to OOo embedded object, the current implementation is now only a wrapper
1537
0
        xWrappedObject->saveCompleted( bUseNew );
1538
0
        return;
1539
0
    }
1540
    // end wrapping related part ====================
1541
1542
0
    osl::ResettableMutexGuard aGuard(m_aMutex);
1543
0
    if ( m_bDisposed )
1544
0
        throw lang::DisposedException(); // TODO
1545
1546
0
    if ( m_nObjectState == -1 )
1547
0
    {
1548
        // the object is still not loaded
1549
0
        throw embed::WrongStateException( u"Can't store object without persistence!"_ustr,
1550
0
                                        static_cast< ::cppu::OWeakObject* >(this) );
1551
0
    }
1552
1553
    // it is allowed to call saveCompleted( false ) for nonstored objects
1554
0
    if ( !m_bWaitSaveCompleted && !bUseNew )
1555
0
        return;
1556
1557
0
    SAL_WARN_IF( !m_bWaitSaveCompleted, "embeddedobj.ole", "Unexpected saveCompleted() call!" );
1558
0
    if ( !m_bWaitSaveCompleted )
1559
0
        throw io::IOException(); // TODO: illegal call
1560
1561
0
    OSL_ENSURE( m_xNewObjectStream.is() && m_xNewParentStorage.is() , "Internal object information is broken!" );
1562
0
    if ( !m_xNewObjectStream.is() || !m_xNewParentStorage.is() )
1563
0
        throw uno::RuntimeException(); // TODO: broken internal information
1564
1565
0
    if ( bUseNew )
1566
0
    {
1567
0
        SwitchOwnPersistence( m_xNewParentStorage, m_xNewObjectStream, m_aNewEntryName );
1568
0
        m_bStoreVisRepl = m_bNewVisReplInStream;
1569
0
        SetVisReplInStream( m_bNewVisReplInStream );
1570
0
        m_xCachedVisualRepresentation = m_xNewCachedVisRepl;
1571
0
    }
1572
0
    else
1573
0
    {
1574
        // close remembered stream
1575
0
        try {
1576
0
            uno::Reference< lang::XComponent > xComponent( m_xNewObjectStream, uno::UNO_QUERY );
1577
0
            SAL_WARN_IF( !xComponent.is(), "embeddedobj.ole", "Wrong storage implementation!" );
1578
0
            if ( xComponent.is() )
1579
0
                xComponent->dispose();
1580
0
        }
1581
0
        catch ( const uno::Exception& )
1582
0
        {
1583
0
        }
1584
0
    }
1585
1586
0
    bool bStoreLoaded = m_bStoreLoaded;
1587
1588
0
    m_xNewObjectStream.clear();
1589
0
    m_xNewParentStorage.clear();
1590
0
    m_aNewEntryName.clear();
1591
0
    m_bWaitSaveCompleted = false;
1592
0
    m_bNewVisReplInStream = false;
1593
0
    m_xNewCachedVisRepl.clear();
1594
0
    m_bStoreLoaded = false;
1595
1596
0
    if ( bUseNew && m_pOleComponent && m_nUpdateMode == embed::EmbedUpdateModes::ALWAYS_UPDATE && !bStoreLoaded
1597
0
      && m_nObjectState != embed::EmbedStates::LOADED )
1598
0
    {
1599
        // the object replacement image should be updated, so the cached size as well
1600
0
        m_bHasCachedSize = false;
1601
0
        try
1602
0
        {
1603
            // the call will cache the size in case of success
1604
            // probably it might need to be done earlier, while the object is in active state
1605
0
            getVisualAreaSize_impl(embed::Aspects::MSOLE_CONTENT, aGuard);
1606
0
        }
1607
0
        catch( const uno::Exception& )
1608
0
        {}
1609
0
    }
1610
1611
0
    if ( bUseNew )
1612
0
    {
1613
0
        MakeEventListenerNotification_Impl( u"OnSaveAsDone"_ustr, aGuard);
1614
1615
        // the object can be changed only on windows
1616
        // the notification should be done only if the object is not in loaded state
1617
0
        if ( m_pOleComponent && m_nUpdateMode == embed::EmbedUpdateModes::ALWAYS_UPDATE && !bStoreLoaded )
1618
0
        {
1619
0
            MakeEventListenerNotification_Impl( u"OnVisAreaChanged"_ustr, aGuard);
1620
0
        }
1621
0
    }
1622
0
}
1623
1624
1625
sal_Bool SAL_CALL OleEmbeddedObject::hasEntry()
1626
0
{
1627
    // begin wrapping related part ====================
1628
0
    uno::Reference< embed::XEmbedPersist > xWrappedObject( m_xWrappedObject, uno::UNO_QUERY );
1629
0
    if ( xWrappedObject.is() )
1630
0
    {
1631
        // the object was converted to OOo embedded object, the current implementation is now only a wrapper
1632
0
        return xWrappedObject->hasEntry();
1633
0
    }
1634
    // end wrapping related part ====================
1635
1636
0
    ::osl::MutexGuard aGuard( m_aMutex );
1637
0
    if ( m_bDisposed )
1638
0
        throw lang::DisposedException(); // TODO
1639
1640
0
    if ( m_bWaitSaveCompleted )
1641
0
        throw embed::WrongStateException(
1642
0
                    u"The object waits for saveCompleted() call!"_ustr,
1643
0
                    static_cast< ::cppu::OWeakObject* >(this) );
1644
1645
0
    if ( m_xObjectStream.is() )
1646
0
        return true;
1647
1648
0
    return false;
1649
0
}
1650
1651
1652
OUString SAL_CALL OleEmbeddedObject::getEntryName()
1653
0
{
1654
    // begin wrapping related part ====================
1655
0
    uno::Reference< embed::XEmbedPersist > xWrappedObject( m_xWrappedObject, uno::UNO_QUERY );
1656
0
    if ( xWrappedObject.is() )
1657
0
    {
1658
        // the object was converted to OOo embedded object, the current implementation is now only a wrapper
1659
0
        return xWrappedObject->getEntryName();
1660
0
    }
1661
    // end wrapping related part ====================
1662
1663
0
    ::osl::MutexGuard aGuard( m_aMutex );
1664
0
    if ( m_bDisposed )
1665
0
        throw lang::DisposedException(); // TODO
1666
1667
0
    if ( m_nObjectState == -1 )
1668
0
    {
1669
        // the object is still not loaded
1670
0
        throw embed::WrongStateException( u"The object persistence is not initialized!"_ustr,
1671
0
                                        static_cast< ::cppu::OWeakObject* >(this) );
1672
0
    }
1673
1674
0
    if ( m_bWaitSaveCompleted )
1675
0
        throw embed::WrongStateException(
1676
0
                    u"The object waits for saveCompleted() call!"_ustr,
1677
0
                    static_cast< ::cppu::OWeakObject* >(this) );
1678
1679
0
    return m_aEntryName;
1680
0
}
1681
1682
1683
void SAL_CALL OleEmbeddedObject::storeOwn()
1684
0
{
1685
    // begin wrapping related part ====================
1686
0
    uno::Reference< embed::XEmbedPersist > xWrappedObject( m_xWrappedObject, uno::UNO_QUERY );
1687
0
    if ( xWrappedObject.is() )
1688
0
    {
1689
        // the object was converted to OOo embedded object, the current implementation is now only a wrapper
1690
0
        xWrappedObject->storeOwn();
1691
0
        return;
1692
0
    }
1693
    // end wrapping related part ====================
1694
1695
    // during switching from Activated to Running and from Running to Loaded states the object will
1696
    // ask container to store the object, the container has to make decision
1697
    // to do so or not
1698
1699
0
    osl::ResettableMutexGuard aGuard(m_aMutex);
1700
0
    if ( m_bDisposed )
1701
0
        throw lang::DisposedException(); // TODO
1702
1703
0
    VerbExecutionControllerGuard aVerbGuard( m_aVerbExecutionController );
1704
1705
0
    if ( m_nObjectState == -1 )
1706
0
    {
1707
        // the object is still not loaded
1708
0
        throw embed::WrongStateException( u"Can't store object without persistence!"_ustr,
1709
0
                                    static_cast< ::cppu::OWeakObject* >(this) );
1710
0
    }
1711
1712
0
    if ( m_bWaitSaveCompleted )
1713
0
        throw embed::WrongStateException(
1714
0
                    u"The object waits for saveCompleted() call!"_ustr,
1715
0
                    static_cast< ::cppu::OWeakObject* >(this) );
1716
1717
0
    if ( m_bReadOnly )
1718
0
        throw io::IOException(); // TODO: access denied
1719
1720
0
    LetCommonStoragePassBeUsed_Impl( m_xObjectStream );
1721
1722
0
    bool bStoreLoaded = true;
1723
1724
#ifdef _WIN32
1725
    if ( m_nObjectState != embed::EmbedStates::LOADED && m_pOleComponent && ExecUnlocked([p = m_pOleComponent] { return p->IsDirty(); }, aGuard) )
1726
    {
1727
        bStoreLoaded = false;
1728
1729
        OSL_ENSURE( m_xParentStorage.is() && m_xObjectStream.is(), "The object has no valid persistence!" );
1730
1731
        if ( !m_xObjectStream.is() )
1732
            throw io::IOException(); //TODO: access denied
1733
1734
        SetStreamMediaType_Impl( m_xObjectStream, "application/vnd.sun.star.oleobject" );
1735
        uno::Reference< io::XOutputStream > xOutStream = m_xObjectStream->getOutputStream();
1736
        if ( !xOutStream.is() )
1737
            throw io::IOException(); //TODO: access denied
1738
1739
        // TODO: does this work for links too?
1740
        StoreObjectToStream(GetStreamForSaving(), aGuard);
1741
1742
        // the replacement is changed probably, and it must be in the object stream
1743
        if ( !m_pOleComponent->IsWorkaroundActive() )
1744
            m_xCachedVisualRepresentation.clear();
1745
        SetVisReplInStream( true );
1746
    }
1747
#endif
1748
1749
0
    if ( m_bStoreVisRepl != HasVisReplInStream() )
1750
0
    {
1751
0
        if ( m_bStoreVisRepl )
1752
0
        {
1753
            // the m_xCachedVisualRepresentation must be set or it should be already stored
1754
0
            if ( m_xCachedVisualRepresentation.is() )
1755
0
                InsertVisualCache_Impl(m_xObjectStream, m_xCachedVisualRepresentation, aGuard);
1756
0
            else
1757
0
            {
1758
0
                m_xCachedVisualRepresentation = TryToRetrieveCachedVisualRepresentation_Impl( m_xObjectStream, aGuard );
1759
0
                SAL_WARN_IF( !m_xCachedVisualRepresentation.is(), "embeddedobj.ole", "No representation is available!" );
1760
0
            }
1761
0
        }
1762
0
        else
1763
0
        {
1764
0
            if ( !m_xCachedVisualRepresentation.is() )
1765
0
                m_xCachedVisualRepresentation = TryToRetrieveCachedVisualRepresentation_Impl( m_xObjectStream, aGuard );
1766
0
            RemoveVisualCache_Impl( m_xObjectStream );
1767
0
        }
1768
1769
0
        SetVisReplInStream( m_bStoreVisRepl );
1770
0
    }
1771
1772
0
    if ( m_pOleComponent && m_nUpdateMode == embed::EmbedUpdateModes::ALWAYS_UPDATE && !bStoreLoaded )
1773
0
    {
1774
        // the object replacement image should be updated, so the cached size as well
1775
0
        m_bHasCachedSize = false;
1776
0
        try
1777
0
        {
1778
            // the call will cache the size in case of success
1779
            // probably it might need to be done earlier, while the object is in active state
1780
0
            getVisualAreaSize_impl(embed::Aspects::MSOLE_CONTENT, aGuard);
1781
0
        }
1782
0
        catch( const uno::Exception& )
1783
0
        {}
1784
0
    }
1785
1786
0
    MakeEventListenerNotification_Impl( u"OnSaveDone"_ustr, aGuard);
1787
1788
    // the object can be changed only on Windows
1789
    // the notification should be done only if the object is not in loaded state
1790
0
    if ( m_pOleComponent && m_nUpdateMode == embed::EmbedUpdateModes::ALWAYS_UPDATE && !bStoreLoaded )
1791
0
        MakeEventListenerNotification_Impl( u"OnVisAreaChanged"_ustr, aGuard);
1792
0
}
1793
1794
1795
sal_Bool SAL_CALL OleEmbeddedObject::isReadonly()
1796
0
{
1797
    // begin wrapping related part ====================
1798
0
    uno::Reference< embed::XEmbedPersist > xWrappedObject( m_xWrappedObject, uno::UNO_QUERY );
1799
0
    if ( xWrappedObject.is() )
1800
0
    {
1801
        // the object was converted to OOo embedded object, the current implementation is now only a wrapper
1802
0
        return xWrappedObject->isReadonly();
1803
0
    }
1804
    // end wrapping related part ====================
1805
1806
0
    ::osl::MutexGuard aGuard( m_aMutex );
1807
0
    if ( m_bDisposed )
1808
0
        throw lang::DisposedException(); // TODO
1809
1810
0
    if ( m_nObjectState == -1 )
1811
0
    {
1812
        // the object is still not loaded
1813
0
        throw embed::WrongStateException( u"The object persistence is not initialized!"_ustr,
1814
0
                                        static_cast< ::cppu::OWeakObject* >(this) );
1815
0
    }
1816
1817
0
    if ( m_bWaitSaveCompleted )
1818
0
        throw embed::WrongStateException(
1819
0
                    u"The object waits for saveCompleted() call!"_ustr,
1820
0
                    static_cast< ::cppu::OWeakObject* >(this) );
1821
1822
0
    return m_bReadOnly;
1823
0
}
1824
1825
1826
void SAL_CALL OleEmbeddedObject::reload(
1827
                const uno::Sequence< beans::PropertyValue >& lArguments,
1828
                const uno::Sequence< beans::PropertyValue >& lObjArgs )
1829
0
{
1830
    // begin wrapping related part ====================
1831
0
    uno::Reference< embed::XEmbedPersist > xWrappedObject( m_xWrappedObject, uno::UNO_QUERY );
1832
0
    if ( xWrappedObject.is() )
1833
0
    {
1834
        // the object was converted to OOo embedded object, the current implementation is now only a wrapper
1835
0
        xWrappedObject->reload( lArguments, lObjArgs );
1836
0
        return;
1837
0
    }
1838
    // end wrapping related part ====================
1839
1840
    // TODO: use lObjArgs
1841
1842
0
    ::osl::MutexGuard aGuard( m_aMutex );
1843
0
    if ( m_bDisposed )
1844
0
        throw lang::DisposedException(); // TODO
1845
1846
0
    if ( m_nObjectState == -1 )
1847
0
    {
1848
        // the object is still not loaded
1849
0
        throw embed::WrongStateException( u"The object persistence is not initialized!"_ustr,
1850
0
                                        static_cast< ::cppu::OWeakObject* >(this) );
1851
0
    }
1852
1853
0
    if ( m_bWaitSaveCompleted )
1854
0
        throw embed::WrongStateException(
1855
0
                    u"The object waits for saveCompleted() call!"_ustr,
1856
0
                    static_cast< ::cppu::OWeakObject* >(this) );
1857
1858
    // TODO:
1859
    // throw away current document
1860
    // load new document from current storage
1861
    // use meaningful part of lArguments
1862
0
}
1863
1864
1865
void SAL_CALL OleEmbeddedObject::breakLink( const uno::Reference< embed::XStorage >& xStorage,
1866
                                                const OUString& sEntName )
1867
0
{
1868
    // begin wrapping related part ====================
1869
0
    uno::Reference< embed::XLinkageSupport > xWrappedObject( m_xWrappedObject, uno::UNO_QUERY );
1870
0
    if ( xWrappedObject.is() )
1871
0
    {
1872
        // the object was converted to OOo embedded object, the current implementation is now only a wrapper
1873
0
        xWrappedObject->breakLink( xStorage, sEntName );
1874
0
        return;
1875
0
    }
1876
    // end wrapping related part ====================
1877
1878
0
    osl::ResettableMutexGuard aGuard( m_aMutex );
1879
0
    if ( m_bDisposed )
1880
0
        throw lang::DisposedException(); // TODO
1881
1882
0
    if ( !xStorage.is() )
1883
0
        throw lang::IllegalArgumentException( u"No parent storage is provided!"_ustr,
1884
0
                                            static_cast< ::cppu::OWeakObject* >(this),
1885
0
                                            1 );
1886
1887
0
    if ( sEntName.isEmpty() )
1888
0
        throw lang::IllegalArgumentException( u"Empty element name is provided!"_ustr,
1889
0
                                            static_cast< ::cppu::OWeakObject* >(this),
1890
0
                                            2 );
1891
1892
    // TODO: The object must be at least in Running state;
1893
0
    if ( !m_bIsLink || m_nObjectState == -1 || !m_pOleComponent )
1894
0
    {
1895
        // it must be a linked initialized object
1896
0
        throw embed::WrongStateException(
1897
0
                    u"The object is not a valid linked object!"_ustr,
1898
0
                    static_cast< ::cppu::OWeakObject* >(this) );
1899
0
    }
1900
1901
0
    if ( m_bReadOnly )
1902
0
        throw io::IOException(); // TODO: Access denied
1903
1904
0
    if ( m_bWaitSaveCompleted )
1905
0
        throw embed::WrongStateException(
1906
0
                    u"The object waits for saveCompleted() call!"_ustr,
1907
0
                    static_cast< ::cppu::OWeakObject* >(this) );
1908
1909
1910
#ifdef _WIN32
1911
    // TODO: create an object based on the link
1912
1913
    // disconnect the old temporary URL
1914
    OUString aOldTempURL = m_aTempURL;
1915
    m_aTempURL.clear();
1916
1917
    rtl::Reference<OleComponent> pNewOleComponent = new OleComponent(m_xContext, this);
1918
    try {
1919
        pNewOleComponent->InitEmbeddedCopyOfLink(m_pOleComponent);
1920
    }
1921
    catch (const uno::Exception&)
1922
    {
1923
        if (!m_aTempURL.isEmpty())
1924
            KillFile_Impl(m_aTempURL, m_xContext);
1925
        m_aTempURL = aOldTempURL;
1926
        throw;
1927
    }
1928
1929
    try {
1930
        GetRidOfComponent(&aGuard);
1931
    }
1932
    catch (const uno::Exception&)
1933
    {
1934
        if (!m_aTempURL.isEmpty())
1935
            KillFile_Impl(m_aTempURL, m_xContext);
1936
        m_aTempURL = aOldTempURL;
1937
        throw;
1938
    }
1939
1940
    KillFile_Impl(aOldTempURL, m_xContext);
1941
1942
    CreateOleComponent_Impl(pNewOleComponent);
1943
1944
    if (m_xParentStorage != xStorage || !m_aEntryName.equals(sEntName))
1945
        SwitchOwnPersistence(xStorage, sEntName);
1946
1947
    if (m_nObjectState != embed::EmbedStates::LOADED)
1948
    {
1949
        // TODO: should we activate the new object if the link was activated?
1950
1951
        const sal_Int32 nTargetState = m_nObjectState;
1952
        m_nObjectState = embed::EmbedStates::LOADED;
1953
1954
        if (nTargetState == embed::EmbedStates::RUNNING)
1955
            m_pOleComponent->RunObject(); // the object already was in running state, the server must be installed
1956
        else // nTargetState == embed::EmbedStates::ACTIVE
1957
        {
1958
            m_pOleComponent->RunObject(); // the object already was in running state, the server must be installed
1959
            m_pOleComponent->ExecuteVerb(embed::EmbedVerbs::MS_OLEVERB_OPEN);
1960
        }
1961
1962
        m_nObjectState = nTargetState;
1963
    }
1964
1965
    m_bIsLink = false;
1966
    m_aLinkURL.clear();
1967
#else // ! _WIN32
1968
0
    throw io::IOException(); //TODO:
1969
0
#endif // _WIN32
1970
0
}
1971
1972
1973
sal_Bool SAL_CALL  OleEmbeddedObject::isLink()
1974
0
{
1975
    // begin wrapping related part ====================
1976
0
    uno::Reference< embed::XLinkageSupport > xWrappedObject( m_xWrappedObject, uno::UNO_QUERY );
1977
0
    if ( xWrappedObject.is() )
1978
0
    {
1979
        // the object was converted to OOo embedded object, the current implementation is now only a wrapper
1980
0
        return xWrappedObject->isLink();
1981
0
    }
1982
    // end wrapping related part ====================
1983
1984
0
    ::osl::MutexGuard aGuard( m_aMutex );
1985
0
    if ( m_bDisposed )
1986
0
        throw lang::DisposedException(); // TODO
1987
1988
0
    return m_bIsLink;
1989
0
}
1990
1991
1992
OUString SAL_CALL OleEmbeddedObject::getLinkURL()
1993
0
{
1994
    // begin wrapping related part ====================
1995
0
    uno::Reference< embed::XLinkageSupport > xWrappedObject( m_xWrappedObject, uno::UNO_QUERY );
1996
0
    if ( xWrappedObject.is() )
1997
0
    {
1998
        // the object was converted to OOo embedded object, the current implementation is now only a wrapper
1999
0
        return xWrappedObject->getLinkURL();
2000
0
    }
2001
    // end wrapping related part ====================
2002
2003
0
    ::osl::MutexGuard aGuard( m_aMutex );
2004
0
    if ( m_bDisposed )
2005
0
        throw lang::DisposedException(); // TODO
2006
2007
0
    if ( m_bWaitSaveCompleted )
2008
0
        throw embed::WrongStateException(
2009
0
                    u"The object waits for saveCompleted() call!"_ustr,
2010
0
                    static_cast< ::cppu::OWeakObject* >(this) );
2011
2012
0
    if ( !m_bIsLink )
2013
0
        throw embed::WrongStateException(
2014
0
                    u"The object is not a link object!"_ustr,
2015
0
                    static_cast< ::cppu::OWeakObject* >(this) );
2016
2017
    // TODO: probably the link URL can be retrieved from OLE
2018
2019
0
    return m_aLinkURL;
2020
0
}
2021
2022
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */