tdf#130857 qt weld: Implement QtInstanceWidget::strip_mnemonic
[LibreOffice.git] / basic / source / runtime / iosys.cxx
blob250149f807c9d6a77fc1472f05f73e625a783618
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 .
20 #include <string.h>
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>
41 #include <iosys.hxx>
43 using namespace com::sun::star::uno;
44 using namespace com::sun::star::ucb;
45 using namespace com::sun::star::io;
48 namespace {
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;
56 OUString m_aText;
57 DECL_LINK(Ok, weld::Button&, void);
58 DECL_LINK(Cancel, weld::Button&, void);
59 public:
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()
91 : nExpandOnWriteTo(0)
92 , nLine(0)
93 , nLen(0)
94 , nMode(SbiStreamFlags::NONE)
95 , nError(0)
99 SbiStream::~SbiStream()
103 // map an SvStream-error to StarBASIC-code
105 void SbiStream::MapError()
107 if( !pStrm )
108 return;
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;
125 else
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
132 bool hasUno()
134 static const bool bRetVal = [] {
135 const Reference< XComponentContext >& xContext = comphelper::getProcessComponentContext();
136 if( !xContext.is() )
138 // No service manager at all
139 return false;
141 else
143 Reference< XUniversalContentBroker > xManager = UniversalContentBroker::create(xContext);
145 if ( !( xManager->queryContentProvider( u"file:///"_ustr ).is() ) )
147 // No UCB
148 return false;
151 return true;
152 }();
153 return bRetVal;
156 namespace {
158 class OslStream : public SvStream
160 osl::File maFile;
162 public:
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 )
175 : maFile( rName )
177 sal_uInt32 nFlags;
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()
208 maFile.close();
211 std::size_t OslStream::GetData(void* pData, std::size_t nSize)
213 sal_uInt64 nBytesRead = nSize;
214 maFile.read( pData, nBytesRead, nBytesRead );
215 return 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 );
234 else
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);
242 return nRealPos;
245 void OslStream::FlushData()
249 void OslStream::SetSize( sal_uInt64 nSize )
251 maFile.setSize( nSize );
254 namespace {
256 class UCBStream : public SvStream
258 Reference< XInputStream > xIS;
259 Reference< XStream > xS;
260 Reference< XSeekable > xSeek;
261 public:
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 )
275 : xIS( rStm )
276 , xSeek( rStm, UNO_QUERY )
280 UCBStream::UCBStream( Reference< XStream > const & rStm )
281 : xS( rStm )
282 , xSeek( rStm, UNO_QUERY )
287 UCBStream::~UCBStream()
291 if( xIS.is() )
293 xIS->closeInput();
295 else if( xS.is() )
297 Reference< XInputStream > xIS_ = xS->getInputStream();
298 if( xIS_.is() )
300 xIS_->closeInput();
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;
315 if( xIS.is() )
317 Sequence<sal_Int8> aData;
318 nSize = xIS->readBytes( aData, nSize );
319 memcpy( pData, aData.getConstArray(), nSize );
320 return 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 );
327 return nSize;
329 else
331 SetError( ERRCODE_IO_GENERAL );
334 catch(const Exception & )
336 SetError( ERRCODE_IO_GENERAL );
338 return 0;
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 );
350 return nSize;
352 else
354 SetError( ERRCODE_IO_GENERAL );
357 catch(const Exception & )
359 SetError( ERRCODE_IO_GENERAL );
361 return 0;
364 sal_uInt64 UCBStream::SeekPos( sal_uInt64 nPos )
368 if( xSeek.is() )
370 sal_uInt64 nLen = static_cast<sal_uInt64>( xSeek->getLength() );
371 if( nPos > nLen )
373 nPos = nLen;
375 xSeek->seek( nPos );
376 return nPos;
378 else
380 SetError( ERRCODE_IO_GENERAL );
383 catch(const Exception & )
385 SetError( ERRCODE_IO_GENERAL );
387 return 0;
390 void UCBStream::FlushData()
394 Reference< XOutputStream > xOSFromS;
395 if( xS.is() && (xOSFromS = xS->getOutputStream()).is() )
397 xOSFromS->flush();
399 else
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 )
420 nMode = nFlags;
421 nLen = nL;
422 nLine = 0;
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 );
431 if( hasUno() )
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;
467 if( !pStrm )
469 pStrm.reset( new OslStream( aNameStr, nStrmMode ) );
471 if( IsAppend() )
473 pStrm->Seek( STREAM_SEEK_TO_END );
475 MapError();
476 if( nError )
478 pStrm.reset();
480 return nError;
483 ErrCode const & SbiStream::Close()
485 if( pStrm )
487 MapError();
488 pStrm.reset();
490 return nError;
493 ErrCode SbiStream::Read(OString& rBuf, sal_uInt16 n, bool bForceReadingPerByte)
495 nExpandOnWriteTo = 0;
496 if( !bForceReadingPerByte && IsText() )
498 pStrm->ReadLine(rBuf);
499 nLine++;
501 else
503 if( !n )
505 n = nLen;
507 if( !n )
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();
517 MapError();
518 if( !nError && pStrm->eof() )
520 nError = ERRCODE_BASIC_READ_PAST_EOF;
522 return nError;
525 ErrCode const & SbiStream::Read( char& ch )
527 nExpandOnWriteTo = 0;
528 if (aLine.isEmpty())
530 Read( aLine );
531 aLine += "\n";
533 ch = aLine[0];
534 aLine = aLine.copy(1);
535 return nError;
538 void SbiStream::ExpandFile()
540 if ( !nExpandOnWriteTo )
541 return;
543 sal_uInt64 nCur = pStrm->Seek(STREAM_SEEK_TO_END);
544 if( nCur < nExpandOnWriteTo )
546 sal_uInt64 nDiff = nExpandOnWriteTo - nCur;
547 while( nDiff-- )
549 pStrm->WriteChar( 0 );
552 else
554 pStrm->Seek( nExpandOnWriteTo );
556 nExpandOnWriteTo = 0;
559 namespace
561 void WriteLines(SvStream &rStream, const OString& rStr)
563 OString aStr(convertLineEnd(rStr, rStream.GetLineDelimiter()) );
564 rStream.WriteBytes(aStr.getStr(), aStr.getLength());
565 endl( rStream );
569 ErrCode SbiStream::Write( const OString& rBuf )
571 ExpandFile();
572 if( IsAppend() )
574 pStrm->Seek( STREAM_SEEK_TO_END );
576 if( IsText() )
578 aLine += rBuf;
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);
590 aLine.clear();
593 else
595 if( !nLen )
597 return nError = ERRCODE_BASIC_BAD_RECORD_LENGTH;
599 pStrm->WriteBytes(rBuf.getStr(), nLen);
600 MapError();
602 return nError;
606 SbiIoSystem::SbiIoSystem()
608 for(SbiStream* & i : pChan)
610 i = nullptr;
612 nChan = 0;
613 nError = ERRCODE_NONE;
616 SbiIoSystem::~SbiIoSystem() COVERITY_NOEXCEPT_FALSE
618 Shutdown();
621 ErrCode SbiIoSystem::GetError()
623 ErrCode n = nError;
624 nError = ERRCODE_NONE;
625 return n;
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;
639 else
641 pChan[ nCh ] = new SbiStream;
642 nError = pChan[ nCh ]->Open( rName, nMode, nFlags, nLen );
643 if( nError )
645 delete pChan[ nCh ];
646 pChan[ nCh ] = nullptr;
649 nChan = 0;
653 void SbiIoSystem::Close()
655 if( !nChan )
657 nError = ERRCODE_BASIC_BAD_CHANNEL;
659 else if( !pChan[ nChan ] )
661 nError = ERRCODE_BASIC_BAD_CHANNEL;
663 else
665 nError = pChan[ nChan ]->Close();
666 delete pChan[ nChan ];
667 pChan[ nChan ] = nullptr;
669 nChan = 0;
673 void SbiIoSystem::Shutdown()
675 for( short i = 1; i < CHANNELS; i++ )
677 if( pChan[ i ] )
679 ErrCode n = pChan[ i ]->Close();
680 delete pChan[ i ];
681 pChan[ i ] = nullptr;
682 if( n && !nError )
684 nError = n;
688 nChan = 0;
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));
694 xBox->run();
696 aOut.clear();
700 void SbiIoSystem::Read(OString& rBuf)
702 if( !nChan )
704 ReadCon( rBuf );
706 else if( !pChan[ nChan ] )
708 nError = ERRCODE_BASIC_BAD_CHANNEL;
710 else
712 nError = pChan[ nChan ]->Read( rBuf );
716 char SbiIoSystem::Read()
718 char ch = ' ';
719 if( !nChan )
721 if( aIn.isEmpty() )
723 ReadCon( aIn );
724 aIn += "\n";
726 ch = aIn[0];
727 aIn = aIn.copy(1);
729 else if( !pChan[ nChan ] )
731 nError = ERRCODE_BASIC_BAD_CHANNEL;
733 else
735 nError = pChan[ nChan ]->Read( ch );
737 return ch;
740 void SbiIoSystem::Write(std::u16string_view rBuf)
742 if( !nChan )
744 WriteCon( rBuf );
746 else if( !pChan[ nChan ] )
748 nError = ERRCODE_BASIC_BAD_CHANNEL;
750 else
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 ];
765 return pRet;
768 void SbiIoSystem::CloseAll()
770 for( short i = 1; i < CHANNELS; i++ )
772 if( pChan[ i ] )
774 ErrCode n = pChan[ i ]->Close();
775 delete pChan[ i ];
776 pChan[ i ] = nullptr;
777 if( n && !nError )
779 nError = n;
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());
793 else
795 nError = ERRCODE_BASIC_USER_ABORT;
797 aPrompt.clear();
800 // output of a MessageBox, if there's a CR in the console-buffer
802 void SbiIoSystem::WriteCon(std::u16string_view rText)
804 aOut += rText;
805 sal_Int32 n1 = aOut.indexOf('\n');
806 sal_Int32 n2 = aOut.indexOf('\r');
807 if( n1 == -1 && n2 == -1 )
808 return;
810 if( n1 == -1 )
812 n1 = n2;
814 else if( n2 == -1 )
816 n2 = n1;
818 if( n1 > n2 )
820 n1 = n2;
822 OUString s(aOut.copy(0, n1));
823 aOut = aOut.copy(n1);
824 while ( !aOut.isEmpty() && (aOut[0] == '\n' || aOut[0] == '\r') )
826 aOut = aOut.copy(1);
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);
834 if (!xBox->run())
836 nError = ERRCODE_BASIC_USER_ABORT;
841 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */