1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 <vcl/svapp.hxx>
22 #include <vcl/weld.hxx>
23 #include <vcl/window.hxx>
24 #include <osl/file.hxx>
26 #include <runtime.hxx>
28 #include <rtl/strbuf.hxx>
29 #include <sal/log.hxx>
31 #include <comphelper/processfactory.hxx>
32 #include <comphelper/string.hxx>
34 #include <com/sun/star/uno/Sequence.hxx>
35 #include <com/sun/star/ucb/SimpleFileAccess.hpp>
36 #include <com/sun/star/ucb/UniversalContentBroker.hpp>
37 #include <com/sun/star/io/XInputStream.hpp>
38 #include <com/sun/star/io/XOutputStream.hpp>
39 #include <com/sun/star/io/XStream.hpp>
40 #include <com/sun/star/io/XSeekable.hpp>
42 using namespace com::sun::star::uno
;
43 using namespace com::sun::star::lang
;
44 using namespace com::sun::star::ucb
;
45 using namespace com::sun::star::io
;
46 using namespace com::sun::star::bridge
;
52 class SbiInputDialog
: public weld::GenericDialogController
54 std::unique_ptr
<weld::Entry
> m_xInput
;
55 std::unique_ptr
<weld::Button
> m_xOk
;
56 std::unique_ptr
<weld::Button
> m_xCancel
;
57 std::unique_ptr
<weld::Label
> m_xPromptText
;
59 DECL_LINK(Ok
, weld::Button
&, void);
60 DECL_LINK(Cancel
, weld::Button
&, void);
62 SbiInputDialog(weld::Window
*, const OUString
&);
63 const OUString
& GetInput() const { return m_aText
; }
68 SbiInputDialog::SbiInputDialog(weld::Window
* pParent
, const OUString
& rPrompt
)
69 : GenericDialogController(pParent
, "svt/ui/inputbox.ui", "InputBox")
70 , m_xInput(m_xBuilder
->weld_entry("entry"))
71 , m_xOk(m_xBuilder
->weld_button("ok"))
72 , m_xCancel(m_xBuilder
->weld_button("cancel"))
73 , m_xPromptText(m_xBuilder
->weld_label("prompt"))
75 m_xDialog
->set_title(rPrompt
);
76 m_xPromptText
->set_label(rPrompt
);
77 m_xOk
->connect_clicked( LINK( this, SbiInputDialog
, Ok
) );
78 m_xCancel
->connect_clicked( LINK( this, SbiInputDialog
, Cancel
) );
81 IMPL_LINK_NOARG( SbiInputDialog
, Ok
, weld::Button
&, void )
83 m_aText
= m_xInput
->get_text();
84 m_xDialog
->response(RET_OK
);
87 IMPL_LINK_NOARG( SbiInputDialog
, Cancel
, weld::Button
&, void )
89 m_xDialog
->response(RET_CANCEL
);
92 SbiStream::SbiStream()
96 , nMode(SbiStreamFlags::NONE
)
101 SbiStream::~SbiStream()
105 // map an SvStream-error to StarBASIC-code
107 void SbiStream::MapError()
112 ErrCode nEC
= pStrm
->GetError();
113 if (nEC
== ERRCODE_NONE
)
114 nError
= ERRCODE_NONE
;
115 else if (nEC
== SVSTREAM_FILE_NOT_FOUND
)
116 nError
= ERRCODE_BASIC_FILE_NOT_FOUND
;
117 else if (nEC
==SVSTREAM_PATH_NOT_FOUND
)
118 nError
= ERRCODE_BASIC_PATH_NOT_FOUND
;
119 else if (nEC
==SVSTREAM_TOO_MANY_OPEN_FILES
)
120 nError
= ERRCODE_BASIC_TOO_MANY_FILES
;
121 else if (nEC
==SVSTREAM_ACCESS_DENIED
)
122 nError
= ERRCODE_BASIC_ACCESS_DENIED
;
123 else if (nEC
==SVSTREAM_INVALID_PARAMETER
)
124 nError
= ERRCODE_BASIC_BAD_ARGUMENT
;
125 else if (nEC
==SVSTREAM_OUTOFMEMORY
)
126 nError
= ERRCODE_BASIC_NO_MEMORY
;
128 nError
= ERRCODE_BASIC_IO_ERROR
;
131 // Returns sal_True if UNO is available, otherwise the old file
132 // system implementation has to be used
133 // #89378 New semantic: Don't just ask for UNO but for UCB
136 static bool bNeedInit
= true;
137 static bool bRetVal
= true;
142 Reference
< XComponentContext
> xContext
= comphelper::getProcessComponentContext();
145 // No service manager at all
150 Reference
< XUniversalContentBroker
> xManager
= UniversalContentBroker::create(xContext
);
152 if ( !( xManager
->queryContentProvider( "file:///" ).is() ) )
164 class OslStream
: public SvStream
169 OslStream( const OUString
& rName
, StreamMode nStrmMode
);
170 virtual ~OslStream() override
;
171 virtual std::size_t GetData(void* pData
, std::size_t nSize
) override
;
172 virtual std::size_t PutData(const void* pData
, std::size_t nSize
) override
;
173 virtual sal_uInt64
SeekPos( sal_uInt64 nPos
) override
;
174 virtual void FlushData() override
;
175 virtual void SetSize( sal_uInt64 nSize
) override
;
180 OslStream::OslStream( const OUString
& rName
, StreamMode nStrmMode
)
185 if( (nStrmMode
& (StreamMode::READ
| StreamMode::WRITE
)) == (StreamMode::READ
| StreamMode::WRITE
) )
187 nFlags
= osl_File_OpenFlag_Read
| osl_File_OpenFlag_Write
;
189 else if( nStrmMode
& StreamMode::WRITE
)
191 nFlags
= osl_File_OpenFlag_Write
;
193 else //if( nStrmMode & StreamMode::READ )
195 nFlags
= osl_File_OpenFlag_Read
;
198 osl::FileBase::RC nRet
= maFile
.open( nFlags
);
199 if( nRet
== osl::FileBase::E_NOENT
&& nFlags
!= osl_File_OpenFlag_Read
)
201 nFlags
|= osl_File_OpenFlag_Create
;
202 nRet
= maFile
.open( nFlags
);
205 if( nRet
!= osl::FileBase::E_None
)
207 SetError( ERRCODE_IO_GENERAL
);
212 OslStream::~OslStream()
217 std::size_t OslStream::GetData(void* pData
, std::size_t nSize
)
219 sal_uInt64 nBytesRead
= nSize
;
220 maFile
.read( pData
, nBytesRead
, nBytesRead
);
224 std::size_t OslStream::PutData(const void* pData
, std::size_t nSize
)
226 sal_uInt64 nBytesWritten
;
227 maFile
.write( pData
, nSize
, nBytesWritten
);
228 return nBytesWritten
;
231 sal_uInt64
OslStream::SeekPos( sal_uInt64 nPos
)
233 ::osl::FileBase::RC rc
= ::osl::FileBase::E_None
;
234 // check if a truncated STREAM_SEEK_TO_END was passed
235 assert(nPos
!= SAL_MAX_UINT32
);
236 if( nPos
== STREAM_SEEK_TO_END
)
238 rc
= maFile
.setPos( osl_Pos_End
, 0 );
242 rc
= maFile
.setPos( osl_Pos_Absolut
, nPos
);
244 OSL_VERIFY(rc
== ::osl::FileBase::E_None
);
245 sal_uInt64
nRealPos(0);
246 rc
= maFile
.getPos( nRealPos
);
247 OSL_VERIFY(rc
== ::osl::FileBase::E_None
);
251 void OslStream::FlushData()
255 void OslStream::SetSize( sal_uInt64 nSize
)
257 maFile
.setSize( nSize
);
262 class UCBStream
: public SvStream
264 Reference
< XInputStream
> xIS
;
265 Reference
< XStream
> xS
;
266 Reference
< XSeekable
> xSeek
;
268 explicit UCBStream( Reference
< XInputStream
> const & xIS
);
269 explicit UCBStream( Reference
< XStream
> const & xS
);
270 virtual ~UCBStream() override
;
271 virtual std::size_t GetData( void* pData
, std::size_t nSize
) override
;
272 virtual std::size_t PutData( const void* pData
, std::size_t nSize
) override
;
273 virtual sal_uInt64
SeekPos( sal_uInt64 nPos
) override
;
274 virtual void FlushData() override
;
275 virtual void SetSize( sal_uInt64 nSize
) override
;
280 UCBStream::UCBStream( Reference
< XInputStream
> const & rStm
)
282 , xSeek( rStm
, UNO_QUERY
)
286 UCBStream::UCBStream( Reference
< XStream
> const & rStm
)
288 , xSeek( rStm
, UNO_QUERY
)
293 UCBStream::~UCBStream()
303 Reference
< XInputStream
> xIS_
= xS
->getInputStream();
310 catch(const Exception
& )
312 SetError( ERRCODE_IO_GENERAL
);
316 std::size_t UCBStream::GetData(void* pData
, std::size_t nSize
)
320 Reference
< XInputStream
> xISFromS
;
323 Sequence
<sal_Int8
> aData
;
324 nSize
= xIS
->readBytes( aData
, nSize
);
325 memcpy( pData
, aData
.getConstArray(), nSize
);
328 else if( xS
.is() && (xISFromS
= xS
->getInputStream()).is() )
330 Sequence
<sal_Int8
> aData
;
331 nSize
= xISFromS
->readBytes( aData
, nSize
);
332 memcpy(pData
, aData
.getConstArray(), nSize
);
337 SetError( ERRCODE_IO_GENERAL
);
340 catch(const Exception
& )
342 SetError( ERRCODE_IO_GENERAL
);
347 std::size_t UCBStream::PutData(const void* pData
, std::size_t nSize
)
351 Reference
< XOutputStream
> xOSFromS
;
352 if( xS
.is() && (xOSFromS
= xS
->getOutputStream()).is() )
354 Sequence
<sal_Int8
> aData( static_cast<const sal_Int8
*>(pData
), nSize
);
355 xOSFromS
->writeBytes( aData
);
360 SetError( ERRCODE_IO_GENERAL
);
363 catch(const Exception
& )
365 SetError( ERRCODE_IO_GENERAL
);
370 sal_uInt64
UCBStream::SeekPos( sal_uInt64 nPos
)
376 sal_uInt64 nLen
= static_cast<sal_uInt64
>( xSeek
->getLength() );
386 SetError( ERRCODE_IO_GENERAL
);
389 catch(const Exception
& )
391 SetError( ERRCODE_IO_GENERAL
);
396 void UCBStream::FlushData()
400 Reference
< XOutputStream
> xOSFromS
;
401 if( xS
.is() && (xOSFromS
= xS
->getOutputStream()).is() )
407 SetError( ERRCODE_IO_GENERAL
);
410 catch(const Exception
& )
412 SetError( ERRCODE_IO_GENERAL
);
416 void UCBStream::SetSize( sal_uInt64
)
418 SAL_WARN("basic", "UCBStream::SetSize not allowed to call from basic" );
419 SetError( ERRCODE_IO_GENERAL
);
423 ErrCode
const & SbiStream::Open
424 ( const OString
& rName
, StreamMode nStrmMode
, SbiStreamFlags nFlags
, short nL
)
429 nExpandOnWriteTo
= 0;
430 if( ( nStrmMode
& ( StreamMode::READ
|StreamMode::WRITE
) ) == StreamMode::READ
)
432 nStrmMode
|= StreamMode::NOCREATE
;
434 OUString
aStr(OStringToOUString(rName
, osl_getThreadTextEncoding()));
435 OUString aNameStr
= getFullPath( aStr
);
439 Reference
< XSimpleFileAccess3
> xSFI( SimpleFileAccess::create( comphelper::getProcessComponentContext() ) );
443 // #??? For write access delete file if it already exists (not for appending)
444 if( (nStrmMode
& StreamMode::WRITE
) && !IsAppend() && !IsBinary() && !IsRandom() &&
445 xSFI
->exists( aNameStr
) && !xSFI
->isFolder( aNameStr
) )
447 xSFI
->kill( aNameStr
);
450 if( (nStrmMode
& (StreamMode::READ
| StreamMode::WRITE
)) == (StreamMode::READ
| StreamMode::WRITE
) )
452 Reference
< XStream
> xIS
= xSFI
->openFileReadWrite( aNameStr
);
453 pStrm
.reset( new UCBStream( xIS
) );
455 else if( nStrmMode
& StreamMode::WRITE
)
457 Reference
< XStream
> xIS
= xSFI
->openFileReadWrite( aNameStr
);
458 pStrm
.reset( new UCBStream( xIS
) );
460 else //if( nStrmMode & StreamMode::READ )
462 Reference
< XInputStream
> xIS
= xSFI
->openFileRead( aNameStr
);
463 pStrm
.reset( new UCBStream( xIS
) );
467 catch(const Exception
& )
469 nError
= ERRCODE_IO_GENERAL
;
475 pStrm
.reset( new OslStream( aNameStr
, nStrmMode
) );
479 pStrm
->Seek( STREAM_SEEK_TO_END
);
489 ErrCode
const & SbiStream::Close()
499 ErrCode
SbiStream::Read(OString
& rBuf
, sal_uInt16 n
, bool bForceReadingPerByte
)
501 nExpandOnWriteTo
= 0;
502 if( !bForceReadingPerByte
&& IsText() )
504 pStrm
->ReadLine(rBuf
);
515 return nError
= ERRCODE_BASIC_BAD_RECORD_LENGTH
;
517 OStringBuffer
aBuffer(read_uInt8s_ToOString(*pStrm
, n
));
518 //Pad it out with ' ' to the requested length on short read
519 sal_Int32 nRequested
= sal::static_int_cast
<sal_Int32
>(n
);
520 comphelper::string::padToLength(aBuffer
, nRequested
, ' ');
521 rBuf
= aBuffer
.makeStringAndClear();
524 if( !nError
&& pStrm
->eof() )
526 nError
= ERRCODE_BASIC_READ_PAST_EOF
;
531 ErrCode
const & SbiStream::Read( char& ch
)
533 nExpandOnWriteTo
= 0;
537 aLine
+= OString('\n');
540 aLine
= aLine
.copy(1);
544 void SbiStream::ExpandFile()
546 if ( !nExpandOnWriteTo
)
549 sal_uInt64 nCur
= pStrm
->Seek(STREAM_SEEK_TO_END
);
550 if( nCur
< nExpandOnWriteTo
)
552 sal_uInt64 nDiff
= nExpandOnWriteTo
- nCur
;
555 pStrm
->WriteChar( 0 );
560 pStrm
->Seek( nExpandOnWriteTo
);
562 nExpandOnWriteTo
= 0;
567 void WriteLines(SvStream
&rStream
, const OString
& rStr
)
569 OString
aStr(convertLineEnd(rStr
, rStream
.GetLineDelimiter()) );
570 write_uInt8s_FromOString(rStream
, aStr
);
575 ErrCode
SbiStream::Write( const OString
& rBuf
)
580 pStrm
->Seek( STREAM_SEEK_TO_END
);
585 // Get it out, if the end is an LF, but strip CRLF before,
586 // because the SvStream adds a CRLF!
587 sal_Int32 nLineLen
= aLine
.getLength();
588 if (nLineLen
&& aLine
[--nLineLen
] == 0x0A)
590 aLine
= aLine
.copy(0, nLineLen
);
591 if (nLineLen
&& aLine
[--nLineLen
] == 0x0D)
593 aLine
= aLine
.copy(0, nLineLen
);
595 WriteLines(*pStrm
, aLine
);
603 return nError
= ERRCODE_BASIC_BAD_RECORD_LENGTH
;
605 pStrm
->WriteBytes(rBuf
.getStr(), nLen
);
612 SbiIoSystem::SbiIoSystem()
614 for(SbiStream
* & i
: pChan
)
619 nError
= ERRCODE_NONE
;
622 SbiIoSystem::~SbiIoSystem() COVERITY_NOEXCEPT_FALSE
627 ErrCode
SbiIoSystem::GetError()
630 nError
= ERRCODE_NONE
;
634 void SbiIoSystem::Open(short nCh
, const OString
& rName
, StreamMode nMode
, SbiStreamFlags nFlags
, short nLen
)
636 nError
= ERRCODE_NONE
;
637 if( nCh
>= CHANNELS
|| !nCh
)
639 nError
= ERRCODE_BASIC_BAD_CHANNEL
;
641 else if( pChan
[ nCh
] )
643 nError
= ERRCODE_BASIC_FILE_ALREADY_OPEN
;
647 pChan
[ nCh
] = new SbiStream
;
648 nError
= pChan
[ nCh
]->Open( rName
, nMode
, nFlags
, nLen
);
652 pChan
[ nCh
] = nullptr;
659 void SbiIoSystem::Close()
663 nError
= ERRCODE_BASIC_BAD_CHANNEL
;
665 else if( !pChan
[ nChan
] )
667 nError
= ERRCODE_BASIC_BAD_CHANNEL
;
671 nError
= pChan
[ nChan
]->Close();
672 delete pChan
[ nChan
];
673 pChan
[ nChan
] = nullptr;
679 void SbiIoSystem::Shutdown()
681 for( short i
= 1; i
< CHANNELS
; i
++ )
685 ErrCode n
= pChan
[ i
]->Close();
687 pChan
[ i
] = nullptr;
695 // anything left to PRINT?
696 if( !aOut
.isEmpty() )
698 vcl::Window
* pParent
= Application::GetDefDialogParent();
699 std::unique_ptr
<weld::MessageDialog
> xBox(Application::CreateMessageDialog(pParent
? pParent
->GetFrameWeld() : nullptr, VclMessageType::Warning
,
700 VclButtonsType::Ok
, aOut
));
707 void SbiIoSystem::Read(OString
& rBuf
)
713 else if( !pChan
[ nChan
] )
715 nError
= ERRCODE_BASIC_BAD_CHANNEL
;
719 nError
= pChan
[ nChan
]->Read( rBuf
);
723 char SbiIoSystem::Read()
731 aIn
+= OString('\n');
736 else if( !pChan
[ nChan
] )
738 nError
= ERRCODE_BASIC_BAD_CHANNEL
;
742 nError
= pChan
[ nChan
]->Read( ch
);
747 void SbiIoSystem::Write(const OUString
& rBuf
)
753 else if( !pChan
[ nChan
] )
755 nError
= ERRCODE_BASIC_BAD_CHANNEL
;
759 nError
= pChan
[ nChan
]->Write( OUStringToOString(rBuf
, osl_getThreadTextEncoding()) );
763 // nChannel == 0..CHANNELS-1
765 SbiStream
* SbiIoSystem::GetStream( short nChannel
) const
767 SbiStream
* pRet
= nullptr;
768 if( nChannel
>= 0 && nChannel
< CHANNELS
)
770 pRet
= pChan
[ nChannel
];
775 void SbiIoSystem::CloseAll()
777 for( short i
= 1; i
< CHANNELS
; i
++ )
781 ErrCode n
= pChan
[ i
]->Close();
783 pChan
[ i
] = nullptr;
792 void SbiIoSystem::ReadCon(OString
& rIn
)
794 OUString
aPromptStr(OStringToOUString(aPrompt
, osl_getThreadTextEncoding()));
795 SbiInputDialog
aDlg(nullptr, aPromptStr
);
796 if (aDlg
.run() == RET_OK
)
798 rIn
= OUStringToOString(aDlg
.GetInput(), osl_getThreadTextEncoding());
802 nError
= ERRCODE_BASIC_USER_ABORT
;
807 // output of a MessageBox, if there's a CR in the console-buffer
809 void SbiIoSystem::WriteCon(const OUString
& rText
)
812 sal_Int32 n1
= aOut
.indexOf('\n');
813 sal_Int32 n2
= aOut
.indexOf('\r');
814 if( n1
== -1 && n2
== -1 )
829 OUString
s(aOut
.copy(0, n1
));
830 aOut
= aOut
.copy(n1
);
831 while ( !aOut
.isEmpty() && (aOut
[0] == '\n' || aOut
[0] == '\r') )
836 SolarMutexGuard aSolarGuard
;
838 vcl::Window
* pParent
= Application::GetDefDialogParent();
839 std::unique_ptr
<weld::MessageDialog
> xBox(Application::CreateMessageDialog(pParent
? pParent
->GetFrameWeld() : nullptr, VclMessageType::Warning
,
840 VclButtonsType::OkCancel
, s
));
841 xBox
->set_default_response(RET_OK
);
844 nError
= ERRCODE_BASIC_USER_ABORT
;
849 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */