Coverage Report

Created: 2026-06-30 11:14

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/sot/source/sdstor/ucbstorage.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 <com/sun/star/io/NotConnectedException.hpp>
21
#include <com/sun/star/io/BufferSizeExceededException.hpp>
22
#include <com/sun/star/uno/RuntimeException.hpp>
23
#include <ucbhelper/content.hxx>
24
#include <com/sun/star/uno/Reference.h>
25
#include <com/sun/star/ucb/NameClash.hpp>
26
#include <unotools/tempfile.hxx>
27
#include <unotools/ucbstreamhelper.hxx>
28
#include <com/sun/star/io/XInputStream.hpp>
29
#include <com/sun/star/ucb/InsertCommandArgument.hpp>
30
#include <com/sun/star/ucb/ResultSetException.hpp>
31
#include <com/sun/star/uno/Sequence.h>
32
#include <com/sun/star/sdbc/XResultSet.hpp>
33
#include <com/sun/star/sdbc/XRow.hpp>
34
#include <com/sun/star/ucb/CommandAbortedException.hpp>
35
#include <com/sun/star/datatransfer/DataFlavor.hpp>
36
#include <com/sun/star/ucb/ContentInfo.hpp>
37
#include <com/sun/star/ucb/ContentInfoAttribute.hpp>
38
#include <com/sun/star/beans/Property.hpp>
39
#include <com/sun/star/packages/manifest/ManifestWriter.hpp>
40
#include <com/sun/star/packages/manifest/ManifestReader.hpp>
41
#include <com/sun/star/ucb/InteractiveIOException.hpp>
42
#include <com/sun/star/ucb/ContentCreationException.hpp>
43
44
#include <memory>
45
#include <optional>
46
#include <o3tl/safeint.hxx>
47
#include <osl/diagnose.h>
48
#include <osl/file.hxx>
49
#include <sal/log.hxx>
50
#include <comphelper/diagnose_ex.hxx>
51
#include <tools/ref.hxx>
52
#include <tools/debug.hxx>
53
#include <unotools/streamwrap.hxx>
54
#include <unotools/ucbhelper.hxx>
55
#include <tools/urlobj.hxx>
56
#include <comphelper/processfactory.hxx>
57
#include <comphelper/propertyvalue.hxx>
58
#include <cppuhelper/implbase.hxx>
59
#include <ucbhelper/commandenvironment.hxx>
60
61
#include <sot/stg.hxx>
62
#include <sot/storinfo.hxx>
63
#include <sot/exchange.hxx>
64
#include <sot/formats.hxx>
65
#include <comphelper/classids.hxx>
66
67
#include <mutex>
68
#include <utility>
69
#include <vector>
70
71
namespace com::sun::star::ucb { class XCommandEnvironment; }
72
73
using namespace ::com::sun::star::lang;
74
using namespace ::com::sun::star::beans;
75
using namespace ::com::sun::star::uno;
76
using namespace ::com::sun::star::ucb;
77
using namespace ::com::sun::star::io;
78
using namespace ::com::sun::star::sdbc;
79
using namespace ::ucbhelper;
80
81
#if OSL_DEBUG_LEVEL > 0
82
static int nOpenFiles=0;
83
static int nOpenStreams=0;
84
#endif
85
86
typedef ::cppu::WeakImplHelper < XInputStream, XSeekable > FileInputStreamWrapper_Base;
87
88
namespace {
89
90
class FileStreamWrapper_Impl : public FileInputStreamWrapper_Base, public comphelper::ByteReader
91
{
92
protected:
93
    std::mutex    m_aMutex;
94
    OUString        m_aURL;
95
    std::unique_ptr<SvStream> m_pSvStream;
96
97
public:
98
    explicit FileStreamWrapper_Impl(OUString aName);
99
    virtual ~FileStreamWrapper_Impl() override;
100
101
    virtual void SAL_CALL seek( sal_Int64 _nLocation ) override;
102
    virtual sal_Int64 SAL_CALL getPosition(  ) override;
103
    virtual sal_Int64 SAL_CALL getLength(  ) override;
104
    virtual sal_Int32 SAL_CALL readBytes( Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead) override;
105
    virtual sal_Int32 SAL_CALL readSomeBytes( Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead) override;
106
    virtual void      SAL_CALL skipBytes(sal_Int32 nBytesToSkip) override;
107
    virtual sal_Int32 SAL_CALL available() override;
108
    virtual void      SAL_CALL closeInput() override;
109
110
    virtual sal_Int32 readSomeBytes(sal_Int8* aData, sal_Int32 nBytesToRead) override;
111
112
protected:
113
    void checkConnected();
114
    void checkError();
115
};
116
117
}
118
119
FileStreamWrapper_Impl::FileStreamWrapper_Impl( OUString aName )
120
0
    : m_aURL(std::move( aName ))
121
0
{
122
    // if no URL is provided the stream is empty
123
0
}
124
125
126
FileStreamWrapper_Impl::~FileStreamWrapper_Impl()
127
0
{
128
0
    if ( m_pSvStream )
129
0
    {
130
0
        m_pSvStream.reset();
131
#if OSL_DEBUG_LEVEL > 0
132
        --nOpenFiles;
133
#endif
134
0
    }
135
136
0
    if (!m_aURL.isEmpty())
137
0
        osl::File::remove(m_aURL);
138
0
}
139
140
141
sal_Int32 SAL_CALL FileStreamWrapper_Impl::readBytes(Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead)
142
0
{
143
0
    if ( m_aURL.isEmpty() )
144
0
    {
145
0
        aData.realloc( 0 );
146
0
        return 0;
147
0
    }
148
149
0
    checkConnected();
150
151
0
    if (nBytesToRead < 0)
152
0
        throw BufferSizeExceededException(OUString(), getXWeak());
153
154
0
    std::scoped_lock aGuard( m_aMutex );
155
156
0
    if (aData.getLength() < nBytesToRead)
157
0
        aData.realloc(nBytesToRead);
158
159
0
    sal_uInt32 nRead = m_pSvStream->ReadBytes(static_cast<void*>(aData.getArray()), nBytesToRead);
160
0
    checkError();
161
162
    // if read characters < MaxLength, adjust sequence
163
0
    if (nRead < o3tl::make_unsigned(aData.getLength()))
164
0
        aData.realloc( nRead );
165
166
0
    return nRead;
167
0
}
168
169
sal_Int32 FileStreamWrapper_Impl::readSomeBytes(sal_Int8* aData, sal_Int32 nBytesToRead)
170
0
{
171
0
    if ( m_aURL.isEmpty() )
172
0
        return 0;
173
174
0
    checkConnected();
175
176
0
    if (nBytesToRead < 0)
177
0
        throw BufferSizeExceededException(OUString(), getXWeak());
178
179
0
    std::scoped_lock aGuard( m_aMutex );
180
181
0
    sal_uInt32 nRead = m_pSvStream->ReadBytes(static_cast<void*>(aData), nBytesToRead);
182
0
    checkError();
183
184
0
    return nRead;
185
0
}
186
187
sal_Int32 SAL_CALL FileStreamWrapper_Impl::readSomeBytes(Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead)
188
0
{
189
0
    if ( m_aURL.isEmpty() )
190
0
    {
191
0
        aData.realloc( 0 );
192
0
        return 0;
193
0
    }
194
195
0
    checkError();
196
197
0
    if (nMaxBytesToRead < 0)
198
0
        throw BufferSizeExceededException(OUString(), getXWeak());
199
200
0
    if (m_pSvStream->eof())
201
0
    {
202
0
        aData.realloc(0);
203
0
        return 0;
204
0
    }
205
0
    else
206
0
        return readBytes(aData, nMaxBytesToRead);
207
0
}
208
209
210
void SAL_CALL FileStreamWrapper_Impl::skipBytes(sal_Int32 nBytesToSkip)
211
0
{
212
0
    if ( m_aURL.isEmpty() )
213
0
        return;
214
215
0
    std::scoped_lock aGuard( m_aMutex );
216
0
    checkError();
217
218
0
    m_pSvStream->SeekRel(nBytesToSkip);
219
0
    checkError();
220
0
}
221
222
223
sal_Int32 SAL_CALL FileStreamWrapper_Impl::available()
224
0
{
225
0
    if ( m_aURL.isEmpty() )
226
0
        return 0;
227
228
0
    std::scoped_lock aGuard( m_aMutex );
229
0
    checkConnected();
230
231
0
    sal_Int64 nAvailable = m_pSvStream->remainingSize();
232
0
    checkError();
233
234
0
    return std::min<sal_Int64>(SAL_MAX_INT32, nAvailable);
235
0
}
236
237
238
void SAL_CALL FileStreamWrapper_Impl::closeInput()
239
0
{
240
0
    if ( m_aURL.isEmpty() )
241
0
        return;
242
243
0
    std::scoped_lock aGuard( m_aMutex );
244
0
    checkConnected();
245
0
    m_pSvStream.reset();
246
#if OSL_DEBUG_LEVEL > 0
247
    --nOpenFiles;
248
#endif
249
0
    osl::File::remove(m_aURL);
250
0
    m_aURL.clear();
251
0
}
252
253
254
void SAL_CALL FileStreamWrapper_Impl::seek( sal_Int64 _nLocation )
255
0
{
256
0
    if ( m_aURL.isEmpty() )
257
0
        return;
258
259
0
    std::scoped_lock aGuard( m_aMutex );
260
0
    checkConnected();
261
262
0
    m_pSvStream->Seek(static_cast<sal_uInt32>(_nLocation));
263
0
    checkError();
264
0
}
265
266
267
sal_Int64 SAL_CALL FileStreamWrapper_Impl::getPosition(  )
268
0
{
269
0
    if ( m_aURL.isEmpty() )
270
0
        return 0;
271
272
0
    std::scoped_lock aGuard( m_aMutex );
273
0
    checkConnected();
274
275
0
    sal_uInt64 nPos = m_pSvStream->Tell();
276
0
    checkError();
277
0
    return nPos;
278
0
}
279
280
281
sal_Int64 SAL_CALL FileStreamWrapper_Impl::getLength(  )
282
0
{
283
0
    if ( m_aURL.isEmpty() )
284
0
        return 0;
285
286
0
    std::scoped_lock aGuard( m_aMutex );
287
0
    checkConnected();
288
289
0
    checkError();
290
291
0
    sal_Int64 nEndPos = m_pSvStream->TellEnd();
292
293
0
    return nEndPos;
294
0
}
295
296
297
void FileStreamWrapper_Impl::checkConnected()
298
0
{
299
0
    if ( m_aURL.isEmpty() )
300
0
        throw NotConnectedException(OUString(), getXWeak());
301
0
    if ( !m_pSvStream )
302
0
    {
303
0
        m_pSvStream = ::utl::UcbStreamHelper::CreateStream( m_aURL, StreamMode::STD_READ );
304
#if OSL_DEBUG_LEVEL > 0
305
        ++nOpenFiles;
306
#endif
307
0
    }
308
0
}
309
310
311
void FileStreamWrapper_Impl::checkError()
312
0
{
313
0
    checkConnected();
314
315
0
    if (m_pSvStream->SvStream::GetError() != ERRCODE_NONE)
316
        // TODO: really evaluate the error
317
0
        throw NotConnectedException(OUString(), getXWeak());
318
0
}
319
320
namespace
321
{
322
    enum class CommitResult
323
    {
324
        Failure,
325
        Nothing_to_do,
326
        Success
327
    };
328
}
329
330
static SotClipboardFormatId GetFormatId_Impl( const SvGlobalName& aName )
331
0
{
332
0
    if ( aName == SvGlobalName( SO3_SW_CLASSID_60 ) )
333
0
        return SotClipboardFormatId::STARWRITER_60;
334
0
    if ( aName == SvGlobalName( SO3_SWWEB_CLASSID_60 ) )
335
0
        return SotClipboardFormatId::STARWRITERWEB_60;
336
0
    if ( aName == SvGlobalName( SO3_SWGLOB_CLASSID_60 ) )
337
0
        return SotClipboardFormatId::STARWRITERGLOB_60;
338
0
    if ( aName == SvGlobalName( SO3_SDRAW_CLASSID_60 ) )
339
0
        return SotClipboardFormatId::STARDRAW_60;
340
0
    if ( aName == SvGlobalName( SO3_SIMPRESS_CLASSID_60 ) )
341
0
        return SotClipboardFormatId::STARIMPRESS_60;
342
0
    if ( aName == SvGlobalName( SO3_SC_CLASSID_60 ) )
343
0
        return SotClipboardFormatId::STARCALC_60;
344
0
    if ( aName == SvGlobalName( SO3_SCH_CLASSID_60 ) )
345
0
        return SotClipboardFormatId::STARCHART_60;
346
0
    if ( aName == SvGlobalName( SO3_SM_CLASSID_60 ) )
347
0
        return SotClipboardFormatId::STARMATH_60;
348
0
    if ( aName == SvGlobalName( SO3_OUT_CLASSID ) ||
349
0
         aName == SvGlobalName( SO3_APPLET_CLASSID ) ||
350
0
         aName == SvGlobalName( SO3_PLUGIN_CLASSID ) ||
351
0
         aName == SvGlobalName( SO3_IFRAME_CLASSID ) )
352
        // allowed, but not supported
353
0
        return SotClipboardFormatId::NONE;
354
0
    else
355
0
    {
356
0
        OSL_FAIL( "Unknown UCB storage format!" );
357
0
        return SotClipboardFormatId::NONE;
358
0
    }
359
0
}
360
361
362
static SvGlobalName GetClassId_Impl( SotClipboardFormatId nFormat )
363
0
{
364
0
    switch ( nFormat )
365
0
    {
366
0
        case SotClipboardFormatId::STARWRITER_8 :
367
0
        case SotClipboardFormatId::STARWRITER_8_TEMPLATE :
368
0
            return SvGlobalName( SO3_SW_CLASSID_60 );
369
0
        case SotClipboardFormatId::STARWRITERWEB_8 :
370
0
            return SvGlobalName( SO3_SWWEB_CLASSID_60 );
371
0
        case SotClipboardFormatId::STARWRITERGLOB_8 :
372
0
        case SotClipboardFormatId::STARWRITERGLOB_8_TEMPLATE :
373
0
            return SvGlobalName( SO3_SWGLOB_CLASSID_60 );
374
0
        case SotClipboardFormatId::STARDRAW_8 :
375
0
        case SotClipboardFormatId::STARDRAW_8_TEMPLATE :
376
0
            return SvGlobalName( SO3_SDRAW_CLASSID_60 );
377
0
        case SotClipboardFormatId::STARIMPRESS_8 :
378
0
        case SotClipboardFormatId::STARIMPRESS_8_TEMPLATE :
379
0
            return SvGlobalName( SO3_SIMPRESS_CLASSID_60 );
380
0
        case SotClipboardFormatId::STARCALC_8 :
381
0
        case SotClipboardFormatId::STARCALC_8_TEMPLATE :
382
0
            return SvGlobalName( SO3_SC_CLASSID_60 );
383
0
        case SotClipboardFormatId::STARCHART_8 :
384
0
        case SotClipboardFormatId::STARCHART_8_TEMPLATE :
385
0
            return SvGlobalName( SO3_SCH_CLASSID_60 );
386
0
        case SotClipboardFormatId::STARMATH_8 :
387
0
        case SotClipboardFormatId::STARMATH_8_TEMPLATE :
388
0
            return SvGlobalName( SO3_SM_CLASSID_60 );
389
0
        case SotClipboardFormatId::STARWRITER_60 :
390
0
            return SvGlobalName( SO3_SW_CLASSID_60 );
391
0
        case SotClipboardFormatId::STARWRITERWEB_60 :
392
0
            return SvGlobalName( SO3_SWWEB_CLASSID_60 );
393
0
        case SotClipboardFormatId::STARWRITERGLOB_60 :
394
0
            return SvGlobalName( SO3_SWGLOB_CLASSID_60 );
395
0
        case SotClipboardFormatId::STARDRAW_60 :
396
0
            return SvGlobalName( SO3_SDRAW_CLASSID_60 );
397
0
        case SotClipboardFormatId::STARIMPRESS_60 :
398
0
            return SvGlobalName( SO3_SIMPRESS_CLASSID_60 );
399
0
        case SotClipboardFormatId::STARCALC_60 :
400
0
            return SvGlobalName( SO3_SC_CLASSID_60 );
401
0
        case SotClipboardFormatId::STARCHART_60 :
402
0
            return SvGlobalName( SO3_SCH_CLASSID_60 );
403
0
        case SotClipboardFormatId::STARMATH_60 :
404
0
            return SvGlobalName( SO3_SM_CLASSID_60 );
405
0
        default :
406
0
            return SvGlobalName();
407
0
    }
408
0
}
409
410
// All storage and streams are refcounted internally; outside of this classes they are only accessible through a handle
411
// class, that uses the refcounted object as impl-class.
412
413
class UCBStorageStream_Impl : public SvRefBase, public SvStream
414
{
415
                                virtual ~UCBStorageStream_Impl() override;
416
public:
417
418
    virtual std::size_t         GetData(void* pData, std::size_t nSize) override;
419
    virtual std::size_t         PutData(const void* pData, std::size_t nSize) override;
420
    virtual sal_uInt64          SeekPos( sal_uInt64 nPos ) override;
421
    virtual void                SetSize( sal_uInt64 nSize ) override;
422
    virtual void                FlushData() override;
423
    virtual void                ResetError() override;
424
425
    UCBStorageStream*           m_pAntiImpl;    // only valid if an external reference exists
426
427
    OUString                    m_aOriginalName;// the original name before accessing the stream
428
    OUString                    m_aName;        // the actual name ( changed with a Rename command at the parent )
429
    OUString                    m_aURL;         // the full path name to create the content
430
    OUString                    m_aContentType;
431
    OUString                    m_aOriginalContentType;
432
    OString                     m_aKey;
433
    ::ucbhelper::Content*       m_pContent;     // the content that provides the data
434
    Reference<XInputStream>     m_rSource;      // the stream covering the original data of the content
435
    std::unique_ptr<SvStream>   m_pStream;      // the stream worked on; for readonly streams it is the original stream of the content
436
                                                // for read/write streams it's a copy into a temporary file
437
    OUString                    m_aTempURL;     // URL of this temporary stream
438
    ErrCode                     m_nError;
439
    StreamMode                  m_nMode;        // open mode ( read/write/trunc/nocreate/sharing )
440
    bool                        m_bSourceRead;  // Source still contains useful information
441
    bool                        m_bModified;    // only modified streams will be sent to the original content
442
    bool                        m_bCommited;    // sending the streams is coordinated by the root storage of the package
443
    bool                        m_bDirect;      // the storage and its streams are opened in direct mode; for UCBStorages
444
                                                // this means that the root storage does an autocommit when its external
445
                                                // reference is destroyed
446
    bool                        m_bIsOLEStorage;// an OLEStorage on a UCBStorageStream makes this an Autocommit-stream
447
448
                                UCBStorageStream_Impl( const OUString&, StreamMode, UCBStorageStream*, bool,
449
                                                       bool bRepair, Reference< XProgressHandler > const & xProgress );
450
451
    void                        Free();
452
    bool                        Init();
453
    bool                        Clear();
454
    CommitResult                Commit();       // if modified and committed: transfer an XInputStream to the content
455
    void                        Revert();       // discard all changes
456
    BaseStorage*                CreateStorage();// create an OLE Storage on the UCBStorageStream
457
    sal_uInt64                  GetSize();
458
459
    sal_uInt64                  ReadSourceWriteTemporary( sal_uInt64 aLength ); // read aLength from source and copy to temporary,
460
                                                                           // no seeking is produced
461
    void                        ReadSourceWriteTemporary();                // read source till the end and copy to temporary,
462
463
    void                        CopySourceToTemporary();                // same as ReadSourceWriteToTemporary()
464
                                                                        // but the writing is done at the end of temporary
465
                                                                        // pointer position is not changed
466
    using SvStream::SetError;
467
    void                        SetError( ErrCode nError );
468
    void                        PrepareCachedForReopen( StreamMode nMode );
469
};
470
471
typedef tools::SvRef<UCBStorageStream_Impl> UCBStorageStream_ImplRef;
472
473
struct UCBStorageElement_Impl;
474
typedef std::vector<std::unique_ptr<UCBStorageElement_Impl>> UCBStorageElementList_Impl;
475
476
class UCBStorage_Impl : public SvRefBase
477
{
478
                                virtual ~UCBStorage_Impl() override;
479
public:
480
    UCBStorage*                 m_pAntiImpl;    // only valid if external references exists
481
482
    OUString                    m_aName;        // the actual name ( changed with a Rename command at the parent )
483
    OUString                    m_aURL;         // the full path name to create the content
484
    OUString                    m_aContentType;
485
    OUString                    m_aOriginalContentType;
486
    std::optional<::ucbhelper::Content> m_oContent;     // the content that provides the storage elements
487
    std::unique_ptr<::utl::TempFileNamed> m_pTempFile;    // temporary file, only for storages on stream
488
    SvStream*                   m_pSource;      // original stream, only for storages on a stream
489
    ErrCode                     m_nError;
490
    StreamMode                  m_nMode;        // open mode ( read/write/trunc/nocreate/sharing )
491
    bool                        m_bCommited;    // sending the streams is coordinated by the root storage of the package
492
    bool                        m_bDirect;      // the storage and its streams are opened in direct mode; for UCBStorages
493
                                                // this means that the root storage does an autocommit when its external
494
                                                // reference is destroyed
495
    bool                        m_bIsRoot;      // marks this storage as root storages that manages all commits and reverts
496
    bool                        m_bIsLinked;
497
    bool                        m_bListCreated;
498
    SotClipboardFormatId        m_nFormat;
499
    OUString                    m_aUserTypeName;
500
    SvGlobalName                m_aClassId;
501
502
    UCBStorageElementList_Impl  m_aChildrenList;
503
504
    bool                        m_bRepairPackage;
505
    Reference< XProgressHandler > m_xProgressHandler;
506
507
                                UCBStorage_Impl( const ::ucbhelper::Content&, const OUString&, StreamMode, UCBStorage*, bool,
508
                                                 bool, bool = false, Reference< XProgressHandler > const & = Reference< XProgressHandler >() );
509
                                UCBStorage_Impl( const OUString&, StreamMode, UCBStorage*, bool, bool,
510
                                                 bool, Reference< XProgressHandler > const & );
511
                                UCBStorage_Impl( SvStream&, UCBStorage*, bool );
512
    void                        Init();
513
    CommitResult                Commit();
514
    void                        Revert();
515
    bool                        Insert( ::ucbhelper::Content *pContent );
516
    UCBStorage_Impl*            OpenStorage( UCBStorageElement_Impl* pElement, StreamMode nMode, bool bDirect );
517
    void                        OpenStream( UCBStorageElement_Impl*, StreamMode, bool );
518
    void                        SetProps( const Sequence < Sequence < PropertyValue > >& rSequence, const OUString& );
519
    void                        GetProps( sal_Int32&, Sequence < Sequence < PropertyValue > >& rSequence, const OUString& );
520
    sal_Int32                   GetObjectCount();
521
    void                        ReadContent();
522
    void                        CreateContent();
523
    ::ucbhelper::Content*       GetContent()
524
22
                                {
525
22
                                    if ( !m_oContent )
526
22
                                        CreateContent();
527
22
                                    return m_oContent ? &*m_oContent : nullptr;
528
22
                                }
529
    UCBStorageElementList_Impl& GetChildrenList()
530
22
                                {
531
22
                                    const ErrCode nError = m_nError;
532
22
                                    ReadContent();
533
22
                                    if ( m_nMode & StreamMode::WRITE )
534
0
                                    {
535
0
                                        m_nError = nError;
536
0
                                        if ( m_pAntiImpl )
537
0
                                        {
538
0
                                            m_pAntiImpl->ResetError();
539
0
                                            m_pAntiImpl->SetError( nError );
540
0
                                        }
541
0
                                    }
542
22
                                    return m_aChildrenList;
543
22
                                }
544
545
    void                        SetError( ErrCode nError );
546
};
547
548
typedef tools::SvRef<UCBStorage_Impl> UCBStorage_ImplRef;
549
550
// this struct contains all necessary information on an element inside a UCBStorage
551
struct UCBStorageElement_Impl
552
{
553
    OUString                    m_aName;        // the actual URL relative to the root "folder"
554
    OUString                    m_aOriginalName;// the original name in the content
555
    sal_uInt64                  m_nSize;
556
    bool                        m_bIsFolder;    // Only true when it is a UCBStorage !
557
    bool                        m_bIsStorage;   // Also true when it is an OLEStorage !
558
    bool                        m_bIsRemoved;   // element will be removed on commit
559
    bool                        m_bIsInserted;  // element will be removed on revert
560
    UCBStorage_ImplRef          m_xStorage;     // reference to the "real" storage
561
    UCBStorageStream_ImplRef    m_xStream;      // reference to the "real" stream
562
563
                                UCBStorageElement_Impl( const OUString& rName,
564
                                                        bool bIsFolder = false, sal_uInt64 nSize = 0 )
565
0
                                    : m_aName( rName )
566
0
                                    , m_aOriginalName( rName )
567
0
                                    , m_nSize( nSize )
568
0
                                    , m_bIsFolder( bIsFolder )
569
0
                                    , m_bIsStorage( bIsFolder )
570
0
                                    , m_bIsRemoved( false )
571
0
                                    , m_bIsInserted( false )
572
0
                                {
573
0
                                }
574
575
    ::ucbhelper::Content*       GetContent();
576
    bool                        IsModified() const;
577
    const OUString &            GetContentType() const;
578
    void                        SetContentType( const OUString& );
579
    const OUString &            GetOriginalContentType() const;
580
    bool                        IsLoaded() const
581
0
                                { return m_xStream.is() || m_xStorage.is(); }
582
};
583
584
::ucbhelper::Content* UCBStorageElement_Impl::GetContent()
585
0
{
586
0
    if ( m_xStream.is() )
587
0
        return m_xStream->m_pContent;
588
0
    else if ( m_xStorage.is() )
589
0
        return m_xStorage->GetContent();
590
0
    else
591
0
        return nullptr;
592
0
}
593
594
const OUString & UCBStorageElement_Impl::GetContentType() const
595
0
{
596
0
    if ( m_xStream.is() )
597
0
        return m_xStream->m_aContentType;
598
0
    else if ( m_xStorage.is() )
599
0
        return m_xStorage->m_aContentType;
600
0
    else
601
0
    {
602
0
        OSL_FAIL("Element not loaded!");
603
0
        return EMPTY_OUSTRING;
604
0
    }
605
0
}
606
607
void UCBStorageElement_Impl::SetContentType( const OUString& rType )
608
0
{
609
0
    if ( m_xStream.is() ) {
610
0
        m_xStream->m_aContentType = m_xStream->m_aOriginalContentType = rType;
611
0
    }
612
0
    else if ( m_xStorage.is() ) {
613
0
        m_xStorage->m_aContentType = m_xStorage->m_aOriginalContentType = rType;
614
0
    }
615
0
    else {
616
0
        OSL_FAIL("Element not loaded!");
617
0
    }
618
0
}
619
620
const OUString & UCBStorageElement_Impl::GetOriginalContentType() const
621
0
{
622
0
    if ( m_xStream.is() )
623
0
        return m_xStream->m_aOriginalContentType;
624
0
    else if ( m_xStorage.is() )
625
0
        return m_xStorage->m_aOriginalContentType;
626
0
    else
627
0
        return EMPTY_OUSTRING;
628
0
}
629
630
bool UCBStorageElement_Impl::IsModified() const
631
0
{
632
0
    bool bModified = m_bIsRemoved || m_bIsInserted || m_aName != m_aOriginalName;
633
0
    if ( bModified )
634
0
    {
635
0
        if ( m_xStream.is() )
636
0
            bModified = m_xStream->m_aContentType != m_xStream->m_aOriginalContentType;
637
0
        else if ( m_xStorage.is() )
638
0
            bModified = m_xStorage->m_aContentType != m_xStorage->m_aOriginalContentType;
639
0
    }
640
641
0
    return bModified;
642
0
}
643
644
UCBStorageStream_Impl::UCBStorageStream_Impl( const OUString& rName, StreamMode nMode, UCBStorageStream* pStream, bool bDirect, bool bRepair, Reference< XProgressHandler > const & xProgress  )
645
0
    : m_pAntiImpl( pStream )
646
0
    , m_aURL( rName )
647
0
    , m_pContent( nullptr )
648
0
    , m_nError( ERRCODE_NONE )
649
0
    , m_nMode( nMode )
650
0
    , m_bSourceRead( !( nMode & StreamMode::TRUNC ) )
651
0
    , m_bModified( false )
652
0
    , m_bCommited( false )
653
0
    , m_bDirect( bDirect )
654
0
    , m_bIsOLEStorage( false )
655
0
{
656
    // name is last segment in URL
657
0
    INetURLObject aObj( rName );
658
0
    m_aName = m_aOriginalName = aObj.GetLastName();
659
0
    try
660
0
    {
661
        // create the content
662
0
        rtl::Reference< ::ucbhelper::CommandEnvironment > xComEnv;
663
664
0
        OUString aTemp( rName );
665
666
0
        if ( bRepair )
667
0
        {
668
0
            xComEnv = new ::ucbhelper::CommandEnvironment( Reference< css::task::XInteractionHandler >(), xProgress );
669
0
            aTemp += "?repairpackage";
670
0
        }
671
672
0
        m_pContent = new ::ucbhelper::Content( aTemp, xComEnv, comphelper::getProcessComponentContext() );
673
0
    }
674
0
    catch (const ContentCreationException&)
675
0
    {
676
        // content could not be created
677
0
        SetError( SVSTREAM_CANNOT_MAKE );
678
0
    }
679
0
    catch (const RuntimeException&)
680
0
    {
681
        // any other error - not specified
682
0
        SetError( ERRCODE_IO_GENERAL );
683
0
    }
684
0
}
685
686
UCBStorageStream_Impl::~UCBStorageStream_Impl()
687
0
{
688
0
    if( m_rSource.is() )
689
0
        m_rSource.clear();
690
691
0
    m_pStream.reset();
692
693
0
    if (!m_aTempURL.isEmpty())
694
0
        osl::File::remove(m_aTempURL);
695
696
0
    delete m_pContent;
697
0
}
698
699
700
bool UCBStorageStream_Impl::Init()
701
0
{
702
0
    if( !m_pStream )
703
0
    {
704
        // no temporary stream was created
705
        // create one
706
707
0
        if ( m_aTempURL.isEmpty() )
708
0
            m_aTempURL = ::utl::CreateTempURL();
709
710
0
        m_pStream = ::utl::UcbStreamHelper::CreateStream( m_aTempURL, StreamMode::STD_READWRITE, true /* bFileExists */ );
711
#if OSL_DEBUG_LEVEL > 0
712
        ++nOpenFiles;
713
#endif
714
715
0
        if( !m_pStream )
716
0
        {
717
0
            OSL_FAIL( "Suspicious temporary stream creation!" );
718
0
            SetError( SVSTREAM_CANNOT_MAKE );
719
0
            return false;
720
0
        }
721
722
0
        SetError( m_pStream->GetError() );
723
0
    }
724
725
0
    if( m_bSourceRead && !m_rSource.is() )
726
0
    {
727
        // source file contain useful information and is not opened
728
        // open it from the point of noncopied data
729
730
0
        try
731
0
        {
732
0
            m_rSource = m_pContent->openStream();
733
0
        }
734
0
        catch (const Exception&)
735
0
        {
736
            // usually means that stream could not be opened
737
0
        }
738
739
0
        if( m_rSource.is() )
740
0
        {
741
0
            m_pStream->Seek( STREAM_SEEK_TO_END );
742
743
0
            try
744
0
            {
745
0
                m_rSource->skipBytes( m_pStream->Tell() );
746
0
            }
747
0
            catch (const BufferSizeExceededException&)
748
0
            {
749
                // the temporary stream already contain all the data
750
0
                m_bSourceRead = false;
751
0
            }
752
0
            catch (const Exception&)
753
0
            {
754
                // something is really wrong
755
0
                m_bSourceRead = false;
756
0
                OSL_FAIL( "Can not operate original stream!" );
757
0
                SetError( SVSTREAM_CANNOT_MAKE );
758
0
            }
759
760
0
            m_pStream->Seek( 0 );
761
0
        }
762
0
        else
763
0
        {
764
            // if the new file is edited then no source exist
765
0
            m_bSourceRead = false;
766
                //SetError( SVSTREAM_CANNOT_MAKE );
767
0
        }
768
0
    }
769
770
0
    DBG_ASSERT( m_rSource.is() || !m_bSourceRead, "Unreadable source stream!" );
771
772
0
    return true;
773
0
}
774
775
void UCBStorageStream_Impl::ReadSourceWriteTemporary()
776
0
{
777
    // read source stream till the end and copy all the data to
778
    // the current position of the temporary stream
779
780
0
    if( m_bSourceRead )
781
0
    {
782
0
        Sequence<sal_Int8> aData(32000);
783
784
0
        try
785
0
        {
786
0
            sal_Int32 aReaded;
787
0
            do
788
0
            {
789
0
                aReaded = m_rSource->readBytes( aData, 32000 );
790
0
                m_pStream->WriteBytes(aData.getConstArray(), aReaded);
791
0
            } while( aReaded == 32000 );
792
0
        }
793
0
        catch (const Exception &)
794
0
        {
795
0
            TOOLS_WARN_EXCEPTION("sot", "");
796
0
        }
797
0
    }
798
799
0
    m_bSourceRead = false;
800
0
}
801
802
sal_uInt64 UCBStorageStream_Impl::ReadSourceWriteTemporary(sal_uInt64 aLength)
803
0
{
804
    // read aLength byte from the source stream and copy them to the current
805
    // position of the temporary stream
806
807
0
    sal_uInt64 aResult = 0;
808
809
0
    if( m_bSourceRead )
810
0
    {
811
0
        Sequence<sal_Int8> aData(32000);
812
813
0
        try
814
0
        {
815
816
0
            sal_Int32 aReaded = 32000;
817
818
0
            for (sal_uInt64 nInd = 0; nInd < aLength && aReaded == 32000 ; nInd += 32000)
819
0
            {
820
0
                sal_Int32 aToCopy = std::min<sal_Int32>( aLength - nInd, 32000 );
821
0
                aReaded = m_rSource->readBytes( aData, aToCopy );
822
0
                aResult += m_pStream->WriteBytes(aData.getConstArray(), aReaded);
823
0
            }
824
825
0
            if( aResult < aLength )
826
0
                m_bSourceRead = false;
827
0
        }
828
0
        catch( const Exception & )
829
0
        {
830
0
            TOOLS_WARN_EXCEPTION("sot", "");
831
0
        }
832
0
    }
833
834
0
    return aResult;
835
0
}
836
837
void UCBStorageStream_Impl::CopySourceToTemporary()
838
0
{
839
    // current position of the temporary stream is not changed
840
0
    if( m_bSourceRead )
841
0
    {
842
0
        sal_uInt64 aPos = m_pStream->Tell();
843
0
        m_pStream->Seek( STREAM_SEEK_TO_END );
844
0
        ReadSourceWriteTemporary();
845
0
        m_pStream->Seek( aPos );
846
0
    }
847
0
}
848
849
// UCBStorageStream_Impl must have a SvStream interface, because it then can be used as underlying stream
850
// of an OLEStorage; so every write access caused by storage operations marks the UCBStorageStream as modified
851
std::size_t UCBStorageStream_Impl::GetData(void* pData, std::size_t const nSize)
852
0
{
853
0
    std::size_t aResult = 0;
854
855
0
    if( !Init() )
856
0
        return 0;
857
858
859
    // read data that is in temporary stream
860
0
    aResult = m_pStream->ReadBytes( pData, nSize );
861
0
    if( m_bSourceRead && aResult < nSize )
862
0
    {
863
        // read the tail of the data from original stream
864
        // copy this tail to the temporary stream
865
866
0
        std::size_t aToRead = nSize - aResult;
867
0
        pData = static_cast<void*>( static_cast<char*>(pData) + aResult );
868
869
0
        try
870
0
        {
871
0
            Sequence<sal_Int8> aData( aToRead );
872
0
            std::size_t aReaded = m_rSource->readBytes( aData, aToRead );
873
0
            aResult += m_pStream->WriteBytes(static_cast<const void*>(aData.getConstArray()), aReaded);
874
0
            memcpy( pData, aData.getArray(), aReaded );
875
0
        }
876
0
        catch (const Exception &)
877
0
        {
878
0
            TOOLS_WARN_EXCEPTION("sot", "");
879
0
        }
880
881
0
        if( aResult < nSize )
882
0
            m_bSourceRead = false;
883
0
    }
884
885
0
    return aResult;
886
0
}
887
888
std::size_t UCBStorageStream_Impl::PutData(const void* pData, std::size_t const nSize)
889
0
{
890
0
    if ( !(m_nMode & StreamMode::WRITE) )
891
0
    {
892
0
        SetError( ERRCODE_IO_ACCESSDENIED );
893
0
        return 0; // ?mav?
894
0
    }
895
896
0
    if( !nSize || !Init() )
897
0
        return 0;
898
899
0
    std::size_t aResult = m_pStream->WriteBytes( pData, nSize );
900
901
0
    m_bModified = aResult > 0;
902
903
0
    return aResult;
904
905
0
}
906
907
sal_uInt64 UCBStorageStream_Impl::SeekPos(sal_uInt64 const nPos)
908
0
{
909
    // check if a truncated STREAM_SEEK_TO_END was passed
910
0
    assert(nPos != SAL_MAX_UINT32);
911
912
0
    if( !Init() )
913
0
        return 0;
914
915
0
    sal_uInt64 aResult;
916
917
0
    if( nPos == STREAM_SEEK_TO_END )
918
0
    {
919
0
        m_pStream->Seek( STREAM_SEEK_TO_END );
920
0
        ReadSourceWriteTemporary();
921
0
        aResult = m_pStream->Tell();
922
0
    }
923
0
    else
924
0
    {
925
        // the problem is that even if nPos is larger the length
926
        // of the stream, the stream pointer will be moved to this position
927
        // so we have to check if temporary stream does not contain required position
928
929
0
        if( m_pStream->Tell() > nPos
930
0
            || m_pStream->Seek( STREAM_SEEK_TO_END ) > nPos )
931
0
        {
932
            // no copying is required
933
0
            aResult = m_pStream->Seek( nPos );
934
0
        }
935
0
        else
936
0
        {
937
            // the temp stream pointer points to the end now
938
0
            aResult = m_pStream->Tell();
939
940
0
            if( aResult < nPos )
941
0
            {
942
0
                if( m_bSourceRead )
943
0
                {
944
0
                    aResult += ReadSourceWriteTemporary( nPos - aResult );
945
0
                    if( aResult < nPos )
946
0
                        m_bSourceRead = false;
947
948
0
                    DBG_ASSERT( aResult == m_pStream->Tell(), "Error in stream arithmetic!\n" );
949
0
                }
950
951
0
                if( (m_nMode & StreamMode::WRITE) && !m_bSourceRead && aResult < nPos )
952
0
                {
953
                    // it means that all the Source stream was copied already
954
                    // but the required position still was not reached
955
                    // for writable streams it should be done
956
0
                    m_pStream->SetStreamSize( nPos );
957
0
                    aResult = m_pStream->Seek( STREAM_SEEK_TO_END );
958
0
                    DBG_ASSERT( aResult == nPos, "Error in stream arithmetic!\n" );
959
0
                }
960
0
            }
961
0
        }
962
0
    }
963
964
0
    return aResult;
965
0
}
966
967
void  UCBStorageStream_Impl::SetSize(sal_uInt64 const nSize)
968
0
{
969
0
    if ( !(m_nMode & StreamMode::WRITE) )
970
0
    {
971
0
        SetError( ERRCODE_IO_ACCESSDENIED );
972
0
        return;
973
0
    }
974
975
0
    if( !Init() )
976
0
        return;
977
978
0
    m_bModified = true;
979
980
0
    if( m_bSourceRead )
981
0
    {
982
0
        sal_uInt64 const aPos = m_pStream->Tell();
983
0
        m_pStream->Seek( STREAM_SEEK_TO_END );
984
0
        if( m_pStream->Tell() < nSize )
985
0
            ReadSourceWriteTemporary( nSize - m_pStream->Tell() );
986
0
        m_pStream->Seek( aPos );
987
0
    }
988
989
0
    m_pStream->SetStreamSize( nSize );
990
0
    m_bSourceRead = false;
991
0
}
992
993
void  UCBStorageStream_Impl::FlushData()
994
0
{
995
0
    if( m_pStream )
996
0
    {
997
0
        CopySourceToTemporary();
998
0
        m_pStream->Flush();
999
0
    }
1000
1001
0
    m_bCommited = true;
1002
0
}
1003
1004
void UCBStorageStream_Impl::SetError( ErrCode nErr )
1005
0
{
1006
0
    if ( !m_nError )
1007
0
    {
1008
0
        m_nError = nErr;
1009
0
        SvStream::SetError( nErr );
1010
0
        if ( m_pAntiImpl ) m_pAntiImpl->SetError( nErr );
1011
0
    }
1012
0
}
1013
1014
void  UCBStorageStream_Impl::ResetError()
1015
0
{
1016
0
    m_nError = ERRCODE_NONE;
1017
0
    SvStream::ResetError();
1018
0
    if ( m_pAntiImpl )
1019
0
        m_pAntiImpl->ResetError();
1020
0
}
1021
1022
sal_uInt64 UCBStorageStream_Impl::GetSize()
1023
0
{
1024
0
    if( !Init() )
1025
0
        return 0;
1026
1027
0
    sal_uInt64 nPos = m_pStream->Tell();
1028
0
    m_pStream->Seek( STREAM_SEEK_TO_END );
1029
0
    ReadSourceWriteTemporary();
1030
0
    sal_uInt64 nRet = m_pStream->Tell();
1031
0
    m_pStream->Seek( nPos );
1032
1033
0
    return nRet;
1034
0
}
1035
1036
BaseStorage* UCBStorageStream_Impl::CreateStorage()
1037
0
{
1038
    // create an OLEStorage on a SvStream ( = this )
1039
    // it gets the root attribute because otherwise it would probably not write before my root is committed
1040
0
    UCBStorageStream* pNewStorageStream = new UCBStorageStream( this );
1041
0
    Storage *pStorage = new Storage( *pNewStorageStream, m_bDirect );
1042
1043
    // GetError() call clears error code for OLE storages, must be changed in future
1044
0
    const ErrCode nTmpErr = pStorage->GetError();
1045
0
    pStorage->SetError( nTmpErr );
1046
1047
0
    m_bIsOLEStorage = !nTmpErr;
1048
0
    return static_cast< BaseStorage* > ( pStorage );
1049
0
}
1050
1051
CommitResult UCBStorageStream_Impl::Commit()
1052
0
{
1053
    // send stream to the original content
1054
    // the  parent storage is responsible for the correct handling of deleted contents
1055
0
    if ( m_bCommited || m_bIsOLEStorage || m_bDirect )
1056
0
    {
1057
        // modified streams with OLEStorages on it have autocommit; it is assumed that the OLEStorage
1058
        // was committed as well ( if not opened in direct mode )
1059
1060
0
        if ( m_bModified )
1061
0
        {
1062
0
            try
1063
0
            {
1064
0
                CopySourceToTemporary();
1065
1066
                // release all stream handles
1067
0
                Free();
1068
1069
                // the temporary file does not exist only for truncated streams
1070
0
                DBG_ASSERT( !m_aTempURL.isEmpty() || ( m_nMode & StreamMode::TRUNC ), "No temporary file to read from!");
1071
0
                if ( m_aTempURL.isEmpty() && !( m_nMode & StreamMode::TRUNC ) )
1072
0
                    throw RuntimeException();
1073
1074
0
                InsertCommandArgument aArg;
1075
                // create wrapper to stream that is only used while reading inside package component
1076
0
                aArg.Data.set(new FileStreamWrapper_Impl(m_aTempURL));
1077
0
                aArg.ReplaceExisting = true;
1078
0
                m_pContent->executeCommand( u"insert"_ustr, Any(aArg) );
1079
1080
                // wrapper now controls lifetime of temporary file
1081
0
                m_aTempURL.clear();
1082
1083
0
                INetURLObject aObj( m_aURL );
1084
0
                aObj.setName( m_aName );
1085
0
                m_aURL = aObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
1086
0
                m_bModified = false;
1087
0
                m_bSourceRead = true;
1088
0
            }
1089
0
            catch (const CommandAbortedException&)
1090
0
            {
1091
                // any command wasn't executed successfully - not specified
1092
0
                SetError( ERRCODE_IO_GENERAL );
1093
0
                return CommitResult::Failure;
1094
0
            }
1095
0
            catch (const RuntimeException&)
1096
0
            {
1097
                // any other error - not specified
1098
0
                SetError( ERRCODE_IO_GENERAL );
1099
0
                return CommitResult::Failure;
1100
0
            }
1101
0
            catch (const Exception&)
1102
0
            {
1103
                // any other error - not specified
1104
0
                SetError( ERRCODE_IO_GENERAL );
1105
0
                return CommitResult::Failure;
1106
0
            }
1107
1108
0
            m_bCommited = false;
1109
0
            return CommitResult::Success;
1110
0
        }
1111
0
    }
1112
1113
0
    return CommitResult::Nothing_to_do;
1114
0
}
1115
1116
void UCBStorageStream_Impl::Revert()
1117
0
{
1118
    // if an OLEStorage is created on this stream, no "revert" is necessary because OLEStorages do nothing on "Revert" !
1119
0
    if ( m_bCommited )
1120
0
    {
1121
0
        OSL_FAIL("Revert while commit is in progress!" );
1122
0
        return;                   //  ???
1123
0
    }
1124
1125
0
    Free();
1126
0
    if ( !m_aTempURL.isEmpty() )
1127
0
    {
1128
0
        osl::File::remove(m_aTempURL);
1129
0
        m_aTempURL.clear();
1130
0
    }
1131
1132
0
    m_bSourceRead = false;
1133
0
    try
1134
0
    {
1135
0
        m_rSource = m_pContent->openStream();
1136
0
        if( m_rSource.is() )
1137
0
        {
1138
0
            if ( m_pAntiImpl && ( m_nMode & StreamMode::TRUNC ) )
1139
                // stream is in use and should be truncated
1140
0
                m_bSourceRead = false;
1141
0
            else
1142
0
            {
1143
0
                m_nMode &= ~StreamMode::TRUNC;
1144
0
                m_bSourceRead = true;
1145
0
            }
1146
0
        }
1147
0
        else
1148
0
            SetError( SVSTREAM_CANNOT_MAKE );
1149
0
    }
1150
0
    catch (const ContentCreationException&)
1151
0
    {
1152
0
        SetError( ERRCODE_IO_GENERAL );
1153
0
    }
1154
0
    catch (const RuntimeException&)
1155
0
    {
1156
0
        SetError( ERRCODE_IO_GENERAL );
1157
0
    }
1158
0
    catch (const Exception&)
1159
0
    {
1160
0
    }
1161
1162
0
    m_bModified = false;
1163
0
    m_aName = m_aOriginalName;
1164
0
    m_aContentType = m_aOriginalContentType;
1165
0
}
1166
1167
bool UCBStorageStream_Impl::Clear()
1168
0
{
1169
0
    bool bRet = ( m_pAntiImpl == nullptr );
1170
0
    DBG_ASSERT( bRet, "Removing used stream!" );
1171
0
    if( bRet )
1172
0
    {
1173
0
        Free();
1174
0
    }
1175
1176
0
    return bRet;
1177
0
}
1178
1179
void UCBStorageStream_Impl::Free()
1180
0
{
1181
#if OSL_DEBUG_LEVEL > 0
1182
    if ( m_pStream )
1183
    {
1184
        if ( !m_aTempURL.isEmpty() )
1185
            --nOpenFiles;
1186
        else
1187
            --nOpenStreams;
1188
    }
1189
#endif
1190
1191
0
    m_rSource.clear();
1192
0
    m_pStream.reset();
1193
0
}
1194
1195
void UCBStorageStream_Impl::PrepareCachedForReopen( StreamMode nMode )
1196
0
{
1197
0
    bool isWritable = bool( m_nMode & StreamMode::WRITE );
1198
0
    if ( isWritable )
1199
0
    {
1200
        // once stream was writable, never reset to readonly
1201
0
        nMode |= StreamMode::WRITE;
1202
0
    }
1203
1204
0
    m_nMode = nMode;
1205
0
    Free();
1206
1207
0
    if ( nMode & StreamMode::TRUNC )
1208
0
    {
1209
0
        m_bSourceRead = false; // usually it should be 0 already but just in case...
1210
1211
0
        if ( !m_aTempURL.isEmpty() )
1212
0
        {
1213
0
            osl::File::remove(m_aTempURL);
1214
0
            m_aTempURL.clear();
1215
0
        }
1216
0
    }
1217
0
}
1218
1219
UCBStorageStream::UCBStorageStream( const OUString& rName, StreamMode nMode, bool bDirect, bool bRepair, Reference< XProgressHandler > const & xProgress )
1220
0
{
1221
    // pImp must be initialized in the body, because otherwise the vtable of the stream is not initialized
1222
    // to class UCBStorageStream !
1223
0
    pImp = new UCBStorageStream_Impl( rName, nMode, this, bDirect, bRepair, xProgress );
1224
0
    pImp->AddFirstRef();             // use direct refcounting because in header file only a pointer should be used
1225
0
    StorageBase::m_nMode = pImp->m_nMode;
1226
0
}
1227
1228
UCBStorageStream::UCBStorageStream( UCBStorageStream_Impl *pImpl )
1229
0
    : pImp( pImpl )
1230
0
{
1231
0
    pImp->AddFirstRef();             // use direct refcounting because in header file only a pointer should be used
1232
0
    pImp->m_pAntiImpl = this;
1233
0
    SetError( pImp->m_nError );
1234
0
    StorageBase::m_nMode = pImp->m_nMode;
1235
0
}
1236
1237
UCBStorageStream::~UCBStorageStream()
1238
0
{
1239
0
    if ( pImp->m_nMode & StreamMode::WRITE )
1240
0
        pImp->Flush();
1241
0
    pImp->m_pAntiImpl = nullptr;
1242
0
    pImp->Free();
1243
0
    pImp->ReleaseRef();
1244
0
}
1245
1246
sal_Int32 UCBStorageStream::Read( void * pData, sal_Int32 nSize )
1247
0
{
1248
    //return pImp->m_pStream->Read( pData, nSize );
1249
0
    return pImp->GetData( pData, nSize );
1250
0
}
1251
1252
sal_Int32 UCBStorageStream::Write( const void* pData, sal_Int32 nSize )
1253
0
{
1254
0
    return pImp->PutData( pData, nSize );
1255
0
}
1256
1257
sal_uInt64 UCBStorageStream::Seek( sal_uInt64 nPos )
1258
0
{
1259
    //return pImp->m_pStream->Seek( nPos );
1260
0
    return pImp->Seek( nPos );
1261
0
}
1262
1263
sal_uInt64 UCBStorageStream::Tell()
1264
0
{
1265
0
    if( !pImp->Init() )
1266
0
        return 0;
1267
0
    return pImp->m_pStream->Tell();
1268
0
}
1269
1270
void UCBStorageStream::Flush()
1271
0
{
1272
    // streams are never really transacted, so flush also means commit !
1273
0
    Commit();
1274
0
}
1275
1276
bool UCBStorageStream::SetSize( sal_uInt64 nNewSize )
1277
0
{
1278
0
    pImp->SetSize( nNewSize );
1279
0
    return !pImp->GetError();
1280
0
}
1281
1282
bool UCBStorageStream::Validate( bool bWrite ) const
1283
0
{
1284
0
    return ( !bWrite || ( pImp->m_nMode & StreamMode::WRITE ) );
1285
0
}
1286
1287
bool UCBStorageStream::ValidateMode( StreamMode m ) const
1288
0
{
1289
    // ???
1290
0
    if( m == ( StreamMode::READ | StreamMode::TRUNC ) )  // from stg.cxx
1291
0
        return true;
1292
0
    if( ( m & StreamMode::READWRITE) == StreamMode::READ )
1293
0
    {
1294
        // only SHARE_DENYWRITE or SHARE_DENYALL allowed
1295
0
        if( ( m & StreamMode::SHARE_DENYWRITE )
1296
0
         || ( m & StreamMode::SHARE_DENYALL ) )
1297
0
            return true;
1298
0
    }
1299
0
    else
1300
0
    {
1301
        // only SHARE_DENYALL allowed
1302
        // storages open in r/o mode are OK, since only
1303
        // the commit may fail
1304
0
        if( m & StreamMode::SHARE_DENYALL )
1305
0
            return true;
1306
0
    }
1307
1308
0
    return true;
1309
0
}
1310
1311
SvStream* UCBStorageStream::GetModifySvStream()
1312
0
{
1313
0
    return static_cast<SvStream*>(pImp);
1314
0
}
1315
1316
bool  UCBStorageStream::Equals( const BaseStorageStream& rStream ) const
1317
0
{
1318
    // ???
1319
0
    return static_cast<BaseStorageStream const *>(this) == &rStream;
1320
0
}
1321
1322
bool UCBStorageStream::Commit()
1323
0
{
1324
    // mark this stream for sending it on root commit
1325
0
    pImp->FlushData();
1326
0
    return true;
1327
0
}
1328
1329
void UCBStorageStream::CopyTo( BaseStorageStream* pDestStm )
1330
0
{
1331
0
    if( !pImp->Init() )
1332
0
        return;
1333
1334
0
    UCBStorageStream* pStg =  dynamic_cast<UCBStorageStream*>( pDestStm );
1335
0
    if ( pStg )
1336
0
        pStg->pImp->m_aContentType = pImp->m_aContentType;
1337
1338
0
    pDestStm->SetSize( 0 );
1339
0
    Seek( STREAM_SEEK_TO_END );
1340
0
    sal_Int32 n = Tell();
1341
0
    if( n < 0 )
1342
0
        return;
1343
1344
0
    if( !pDestStm->SetSize( n ) || !n )
1345
0
        return;
1346
1347
0
    std::unique_ptr<sal_uInt8[]> p(new sal_uInt8[ 4096 ]);
1348
0
    Seek( 0 );
1349
0
    pDestStm->Seek( 0 );
1350
0
    while( n )
1351
0
    {
1352
0
        sal_Int32 nn = n;
1353
0
        if( nn > 4096 )
1354
0
            nn = 4096;
1355
0
        if( Read( p.get(), nn ) != nn )
1356
0
            break;
1357
0
        if( pDestStm->Write( p.get(), nn ) != nn )
1358
0
            break;
1359
0
        n -= nn;
1360
0
    }
1361
0
}
1362
1363
bool UCBStorageStream::SetProperty( const OUString& rName, const css::uno::Any& rValue )
1364
0
{
1365
0
    if ( rName == "Title")
1366
0
        return false;
1367
1368
0
    if ( rName == "MediaType")
1369
0
    {
1370
0
        OUString aTmp;
1371
0
        rValue >>= aTmp;
1372
0
        pImp->m_aContentType = aTmp;
1373
0
    }
1374
1375
0
    try
1376
0
    {
1377
0
        if ( pImp->m_pContent )
1378
0
        {
1379
0
            pImp->m_pContent->setPropertyValue( rName, rValue );
1380
0
            return true;
1381
0
        }
1382
0
    }
1383
0
    catch (const Exception&)
1384
0
    {
1385
0
    }
1386
1387
0
    return false;
1388
0
}
1389
1390
sal_uInt64 UCBStorageStream::GetSize() const
1391
0
{
1392
0
    return pImp->GetSize();
1393
0
}
1394
1395
UCBStorage::UCBStorage( SvStream& rStrm, bool bDirect )
1396
59
{
1397
    // pImp must be initialized in the body, because otherwise the vtable of the stream is not initialized
1398
    // to class UCBStorage !
1399
59
    pImp = new UCBStorage_Impl( rStrm, this, bDirect );
1400
1401
59
    pImp->AddFirstRef();
1402
59
    pImp->Init();
1403
59
    StorageBase::m_nMode = pImp->m_nMode;
1404
59
}
1405
1406
UCBStorage::UCBStorage( const ::ucbhelper::Content& rContent, const OUString& rName, StreamMode nMode, bool bDirect, bool bIsRoot )
1407
0
{
1408
    // pImp must be initialized in the body, because otherwise the vtable of the stream is not initialized
1409
    // to class UCBStorage !
1410
0
    pImp = new UCBStorage_Impl( rContent, rName, nMode, this, bDirect, bIsRoot );
1411
0
    pImp->AddFirstRef();
1412
0
    pImp->Init();
1413
0
    StorageBase::m_nMode = pImp->m_nMode;
1414
0
}
1415
1416
UCBStorage::UCBStorage( const OUString& rName, StreamMode nMode, bool bDirect, bool bIsRoot, bool bIsRepair, Reference< XProgressHandler > const & xProgressHandler )
1417
0
{
1418
    // pImp must be initialized in the body, because otherwise the vtable of the stream is not initialized
1419
    // to class UCBStorage !
1420
0
    pImp = new UCBStorage_Impl( rName, nMode, this, bDirect, bIsRoot, bIsRepair, xProgressHandler );
1421
0
    pImp->AddFirstRef();
1422
0
    pImp->Init();
1423
0
    StorageBase::m_nMode = pImp->m_nMode;
1424
0
}
1425
1426
UCBStorage::UCBStorage( const OUString& rName, StreamMode nMode, bool bDirect, bool bIsRoot )
1427
0
{
1428
    // pImp must be initialized in the body, because otherwise the vtable of the stream is not initialized
1429
    // to class UCBStorage !
1430
0
    pImp = new UCBStorage_Impl( rName, nMode, this, bDirect, bIsRoot, false, Reference< XProgressHandler >() );
1431
0
    pImp->AddFirstRef();
1432
0
    pImp->Init();
1433
0
    StorageBase::m_nMode = pImp->m_nMode;
1434
0
}
1435
1436
UCBStorage::UCBStorage( UCBStorage_Impl *pImpl )
1437
0
    : pImp( pImpl )
1438
0
{
1439
0
    pImp->m_pAntiImpl = this;
1440
0
    SetError( pImp->m_nError );
1441
0
    pImp->AddFirstRef();             // use direct refcounting because in header file only a pointer should be used
1442
0
    StorageBase::m_nMode = pImp->m_nMode;
1443
0
}
1444
1445
UCBStorage::~UCBStorage()
1446
59
{
1447
59
    if ( pImp->m_bIsRoot && pImp->m_bDirect && ( !pImp->m_pTempFile || pImp->m_pSource ) )
1448
        // DirectMode is simulated with an AutoCommit
1449
0
        Commit();
1450
1451
59
    pImp->m_pAntiImpl = nullptr;
1452
59
    pImp->ReleaseRef();
1453
59
}
1454
1455
UCBStorage_Impl::UCBStorage_Impl( const ::ucbhelper::Content& rContent, const OUString& rName, StreamMode nMode, UCBStorage* pStorage, bool bDirect, bool bIsRoot, bool bIsRepair, Reference< XProgressHandler > const & xProgressHandler  )
1456
0
    : m_pAntiImpl( pStorage )
1457
0
    , m_oContent( rContent )
1458
0
    , m_pSource( nullptr )
1459
    //, m_pStream( NULL )
1460
0
    , m_nError( ERRCODE_NONE )
1461
0
    , m_nMode( nMode )
1462
0
    , m_bCommited( false )
1463
0
    , m_bDirect( bDirect )
1464
0
    , m_bIsRoot( bIsRoot )
1465
0
    , m_bIsLinked( true )
1466
0
    , m_bListCreated( false )
1467
0
    , m_nFormat( SotClipboardFormatId::NONE )
1468
0
    , m_bRepairPackage( bIsRepair )
1469
0
    , m_xProgressHandler( xProgressHandler )
1470
0
{
1471
0
    OUString aName( rName );
1472
0
    if( aName.isEmpty() )
1473
0
    {
1474
        // no name given = use temporary name!
1475
0
        DBG_ASSERT( m_bIsRoot, "SubStorage must have a name!" );
1476
0
        m_pTempFile.reset(new ::utl::TempFileNamed);
1477
0
        m_pTempFile->EnableKillingFile();
1478
0
        m_aName = aName = m_pTempFile->GetURL();
1479
0
    }
1480
1481
0
    m_aURL = rName;
1482
0
}
1483
1484
UCBStorage_Impl::UCBStorage_Impl( const OUString& rName, StreamMode nMode, UCBStorage* pStorage, bool bDirect, bool bIsRoot, bool bIsRepair, Reference< XProgressHandler > const & xProgressHandler )
1485
0
    : m_pAntiImpl( pStorage )
1486
0
    , m_pSource( nullptr )
1487
    //, m_pStream( NULL )
1488
0
    , m_nError( ERRCODE_NONE )
1489
0
    , m_nMode( nMode )
1490
0
    , m_bCommited( false )
1491
0
    , m_bDirect( bDirect )
1492
0
    , m_bIsRoot( bIsRoot )
1493
0
    , m_bIsLinked( false )
1494
0
    , m_bListCreated( false )
1495
0
    , m_nFormat( SotClipboardFormatId::NONE )
1496
0
    , m_bRepairPackage( bIsRepair )
1497
0
    , m_xProgressHandler( xProgressHandler )
1498
0
{
1499
0
    OUString aName( rName );
1500
0
    if( aName.isEmpty() )
1501
0
    {
1502
        // no name given = use temporary name!
1503
0
        DBG_ASSERT( m_bIsRoot, "SubStorage must have a name!" );
1504
0
        m_pTempFile.reset(new ::utl::TempFileNamed);
1505
0
        m_pTempFile->EnableKillingFile();
1506
0
        m_aName = aName = m_pTempFile->GetURL();
1507
0
    }
1508
1509
0
    if ( m_bIsRoot )
1510
0
    {
1511
        // create the special package URL for the package content
1512
0
        m_aURL = "vnd.sun.star.pkg://" +
1513
0
            INetURLObject::encode( aName, INetURLObject::PART_AUTHORITY, INetURLObject::EncodeMechanism::All );
1514
1515
0
        if ( m_nMode & StreamMode::WRITE )
1516
0
        {
1517
            // the root storage opens the package, so make sure that there is any
1518
0
            ::utl::UcbStreamHelper::CreateStream( aName, StreamMode::STD_READWRITE, m_pTempFile != nullptr /* bFileExists */ );
1519
0
        }
1520
0
    }
1521
0
    else
1522
0
    {
1523
        // substorages are opened like streams: the URL is a "child URL" of the root package URL
1524
0
        m_aURL = rName;
1525
0
        if ( !m_aURL.startsWith( "vnd.sun.star.pkg://") )
1526
0
            m_bIsLinked = true;
1527
0
    }
1528
0
}
1529
1530
UCBStorage_Impl::UCBStorage_Impl( SvStream& rStream, UCBStorage* pStorage, bool bDirect )
1531
59
    : m_pAntiImpl( pStorage )
1532
59
    , m_pTempFile( new ::utl::TempFileNamed )
1533
59
    , m_pSource( &rStream )
1534
59
    , m_nError( ERRCODE_NONE )
1535
59
    , m_bCommited( false )
1536
59
    , m_bDirect( bDirect )
1537
59
    , m_bIsRoot( true )
1538
59
    , m_bIsLinked( false )
1539
59
    , m_bListCreated( false )
1540
59
    , m_nFormat( SotClipboardFormatId::NONE )
1541
59
    , m_bRepairPackage( false )
1542
59
{
1543
    // opening in direct mode is too fuzzy because the data is transferred to the stream in the Commit() call,
1544
    // which will be called in the storages' dtor
1545
59
    m_pTempFile->EnableKillingFile();
1546
59
    DBG_ASSERT( !bDirect, "Storage on a stream must not be opened in direct mode!" );
1547
1548
    // UCBStorages work on a content, so a temporary file for a content must be created, even if the stream is only
1549
    // accessed readonly
1550
    // the root storage opens the package; create the special package URL for the package content
1551
59
    m_aURL = "vnd.sun.star.pkg://" +
1552
59
        INetURLObject::encode( m_pTempFile->GetURL(), INetURLObject::PART_AUTHORITY, INetURLObject::EncodeMechanism::All );
1553
1554
    // copy data into the temporary file
1555
59
    std::unique_ptr<SvStream> pStream(::utl::UcbStreamHelper::CreateStream( m_pTempFile->GetURL(), StreamMode::STD_READWRITE, true /* bFileExists */ ));
1556
59
    if ( pStream )
1557
17
    {
1558
17
        rStream.Seek(0);
1559
17
        rStream.ReadStream( *pStream );
1560
17
        pStream->Flush();
1561
17
        pStream.reset();
1562
17
    }
1563
1564
    // close stream and let content access the file
1565
59
    m_pSource->Seek(0);
1566
1567
    // check opening mode
1568
59
    m_nMode = StreamMode::READ;
1569
59
    if( rStream.IsWritable() )
1570
17
        m_nMode = StreamMode::READ | StreamMode::WRITE;
1571
59
}
1572
1573
void UCBStorage_Impl::Init()
1574
59
{
1575
    // name is last segment in URL
1576
59
    INetURLObject aObj( m_aURL );
1577
59
    if ( m_aName.isEmpty() )
1578
        // if the name was not already set to a temp name
1579
59
        m_aName = aObj.GetLastName();
1580
1581
59
    if ( !m_oContent )
1582
59
        CreateContent();
1583
1584
59
    if ( m_oContent )
1585
0
    {
1586
0
        if ( m_bIsLinked )
1587
0
        {
1588
0
            if( m_bIsRoot )
1589
0
            {
1590
0
                ReadContent();
1591
0
                if ( m_nError == ERRCODE_NONE )
1592
0
                {
1593
                    // read the manifest.xml file
1594
0
                    aObj.Append( u"META-INF" );
1595
0
                    aObj.Append( u"manifest.xml" );
1596
1597
                    // create input stream
1598
0
                    std::unique_ptr<SvStream> pStream(::utl::UcbStreamHelper::CreateStream( aObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ), StreamMode::STD_READ ));
1599
                    // no stream means no manifest.xml
1600
0
                    if ( pStream )
1601
0
                    {
1602
0
                        if ( !pStream->GetError() )
1603
0
                        {
1604
0
                            rtl::Reference<::utl::OInputStreamWrapper> pHelper = new ::utl::OInputStreamWrapper( *pStream );
1605
1606
                            // create a manifest reader object that will read in the manifest from the stream
1607
0
                            Reference < css::packages::manifest::XManifestReader > xReader =
1608
0
                                css::packages::manifest::ManifestReader::create(
1609
0
                                    ::comphelper::getProcessComponentContext() ) ;
1610
0
                            Sequence < Sequence < PropertyValue > > aProps = xReader->readManifestSequence( pHelper );
1611
1612
                            // cleanup
1613
0
                            xReader = nullptr;
1614
0
                            pHelper = nullptr;
1615
0
                            SetProps( aProps, OUString() );
1616
0
                        }
1617
0
                    }
1618
0
                }
1619
0
            }
1620
0
            else
1621
0
                ReadContent();
1622
0
        }
1623
0
        else
1624
0
        {
1625
            // get the manifest information from the package
1626
0
            try {
1627
0
                Any aAny = m_oContent->getPropertyValue(u"MediaType"_ustr);
1628
0
                OUString aTmp;
1629
0
                if ( ( aAny >>= aTmp ) && !aTmp.isEmpty() )
1630
0
                    m_aContentType = m_aOriginalContentType = aTmp;
1631
0
            }
1632
0
            catch (const Exception&)
1633
0
            {
1634
0
                SAL_WARN( "sot",
1635
0
                          "getPropertyValue has thrown an exception! Please let developers know the scenario!" );
1636
0
            }
1637
0
        }
1638
0
    }
1639
1640
59
    if ( m_aContentType.isEmpty() )
1641
59
        return;
1642
1643
    // get the clipboard format using the content type
1644
0
    css::datatransfer::DataFlavor aDataFlavor;
1645
0
    aDataFlavor.MimeType = m_aContentType;
1646
0
    m_nFormat = SotExchange::GetFormat( aDataFlavor );
1647
1648
    // get the ClassId using the clipboard format ( internal table )
1649
0
    m_aClassId = GetClassId_Impl( m_nFormat );
1650
1651
    // get human presentable name using the clipboard format
1652
0
    SotExchange::GetFormatDataFlavor( m_nFormat, aDataFlavor );
1653
0
    m_aUserTypeName = aDataFlavor.HumanPresentableName;
1654
1655
0
    if( m_oContent && !m_bIsLinked && m_aClassId != SvGlobalName() )
1656
0
        ReadContent();
1657
0
}
1658
1659
void UCBStorage_Impl::CreateContent()
1660
81
{
1661
81
    try
1662
81
    {
1663
        // create content; where to put StreamMode ?! ( already done when opening the file of the package ? )
1664
81
        rtl::Reference< ::ucbhelper::CommandEnvironment > xComEnv;
1665
1666
81
        OUString aTemp( m_aURL );
1667
1668
81
        if ( m_bRepairPackage )
1669
0
        {
1670
0
            xComEnv = new ::ucbhelper::CommandEnvironment( Reference< css::task::XInteractionHandler >(),
1671
0
                                                     m_xProgressHandler );
1672
0
            aTemp += "?repairpackage";
1673
0
        }
1674
1675
81
        m_oContent.emplace( aTemp, xComEnv, comphelper::getProcessComponentContext() );
1676
81
    }
1677
81
    catch (const ContentCreationException&)
1678
81
    {
1679
        // content could not be created
1680
37
        SetError( SVSTREAM_CANNOT_MAKE );
1681
37
    }
1682
81
    catch (const RuntimeException&)
1683
81
    {
1684
        // any other error - not specified
1685
44
        SetError( SVSTREAM_CANNOT_MAKE );
1686
44
    }
1687
81
}
1688
1689
void UCBStorage_Impl::ReadContent()
1690
22
{
1691
22
    if ( m_bListCreated )
1692
0
        return;
1693
1694
22
    m_bListCreated = true;
1695
1696
22
    try
1697
22
    {
1698
22
        GetContent();
1699
22
        if ( !m_oContent )
1700
22
            return;
1701
1702
        // create cursor for access to children
1703
0
        Reference< XResultSet > xResultSet = m_oContent->createCursor( { u"Title"_ustr, u"IsFolder"_ustr, u"MediaType"_ustr, u"Size"_ustr }, ::ucbhelper::INCLUDE_FOLDERS_AND_DOCUMENTS );
1704
0
        Reference< XRow > xRow( xResultSet, UNO_QUERY );
1705
0
        if ( xResultSet.is() )
1706
0
        {
1707
0
            while ( xResultSet->next() )
1708
0
            {
1709
                // insert all into the children list
1710
0
                OUString aTitle( xRow->getString(1) );
1711
0
                if ( m_bIsLinked )
1712
0
                {
1713
                    // unpacked storages have to deal with the meta-inf folder by themselves
1714
0
                    if ( aTitle == "META-INF" )
1715
0
                        continue;
1716
0
                }
1717
1718
0
                bool bIsFolder( xRow->getBoolean(2) );
1719
0
                sal_Int64 nSize = xRow->getLong(4);
1720
0
                UCBStorageElement_Impl* pElement = new UCBStorageElement_Impl( aTitle, bIsFolder, nSize );
1721
0
                m_aChildrenList.emplace_back( pElement );
1722
1723
0
                bool bIsOfficeDocument = m_bIsLinked || ( m_aClassId != SvGlobalName() );
1724
0
                if ( bIsFolder )
1725
0
                {
1726
0
                    if ( m_bIsLinked )
1727
0
                        OpenStorage( pElement, m_nMode, m_bDirect );
1728
0
                    if ( pElement->m_xStorage.is() )
1729
0
                        pElement->m_xStorage->Init();
1730
0
                }
1731
0
                else if ( bIsOfficeDocument )
1732
0
                {
1733
                    // streams can be external OLE objects, so they are now folders, but storages!
1734
0
                    OUString aName( m_aURL + "/" + xRow->getString(1));
1735
1736
0
                    rtl::Reference< ::ucbhelper::CommandEnvironment > xComEnv;
1737
0
                    if ( m_bRepairPackage )
1738
0
                    {
1739
0
                        xComEnv = new ::ucbhelper::CommandEnvironment( Reference< css::task::XInteractionHandler >(),
1740
0
                                                                m_xProgressHandler );
1741
0
                        aName += "?repairpackage";
1742
0
                    }
1743
1744
0
                    ::ucbhelper::Content aContent( aName, xComEnv, comphelper::getProcessComponentContext() );
1745
1746
0
                    OUString aMediaType;
1747
0
                    Any aAny = aContent.getPropertyValue(u"MediaType"_ustr);
1748
0
                    if ( ( aAny >>= aMediaType ) && ( aMediaType == "application/vnd.sun.star.oleobject" ) )
1749
0
                        pElement->m_bIsStorage = true;
1750
0
                    else if ( aMediaType.isEmpty() )
1751
0
                    {
1752
                        // older files didn't have that special content type, so they must be detected
1753
0
                        OpenStream( pElement, StreamMode::STD_READ, m_bDirect );
1754
0
                        if ( Storage::IsStorageFile( pElement->m_xStream.get() ) )
1755
0
                            pElement->m_bIsStorage = true;
1756
0
                        else
1757
0
                            pElement->m_xStream->Free();
1758
0
                    }
1759
0
                }
1760
0
            }
1761
0
        }
1762
0
    }
1763
22
    catch (const InteractiveIOException& r)
1764
22
    {
1765
0
        if ( r.Code != IOErrorCode_NOT_EXISTING )
1766
0
            SetError( ERRCODE_IO_GENERAL );
1767
0
    }
1768
22
    catch (const CommandAbortedException&)
1769
22
    {
1770
        // any command wasn't executed successfully - not specified
1771
0
        if ( !( m_nMode & StreamMode::WRITE ) )
1772
            // if the folder was just inserted and not already committed, this is not an error!
1773
0
            SetError( ERRCODE_IO_GENERAL );
1774
0
    }
1775
22
    catch (const RuntimeException&)
1776
22
    {
1777
        // any other error - not specified
1778
0
        SetError( ERRCODE_IO_GENERAL );
1779
0
    }
1780
22
    catch (const ResultSetException&)
1781
22
    {
1782
        // means that the package file is broken
1783
0
        SetError( ERRCODE_IO_BROKENPACKAGE );
1784
0
    }
1785
22
    catch (const SQLException&)
1786
22
    {
1787
        // means that the file can be broken
1788
0
        SetError( ERRCODE_IO_WRONGFORMAT );
1789
0
    }
1790
22
    catch (const Exception&)
1791
22
    {
1792
        // any other error - not specified
1793
0
        SetError( ERRCODE_IO_GENERAL );
1794
0
    }
1795
22
}
1796
1797
void UCBStorage_Impl::SetError( ErrCode nError )
1798
81
{
1799
81
    if ( !m_nError )
1800
59
    {
1801
59
        m_nError = nError;
1802
59
        if ( m_pAntiImpl ) m_pAntiImpl->SetError( nError );
1803
59
    }
1804
81
}
1805
1806
sal_Int32 UCBStorage_Impl::GetObjectCount()
1807
0
{
1808
0
    sal_Int32 nCount = m_aChildrenList.size();
1809
0
    for (auto& pElement : m_aChildrenList)
1810
0
    {
1811
0
        DBG_ASSERT( !pElement->m_bIsFolder || pElement->m_xStorage.is(), "Storage should be open!" );
1812
0
        if ( pElement->m_bIsFolder && pElement->m_xStorage.is() )
1813
0
            nCount += pElement->m_xStorage->GetObjectCount();
1814
0
    }
1815
1816
0
    return nCount;
1817
0
}
1818
1819
static OUString Find_Impl( const Sequence < Sequence < PropertyValue > >& rSequence, std::u16string_view rPath )
1820
0
{
1821
0
    bool bFound = false;
1822
0
    for ( const Sequence < PropertyValue >& rMyProps : rSequence )
1823
0
    {
1824
0
        OUString aType;
1825
1826
0
        for ( const PropertyValue& rAny : rMyProps )
1827
0
        {
1828
0
            if ( rAny.Name == "FullPath" )
1829
0
            {
1830
0
                OUString aTmp;
1831
0
                if ( ( rAny.Value >>= aTmp ) && aTmp == rPath )
1832
0
                    bFound = true;
1833
0
                if ( !aType.isEmpty() )
1834
0
                    break;
1835
0
            }
1836
0
            else if ( rAny.Name == "MediaType" )
1837
0
            {
1838
0
                if ( ( rAny.Value >>= aType ) && !aType.isEmpty() && bFound )
1839
0
                    break;
1840
0
            }
1841
0
        }
1842
1843
0
        if ( bFound )
1844
0
            return aType;
1845
0
    }
1846
1847
0
    return OUString();
1848
0
}
1849
1850
void UCBStorage_Impl::SetProps( const Sequence < Sequence < PropertyValue > >& rSequence, const OUString& rPath )
1851
0
{
1852
0
    OUString aPath( rPath );
1853
0
    if ( !m_bIsRoot )
1854
0
        aPath += m_aName;
1855
0
    aPath += "/";
1856
1857
0
    m_aContentType = m_aOriginalContentType = Find_Impl( rSequence, aPath );
1858
1859
0
    if ( m_bIsRoot )
1860
        // the "FullPath" of a child always starts without '/'
1861
0
        aPath.clear();
1862
1863
0
    for (auto& pElement : m_aChildrenList)
1864
0
    {
1865
0
        DBG_ASSERT( !pElement->m_bIsFolder || pElement->m_xStorage.is(), "Storage should be open!" );
1866
0
        if ( pElement->m_bIsFolder && pElement->m_xStorage.is() )
1867
0
            pElement->m_xStorage->SetProps( rSequence, aPath );
1868
0
        else
1869
0
        {
1870
0
            OUString aElementPath = aPath + pElement->m_aName;
1871
0
            pElement->SetContentType( Find_Impl( rSequence, aElementPath ) );
1872
0
        }
1873
0
    }
1874
1875
0
    if ( m_aContentType.isEmpty() )
1876
0
        return;
1877
1878
    // get the clipboard format using the content type
1879
0
    css::datatransfer::DataFlavor aDataFlavor;
1880
0
    aDataFlavor.MimeType = m_aContentType;
1881
0
    m_nFormat = SotExchange::GetFormat( aDataFlavor );
1882
1883
    // get the ClassId using the clipboard format ( internal table )
1884
0
    m_aClassId = GetClassId_Impl( m_nFormat );
1885
1886
    // get human presentable name using the clipboard format
1887
0
    SotExchange::GetFormatDataFlavor( m_nFormat, aDataFlavor );
1888
0
    m_aUserTypeName = aDataFlavor.HumanPresentableName;
1889
0
}
1890
1891
void UCBStorage_Impl::GetProps( sal_Int32& nProps, Sequence < Sequence < PropertyValue > >& rSequence, const OUString& rPath )
1892
0
{
1893
0
    auto pSequence = rSequence.getArray();
1894
1895
    // first my own properties
1896
    // first property is the "FullPath" name
1897
    // it's '/' for the root storage and m_aName for each element, followed by a '/' if it's a folder
1898
0
    OUString aPath( rPath );
1899
0
    if ( !m_bIsRoot )
1900
0
        aPath += m_aName;
1901
0
    aPath += "/";
1902
0
    Sequence < PropertyValue > aProps{ comphelper::makePropertyValue(u"MediaType"_ustr, m_aContentType),
1903
0
                                       comphelper::makePropertyValue(u"FullPath"_ustr, aPath) };
1904
0
    pSequence[nProps++] = aProps;
1905
1906
0
    if ( m_bIsRoot )
1907
        // the "FullPath" of a child always starts without '/'
1908
0
        aPath.clear();
1909
1910
    // now the properties of my elements
1911
0
    for (auto& pElement : m_aChildrenList)
1912
0
    {
1913
0
        DBG_ASSERT( !pElement->m_bIsFolder || pElement->m_xStorage.is(), "Storage should be open!" );
1914
0
        if ( pElement->m_bIsFolder && pElement->m_xStorage.is() )
1915
            // storages add there properties by themselves ( see above )
1916
0
            pElement->m_xStorage->GetProps( nProps, rSequence, aPath );
1917
0
        else
1918
0
        {
1919
            // properties of streams
1920
0
            OUString aElementPath = aPath + pElement->m_aName;
1921
0
            aProps = { comphelper::makePropertyValue(u"MediaType"_ustr, pElement->GetContentType()),
1922
0
                       comphelper::makePropertyValue(u"FullPath"_ustr, aElementPath) };
1923
0
            pSequence[ nProps++ ] = aProps;
1924
0
        }
1925
0
    }
1926
0
}
1927
1928
UCBStorage_Impl::~UCBStorage_Impl()
1929
59
{
1930
59
    m_aChildrenList.clear();
1931
1932
59
    m_oContent.reset();
1933
59
    m_pTempFile.reset();
1934
59
}
1935
1936
bool UCBStorage_Impl::Insert( ::ucbhelper::Content *pContent )
1937
0
{
1938
    // a new substorage is inserted into a UCBStorage ( given by the parameter pContent )
1939
    // it must be inserted with a title and a type
1940
0
    bool bRet = false;
1941
1942
0
    try
1943
0
    {
1944
0
        const Sequence< ContentInfo > aInfo = pContent->queryCreatableContentsInfo();
1945
0
        if ( !aInfo.hasElements() )
1946
0
            return false;
1947
1948
0
        for ( const ContentInfo & rCurr : aInfo )
1949
0
        {
1950
            // Simply look for the first KIND_FOLDER...
1951
0
            if ( rCurr.Attributes & ContentInfoAttribute::KIND_FOLDER )
1952
0
            {
1953
                // Make sure the only required bootstrap property is "Title",
1954
0
                const Sequence< Property > & rProps = rCurr.Properties;
1955
0
                if ( rProps.getLength() != 1 )
1956
0
                    continue;
1957
1958
0
                if ( rProps[ 0 ].Name != "Title" )
1959
0
                    continue;
1960
1961
0
                Content aNewFolder;
1962
0
                if ( !pContent->insertNewContent( rCurr.Type, { u"Title"_ustr }, { Any(m_aName) }, aNewFolder ) )
1963
0
                    continue;
1964
1965
                // remove old content, create an "empty" new one and initialize it with the new inserted
1966
0
                m_oContent.emplace( aNewFolder );
1967
0
                bRet = true;
1968
0
            }
1969
0
        }
1970
0
    }
1971
0
    catch (const CommandAbortedException&)
1972
0
    {
1973
        // any command wasn't executed successfully - not specified
1974
0
        SetError( ERRCODE_IO_GENERAL );
1975
0
    }
1976
0
    catch (const RuntimeException&)
1977
0
    {
1978
        // any other error - not specified
1979
0
        SetError( ERRCODE_IO_GENERAL );
1980
0
    }
1981
0
    catch (const Exception&)
1982
0
    {
1983
        // any other error - not specified
1984
0
        SetError( ERRCODE_IO_GENERAL );
1985
0
    }
1986
1987
0
    return bRet;
1988
0
}
1989
1990
CommitResult UCBStorage_Impl::Commit()
1991
0
{
1992
    // send all changes to the package
1993
0
    CommitResult nRet = CommitResult::Nothing_to_do;
1994
1995
    // there is nothing to do if the storage has been opened readonly or if it was opened in transacted mode and no
1996
    // commit command has been sent
1997
0
    if ( ( m_nMode & StreamMode::WRITE ) && ( m_bCommited || m_bDirect ) )
1998
0
    {
1999
0
        try
2000
0
        {
2001
            // all errors will be caught in the "catch" statement outside the loop
2002
0
            for ( size_t i = 0; i < m_aChildrenList.size() && static_cast<sal_Int16>(nRet); ++i )
2003
0
            {
2004
0
                auto& pElement = m_aChildrenList[ i ];
2005
0
                ::ucbhelper::Content* pContent = pElement->GetContent();
2006
0
                std::unique_ptr< ::ucbhelper::Content > xDeleteContent;
2007
0
                if ( !pContent && pElement->IsModified() )
2008
0
                {
2009
                    // if the element has never been opened, no content has been created until now
2010
0
                    OUString aName = m_aURL + "/" + pElement->m_aOriginalName;
2011
0
                    pContent = new ::ucbhelper::Content( aName, Reference< css::ucb::XCommandEnvironment >(), comphelper::getProcessComponentContext() );
2012
0
                    xDeleteContent.reset(pContent);  // delete it later on exit scope
2013
0
                }
2014
2015
0
                if ( pElement->m_bIsRemoved )
2016
0
                {
2017
                    // was it inserted, then removed (so there would be nothing to do!)
2018
0
                    if ( !pElement->m_bIsInserted )
2019
0
                    {
2020
                        // first remove all open stream handles
2021
0
                        if (pContent && (!pElement->m_xStream.is() || pElement->m_xStream->Clear()))
2022
0
                        {
2023
0
                            pContent->executeCommand( u"delete"_ustr, Any( true ) );
2024
0
                            nRet = CommitResult::Success;
2025
0
                        }
2026
0
                        else
2027
                            // couldn't release stream because there are external references to it
2028
0
                            nRet = CommitResult::Failure;
2029
0
                    }
2030
0
                }
2031
0
                else
2032
0
                {
2033
0
                    CommitResult nLocalRet = CommitResult::Nothing_to_do;
2034
0
                    if ( pElement->m_xStorage.is() )
2035
0
                    {
2036
                        // element is a storage
2037
                        // do a commit in the following cases:
2038
                        //  - if storage is already inserted, and changed
2039
                        //  - storage is not in a package
2040
                        //  - it's a new storage, try to insert and commit if Successful inserted
2041
0
                        if ( !pElement->m_bIsInserted || m_bIsLinked
2042
0
                             || pElement->m_xStorage->Insert( m_oContent ? &*m_oContent : nullptr ) )
2043
0
                        {
2044
0
                            nLocalRet = pElement->m_xStorage->Commit();
2045
0
                            pContent = pElement->GetContent();
2046
0
                        }
2047
0
                    }
2048
0
                    else if ( pElement->m_xStream.is() )
2049
0
                    {
2050
                        // element is a stream
2051
0
                        nLocalRet = pElement->m_xStream->Commit();
2052
0
                        if ( pElement->m_xStream->m_bIsOLEStorage )
2053
0
                        {
2054
                            // OLE storage should be stored encrypted, if the storage uses encryption
2055
0
                            pElement->m_xStream->m_aContentType = "application/vnd.sun.star.oleobject";
2056
0
                            Any aValue;
2057
0
                            aValue <<= true;
2058
0
                            pElement->m_xStream->m_pContent->setPropertyValue(u"Encrypted"_ustr, aValue );
2059
0
                        }
2060
2061
0
                        pContent = pElement->GetContent();
2062
0
                    }
2063
2064
0
                    if (pContent && pElement->m_aName != pElement->m_aOriginalName)
2065
0
                    {
2066
                        // name ( title ) of the element was changed
2067
0
                        nLocalRet = CommitResult::Success;
2068
0
                        pContent->setPropertyValue(u"Title"_ustr, Any(pElement->m_aName) );
2069
0
                    }
2070
2071
0
                    if (pContent && pElement->IsLoaded() && pElement->GetContentType() != pElement->GetOriginalContentType())
2072
0
                    {
2073
                        // mediatype of the element was changed
2074
0
                        nLocalRet = CommitResult::Success;
2075
0
                        pContent->setPropertyValue(u"MediaType"_ustr, Any(pElement->GetContentType()) );
2076
0
                    }
2077
2078
0
                    if ( nLocalRet != CommitResult::Nothing_to_do )
2079
0
                        nRet = nLocalRet;
2080
0
                }
2081
2082
0
                if ( nRet == CommitResult::Failure )
2083
0
                    break;
2084
0
            }
2085
0
        }
2086
0
        catch (const ContentCreationException&)
2087
0
        {
2088
            // content could not be created
2089
0
            SetError( ERRCODE_IO_NOTEXISTS );
2090
0
            return CommitResult::Failure;
2091
0
        }
2092
0
        catch (const CommandAbortedException&)
2093
0
        {
2094
            // any command wasn't executed Successfully - not specified
2095
0
            SetError( ERRCODE_IO_GENERAL );
2096
0
            return CommitResult::Failure;
2097
0
        }
2098
0
        catch (const RuntimeException&)
2099
0
        {
2100
            // any other error - not specified
2101
0
            SetError( ERRCODE_IO_GENERAL );
2102
0
            return CommitResult::Failure;
2103
0
        }
2104
0
        catch (const Exception&)
2105
0
        {
2106
            // any other error - not specified
2107
0
            SetError( ERRCODE_IO_GENERAL );
2108
0
            return CommitResult::Failure;
2109
0
        }
2110
2111
0
        if ( m_bIsRoot && m_oContent )
2112
0
        {
2113
            // the root storage must flush the root package content
2114
0
            if ( nRet == CommitResult::Success )
2115
0
            {
2116
0
                try
2117
0
                {
2118
                    // commit the media type to the JAR file
2119
                    // clipboard format and ClassId will be retrieved from the media type when the file is loaded again
2120
0
                    Any aType;
2121
0
                    aType <<= m_aContentType;
2122
0
                    m_oContent->setPropertyValue(u"MediaType"_ustr, aType );
2123
2124
0
                    if (  m_bIsLinked )
2125
0
                    {
2126
                        // write a manifest file
2127
                        // first create a subfolder "META-inf"
2128
0
                        Content aNewSubFolder;
2129
0
                        bool bRet = ::utl::UCBContentHelper::MakeFolder( *m_oContent, u"META-INF"_ustr, aNewSubFolder );
2130
0
                        if ( bRet )
2131
0
                        {
2132
                            // create a stream to write the manifest file - use a temp file
2133
0
                            OUString aURL( aNewSubFolder.getURL() );
2134
0
                            std::optional< ::utl::TempFileNamed > pTempFile(&aURL );
2135
2136
                            // get the stream from the temp file and create an output stream wrapper
2137
0
                            SvStream* pStream = pTempFile->GetStream( StreamMode::STD_READWRITE );
2138
0
                            rtl::Reference<::utl::OOutputStreamWrapper> xOutputStream = new ::utl::OOutputStreamWrapper( *pStream );
2139
2140
                            // create a manifest writer object that will fill the stream
2141
0
                            Reference < css::packages::manifest::XManifestWriter > xWriter =
2142
0
                                css::packages::manifest::ManifestWriter::create(
2143
0
                                    ::comphelper::getProcessComponentContext() );
2144
0
                            sal_Int32 nCount = GetObjectCount() + 1;
2145
0
                            Sequence < Sequence < PropertyValue > > aProps( nCount );
2146
0
                            sal_Int32 nProps = 0;
2147
0
                            GetProps( nProps, aProps, OUString() );
2148
0
                            xWriter->writeManifestSequence( xOutputStream, aProps );
2149
2150
                            // move the stream to its desired location
2151
0
                            Content aSource( pTempFile->GetURL(), Reference < XCommandEnvironment >(), comphelper::getProcessComponentContext() );
2152
0
                            xWriter = nullptr;
2153
0
                            xOutputStream = nullptr;
2154
0
                            pTempFile.reset();
2155
0
                            aNewSubFolder.transferContent( aSource, InsertOperation::Move, u"manifest.xml"_ustr, NameClash::OVERWRITE );
2156
0
                        }
2157
0
                    }
2158
0
                    else
2159
0
                    {
2160
#if OSL_DEBUG_LEVEL > 0
2161
                        SAL_INFO("sot", "Files: " << nOpenFiles);
2162
                        SAL_INFO("sot", "Streams: " << nOpenStreams);
2163
#endif
2164
                        // force writing
2165
0
                        Any aAny;
2166
0
                        m_oContent->executeCommand( u"flush"_ustr, aAny );
2167
0
                        if ( m_pSource != nullptr )
2168
0
                        {
2169
0
                            std::unique_ptr<SvStream> pStream(::utl::UcbStreamHelper::CreateStream( m_pTempFile->GetURL(), StreamMode::STD_READ ));
2170
0
                            m_pSource->SetStreamSize(0);
2171
                            // m_pSource->Seek(0);
2172
0
                            pStream->ReadStream( *m_pSource );
2173
0
                            pStream.reset();
2174
0
                            m_pSource->Seek(0);
2175
0
                        }
2176
0
                    }
2177
0
                }
2178
0
                catch (const CommandAbortedException&)
2179
0
                {
2180
                    // how to tell the content : forget all changes ?!
2181
                    // or should we assume that the content does it by itself because he threw an exception ?!
2182
                    // any command wasn't executed Successfully - not specified
2183
0
                    SetError( ERRCODE_IO_GENERAL );
2184
0
                    return CommitResult::Failure;
2185
0
                }
2186
0
                catch (const RuntimeException&)
2187
0
                {
2188
                    // how to tell the content : forget all changes ?!
2189
                    // or should we assume that the content does it by itself because he threw an exception ?!
2190
                    // any other error - not specified
2191
0
                    SetError( ERRCODE_IO_GENERAL );
2192
0
                    return CommitResult::Failure;
2193
0
                }
2194
0
                catch (const InteractiveIOException& r)
2195
0
                {
2196
0
                    if ( r.Code == IOErrorCode_ACCESS_DENIED || r.Code == IOErrorCode_LOCKING_VIOLATION )
2197
0
                        SetError( ERRCODE_IO_ACCESSDENIED );
2198
0
                    else if ( r.Code == IOErrorCode_NOT_EXISTING )
2199
0
                        SetError( ERRCODE_IO_NOTEXISTS );
2200
0
                    else if ( r.Code == IOErrorCode_CANT_READ )
2201
0
                        SetError( ERRCODE_IO_CANTREAD );
2202
0
                    else if ( r.Code == IOErrorCode_CANT_WRITE )
2203
0
                        SetError( ERRCODE_IO_CANTWRITE );
2204
0
                    else
2205
0
                        SetError( ERRCODE_IO_GENERAL );
2206
2207
0
                    return CommitResult::Failure;
2208
0
                }
2209
0
                catch (const Exception&)
2210
0
                {
2211
                    // how to tell the content : forget all changes ?!
2212
                    // or should we assume that the content does it by itself because he threw an exception ?!
2213
                    // any other error - not specified
2214
0
                    SetError( ERRCODE_IO_GENERAL );
2215
0
                    return CommitResult::Failure;
2216
0
                }
2217
0
            }
2218
0
            else if ( nRet != CommitResult::Nothing_to_do )
2219
0
            {
2220
                // how to tell the content : forget all changes ?! Should we ?!
2221
0
                SetError( ERRCODE_IO_GENERAL );
2222
0
                return nRet;
2223
0
            }
2224
2225
            // after Successful root commit all elements names and types are adjusted and all removed elements
2226
            // are also removed from the lists
2227
0
            for ( size_t i = 0; i < m_aChildrenList.size(); )
2228
0
            {
2229
0
                auto& pInnerElement = m_aChildrenList[ i ];
2230
0
                if ( pInnerElement->m_bIsRemoved )
2231
0
                    m_aChildrenList.erase( m_aChildrenList.begin() + i );
2232
0
                else
2233
0
                {
2234
0
                    pInnerElement->m_aOriginalName = pInnerElement->m_aName;
2235
0
                    pInnerElement->m_bIsInserted = false;
2236
0
                    ++i;
2237
0
                }
2238
0
            }
2239
0
        }
2240
2241
0
        m_bCommited = false;
2242
0
    }
2243
2244
0
    return nRet;
2245
0
}
2246
2247
void UCBStorage_Impl::Revert()
2248
0
{
2249
0
    for ( size_t i = 0; i < m_aChildrenList.size(); )
2250
0
    {
2251
0
        auto& pElement = m_aChildrenList[ i ];
2252
0
        pElement->m_bIsRemoved = false;
2253
0
        if ( pElement->m_bIsInserted )
2254
0
            m_aChildrenList.erase( m_aChildrenList.begin() + i );
2255
0
        else
2256
0
        {
2257
0
            if ( pElement->m_xStream.is() )
2258
0
            {
2259
0
                pElement->m_xStream->m_bCommited = false;
2260
0
                pElement->m_xStream->Revert();
2261
0
            }
2262
0
            else if ( pElement->m_xStorage.is() )
2263
0
            {
2264
0
                pElement->m_xStorage->m_bCommited = false;
2265
0
                pElement->m_xStorage->Revert();
2266
0
            }
2267
2268
0
            pElement->m_aName = pElement->m_aOriginalName;
2269
0
            pElement->m_bIsRemoved = false;
2270
0
            ++i;
2271
0
        }
2272
0
    }
2273
0
}
2274
2275
const OUString& UCBStorage::GetName() const
2276
0
{
2277
0
    return pImp->m_aName; // pImp->m_aURL ?!
2278
0
}
2279
2280
bool UCBStorage::IsRoot() const
2281
59
{
2282
59
    return pImp->m_bIsRoot;
2283
59
}
2284
2285
void UCBStorage::SetDirty()
2286
0
{
2287
0
}
2288
2289
void UCBStorage::SetClass( const SvGlobalName & rClass, SotClipboardFormatId nOriginalClipFormat, const OUString & rUserTypeName )
2290
0
{
2291
0
    pImp->m_aClassId = rClass;
2292
0
    pImp->m_nFormat = nOriginalClipFormat;
2293
0
    pImp->m_aUserTypeName = rUserTypeName;
2294
2295
    // in UCB storages only the content type will be stored, all other information can be reconstructed
2296
    // ( see the UCBStorage_Impl::Init() method )
2297
0
    css::datatransfer::DataFlavor aDataFlavor;
2298
0
    SotExchange::GetFormatDataFlavor( pImp->m_nFormat, aDataFlavor );
2299
0
    pImp->m_aContentType = aDataFlavor.MimeType;
2300
0
}
2301
2302
void UCBStorage::SetClassId( const ClsId& rClsId )
2303
0
{
2304
0
    pImp->m_aClassId = SvGlobalName( rClsId );
2305
0
    if ( pImp->m_aClassId == SvGlobalName() )
2306
0
        return;
2307
2308
    // in OLE storages the clipboard format and the user name will be transferred when a storage is copied because both are
2309
    // stored in one the substreams
2310
    // UCB storages store the content type information as content type in the manifest file and so this information must be
2311
    // kept up to date, and also the other type information that is hold only at runtime because it can be reconstructed from
2312
    // the content type
2313
0
    pImp->m_nFormat = GetFormatId_Impl( pImp->m_aClassId );
2314
0
    if ( pImp->m_nFormat != SotClipboardFormatId::NONE )
2315
0
    {
2316
0
        css::datatransfer::DataFlavor aDataFlavor;
2317
0
        SotExchange::GetFormatDataFlavor( pImp->m_nFormat, aDataFlavor );
2318
0
        pImp->m_aUserTypeName = aDataFlavor.HumanPresentableName;
2319
0
        pImp->m_aContentType = aDataFlavor.MimeType;
2320
0
    }
2321
0
}
2322
2323
const ClsId& UCBStorage::GetClassId() const
2324
0
{
2325
0
    return pImp->m_aClassId.GetCLSID();
2326
0
}
2327
2328
SvGlobalName UCBStorage::GetClassName()
2329
0
{
2330
0
    return  pImp->m_aClassId;
2331
0
}
2332
2333
SotClipboardFormatId UCBStorage::GetFormat()
2334
0
{
2335
0
    return pImp->m_nFormat;
2336
0
}
2337
2338
OUString UCBStorage::GetUserName()
2339
0
{
2340
0
    OSL_FAIL("UserName is not implemented in UCB storages!" );
2341
0
    return pImp->m_aUserTypeName;
2342
0
}
2343
2344
void UCBStorage::FillInfoList( SvStorageInfoList* pList ) const
2345
22
{
2346
    // put information in childrenlist into StorageInfoList
2347
22
    for (auto& pElement : pImp->GetChildrenList())
2348
0
    {
2349
0
        if ( !pElement->m_bIsRemoved )
2350
0
        {
2351
            // problem: what about the size of a substorage ?!
2352
0
            sal_uInt64 nSize = pElement->m_nSize;
2353
0
            if ( pElement->m_xStream.is() )
2354
0
                nSize = pElement->m_xStream->GetSize();
2355
0
            SvStorageInfo aInfo( pElement->m_aName, nSize, pElement->m_bIsStorage );
2356
0
            pList->push_back( aInfo );
2357
0
        }
2358
0
    }
2359
22
}
2360
2361
bool UCBStorage::CopyStorageElement_Impl( UCBStorageElement_Impl const & rElement, BaseStorage* pDest, const OUString& rNew ) const
2362
0
{
2363
    // insert stream or storage into the list or stream of the destination storage
2364
    // not into the content, this will be done on commit !
2365
    // be aware of name changes !
2366
0
    if ( !rElement.m_bIsStorage )
2367
0
    {
2368
        // copy the streams data
2369
        // the destination stream must not be open
2370
0
        tools::SvRef<BaseStorageStream> pOtherStream(pDest->OpenStream( rNew, StreamMode::WRITE | StreamMode::SHARE_DENYALL, pImp->m_bDirect ));
2371
0
        BaseStorageStream* pStream = nullptr;
2372
0
        bool bDeleteStream = false;
2373
2374
        // if stream is already open, it is allowed to copy it, so be aware of this
2375
0
        if ( rElement.m_xStream.is() )
2376
0
            pStream = rElement.m_xStream->m_pAntiImpl;
2377
0
        if ( !pStream )
2378
0
        {
2379
0
            pStream = const_cast< UCBStorage* >(this)->OpenStream( rElement.m_aName, StreamMode::STD_READ, pImp->m_bDirect );
2380
0
            bDeleteStream = true;
2381
0
        }
2382
2383
0
        pStream->CopyTo( pOtherStream.get() );
2384
0
        SetError( pStream->GetError() );
2385
0
        if( pOtherStream->GetError() )
2386
0
            pDest->SetError( pOtherStream->GetError() );
2387
0
        else
2388
0
            pOtherStream->Commit();
2389
2390
0
        if ( bDeleteStream )
2391
0
            delete pStream;
2392
0
    }
2393
0
    else
2394
0
    {
2395
        // copy the storage content
2396
        // the destination storage must not be open
2397
0
        BaseStorage* pStorage = nullptr;
2398
2399
        // if stream is already open, it is allowed to copy it, so be aware of this
2400
0
        bool bDeleteStorage = false;
2401
0
        if ( rElement.m_xStorage.is() )
2402
0
            pStorage = rElement.m_xStorage->m_pAntiImpl;
2403
0
        if ( !pStorage )
2404
0
        {
2405
0
            pStorage = const_cast<UCBStorage*>(this)->OpenStorage( rElement.m_aName, pImp->m_nMode, pImp->m_bDirect );
2406
0
            bDeleteStorage = true;
2407
0
        }
2408
2409
0
        UCBStorage* pUCBDest =  dynamic_cast<UCBStorage*>( pDest );
2410
0
        UCBStorage* pUCBCopy =  dynamic_cast<UCBStorage*>( pStorage );
2411
2412
0
        bool bOpenUCBStorage = pUCBDest && pUCBCopy;
2413
0
        tools::SvRef<BaseStorage> pOtherStorage(bOpenUCBStorage ?
2414
0
                pDest->OpenUCBStorage( rNew, StreamMode::WRITE | StreamMode::SHARE_DENYALL, pImp->m_bDirect ) :
2415
0
                pDest->OpenOLEStorage( rNew, StreamMode::WRITE | StreamMode::SHARE_DENYALL, pImp->m_bDirect ));
2416
2417
        // For UCB storages, the class id and the format id may differ,
2418
        // do passing the class id is not sufficient.
2419
0
        if( bOpenUCBStorage )
2420
0
            pOtherStorage->SetClass( pStorage->GetClassName(),
2421
0
                                     pStorage->GetFormat(),
2422
0
                                     pUCBCopy->pImp->m_aUserTypeName );
2423
0
        else
2424
0
            pOtherStorage->SetClassId( pStorage->GetClassId() );
2425
0
        pStorage->CopyTo( *pOtherStorage );
2426
0
        SetError( pStorage->GetError() );
2427
0
        if( pOtherStorage->GetError() )
2428
0
            pDest->SetError( pOtherStorage->GetError() );
2429
0
        else
2430
0
            pOtherStorage->Commit();
2431
2432
0
        if ( bDeleteStorage )
2433
0
            delete pStorage;
2434
0
    }
2435
2436
0
    return Good() && pDest->Good();
2437
0
}
2438
2439
UCBStorageElement_Impl* UCBStorage::FindElement_Impl( std::u16string_view rName ) const
2440
0
{
2441
0
    DBG_ASSERT( !rName.empty(), "Name is empty!" );
2442
0
    for (const auto& pElement : pImp->GetChildrenList())
2443
0
    {
2444
0
        if ( pElement->m_aName == rName && !pElement->m_bIsRemoved )
2445
0
            return pElement.get();
2446
0
    }
2447
0
    return nullptr;
2448
0
}
2449
2450
bool UCBStorage::CopyTo( BaseStorage& rDestStg ) const
2451
0
{
2452
0
    DBG_ASSERT( &rDestStg != static_cast<BaseStorage const *>(this), "Self-Copying is not possible!" );
2453
0
    if ( &rDestStg == static_cast<BaseStorage const *>(this) )
2454
0
        return false;
2455
2456
    // perhaps it's also a problem if one storage is a parent of the other ?!
2457
    // or if not: could be optimized ?!
2458
2459
    // For UCB storages, the class id and the format id may differ,
2460
    // do passing the class id is not sufficient.
2461
0
    if( dynamic_cast<const UCBStorage *>(&rDestStg) != nullptr )
2462
0
        rDestStg.SetClass( pImp->m_aClassId, pImp->m_nFormat,
2463
0
                           pImp->m_aUserTypeName );
2464
0
    else
2465
0
        rDestStg.SetClassId( GetClassId() );
2466
0
    rDestStg.SetDirty();
2467
2468
0
    bool bRet = true;
2469
0
    for ( size_t i = 0; i < pImp->GetChildrenList().size() && bRet; ++i )
2470
0
    {
2471
0
        auto& pElement = pImp->GetChildrenList()[ i ];
2472
0
        if ( !pElement->m_bIsRemoved )
2473
0
            bRet = CopyStorageElement_Impl( *pElement, &rDestStg, pElement->m_aName );
2474
0
    }
2475
2476
0
    if( !bRet )
2477
0
        SetError( rDestStg.GetError() );
2478
0
    return Good() && rDestStg.Good();
2479
0
}
2480
2481
bool UCBStorage::CopyTo( const OUString& rElemName, BaseStorage* pDest, const OUString& rNew )
2482
0
{
2483
0
    if( rElemName.isEmpty() )
2484
0
        return false;
2485
2486
0
    if ( pDest == static_cast<BaseStorage*>(this) )
2487
0
    {
2488
        // can't double an element
2489
0
        return false;
2490
0
    }
2491
0
    else
2492
0
    {
2493
        // for copying no optimization is useful, because in every case the stream data must be copied
2494
0
        UCBStorageElement_Impl* pElement = FindElement_Impl( rElemName );
2495
0
        if ( pElement )
2496
0
            return CopyStorageElement_Impl( *pElement, pDest, rNew );
2497
0
        else
2498
0
        {
2499
0
            SetError( SVSTREAM_FILE_NOT_FOUND );
2500
0
            return false;
2501
0
        }
2502
0
    }
2503
0
}
2504
2505
bool UCBStorage::Commit()
2506
0
{
2507
    // mark this storage for sending it on root commit
2508
0
    pImp->m_bCommited = true;
2509
0
    if ( pImp->m_bIsRoot )
2510
        // the root storage coordinates committing by sending a Commit command to its content
2511
0
        return ( pImp->Commit() != CommitResult::Failure );
2512
0
    else
2513
0
        return true;
2514
0
}
2515
2516
bool UCBStorage::Revert()
2517
0
{
2518
0
    pImp->Revert();
2519
0
    return true;
2520
0
}
2521
2522
BaseStorageStream* UCBStorage::OpenStream( const OUString& rEleName, StreamMode nMode, bool bDirect )
2523
0
{
2524
0
    if( rEleName.isEmpty() )
2525
0
        return nullptr;
2526
2527
    // try to find the storage element
2528
0
    UCBStorageElement_Impl *pElement = FindElement_Impl( rEleName );
2529
0
    if ( !pElement )
2530
0
    {
2531
        // element does not exist, check if creation is allowed
2532
0
        if( nMode & StreamMode::NOCREATE )
2533
0
        {
2534
0
            SetError( ( nMode & StreamMode::WRITE ) ? SVSTREAM_CANNOT_MAKE : SVSTREAM_FILE_NOT_FOUND );
2535
0
            OUString aName = pImp->m_aURL + "/" + rEleName;
2536
0
            UCBStorageStream* pStream = new UCBStorageStream( aName, nMode, bDirect, pImp->m_bRepairPackage, pImp->m_xProgressHandler );
2537
0
            pStream->SetError( GetError() );
2538
0
            pStream->pImp->m_aName = rEleName;
2539
0
            return pStream;
2540
0
        }
2541
0
        else
2542
0
        {
2543
            // create a new UCBStorageElement and insert it into the list
2544
0
            pElement = new UCBStorageElement_Impl( rEleName );
2545
0
            pElement->m_bIsInserted = true;
2546
0
            pImp->m_aChildrenList.emplace_back( pElement );
2547
0
        }
2548
0
    }
2549
2550
0
    if ( !pElement->m_bIsFolder )
2551
0
    {
2552
        // check if stream is already created
2553
0
        if ( pElement->m_xStream.is() )
2554
0
        {
2555
            // stream has already been created; if it has no external reference, it may be opened another time
2556
0
            if ( pElement->m_xStream->m_pAntiImpl )
2557
0
            {
2558
0
                OSL_FAIL("Stream is already open!" );
2559
0
                SetError( SVSTREAM_ACCESS_DENIED );  // ???
2560
0
                return nullptr;
2561
0
            }
2562
0
            else
2563
0
            {
2564
                // check if stream is opened with the same keyword as before
2565
                // if not, generate a new stream because it could be encrypted vs. decrypted!
2566
0
                if ( pElement->m_xStream->m_aKey.isEmpty() )
2567
0
                {
2568
0
                    pElement->m_xStream->PrepareCachedForReopen( nMode );
2569
2570
0
                    return new UCBStorageStream( pElement->m_xStream.get() );
2571
0
                }
2572
0
            }
2573
0
        }
2574
2575
        // stream is opened the first time
2576
0
        pImp->OpenStream( pElement, nMode, bDirect );
2577
2578
        // if name has been changed before creating the stream: set name!
2579
0
        pElement->m_xStream->m_aName = rEleName;
2580
0
        return new UCBStorageStream( pElement->m_xStream.get() );
2581
0
    }
2582
2583
0
    return nullptr;
2584
0
}
2585
2586
void UCBStorage_Impl::OpenStream( UCBStorageElement_Impl* pElement, StreamMode nMode, bool bDirect )
2587
0
{
2588
0
    OUString aName = m_aURL + "/" +pElement->m_aOriginalName;
2589
0
    pElement->m_xStream = new UCBStorageStream_Impl( aName, nMode, nullptr, bDirect, m_bRepairPackage, m_xProgressHandler );
2590
0
}
2591
2592
BaseStorage* UCBStorage::OpenUCBStorage( const OUString& rEleName, StreamMode nMode, bool bDirect )
2593
0
{
2594
0
    if( rEleName.isEmpty() )
2595
0
        return nullptr;
2596
2597
0
    return OpenStorage_Impl( rEleName, nMode, bDirect, true );
2598
0
}
2599
2600
BaseStorage* UCBStorage::OpenOLEStorage( const OUString& rEleName, StreamMode nMode, bool bDirect )
2601
0
{
2602
0
    if( rEleName.isEmpty() )
2603
0
        return nullptr;
2604
2605
0
    return OpenStorage_Impl( rEleName, nMode, bDirect, false );
2606
0
}
2607
2608
BaseStorage* UCBStorage::OpenStorage( const OUString& rEleName, StreamMode nMode, bool bDirect )
2609
0
{
2610
0
    if( rEleName.isEmpty() )
2611
0
        return nullptr;
2612
2613
0
    return OpenStorage_Impl( rEleName, nMode, bDirect, true );
2614
0
}
2615
2616
BaseStorage* UCBStorage::OpenStorage_Impl( const OUString& rEleName, StreamMode nMode, bool bDirect, bool bForceUCBStorage )
2617
0
{
2618
    // try to find the storage element
2619
0
    UCBStorageElement_Impl *pElement = FindElement_Impl( rEleName );
2620
0
    if ( !pElement )
2621
0
    {
2622
        // element does not exist, check if creation is allowed
2623
0
        if( nMode & StreamMode::NOCREATE )
2624
0
        {
2625
0
            SetError( ( nMode & StreamMode::WRITE ) ? SVSTREAM_CANNOT_MAKE : SVSTREAM_FILE_NOT_FOUND );
2626
0
            OUString aName = pImp->m_aURL + "/" + rEleName;  //  ???
2627
0
            UCBStorage *pStorage = new UCBStorage( aName, nMode, bDirect, false, pImp->m_bRepairPackage, pImp->m_xProgressHandler );
2628
0
            pStorage->pImp->m_bIsRoot = false;
2629
0
            pStorage->pImp->m_bListCreated = true; // the storage is pretty new, nothing to read
2630
0
            pStorage->SetError( GetError() );
2631
0
            return pStorage;
2632
0
        }
2633
2634
        // create a new UCBStorageElement and insert it into the list
2635
        // problem: perhaps an OLEStorage should be created ?!
2636
        // Because nothing is known about the element that should be created, an external parameter is needed !
2637
0
        pElement = new UCBStorageElement_Impl( rEleName );
2638
0
        pElement->m_bIsInserted = true;
2639
0
        pImp->m_aChildrenList.emplace_back( pElement );
2640
0
    }
2641
2642
0
    if ( !pElement->m_bIsFolder && ( pElement->m_bIsStorage || !bForceUCBStorage ) )
2643
0
    {
2644
        // create OLE storages on a stream ( see ctor of SotStorage )
2645
        // Such a storage will be created on a UCBStorageStream; it will write into the stream
2646
        // if it is opened in direct mode or when it is committed. In this case the stream will be
2647
        // modified and then it MUST be treated as committed.
2648
0
        if ( !pElement->m_xStream.is() )
2649
0
        {
2650
0
            BaseStorageStream* pStr = OpenStream( rEleName, nMode, bDirect );
2651
0
            UCBStorageStream* pStream =  dynamic_cast<UCBStorageStream*>( pStr );
2652
0
            if ( !pStream )
2653
0
            {
2654
0
                SetError( ( nMode & StreamMode::WRITE ) ? SVSTREAM_CANNOT_MAKE : SVSTREAM_FILE_NOT_FOUND );
2655
0
                return nullptr;
2656
0
            }
2657
2658
0
            pElement->m_xStream = pStream->pImp;
2659
0
            delete pStream;
2660
0
        }
2661
2662
0
        pElement->m_xStream->PrepareCachedForReopen( nMode );
2663
0
        bool bInited = pElement->m_xStream->Init();
2664
0
        if (!bInited)
2665
0
        {
2666
0
            SetError( ( nMode & StreamMode::WRITE ) ? SVSTREAM_CANNOT_MAKE : SVSTREAM_FILE_NOT_FOUND );
2667
0
            return nullptr;
2668
0
        }
2669
2670
0
        pElement->m_bIsStorage = true;
2671
0
        return pElement->m_xStream->CreateStorage();  // can only be created in transacted mode
2672
0
    }
2673
0
    else if ( pElement->m_xStorage.is() )
2674
0
    {
2675
        // storage has already been opened; if it has no external reference, it may be opened another time
2676
0
        if ( pElement->m_xStorage->m_pAntiImpl )
2677
0
        {
2678
0
            OSL_FAIL("Storage is already open!" );
2679
0
            SetError( SVSTREAM_ACCESS_DENIED );  // ???
2680
0
        }
2681
0
        else
2682
0
        {
2683
0
            bool bIsWritable = bool( pElement->m_xStorage->m_nMode & StreamMode::WRITE );
2684
0
            if ( !bIsWritable && ( nMode & StreamMode::WRITE ) )
2685
0
            {
2686
0
                OUString aName = pImp->m_aURL + "/" + pElement->m_aOriginalName;
2687
0
                UCBStorage* pStorage = new UCBStorage( aName, nMode, bDirect, false, pImp->m_bRepairPackage, pImp->m_xProgressHandler );
2688
0
                pElement->m_xStorage = pStorage->pImp;
2689
0
                return pStorage;
2690
0
            }
2691
0
            else
2692
0
            {
2693
0
                return new UCBStorage( pElement->m_xStorage.get() );
2694
0
            }
2695
0
        }
2696
0
    }
2697
0
    else if ( !pElement->m_xStream.is() )
2698
0
    {
2699
        // storage is opened the first time
2700
0
        bool bIsWritable = bool(pImp->m_nMode & StreamMode::WRITE);
2701
0
        if ( pImp->m_bIsLinked && pImp->m_bIsRoot && bIsWritable )
2702
0
        {
2703
            // make sure that the root storage object has been created before substorages will be created
2704
0
            INetURLObject aFolderObj( pImp->m_aURL );
2705
0
            aFolderObj.removeSegment();
2706
2707
0
            Content aFolder( aFolderObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ), Reference < XCommandEnvironment >(), comphelper::getProcessComponentContext() );
2708
0
            pImp->m_oContent.emplace();
2709
0
            bool bRet = ::utl::UCBContentHelper::MakeFolder( aFolder, pImp->m_aName, *pImp->m_oContent );
2710
0
            if ( !bRet )
2711
0
            {
2712
0
                SetError( SVSTREAM_CANNOT_MAKE );
2713
0
                return nullptr;
2714
0
            }
2715
0
        }
2716
2717
0
        UCBStorage_Impl* pStor = pImp->OpenStorage( pElement, nMode, bDirect );
2718
0
        if ( pStor )
2719
0
        {
2720
0
            if ( pElement->m_bIsInserted )
2721
0
                pStor->m_bListCreated = true; // the storage is pretty new, nothing to read
2722
2723
0
            return new UCBStorage( pStor );
2724
0
        }
2725
0
    }
2726
2727
0
    return nullptr;
2728
0
}
2729
2730
UCBStorage_Impl* UCBStorage_Impl::OpenStorage( UCBStorageElement_Impl* pElement, StreamMode nMode, bool bDirect )
2731
0
{
2732
0
    UCBStorage_Impl* pRet = nullptr;
2733
0
    OUString aName = m_aURL + "/" + pElement->m_aOriginalName;  //  ???
2734
2735
0
    pElement->m_bIsStorage = pElement->m_bIsFolder = true;
2736
2737
0
    if ( m_bIsLinked && !::utl::UCBContentHelper::Exists( aName ) )
2738
0
    {
2739
0
        Content aNewFolder;
2740
0
        bool bRet = ::utl::UCBContentHelper::MakeFolder( *m_oContent, pElement->m_aOriginalName, aNewFolder );
2741
0
        if ( bRet )
2742
0
            pRet = new UCBStorage_Impl( aNewFolder, aName, nMode, nullptr, bDirect, false, m_bRepairPackage, m_xProgressHandler );
2743
0
    }
2744
0
    else
2745
0
    {
2746
0
        pRet = new UCBStorage_Impl( aName, nMode, nullptr, bDirect, false, m_bRepairPackage, m_xProgressHandler );
2747
0
    }
2748
2749
0
    if ( pRet )
2750
0
    {
2751
0
        pRet->m_bIsLinked = m_bIsLinked;
2752
0
        pRet->m_bIsRoot = false;
2753
2754
        // if name has been changed before creating the stream: set name!
2755
0
        pRet->m_aName = pElement->m_aOriginalName;
2756
0
        pElement->m_xStorage = pRet;
2757
0
    }
2758
2759
0
    if ( pRet )
2760
0
        pRet->Init();
2761
2762
0
    return pRet;
2763
0
}
2764
2765
bool UCBStorage::IsStorage( const OUString& rEleName ) const
2766
0
{
2767
0
    if( rEleName.isEmpty() )
2768
0
        return false;
2769
2770
0
    const UCBStorageElement_Impl *pElement = FindElement_Impl( rEleName );
2771
0
    return ( pElement && pElement->m_bIsStorage );
2772
0
}
2773
2774
bool UCBStorage::IsStream( const OUString& rEleName ) const
2775
0
{
2776
0
    if( rEleName.isEmpty() )
2777
0
        return false;
2778
2779
0
    const UCBStorageElement_Impl *pElement = FindElement_Impl( rEleName );
2780
0
    return ( pElement && !pElement->m_bIsStorage );
2781
0
}
2782
2783
bool UCBStorage::IsContained( const OUString & rEleName ) const
2784
0
{
2785
0
    if( rEleName.isEmpty() )
2786
0
        return false;
2787
0
    const UCBStorageElement_Impl *pElement = FindElement_Impl( rEleName );
2788
0
    return ( pElement != nullptr );
2789
0
}
2790
2791
void UCBStorage::Remove( const OUString& rEleName )
2792
0
{
2793
0
    if( rEleName.isEmpty() )
2794
0
        return;
2795
2796
0
    UCBStorageElement_Impl *pElement = FindElement_Impl( rEleName );
2797
0
    if ( pElement )
2798
0
    {
2799
0
        pElement->m_bIsRemoved = true;
2800
0
    }
2801
0
    else
2802
0
        SetError( SVSTREAM_FILE_NOT_FOUND );
2803
0
}
2804
2805
bool UCBStorage::ValidateFAT()
2806
0
{
2807
    // ???
2808
0
    return true;
2809
0
}
2810
2811
bool UCBStorage::Validate( bool  bWrite ) const
2812
0
{
2813
    // ???
2814
0
    return ( !bWrite || ( pImp->m_nMode & StreamMode::WRITE ) );
2815
0
}
2816
2817
bool UCBStorage::ValidateMode( StreamMode m ) const
2818
0
{
2819
    // ???
2820
0
    if( m == ( StreamMode::READ | StreamMode::TRUNC ) )  // from stg.cxx
2821
0
        return true;
2822
    // only SHARE_DENYALL allowed
2823
    // storages open in r/o mode are OK, since only
2824
    // the commit may fail
2825
0
    if( m & StreamMode::SHARE_DENYALL )
2826
0
        return true;
2827
2828
0
    return true;
2829
0
}
2830
2831
bool UCBStorage::Equals( const BaseStorage& rStorage ) const
2832
0
{
2833
    // ???
2834
0
    return static_cast<BaseStorage const *>(this) == &rStorage;
2835
0
}
2836
2837
bool UCBStorage::IsStorageFile( SvStream* pFile )
2838
47.2k
{
2839
47.2k
    if ( !pFile )
2840
0
        return false;
2841
2842
47.2k
    sal_uInt64 nPos = pFile->Tell();
2843
47.2k
    if ( pFile->TellEnd() < 4 )
2844
31
        return false;
2845
2846
47.2k
    pFile->Seek(0);
2847
47.2k
    sal_uInt32 nBytes(0);
2848
47.2k
    pFile->ReadUInt32( nBytes );
2849
2850
    // search for the magic bytes
2851
47.2k
    bool bRet = ( nBytes == 0x04034b50 );
2852
47.2k
    if ( !bRet )
2853
47.1k
    {
2854
        // disk spanned file have an additional header in front of the usual one
2855
47.1k
        bRet = ( nBytes == 0x08074b50 );
2856
47.1k
        if ( bRet )
2857
130
        {
2858
130
            nBytes = 0;
2859
130
            pFile->ReadUInt32( nBytes );
2860
130
            bRet = ( nBytes == 0x04034b50 );
2861
130
        }
2862
47.1k
    }
2863
2864
47.2k
    pFile->Seek( nPos );
2865
47.2k
    return bRet;
2866
47.2k
}
2867
2868
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */