xref: /trunk/main/unotools/source/ucbhelper/ucblockbytes.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_unotools.hxx"
30 
31 #include <unotools/ucblockbytes.hxx>
32 #include <comphelper/processfactory.hxx>
33 #include <salhelper/condition.hxx>
34 #ifndef _OSL_THREAD_HXX_
35 #include <osl/thread.hxx>
36 #endif
37 #include <tools/urlobj.hxx>
38 #include <ucbhelper/interactionrequest.hxx>
39 #include <com/sun/star/task/XInteractionAbort.hpp>
40 #include <com/sun/star/ucb/InteractiveNetworkConnectException.hpp>
41 #include <com/sun/star/ucb/CommandFailedException.hpp>
42 #include <com/sun/star/ucb/UnsupportedDataSinkException.hpp>
43 #ifndef _COM_SUN_STAR_UCB_INTERACTIVEIODEXCEPTION_HPP_
44 #include <com/sun/star/ucb/InteractiveIOException.hpp>
45 #endif
46 #include <com/sun/star/io/XActiveDataStreamer.hpp>
47 #include <com/sun/star/ucb/DocumentHeaderField.hpp>
48 #include <com/sun/star/ucb/XCommandInfo.hpp>
49 #include <com/sun/star/ucb/XCommandProcessor.hpp>
50 #include <com/sun/star/task/XInteractionHandler.hpp>
51 #include <com/sun/star/ucb/OpenCommandArgument2.hpp>
52 #include <com/sun/star/ucb/PostCommandArgument2.hpp>
53 #include <com/sun/star/ucb/OpenMode.hpp>
54 #include <com/sun/star/beans/Property.hpp>
55 #include <com/sun/star/beans/PropertyValue.hpp>
56 #include <com/sun/star/beans/XPropertiesChangeNotifier.hpp>
57 #include <com/sun/star/beans/XPropertiesChangeListener.hpp>
58 #include <com/sun/star/sdbc/XRow.hpp>
59 #include <com/sun/star/io/XActiveDataSink.hpp>
60 #include <com/sun/star/io/XActiveDataControl.hpp>
61 #include <com/sun/star/io/XSeekable.hpp>
62 #include <cppuhelper/implbase1.hxx>
63 #include <cppuhelper/implbase2.hxx>
64 #include <tools/inetmsg.hxx>
65 #include <com/sun/star/io/XTruncate.hpp>
66 #include <com/sun/star/lang/IllegalArgumentException.hpp>
67 
68 #include <comphelper/storagehelper.hxx>
69 
70 #include <ucbhelper/contentbroker.hxx>
71 #include <ucbhelper/content.hxx>
72 
73 using namespace ::com::sun::star::uno;
74 using namespace ::com::sun::star::io;
75 using namespace ::com::sun::star::uno;
76 using namespace ::com::sun::star::ucb;
77 using namespace ::com::sun::star::task;
78 using namespace ::com::sun::star::lang;
79 using namespace ::com::sun::star::beans;
80 
81 
82 namespace utl
83 {
84 
85 /**
86     Helper class for getting a XInputStream when opening a content
87  */
88 class UcbDataSink_Impl : public ::cppu::WeakImplHelper2< XActiveDataControl, XActiveDataSink >
89 {
90     UcbLockBytesRef         m_xLockBytes;
91 
92 public:
93                             UcbDataSink_Impl( UcbLockBytes* pLockBytes )
94                                 : m_xLockBytes( pLockBytes )
95                             {}
96 
97     SvLockBytes*            getLockBytes (void)
98                             { return m_xLockBytes; }
99 
100     // XActiveDataControl.
101     virtual void SAL_CALL   addListener ( const Reference<XStreamListener> &/*rxListener*/) throw(RuntimeException) {}
102     virtual void SAL_CALL   removeListener ( const Reference<XStreamListener> &/*rxListener*/) throw(RuntimeException) {}
103     virtual void SAL_CALL   start (void) throw(RuntimeException) {}
104     virtual void SAL_CALL   terminate (void) throw(RuntimeException)
105                             { m_xLockBytes->terminate_Impl(); }
106 
107     // XActiveDataSink.
108     virtual void SAL_CALL   setInputStream ( const Reference<XInputStream> &rxInputStream) throw(RuntimeException)
109                             { m_xLockBytes->setInputStream_Impl (rxInputStream); }
110     virtual Reference<XInputStream> SAL_CALL getInputStream (void) throw(RuntimeException)
111                             { return m_xLockBytes->getInputStream_Impl(); }
112 };
113 
114 /**
115     Helper class for getting a XStream when opening a content
116  */
117 class UcbStreamer_Impl : public ::cppu::WeakImplHelper2< XActiveDataStreamer, XActiveDataControl >
118 {
119     Reference < XStream >   m_xStream;
120     UcbLockBytesRef         m_xLockBytes;
121 
122 public:
123 
124                             UcbStreamer_Impl( UcbLockBytes* pLockBytes )
125                                 : m_xLockBytes( pLockBytes )
126                             {}
127 
128     // XActiveDataControl.
129     virtual void SAL_CALL   addListener ( const Reference<XStreamListener> &/*rxListener*/) throw(RuntimeException) {}
130     virtual void SAL_CALL   removeListener ( const Reference<XStreamListener> &/*rxListener*/) throw(RuntimeException) {}
131     virtual void SAL_CALL   start (void) throw(RuntimeException) {}
132     virtual void SAL_CALL   terminate (void) throw(RuntimeException)
133                             { m_xLockBytes->terminate_Impl(); }
134 
135     // XActiveDataStreamer
136     virtual void SAL_CALL   setStream( const Reference< XStream >& aStream ) throw(RuntimeException)
137                             { m_xStream = aStream; m_xLockBytes->setStream_Impl( aStream ); }
138     virtual Reference< XStream > SAL_CALL getStream() throw(RuntimeException)
139                             { return m_xStream; }
140 };
141 
142 /**
143     Helper class for progress handling while executing UCB commands
144  */
145 class ProgressHandler_Impl: public ::cppu::WeakImplHelper1< XProgressHandler >
146 {
147     Link                    m_aProgress;
148 
149 public:
150                             ProgressHandler_Impl( const Link& rLink )
151                                 : m_aProgress( rLink )
152                             {}
153     // XProgressHandler
154     virtual void SAL_CALL   push(const Any & /*rStatus*/) throw (RuntimeException) {}
155     virtual void SAL_CALL   pop() throw (RuntimeException) {}
156     virtual void SAL_CALL   update(const Any & /*rStatus*/) throw (RuntimeException)
157                             { if ( m_aProgress.IsSet() ) m_aProgress.Call( 0 ); }
158 };
159 
160 /**
161     Helper class for managing interactions and progress when executing UCB commands
162  */
163 class UcbTaskEnvironment : public ::cppu::WeakImplHelper1< XCommandEnvironment >
164 {
165     Reference< XInteractionHandler >                m_xInteractionHandler;
166     Reference< XProgressHandler >                   m_xProgressHandler;
167 
168 public:
169                             UcbTaskEnvironment( const Reference< XInteractionHandler>& rxInteractionHandler,
170                                                 const Reference< XProgressHandler>& rxProgressHandler )
171                                 : m_xInteractionHandler( rxInteractionHandler )
172                                 , m_xProgressHandler( rxProgressHandler )
173                             {}
174 
175 
176     virtual Reference<XInteractionHandler> SAL_CALL getInteractionHandler() throw (RuntimeException)
177     { return m_xInteractionHandler; }
178 
179     virtual Reference<XProgressHandler> SAL_CALL    getProgressHandler() throw (RuntimeException)
180     { return m_xProgressHandler; }
181 };
182 
183 
184 /**
185     Helper class for property change notifies when executing UCB commands
186 */
187 class UcbPropertiesChangeListener_Impl : public ::cppu::WeakImplHelper1< XPropertiesChangeListener >
188 {
189 public:
190     UcbLockBytesRef         m_xLockBytes;
191 
192                             UcbPropertiesChangeListener_Impl( UcbLockBytesRef rRef )
193                                 : m_xLockBytes( rRef )
194                             {}
195 
196     virtual void SAL_CALL   disposing ( const EventObject &/*rEvent*/) throw(RuntimeException) {}
197     virtual void SAL_CALL   propertiesChange ( const Sequence<PropertyChangeEvent> &rEvent) throw(RuntimeException);
198 };
199 
200 void SAL_CALL UcbPropertiesChangeListener_Impl::propertiesChange ( const Sequence<PropertyChangeEvent> &rEvent) throw(RuntimeException)
201 {
202     sal_Int32 i, n = rEvent.getLength();
203     for (i = 0; i < n; i++)
204     {
205         PropertyChangeEvent evt (rEvent[i]);
206         if (evt.PropertyName == ::rtl::OUString::createFromAscii ("DocumentHeader"))
207         {
208             Sequence<DocumentHeaderField> aHead;
209             if (evt.NewValue >>= aHead)
210             {
211                 sal_Int32 k, m = aHead.getLength();
212                 for (k = 0; k < m; k++)
213                 {
214                     String aName( aHead[k].Name );
215                     String aValue( aHead[k].Value );
216 
217                     if (aName.CompareIgnoreCaseToAscii("Expires") == COMPARE_EQUAL)
218                     {
219                         DateTime aExpires (0, 0);
220                         if (INetRFC822Message::ParseDateField (aValue, aExpires))
221                         {
222                             aExpires.ConvertToLocalTime();
223                             m_xLockBytes->SetExpireDate_Impl( aExpires );
224                         }
225                     }
226                 }
227             }
228 
229             m_xLockBytes->SetStreamValid_Impl();
230         }
231         else if (evt.PropertyName == rtl::OUString::createFromAscii ("PresentationURL"))
232         {
233             ::rtl::OUString aUrl;
234             if (evt.NewValue >>= aUrl)
235             {
236                 ::rtl::OUString aBad (::rtl::OUString::createFromAscii ("private:"));
237                 if (!(aUrl.compareTo (aBad, aBad.getLength()) == 0))
238                 {
239                     // URL changed (Redirection).
240                     m_xLockBytes->SetRealURL_Impl( aUrl );
241                 }
242             }
243         }
244         else if (evt.PropertyName == ::rtl::OUString::createFromAscii ("MediaType"))
245         {
246             ::rtl::OUString aContentType;
247             if (evt.NewValue >>= aContentType)
248                 m_xLockBytes->SetContentType_Impl( aContentType );
249         }
250     }
251 }
252 
253 
254 
255 class Moderator
256     : public osl::Thread
257 {
258     // usage restriction:
259     // It might be possible, that the call to the interactionhandler and/or
260     // progresshandler is done asynchrounsly, while the 'execute' simply
261     // returns. This would imply that these class must be refcounted !!!
262 
263 public:
264 
265     Moderator(
266         Reference < XContent >& xContent,
267         Reference < XInteractionHandler >& xInteract,
268         Reference < XProgressHandler >& xProgress,
269         const Command& rArg
270     )
271         throw(
272             ContentCreationException,
273             RuntimeException
274         );
275 
276     ~Moderator();
277 
278 
279     enum ResultType {
280         NORESULT,
281 
282         INTERACTIONREQUEST,    // reply expected
283 
284         PROGRESSPUSH,
285         PROGRESSUPDATE,
286         PROGRESSPOP,
287 
288         INPUTSTREAM,
289         STREAM,
290 
291         RESULT,
292         TIMEDOUT,
293         COMMANDABORTED,
294         COMMANDFAILED,
295         INTERACTIVEIO,
296         UNSUPPORTED,
297         GENERAL
298     };
299 
300 
301     class ConditionRes
302         : public salhelper::Condition
303     {
304     public:
305 
306         ConditionRes(osl::Mutex& aMutex,Moderator& aModerator)
307             : salhelper::Condition(aMutex),
308               m_aModerator(aModerator)
309         {
310         }
311 
312     protected:
313 
314         bool applies() const {
315             return m_aModerator.m_aResultType != NORESULT;
316         }
317 
318     private:
319 
320         Moderator& m_aModerator;
321     };
322 
323 
324     struct Result {
325         ResultType        type;
326         Any               result;
327         sal_Int32         ioErrorCode;
328     };
329 
330 
331     Result getResult(const sal_uInt32 milliSec);
332 
333 
334     enum ReplyType {
335         NOREPLY,
336         EXIT,
337         RETRY,
338         REQUESTHANDLED
339     };
340 
341 
342     class ConditionRep
343         : public salhelper::Condition
344     {
345     public:
346 
347         ConditionRep(osl::Mutex& aMutex,Moderator& aModerator)
348             : salhelper::Condition(aMutex),
349               m_aModerator(aModerator)
350         {
351         }
352 
353     protected:
354 
355         bool applies() const {
356             return m_aModerator.m_aReplyType != NOREPLY;
357         }
358 
359     private:
360 
361         Moderator& m_aModerator;
362     };
363 
364     void setReply(ReplyType);
365 
366 
367     void handle( const Reference<XInteractionRequest >& Request );
368 
369     void push( const Any& Status );
370 
371     void update( const Any& Status );
372 
373     void pop(  );
374 
375     void setStream(const Reference< XStream >& aStream);
376 
377     void setInputStream(const Reference<XInputStream> &rxInputStream);
378 
379 
380 protected:
381 
382     virtual void SAL_CALL run();
383 
384     virtual void SAL_CALL onTerminated();
385 
386 private:
387 
388     osl::Mutex        m_aMutex;
389 
390     friend class ConditionRes;
391 
392     ConditionRes      m_aRes;
393     ResultType        m_aResultType;
394     sal_Int32         m_nIOErrorCode;
395     Any               m_aResult;
396 
397     friend class ConditionRep;
398 
399     ConditionRep      m_aRep;
400     ReplyType         m_aReplyType;
401 
402     Command                           m_aArg;
403     ::ucbhelper::Content              m_aContent;
404 };
405 
406 
407 class ModeratorsActiveDataStreamer
408     : public ::cppu::WeakImplHelper1<XActiveDataStreamer>
409 {
410 public:
411 
412     ModeratorsActiveDataStreamer(Moderator &theModerator);
413 
414     ~ModeratorsActiveDataStreamer();
415 
416     // XActiveDataStreamer
417     virtual void SAL_CALL
418     setStream(
419         const Reference< XStream >& aStream
420     )
421         throw(
422             RuntimeException
423         );
424 
425     virtual Reference<XStream> SAL_CALL
426     getStream (
427         void
428     ) throw(
429         RuntimeException
430     )
431     {
432         osl::MutexGuard aGuard(m_aMutex);
433         return m_xStream;
434     }
435 
436 
437 private:
438 
439     Moderator& m_aModerator;
440 
441     osl::Mutex m_aMutex;
442     Reference<XStream> m_xStream;
443 };
444 
445 
446 
447 class ModeratorsActiveDataSink
448     : public ::cppu::WeakImplHelper1<XActiveDataSink>
449 {
450 public:
451 
452     ModeratorsActiveDataSink(Moderator &theModerator);
453 
454     ~ModeratorsActiveDataSink();
455 
456     // XActiveDataSink.
457     virtual void SAL_CALL
458     setInputStream (
459         const Reference<XInputStream> &rxInputStream
460     )
461         throw(
462             RuntimeException
463         );
464 
465     virtual Reference<XInputStream> SAL_CALL
466     getInputStream (
467         void
468     ) throw(
469         RuntimeException
470     )
471     {
472         osl::MutexGuard aGuard(m_aMutex);
473         return m_xStream;
474     }
475 
476 
477 private:
478 
479     Moderator& m_aModerator;
480     osl::Mutex m_aMutex;
481     Reference<XInputStream> m_xStream;
482 };
483 
484 
485 
486 ModeratorsActiveDataSink::ModeratorsActiveDataSink(Moderator &theModerator)
487     : m_aModerator(theModerator)
488 {
489 }
490 
491 
492 ModeratorsActiveDataSink::~ModeratorsActiveDataSink()
493 {
494 }
495 
496 // XActiveDataSink.
497 void SAL_CALL
498 ModeratorsActiveDataSink::setInputStream (
499     const Reference<XInputStream> &rxInputStream
500 )
501     throw(
502         RuntimeException
503     )
504 {
505     m_aModerator.setInputStream(rxInputStream);
506     osl::MutexGuard aGuard(m_aMutex);
507     m_xStream = rxInputStream;
508 }
509 
510 
511 ModeratorsActiveDataStreamer::ModeratorsActiveDataStreamer(
512     Moderator &theModerator
513 )
514     : m_aModerator(theModerator)
515 {
516 }
517 
518 
519 ModeratorsActiveDataStreamer::~ModeratorsActiveDataStreamer()
520 {
521 }
522 
523 // XActiveDataStreamer.
524 void SAL_CALL
525 ModeratorsActiveDataStreamer::setStream (
526     const Reference<XStream> &rxStream
527 )
528     throw(
529         RuntimeException
530     )
531 {
532     m_aModerator.setStream(rxStream);
533     osl::MutexGuard aGuard(m_aMutex);
534     m_xStream = rxStream;
535 }
536 
537 
538 
539 class ModeratorsInteractionHandler
540     : public ::cppu::WeakImplHelper1<XInteractionHandler>
541 {
542 public:
543 
544     ModeratorsInteractionHandler(Moderator &theModerator);
545 
546     ~ModeratorsInteractionHandler();
547 
548     virtual void SAL_CALL
549     handle( const Reference<XInteractionRequest >& Request )
550         throw (RuntimeException);
551 
552 private:
553 
554     Moderator& m_aModerator;
555 };
556 
557 
558 class ModeratorsProgressHandler
559     : public ::cppu::WeakImplHelper1<XProgressHandler>
560 {
561 public:
562 
563     ModeratorsProgressHandler(Moderator &theModerator);
564 
565     ~ModeratorsProgressHandler();
566 
567     virtual void SAL_CALL push( const Any& Status )
568         throw (
569             RuntimeException);
570 
571     virtual void SAL_CALL update( const Any& Status )
572         throw (RuntimeException);
573 
574     virtual void SAL_CALL pop(  )
575         throw (RuntimeException);
576 
577 
578 private:
579 
580     Moderator& m_aModerator;
581 };
582 
583 
584 ModeratorsProgressHandler::ModeratorsProgressHandler(Moderator &theModerator)
585     : m_aModerator(theModerator)
586 {
587 }
588 
589 ModeratorsProgressHandler::~ModeratorsProgressHandler()
590 {
591 }
592 
593 
594 void SAL_CALL ModeratorsProgressHandler::push( const Any& Status )
595     throw (
596         RuntimeException)
597 {
598     m_aModerator.push(Status);
599 }
600 
601 
602 void SAL_CALL ModeratorsProgressHandler::update( const Any& Status )
603     throw (RuntimeException)
604 {
605     m_aModerator.update(Status);
606 }
607 
608 
609 void SAL_CALL ModeratorsProgressHandler::pop(  )
610     throw (RuntimeException)
611 {
612     m_aModerator.pop();
613 }
614 
615 
616 
617 
618 ModeratorsInteractionHandler::ModeratorsInteractionHandler(
619     Moderator &aModerator)
620     : m_aModerator(aModerator)
621 {
622 }
623 
624 
625 ModeratorsInteractionHandler::~ModeratorsInteractionHandler()
626 {
627 }
628 
629 
630 void SAL_CALL
631 ModeratorsInteractionHandler::handle(
632     const Reference<XInteractionRequest >& Request
633 )
634     throw (
635         RuntimeException
636     )
637 {
638     // wakes up the mainthread
639     m_aModerator.handle(Request);
640 }
641 
642 
643 
644 
645 Moderator::Moderator(
646     Reference < XContent >& xContent,
647     Reference < XInteractionHandler >& xInteract,
648     Reference < XProgressHandler >& xProgress,
649     const Command& rArg
650 )
651     throw(
652         ::com::sun::star::ucb::ContentCreationException,
653         ::com::sun::star::uno::RuntimeException
654     )
655     : m_aMutex(),
656 
657       m_aRes(m_aMutex,*this),
658       m_aResultType(NORESULT),
659       m_nIOErrorCode(0),
660       m_aResult(),
661 
662       m_aRep(m_aMutex,*this),
663       m_aReplyType(NOREPLY),
664 
665       m_aArg(rArg),
666       m_aContent(
667           xContent,
668           new UcbTaskEnvironment(
669               xInteract.is() ? new ModeratorsInteractionHandler(*this) : 0,
670               xProgress.is() ? new ModeratorsProgressHandler(*this) : 0
671           ))
672 {
673     // now exchange the whole data sink stuff
674     // with a thread safe version
675 
676     Reference<XInterface> *pxSink = NULL;
677 
678     PostCommandArgument2 aPostArg;
679     OpenCommandArgument2 aOpenArg;
680 
681     int dec(2);
682     if(m_aArg.Argument >>= aPostArg) {
683         pxSink = &aPostArg.Sink;
684         dec = 0;
685     }
686     else if(m_aArg.Argument >>= aOpenArg) {
687         pxSink = &aOpenArg.Sink;
688         dec = 1;
689     }
690 
691     if(dec ==2)
692         throw ContentCreationException();
693 
694     Reference < XActiveDataSink > xActiveSink(*pxSink,UNO_QUERY);
695     if(xActiveSink.is())
696         *pxSink = Reference<XInterface>(
697             (cppu::OWeakObject*)new ModeratorsActiveDataSink(*this));
698 
699     Reference<XActiveDataStreamer> xStreamer( *pxSink, UNO_QUERY );
700     if ( xStreamer.is() )
701         *pxSink = Reference<XInterface>(
702             (cppu::OWeakObject*)new ModeratorsActiveDataStreamer(*this));
703 
704     if(dec == 0)
705         m_aArg.Argument <<= aPostArg;
706     else if(dec == 1)
707         m_aArg.Argument <<= aOpenArg;
708 }
709 
710 
711 Moderator::~Moderator()
712 {
713 }
714 
715 
716 Moderator::Result Moderator::getResult(const sal_uInt32 milliSec)
717 {
718     Result ret;
719     try {
720         salhelper::ConditionWaiter aWaiter(m_aRes,milliSec);
721         ret.type = m_aResultType;
722         ret.result = m_aResult;
723         ret.ioErrorCode = m_nIOErrorCode;
724 
725         // reset
726         m_aResultType = NORESULT;
727     }
728     catch(const salhelper::ConditionWaiter::timedout&)
729     {
730         ret.type = TIMEDOUT;
731     }
732 
733     return ret;
734 }
735 
736 
737 void Moderator::setReply(ReplyType aReplyType )
738 {
739     salhelper::ConditionModifier aMod(m_aRep);
740     m_aReplyType = aReplyType;
741 }
742 
743 
744 void Moderator::handle( const Reference<XInteractionRequest >& Request )
745 {
746     ReplyType aReplyType;
747 
748     do {
749         {
750             salhelper::ConditionModifier aMod(m_aRes);
751             m_aResultType = INTERACTIONREQUEST;
752             m_aResult <<= Request;
753         }
754 
755         {
756             salhelper::ConditionWaiter aWait(m_aRep);
757             aReplyType = m_aReplyType;
758 
759             // reset
760             m_aReplyType = NOREPLY;
761         }
762 
763         if(aReplyType == EXIT) {
764             Sequence<Reference<XInteractionContinuation> > aSeq(
765                 Request->getContinuations());
766             for(sal_Int32 i = 0; i < aSeq.getLength(); ++i) {
767                 Reference<XInteractionAbort> aRef(aSeq[i],UNO_QUERY);
768                 if(aRef.is()) {
769                     aRef->select();
770                 }
771             }
772 
773             // resignal the exitcondition
774             setReply(EXIT);
775             break;
776         }
777     } while(aReplyType != REQUESTHANDLED);
778 }
779 
780 
781 
782 void Moderator::push( const Any& Status )
783 {
784     {
785         salhelper::ConditionModifier aMod(m_aRes);
786         m_aResultType = PROGRESSPUSH;
787         m_aResult = Status;
788     }
789     ReplyType aReplyType;
790     {
791         salhelper::ConditionWaiter aWait(m_aRep);
792         aReplyType = m_aReplyType;
793         m_aReplyType = NOREPLY;
794     }
795     if(aReplyType == EXIT)
796         setReply(EXIT);
797 }
798 
799 
800 void Moderator::update( const Any& Status )
801 {
802     {
803         salhelper::ConditionModifier aMod(m_aRes);
804         m_aResultType = PROGRESSUPDATE;
805         m_aResult = Status;
806     }
807     ReplyType aReplyType;
808     {
809         salhelper::ConditionWaiter aWait(m_aRep);
810         aReplyType = m_aReplyType;
811         m_aReplyType = NOREPLY;
812     }
813     if(aReplyType == EXIT)
814         setReply(EXIT);
815 }
816 
817 
818 void Moderator::pop(  )
819 {
820     {
821         salhelper::ConditionModifier aMod(m_aRes);
822         m_aResultType = PROGRESSPOP;
823     }
824     ReplyType aReplyType;
825     {
826         salhelper::ConditionWaiter aWait(m_aRep);
827         aReplyType = m_aReplyType;
828         m_aReplyType = NOREPLY;
829     }
830     if(aReplyType == EXIT)
831         setReply(EXIT);
832 }
833 
834 
835 void Moderator::setStream(const Reference< XStream >& aStream)
836 {
837     {
838         salhelper::ConditionModifier aMod(m_aRes);
839         m_aResultType = STREAM;
840         m_aResult <<= aStream;
841     }
842     ReplyType aReplyType;
843     {
844         salhelper::ConditionWaiter aWait(m_aRep);
845         aReplyType = m_aReplyType;
846         m_aReplyType = NOREPLY;
847     }
848     if(aReplyType == EXIT)
849         setReply(EXIT);
850 }
851 
852 
853 void Moderator::setInputStream(const Reference<XInputStream> &rxInputStream)
854 {
855     {
856         salhelper::ConditionModifier aMod(m_aRes);
857         m_aResultType = INPUTSTREAM;
858         m_aResult <<= rxInputStream;
859     }
860     ReplyType aReplyType;
861     {
862         salhelper::ConditionWaiter aWait(m_aRep);
863         aReplyType = m_aReplyType;
864         m_aReplyType = NOREPLY;
865     }
866     if(aReplyType == EXIT)
867         setReply(EXIT);
868 }
869 
870 
871 
872 void SAL_CALL Moderator::run()
873 {
874     ResultType aResultType;
875     Any        aResult;
876     sal_Int32  nIOErrorCode = 0;
877 
878     try
879     {
880         aResult = m_aContent.executeCommand(m_aArg.Name,m_aArg.Argument);
881         aResultType = RESULT;
882     }
883     catch ( CommandAbortedException )
884     {
885         aResultType = COMMANDABORTED;
886     }
887     catch ( CommandFailedException )
888     {
889         aResultType = COMMANDFAILED;
890     }
891     catch ( InteractiveIOException& r )
892     {
893         nIOErrorCode = r.Code;
894         aResultType = INTERACTIVEIO;
895     }
896     catch ( UnsupportedDataSinkException& )
897     {
898         aResultType = UNSUPPORTED;
899     }
900     catch ( Exception )
901     {
902         aResultType = GENERAL;
903     }
904 
905     {
906         salhelper::ConditionModifier aMod(m_aRes);
907         m_aResultType = aResultType;
908         m_aResult = aResult;
909         m_nIOErrorCode = nIOErrorCode;
910     }
911 }
912 
913 
914 
915 void SAL_CALL Moderator::onTerminated()
916 {
917     {
918         salhelper::ConditionWaiter aWaiter(m_aRep);
919     }
920     delete this;
921 }
922 
923 
924 /**
925    Function for opening UCB contents synchronously,
926    but with handled timeout;
927 */
928 
929 static sal_Bool _UCBOpenContentSync(
930     UcbLockBytesRef xLockBytes,
931     Reference < XContent > xContent,
932     const Command& rArg,
933     Reference < XInterface > xSink,
934     Reference < XInteractionHandler > xInteract,
935     Reference < XProgressHandler > xProgress,
936     UcbLockBytesHandlerRef xHandler );
937 
938 
939 static sal_Bool UCBOpenContentSync(
940     UcbLockBytesRef xLockBytes,
941     Reference < XContent > xContent,
942     const Command& rArg,
943     Reference < XInterface > xSink,
944     Reference < XInteractionHandler > xInteract,
945     Reference < XProgressHandler > xProgress,
946     UcbLockBytesHandlerRef xHandler )
947 {
948     // http protocol must be handled in a special way:
949     //        during the opening process the input stream may change
950     //        only the last inputstream after notifying the document
951     //        headers is valid
952 
953     Reference<XContentIdentifier> xContId(
954         xContent.is() ? xContent->getIdentifier() : 0 );
955 
956     rtl::OUString aScheme;
957     if(xContId.is())
958         aScheme = xContId->getContentProviderScheme();
959 
960     // now determine wether we use a timeout or not;
961     if( ! aScheme.equalsIgnoreAsciiCaseAscii("http")                &&
962         ! aScheme.equalsIgnoreAsciiCaseAscii("https")                &&
963         ! aScheme.equalsIgnoreAsciiCaseAscii("vnd.sun.star.webdav") &&
964         ! aScheme.equalsIgnoreAsciiCaseAscii("ftp"))
965         return _UCBOpenContentSync(
966             xLockBytes,xContent,rArg,xSink,xInteract,xProgress,xHandler);
967 
968     if ( (aScheme.compareToAscii( "http" ) != COMPARE_EQUAL) ||
969          (aScheme.compareToAscii( "https" ) != COMPARE_EQUAL) )
970         xLockBytes->SetStreamValid_Impl();
971 
972     Reference< XPropertiesChangeListener > xListener;
973     Reference< XPropertiesChangeNotifier > xProps(xContent,UNO_QUERY);
974     if(xProps.is()) {
975         xListener =
976             new UcbPropertiesChangeListener_Impl(xLockBytes);
977         xProps->addPropertiesChangeListener(
978             Sequence< ::rtl::OUString >(),
979             xListener);
980     }
981 
982     Any aResult;
983     bool bException(false);
984     bool bAborted(false);
985     bool bResultAchieved(false);
986 
987     Moderator* pMod = 0;
988     try {
989         pMod = new Moderator(xContent,xInteract,xProgress,rArg);
990         pMod->create();
991     } catch(const ContentCreationException&) {
992         bResultAchieved = bException = true;
993         xLockBytes->SetError( ERRCODE_IO_GENERAL );
994     }
995 
996     sal_uInt32 nTimeout(5000); // initially 5000 milliSec
997     while(!bResultAchieved) {
998 
999         Moderator::Result res;
1000         // try to get the result for with timeout
1001         res = pMod->getResult(nTimeout);
1002 
1003         switch(res.type) {
1004         case Moderator::PROGRESSPUSH:
1005             {
1006                 if(xProgress.is())
1007                     xProgress->push(res.result);
1008                 pMod->setReply(Moderator::REQUESTHANDLED);
1009                 break;
1010             }
1011         case Moderator::PROGRESSUPDATE:
1012             {
1013                 if(xProgress.is())
1014                     xProgress->update(res.result);
1015                 pMod->setReply(Moderator::REQUESTHANDLED);
1016                 break;
1017             }
1018         case Moderator::PROGRESSPOP:
1019             {
1020                 if(xProgress.is())
1021                     xProgress->pop();
1022                 pMod->setReply(Moderator::REQUESTHANDLED);
1023                 break;
1024             }
1025         case Moderator::STREAM:
1026             {
1027                 Reference<XStream> result;
1028                 if(res.result >>= result) {
1029                     Reference < XActiveDataStreamer > xStreamer(
1030                         xSink, UNO_QUERY
1031                     );
1032 
1033                     if(xStreamer.is())
1034                         xStreamer->setStream(result);
1035                 }
1036                 pMod->setReply(Moderator::REQUESTHANDLED);
1037                 break;
1038             }
1039         case Moderator::INPUTSTREAM:
1040             {
1041                 Reference<XInputStream> result;
1042                 res.result >>= result;
1043                 Reference < XActiveDataSink > xActiveSink(
1044                     xSink, UNO_QUERY
1045                 );
1046 
1047                 if(xActiveSink.is())
1048                     xActiveSink->setInputStream(result);
1049                 pMod->setReply(Moderator::REQUESTHANDLED);
1050                 break;
1051             }
1052         case Moderator::TIMEDOUT:
1053             {
1054                 Reference<XInteractionRetry> xRet;
1055                 if(xInteract.is()) {
1056                     InteractiveNetworkConnectException aExcep;
1057                     INetURLObject aURL(
1058                         xContId.is() ?
1059                         xContId->getContentIdentifier() :
1060                         rtl::OUString() );
1061                     aExcep.Server = aURL.GetHost();
1062                     aExcep.Classification = InteractionClassification_ERROR;
1063                     aExcep.Message =
1064                         rtl::OUString(
1065                             RTL_CONSTASCII_USTRINGPARAM(
1066                                 "server not responding after five seconds"));
1067                     Any request;
1068                     request <<= aExcep;
1069                     ucbhelper::InteractionRequest *ir =
1070                         new ucbhelper::InteractionRequest(request);
1071                     Reference<XInteractionRequest> xIR(ir);
1072                     Sequence<Reference<XInteractionContinuation> > aSeq(2);
1073                     ucbhelper::InteractionRetry *retryP =
1074                         new ucbhelper::InteractionRetry(ir);
1075                     aSeq[0] = retryP;
1076                     ucbhelper::InteractionAbort *abortP =
1077                         new ucbhelper::InteractionAbort(ir);
1078                     aSeq[1] = abortP;
1079 
1080                     ir->setContinuations(aSeq);
1081                     xInteract->handle(xIR);
1082                     rtl::Reference< ucbhelper::InteractionContinuation > ref
1083                         = ir->getSelection();
1084                     if(ref.is()) {
1085                         Reference<XInterface> xInt(ref.get());
1086                         xRet = Reference<XInteractionRetry>(xInt,UNO_QUERY);
1087                     }
1088                 }
1089 
1090                 if(!xRet.is()) {
1091                     bAborted = true;
1092                     xLockBytes->SetError(ERRCODE_ABORT);
1093                 }
1094 
1095                 break;
1096             }
1097         case Moderator::INTERACTIONREQUEST:
1098             {
1099                 Reference<XInteractionRequest> Request;
1100                 res.result >>= Request;
1101                 xInteract->handle(Request);
1102                 pMod->setReply(Moderator::REQUESTHANDLED);
1103                 break;
1104             }
1105         case Moderator::RESULT:
1106             {
1107                 bResultAchieved = true;
1108                 aResult = res.result;
1109                 break;
1110             }
1111         case Moderator::COMMANDABORTED:
1112             {
1113                 bAborted = true;
1114                 xLockBytes->SetError( ERRCODE_ABORT );
1115                 break;
1116             }
1117         case Moderator::COMMANDFAILED:
1118             {
1119                 bAborted = true;
1120                 xLockBytes->SetError( ERRCODE_ABORT );
1121                 break;
1122             }
1123         case Moderator::INTERACTIVEIO:
1124             {
1125                 bException = true;
1126                 if ( res.ioErrorCode == IOErrorCode_ACCESS_DENIED ||
1127                      res.ioErrorCode == IOErrorCode_LOCKING_VIOLATION )
1128                     xLockBytes->SetError( ERRCODE_IO_ACCESSDENIED );
1129                 else if ( res.ioErrorCode == IOErrorCode_NOT_EXISTING )
1130                     xLockBytes->SetError( ERRCODE_IO_NOTEXISTS );
1131                 else if ( res.ioErrorCode == IOErrorCode_CANT_READ )
1132                     xLockBytes->SetError( ERRCODE_IO_CANTREAD );
1133                 else
1134                     xLockBytes->SetError( ERRCODE_IO_GENERAL );
1135                 break;
1136             }
1137         case Moderator::UNSUPPORTED:
1138             {
1139                 bException = true;
1140                 xLockBytes->SetError( ERRCODE_IO_NOTSUPPORTED );
1141                 break;
1142             }
1143         default:
1144             {
1145                 bException = true;
1146                 xLockBytes->SetError( ERRCODE_IO_GENERAL );
1147                 break;
1148             }
1149         }
1150 
1151         bResultAchieved |= bException;
1152         bResultAchieved |= bAborted;
1153         if(nTimeout == 5000) nTimeout *= 2;
1154     }
1155 
1156     if(pMod) pMod->setReply(Moderator::EXIT);
1157 
1158     if ( bAborted || bException )
1159     {
1160         if( xHandler.Is() )
1161             xHandler->Handle( UcbLockBytesHandler::CANCEL, xLockBytes );
1162 
1163         Reference < XActiveDataSink > xActiveSink( xSink, UNO_QUERY );
1164         if ( xActiveSink.is() )
1165             xActiveSink->setInputStream( Reference < XInputStream >() );
1166 
1167         Reference < XActiveDataStreamer > xStreamer( xSink, UNO_QUERY );
1168         if ( xStreamer.is() )
1169             xStreamer->setStream( Reference < XStream >() );
1170     }
1171 
1172     Reference < XActiveDataControl > xControl( xSink, UNO_QUERY );
1173     if ( xControl.is() )
1174         xControl->terminate();
1175 
1176     if ( xProps.is() )
1177         xProps->removePropertiesChangeListener(
1178             Sequence< ::rtl::OUString >(),
1179             xListener );
1180 
1181     return ( bAborted || bException );
1182 }
1183 
1184 /**
1185     Function for opening UCB contents synchronously
1186  */
1187 static sal_Bool _UCBOpenContentSync(
1188     UcbLockBytesRef xLockBytes,
1189     Reference < XContent > xContent,
1190     const Command& rArg,
1191     Reference < XInterface > xSink,
1192     Reference < XInteractionHandler > xInteract,
1193     Reference < XProgressHandler > xProgress,
1194     UcbLockBytesHandlerRef xHandler )
1195 {
1196     ::ucbhelper::Content aContent( xContent, new UcbTaskEnvironment( xInteract, xProgress ) );
1197     Reference < XContentIdentifier > xIdent = xContent->getIdentifier();
1198     ::rtl::OUString aScheme = xIdent->getContentProviderScheme();
1199 
1200     // http protocol must be handled in a special way: during the opening process the input stream may change
1201     // only the last inputstream after notifying the document headers is valid
1202     if ( aScheme.compareToAscii("http") != COMPARE_EQUAL )
1203         xLockBytes->SetStreamValid_Impl();
1204 
1205     Reference< XPropertiesChangeListener > xListener = new UcbPropertiesChangeListener_Impl( xLockBytes );
1206     Reference< XPropertiesChangeNotifier > xProps ( xContent, UNO_QUERY );
1207     if ( xProps.is() )
1208         xProps->addPropertiesChangeListener( Sequence< ::rtl::OUString >(), xListener );
1209 
1210     Any aResult;
1211     bool bException = false;
1212     bool bAborted = false;
1213 
1214     try
1215     {
1216         aResult = aContent.executeCommand( rArg.Name, rArg.Argument );
1217     }
1218     catch ( CommandAbortedException )
1219     {
1220         bAborted = true;
1221         xLockBytes->SetError( ERRCODE_ABORT );
1222     }
1223     catch ( CommandFailedException )
1224     {
1225         bAborted = true;
1226         xLockBytes->SetError( ERRCODE_ABORT );
1227     }
1228     catch ( InteractiveIOException& r )
1229     {
1230         bException = true;
1231         if ( r.Code == IOErrorCode_ACCESS_DENIED || r.Code == IOErrorCode_LOCKING_VIOLATION )
1232             xLockBytes->SetError( ERRCODE_IO_ACCESSDENIED );
1233         else if ( r.Code == IOErrorCode_NOT_EXISTING )
1234             xLockBytes->SetError( ERRCODE_IO_NOTEXISTS );
1235         else if ( r.Code == IOErrorCode_CANT_READ )
1236             xLockBytes->SetError( ERRCODE_IO_CANTREAD );
1237         else
1238             xLockBytes->SetError( ERRCODE_IO_GENERAL );
1239     }
1240     catch ( UnsupportedDataSinkException& )
1241     {
1242         bException = true;
1243         xLockBytes->SetError( ERRCODE_IO_NOTSUPPORTED );
1244     }
1245     catch ( Exception )
1246     {
1247         bException = true;
1248         xLockBytes->SetError( ERRCODE_IO_GENERAL );
1249     }
1250 
1251     if ( bAborted || bException )
1252     {
1253         if( xHandler.Is() )
1254             xHandler->Handle( UcbLockBytesHandler::CANCEL, xLockBytes );
1255 
1256         Reference < XActiveDataSink > xActiveSink( xSink, UNO_QUERY );
1257         if ( xActiveSink.is() )
1258             xActiveSink->setInputStream( Reference < XInputStream >() );
1259 
1260         Reference < XActiveDataStreamer > xStreamer( xSink, UNO_QUERY );
1261         if ( xStreamer.is() )
1262             xStreamer->setStream( Reference < XStream >() );
1263     }
1264 
1265     Reference < XActiveDataControl > xControl( xSink, UNO_QUERY );
1266     if ( xControl.is() )
1267         xControl->terminate();
1268 
1269 
1270     if ( xProps.is() )
1271         xProps->removePropertiesChangeListener( Sequence< ::rtl::OUString >(), xListener );
1272 
1273     return ( bAborted || bException );
1274 }
1275 
1276 
1277 //----------------------------------------------------------------------------
1278 UcbLockBytes::UcbLockBytes( UcbLockBytesHandler* pHandler )
1279     : m_xInputStream (NULL)
1280     , m_pCommandThread( NULL )
1281     , m_xHandler( pHandler )
1282     , m_nError( ERRCODE_NONE )
1283     , m_bTerminated  (sal_False)
1284     , m_bDontClose( sal_False )
1285     , m_bStreamValid  (sal_False)
1286 {
1287     SetSynchronMode( sal_True );
1288 }
1289 
1290 //----------------------------------------------------------------------------
1291 UcbLockBytes::~UcbLockBytes()
1292 {
1293     if ( !m_bDontClose )
1294     {
1295         if ( m_xInputStream.is() )
1296         {
1297             try
1298             {
1299                 m_xInputStream->closeInput();
1300             }
1301             catch ( RuntimeException const & )
1302             {}
1303             catch ( IOException const & )
1304             {}
1305         }
1306     }
1307 
1308     if ( !m_xInputStream.is() && m_xOutputStream.is() )
1309     {
1310         try
1311         {
1312             m_xOutputStream->closeOutput();
1313         }
1314         catch ( RuntimeException const & )
1315         {}
1316         catch ( IOException const & )
1317         {}
1318     }
1319 }
1320 
1321 Reference < XInputStream > UcbLockBytes::getInputStream()
1322 {
1323     vos::OClearableGuard aGuard( m_aMutex );
1324     m_bDontClose = sal_True;
1325     return m_xInputStream;
1326 }
1327 
1328 Reference < XStream > UcbLockBytes::getStream()
1329 {
1330     vos::OClearableGuard aGuard( m_aMutex );
1331     Reference < XStream > xStream( m_xSeekable, UNO_QUERY );
1332     if ( xStream.is() )
1333         m_bDontClose = sal_True;
1334     return xStream;
1335 }
1336 
1337 //----------------------------------------------------------------------------
1338 
1339 sal_Bool UcbLockBytes::setStream_Impl( const Reference<XStream>& aStream )
1340 {
1341     vos::OClearableGuard aGuard( m_aMutex );
1342     if ( aStream.is() )
1343     {
1344         m_xOutputStream = aStream->getOutputStream();
1345         setInputStream_Impl( aStream->getInputStream(), sal_False );
1346         m_xSeekable = Reference < XSeekable > ( aStream, UNO_QUERY );
1347     }
1348     else
1349     {
1350         m_xOutputStream = Reference < XOutputStream >();
1351         setInputStream_Impl( Reference < XInputStream >() );
1352     }
1353 
1354     return m_xInputStream.is();
1355 }
1356 
1357 sal_Bool UcbLockBytes::setInputStream_Impl( const Reference<XInputStream> &rxInputStream, sal_Bool bSetXSeekable )
1358 {
1359     sal_Bool bRet = sal_False;
1360 
1361     try
1362     {
1363         vos::OClearableGuard aGuard( m_aMutex );
1364 
1365         if ( !m_bDontClose && m_xInputStream.is() )
1366             m_xInputStream->closeInput();
1367 
1368         m_xInputStream = rxInputStream;
1369 
1370         if( bSetXSeekable )
1371         {
1372             m_xSeekable = Reference < XSeekable > ( rxInputStream, UNO_QUERY );
1373             if( !m_xSeekable.is() && rxInputStream.is() )
1374             {
1375                 Reference < XMultiServiceFactory > xFactory = ::comphelper::getProcessServiceFactory();
1376                 Reference< XOutputStream > rxTempOut = Reference < XOutputStream > (
1377                                     xFactory->createInstance ( ::rtl::OUString::createFromAscii( "com.sun.star.io.TempFile" ) ),
1378                                     UNO_QUERY );
1379 
1380                 if( rxTempOut.is() )
1381                 {
1382                     ::comphelper::OStorageHelper::CopyInputToOutput( rxInputStream, rxTempOut );
1383                     m_xInputStream = Reference< XInputStream >( rxTempOut, UNO_QUERY );
1384                     m_xSeekable = Reference < XSeekable > ( rxTempOut, UNO_QUERY );
1385                 }
1386             }
1387         }
1388 
1389         bRet = m_xInputStream.is();
1390         // aGuard.clear();
1391     }
1392     catch( Exception& )
1393     {}
1394 
1395     if ( m_bStreamValid && m_xInputStream.is() )
1396         m_aInitialized.set();
1397 
1398     return bRet;
1399 }
1400 
1401 void UcbLockBytes::SetStreamValid_Impl()
1402 {
1403     m_bStreamValid = sal_True;
1404     if ( m_xInputStream.is() )
1405         m_aInitialized.set();
1406 }
1407 
1408 //----------------------------------------------------------------------------
1409 void UcbLockBytes::terminate_Impl()
1410 {
1411     m_bTerminated = sal_True;
1412     m_aInitialized.set();
1413     m_aTerminated.set();
1414 
1415     if ( GetError() == ERRCODE_NONE && !m_xInputStream.is() )
1416     {
1417         DBG_ERROR("No InputStream, but no error set!" );
1418         SetError( ERRCODE_IO_NOTEXISTS );
1419     }
1420 
1421     if ( m_xHandler.Is() )
1422         m_xHandler->Handle( UcbLockBytesHandler::DONE, this );
1423 }
1424 
1425 //----------------------------------------------------------------------------
1426 void UcbLockBytes::SetSynchronMode (sal_Bool bSynchron)
1427 {
1428     SvLockBytes::SetSynchronMode (bSynchron);
1429 }
1430 
1431 //----------------------------------------------------------------------------
1432 ErrCode UcbLockBytes::ReadAt ( sal_uLong nPos, void *pBuffer, sal_uLong nCount, sal_uLong *pRead) const
1433 {
1434     if ( IsSynchronMode() )
1435     {
1436         UcbLockBytes* pThis = const_cast < UcbLockBytes* >( this );
1437         pThis->m_aInitialized.wait();
1438     }
1439 
1440     Reference <XInputStream> xStream = getInputStream_Impl();
1441     if ( !xStream.is() )
1442     {
1443         if ( m_bTerminated )
1444             return ERRCODE_IO_CANTREAD;
1445         else
1446             return ERRCODE_IO_PENDING;
1447     }
1448 
1449     if ( pRead )
1450         *pRead = 0;
1451 
1452     Reference <XSeekable> xSeekable = getSeekable_Impl();
1453     if ( !xSeekable.is() )
1454         return ERRCODE_IO_CANTREAD;
1455 
1456     try
1457     {
1458         xSeekable->seek( nPos );
1459     }
1460     catch ( IOException )
1461     {
1462         return ERRCODE_IO_CANTSEEK;
1463     }
1464     catch (com::sun::star::lang::IllegalArgumentException)
1465     {
1466         return ERRCODE_IO_CANTSEEK;
1467     }
1468 
1469     Sequence<sal_Int8> aData;
1470     sal_Int32          nSize;
1471 
1472     nCount = VOS_MIN(nCount, 0x7FFFFFFF);
1473     try
1474     {
1475         if ( !m_bTerminated && !IsSynchronMode() )
1476         {
1477             sal_uInt64 nLen = xSeekable->getLength();
1478             if ( nPos + nCount > nLen )
1479                 return ERRCODE_IO_PENDING;
1480         }
1481 
1482         nSize = xStream->readBytes( aData, sal_Int32(nCount) );
1483     }
1484     catch (IOException)
1485     {
1486         return ERRCODE_IO_CANTREAD;
1487     }
1488 
1489     rtl_copyMemory (pBuffer, aData.getConstArray(), nSize);
1490     if (pRead)
1491         *pRead = sal_uLong(nSize);
1492 
1493     return ERRCODE_NONE;
1494 }
1495 
1496 //----------------------------------------------------------------------------
1497 ErrCode UcbLockBytes::WriteAt ( sal_uLong nPos, const void *pBuffer, sal_uLong nCount, sal_uLong *pWritten)
1498 {
1499     if ( pWritten )
1500         *pWritten = 0;
1501 
1502     DBG_ASSERT( IsSynchronMode(), "Writing is only possible in SynchronMode!" );
1503     DBG_ASSERT( m_aInitialized.check(), "Writing bevor stream is ready!" );
1504 
1505     Reference <XSeekable> xSeekable = getSeekable_Impl();
1506     Reference <XOutputStream> xOutputStream = getOutputStream_Impl();
1507     if ( !xOutputStream.is() || !xSeekable.is() )
1508         return ERRCODE_IO_CANTWRITE;
1509 
1510     try
1511     {
1512         xSeekable->seek( nPos );
1513     }
1514     catch ( IOException )
1515     {
1516         return ERRCODE_IO_CANTSEEK;
1517     }
1518 
1519     sal_Int8* pData = (sal_Int8*) pBuffer;
1520     Sequence<sal_Int8> aData( pData, nCount );
1521     try
1522     {
1523         xOutputStream->writeBytes( aData );
1524         if ( pWritten )
1525             *pWritten = nCount;
1526     }
1527     catch ( Exception )
1528     {
1529         return ERRCODE_IO_CANTWRITE;
1530     }
1531 
1532     return ERRCODE_NONE;
1533 }
1534 
1535 //----------------------------------------------------------------------------
1536 ErrCode UcbLockBytes::Flush() const
1537 {
1538     Reference <XOutputStream > xOutputStream = getOutputStream_Impl();
1539     if ( !xOutputStream.is() )
1540         return ERRCODE_IO_CANTWRITE;
1541 
1542     try
1543     {
1544         xOutputStream->flush();
1545     }
1546     catch( Exception )
1547     {
1548         return ERRCODE_IO_CANTWRITE;
1549     }
1550 
1551     return ERRCODE_NONE;
1552 }
1553 
1554 //----------------------------------------------------------------------------
1555 ErrCode UcbLockBytes::SetSize (sal_uLong nNewSize)
1556 {
1557     SvLockBytesStat aStat;
1558     Stat( &aStat, (SvLockBytesStatFlag) 0 );
1559     sal_uLong nSize = aStat.nSize;
1560 
1561     if ( nSize > nNewSize )
1562     {
1563         Reference < XTruncate > xTrunc( getOutputStream_Impl(), UNO_QUERY );
1564         if ( xTrunc.is() )
1565         {
1566             xTrunc->truncate();
1567             nSize = 0;
1568         }
1569         else {
1570             DBG_WARNING("Not truncatable!");
1571         }
1572     }
1573 
1574     if ( nSize < nNewSize )
1575     {
1576         sal_uLong nDiff = nNewSize-nSize, nCount=0;
1577         sal_uInt8* pBuffer = new sal_uInt8[ nDiff ];
1578         memset(pBuffer, 0, nDiff); // initialize for enhanced security
1579         WriteAt( nSize, pBuffer, nDiff, &nCount );
1580         delete[] pBuffer;
1581         if ( nCount != nDiff )
1582             return ERRCODE_IO_CANTWRITE;
1583     }
1584 
1585     return ERRCODE_NONE;
1586 }
1587 
1588 //----------------------------------------------------------------------------
1589 ErrCode UcbLockBytes::Stat( SvLockBytesStat *pStat, SvLockBytesStatFlag) const
1590 {
1591     if ( IsSynchronMode() )
1592     {
1593         UcbLockBytes* pThis = const_cast < UcbLockBytes* >( this );
1594         pThis->m_aInitialized.wait();
1595     }
1596 
1597     if (!pStat)
1598         return ERRCODE_IO_INVALIDPARAMETER;
1599 
1600     Reference <XInputStream> xStream = getInputStream_Impl();
1601     Reference <XSeekable> xSeekable = getSeekable_Impl();
1602 
1603     if ( !xStream.is() )
1604     {
1605         if ( m_bTerminated )
1606             return ERRCODE_IO_INVALIDACCESS;
1607         else
1608             return ERRCODE_IO_PENDING;
1609     }
1610     else if( !xSeekable.is() )
1611         return ERRCODE_IO_CANTTELL;
1612 
1613     try
1614     {
1615         pStat->nSize = sal_uLong(xSeekable->getLength());
1616     }
1617     catch (IOException)
1618     {
1619         return ERRCODE_IO_CANTTELL;
1620     }
1621 
1622     return ERRCODE_NONE;
1623 }
1624 
1625 //----------------------------------------------------------------------------
1626 void UcbLockBytes::Cancel()
1627 {
1628     // is alive only for compatibility reasons
1629     OSL_ENSURE( m_bTerminated, "UcbLockBytes is not thread safe so it can be used only syncronously!\n" );
1630 }
1631 
1632 //----------------------------------------------------------------------------
1633 IMPL_LINK( UcbLockBytes, DataAvailHdl, void*, EMPTYARG )
1634 {
1635     if ( hasInputStream_Impl() && m_xHandler.Is() )
1636         m_xHandler->Handle( UcbLockBytesHandler::DATA_AVAILABLE, this );
1637 
1638     return 0;
1639 }
1640 
1641 UcbLockBytesRef UcbLockBytes::CreateInputLockBytes( const Reference< XInputStream >& xInputStream )
1642 {
1643     if( !xInputStream.is() )
1644         return NULL;;
1645 
1646     UcbLockBytesRef xLockBytes = new UcbLockBytes();
1647     xLockBytes->setDontClose_Impl();
1648     xLockBytes->setInputStream_Impl( xInputStream );
1649     xLockBytes->terminate_Impl();
1650     return xLockBytes;
1651 }
1652 
1653 UcbLockBytesRef UcbLockBytes::CreateLockBytes( const Reference< XStream >& xStream )
1654 {
1655     if( !xStream.is() )
1656         return NULL;;
1657 
1658     UcbLockBytesRef xLockBytes = new UcbLockBytes();
1659     xLockBytes->setDontClose_Impl();
1660     xLockBytes->setStream_Impl( xStream );
1661     xLockBytes->terminate_Impl();
1662     return xLockBytes;
1663 }
1664 
1665 UcbLockBytesRef UcbLockBytes::CreateLockBytes( const Reference < XContent >& xContent, const ::rtl::OUString& rReferer, const ::rtl::OUString& rMediaType,
1666         const Reference < XInputStream >& xPostData, const Reference < XInteractionHandler >& xInteractionHandler, UcbLockBytesHandler* pHandler )
1667 {
1668     if( !xContent.is() )
1669         return NULL;;
1670 
1671     UcbLockBytesRef xLockBytes = new UcbLockBytes( pHandler );
1672     xLockBytes->SetSynchronMode( !pHandler );
1673     Reference< XActiveDataControl > xSink = (XActiveDataControl*) new UcbDataSink_Impl( xLockBytes );
1674 
1675     PostCommandArgument2 aArgument;
1676     aArgument.Source = xPostData;
1677     aArgument.Sink = xSink;
1678     aArgument.MediaType = rMediaType;
1679     aArgument.Referer = rReferer;
1680 
1681     Command aCommand;
1682     aCommand.Name = ::rtl::OUString::createFromAscii ("post");
1683     aCommand.Argument <<= aArgument;
1684 
1685     Reference< XProgressHandler > xProgressHdl = new ProgressHandler_Impl( LINK( &xLockBytes, UcbLockBytes, DataAvailHdl ) );
1686 
1687     sal_Bool bError = UCBOpenContentSync( xLockBytes,
1688                                           xContent,
1689                                           aCommand,
1690                                           xSink,
1691                                           xInteractionHandler,
1692                                           xProgressHdl,
1693                                           pHandler );
1694 
1695     if ( xLockBytes->GetError() == ERRCODE_NONE && ( bError || !xLockBytes->getInputStream().is() ) )
1696     {
1697         DBG_ERROR("No InputStream, but no error set!" );
1698         xLockBytes->SetError( ERRCODE_IO_GENERAL );
1699     }
1700 
1701     return xLockBytes;
1702 }
1703 
1704 UcbLockBytesRef UcbLockBytes::CreateLockBytes( const Reference < XContent >& xContent, const Sequence < PropertyValue >& rProps,
1705         StreamMode eOpenMode, const Reference < XInteractionHandler >& xInteractionHandler, UcbLockBytesHandler* pHandler )
1706 {
1707     if( !xContent.is() )
1708         return NULL;;
1709 
1710     UcbLockBytesRef xLockBytes = new UcbLockBytes( pHandler );
1711     xLockBytes->SetSynchronMode( !pHandler );
1712     Reference< XActiveDataControl > xSink;
1713     if ( eOpenMode & STREAM_WRITE )
1714         xSink = (XActiveDataControl*) new UcbStreamer_Impl( xLockBytes );
1715     else
1716         xSink = (XActiveDataControl*) new UcbDataSink_Impl( xLockBytes );
1717 
1718     if ( rProps.getLength() )
1719     {
1720         Reference < XCommandProcessor > xProcessor( xContent, UNO_QUERY );
1721         Command aCommand;
1722         aCommand.Name     = ::rtl::OUString::createFromAscii("setPropertyValues");
1723         aCommand.Handle   = -1; /* unknown */
1724         aCommand.Argument <<= rProps;
1725         xProcessor->execute( aCommand, 0, Reference < XCommandEnvironment >() );
1726     }
1727 
1728     OpenCommandArgument2 aArgument;
1729     aArgument.Sink = xSink;
1730     aArgument.Mode = OpenMode::DOCUMENT;
1731 
1732     Command aCommand;
1733     aCommand.Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("open") );
1734     aCommand.Argument <<= aArgument;
1735 
1736     Reference< XProgressHandler > xProgressHdl = new ProgressHandler_Impl( LINK( &xLockBytes, UcbLockBytes, DataAvailHdl ) );
1737 
1738     sal_Bool bError = UCBOpenContentSync( xLockBytes,
1739                                           xContent,
1740                                           aCommand,
1741                                           xSink,
1742                                           xInteractionHandler,
1743                                           xProgressHdl,
1744                                           pHandler );
1745 
1746     if ( xLockBytes->GetError() == ERRCODE_NONE && ( bError || !xLockBytes->getInputStream().is() ) )
1747     {
1748         DBG_ERROR("No InputStream, but no error set!" );
1749         xLockBytes->SetError( ERRCODE_IO_GENERAL );
1750     }
1751 
1752     return xLockBytes;
1753 }
1754 
1755 }
1756