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