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 <osl/diagnose.h>
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>
43 using namespace com::sun::star::uno
;
44 using namespace com::sun::star::ucb
;
45 using namespace com::sun::star::io
;
50 class SbiInputDialog
: public weld::GenericDialogController
52 std::unique_ptr
<weld::Entry
> m_xInput
;
53 std::unique_ptr
<weld::Button
> m_xOk
;
54 std::unique_ptr
<weld::Button
> m_xCancel
;
55 std::unique_ptr
<weld::Label
> m_xPromptText
;
57 DECL_LINK(Ok
, weld::Button
&, void);
58 DECL_LINK(Cancel
, weld::Button
&, void);
60 SbiInputDialog(weld::Window
*, const OUString
&);
61 const OUString
& GetInput() const { return m_aText
; }
66 SbiInputDialog::SbiInputDialog(weld::Window
* pParent
, const OUString
& rPrompt
)
67 : GenericDialogController(pParent
, u
"svt/ui/inputbox.ui"_ustr
, u
"InputBox"_ustr
)
68 , m_xInput(m_xBuilder
->weld_entry(u
"entry"_ustr
))
69 , m_xOk(m_xBuilder
->weld_button(u
"ok"_ustr
))
70 , m_xCancel(m_xBuilder
->weld_button(u
"cancel"_ustr
))
71 , m_xPromptText(m_xBuilder
->weld_label(u
"prompt"_ustr
))
73 m_xDialog
->set_title(rPrompt
);
74 m_xPromptText
->set_label(rPrompt
);
75 m_xOk
->connect_clicked( LINK( this, SbiInputDialog
, Ok
) );
76 m_xCancel
->connect_clicked( LINK( this, SbiInputDialog
, Cancel
) );
79 IMPL_LINK_NOARG( SbiInputDialog
, Ok
, weld::Button
&, void )
81 m_aText
= m_xInput
->get_text();
82 m_xDialog
->response(RET_OK
);
85 IMPL_LINK_NOARG( SbiInputDialog
, Cancel
, weld::Button
&, void )
87 m_xDialog
->response(RET_CANCEL
);
90 SbiStream::SbiStream()
94 , nMode(SbiStreamFlags::NONE
)
99 SbiStream::~SbiStream()
103 // map an SvStream-error to StarBASIC-code
105 void SbiStream::MapError()
110 ErrCode nEC
= pStrm
->GetError();
111 if (nEC
== ERRCODE_NONE
)
112 nError
= ERRCODE_NONE
;
113 else if (nEC
== SVSTREAM_FILE_NOT_FOUND
)
114 nError
= ERRCODE_BASIC_FILE_NOT_FOUND
;
115 else if (nEC
==SVSTREAM_PATH_NOT_FOUND
)
116 nError
= ERRCODE_BASIC_PATH_NOT_FOUND
;
117 else if (nEC
==SVSTREAM_TOO_MANY_OPEN_FILES
)
118 nError
= ERRCODE_BASIC_TOO_MANY_FILES
;
119 else if (nEC
==SVSTREAM_ACCESS_DENIED
)
120 nError
= ERRCODE_BASIC_ACCESS_DENIED
;
121 else if (nEC
==SVSTREAM_INVALID_PARAMETER
)
122 nError
= ERRCODE_BASIC_BAD_ARGUMENT
;
123 else if (nEC
==SVSTREAM_OUTOFMEMORY
)
124 nError
= ERRCODE_BASIC_NO_MEMORY
;
126 nError
= ERRCODE_BASIC_IO_ERROR
;
129 // Returns sal_True if UNO is available, otherwise the old file
130 // system implementation has to be used
131 // #89378 New semantic: Don't just ask for UNO but for UCB
134 static const bool bRetVal
= [] {
135 const Reference
< XComponentContext
>& xContext
= comphelper::getProcessComponentContext();
138 // No service manager at all
143 Reference
< XUniversalContentBroker
> xManager
= UniversalContentBroker::create(xContext
);
145 if ( !( xManager
->queryContentProvider( u
"file:///"_ustr
).is() ) )
158 class OslStream
: public SvStream
163 OslStream( const OUString
& rName
, StreamMode nStrmMode
);
164 virtual ~OslStream() override
;
165 virtual std::size_t GetData(void* pData
, std::size_t nSize
) override
;
166 virtual std::size_t PutData(const void* pData
, std::size_t nSize
) override
;
167 virtual sal_uInt64
SeekPos( sal_uInt64 nPos
) override
;
168 virtual void FlushData() override
;
169 virtual void SetSize( sal_uInt64 nSize
) override
;
174 OslStream::OslStream( const OUString
& rName
, StreamMode nStrmMode
)
179 if( (nStrmMode
& (StreamMode::READ
| StreamMode::WRITE
)) == (StreamMode::READ
| StreamMode::WRITE
) )
181 nFlags
= osl_File_OpenFlag_Read
| osl_File_OpenFlag_Write
;
183 else if( nStrmMode
& StreamMode::WRITE
)
185 nFlags
= osl_File_OpenFlag_Write
;
187 else //if( nStrmMode & StreamMode::READ )
189 nFlags
= osl_File_OpenFlag_Read
;
192 osl::FileBase::RC nRet
= maFile
.open( nFlags
);
193 if( nRet
== osl::FileBase::E_NOENT
&& nFlags
!= osl_File_OpenFlag_Read
)
195 nFlags
|= osl_File_OpenFlag_Create
;
196 nRet
= maFile
.open( nFlags
);
199 if( nRet
!= osl::FileBase::E_None
)
201 SetError( ERRCODE_IO_GENERAL
);
206 OslStream::~OslStream()
211 std::size_t OslStream::GetData(void* pData
, std::size_t nSize
)
213 sal_uInt64 nBytesRead
= nSize
;
214 maFile
.read( pData
, nBytesRead
, nBytesRead
);
218 std::size_t OslStream::PutData(const void* pData
, std::size_t nSize
)
220 sal_uInt64 nBytesWritten
;
221 maFile
.write( pData
, nSize
, nBytesWritten
);
222 return nBytesWritten
;
225 sal_uInt64
OslStream::SeekPos( sal_uInt64 nPos
)
227 ::osl::FileBase::RC rc
= ::osl::FileBase::E_None
;
228 // check if a truncated STREAM_SEEK_TO_END was passed
229 assert(nPos
!= SAL_MAX_UINT32
);
230 if( nPos
== STREAM_SEEK_TO_END
)
232 rc
= maFile
.setPos( osl_Pos_End
, 0 );
236 rc
= maFile
.setPos( osl_Pos_Absolut
, nPos
);
238 OSL_VERIFY(rc
== ::osl::FileBase::E_None
);
239 sal_uInt64
nRealPos(0);
240 rc
= maFile
.getPos( nRealPos
);
241 OSL_VERIFY(rc
== ::osl::FileBase::E_None
);
245 void OslStream::FlushData()
249 void OslStream::SetSize( sal_uInt64 nSize
)
251 maFile
.setSize( nSize
);
256 class UCBStream
: public SvStream
258 Reference
< XInputStream
> xIS
;
259 Reference
< XStream
> xS
;
260 Reference
< XSeekable
> xSeek
;
262 explicit UCBStream( Reference
< XInputStream
> const & xIS
);
263 explicit UCBStream( Reference
< XStream
> const & xS
);
264 virtual ~UCBStream() override
;
265 virtual std::size_t GetData( void* pData
, std::size_t nSize
) override
;
266 virtual std::size_t PutData( const void* pData
, std::size_t nSize
) override
;
267 virtual sal_uInt64
SeekPos( sal_uInt64 nPos
) override
;
268 virtual void FlushData() override
;
269 virtual void SetSize( sal_uInt64 nSize
) override
;
274 UCBStream::UCBStream( Reference
< XInputStream
> const & rStm
)
276 , xSeek( rStm
, UNO_QUERY
)
280 UCBStream::UCBStream( Reference
< XStream
> const & rStm
)
282 , xSeek( rStm
, UNO_QUERY
)
287 UCBStream::~UCBStream()
297 Reference
< XInputStream
> xIS_
= xS
->getInputStream();
304 catch(const Exception
& )
306 SetError( ERRCODE_IO_GENERAL
);
310 std::size_t UCBStream::GetData(void* pData
, std::size_t nSize
)
314 Reference
< XInputStream
> xISFromS
;
317 Sequence
<sal_Int8
> aData
;
318 nSize
= xIS
->readBytes( aData
, nSize
);
319 memcpy( pData
, aData
.getConstArray(), nSize
);
322 else if( xS
.is() && (xISFromS
= xS
->getInputStream()).is() )
324 Sequence
<sal_Int8
> aData
;
325 nSize
= xISFromS
->readBytes( aData
, nSize
);
326 memcpy(pData
, aData
.getConstArray(), nSize
);
331 SetError( ERRCODE_IO_GENERAL
);
334 catch(const Exception
& )
336 SetError( ERRCODE_IO_GENERAL
);
341 std::size_t UCBStream::PutData(const void* pData
, std::size_t nSize
)
345 Reference
< XOutputStream
> xOSFromS
;
346 if( xS
.is() && (xOSFromS
= xS
->getOutputStream()).is() )
348 Sequence
<sal_Int8
> aData( static_cast<const sal_Int8
*>(pData
), nSize
);
349 xOSFromS
->writeBytes( aData
);
354 SetError( ERRCODE_IO_GENERAL
);
357 catch(const Exception
& )
359 SetError( ERRCODE_IO_GENERAL
);
364 sal_uInt64
UCBStream::SeekPos( sal_uInt64 nPos
)
370 sal_uInt64 nLen
= static_cast<sal_uInt64
>( xSeek
->getLength() );
380 SetError( ERRCODE_IO_GENERAL
);
383 catch(const Exception
& )
385 SetError( ERRCODE_IO_GENERAL
);
390 void UCBStream::FlushData()
394 Reference
< XOutputStream
> xOSFromS
;
395 if( xS
.is() && (xOSFromS
= xS
->getOutputStream()).is() )
401 SetError( ERRCODE_IO_GENERAL
);
404 catch(const Exception
& )
406 SetError( ERRCODE_IO_GENERAL
);
410 void UCBStream::SetSize( sal_uInt64
)
412 SAL_WARN("basic", "UCBStream::SetSize not allowed to call from basic" );
413 SetError( ERRCODE_IO_GENERAL
);
417 ErrCode
const & SbiStream::Open
418 ( std::string_view rName
, StreamMode nStrmMode
, SbiStreamFlags nFlags
, short nL
)
423 nExpandOnWriteTo
= 0;
424 if( ( nStrmMode
& ( StreamMode::READ
|StreamMode::WRITE
) ) == StreamMode::READ
)
426 nStrmMode
|= StreamMode::NOCREATE
;
428 OUString
aStr(OStringToOUString(rName
, osl_getThreadTextEncoding()));
429 OUString aNameStr
= getFullPath( aStr
);
433 Reference
< XSimpleFileAccess3
> xSFI( SimpleFileAccess::create( comphelper::getProcessComponentContext() ) );
437 // #??? For write access delete file if it already exists (not for appending)
438 if( (nStrmMode
& StreamMode::WRITE
) && !IsAppend() && !IsBinary() && !IsRandom() &&
439 xSFI
->exists( aNameStr
) && !xSFI
->isFolder( aNameStr
) )
441 xSFI
->kill( aNameStr
);
444 if( (nStrmMode
& (StreamMode::READ
| StreamMode::WRITE
)) == (StreamMode::READ
| StreamMode::WRITE
) )
446 Reference
< XStream
> xIS
= xSFI
->openFileReadWrite( aNameStr
);
447 pStrm
.reset( new UCBStream( xIS
) );
449 else if( nStrmMode
& StreamMode::WRITE
)
451 Reference
< XStream
> xIS
= xSFI
->openFileReadWrite( aNameStr
);
452 pStrm
.reset( new UCBStream( xIS
) );
454 else //if( nStrmMode & StreamMode::READ )
456 Reference
< XInputStream
> xIS
= xSFI
->openFileRead( aNameStr
);
457 pStrm
.reset( new UCBStream( xIS
) );
461 catch(const Exception
& )
463 nError
= ERRCODE_IO_GENERAL
;
469 pStrm
.reset( new OslStream( aNameStr
, nStrmMode
) );
473 pStrm
->Seek( STREAM_SEEK_TO_END
);
483 ErrCode
const & SbiStream::Close()
493 ErrCode
SbiStream::Read(OString
& rBuf
, sal_uInt16 n
, bool bForceReadingPerByte
)
495 nExpandOnWriteTo
= 0;
496 if( !bForceReadingPerByte
&& IsText() )
498 pStrm
->ReadLine(rBuf
);
509 return nError
= ERRCODE_BASIC_BAD_RECORD_LENGTH
;
511 OStringBuffer
aBuffer(read_uInt8s_ToOString(*pStrm
, n
));
512 //Pad it out with ' ' to the requested length on short read
513 sal_Int32 nRequested
= sal::static_int_cast
<sal_Int32
>(n
);
514 comphelper::string::padToLength(aBuffer
, nRequested
, ' ');
515 rBuf
= aBuffer
.makeStringAndClear();
518 if( !nError
&& pStrm
->eof() )
520 nError
= ERRCODE_BASIC_READ_PAST_EOF
;
525 ErrCode
const & SbiStream::Read( char& ch
)
527 nExpandOnWriteTo
= 0;
534 aLine
= aLine
.copy(1);
538 void SbiStream::ExpandFile()
540 if ( !nExpandOnWriteTo
)
543 sal_uInt64 nCur
= pStrm
->Seek(STREAM_SEEK_TO_END
);
544 if( nCur
< nExpandOnWriteTo
)
546 sal_uInt64 nDiff
= nExpandOnWriteTo
- nCur
;
549 pStrm
->WriteChar( 0 );
554 pStrm
->Seek( nExpandOnWriteTo
);
556 nExpandOnWriteTo
= 0;
561 void WriteLines(SvStream
&rStream
, const OString
& rStr
)
563 OString
aStr(convertLineEnd(rStr
, rStream
.GetLineDelimiter()) );
564 rStream
.WriteBytes(aStr
.getStr(), aStr
.getLength());
569 ErrCode
SbiStream::Write( const OString
& rBuf
)
574 pStrm
->Seek( STREAM_SEEK_TO_END
);
579 // Get it out, if the end is an LF, but strip CRLF before,
580 // because the SvStream adds a CRLF!
581 sal_Int32 nLineLen
= aLine
.getLength();
582 if (nLineLen
&& aLine
[--nLineLen
] == 0x0A)
584 aLine
= aLine
.copy(0, nLineLen
);
585 if (nLineLen
&& aLine
[--nLineLen
] == 0x0D)
587 aLine
= aLine
.copy(0, nLineLen
);
589 WriteLines(*pStrm
, aLine
);
597 return nError
= ERRCODE_BASIC_BAD_RECORD_LENGTH
;
599 pStrm
->WriteBytes(rBuf
.getStr(), nLen
);
606 SbiIoSystem::SbiIoSystem()
608 for(SbiStream
* & i
: pChan
)
613 nError
= ERRCODE_NONE
;
616 SbiIoSystem::~SbiIoSystem() COVERITY_NOEXCEPT_FALSE
621 ErrCode
SbiIoSystem::GetError()
624 nError
= ERRCODE_NONE
;
628 void SbiIoSystem::Open(short nCh
, std::string_view rName
, StreamMode nMode
, SbiStreamFlags nFlags
, short nLen
)
630 nError
= ERRCODE_NONE
;
631 if( nCh
>= CHANNELS
|| !nCh
)
633 nError
= ERRCODE_BASIC_BAD_CHANNEL
;
635 else if( pChan
[ nCh
] )
637 nError
= ERRCODE_BASIC_FILE_ALREADY_OPEN
;
641 pChan
[ nCh
] = new SbiStream
;
642 nError
= pChan
[ nCh
]->Open( rName
, nMode
, nFlags
, nLen
);
646 pChan
[ nCh
] = nullptr;
653 void SbiIoSystem::Close()
657 nError
= ERRCODE_BASIC_BAD_CHANNEL
;
659 else if( !pChan
[ nChan
] )
661 nError
= ERRCODE_BASIC_BAD_CHANNEL
;
665 nError
= pChan
[ nChan
]->Close();
666 delete pChan
[ nChan
];
667 pChan
[ nChan
] = nullptr;
673 void SbiIoSystem::Shutdown()
675 for( short i
= 1; i
< CHANNELS
; i
++ )
679 ErrCode n
= pChan
[ i
]->Close();
681 pChan
[ i
] = nullptr;
689 // anything left to PRINT?
690 if( !aOut
.isEmpty() )
692 std::unique_ptr
<weld::MessageDialog
> xBox(Application::CreateMessageDialog(Application::GetDefDialogParent(), VclMessageType::Warning
,
693 VclButtonsType::Ok
, aOut
));
700 void SbiIoSystem::Read(OString
& rBuf
)
706 else if( !pChan
[ nChan
] )
708 nError
= ERRCODE_BASIC_BAD_CHANNEL
;
712 nError
= pChan
[ nChan
]->Read( rBuf
);
716 char SbiIoSystem::Read()
729 else if( !pChan
[ nChan
] )
731 nError
= ERRCODE_BASIC_BAD_CHANNEL
;
735 nError
= pChan
[ nChan
]->Read( ch
);
740 void SbiIoSystem::Write(std::u16string_view rBuf
)
746 else if( !pChan
[ nChan
] )
748 nError
= ERRCODE_BASIC_BAD_CHANNEL
;
752 nError
= pChan
[ nChan
]->Write( OUStringToOString(rBuf
, osl_getThreadTextEncoding()) );
756 // nChannel == 0..CHANNELS-1
758 SbiStream
* SbiIoSystem::GetStream( short nChannel
) const
760 SbiStream
* pRet
= nullptr;
761 if( nChannel
>= 0 && nChannel
< CHANNELS
)
763 pRet
= pChan
[ nChannel
];
768 void SbiIoSystem::CloseAll()
770 for( short i
= 1; i
< CHANNELS
; i
++ )
774 ErrCode n
= pChan
[ i
]->Close();
776 pChan
[ i
] = nullptr;
785 void SbiIoSystem::ReadCon(OString
& rIn
)
787 OUString
aPromptStr(OStringToOUString(aPrompt
, osl_getThreadTextEncoding()));
788 SbiInputDialog
aDlg(nullptr, aPromptStr
);
789 if (aDlg
.run() == RET_OK
)
791 rIn
= OUStringToOString(aDlg
.GetInput(), osl_getThreadTextEncoding());
795 nError
= ERRCODE_BASIC_USER_ABORT
;
800 // output of a MessageBox, if there's a CR in the console-buffer
802 void SbiIoSystem::WriteCon(std::u16string_view rText
)
805 sal_Int32 n1
= aOut
.indexOf('\n');
806 sal_Int32 n2
= aOut
.indexOf('\r');
807 if( n1
== -1 && n2
== -1 )
822 OUString
s(aOut
.copy(0, n1
));
823 aOut
= aOut
.copy(n1
);
824 while ( !aOut
.isEmpty() && (aOut
[0] == '\n' || aOut
[0] == '\r') )
829 SolarMutexGuard aSolarGuard
;
831 std::unique_ptr
<weld::MessageDialog
> xBox(Application::CreateMessageDialog(Application::GetDefDialogParent(), VclMessageType::Warning
,
832 VclButtonsType::OkCancel
, s
));
833 xBox
->set_default_response(RET_OK
);
836 nError
= ERRCODE_BASIC_USER_ABORT
;
841 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */