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
;
51 class SbiInputDialog
: public weld::GenericDialogController
53 std::unique_ptr
<weld::Entry
> m_xInput
;
54 std::unique_ptr
<weld::Button
> m_xOk
;
55 std::unique_ptr
<weld::Button
> m_xCancel
;
56 std::unique_ptr
<weld::Label
> m_xPromptText
;
58 DECL_LINK(Ok
, weld::Button
&, void);
59 DECL_LINK(Cancel
, weld::Button
&, void);
61 SbiInputDialog(weld::Window
*, const OUString
&);
62 const OUString
& GetInput() const { return m_aText
; }
65 SbiInputDialog::SbiInputDialog(weld::Window
* pParent
, const OUString
& rPrompt
)
66 : GenericDialogController(pParent
, "svt/ui/inputbox.ui", "InputBox")
67 , m_xInput(m_xBuilder
->weld_entry("entry"))
68 , m_xOk(m_xBuilder
->weld_button("ok"))
69 , m_xCancel(m_xBuilder
->weld_button("cancel"))
70 , m_xPromptText(m_xBuilder
->weld_label("prompt"))
72 m_xDialog
->set_title(rPrompt
);
73 m_xPromptText
->set_label(rPrompt
);
74 m_xOk
->connect_clicked( LINK( this, SbiInputDialog
, Ok
) );
75 m_xCancel
->connect_clicked( LINK( this, SbiInputDialog
, Cancel
) );
78 IMPL_LINK_NOARG( SbiInputDialog
, Ok
, weld::Button
&, void )
80 m_aText
= m_xInput
->get_text();
81 m_xDialog
->response(RET_OK
);
84 IMPL_LINK_NOARG( SbiInputDialog
, Cancel
, weld::Button
&, void )
86 m_xDialog
->response(RET_CANCEL
);
89 SbiStream::SbiStream()
93 , nMode(SbiStreamFlags::NONE
)
98 SbiStream::~SbiStream()
102 // map an SvStream-error to StarBASIC-code
104 void SbiStream::MapError()
108 ErrCode nEC
= pStrm
->GetError();
109 if (nEC
== ERRCODE_NONE
)
110 nError
= ERRCODE_NONE
;
111 else if (nEC
== SVSTREAM_FILE_NOT_FOUND
)
112 nError
= ERRCODE_BASIC_FILE_NOT_FOUND
;
113 else if (nEC
==SVSTREAM_PATH_NOT_FOUND
)
114 nError
= ERRCODE_BASIC_PATH_NOT_FOUND
;
115 else if (nEC
==SVSTREAM_TOO_MANY_OPEN_FILES
)
116 nError
= ERRCODE_BASIC_TOO_MANY_FILES
;
117 else if (nEC
==SVSTREAM_ACCESS_DENIED
)
118 nError
= ERRCODE_BASIC_ACCESS_DENIED
;
119 else if (nEC
==SVSTREAM_INVALID_PARAMETER
)
120 nError
= ERRCODE_BASIC_BAD_ARGUMENT
;
121 else if (nEC
==SVSTREAM_OUTOFMEMORY
)
122 nError
= ERRCODE_BASIC_NO_MEMORY
;
124 nError
= ERRCODE_BASIC_IO_ERROR
;
128 // Returns sal_True if UNO is available, otherwise the old file
129 // system implementation has to be used
130 // #89378 New semantic: Don't just ask for UNO but for UCB
133 static bool bNeedInit
= true;
134 static bool bRetVal
= true;
139 Reference
< XComponentContext
> xContext
= comphelper::getProcessComponentContext();
142 // No service manager at all
147 Reference
< XUniversalContentBroker
> xManager
= UniversalContentBroker::create(xContext
);
149 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
;
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
);
255 class UCBStream
: public SvStream
257 Reference
< XInputStream
> xIS
;
258 Reference
< XStream
> xS
;
259 Reference
< XSeekable
> xSeek
;
261 explicit UCBStream( Reference
< XInputStream
> const & xIS
);
262 explicit UCBStream( Reference
< XStream
> const & xS
);
263 virtual ~UCBStream() override
;
264 virtual std::size_t GetData( void* pData
, std::size_t nSize
) override
;
265 virtual std::size_t PutData( const void* pData
, std::size_t nSize
) override
;
266 virtual sal_uInt64
SeekPos( sal_uInt64 nPos
) override
;
267 virtual void FlushData() override
;
268 virtual void SetSize( sal_uInt64 nSize
) override
;
271 UCBStream::UCBStream( Reference
< XInputStream
> const & rStm
)
273 , xSeek( rStm
, UNO_QUERY
)
277 UCBStream::UCBStream( Reference
< XStream
> const & rStm
)
279 , xSeek( rStm
, UNO_QUERY
)
284 UCBStream::~UCBStream()
294 Reference
< XInputStream
> xIS_
= xS
->getInputStream();
301 catch(const Exception
& )
303 SetError( ERRCODE_IO_GENERAL
);
307 std::size_t UCBStream::GetData(void* pData
, std::size_t nSize
)
311 Reference
< XInputStream
> xISFromS
;
314 Sequence
<sal_Int8
> aData
;
315 nSize
= xIS
->readBytes( aData
, nSize
);
316 memcpy( pData
, aData
.getConstArray(), nSize
);
319 else if( xS
.is() && (xISFromS
= xS
->getInputStream()).is() )
321 Sequence
<sal_Int8
> aData
;
322 nSize
= xISFromS
->readBytes( aData
, nSize
);
323 memcpy(pData
, aData
.getConstArray(), nSize
);
328 SetError( ERRCODE_IO_GENERAL
);
331 catch(const Exception
& )
333 SetError( ERRCODE_IO_GENERAL
);
338 std::size_t UCBStream::PutData(const void* pData
, std::size_t nSize
)
342 Reference
< XOutputStream
> xOSFromS
;
343 if( xS
.is() && (xOSFromS
= xS
->getOutputStream()).is() )
345 Sequence
<sal_Int8
> aData( static_cast<const sal_Int8
*>(pData
), nSize
);
346 xOSFromS
->writeBytes( aData
);
351 SetError( ERRCODE_IO_GENERAL
);
354 catch(const Exception
& )
356 SetError( ERRCODE_IO_GENERAL
);
361 sal_uInt64
UCBStream::SeekPos( sal_uInt64 nPos
)
367 sal_uInt64 nLen
= static_cast<sal_uInt64
>( xSeek
->getLength() );
377 SetError( ERRCODE_IO_GENERAL
);
380 catch(const Exception
& )
382 SetError( ERRCODE_IO_GENERAL
);
387 void UCBStream::FlushData()
391 Reference
< XOutputStream
> xOSFromS
;
392 if( xS
.is() && (xOSFromS
= xS
->getOutputStream()).is() )
398 SetError( ERRCODE_IO_GENERAL
);
401 catch(const Exception
& )
403 SetError( ERRCODE_IO_GENERAL
);
407 void UCBStream::SetSize( sal_uInt64
)
409 SAL_WARN("basic", "UCBStream::SetSize not allowed to call from basic" );
410 SetError( ERRCODE_IO_GENERAL
);
414 ErrCode
const & SbiStream::Open
415 ( const OString
& rName
, StreamMode nStrmMode
, SbiStreamFlags nFlags
, short nL
)
420 nExpandOnWriteTo
= 0;
421 if( ( nStrmMode
& ( StreamMode::READ
|StreamMode::WRITE
) ) == StreamMode::READ
)
423 nStrmMode
|= StreamMode::NOCREATE
;
425 OUString
aStr(OStringToOUString(rName
, osl_getThreadTextEncoding()));
426 OUString aNameStr
= getFullPath( aStr
);
430 Reference
< XSimpleFileAccess3
> xSFI( SimpleFileAccess::create( comphelper::getProcessComponentContext() ) );
434 // #??? For write access delete file if it already exists (not for appending)
435 if( (nStrmMode
& StreamMode::WRITE
) && !IsAppend() && !IsBinary() && !IsRandom() &&
436 xSFI
->exists( aNameStr
) && !xSFI
->isFolder( aNameStr
) )
438 xSFI
->kill( aNameStr
);
441 if( (nStrmMode
& (StreamMode::READ
| StreamMode::WRITE
)) == (StreamMode::READ
| StreamMode::WRITE
) )
443 Reference
< XStream
> xIS
= xSFI
->openFileReadWrite( aNameStr
);
444 pStrm
.reset( new UCBStream( xIS
) );
446 else if( nStrmMode
& StreamMode::WRITE
)
448 Reference
< XStream
> xIS
= xSFI
->openFileReadWrite( aNameStr
);
449 pStrm
.reset( new UCBStream( xIS
) );
451 else //if( nStrmMode & StreamMode::READ )
453 Reference
< XInputStream
> xIS
= xSFI
->openFileRead( aNameStr
);
454 pStrm
.reset( new UCBStream( xIS
) );
458 catch(const Exception
& )
460 nError
= ERRCODE_IO_GENERAL
;
466 pStrm
.reset( new OslStream( aNameStr
, nStrmMode
) );
470 pStrm
->Seek( STREAM_SEEK_TO_END
);
480 ErrCode
const & SbiStream::Close()
490 ErrCode
SbiStream::Read(OString
& rBuf
, sal_uInt16 n
, bool bForceReadingPerByte
)
492 nExpandOnWriteTo
= 0;
493 if( !bForceReadingPerByte
&& IsText() )
495 pStrm
->ReadLine(rBuf
);
506 return nError
= ERRCODE_BASIC_BAD_RECORD_LENGTH
;
508 OStringBuffer
aBuffer(read_uInt8s_ToOString(*pStrm
, n
));
509 //Pad it out with ' ' to the requested length on short read
510 sal_Int32 nRequested
= sal::static_int_cast
<sal_Int32
>(n
);
511 comphelper::string::padToLength(aBuffer
, nRequested
, ' ');
512 rBuf
= aBuffer
.makeStringAndClear();
515 if( !nError
&& pStrm
->eof() )
517 nError
= ERRCODE_BASIC_READ_PAST_EOF
;
522 ErrCode
const & SbiStream::Read( char& ch
)
524 nExpandOnWriteTo
= 0;
528 aLine
+= OString('\n');
531 aLine
= aLine
.copy(1);
535 void SbiStream::ExpandFile()
537 if ( nExpandOnWriteTo
)
539 sal_uInt64 nCur
= pStrm
->Seek(STREAM_SEEK_TO_END
);
540 if( nCur
< nExpandOnWriteTo
)
542 sal_uInt64 nDiff
= nExpandOnWriteTo
- nCur
;
545 pStrm
->WriteChar( 0 );
550 pStrm
->Seek( nExpandOnWriteTo
);
552 nExpandOnWriteTo
= 0;
558 void WriteLines(SvStream
&rStream
, const OString
& rStr
)
560 OString
aStr(convertLineEnd(rStr
, rStream
.GetLineDelimiter()) );
561 write_uInt8s_FromOString(rStream
, aStr
);
566 ErrCode
SbiStream::Write( const OString
& rBuf
)
571 pStrm
->Seek( STREAM_SEEK_TO_END
);
576 // Get it out, if the end is an LF, but strip CRLF before,
577 // because the SvStream adds a CRLF!
578 sal_Int32 nLineLen
= aLine
.getLength();
579 if (nLineLen
&& aLine
[--nLineLen
] == 0x0A)
581 aLine
= aLine
.copy(0, nLineLen
);
582 if (nLineLen
&& aLine
[--nLineLen
] == 0x0D)
584 aLine
= aLine
.copy(0, nLineLen
);
586 WriteLines(*pStrm
, aLine
);
594 return nError
= ERRCODE_BASIC_BAD_RECORD_LENGTH
;
596 pStrm
->WriteBytes(rBuf
.getStr(), nLen
);
603 SbiIoSystem::SbiIoSystem()
605 for(SbiStream
* & i
: pChan
)
610 nError
= ERRCODE_NONE
;
613 SbiIoSystem::~SbiIoSystem() COVERITY_NOEXCEPT_FALSE
618 ErrCode
SbiIoSystem::GetError()
621 nError
= ERRCODE_NONE
;
625 void SbiIoSystem::Open(short nCh
, const OString
& rName
, StreamMode nMode
, SbiStreamFlags nFlags
, short nLen
)
627 nError
= ERRCODE_NONE
;
628 if( nCh
>= CHANNELS
|| !nCh
)
630 nError
= ERRCODE_BASIC_BAD_CHANNEL
;
632 else if( pChan
[ nCh
] )
634 nError
= ERRCODE_BASIC_FILE_ALREADY_OPEN
;
638 pChan
[ nCh
] = new SbiStream
;
639 nError
= pChan
[ nCh
]->Open( rName
, nMode
, nFlags
, nLen
);
643 pChan
[ nCh
] = nullptr;
650 void SbiIoSystem::Close()
654 nError
= ERRCODE_BASIC_BAD_CHANNEL
;
656 else if( !pChan
[ nChan
] )
658 nError
= ERRCODE_BASIC_BAD_CHANNEL
;
662 nError
= pChan
[ nChan
]->Close();
663 delete pChan
[ nChan
];
664 pChan
[ nChan
] = nullptr;
670 void SbiIoSystem::Shutdown()
672 for( short i
= 1; i
< CHANNELS
; i
++ )
676 ErrCode n
= pChan
[ i
]->Close();
678 pChan
[ i
] = nullptr;
686 // anything left to PRINT?
687 if( !aOut
.isEmpty() )
689 vcl::Window
* pParent
= Application::GetDefDialogParent();
690 std::unique_ptr
<weld::MessageDialog
> xBox(Application::CreateMessageDialog(pParent
? pParent
->GetFrameWeld() : nullptr, VclMessageType::Warning
,
691 VclButtonsType::Ok
, aOut
));
698 void SbiIoSystem::Read(OString
& rBuf
)
704 else if( !pChan
[ nChan
] )
706 nError
= ERRCODE_BASIC_BAD_CHANNEL
;
710 nError
= pChan
[ nChan
]->Read( rBuf
);
714 char SbiIoSystem::Read()
722 aIn
+= OString('\n');
727 else if( !pChan
[ nChan
] )
729 nError
= ERRCODE_BASIC_BAD_CHANNEL
;
733 nError
= pChan
[ nChan
]->Read( ch
);
738 void SbiIoSystem::Write(const OUString
& rBuf
)
744 else if( !pChan
[ nChan
] )
746 nError
= ERRCODE_BASIC_BAD_CHANNEL
;
750 nError
= pChan
[ nChan
]->Write( OUStringToOString(rBuf
, osl_getThreadTextEncoding()) );
754 // nChannel == 0..CHANNELS-1
756 SbiStream
* SbiIoSystem::GetStream( short nChannel
) const
758 SbiStream
* pRet
= nullptr;
759 if( nChannel
>= 0 && nChannel
< CHANNELS
)
761 pRet
= pChan
[ nChannel
];
766 void SbiIoSystem::CloseAll()
768 for( short i
= 1; i
< CHANNELS
; i
++ )
772 ErrCode n
= pChan
[ i
]->Close();
774 pChan
[ i
] = nullptr;
783 void SbiIoSystem::ReadCon(OString
& rIn
)
785 OUString
aPromptStr(OStringToOUString(aPrompt
, osl_getThreadTextEncoding()));
786 SbiInputDialog
aDlg(nullptr, aPromptStr
);
787 if (aDlg
.run() == RET_OK
)
789 rIn
= OUStringToOString(aDlg
.GetInput(), osl_getThreadTextEncoding());
793 nError
= ERRCODE_BASIC_USER_ABORT
;
798 // output of a MessageBox, if there's a CR in the console-buffer
800 void SbiIoSystem::WriteCon(const OUString
& rText
)
803 sal_Int32 n1
= aOut
.indexOf('\n');
804 sal_Int32 n2
= aOut
.indexOf('\r');
805 if( n1
!= -1 || n2
!= -1 )
819 OUString
s(aOut
.copy(0, n1
));
820 aOut
= aOut
.copy(n1
);
821 while ( !aOut
.isEmpty() && (aOut
[0] == '\n' || aOut
[0] == '\r') )
826 SolarMutexGuard aSolarGuard
;
828 vcl::Window
* pParent
= Application::GetDefDialogParent();
829 std::unique_ptr
<weld::MessageDialog
> xBox(Application::CreateMessageDialog(pParent
? pParent
->GetFrameWeld() : nullptr, VclMessageType::Warning
,
830 VclButtonsType::OkCancel
, s
));
831 xBox
->set_default_response(RET_OK
);
834 nError
= ERRCODE_BASIC_USER_ABORT
;
840 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */