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