xref: /trunk/main/basic/source/runtime/iosys.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_basic.hxx"
30 #include <vcl/dialog.hxx>
31 #include <vcl/edit.hxx>
32 #ifndef _SV_BUTTON_HXX //autogen
33 #include <vcl/button.hxx>
34 #endif
35 #include <vcl/msgbox.hxx>
36 #include <vcl/svapp.hxx>
37 #include <osl/security.h>
38 #include <osl/file.hxx>
39 #include <tools/urlobj.hxx>
40 #include <vos/mutex.hxx>
41 
42 #include "runtime.hxx"
43 
44 #ifdef _USE_UNO
45 
46 // <-- encoding
47 #include <sal/alloca.h>
48 
49 #include <ctype.h>
50 #include <rtl/byteseq.hxx>
51 #include <rtl/textenc.h>
52 #include <rtl/ustrbuf.hxx>
53 #include <rtl/textenc.h>
54 #include <rtl/ustrbuf.hxx>
55 // encoding -->
56 #include <comphelper/processfactory.hxx>
57 
58 #include <com/sun/star/uno/Sequence.hxx>
59 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
60 #include <com/sun/star/ucb/XSimpleFileAccess.hpp>
61 #include <com/sun/star/ucb/XContentProvider.hpp>
62 #include <com/sun/star/ucb/XContentProviderManager.hpp>
63 #include <com/sun/star/io/XInputStream.hpp>
64 #include <com/sun/star/io/XOutputStream.hpp>
65 #include <com/sun/star/io/XStream.hpp>
66 #include <com/sun/star/io/XSeekable.hpp>
67 #include <com/sun/star/bridge/XBridge.hpp>
68 #include <com/sun/star/bridge/XBridgeFactory.hpp>
69 
70 using namespace comphelper;
71 using namespace osl;
72 using namespace com::sun::star::uno;
73 using namespace com::sun::star::lang;
74 using namespace com::sun::star::ucb;
75 using namespace com::sun::star::io;
76 using namespace com::sun::star::bridge;
77 
78 #endif /* _USE_UNO */
79 
80 #include "iosys.hxx"
81 #include "sbintern.hxx"
82 
83 // Der Input-Dialog:
84 
85 class SbiInputDialog : public ModalDialog {
86     Edit aInput;
87     OKButton aOk;
88     CancelButton aCancel;
89     String aText;
90     DECL_LINK( Ok, Window * );
91     DECL_LINK( Cancel, Window * );
92 public:
93     SbiInputDialog( Window*, const String& );
94     const String& GetInput() { return aText; }
95 };
96 
97 SbiInputDialog::SbiInputDialog( Window* pParent, const String& rPrompt )
98             :ModalDialog( pParent, WB_3DLOOK | WB_MOVEABLE | WB_CLOSEABLE ),
99              aInput( this, WB_3DLOOK | WB_LEFT | WB_BORDER ),
100              aOk( this ), aCancel( this )
101 {
102     SetText( rPrompt );
103     aOk.SetClickHdl( LINK( this, SbiInputDialog, Ok ) );
104     aCancel.SetClickHdl( LINK( this, SbiInputDialog, Cancel ) );
105     SetMapMode( MapMode( MAP_APPFONT ) );
106 
107     Point aPt = LogicToPixel( Point( 50, 50 ) );
108     Size  aSz = LogicToPixel( Size( 145, 65 ) );
109     SetPosSizePixel( aPt, aSz );
110     aPt = LogicToPixel( Point( 10, 10 ) );
111     aSz = LogicToPixel( Size( 120, 12 ) );
112     aInput.SetPosSizePixel( aPt, aSz );
113     aPt = LogicToPixel( Point( 15, 30 ) );
114     aSz = LogicToPixel( Size( 45, 15) );
115     aOk.SetPosSizePixel( aPt, aSz );
116     aPt = LogicToPixel( Point( 80, 30 ) );
117     aSz = LogicToPixel( Size( 45, 15) );
118     aCancel.SetPosSizePixel( aPt, aSz );
119 
120     aInput.Show();
121     aOk.Show();
122     aCancel.Show();
123 }
124 
125 IMPL_LINK_INLINE_START( SbiInputDialog, Ok, Window *, pWindow )
126 {
127     (void)pWindow;
128 
129     aText = aInput.GetText();
130     EndDialog( 1 );
131     return 0;
132 }
133 IMPL_LINK_INLINE_END( SbiInputDialog, Ok, Window *, pWindow )
134 
135 IMPL_LINK_INLINE_START( SbiInputDialog, Cancel, Window *, pWindow )
136 {
137     (void)pWindow;
138 
139     EndDialog( 0 );
140     return 0;
141 }
142 IMPL_LINK_INLINE_END( SbiInputDialog, Cancel, Window *, pWindow )
143 
144 //////////////////////////////////////////////////////////////////////////
145 
146 SbiStream::SbiStream()
147     : pStrm( 0 )
148 {
149 }
150 
151 SbiStream::~SbiStream()
152 {
153     delete pStrm;
154 }
155 
156 // Ummappen eines SvStream-Fehlers auf einen StarBASIC-Code
157 
158 void SbiStream::MapError()
159 {
160     if( pStrm )
161      switch( pStrm->GetError() )
162      {
163         case SVSTREAM_OK:
164             nError = 0; break;
165         case SVSTREAM_FILE_NOT_FOUND:
166             nError = SbERR_FILE_NOT_FOUND; break;
167         case SVSTREAM_PATH_NOT_FOUND:
168             nError = SbERR_PATH_NOT_FOUND; break;
169         case SVSTREAM_TOO_MANY_OPEN_FILES:
170             nError = SbERR_TOO_MANY_FILES; break;
171         case SVSTREAM_ACCESS_DENIED:
172             nError = SbERR_ACCESS_DENIED; break;
173         case SVSTREAM_INVALID_PARAMETER:
174             nError = SbERR_BAD_ARGUMENT; break;
175         case SVSTREAM_OUTOFMEMORY:
176             nError = SbERR_NO_MEMORY; break;
177         default:
178             nError = SbERR_IO_ERROR; break;
179     }
180 }
181 
182 #ifdef _USE_UNO
183 
184 // TODO: Code is copied from daemons2/source/uno/asciiEncoder.cxx
185 
186 ::rtl::OUString findUserInDescription( const ::rtl::OUString& aDescription )
187 {
188     ::rtl::OUString user;
189 
190     sal_Int32 index;
191     sal_Int32 lastIndex = 0;
192 
193     do
194     {
195         index = aDescription.indexOf((sal_Unicode) ',', lastIndex);
196         ::rtl::OUString token = (index == -1) ? aDescription.copy(lastIndex) : aDescription.copy(lastIndex, index - lastIndex);
197 
198         lastIndex = index + 1;
199 
200         sal_Int32 eindex = token.indexOf((sal_Unicode)'=');
201         ::rtl::OUString left = token.copy(0, eindex).toAsciiLowerCase().trim();
202         ::rtl::OUString right = INetURLObject::decode( token.copy(eindex + 1).trim(), '%',
203                             INetURLObject::DECODE_WITH_CHARSET );
204 
205         if(left.equals(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("user"))))
206         {
207             user = right;
208             break;
209         }
210     }
211     while(index != -1);
212 
213     return user;
214 }
215 
216 #endif
217 
218 
219 // Hack for #83750
220 sal_Bool runsInSetup( void );
221 
222 sal_Bool needSecurityRestrictions( void )
223 {
224 #ifdef _USE_UNO
225     static sal_Bool bNeedInit = sal_True;
226     static sal_Bool bRetVal = sal_True;
227 
228     if( bNeedInit )
229     {
230         // Hack for #83750, use internal flag until
231         // setup provides own service manager
232         if( runsInSetup() )
233         {
234             // Setup is not critical
235             bRetVal = sal_False;
236             return bRetVal;
237         }
238 
239         bNeedInit = sal_False;
240 
241         // Get system user to compare to portal user
242         oslSecurity aSecurity = osl_getCurrentSecurity();
243         ::rtl::OUString aSystemUser;
244         sal_Bool bRet = osl_getUserName( aSecurity, &aSystemUser.pData );
245         if( !bRet )
246         {
247             // No valid security! -> Secure mode!
248             return sal_True;
249         }
250 
251         Reference< XMultiServiceFactory > xSMgr = getProcessServiceFactory();
252         if( !xSMgr.is() )
253             return sal_True;
254         Reference< XBridgeFactory > xBridgeFac( xSMgr->createInstance
255             ( ::rtl::OUString::createFromAscii( "com.sun.star.bridge.BridgeFactory" ) ), UNO_QUERY );
256 
257         Sequence< Reference< XBridge > > aBridgeSeq;
258         sal_Int32 nBridgeCount = 0;
259         if( xBridgeFac.is() )
260         {
261             aBridgeSeq = xBridgeFac->getExistingBridges();
262             nBridgeCount = aBridgeSeq.getLength();
263         }
264 
265         if( nBridgeCount == 0 )
266         {
267             // No bridges -> local
268             bRetVal = sal_False;
269             return bRetVal;
270         }
271 
272         // Iterate through all bridges to find (portal) user property
273         const Reference< XBridge >* pBridges = aBridgeSeq.getConstArray();
274         bRetVal = sal_False;    // Now only sal_True if user different from portal user is found
275         sal_Int32 i;
276         for( i = 0 ; i < nBridgeCount ; i++ )
277         {
278             const Reference< XBridge >& rxBridge = pBridges[ i ];
279             ::rtl::OUString aDescription = rxBridge->getDescription();
280             ::rtl::OUString aPortalUser = findUserInDescription( aDescription );
281             if( aPortalUser.getLength() > 0 )
282             {
283                 // User Found, compare to system user
284                 if( aPortalUser == aSystemUser )
285                 {
286                     // Same user -> system security is ok, bRetVal stays FALSE
287                     break;
288                 }
289                 else
290                 {
291                     // Different user -> Secure mode!
292                     bRetVal = sal_True;
293                     break;
294                 }
295             }
296         }
297         // No user found or PortalUser != SystemUser -> Secure mode! (Keep default value)
298     }
299 
300     return bRetVal;
301 #else
302     return sal_False;
303 #endif
304 }
305 
306 // Returns sal_True if UNO is available, otherwise the old file
307 // system implementation has to be used
308 // #89378 New semantic: Don't just ask for UNO but for UCB
309 sal_Bool hasUno( void )
310 {
311 #ifdef _USE_UNO
312     static sal_Bool bNeedInit = sal_True;
313     static sal_Bool bRetVal = sal_True;
314 
315     if( bNeedInit )
316     {
317         bNeedInit = sal_False;
318         Reference< XMultiServiceFactory > xSMgr = getProcessServiceFactory();
319         if( !xSMgr.is() )
320         {
321             // No service manager at all
322             bRetVal = sal_False;
323         }
324         else
325         {
326             Reference< XContentProviderManager > xManager( xSMgr->createInstance( ::rtl::OUString::createFromAscii
327                     ( "com.sun.star.ucb.UniversalContentBroker" ) ), UNO_QUERY );
328 
329             if ( !( xManager.is() && xManager->queryContentProvider( ::rtl::OUString::createFromAscii( "file:///" ) ).is() ) )
330             {
331                 // No UCB
332                 bRetVal = sal_False;
333             }
334         }
335     }
336     return bRetVal;
337 #else
338     return sal_False;
339 #endif
340 }
341 
342 
343 
344 #ifndef _OLD_FILE_IMPL
345 
346 class OslStream : public SvStream
347 {
348     File maFile;
349     short mnStrmMode;
350 
351 public:
352                     OslStream( const String& rName, short nStrmMode );
353                     ~OslStream();
354     virtual sal_uIntPtr GetData( void* pData, sal_uIntPtr nSize );
355     virtual sal_uIntPtr PutData( const void* pData, sal_uIntPtr nSize );
356     virtual sal_uIntPtr SeekPos( sal_uIntPtr nPos );
357     virtual void    FlushData();
358     virtual void    SetSize( sal_uIntPtr nSize );
359 };
360 
361 OslStream::OslStream( const String& rName, short nStrmMode )
362     : maFile( rName )
363     , mnStrmMode( nStrmMode )
364 {
365     sal_uInt32 nFlags;
366 
367     if( (nStrmMode & (STREAM_READ | STREAM_WRITE)) == (STREAM_READ | STREAM_WRITE) )
368     {
369         nFlags = OpenFlag_Read | OpenFlag_Write;
370     }
371     else if( nStrmMode & STREAM_WRITE )
372     {
373         nFlags = OpenFlag_Write;
374     }
375     else //if( nStrmMode & STREAM_READ )
376     {
377         nFlags = OpenFlag_Read;
378     }
379 
380     FileBase::RC nRet = maFile.open( nFlags );
381     if( nRet == FileBase::E_NOENT && nFlags != OpenFlag_Read )
382     {
383         nFlags |= OpenFlag_Create;
384         nRet = maFile.open( nFlags );
385     }
386 
387     if( nRet != FileBase::E_None )
388     {
389         SetError( ERRCODE_IO_GENERAL );
390     }
391 }
392 
393 
394 OslStream::~OslStream()
395 {
396     maFile.close();
397 }
398 
399 sal_uIntPtr OslStream::GetData( void* pData, sal_uIntPtr nSize )
400 {
401     sal_uInt64 nBytesRead = nSize;
402     FileBase::RC nRet = FileBase::E_None;
403     nRet = maFile.read( pData, nBytesRead, nBytesRead );
404     return (sal_uIntPtr)nBytesRead;
405 }
406 
407 sal_uIntPtr OslStream::PutData( const void* pData, sal_uIntPtr nSize )
408 {
409     sal_uInt64 nBytesWritten;
410     FileBase::RC nRet = FileBase::E_None;
411     nRet = maFile.write( pData, (sal_uInt64)nSize, nBytesWritten );
412     return (sal_uIntPtr)nBytesWritten;
413 }
414 
415 sal_uIntPtr OslStream::SeekPos( sal_uIntPtr nPos )
416 {
417     FileBase::RC nRet;
418     if( nPos == STREAM_SEEK_TO_END )
419     {
420         nRet = maFile.setPos( Pos_End, 0 );
421     }
422     else
423     {
424         nRet = maFile.setPos( Pos_Absolut, (sal_uInt64)nPos );
425     }
426     sal_uInt64 nRealPos;
427     nRet = maFile.getPos( nRealPos );
428     return sal::static_int_cast<sal_uIntPtr>(nRealPos);
429 }
430 
431 void OslStream::FlushData()
432 {
433 }
434 
435 void OslStream::SetSize( sal_uIntPtr nSize )
436 {
437     FileBase::RC nRet = FileBase::E_None;
438     nRet = maFile.setSize( (sal_uInt64)nSize );
439 }
440 
441 #endif
442 
443 
444 #ifdef _USE_UNO
445 
446 class UCBStream : public SvStream
447 {
448     Reference< XInputStream >   xIS;
449     Reference< XOutputStream >  xOS;
450     Reference< XStream >        xS;
451     Reference< XSeekable >      xSeek;
452 public:
453                     UCBStream( Reference< XInputStream > & xIS );
454                     UCBStream( Reference< XOutputStream > & xOS );
455                     UCBStream( Reference< XStream > & xS );
456                     ~UCBStream();
457     virtual sal_uIntPtr GetData( void* pData, sal_uIntPtr nSize );
458     virtual sal_uIntPtr PutData( const void* pData, sal_uIntPtr nSize );
459     virtual sal_uIntPtr SeekPos( sal_uIntPtr nPos );
460     virtual void    FlushData();
461     virtual void    SetSize( sal_uIntPtr nSize );
462 };
463 
464 /*
465 sal_uIntPtr UCBErrorToSvStramError( ucb::IOErrorCode nError )
466 {
467     sal_uIntPtr eReturn = ERRCODE_IO_GENERAL;
468     switch( nError )
469     {
470         case ucb::IOErrorCode_ABORT:                eReturn = SVSTREAM_GENERALERROR; break;
471         case ucb::IOErrorCode_NOT_EXISTING:         eReturn = SVSTREAM_FILE_NOT_FOUND; break;
472         case ucb::IOErrorCode_NOT_EXISTING_PATH:    eReturn = SVSTREAM_PATH_NOT_FOUND; break;
473         case ucb::IOErrorCode_OUT_OF_FILE_HANDLES:  eReturn = SVSTREAM_TOO_MANY_OPEN_FILES; break;
474         case ucb::IOErrorCode_ACCESS_DENIED:        eReturn = SVSTREAM_ACCESS_DENIED; break;
475         case ucb::IOErrorCode_LOCKING_VIOLATION:    eReturn = SVSTREAM_SHARING_VIOLATION; break;
476 
477         case ucb::IOErrorCode_INVALID_ACCESS:       eReturn = SVSTREAM_INVALID_ACCESS; break;
478         case ucb::IOErrorCode_CANT_CREATE:          eReturn = SVSTREAM_CANNOT_MAKE; break;
479         case ucb::IOErrorCode_INVALID_PARAMETER:    eReturn = SVSTREAM_INVALID_PARAMETER; break;
480 
481         case ucb::IOErrorCode_CANT_READ:            eReturn = SVSTREAM_READ_ERROR; break;
482         case ucb::IOErrorCode_CANT_WRITE:           eReturn = SVSTREAM_WRITE_ERROR; break;
483         case ucb::IOErrorCode_CANT_SEEK:            eReturn = SVSTREAM_SEEK_ERROR; break;
484         case ucb::IOErrorCode_CANT_TELL:            eReturn = SVSTREAM_TELL_ERROR; break;
485 
486         case ucb::IOErrorCode_OUT_OF_MEMORY:        eReturn = SVSTREAM_OUTOFMEMORY; break;
487 
488         case SVSTREAM_FILEFORMAT_ERROR:             eReturn = SVSTREAM_FILEFORMAT_ERROR; break;
489         case ucb::IOErrorCode_WRONG_VERSION:        eReturn = SVSTREAM_WRONGVERSION;
490         case ucb::IOErrorCode_OUT_OF_DISK_SPACE:    eReturn = SVSTREAM_DISK_FULL; break;
491 
492         case ucb::IOErrorCode_BAD_CRC:              eReturn = ERRCODE_IO_BADCRC; break;
493     }
494     return eReturn;
495 }
496 */
497 
498 UCBStream::UCBStream( Reference< XInputStream > & rStm )
499     : xIS( rStm )
500     , xSeek( rStm, UNO_QUERY )
501 {
502 }
503 
504 UCBStream::UCBStream( Reference< XOutputStream > & rStm )
505     : xOS( rStm )
506     , xSeek( rStm, UNO_QUERY )
507 {
508 }
509 
510 UCBStream::UCBStream( Reference< XStream > & rStm )
511     : xS( rStm )
512     , xSeek( rStm, UNO_QUERY )
513 {
514 }
515 
516 
517 UCBStream::~UCBStream()
518 {
519     try
520     {
521         if( xIS.is() )
522             xIS->closeInput();
523         else if( xOS.is() )
524             xOS->closeOutput();
525         else if( xS.is() )
526         {
527             Reference< XInputStream > xIS_ = xS->getInputStream();
528             if( xIS_.is() )
529                 xIS_->closeInput();
530         }
531     }
532     catch( Exception & )
533     {
534         SetError( ERRCODE_IO_GENERAL );
535     }
536 }
537 
538 sal_uIntPtr UCBStream::GetData( void* pData, sal_uIntPtr nSize )
539 {
540     try
541     {
542         Reference< XInputStream > xISFromS;
543         if( xIS.is() )
544         {
545             Sequence<sal_Int8> aData;
546             nSize = xIS->readBytes( aData, nSize );
547             rtl_copyMemory( pData, aData.getConstArray(), nSize );
548             return nSize;
549         }
550         else if( xS.is() && (xISFromS = xS->getInputStream()).is() )
551         {
552             Sequence<sal_Int8> aData;
553             nSize = xISFromS->readBytes( aData, nSize );
554             rtl_copyMemory( pData, aData.getConstArray(), nSize );
555             return nSize;
556         }
557         else
558             SetError( ERRCODE_IO_GENERAL );
559     }
560     catch( Exception & )
561     {
562         SetError( ERRCODE_IO_GENERAL );
563     }
564     return 0;
565 }
566 
567 sal_uIntPtr UCBStream::PutData( const void* pData, sal_uIntPtr nSize )
568 {
569     try
570     {
571         Reference< XOutputStream > xOSFromS;
572         if( xOS.is() )
573         {
574             Sequence<sal_Int8> aData( (const sal_Int8 *)pData, nSize );
575             xOS->writeBytes( aData );
576             return nSize;
577         }
578         else if( xS.is() && (xOSFromS = xS->getOutputStream()).is() )
579         {
580             Sequence<sal_Int8> aData( (const sal_Int8 *)pData, nSize );
581             xOSFromS->writeBytes( aData );
582             return nSize;
583         }
584         else
585             SetError( ERRCODE_IO_GENERAL );
586     }
587     catch( Exception & )
588     {
589         SetError( ERRCODE_IO_GENERAL );
590     }
591     return 0;
592 }
593 
594 sal_uIntPtr UCBStream::SeekPos( sal_uIntPtr nPos )
595 {
596     try
597     {
598         if( xSeek.is() )
599         {
600             sal_uIntPtr nLen = sal::static_int_cast<sal_uIntPtr>( xSeek->getLength() );
601             if( nPos > nLen )
602                 nPos = nLen;
603             xSeek->seek( nPos );
604             return nPos;
605         }
606         else
607             SetError( ERRCODE_IO_GENERAL );
608     }
609     catch( Exception & )
610     {
611         SetError( ERRCODE_IO_GENERAL );
612     }
613     return 0;
614 }
615 
616 void    UCBStream::FlushData()
617 {
618     try
619     {
620         Reference< XOutputStream > xOSFromS;
621         if( xOS.is() )
622             xOS->flush();
623         else if( xS.is() && (xOSFromS = xS->getOutputStream()).is() )
624             xOSFromS->flush();
625         else
626             SetError( ERRCODE_IO_GENERAL );
627     }
628     catch( Exception & )
629     {
630         SetError( ERRCODE_IO_GENERAL );
631     }
632 }
633 
634 void    UCBStream::SetSize( sal_uIntPtr nSize )
635 {
636     (void)nSize;
637 
638     DBG_ERROR( "not allowed to call from basic" );
639     SetError( ERRCODE_IO_GENERAL );
640 }
641 
642 #endif
643 
644 // Oeffnen eines Streams
645 SbError SbiStream::Open
646 ( short nCh, const ByteString& rName, short nStrmMode, short nFlags, short nL )
647 {
648     nMode   = nFlags;
649     nLen    = nL;
650     nChan   = nCh;
651     nLine   = 0;
652     nExpandOnWriteTo = 0;
653     if( ( nStrmMode & ( STREAM_READ|STREAM_WRITE ) ) == STREAM_READ )
654         nStrmMode |= STREAM_NOCREATE;
655     String aStr( rName, gsl_getSystemTextEncoding() );
656     String aNameStr = getFullPath( aStr );
657 
658 #ifdef _USE_UNO
659     if( hasUno() )
660     {
661         Reference< XMultiServiceFactory > xSMgr = getProcessServiceFactory();
662         if( xSMgr.is() )
663         {
664             Reference< XSimpleFileAccess >
665                 xSFI( xSMgr->createInstance( ::rtl::OUString::createFromAscii( "com.sun.star.ucb.SimpleFileAccess" ) ), UNO_QUERY );
666             if( xSFI.is() )
667             {
668                 try
669                 {
670 
671                 // #??? For write access delete file if it already exists (not for appending)
672                 if( (nStrmMode & STREAM_WRITE) != 0 && !IsAppend() && !IsBinary() &&
673                     xSFI->exists( aNameStr ) && !xSFI->isFolder( aNameStr ) )
674                 {
675                     xSFI->kill( aNameStr );
676                 }
677 
678                 if( (nStrmMode & (STREAM_READ | STREAM_WRITE)) == (STREAM_READ | STREAM_WRITE) )
679                 {
680                     Reference< XStream > xIS = xSFI->openFileReadWrite( aNameStr );
681                     pStrm = new UCBStream( xIS );
682                 }
683                 else if( nStrmMode & STREAM_WRITE )
684                 {
685                     Reference< XStream > xIS = xSFI->openFileReadWrite( aNameStr );
686                     pStrm = new UCBStream( xIS );
687                     // Open for writing is not implemented in ucb yet!!!
688                     //Reference< XOutputStream > xIS = xSFI->openFileWrite( aNameStr );
689                     //pStrm = new UCBStream( xIS );
690                 }
691                 else //if( nStrmMode & STREAM_READ )
692                 {
693                     Reference< XInputStream > xIS = xSFI->openFileRead( aNameStr );
694                     pStrm = new UCBStream( xIS );
695                 }
696 
697                 }
698                 catch( Exception & )
699                 {
700                     nError = ERRCODE_IO_GENERAL;
701                 }
702             }
703         }
704     }
705 
706 #endif
707     if( !pStrm )
708     {
709 #ifdef _OLD_FILE_IMPL
710         pStrm = new SvFileStream( aNameStr, nStrmMode );
711 #else
712         pStrm = new OslStream( aNameStr, nStrmMode );
713 #endif
714     }
715     if( IsAppend() )
716         pStrm->Seek( STREAM_SEEK_TO_END );
717     MapError();
718     if( nError )
719         delete pStrm, pStrm = NULL;
720     return nError;
721 }
722 
723 SbError SbiStream::Close()
724 {
725     if( pStrm )
726     {
727         if( !hasUno() )
728         {
729 #ifdef _OLD_FILE_IMPL
730             ((SvFileStream *)pStrm)->Close();
731 #endif
732         }
733         MapError();
734         delete pStrm;
735         pStrm = NULL;
736     }
737     nChan = 0;
738     return nError;
739 }
740 
741 SbError SbiStream::Read( ByteString& rBuf, sal_uInt16 n, bool bForceReadingPerByte )
742 {
743     nExpandOnWriteTo = 0;
744     if( !bForceReadingPerByte && IsText() )
745     {
746         pStrm->ReadLine( rBuf );
747         nLine++;
748     }
749     else
750     {
751         if( !n ) n = nLen;
752         if( !n )
753             return nError = SbERR_BAD_RECORD_LENGTH;
754         rBuf.Fill( n, ' ' );
755         pStrm->Read( (void*)rBuf.GetBuffer(), n );
756     }
757     MapError();
758     if( !nError && pStrm->IsEof() )
759         nError = SbERR_READ_PAST_EOF;
760     return nError;
761 }
762 
763 SbError SbiStream::Read( char& ch )
764 {
765     nExpandOnWriteTo = 0;
766     if( !aLine.Len() )
767     {
768         Read( aLine, 0 );
769         aLine += '\n';
770     }
771     ch = aLine.GetBuffer()[0];
772     aLine.Erase( 0, 1 );
773     return nError;
774 }
775 
776 void SbiStream::ExpandFile()
777 {
778     if ( nExpandOnWriteTo )
779     {
780         sal_uIntPtr nCur = pStrm->Seek(STREAM_SEEK_TO_END);
781         if( nCur < nExpandOnWriteTo )
782         {
783             sal_uIntPtr nDiff = nExpandOnWriteTo - nCur;
784             char c = 0;
785             while( nDiff-- )
786                 *pStrm << c;
787         }
788         else
789         {
790             pStrm->Seek( nExpandOnWriteTo );
791         }
792         nExpandOnWriteTo = 0;
793     }
794 }
795 
796 SbError SbiStream::Write( const ByteString& rBuf, sal_uInt16 n )
797 {
798     ExpandFile();
799     if( IsAppend() )
800         pStrm->Seek( STREAM_SEEK_TO_END );
801 
802     if( IsText() )
803     {
804         aLine += rBuf;
805         // Raus damit, wenn das Ende ein LF ist, aber CRLF vorher
806         // strippen, da der SvStrm ein CRLF anfuegt!
807         sal_uInt16 nLineLen = aLine.Len();
808         if( nLineLen && aLine.GetBuffer()[ --nLineLen ] == 0x0A )
809         {
810             aLine.Erase( nLineLen );
811             if( nLineLen && aLine.GetBuffer()[ --nLineLen ] == 0x0D )
812                 aLine.Erase( nLineLen );
813             pStrm->WriteLines( aLine );
814             aLine.Erase();
815         }
816     }
817     else
818     {
819         if( !n ) n = nLen;
820         if( !n )
821             return nError = SbERR_BAD_RECORD_LENGTH;
822         pStrm->Write( rBuf.GetBuffer(), n );
823         MapError();
824     }
825     return nError;
826 }
827 
828 //////////////////////////////////////////////////////////////////////////
829 
830 // Zugriff auf das aktuelle I/O-System:
831 
832 SbiIoSystem* SbGetIoSystem()
833 {
834     SbiInstance* pInst = pINST;
835     return pInst ? pInst->GetIoSystem() : NULL;
836 }
837 
838 //////////////////////////////////////////////////////////////////////////
839 
840 SbiIoSystem::SbiIoSystem()
841 {
842     for( short i = 0; i < CHANNELS; i++ )
843         pChan[ i ] = NULL;
844     nChan  = 0;
845     nError = 0;
846 }
847 
848 SbiIoSystem::~SbiIoSystem()
849 {
850     Shutdown();
851 }
852 
853 SbError SbiIoSystem::GetError()
854 {
855     SbError n = nError; nError = 0;
856     return n;
857 }
858 
859 void SbiIoSystem::Open
860     ( short nCh, const ByteString& rName, short nMode, short nFlags, short nLen )
861 {
862     nError = 0;
863     if( nCh >= CHANNELS || !nCh )
864         nError = SbERR_BAD_CHANNEL;
865     else if( pChan[ nCh ] )
866         nError = SbERR_FILE_ALREADY_OPEN;
867     else
868     {
869         pChan[ nCh ] = new SbiStream;
870         nError = pChan[ nCh ]->Open( nCh, rName, nMode, nFlags, nLen );
871         if( nError )
872             delete pChan[ nCh ], pChan[ nCh ] = NULL;
873     }
874     nChan = 0;
875 }
876 
877 // Aktuellen Kanal schliessen
878 
879 void SbiIoSystem::Close()
880 {
881     if( !nChan )
882         nError = SbERR_BAD_CHANNEL;
883     else if( !pChan[ nChan ] )
884         nError = SbERR_BAD_CHANNEL;
885     else
886     {
887         nError = pChan[ nChan ]->Close();
888         delete pChan[ nChan ];
889         pChan[ nChan ] = NULL;
890     }
891     nChan = 0;
892 }
893 
894 // Shutdown nach Programmlauf
895 
896 void SbiIoSystem::Shutdown()
897 {
898     for( short i = 1; i < CHANNELS; i++ )
899     {
900         if( pChan[ i ] )
901         {
902             SbError n = pChan[ i ]->Close();
903             delete pChan[ i ];
904             pChan[ i ] = NULL;
905             if( n && !nError )
906                 nError = n;
907         }
908     }
909     nChan = 0;
910     // Noch was zu PRINTen?
911     if( aOut.Len() )
912     {
913         String aOutStr( aOut, gsl_getSystemTextEncoding() );
914 #if defined GCC
915         Window* pParent = Application::GetDefDialogParent();
916         MessBox( pParent, WinBits( WB_OK ), String(), aOutStr ).Execute();
917 #else
918         MessBox( GetpApp()->GetDefDialogParent(), WinBits( WB_OK ), String(), aOutStr ).Execute();
919 #endif
920     }
921     aOut.Erase();
922 }
923 
924 // Aus aktuellem Kanal lesen
925 
926 void SbiIoSystem::Read( ByteString& rBuf, short n )
927 {
928     if( !nChan )
929         ReadCon( rBuf );
930     else if( !pChan[ nChan ] )
931         nError = SbERR_BAD_CHANNEL;
932     else
933         nError = pChan[ nChan ]->Read( rBuf, n );
934 }
935 
936 char SbiIoSystem::Read()
937 {
938     char ch = ' ';
939     if( !nChan )
940     {
941         if( !aIn.Len() )
942         {
943             ReadCon( aIn );
944             aIn += '\n';
945         }
946         ch = aIn.GetBuffer()[0];
947         aIn.Erase( 0, 1 );
948     }
949     else if( !pChan[ nChan ] )
950         nError = SbERR_BAD_CHANNEL;
951     else
952         nError = pChan[ nChan ]->Read( ch );
953     return ch;
954 }
955 
956 void SbiIoSystem::Write( const ByteString& rBuf, short n )
957 {
958     if( !nChan )
959         WriteCon( rBuf );
960     else if( !pChan[ nChan ] )
961         nError = SbERR_BAD_CHANNEL;
962     else
963         nError = pChan[ nChan ]->Write( rBuf, n );
964 }
965 
966 short SbiIoSystem::NextChannel()
967 {
968     for( short i = 1; i < CHANNELS; i++ )
969     {
970         if( !pChan[ i ] )
971             return i;
972     }
973     nError = SbERR_TOO_MANY_FILES;
974     return CHANNELS;
975 }
976 
977 // nChannel == 0..CHANNELS-1
978 
979 SbiStream* SbiIoSystem::GetStream( short nChannel ) const
980 {
981     SbiStream* pRet = 0;
982     if( nChannel >= 0 && nChannel < CHANNELS )
983         pRet = pChan[ nChannel ];
984     return pRet;
985 }
986 
987 void SbiIoSystem::CloseAll(void)
988 {
989     for( short i = 1; i < CHANNELS; i++ )
990     {
991         if( pChan[ i ] )
992         {
993             SbError n = pChan[ i ]->Close();
994             delete pChan[ i ];
995             pChan[ i ] = NULL;
996             if( n && !nError )
997                 nError = n;
998         }
999     }
1000 }
1001 
1002 /***************************************************************************
1003 *
1004 *   Console Support
1005 *
1006 ***************************************************************************/
1007 
1008 // Einlesen einer Zeile von der Console
1009 
1010 void SbiIoSystem::ReadCon( ByteString& rIn )
1011 {
1012     String aPromptStr( aPrompt, gsl_getSystemTextEncoding() );
1013     SbiInputDialog aDlg( NULL, aPromptStr );
1014     if( aDlg.Execute() )
1015         rIn = ByteString( aDlg.GetInput(), gsl_getSystemTextEncoding() );
1016     else
1017         nError = SbERR_USER_ABORT;
1018     aPrompt.Erase();
1019 }
1020 
1021 // Ausgabe einer MessageBox, wenn im Console-Puffer ein CR ist
1022 
1023 void SbiIoSystem::WriteCon( const ByteString& rText )
1024 {
1025     aOut += rText;
1026     sal_uInt16 n1 = aOut.Search( '\n' );
1027     sal_uInt16 n2 = aOut.Search( '\r' );
1028     if( n1 != STRING_NOTFOUND || n2 != STRING_NOTFOUND )
1029     {
1030         if( n1 == STRING_NOTFOUND ) n1 = n2;
1031         else
1032         if( n2 == STRING_NOTFOUND ) n2 = n1;
1033         if( n1 > n2 ) n1 = n2;
1034         ByteString s( aOut.Copy( 0, n1 ) );
1035         aOut.Erase( 0, n1 );
1036         while( aOut.GetBuffer()[0] == '\n' || aOut.GetBuffer()[0] == '\r' )
1037             aOut.Erase( 0, 1 );
1038         String aStr( s, gsl_getSystemTextEncoding() );
1039         {
1040             vos::OGuard aSolarGuard( Application::GetSolarMutex() );
1041             if( !MessBox( GetpApp()->GetDefDialogParent(),
1042                         WinBits( WB_OK_CANCEL | WB_DEF_OK ),
1043                         String(), aStr ).Execute() )
1044                 nError = SbERR_USER_ABORT;
1045         }
1046     }
1047 }
1048 
1049