Coverage Report

Created: 2026-02-14 09:37

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/unotools/source/ucbhelper/ucblockbytes.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 "ucblockbytes.hxx"
21
22
#include <sal/log.hxx>
23
#include <comphelper/processfactory.hxx>
24
#include <salhelper/condition.hxx>
25
#include <osl/thread.hxx>
26
#include <osl/diagnose.h>
27
#include <tools/urlobj.hxx>
28
#include <tools/solar.h>
29
#include <ucbhelper/interactionrequest.hxx>
30
#include <com/sun/star/lang/XUnoTunnel.hpp>
31
#include <com/sun/star/task/XInteractionAbort.hpp>
32
#include <com/sun/star/ucb/InteractiveNetworkConnectException.hpp>
33
#include <com/sun/star/ucb/CommandFailedException.hpp>
34
#include <com/sun/star/ucb/ContentCreationException.hpp>
35
#include <com/sun/star/ucb/CommandAbortedException.hpp>
36
#include <com/sun/star/ucb/UnsupportedDataSinkException.hpp>
37
#include <com/sun/star/ucb/InteractiveIOException.hpp>
38
#include <com/sun/star/ucb/XContentIdentifier.hpp>
39
#include <com/sun/star/ucb/XContent.hpp>
40
#include <com/sun/star/io/IOException.hpp>
41
#include <com/sun/star/io/XActiveDataStreamer.hpp>
42
#include <com/sun/star/io/TempFile.hpp>
43
#include <com/sun/star/ucb/XCommandProcessor.hpp>
44
#include <com/sun/star/task/XInteractionHandler.hpp>
45
#include <com/sun/star/ucb/OpenCommandArgument2.hpp>
46
#include <com/sun/star/ucb/PostCommandArgument2.hpp>
47
#include <com/sun/star/ucb/OpenMode.hpp>
48
#include <com/sun/star/beans/PropertyValue.hpp>
49
#include <com/sun/star/beans/XPropertiesChangeNotifier.hpp>
50
#include <com/sun/star/beans/XPropertiesChangeListener.hpp>
51
#include <com/sun/star/io/XActiveDataSink.hpp>
52
#include <com/sun/star/io/XActiveDataControl.hpp>
53
#include <com/sun/star/io/XSeekable.hpp>
54
#include <cppuhelper/implbase.hxx>
55
#include <tools/debug.hxx>
56
#include <com/sun/star/io/XTruncate.hpp>
57
#include <com/sun/star/lang/IllegalArgumentException.hpp>
58
59
#include <comphelper/bytereader.hxx>
60
#include <comphelper/storagehelper.hxx>
61
#include <ucbhelper/content.hxx>
62
#include <unotools/tempfile.hxx>
63
#include <mutex>
64
#include <utility>
65
66
using namespace ::com::sun::star::uno;
67
using namespace ::com::sun::star::io;
68
using namespace ::com::sun::star::ucb;
69
using namespace ::com::sun::star::task;
70
using namespace ::com::sun::star::lang;
71
using namespace ::com::sun::star::beans;
72
73
namespace utl
74
{
75
76
namespace {
77
78
/**
79
    Helper class for getting a XInputStream when opening a content
80
 */
81
class UcbDataSink_Impl : public ::cppu::WeakImplHelper< XActiveDataControl, XActiveDataSink >
82
{
83
    UcbLockBytesRef         m_xLockBytes;
84
85
public:
86
    explicit UcbDataSink_Impl( UcbLockBytes* pLockBytes )
87
3.28k
        : m_xLockBytes( pLockBytes )
88
3.28k
    {}
89
90
    // XActiveDataControl.
91
0
    virtual void SAL_CALL   addListener ( const Reference<XStreamListener> &/*rxListener*/) override {}
92
0
    virtual void SAL_CALL   removeListener ( const Reference<XStreamListener> &/*rxListener*/) override {}
93
0
    virtual void SAL_CALL   start() override {}
94
    virtual void SAL_CALL   terminate() override
95
3.28k
                            { m_xLockBytes->terminate(); }
96
97
    // XActiveDataSink.
98
    virtual void SAL_CALL   setInputStream ( const Reference<XInputStream> &rxInputStream) override
99
3.28k
                            { m_xLockBytes->setInputStream(rxInputStream); }
100
    virtual Reference<XInputStream> SAL_CALL getInputStream() override
101
0
                            { return m_xLockBytes->getInputStream(); }
102
};
103
104
/**
105
    Helper class for getting a XStream when opening a content
106
 */
107
class UcbStreamer_Impl : public ::cppu::WeakImplHelper< XActiveDataStreamer, XActiveDataControl >
108
{
109
    Reference < XStream >   m_xStream;
110
    UcbLockBytesRef         m_xLockBytes;
111
112
public:
113
    explicit UcbStreamer_Impl( UcbLockBytes* pLockBytes )
114
38.5k
        : m_xLockBytes( pLockBytes )
115
38.5k
    {}
116
117
    // XActiveDataControl.
118
0
    virtual void SAL_CALL   addListener ( const Reference<XStreamListener> &/*rxListener*/) override {}
119
0
    virtual void SAL_CALL   removeListener ( const Reference<XStreamListener> &/*rxListener*/) override {}
120
0
    virtual void SAL_CALL   start() override {}
121
    virtual void SAL_CALL   terminate() override
122
38.5k
                            { m_xLockBytes->terminate(); }
123
124
    // XActiveDataStreamer
125
    virtual void SAL_CALL   setStream( const Reference< XStream >& aStream ) override
126
38.5k
                            { m_xStream = aStream; m_xLockBytes->setStream( aStream ); }
127
    virtual Reference< XStream > SAL_CALL getStream() override
128
0
                            { return m_xStream; }
129
};
130
131
/**
132
    Helper class for managing interactions and progress when executing UCB commands
133
 */
134
class UcbTaskEnvironment : public ::cppu::WeakImplHelper< XCommandEnvironment >
135
{
136
    Reference< XInteractionHandler >                m_xInteractionHandler;
137
    Reference< XProgressHandler >                   m_xProgressHandler;
138
139
public:
140
                            UcbTaskEnvironment( const Reference< XInteractionHandler>& rxInteractionHandler,
141
                                                const Reference< XProgressHandler>& rxProgressHandler )
142
41.8k
                                : m_xInteractionHandler( rxInteractionHandler )
143
41.8k
                                , m_xProgressHandler( rxProgressHandler )
144
41.8k
                            {}
145
146
    virtual Reference<XInteractionHandler> SAL_CALL getInteractionHandler() override
147
0
    { return m_xInteractionHandler; }
148
149
    virtual Reference<XProgressHandler> SAL_CALL    getProgressHandler() override
150
0
    { return m_xProgressHandler; }
151
};
152
153
/**
154
    Helper class for property change notifies when executing UCB commands
155
*/
156
class UcbPropertiesChangeListener_Impl : public ::cppu::WeakImplHelper< XPropertiesChangeListener >
157
{
158
public:
159
    UcbLockBytesRef         m_xLockBytes;
160
161
    explicit UcbPropertiesChangeListener_Impl( UcbLockBytesRef xRef )
162
41.8k
        : m_xLockBytes(std::move( xRef ))
163
41.8k
    {}
164
165
0
    virtual void SAL_CALL   disposing ( const EventObject &/*rEvent*/) override {}
166
    virtual void SAL_CALL   propertiesChange ( const Sequence<PropertyChangeEvent> &rEvent) override;
167
};
168
169
}
170
171
void SAL_CALL UcbPropertiesChangeListener_Impl::propertiesChange ( const Sequence<PropertyChangeEvent> &rEvent)
172
0
{
173
0
    for (const auto& rPropChangeEvent : rEvent)
174
0
    {
175
0
        if (rPropChangeEvent.PropertyName == "DocumentHeader")
176
0
        {
177
0
            m_xLockBytes->SetStreamValid();
178
0
        }
179
0
    }
180
0
}
181
182
namespace {
183
184
class Moderator
185
    : public osl::Thread
186
{
187
    // usage restriction:
188
    // It might be possible, that the call to the interactionhandler and/or
189
    // progresshandler is done asynchronously, while the 'execute' simply
190
    // returns. This would imply that these class must be refcounted!!!
191
192
public:
193
    /// @throws ContentCreationException
194
    /// @throws RuntimeException
195
    Moderator(
196
        Reference < XContent > const & xContent,
197
        Reference < XInteractionHandler > const & xInteract,
198
        Command aArg
199
    );
200
201
    enum class ResultType {
202
        NORESULT,
203
204
        INTERACTIONREQUEST,    // reply expected
205
206
        INPUTSTREAM,
207
        STREAM,
208
209
        RESULT,
210
        TIMEDOUT,
211
        COMMANDABORTED,
212
        COMMANDFAILED,
213
        INTERACTIVEIO,
214
        UNSUPPORTED,
215
        GENERAL
216
    };
217
218
    class ConditionRes
219
        : public salhelper::Condition
220
    {
221
    public:
222
        ConditionRes(osl::Mutex& aMutex,Moderator& aModerator)
223
0
            : salhelper::Condition(aMutex),
224
0
              m_aModerator(aModerator)
225
0
        {
226
0
        }
227
228
    protected:
229
0
        bool applies() const override {
230
0
            return m_aModerator.m_aResultType != ResultType::NORESULT;
231
0
        }
232
233
    private:
234
        Moderator& m_aModerator;
235
    };
236
237
    struct Result {
238
        ResultType        type;
239
        Any               result;
240
        IOErrorCode       ioErrorCode;
241
    };
242
243
    Result getResult(const sal_uInt32 milliSec);
244
245
    enum ReplyType {
246
        NOREPLY,
247
        EXIT,
248
        REQUESTHANDLED
249
    };
250
251
    class ConditionRep
252
        : public salhelper::Condition
253
    {
254
    public:
255
        ConditionRep(osl::Mutex& aMutex,Moderator& aModerator)
256
0
            : salhelper::Condition(aMutex),
257
0
              m_aModerator(aModerator)
258
0
        {
259
0
        }
260
261
    protected:
262
0
        bool applies() const override {
263
0
            return m_aModerator.m_aReplyType != NOREPLY;
264
0
        }
265
266
    private:
267
        Moderator& m_aModerator;
268
    };
269
270
    void setReply(ReplyType);
271
272
    void handle( const Reference<XInteractionRequest >& Request );
273
274
    void setStream(const Reference< XStream >& aStream);
275
    void setInputStream(const Reference<XInputStream> &rxInputStream);
276
277
protected:
278
    virtual void SAL_CALL run() override;
279
    virtual void SAL_CALL onTerminated() override;
280
281
private:
282
    osl::Mutex        m_aMutex;
283
284
    friend class ConditionRes;
285
286
    ConditionRes      m_aRes;
287
    ResultType        m_aResultType;
288
    IOErrorCode       m_nIOErrorCode;
289
    Any               m_aResult;
290
291
    friend class ConditionRep;
292
293
    ConditionRep      m_aRep;
294
    ReplyType         m_aReplyType;
295
296
    Command                           m_aArg;
297
    ::ucbhelper::Content              m_aContent;
298
};
299
300
class ModeratorsActiveDataStreamer
301
    : public ::cppu::WeakImplHelper<XActiveDataStreamer>
302
{
303
public:
304
305
    explicit ModeratorsActiveDataStreamer(Moderator &theModerator);
306
307
    // XActiveDataStreamer
308
    virtual void SAL_CALL
309
    setStream(
310
        const Reference< XStream >& aStream
311
    ) override;
312
313
    virtual Reference<XStream> SAL_CALL getStream () override
314
0
    {
315
0
        std::scoped_lock aGuard(m_aMutex);
316
0
        return m_xStream;
317
0
    }
318
319
private:
320
    Moderator& m_aModerator;
321
322
    std::mutex m_aMutex;
323
    Reference<XStream> m_xStream;
324
};
325
326
class ModeratorsActiveDataSink
327
    : public ::cppu::WeakImplHelper<XActiveDataSink>
328
{
329
public:
330
331
    explicit ModeratorsActiveDataSink(Moderator &theModerator);
332
333
    // XActiveDataSink.
334
    virtual void SAL_CALL
335
    setInputStream (
336
        const Reference<XInputStream> &rxInputStream
337
    ) override;
338
339
    virtual Reference<XInputStream> SAL_CALL getInputStream() override
340
0
    {
341
0
        std::scoped_lock aGuard(m_aMutex);
342
0
        return m_xStream;
343
0
    }
344
345
private:
346
    Moderator& m_aModerator;
347
    std::mutex m_aMutex;
348
    Reference<XInputStream> m_xStream;
349
};
350
351
}
352
353
ModeratorsActiveDataSink::ModeratorsActiveDataSink(Moderator &theModerator)
354
0
    : m_aModerator(theModerator)
355
0
{
356
0
}
357
358
// XActiveDataSink.
359
void SAL_CALL
360
ModeratorsActiveDataSink::setInputStream (
361
    const Reference<XInputStream> &rxInputStream
362
)
363
0
{
364
0
    m_aModerator.setInputStream(rxInputStream);
365
0
    std::scoped_lock aGuard(m_aMutex);
366
0
    m_xStream = rxInputStream;
367
0
}
368
369
ModeratorsActiveDataStreamer::ModeratorsActiveDataStreamer(
370
    Moderator &theModerator
371
)
372
0
    : m_aModerator(theModerator)
373
0
{
374
0
}
375
376
// XActiveDataStreamer.
377
void SAL_CALL
378
ModeratorsActiveDataStreamer::setStream (
379
    const Reference<XStream> &rxStream
380
)
381
0
{
382
0
    m_aModerator.setStream(rxStream);
383
0
    std::scoped_lock aGuard(m_aMutex);
384
0
    m_xStream = rxStream;
385
0
}
386
387
namespace {
388
389
class ModeratorsInteractionHandler
390
    : public ::cppu::WeakImplHelper<XInteractionHandler>
391
{
392
public:
393
394
    explicit ModeratorsInteractionHandler(Moderator &theModerator);
395
396
    virtual void SAL_CALL
397
    handle( const Reference<XInteractionRequest >& Request ) override;
398
399
private:
400
401
    Moderator& m_aModerator;
402
};
403
404
}
405
406
ModeratorsInteractionHandler::ModeratorsInteractionHandler(
407
    Moderator &aModerator)
408
0
    : m_aModerator(aModerator)
409
0
{
410
0
}
411
412
void SAL_CALL
413
ModeratorsInteractionHandler::handle(
414
    const Reference<XInteractionRequest >& Request
415
)
416
0
{
417
    // wakes up the mainthread
418
0
    m_aModerator.handle(Request);
419
0
}
420
421
Moderator::Moderator(
422
    Reference < XContent > const & xContent,
423
    Reference < XInteractionHandler > const & xInteract,
424
    Command aArg
425
)
426
0
    : m_aRes(m_aMutex,*this),
427
0
      m_aResultType(ResultType::NORESULT),
428
0
      m_nIOErrorCode(IOErrorCode_ABORT),
429
0
      m_aRep(m_aMutex,*this),
430
0
      m_aReplyType(NOREPLY),
431
0
      m_aArg(std::move(aArg)),
432
0
      m_aContent(
433
0
          xContent,
434
0
          new UcbTaskEnvironment(
435
0
              xInteract.is() ? new ModeratorsInteractionHandler(*this) : nullptr,
436
0
              nullptr),
437
0
          comphelper::getProcessComponentContext())
438
0
{
439
    // now exchange the whole data sink stuff
440
    // with a thread safe version
441
442
0
    Reference<XInterface> *pxSink = nullptr;
443
444
0
    PostCommandArgument2 aPostArg;
445
0
    OpenCommandArgument2 aOpenArg;
446
447
0
    int dec(2);
448
0
    if(m_aArg.Argument >>= aPostArg) {
449
0
        pxSink = &aPostArg.Sink;
450
0
        dec = 0;
451
0
    }
452
0
    else if(m_aArg.Argument >>= aOpenArg) {
453
0
        pxSink = &aOpenArg.Sink;
454
0
        dec = 1;
455
0
    }
456
457
0
    if(dec ==2)
458
0
        throw ContentCreationException();
459
460
0
    Reference < XActiveDataSink > xActiveSink(*pxSink,UNO_QUERY);
461
0
    if(xActiveSink.is())
462
0
        pxSink->set(getXWeak(new ModeratorsActiveDataSink(*this)));
463
464
0
    Reference<XActiveDataStreamer> xStreamer( *pxSink, UNO_QUERY );
465
0
    if ( xStreamer.is() )
466
0
        pxSink->set(getXWeak(new ModeratorsActiveDataStreamer(*this)));
467
468
0
    if(dec == 0)
469
0
        m_aArg.Argument <<= aPostArg;
470
0
    else if(dec == 1)
471
0
        m_aArg.Argument <<= aOpenArg;
472
0
}
473
474
Moderator::Result Moderator::getResult(const sal_uInt32 milliSec)
475
0
{
476
0
    Result ret;
477
0
    try {
478
0
        salhelper::ConditionWaiter aWaiter(m_aRes,milliSec);
479
0
        ret.type = m_aResultType;
480
0
        ret.result = m_aResult;
481
0
        ret.ioErrorCode = m_nIOErrorCode;
482
483
        // reset
484
0
        m_aResultType = ResultType::NORESULT;
485
0
    }
486
0
    catch (const salhelper::ConditionWaiter::timedout&)
487
0
    {
488
0
        ret.type = ResultType::TIMEDOUT;
489
0
    }
490
491
0
    return ret;
492
0
}
493
494
void Moderator::setReply(ReplyType aReplyType )
495
0
{
496
0
    salhelper::ConditionModifier aMod(m_aRep);
497
0
    m_aReplyType = aReplyType;
498
0
}
499
500
void Moderator::handle( const Reference<XInteractionRequest >& Request )
501
0
{
502
0
    ReplyType aReplyType;
503
504
0
    do {
505
0
        {
506
0
            salhelper::ConditionModifier aMod(m_aRes);
507
0
            m_aResultType = ResultType::INTERACTIONREQUEST;
508
0
            m_aResult <<= Request;
509
0
        }
510
511
0
        {
512
0
            salhelper::ConditionWaiter aWait(m_aRep);
513
0
            aReplyType = m_aReplyType;
514
515
            // reset
516
0
            m_aReplyType = NOREPLY;
517
0
        }
518
519
0
        if(aReplyType == EXIT) {
520
0
            const Sequence<Reference<XInteractionContinuation> > aSeq(
521
0
                Request->getContinuations());
522
0
            for(const auto& rContinuation : aSeq) {
523
0
                Reference<XInteractionAbort> aRef(rContinuation,UNO_QUERY);
524
0
                if(aRef.is()) {
525
0
                    aRef->select();
526
0
                }
527
0
            }
528
529
            // resignal the exit condition
530
0
            setReply(EXIT);
531
0
            break;
532
0
        }
533
0
    } while(aReplyType != REQUESTHANDLED);
534
0
}
535
536
void Moderator::setStream(const Reference< XStream >& aStream)
537
0
{
538
0
    {
539
0
        salhelper::ConditionModifier aMod(m_aRes);
540
0
        m_aResultType = ResultType::STREAM;
541
0
        m_aResult <<= aStream;
542
0
    }
543
0
    ReplyType aReplyType;
544
0
    {
545
0
        salhelper::ConditionWaiter aWait(m_aRep);
546
0
        aReplyType = m_aReplyType;
547
0
        m_aReplyType = NOREPLY;
548
0
    }
549
0
    if(aReplyType == EXIT)
550
0
        setReply(EXIT);
551
0
}
552
553
void Moderator::setInputStream(const Reference<XInputStream> &rxInputStream)
554
0
{
555
0
    {
556
0
        salhelper::ConditionModifier aMod(m_aRes);
557
0
        m_aResultType = ResultType::INPUTSTREAM;
558
0
        m_aResult <<= rxInputStream;
559
0
    }
560
0
    ReplyType aReplyType;
561
0
    {
562
0
        salhelper::ConditionWaiter aWait(m_aRep);
563
0
        aReplyType = m_aReplyType;
564
0
        m_aReplyType = NOREPLY;
565
0
    }
566
0
    if(aReplyType == EXIT)
567
0
        setReply(EXIT);
568
0
}
569
570
void SAL_CALL Moderator::run()
571
0
{
572
0
    osl_setThreadName("utl::Moderator");
573
574
0
    ResultType  aResultType;
575
0
    Any         aResult;
576
0
    IOErrorCode nIOErrorCode = IOErrorCode_ABORT;
577
578
0
    try
579
0
    {
580
0
        aResult = m_aContent.executeCommand(m_aArg.Name,m_aArg.Argument);
581
0
        aResultType = ResultType::RESULT;
582
0
    }
583
0
    catch (const CommandAbortedException&)
584
0
    {
585
0
        aResultType = ResultType::COMMANDABORTED;
586
0
    }
587
0
    catch (const CommandFailedException&)
588
0
    {
589
0
        aResultType = ResultType::COMMANDFAILED;
590
0
    }
591
0
    catch (const InteractiveIOException& r)
592
0
    {
593
0
        nIOErrorCode = r.Code;
594
0
        aResultType = ResultType::INTERACTIVEIO;
595
0
    }
596
0
    catch (const UnsupportedDataSinkException &)
597
0
    {
598
0
        aResultType = ResultType::UNSUPPORTED;
599
0
    }
600
0
    catch (const Exception&)
601
0
    {
602
0
        aResultType = ResultType::GENERAL;
603
0
    }
604
605
0
    {
606
0
        salhelper::ConditionModifier aMod(m_aRes);
607
0
        m_aResultType = aResultType;
608
0
        m_aResult = std::move(aResult);
609
0
        m_nIOErrorCode = nIOErrorCode;
610
0
    }
611
0
}
612
613
void SAL_CALL Moderator::onTerminated()
614
0
{
615
0
    {
616
0
        salhelper::ConditionWaiter aWaiter(m_aRep);
617
0
    }
618
0
    delete this;
619
0
}
620
621
/**
622
   Function for opening UCB contents synchronously,
623
   but with handled timeout;
624
*/
625
static bool UCBOpenContentSync_(
626
    const UcbLockBytesRef& xLockBytes,
627
    const Reference < XContent >& xContent,
628
    const Command& rArg,
629
    const Reference < XInterface >& xSink,
630
    const Reference < XInteractionHandler >& xInteract );
631
632
static bool UCBOpenContentSync(
633
    const UcbLockBytesRef& xLockBytes,
634
    Reference < XContent > const & xContent,
635
    const Command& rArg,
636
    const Reference < XInterface >& xSink,
637
    Reference < XInteractionHandler > const & xInteract )
638
41.8k
{
639
    // http protocol must be handled in a special way:
640
    //        during the opening process the input stream may change
641
    //        only the last inputstream after notifying the document
642
    //        headers is valid
643
644
41.8k
    Reference<XContentIdentifier> xContId(
645
41.8k
        xContent.is() ? xContent->getIdentifier() : nullptr );
646
647
41.8k
    OUString aScheme;
648
41.8k
    if(xContId.is())
649
41.8k
        aScheme = xContId->getContentProviderScheme();
650
651
    // now determine whether we use a timeout or not;
652
41.8k
    if( ! aScheme.equalsIgnoreAsciiCase("http")                &&
653
41.8k
        ! aScheme.equalsIgnoreAsciiCase("https")               &&
654
41.8k
        ! aScheme.equalsIgnoreAsciiCase("vnd.sun.star.webdav") &&
655
41.8k
        ! aScheme.equalsIgnoreAsciiCase("vnd.sun.star.webdavs") &&
656
41.8k
        ! aScheme.equalsIgnoreAsciiCase("ftp"))
657
41.8k
        return UCBOpenContentSync_(
658
41.8k
            xLockBytes,xContent,rArg,xSink,xInteract);
659
660
0
    if ( !aScheme.equalsIgnoreAsciiCase( "http" ) &&
661
0
         !aScheme.equalsIgnoreAsciiCase( "https" ) )
662
0
        xLockBytes->SetStreamValid();
663
664
0
    rtl::Reference< UcbPropertiesChangeListener_Impl > xListener;
665
0
    Reference< XPropertiesChangeNotifier > xProps(xContent,UNO_QUERY);
666
0
    if(xProps.is()) {
667
0
        xListener =
668
0
            new UcbPropertiesChangeListener_Impl(xLockBytes);
669
0
        xProps->addPropertiesChangeListener(
670
0
            Sequence< OUString >(),
671
0
            xListener);
672
0
    }
673
674
0
    bool bException(false);
675
0
    bool bAborted(false);
676
0
    bool bResultAchieved(false);
677
678
0
    Moderator* pMod = nullptr;
679
0
    try
680
0
    {
681
0
        pMod = new Moderator(xContent,xInteract,rArg);
682
0
        pMod->create();
683
            //TODO: a protocol is missing how to join with the launched thread before exit(3), to
684
            // ensure the thread is no longer relying on any infrastructure while that
685
            // infrastructure is being shut down in atexit handlers
686
0
    }
687
0
    catch (const ContentCreationException&)
688
0
    {
689
0
        bResultAchieved = bException = true;
690
0
        xLockBytes->SetError( ERRCODE_IO_GENERAL );
691
0
    }
692
693
0
    sal_uInt32 nTimeout(5000); // initially 5000 milliSec
694
0
    while(!bResultAchieved) {
695
696
        // try to get the result for with timeout
697
0
        Moderator::Result res = pMod->getResult(nTimeout);
698
699
0
        switch(res.type) {
700
0
        case Moderator::ResultType::STREAM:
701
0
            {
702
0
                Reference<XStream> result;
703
0
                if(res.result >>= result) {
704
0
                    Reference < XActiveDataStreamer > xStreamer(
705
0
                        xSink, UNO_QUERY
706
0
                    );
707
708
0
                    if(xStreamer.is())
709
0
                        xStreamer->setStream(result);
710
0
                }
711
0
                pMod->setReply(Moderator::REQUESTHANDLED);
712
0
                break;
713
0
            }
714
0
        case Moderator::ResultType::INPUTSTREAM:
715
0
            {
716
0
                Reference<XInputStream> result;
717
0
                res.result >>= result;
718
0
                Reference < XActiveDataSink > xActiveSink(
719
0
                    xSink, UNO_QUERY
720
0
                );
721
722
0
                if(xActiveSink.is())
723
0
                    xActiveSink->setInputStream(result);
724
0
                pMod->setReply(Moderator::REQUESTHANDLED);
725
0
                break;
726
0
            }
727
0
        case Moderator::ResultType::TIMEDOUT:
728
0
            {
729
0
                Reference<XInteractionRetry> xRet;
730
0
                if(xInteract.is()) {
731
0
                    INetURLObject aURL(
732
0
                        xContId.is() ?
733
0
                        xContId->getContentIdentifier() :
734
0
                        OUString() );
735
0
                    InteractiveNetworkConnectException aExcep(
736
0
                        u"server not responding after five seconds"_ustr, {},
737
0
                        InteractionClassification_ERROR, aURL.GetHost());
738
0
                    Any request;
739
0
                    request <<= aExcep;
740
0
                    rtl::Reference<ucbhelper::InteractionRequest> xIR =
741
0
                        new ucbhelper::InteractionRequest(request);
742
0
                    rtl::Reference<ucbhelper::InteractionRetry> retryP =
743
0
                        new ucbhelper::InteractionRetry(xIR.get());
744
0
                    rtl::Reference<ucbhelper::InteractionAbort> abortP =
745
0
                        new ucbhelper::InteractionAbort(xIR.get());
746
0
                    Sequence<Reference<XInteractionContinuation> > aSeq { retryP, abortP };
747
748
0
                    xIR->setContinuations(aSeq);
749
0
                    xInteract->handle(xIR);
750
0
                    rtl::Reference< ucbhelper::InteractionContinuation > ref
751
0
                        = xIR->getSelection();
752
0
                    if(ref.is()) {
753
0
                        xRet.set(ref->getXWeak(), UNO_QUERY);
754
0
                    }
755
0
                }
756
757
0
                if(!xRet.is()) {
758
0
                    bAborted = true;
759
0
                    xLockBytes->SetError(ERRCODE_ABORT);
760
0
                }
761
762
0
                break;
763
0
            }
764
0
        case Moderator::ResultType::INTERACTIONREQUEST:
765
0
            {
766
0
                Reference<XInteractionRequest> Request;
767
0
                res.result >>= Request;
768
0
                xInteract->handle(Request);
769
0
                pMod->setReply(Moderator::REQUESTHANDLED);
770
0
                break;
771
0
            }
772
0
        case Moderator::ResultType::RESULT:
773
0
            {
774
0
                bResultAchieved = true;
775
0
                break;
776
0
            }
777
0
        case Moderator::ResultType::COMMANDABORTED:
778
0
        case Moderator::ResultType::COMMANDFAILED:
779
0
            {
780
0
                bAborted = true;
781
0
                xLockBytes->SetError( ERRCODE_ABORT );
782
0
                break;
783
0
            }
784
0
        case Moderator::ResultType::INTERACTIVEIO:
785
0
            {
786
0
                bException = true;
787
0
                if ( res.ioErrorCode == IOErrorCode_ACCESS_DENIED ||
788
0
                     res.ioErrorCode == IOErrorCode_LOCKING_VIOLATION )
789
0
                    xLockBytes->SetError( ERRCODE_IO_ACCESSDENIED );
790
0
                else if ( res.ioErrorCode == IOErrorCode_NOT_EXISTING )
791
0
                    xLockBytes->SetError( ERRCODE_IO_NOTEXISTS );
792
0
                else if ( res.ioErrorCode == IOErrorCode_CANT_READ )
793
0
                    xLockBytes->SetError( ERRCODE_IO_CANTREAD );
794
0
                else
795
0
                    xLockBytes->SetError( ERRCODE_IO_GENERAL );
796
0
                break;
797
0
            }
798
0
        case Moderator::ResultType::UNSUPPORTED:
799
0
            {
800
0
                bException = true;
801
0
                xLockBytes->SetError( ERRCODE_IO_NOTSUPPORTED );
802
0
                break;
803
0
            }
804
0
        default:
805
0
            {
806
0
                bException = true;
807
0
                xLockBytes->SetError( ERRCODE_IO_GENERAL );
808
0
                break;
809
0
            }
810
0
        }
811
812
0
        bResultAchieved |= bException;
813
0
        bResultAchieved |= bAborted;
814
0
        if(nTimeout == 5000) nTimeout *= 2;
815
0
    }
816
817
0
    if(pMod) pMod->setReply(Moderator::EXIT);
818
819
0
    if ( bAborted || bException )
820
0
    {
821
0
        Reference < XActiveDataSink > xActiveSink( xSink, UNO_QUERY );
822
0
        if ( xActiveSink.is() )
823
0
            xActiveSink->setInputStream( Reference < XInputStream >() );
824
825
0
        Reference < XActiveDataStreamer > xStreamer( xSink, UNO_QUERY );
826
0
        if ( xStreamer.is() )
827
0
            xStreamer->setStream( Reference < XStream >() );
828
0
    }
829
830
0
    Reference < XActiveDataControl > xControl( xSink, UNO_QUERY );
831
0
    if ( xControl.is() )
832
0
        xControl->terminate();
833
834
0
    if ( xProps.is() )
835
0
        xProps->removePropertiesChangeListener(
836
0
            Sequence< OUString >(),
837
0
            xListener );
838
839
0
    return ( bAborted || bException );
840
0
}
841
842
/**
843
    Function for opening UCB contents synchronously
844
 */
845
static bool UCBOpenContentSync_(
846
    const UcbLockBytesRef& xLockBytes,
847
    const Reference < XContent >& xContent,
848
    const Command& rArg,
849
    const Reference < XInterface >& xSink,
850
    const Reference < XInteractionHandler >& xInteract )
851
41.8k
{
852
41.8k
    ::ucbhelper::Content aContent(
853
41.8k
        xContent, new UcbTaskEnvironment( xInteract, nullptr ),
854
41.8k
        comphelper::getProcessComponentContext() );
855
41.8k
    Reference < XContentIdentifier > xIdent = xContent->getIdentifier();
856
41.8k
    OUString aScheme = xIdent->getContentProviderScheme();
857
858
    // http protocol must be handled in a special way: during the opening process the input stream may change
859
    // only the last inputstream after notifying the document headers is valid
860
41.8k
    if ( !aScheme.equalsIgnoreAsciiCase("http") )
861
41.8k
        xLockBytes->SetStreamValid();
862
863
41.8k
    Reference< XPropertiesChangeListener > xListener = new UcbPropertiesChangeListener_Impl( xLockBytes );
864
41.8k
    Reference< XPropertiesChangeNotifier > xProps ( xContent, UNO_QUERY );
865
41.8k
    if ( xProps.is() )
866
41.8k
        xProps->addPropertiesChangeListener( Sequence< OUString >(), xListener );
867
868
41.8k
    bool bException = false;
869
41.8k
    bool bAborted = false;
870
871
41.8k
    try
872
41.8k
    {
873
41.8k
        aContent.executeCommand( rArg.Name, rArg.Argument );
874
41.8k
    }
875
41.8k
    catch (const CommandAbortedException&)
876
41.8k
    {
877
0
        bAborted = true;
878
0
        xLockBytes->SetError( ERRCODE_ABORT );
879
0
    }
880
41.8k
    catch (const CommandFailedException&)
881
41.8k
    {
882
0
        bAborted = true;
883
0
        xLockBytes->SetError( ERRCODE_ABORT );
884
0
    }
885
41.8k
    catch (const InteractiveIOException& r)
886
41.8k
    {
887
0
        bException = true;
888
0
        if ( r.Code == IOErrorCode_ACCESS_DENIED || r.Code == IOErrorCode_LOCKING_VIOLATION )
889
0
            xLockBytes->SetError( ERRCODE_IO_ACCESSDENIED );
890
0
        else if ( r.Code == IOErrorCode_NOT_EXISTING )
891
0
            xLockBytes->SetError( ERRCODE_IO_NOTEXISTS );
892
0
        else if ( r.Code == IOErrorCode_CANT_READ )
893
0
            xLockBytes->SetError( ERRCODE_IO_CANTREAD );
894
0
        else
895
0
            xLockBytes->SetError( ERRCODE_IO_GENERAL );
896
0
    }
897
41.8k
    catch (const UnsupportedDataSinkException&)
898
41.8k
    {
899
0
        bException = true;
900
0
        xLockBytes->SetError( ERRCODE_IO_NOTSUPPORTED );
901
0
    }
902
41.8k
    catch (const Exception&)
903
41.8k
    {
904
0
        bException = true;
905
0
        xLockBytes->SetError( ERRCODE_IO_GENERAL );
906
0
    }
907
908
41.8k
    if ( bAborted || bException )
909
0
    {
910
0
        Reference < XActiveDataSink > xActiveSink( xSink, UNO_QUERY );
911
0
        if ( xActiveSink.is() )
912
0
            xActiveSink->setInputStream( Reference < XInputStream >() );
913
914
0
        Reference < XActiveDataStreamer > xStreamer( xSink, UNO_QUERY );
915
0
        if ( xStreamer.is() )
916
0
            xStreamer->setStream( Reference < XStream >() );
917
0
    }
918
919
41.8k
    Reference < XActiveDataControl > xControl( xSink, UNO_QUERY );
920
41.8k
    if ( xControl.is() )
921
41.8k
        xControl->terminate();
922
923
41.8k
    if ( xProps.is() )
924
41.8k
        xProps->removePropertiesChangeListener( Sequence< OUString >(), xListener );
925
926
41.8k
    return ( bAborted || bException );
927
41.8k
}
928
929
UcbLockBytes::UcbLockBytes()
930
144k
    : m_nError( ERRCODE_NONE )
931
144k
    , m_bTerminated  (false)
932
144k
    , m_bDontClose( false )
933
144k
    , m_bStreamValid  (false)
934
144k
{
935
144k
    SetSynchronMode();
936
144k
}
937
938
UcbLockBytes::~UcbLockBytes()
939
144k
{
940
144k
    if ( !m_bDontClose )
941
0
    {
942
0
        if ( m_xInputStream.is() )
943
0
        {
944
0
            try
945
0
            {
946
0
                m_xInputStream->closeInput();
947
0
            }
948
0
            catch (const RuntimeException&)
949
0
            {
950
0
            }
951
0
            catch (const IOException&)
952
0
            {
953
0
            }
954
0
        }
955
0
    }
956
957
144k
    if ( m_xInputStream.is() || !m_xOutputStream.is() )
958
144k
        return;
959
960
0
    try
961
0
    {
962
0
        m_xOutputStream->closeOutput();
963
0
    }
964
0
    catch (const RuntimeException&)
965
0
    {
966
0
    }
967
0
    catch (const IOException&)
968
0
    {
969
0
    }
970
0
}
971
972
Reference < XInputStream > UcbLockBytes::getInputStream()
973
41.8k
{
974
41.8k
    std::unique_lock aGuard( m_aMutex );
975
41.8k
    m_bDontClose = true;
976
41.8k
    return m_xInputStream;
977
41.8k
}
978
979
void UcbLockBytes::setStream( const Reference<XStream>& aStream )
980
95.1k
{
981
95.1k
    std::unique_lock aGuard( m_aMutex );
982
95.1k
    if ( aStream.is() )
983
95.1k
    {
984
95.1k
        m_xOutputStream = aStream->getOutputStream();
985
95.1k
        setInputStreamImpl( aGuard, aStream->getInputStream(), false );
986
95.1k
        m_xSeekable.set( aStream, UNO_QUERY );
987
95.1k
    }
988
0
    else
989
0
    {
990
0
        m_xOutputStream.clear();
991
0
        setInputStreamImpl( aGuard, Reference < XInputStream >() );
992
0
    }
993
95.1k
}
994
995
bool UcbLockBytes::setInputStream( const Reference<XInputStream> &rxInputStream )
996
49.2k
{
997
49.2k
    std::unique_lock aGuard( m_aMutex );
998
49.2k
    return setInputStreamImpl(aGuard, rxInputStream, /*bSetXSeekable*/true);
999
49.2k
}
1000
1001
bool UcbLockBytes::setInputStreamImpl( std::unique_lock<std::mutex>& /*rGuard*/, const Reference<XInputStream> &rxInputStream, bool bSetXSeekable )
1002
144k
{
1003
144k
    bool bRet = false;
1004
1005
144k
    try
1006
144k
    {
1007
144k
        if ( !m_bDontClose && m_xInputStream.is() )
1008
0
            m_xInputStream->closeInput();
1009
1010
144k
        m_xInputStream = rxInputStream;
1011
1012
144k
        if( bSetXSeekable )
1013
49.2k
        {
1014
49.2k
            m_xSeekable.set( rxInputStream, UNO_QUERY );
1015
49.2k
            if( !m_xSeekable.is() && rxInputStream.is() )
1016
15.1k
            {
1017
15.1k
                rtl::Reference< utl::TempFileFastService > rxTempOut( new utl::TempFileFastService );
1018
15.1k
                ::comphelper::OStorageHelper::CopyInputToOutput( rxInputStream, rxTempOut );
1019
15.1k
                m_xInputStream.set( rxTempOut );
1020
15.1k
                m_xSeekable.set( rxTempOut );
1021
15.1k
            }
1022
49.2k
        }
1023
1024
144k
        bRet = m_xInputStream.is();
1025
144k
    }
1026
144k
    catch (const Exception&)
1027
144k
    {
1028
33
    }
1029
1030
144k
    if ( m_bStreamValid && m_xInputStream.is() )
1031
41.8k
        m_aInitialized.set();
1032
1033
144k
    return bRet;
1034
144k
}
1035
1036
void UcbLockBytes::SetStreamValid()
1037
41.8k
{
1038
41.8k
    m_bStreamValid = true;
1039
41.8k
    if ( m_xInputStream.is() )
1040
0
        m_aInitialized.set();
1041
41.8k
}
1042
1043
void UcbLockBytes::terminate()
1044
144k
{
1045
144k
    m_bTerminated = true;
1046
144k
    m_aInitialized.set();
1047
144k
    m_aTerminated.set();
1048
1049
144k
    if ( GetError() == ERRCODE_NONE && !m_xInputStream.is() )
1050
0
    {
1051
0
        OSL_FAIL("No InputStream, but no error set!" );
1052
0
        SetError( ERRCODE_IO_NOTEXISTS );
1053
0
    }
1054
144k
}
1055
1056
ErrCode UcbLockBytes::ReadAt(sal_uInt64 const nPos,
1057
        void *pBuffer, std::size_t nCount, std::size_t *pRead) const
1058
40.1M
{
1059
40.1M
    if ( IsSynchronMode() )
1060
40.1M
    {
1061
40.1M
        UcbLockBytes* pThis = const_cast < UcbLockBytes* >( this );
1062
40.1M
        pThis->m_aInitialized.wait();
1063
40.1M
    }
1064
1065
40.1M
    Reference <XInputStream> xStream = getInputStream();
1066
40.1M
    if ( !xStream.is() )
1067
0
    {
1068
0
        if ( m_bTerminated )
1069
0
            return ERRCODE_IO_CANTREAD;
1070
0
        else
1071
0
            return ERRCODE_IO_PENDING;
1072
0
    }
1073
1074
40.1M
    if ( pRead )
1075
40.1M
        *pRead = 0;
1076
1077
40.1M
    Reference <XSeekable> xSeekable = getSeekable();
1078
40.1M
    if ( !xSeekable.is() )
1079
0
        return ERRCODE_IO_CANTREAD;
1080
1081
40.1M
    try
1082
40.1M
    {
1083
40.1M
        xSeekable->seek( nPos );
1084
40.1M
    }
1085
40.1M
    catch (const IOException&)
1086
40.1M
    {
1087
0
        return ERRCODE_IO_CANTSEEK;
1088
0
    }
1089
40.1M
    catch (const css::lang::IllegalArgumentException&)
1090
40.1M
    {
1091
791
        return ERRCODE_IO_CANTSEEK;
1092
791
    }
1093
1094
40.1M
    sal_Int32          nSize;
1095
1096
40.1M
    if(nCount > 0x7FFFFFFF)
1097
0
    {
1098
0
        nCount = 0x7FFFFFFF;
1099
0
    }
1100
40.1M
    try
1101
40.1M
    {
1102
40.1M
        if ( !m_bTerminated && !IsSynchronMode() )
1103
0
        {
1104
0
            sal_uInt64 nLen = xSeekable->getLength();
1105
0
            if ( nPos + nCount > nLen )
1106
0
                return ERRCODE_IO_PENDING;
1107
0
        }
1108
1109
40.1M
        comphelper::ByteReader* pByteReader = dynamic_cast< comphelper::ByteReader* >(xStream.get());
1110
40.1M
        if (pByteReader)
1111
40.1M
        {
1112
40.1M
            nSize = pByteReader->readSomeBytes( static_cast<sal_Int8*>(pBuffer), sal_Int32(nCount) );
1113
40.1M
        }
1114
0
        else
1115
0
        {
1116
0
            Sequence<sal_Int8> aData;
1117
0
            nSize = xStream->readBytes( aData, sal_Int32(nCount) );
1118
0
            memcpy (pBuffer, aData.getConstArray(), nSize);
1119
0
        }
1120
40.1M
    }
1121
40.1M
    catch (const IOException&)
1122
40.1M
    {
1123
0
        return ERRCODE_IO_CANTREAD;
1124
0
    }
1125
1126
40.1M
    if (pRead)
1127
40.1M
        *pRead = static_cast<std::size_t>(nSize);
1128
1129
40.1M
    return ERRCODE_NONE;
1130
40.1M
}
1131
1132
ErrCode UcbLockBytes::WriteAt(sal_uInt64 const nPos, const void *pBuffer,
1133
        std::size_t nCount, std::size_t *pWritten)
1134
279k
{
1135
279k
    if ( pWritten )
1136
279k
        *pWritten = 0;
1137
1138
279k
    DBG_ASSERT( IsSynchronMode(), "Writing is only possible in SynchronMode!" );
1139
279k
    DBG_ASSERT( m_aInitialized.check(), "Writing bevor stream is ready!" );
1140
1141
279k
    Reference <XSeekable> xSeekable = getSeekable();
1142
279k
    Reference <XOutputStream> xOutputStream = getOutputStream();
1143
279k
    if ( !xOutputStream.is() || !xSeekable.is() )
1144
0
        return ERRCODE_IO_CANTWRITE;
1145
1146
279k
    try
1147
279k
    {
1148
279k
        xSeekable->seek( nPos );
1149
279k
    }
1150
279k
    catch (const IOException&)
1151
279k
    {
1152
0
        return ERRCODE_IO_CANTSEEK;
1153
0
    }
1154
1155
279k
    sal_Int8 const * pData = static_cast<sal_Int8 const *>(pBuffer);
1156
279k
    Sequence<sal_Int8> aData( pData, nCount );
1157
279k
    try
1158
279k
    {
1159
279k
        xOutputStream->writeBytes( aData );
1160
279k
        if ( pWritten )
1161
279k
            *pWritten = nCount;
1162
279k
    }
1163
279k
    catch (const Exception&)
1164
279k
    {
1165
0
        return ERRCODE_IO_CANTWRITE;
1166
0
    }
1167
1168
279k
    return ERRCODE_NONE;
1169
279k
}
1170
1171
ErrCode UcbLockBytes::Flush() const
1172
246k
{
1173
246k
    Reference <XOutputStream > xOutputStream = getOutputStream();
1174
246k
    if ( !xOutputStream.is() )
1175
41.0k
        return ERRCODE_IO_CANTWRITE;
1176
1177
205k
    try
1178
205k
    {
1179
205k
        xOutputStream->flush();
1180
205k
    }
1181
205k
    catch (const Exception&)
1182
205k
    {
1183
0
        return ERRCODE_IO_CANTWRITE;
1184
0
    }
1185
1186
205k
    return ERRCODE_NONE;
1187
205k
}
1188
1189
ErrCode UcbLockBytes::SetSize (sal_uInt64 const nNewSize)
1190
71.9k
{
1191
71.9k
    SvLockBytesStat aStat;
1192
71.9k
    Stat( &aStat );
1193
71.9k
    std::size_t nSize = aStat.nSize;
1194
1195
71.9k
    if ( nSize > nNewSize )
1196
0
    {
1197
0
        Reference < XTruncate > xTrunc( getOutputStream(), UNO_QUERY );
1198
0
        if ( xTrunc.is() )
1199
0
        {
1200
0
            xTrunc->truncate();
1201
0
            nSize = 0;
1202
0
        }
1203
0
        else {
1204
0
            SAL_INFO("unotools.ucbhelper", "Not truncable!");
1205
0
        }
1206
0
    }
1207
1208
71.9k
    if ( nSize < nNewSize )
1209
71.9k
    {
1210
71.9k
        std::size_t nDiff = nNewSize-nSize, nCount=0;
1211
71.9k
        std::unique_ptr<sal_uInt8[]> pBuffer(new sal_uInt8[ nDiff ]);
1212
71.9k
        memset(pBuffer.get(), 0, nDiff); // initialize for enhanced security
1213
71.9k
        WriteAt( nSize, pBuffer.get(), nDiff, &nCount );
1214
71.9k
        if ( nCount != nDiff )
1215
0
            return ERRCODE_IO_CANTWRITE;
1216
71.9k
    }
1217
1218
71.9k
    return ERRCODE_NONE;
1219
71.9k
}
1220
1221
ErrCode UcbLockBytes::Stat( SvLockBytesStat *pStat ) const
1222
3.51M
{
1223
3.51M
    if ( IsSynchronMode() )
1224
3.51M
    {
1225
3.51M
        UcbLockBytes* pThis = const_cast < UcbLockBytes* >( this );
1226
3.51M
        pThis->m_aInitialized.wait();
1227
3.51M
    }
1228
1229
3.51M
    if (!pStat)
1230
0
        return ERRCODE_IO_INVALIDPARAMETER;
1231
1232
3.51M
    Reference <XInputStream> xStream = getInputStream();
1233
3.51M
    Reference <XSeekable> xSeekable = getSeekable();
1234
1235
3.51M
    if ( !xStream.is() )
1236
0
    {
1237
0
        if ( m_bTerminated )
1238
0
            return ERRCODE_IO_INVALIDACCESS;
1239
0
        else
1240
0
            return ERRCODE_IO_PENDING;
1241
0
    }
1242
3.51M
    else if( !xSeekable.is() )
1243
128
        return ERRCODE_IO_CANTTELL;
1244
1245
3.51M
    try
1246
3.51M
    {
1247
3.51M
        pStat->nSize = xSeekable->getLength();
1248
3.51M
    }
1249
3.51M
    catch (const IOException&)
1250
3.51M
    {
1251
0
        return ERRCODE_IO_CANTTELL;
1252
0
    }
1253
1254
3.51M
    return ERRCODE_NONE;
1255
3.51M
}
1256
1257
UcbLockBytesRef UcbLockBytes::CreateInputLockBytes( const Reference< XInputStream >& xInputStream )
1258
45.9k
{
1259
45.9k
    if( !xInputStream.is() )
1260
0
        return nullptr;
1261
1262
45.9k
    UcbLockBytesRef xLockBytes = new UcbLockBytes;
1263
45.9k
    xLockBytes->setDontClose();
1264
45.9k
    xLockBytes->setInputStream( xInputStream );
1265
45.9k
    xLockBytes->terminate();
1266
45.9k
    return xLockBytes;
1267
45.9k
}
1268
1269
UcbLockBytesRef UcbLockBytes::CreateLockBytes( const Reference< XStream >& xStream )
1270
56.6k
{
1271
56.6k
    if( !xStream.is() )
1272
0
        return nullptr;
1273
1274
56.6k
    UcbLockBytesRef xLockBytes = new UcbLockBytes;
1275
56.6k
    xLockBytes->setDontClose();
1276
56.6k
    xLockBytes->setStream( xStream );
1277
56.6k
    xLockBytes->terminate();
1278
56.6k
    return xLockBytes;
1279
56.6k
}
1280
1281
UcbLockBytesRef UcbLockBytes::CreateLockBytes( const Reference < XContent >& xContent, const Sequence < PropertyValue >& rProps,
1282
        StreamMode eOpenMode, const Reference < XInteractionHandler >& xInteractionHandler )
1283
41.8k
{
1284
41.8k
    if( !xContent.is() )
1285
0
        return nullptr;
1286
1287
41.8k
    UcbLockBytesRef xLockBytes = new UcbLockBytes;
1288
41.8k
    xLockBytes->SetSynchronMode();
1289
41.8k
    Reference< XActiveDataControl > xSink;
1290
41.8k
    if ( eOpenMode & StreamMode::WRITE )
1291
38.5k
        xSink = new UcbStreamer_Impl(xLockBytes.get());
1292
3.28k
    else
1293
3.28k
        xSink = new UcbDataSink_Impl(xLockBytes.get());
1294
1295
41.8k
    if ( rProps.hasElements() )
1296
0
    {
1297
0
        Reference < XCommandProcessor > xProcessor( xContent, UNO_QUERY );
1298
0
        Command aCommand;
1299
0
        aCommand.Name     = "setPropertyValues";
1300
0
        aCommand.Handle   = -1; /* unknown */
1301
0
        aCommand.Argument <<= rProps;
1302
0
        xProcessor->execute( aCommand, 0, Reference < XCommandEnvironment >() );
1303
0
    }
1304
1305
41.8k
    OpenCommandArgument2 aArgument;
1306
41.8k
    aArgument.Sink = xSink;
1307
41.8k
    aArgument.Mode = OpenMode::DOCUMENT;
1308
1309
41.8k
    Command aCommand;
1310
41.8k
    aCommand.Name = "open";
1311
41.8k
    aCommand.Argument <<= aArgument;
1312
1313
41.8k
    bool bError = UCBOpenContentSync( xLockBytes,
1314
41.8k
                                      xContent,
1315
41.8k
                                      aCommand,
1316
41.8k
                                      xSink,
1317
41.8k
                                      xInteractionHandler );
1318
1319
41.8k
    if ( xLockBytes->GetError() == ERRCODE_NONE && ( bError || !xLockBytes->getInputStream().is() ) )
1320
0
    {
1321
0
        OSL_FAIL("No InputStream, but no error set!" );
1322
0
        xLockBytes->SetError( ERRCODE_IO_GENERAL );
1323
0
    }
1324
1325
41.8k
    return xLockBytes;
1326
41.8k
}
1327
1328
}
1329
1330
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */