Coverage Report

Created: 2026-10-14 09:33

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
39.8k
#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
757
{
76
757
    static const sal_Int32 nConstBufferSize = 32000;
77
78
757
    if (auto pByteReader = dynamic_cast< comphelper::ByteReader* >( xInput.get() ))
79
757
    {
80
757
        sal_Int32 nRead;
81
757
        sal_Int8 aTempBuf[ nConstBufferSize ];
82
757
        do
83
1.55k
        {
84
1.55k
            nRead = pByteReader->readSomeBytes ( aTempBuf, nConstBufferSize );
85
1.55k
            rOutput.WriteBytes ( aTempBuf, nRead );
86
1.55k
        }
87
1.55k
        while ( nRead == nConstBufferSize );
88
757
    }
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
757
}
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
160k
: m_xMutex( new comphelper::RefCountedMutex )
234
160k
, m_pAntiImpl( nullptr )
235
160k
, m_bHasDataToFlush( false )
236
160k
, m_bFlushed( false )
237
160k
, m_xPackageStream( xPackageStream )
238
160k
, m_xContext(std::move( xContext ))
239
160k
, m_pParent( pParent )
240
160k
, m_bForceEncrypted( bForceEncrypted )
241
160k
, m_bUseCommonEncryption( !bForceEncrypted && nStorageType == embed::StorageFormats::PACKAGE )
242
160k
, m_bHasCachedEncryptionData( false )
243
160k
, m_bCompressedSetExplicit( !bDefaultCompress )
244
160k
, m_xPackage( xPackage )
245
160k
, m_bHasInsertedStreamOptimization( false )
246
160k
, m_nStorageType( nStorageType )
247
160k
, m_xOrigRelInfoStream(std::move( xRelInfoStream ))
248
160k
, m_bOrigRelInfoBroken( false )
249
160k
, m_nRelInfoStatus( RELINFO_NO_INIT )
250
160k
, m_nRelId( 1 )
251
160k
{
252
160k
    SAL_WARN_IF( !xPackageStream.is(), "package.xstor", "No package stream is provided!" );
253
160k
    SAL_WARN_IF( !xPackage.is(), "package.xstor", "No package component is provided!" );
254
160k
    SAL_WARN_IF( !m_xContext.is(), "package.xstor", "No package stream is provided!" );
255
160k
    OSL_ENSURE( pParent, "No parent storage is provided!" );
256
160k
    OSL_ENSURE( m_nStorageType == embed::StorageFormats::OFOPXML || !m_xOrigRelInfoStream.is(), "The Relations info makes sense only for OFOPXML format!" );
257
160k
}
258
259
OWriteStream_Impl::~OWriteStream_Impl()
260
160k
{
261
160k
    DisposeWrappers();
262
263
160k
    m_oTempFile.reset();
264
265
160k
    CleanCacheStream();
266
160k
}
267
268
void OWriteStream_Impl::CleanCacheStream()
269
160k
{
270
160k
    if ( !m_xCacheStream.is() )
271
149k
        return;
272
273
11.0k
    try
274
11.0k
    {
275
11.0k
        uno::Reference< io::XInputStream > xInputCache = m_xCacheStream->getInputStream();
276
11.0k
        if ( xInputCache.is() )
277
11.0k
            xInputCache->closeInput();
278
11.0k
    }
279
11.0k
    catch( const uno::Exception& )
280
11.0k
    {}
281
282
11.0k
    try
283
11.0k
    {
284
11.0k
        uno::Reference< io::XOutputStream > xOutputCache = m_xCacheStream->getOutputStream();
285
11.0k
        if ( xOutputCache.is() )
286
11.0k
            xOutputCache->closeOutput();
287
11.0k
    }
288
11.0k
    catch( const uno::Exception& )
289
11.0k
    {}
290
291
11.0k
    m_xCacheStream.clear();
292
11.0k
    m_xCacheSeek.clear();
293
11.0k
}
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
184k
{
313
184k
    if ( m_nStorageType != embed::StorageFormats::PACKAGE )
314
183k
        return false;
315
316
921
    if ( m_bForceEncrypted || m_bHasCachedEncryptionData )
317
0
        return true;
318
319
921
    if ( m_oTempFile.has_value() || m_xCacheStream.is() )
320
0
        return false;
321
322
921
    GetStreamProperties();
323
324
    // the following value can not be cached since it can change after root commit
325
921
    bool bWasEncr = false;
326
921
    uno::Reference< beans::XPropertySet > xPropSet( m_xPackageStream, uno::UNO_QUERY );
327
921
    if ( xPropSet.is() )
328
921
    {
329
921
        uno::Any aValue = xPropSet->getPropertyValue(u"WasEncrypted"_ustr);
330
921
        if ( !( aValue >>= bWasEncr ) )
331
0
        {
332
0
            SAL_WARN( "package.xstor", "The property WasEncrypted has wrong type!" );
333
0
        }
334
921
    }
335
336
921
    bool bToBeEncr = false;
337
921
    for (const auto& rProp : m_aProps)
338
3.68k
    {
339
3.68k
        if ( rProp.Name == "Encrypted" )
340
921
        {
341
921
            if ( !( rProp.Value >>= bToBeEncr ) )
342
0
            {
343
0
                SAL_WARN( "package.xstor", "The property has wrong type!" );
344
0
            }
345
921
        }
346
3.68k
    }
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
921
    uno::Sequence< beans::NamedValue > aKey;
351
921
    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
921
    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
921
    else
367
921
        return bToBeEncr;
368
921
}
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
160k
{
424
160k
    ::osl::MutexGuard aGuard( m_xMutex->GetMutex() );
425
160k
    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
160k
    m_pParent = nullptr;
438
439
160k
    if ( m_aInputStreamsVector.empty() )
440
160k
        return;
441
442
2
    for ( auto& pStream : m_aInputStreamsVector )
443
2
    {
444
2
        if ( pStream )
445
2
        {
446
2
            pStream->InternalDispose();
447
2
            pStream = nullptr;
448
2
        }
449
2
    }
450
451
2
    m_aInputStreamsVector.clear();
452
2
}
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
13.2k
{
487
    // should try to create cache first, if the amount of contents is too big, the temp file should be taken
488
13.2k
    if ( !m_xCacheStream.is() && !m_oTempFile.has_value() )
489
13.2k
    {
490
13.2k
        uno::Reference< io::XInputStream > xOrigStream = m_xPackageStream->getDataStream();
491
13.2k
        if ( !xOrigStream.is() )
492
37
        {
493
            // in case of new inserted package stream it is possible that input stream still was not set
494
37
            rtl::Reference< comphelper::UNOMemoryStream > xCacheStream = new comphelper::UNOMemoryStream();
495
37
            m_xCacheSeek = xCacheStream;
496
37
            m_xCacheStream = std::move(xCacheStream);
497
37
        }
498
13.2k
        else
499
13.2k
        {
500
13.2k
            sal_Int32 nRead = 0;
501
13.2k
            uno::Sequence< sal_Int8 > aData( MAX_STORCACHE_SIZE + 1 );
502
13.2k
            nRead = xOrigStream->readBytes( aData, MAX_STORCACHE_SIZE + 1 );
503
13.2k
            if ( aData.getLength() > nRead )
504
0
                aData.realloc( nRead );
505
506
13.2k
            if ( nRead <= MAX_STORCACHE_SIZE )
507
11.2k
            {
508
11.2k
                rtl::Reference< comphelper::UNOMemoryStream > xCacheStream = new comphelper::UNOMemoryStream();
509
510
11.2k
                if ( nRead )
511
11.2k
                {
512
11.2k
                    uno::Reference< io::XOutputStream > xOutStream( xCacheStream->getOutputStream(), uno::UNO_SET_THROW );
513
11.2k
                    xOutStream->writeBytes( aData );
514
11.2k
                }
515
11.2k
                m_xCacheSeek = xCacheStream;
516
11.2k
                m_xCacheStream = std::move(xCacheStream);
517
11.2k
                m_xCacheSeek->seek( 0 );
518
11.2k
            }
519
1.93k
            else if ( !m_oTempFile.has_value() )
520
753
            {
521
753
                m_oTempFile.emplace();
522
523
753
                try {
524
                    // copy stream contents to the file
525
753
                    SvStream* pStream = m_oTempFile->GetStream(StreamMode::READWRITE);
526
753
                    pStream->WriteBytes( aData.getConstArray(), aData.getLength() );
527
528
                    // the current position of the original stream should be still OK, copy further
529
753
                    package::CopyInputToOutput( xOrigStream, *pStream );
530
753
                }
531
753
                catch( const packages::WrongPasswordException& )
532
753
                {
533
0
                    m_oTempFile.reset();
534
0
                    throw;
535
0
                }
536
753
                catch( const uno::Exception& )
537
753
                {
538
100
                    m_oTempFile.reset();
539
100
                }
540
753
            }
541
13.2k
        }
542
13.2k
    }
543
13.2k
}
544
545
uno::Reference< io::XStream > OWriteStream_Impl::GetTempFileAsStream()
546
229
{
547
229
    uno::Reference< io::XStream > xTempStream;
548
549
229
    if ( !m_xCacheStream.is() )
550
229
    {
551
229
        if ( !m_oTempFile.has_value() )
552
225
            FillTempGetFileName();
553
554
229
        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
229
    }
569
570
229
    if ( m_xCacheStream.is() )
571
221
        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
229
    if ( !xTempStream.is() )
577
0
        throw io::IOException(u"no temp stream"_ustr); //TODO:
578
579
229
    return xTempStream;
580
229
}
581
582
uno::Reference< io::XInputStream > OWriteStream_Impl::GetTempFileAsInputStream()
583
15.2k
{
584
15.2k
    uno::Reference< io::XInputStream > xInputStream;
585
586
15.2k
    if ( !m_xCacheStream.is() )
587
13.0k
    {
588
13.0k
        if ( !m_oTempFile.has_value() )
589
13.0k
            FillTempGetFileName();
590
591
13.0k
        if ( m_oTempFile.has_value() )
592
649
        {
593
            // the temporary file is not used if the cache is used
594
649
            try
595
649
            {
596
649
                SvStream* pStream = m_oTempFile->GetStream(StreamMode::READWRITE);
597
649
                pStream->Seek(0);
598
649
                xInputStream = new utl::OStreamWrapper(pStream, /*bOwner*/false);
599
649
            }
600
649
            catch( const uno::Exception& )
601
649
            {
602
0
                TOOLS_INFO_EXCEPTION("package.xstor", "Quiet exception");
603
0
            }
604
649
        }
605
13.0k
    }
606
607
15.2k
    if ( m_xCacheStream.is() )
608
13.3k
        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
15.2k
    if ( !xInputStream.is() )
614
100
        throw io::IOException(); // TODO:
615
616
15.1k
    return xInputStream;
617
15.2k
}
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
405
{
703
405
    ::osl::MutexGuard aGuard( m_xMutex->GetMutex() ) ;
704
705
405
    SAL_WARN_IF( !m_xPackageStream.is(), "package.xstor", "No package stream is set!" );
706
707
405
    if ( !m_bHasDataToFlush )
708
0
        return;
709
710
405
    uno::Reference< packages::XDataSinkEncrSupport > xNewPackageStream;
711
405
    uno::Sequence< uno::Any > aSeq{ uno::Any(false) };
712
713
405
    if ( m_xCacheStream.is() )
714
397
    {
715
397
        if ( m_pAntiImpl )
716
191
            m_pAntiImpl->DeInit();
717
718
397
        uno::Reference< io::XInputStream > xInStream( m_xCacheStream->getInputStream(), uno::UNO_SET_THROW );
719
720
397
        xNewPackageStream.set( m_xPackage->createInstanceWithArguments( aSeq ), uno::UNO_QUERY_THROW );
721
722
397
        xNewPackageStream->setDataStream( xInStream );
723
724
397
        m_xCacheStream.clear();
725
397
        m_xCacheSeek.clear();
726
727
397
    }
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
405
    uno::Reference< beans::XPropertySet > xPropertySet( xNewPackageStream, uno::UNO_QUERY_THROW );
760
761
405
    for ( auto& rProp : asNonConstRange(m_aProps) )
762
1.62k
    {
763
1.62k
        if ( rProp.Name == "Size" )
764
405
        {
765
405
            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
405
        }
771
1.21k
        else
772
1.21k
            xPropertySet->setPropertyValue( rProp.Name, rProp.Value );
773
1.62k
    }
774
775
405
    if ( m_bUseCommonEncryption )
776
405
    {
777
405
        if ( m_nStorageType != embed::StorageFormats::PACKAGE )
778
0
            throw uno::RuntimeException();
779
780
        // set to be encrypted but do not use encryption key
781
405
        xPropertySet->setPropertyValue( STORAGE_ENCRYPTION_KEYS_PROPERTY,
782
405
                                        uno::Any( uno::Sequence< beans::NamedValue >() ) );
783
405
        xPropertySet->setPropertyValue( u"Encrypted"_ustr,
784
405
                                        uno::Any( true ) );
785
405
    }
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
405
    m_xPackageStream = std::move(xNewPackageStream);
797
405
    m_bHasDataToFlush = false;
798
405
    m_bFlushed = true; // will allow to use transaction on stream level if will need it
799
405
}
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
186k
{
853
186k
    if ( !m_aProps.hasElements() )
854
160k
        m_aProps = ReadPackageStreamProperties();
855
856
186k
    return m_aProps;
857
186k
}
858
859
uno::Sequence< beans::PropertyValue > OWriteStream_Impl::InsertOwnProps(
860
                                                                    const uno::Sequence< beans::PropertyValue >& aProps,
861
                                                                    bool bUseCommonEncryption )
862
146k
{
863
146k
    uno::Sequence< beans::PropertyValue > aResult( aProps );
864
146k
    beans::PropertyValue aPropVal;
865
866
146k
    if ( m_nStorageType == embed::StorageFormats::PACKAGE )
867
691
    {
868
691
        aPropVal.Name = "UseCommonStoragePasswordEncryption";
869
691
        aPropVal.Value <<= bUseCommonEncryption;
870
691
    }
871
146k
    else if ( m_nStorageType == embed::StorageFormats::OFOPXML )
872
41.7k
    {
873
41.7k
        ReadRelInfoIfNecessary();
874
875
41.7k
        aPropVal.Name = "RelationsInfo";
876
41.7k
        if ( m_nRelInfoStatus == RELINFO_READ )
877
41.7k
            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
41.7k
    }
883
146k
    if (!aPropVal.Name.isEmpty())
884
42.4k
    {
885
42.4k
        sal_Int32 i = 0;
886
170k
        for (auto p = aResult.getConstArray(); i < aResult.getLength(); ++i)
887
127k
            if (p[i].Name == aPropVal.Name)
888
0
                break;
889
42.4k
        if (i == aResult.getLength())
890
42.4k
            aResult.realloc(i + 1);
891
42.4k
        aResult.getArray()[i] = std::move(aPropVal);
892
42.4k
    }
893
894
146k
    return aResult;
895
146k
}
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
226k
{
905
226k
    if ( m_nStorageType != embed::StorageFormats::OFOPXML )
906
128k
        return;
907
908
97.9k
    if ( m_nRelInfoStatus == RELINFO_NO_INIT )
909
51.2k
    {
910
51.2k
        try
911
51.2k
        {
912
            // Init from original stream
913
51.2k
            if ( m_xOrigRelInfoStream.is() )
914
3.88k
                m_aOrigRelInfo = ::comphelper::OFOPXMLHelper::ReadRelationsInfoSequence(
915
3.88k
                                        m_xOrigRelInfoStream,
916
3.88k
                                        u"_rels/*.rels",
917
3.88k
                                        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
51.2k
            m_xOrigRelInfoStream.clear();
923
51.2k
            m_nRelInfoStatus = RELINFO_READ;
924
51.2k
        }
925
51.2k
        catch( const uno::Exception& )
926
51.2k
        {
927
0
            TOOLS_INFO_EXCEPTION("package.xstor", "Quiet exception");
928
929
0
            m_nRelInfoStatus = RELINFO_BROKEN;
930
0
            m_bOrigRelInfoBroken = true;
931
0
        }
932
51.2k
    }
933
46.6k
    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
97.9k
}
952
953
uno::Sequence< beans::PropertyValue > OWriteStream_Impl::ReadPackageStreamProperties()
954
160k
{
955
160k
    sal_Int32 nPropNum = 0;
956
160k
    if ( m_nStorageType == embed::StorageFormats::ZIP )
957
109k
        nPropNum = 2;
958
51.4k
    else if ( m_nStorageType == embed::StorageFormats::OFOPXML )
959
51.2k
        nPropNum = 3;
960
204
    else if ( m_nStorageType == embed::StorageFormats::PACKAGE )
961
204
        nPropNum = 4;
962
160k
    assert(nPropNum >= 2);
963
160k
    uno::Sequence< beans::PropertyValue > aResult( nPropNum );
964
160k
    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
160k
    static constexpr OUStringLiteral sMediaType = u"MediaType";
969
160k
    static constexpr OUString sCompressed = u"Compressed"_ustr;
970
160k
    static constexpr OUString sSize = u"Size"_ustr;
971
160k
    static constexpr OUStringLiteral sEncrypted = u"Encrypted";
972
160k
    if ( m_nStorageType == embed::StorageFormats::OFOPXML || m_nStorageType == embed::StorageFormats::PACKAGE )
973
51.4k
    {
974
51.4k
        aResultRange[0].Name = sMediaType;
975
51.4k
        aResultRange[1].Name = sCompressed;
976
51.4k
        aResultRange[2].Name = sSize;
977
978
51.4k
        if ( m_nStorageType == embed::StorageFormats::PACKAGE )
979
204
            aResultRange[3].Name = sEncrypted;
980
51.4k
    }
981
109k
    else
982
109k
    {
983
109k
        aResultRange[0].Name = sCompressed;
984
109k
        aResultRange[1].Name = sSize;
985
109k
    }
986
987
    // TODO: may be also raw stream should be marked
988
989
160k
    uno::Reference< beans::XPropertySet > xPropSet( m_xPackageStream, uno::UNO_QUERY_THROW );
990
160k
    for ( auto& rProp : aResultRange )
991
373k
    {
992
373k
        try {
993
373k
            rProp.Value = xPropSet->getPropertyValue( rProp.Name );
994
373k
        }
995
373k
        catch( const uno::Exception& )
996
373k
        {
997
0
            TOOLS_WARN_EXCEPTION( "package.xstor", "A property can't be retrieved" );
998
0
        }
999
373k
    }
1000
1001
160k
    return aResult;
1002
160k
}
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
13
{
1034
13
    if ( m_nStorageType != embed::StorageFormats::OFOPXML )
1035
13
        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
13
{
1049
13
    ::osl::MutexGuard aGuard( m_xMutex->GetMutex() ) ;
1050
1051
13
    if ( m_pAntiImpl )
1052
0
    {
1053
0
        m_pAntiImpl->CopyToStreamInternally_Impl( xDestStream );
1054
0
    }
1055
13
    else
1056
13
    {
1057
13
        uno::Reference< io::XStream > xOwnStream = GetStream( embed::ElementModes::READ, false );
1058
13
        if ( !xOwnStream.is() )
1059
0
            throw io::IOException(); // TODO
1060
1061
13
        OStorage_Impl::completeStorageStreamCopy_Impl( xOwnStream, xDestStream, m_nStorageType, GetAllRelationshipsIfAny() );
1062
13
    }
1063
13
}
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
184k
{
1121
184k
    ::osl::MutexGuard aGuard( m_xMutex->GetMutex() ) ;
1122
1123
184k
    SAL_WARN_IF( !m_xPackageStream.is(), "package.xstor", "No package stream is set!" );
1124
1125
184k
    if ( m_pAntiImpl )
1126
0
        throw io::IOException(); // TODO:
1127
1128
184k
    uno::Reference< io::XStream > xResultStream;
1129
1130
184k
    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
184k
    else
1146
184k
        xResultStream = GetStream_Impl( nStreamMode, bHierarchyAccess );
1147
1148
184k
    return xResultStream;
1149
184k
}
1150
1151
uno::Reference< io::XStream > OWriteStream_Impl::GetStream_Impl( sal_Int32 nStreamMode, bool bHierarchyAccess )
1152
184k
{
1153
    // private method, no mutex is used
1154
184k
    GetStreamProperties();
1155
1156
    // TODO/LATER: this info might be read later, on demand in future
1157
184k
    ReadRelInfoIfNecessary();
1158
1159
184k
    if ( ( nStreamMode & embed::ElementModes::READWRITE ) == embed::ElementModes::READ )
1160
159k
    {
1161
159k
        uno::Reference< io::XInputStream > xInStream;
1162
159k
        if ( m_xCacheStream.is() || m_oTempFile.has_value() )
1163
0
            xInStream = GetTempFileAsInputStream(); //TODO:
1164
159k
        else
1165
159k
            xInStream = m_xPackageStream->getDataStream();
1166
1167
        // The stream does not exist in the storage
1168
159k
        if ( !xInStream.is() )
1169
0
            throw io::IOException();
1170
1171
159k
        rtl::Reference<OInputCompStream> pStream = new OInputCompStream( *this, xInStream, InsertOwnProps( m_aProps, m_bUseCommonEncryption ), m_nStorageType );
1172
159k
        m_aInputStreamsVector.push_back( pStream.get() );
1173
159k
        return pStream;
1174
159k
    }
1175
25.1k
    else if ( ( nStreamMode & embed::ElementModes::READWRITE ) == embed::ElementModes::SEEKABLEREAD )
1176
24.9k
    {
1177
24.9k
        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
24.9k
        uno::Reference< io::XInputStream > xInStream = GetTempFileAsInputStream(); //TODO:
1184
1185
24.9k
        if ( !xInStream.is() )
1186
0
            throw io::IOException();
1187
1188
24.9k
        rtl::Reference<OInputSeekStream> pStream = new OInputSeekStream( *this, xInStream, InsertOwnProps( m_aProps, m_bUseCommonEncryption ), m_nStorageType );
1189
24.9k
        m_aInputStreamsVector.push_back( pStream.get() );
1190
24.9k
        return pStream;
1191
24.9k
    }
1192
217
    else if ( ( nStreamMode & embed::ElementModes::WRITE ) == embed::ElementModes::WRITE )
1193
217
    {
1194
217
        if ( !m_aInputStreamsVector.empty() )
1195
0
            throw io::IOException(); // TODO:
1196
1197
217
        uno::Reference< io::XStream > xStream;
1198
217
        if ( ( nStreamMode & embed::ElementModes::TRUNCATE ) == embed::ElementModes::TRUNCATE )
1199
180
        {
1200
180
            m_oTempFile.reset();
1201
180
            if ( m_xCacheStream.is() )
1202
0
                CleanCacheStream();
1203
1204
180
            m_bHasDataToFlush = true;
1205
1206
            // this call is triggered by the parent and it will recognize the change of the state
1207
180
            if ( m_pParent )
1208
180
                m_pParent->m_bIsModified = true;
1209
1210
180
            rtl::Reference<comphelper::UNOMemoryStream> xMemStream = new comphelper::UNOMemoryStream();
1211
180
            xStream = xMemStream;
1212
180
            m_xCacheSeek = xMemStream;
1213
180
            m_xCacheStream = xStream;
1214
180
        }
1215
37
        else if ( !m_bHasInsertedStreamOptimization )
1216
37
        {
1217
37
            if ( !m_oTempFile.has_value() && !m_xCacheStream.is() && !( m_xPackageStream->getDataStream().is() ) )
1218
37
            {
1219
                // The stream does not exist in the storage
1220
37
                m_bHasDataToFlush = true;
1221
1222
                // this call is triggered by the parent and it will recognize the change of the state
1223
37
                if ( m_pParent )
1224
37
                    m_pParent->m_bIsModified = true;
1225
37
                xStream = GetTempFileAsStream();
1226
37
            }
1227
1228
            // if the stream exists the temporary file is created on demand
1229
            // xStream = GetTempFileAsStream();
1230
37
        }
1231
1232
217
        rtl::Reference<OWriteStream> tmp;
1233
217
        assert(m_xMutex.is() && "No mutex!");
1234
217
        if ( !xStream.is() )
1235
0
            tmp = new OWriteStream( *this, bHierarchyAccess );
1236
217
        else
1237
217
            tmp = new OWriteStream( *this, xStream, bHierarchyAccess );
1238
1239
217
        m_pAntiImpl = tmp.get();
1240
217
        return tmp;
1241
217
    }
1242
1243
0
    throw lang::IllegalArgumentException(); // TODO
1244
184k
}
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
146k
{
1287
146k
    ::osl::MutexGuard aGuard( m_xMutex->GetMutex() );
1288
146k
    std::erase(m_aInputStreamsVector, pStream);
1289
146k
}
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
217
: m_pImpl( &rImpl )
1532
217
, m_xSharedMutex( rImpl.m_xMutex )
1533
217
, m_aListenersContainer( rImpl.m_xMutex->GetMutex() )
1534
217
, m_nStorageType( m_pImpl->m_nStorageType )
1535
217
, m_bInStreamDisconnected( false )
1536
217
, m_bInitOnDemand( false )
1537
217
, m_nInitPosition( 0 )
1538
217
, m_bTransacted( bTransacted )
1539
217
{
1540
217
    if ( xStream.is() )
1541
217
    {
1542
217
        m_xInStream = xStream->getInputStream();
1543
217
        m_xOutStream = xStream->getOutputStream();
1544
217
        m_xSeekable.set( xStream, uno::UNO_QUERY );
1545
217
        OSL_ENSURE( m_xInStream.is() && m_xOutStream.is() && m_xSeekable.is(), "Stream implementation is incomplete!" );
1546
217
    }
1547
217
}
1548
1549
OWriteStream::~OWriteStream()
1550
217
{
1551
217
    ::osl::MutexGuard aGuard( m_xSharedMutex->GetMutex() );
1552
217
    if ( m_pImpl )
1553
187
    {
1554
187
        osl_atomic_increment(&m_refCount);
1555
187
        try {
1556
187
            dispose();
1557
187
        }
1558
187
        catch( const uno::RuntimeException& )
1559
187
        {
1560
0
            TOOLS_INFO_EXCEPTION("package.xstor", "Quiet exception");
1561
0
        }
1562
187
    }
1563
217
}
1564
1565
void OWriteStream::DeInit()
1566
199
{
1567
199
    if ( !m_pImpl )
1568
0
        return; // do nothing
1569
1570
199
    if ( m_xSeekable.is() )
1571
199
        m_nInitPosition = m_xSeekable->getPosition();
1572
1573
199
    m_xInStream.clear();
1574
199
    m_xOutStream.clear();
1575
199
    m_xSeekable.clear();
1576
199
    m_bInitOnDemand = true;
1577
199
}
1578
1579
void OWriteStream::CheckInitOnDemand()
1580
1.11k
{
1581
1.11k
    if ( !m_pImpl )
1582
0
    {
1583
0
        SAL_INFO("package.xstor", "Disposed!");
1584
0
        throw lang::DisposedException();
1585
0
    }
1586
1587
1.11k
    if ( !m_bInitOnDemand )
1588
923
        return;
1589
1590
188
    SAL_INFO( "package.xstor", "package (mv76033) OWriteStream::CheckInitOnDemand, initializing" );
1591
188
    uno::Reference< io::XStream > xStream = m_pImpl->GetTempFileAsStream();
1592
188
    if ( xStream.is() )
1593
188
    {
1594
188
        m_xInStream.set( xStream->getInputStream(), uno::UNO_SET_THROW );
1595
188
        m_xOutStream.set( xStream->getOutputStream(), uno::UNO_SET_THROW );
1596
188
        m_xSeekable.set( xStream, uno::UNO_QUERY_THROW );
1597
188
        m_xSeekable->seek( m_nInitPosition );
1598
1599
188
        m_nInitPosition = 0;
1600
188
        m_bInitOnDemand = false;
1601
188
    }
1602
188
}
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
501
{
1670
501
    if ( m_pImpl->m_pParent )
1671
501
    {
1672
501
        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
501
        else
1679
501
            m_pImpl->m_pParent->m_bIsModified = true;
1680
501
    }
1681
501
}
1682
1683
uno::Any SAL_CALL OWriteStream::queryInterface( const uno::Type& rType )
1684
451
{
1685
    // common interfaces
1686
451
    uno::Any aReturn = ::cppu::queryInterface
1687
451
                (   rType
1688
451
                    ,   static_cast<lang::XTypeProvider*> ( this )
1689
451
                    ,   static_cast<io::XInputStream*> ( this )
1690
451
                    ,   static_cast<io::XOutputStream*> ( this )
1691
451
                    ,   static_cast<io::XStream*> ( this )
1692
451
                    ,   static_cast<embed::XExtendedStorageStream*> ( this )
1693
451
                    ,   static_cast<io::XSeekable*> ( this )
1694
451
                    ,   static_cast<io::XTruncate*> ( this )
1695
451
                    ,   static_cast<lang::XComponent*> ( this )
1696
451
                    ,   static_cast<beans::XPropertySet*> ( this ) );
1697
1698
451
    if ( aReturn.hasValue() )
1699
451
        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.12k
{
1734
3.12k
    OWeakObject::acquire();
1735
3.12k
}
1736
1737
void SAL_CALL OWriteStream::release() noexcept
1738
3.12k
{
1739
3.12k
    OWeakObject::release();
1740
3.12k
}
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
174
{
1945
174
    ::osl::MutexGuard aGuard( m_xSharedMutex->GetMutex() );
1946
1947
174
    if ( !m_bInitOnDemand && ( m_bInStreamDisconnected || !m_xInStream.is() ) )
1948
0
        return uno::Reference< io::XInputStream >();
1949
1950
174
    return this;
1951
174
}
1952
1953
uno::Reference< io::XOutputStream > SAL_CALL OWriteStream::getOutputStream()
1954
528
{
1955
528
    ::osl::MutexGuard aGuard( m_xSharedMutex->GetMutex() );
1956
1957
528
    try
1958
528
    {
1959
528
        CheckInitOnDemand();
1960
528
    }
1961
528
    catch( const io::IOException& r )
1962
528
    {
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
528
    if ( !m_xOutStream.is() )
1968
0
        return uno::Reference< io::XOutputStream >();
1969
1970
528
    return this;
1971
528
}
1972
1973
void OWriteStream::CheckInitOnWriteDemand(sal_Int32 dataSize)
1974
288
{
1975
    // write methods need a different initialization, since they depend on data length
1976
1977
288
    if ( !m_pImpl )
1978
0
    {
1979
0
        SAL_INFO("package.xstor", "Disposed!");
1980
0
        throw lang::DisposedException();
1981
0
    }
1982
1983
288
    if ( !m_bInitOnDemand )
1984
288
    {
1985
288
        if ( !m_xOutStream.is() || !m_xSeekable.is())
1986
0
            throw io::NotConnectedException();
1987
1988
288
        if ( m_pImpl->m_xCacheStream.is() )
1989
256
        {
1990
            // check whether the cache should be turned off
1991
256
            sal_Int64 nPos = m_xSeekable->getPosition();
1992
256
            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
256
        }
2007
288
    }
2008
2009
288
    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
288
}
2025
2026
void SAL_CALL OWriteStream::writeBytes( const uno::Sequence< sal_Int8 >& aData )
2027
275
{
2028
275
    osl::ClearableMutexGuard aGuard(m_xSharedMutex->GetMutex());
2029
2030
275
    CheckInitOnWriteDemand(aData.getLength());
2031
2032
275
    if ( !m_xOutStream.is() )
2033
0
        throw io::NotConnectedException();
2034
2035
275
    m_xOutStream->writeBytes( aData );
2036
275
    m_pImpl->m_bHasDataToFlush = true;
2037
2038
275
    ModifyParentUnlockMutex_Impl( aGuard );
2039
275
}
2040
2041
void OWriteStream::writeBytes( const sal_Int8* pData, sal_Int32 nBytesToWrite )
2042
13
{
2043
13
    assert(nBytesToWrite >= 0);
2044
2045
13
    osl::ClearableMutexGuard aGuard(m_xSharedMutex->GetMutex());
2046
2047
13
    CheckInitOnWriteDemand(nBytesToWrite);
2048
2049
13
    if ( !m_xOutStream.is() )
2050
0
        throw io::NotConnectedException();
2051
2052
13
    if (auto pByteWriter = dynamic_cast< comphelper::ByteWriter* >( m_xOutStream.get() ))
2053
13
        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
13
    m_pImpl->m_bHasDataToFlush = true;
2060
2061
13
    ModifyParentUnlockMutex_Impl( aGuard );
2062
13
}
2063
2064
void SAL_CALL OWriteStream::flush()
2065
202
{
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
202
    ::osl::MutexGuard aGuard( m_xSharedMutex->GetMutex() );
2072
2073
202
    if ( !m_pImpl )
2074
0
    {
2075
0
        SAL_INFO("package.xstor", "Disposed!");
2076
0
        throw lang::DisposedException();
2077
0
    }
2078
2079
202
    if ( !m_bInitOnDemand )
2080
195
    {
2081
195
        if ( !m_xOutStream.is() )
2082
0
            throw io::NotConnectedException();
2083
2084
195
        m_xOutStream->flush();
2085
195
        m_pImpl->Commit();
2086
195
    }
2087
202
}
2088
2089
void OWriteStream::CloseOutput_Impl()
2090
210
{
2091
    // all the checks must be done in calling method
2092
2093
210
    m_xOutStream->closeOutput();
2094
210
    m_xOutStream.clear();
2095
2096
210
    if ( m_bInitOnDemand )
2097
0
        return;
2098
2099
    // after the stream is disposed it can be committed
2100
    // so transport correct size property
2101
210
    if ( !m_xSeekable.is() )
2102
0
        throw uno::RuntimeException();
2103
2104
210
    for ( auto& rProp : asNonConstRange(m_pImpl->m_aProps) )
2105
840
    {
2106
840
        if ( rProp.Name == "Size" )
2107
210
            rProp.Value <<= m_xSeekable->getLength();
2108
840
    }
2109
210
}
2110
2111
void SAL_CALL OWriteStream::closeOutput()
2112
167
{
2113
167
    ::osl::MutexGuard aGuard( m_xSharedMutex->GetMutex() );
2114
2115
167
    CheckInitOnDemand();
2116
2117
167
    if ( !m_xOutStream.is() )
2118
0
        throw io::NotConnectedException();
2119
2120
167
    CloseOutput_Impl();
2121
2122
167
    if ( m_bInStreamDisconnected || !m_xInStream.is() )
2123
0
        dispose();
2124
167
}
2125
2126
void SAL_CALL OWriteStream::seek( sal_Int64 location )
2127
282
{
2128
282
    ::osl::MutexGuard aGuard( m_xSharedMutex->GetMutex() );
2129
2130
282
    CheckInitOnDemand();
2131
2132
282
    if ( !m_xSeekable.is() )
2133
0
        throw uno::RuntimeException();
2134
2135
282
    m_xSeekable->seek( location );
2136
282
}
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
127
{
2152
127
    ::osl::MutexGuard aGuard( m_xSharedMutex->GetMutex() );
2153
2154
127
    CheckInitOnDemand();
2155
2156
127
    if ( !m_xSeekable.is() )
2157
0
        throw uno::RuntimeException();
2158
2159
127
    return m_xSeekable->getLength();
2160
127
}
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
217
{
2181
    // should be an internal method since it can be called only from parent storage
2182
217
    {
2183
217
        ::osl::MutexGuard aGuard( m_xSharedMutex->GetMutex() );
2184
2185
217
        if ( !m_pImpl )
2186
0
        {
2187
0
            SAL_INFO("package.xstor", "Disposed!");
2188
0
            throw lang::DisposedException();
2189
0
        }
2190
2191
217
        if ( m_xOutStream.is() )
2192
43
            CloseOutput_Impl();
2193
2194
217
        if ( m_xInStream.is() )
2195
210
        {
2196
210
            m_xInStream->closeInput();
2197
210
            m_xInStream.clear();
2198
210
        }
2199
2200
217
        m_xSeekable.clear();
2201
2202
217
        m_pImpl->m_pAntiImpl = nullptr;
2203
2204
217
        if ( !m_bInitOnDemand )
2205
210
        {
2206
210
            try
2207
210
            {
2208
210
                if ( !m_bTransacted )
2209
210
                {
2210
210
                    m_pImpl->Commit();
2211
210
                }
2212
0
                else
2213
0
                {
2214
                    // throw away all the changes
2215
0
                    m_pImpl->Revert();
2216
0
                }
2217
210
            }
2218
210
            catch( const uno::Exception& )
2219
210
            {
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
210
        }
2227
2228
217
        m_pImpl = nullptr;
2229
217
    }
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
217
    m_aListenersContainer.disposeAndClear( aSource );
2237
217
}
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
213
{
2641
213
    osl::ClearableMutexGuard aGuard(m_xSharedMutex->GetMutex());
2642
2643
213
    if ( !m_pImpl )
2644
0
    {
2645
0
        SAL_INFO("package.xstor", "Disposed!");
2646
0
        throw lang::DisposedException();
2647
0
    }
2648
2649
213
    m_pImpl->GetStreamProperties();
2650
213
    static constexpr OUString aCompressedString( u"Compressed"_ustr );
2651
213
    static constexpr OUString aMediaTypeString( u"MediaType"_ustr );
2652
213
    if ( m_nStorageType == embed::StorageFormats::PACKAGE && aPropertyName == aMediaTypeString )
2653
187
    {
2654
        // if the "Compressed" property is not set explicitly, the MediaType can change the default value
2655
187
        bool bCompressedValueFromType = true;
2656
187
        OUString aType;
2657
187
        aValue >>= aType;
2658
2659
187
        if ( !m_pImpl->m_bCompressedSetExplicit )
2660
174
        {
2661
174
            if ( aType == "image/jpeg" || aType == "image/png" || aType == "image/gif" )
2662
0
                bCompressedValueFromType = false;
2663
174
        }
2664
2665
187
        for ( auto& rProp : asNonConstRange(m_pImpl->m_aProps) )
2666
748
        {
2667
748
            if ( aPropertyName == rProp.Name )
2668
187
                rProp.Value = aValue;
2669
561
            else if ( !m_pImpl->m_bCompressedSetExplicit && aCompressedString == rProp.Name )
2670
174
                rProp.Value <<= bCompressedValueFromType;
2671
748
        }
2672
187
    }
2673
26
    else if ( aPropertyName == aCompressedString )
2674
13
    {
2675
        // if the "Compressed" property is not set explicitly, the MediaType can change the default value
2676
13
        m_pImpl->m_bCompressedSetExplicit = true;
2677
13
        for ( auto& rProp : asNonConstRange(m_pImpl->m_aProps) )
2678
52
        {
2679
52
            if ( aPropertyName == rProp.Name )
2680
13
                rProp.Value = aValue;
2681
52
        }
2682
13
    }
2683
13
    else if ( m_nStorageType == embed::StorageFormats::PACKAGE
2684
13
            && aPropertyName == "UseCommonStoragePasswordEncryption" )
2685
13
    {
2686
13
        bool bUseCommonEncryption = false;
2687
13
        if ( !(aValue >>= bUseCommonEncryption) )
2688
0
            throw lang::IllegalArgumentException(); //TODO
2689
2690
13
        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
13
        else if ( bUseCommonEncryption )
2696
13
        {
2697
13
            if ( !m_pImpl->m_bUseCommonEncryption )
2698
0
            {
2699
0
                m_pImpl->SetDecrypted();
2700
0
                m_pImpl->m_bUseCommonEncryption = true;
2701
0
            }
2702
13
        }
2703
0
        else
2704
0
            m_pImpl->m_bUseCommonEncryption = false;
2705
13
    }
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
213
    m_pImpl->m_bHasDataToFlush = true;
2751
213
    ModifyParentUnlockMutex_Impl( aGuard );
2752
213
}
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: */