1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include "ucblockbytes.hxx"
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/task/XInteractionAbort.hpp>
31 #include <com/sun/star/ucb/InteractiveNetworkConnectException.hpp>
32 #include <com/sun/star/ucb/CommandFailedException.hpp>
33 #include <com/sun/star/ucb/ContentCreationException.hpp>
34 #include <com/sun/star/ucb/CommandAbortedException.hpp>
35 #include <com/sun/star/ucb/UnsupportedDataSinkException.hpp>
36 #include <com/sun/star/ucb/InteractiveIOException.hpp>
37 #include <com/sun/star/ucb/XContentIdentifier.hpp>
38 #include <com/sun/star/ucb/XContent.hpp>
39 #include <com/sun/star/io/IOException.hpp>
40 #include <com/sun/star/io/XActiveDataStreamer.hpp>
41 #include <com/sun/star/io/TempFile.hpp>
42 #include <com/sun/star/ucb/XCommandProcessor.hpp>
43 #include <com/sun/star/task/XInteractionHandler.hpp>
44 #include <com/sun/star/ucb/OpenCommandArgument2.hpp>
45 #include <com/sun/star/ucb/PostCommandArgument2.hpp>
46 #include <com/sun/star/ucb/OpenMode.hpp>
47 #include <com/sun/star/beans/PropertyValue.hpp>
48 #include <com/sun/star/beans/XPropertiesChangeNotifier.hpp>
49 #include <com/sun/star/beans/XPropertiesChangeListener.hpp>
50 #include <com/sun/star/io/XActiveDataSink.hpp>
51 #include <com/sun/star/io/XActiveDataControl.hpp>
52 #include <com/sun/star/io/XSeekable.hpp>
53 #include <cppuhelper/implbase.hxx>
54 #include <tools/debug.hxx>
55 #include <com/sun/star/io/XTruncate.hpp>
56 #include <com/sun/star/lang/IllegalArgumentException.hpp>
58 #include <comphelper/storagehelper.hxx>
59 #include <ucbhelper/content.hxx>
61 using namespace ::com::sun::star::uno
;
62 using namespace ::com::sun::star::io
;
63 using namespace ::com::sun::star::ucb
;
64 using namespace ::com::sun::star::task
;
65 using namespace ::com::sun::star::lang
;
66 using namespace ::com::sun::star::beans
;
72 Helper class for getting a XInputStream when opening a content
74 class UcbDataSink_Impl
: public ::cppu::WeakImplHelper
< XActiveDataControl
, XActiveDataSink
>
76 UcbLockBytesRef m_xLockBytes
;
79 explicit UcbDataSink_Impl( UcbLockBytes
* pLockBytes
)
80 : m_xLockBytes( pLockBytes
)
83 // XActiveDataControl.
84 virtual void SAL_CALL
addListener ( const Reference
<XStreamListener
> &/*rxListener*/) override
{}
85 virtual void SAL_CALL
removeListener ( const Reference
<XStreamListener
> &/*rxListener*/) override
{}
86 virtual void SAL_CALL
start() override
{}
87 virtual void SAL_CALL
terminate() override
88 { m_xLockBytes
->terminate_Impl(); }
91 virtual void SAL_CALL
setInputStream ( const Reference
<XInputStream
> &rxInputStream
) override
92 { m_xLockBytes
->setInputStream_Impl (rxInputStream
); }
93 virtual Reference
<XInputStream
> SAL_CALL
getInputStream() override
94 { return m_xLockBytes
->getInputStream_Impl(); }
98 Helper class for getting a XStream when opening a content
100 class UcbStreamer_Impl
: public ::cppu::WeakImplHelper
< XActiveDataStreamer
, XActiveDataControl
>
102 Reference
< XStream
> m_xStream
;
103 UcbLockBytesRef m_xLockBytes
;
106 explicit UcbStreamer_Impl( UcbLockBytes
* pLockBytes
)
107 : m_xLockBytes( pLockBytes
)
110 // XActiveDataControl.
111 virtual void SAL_CALL
addListener ( const Reference
<XStreamListener
> &/*rxListener*/) override
{}
112 virtual void SAL_CALL
removeListener ( const Reference
<XStreamListener
> &/*rxListener*/) override
{}
113 virtual void SAL_CALL
start() override
{}
114 virtual void SAL_CALL
terminate() override
115 { m_xLockBytes
->terminate_Impl(); }
117 // XActiveDataStreamer
118 virtual void SAL_CALL
setStream( const Reference
< XStream
>& aStream
) override
119 { m_xStream
= aStream
; m_xLockBytes
->setStream_Impl( aStream
); }
120 virtual Reference
< XStream
> SAL_CALL
getStream() override
121 { return m_xStream
; }
125 Helper class for managing interactions and progress when executing UCB commands
127 class UcbTaskEnvironment
: public ::cppu::WeakImplHelper
< XCommandEnvironment
>
129 Reference
< XInteractionHandler
> m_xInteractionHandler
;
130 Reference
< XProgressHandler
> m_xProgressHandler
;
133 UcbTaskEnvironment( const Reference
< XInteractionHandler
>& rxInteractionHandler
,
134 const Reference
< XProgressHandler
>& rxProgressHandler
)
135 : m_xInteractionHandler( rxInteractionHandler
)
136 , m_xProgressHandler( rxProgressHandler
)
139 virtual Reference
<XInteractionHandler
> SAL_CALL
getInteractionHandler() override
140 { return m_xInteractionHandler
; }
142 virtual Reference
<XProgressHandler
> SAL_CALL
getProgressHandler() override
143 { return m_xProgressHandler
; }
147 Helper class for property change notifies when executing UCB commands
149 class UcbPropertiesChangeListener_Impl
: public ::cppu::WeakImplHelper
< XPropertiesChangeListener
>
152 UcbLockBytesRef m_xLockBytes
;
154 explicit UcbPropertiesChangeListener_Impl( UcbLockBytesRef
const & rRef
)
155 : m_xLockBytes( rRef
)
158 virtual void SAL_CALL
disposing ( const EventObject
&/*rEvent*/) override
{}
159 virtual void SAL_CALL
propertiesChange ( const Sequence
<PropertyChangeEvent
> &rEvent
) override
;
162 void SAL_CALL
UcbPropertiesChangeListener_Impl::propertiesChange ( const Sequence
<PropertyChangeEvent
> &rEvent
)
164 for (const auto& rPropChangeEvent
: rEvent
)
166 if (rPropChangeEvent
.PropertyName
== "DocumentHeader")
168 m_xLockBytes
->SetStreamValid_Impl();
176 // usage restriction:
177 // It might be possible, that the call to the interactionhandler and/or
178 // progresshandler is done asynchronously, while the 'execute' simply
179 // returns. This would imply that these class must be refcounted!!!
182 /// @throws ContentCreationException
183 /// @throws RuntimeException
185 Reference
< XContent
> const & xContent
,
186 Reference
< XInteractionHandler
> const & xInteract
,
190 enum class ResultType
{
193 INTERACTIONREQUEST
, // reply expected
208 : public salhelper::Condition
211 ConditionRes(osl::Mutex
& aMutex
,Moderator
& aModerator
)
212 : salhelper::Condition(aMutex
),
213 m_aModerator(aModerator
)
218 bool applies() const override
{
219 return m_aModerator
.m_aResultType
!= ResultType::NORESULT
;
223 Moderator
& m_aModerator
;
229 IOErrorCode ioErrorCode
;
232 Result
getResult(const sal_uInt32 milliSec
);
241 : public salhelper::Condition
244 ConditionRep(osl::Mutex
& aMutex
,Moderator
& aModerator
)
245 : salhelper::Condition(aMutex
),
246 m_aModerator(aModerator
)
251 bool applies() const override
{
252 return m_aModerator
.m_aReplyType
!= NOREPLY
;
256 Moderator
& m_aModerator
;
259 void setReply(ReplyType
);
261 void handle( const Reference
<XInteractionRequest
>& Request
);
263 void setStream(const Reference
< XStream
>& aStream
);
264 void setInputStream(const Reference
<XInputStream
> &rxInputStream
);
267 virtual void SAL_CALL
run() override
;
268 virtual void SAL_CALL
onTerminated() override
;
273 friend class ConditionRes
;
276 ResultType m_aResultType
;
277 IOErrorCode m_nIOErrorCode
;
280 friend class ConditionRep
;
283 ReplyType m_aReplyType
;
286 ::ucbhelper::Content m_aContent
;
289 class ModeratorsActiveDataStreamer
290 : public ::cppu::WeakImplHelper
<XActiveDataStreamer
>
294 explicit ModeratorsActiveDataStreamer(Moderator
&theModerator
);
296 // XActiveDataStreamer
297 virtual void SAL_CALL
299 const Reference
< XStream
>& aStream
302 virtual Reference
<XStream
> SAL_CALL
getStream () override
304 osl::MutexGuard
aGuard(m_aMutex
);
309 Moderator
& m_aModerator
;
312 Reference
<XStream
> m_xStream
;
315 class ModeratorsActiveDataSink
316 : public ::cppu::WeakImplHelper
<XActiveDataSink
>
320 explicit ModeratorsActiveDataSink(Moderator
&theModerator
);
323 virtual void SAL_CALL
325 const Reference
<XInputStream
> &rxInputStream
328 virtual Reference
<XInputStream
> SAL_CALL
getInputStream() override
330 osl::MutexGuard
aGuard(m_aMutex
);
335 Moderator
& m_aModerator
;
337 Reference
<XInputStream
> m_xStream
;
340 ModeratorsActiveDataSink::ModeratorsActiveDataSink(Moderator
&theModerator
)
341 : m_aModerator(theModerator
)
347 ModeratorsActiveDataSink::setInputStream (
348 const Reference
<XInputStream
> &rxInputStream
351 m_aModerator
.setInputStream(rxInputStream
);
352 osl::MutexGuard
aGuard(m_aMutex
);
353 m_xStream
= rxInputStream
;
356 ModeratorsActiveDataStreamer::ModeratorsActiveDataStreamer(
357 Moderator
&theModerator
359 : m_aModerator(theModerator
)
363 // XActiveDataStreamer.
365 ModeratorsActiveDataStreamer::setStream (
366 const Reference
<XStream
> &rxStream
369 m_aModerator
.setStream(rxStream
);
370 osl::MutexGuard
aGuard(m_aMutex
);
371 m_xStream
= rxStream
;
374 class ModeratorsInteractionHandler
375 : public ::cppu::WeakImplHelper
<XInteractionHandler
>
379 explicit ModeratorsInteractionHandler(Moderator
&theModerator
);
381 virtual void SAL_CALL
382 handle( const Reference
<XInteractionRequest
>& Request
) override
;
386 Moderator
& m_aModerator
;
389 ModeratorsInteractionHandler::ModeratorsInteractionHandler(
390 Moderator
&aModerator
)
391 : m_aModerator(aModerator
)
396 ModeratorsInteractionHandler::handle(
397 const Reference
<XInteractionRequest
>& Request
400 // wakes up the mainthread
401 m_aModerator
.handle(Request
);
404 Moderator::Moderator(
405 Reference
< XContent
> const & xContent
,
406 Reference
< XInteractionHandler
> const & xInteract
,
411 m_aRes(m_aMutex
,*this),
412 m_aResultType(ResultType::NORESULT
),
413 m_nIOErrorCode(IOErrorCode_ABORT
),
416 m_aRep(m_aMutex
,*this),
417 m_aReplyType(NOREPLY
),
422 new UcbTaskEnvironment(
423 xInteract
.is() ? new ModeratorsInteractionHandler(*this) : nullptr,
425 comphelper::getProcessComponentContext())
427 // now exchange the whole data sink stuff
428 // with a thread safe version
430 Reference
<XInterface
> *pxSink
= nullptr;
432 PostCommandArgument2 aPostArg
;
433 OpenCommandArgument2 aOpenArg
;
436 if(m_aArg
.Argument
>>= aPostArg
) {
437 pxSink
= &aPostArg
.Sink
;
440 else if(m_aArg
.Argument
>>= aOpenArg
) {
441 pxSink
= &aOpenArg
.Sink
;
446 throw ContentCreationException();
448 Reference
< XActiveDataSink
> xActiveSink(*pxSink
,UNO_QUERY
);
450 pxSink
->set( static_cast<cppu::OWeakObject
*>(new ModeratorsActiveDataSink(*this)));
452 Reference
<XActiveDataStreamer
> xStreamer( *pxSink
, UNO_QUERY
);
453 if ( xStreamer
.is() )
454 pxSink
->set( static_cast<cppu::OWeakObject
*>(new ModeratorsActiveDataStreamer(*this)));
457 m_aArg
.Argument
<<= aPostArg
;
459 m_aArg
.Argument
<<= aOpenArg
;
462 Moderator::Result
Moderator::getResult(const sal_uInt32 milliSec
)
466 salhelper::ConditionWaiter
aWaiter(m_aRes
,milliSec
);
467 ret
.type
= m_aResultType
;
468 ret
.result
= m_aResult
;
469 ret
.ioErrorCode
= m_nIOErrorCode
;
472 m_aResultType
= ResultType::NORESULT
;
474 catch (const salhelper::ConditionWaiter::timedout
&)
476 ret
.type
= ResultType::TIMEDOUT
;
482 void Moderator::setReply(ReplyType aReplyType
)
484 salhelper::ConditionModifier
aMod(m_aRep
);
485 m_aReplyType
= aReplyType
;
488 void Moderator::handle( const Reference
<XInteractionRequest
>& Request
)
490 ReplyType aReplyType
;
494 salhelper::ConditionModifier
aMod(m_aRes
);
495 m_aResultType
= ResultType::INTERACTIONREQUEST
;
496 m_aResult
<<= Request
;
500 salhelper::ConditionWaiter
aWait(m_aRep
);
501 aReplyType
= m_aReplyType
;
504 m_aReplyType
= NOREPLY
;
507 if(aReplyType
== EXIT
) {
508 const Sequence
<Reference
<XInteractionContinuation
> > aSeq(
509 Request
->getContinuations());
510 for(const auto& rContinuation
: aSeq
) {
511 Reference
<XInteractionAbort
> aRef(rContinuation
,UNO_QUERY
);
517 // resignal the exit condition
521 } while(aReplyType
!= REQUESTHANDLED
);
524 void Moderator::setStream(const Reference
< XStream
>& aStream
)
527 salhelper::ConditionModifier
aMod(m_aRes
);
528 m_aResultType
= ResultType::STREAM
;
529 m_aResult
<<= aStream
;
531 ReplyType aReplyType
;
533 salhelper::ConditionWaiter
aWait(m_aRep
);
534 aReplyType
= m_aReplyType
;
535 m_aReplyType
= NOREPLY
;
537 if(aReplyType
== EXIT
)
541 void Moderator::setInputStream(const Reference
<XInputStream
> &rxInputStream
)
544 salhelper::ConditionModifier
aMod(m_aRes
);
545 m_aResultType
= ResultType::INPUTSTREAM
;
546 m_aResult
<<= rxInputStream
;
548 ReplyType aReplyType
;
550 salhelper::ConditionWaiter
aWait(m_aRep
);
551 aReplyType
= m_aReplyType
;
552 m_aReplyType
= NOREPLY
;
554 if(aReplyType
== EXIT
)
558 void SAL_CALL
Moderator::run()
560 osl_setThreadName("utl::Moderator");
562 ResultType aResultType
;
564 IOErrorCode nIOErrorCode
= IOErrorCode_ABORT
;
568 aResult
= m_aContent
.executeCommand(m_aArg
.Name
,m_aArg
.Argument
);
569 aResultType
= ResultType::RESULT
;
571 catch (const CommandAbortedException
&)
573 aResultType
= ResultType::COMMANDABORTED
;
575 catch (const CommandFailedException
&)
577 aResultType
= ResultType::COMMANDFAILED
;
579 catch (const InteractiveIOException
& r
)
581 nIOErrorCode
= r
.Code
;
582 aResultType
= ResultType::INTERACTIVEIO
;
584 catch (const UnsupportedDataSinkException
&)
586 aResultType
= ResultType::UNSUPPORTED
;
588 catch (const Exception
&)
590 aResultType
= ResultType::GENERAL
;
594 salhelper::ConditionModifier
aMod(m_aRes
);
595 m_aResultType
= aResultType
;
597 m_nIOErrorCode
= nIOErrorCode
;
601 void SAL_CALL
Moderator::onTerminated()
604 salhelper::ConditionWaiter
aWaiter(m_aRep
);
610 Function for opening UCB contents synchronously,
611 but with handled timeout;
613 static bool UCBOpenContentSync_(
614 const UcbLockBytesRef
& xLockBytes
,
615 const Reference
< XContent
>& xContent
,
617 const Reference
< XInterface
>& xSink
,
618 const Reference
< XInteractionHandler
>& xInteract
);
620 static bool UCBOpenContentSync(
621 const UcbLockBytesRef
& xLockBytes
,
622 Reference
< XContent
> const & xContent
,
624 const Reference
< XInterface
>& xSink
,
625 Reference
< XInteractionHandler
> const & xInteract
)
627 // http protocol must be handled in a special way:
628 // during the opening process the input stream may change
629 // only the last inputstream after notifying the document
632 Reference
<XContentIdentifier
> xContId(
633 xContent
.is() ? xContent
->getIdentifier() : nullptr );
637 aScheme
= xContId
->getContentProviderScheme();
639 // now determine whether we use a timeout or not;
640 if( ! aScheme
.equalsIgnoreAsciiCase("http") &&
641 ! aScheme
.equalsIgnoreAsciiCase("https") &&
642 ! aScheme
.equalsIgnoreAsciiCase("vnd.sun.star.webdav") &&
643 ! aScheme
.equalsIgnoreAsciiCase("vnd.sun.star.webdavs") &&
644 ! aScheme
.equalsIgnoreAsciiCase("ftp"))
645 return UCBOpenContentSync_(
646 xLockBytes
,xContent
,rArg
,xSink
,xInteract
);
648 if ( !aScheme
.equalsIgnoreAsciiCase( "http" ) &&
649 !aScheme
.equalsIgnoreAsciiCase( "https" ) )
650 xLockBytes
->SetStreamValid_Impl();
652 Reference
< XPropertiesChangeListener
> xListener
;
653 Reference
< XPropertiesChangeNotifier
> xProps(xContent
,UNO_QUERY
);
656 new UcbPropertiesChangeListener_Impl(xLockBytes
);
657 xProps
->addPropertiesChangeListener(
658 Sequence
< OUString
>(),
662 bool bException(false);
663 bool bAborted(false);
664 bool bResultAchieved(false);
666 Moderator
* pMod
= nullptr;
669 pMod
= new Moderator(xContent
,xInteract
,rArg
);
672 catch (const ContentCreationException
&)
674 bResultAchieved
= bException
= true;
675 xLockBytes
->SetError( ERRCODE_IO_GENERAL
);
678 sal_uInt32
nTimeout(5000); // initially 5000 milliSec
679 while(!bResultAchieved
) {
681 // try to get the result for with timeout
682 Moderator::Result res
= pMod
->getResult(nTimeout
);
685 case Moderator::ResultType::STREAM
:
687 Reference
<XStream
> result
;
688 if(res
.result
>>= result
) {
689 Reference
< XActiveDataStreamer
> xStreamer(
694 xStreamer
->setStream(result
);
696 pMod
->setReply(Moderator::REQUESTHANDLED
);
699 case Moderator::ResultType::INPUTSTREAM
:
701 Reference
<XInputStream
> result
;
702 res
.result
>>= result
;
703 Reference
< XActiveDataSink
> xActiveSink(
708 xActiveSink
->setInputStream(result
);
709 pMod
->setReply(Moderator::REQUESTHANDLED
);
712 case Moderator::ResultType::TIMEDOUT
:
714 Reference
<XInteractionRetry
> xRet
;
716 InteractiveNetworkConnectException aExcep
;
719 xContId
->getContentIdentifier() :
721 aExcep
.Server
= aURL
.GetHost();
722 aExcep
.Classification
= InteractionClassification_ERROR
;
723 aExcep
.Message
= "server not responding after five seconds";
726 ucbhelper::InteractionRequest
*ir
=
727 new ucbhelper::InteractionRequest(request
);
728 Reference
<XInteractionRequest
> xIR(ir
);
729 Sequence
<Reference
<XInteractionContinuation
> > aSeq(2);
730 ucbhelper::InteractionRetry
*retryP
=
731 new ucbhelper::InteractionRetry(ir
);
733 ucbhelper::InteractionAbort
*abortP
=
734 new ucbhelper::InteractionAbort(ir
);
737 ir
->setContinuations(aSeq
);
738 xInteract
->handle(xIR
);
739 rtl::Reference
< ucbhelper::InteractionContinuation
> ref
740 = ir
->getSelection();
742 Reference
<XInterface
> xInt(ref
.get());
743 xRet
.set(xInt
,UNO_QUERY
);
749 xLockBytes
->SetError(ERRCODE_ABORT
);
754 case Moderator::ResultType::INTERACTIONREQUEST
:
756 Reference
<XInteractionRequest
> Request
;
757 res
.result
>>= Request
;
758 xInteract
->handle(Request
);
759 pMod
->setReply(Moderator::REQUESTHANDLED
);
762 case Moderator::ResultType::RESULT
:
764 bResultAchieved
= true;
767 case Moderator::ResultType::COMMANDABORTED
:
770 xLockBytes
->SetError( ERRCODE_ABORT
);
773 case Moderator::ResultType::COMMANDFAILED
:
776 xLockBytes
->SetError( ERRCODE_ABORT
);
779 case Moderator::ResultType::INTERACTIVEIO
:
782 if ( res
.ioErrorCode
== IOErrorCode_ACCESS_DENIED
||
783 res
.ioErrorCode
== IOErrorCode_LOCKING_VIOLATION
)
784 xLockBytes
->SetError( ERRCODE_IO_ACCESSDENIED
);
785 else if ( res
.ioErrorCode
== IOErrorCode_NOT_EXISTING
)
786 xLockBytes
->SetError( ERRCODE_IO_NOTEXISTS
);
787 else if ( res
.ioErrorCode
== IOErrorCode_CANT_READ
)
788 xLockBytes
->SetError( ERRCODE_IO_CANTREAD
);
790 xLockBytes
->SetError( ERRCODE_IO_GENERAL
);
793 case Moderator::ResultType::UNSUPPORTED
:
796 xLockBytes
->SetError( ERRCODE_IO_NOTSUPPORTED
);
802 xLockBytes
->SetError( ERRCODE_IO_GENERAL
);
807 bResultAchieved
|= bException
;
808 bResultAchieved
|= bAborted
;
809 if(nTimeout
== 5000) nTimeout
*= 2;
812 if(pMod
) pMod
->setReply(Moderator::EXIT
);
814 if ( bAborted
|| bException
)
816 Reference
< XActiveDataSink
> xActiveSink( xSink
, UNO_QUERY
);
817 if ( xActiveSink
.is() )
818 xActiveSink
->setInputStream( Reference
< XInputStream
>() );
820 Reference
< XActiveDataStreamer
> xStreamer( xSink
, UNO_QUERY
);
821 if ( xStreamer
.is() )
822 xStreamer
->setStream( Reference
< XStream
>() );
825 Reference
< XActiveDataControl
> xControl( xSink
, UNO_QUERY
);
827 xControl
->terminate();
830 xProps
->removePropertiesChangeListener(
831 Sequence
< OUString
>(),
834 return ( bAborted
|| bException
);
838 Function for opening UCB contents synchronously
840 static bool UCBOpenContentSync_(
841 const UcbLockBytesRef
& xLockBytes
,
842 const Reference
< XContent
>& xContent
,
844 const Reference
< XInterface
>& xSink
,
845 const Reference
< XInteractionHandler
>& xInteract
)
847 ::ucbhelper::Content
aContent(
848 xContent
, new UcbTaskEnvironment( xInteract
, nullptr ),
849 comphelper::getProcessComponentContext() );
850 Reference
< XContentIdentifier
> xIdent
= xContent
->getIdentifier();
851 OUString aScheme
= xIdent
->getContentProviderScheme();
853 // http protocol must be handled in a special way: during the opening process the input stream may change
854 // only the last inputstream after notifying the document headers is valid
855 if ( !aScheme
.equalsIgnoreAsciiCase("http") )
856 xLockBytes
->SetStreamValid_Impl();
858 Reference
< XPropertiesChangeListener
> xListener
= new UcbPropertiesChangeListener_Impl( xLockBytes
);
859 Reference
< XPropertiesChangeNotifier
> xProps ( xContent
, UNO_QUERY
);
861 xProps
->addPropertiesChangeListener( Sequence
< OUString
>(), xListener
);
863 bool bException
= false;
864 bool bAborted
= false;
868 aContent
.executeCommand( rArg
.Name
, rArg
.Argument
);
870 catch (const CommandAbortedException
&)
873 xLockBytes
->SetError( ERRCODE_ABORT
);
875 catch (const CommandFailedException
&)
878 xLockBytes
->SetError( ERRCODE_ABORT
);
880 catch (const InteractiveIOException
& r
)
883 if ( r
.Code
== IOErrorCode_ACCESS_DENIED
|| r
.Code
== IOErrorCode_LOCKING_VIOLATION
)
884 xLockBytes
->SetError( ERRCODE_IO_ACCESSDENIED
);
885 else if ( r
.Code
== IOErrorCode_NOT_EXISTING
)
886 xLockBytes
->SetError( ERRCODE_IO_NOTEXISTS
);
887 else if ( r
.Code
== IOErrorCode_CANT_READ
)
888 xLockBytes
->SetError( ERRCODE_IO_CANTREAD
);
890 xLockBytes
->SetError( ERRCODE_IO_GENERAL
);
892 catch (const UnsupportedDataSinkException
&)
895 xLockBytes
->SetError( ERRCODE_IO_NOTSUPPORTED
);
897 catch (const Exception
&)
900 xLockBytes
->SetError( ERRCODE_IO_GENERAL
);
903 if ( bAborted
|| bException
)
905 Reference
< XActiveDataSink
> xActiveSink( xSink
, UNO_QUERY
);
906 if ( xActiveSink
.is() )
907 xActiveSink
->setInputStream( Reference
< XInputStream
>() );
909 Reference
< XActiveDataStreamer
> xStreamer( xSink
, UNO_QUERY
);
910 if ( xStreamer
.is() )
911 xStreamer
->setStream( Reference
< XStream
>() );
914 Reference
< XActiveDataControl
> xControl( xSink
, UNO_QUERY
);
916 xControl
->terminate();
919 xProps
->removePropertiesChangeListener( Sequence
< OUString
>(), xListener
);
921 return ( bAborted
|| bException
);
924 UcbLockBytes::UcbLockBytes()
925 : m_nError( ERRCODE_NONE
)
926 , m_bTerminated (false)
927 , m_bDontClose( false )
928 , m_bStreamValid (false)
933 UcbLockBytes::~UcbLockBytes()
937 if ( m_xInputStream
.is() )
941 m_xInputStream
->closeInput();
943 catch (const RuntimeException
&)
946 catch (const IOException
&)
952 if ( !m_xInputStream
.is() && m_xOutputStream
.is() )
956 m_xOutputStream
->closeOutput();
958 catch (const RuntimeException
&)
961 catch (const IOException
&)
967 Reference
< XInputStream
> UcbLockBytes::getInputStream()
969 osl::MutexGuard
aGuard( m_aMutex
);
971 return m_xInputStream
;
974 void UcbLockBytes::setStream_Impl( const Reference
<XStream
>& aStream
)
976 osl::MutexGuard
aGuard( m_aMutex
);
979 m_xOutputStream
= aStream
->getOutputStream();
980 setInputStream_Impl( aStream
->getInputStream(), false );
981 m_xSeekable
.set( aStream
, UNO_QUERY
);
985 m_xOutputStream
.clear();
986 setInputStream_Impl( Reference
< XInputStream
>() );
990 bool UcbLockBytes::setInputStream_Impl( const Reference
<XInputStream
> &rxInputStream
, bool bSetXSeekable
)
996 osl::MutexGuard
aGuard( m_aMutex
);
998 if ( !m_bDontClose
&& m_xInputStream
.is() )
999 m_xInputStream
->closeInput();
1001 m_xInputStream
= rxInputStream
;
1005 m_xSeekable
.set( rxInputStream
, UNO_QUERY
);
1006 if( !m_xSeekable
.is() && rxInputStream
.is() )
1008 Reference
< XComponentContext
> xContext
= ::comphelper::getProcessComponentContext();
1009 Reference
< XOutputStream
> rxTempOut( css::io::TempFile::create(xContext
), UNO_QUERY_THROW
);
1011 ::comphelper::OStorageHelper::CopyInputToOutput( rxInputStream
, rxTempOut
);
1012 m_xInputStream
.set( rxTempOut
, UNO_QUERY
);
1013 m_xSeekable
.set( rxTempOut
, UNO_QUERY
);
1017 bRet
= m_xInputStream
.is();
1019 catch (const Exception
&)
1023 if ( m_bStreamValid
&& m_xInputStream
.is() )
1024 m_aInitialized
.set();
1029 void UcbLockBytes::SetStreamValid_Impl()
1031 m_bStreamValid
= true;
1032 if ( m_xInputStream
.is() )
1033 m_aInitialized
.set();
1036 void UcbLockBytes::terminate_Impl()
1038 m_bTerminated
= true;
1039 m_aInitialized
.set();
1040 m_aTerminated
.set();
1042 if ( GetError() == ERRCODE_NONE
&& !m_xInputStream
.is() )
1044 OSL_FAIL("No InputStream, but no error set!" );
1045 SetError( ERRCODE_IO_NOTEXISTS
);
1049 ErrCode
UcbLockBytes::ReadAt(sal_uInt64
const nPos
,
1050 void *pBuffer
, std::size_t nCount
, std::size_t *pRead
) const
1052 if ( IsSynchronMode() )
1054 UcbLockBytes
* pThis
= const_cast < UcbLockBytes
* >( this );
1055 pThis
->m_aInitialized
.wait();
1058 Reference
<XInputStream
> xStream
= getInputStream_Impl();
1059 if ( !xStream
.is() )
1061 if ( m_bTerminated
)
1062 return ERRCODE_IO_CANTREAD
;
1064 return ERRCODE_IO_PENDING
;
1070 Reference
<XSeekable
> xSeekable
= getSeekable_Impl();
1071 if ( !xSeekable
.is() )
1072 return ERRCODE_IO_CANTREAD
;
1076 xSeekable
->seek( nPos
);
1078 catch (const IOException
&)
1080 return ERRCODE_IO_CANTSEEK
;
1082 catch (const css::lang::IllegalArgumentException
&)
1084 return ERRCODE_IO_CANTSEEK
;
1087 Sequence
<sal_Int8
> aData
;
1090 if(nCount
> 0x7FFFFFFF)
1092 nCount
= 0x7FFFFFFF;
1096 if ( !m_bTerminated
&& !IsSynchronMode() )
1098 sal_uInt64 nLen
= xSeekable
->getLength();
1099 if ( nPos
+ nCount
> nLen
)
1100 return ERRCODE_IO_PENDING
;
1103 nSize
= xStream
->readBytes( aData
, sal_Int32(nCount
) );
1105 catch (const IOException
&)
1107 return ERRCODE_IO_CANTREAD
;
1110 memcpy (pBuffer
, aData
.getConstArray(), nSize
);
1112 *pRead
= static_cast<std::size_t>(nSize
);
1114 return ERRCODE_NONE
;
1117 ErrCode
UcbLockBytes::WriteAt(sal_uInt64
const nPos
, const void *pBuffer
,
1118 std::size_t nCount
, std::size_t *pWritten
)
1123 DBG_ASSERT( IsSynchronMode(), "Writing is only possible in SynchronMode!" );
1124 DBG_ASSERT( m_aInitialized
.check(), "Writing bevor stream is ready!" );
1126 Reference
<XSeekable
> xSeekable
= getSeekable_Impl();
1127 Reference
<XOutputStream
> xOutputStream
= getOutputStream_Impl();
1128 if ( !xOutputStream
.is() || !xSeekable
.is() )
1129 return ERRCODE_IO_CANTWRITE
;
1133 xSeekable
->seek( nPos
);
1135 catch (const IOException
&)
1137 return ERRCODE_IO_CANTSEEK
;
1140 sal_Int8
const * pData
= static_cast<sal_Int8
const *>(pBuffer
);
1141 Sequence
<sal_Int8
> aData( pData
, nCount
);
1144 xOutputStream
->writeBytes( aData
);
1148 catch (const Exception
&)
1150 return ERRCODE_IO_CANTWRITE
;
1153 return ERRCODE_NONE
;
1156 ErrCode
UcbLockBytes::Flush() const
1158 Reference
<XOutputStream
> xOutputStream
= getOutputStream_Impl();
1159 if ( !xOutputStream
.is() )
1160 return ERRCODE_IO_CANTWRITE
;
1164 xOutputStream
->flush();
1166 catch (const Exception
&)
1168 return ERRCODE_IO_CANTWRITE
;
1171 return ERRCODE_NONE
;
1174 ErrCode
UcbLockBytes::SetSize (sal_uInt64
const nNewSize
)
1176 SvLockBytesStat aStat
;
1178 std::size_t nSize
= aStat
.nSize
;
1180 if ( nSize
> nNewSize
)
1182 Reference
< XTruncate
> xTrunc( getOutputStream_Impl(), UNO_QUERY
);
1189 SAL_INFO("unotools.ucbhelper", "Not truncable!");
1193 if ( nSize
< nNewSize
)
1195 std::size_t nDiff
= nNewSize
-nSize
, nCount
=0;
1196 std::unique_ptr
<sal_uInt8
[]> pBuffer(new sal_uInt8
[ nDiff
]);
1197 memset(pBuffer
.get(), 0, nDiff
); // initialize for enhanced security
1198 WriteAt( nSize
, pBuffer
.get(), nDiff
, &nCount
);
1199 if ( nCount
!= nDiff
)
1200 return ERRCODE_IO_CANTWRITE
;
1203 return ERRCODE_NONE
;
1206 ErrCode
UcbLockBytes::Stat( SvLockBytesStat
*pStat
) const
1208 if ( IsSynchronMode() )
1210 UcbLockBytes
* pThis
= const_cast < UcbLockBytes
* >( this );
1211 pThis
->m_aInitialized
.wait();
1215 return ERRCODE_IO_INVALIDPARAMETER
;
1217 Reference
<XInputStream
> xStream
= getInputStream_Impl();
1218 Reference
<XSeekable
> xSeekable
= getSeekable_Impl();
1220 if ( !xStream
.is() )
1222 if ( m_bTerminated
)
1223 return ERRCODE_IO_INVALIDACCESS
;
1225 return ERRCODE_IO_PENDING
;
1227 else if( !xSeekable
.is() )
1228 return ERRCODE_IO_CANTTELL
;
1232 pStat
->nSize
= sal_uLong(xSeekable
->getLength());
1234 catch (const IOException
&)
1236 return ERRCODE_IO_CANTTELL
;
1239 return ERRCODE_NONE
;
1242 UcbLockBytesRef
UcbLockBytes::CreateInputLockBytes( const Reference
< XInputStream
>& xInputStream
)
1244 if( !xInputStream
.is() )
1247 UcbLockBytesRef xLockBytes
= new UcbLockBytes
;
1248 xLockBytes
->setDontClose_Impl();
1249 xLockBytes
->setInputStream_Impl( xInputStream
);
1250 xLockBytes
->terminate_Impl();
1254 UcbLockBytesRef
UcbLockBytes::CreateLockBytes( const Reference
< XStream
>& xStream
)
1259 UcbLockBytesRef xLockBytes
= new UcbLockBytes
;
1260 xLockBytes
->setDontClose_Impl();
1261 xLockBytes
->setStream_Impl( xStream
);
1262 xLockBytes
->terminate_Impl();
1266 UcbLockBytesRef
UcbLockBytes::CreateLockBytes( const Reference
< XContent
>& xContent
, const Sequence
< PropertyValue
>& rProps
,
1267 StreamMode eOpenMode
, const Reference
< XInteractionHandler
>& xInteractionHandler
)
1269 if( !xContent
.is() )
1272 UcbLockBytesRef xLockBytes
= new UcbLockBytes
;
1273 xLockBytes
->SetSynchronMode();
1274 Reference
< XActiveDataControl
> xSink
;
1275 if ( eOpenMode
& StreamMode::WRITE
)
1276 xSink
= new UcbStreamer_Impl(xLockBytes
.get());
1278 xSink
= new UcbDataSink_Impl(xLockBytes
.get());
1280 if ( rProps
.hasElements() )
1282 Reference
< XCommandProcessor
> xProcessor( xContent
, UNO_QUERY
);
1284 aCommand
.Name
= "setPropertyValues";
1285 aCommand
.Handle
= -1; /* unknown */
1286 aCommand
.Argument
<<= rProps
;
1287 xProcessor
->execute( aCommand
, 0, Reference
< XCommandEnvironment
>() );
1290 OpenCommandArgument2 aArgument
;
1291 aArgument
.Sink
= xSink
;
1292 aArgument
.Mode
= OpenMode::DOCUMENT
;
1295 aCommand
.Name
= "open";
1296 aCommand
.Argument
<<= aArgument
;
1298 bool bError
= UCBOpenContentSync( xLockBytes
,
1302 xInteractionHandler
);
1304 if ( xLockBytes
->GetError() == ERRCODE_NONE
&& ( bError
|| !xLockBytes
->getInputStream().is() ) )
1306 OSL_FAIL("No InputStream, but no error set!" );
1307 xLockBytes
->SetError( ERRCODE_IO_GENERAL
);
1315 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */