update credits
[LibreOffice.git] / unotools / source / ucbhelper / ucblockbytes.cxx
bloba5ff6fcad3f071c199f5d4129b3e7cea89b28105
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <sal/macros.h>
22 #include <unotools/ucblockbytes.hxx>
23 #include <comphelper/processfactory.hxx>
24 #include <salhelper/condition.hxx>
25 #include <osl/thread.hxx>
26 #include <tools/urlobj.hxx>
27 #include <ucbhelper/interactionrequest.hxx>
28 #include <com/sun/star/task/XInteractionAbort.hpp>
29 #include <com/sun/star/ucb/InteractiveNetworkConnectException.hpp>
30 #include <com/sun/star/ucb/CommandFailedException.hpp>
31 #include <com/sun/star/ucb/UnsupportedDataSinkException.hpp>
32 #include <com/sun/star/ucb/InteractiveIOException.hpp>
33 #include <com/sun/star/io/XActiveDataStreamer.hpp>
34 #include <com/sun/star/io/TempFile.hpp>
35 #include <com/sun/star/ucb/DocumentHeaderField.hpp>
36 #include <com/sun/star/ucb/XCommandInfo.hpp>
37 #include <com/sun/star/ucb/XCommandProcessor.hpp>
38 #include <com/sun/star/task/XInteractionHandler.hpp>
39 #include <com/sun/star/ucb/OpenCommandArgument2.hpp>
40 #include <com/sun/star/ucb/PostCommandArgument2.hpp>
41 #include <com/sun/star/ucb/OpenMode.hpp>
42 #include <com/sun/star/beans/Property.hpp>
43 #include <com/sun/star/beans/PropertyValue.hpp>
44 #include <com/sun/star/beans/XPropertiesChangeNotifier.hpp>
45 #include <com/sun/star/beans/XPropertiesChangeListener.hpp>
46 #include <com/sun/star/sdbc/XRow.hpp>
47 #include <com/sun/star/io/XActiveDataSink.hpp>
48 #include <com/sun/star/io/XActiveDataControl.hpp>
49 #include <com/sun/star/io/XSeekable.hpp>
50 #include <cppuhelper/implbase1.hxx>
51 #include <cppuhelper/implbase2.hxx>
52 #include <tools/inetmsg.hxx>
53 #include <com/sun/star/io/XTruncate.hpp>
54 #include <com/sun/star/lang/IllegalArgumentException.hpp>
56 #include <comphelper/storagehelper.hxx>
57 #include <ucbhelper/content.hxx>
59 using namespace ::com::sun::star::uno;
60 using namespace ::com::sun::star::io;
61 using namespace ::com::sun::star::ucb;
62 using namespace ::com::sun::star::task;
63 using namespace ::com::sun::star::lang;
64 using namespace ::com::sun::star::beans;
67 namespace utl
70 /**
71 Helper class for getting a XInputStream when opening a content
73 class UcbDataSink_Impl : public ::cppu::WeakImplHelper2< XActiveDataControl, XActiveDataSink >
75 UcbLockBytesRef m_xLockBytes;
77 public:
78 UcbDataSink_Impl( UcbLockBytes* pLockBytes )
79 : m_xLockBytes( pLockBytes )
82 SvLockBytes* getLockBytes (void)
83 { return m_xLockBytes; }
85 // XActiveDataControl.
86 virtual void SAL_CALL addListener ( const Reference<XStreamListener> &/*rxListener*/) throw(RuntimeException) {}
87 virtual void SAL_CALL removeListener ( const Reference<XStreamListener> &/*rxListener*/) throw(RuntimeException) {}
88 virtual void SAL_CALL start (void) throw(RuntimeException) {}
89 virtual void SAL_CALL terminate (void) throw(RuntimeException)
90 { m_xLockBytes->terminate_Impl(); }
92 // XActiveDataSink.
93 virtual void SAL_CALL setInputStream ( const Reference<XInputStream> &rxInputStream) throw(RuntimeException)
94 { m_xLockBytes->setInputStream_Impl (rxInputStream); }
95 virtual Reference<XInputStream> SAL_CALL getInputStream (void) throw(RuntimeException)
96 { return m_xLockBytes->getInputStream_Impl(); }
99 /**
100 Helper class for getting a XStream when opening a content
102 class UcbStreamer_Impl : public ::cppu::WeakImplHelper2< XActiveDataStreamer, XActiveDataControl >
104 Reference < XStream > m_xStream;
105 UcbLockBytesRef m_xLockBytes;
107 public:
108 UcbStreamer_Impl( UcbLockBytes* pLockBytes )
109 : m_xLockBytes( pLockBytes )
112 // XActiveDataControl.
113 virtual void SAL_CALL addListener ( const Reference<XStreamListener> &/*rxListener*/) throw(RuntimeException) {}
114 virtual void SAL_CALL removeListener ( const Reference<XStreamListener> &/*rxListener*/) throw(RuntimeException) {}
115 virtual void SAL_CALL start (void) throw(RuntimeException) {}
116 virtual void SAL_CALL terminate (void) throw(RuntimeException)
117 { m_xLockBytes->terminate_Impl(); }
119 // XActiveDataStreamer
120 virtual void SAL_CALL setStream( const Reference< XStream >& aStream ) throw(RuntimeException)
121 { m_xStream = aStream; m_xLockBytes->setStream_Impl( aStream ); }
122 virtual Reference< XStream > SAL_CALL getStream() throw(RuntimeException)
123 { return m_xStream; }
127 Helper class for progress handling while executing UCB commands
129 class ProgressHandler_Impl: public ::cppu::WeakImplHelper1< XProgressHandler >
131 Link m_aProgress;
133 public:
134 ProgressHandler_Impl( const Link& rLink )
135 : m_aProgress( rLink )
137 // XProgressHandler
138 virtual void SAL_CALL push(const Any & /*rStatus*/) throw (RuntimeException) {}
139 virtual void SAL_CALL pop() throw (RuntimeException) {}
140 virtual void SAL_CALL update(const Any & /*rStatus*/) throw (RuntimeException)
141 { if ( m_aProgress.IsSet() ) m_aProgress.Call( 0 ); }
145 Helper class for managing interactions and progress when executing UCB commands
147 class UcbTaskEnvironment : public ::cppu::WeakImplHelper1< XCommandEnvironment >
149 Reference< XInteractionHandler > m_xInteractionHandler;
150 Reference< XProgressHandler > m_xProgressHandler;
152 public:
153 UcbTaskEnvironment( const Reference< XInteractionHandler>& rxInteractionHandler,
154 const Reference< XProgressHandler>& rxProgressHandler )
155 : m_xInteractionHandler( rxInteractionHandler )
156 , m_xProgressHandler( rxProgressHandler )
159 virtual Reference<XInteractionHandler> SAL_CALL getInteractionHandler() throw (RuntimeException)
160 { return m_xInteractionHandler; }
162 virtual Reference<XProgressHandler> SAL_CALL getProgressHandler() throw (RuntimeException)
163 { return m_xProgressHandler; }
168 Helper class for property change notifies when executing UCB commands
170 class UcbPropertiesChangeListener_Impl : public ::cppu::WeakImplHelper1< XPropertiesChangeListener >
172 public:
173 UcbLockBytesRef m_xLockBytes;
175 UcbPropertiesChangeListener_Impl( UcbLockBytesRef rRef )
176 : m_xLockBytes( rRef )
179 virtual void SAL_CALL disposing ( const EventObject &/*rEvent*/) throw(RuntimeException) {}
180 virtual void SAL_CALL propertiesChange ( const Sequence<PropertyChangeEvent> &rEvent) throw(RuntimeException);
183 void SAL_CALL UcbPropertiesChangeListener_Impl::propertiesChange ( const Sequence<PropertyChangeEvent> &rEvent) throw(RuntimeException)
185 sal_Int32 i, n = rEvent.getLength();
186 for (i = 0; i < n; i++)
188 PropertyChangeEvent evt (rEvent[i]);
189 if (evt.PropertyName == OUString("DocumentHeader"))
191 Sequence<DocumentHeaderField> aHead;
192 if (evt.NewValue >>= aHead)
194 sal_Int32 k, m = aHead.getLength();
195 for (k = 0; k < m; k++)
197 String aName( aHead[k].Name );
198 String aValue( aHead[k].Value );
200 if (aName.CompareIgnoreCaseToAscii("Expires") == COMPARE_EQUAL)
202 DateTime aExpires (0, 0);
203 if (INetRFC822Message::ParseDateField (aValue, aExpires))
205 aExpires.ConvertToLocalTime();
206 m_xLockBytes->SetExpireDate_Impl( aExpires );
212 m_xLockBytes->SetStreamValid_Impl();
214 else if (evt.PropertyName == OUString("PresentationURL"))
216 OUString aUrl;
217 if (evt.NewValue >>= aUrl)
219 OUString aBad ("private:");
220 if (!aUrl.startsWith(aBad))
222 // URL changed (Redirection).
223 m_xLockBytes->SetRealURL_Impl( aUrl );
227 else if (evt.PropertyName == OUString("MediaType"))
229 OUString aContentType;
230 if (evt.NewValue >>= aContentType)
231 m_xLockBytes->SetContentType_Impl( aContentType );
238 class Moderator
239 : public osl::Thread
241 // usage restriction:
242 // It might be possible, that the call to the interactionhandler and/or
243 // progresshandler is done asynchrounsly, while the 'execute' simply
244 // returns. This would imply that these class must be refcounted !!!
246 public:
247 Moderator(
248 Reference < XContent >& xContent,
249 Reference < XInteractionHandler >& xInteract,
250 Reference < XProgressHandler >& xProgress,
251 const Command& rArg
253 throw(
254 ContentCreationException,
255 RuntimeException
258 ~Moderator();
261 enum ResultType {
262 NORESULT,
264 INTERACTIONREQUEST, // reply expected
266 PROGRESSPUSH,
267 PROGRESSUPDATE,
268 PROGRESSPOP,
270 INPUTSTREAM,
271 STREAM,
273 RESULT,
274 TIMEDOUT,
275 COMMANDABORTED,
276 COMMANDFAILED,
277 INTERACTIVEIO,
278 UNSUPPORTED,
279 GENERAL
283 class ConditionRes
284 : public salhelper::Condition
286 public:
287 ConditionRes(osl::Mutex& aMutex,Moderator& aModerator)
288 : salhelper::Condition(aMutex),
289 m_aModerator(aModerator)
293 protected:
294 bool applies() const {
295 return m_aModerator.m_aResultType != NORESULT;
298 private:
299 Moderator& m_aModerator;
303 struct Result {
304 ResultType type;
305 Any result;
306 sal_Int32 ioErrorCode;
309 Result getResult(const sal_uInt32 milliSec);
311 enum ReplyType {
312 NOREPLY,
313 EXIT,
314 RETRY,
315 REQUESTHANDLED
318 class ConditionRep
319 : public salhelper::Condition
321 public:
322 ConditionRep(osl::Mutex& aMutex,Moderator& aModerator)
323 : salhelper::Condition(aMutex),
324 m_aModerator(aModerator)
328 protected:
329 bool applies() const {
330 return m_aModerator.m_aReplyType != NOREPLY;
333 private:
334 Moderator& m_aModerator;
337 void setReply(ReplyType);
339 void handle( const Reference<XInteractionRequest >& Request );
340 void push( const Any& Status );
341 void update( const Any& Status );
342 void pop( );
344 void setStream(const Reference< XStream >& aStream);
345 void setInputStream(const Reference<XInputStream> &rxInputStream);
348 protected:
349 virtual void SAL_CALL run();
350 virtual void SAL_CALL onTerminated();
352 private:
353 osl::Mutex m_aMutex;
355 friend class ConditionRes;
357 ConditionRes m_aRes;
358 ResultType m_aResultType;
359 sal_Int32 m_nIOErrorCode;
360 Any m_aResult;
362 friend class ConditionRep;
364 ConditionRep m_aRep;
365 ReplyType m_aReplyType;
367 Command m_aArg;
368 ::ucbhelper::Content m_aContent;
372 class ModeratorsActiveDataStreamer
373 : public ::cppu::WeakImplHelper1<XActiveDataStreamer>
375 public:
377 ModeratorsActiveDataStreamer(Moderator &theModerator);
379 ~ModeratorsActiveDataStreamer();
381 // XActiveDataStreamer
382 virtual void SAL_CALL
383 setStream(
384 const Reference< XStream >& aStream
386 throw(
387 RuntimeException
390 virtual Reference<XStream> SAL_CALL
391 getStream (
392 void
393 ) throw(
394 RuntimeException
397 osl::MutexGuard aGuard(m_aMutex);
398 return m_xStream;
402 private:
403 Moderator& m_aModerator;
405 osl::Mutex m_aMutex;
406 Reference<XStream> m_xStream;
410 class ModeratorsActiveDataSink
411 : public ::cppu::WeakImplHelper1<XActiveDataSink>
413 public:
415 ModeratorsActiveDataSink(Moderator &theModerator);
417 ~ModeratorsActiveDataSink();
419 // XActiveDataSink.
420 virtual void SAL_CALL
421 setInputStream (
422 const Reference<XInputStream> &rxInputStream
424 throw(
425 RuntimeException
428 virtual Reference<XInputStream> SAL_CALL
429 getInputStream (
430 void
431 ) throw(
432 RuntimeException
435 osl::MutexGuard aGuard(m_aMutex);
436 return m_xStream;
440 private:
441 Moderator& m_aModerator;
442 osl::Mutex m_aMutex;
443 Reference<XInputStream> m_xStream;
448 ModeratorsActiveDataSink::ModeratorsActiveDataSink(Moderator &theModerator)
449 : m_aModerator(theModerator)
454 ModeratorsActiveDataSink::~ModeratorsActiveDataSink()
458 // XActiveDataSink.
459 void SAL_CALL
460 ModeratorsActiveDataSink::setInputStream (
461 const Reference<XInputStream> &rxInputStream
463 throw(
464 RuntimeException
467 m_aModerator.setInputStream(rxInputStream);
468 osl::MutexGuard aGuard(m_aMutex);
469 m_xStream = rxInputStream;
473 ModeratorsActiveDataStreamer::ModeratorsActiveDataStreamer(
474 Moderator &theModerator
476 : m_aModerator(theModerator)
481 ModeratorsActiveDataStreamer::~ModeratorsActiveDataStreamer()
485 // XActiveDataStreamer.
486 void SAL_CALL
487 ModeratorsActiveDataStreamer::setStream (
488 const Reference<XStream> &rxStream
490 throw(
491 RuntimeException
494 m_aModerator.setStream(rxStream);
495 osl::MutexGuard aGuard(m_aMutex);
496 m_xStream = rxStream;
501 class ModeratorsInteractionHandler
502 : public ::cppu::WeakImplHelper1<XInteractionHandler>
504 public:
506 ModeratorsInteractionHandler(Moderator &theModerator);
508 ~ModeratorsInteractionHandler();
510 virtual void SAL_CALL
511 handle( const Reference<XInteractionRequest >& Request )
512 throw (RuntimeException);
514 private:
516 Moderator& m_aModerator;
520 class ModeratorsProgressHandler
521 : public ::cppu::WeakImplHelper1<XProgressHandler>
523 public:
524 ModeratorsProgressHandler(Moderator &theModerator);
526 ~ModeratorsProgressHandler();
528 virtual void SAL_CALL push( const Any& Status )
529 throw (
530 RuntimeException);
532 virtual void SAL_CALL update( const Any& Status )
533 throw (RuntimeException);
535 virtual void SAL_CALL pop( )
536 throw (RuntimeException);
539 private:
540 Moderator& m_aModerator;
544 ModeratorsProgressHandler::ModeratorsProgressHandler(Moderator &theModerator)
545 : m_aModerator(theModerator)
549 ModeratorsProgressHandler::~ModeratorsProgressHandler()
554 void SAL_CALL ModeratorsProgressHandler::push( const Any& Status )
555 throw (
556 RuntimeException)
558 m_aModerator.push(Status);
562 void SAL_CALL ModeratorsProgressHandler::update( const Any& Status )
563 throw (RuntimeException)
565 m_aModerator.update(Status);
569 void SAL_CALL ModeratorsProgressHandler::pop( )
570 throw (RuntimeException)
572 m_aModerator.pop();
576 ModeratorsInteractionHandler::ModeratorsInteractionHandler(
577 Moderator &aModerator)
578 : m_aModerator(aModerator)
583 ModeratorsInteractionHandler::~ModeratorsInteractionHandler()
588 void SAL_CALL
589 ModeratorsInteractionHandler::handle(
590 const Reference<XInteractionRequest >& Request
592 throw (
593 RuntimeException
596 // wakes up the mainthread
597 m_aModerator.handle(Request);
603 Moderator::Moderator(
604 Reference < XContent >& xContent,
605 Reference < XInteractionHandler >& xInteract,
606 Reference < XProgressHandler >& xProgress,
607 const Command& rArg
609 throw(
610 ::com::sun::star::ucb::ContentCreationException,
611 ::com::sun::star::uno::RuntimeException
613 : m_aMutex(),
615 m_aRes(m_aMutex,*this),
616 m_aResultType(NORESULT),
617 m_nIOErrorCode(0),
618 m_aResult(),
620 m_aRep(m_aMutex,*this),
621 m_aReplyType(NOREPLY),
623 m_aArg(rArg),
624 m_aContent(
625 xContent,
626 new UcbTaskEnvironment(
627 xInteract.is() ? new ModeratorsInteractionHandler(*this) : 0,
628 xProgress.is() ? new ModeratorsProgressHandler(*this) : 0),
629 comphelper::getProcessComponentContext())
631 // now exchange the whole data sink stuff
632 // with a thread safe version
634 Reference<XInterface> *pxSink = NULL;
636 PostCommandArgument2 aPostArg;
637 OpenCommandArgument2 aOpenArg;
639 int dec(2);
640 if(m_aArg.Argument >>= aPostArg) {
641 pxSink = &aPostArg.Sink;
642 dec = 0;
644 else if(m_aArg.Argument >>= aOpenArg) {
645 pxSink = &aOpenArg.Sink;
646 dec = 1;
649 if(dec ==2)
650 throw ContentCreationException();
652 Reference < XActiveDataSink > xActiveSink(*pxSink,UNO_QUERY);
653 if(xActiveSink.is())
654 *pxSink = Reference<XInterface>(
655 (cppu::OWeakObject*)new ModeratorsActiveDataSink(*this));
657 Reference<XActiveDataStreamer> xStreamer( *pxSink, UNO_QUERY );
658 if ( xStreamer.is() )
659 *pxSink = Reference<XInterface>(
660 (cppu::OWeakObject*)new ModeratorsActiveDataStreamer(*this));
662 if(dec == 0)
663 m_aArg.Argument <<= aPostArg;
664 else if(dec == 1)
665 m_aArg.Argument <<= aOpenArg;
669 Moderator::~Moderator()
674 Moderator::Result Moderator::getResult(const sal_uInt32 milliSec)
676 Result ret;
677 try {
678 salhelper::ConditionWaiter aWaiter(m_aRes,milliSec);
679 ret.type = m_aResultType;
680 ret.result = m_aResult;
681 ret.ioErrorCode = m_nIOErrorCode;
683 // reset
684 m_aResultType = NORESULT;
686 catch (const salhelper::ConditionWaiter::timedout&)
688 ret.type = TIMEDOUT;
691 return ret;
695 void Moderator::setReply(ReplyType aReplyType )
697 salhelper::ConditionModifier aMod(m_aRep);
698 m_aReplyType = aReplyType;
702 void Moderator::handle( const Reference<XInteractionRequest >& Request )
704 ReplyType aReplyType;
706 do {
708 salhelper::ConditionModifier aMod(m_aRes);
709 m_aResultType = INTERACTIONREQUEST;
710 m_aResult <<= Request;
714 salhelper::ConditionWaiter aWait(m_aRep);
715 aReplyType = m_aReplyType;
717 // reset
718 m_aReplyType = NOREPLY;
721 if(aReplyType == EXIT) {
722 Sequence<Reference<XInteractionContinuation> > aSeq(
723 Request->getContinuations());
724 for(sal_Int32 i = 0; i < aSeq.getLength(); ++i) {
725 Reference<XInteractionAbort> aRef(aSeq[i],UNO_QUERY);
726 if(aRef.is()) {
727 aRef->select();
731 // resignal the exitcondition
732 setReply(EXIT);
733 break;
735 } while(aReplyType != REQUESTHANDLED);
739 void Moderator::push( const Any& Status )
742 salhelper::ConditionModifier aMod(m_aRes);
743 m_aResultType = PROGRESSPUSH;
744 m_aResult = Status;
746 ReplyType aReplyType;
748 salhelper::ConditionWaiter aWait(m_aRep);
749 aReplyType = m_aReplyType;
750 m_aReplyType = NOREPLY;
752 if(aReplyType == EXIT)
753 setReply(EXIT);
757 void Moderator::update( const Any& Status )
760 salhelper::ConditionModifier aMod(m_aRes);
761 m_aResultType = PROGRESSUPDATE;
762 m_aResult = Status;
764 ReplyType aReplyType;
766 salhelper::ConditionWaiter aWait(m_aRep);
767 aReplyType = m_aReplyType;
768 m_aReplyType = NOREPLY;
770 if(aReplyType == EXIT)
771 setReply(EXIT);
775 void Moderator::pop( )
778 salhelper::ConditionModifier aMod(m_aRes);
779 m_aResultType = PROGRESSPOP;
781 ReplyType aReplyType;
783 salhelper::ConditionWaiter aWait(m_aRep);
784 aReplyType = m_aReplyType;
785 m_aReplyType = NOREPLY;
787 if(aReplyType == EXIT)
788 setReply(EXIT);
792 void Moderator::setStream(const Reference< XStream >& aStream)
795 salhelper::ConditionModifier aMod(m_aRes);
796 m_aResultType = STREAM;
797 m_aResult <<= aStream;
799 ReplyType aReplyType;
801 salhelper::ConditionWaiter aWait(m_aRep);
802 aReplyType = m_aReplyType;
803 m_aReplyType = NOREPLY;
805 if(aReplyType == EXIT)
806 setReply(EXIT);
810 void Moderator::setInputStream(const Reference<XInputStream> &rxInputStream)
813 salhelper::ConditionModifier aMod(m_aRes);
814 m_aResultType = INPUTSTREAM;
815 m_aResult <<= rxInputStream;
817 ReplyType aReplyType;
819 salhelper::ConditionWaiter aWait(m_aRep);
820 aReplyType = m_aReplyType;
821 m_aReplyType = NOREPLY;
823 if(aReplyType == EXIT)
824 setReply(EXIT);
828 void SAL_CALL Moderator::run()
830 ResultType aResultType;
831 Any aResult;
832 sal_Int32 nIOErrorCode = 0;
836 aResult = m_aContent.executeCommand(m_aArg.Name,m_aArg.Argument);
837 aResultType = RESULT;
839 catch (const CommandAbortedException&)
841 aResultType = COMMANDABORTED;
843 catch (const CommandFailedException&)
845 aResultType = COMMANDFAILED;
847 catch (const InteractiveIOException& r)
849 nIOErrorCode = r.Code;
850 aResultType = INTERACTIVEIO;
852 catch (const UnsupportedDataSinkException &)
854 aResultType = UNSUPPORTED;
856 catch (const Exception&)
858 aResultType = GENERAL;
862 salhelper::ConditionModifier aMod(m_aRes);
863 m_aResultType = aResultType;
864 m_aResult = aResult;
865 m_nIOErrorCode = nIOErrorCode;
869 void SAL_CALL Moderator::onTerminated()
872 salhelper::ConditionWaiter aWaiter(m_aRep);
874 delete this;
878 Function for opening UCB contents synchronously,
879 but with handled timeout;
881 static sal_Bool _UCBOpenContentSync(
882 UcbLockBytesRef xLockBytes,
883 Reference < XContent > xContent,
884 const Command& rArg,
885 Reference < XInterface > xSink,
886 Reference < XInteractionHandler > xInteract,
887 Reference < XProgressHandler > xProgress,
888 UcbLockBytesHandlerRef xHandler );
891 static sal_Bool UCBOpenContentSync(
892 UcbLockBytesRef xLockBytes,
893 Reference < XContent > xContent,
894 const Command& rArg,
895 Reference < XInterface > xSink,
896 Reference < XInteractionHandler > xInteract,
897 Reference < XProgressHandler > xProgress,
898 UcbLockBytesHandlerRef xHandler )
900 // http protocol must be handled in a special way:
901 // during the opening process the input stream may change
902 // only the last inputstream after notifying the document
903 // headers is valid
905 Reference<XContentIdentifier> xContId(
906 xContent.is() ? xContent->getIdentifier() : 0 );
908 OUString aScheme;
909 if(xContId.is())
910 aScheme = xContId->getContentProviderScheme();
912 // now determine whether we use a timeout or not;
913 if( ! aScheme.equalsIgnoreAsciiCase("http") &&
914 ! aScheme.equalsIgnoreAsciiCase("https") &&
915 ! aScheme.equalsIgnoreAsciiCase("vnd.sun.star.webdav") &&
916 ! aScheme.equalsIgnoreAsciiCase("ftp"))
917 return _UCBOpenContentSync(
918 xLockBytes,xContent,rArg,xSink,xInteract,xProgress,xHandler);
920 if ( (aScheme.compareToAscii( "http" ) != COMPARE_EQUAL) ||
921 (aScheme.compareToAscii( "https" ) != COMPARE_EQUAL) )
922 xLockBytes->SetStreamValid_Impl();
924 Reference< XPropertiesChangeListener > xListener;
925 Reference< XPropertiesChangeNotifier > xProps(xContent,UNO_QUERY);
926 if(xProps.is()) {
927 xListener =
928 new UcbPropertiesChangeListener_Impl(xLockBytes);
929 xProps->addPropertiesChangeListener(
930 Sequence< OUString >(),
931 xListener);
934 Any aResult;
935 bool bException(false);
936 bool bAborted(false);
937 bool bResultAchieved(false);
939 Moderator* pMod = 0;
942 pMod = new Moderator(xContent,xInteract,xProgress,rArg);
943 pMod->create();
945 catch (const ContentCreationException&)
947 bResultAchieved = bException = true;
948 xLockBytes->SetError( ERRCODE_IO_GENERAL );
951 sal_uInt32 nTimeout(5000); // initially 5000 milliSec
952 while(!bResultAchieved) {
954 Moderator::Result res;
955 // try to get the result for with timeout
956 res = pMod->getResult(nTimeout);
958 switch(res.type) {
959 case Moderator::PROGRESSPUSH:
961 if(xProgress.is())
962 xProgress->push(res.result);
963 pMod->setReply(Moderator::REQUESTHANDLED);
964 break;
966 case Moderator::PROGRESSUPDATE:
968 if(xProgress.is())
969 xProgress->update(res.result);
970 pMod->setReply(Moderator::REQUESTHANDLED);
971 break;
973 case Moderator::PROGRESSPOP:
975 if(xProgress.is())
976 xProgress->pop();
977 pMod->setReply(Moderator::REQUESTHANDLED);
978 break;
980 case Moderator::STREAM:
982 Reference<XStream> result;
983 if(res.result >>= result) {
984 Reference < XActiveDataStreamer > xStreamer(
985 xSink, UNO_QUERY
988 if(xStreamer.is())
989 xStreamer->setStream(result);
991 pMod->setReply(Moderator::REQUESTHANDLED);
992 break;
994 case Moderator::INPUTSTREAM:
996 Reference<XInputStream> result;
997 res.result >>= result;
998 Reference < XActiveDataSink > xActiveSink(
999 xSink, UNO_QUERY
1002 if(xActiveSink.is())
1003 xActiveSink->setInputStream(result);
1004 pMod->setReply(Moderator::REQUESTHANDLED);
1005 break;
1007 case Moderator::TIMEDOUT:
1009 Reference<XInteractionRetry> xRet;
1010 if(xInteract.is()) {
1011 InteractiveNetworkConnectException aExcep;
1012 INetURLObject aURL(
1013 xContId.is() ?
1014 xContId->getContentIdentifier() :
1015 OUString() );
1016 aExcep.Server = aURL.GetHost();
1017 aExcep.Classification = InteractionClassification_ERROR;
1018 aExcep.Message =
1019 OUString( "server not responding after five seconds");
1020 Any request;
1021 request <<= aExcep;
1022 ucbhelper::InteractionRequest *ir =
1023 new ucbhelper::InteractionRequest(request);
1024 Reference<XInteractionRequest> xIR(ir);
1025 Sequence<Reference<XInteractionContinuation> > aSeq(2);
1026 ucbhelper::InteractionRetry *retryP =
1027 new ucbhelper::InteractionRetry(ir);
1028 aSeq[0] = retryP;
1029 ucbhelper::InteractionAbort *abortP =
1030 new ucbhelper::InteractionAbort(ir);
1031 aSeq[1] = abortP;
1033 ir->setContinuations(aSeq);
1034 xInteract->handle(xIR);
1035 rtl::Reference< ucbhelper::InteractionContinuation > ref
1036 = ir->getSelection();
1037 if(ref.is()) {
1038 Reference<XInterface> xInt(ref.get());
1039 xRet = Reference<XInteractionRetry>(xInt,UNO_QUERY);
1043 if(!xRet.is()) {
1044 bAborted = true;
1045 xLockBytes->SetError(ERRCODE_ABORT);
1048 break;
1050 case Moderator::INTERACTIONREQUEST:
1052 Reference<XInteractionRequest> Request;
1053 res.result >>= Request;
1054 xInteract->handle(Request);
1055 pMod->setReply(Moderator::REQUESTHANDLED);
1056 break;
1058 case Moderator::RESULT:
1060 bResultAchieved = true;
1061 aResult = res.result;
1062 break;
1064 case Moderator::COMMANDABORTED:
1066 bAborted = true;
1067 xLockBytes->SetError( ERRCODE_ABORT );
1068 break;
1070 case Moderator::COMMANDFAILED:
1072 bAborted = true;
1073 xLockBytes->SetError( ERRCODE_ABORT );
1074 break;
1076 case Moderator::INTERACTIVEIO:
1078 bException = true;
1079 if ( res.ioErrorCode == IOErrorCode_ACCESS_DENIED ||
1080 res.ioErrorCode == IOErrorCode_LOCKING_VIOLATION )
1081 xLockBytes->SetError( ERRCODE_IO_ACCESSDENIED );
1082 else if ( res.ioErrorCode == IOErrorCode_NOT_EXISTING )
1083 xLockBytes->SetError( ERRCODE_IO_NOTEXISTS );
1084 else if ( res.ioErrorCode == IOErrorCode_CANT_READ )
1085 xLockBytes->SetError( ERRCODE_IO_CANTREAD );
1086 else
1087 xLockBytes->SetError( ERRCODE_IO_GENERAL );
1088 break;
1090 case Moderator::UNSUPPORTED:
1092 bException = true;
1093 xLockBytes->SetError( ERRCODE_IO_NOTSUPPORTED );
1094 break;
1096 default:
1098 bException = true;
1099 xLockBytes->SetError( ERRCODE_IO_GENERAL );
1100 break;
1104 bResultAchieved |= bException;
1105 bResultAchieved |= bAborted;
1106 if(nTimeout == 5000) nTimeout *= 2;
1109 if(pMod) pMod->setReply(Moderator::EXIT);
1111 if ( bAborted || bException )
1113 if( xHandler.Is() )
1114 xHandler->Handle( UcbLockBytesHandler::CANCEL, xLockBytes );
1116 Reference < XActiveDataSink > xActiveSink( xSink, UNO_QUERY );
1117 if ( xActiveSink.is() )
1118 xActiveSink->setInputStream( Reference < XInputStream >() );
1120 Reference < XActiveDataStreamer > xStreamer( xSink, UNO_QUERY );
1121 if ( xStreamer.is() )
1122 xStreamer->setStream( Reference < XStream >() );
1125 Reference < XActiveDataControl > xControl( xSink, UNO_QUERY );
1126 if ( xControl.is() )
1127 xControl->terminate();
1129 if ( xProps.is() )
1130 xProps->removePropertiesChangeListener(
1131 Sequence< OUString >(),
1132 xListener );
1134 return ( bAborted || bException );
1138 Function for opening UCB contents synchronously
1140 static sal_Bool _UCBOpenContentSync(
1141 UcbLockBytesRef xLockBytes,
1142 Reference < XContent > xContent,
1143 const Command& rArg,
1144 Reference < XInterface > xSink,
1145 Reference < XInteractionHandler > xInteract,
1146 Reference < XProgressHandler > xProgress,
1147 UcbLockBytesHandlerRef xHandler )
1149 ::ucbhelper::Content aContent(
1150 xContent, new UcbTaskEnvironment( xInteract, xProgress ),
1151 comphelper::getProcessComponentContext() );
1152 Reference < XContentIdentifier > xIdent = xContent->getIdentifier();
1153 OUString aScheme = xIdent->getContentProviderScheme();
1155 // http protocol must be handled in a special way: during the opening process the input stream may change
1156 // only the last inputstream after notifying the document headers is valid
1157 if ( aScheme.compareToAscii("http") != COMPARE_EQUAL )
1158 xLockBytes->SetStreamValid_Impl();
1160 Reference< XPropertiesChangeListener > xListener = new UcbPropertiesChangeListener_Impl( xLockBytes );
1161 Reference< XPropertiesChangeNotifier > xProps ( xContent, UNO_QUERY );
1162 if ( xProps.is() )
1163 xProps->addPropertiesChangeListener( Sequence< OUString >(), xListener );
1165 Any aResult;
1166 bool bException = false;
1167 bool bAborted = false;
1171 aResult = aContent.executeCommand( rArg.Name, rArg.Argument );
1173 catch (const CommandAbortedException&)
1175 bAborted = true;
1176 xLockBytes->SetError( ERRCODE_ABORT );
1178 catch (const CommandFailedException&)
1180 bAborted = true;
1181 xLockBytes->SetError( ERRCODE_ABORT );
1183 catch (const InteractiveIOException& r)
1185 bException = true;
1186 if ( r.Code == IOErrorCode_ACCESS_DENIED || r.Code == IOErrorCode_LOCKING_VIOLATION )
1187 xLockBytes->SetError( ERRCODE_IO_ACCESSDENIED );
1188 else if ( r.Code == IOErrorCode_NOT_EXISTING )
1189 xLockBytes->SetError( ERRCODE_IO_NOTEXISTS );
1190 else if ( r.Code == IOErrorCode_CANT_READ )
1191 xLockBytes->SetError( ERRCODE_IO_CANTREAD );
1192 else
1193 xLockBytes->SetError( ERRCODE_IO_GENERAL );
1195 catch (const UnsupportedDataSinkException&)
1197 bException = true;
1198 xLockBytes->SetError( ERRCODE_IO_NOTSUPPORTED );
1200 catch (const Exception&)
1202 bException = true;
1203 xLockBytes->SetError( ERRCODE_IO_GENERAL );
1206 if ( bAborted || bException )
1208 if( xHandler.Is() )
1209 xHandler->Handle( UcbLockBytesHandler::CANCEL, xLockBytes );
1211 Reference < XActiveDataSink > xActiveSink( xSink, UNO_QUERY );
1212 if ( xActiveSink.is() )
1213 xActiveSink->setInputStream( Reference < XInputStream >() );
1215 Reference < XActiveDataStreamer > xStreamer( xSink, UNO_QUERY );
1216 if ( xStreamer.is() )
1217 xStreamer->setStream( Reference < XStream >() );
1220 Reference < XActiveDataControl > xControl( xSink, UNO_QUERY );
1221 if ( xControl.is() )
1222 xControl->terminate();
1225 if ( xProps.is() )
1226 xProps->removePropertiesChangeListener( Sequence< OUString >(), xListener );
1228 return ( bAborted || bException );
1231 //----------------------------------------------------------------------------
1232 UcbLockBytes::UcbLockBytes( UcbLockBytesHandler* pHandler )
1233 : m_aExpireDate( DateTime::EMPTY )
1234 , m_xInputStream (NULL)
1235 , m_pCommandThread( NULL )
1236 , m_xHandler( pHandler )
1237 , m_nError( ERRCODE_NONE )
1238 , m_bTerminated (sal_False)
1239 , m_bDontClose( sal_False )
1240 , m_bStreamValid (sal_False)
1242 SetSynchronMode( sal_True );
1245 //----------------------------------------------------------------------------
1246 UcbLockBytes::~UcbLockBytes()
1248 if ( !m_bDontClose )
1250 if ( m_xInputStream.is() )
1254 m_xInputStream->closeInput();
1256 catch (const RuntimeException&)
1259 catch (const IOException&)
1265 if ( !m_xInputStream.is() && m_xOutputStream.is() )
1269 m_xOutputStream->closeOutput();
1271 catch (const RuntimeException&)
1274 catch (const IOException&)
1280 Reference < XInputStream > UcbLockBytes::getInputStream()
1282 osl::MutexGuard aGuard( m_aMutex );
1283 m_bDontClose = sal_True;
1284 return m_xInputStream;
1287 //----------------------------------------------------------------------------
1289 sal_Bool UcbLockBytes::setStream_Impl( const Reference<XStream>& aStream )
1291 osl::MutexGuard aGuard( m_aMutex );
1292 if ( aStream.is() )
1294 m_xOutputStream = aStream->getOutputStream();
1295 setInputStream_Impl( aStream->getInputStream(), sal_False );
1296 m_xSeekable = Reference < XSeekable > ( aStream, UNO_QUERY );
1298 else
1300 m_xOutputStream = Reference < XOutputStream >();
1301 setInputStream_Impl( Reference < XInputStream >() );
1304 return m_xInputStream.is();
1307 sal_Bool UcbLockBytes::setInputStream_Impl( const Reference<XInputStream> &rxInputStream, sal_Bool bSetXSeekable )
1309 sal_Bool bRet = sal_False;
1313 osl::MutexGuard aGuard( m_aMutex );
1315 if ( !m_bDontClose && m_xInputStream.is() )
1316 m_xInputStream->closeInput();
1318 m_xInputStream = rxInputStream;
1320 if( bSetXSeekable )
1322 m_xSeekable = Reference < XSeekable > ( rxInputStream, UNO_QUERY );
1323 if( !m_xSeekable.is() && rxInputStream.is() )
1325 Reference < XComponentContext > xContext = ::comphelper::getProcessComponentContext();
1326 Reference< XOutputStream > rxTempOut = Reference < XOutputStream > ( TempFile::create(xContext), UNO_QUERY_THROW );
1328 ::comphelper::OStorageHelper::CopyInputToOutput( rxInputStream, rxTempOut );
1329 m_xInputStream = Reference< XInputStream >( rxTempOut, UNO_QUERY );
1330 m_xSeekable = Reference < XSeekable > ( rxTempOut, UNO_QUERY );
1334 bRet = m_xInputStream.is();
1336 catch (const Exception&)
1340 if ( m_bStreamValid && m_xInputStream.is() )
1341 m_aInitialized.set();
1343 return bRet;
1346 void UcbLockBytes::SetStreamValid_Impl()
1348 m_bStreamValid = sal_True;
1349 if ( m_xInputStream.is() )
1350 m_aInitialized.set();
1353 //----------------------------------------------------------------------------
1354 void UcbLockBytes::terminate_Impl()
1356 m_bTerminated = sal_True;
1357 m_aInitialized.set();
1358 m_aTerminated.set();
1360 if ( GetError() == ERRCODE_NONE && !m_xInputStream.is() )
1362 OSL_FAIL("No InputStream, but no error set!" );
1363 SetError( ERRCODE_IO_NOTEXISTS );
1366 if ( m_xHandler.Is() )
1367 m_xHandler->Handle( UcbLockBytesHandler::DONE, this );
1370 //----------------------------------------------------------------------------
1371 void UcbLockBytes::SetSynchronMode (sal_Bool bSynchron)
1373 SvLockBytes::SetSynchronMode (bSynchron);
1376 //----------------------------------------------------------------------------
1377 ErrCode UcbLockBytes::ReadAt ( sal_uLong nPos, void *pBuffer, sal_uLong nCount, sal_uLong *pRead) const
1379 if ( IsSynchronMode() )
1381 UcbLockBytes* pThis = const_cast < UcbLockBytes* >( this );
1382 pThis->m_aInitialized.wait();
1385 Reference <XInputStream> xStream = getInputStream_Impl();
1386 if ( !xStream.is() )
1388 if ( m_bTerminated )
1389 return ERRCODE_IO_CANTREAD;
1390 else
1391 return ERRCODE_IO_PENDING;
1394 if ( pRead )
1395 *pRead = 0;
1397 Reference <XSeekable> xSeekable = getSeekable_Impl();
1398 if ( !xSeekable.is() )
1399 return ERRCODE_IO_CANTREAD;
1403 xSeekable->seek( nPos );
1405 catch (const IOException&)
1407 return ERRCODE_IO_CANTSEEK;
1409 catch (const com::sun::star::lang::IllegalArgumentException&)
1411 return ERRCODE_IO_CANTSEEK;
1414 Sequence<sal_Int8> aData;
1415 sal_Int32 nSize;
1417 if(nCount > 0x7FFFFFFF)
1419 nCount = 0x7FFFFFFF;
1423 if ( !m_bTerminated && !IsSynchronMode() )
1425 sal_uInt64 nLen = xSeekable->getLength();
1426 if ( nPos + nCount > nLen )
1427 return ERRCODE_IO_PENDING;
1430 nSize = xStream->readBytes( aData, sal_Int32(nCount) );
1432 catch (const IOException&)
1434 return ERRCODE_IO_CANTREAD;
1437 memcpy (pBuffer, aData.getConstArray(), nSize);
1438 if (pRead)
1439 *pRead = sal_uLong(nSize);
1441 return ERRCODE_NONE;
1444 //----------------------------------------------------------------------------
1445 ErrCode UcbLockBytes::WriteAt ( sal_uLong nPos, const void *pBuffer, sal_uLong nCount, sal_uLong *pWritten)
1447 if ( pWritten )
1448 *pWritten = 0;
1450 DBG_ASSERT( IsSynchronMode(), "Writing is only possible in SynchronMode!" );
1451 DBG_ASSERT( m_aInitialized.check(), "Writing bevor stream is ready!" );
1453 Reference <XSeekable> xSeekable = getSeekable_Impl();
1454 Reference <XOutputStream> xOutputStream = getOutputStream_Impl();
1455 if ( !xOutputStream.is() || !xSeekable.is() )
1456 return ERRCODE_IO_CANTWRITE;
1460 xSeekable->seek( nPos );
1462 catch (const IOException&)
1464 return ERRCODE_IO_CANTSEEK;
1467 sal_Int8* pData = (sal_Int8*) pBuffer;
1468 Sequence<sal_Int8> aData( pData, nCount );
1471 xOutputStream->writeBytes( aData );
1472 if ( pWritten )
1473 *pWritten = nCount;
1475 catch (const Exception&)
1477 return ERRCODE_IO_CANTWRITE;
1480 return ERRCODE_NONE;
1483 //----------------------------------------------------------------------------
1484 ErrCode UcbLockBytes::Flush() const
1486 Reference <XOutputStream > xOutputStream = getOutputStream_Impl();
1487 if ( !xOutputStream.is() )
1488 return ERRCODE_IO_CANTWRITE;
1492 xOutputStream->flush();
1494 catch (const Exception&)
1496 return ERRCODE_IO_CANTWRITE;
1499 return ERRCODE_NONE;
1502 //----------------------------------------------------------------------------
1503 ErrCode UcbLockBytes::SetSize (sal_uLong nNewSize)
1505 SvLockBytesStat aStat;
1506 Stat( &aStat, (SvLockBytesStatFlag) 0 );
1507 sal_uLong nSize = aStat.nSize;
1509 if ( nSize > nNewSize )
1511 Reference < XTruncate > xTrunc( getOutputStream_Impl(), UNO_QUERY );
1512 if ( xTrunc.is() )
1514 xTrunc->truncate();
1515 nSize = 0;
1517 else {
1518 DBG_WARNING("Not truncatable!");
1522 if ( nSize < nNewSize )
1524 sal_uLong nDiff = nNewSize-nSize, nCount=0;
1525 sal_uInt8* pBuffer = new sal_uInt8[ nDiff ];
1526 memset(pBuffer, 0, nDiff); // initialize for enhanced security
1527 WriteAt( nSize, pBuffer, nDiff, &nCount );
1528 delete[] pBuffer;
1529 if ( nCount != nDiff )
1530 return ERRCODE_IO_CANTWRITE;
1533 return ERRCODE_NONE;
1536 //----------------------------------------------------------------------------
1537 ErrCode UcbLockBytes::Stat( SvLockBytesStat *pStat, SvLockBytesStatFlag) const
1539 if ( IsSynchronMode() )
1541 UcbLockBytes* pThis = const_cast < UcbLockBytes* >( this );
1542 pThis->m_aInitialized.wait();
1545 if (!pStat)
1546 return ERRCODE_IO_INVALIDPARAMETER;
1548 Reference <XInputStream> xStream = getInputStream_Impl();
1549 Reference <XSeekable> xSeekable = getSeekable_Impl();
1551 if ( !xStream.is() )
1553 if ( m_bTerminated )
1554 return ERRCODE_IO_INVALIDACCESS;
1555 else
1556 return ERRCODE_IO_PENDING;
1558 else if( !xSeekable.is() )
1559 return ERRCODE_IO_CANTTELL;
1563 pStat->nSize = sal_uLong(xSeekable->getLength());
1565 catch (const IOException&)
1567 return ERRCODE_IO_CANTTELL;
1570 return ERRCODE_NONE;
1573 //----------------------------------------------------------------------------
1574 IMPL_LINK_NOARG(UcbLockBytes, DataAvailHdl)
1576 if ( hasInputStream_Impl() && m_xHandler.Is() )
1577 m_xHandler->Handle( UcbLockBytesHandler::DATA_AVAILABLE, this );
1579 return 0;
1582 UcbLockBytesRef UcbLockBytes::CreateInputLockBytes( const Reference< XInputStream >& xInputStream )
1584 if( !xInputStream.is() )
1585 return NULL;
1587 UcbLockBytesRef xLockBytes = new UcbLockBytes();
1588 xLockBytes->setDontClose_Impl();
1589 xLockBytes->setInputStream_Impl( xInputStream );
1590 xLockBytes->terminate_Impl();
1591 return xLockBytes;
1594 UcbLockBytesRef UcbLockBytes::CreateLockBytes( const Reference< XStream >& xStream )
1596 if( !xStream.is() )
1597 return NULL;
1599 UcbLockBytesRef xLockBytes = new UcbLockBytes();
1600 xLockBytes->setDontClose_Impl();
1601 xLockBytes->setStream_Impl( xStream );
1602 xLockBytes->terminate_Impl();
1603 return xLockBytes;
1606 UcbLockBytesRef UcbLockBytes::CreateLockBytes( const Reference < XContent >& xContent, const Sequence < PropertyValue >& rProps,
1607 StreamMode eOpenMode, const Reference < XInteractionHandler >& xInteractionHandler, UcbLockBytesHandler* pHandler )
1609 if( !xContent.is() )
1610 return NULL;
1612 UcbLockBytesRef xLockBytes = new UcbLockBytes( pHandler );
1613 xLockBytes->SetSynchronMode( !pHandler );
1614 Reference< XActiveDataControl > xSink;
1615 if ( eOpenMode & STREAM_WRITE )
1616 xSink = (XActiveDataControl*) new UcbStreamer_Impl( xLockBytes );
1617 else
1618 xSink = (XActiveDataControl*) new UcbDataSink_Impl( xLockBytes );
1620 if ( rProps.getLength() )
1622 Reference < XCommandProcessor > xProcessor( xContent, UNO_QUERY );
1623 Command aCommand;
1624 aCommand.Name = OUString("setPropertyValues");
1625 aCommand.Handle = -1; /* unknown */
1626 aCommand.Argument <<= rProps;
1627 xProcessor->execute( aCommand, 0, Reference < XCommandEnvironment >() );
1630 OpenCommandArgument2 aArgument;
1631 aArgument.Sink = xSink;
1632 aArgument.Mode = OpenMode::DOCUMENT;
1634 Command aCommand;
1635 aCommand.Name = OUString( "open" );
1636 aCommand.Argument <<= aArgument;
1638 Reference< XProgressHandler > xProgressHdl = new ProgressHandler_Impl( LINK( &xLockBytes, UcbLockBytes, DataAvailHdl ) );
1640 sal_Bool bError = UCBOpenContentSync( xLockBytes,
1641 xContent,
1642 aCommand,
1643 xSink,
1644 xInteractionHandler,
1645 xProgressHdl,
1646 pHandler );
1648 if ( xLockBytes->GetError() == ERRCODE_NONE && ( bError || !xLockBytes->getInputStream().is() ) )
1650 OSL_FAIL("No InputStream, but no error set!" );
1651 xLockBytes->SetError( ERRCODE_IO_GENERAL );
1654 return xLockBytes;
1659 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */