diff options
Diffstat (limited to 'unotools/source/ucbhelper/ucblockbytes.cxx')
-rw-r--r-- | unotools/source/ucbhelper/ucblockbytes.cxx | 1755 |
1 files changed, 1755 insertions, 0 deletions
diff --git a/unotools/source/ucbhelper/ucblockbytes.cxx b/unotools/source/ucbhelper/ucblockbytes.cxx new file mode 100644 index 000000000000..71640c6e5b08 --- /dev/null +++ b/unotools/source/ucbhelper/ucblockbytes.cxx @@ -0,0 +1,1755 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_unotools.hxx" + +#include <unotools/ucblockbytes.hxx> +#include <comphelper/processfactory.hxx> +#include <salhelper/condition.hxx> +#ifndef _OSL_THREAD_HXX_ +#include <osl/thread.hxx> +#endif +#include <tools/urlobj.hxx> +#include <ucbhelper/interactionrequest.hxx> +#include <com/sun/star/task/XInteractionAbort.hpp> +#include <com/sun/star/ucb/InteractiveNetworkConnectException.hpp> +#include <com/sun/star/ucb/CommandFailedException.hpp> +#include <com/sun/star/ucb/UnsupportedDataSinkException.hpp> +#ifndef _COM_SUN_STAR_UCB_INTERACTIVEIODEXCEPTION_HPP_ +#include <com/sun/star/ucb/InteractiveIOException.hpp> +#endif +#include <com/sun/star/io/XActiveDataStreamer.hpp> +#include <com/sun/star/ucb/DocumentHeaderField.hpp> +#include <com/sun/star/ucb/XCommandInfo.hpp> +#include <com/sun/star/ucb/XCommandProcessor.hpp> +#include <com/sun/star/task/XInteractionHandler.hpp> +#include <com/sun/star/ucb/OpenCommandArgument2.hpp> +#include <com/sun/star/ucb/PostCommandArgument2.hpp> +#include <com/sun/star/ucb/OpenMode.hpp> +#include <com/sun/star/beans/Property.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/beans/XPropertiesChangeNotifier.hpp> +#include <com/sun/star/beans/XPropertiesChangeListener.hpp> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/io/XActiveDataSink.hpp> +#include <com/sun/star/io/XActiveDataControl.hpp> +#include <com/sun/star/io/XSeekable.hpp> +#include <cppuhelper/implbase1.hxx> +#include <cppuhelper/implbase2.hxx> +#include <tools/inetmsg.hxx> +#include <com/sun/star/io/XTruncate.hpp> +#include <com/sun/star/lang/IllegalArgumentException.hpp> + +#include <comphelper/storagehelper.hxx> + +#include <ucbhelper/contentbroker.hxx> +#include <ucbhelper/content.hxx> + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::io; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::ucb; +using namespace ::com::sun::star::task; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::beans; + + +namespace utl +{ + +/** + Helper class for getting a XInputStream when opening a content + */ +class UcbDataSink_Impl : public ::cppu::WeakImplHelper2< XActiveDataControl, XActiveDataSink > +{ + UcbLockBytesRef m_xLockBytes; + +public: + UcbDataSink_Impl( UcbLockBytes* pLockBytes ) + : m_xLockBytes( pLockBytes ) + {} + + SvLockBytes* getLockBytes (void) + { return m_xLockBytes; } + + // XActiveDataControl. + virtual void SAL_CALL addListener ( const Reference<XStreamListener> &/*rxListener*/) throw(RuntimeException) {} + virtual void SAL_CALL removeListener ( const Reference<XStreamListener> &/*rxListener*/) throw(RuntimeException) {} + virtual void SAL_CALL start (void) throw(RuntimeException) {} + virtual void SAL_CALL terminate (void) throw(RuntimeException) + { m_xLockBytes->terminate_Impl(); } + + // XActiveDataSink. + virtual void SAL_CALL setInputStream ( const Reference<XInputStream> &rxInputStream) throw(RuntimeException) + { m_xLockBytes->setInputStream_Impl (rxInputStream); } + virtual Reference<XInputStream> SAL_CALL getInputStream (void) throw(RuntimeException) + { return m_xLockBytes->getInputStream_Impl(); } +}; + +/** + Helper class for getting a XStream when opening a content + */ +class UcbStreamer_Impl : public ::cppu::WeakImplHelper2< XActiveDataStreamer, XActiveDataControl > +{ + Reference < XStream > m_xStream; + UcbLockBytesRef m_xLockBytes; + +public: + + UcbStreamer_Impl( UcbLockBytes* pLockBytes ) + : m_xLockBytes( pLockBytes ) + {} + + // XActiveDataControl. + virtual void SAL_CALL addListener ( const Reference<XStreamListener> &/*rxListener*/) throw(RuntimeException) {} + virtual void SAL_CALL removeListener ( const Reference<XStreamListener> &/*rxListener*/) throw(RuntimeException) {} + virtual void SAL_CALL start (void) throw(RuntimeException) {} + virtual void SAL_CALL terminate (void) throw(RuntimeException) + { m_xLockBytes->terminate_Impl(); } + + // XActiveDataStreamer + virtual void SAL_CALL setStream( const Reference< XStream >& aStream ) throw(RuntimeException) + { m_xStream = aStream; m_xLockBytes->setStream_Impl( aStream ); } + virtual Reference< XStream > SAL_CALL getStream() throw(RuntimeException) + { return m_xStream; } +}; + +/** + Helper class for progress handling while executing UCB commands + */ +class ProgressHandler_Impl: public ::cppu::WeakImplHelper1< XProgressHandler > +{ + Link m_aProgress; + +public: + ProgressHandler_Impl( const Link& rLink ) + : m_aProgress( rLink ) + {} + // XProgressHandler + virtual void SAL_CALL push(const Any & /*rStatus*/) throw (RuntimeException) {} + virtual void SAL_CALL pop() throw (RuntimeException) {} + virtual void SAL_CALL update(const Any & /*rStatus*/) throw (RuntimeException) + { if ( m_aProgress.IsSet() ) m_aProgress.Call( 0 ); } +}; + +/** + Helper class for managing interactions and progress when executing UCB commands + */ +class UcbTaskEnvironment : public ::cppu::WeakImplHelper1< XCommandEnvironment > +{ + Reference< XInteractionHandler > m_xInteractionHandler; + Reference< XProgressHandler > m_xProgressHandler; + +public: + UcbTaskEnvironment( const Reference< XInteractionHandler>& rxInteractionHandler, + const Reference< XProgressHandler>& rxProgressHandler ) + : m_xInteractionHandler( rxInteractionHandler ) + , m_xProgressHandler( rxProgressHandler ) + {} + + + virtual Reference<XInteractionHandler> SAL_CALL getInteractionHandler() throw (RuntimeException) + { return m_xInteractionHandler; } + + virtual Reference<XProgressHandler> SAL_CALL getProgressHandler() throw (RuntimeException) + { return m_xProgressHandler; } +}; + + +/** + Helper class for property change notifies when executing UCB commands +*/ +class UcbPropertiesChangeListener_Impl : public ::cppu::WeakImplHelper1< XPropertiesChangeListener > +{ +public: + UcbLockBytesRef m_xLockBytes; + + UcbPropertiesChangeListener_Impl( UcbLockBytesRef rRef ) + : m_xLockBytes( rRef ) + {} + + virtual void SAL_CALL disposing ( const EventObject &/*rEvent*/) throw(RuntimeException) {} + virtual void SAL_CALL propertiesChange ( const Sequence<PropertyChangeEvent> &rEvent) throw(RuntimeException); +}; + +void SAL_CALL UcbPropertiesChangeListener_Impl::propertiesChange ( const Sequence<PropertyChangeEvent> &rEvent) throw(RuntimeException) +{ + sal_Int32 i, n = rEvent.getLength(); + for (i = 0; i < n; i++) + { + PropertyChangeEvent evt (rEvent[i]); + if (evt.PropertyName == ::rtl::OUString::createFromAscii ("DocumentHeader")) + { + Sequence<DocumentHeaderField> aHead; + if (evt.NewValue >>= aHead) + { + sal_Int32 k, m = aHead.getLength(); + for (k = 0; k < m; k++) + { + String aName( aHead[k].Name ); + String aValue( aHead[k].Value ); + + if (aName.CompareIgnoreCaseToAscii("Expires") == COMPARE_EQUAL) + { + DateTime aExpires (0, 0); + if (INetRFC822Message::ParseDateField (aValue, aExpires)) + { + aExpires.ConvertToLocalTime(); + m_xLockBytes->SetExpireDate_Impl( aExpires ); + } + } + } + } + + m_xLockBytes->SetStreamValid_Impl(); + } + else if (evt.PropertyName == rtl::OUString::createFromAscii ("PresentationURL")) + { + ::rtl::OUString aUrl; + if (evt.NewValue >>= aUrl) + { + ::rtl::OUString aBad (::rtl::OUString::createFromAscii ("private:")); + if (!(aUrl.compareTo (aBad, aBad.getLength()) == 0)) + { + // URL changed (Redirection). + m_xLockBytes->SetRealURL_Impl( aUrl ); + } + } + } + else if (evt.PropertyName == ::rtl::OUString::createFromAscii ("MediaType")) + { + ::rtl::OUString aContentType; + if (evt.NewValue >>= aContentType) + m_xLockBytes->SetContentType_Impl( aContentType ); + } + } +} + + + +class Moderator + : public osl::Thread +{ + // usage restriction: + // It might be possible, that the call to the interactionhandler and/or + // progresshandler is done asynchrounsly, while the 'execute' simply + // returns. This would imply that these class must be refcounted !!! + +public: + + Moderator( + Reference < XContent >& xContent, + Reference < XInteractionHandler >& xInteract, + Reference < XProgressHandler >& xProgress, + const Command& rArg + ) + throw( + ContentCreationException, + RuntimeException + ); + + ~Moderator(); + + + enum ResultType { + NORESULT, + + INTERACTIONREQUEST, // reply expected + + PROGRESSPUSH, + PROGRESSUPDATE, + PROGRESSPOP, + + INPUTSTREAM, + STREAM, + + RESULT, + TIMEDOUT, + COMMANDABORTED, + COMMANDFAILED, + INTERACTIVEIO, + UNSUPPORTED, + GENERAL + }; + + + class ConditionRes + : public salhelper::Condition + { + public: + + ConditionRes(osl::Mutex& aMutex,Moderator& aModerator) + : salhelper::Condition(aMutex), + m_aModerator(aModerator) + { + } + + protected: + + bool applies() const { + return m_aModerator.m_aResultType != NORESULT; + } + + private: + + Moderator& m_aModerator; + }; + + + struct Result { + ResultType type; + Any result; + sal_Int32 ioErrorCode; + }; + + + Result getResult(const sal_uInt32 milliSec); + + + enum ReplyType { + NOREPLY, + EXIT, + RETRY, + REQUESTHANDLED + }; + + + class ConditionRep + : public salhelper::Condition + { + public: + + ConditionRep(osl::Mutex& aMutex,Moderator& aModerator) + : salhelper::Condition(aMutex), + m_aModerator(aModerator) + { + } + + protected: + + bool applies() const { + return m_aModerator.m_aReplyType != NOREPLY; + } + + private: + + Moderator& m_aModerator; + }; + + void setReply(ReplyType); + + + void handle( const Reference<XInteractionRequest >& Request ); + + void push( const Any& Status ); + + void update( const Any& Status ); + + void pop( ); + + void setStream(const Reference< XStream >& aStream); + + void setInputStream(const Reference<XInputStream> &rxInputStream); + + +protected: + + virtual void SAL_CALL run(); + + virtual void SAL_CALL onTerminated(); + +private: + + osl::Mutex m_aMutex; + + friend class ConditionRes; + + ConditionRes m_aRes; + ResultType m_aResultType; + sal_Int32 m_nIOErrorCode; + Any m_aResult; + + friend class ConditionRep; + + ConditionRep m_aRep; + ReplyType m_aReplyType; + + Command m_aArg; + ::ucbhelper::Content m_aContent; +}; + + +class ModeratorsActiveDataStreamer + : public ::cppu::WeakImplHelper1<XActiveDataStreamer> +{ +public: + + ModeratorsActiveDataStreamer(Moderator &theModerator); + + ~ModeratorsActiveDataStreamer(); + + // XActiveDataStreamer + virtual void SAL_CALL + setStream( + const Reference< XStream >& aStream + ) + throw( + RuntimeException + ); + + virtual Reference<XStream> SAL_CALL + getStream ( + void + ) throw( + RuntimeException + ) + { + osl::MutexGuard aGuard(m_aMutex); + return m_xStream; + } + + +private: + + Moderator& m_aModerator; + + osl::Mutex m_aMutex; + Reference<XStream> m_xStream; +}; + + + +class ModeratorsActiveDataSink + : public ::cppu::WeakImplHelper1<XActiveDataSink> +{ +public: + + ModeratorsActiveDataSink(Moderator &theModerator); + + ~ModeratorsActiveDataSink(); + + // XActiveDataSink. + virtual void SAL_CALL + setInputStream ( + const Reference<XInputStream> &rxInputStream + ) + throw( + RuntimeException + ); + + virtual Reference<XInputStream> SAL_CALL + getInputStream ( + void + ) throw( + RuntimeException + ) + { + osl::MutexGuard aGuard(m_aMutex); + return m_xStream; + } + + +private: + + Moderator& m_aModerator; + osl::Mutex m_aMutex; + Reference<XInputStream> m_xStream; +}; + + + +ModeratorsActiveDataSink::ModeratorsActiveDataSink(Moderator &theModerator) + : m_aModerator(theModerator) +{ +} + + +ModeratorsActiveDataSink::~ModeratorsActiveDataSink() +{ +} + +// XActiveDataSink. +void SAL_CALL +ModeratorsActiveDataSink::setInputStream ( + const Reference<XInputStream> &rxInputStream +) + throw( + RuntimeException + ) +{ + m_aModerator.setInputStream(rxInputStream); + osl::MutexGuard aGuard(m_aMutex); + m_xStream = rxInputStream; +} + + +ModeratorsActiveDataStreamer::ModeratorsActiveDataStreamer( + Moderator &theModerator +) + : m_aModerator(theModerator) +{ +} + + +ModeratorsActiveDataStreamer::~ModeratorsActiveDataStreamer() +{ +} + +// XActiveDataStreamer. +void SAL_CALL +ModeratorsActiveDataStreamer::setStream ( + const Reference<XStream> &rxStream +) + throw( + RuntimeException + ) +{ + m_aModerator.setStream(rxStream); + osl::MutexGuard aGuard(m_aMutex); + m_xStream = rxStream; +} + + + +class ModeratorsInteractionHandler + : public ::cppu::WeakImplHelper1<XInteractionHandler> +{ +public: + + ModeratorsInteractionHandler(Moderator &theModerator); + + ~ModeratorsInteractionHandler(); + + virtual void SAL_CALL + handle( const Reference<XInteractionRequest >& Request ) + throw (RuntimeException); + +private: + + Moderator& m_aModerator; +}; + + +class ModeratorsProgressHandler + : public ::cppu::WeakImplHelper1<XProgressHandler> +{ +public: + + ModeratorsProgressHandler(Moderator &theModerator); + + ~ModeratorsProgressHandler(); + + virtual void SAL_CALL push( const Any& Status ) + throw ( + RuntimeException); + + virtual void SAL_CALL update( const Any& Status ) + throw (RuntimeException); + + virtual void SAL_CALL pop( ) + throw (RuntimeException); + + +private: + + Moderator& m_aModerator; +}; + + +ModeratorsProgressHandler::ModeratorsProgressHandler(Moderator &theModerator) + : m_aModerator(theModerator) +{ +} + +ModeratorsProgressHandler::~ModeratorsProgressHandler() +{ +} + + +void SAL_CALL ModeratorsProgressHandler::push( const Any& Status ) + throw ( + RuntimeException) +{ + m_aModerator.push(Status); +} + + +void SAL_CALL ModeratorsProgressHandler::update( const Any& Status ) + throw (RuntimeException) +{ + m_aModerator.update(Status); +} + + +void SAL_CALL ModeratorsProgressHandler::pop( ) + throw (RuntimeException) +{ + m_aModerator.pop(); +} + + + + +ModeratorsInteractionHandler::ModeratorsInteractionHandler( + Moderator &aModerator) + : m_aModerator(aModerator) +{ +} + + +ModeratorsInteractionHandler::~ModeratorsInteractionHandler() +{ +} + + +void SAL_CALL +ModeratorsInteractionHandler::handle( + const Reference<XInteractionRequest >& Request +) + throw ( + RuntimeException + ) +{ + // wakes up the mainthread + m_aModerator.handle(Request); +} + + + + +Moderator::Moderator( + Reference < XContent >& xContent, + Reference < XInteractionHandler >& xInteract, + Reference < XProgressHandler >& xProgress, + const Command& rArg +) + throw( + ::com::sun::star::ucb::ContentCreationException, + ::com::sun::star::uno::RuntimeException + ) + : m_aMutex(), + + m_aRes(m_aMutex,*this), + m_aResultType(NORESULT), + m_nIOErrorCode(0), + m_aResult(), + + m_aRep(m_aMutex,*this), + m_aReplyType(NOREPLY), + + m_aArg(rArg), + m_aContent( + xContent, + new UcbTaskEnvironment( + xInteract.is() ? new ModeratorsInteractionHandler(*this) : 0, + xProgress.is() ? new ModeratorsProgressHandler(*this) : 0 + )) +{ + // now exchange the whole data sink stuff + // with a thread safe version + + Reference<XInterface> *pxSink = NULL; + + PostCommandArgument2 aPostArg; + OpenCommandArgument2 aOpenArg; + + int dec(2); + if(m_aArg.Argument >>= aPostArg) { + pxSink = &aPostArg.Sink; + dec = 0; + } + else if(m_aArg.Argument >>= aOpenArg) { + pxSink = &aOpenArg.Sink; + dec = 1; + } + + if(dec ==2) + throw ContentCreationException(); + + Reference < XActiveDataSink > xActiveSink(*pxSink,UNO_QUERY); + if(xActiveSink.is()) + *pxSink = Reference<XInterface>( + (cppu::OWeakObject*)new ModeratorsActiveDataSink(*this)); + + Reference<XActiveDataStreamer> xStreamer( *pxSink, UNO_QUERY ); + if ( xStreamer.is() ) + *pxSink = Reference<XInterface>( + (cppu::OWeakObject*)new ModeratorsActiveDataStreamer(*this)); + + if(dec == 0) + m_aArg.Argument <<= aPostArg; + else if(dec == 1) + m_aArg.Argument <<= aOpenArg; +} + + +Moderator::~Moderator() +{ +} + + +Moderator::Result Moderator::getResult(const sal_uInt32 milliSec) +{ + Result ret; + try { + salhelper::ConditionWaiter aWaiter(m_aRes,milliSec); + ret.type = m_aResultType; + ret.result = m_aResult; + ret.ioErrorCode = m_nIOErrorCode; + + // reset + m_aResultType = NORESULT; + } + catch(const salhelper::ConditionWaiter::timedout&) + { + ret.type = TIMEDOUT; + } + + return ret; +} + + +void Moderator::setReply(ReplyType aReplyType ) +{ + salhelper::ConditionModifier aMod(m_aRep); + m_aReplyType = aReplyType; +} + + +void Moderator::handle( const Reference<XInteractionRequest >& Request ) +{ + ReplyType aReplyType; + + do { + { + salhelper::ConditionModifier aMod(m_aRes); + m_aResultType = INTERACTIONREQUEST; + m_aResult <<= Request; + } + + { + salhelper::ConditionWaiter aWait(m_aRep); + aReplyType = m_aReplyType; + + // reset + m_aReplyType = NOREPLY; + } + + if(aReplyType == EXIT) { + Sequence<Reference<XInteractionContinuation> > aSeq( + Request->getContinuations()); + for(sal_Int32 i = 0; i < aSeq.getLength(); ++i) { + Reference<XInteractionAbort> aRef(aSeq[i],UNO_QUERY); + if(aRef.is()) { + aRef->select(); + } + } + + // resignal the exitcondition + setReply(EXIT); + break; + } + } while(aReplyType != REQUESTHANDLED); +} + + + +void Moderator::push( const Any& Status ) +{ + { + salhelper::ConditionModifier aMod(m_aRes); + m_aResultType = PROGRESSPUSH; + m_aResult = Status; + } + ReplyType aReplyType; + { + salhelper::ConditionWaiter aWait(m_aRep); + aReplyType = m_aReplyType; + m_aReplyType = NOREPLY; + } + if(aReplyType == EXIT) + setReply(EXIT); +} + + +void Moderator::update( const Any& Status ) +{ + { + salhelper::ConditionModifier aMod(m_aRes); + m_aResultType = PROGRESSUPDATE; + m_aResult = Status; + } + ReplyType aReplyType; + { + salhelper::ConditionWaiter aWait(m_aRep); + aReplyType = m_aReplyType; + m_aReplyType = NOREPLY; + } + if(aReplyType == EXIT) + setReply(EXIT); +} + + +void Moderator::pop( ) +{ + { + salhelper::ConditionModifier aMod(m_aRes); + m_aResultType = PROGRESSPOP; + } + ReplyType aReplyType; + { + salhelper::ConditionWaiter aWait(m_aRep); + aReplyType = m_aReplyType; + m_aReplyType = NOREPLY; + } + if(aReplyType == EXIT) + setReply(EXIT); +} + + +void Moderator::setStream(const Reference< XStream >& aStream) +{ + { + salhelper::ConditionModifier aMod(m_aRes); + m_aResultType = STREAM; + m_aResult <<= aStream; + } + ReplyType aReplyType; + { + salhelper::ConditionWaiter aWait(m_aRep); + aReplyType = m_aReplyType; + m_aReplyType = NOREPLY; + } + if(aReplyType == EXIT) + setReply(EXIT); +} + + +void Moderator::setInputStream(const Reference<XInputStream> &rxInputStream) +{ + { + salhelper::ConditionModifier aMod(m_aRes); + m_aResultType = INPUTSTREAM; + m_aResult <<= rxInputStream; + } + ReplyType aReplyType; + { + salhelper::ConditionWaiter aWait(m_aRep); + aReplyType = m_aReplyType; + m_aReplyType = NOREPLY; + } + if(aReplyType == EXIT) + setReply(EXIT); +} + + + +void SAL_CALL Moderator::run() +{ + ResultType aResultType; + Any aResult; + sal_Int32 nIOErrorCode = 0; + + try + { + aResult = m_aContent.executeCommand(m_aArg.Name,m_aArg.Argument); + aResultType = RESULT; + } + catch ( CommandAbortedException ) + { + aResultType = COMMANDABORTED; + } + catch ( CommandFailedException ) + { + aResultType = COMMANDFAILED; + } + catch ( InteractiveIOException& r ) + { + nIOErrorCode = r.Code; + aResultType = INTERACTIVEIO; + } + catch ( UnsupportedDataSinkException& ) + { + aResultType = UNSUPPORTED; + } + catch ( Exception ) + { + aResultType = GENERAL; + } + + { + salhelper::ConditionModifier aMod(m_aRes); + m_aResultType = aResultType; + m_aResult = aResult; + m_nIOErrorCode = nIOErrorCode; + } +} + + + +void SAL_CALL Moderator::onTerminated() +{ + { + salhelper::ConditionWaiter aWaiter(m_aRep); + } + delete this; +} + + +/** + Function for opening UCB contents synchronously, + but with handled timeout; +*/ + +static sal_Bool _UCBOpenContentSync( + UcbLockBytesRef xLockBytes, + Reference < XContent > xContent, + const Command& rArg, + Reference < XInterface > xSink, + Reference < XInteractionHandler > xInteract, + Reference < XProgressHandler > xProgress, + UcbLockBytesHandlerRef xHandler ); + + +static sal_Bool UCBOpenContentSync( + UcbLockBytesRef xLockBytes, + Reference < XContent > xContent, + const Command& rArg, + Reference < XInterface > xSink, + Reference < XInteractionHandler > xInteract, + Reference < XProgressHandler > xProgress, + UcbLockBytesHandlerRef xHandler ) +{ + // http protocol must be handled in a special way: + // during the opening process the input stream may change + // only the last inputstream after notifying the document + // headers is valid + + Reference<XContentIdentifier> xContId( + xContent.is() ? xContent->getIdentifier() : 0 ); + + rtl::OUString aScheme; + if(xContId.is()) + aScheme = xContId->getContentProviderScheme(); + + // now determine wether we use a timeout or not; + if( ! aScheme.equalsIgnoreAsciiCaseAscii("http") && + ! aScheme.equalsIgnoreAsciiCaseAscii("https") && + ! aScheme.equalsIgnoreAsciiCaseAscii("vnd.sun.star.webdav") && + ! aScheme.equalsIgnoreAsciiCaseAscii("ftp")) + return _UCBOpenContentSync( + xLockBytes,xContent,rArg,xSink,xInteract,xProgress,xHandler); + + if ( (aScheme.compareToAscii( "http" ) != COMPARE_EQUAL) || + (aScheme.compareToAscii( "https" ) != COMPARE_EQUAL) ) + xLockBytes->SetStreamValid_Impl(); + + Reference< XPropertiesChangeListener > xListener; + Reference< XPropertiesChangeNotifier > xProps(xContent,UNO_QUERY); + if(xProps.is()) { + xListener = + new UcbPropertiesChangeListener_Impl(xLockBytes); + xProps->addPropertiesChangeListener( + Sequence< ::rtl::OUString >(), + xListener); + } + + Any aResult; + bool bException(false); + bool bAborted(false); + bool bResultAchieved(false); + + Moderator* pMod = 0; + try { + pMod = new Moderator(xContent,xInteract,xProgress,rArg); + pMod->create(); + } catch(const ContentCreationException&) { + bResultAchieved = bException = true; + xLockBytes->SetError( ERRCODE_IO_GENERAL ); + } + + sal_uInt32 nTimeout(5000); // initially 5000 milliSec + while(!bResultAchieved) { + + Moderator::Result res; + // try to get the result for with timeout + res = pMod->getResult(nTimeout); + + switch(res.type) { + case Moderator::PROGRESSPUSH: + { + if(xProgress.is()) + xProgress->push(res.result); + pMod->setReply(Moderator::REQUESTHANDLED); + break; + } + case Moderator::PROGRESSUPDATE: + { + if(xProgress.is()) + xProgress->update(res.result); + pMod->setReply(Moderator::REQUESTHANDLED); + break; + } + case Moderator::PROGRESSPOP: + { + if(xProgress.is()) + xProgress->pop(); + pMod->setReply(Moderator::REQUESTHANDLED); + break; + } + case Moderator::STREAM: + { + Reference<XStream> result; + if(res.result >>= result) { + Reference < XActiveDataStreamer > xStreamer( + xSink, UNO_QUERY + ); + + if(xStreamer.is()) + xStreamer->setStream(result); + } + pMod->setReply(Moderator::REQUESTHANDLED); + break; + } + case Moderator::INPUTSTREAM: + { + Reference<XInputStream> result; + res.result >>= result; + Reference < XActiveDataSink > xActiveSink( + xSink, UNO_QUERY + ); + + if(xActiveSink.is()) + xActiveSink->setInputStream(result); + pMod->setReply(Moderator::REQUESTHANDLED); + break; + } + case Moderator::TIMEDOUT: + { + Reference<XInteractionRetry> xRet; + if(xInteract.is()) { + InteractiveNetworkConnectException aExcep; + INetURLObject aURL( + xContId.is() ? + xContId->getContentIdentifier() : + rtl::OUString() ); + aExcep.Server = aURL.GetHost(); + aExcep.Classification = InteractionClassification_ERROR; + aExcep.Message = + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "server not responding after five seconds")); + Any request; + request <<= aExcep; + ucbhelper::InteractionRequest *ir = + new ucbhelper::InteractionRequest(request); + Reference<XInteractionRequest> xIR(ir); + Sequence<Reference<XInteractionContinuation> > aSeq(2); + ucbhelper::InteractionRetry *retryP = + new ucbhelper::InteractionRetry(ir); + aSeq[0] = retryP; + ucbhelper::InteractionAbort *abortP = + new ucbhelper::InteractionAbort(ir); + aSeq[1] = abortP; + + ir->setContinuations(aSeq); + xInteract->handle(xIR); + rtl::Reference< ucbhelper::InteractionContinuation > ref + = ir->getSelection(); + if(ref.is()) { + Reference<XInterface> xInt(ref.get()); + xRet = Reference<XInteractionRetry>(xInt,UNO_QUERY); + } + } + + if(!xRet.is()) { + bAborted = true; + xLockBytes->SetError(ERRCODE_ABORT); + } + + break; + } + case Moderator::INTERACTIONREQUEST: + { + Reference<XInteractionRequest> Request; + res.result >>= Request; + xInteract->handle(Request); + pMod->setReply(Moderator::REQUESTHANDLED); + break; + } + case Moderator::RESULT: + { + bResultAchieved = true; + aResult = res.result; + break; + } + case Moderator::COMMANDABORTED: + { + bAborted = true; + xLockBytes->SetError( ERRCODE_ABORT ); + break; + } + case Moderator::COMMANDFAILED: + { + bAborted = true; + xLockBytes->SetError( ERRCODE_ABORT ); + break; + } + case Moderator::INTERACTIVEIO: + { + bException = true; + if ( res.ioErrorCode == IOErrorCode_ACCESS_DENIED || + res.ioErrorCode == IOErrorCode_LOCKING_VIOLATION ) + xLockBytes->SetError( ERRCODE_IO_ACCESSDENIED ); + else if ( res.ioErrorCode == IOErrorCode_NOT_EXISTING ) + xLockBytes->SetError( ERRCODE_IO_NOTEXISTS ); + else if ( res.ioErrorCode == IOErrorCode_CANT_READ ) + xLockBytes->SetError( ERRCODE_IO_CANTREAD ); + else + xLockBytes->SetError( ERRCODE_IO_GENERAL ); + break; + } + case Moderator::UNSUPPORTED: + { + bException = true; + xLockBytes->SetError( ERRCODE_IO_NOTSUPPORTED ); + break; + } + default: + { + bException = true; + xLockBytes->SetError( ERRCODE_IO_GENERAL ); + break; + } + } + + bResultAchieved |= bException; + bResultAchieved |= bAborted; + if(nTimeout == 5000) nTimeout *= 2; + } + + if(pMod) pMod->setReply(Moderator::EXIT); + + if ( bAborted || bException ) + { + if( xHandler.Is() ) + xHandler->Handle( UcbLockBytesHandler::CANCEL, xLockBytes ); + + Reference < XActiveDataSink > xActiveSink( xSink, UNO_QUERY ); + if ( xActiveSink.is() ) + xActiveSink->setInputStream( Reference < XInputStream >() ); + + Reference < XActiveDataStreamer > xStreamer( xSink, UNO_QUERY ); + if ( xStreamer.is() ) + xStreamer->setStream( Reference < XStream >() ); + } + + Reference < XActiveDataControl > xControl( xSink, UNO_QUERY ); + if ( xControl.is() ) + xControl->terminate(); + + if ( xProps.is() ) + xProps->removePropertiesChangeListener( + Sequence< ::rtl::OUString >(), + xListener ); + + return ( bAborted || bException ); +} + +/** + Function for opening UCB contents synchronously + */ +static sal_Bool _UCBOpenContentSync( + UcbLockBytesRef xLockBytes, + Reference < XContent > xContent, + const Command& rArg, + Reference < XInterface > xSink, + Reference < XInteractionHandler > xInteract, + Reference < XProgressHandler > xProgress, + UcbLockBytesHandlerRef xHandler ) +{ + ::ucbhelper::Content aContent( xContent, new UcbTaskEnvironment( xInteract, xProgress ) ); + Reference < XContentIdentifier > xIdent = xContent->getIdentifier(); + ::rtl::OUString aScheme = xIdent->getContentProviderScheme(); + + // http protocol must be handled in a special way: during the opening process the input stream may change + // only the last inputstream after notifying the document headers is valid + if ( aScheme.compareToAscii("http") != COMPARE_EQUAL ) + xLockBytes->SetStreamValid_Impl(); + + Reference< XPropertiesChangeListener > xListener = new UcbPropertiesChangeListener_Impl( xLockBytes ); + Reference< XPropertiesChangeNotifier > xProps ( xContent, UNO_QUERY ); + if ( xProps.is() ) + xProps->addPropertiesChangeListener( Sequence< ::rtl::OUString >(), xListener ); + + Any aResult; + bool bException = false; + bool bAborted = false; + + try + { + aResult = aContent.executeCommand( rArg.Name, rArg.Argument ); + } + catch ( CommandAbortedException ) + { + bAborted = true; + xLockBytes->SetError( ERRCODE_ABORT ); + } + catch ( CommandFailedException ) + { + bAborted = true; + xLockBytes->SetError( ERRCODE_ABORT ); + } + catch ( InteractiveIOException& r ) + { + bException = true; + if ( r.Code == IOErrorCode_ACCESS_DENIED || r.Code == IOErrorCode_LOCKING_VIOLATION ) + xLockBytes->SetError( ERRCODE_IO_ACCESSDENIED ); + else if ( r.Code == IOErrorCode_NOT_EXISTING ) + xLockBytes->SetError( ERRCODE_IO_NOTEXISTS ); + else if ( r.Code == IOErrorCode_CANT_READ ) + xLockBytes->SetError( ERRCODE_IO_CANTREAD ); + else + xLockBytes->SetError( ERRCODE_IO_GENERAL ); + } + catch ( UnsupportedDataSinkException& ) + { + bException = true; + xLockBytes->SetError( ERRCODE_IO_NOTSUPPORTED ); + } + catch ( Exception ) + { + bException = true; + xLockBytes->SetError( ERRCODE_IO_GENERAL ); + } + + if ( bAborted || bException ) + { + if( xHandler.Is() ) + xHandler->Handle( UcbLockBytesHandler::CANCEL, xLockBytes ); + + Reference < XActiveDataSink > xActiveSink( xSink, UNO_QUERY ); + if ( xActiveSink.is() ) + xActiveSink->setInputStream( Reference < XInputStream >() ); + + Reference < XActiveDataStreamer > xStreamer( xSink, UNO_QUERY ); + if ( xStreamer.is() ) + xStreamer->setStream( Reference < XStream >() ); + } + + Reference < XActiveDataControl > xControl( xSink, UNO_QUERY ); + if ( xControl.is() ) + xControl->terminate(); + + + if ( xProps.is() ) + xProps->removePropertiesChangeListener( Sequence< ::rtl::OUString >(), xListener ); + + return ( bAborted || bException ); +} + + +//---------------------------------------------------------------------------- +UcbLockBytes::UcbLockBytes( UcbLockBytesHandler* pHandler ) + : m_xInputStream (NULL) + , m_pCommandThread( NULL ) + , m_xHandler( pHandler ) + , m_nError( ERRCODE_NONE ) + , m_bTerminated (sal_False) + , m_bDontClose( sal_False ) + , m_bStreamValid (sal_False) +{ + SetSynchronMode( sal_True ); +} + +//---------------------------------------------------------------------------- +UcbLockBytes::~UcbLockBytes() +{ + if ( !m_bDontClose ) + { + if ( m_xInputStream.is() ) + { + try + { + m_xInputStream->closeInput(); + } + catch ( RuntimeException const & ) + {} + catch ( IOException const & ) + {} + } + } + + if ( !m_xInputStream.is() && m_xOutputStream.is() ) + { + try + { + m_xOutputStream->closeOutput(); + } + catch ( RuntimeException const & ) + {} + catch ( IOException const & ) + {} + } +} + +Reference < XInputStream > UcbLockBytes::getInputStream() +{ + vos::OClearableGuard aGuard( m_aMutex ); + m_bDontClose = sal_True; + return m_xInputStream; +} + +Reference < XStream > UcbLockBytes::getStream() +{ + vos::OClearableGuard aGuard( m_aMutex ); + Reference < XStream > xStream( m_xSeekable, UNO_QUERY ); + if ( xStream.is() ) + m_bDontClose = sal_True; + return xStream; +} + +//---------------------------------------------------------------------------- + +sal_Bool UcbLockBytes::setStream_Impl( const Reference<XStream>& aStream ) +{ + vos::OClearableGuard aGuard( m_aMutex ); + if ( aStream.is() ) + { + m_xOutputStream = aStream->getOutputStream(); + setInputStream_Impl( aStream->getInputStream(), sal_False ); + m_xSeekable = Reference < XSeekable > ( aStream, UNO_QUERY ); + } + else + { + m_xOutputStream = Reference < XOutputStream >(); + setInputStream_Impl( Reference < XInputStream >() ); + } + + return m_xInputStream.is(); +} + +sal_Bool UcbLockBytes::setInputStream_Impl( const Reference<XInputStream> &rxInputStream, sal_Bool bSetXSeekable ) +{ + sal_Bool bRet = sal_False; + + try + { + vos::OClearableGuard aGuard( m_aMutex ); + + if ( !m_bDontClose && m_xInputStream.is() ) + m_xInputStream->closeInput(); + + m_xInputStream = rxInputStream; + + if( bSetXSeekable ) + { + m_xSeekable = Reference < XSeekable > ( rxInputStream, UNO_QUERY ); + if( !m_xSeekable.is() && rxInputStream.is() ) + { + Reference < XMultiServiceFactory > xFactory = ::comphelper::getProcessServiceFactory(); + Reference< XOutputStream > rxTempOut = Reference < XOutputStream > ( + xFactory->createInstance ( ::rtl::OUString::createFromAscii( "com.sun.star.io.TempFile" ) ), + UNO_QUERY ); + + if( rxTempOut.is() ) + { + ::comphelper::OStorageHelper::CopyInputToOutput( rxInputStream, rxTempOut ); + m_xInputStream = Reference< XInputStream >( rxTempOut, UNO_QUERY ); + m_xSeekable = Reference < XSeekable > ( rxTempOut, UNO_QUERY ); + } + } + } + + bRet = m_xInputStream.is(); + // aGuard.clear(); + } + catch( Exception& ) + {} + + if ( m_bStreamValid && m_xInputStream.is() ) + m_aInitialized.set(); + + return bRet; +} + +void UcbLockBytes::SetStreamValid_Impl() +{ + m_bStreamValid = sal_True; + if ( m_xInputStream.is() ) + m_aInitialized.set(); +} + +//---------------------------------------------------------------------------- +void UcbLockBytes::terminate_Impl() +{ + m_bTerminated = sal_True; + m_aInitialized.set(); + m_aTerminated.set(); + + if ( GetError() == ERRCODE_NONE && !m_xInputStream.is() ) + { + DBG_ERROR("No InputStream, but no error set!" ); + SetError( ERRCODE_IO_NOTEXISTS ); + } + + if ( m_xHandler.Is() ) + m_xHandler->Handle( UcbLockBytesHandler::DONE, this ); +} + +//---------------------------------------------------------------------------- +void UcbLockBytes::SetSynchronMode (sal_Bool bSynchron) +{ + SvLockBytes::SetSynchronMode (bSynchron); +} + +//---------------------------------------------------------------------------- +ErrCode UcbLockBytes::ReadAt ( sal_uLong nPos, void *pBuffer, sal_uLong nCount, sal_uLong *pRead) const +{ + if ( IsSynchronMode() ) + { + UcbLockBytes* pThis = const_cast < UcbLockBytes* >( this ); + pThis->m_aInitialized.wait(); + } + + Reference <XInputStream> xStream = getInputStream_Impl(); + if ( !xStream.is() ) + { + if ( m_bTerminated ) + return ERRCODE_IO_CANTREAD; + else + return ERRCODE_IO_PENDING; + } + + if ( pRead ) + *pRead = 0; + + Reference <XSeekable> xSeekable = getSeekable_Impl(); + if ( !xSeekable.is() ) + return ERRCODE_IO_CANTREAD; + + try + { + xSeekable->seek( nPos ); + } + catch ( IOException ) + { + return ERRCODE_IO_CANTSEEK; + } + catch (com::sun::star::lang::IllegalArgumentException) + { + return ERRCODE_IO_CANTSEEK; + } + + Sequence<sal_Int8> aData; + sal_Int32 nSize; + + nCount = VOS_MIN(nCount, 0x7FFFFFFF); + try + { + if ( !m_bTerminated && !IsSynchronMode() ) + { + sal_uInt64 nLen = xSeekable->getLength(); + if ( nPos + nCount > nLen ) + return ERRCODE_IO_PENDING; + } + + nSize = xStream->readBytes( aData, sal_Int32(nCount) ); + } + catch (IOException) + { + return ERRCODE_IO_CANTREAD; + } + + rtl_copyMemory (pBuffer, aData.getConstArray(), nSize); + if (pRead) + *pRead = sal_uLong(nSize); + + return ERRCODE_NONE; +} + +//---------------------------------------------------------------------------- +ErrCode UcbLockBytes::WriteAt ( sal_uLong nPos, const void *pBuffer, sal_uLong nCount, sal_uLong *pWritten) +{ + if ( pWritten ) + *pWritten = 0; + + DBG_ASSERT( IsSynchronMode(), "Writing is only possible in SynchronMode!" ); + DBG_ASSERT( m_aInitialized.check(), "Writing bevor stream is ready!" ); + + Reference <XSeekable> xSeekable = getSeekable_Impl(); + Reference <XOutputStream> xOutputStream = getOutputStream_Impl(); + if ( !xOutputStream.is() || !xSeekable.is() ) + return ERRCODE_IO_CANTWRITE; + + try + { + xSeekable->seek( nPos ); + } + catch ( IOException ) + { + return ERRCODE_IO_CANTSEEK; + } + + sal_Int8* pData = (sal_Int8*) pBuffer; + Sequence<sal_Int8> aData( pData, nCount ); + try + { + xOutputStream->writeBytes( aData ); + if ( pWritten ) + *pWritten = nCount; + } + catch ( Exception ) + { + return ERRCODE_IO_CANTWRITE; + } + + return ERRCODE_NONE; +} + +//---------------------------------------------------------------------------- +ErrCode UcbLockBytes::Flush() const +{ + Reference <XOutputStream > xOutputStream = getOutputStream_Impl(); + if ( !xOutputStream.is() ) + return ERRCODE_IO_CANTWRITE; + + try + { + xOutputStream->flush(); + } + catch( Exception ) + { + return ERRCODE_IO_CANTWRITE; + } + + return ERRCODE_NONE; +} + +//---------------------------------------------------------------------------- +ErrCode UcbLockBytes::SetSize (sal_uLong nNewSize) +{ + SvLockBytesStat aStat; + Stat( &aStat, (SvLockBytesStatFlag) 0 ); + sal_uLong nSize = aStat.nSize; + + if ( nSize > nNewSize ) + { + Reference < XTruncate > xTrunc( getOutputStream_Impl(), UNO_QUERY ); + if ( xTrunc.is() ) + { + xTrunc->truncate(); + nSize = 0; + } + else { + DBG_WARNING("Not truncatable!"); + } + } + + if ( nSize < nNewSize ) + { + sal_uLong nDiff = nNewSize-nSize, nCount=0; + sal_uInt8* pBuffer = new sal_uInt8[ nDiff ]; + memset(pBuffer, 0, nDiff); // initialize for enhanced security + WriteAt( nSize, pBuffer, nDiff, &nCount ); + delete[] pBuffer; + if ( nCount != nDiff ) + return ERRCODE_IO_CANTWRITE; + } + + return ERRCODE_NONE; +} + +//---------------------------------------------------------------------------- +ErrCode UcbLockBytes::Stat( SvLockBytesStat *pStat, SvLockBytesStatFlag) const +{ + if ( IsSynchronMode() ) + { + UcbLockBytes* pThis = const_cast < UcbLockBytes* >( this ); + pThis->m_aInitialized.wait(); + } + + if (!pStat) + return ERRCODE_IO_INVALIDPARAMETER; + + Reference <XInputStream> xStream = getInputStream_Impl(); + Reference <XSeekable> xSeekable = getSeekable_Impl(); + + if ( !xStream.is() ) + { + if ( m_bTerminated ) + return ERRCODE_IO_INVALIDACCESS; + else + return ERRCODE_IO_PENDING; + } + else if( !xSeekable.is() ) + return ERRCODE_IO_CANTTELL; + + try + { + pStat->nSize = sal_uLong(xSeekable->getLength()); + } + catch (IOException) + { + return ERRCODE_IO_CANTTELL; + } + + return ERRCODE_NONE; +} + +//---------------------------------------------------------------------------- +void UcbLockBytes::Cancel() +{ + // is alive only for compatibility reasons + OSL_ENSURE( m_bTerminated, "UcbLockBytes is not thread safe so it can be used only syncronously!\n" ); +} + +//---------------------------------------------------------------------------- +IMPL_LINK( UcbLockBytes, DataAvailHdl, void*, EMPTYARG ) +{ + if ( hasInputStream_Impl() && m_xHandler.Is() ) + m_xHandler->Handle( UcbLockBytesHandler::DATA_AVAILABLE, this ); + + return 0; +} + +UcbLockBytesRef UcbLockBytes::CreateInputLockBytes( const Reference< XInputStream >& xInputStream ) +{ + if( !xInputStream.is() ) + return NULL;; + + UcbLockBytesRef xLockBytes = new UcbLockBytes(); + xLockBytes->setDontClose_Impl(); + xLockBytes->setInputStream_Impl( xInputStream ); + xLockBytes->terminate_Impl(); + return xLockBytes; +} + +UcbLockBytesRef UcbLockBytes::CreateLockBytes( const Reference< XStream >& xStream ) +{ + if( !xStream.is() ) + return NULL;; + + UcbLockBytesRef xLockBytes = new UcbLockBytes(); + xLockBytes->setDontClose_Impl(); + xLockBytes->setStream_Impl( xStream ); + xLockBytes->terminate_Impl(); + return xLockBytes; +} + +UcbLockBytesRef UcbLockBytes::CreateLockBytes( const Reference < XContent >& xContent, const ::rtl::OUString& rReferer, const ::rtl::OUString& rMediaType, + const Reference < XInputStream >& xPostData, const Reference < XInteractionHandler >& xInteractionHandler, UcbLockBytesHandler* pHandler ) +{ + if( !xContent.is() ) + return NULL;; + + UcbLockBytesRef xLockBytes = new UcbLockBytes( pHandler ); + xLockBytes->SetSynchronMode( !pHandler ); + Reference< XActiveDataControl > xSink = (XActiveDataControl*) new UcbDataSink_Impl( xLockBytes ); + + PostCommandArgument2 aArgument; + aArgument.Source = xPostData; + aArgument.Sink = xSink; + aArgument.MediaType = rMediaType; + aArgument.Referer = rReferer; + + Command aCommand; + aCommand.Name = ::rtl::OUString::createFromAscii ("post"); + aCommand.Argument <<= aArgument; + + Reference< XProgressHandler > xProgressHdl = new ProgressHandler_Impl( LINK( &xLockBytes, UcbLockBytes, DataAvailHdl ) ); + + sal_Bool bError = UCBOpenContentSync( xLockBytes, + xContent, + aCommand, + xSink, + xInteractionHandler, + xProgressHdl, + pHandler ); + + if ( xLockBytes->GetError() == ERRCODE_NONE && ( bError || !xLockBytes->getInputStream().is() ) ) + { + DBG_ERROR("No InputStream, but no error set!" ); + xLockBytes->SetError( ERRCODE_IO_GENERAL ); + } + + return xLockBytes; +} + +UcbLockBytesRef UcbLockBytes::CreateLockBytes( const Reference < XContent >& xContent, const Sequence < PropertyValue >& rProps, + StreamMode eOpenMode, const Reference < XInteractionHandler >& xInteractionHandler, UcbLockBytesHandler* pHandler ) +{ + if( !xContent.is() ) + return NULL;; + + UcbLockBytesRef xLockBytes = new UcbLockBytes( pHandler ); + xLockBytes->SetSynchronMode( !pHandler ); + Reference< XActiveDataControl > xSink; + if ( eOpenMode & STREAM_WRITE ) + xSink = (XActiveDataControl*) new UcbStreamer_Impl( xLockBytes ); + else + xSink = (XActiveDataControl*) new UcbDataSink_Impl( xLockBytes ); + + if ( rProps.getLength() ) + { + Reference < XCommandProcessor > xProcessor( xContent, UNO_QUERY ); + Command aCommand; + aCommand.Name = ::rtl::OUString::createFromAscii("setPropertyValues"); + aCommand.Handle = -1; /* unknown */ + aCommand.Argument <<= rProps; + xProcessor->execute( aCommand, 0, Reference < XCommandEnvironment >() ); + } + + OpenCommandArgument2 aArgument; + aArgument.Sink = xSink; + aArgument.Mode = OpenMode::DOCUMENT; + + Command aCommand; + aCommand.Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("open") ); + aCommand.Argument <<= aArgument; + + Reference< XProgressHandler > xProgressHdl = new ProgressHandler_Impl( LINK( &xLockBytes, UcbLockBytes, DataAvailHdl ) ); + + sal_Bool bError = UCBOpenContentSync( xLockBytes, + xContent, + aCommand, + xSink, + xInteractionHandler, + xProgressHdl, + pHandler ); + + if ( xLockBytes->GetError() == ERRCODE_NONE && ( bError || !xLockBytes->getInputStream().is() ) ) + { + DBG_ERROR("No InputStream, but no error set!" ); + xLockBytes->SetError( ERRCODE_IO_GENERAL ); + } + + return xLockBytes; +} + +} |