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 const bool bRetVal
= [] {
137 Reference
< XComponentContext
> xContext
= comphelper::getProcessComponentContext();
140 // No service manager at all
145 Reference
< XUniversalContentBroker
> xManager
= UniversalContentBroker::create(xContext
);
147 if ( !( xManager
->queryContentProvider( "file:///" ).is() ) )
160 class OslStream
: public SvStream
165 OslStream( const OUString
& rName
, StreamMode nStrmMode
);
166 virtual ~OslStream() override
;
167 virtual std::size_t GetData(void* pData
, std::size_t nSize
) override
;
168 virtual std::size_t PutData(const void* pData
, std::size_t nSize
) override
;
169 virtual sal_uInt64
SeekPos( sal_uInt64 nPos
) override
;
170 virtual void FlushData() override
;
171 virtual void SetSize( sal_uInt64 nSize
) override
;
176 OslStream::OslStream( const OUString
& rName
, StreamMode nStrmMode
)
181 if( (nStrmMode
& (StreamMode::READ
| StreamMode::WRITE
)) == (StreamMode::READ
| StreamMode::WRITE
) )
183 nFlags
= osl_File_OpenFlag_Read
| osl_File_OpenFlag_Write
;
185 else if( nStrmMode
& StreamMode::WRITE
)
187 nFlags
= osl_File_OpenFlag_Write
;
189 else //if( nStrmMode & StreamMode::READ )
191 nFlags
= osl_File_OpenFlag_Read
;
194 osl::FileBase::RC nRet
= maFile
.open( nFlags
);
195 if( nRet
== osl::FileBase::E_NOENT
&& nFlags
!= osl_File_OpenFlag_Read
)
197 nFlags
|= osl_File_OpenFlag_Create
;
198 nRet
= maFile
.open( nFlags
);
201 if( nRet
!= osl::FileBase::E_None
)
203 SetError( ERRCODE_IO_GENERAL
);
208 OslStream::~OslStream()
213 std::size_t OslStream::GetData(void* pData
, std::size_t nSize
)
215 sal_uInt64 nBytesRead
= nSize
;
216 maFile
.read( pData
, nBytesRead
, nBytesRead
);
220 std::size_t OslStream::PutData(const void* pData
, std::size_t nSize
)
222 sal_uInt64 nBytesWritten
;
223 maFile
.write( pData
, nSize
, nBytesWritten
);
224 return nBytesWritten
;
227 sal_uInt64
OslStream::SeekPos( sal_uInt64 nPos
)
229 ::osl::FileBase::RC rc
= ::osl::FileBase::E_None
;
230 // check if a truncated STREAM_SEEK_TO_END was passed
231 assert(nPos
!= SAL_MAX_UINT32
);
232 if( nPos
== STREAM_SEEK_TO_END
)
234 rc
= maFile
.setPos( osl_Pos_End
, 0 );
238 rc
= maFile
.setPos( osl_Pos_Absolut
, nPos
);
240 OSL_VERIFY(rc
== ::osl::FileBase::E_None
);
241 sal_uInt64
nRealPos(0);
242 rc
= maFile
.getPos( nRealPos
);
243 OSL_VERIFY(rc
== ::osl::FileBase::E_None
);
247 void OslStream::FlushData()
251 void OslStream::SetSize( sal_uInt64 nSize
)
253 maFile
.setSize( nSize
);
258 class UCBStream
: public SvStream
260 Reference
< XInputStream
> xIS
;
261 Reference
< XStream
> xS
;
262 Reference
< XSeekable
> xSeek
;
264 explicit UCBStream( Reference
< XInputStream
> const & xIS
);
265 explicit UCBStream( Reference
< XStream
> const & xS
);
266 virtual ~UCBStream() override
;
267 virtual std::size_t GetData( void* pData
, std::size_t nSize
) override
;
268 virtual std::size_t PutData( const void* pData
, std::size_t nSize
) override
;
269 virtual sal_uInt64
SeekPos( sal_uInt64 nPos
) override
;
270 virtual void FlushData() override
;
271 virtual void SetSize( sal_uInt64 nSize
) override
;
276 UCBStream::UCBStream( Reference
< XInputStream
> const & rStm
)
278 , xSeek( rStm
, UNO_QUERY
)
282 UCBStream::UCBStream( Reference
< XStream
> const & rStm
)
284 , xSeek( rStm
, UNO_QUERY
)
289 UCBStream::~UCBStream()
299 Reference
< XInputStream
> xIS_
= xS
->getInputStream();
306 catch(const Exception
& )
308 SetError( ERRCODE_IO_GENERAL
);
312 std::size_t UCBStream::GetData(void* pData
, std::size_t nSize
)
316 Reference
< XInputStream
> xISFromS
;
319 Sequence
<sal_Int8
> aData
;
320 nSize
= xIS
->readBytes( aData
, nSize
);
321 memcpy( pData
, aData
.getConstArray(), nSize
);
324 else if( xS
.is() && (xISFromS
= xS
->getInputStream()).is() )
326 Sequence
<sal_Int8
> aData
;
327 nSize
= xISFromS
->readBytes( aData
, nSize
);
328 memcpy(pData
, aData
.getConstArray(), nSize
);
333 SetError( ERRCODE_IO_GENERAL
);
336 catch(const Exception
& )
338 SetError( ERRCODE_IO_GENERAL
);
343 std::size_t UCBStream::PutData(const void* pData
, std::size_t nSize
)
347 Reference
< XOutputStream
> xOSFromS
;
348 if( xS
.is() && (xOSFromS
= xS
->getOutputStream()).is() )
350 Sequence
<sal_Int8
> aData( static_cast<const sal_Int8
*>(pData
), nSize
);
351 xOSFromS
->writeBytes( aData
);
356 SetError( ERRCODE_IO_GENERAL
);
359 catch(const Exception
& )
361 SetError( ERRCODE_IO_GENERAL
);
366 sal_uInt64
UCBStream::SeekPos( sal_uInt64 nPos
)
372 sal_uInt64 nLen
= static_cast<sal_uInt64
>( xSeek
->getLength() );
382 SetError( ERRCODE_IO_GENERAL
);
385 catch(const Exception
& )
387 SetError( ERRCODE_IO_GENERAL
);
392 void UCBStream::FlushData()
396 Reference
< XOutputStream
> xOSFromS
;
397 if( xS
.is() && (xOSFromS
= xS
->getOutputStream()).is() )
403 SetError( ERRCODE_IO_GENERAL
);
406 catch(const Exception
& )
408 SetError( ERRCODE_IO_GENERAL
);
412 void UCBStream::SetSize( sal_uInt64
)
414 SAL_WARN("basic", "UCBStream::SetSize not allowed to call from basic" );
415 SetError( ERRCODE_IO_GENERAL
);
419 ErrCode
const & SbiStream::Open
420 ( std::string_view rName
, StreamMode nStrmMode
, SbiStreamFlags nFlags
, short nL
)
425 nExpandOnWriteTo
= 0;
426 if( ( nStrmMode
& ( StreamMode::READ
|StreamMode::WRITE
) ) == StreamMode::READ
)
428 nStrmMode
|= StreamMode::NOCREATE
;
430 OUString
aStr(OStringToOUString(rName
, osl_getThreadTextEncoding()));
431 OUString aNameStr
= getFullPath( aStr
);
435 Reference
< XSimpleFileAccess3
> xSFI( SimpleFileAccess::create( comphelper::getProcessComponentContext() ) );
439 // #??? For write access delete file if it already exists (not for appending)
440 if( (nStrmMode
& StreamMode::WRITE
) && !IsAppend() && !IsBinary() && !IsRandom() &&
441 xSFI
->exists( aNameStr
) && !xSFI
->isFolder( aNameStr
) )
443 xSFI
->kill( aNameStr
);
446 if( (nStrmMode
& (StreamMode::READ
| StreamMode::WRITE
)) == (StreamMode::READ
| StreamMode::WRITE
) )
448 Reference
< XStream
> xIS
= xSFI
->openFileReadWrite( aNameStr
);
449 pStrm
.reset( new UCBStream( xIS
) );
451 else if( nStrmMode
& StreamMode::WRITE
)
453 Reference
< XStream
> xIS
= xSFI
->openFileReadWrite( aNameStr
);
454 pStrm
.reset( new UCBStream( xIS
) );
456 else //if( nStrmMode & StreamMode::READ )
458 Reference
< XInputStream
> xIS
= xSFI
->openFileRead( aNameStr
);
459 pStrm
.reset( new UCBStream( xIS
) );
463 catch(const Exception
& )
465 nError
= ERRCODE_IO_GENERAL
;
471 pStrm
.reset( new OslStream( aNameStr
, nStrmMode
) );
475 pStrm
->Seek( STREAM_SEEK_TO_END
);
485 ErrCode
const & SbiStream::Close()
495 ErrCode
SbiStream::Read(OString
& rBuf
, sal_uInt16 n
, bool bForceReadingPerByte
)
497 nExpandOnWriteTo
= 0;
498 if( !bForceReadingPerByte
&& IsText() )
500 pStrm
->ReadLine(rBuf
);
511 return nError
= ERRCODE_BASIC_BAD_RECORD_LENGTH
;
513 OStringBuffer
aBuffer(read_uInt8s_ToOString(*pStrm
, n
));
514 //Pad it out with ' ' to the requested length on short read
515 sal_Int32 nRequested
= sal::static_int_cast
<sal_Int32
>(n
);
516 comphelper::string::padToLength(aBuffer
, nRequested
, ' ');
517 rBuf
= aBuffer
.makeStringAndClear();
520 if( !nError
&& pStrm
->eof() )
522 nError
= ERRCODE_BASIC_READ_PAST_EOF
;
527 ErrCode
const & SbiStream::Read( char& ch
)
529 nExpandOnWriteTo
= 0;
536 aLine
= aLine
.copy(1);
540 void SbiStream::ExpandFile()
542 if ( !nExpandOnWriteTo
)
545 sal_uInt64 nCur
= pStrm
->Seek(STREAM_SEEK_TO_END
);
546 if( nCur
< nExpandOnWriteTo
)
548 sal_uInt64 nDiff
= nExpandOnWriteTo
- nCur
;
551 pStrm
->WriteChar( 0 );
556 pStrm
->Seek( nExpandOnWriteTo
);
558 nExpandOnWriteTo
= 0;
563 void WriteLines(SvStream
&rStream
, const OString
& rStr
)
565 OString
aStr(convertLineEnd(rStr
, rStream
.GetLineDelimiter()) );
566 write_uInt8s_FromOString(rStream
, aStr
);
571 ErrCode
SbiStream::Write( const OString
& rBuf
)
576 pStrm
->Seek( STREAM_SEEK_TO_END
);
581 // Get it out, if the end is an LF, but strip CRLF before,
582 // because the SvStream adds a CRLF!
583 sal_Int32 nLineLen
= aLine
.getLength();
584 if (nLineLen
&& aLine
[--nLineLen
] == 0x0A)
586 aLine
= aLine
.copy(0, nLineLen
);
587 if (nLineLen
&& aLine
[--nLineLen
] == 0x0D)
589 aLine
= aLine
.copy(0, nLineLen
);
591 WriteLines(*pStrm
, aLine
);
599 return nError
= ERRCODE_BASIC_BAD_RECORD_LENGTH
;
601 pStrm
->WriteBytes(rBuf
.getStr(), nLen
);
608 SbiIoSystem::SbiIoSystem()
610 for(SbiStream
* & i
: pChan
)
615 nError
= ERRCODE_NONE
;
618 SbiIoSystem::~SbiIoSystem() COVERITY_NOEXCEPT_FALSE
623 ErrCode
SbiIoSystem::GetError()
626 nError
= ERRCODE_NONE
;
630 void SbiIoSystem::Open(short nCh
, std::string_view rName
, StreamMode nMode
, SbiStreamFlags nFlags
, short nLen
)
632 nError
= ERRCODE_NONE
;
633 if( nCh
>= CHANNELS
|| !nCh
)
635 nError
= ERRCODE_BASIC_BAD_CHANNEL
;
637 else if( pChan
[ nCh
] )
639 nError
= ERRCODE_BASIC_FILE_ALREADY_OPEN
;
643 pChan
[ nCh
] = new SbiStream
;
644 nError
= pChan
[ nCh
]->Open( rName
, nMode
, nFlags
, nLen
);
648 pChan
[ nCh
] = nullptr;
655 void SbiIoSystem::Close()
659 nError
= ERRCODE_BASIC_BAD_CHANNEL
;
661 else if( !pChan
[ nChan
] )
663 nError
= ERRCODE_BASIC_BAD_CHANNEL
;
667 nError
= pChan
[ nChan
]->Close();
668 delete pChan
[ nChan
];
669 pChan
[ nChan
] = nullptr;
675 void SbiIoSystem::Shutdown()
677 for( short i
= 1; i
< CHANNELS
; i
++ )
681 ErrCode n
= pChan
[ i
]->Close();
683 pChan
[ i
] = nullptr;
691 // anything left to PRINT?
692 if( !aOut
.isEmpty() )
694 std::unique_ptr
<weld::MessageDialog
> xBox(Application::CreateMessageDialog(Application::GetDefDialogParent(), VclMessageType::Warning
,
695 VclButtonsType::Ok
, aOut
));
702 void SbiIoSystem::Read(OString
& rBuf
)
708 else if( !pChan
[ nChan
] )
710 nError
= ERRCODE_BASIC_BAD_CHANNEL
;
714 nError
= pChan
[ nChan
]->Read( rBuf
);
718 char SbiIoSystem::Read()
731 else if( !pChan
[ nChan
] )
733 nError
= ERRCODE_BASIC_BAD_CHANNEL
;
737 nError
= pChan
[ nChan
]->Read( ch
);
742 void SbiIoSystem::Write(std::u16string_view rBuf
)
748 else if( !pChan
[ nChan
] )
750 nError
= ERRCODE_BASIC_BAD_CHANNEL
;
754 nError
= pChan
[ nChan
]->Write( OUStringToOString(rBuf
, osl_getThreadTextEncoding()) );
758 // nChannel == 0..CHANNELS-1
760 SbiStream
* SbiIoSystem::GetStream( short nChannel
) const
762 SbiStream
* pRet
= nullptr;
763 if( nChannel
>= 0 && nChannel
< CHANNELS
)
765 pRet
= pChan
[ nChannel
];
770 void SbiIoSystem::CloseAll()
772 for( short i
= 1; i
< CHANNELS
; i
++ )
776 ErrCode n
= pChan
[ i
]->Close();
778 pChan
[ i
] = nullptr;
787 void SbiIoSystem::ReadCon(OString
& rIn
)
789 OUString
aPromptStr(OStringToOUString(aPrompt
, osl_getThreadTextEncoding()));
790 SbiInputDialog
aDlg(nullptr, aPromptStr
);
791 if (aDlg
.run() == RET_OK
)
793 rIn
= OUStringToOString(aDlg
.GetInput(), osl_getThreadTextEncoding());
797 nError
= ERRCODE_BASIC_USER_ABORT
;
802 // output of a MessageBox, if there's a CR in the console-buffer
804 void SbiIoSystem::WriteCon(std::u16string_view rText
)
807 sal_Int32 n1
= aOut
.indexOf('\n');
808 sal_Int32 n2
= aOut
.indexOf('\r');
809 if( n1
== -1 && n2
== -1 )
824 OUString
s(aOut
.copy(0, n1
));
825 aOut
= aOut
.copy(n1
);
826 while ( !aOut
.isEmpty() && (aOut
[0] == '\n' || aOut
[0] == '\r') )
831 SolarMutexGuard aSolarGuard
;
833 std::unique_ptr
<weld::MessageDialog
> xBox(Application::CreateMessageDialog(Application::GetDefDialogParent(), VclMessageType::Warning
,
834 VclButtonsType::OkCancel
, s
));
835 xBox
->set_default_response(RET_OK
);
838 nError
= ERRCODE_BASIC_USER_ABORT
;
843 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */