Coverage Report

Created: 2026-06-30 11:14

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/package/source/xstor/owriteablestream.cxx
Line
Count
Source
1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
/*
3
 * This file is part of the LibreOffice project.
4
 *
5
 * This Source Code Form is subject to the terms of the Mozilla Public
6
 * License, v. 2.0. If a copy of the MPL was not distributed with this
7
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8
 *
9
 * This file incorporates work covered by the following license notice:
10
 *
11
 *   Licensed to the Apache Software Foundation (ASF) under one or more
12
 *   contributor license agreements. See the NOTICE file distributed
13
 *   with this work for additional information regarding copyright
14
 *   ownership. The ASF licenses this file to you under the Apache
15
 *   License, Version 2.0 (the "License"); you may not use this file
16
 *   except in compliance with the License. You may obtain a copy of
17
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18
 */
19
20
#include <sal/config.h>
21
22
#include <cassert>
23
#include <memory>
24
#include <sal/log.hxx>
25
26
#include <com/sun/star/packages/NoEncryptionException.hpp>
27
#include <com/sun/star/packages/WrongPasswordException.hpp>
28
#include <com/sun/star/uno/XComponentContext.hpp>
29
#include <com/sun/star/ucb/SimpleFileAccess.hpp>
30
#include <com/sun/star/lang/DisposedException.hpp>
31
#include <com/sun/star/lang/XTypeProvider.hpp>
32
#include <com/sun/star/io/NotConnectedException.hpp>
33
#include <com/sun/star/io/TempFile.hpp>
34
#include <com/sun/star/io/XInputStream.hpp>
35
#include <com/sun/star/io/IOException.hpp>
36
#include <com/sun/star/embed/ElementModes.hpp>
37
#include <com/sun/star/embed/StorageFormats.hpp>
38
#include <com/sun/star/embed/StorageWrappedTargetException.hpp>
39
#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
40
#include <cppuhelper/typeprovider.hxx>
41
#include <cppuhelper/queryinterface.hxx>
42
#include <cppuhelper/exc_hlp.hxx>
43
#include <osl/diagnose.h>
44
#include <tools/stream.hxx>
45
46
#include <comphelper/memorystream.hxx>
47
#include <comphelper/processfactory.hxx>
48
#include <comphelper/servicehelper.hxx>
49
#include <comphelper/storagehelper.hxx>
50
#include <comphelper/ofopxmlhelper.hxx>
51
#include <comphelper/refcountedmutex.hxx>
52
#include <comphelper/sequence.hxx>
53
54
#include <comphelper/diagnose_ex.hxx>
55
56
#include <PackageConstants.hxx>
57
#include <utility>
58
59
#include "selfterminatefilestream.hxx"
60
#include "owriteablestream.hxx"
61
#include "oseekinstream.hxx"
62
#include "xstorage.hxx"
63
64
// since the copying uses 32000 blocks usually, it makes sense to have a smaller size
65
33.3k
#define MAX_STORCACHE_SIZE 30000
66
67
using namespace ::com::sun::star;
68
69
namespace package
70
{
71
72
static void CopyInputToOutput(
73
    const css::uno::Reference< css::io::XInputStream >& xInput,
74
    SvStream& rOutput )
75
717
{
76
717
    static const sal_Int32 nConstBufferSize = 32000;
77
78
717
    if (auto pByteReader = dynamic_cast< comphelper::ByteReader* >( xInput.get() ))
79
717
    {
80
717
        sal_Int32 nRead;
81
717
        sal_Int8 aTempBuf[ nConstBufferSize ];
82
717
        do
83
1.42k
        {
84
1.42k
            nRead = pByteReader->readSomeBytes ( aTempBuf, nConstBufferSize );
85
1.42k
            rOutput.WriteBytes ( aTempBuf, nRead );
86
1.42k
        }
87
1.42k
        while ( nRead == nConstBufferSize );
88
717
    }
89
0
    else
90
0
    {
91
0
        sal_Int32 nRead;
92
0
        uno::Sequence < sal_Int8 > aSequence ( nConstBufferSize );
93
94
0
        do
95
0
        {
96
0
            nRead = xInput->readBytes ( aSequence, nConstBufferSize );
97
0
            rOutput.WriteBytes ( aSequence.getConstArray(), nRead );
98
0
        }
99
0
        while ( nRead == nConstBufferSize );
100
0
    }
101
717
}
102
103
bool PackageEncryptionDataLessOrEqual( const ::comphelper::SequenceAsHashMap& aHash1, const ::comphelper::SequenceAsHashMap& aHash2 )
104
0
{
105
    // tdf#93389: aHash2 may contain more than in aHash1, if it contains also data for other package
106
    // formats (as in case of autorecovery)
107
0
    bool bResult = !aHash1.empty() && aHash1.size() <= aHash2.size();
108
0
    for ( ::comphelper::SequenceAsHashMap::const_iterator aIter = aHash1.begin();
109
0
          bResult && aIter != aHash1.end();
110
0
          ++aIter )
111
0
    {
112
0
        uno::Sequence< sal_Int8 > aKey1;
113
0
        bResult = ( ( aIter->second >>= aKey1 ) && aKey1.hasElements() );
114
0
        if ( bResult )
115
0
        {
116
0
            const uno::Sequence< sal_Int8 > aKey2 = aHash2.getUnpackedValueOrDefault( aIter->first.maString, uno::Sequence< sal_Int8 >() );
117
0
            bResult = aKey1.getLength() == aKey2.getLength()
118
0
                && std::equal(std::cbegin(aKey1), std::cend(aKey1), aKey2.begin(), aKey2.end());
119
0
        }
120
0
    }
121
122
0
    return bResult;
123
0
}
124
125
} // namespace package
126
127
namespace
128
{
129
130
void SetEncryptionKeyProperty_Impl( const uno::Reference< beans::XPropertySet >& xPropertySet,
131
                                    const uno::Sequence< beans::NamedValue >& aKey )
132
0
{
133
0
    SAL_WARN_IF( !xPropertySet.is(), "package.xstor", "No property set is provided!" );
134
0
    if ( !xPropertySet.is() )
135
0
        throw uno::RuntimeException();
136
137
0
    try {
138
0
        xPropertySet->setPropertyValue( STORAGE_ENCRYPTION_KEYS_PROPERTY, uno::Any( aKey ) );
139
0
    }
140
0
    catch ( const uno::Exception& ex )
141
0
    {
142
0
        TOOLS_WARN_EXCEPTION( "package.xstor", "Can't write encryption related properties");
143
0
        throw io::IOException(ex.Message); // TODO
144
0
    }
145
0
}
146
147
uno::Any GetEncryptionKeyProperty_Impl( const uno::Reference< beans::XPropertySet >& xPropertySet )
148
0
{
149
0
    SAL_WARN_IF( !xPropertySet.is(), "package.xstor", "No property set is provided!" );
150
0
    if ( !xPropertySet.is() )
151
0
        throw uno::RuntimeException();
152
153
0
    try {
154
0
        return xPropertySet->getPropertyValue(STORAGE_ENCRYPTION_KEYS_PROPERTY);
155
0
    }
156
0
    catch ( const uno::Exception& ex )
157
0
    {
158
0
        TOOLS_WARN_EXCEPTION( "package.xstor", "Can't get encryption related properties");
159
0
        throw io::IOException(ex.Message); // TODO
160
0
    }
161
0
}
162
163
bool SequencesEqual( const uno::Sequence< sal_Int8 >& aSequence1, const uno::Sequence< sal_Int8 >& aSequence2 )
164
0
{
165
0
    return aSequence1.getLength() == aSequence2.getLength()
166
0
        && std::equal(aSequence1.begin(), aSequence1.end(), aSequence2.begin(), aSequence2.end());
167
0
}
168
169
bool SequencesEqual( const uno::Sequence< beans::NamedValue >& aSequence1, const uno::Sequence< beans::NamedValue >& aSequence2 )
170
0
{
171
0
    if ( aSequence1.getLength() != aSequence2.getLength() )
172
0
        return false;
173
174
0
    for ( const auto& rProp1 : aSequence1 )
175
0
    {
176
0
        bool bHasMember = false;
177
0
        uno::Sequence< sal_Int8 > aMember1;
178
0
        sal_Int32 nMember1 = 0;
179
0
        if ( rProp1.Value >>= aMember1 )
180
0
        {
181
0
            for ( const auto& rProp2 : aSequence2 )
182
0
            {
183
0
                if ( rProp1.Name == rProp2.Name )
184
0
                {
185
0
                    bHasMember = true;
186
187
0
                    uno::Sequence< sal_Int8 > aMember2;
188
0
                    if ( !( rProp2.Value >>= aMember2 ) || !SequencesEqual( aMember1, aMember2 ) )
189
0
                        return false;
190
0
                }
191
0
            }
192
0
        }
193
0
        else if ( rProp1.Value >>= nMember1 )
194
0
        {
195
0
            for ( const auto& rProp2 : aSequence2 )
196
0
            {
197
0
                if ( rProp1.Name == rProp2.Name )
198
0
                {
199
0
                    bHasMember = true;
200
201
0
                    sal_Int32 nMember2 = 0;
202
0
                    if ( !( rProp2.Value >>= nMember2 ) || nMember1 != nMember2 )
203
0
                        return false;
204
0
                }
205
0
            }
206
0
        }
207
0
        else
208
0
            return false;
209
210
0
        if ( !bHasMember )
211
0
            return false;
212
0
    }
213
214
0
    return true;
215
0
}
216
217
const beans::StringPair* lcl_findPairByName(const uno::Sequence<beans::StringPair>& rSeq, const OUString& rName)
218
0
{
219
0
    return std::find_if(rSeq.begin(), rSeq.end(),
220
0
        [&rName](const beans::StringPair& rPair) { return rPair.First == rName; });
221
0
}
222
223
} // anonymous namespace
224
225
OWriteStream_Impl::OWriteStream_Impl( OStorage_Impl* pParent,
226
                                      const uno::Reference< packages::XDataSinkEncrSupport >& xPackageStream,
227
                                      const uno::Reference< lang::XSingleServiceFactory >& xPackage,
228
                                      uno::Reference< uno::XComponentContext > xContext,
229
                                      bool bForceEncrypted,
230
                                      sal_Int32 nStorageType,
231
                                      bool bDefaultCompress,
232
                                      uno::Reference< io::XInputStream > xRelInfoStream )
233
153k
: m_xMutex( new comphelper::RefCountedMutex )
234
153k
, m_pAntiImpl( nullptr )
235
153k
, m_bHasDataToFlush( false )
236
153k
, m_bFlushed( false )
237
153k
, m_xPackageStream( xPackageStream )
238
153k
, m_xContext(std::move( xContext ))
239
153k
, m_pParent( pParent )
240
153k
, m_bForceEncrypted( bForceEncrypted )
241
153k
, m_bUseCommonEncryption( !bForceEncrypted && nStorageType == embed::StorageFormats::PACKAGE )
242
153k
, m_bHasCachedEncryptionData( false )
243
153k
, m_bCompressedSetExplicit( !bDefaultCompress )
244
153k
, m_xPackage( xPackage )
245
153k
, m_bHasInsertedStreamOptimization( false )
246
153k
, m_nStorageType( nStorageType )
247
153k
, m_xOrigRelInfoStream(std::move( xRelInfoStream ))
248
153k
, m_bOrigRelInfoBroken( false )
249
153k
, m_nRelInfoStatus( RELINFO_NO_INIT )
250
153k
, m_nRelId( 1 )
251
153k
{
252
153k
    SAL_WARN_IF( !xPackageStream.is(), "package.xstor", "No package stream is provided!" );
253
153k
    SAL_WARN_IF( !xPackage.is(), "package.xstor", "No package component is provided!" );
254
153k
    SAL_WARN_IF( !m_xContext.is(), "package.xstor", "No package stream is provided!" );
255
153k
    OSL_ENSURE( pParent, "No parent storage is provided!" );
256
153k
    OSL_ENSURE( m_nStorageType == embed::StorageFormats::OFOPXML || !m_xOrigRelInfoStream.is(), "The Relations info makes sense only for OFOPXML format!" );
257
153k
}
258
259
OWriteStream_Impl::~OWriteStream_Impl()
260
153k
{
261
153k
    DisposeWrappers();
262
263
153k
    m_oTempFile.reset();
264
265
153k
    CleanCacheStream();
266
153k
}
267
268
void OWriteStream_Impl::CleanCacheStream()
269
153k
{
270
153k
    if ( !m_xCacheStream.is() )
271
144k
        return;
272
273
8.98k
    try
274
8.98k
    {
275
8.98k
        uno::Reference< io::XInputStream > xInputCache = m_xCacheStream->getInputStream();
276
8.98k
        if ( xInputCache.is() )
277
8.98k
            xInputCache->closeInput();
278
8.98k
    }
279
8.98k
    catch( const uno::Exception& )
280
8.98k
    {}
281
282
8.98k
    try
283
8.98k
    {
284
8.98k
        uno::Reference< io::XOutputStream > xOutputCache = m_xCacheStream->getOutputStream();
285
8.98k
        if ( xOutputCache.is() )
286
8.98k
            xOutputCache->closeOutput();
287
8.98k
    }
288
8.98k
    catch( const uno::Exception& )
289
8.98k
    {}
290
291
8.98k
    m_xCacheStream.clear();
292
8.98k
    m_xCacheSeek.clear();
293
8.98k
}
294
295
void OWriteStream_Impl::InsertIntoPackageFolder( const OUString& aName,
296
                                                  const uno::Reference< container::XNameContainer >& xParentPackageFolder )
297
0
{
298
0
    ::osl::MutexGuard aGuard( m_xMutex->GetMutex() );
299
300
0
    SAL_WARN_IF( !m_bFlushed, "package.xstor", "This method must not be called for nonflushed streams!" );
301
0
    if ( m_bFlushed )
302
0
    {
303
0
        SAL_WARN_IF( !m_xPackageStream.is(), "package.xstor", "An inserted stream is incomplete!" );
304
0
        uno::Reference< uno::XInterface > xTmp( m_xPackageStream, uno::UNO_QUERY_THROW );
305
0
        xParentPackageFolder->insertByName( aName, uno::Any( xTmp ) );
306
307
0
        m_bFlushed = false;
308
0
        m_bHasInsertedStreamOptimization = false;
309
0
    }
310
0
}
311
bool OWriteStream_Impl::IsEncrypted()
312
174k
{
313
174k
    if ( m_nStorageType != embed::StorageFormats::PACKAGE )
314
173k
        return false;
315
316
1.07k
    if ( m_bForceEncrypted || m_bHasCachedEncryptionData )
317
0
        return true;
318
319
1.07k
    if ( m_oTempFile.has_value() || m_xCacheStream.is() )
320
0
        return false;
321
322
1.07k
    GetStreamProperties();
323
324
    // the following value can not be cached since it can change after root commit
325
1.07k
    bool bWasEncr = false;
326
1.07k
    uno::Reference< beans::XPropertySet > xPropSet( m_xPackageStream, uno::UNO_QUERY );
327
1.07k
    if ( xPropSet.is() )
328
1.07k
    {
329
1.07k
        uno::Any aValue = xPropSet->getPropertyValue(u"WasEncrypted"_ustr);
330
1.07k
        if ( !( aValue >>= bWasEncr ) )
331
0
        {
332
0
            SAL_WARN( "package.xstor", "The property WasEncrypted has wrong type!" );
333
0
        }
334
1.07k
    }
335
336
1.07k
    bool bToBeEncr = false;
337
1.07k
    for (const auto& rProp : m_aProps)
338
4.31k
    {
339
4.31k
        if ( rProp.Name == "Encrypted" )
340
1.07k
        {
341
1.07k
            if ( !( rProp.Value >>= bToBeEncr ) )
342
0
            {
343
0
                SAL_WARN( "package.xstor", "The property has wrong type!" );
344
0
            }
345
1.07k
        }
346
4.31k
    }
347
348
    // since a new key set to the package stream it should not be removed except the case when
349
    // the stream becomes nonencrypted
350
1.07k
    uno::Sequence< beans::NamedValue > aKey;
351
1.07k
    if ( bToBeEncr )
352
0
        GetEncryptionKeyProperty_Impl( xPropSet ) >>= aKey;
353
354
    // If the properties must be investigated the stream is either
355
    // was never changed or was changed, the parent was committed
356
    // and the stream was closed.
357
    // That means that if it is intended to use common storage key
358
    // it is already has no encryption but is marked to be stored
359
    // encrypted and the key is empty.
360
1.07k
    if ( !bWasEncr && bToBeEncr && !aKey.hasElements() )
361
0
    {
362
        // the stream is intended to use common storage password
363
0
        m_bUseCommonEncryption = true;
364
0
        return false;
365
0
    }
366
1.07k
    else
367
1.07k
        return bToBeEncr;
368
1.07k
}
369
370
void OWriteStream_Impl::SetDecrypted()
371
0
{
372
0
    SAL_WARN_IF( m_nStorageType != embed::StorageFormats::PACKAGE, "package.xstor", "The encryption is supported only for package storages!" );
373
0
    if ( m_nStorageType != embed::StorageFormats::PACKAGE )
374
0
        throw uno::RuntimeException();
375
376
0
    GetStreamProperties();
377
378
    // let the stream be modified
379
0
    FillTempGetFileName();
380
0
    m_bHasDataToFlush = true;
381
382
    // remove encryption
383
0
    m_bForceEncrypted = false;
384
0
    m_bHasCachedEncryptionData = false;
385
0
    m_aEncryptionData.clear();
386
387
0
    for ( auto& rProp : asNonConstRange(m_aProps) )
388
0
    {
389
0
        if ( rProp.Name == "Encrypted" )
390
0
            rProp.Value <<= false;
391
0
    }
392
0
}
393
394
void OWriteStream_Impl::SetEncrypted( const ::comphelper::SequenceAsHashMap& aEncryptionData )
395
0
{
396
0
    SAL_WARN_IF( m_nStorageType != embed::StorageFormats::PACKAGE, "package.xstor", "The encryption is supported only for package storages!" );
397
0
    if ( m_nStorageType != embed::StorageFormats::PACKAGE )
398
0
        throw uno::RuntimeException();
399
400
0
    if ( aEncryptionData.empty() )
401
0
        throw uno::RuntimeException();
402
403
0
    GetStreamProperties();
404
405
    // let the stream be modified
406
0
    FillTempGetFileName();
407
0
    m_bHasDataToFlush = true;
408
409
    // introduce encryption info
410
0
    for ( auto& rProp : asNonConstRange(m_aProps) )
411
0
    {
412
0
        if ( rProp.Name == "Encrypted" )
413
0
            rProp.Value <<= true;
414
0
    }
415
416
0
    m_bUseCommonEncryption = false; // very important to set it to false
417
418
0
    m_bHasCachedEncryptionData = true;
419
0
    m_aEncryptionData = aEncryptionData;
420
0
}
421
422
void OWriteStream_Impl::DisposeWrappers()
423
153k
{
424
153k
    ::osl::MutexGuard aGuard( m_xMutex->GetMutex() );
425
153k
    if ( m_pAntiImpl )
426
0
    {
427
0
        try {
428
0
            m_pAntiImpl->dispose();
429
0
        }
430
0
        catch ( const uno::RuntimeException& )
431
0
        {
432
0
            TOOLS_INFO_EXCEPTION("package.xstor", "Quiet exception");
433
0
        }
434
435
0
        m_pAntiImpl = nullptr;
436
0
    }
437
153k
    m_pParent = nullptr;
438
439
153k
    if ( m_aInputStreamsVector.empty() )
440
153k
        return;
441
442
3
    for ( auto& pStream : m_aInputStreamsVector )
443
3
    {
444
3
        if ( pStream )
445
3
        {
446
3
            pStream->InternalDispose();
447
3
            pStream = nullptr;
448
3
        }
449
3
    }
450
451
3
    m_aInputStreamsVector.clear();
452
3
}
453
454
void OWriteStream_Impl::GetFilledTempFileIfNo( const uno::Reference< io::XInputStream >& xStream )
455
4
{
456
4
    if ( !m_oTempFile.has_value() )
457
4
    {
458
4
        m_oTempFile.emplace();
459
460
4
        try {
461
4
            if ( xStream.is() )
462
4
            {
463
                // the current position of the original stream should be still OK, copy further
464
4
                package::CopyInputToOutput( xStream, *m_oTempFile->GetStream(StreamMode::READWRITE) );
465
4
            }
466
4
        }
467
4
        catch( const packages::WrongPasswordException& )
468
4
        {
469
0
            TOOLS_INFO_EXCEPTION("package.xstor", "Rethrow");
470
0
            m_oTempFile.reset();
471
0
            throw;
472
0
        }
473
4
        catch( const uno::Exception& )
474
4
        {
475
0
            TOOLS_INFO_EXCEPTION("package.xstor", "Rethrow");
476
0
            m_oTempFile.reset();
477
0
            throw;
478
0
        }
479
480
4
        if ( m_oTempFile.has_value() )
481
4
            CleanCacheStream();
482
4
    }
483
4
}
484
485
void OWriteStream_Impl::FillTempGetFileName()
486
11.0k
{
487
    // should try to create cache first, if the amount of contents is too big, the temp file should be taken
488
11.0k
    if ( !m_xCacheStream.is() && !m_oTempFile.has_value() )
489
11.0k
    {
490
11.0k
        uno::Reference< io::XInputStream > xOrigStream = m_xPackageStream->getDataStream();
491
11.0k
        if ( !xOrigStream.is() )
492
54
        {
493
            // in case of new inserted package stream it is possible that input stream still was not set
494
54
            rtl::Reference< comphelper::UNOMemoryStream > xCacheStream = new comphelper::UNOMemoryStream();
495
54
            m_xCacheSeek = xCacheStream;
496
54
            m_xCacheStream = std::move(xCacheStream);
497
54
        }
498
11.0k
        else
499
11.0k
        {
500
11.0k
            sal_Int32 nRead = 0;
501
11.0k
            uno::Sequence< sal_Int8 > aData( MAX_STORCACHE_SIZE + 1 );
502
11.0k
            nRead = xOrigStream->readBytes( aData, MAX_STORCACHE_SIZE + 1 );
503
11.0k
            if ( aData.getLength() > nRead )
504
0
                aData.realloc( nRead );
505
506
11.0k
            if ( nRead <= MAX_STORCACHE_SIZE )
507
9.19k
            {
508
9.19k
                rtl::Reference< comphelper::UNOMemoryStream > xCacheStream = new comphelper::UNOMemoryStream();
509
510
9.19k
                if ( nRead )
511
9.19k
                {
512
9.19k
                    uno::Reference< io::XOutputStream > xOutStream( xCacheStream->getOutputStream(), uno::UNO_SET_THROW );
513
9.19k
                    xOutStream->writeBytes( aData );
514
9.19k
                }
515
9.19k
                m_xCacheSeek = xCacheStream;
516
9.19k
                m_xCacheStream = std::move(xCacheStream);
517
9.19k
                m_xCacheSeek->seek( 0 );
518
9.19k
            }
519
1.81k
            else if ( !m_oTempFile.has_value() )
520
713
            {
521
713
                m_oTempFile.emplace();
522
523
713
                try {
524
                    // copy stream contents to the file
525
713
                    SvStream* pStream = m_oTempFile->GetStream(StreamMode::READWRITE);
526
713
                    pStream->WriteBytes( aData.getConstArray(), aData.getLength() );
527
528
                    // the current position of the original stream should be still OK, copy further
529
713
                    package::CopyInputToOutput( xOrigStream, *pStream );
530
713
                }
531
713
                catch( const packages::WrongPasswordException& )
532
713
                {
533
0
                    m_oTempFile.reset();
534
0
                    throw;
535
0
                }
536
713
                catch( const uno::Exception& )
537
713
                {
538
93
                    m_oTempFile.reset();
539
93
                }
540
713
            }
541
11.0k
        }
542
11.0k
    }
543
11.0k
}
544
545
uno::Reference< io::XStream > OWriteStream_Impl::GetTempFileAsStream()
546
276
{
547
276
    uno::Reference< io::XStream > xTempStream;
548
549
276
    if ( !m_xCacheStream.is() )
550
276
    {
551
276
        if ( !m_oTempFile.has_value() )
552
272
            FillTempGetFileName();
553
554
276
        if ( m_oTempFile.has_value() )
555
8
        {
556
            // the temporary file is not used if the cache is used
557
8
            try
558
8
            {
559
8
                SvStream* pStream = m_oTempFile->GetStream(StreamMode::READWRITE);
560
8
                pStream->Seek(0);
561
8
                xTempStream = new utl::OStreamWrapper(pStream, /*bOwner*/false);
562
8
            }
563
8
            catch( const uno::Exception& )
564
8
            {
565
0
                TOOLS_INFO_EXCEPTION("package.xstor", "Quiet exception");
566
0
            }
567
8
        }
568
276
    }
569
570
276
    if ( m_xCacheStream.is() )
571
268
        xTempStream = m_xCacheStream;
572
573
    // the method must always return a stream
574
    // in case the stream can not be open
575
    // an exception should be thrown
576
276
    if ( !xTempStream.is() )
577
0
        throw io::IOException(u"no temp stream"_ustr); //TODO:
578
579
276
    return xTempStream;
580
276
}
581
582
uno::Reference< io::XInputStream > OWriteStream_Impl::GetTempFileAsInputStream()
583
12.8k
{
584
12.8k
    uno::Reference< io::XInputStream > xInputStream;
585
586
12.8k
    if ( !m_xCacheStream.is() )
587
10.7k
    {
588
10.7k
        if ( !m_oTempFile.has_value() )
589
10.7k
            FillTempGetFileName();
590
591
10.7k
        if ( m_oTempFile.has_value() )
592
616
        {
593
            // the temporary file is not used if the cache is used
594
616
            try
595
616
            {
596
616
                SvStream* pStream = m_oTempFile->GetStream(StreamMode::READWRITE);
597
616
                pStream->Seek(0);
598
616
                xInputStream = new utl::OStreamWrapper(pStream, /*bOwner*/false);
599
616
            }
600
616
            catch( const uno::Exception& )
601
616
            {
602
0
                TOOLS_INFO_EXCEPTION("package.xstor", "Quiet exception");
603
0
            }
604
616
        }
605
10.7k
    }
606
607
12.8k
    if ( m_xCacheStream.is() )
608
11.0k
        xInputStream = m_xCacheStream->getInputStream();
609
610
    // the method must always return a stream
611
    // in case the stream can not be open
612
    // an exception should be thrown
613
12.8k
    if ( !xInputStream.is() )
614
93
        throw io::IOException(); // TODO:
615
616
12.7k
    return xInputStream;
617
12.8k
}
618
619
void OWriteStream_Impl::InsertStreamDirectly( const uno::Reference< io::XInputStream >& xInStream,
620
                                              const uno::Sequence< beans::PropertyValue >& aProps )
621
0
{
622
0
    ::osl::MutexGuard aGuard( m_xMutex->GetMutex() ) ;
623
624
    // this call can be made only during parent storage commit
625
    // the  parent storage is responsible for the correct handling
626
    // of deleted and renamed contents
627
628
0
    SAL_WARN_IF( !m_xPackageStream.is(), "package.xstor", "No package stream is set!" );
629
630
0
    if ( m_bHasDataToFlush )
631
0
        throw io::IOException(u"m_bHasDataToFlush==true"_ustr);
632
633
0
    OSL_ENSURE( !m_oTempFile.has_value() && !m_xCacheStream.is(), "The temporary must not exist!" );
634
635
    // use new file as current persistent representation
636
    // the new file will be removed after it's stream is closed
637
0
    m_xPackageStream->setDataStream( xInStream );
638
639
    // copy properties to the package stream
640
0
    uno::Reference< beans::XPropertySet > xPropertySet( m_xPackageStream, uno::UNO_QUERY_THROW );
641
642
    // The storage-package communication has a problem
643
    // the storage caches properties, thus if the package changes one of them itself
644
    // the storage does not know about it
645
646
    // Depending from MediaType value the package can change the compressed property itself
647
    // Thus if Compressed property is provided it must be set as the latest one
648
0
    bool bCompressedIsSet = false;
649
0
    bool bCompressed = false;
650
0
    OUString aComprPropName( u"Compressed"_ustr );
651
0
    OUString aMedTypePropName( u"MediaType"_ustr );
652
0
    for ( const auto& rProp : aProps )
653
0
    {
654
0
        if ( rProp.Name == aComprPropName )
655
0
        {
656
0
            bCompressedIsSet = true;
657
0
            rProp.Value >>= bCompressed;
658
0
        }
659
0
        else if ( ( m_nStorageType == embed::StorageFormats::OFOPXML || m_nStorageType == embed::StorageFormats::PACKAGE )
660
0
               && rProp.Name == aMedTypePropName )
661
0
        {
662
0
            xPropertySet->setPropertyValue( rProp.Name, rProp.Value );
663
0
        }
664
0
        else if ( m_nStorageType == embed::StorageFormats::PACKAGE && rProp.Name == "UseCommonStoragePasswordEncryption" )
665
0
            rProp.Value >>= m_bUseCommonEncryption;
666
0
        else
667
0
            throw lang::IllegalArgumentException();
668
669
        // if there are cached properties update them
670
0
        if ( rProp.Name == aMedTypePropName || rProp.Name == aComprPropName )
671
0
            for ( auto& rMemProp : asNonConstRange(m_aProps) )
672
0
            {
673
0
                if ( rProp.Name == rMemProp.Name )
674
0
                    rMemProp.Value = rProp.Value;
675
0
            }
676
0
    }
677
678
0
    if ( bCompressedIsSet )
679
0
    {
680
0
        xPropertySet->setPropertyValue( aComprPropName, uno::Any( bCompressed ) );
681
0
        m_bCompressedSetExplicit = true;
682
0
    }
683
684
0
    if ( m_bUseCommonEncryption )
685
0
    {
686
0
        if ( m_nStorageType != embed::StorageFormats::PACKAGE )
687
0
            throw uno::RuntimeException();
688
689
        // set to be encrypted but do not use encryption key
690
0
        xPropertySet->setPropertyValue( STORAGE_ENCRYPTION_KEYS_PROPERTY,
691
0
                                        uno::Any( uno::Sequence< beans::NamedValue >() ) );
692
0
        xPropertySet->setPropertyValue( u"Encrypted"_ustr, uno::Any( true ) );
693
0
    }
694
695
    // the stream should be free soon, after package is stored
696
0
    m_bHasDataToFlush = false;
697
0
    m_bFlushed = true; // will allow to use transaction on stream level if will need it
698
0
    m_bHasInsertedStreamOptimization = true;
699
0
}
700
701
void OWriteStream_Impl::Commit()
702
480
{
703
480
    ::osl::MutexGuard aGuard( m_xMutex->GetMutex() ) ;
704
705
480
    SAL_WARN_IF( !m_xPackageStream.is(), "package.xstor", "No package stream is set!" );
706
707
480
    if ( !m_bHasDataToFlush )
708
0
        return;
709
710
480
    uno::Reference< packages::XDataSinkEncrSupport > xNewPackageStream;
711
480
    uno::Sequence< uno::Any > aSeq{ uno::Any(false) };
712
713
480
    if ( m_xCacheStream.is() )
714
472
    {
715
472
        if ( m_pAntiImpl )
716
221
            m_pAntiImpl->DeInit();
717
718
472
        uno::Reference< io::XInputStream > xInStream( m_xCacheStream->getInputStream(), uno::UNO_SET_THROW );
719
720
472
        xNewPackageStream.set( m_xPackage->createInstanceWithArguments( aSeq ), uno::UNO_QUERY_THROW );
721
722
472
        xNewPackageStream->setDataStream( xInStream );
723
724
472
        m_xCacheStream.clear();
725
472
        m_xCacheSeek.clear();
726
727
472
    }
728
8
    else if ( m_oTempFile.has_value() )
729
8
    {
730
8
        if ( m_pAntiImpl )
731
4
            m_pAntiImpl->DeInit();
732
733
8
        rtl::Reference< OSelfTerminateFileStream > xInStream;
734
8
        try
735
8
        {
736
8
            xInStream = new OSelfTerminateFileStream(m_xContext, std::move(*m_oTempFile));
737
8
        }
738
8
        catch( const uno::Exception& )
739
8
        {
740
0
            TOOLS_WARN_EXCEPTION("package", "");
741
0
        }
742
743
8
        if ( !xInStream.is() )
744
0
            throw io::IOException();
745
746
8
        xNewPackageStream.set( m_xPackage->createInstanceWithArguments( aSeq ), uno::UNO_QUERY_THROW );
747
748
        // TODO/NEW: Let the temporary file be removed after commit
749
8
        xNewPackageStream->setDataStream( xInStream );
750
8
        m_oTempFile.reset();
751
8
    }
752
0
    else // if ( m_bHasInsertedStreamOptimization )
753
0
    {
754
        // if the optimization is used the stream can be accessed directly
755
0
        xNewPackageStream = m_xPackageStream;
756
0
    }
757
758
    // copy properties to the package stream
759
480
    uno::Reference< beans::XPropertySet > xPropertySet( xNewPackageStream, uno::UNO_QUERY_THROW );
760
761
480
    for ( auto& rProp : asNonConstRange(m_aProps) )
762
1.92k
    {
763
1.92k
        if ( rProp.Name == "Size" )
764
480
        {
765
480
            if ( m_pAntiImpl && !m_bHasInsertedStreamOptimization && m_pAntiImpl->m_xSeekable.is() )
766
0
            {
767
0
                rProp.Value <<= m_pAntiImpl->m_xSeekable->getLength();
768
0
                xPropertySet->setPropertyValue( rProp.Name, rProp.Value );
769
0
            }
770
480
        }
771
1.44k
        else
772
1.44k
            xPropertySet->setPropertyValue( rProp.Name, rProp.Value );
773
1.92k
    }
774
775
480
    if ( m_bUseCommonEncryption )
776
480
    {
777
480
        if ( m_nStorageType != embed::StorageFormats::PACKAGE )
778
0
            throw uno::RuntimeException();
779
780
        // set to be encrypted but do not use encryption key
781
480
        xPropertySet->setPropertyValue( STORAGE_ENCRYPTION_KEYS_PROPERTY,
782
480
                                        uno::Any( uno::Sequence< beans::NamedValue >() ) );
783
480
        xPropertySet->setPropertyValue( u"Encrypted"_ustr,
784
480
                                        uno::Any( true ) );
785
480
    }
786
0
    else if ( m_bHasCachedEncryptionData )
787
0
    {
788
0
        if ( m_nStorageType != embed::StorageFormats::PACKAGE )
789
0
            throw uno::RuntimeException();
790
791
0
        xPropertySet->setPropertyValue( STORAGE_ENCRYPTION_KEYS_PROPERTY,
792
0
                                        uno::Any( m_aEncryptionData.getAsConstNamedValueList() ) );
793
0
    }
794
795
    // the stream should be free soon, after package is stored
796
480
    m_xPackageStream = std::move(xNewPackageStream);
797
480
    m_bHasDataToFlush = false;
798
480
    m_bFlushed = true; // will allow to use transaction on stream level if will need it
799
480
}
800
801
void OWriteStream_Impl::Revert()
802
0
{
803
    // can be called only from parent storage
804
    // means complete reload of the stream
805
806
0
    ::osl::MutexGuard aGuard( m_xMutex->GetMutex() ) ;
807
808
0
    if ( !m_bHasDataToFlush )
809
0
        return; // nothing to do
810
811
0
    OSL_ENSURE( m_oTempFile.has_value() || m_xCacheStream.is(), "The temporary must exist!" );
812
813
0
    if ( m_xCacheStream.is() )
814
0
    {
815
0
        m_xCacheStream.clear();
816
0
        m_xCacheSeek.clear();
817
0
    }
818
819
0
    m_oTempFile.reset();
820
821
0
    m_aProps.realloc( 0 );
822
823
0
    m_bHasDataToFlush = false;
824
825
0
    m_bUseCommonEncryption = true;
826
0
    m_bHasCachedEncryptionData = false;
827
0
    m_aEncryptionData.clear();
828
829
0
    if ( m_nStorageType != embed::StorageFormats::OFOPXML )
830
0
        return;
831
832
    // currently the relations storage is changed only on commit
833
0
    m_xNewRelInfoStream.clear();
834
0
    m_aNewRelInfo = uno::Sequence< uno::Sequence< beans::StringPair > >();
835
0
    if ( m_xOrigRelInfoStream.is() )
836
0
    {
837
        // the original stream is still here, that means that it was not parsed
838
0
        m_aOrigRelInfo = uno::Sequence< uno::Sequence< beans::StringPair > >();
839
0
        m_nRelInfoStatus = RELINFO_NO_INIT;
840
0
    }
841
0
    else
842
0
    {
843
        // the original stream was already parsed
844
0
        if ( !m_bOrigRelInfoBroken )
845
0
            m_nRelInfoStatus = RELINFO_READ;
846
0
        else
847
0
            m_nRelInfoStatus = RELINFO_BROKEN;
848
0
    }
849
0
}
850
851
uno::Sequence< beans::PropertyValue > const & OWriteStream_Impl::GetStreamProperties()
852
176k
{
853
176k
    if ( !m_aProps.hasElements() )
854
153k
        m_aProps = ReadPackageStreamProperties();
855
856
176k
    return m_aProps;
857
176k
}
858
859
uno::Sequence< beans::PropertyValue > OWriteStream_Impl::InsertOwnProps(
860
                                                                    const uno::Sequence< beans::PropertyValue >& aProps,
861
                                                                    bool bUseCommonEncryption )
862
141k
{
863
141k
    uno::Sequence< beans::PropertyValue > aResult( aProps );
864
141k
    beans::PropertyValue aPropVal;
865
866
141k
    if ( m_nStorageType == embed::StorageFormats::PACKAGE )
867
806
    {
868
806
        aPropVal.Name = "UseCommonStoragePasswordEncryption";
869
806
        aPropVal.Value <<= bUseCommonEncryption;
870
806
    }
871
140k
    else if ( m_nStorageType == embed::StorageFormats::OFOPXML )
872
37.9k
    {
873
37.9k
        ReadRelInfoIfNecessary();
874
875
37.9k
        aPropVal.Name = "RelationsInfo";
876
37.9k
        if ( m_nRelInfoStatus == RELINFO_READ )
877
37.9k
            aPropVal.Value <<= m_aOrigRelInfo;
878
0
        else if ( m_nRelInfoStatus == RELINFO_CHANGED_STREAM_READ || m_nRelInfoStatus == RELINFO_CHANGED )
879
0
            aPropVal.Value <<= m_aNewRelInfo;
880
0
        else // m_nRelInfoStatus == RELINFO_CHANGED_BROKEN || m_nRelInfoStatus == RELINFO_BROKEN
881
0
            throw io::IOException( u"Wrong relinfo stream!"_ustr );
882
37.9k
    }
883
141k
    if (!aPropVal.Name.isEmpty())
884
38.7k
    {
885
38.7k
        sal_Int32 i = 0;
886
155k
        for (auto p = aResult.getConstArray(); i < aResult.getLength(); ++i)
887
117k
            if (p[i].Name == aPropVal.Name)
888
0
                break;
889
38.7k
        if (i == aResult.getLength())
890
38.7k
            aResult.realloc(i + 1);
891
38.7k
        aResult.getArray()[i] = std::move(aPropVal);
892
38.7k
    }
893
894
141k
    return aResult;
895
141k
}
896
897
bool OWriteStream_Impl::IsTransacted()
898
0
{
899
0
    ::osl::MutexGuard aGuard( m_xMutex->GetMutex() ) ;
900
0
    return ( m_pAntiImpl && m_pAntiImpl->m_bTransacted );
901
0
}
902
903
void OWriteStream_Impl::ReadRelInfoIfNecessary()
904
212k
{
905
212k
    if ( m_nStorageType != embed::StorageFormats::OFOPXML )
906
125k
        return;
907
908
86.7k
    if ( m_nRelInfoStatus == RELINFO_NO_INIT )
909
44.8k
    {
910
44.8k
        try
911
44.8k
        {
912
            // Init from original stream
913
44.8k
            if ( m_xOrigRelInfoStream.is() )
914
3.42k
                m_aOrigRelInfo = ::comphelper::OFOPXMLHelper::ReadRelationsInfoSequence(
915
3.42k
                                        m_xOrigRelInfoStream,
916
3.42k
                                        u"_rels/*.rels",
917
3.42k
                                        m_xContext );
918
919
            // in case of success the stream must be thrown away, that means that the OrigRelInfo is initialized
920
            // the reason for this is that the original stream might not be seekable ( at the same time the new
921
            // provided stream must be seekable ), so it must be read only once
922
44.8k
            m_xOrigRelInfoStream.clear();
923
44.8k
            m_nRelInfoStatus = RELINFO_READ;
924
44.8k
        }
925
44.8k
        catch( const uno::Exception& )
926
44.8k
        {
927
0
            TOOLS_INFO_EXCEPTION("package.xstor", "Quiet exception");
928
929
0
            m_nRelInfoStatus = RELINFO_BROKEN;
930
0
            m_bOrigRelInfoBroken = true;
931
0
        }
932
44.8k
    }
933
41.9k
    else if ( m_nRelInfoStatus == RELINFO_CHANGED_STREAM )
934
0
    {
935
        // Init from the new stream
936
0
        try
937
0
        {
938
0
            if ( m_xNewRelInfoStream.is() )
939
0
                m_aNewRelInfo = ::comphelper::OFOPXMLHelper::ReadRelationsInfoSequence(
940
0
                                        m_xNewRelInfoStream,
941
0
                                        u"_rels/*.rels",
942
0
                                        m_xContext );
943
944
0
            m_nRelInfoStatus = RELINFO_CHANGED_STREAM_READ;
945
0
        }
946
0
        catch( const uno::Exception& )
947
0
        {
948
0
            m_nRelInfoStatus = RELINFO_CHANGED_BROKEN;
949
0
        }
950
0
    }
951
86.7k
}
952
953
uno::Sequence< beans::PropertyValue > OWriteStream_Impl::ReadPackageStreamProperties()
954
153k
{
955
153k
    sal_Int32 nPropNum = 0;
956
153k
    if ( m_nStorageType == embed::StorageFormats::ZIP )
957
108k
        nPropNum = 2;
958
45.1k
    else if ( m_nStorageType == embed::StorageFormats::OFOPXML )
959
44.8k
        nPropNum = 3;
960
251
    else if ( m_nStorageType == embed::StorageFormats::PACKAGE )
961
251
        nPropNum = 4;
962
153k
    assert(nPropNum >= 2);
963
153k
    uno::Sequence< beans::PropertyValue > aResult( nPropNum );
964
153k
    auto aResultRange = asNonConstRange(aResult);
965
966
    // The "Compressed" property must be set after "MediaType" property,
967
    // since the setting of the last one can change the value of the first one
968
153k
    static constexpr OUStringLiteral sMediaType = u"MediaType";
969
153k
    static constexpr OUString sCompressed = u"Compressed"_ustr;
970
153k
    static constexpr OUString sSize = u"Size"_ustr;
971
153k
    static constexpr OUStringLiteral sEncrypted = u"Encrypted";
972
153k
    if ( m_nStorageType == embed::StorageFormats::OFOPXML || m_nStorageType == embed::StorageFormats::PACKAGE )
973
45.1k
    {
974
45.1k
        aResultRange[0].Name = sMediaType;
975
45.1k
        aResultRange[1].Name = sCompressed;
976
45.1k
        aResultRange[2].Name = sSize;
977
978
45.1k
        if ( m_nStorageType == embed::StorageFormats::PACKAGE )
979
251
            aResultRange[3].Name = sEncrypted;
980
45.1k
    }
981
108k
    else
982
108k
    {
983
108k
        aResultRange[0].Name = sCompressed;
984
108k
        aResultRange[1].Name = sSize;
985
108k
    }
986
987
    // TODO: may be also raw stream should be marked
988
989
153k
    uno::Reference< beans::XPropertySet > xPropSet( m_xPackageStream, uno::UNO_QUERY_THROW );
990
153k
    for ( auto& rProp : aResultRange )
991
352k
    {
992
352k
        try {
993
352k
            rProp.Value = xPropSet->getPropertyValue( rProp.Name );
994
352k
        }
995
352k
        catch( const uno::Exception& )
996
352k
        {
997
0
            TOOLS_WARN_EXCEPTION( "package.xstor", "A property can't be retrieved" );
998
0
        }
999
352k
    }
1000
1001
153k
    return aResult;
1002
153k
}
1003
1004
void OWriteStream_Impl::CopyInternallyTo_Impl( const uno::Reference< io::XStream >& xDestStream,
1005
                                                const ::comphelper::SequenceAsHashMap& aEncryptionData )
1006
0
{
1007
0
    ::osl::MutexGuard aGuard( m_xMutex->GetMutex() ) ;
1008
1009
0
    SAL_WARN_IF( m_bUseCommonEncryption, "package.xstor", "The stream can not be encrypted!" );
1010
1011
0
    if ( m_nStorageType != embed::StorageFormats::PACKAGE )
1012
0
        throw packages::NoEncryptionException();
1013
1014
0
    if ( m_pAntiImpl )
1015
0
    {
1016
0
        m_pAntiImpl->CopyToStreamInternally_Impl( xDestStream );
1017
0
    }
1018
0
    else
1019
0
    {
1020
0
        uno::Reference< io::XStream > xOwnStream = GetStream( embed::ElementModes::READ, aEncryptionData, false );
1021
0
        if ( !xOwnStream.is() )
1022
0
            throw io::IOException(); // TODO
1023
1024
0
        OStorage_Impl::completeStorageStreamCopy_Impl( xOwnStream, xDestStream, m_nStorageType, GetAllRelationshipsIfAny() );
1025
0
    }
1026
1027
0
    uno::Reference< embed::XEncryptionProtectedSource2 > xEncr( xDestStream, uno::UNO_QUERY );
1028
0
    if ( xEncr.is() )
1029
0
        xEncr->setEncryptionData( aEncryptionData.getAsConstNamedValueList() );
1030
0
}
1031
1032
uno::Sequence< uno::Sequence< beans::StringPair > > OWriteStream_Impl::GetAllRelationshipsIfAny()
1033
11
{
1034
11
    if ( m_nStorageType != embed::StorageFormats::OFOPXML )
1035
11
        return uno::Sequence< uno::Sequence< beans::StringPair > >();
1036
1037
0
    ReadRelInfoIfNecessary();
1038
1039
0
    if ( m_nRelInfoStatus == RELINFO_READ )
1040
0
        return m_aOrigRelInfo;
1041
0
    else if ( m_nRelInfoStatus == RELINFO_CHANGED_STREAM_READ || m_nRelInfoStatus == RELINFO_CHANGED )
1042
0
        return m_aNewRelInfo;
1043
0
    else // m_nRelInfoStatus == RELINFO_CHANGED_BROKEN || m_nRelInfoStatus == RELINFO_BROKEN
1044
0
            throw io::IOException( u"Wrong relinfo stream!"_ustr );
1045
0
}
1046
1047
void OWriteStream_Impl::CopyInternallyTo_Impl( const uno::Reference< io::XStream >& xDestStream )
1048
11
{
1049
11
    ::osl::MutexGuard aGuard( m_xMutex->GetMutex() ) ;
1050
1051
11
    if ( m_pAntiImpl )
1052
0
    {
1053
0
        m_pAntiImpl->CopyToStreamInternally_Impl( xDestStream );
1054
0
    }
1055
11
    else
1056
11
    {
1057
11
        uno::Reference< io::XStream > xOwnStream = GetStream( embed::ElementModes::READ, false );
1058
11
        if ( !xOwnStream.is() )
1059
0
            throw io::IOException(); // TODO
1060
1061
11
        OStorage_Impl::completeStorageStreamCopy_Impl( xOwnStream, xDestStream, m_nStorageType, GetAllRelationshipsIfAny() );
1062
11
    }
1063
11
}
1064
1065
uno::Reference< io::XStream > OWriteStream_Impl::GetStream( sal_Int32 nStreamMode, const ::comphelper::SequenceAsHashMap& aEncryptionData, bool bHierarchyAccess )
1066
0
{
1067
0
    ::osl::MutexGuard aGuard( m_xMutex->GetMutex() ) ;
1068
1069
0
    SAL_WARN_IF( !m_xPackageStream.is(), "package.xstor", "No package stream is set!" );
1070
1071
0
    if ( m_pAntiImpl )
1072
0
        throw io::IOException(); // TODO:
1073
1074
0
    if ( !IsEncrypted() )
1075
0
        throw packages::NoEncryptionException();
1076
1077
0
    uno::Reference< io::XStream > xResultStream;
1078
1079
0
    uno::Reference< beans::XPropertySet > xPropertySet( m_xPackageStream, uno::UNO_QUERY_THROW );
1080
1081
0
    if ( m_bHasCachedEncryptionData )
1082
0
    {
1083
0
        if ( !::package::PackageEncryptionDataLessOrEqual( m_aEncryptionData, aEncryptionData ) )
1084
0
            throw packages::WrongPasswordException();
1085
1086
        // the correct key must be set already
1087
0
        xResultStream = GetStream_Impl( nStreamMode, bHierarchyAccess );
1088
0
    }
1089
0
    else
1090
0
    {
1091
0
        SetEncryptionKeyProperty_Impl( xPropertySet, aEncryptionData.getAsConstNamedValueList() );
1092
1093
0
        try {
1094
0
            xResultStream = GetStream_Impl( nStreamMode, bHierarchyAccess );
1095
1096
0
            m_bUseCommonEncryption = false; // very important to set it to false
1097
0
            m_bHasCachedEncryptionData = true;
1098
0
            m_aEncryptionData = aEncryptionData;
1099
0
        }
1100
0
        catch( const packages::WrongPasswordException& )
1101
0
        {
1102
0
            TOOLS_INFO_EXCEPTION("package.xstor", "Rethrow");
1103
0
            SetEncryptionKeyProperty_Impl( xPropertySet, uno::Sequence< beans::NamedValue >() );
1104
0
            throw;
1105
0
        }
1106
0
        catch ( const uno::Exception& ex )
1107
0
        {
1108
0
            TOOLS_WARN_EXCEPTION("package.xstor", "GetStream: decrypting stream failed");
1109
0
            SetEncryptionKeyProperty_Impl( xPropertySet, uno::Sequence< beans::NamedValue >() );
1110
0
            throw io::IOException(ex.Message); // TODO:
1111
0
        }
1112
0
    }
1113
1114
0
    SAL_WARN_IF( !xResultStream.is(), "package.xstor", "In case stream can not be retrieved an exception must be thrown!" );
1115
1116
0
    return xResultStream;
1117
0
}
1118
1119
uno::Reference< io::XStream > OWriteStream_Impl::GetStream( sal_Int32 nStreamMode, bool bHierarchyAccess )
1120
174k
{
1121
174k
    ::osl::MutexGuard aGuard( m_xMutex->GetMutex() ) ;
1122
1123
174k
    SAL_WARN_IF( !m_xPackageStream.is(), "package.xstor", "No package stream is set!" );
1124
1125
174k
    if ( m_pAntiImpl )
1126
0
        throw io::IOException(); // TODO:
1127
1128
174k
    uno::Reference< io::XStream > xResultStream;
1129
1130
174k
    if ( IsEncrypted() )
1131
0
    {
1132
0
        ::comphelper::SequenceAsHashMap aGlobalEncryptionData;
1133
0
        try
1134
0
        {
1135
0
            aGlobalEncryptionData = GetCommonRootEncryptionData();
1136
0
        }
1137
0
        catch( const packages::NoEncryptionException& )
1138
0
        {
1139
0
            TOOLS_INFO_EXCEPTION("package.xstor", "Rethrow");
1140
0
            throw packages::WrongPasswordException();
1141
0
        }
1142
1143
0
        xResultStream = GetStream( nStreamMode, aGlobalEncryptionData, bHierarchyAccess );
1144
0
    }
1145
174k
    else
1146
174k
        xResultStream = GetStream_Impl( nStreamMode, bHierarchyAccess );
1147
1148
174k
    return xResultStream;
1149
174k
}
1150
1151
uno::Reference< io::XStream > OWriteStream_Impl::GetStream_Impl( sal_Int32 nStreamMode, bool bHierarchyAccess )
1152
174k
{
1153
    // private method, no mutex is used
1154
174k
    GetStreamProperties();
1155
1156
    // TODO/LATER: this info might be read later, on demand in future
1157
174k
    ReadRelInfoIfNecessary();
1158
1159
174k
    if ( ( nStreamMode & embed::ElementModes::READWRITE ) == embed::ElementModes::READ )
1160
154k
    {
1161
154k
        uno::Reference< io::XInputStream > xInStream;
1162
154k
        if ( m_xCacheStream.is() || m_oTempFile.has_value() )
1163
0
            xInStream = GetTempFileAsInputStream(); //TODO:
1164
154k
        else
1165
154k
            xInStream = m_xPackageStream->getDataStream();
1166
1167
        // The stream does not exist in the storage
1168
154k
        if ( !xInStream.is() )
1169
0
            throw io::IOException();
1170
1171
154k
        rtl::Reference<OInputCompStream> pStream = new OInputCompStream( *this, xInStream, InsertOwnProps( m_aProps, m_bUseCommonEncryption ), m_nStorageType );
1172
154k
        m_aInputStreamsVector.push_back( pStream.get() );
1173
154k
        return pStream;
1174
154k
    }
1175
20.0k
    else if ( ( nStreamMode & embed::ElementModes::READWRITE ) == embed::ElementModes::SEEKABLEREAD )
1176
19.7k
    {
1177
19.7k
        if ( !m_xCacheStream.is() && !m_oTempFile.has_value() && !( m_xPackageStream->getDataStream().is() ) )
1178
0
        {
1179
            // The stream does not exist in the storage
1180
0
            throw io::IOException();
1181
0
        }
1182
1183
19.7k
        uno::Reference< io::XInputStream > xInStream = GetTempFileAsInputStream(); //TODO:
1184
1185
19.7k
        if ( !xInStream.is() )
1186
0
            throw io::IOException();
1187
1188
19.7k
        rtl::Reference<OInputSeekStream> pStream = new OInputSeekStream( *this, xInStream, InsertOwnProps( m_aProps, m_bUseCommonEncryption ), m_nStorageType );
1189
19.7k
        m_aInputStreamsVector.push_back( pStream.get() );
1190
19.7k
        return pStream;
1191
19.7k
    }
1192
262
    else if ( ( nStreamMode & embed::ElementModes::WRITE ) == embed::ElementModes::WRITE )
1193
262
    {
1194
262
        if ( !m_aInputStreamsVector.empty() )
1195
0
            throw io::IOException(); // TODO:
1196
1197
262
        uno::Reference< io::XStream > xStream;
1198
262
        if ( ( nStreamMode & embed::ElementModes::TRUNCATE ) == embed::ElementModes::TRUNCATE )
1199
208
        {
1200
208
            m_oTempFile.reset();
1201
208
            if ( m_xCacheStream.is() )
1202
0
                CleanCacheStream();
1203
1204
208
            m_bHasDataToFlush = true;
1205
1206
            // this call is triggered by the parent and it will recognize the change of the state
1207
208
            if ( m_pParent )
1208
208
                m_pParent->m_bIsModified = true;
1209
1210
208
            rtl::Reference<comphelper::UNOMemoryStream> xMemStream = new comphelper::UNOMemoryStream();
1211
208
            xStream = xMemStream;
1212
208
            m_xCacheSeek = xMemStream;
1213
208
            m_xCacheStream = xStream;
1214
208
        }
1215
54
        else if ( !m_bHasInsertedStreamOptimization )
1216
54
        {
1217
54
            if ( !m_oTempFile.has_value() && !m_xCacheStream.is() && !( m_xPackageStream->getDataStream().is() ) )
1218
54
            {
1219
                // The stream does not exist in the storage
1220
54
                m_bHasDataToFlush = true;
1221
1222
                // this call is triggered by the parent and it will recognize the change of the state
1223
54
                if ( m_pParent )
1224
54
                    m_pParent->m_bIsModified = true;
1225
54
                xStream = GetTempFileAsStream();
1226
54
            }
1227
1228
            // if the stream exists the temporary file is created on demand
1229
            // xStream = GetTempFileAsStream();
1230
54
        }
1231
1232
262
        rtl::Reference<OWriteStream> tmp;
1233
262
        assert(m_xMutex.is() && "No mutex!");
1234
262
        if ( !xStream.is() )
1235
0
            tmp = new OWriteStream( *this, bHierarchyAccess );
1236
262
        else
1237
262
            tmp = new OWriteStream( *this, xStream, bHierarchyAccess );
1238
1239
262
        m_pAntiImpl = tmp.get();
1240
262
        return tmp;
1241
262
    }
1242
1243
0
    throw lang::IllegalArgumentException(); // TODO
1244
174k
}
1245
1246
uno::Reference< io::XInputStream > OWriteStream_Impl::GetPlainRawInStream()
1247
0
{
1248
0
    ::osl::MutexGuard aGuard( m_xMutex->GetMutex() ) ;
1249
1250
0
    SAL_WARN_IF( !m_xPackageStream.is(), "package.xstor", "No package stream is set!" );
1251
1252
    // this method is used only internally, this stream object should not go outside of this implementation
1253
    // if ( m_pAntiImpl )
1254
    //  throw io::IOException(); // TODO:
1255
1256
0
    return m_xPackageStream->getPlainRawStream();
1257
0
}
1258
1259
uno::Reference< io::XInputStream > OWriteStream_Impl::GetRawInStream()
1260
0
{
1261
0
    ::osl::MutexGuard aGuard( m_xMutex->GetMutex() ) ;
1262
1263
0
    SAL_WARN_IF( !m_xPackageStream.is(), "package.xstor", "No package stream is set!" );
1264
1265
0
    if ( m_pAntiImpl )
1266
0
        throw io::IOException(); // TODO:
1267
1268
0
    SAL_WARN_IF( !IsEncrypted(), "package.xstor", "Impossible to get raw representation for nonencrypted stream!" );
1269
0
    if ( !IsEncrypted() )
1270
0
        throw packages::NoEncryptionException();
1271
1272
0
    return m_xPackageStream->getRawStream();
1273
0
}
1274
1275
::comphelper::SequenceAsHashMap OWriteStream_Impl::GetCommonRootEncryptionData()
1276
0
{
1277
0
    ::osl::MutexGuard aGuard( m_xMutex->GetMutex() ) ;
1278
1279
0
    if ( m_nStorageType != embed::StorageFormats::PACKAGE || !m_pParent )
1280
0
        throw packages::NoEncryptionException();
1281
1282
0
    return m_pParent->GetCommonRootEncryptionData();
1283
0
}
1284
1285
void OWriteStream_Impl::InputStreamDisposed( OInputCompStream* pStream )
1286
141k
{
1287
141k
    ::osl::MutexGuard aGuard( m_xMutex->GetMutex() );
1288
141k
    std::erase(m_aInputStreamsVector, pStream);
1289
141k
}
1290
1291
void OWriteStream_Impl::CreateReadonlyCopyBasedOnData( const uno::Reference< io::XInputStream >& xDataToCopy, const uno::Sequence< beans::PropertyValue >& aProps, uno::Reference< io::XStream >& xTargetStream )
1292
0
{
1293
0
    uno::Reference < io::XStream > xTempFile;
1294
0
    if ( !xTargetStream.is() )
1295
0
        xTempFile = new utl::TempFileFastService;
1296
0
    else
1297
0
        xTempFile = xTargetStream;
1298
1299
0
    uno::Reference < io::XSeekable > xTempSeek( xTempFile, uno::UNO_QUERY_THROW );
1300
1301
0
    uno::Reference < io::XOutputStream > xTempOut(xTempFile->getOutputStream(), uno::UNO_SET_THROW);
1302
1303
0
    if ( xDataToCopy.is() )
1304
0
        ::comphelper::OStorageHelper::CopyInputToOutput( xDataToCopy, xTempOut );
1305
1306
0
    xTempOut->closeOutput();
1307
0
    xTempSeek->seek( 0 );
1308
1309
0
    uno::Reference< io::XInputStream > xInStream = xTempFile->getInputStream();
1310
0
    if ( !xInStream.is() )
1311
0
        throw io::IOException();
1312
1313
    // TODO: remember last state of m_bUseCommonEncryption
1314
0
    if ( !xTargetStream.is() )
1315
0
        xTargetStream.set(
1316
0
            new OInputSeekStream( xInStream, InsertOwnProps( aProps, m_bUseCommonEncryption ), m_nStorageType ) );
1317
0
}
1318
1319
void OWriteStream_Impl::GetCopyOfLastCommit( uno::Reference< io::XStream >& xTargetStream )
1320
0
{
1321
0
    ::osl::MutexGuard aGuard( m_xMutex->GetMutex() );
1322
1323
0
    SAL_WARN_IF( !m_xPackageStream.is(), "package.xstor", "The source stream for copying is incomplete!" );
1324
0
    if ( !m_xPackageStream.is() )
1325
0
        throw uno::RuntimeException();
1326
1327
0
    uno::Reference< io::XInputStream > xDataToCopy;
1328
0
    if ( IsEncrypted() )
1329
0
    {
1330
        // an encrypted stream must contain input stream
1331
0
        ::comphelper::SequenceAsHashMap aGlobalEncryptionData;
1332
0
        try
1333
0
        {
1334
0
            aGlobalEncryptionData = GetCommonRootEncryptionData();
1335
0
        }
1336
0
        catch( const packages::NoEncryptionException& )
1337
0
        {
1338
0
            TOOLS_INFO_EXCEPTION("package.xstor", "No Element");
1339
0
            throw packages::WrongPasswordException();
1340
0
        }
1341
1342
0
        GetCopyOfLastCommit( xTargetStream, aGlobalEncryptionData );
1343
0
    }
1344
0
    else
1345
0
    {
1346
0
        xDataToCopy = m_xPackageStream->getDataStream();
1347
1348
        // in case of new inserted package stream it is possible that input stream still was not set
1349
0
        GetStreamProperties();
1350
1351
0
        CreateReadonlyCopyBasedOnData( xDataToCopy, m_aProps, xTargetStream );
1352
0
    }
1353
0
}
1354
1355
void OWriteStream_Impl::GetCopyOfLastCommit( uno::Reference< io::XStream >& xTargetStream, const ::comphelper::SequenceAsHashMap& aEncryptionData )
1356
0
{
1357
0
    ::osl::MutexGuard aGuard( m_xMutex->GetMutex() );
1358
1359
0
    SAL_WARN_IF( !m_xPackageStream.is(), "package.xstor", "The source stream for copying is incomplete!" );
1360
0
    if ( !m_xPackageStream.is() )
1361
0
        throw uno::RuntimeException();
1362
1363
0
    if ( !IsEncrypted() )
1364
0
        throw packages::NoEncryptionException();
1365
1366
0
    uno::Reference< io::XInputStream > xDataToCopy;
1367
1368
0
    if ( m_bHasCachedEncryptionData )
1369
0
    {
1370
        // TODO: introduce last committed cashed password information and use it here
1371
        // that means "use common pass" also should be remembered on flash
1372
0
        uno::Sequence< beans::NamedValue > aKey = aEncryptionData.getAsConstNamedValueList();
1373
1374
0
        uno::Reference< beans::XPropertySet > xProps( m_xPackageStream, uno::UNO_QUERY_THROW );
1375
1376
0
        bool bEncr = false;
1377
0
        xProps->getPropertyValue( u"Encrypted"_ustr ) >>= bEncr;
1378
0
        if ( !bEncr )
1379
0
            throw packages::NoEncryptionException();
1380
1381
0
        uno::Sequence< beans::NamedValue > aPackKey;
1382
0
        xProps->getPropertyValue( STORAGE_ENCRYPTION_KEYS_PROPERTY ) >>= aPackKey;
1383
0
        if ( !SequencesEqual( aKey, aPackKey ) )
1384
0
            throw packages::WrongPasswordException();
1385
1386
        // the correct key must be set already
1387
0
        xDataToCopy = m_xPackageStream->getDataStream();
1388
0
    }
1389
0
    else
1390
0
    {
1391
0
        uno::Reference< beans::XPropertySet > xPropertySet( m_xPackageStream, uno::UNO_QUERY );
1392
0
        SetEncryptionKeyProperty_Impl( xPropertySet, aEncryptionData.getAsConstNamedValueList() );
1393
1394
0
        try {
1395
0
            xDataToCopy = m_xPackageStream->getDataStream();
1396
1397
0
            if ( !xDataToCopy.is() )
1398
0
            {
1399
0
                SAL_WARN( "package.xstor", "Encrypted ZipStream must already have input stream inside!" );
1400
0
                SetEncryptionKeyProperty_Impl( xPropertySet, uno::Sequence< beans::NamedValue >() );
1401
0
            }
1402
0
        }
1403
0
        catch( const uno::Exception& )
1404
0
        {
1405
0
            TOOLS_WARN_EXCEPTION( "package.xstor", "Can't open encrypted stream");
1406
0
            SetEncryptionKeyProperty_Impl( xPropertySet, uno::Sequence< beans::NamedValue >() );
1407
0
            throw;
1408
0
        }
1409
1410
0
        SetEncryptionKeyProperty_Impl( xPropertySet, uno::Sequence< beans::NamedValue >() );
1411
0
    }
1412
1413
    // in case of new inserted package stream it is possible that input stream still was not set
1414
0
    GetStreamProperties();
1415
1416
0
    CreateReadonlyCopyBasedOnData( xDataToCopy, m_aProps, xTargetStream );
1417
0
}
1418
1419
void OWriteStream_Impl::CommitStreamRelInfo( const uno::Reference< embed::XStorage >& xRelStorage, std::u16string_view aOrigStreamName, std::u16string_view aNewStreamName )
1420
0
{
1421
    // at this point of time the old stream must be already cleaned
1422
0
    OSL_ENSURE( m_nStorageType == embed::StorageFormats::OFOPXML, "The method should be used only with OFOPXML format!" );
1423
1424
0
    if ( m_nStorageType != embed::StorageFormats::OFOPXML )
1425
0
        return;
1426
1427
0
    OSL_ENSURE( !aOrigStreamName.empty() && !aNewStreamName.empty() && xRelStorage.is(),
1428
0
                "Wrong relation persistence information is provided!" );
1429
1430
0
    if ( !xRelStorage.is() || aOrigStreamName.empty() || aNewStreamName.empty() )
1431
0
        throw uno::RuntimeException();
1432
1433
0
    if ( m_nRelInfoStatus == RELINFO_BROKEN || m_nRelInfoStatus == RELINFO_CHANGED_BROKEN )
1434
0
        throw io::IOException(); // TODO:
1435
1436
0
    OUString aOrigRelStreamName = OUString::Concat(aOrigStreamName) + ".rels";
1437
0
    OUString aNewRelStreamName = OUString::Concat(aNewStreamName) + ".rels";
1438
1439
0
    bool bRenamed = aOrigRelStreamName != aNewRelStreamName;
1440
0
    if ( m_nRelInfoStatus == RELINFO_CHANGED
1441
0
      || m_nRelInfoStatus == RELINFO_CHANGED_STREAM_READ
1442
0
      || m_nRelInfoStatus == RELINFO_CHANGED_STREAM )
1443
0
    {
1444
0
        if ( bRenamed && xRelStorage->hasByName( aOrigRelStreamName ) )
1445
0
            xRelStorage->removeElement( aOrigRelStreamName );
1446
1447
0
        if ( m_nRelInfoStatus == RELINFO_CHANGED )
1448
0
        {
1449
0
            if ( m_aNewRelInfo.hasElements() )
1450
0
            {
1451
0
                uno::Reference< io::XStream > xRelsStream =
1452
0
                    xRelStorage->openStreamElement( aNewRelStreamName,
1453
0
                                                      embed::ElementModes::TRUNCATE | embed::ElementModes::READWRITE );
1454
1455
0
                uno::Reference< io::XOutputStream > xOutStream = xRelsStream->getOutputStream();
1456
0
                if ( !xOutStream.is() )
1457
0
                    throw uno::RuntimeException();
1458
1459
0
                ::comphelper::OFOPXMLHelper::WriteRelationsInfoSequence( xOutStream, m_aNewRelInfo, m_xContext );
1460
1461
                // set the mediatype
1462
0
                uno::Reference< beans::XPropertySet > xPropSet( xRelsStream, uno::UNO_QUERY_THROW );
1463
0
                xPropSet->setPropertyValue(
1464
0
                    u"MediaType"_ustr,
1465
0
                    uno::Any( u"application/vnd.openxmlformats-package.relationships+xml"_ustr ) );
1466
1467
0
                m_nRelInfoStatus = RELINFO_READ;
1468
0
            }
1469
0
        }
1470
0
        else if ( m_nRelInfoStatus == RELINFO_CHANGED_STREAM_READ
1471
0
                  || m_nRelInfoStatus == RELINFO_CHANGED_STREAM )
1472
0
        {
1473
0
            uno::Reference< io::XStream > xRelsStream =
1474
0
                xRelStorage->openStreamElement( aNewRelStreamName,
1475
0
                                                    embed::ElementModes::TRUNCATE | embed::ElementModes::READWRITE );
1476
1477
0
            uno::Reference< io::XOutputStream > xOutputStream = xRelsStream->getOutputStream();
1478
0
            if ( !xOutputStream.is() )
1479
0
                throw uno::RuntimeException();
1480
1481
0
            uno::Reference< io::XSeekable > xSeek( m_xNewRelInfoStream, uno::UNO_QUERY_THROW );
1482
0
            xSeek->seek( 0 );
1483
0
            ::comphelper::OStorageHelper::CopyInputToOutput( m_xNewRelInfoStream, xOutputStream );
1484
0
            xSeek->seek( 0 );
1485
1486
            // set the mediatype
1487
0
            uno::Reference< beans::XPropertySet > xPropSet( xRelsStream, uno::UNO_QUERY_THROW );
1488
0
            xPropSet->setPropertyValue(u"MediaType"_ustr,
1489
0
                uno::Any( u"application/vnd.openxmlformats-package.relationships+xml"_ustr ) );
1490
1491
0
            if ( m_nRelInfoStatus == RELINFO_CHANGED_STREAM )
1492
0
                m_nRelInfoStatus = RELINFO_NO_INIT;
1493
0
            else
1494
0
            {
1495
                // the information is already parsed and the stream is stored, no need in temporary stream any more
1496
0
                m_xNewRelInfoStream.clear();
1497
0
                m_nRelInfoStatus = RELINFO_READ;
1498
0
            }
1499
0
        }
1500
1501
        // the original stream makes no sense after this step
1502
0
        m_xOrigRelInfoStream = m_xNewRelInfoStream;
1503
0
        m_aOrigRelInfo = m_aNewRelInfo;
1504
0
        m_bOrigRelInfoBroken = false;
1505
0
        m_aNewRelInfo = uno::Sequence< uno::Sequence< beans::StringPair > >();
1506
0
        m_xNewRelInfoStream.clear();
1507
0
    }
1508
0
    else
1509
0
    {
1510
        // the stream is not changed but it might be renamed
1511
0
        if ( bRenamed && xRelStorage->hasByName( aOrigRelStreamName ) )
1512
0
            xRelStorage->renameElement( aOrigRelStreamName, aNewRelStreamName );
1513
0
    }
1514
0
}
1515
1516
// OWriteStream implementation
1517
1518
OWriteStream::OWriteStream( OWriteStream_Impl& rImpl, bool bTransacted )
1519
0
: m_pImpl( &rImpl )
1520
0
, m_xSharedMutex( rImpl.m_xMutex )
1521
0
, m_aListenersContainer( rImpl.m_xMutex->GetMutex() )
1522
0
, m_nStorageType( m_pImpl->m_nStorageType )
1523
0
, m_bInStreamDisconnected( false )
1524
0
, m_bInitOnDemand( true )
1525
0
, m_nInitPosition( 0 )
1526
0
, m_bTransacted( bTransacted )
1527
0
{
1528
0
}
1529
1530
OWriteStream::OWriteStream( OWriteStream_Impl& rImpl, uno::Reference< io::XStream > const & xStream, bool bTransacted )
1531
262
: m_pImpl( &rImpl )
1532
262
, m_xSharedMutex( rImpl.m_xMutex )
1533
262
, m_aListenersContainer( rImpl.m_xMutex->GetMutex() )
1534
262
, m_nStorageType( m_pImpl->m_nStorageType )
1535
262
, m_bInStreamDisconnected( false )
1536
262
, m_bInitOnDemand( false )
1537
262
, m_nInitPosition( 0 )
1538
262
, m_bTransacted( bTransacted )
1539
262
{
1540
262
    if ( xStream.is() )
1541
262
    {
1542
262
        m_xInStream = xStream->getInputStream();
1543
262
        m_xOutStream = xStream->getOutputStream();
1544
262
        m_xSeekable.set( xStream, uno::UNO_QUERY );
1545
262
        OSL_ENSURE( m_xInStream.is() && m_xOutStream.is() && m_xSeekable.is(), "Stream implementation is incomplete!" );
1546
262
    }
1547
262
}
1548
1549
OWriteStream::~OWriteStream()
1550
262
{
1551
262
    ::osl::MutexGuard aGuard( m_xSharedMutex->GetMutex() );
1552
262
    if ( m_pImpl )
1553
215
    {
1554
215
        osl_atomic_increment(&m_refCount);
1555
215
        try {
1556
215
            dispose();
1557
215
        }
1558
215
        catch( const uno::RuntimeException& )
1559
215
        {
1560
0
            TOOLS_INFO_EXCEPTION("package.xstor", "Quiet exception");
1561
0
        }
1562
215
    }
1563
262
}
1564
1565
void OWriteStream::DeInit()
1566
229
{
1567
229
    if ( !m_pImpl )
1568
0
        return; // do nothing
1569
1570
229
    if ( m_xSeekable.is() )
1571
229
        m_nInitPosition = m_xSeekable->getPosition();
1572
1573
229
    m_xInStream.clear();
1574
229
    m_xOutStream.clear();
1575
229
    m_xSeekable.clear();
1576
229
    m_bInitOnDemand = true;
1577
229
}
1578
1579
void OWriteStream::CheckInitOnDemand()
1580
1.29k
{
1581
1.29k
    if ( !m_pImpl )
1582
0
    {
1583
0
        SAL_INFO("package.xstor", "Disposed!");
1584
0
        throw lang::DisposedException();
1585
0
    }
1586
1587
1.29k
    if ( !m_bInitOnDemand )
1588
1.07k
        return;
1589
1590
218
    SAL_INFO( "package.xstor", "package (mv76033) OWriteStream::CheckInitOnDemand, initializing" );
1591
218
    uno::Reference< io::XStream > xStream = m_pImpl->GetTempFileAsStream();
1592
218
    if ( xStream.is() )
1593
218
    {
1594
218
        m_xInStream.set( xStream->getInputStream(), uno::UNO_SET_THROW );
1595
218
        m_xOutStream.set( xStream->getOutputStream(), uno::UNO_SET_THROW );
1596
218
        m_xSeekable.set( xStream, uno::UNO_QUERY_THROW );
1597
218
        m_xSeekable->seek( m_nInitPosition );
1598
1599
218
        m_nInitPosition = 0;
1600
218
        m_bInitOnDemand = false;
1601
218
    }
1602
218
}
1603
1604
void OWriteStream::CopyToStreamInternally_Impl( const uno::Reference< io::XStream >& xDest )
1605
0
{
1606
0
    ::osl::MutexGuard aGuard( m_xSharedMutex->GetMutex() );
1607
1608
0
    CheckInitOnDemand();
1609
1610
0
    if ( !m_xInStream.is() )
1611
0
        throw uno::RuntimeException();
1612
1613
0
    if ( !m_xSeekable.is() )
1614
0
        throw uno::RuntimeException();
1615
1616
0
    uno::Reference< beans::XPropertySet > xDestProps( xDest, uno::UNO_QUERY_THROW );
1617
1618
0
    uno::Reference< io::XOutputStream > xDestOutStream = xDest->getOutputStream();
1619
0
    if ( !xDestOutStream.is() )
1620
0
        throw io::IOException(); // TODO
1621
1622
0
    sal_Int64 nCurPos = m_xSeekable->getPosition();
1623
0
    m_xSeekable->seek( 0 );
1624
1625
0
    uno::Exception eThrown;
1626
0
    bool bThrown = false;
1627
0
    try {
1628
0
        ::comphelper::OStorageHelper::CopyInputToOutput( m_xInStream, xDestOutStream );
1629
0
    }
1630
0
    catch ( const uno::Exception& e )
1631
0
    {
1632
0
        eThrown = e;
1633
0
        bThrown = true;
1634
0
    }
1635
1636
    // position-related section below is critical
1637
    // if it fails the stream will become invalid
1638
0
    try {
1639
0
        m_xSeekable->seek( nCurPos );
1640
0
    }
1641
0
    catch ( const uno::Exception& )
1642
0
    {
1643
        // TODO: set the stream in invalid state or dispose
1644
0
        TOOLS_WARN_EXCEPTION( "package.xstor", "The stream become invalid during copying" );
1645
0
        throw uno::RuntimeException();
1646
0
    }
1647
1648
0
    if ( bThrown )
1649
0
        throw eThrown;
1650
1651
    // now the properties can be copied
1652
    // the order of the properties setting is not important for StorageStream API
1653
0
    OUString aPropName (u"Compressed"_ustr);
1654
0
    xDestProps->setPropertyValue( aPropName, getPropertyValue( aPropName ) );
1655
0
    if ( m_nStorageType == embed::StorageFormats::PACKAGE || m_nStorageType == embed::StorageFormats::OFOPXML )
1656
0
    {
1657
0
        aPropName = "MediaType";
1658
0
        xDestProps->setPropertyValue( aPropName, getPropertyValue( aPropName ) );
1659
1660
0
        if ( m_nStorageType == embed::StorageFormats::PACKAGE )
1661
0
        {
1662
0
            aPropName = "UseCommonStoragePasswordEncryption";
1663
0
            xDestProps->setPropertyValue( aPropName, getPropertyValue( aPropName ) );
1664
0
        }
1665
0
    }
1666
0
}
1667
1668
void OWriteStream::ModifyParentUnlockMutex_Impl(osl::ClearableMutexGuard& aGuard)
1669
553
{
1670
553
    if ( m_pImpl->m_pParent )
1671
553
    {
1672
553
        if ( m_pImpl->m_pParent->HasModifiedListener() )
1673
0
        {
1674
0
            uno::Reference< util::XModifiable > xParentModif( static_cast<util::XModifiable*>(m_pImpl->m_pParent->m_pAntiImpl) );
1675
0
            aGuard.clear();
1676
0
            xParentModif->setModified( true );
1677
0
        }
1678
553
        else
1679
553
            m_pImpl->m_pParent->m_bIsModified = true;
1680
553
    }
1681
553
}
1682
1683
uno::Any SAL_CALL OWriteStream::queryInterface( const uno::Type& rType )
1684
560
{
1685
    // common interfaces
1686
560
    uno::Any aReturn = ::cppu::queryInterface
1687
560
                (   rType
1688
560
                    ,   static_cast<lang::XTypeProvider*> ( this )
1689
560
                    ,   static_cast<io::XInputStream*> ( this )
1690
560
                    ,   static_cast<io::XOutputStream*> ( this )
1691
560
                    ,   static_cast<io::XStream*> ( this )
1692
560
                    ,   static_cast<embed::XExtendedStorageStream*> ( this )
1693
560
                    ,   static_cast<io::XSeekable*> ( this )
1694
560
                    ,   static_cast<io::XTruncate*> ( this )
1695
560
                    ,   static_cast<lang::XComponent*> ( this )
1696
560
                    ,   static_cast<beans::XPropertySet*> ( this ) );
1697
1698
560
    if ( aReturn.hasValue() )
1699
560
        return aReturn ;
1700
1701
0
    if ( m_nStorageType == embed::StorageFormats::PACKAGE )
1702
0
    {
1703
0
        aReturn = ::cppu::queryInterface
1704
0
                    (   rType
1705
0
                        ,   static_cast<embed::XEncryptionProtectedSource2*> ( this )
1706
0
                        ,   static_cast<embed::XEncryptionProtectedSource*> ( this ) );
1707
0
    }
1708
0
    else if ( m_nStorageType == embed::StorageFormats::OFOPXML )
1709
0
    {
1710
0
        aReturn = ::cppu::queryInterface
1711
0
                    (   rType
1712
0
                        ,   static_cast<embed::XRelationshipAccess*> ( this ) );
1713
0
    }
1714
1715
0
    if ( aReturn.hasValue() )
1716
0
        return aReturn ;
1717
1718
0
    if ( m_bTransacted )
1719
0
    {
1720
0
        aReturn = ::cppu::queryInterface
1721
0
                    (   rType
1722
0
                        ,   static_cast<embed::XTransactedObject*> ( this )
1723
0
                        ,   static_cast<embed::XTransactionBroadcaster*> ( this ) );
1724
1725
0
        if ( aReturn.hasValue() )
1726
0
            return aReturn ;
1727
0
    }
1728
1729
0
    return OWeakObject::queryInterface( rType );
1730
0
}
1731
1732
void SAL_CALL OWriteStream::acquire() noexcept
1733
3.66k
{
1734
3.66k
    OWeakObject::acquire();
1735
3.66k
}
1736
1737
void SAL_CALL OWriteStream::release() noexcept
1738
3.66k
{
1739
3.66k
    OWeakObject::release();
1740
3.66k
}
1741
1742
uno::Sequence< uno::Type > SAL_CALL OWriteStream::getTypes()
1743
0
{
1744
0
    if (! m_oTypeCollection)
1745
0
    {
1746
0
        ::osl::MutexGuard aGuard( m_xSharedMutex->GetMutex() );
1747
1748
0
        if (! m_oTypeCollection)
1749
0
        {
1750
0
            if ( m_bTransacted )
1751
0
            {
1752
0
                if ( m_nStorageType == embed::StorageFormats::PACKAGE )
1753
0
                {
1754
0
                    ::cppu::OTypeCollection aTmpCollection
1755
0
                                    (   cppu::UnoType<lang::XTypeProvider>::get()
1756
0
                                    ,   cppu::UnoType<io::XInputStream>::get()
1757
0
                                    ,   cppu::UnoType<io::XOutputStream>::get()
1758
0
                                    ,   cppu::UnoType<io::XStream>::get()
1759
0
                                    ,   cppu::UnoType<io::XSeekable>::get()
1760
0
                                    ,   cppu::UnoType<io::XTruncate>::get()
1761
0
                                    ,   cppu::UnoType<lang::XComponent>::get()
1762
0
                                    ,   cppu::UnoType<embed::XEncryptionProtectedSource2>::get()
1763
0
                                    ,   cppu::UnoType<embed::XEncryptionProtectedSource>::get()
1764
0
                                    ,   cppu::UnoType<embed::XExtendedStorageStream>::get()
1765
0
                                    ,   cppu::UnoType<embed::XTransactedObject>::get()
1766
0
                                    ,   cppu::UnoType<embed::XTransactionBroadcaster>::get());
1767
1768
0
                    m_oTypeCollection.emplace(
1769
0
                                        cppu::UnoType<beans::XPropertySet>::get()
1770
0
                                    ,   aTmpCollection.getTypes());
1771
0
                }
1772
0
                else if ( m_nStorageType == embed::StorageFormats::OFOPXML )
1773
0
                {
1774
0
                    m_oTypeCollection.emplace(
1775
0
                                        cppu::UnoType<lang::XTypeProvider>::get()
1776
0
                                    ,   cppu::UnoType<io::XInputStream>::get()
1777
0
                                    ,   cppu::UnoType<io::XOutputStream>::get()
1778
0
                                    ,   cppu::UnoType<io::XStream>::get()
1779
0
                                    ,   cppu::UnoType<io::XSeekable>::get()
1780
0
                                    ,   cppu::UnoType<io::XTruncate>::get()
1781
0
                                    ,   cppu::UnoType<lang::XComponent>::get()
1782
0
                                    ,   cppu::UnoType<embed::XRelationshipAccess>::get()
1783
0
                                    ,   cppu::UnoType<embed::XExtendedStorageStream>::get()
1784
0
                                    ,   cppu::UnoType<embed::XTransactedObject>::get()
1785
0
                                    ,   cppu::UnoType<embed::XTransactionBroadcaster>::get()
1786
0
                                    ,   cppu::UnoType<beans::XPropertySet>::get());
1787
0
                }
1788
0
                else // if ( m_pData->m_nStorageType == embed::StorageFormats::ZIP )
1789
0
                {
1790
0
                    m_oTypeCollection.emplace(
1791
0
                                        cppu::UnoType<lang::XTypeProvider>::get()
1792
0
                                    ,   cppu::UnoType<io::XInputStream>::get()
1793
0
                                    ,   cppu::UnoType<io::XOutputStream>::get()
1794
0
                                    ,   cppu::UnoType<io::XStream>::get()
1795
0
                                    ,   cppu::UnoType<io::XSeekable>::get()
1796
0
                                    ,   cppu::UnoType<io::XTruncate>::get()
1797
0
                                    ,   cppu::UnoType<lang::XComponent>::get()
1798
0
                                    ,   cppu::UnoType<embed::XExtendedStorageStream>::get()
1799
0
                                    ,   cppu::UnoType<embed::XTransactedObject>::get()
1800
0
                                    ,   cppu::UnoType<embed::XTransactionBroadcaster>::get()
1801
0
                                    ,   cppu::UnoType<beans::XPropertySet>::get());
1802
0
                }
1803
0
            }
1804
0
            else
1805
0
            {
1806
0
                if ( m_nStorageType == embed::StorageFormats::PACKAGE )
1807
0
                {
1808
0
                    m_oTypeCollection.emplace(
1809
0
                                        cppu::UnoType<lang::XTypeProvider>::get()
1810
0
                                    ,   cppu::UnoType<io::XInputStream>::get()
1811
0
                                    ,   cppu::UnoType<io::XOutputStream>::get()
1812
0
                                    ,   cppu::UnoType<io::XStream>::get()
1813
0
                                    ,   cppu::UnoType<io::XSeekable>::get()
1814
0
                                    ,   cppu::UnoType<io::XTruncate>::get()
1815
0
                                    ,   cppu::UnoType<lang::XComponent>::get()
1816
0
                                    ,   cppu::UnoType<embed::XEncryptionProtectedSource2>::get()
1817
0
                                    ,   cppu::UnoType<embed::XEncryptionProtectedSource>::get()
1818
0
                                    ,   cppu::UnoType<beans::XPropertySet>::get());
1819
0
                }
1820
0
                else if ( m_nStorageType == embed::StorageFormats::OFOPXML )
1821
0
                {
1822
0
                    m_oTypeCollection.emplace(
1823
0
                                        cppu::UnoType<lang::XTypeProvider>::get()
1824
0
                                    ,   cppu::UnoType<io::XInputStream>::get()
1825
0
                                    ,   cppu::UnoType<io::XOutputStream>::get()
1826
0
                                    ,   cppu::UnoType<io::XStream>::get()
1827
0
                                    ,   cppu::UnoType<io::XSeekable>::get()
1828
0
                                    ,   cppu::UnoType<io::XTruncate>::get()
1829
0
                                    ,   cppu::UnoType<lang::XComponent>::get()
1830
0
                                    ,   cppu::UnoType<embed::XRelationshipAccess>::get()
1831
0
                                    ,   cppu::UnoType<beans::XPropertySet>::get());
1832
0
                }
1833
0
                else // if ( m_pData->m_nStorageType == embed::StorageFormats::ZIP )
1834
0
                {
1835
0
                    m_oTypeCollection.emplace(
1836
0
                                        cppu::UnoType<lang::XTypeProvider>::get()
1837
0
                                    ,   cppu::UnoType<io::XInputStream>::get()
1838
0
                                    ,   cppu::UnoType<io::XOutputStream>::get()
1839
0
                                    ,   cppu::UnoType<io::XStream>::get()
1840
0
                                    ,   cppu::UnoType<io::XSeekable>::get()
1841
0
                                    ,   cppu::UnoType<io::XTruncate>::get()
1842
0
                                    ,   cppu::UnoType<lang::XComponent>::get()
1843
0
                                    ,   cppu::UnoType<beans::XPropertySet>::get());
1844
0
                }
1845
0
            }
1846
0
        }
1847
0
    }
1848
1849
0
    return m_oTypeCollection->getTypes() ;
1850
0
}
1851
1852
uno::Sequence< sal_Int8 > SAL_CALL OWriteStream::getImplementationId()
1853
0
{
1854
0
    static const comphelper::UnoIdInit lcl_ImplId;
1855
0
    return lcl_ImplId.getSeq();
1856
0
}
1857
1858
sal_Int32 SAL_CALL OWriteStream::readBytes( uno::Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead )
1859
0
{
1860
0
    ::osl::MutexGuard aGuard( m_xSharedMutex->GetMutex() );
1861
1862
0
    CheckInitOnDemand();
1863
1864
0
    if ( !m_xInStream.is() )
1865
0
        throw io::NotConnectedException();
1866
1867
0
    return m_xInStream->readBytes( aData, nBytesToRead );
1868
0
}
1869
1870
sal_Int32 SAL_CALL OWriteStream::readSomeBytes( uno::Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead )
1871
0
{
1872
0
    ::osl::MutexGuard aGuard( m_xSharedMutex->GetMutex() );
1873
1874
0
    CheckInitOnDemand();
1875
1876
0
    if ( !m_xInStream.is() )
1877
0
        throw io::NotConnectedException();
1878
1879
0
    return m_xInStream->readSomeBytes( aData, nMaxBytesToRead );
1880
0
}
1881
1882
sal_Int32 OWriteStream::readSomeBytes(sal_Int8* pData, sal_Int32 nBytesToRead)
1883
7
{
1884
7
    osl::MutexGuard aGuard(m_xSharedMutex->GetMutex());
1885
1886
7
    CheckInitOnDemand();
1887
1888
7
    if (!m_xInStream.is())
1889
0
        throw io::NotConnectedException();
1890
1891
7
    if (auto pByteReader = dynamic_cast<comphelper::ByteReader*>(m_xInStream.get()))
1892
7
        return pByteReader->readSomeBytes(pData, nBytesToRead);
1893
1894
0
    uno::Sequence<sal_Int8> aData;
1895
0
    sal_Int32 nRead = m_xInStream->readSomeBytes(aData, nBytesToRead);
1896
0
    std::copy_n(aData.getConstArray(), nRead, pData);
1897
1898
0
    return nRead;
1899
7
}
1900
1901
void SAL_CALL OWriteStream::skipBytes( sal_Int32 nBytesToSkip )
1902
0
{
1903
0
    ::osl::MutexGuard aGuard( m_xSharedMutex->GetMutex() );
1904
1905
0
    CheckInitOnDemand();
1906
1907
0
    if ( !m_xInStream.is() )
1908
0
        throw io::NotConnectedException();
1909
1910
0
    m_xInStream->skipBytes( nBytesToSkip );
1911
0
}
1912
1913
sal_Int32 SAL_CALL OWriteStream::available(  )
1914
0
{
1915
0
    ::osl::MutexGuard aGuard( m_xSharedMutex->GetMutex() );
1916
1917
0
    CheckInitOnDemand();
1918
1919
0
    if ( !m_xInStream.is() )
1920
0
        throw io::NotConnectedException();
1921
1922
0
    return m_xInStream->available();
1923
1924
0
}
1925
1926
void SAL_CALL OWriteStream::closeInput(  )
1927
0
{
1928
0
    ::osl::MutexGuard aGuard( m_xSharedMutex->GetMutex() );
1929
1930
0
    if ( !m_bInitOnDemand && ( m_bInStreamDisconnected || !m_xInStream.is() ) )
1931
0
        throw io::NotConnectedException();
1932
1933
    // the input part of the stream stays open for internal purposes (to allow reading during copying)
1934
    // since it can not be reopened until output part is closed, it will be closed with output part.
1935
0
    m_bInStreamDisconnected = true;
1936
    // m_xInStream->closeInput();
1937
    // m_xInStream.clear();
1938
1939
0
    if ( !m_xOutStream.is() )
1940
0
        dispose();
1941
0
}
1942
1943
uno::Reference< io::XInputStream > SAL_CALL OWriteStream::getInputStream()
1944
204
{
1945
204
    ::osl::MutexGuard aGuard( m_xSharedMutex->GetMutex() );
1946
1947
204
    if ( !m_bInitOnDemand && ( m_bInStreamDisconnected || !m_xInStream.is() ) )
1948
0
        return uno::Reference< io::XInputStream >();
1949
1950
204
    return this;
1951
204
}
1952
1953
uno::Reference< io::XOutputStream > SAL_CALL OWriteStream::getOutputStream()
1954
616
{
1955
616
    ::osl::MutexGuard aGuard( m_xSharedMutex->GetMutex() );
1956
1957
616
    try
1958
616
    {
1959
616
        CheckInitOnDemand();
1960
616
    }
1961
616
    catch( const io::IOException& r )
1962
616
    {
1963
0
        throw lang::WrappedTargetRuntimeException(u"OWriteStream::getOutputStream: Could not create backing temp file"_ustr,
1964
0
                getXWeak(), css::uno::Any ( r ) );
1965
0
    }
1966
1967
616
    if ( !m_xOutStream.is() )
1968
0
        return uno::Reference< io::XOutputStream >();
1969
1970
616
    return this;
1971
616
}
1972
1973
void OWriteStream::CheckInitOnWriteDemand(sal_Int32 dataSize)
1974
316
{
1975
    // write methods need a different initialization, since they depend on data length
1976
1977
316
    if ( !m_pImpl )
1978
0
    {
1979
0
        SAL_INFO("package.xstor", "Disposed!");
1980
0
        throw lang::DisposedException();
1981
0
    }
1982
1983
316
    if ( !m_bInitOnDemand )
1984
316
    {
1985
316
        if ( !m_xOutStream.is() || !m_xSeekable.is())
1986
0
            throw io::NotConnectedException();
1987
1988
316
        if ( m_pImpl->m_xCacheStream.is() )
1989
284
        {
1990
            // check whether the cache should be turned off
1991
284
            sal_Int64 nPos = m_xSeekable->getPosition();
1992
284
            if (nPos + dataSize > MAX_STORCACHE_SIZE)
1993
4
            {
1994
                // disconnect the cache and copy the data to the temporary file
1995
4
                m_xSeekable->seek( 0 );
1996
1997
                // it is enough to copy the cached stream, the cache should already contain everything
1998
4
                m_pImpl->GetFilledTempFileIfNo( m_xInStream );
1999
4
                if ( m_pImpl->m_oTempFile.has_value() )
2000
4
                {
2001
4
                    DeInit();
2002
                    // the last position is known and it is differs from the current stream position
2003
4
                    m_nInitPosition = nPos;
2004
4
                }
2005
4
            }
2006
284
        }
2007
316
    }
2008
2009
316
    if ( m_bInitOnDemand )
2010
4
    {
2011
4
        SAL_INFO("package.xstor", "OWriteStream::CheckInitOnWriteDemand: initializing");
2012
4
        uno::Reference< io::XStream > xStream = m_pImpl->GetTempFileAsStream();
2013
4
        if ( xStream.is() )
2014
4
        {
2015
4
            m_xInStream.set( xStream->getInputStream(), uno::UNO_SET_THROW );
2016
4
            m_xOutStream.set( xStream->getOutputStream(), uno::UNO_SET_THROW );
2017
4
            m_xSeekable.set( xStream, uno::UNO_QUERY_THROW );
2018
4
            m_xSeekable->seek( m_nInitPosition );
2019
2020
4
            m_nInitPosition = 0;
2021
4
            m_bInitOnDemand = false;
2022
4
        }
2023
4
    }
2024
316
}
2025
2026
void SAL_CALL OWriteStream::writeBytes( const uno::Sequence< sal_Int8 >& aData )
2027
305
{
2028
305
    osl::ClearableMutexGuard aGuard(m_xSharedMutex->GetMutex());
2029
2030
305
    CheckInitOnWriteDemand(aData.getLength());
2031
2032
305
    if ( !m_xOutStream.is() )
2033
0
        throw io::NotConnectedException();
2034
2035
305
    m_xOutStream->writeBytes( aData );
2036
305
    m_pImpl->m_bHasDataToFlush = true;
2037
2038
305
    ModifyParentUnlockMutex_Impl( aGuard );
2039
305
}
2040
2041
void OWriteStream::writeBytes( const sal_Int8* pData, sal_Int32 nBytesToWrite )
2042
11
{
2043
11
    assert(nBytesToWrite >= 0);
2044
2045
11
    osl::ClearableMutexGuard aGuard(m_xSharedMutex->GetMutex());
2046
2047
11
    CheckInitOnWriteDemand(nBytesToWrite);
2048
2049
11
    if ( !m_xOutStream.is() )
2050
0
        throw io::NotConnectedException();
2051
2052
11
    if (auto pByteWriter = dynamic_cast< comphelper::ByteWriter* >( m_xOutStream.get() ))
2053
11
        pByteWriter->writeBytes(pData, nBytesToWrite);
2054
0
    else
2055
0
    {
2056
0
        uno::Sequence<sal_Int8> aData(pData, nBytesToWrite);
2057
0
        m_xOutStream->writeBytes( aData );
2058
0
    }
2059
11
    m_pImpl->m_bHasDataToFlush = true;
2060
2061
11
    ModifyParentUnlockMutex_Impl( aGuard );
2062
11
}
2063
2064
void SAL_CALL OWriteStream::flush()
2065
232
{
2066
    // In case stream is flushed its current version becomes visible
2067
    // to the parent storage. Usually parent storage flushes the stream
2068
    // during own commit but a user can explicitly flush the stream
2069
    // so the changes will be available through cloning functionality.
2070
2071
232
    ::osl::MutexGuard aGuard( m_xSharedMutex->GetMutex() );
2072
2073
232
    if ( !m_pImpl )
2074
0
    {
2075
0
        SAL_INFO("package.xstor", "Disposed!");
2076
0
        throw lang::DisposedException();
2077
0
    }
2078
2079
232
    if ( !m_bInitOnDemand )
2080
225
    {
2081
225
        if ( !m_xOutStream.is() )
2082
0
            throw io::NotConnectedException();
2083
2084
225
        m_xOutStream->flush();
2085
225
        m_pImpl->Commit();
2086
225
    }
2087
232
}
2088
2089
void OWriteStream::CloseOutput_Impl()
2090
255
{
2091
    // all the checks must be done in calling method
2092
2093
255
    m_xOutStream->closeOutput();
2094
255
    m_xOutStream.clear();
2095
2096
255
    if ( m_bInitOnDemand )
2097
0
        return;
2098
2099
    // after the stream is disposed it can be committed
2100
    // so transport correct size property
2101
255
    if ( !m_xSeekable.is() )
2102
0
        throw uno::RuntimeException();
2103
2104
255
    for ( auto& rProp : asNonConstRange(m_pImpl->m_aProps) )
2105
1.02k
    {
2106
1.02k
        if ( rProp.Name == "Size" )
2107
255
            rProp.Value <<= m_xSeekable->getLength();
2108
1.02k
    }
2109
255
}
2110
2111
void SAL_CALL OWriteStream::closeOutput()
2112
197
{
2113
197
    ::osl::MutexGuard aGuard( m_xSharedMutex->GetMutex() );
2114
2115
197
    CheckInitOnDemand();
2116
2117
197
    if ( !m_xOutStream.is() )
2118
0
        throw io::NotConnectedException();
2119
2120
197
    CloseOutput_Impl();
2121
2122
197
    if ( m_bInStreamDisconnected || !m_xInStream.is() )
2123
0
        dispose();
2124
197
}
2125
2126
void SAL_CALL OWriteStream::seek( sal_Int64 location )
2127
312
{
2128
312
    ::osl::MutexGuard aGuard( m_xSharedMutex->GetMutex() );
2129
2130
312
    CheckInitOnDemand();
2131
2132
312
    if ( !m_xSeekable.is() )
2133
0
        throw uno::RuntimeException();
2134
2135
312
    m_xSeekable->seek( location );
2136
312
}
2137
2138
sal_Int64 SAL_CALL OWriteStream::getPosition()
2139
0
{
2140
0
    ::osl::MutexGuard aGuard( m_xSharedMutex->GetMutex() );
2141
2142
0
    CheckInitOnDemand();
2143
2144
0
    if ( !m_xSeekable.is() )
2145
0
        throw uno::RuntimeException();
2146
2147
0
    return m_xSeekable->getPosition();
2148
0
}
2149
2150
sal_Int64 SAL_CALL OWriteStream::getLength()
2151
161
{
2152
161
    ::osl::MutexGuard aGuard( m_xSharedMutex->GetMutex() );
2153
2154
161
    CheckInitOnDemand();
2155
2156
161
    if ( !m_xSeekable.is() )
2157
0
        throw uno::RuntimeException();
2158
2159
161
    return m_xSeekable->getLength();
2160
161
}
2161
2162
void SAL_CALL OWriteStream::truncate()
2163
0
{
2164
0
    osl::ClearableMutexGuard aGuard(m_xSharedMutex->GetMutex());
2165
2166
0
    CheckInitOnDemand();
2167
2168
0
    if ( !m_xOutStream.is() )
2169
0
        throw uno::RuntimeException();
2170
2171
0
    uno::Reference< io::XTruncate > xTruncate( m_xOutStream, uno::UNO_QUERY_THROW );
2172
0
    xTruncate->truncate();
2173
2174
0
    m_pImpl->m_bHasDataToFlush = true;
2175
2176
0
    ModifyParentUnlockMutex_Impl( aGuard );
2177
0
}
2178
2179
void SAL_CALL OWriteStream::dispose()
2180
262
{
2181
    // should be an internal method since it can be called only from parent storage
2182
262
    {
2183
262
        ::osl::MutexGuard aGuard( m_xSharedMutex->GetMutex() );
2184
2185
262
        if ( !m_pImpl )
2186
0
        {
2187
0
            SAL_INFO("package.xstor", "Disposed!");
2188
0
            throw lang::DisposedException();
2189
0
        }
2190
2191
262
        if ( m_xOutStream.is() )
2192
58
            CloseOutput_Impl();
2193
2194
262
        if ( m_xInStream.is() )
2195
255
        {
2196
255
            m_xInStream->closeInput();
2197
255
            m_xInStream.clear();
2198
255
        }
2199
2200
262
        m_xSeekable.clear();
2201
2202
262
        m_pImpl->m_pAntiImpl = nullptr;
2203
2204
262
        if ( !m_bInitOnDemand )
2205
255
        {
2206
255
            try
2207
255
            {
2208
255
                if ( !m_bTransacted )
2209
255
                {
2210
255
                    m_pImpl->Commit();
2211
255
                }
2212
0
                else
2213
0
                {
2214
                    // throw away all the changes
2215
0
                    m_pImpl->Revert();
2216
0
                }
2217
255
            }
2218
255
            catch( const uno::Exception& )
2219
255
            {
2220
0
                uno::Any aCaught( ::cppu::getCaughtException() );
2221
0
                SAL_INFO("package.xstor", "Rethrow: " << exceptionToString(aCaught));
2222
0
                throw lang::WrappedTargetRuntimeException(u"Can not commit/revert the storage!"_ustr,
2223
0
                                                getXWeak(),
2224
0
                                                aCaught );
2225
0
            }
2226
255
        }
2227
2228
262
        m_pImpl = nullptr;
2229
262
    }
2230
2231
    // the listener might try to get rid of parent storage, and the storage would delete this object;
2232
    // for now the listener is just notified at the end of the method to workaround the problem
2233
    // in future a more elegant way should be found
2234
2235
0
    lang::EventObject aSource( getXWeak() );
2236
262
    m_aListenersContainer.disposeAndClear( aSource );
2237
262
}
2238
2239
void SAL_CALL OWriteStream::addEventListener(
2240
            const uno::Reference< lang::XEventListener >& xListener )
2241
0
{
2242
0
    ::osl::MutexGuard aGuard( m_xSharedMutex->GetMutex() );
2243
2244
0
    if ( !m_pImpl )
2245
0
    {
2246
0
        SAL_INFO("package.xstor", "Disposed!");
2247
0
        throw lang::DisposedException();
2248
0
    }
2249
2250
0
    m_aListenersContainer.addInterface( cppu::UnoType<lang::XEventListener>::get(),
2251
0
                                                 xListener );
2252
0
}
2253
2254
void SAL_CALL OWriteStream::removeEventListener(
2255
            const uno::Reference< lang::XEventListener >& xListener )
2256
0
{
2257
0
    ::osl::MutexGuard aGuard( m_xSharedMutex->GetMutex() );
2258
2259
0
    if ( !m_pImpl )
2260
0
    {
2261
0
        SAL_INFO("package.xstor", "Disposed!");
2262
0
        throw lang::DisposedException();
2263
0
    }
2264
2265
0
    m_aListenersContainer.removeInterface( cppu::UnoType<lang::XEventListener>::get(),
2266
0
                                                    xListener );
2267
0
}
2268
2269
void SAL_CALL OWriteStream::setEncryptionPassword( const OUString& aPass )
2270
0
{
2271
0
    osl::ClearableMutexGuard aGuard(m_xSharedMutex->GetMutex());
2272
2273
0
    CheckInitOnDemand();
2274
2275
0
    OSL_ENSURE( m_pImpl->m_xPackageStream.is(), "No package stream is set!" );
2276
2277
0
    m_pImpl->SetEncrypted( ::comphelper::OStorageHelper::CreatePackageEncryptionData( aPass ) );
2278
2279
0
    ModifyParentUnlockMutex_Impl( aGuard );
2280
0
}
2281
2282
void SAL_CALL OWriteStream::removeEncryption()
2283
0
{
2284
0
    osl::ClearableMutexGuard aGuard(m_xSharedMutex->GetMutex());
2285
2286
0
    CheckInitOnDemand();
2287
2288
0
    OSL_ENSURE( m_pImpl->m_xPackageStream.is(), "No package stream is set!" );
2289
2290
0
    m_pImpl->SetDecrypted();
2291
2292
0
    ModifyParentUnlockMutex_Impl( aGuard );
2293
0
}
2294
2295
void SAL_CALL OWriteStream::setEncryptionData( const uno::Sequence< beans::NamedValue >& aEncryptionData )
2296
0
{
2297
0
    osl::ClearableMutexGuard aGuard(m_xSharedMutex->GetMutex());
2298
2299
0
    CheckInitOnDemand();
2300
2301
0
    OSL_ENSURE( m_pImpl->m_xPackageStream.is(), "No package stream is set!" );
2302
2303
0
    m_pImpl->SetEncrypted( aEncryptionData );
2304
2305
0
    ModifyParentUnlockMutex_Impl( aGuard );
2306
0
}
2307
2308
sal_Bool SAL_CALL OWriteStream::hasEncryptionData()
2309
0
{
2310
0
    osl::ClearableMutexGuard aGuard(m_xSharedMutex->GetMutex());
2311
2312
0
    if (!m_pImpl)
2313
0
        return false;
2314
2315
0
    bool bRet = false;
2316
2317
0
    try
2318
0
    {
2319
0
        bRet = m_pImpl->IsEncrypted();
2320
2321
0
        if (!bRet && m_pImpl->m_bUseCommonEncryption && m_pImpl->m_pParent)
2322
0
            bRet = m_pImpl->m_pParent->m_bHasCommonEncryptionData;
2323
0
    }
2324
0
    catch( const uno::RuntimeException& )
2325
0
    {
2326
0
        TOOLS_INFO_EXCEPTION("package.xstor", "Rethrow");
2327
0
        throw;
2328
0
    }
2329
0
    catch( const uno::Exception& )
2330
0
    {
2331
0
        uno::Any aCaught( ::cppu::getCaughtException() );
2332
0
        SAL_INFO("package.xstor", "Rethrow: " << exceptionToString(aCaught));
2333
0
        throw lang::WrappedTargetRuntimeException( u"Problems on hasEncryptionData!"_ustr,
2334
0
                                  getXWeak(),
2335
0
                                  aCaught );
2336
0
    }
2337
2338
0
    return bRet;
2339
0
}
2340
2341
sal_Bool SAL_CALL OWriteStream::hasByID(  const OUString& sID )
2342
0
{
2343
0
    ::osl::MutexGuard aGuard( m_xSharedMutex->GetMutex() );
2344
2345
0
    if ( !m_pImpl )
2346
0
    {
2347
0
        SAL_INFO("package.xstor", "Disposed!");
2348
0
        throw lang::DisposedException();
2349
0
    }
2350
2351
0
    if ( m_nStorageType != embed::StorageFormats::OFOPXML )
2352
0
        throw uno::RuntimeException();
2353
2354
0
    try
2355
0
    {
2356
0
        getRelationshipByID( sID );
2357
0
        return true;
2358
0
    }
2359
0
    catch( const container::NoSuchElementException& )
2360
0
    {
2361
0
        TOOLS_INFO_EXCEPTION("package.xstor", "No Element");
2362
0
    }
2363
2364
0
    return false;
2365
0
}
2366
2367
OUString SAL_CALL OWriteStream::getTargetByID(  const OUString& sID  )
2368
0
{
2369
0
    ::osl::MutexGuard aGuard( m_xSharedMutex->GetMutex() );
2370
2371
0
    if ( !m_pImpl )
2372
0
    {
2373
0
        SAL_INFO("package.xstor", "Disposed!");
2374
0
        throw lang::DisposedException();
2375
0
    }
2376
2377
0
    if ( m_nStorageType != embed::StorageFormats::OFOPXML )
2378
0
        throw uno::RuntimeException();
2379
2380
0
    const uno::Sequence< beans::StringPair > aSeq = getRelationshipByID( sID );
2381
0
    auto pRel = lcl_findPairByName(aSeq, u"Target"_ustr);
2382
0
    if (pRel != aSeq.end())
2383
0
        return pRel->Second;
2384
2385
0
    return OUString();
2386
0
}
2387
2388
OUString SAL_CALL OWriteStream::getTypeByID(  const OUString& sID  )
2389
0
{
2390
0
    ::osl::MutexGuard aGuard( m_xSharedMutex->GetMutex() );
2391
2392
0
    if ( !m_pImpl )
2393
0
    {
2394
0
        SAL_INFO("package.xstor", "Disposed!");
2395
0
        throw lang::DisposedException();
2396
0
    }
2397
2398
0
    if ( m_nStorageType != embed::StorageFormats::OFOPXML )
2399
0
        throw uno::RuntimeException();
2400
2401
0
    const uno::Sequence< beans::StringPair > aSeq = getRelationshipByID( sID );
2402
0
    auto pRel = lcl_findPairByName(aSeq, u"Type"_ustr);
2403
0
    if (pRel != aSeq.end())
2404
0
        return pRel->Second;
2405
2406
0
    return OUString();
2407
0
}
2408
2409
uno::Sequence< beans::StringPair > SAL_CALL OWriteStream::getRelationshipByID(  const OUString& sID  )
2410
0
{
2411
0
    ::osl::MutexGuard aGuard( m_xSharedMutex->GetMutex() );
2412
2413
0
    if ( !m_pImpl )
2414
0
    {
2415
0
        SAL_INFO("package.xstor", "Disposed!");
2416
0
        throw lang::DisposedException();
2417
0
    }
2418
2419
0
    if ( m_nStorageType != embed::StorageFormats::OFOPXML )
2420
0
        throw uno::RuntimeException();
2421
2422
    // TODO/LATER: in future the unification of the ID could be checked
2423
0
    const uno::Sequence< uno::Sequence< beans::StringPair > > aSeq = getAllRelationships();
2424
0
    const beans::StringPair aIDRel(u"Id"_ustr, sID);
2425
0
    auto pRel = std::find_if(aSeq.begin(), aSeq.end(),
2426
0
        [&aIDRel](const uno::Sequence<beans::StringPair>& rRel) {
2427
0
            return std::find(rRel.begin(), rRel.end(), aIDRel) != rRel.end(); });
2428
0
    if (pRel != aSeq.end())
2429
0
        return *pRel;
2430
2431
0
    throw container::NoSuchElementException();
2432
0
}
2433
2434
uno::Sequence< uno::Sequence< beans::StringPair > > SAL_CALL OWriteStream::getRelationshipsByType(  const OUString& sType  )
2435
0
{
2436
0
    ::osl::MutexGuard aGuard( m_xSharedMutex->GetMutex() );
2437
2438
0
    if ( !m_pImpl )
2439
0
    {
2440
0
        SAL_INFO("package.xstor", "Disposed!");
2441
0
        throw lang::DisposedException();
2442
0
    }
2443
2444
0
    if ( m_nStorageType != embed::StorageFormats::OFOPXML )
2445
0
        throw uno::RuntimeException();
2446
2447
    // TODO/LATER: in future the unification of the ID could be checked
2448
0
    const uno::Sequence< uno::Sequence< beans::StringPair > > aSeq = getAllRelationships();
2449
0
    const beans::StringPair aTypeRel(u"Type"_ustr, sType);
2450
0
    std::vector< uno::Sequence<beans::StringPair> > aResult;
2451
0
    aResult.reserve(aSeq.getLength());
2452
2453
0
    std::copy_if(aSeq.begin(), aSeq.end(), std::back_inserter(aResult),
2454
0
        [&aTypeRel](const uno::Sequence<beans::StringPair>& rRel) {
2455
0
            return std::find(rRel.begin(), rRel.end(), aTypeRel) != rRel.end(); });
2456
2457
0
    return comphelper::containerToSequence(aResult);
2458
0
}
2459
2460
uno::Sequence< uno::Sequence< beans::StringPair > > SAL_CALL OWriteStream::getAllRelationships()
2461
0
{
2462
0
    ::osl::MutexGuard aGuard( m_xSharedMutex->GetMutex() );
2463
2464
0
    if ( !m_pImpl )
2465
0
    {
2466
0
        SAL_INFO("package.xstor", "Disposed!");
2467
0
        throw lang::DisposedException();
2468
0
    }
2469
2470
0
    if ( m_nStorageType != embed::StorageFormats::OFOPXML )
2471
0
        throw uno::RuntimeException();
2472
2473
0
    return m_pImpl->GetAllRelationshipsIfAny();
2474
0
}
2475
2476
void SAL_CALL OWriteStream::insertRelationshipByID(  const OUString& sID, const uno::Sequence< beans::StringPair >& aEntry, sal_Bool bReplace  )
2477
0
{
2478
0
    ::osl::MutexGuard aGuard( m_xSharedMutex->GetMutex() );
2479
2480
0
    if ( !m_pImpl )
2481
0
    {
2482
0
        SAL_INFO("package.xstor", "Disposed!");
2483
0
        throw lang::DisposedException();
2484
0
    }
2485
2486
0
    if ( m_nStorageType != embed::StorageFormats::OFOPXML )
2487
0
        throw uno::RuntimeException();
2488
2489
0
    const beans::StringPair aIDRel(u"Id"_ustr, sID);
2490
2491
0
    uno::Sequence<beans::StringPair>* pPair = nullptr;
2492
2493
    // TODO/LATER: in future the unification of the ID could be checked
2494
0
    uno::Sequence< uno::Sequence< beans::StringPair > > aSeq = getAllRelationships();
2495
0
    for ( sal_Int32 nInd = 0; nInd < aSeq.getLength(); nInd++ )
2496
0
    {
2497
0
        const auto& rRel = aSeq[nInd];
2498
0
        if (std::find(rRel.begin(), rRel.end(), aIDRel) != rRel.end())
2499
0
            pPair = &aSeq.getArray()[nInd];
2500
0
    }
2501
2502
0
    if ( pPair && !bReplace )
2503
0
        throw container::ElementExistException(); // TODO
2504
2505
0
    if ( !pPair )
2506
0
    {
2507
0
        sal_Int32 nIDInd = aSeq.getLength();
2508
0
        aSeq.realloc( nIDInd + 1 );
2509
0
        pPair = &aSeq.getArray()[nIDInd];
2510
0
    }
2511
2512
0
    std::vector<beans::StringPair> aResult;
2513
0
    aResult.reserve(aEntry.getLength() + 1);
2514
2515
0
    aResult.push_back(aIDRel);
2516
0
    std::copy_if(aEntry.begin(), aEntry.end(), std::back_inserter(aResult),
2517
0
        [](const beans::StringPair& rRel) { return rRel.First != "Id"; });
2518
2519
0
    *pPair = comphelper::containerToSequence(aResult);
2520
2521
0
    m_pImpl->m_aNewRelInfo = std::move(aSeq);
2522
0
    m_pImpl->m_xNewRelInfoStream.clear();
2523
0
    m_pImpl->m_nRelInfoStatus = RELINFO_CHANGED;
2524
0
}
2525
2526
void SAL_CALL OWriteStream::removeRelationshipByID(  const OUString& sID  )
2527
0
{
2528
0
    ::osl::MutexGuard aGuard( m_xSharedMutex->GetMutex() );
2529
2530
0
    if ( !m_pImpl )
2531
0
    {
2532
0
        SAL_INFO("package.xstor", "Disposed!");
2533
0
        throw lang::DisposedException();
2534
0
    }
2535
2536
0
    if ( m_nStorageType != embed::StorageFormats::OFOPXML )
2537
0
        throw uno::RuntimeException();
2538
2539
0
    uno::Sequence< uno::Sequence< beans::StringPair > > aSeq = getAllRelationships();
2540
0
    const beans::StringPair aIDRel(u"Id"_ustr, sID);
2541
0
    auto pRel = std::find_if(std::cbegin(aSeq), std::cend(aSeq),
2542
0
        [&aIDRel](const uno::Sequence< beans::StringPair >& rRel) {
2543
0
            return std::find(rRel.begin(), rRel.end(), aIDRel) != rRel.end(); });
2544
0
    if (pRel != std::cend(aSeq))
2545
0
    {
2546
0
        auto nInd = static_cast<sal_Int32>(std::distance(std::cbegin(aSeq), pRel));
2547
0
        comphelper::removeElementAt(aSeq, nInd);
2548
2549
0
        m_pImpl->m_aNewRelInfo = std::move(aSeq);
2550
0
        m_pImpl->m_xNewRelInfoStream.clear();
2551
0
        m_pImpl->m_nRelInfoStatus = RELINFO_CHANGED;
2552
2553
        // TODO/LATER: in future the unification of the ID could be checked
2554
0
        return;
2555
0
    }
2556
2557
0
    throw container::NoSuchElementException();
2558
0
}
2559
2560
void SAL_CALL OWriteStream::insertRelationships(  const uno::Sequence< uno::Sequence< beans::StringPair > >& aEntries, sal_Bool bReplace  )
2561
0
{
2562
0
    ::osl::MutexGuard aGuard( m_xSharedMutex->GetMutex() );
2563
2564
0
    if ( !m_pImpl )
2565
0
    {
2566
0
        SAL_INFO("package.xstor", "Disposed!");
2567
0
        throw lang::DisposedException();
2568
0
    }
2569
2570
0
    if ( m_nStorageType != embed::StorageFormats::OFOPXML )
2571
0
        throw uno::RuntimeException();
2572
2573
0
    OUString aIDTag( u"Id"_ustr );
2574
0
    const uno::Sequence< uno::Sequence< beans::StringPair > > aSeq = getAllRelationships();
2575
0
    std::vector< uno::Sequence<beans::StringPair> > aResultVec;
2576
0
    aResultVec.reserve(aSeq.getLength() + aEntries.getLength());
2577
2578
0
    std::copy_if(aSeq.begin(), aSeq.end(), std::back_inserter(aResultVec),
2579
0
        [&aIDTag, &aEntries, bReplace](const uno::Sequence<beans::StringPair>& rTargetRel) {
2580
0
            auto pTargetPair = lcl_findPairByName(rTargetRel, aIDTag);
2581
0
            if (pTargetPair == rTargetRel.end())
2582
0
                return false;
2583
2584
0
            bool bIsSourceSame = std::any_of(aEntries.begin(), aEntries.end(),
2585
0
                [&pTargetPair](const uno::Sequence<beans::StringPair>& rSourceEntry) {
2586
0
                    return std::find(rSourceEntry.begin(), rSourceEntry.end(), *pTargetPair) != rSourceEntry.end(); });
2587
2588
0
            if ( bIsSourceSame && !bReplace )
2589
0
                throw container::ElementExistException();
2590
2591
            // if no such element in the provided sequence
2592
0
            return !bIsSourceSame;
2593
0
        });
2594
2595
0
    std::transform(aEntries.begin(), aEntries.end(), std::back_inserter(aResultVec),
2596
0
        [&aIDTag](const uno::Sequence<beans::StringPair>& rEntry) -> uno::Sequence<beans::StringPair> {
2597
0
            auto pPair = lcl_findPairByName(rEntry, aIDTag);
2598
0
            if (pPair == rEntry.end())
2599
0
                throw io::IOException(); // TODO: illegal relation ( no ID )
2600
2601
0
            auto aResult = comphelper::sequenceToContainer<std::vector<beans::StringPair>>(rEntry);
2602
0
            auto nIDInd = std::distance(rEntry.begin(), pPair);
2603
0
            std::rotate(aResult.begin(), std::next(aResult.begin(), nIDInd), std::next(aResult.begin(), nIDInd + 1));
2604
2605
0
            return comphelper::containerToSequence(aResult);
2606
0
        });
2607
2608
0
    m_pImpl->m_aNewRelInfo = comphelper::containerToSequence(aResultVec);
2609
0
    m_pImpl->m_xNewRelInfoStream.clear();
2610
0
    m_pImpl->m_nRelInfoStatus = RELINFO_CHANGED;
2611
0
}
2612
2613
void SAL_CALL OWriteStream::clearRelationships()
2614
0
{
2615
0
    ::osl::MutexGuard aGuard( m_xSharedMutex->GetMutex() );
2616
2617
0
    if ( !m_pImpl )
2618
0
    {
2619
0
        SAL_INFO("package.xstor", "Disposed!");
2620
0
        throw lang::DisposedException();
2621
0
    }
2622
2623
0
    if ( m_nStorageType != embed::StorageFormats::OFOPXML )
2624
0
        throw uno::RuntimeException();
2625
2626
0
    m_pImpl->m_aNewRelInfo.realloc( 0 );
2627
0
    m_pImpl->m_xNewRelInfoStream.clear();
2628
0
    m_pImpl->m_nRelInfoStatus = RELINFO_CHANGED;
2629
0
}
2630
2631
uno::Reference< beans::XPropertySetInfo > SAL_CALL OWriteStream::getPropertySetInfo()
2632
0
{
2633
0
    ::osl::MutexGuard aGuard( m_xSharedMutex->GetMutex() );
2634
2635
    //TODO:
2636
0
    return uno::Reference< beans::XPropertySetInfo >();
2637
0
}
2638
2639
void SAL_CALL OWriteStream::setPropertyValue( const OUString& aPropertyName, const uno::Any& aValue )
2640
237
{
2641
237
    osl::ClearableMutexGuard aGuard(m_xSharedMutex->GetMutex());
2642
2643
237
    if ( !m_pImpl )
2644
0
    {
2645
0
        SAL_INFO("package.xstor", "Disposed!");
2646
0
        throw lang::DisposedException();
2647
0
    }
2648
2649
237
    m_pImpl->GetStreamProperties();
2650
237
    static constexpr OUString aCompressedString( u"Compressed"_ustr );
2651
237
    static constexpr OUString aMediaTypeString( u"MediaType"_ustr );
2652
237
    if ( m_nStorageType == embed::StorageFormats::PACKAGE && aPropertyName == aMediaTypeString )
2653
215
    {
2654
        // if the "Compressed" property is not set explicitly, the MediaType can change the default value
2655
215
        bool bCompressedValueFromType = true;
2656
215
        OUString aType;
2657
215
        aValue >>= aType;
2658
2659
215
        if ( !m_pImpl->m_bCompressedSetExplicit )
2660
204
        {
2661
204
            if ( aType == "image/jpeg" || aType == "image/png" || aType == "image/gif" )
2662
0
                bCompressedValueFromType = false;
2663
204
        }
2664
2665
215
        for ( auto& rProp : asNonConstRange(m_pImpl->m_aProps) )
2666
860
        {
2667
860
            if ( aPropertyName == rProp.Name )
2668
215
                rProp.Value = aValue;
2669
645
            else if ( !m_pImpl->m_bCompressedSetExplicit && aCompressedString == rProp.Name )
2670
204
                rProp.Value <<= bCompressedValueFromType;
2671
860
        }
2672
215
    }
2673
22
    else if ( aPropertyName == aCompressedString )
2674
11
    {
2675
        // if the "Compressed" property is not set explicitly, the MediaType can change the default value
2676
11
        m_pImpl->m_bCompressedSetExplicit = true;
2677
11
        for ( auto& rProp : asNonConstRange(m_pImpl->m_aProps) )
2678
44
        {
2679
44
            if ( aPropertyName == rProp.Name )
2680
11
                rProp.Value = aValue;
2681
44
        }
2682
11
    }
2683
11
    else if ( m_nStorageType == embed::StorageFormats::PACKAGE
2684
11
            && aPropertyName == "UseCommonStoragePasswordEncryption" )
2685
11
    {
2686
11
        bool bUseCommonEncryption = false;
2687
11
        if ( !(aValue >>= bUseCommonEncryption) )
2688
0
            throw lang::IllegalArgumentException(); //TODO
2689
2690
11
        if ( m_bInitOnDemand && m_pImpl->m_bHasInsertedStreamOptimization )
2691
0
        {
2692
            // the data stream is provided to the packagestream directly
2693
0
            m_pImpl->m_bUseCommonEncryption = bUseCommonEncryption;
2694
0
        }
2695
11
        else if ( bUseCommonEncryption )
2696
11
        {
2697
11
            if ( !m_pImpl->m_bUseCommonEncryption )
2698
0
            {
2699
0
                m_pImpl->SetDecrypted();
2700
0
                m_pImpl->m_bUseCommonEncryption = true;
2701
0
            }
2702
11
        }
2703
0
        else
2704
0
            m_pImpl->m_bUseCommonEncryption = false;
2705
11
    }
2706
0
    else if ( m_nStorageType == embed::StorageFormats::OFOPXML && aPropertyName == aMediaTypeString )
2707
0
    {
2708
0
        for ( auto& rProp : asNonConstRange(m_pImpl->m_aProps) )
2709
0
        {
2710
0
            if ( aPropertyName == rProp.Name )
2711
0
                rProp.Value = aValue;
2712
0
        }
2713
0
    }
2714
0
    else if ( m_nStorageType == embed::StorageFormats::OFOPXML && aPropertyName == "RelationsInfoStream" )
2715
0
    {
2716
0
        uno::Reference< io::XInputStream > xInRelStream;
2717
0
        if ( !( aValue >>= xInRelStream ) || !xInRelStream.is() )
2718
0
            throw lang::IllegalArgumentException(); // TODO
2719
2720
0
        uno::Reference< io::XSeekable > xSeek( xInRelStream, uno::UNO_QUERY );
2721
0
        if ( !xSeek.is() )
2722
0
        {
2723
            // currently this is an internal property that is used for optimization
2724
            // and the stream must support XSeekable interface
2725
            // TODO/LATER: in future it can be changed if property is used from outside
2726
0
            throw lang::IllegalArgumentException(); // TODO
2727
0
        }
2728
2729
0
        m_pImpl->m_xNewRelInfoStream = std::move(xInRelStream);
2730
0
        m_pImpl->m_aNewRelInfo = uno::Sequence< uno::Sequence< beans::StringPair > >();
2731
0
        m_pImpl->m_nRelInfoStatus = RELINFO_CHANGED_STREAM;
2732
0
    }
2733
0
    else if ( m_nStorageType == embed::StorageFormats::OFOPXML && aPropertyName == "RelationsInfo" )
2734
0
    {
2735
0
        if ( !(aValue >>= m_pImpl->m_aNewRelInfo) )
2736
0
            throw lang::IllegalArgumentException(); // TODO
2737
0
    }
2738
0
    else if ( aPropertyName == "Size" )
2739
0
        throw beans::PropertyVetoException(); // TODO
2740
0
    else if ( m_nStorageType == embed::StorageFormats::PACKAGE
2741
0
           && ( aPropertyName == "IsEncrypted" || aPropertyName == "Encrypted" ) )
2742
0
        throw beans::PropertyVetoException(); // TODO
2743
0
    else if ( aPropertyName == "RelId" )
2744
0
    {
2745
0
        aValue >>= m_pImpl->m_nRelId;
2746
0
    }
2747
0
    else
2748
0
        throw beans::UnknownPropertyException(aPropertyName); // TODO
2749
2750
237
    m_pImpl->m_bHasDataToFlush = true;
2751
237
    ModifyParentUnlockMutex_Impl( aGuard );
2752
237
}
2753
2754
uno::Any SAL_CALL OWriteStream::getPropertyValue( const OUString& aProp )
2755
0
{
2756
0
    ::osl::MutexGuard aGuard( m_xSharedMutex->GetMutex() );
2757
2758
0
    if ( !m_pImpl )
2759
0
    {
2760
0
        SAL_INFO("package.xstor", "Disposed!");
2761
0
        throw lang::DisposedException();
2762
0
    }
2763
2764
0
    if ( aProp == "RelId" )
2765
0
    {
2766
0
        return uno::Any( m_pImpl->GetNewRelId() );
2767
0
    }
2768
2769
0
    OUString aPropertyName;
2770
0
    if ( aProp == "IsEncrypted" )
2771
0
        aPropertyName = "Encrypted";
2772
0
    else
2773
0
        aPropertyName = aProp;
2774
2775
0
    if ( ( ( m_nStorageType == embed::StorageFormats::PACKAGE || m_nStorageType == embed::StorageFormats::OFOPXML )
2776
0
            && aPropertyName == "MediaType" )
2777
0
      || ( m_nStorageType == embed::StorageFormats::PACKAGE && aPropertyName == "Encrypted" )
2778
0
      || aPropertyName == "Compressed" )
2779
0
    {
2780
0
        m_pImpl->GetStreamProperties();
2781
2782
0
        auto pProp = std::find_if(std::cbegin(m_pImpl->m_aProps), std::cend(m_pImpl->m_aProps),
2783
0
            [&aPropertyName](const css::beans::PropertyValue& rProp){ return aPropertyName == rProp.Name; });
2784
0
        if (pProp != std::cend(m_pImpl->m_aProps))
2785
0
            return pProp->Value;
2786
0
    }
2787
0
    else if ( m_nStorageType == embed::StorageFormats::PACKAGE
2788
0
            && aPropertyName == "UseCommonStoragePasswordEncryption" )
2789
0
        return uno::Any( m_pImpl->m_bUseCommonEncryption );
2790
0
    else if ( aPropertyName == "Size" )
2791
0
    {
2792
0
        bool bThrow = false;
2793
0
        try
2794
0
        {
2795
0
            CheckInitOnDemand();
2796
0
        }
2797
0
        catch (const io::IOException&)
2798
0
        {
2799
0
            bThrow = true;
2800
0
        }
2801
0
        if (bThrow || !m_xSeekable.is())
2802
0
            throw uno::RuntimeException();
2803
2804
0
        return uno::Any( m_xSeekable->getLength() );
2805
0
    }
2806
2807
0
    throw beans::UnknownPropertyException(aPropertyName); // TODO
2808
0
}
2809
2810
void SAL_CALL OWriteStream::addPropertyChangeListener(
2811
    const OUString& /*aPropertyName*/,
2812
    const uno::Reference< beans::XPropertyChangeListener >& /*xListener*/ )
2813
0
{
2814
0
    ::osl::MutexGuard aGuard( m_xSharedMutex->GetMutex() );
2815
2816
0
    if ( !m_pImpl )
2817
0
    {
2818
0
        SAL_INFO("package.xstor", "Disposed!");
2819
0
        throw lang::DisposedException();
2820
0
    }
2821
2822
    //TODO:
2823
0
}
2824
2825
void SAL_CALL OWriteStream::removePropertyChangeListener(
2826
    const OUString& /*aPropertyName*/,
2827
    const uno::Reference< beans::XPropertyChangeListener >& /*aListener*/ )
2828
0
{
2829
0
    ::osl::MutexGuard aGuard( m_xSharedMutex->GetMutex() );
2830
2831
0
    if ( !m_pImpl )
2832
0
    {
2833
0
        SAL_INFO("package.xstor", "Disposed!");
2834
0
        throw lang::DisposedException();
2835
0
    }
2836
2837
    //TODO:
2838
0
}
2839
2840
void SAL_CALL OWriteStream::addVetoableChangeListener(
2841
    const OUString& /*PropertyName*/,
2842
    const uno::Reference< beans::XVetoableChangeListener >& /*aListener*/ )
2843
0
{
2844
0
    ::osl::MutexGuard aGuard( m_xSharedMutex->GetMutex() );
2845
2846
0
    if ( !m_pImpl )
2847
0
    {
2848
0
        SAL_INFO("package.xstor", "Disposed!");
2849
0
        throw lang::DisposedException();
2850
0
    }
2851
2852
    //TODO:
2853
0
}
2854
2855
void SAL_CALL OWriteStream::removeVetoableChangeListener(
2856
    const OUString& /*PropertyName*/,
2857
    const uno::Reference< beans::XVetoableChangeListener >& /*aListener*/ )
2858
0
{
2859
0
    ::osl::MutexGuard aGuard( m_xSharedMutex->GetMutex() );
2860
2861
0
    if ( !m_pImpl )
2862
0
    {
2863
0
        SAL_INFO("package.xstor", "Disposed!");
2864
0
        throw lang::DisposedException();
2865
0
    }
2866
2867
    //TODO:
2868
0
}
2869
2870
//  XTransactedObject
2871
2872
void OWriteStream::BroadcastTransaction( sal_Int8 nMessage )
2873
/*
2874
    1 - preCommit
2875
    2 - committed
2876
    3 - preRevert
2877
    4 - reverted
2878
*/
2879
0
{
2880
    // no need to lock mutex here for the checking of m_pImpl, and m_pData is alive until the object is destructed
2881
0
    if ( !m_pImpl )
2882
0
    {
2883
0
        SAL_INFO("package.xstor", "Disposed!");
2884
0
        throw lang::DisposedException();
2885
0
    }
2886
2887
0
    lang::EventObject aSource( getXWeak() );
2888
2889
0
    comphelper::OInterfaceContainerHelper2* pContainer =
2890
0
            m_aListenersContainer.getContainer(
2891
0
                cppu::UnoType<embed::XTransactionListener>::get());
2892
0
    if ( !pContainer )
2893
0
           return;
2894
2895
0
    comphelper::OInterfaceIteratorHelper2 pIterator( *pContainer );
2896
0
    while ( pIterator.hasMoreElements( ) )
2897
0
    {
2898
0
        OSL_ENSURE( nMessage >= 1 && nMessage <= 4, "Wrong internal notification code is used!" );
2899
2900
0
        switch( nMessage )
2901
0
        {
2902
0
            case STOR_MESS_PRECOMMIT:
2903
0
                   static_cast<embed::XTransactionListener*>( pIterator.next( ) )->preCommit( aSource );
2904
0
                break;
2905
0
            case STOR_MESS_COMMITTED:
2906
0
                   static_cast<embed::XTransactionListener*>( pIterator.next( ) )->commited( aSource );
2907
0
                break;
2908
0
            case STOR_MESS_PREREVERT:
2909
0
                   static_cast<embed::XTransactionListener*>( pIterator.next( ) )->preRevert( aSource );
2910
0
                break;
2911
0
            case STOR_MESS_REVERTED:
2912
0
                   static_cast< embed::XTransactionListener*>( pIterator.next( ) )->reverted( aSource );
2913
0
                break;
2914
0
        }
2915
0
    }
2916
0
}
2917
void SAL_CALL OWriteStream::commit()
2918
0
{
2919
0
    SAL_INFO( "package.xstor", "package (mv76033) OWriteStream::commit" );
2920
2921
0
    if ( !m_pImpl )
2922
0
    {
2923
0
        SAL_INFO("package.xstor", "Disposed!");
2924
0
        throw lang::DisposedException();
2925
0
    }
2926
2927
0
    if ( !m_bTransacted )
2928
0
        throw uno::RuntimeException();
2929
2930
0
    try {
2931
0
        BroadcastTransaction( STOR_MESS_PRECOMMIT );
2932
2933
0
        osl::ClearableMutexGuard aGuard(m_xSharedMutex->GetMutex());
2934
2935
0
        if ( !m_pImpl )
2936
0
        {
2937
0
            SAL_INFO("package.xstor", "Disposed!");
2938
0
            throw lang::DisposedException();
2939
0
        }
2940
2941
0
        m_pImpl->Commit();
2942
2943
        // when the storage is committed the parent is modified
2944
0
        ModifyParentUnlockMutex_Impl( aGuard );
2945
0
    }
2946
0
    catch( const io::IOException& )
2947
0
    {
2948
0
        TOOLS_INFO_EXCEPTION("package.xstor", "Rethrow");
2949
0
        throw;
2950
0
    }
2951
0
    catch( const embed::StorageWrappedTargetException& )
2952
0
    {
2953
0
        TOOLS_INFO_EXCEPTION("package.xstor", "Rethrow");
2954
0
        throw;
2955
0
    }
2956
0
    catch( const uno::RuntimeException& )
2957
0
    {
2958
0
        TOOLS_INFO_EXCEPTION("package.xstor", "Rethrow");
2959
0
        throw;
2960
0
    }
2961
0
    catch( const uno::Exception& )
2962
0
    {
2963
0
        uno::Any aCaught( ::cppu::getCaughtException() );
2964
0
        SAL_INFO("package.xstor", "Rethrow: " << exceptionToString(aCaught));
2965
0
        throw embed::StorageWrappedTargetException( u"Problems on commit!"_ustr,
2966
0
                                  getXWeak(),
2967
0
                                  aCaught );
2968
0
    }
2969
2970
0
    BroadcastTransaction( STOR_MESS_COMMITTED );
2971
0
}
2972
2973
void SAL_CALL OWriteStream::revert()
2974
0
{
2975
0
    SAL_INFO( "package.xstor", "package (mv76033) OWriteStream::revert" );
2976
2977
    // the method removes all the changes done after last commit
2978
2979
0
    if ( !m_pImpl )
2980
0
    {
2981
0
        SAL_INFO("package.xstor", "Disposed!");
2982
0
        throw lang::DisposedException();
2983
0
    }
2984
2985
0
    if ( !m_bTransacted )
2986
0
        throw uno::RuntimeException();
2987
2988
0
    BroadcastTransaction( STOR_MESS_PREREVERT );
2989
2990
0
    {
2991
0
        osl::MutexGuard aGuard(m_xSharedMutex->GetMutex());
2992
2993
0
        if (!m_pImpl)
2994
0
        {
2995
0
            SAL_INFO("package.xstor", "Disposed!");
2996
0
            throw lang::DisposedException();
2997
0
        }
2998
2999
0
        try {
3000
0
            m_pImpl->Revert();
3001
0
        }
3002
0
        catch (const io::IOException&)
3003
0
        {
3004
0
            TOOLS_INFO_EXCEPTION("package.xstor", "Rethrow");
3005
0
            throw;
3006
0
        }
3007
0
        catch (const embed::StorageWrappedTargetException&)
3008
0
        {
3009
0
            TOOLS_INFO_EXCEPTION("package.xstor", "Rethrow");
3010
0
            throw;
3011
0
        }
3012
0
        catch (const uno::RuntimeException&)
3013
0
        {
3014
0
            TOOLS_INFO_EXCEPTION("package.xstor", "Rethrow");
3015
0
            throw;
3016
0
        }
3017
0
        catch (const uno::Exception&)
3018
0
        {
3019
0
            uno::Any aCaught(::cppu::getCaughtException());
3020
0
            SAL_INFO("package.xstor", "Rethrow: " << exceptionToString(aCaught));
3021
0
            throw embed::StorageWrappedTargetException(u"Problems on revert!"_ustr,
3022
0
                getXWeak(),
3023
0
                aCaught);
3024
0
        }
3025
0
    }
3026
3027
0
    BroadcastTransaction( STOR_MESS_REVERTED );
3028
0
}
3029
3030
//  XTransactionBroadcaster
3031
3032
void SAL_CALL OWriteStream::addTransactionListener( const uno::Reference< embed::XTransactionListener >& aListener )
3033
0
{
3034
0
    ::osl::MutexGuard aGuard( m_xSharedMutex->GetMutex() );
3035
3036
0
    if ( !m_pImpl )
3037
0
    {
3038
0
        SAL_INFO("package.xstor", "Disposed!");
3039
0
        throw lang::DisposedException();
3040
0
    }
3041
3042
0
    if ( !m_bTransacted )
3043
0
        throw uno::RuntimeException();
3044
3045
0
    m_aListenersContainer.addInterface( cppu::UnoType<embed::XTransactionListener>::get(),
3046
0
                                                aListener );
3047
0
}
3048
3049
void SAL_CALL OWriteStream::removeTransactionListener( const uno::Reference< embed::XTransactionListener >& aListener )
3050
0
{
3051
0
    ::osl::MutexGuard aGuard( m_xSharedMutex->GetMutex() );
3052
3053
0
    if ( !m_pImpl )
3054
0
    {
3055
0
        SAL_INFO("package.xstor", "Disposed!");
3056
0
        throw lang::DisposedException();
3057
0
    }
3058
3059
0
    if ( !m_bTransacted )
3060
0
        throw uno::RuntimeException();
3061
3062
0
    m_aListenersContainer.removeInterface( cppu::UnoType<embed::XTransactionListener>::get(),
3063
0
                                                    aListener );
3064
0
}
3065
3066
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */