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