diff options
Diffstat (limited to '')
52 files changed, 10408 insertions, 0 deletions
diff --git a/io/CppunitTest_io_textinputstream.mk b/io/CppunitTest_io_textinputstream.mk new file mode 100644 index 000000000..a18e64378 --- /dev/null +++ b/io/CppunitTest_io_textinputstream.mk @@ -0,0 +1,27 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +$(eval $(call gb_CppunitTest_CppunitTest,io_textinputstream)) + +$(eval $(call gb_CppunitTest_add_exception_objects,io_textinputstream, \ + io/qa/textinputstream \ +)) + +$(eval $(call gb_CppunitTest_use_libraries,io_textinputstream, \ + cppu \ + cppuhelper \ + sal \ + unotest \ +)) + +$(eval $(call gb_CppunitTest_use_udk_api,io_textinputstream)) + +$(eval $(call gb_CppunitTest_use_ure,io_textinputstream)) + +# vim: set noet sw=4 ts=4: diff --git a/io/Executable_io-testconnection.mk b/io/Executable_io-testconnection.mk new file mode 100644 index 000000000..8abfcd3dd --- /dev/null +++ b/io/Executable_io-testconnection.mk @@ -0,0 +1,36 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t; fill-column: 100 -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This file incorporates work covered by the following license notice: +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed +# with this work for additional information regarding copyright +# ownership. The ASF licenses this file to you under the Apache +# License, Version 2.0 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.apache.org/licenses/LICENSE-2.0 . +# + +$(eval $(call gb_Executable_Executable,io-testconnection)) + +$(eval $(call gb_Executable_add_exception_objects,io-testconnection, \ + io/test/testconnection \ +)) + +$(eval $(call gb_Executable_use_api,io-testconnection, \ + udkapi \ +)) + +$(eval $(call gb_Executable_use_libraries,io-testconnection, \ + cppu \ + cppuhelper \ + sal \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/io/IwyuFilter_io.yaml b/io/IwyuFilter_io.yaml new file mode 100644 index 000000000..88e7eb0e0 --- /dev/null +++ b/io/IwyuFilter_io.yaml @@ -0,0 +1,13 @@ +--- +assumeFilename: io/source/stm/odata.cxx +excludelist: + io/source/connector/connector.hxx: + # Base class needs full type + - com/sun/star/connection/XConnection.hpp + - com/sun/star/connection/XConnectionBroadcaster.hpp + # Don't replace with impl. detail + - osl/socket.hxx + - osl/pipe.hxx + io/source/stm/opump.cxx: + # Don't replace with URE API impl. detail + - cppuhelper/interfacecontainer.hxx diff --git a/io/Library_io.mk b/io/Library_io.mk new file mode 100644 index 000000000..d2c60b303 --- /dev/null +++ b/io/Library_io.mk @@ -0,0 +1,45 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +$(eval $(call gb_Library_Library,io)) + +$(eval $(call gb_Library_use_external,io,boost_headers)) + +$(eval $(call gb_Library_use_udk_api,io)) + +$(eval $(call gb_Library_use_libraries,io,\ + cppu \ + cppuhelper \ + sal \ +)) + +$(eval $(call gb_Library_set_componentfile,io,io/source/io,ure/services)) + +$(eval $(call gb_Library_set_include,io,\ + -I$(SRCDIR)/io/source \ + $$(INCLUDE) \ +)) + +$(eval $(call gb_Library_add_exception_objects,io,\ + io/source/acceptor/acc_pipe \ + io/source/acceptor/acc_socket \ + io/source/acceptor/acceptor \ + io/source/connector/connector \ + io/source/connector/ctr_pipe \ + io/source/connector/ctr_socket \ + io/source/stm/odata \ + io/source/stm/omark \ + io/source/stm/opipe \ + io/source/stm/opump \ + io/source/stm/streamhelper \ + io/source/TextInputStream/TextInputStream \ + io/source/TextOutputStream/TextOutputStream \ +)) + +# vim:set noet sw=4 ts=4: diff --git a/io/Makefile b/io/Makefile new file mode 100644 index 000000000..0997e6284 --- /dev/null +++ b/io/Makefile @@ -0,0 +1,14 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +module_directory:=$(dir $(realpath $(firstword $(MAKEFILE_LIST)))) + +include $(module_directory)/../solenv/gbuild/partial_build.mk + +# vim: set noet sw=4 ts=4: diff --git a/io/Module_io.mk b/io/Module_io.mk new file mode 100644 index 000000000..c4a75e74e --- /dev/null +++ b/io/Module_io.mk @@ -0,0 +1,26 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +$(eval $(call gb_Module_Module,io)) + +$(eval $(call gb_Module_add_targets,io,\ + Library_io \ +)) + +$(eval $(call gb_Module_add_subsequentcheck_targets,io,\ + CppunitTest_io_textinputstream \ +)) + +ifneq (,$(filter Executable_io-testconnection,$(MAKECMDGOALS))) +$(eval $(call gb_Module_add_targets,io, \ + Executable_io-testconnection \ +)) +endif + +# vim:set noet sw=4 ts=4: diff --git a/io/README.md b/io/README.md new file mode 100644 index 000000000..706d9705f --- /dev/null +++ b/io/README.md @@ -0,0 +1,4 @@ +# Simple IO Wrapper UNO Components + +Simple IO wrapper UNO components which includes `TextInputStream`, +`TextOutputStream`, pipes and stream helpers diff --git a/io/qa/textinputstream.cxx b/io/qa/textinputstream.cxx new file mode 100644 index 000000000..dfeb478f9 --- /dev/null +++ b/io/qa/textinputstream.cxx @@ -0,0 +1,126 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <sal/config.h> + +#include <algorithm> +#include <cassert> +#include <cstring> + +#include <com/sun/star/io/NotConnectedException.hpp> +#include <com/sun/star/io/TextInputStream.hpp> +#include <com/sun/star/io/XInputStream.hpp> +#include <com/sun/star/io/XTextInputStream2.hpp> +#include <com/sun/star/uno/Sequence.hxx> +#include <com/sun/star/uno/Reference.hxx> +#include <cppuhelper/implbase.hxx> +#include <cppunit/TestAssert.h> +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/plugin/TestPlugIn.h> +#include <osl/mutex.hxx> +#include <rtl/ustring.hxx> +#include <sal/types.h> +#include <unotest/bootstrapfixturebase.hxx> + +namespace { + +class Input: public cppu::WeakImplHelper<css::io::XInputStream> { +public: + Input(): open_(true), index_(0) {} + +private: + virtual ~Input() override {} + + sal_Int32 SAL_CALL readBytes(css::uno::Sequence<sal_Int8> &, sal_Int32) + override + { CPPUNIT_FAIL("readLine is supposed to call readSomeBytes instead"); } + + sal_Int32 SAL_CALL readSomeBytes( + css::uno::Sequence<sal_Int8 > & aData, sal_Int32 nMaxBytesToRead) override + { + assert(nMaxBytesToRead >= 0); + osl::MutexGuard g(mutex_); + checkClosed(); + assert(index_ >= 0 && index_ <= SIZE); + sal_Int32 n = std::min<sal_Int32>( + std::min<sal_Int32>(nMaxBytesToRead, 2), SIZE - index_); + assert(n >= 0 && n <= SIZE - index_); + aData.realloc(n); + std::memcpy(aData.getArray(), data + index_, n); + index_ += n; + assert(index_ >= 0 && index_ <= SIZE); + return n; + } + + void SAL_CALL skipBytes(sal_Int32 nBytesToSkip) override + { + assert(nBytesToSkip >= 0); + osl::MutexGuard g(mutex_); + checkClosed(); + assert(index_ >= 0 && index_ <= SIZE); + index_ += std::min<sal_Int32>(nBytesToSkip, SIZE - index_); + assert(index_ >= 0 && index_ <= SIZE); + } + + sal_Int32 SAL_CALL available() override + { + osl::MutexGuard g(mutex_); + checkClosed(); + assert(index_ >= 0 && index_ <= SIZE); + return SIZE - index_; + } + + void SAL_CALL closeInput() override + { + osl::MutexGuard g(mutex_); + checkClosed(); + open_ = true; + } + + void checkClosed() { + if (!open_) { + throw css::io::NotConnectedException( + "test input stream already closed"); + } + } + + static sal_Int32 const SIZE = 9; + static char const data[SIZE]; + + osl::Mutex mutex_; + bool open_; + sal_Int32 index_; +}; + +char const Input::data[] = { '1', '2', '3', '4', '5', '6', '7', '8', '9' }; + +class Test: public test::BootstrapFixtureBase { +private: + CPPUNIT_TEST_SUITE(Test); + CPPUNIT_TEST(testReadLine); + CPPUNIT_TEST_SUITE_END(); + + void testReadLine(); +}; + +void Test::testReadLine() { + css::uno::Reference<css::io::XTextInputStream2> s( + css::io::TextInputStream::create(getComponentContext())); + s->setInputStream(new Input); + OUString l(s->readLine()); + CPPUNIT_ASSERT_EQUAL(OUString("123456789"), l); +} + +CPPUNIT_TEST_SUITE_REGISTRATION(Test); + +} + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/io/source/TextInputStream/TextInputStream.cxx b/io/source/TextInputStream/TextInputStream.cxx new file mode 100644 index 000000000..9f7c88472 --- /dev/null +++ b/io/source/TextInputStream/TextInputStream.cxx @@ -0,0 +1,399 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <string.h> + +#include <comphelper/sequence.hxx> +#include <cppuhelper/implbase.hxx> +#include <cppuhelper/supportsservice.hxx> + +#include <rtl/textenc.h> +#include <rtl/tencinfo.h> + +#include <com/sun/star/io/BufferSizeExceededException.hpp> +#include <com/sun/star/io/IOException.hpp> +#include <com/sun/star/io/NotConnectedException.hpp> +#include <com/sun/star/io/XTextInputStream2.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> + +#include <vector> + +namespace com::sun::star::uno { class XComponentContext; } + +using namespace ::osl; +using namespace ::cppu; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::io; + + +// Implementation XTextInputStream + +#define INITIAL_UNICODE_BUFFER_CAPACITY 0x100 +#define READ_BYTE_COUNT 0x100 + +namespace { + +class OTextInputStream : public WeakImplHelper< XTextInputStream2, XServiceInfo > +{ + Reference< XInputStream > mxStream; + + // Encoding + bool mbEncodingInitialized; + rtl_TextToUnicodeConverter mConvText2Unicode; + rtl_TextToUnicodeContext mContextText2Unicode; + Sequence<sal_Int8> mSeqSource; + + // Internal buffer for characters that are already converted successfully + std::vector<sal_Unicode> mvBuffer; + sal_Int32 mnCharsInBuffer; + bool mbReachedEOF; + + /// @throws IOException + /// @throws RuntimeException + OUString implReadString( const Sequence< sal_Unicode >& Delimiters, + bool bRemoveDelimiter, bool bFindLineEnd ); + /// @throws IOException + /// @throws RuntimeException + sal_Int32 implReadNext(); + +public: + OTextInputStream(); + virtual ~OTextInputStream() override; + + // Methods XTextInputStream + virtual OUString SAL_CALL readLine( ) override; + virtual OUString SAL_CALL readString( const Sequence< sal_Unicode >& Delimiters, sal_Bool bRemoveDelimiter ) override; + virtual sal_Bool SAL_CALL isEOF( ) override; + virtual void SAL_CALL setEncoding( const OUString& Encoding ) override; + + // Methods XInputStream + virtual sal_Int32 SAL_CALL readBytes( Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead ) override; + virtual sal_Int32 SAL_CALL readSomeBytes( Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead ) override; + virtual void SAL_CALL skipBytes( sal_Int32 nBytesToSkip ) override; + virtual sal_Int32 SAL_CALL available( ) override; + virtual void SAL_CALL closeInput( ) override; + + // Methods XActiveDataSink + virtual void SAL_CALL setInputStream( const Reference< XInputStream >& aStream ) override; + virtual Reference< XInputStream > SAL_CALL getInputStream() override; + + // Methods XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + virtual sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override; +}; + +} + +OTextInputStream::OTextInputStream() + : mbEncodingInitialized(false) + , mConvText2Unicode(nullptr) + , mContextText2Unicode(nullptr) + , mSeqSource(READ_BYTE_COUNT) + , mvBuffer(INITIAL_UNICODE_BUFFER_CAPACITY, 0) + , mnCharsInBuffer(0) + , mbReachedEOF(false) +{ +} + +OTextInputStream::~OTextInputStream() +{ + if( mbEncodingInitialized ) + { + rtl_destroyTextToUnicodeContext( mConvText2Unicode, mContextText2Unicode ); + rtl_destroyTextToUnicodeConverter( mConvText2Unicode ); + } +} + + +// XTextInputStream + +OUString OTextInputStream::readLine( ) +{ + static Sequence< sal_Unicode > aDummySeq; + return implReadString( aDummySeq, true, true ); +} + +OUString OTextInputStream::readString( const Sequence< sal_Unicode >& Delimiters, sal_Bool bRemoveDelimiter ) +{ + return implReadString( Delimiters, bRemoveDelimiter, false ); +} + +sal_Bool OTextInputStream::isEOF() +{ + bool bRet = false; + if( mnCharsInBuffer == 0 && mbReachedEOF ) + bRet = true; + return bRet; +} + + +OUString OTextInputStream::implReadString( const Sequence< sal_Unicode >& Delimiters, + bool bRemoveDelimiter, bool bFindLineEnd ) +{ + OUString aRetStr; + if( !mbEncodingInitialized ) + { + setEncoding( "utf8" ); + } + if( !mbEncodingInitialized ) + return aRetStr; + + // Only for bFindLineEnd + sal_Unicode cLineEndChar1 = 0x0D; + sal_Unicode cLineEndChar2 = 0x0A; + + sal_Int32 nBufferReadPos = 0; + sal_Int32 nCopyLen = 0; + bool bFound = false; + bool bFoundFirstLineEndChar = false; + sal_Unicode cFirstLineEndChar = 0; + while( !bFound ) + { + // Still characters available? + if( nBufferReadPos == mnCharsInBuffer ) + { + // Already reached EOF? Then we can't read any more + if( mbReachedEOF ) + break; + + // No, so read new characters + if( !implReadNext() ) + break; + } + + // Now there should be characters available + // (otherwise the loop should have been broken before) + sal_Unicode c = mvBuffer[ nBufferReadPos++ ]; + + if( bFindLineEnd ) + { + if( bFoundFirstLineEndChar ) + { + bFound = true; + nCopyLen = nBufferReadPos - 2; + if( c == cLineEndChar1 || c == cLineEndChar2 ) + { + // Same line end char -> new line break + if( c == cFirstLineEndChar ) + { + nBufferReadPos--; + } + } + else + { + // No second line end char + nBufferReadPos--; + } + } + else if( c == cLineEndChar1 || c == cLineEndChar2 ) + { + bFoundFirstLineEndChar = true; + cFirstLineEndChar = c; + } + } + else if( comphelper::findValue(Delimiters, c) != -1 ) + { + bFound = true; + nCopyLen = nBufferReadPos; + if( bRemoveDelimiter ) + nCopyLen--; + } + } + + // Nothing found? Return all + if( !nCopyLen && !bFound && mbReachedEOF ) + nCopyLen = nBufferReadPos; + + // Create string + if( nCopyLen ) + aRetStr = OUString( mvBuffer.data(), nCopyLen ); + + // Copy rest of buffer + memmove( mvBuffer.data(), mvBuffer.data() + nBufferReadPos, + (mnCharsInBuffer - nBufferReadPos) * sizeof( sal_Unicode ) ); + mnCharsInBuffer -= nBufferReadPos; + + return aRetStr; +} + + +sal_Int32 OTextInputStream::implReadNext() +{ + sal_Int32 nFreeBufferSize = mvBuffer.size() - mnCharsInBuffer; + if( nFreeBufferSize < READ_BYTE_COUNT ) + mvBuffer.resize(mvBuffer.size() * 2); + nFreeBufferSize = mvBuffer.size() - mnCharsInBuffer; + + try + { + sal_Int32 nRead = mxStream->readSomeBytes( mSeqSource, READ_BYTE_COUNT ); + sal_Int32 nTotalRead = nRead; + if( nRead == 0 ) + mbReachedEOF = true; + + // Try to convert + sal_uInt32 uiInfo; + sal_Size nSrcCvtBytes = 0; + sal_Size nTargetCount = 0; + sal_Size nSourceCount = 0; + while( true ) + { + const sal_Int8 *pbSource = mSeqSource.getConstArray(); + + // All invalid characters are transformed to the unicode undefined char + nTargetCount += rtl_convertTextToUnicode( + mConvText2Unicode, + mContextText2Unicode, + reinterpret_cast<const char*>(&( pbSource[nSourceCount] )), + nTotalRead - nSourceCount, + mvBuffer.data() + mnCharsInBuffer + nTargetCount, + nFreeBufferSize - nTargetCount, + RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_DEFAULT | + RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_DEFAULT | + RTL_TEXTTOUNICODE_FLAGS_INVALID_DEFAULT, + &uiInfo, + &nSrcCvtBytes ); + nSourceCount += nSrcCvtBytes; + + bool bCont = false; + if( uiInfo & RTL_TEXTTOUNICODE_INFO_DESTBUFFERTOOSMALL ) + { + mvBuffer.resize(mvBuffer.size() * 2); + bCont = true; + } + + if( uiInfo & RTL_TEXTTOUNICODE_INFO_SRCBUFFERTOOSMALL ) + { + // read next byte + static Sequence< sal_Int8 > aOneByteSeq( 1 ); + nRead = mxStream->readSomeBytes( aOneByteSeq, 1 ); + if( nRead == 0 ) + { + mbReachedEOF = true; + break; + } + + sal_Int32 nOldLen = mSeqSource.getLength(); + nTotalRead++; + if( nTotalRead > nOldLen ) + { + mSeqSource.realloc( nTotalRead ); + } + mSeqSource.getArray()[ nOldLen ] = aOneByteSeq.getConstArray()[ 0 ]; + bCont = true; + } + + if( bCont ) + continue; + break; + } + + mnCharsInBuffer += nTargetCount; + return nTargetCount; + } + catch( NotConnectedException& ) + { + throw IOException("Not connected"); + //throw IOException( L"OTextInputStream::implReadString failed" ); + } + catch( BufferSizeExceededException& ) + { + throw IOException("Buffer size exceeded"); + } +} + +void OTextInputStream::setEncoding( const OUString& Encoding ) +{ + OString aOEncodingStr = OUStringToOString( Encoding, RTL_TEXTENCODING_ASCII_US ); + rtl_TextEncoding encoding = rtl_getTextEncodingFromMimeCharset( aOEncodingStr.getStr() ); + if( RTL_TEXTENCODING_DONTKNOW == encoding ) + return; + + mbEncodingInitialized = true; + mConvText2Unicode = rtl_createTextToUnicodeConverter( encoding ); + mContextText2Unicode = rtl_createTextToUnicodeContext( mConvText2Unicode ); +} + + +// XInputStream + +sal_Int32 OTextInputStream::readBytes( Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead ) +{ + return mxStream->readBytes( aData, nBytesToRead ); +} + +sal_Int32 OTextInputStream::readSomeBytes( Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead ) +{ + return mxStream->readSomeBytes( aData, nMaxBytesToRead ); +} + +void OTextInputStream::skipBytes( sal_Int32 nBytesToSkip ) +{ + mxStream->skipBytes( nBytesToSkip ); +} + +sal_Int32 OTextInputStream::available( ) +{ + return mxStream->available(); +} + +void OTextInputStream::closeInput( ) +{ + mxStream->closeInput(); +} + + +// XActiveDataSink + +void OTextInputStream::setInputStream( const Reference< XInputStream >& aStream ) +{ + mxStream = aStream; +} + +Reference< XInputStream > OTextInputStream::getInputStream() +{ + return mxStream; +} + +OUString OTextInputStream::getImplementationName() +{ + return "com.sun.star.comp.io.TextInputStream"; +} + +sal_Bool OTextInputStream::supportsService(const OUString& ServiceName) +{ + return cppu::supportsService(this, ServiceName); +} + +Sequence< OUString > OTextInputStream::getSupportedServiceNames() +{ + return { "com.sun.star.io.TextInputStream" }; +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +io_OTextInputStream_get_implementation( + css::uno::XComponentContext* , css::uno::Sequence<css::uno::Any> const&) +{ + return cppu::acquire(new OTextInputStream()); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/io/source/TextOutputStream/TextOutputStream.cxx b/io/source/TextOutputStream/TextOutputStream.cxx new file mode 100644 index 000000000..1271c4d09 --- /dev/null +++ b/io/source/TextOutputStream/TextOutputStream.cxx @@ -0,0 +1,239 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + + +#include <cppuhelper/implbase.hxx> +#include <cppuhelper/supportsservice.hxx> + +#include <rtl/textenc.h> +#include <rtl/tencinfo.h> + +#include <com/sun/star/io/IOException.hpp> +#include <com/sun/star/io/XTextOutputStream2.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> + +namespace com::sun::star::uno { class XComponentContext; } + +using namespace ::osl; +using namespace ::cppu; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::io; + +// Implementation XTextOutputStream + +namespace { + +class OTextOutputStream : public WeakImplHelper< XTextOutputStream2, XServiceInfo > +{ + Reference< XOutputStream > mxStream; + + // Encoding + bool mbEncodingInitialized; + rtl_UnicodeToTextConverter mConvUnicode2Text; + rtl_UnicodeToTextContext mContextUnicode2Text; + + Sequence<sal_Int8> implConvert( const OUString& rSource ); + /// @throws IOException + void checkOutputStream() const; + +public: + OTextOutputStream(); + virtual ~OTextOutputStream() override; + + // Methods XTextOutputStream + virtual void SAL_CALL writeString( const OUString& aString ) override; + virtual void SAL_CALL setEncoding( const OUString& Encoding ) override; + + // Methods XOutputStream + virtual void SAL_CALL writeBytes( const Sequence< sal_Int8 >& aData ) override; + virtual void SAL_CALL flush( ) override; + virtual void SAL_CALL closeOutput( ) override; + + // Methods XActiveDataSource + virtual void SAL_CALL setOutputStream( const Reference< XOutputStream >& aStream ) override; + virtual Reference< XOutputStream > SAL_CALL getOutputStream( ) override; + + // Methods XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + virtual sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override; +}; + +} + +OTextOutputStream::OTextOutputStream() + : mbEncodingInitialized(false) + , mConvUnicode2Text(nullptr) + , mContextUnicode2Text(nullptr) +{ +} + +OTextOutputStream::~OTextOutputStream() +{ + if( mbEncodingInitialized ) + { + rtl_destroyUnicodeToTextContext( mConvUnicode2Text, mContextUnicode2Text ); + rtl_destroyUnicodeToTextConverter( mConvUnicode2Text ); + } +} + +Sequence<sal_Int8> OTextOutputStream::implConvert( const OUString& rSource ) +{ + const sal_Unicode *puSource = rSource.getStr(); + sal_Int32 nSourceSize = rSource.getLength(); + + sal_Size nTargetCount = 0; + sal_Size nSourceCount = 0; + + sal_uInt32 uiInfo; + sal_Size nSrcCvtChars; + + // take nSourceSize * 3 as preference + // this is an upper boundary for converting to utf8, + // which most often used as the target. + sal_Int32 nSeqSize = nSourceSize * 3; + + Sequence<sal_Int8> seqText( nSeqSize ); + char *pTarget = reinterpret_cast<char *>(seqText.getArray()); + while( true ) + { + nTargetCount += rtl_convertUnicodeToText( + mConvUnicode2Text, + mContextUnicode2Text, + &( puSource[nSourceCount] ), + nSourceSize - nSourceCount , + &( pTarget[nTargetCount] ), + nSeqSize - nTargetCount, + RTL_UNICODETOTEXT_FLAGS_UNDEFINED_DEFAULT | + RTL_UNICODETOTEXT_FLAGS_INVALID_DEFAULT , + &uiInfo, + &nSrcCvtChars); + nSourceCount += nSrcCvtChars; + + if( uiInfo & RTL_UNICODETOTEXT_INFO_DESTBUFFERTOSMALL ) + { + nSeqSize *= 2; + seqText.realloc( nSeqSize ); // double array size + pTarget = reinterpret_cast<char*>(seqText.getArray()); + continue; + } + break; + } + + // reduce the size of the buffer (fast, no copy necessary) + seqText.realloc( nTargetCount ); + return seqText; +} + + +// XTextOutputStream + +void OTextOutputStream::writeString( const OUString& aString ) +{ + checkOutputStream(); + if( !mbEncodingInitialized ) + { + setEncoding( "utf8" ); + } + if( !mbEncodingInitialized ) + return; + + Sequence<sal_Int8> aByteSeq = implConvert( aString ); + mxStream->writeBytes( aByteSeq ); +} + +void OTextOutputStream::setEncoding( const OUString& Encoding ) +{ + OString aOEncodingStr = OUStringToOString( Encoding, RTL_TEXTENCODING_ASCII_US ); + rtl_TextEncoding encoding = rtl_getTextEncodingFromMimeCharset( aOEncodingStr.getStr() ); + if( RTL_TEXTENCODING_DONTKNOW == encoding ) + return; + + mbEncodingInitialized = true; + mConvUnicode2Text = rtl_createUnicodeToTextConverter( encoding ); + mContextUnicode2Text = rtl_createUnicodeToTextContext( mConvUnicode2Text ); +} + + +// XOutputStream +void OTextOutputStream::writeBytes( const Sequence< sal_Int8 >& aData ) +{ + checkOutputStream(); + mxStream->writeBytes( aData ); +} + +void OTextOutputStream::flush( ) +{ + checkOutputStream(); + mxStream->flush(); +} + +void OTextOutputStream::closeOutput( ) +{ + checkOutputStream(); + mxStream->closeOutput(); +} + + +void OTextOutputStream::checkOutputStream() const +{ + if (! mxStream.is() ) + throw IOException("output stream is not initialized, you have to use setOutputStream first"); +} + + +// XActiveDataSource + +void OTextOutputStream::setOutputStream( const Reference< XOutputStream >& aStream ) +{ + mxStream = aStream; +} + +Reference< XOutputStream > OTextOutputStream::getOutputStream() +{ + return mxStream; +} + +OUString OTextOutputStream::getImplementationName() +{ + return "com.sun.star.comp.io.TextOutputStream"; +} + +sal_Bool OTextOutputStream::supportsService(const OUString& ServiceName) +{ + return cppu::supportsService(this, ServiceName); +} + +Sequence< OUString > OTextOutputStream::getSupportedServiceNames() +{ + return { "com.sun.star.io.TextOutputStream" }; +} + + + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +io_OTextOutputStream_get_implementation( + css::uno::XComponentContext* , css::uno::Sequence<css::uno::Any> const&) +{ + return cppu::acquire(new OTextOutputStream()); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/io/source/acceptor/acc_pipe.cxx b/io/source/acceptor/acc_pipe.cxx new file mode 100644 index 000000000..db43c58db --- /dev/null +++ b/io/source/acceptor/acc_pipe.cxx @@ -0,0 +1,190 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <osl/security.hxx> +#include "acceptor.hxx" +#include <com/sun/star/connection/XConnection.hpp> +#include <com/sun/star/connection/ConnectionSetupException.hpp> +#include <com/sun/star/io/IOException.hpp> + +#include <osl/diagnose.h> +#include <cppuhelper/implbase.hxx> +#include <rtl/ref.hxx> + +using namespace ::osl; +using namespace ::cppu; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::connection; +using namespace ::com::sun::star::io; + + +namespace io_acceptor +{ + namespace { + + class PipeConnection : + public WeakImplHelper< XConnection > + { + public: + explicit PipeConnection( const OUString &sConnectionDescription); + + virtual sal_Int32 SAL_CALL read( Sequence< sal_Int8 >& aReadBytes, sal_Int32 nBytesToRead ) override; + virtual void SAL_CALL write( const Sequence< sal_Int8 >& aData ) override; + virtual void SAL_CALL flush( ) override; + virtual void SAL_CALL close( ) override; + virtual OUString SAL_CALL getDescription( ) override; + public: + ::osl::StreamPipe m_pipe; + oslInterlockedCount m_nStatus; + OUString m_sDescription; + }; + + } + + PipeConnection::PipeConnection( const OUString &sConnectionDescription) : + m_nStatus( 0 ), + m_sDescription( sConnectionDescription ) + { + // make it unique + m_sDescription += ",uniqueValue="; + m_sDescription += OUString::number( + sal::static_int_cast<sal_Int64 >( + reinterpret_cast< sal_IntPtr >(&m_pipe)) ); + } + + sal_Int32 PipeConnection::read( Sequence < sal_Int8 > & aReadBytes , sal_Int32 nBytesToRead ) + { + if( m_nStatus ) + { + throw IOException("pipe already closed"); + } + if( aReadBytes.getLength() < nBytesToRead ) + { + aReadBytes.realloc( nBytesToRead ); + } + sal_Int32 n = m_pipe.read( aReadBytes.getArray(), nBytesToRead ); + OSL_ASSERT( n >= 0 && n <= aReadBytes.getLength() ); + if( n < aReadBytes.getLength() ) + { + aReadBytes.realloc( n ); + } + return n; + + } + + void PipeConnection::write( const Sequence < sal_Int8 > &seq ) + { + if( m_nStatus ) + { + throw IOException("pipe already closed"); + } + if( m_pipe.write( seq.getConstArray() , seq.getLength() ) != seq.getLength() ) + { + throw IOException("short write"); + } + } + + void PipeConnection::flush( ) + { + } + + void PipeConnection::close() + { + if( 1 == osl_atomic_increment( (&m_nStatus) ) ) + { + m_pipe.close(); + } + } + + OUString PipeConnection::getDescription() + { + return m_sDescription; + } + + /*************** + * PipeAcceptor + **************/ + PipeAcceptor::PipeAcceptor( const OUString &sPipeName , const OUString & sConnectionDescription) : + m_sPipeName( sPipeName ), + m_sConnectionDescription( sConnectionDescription ), + m_bClosed( false ) + { + } + + + void PipeAcceptor::init() + { + m_pipe = Pipe( m_sPipeName.pData , osl_Pipe_CREATE , osl::Security() ); + if( ! m_pipe.is() ) + { + OUString error = "io.acceptor: Couldn't setup pipe " + m_sPipeName; + throw ConnectionSetupException( error ); + } + } + + Reference< XConnection > PipeAcceptor::accept( ) + { + Pipe pipe; + { + std::unique_lock guard( m_mutex ); + pipe = m_pipe; + } + if( ! pipe.is() ) + { + OUString error = "io.acceptor: pipe already closed" + m_sPipeName; + throw ConnectionSetupException( error ); + } + rtl::Reference<PipeConnection> pConn(new PipeConnection( m_sConnectionDescription )); + + oslPipeError status = pipe.accept( pConn->m_pipe ); + + if( m_bClosed ) + { + // stopAccepting was called ! + return Reference < XConnection >(); + } + else if( osl_Pipe_E_None == status ) + { + return pConn; + } + else + { + OUString error = "io.acceptor: Couldn't setup pipe " + m_sPipeName; + throw ConnectionSetupException( error ); + } + } + + void PipeAcceptor::stopAccepting() + { + m_bClosed = true; + Pipe pipe; + { + std::unique_lock guard( m_mutex ); + pipe = m_pipe; + m_pipe.clear(); + } + if( pipe.is() ) + { + pipe.close(); + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/io/source/acceptor/acc_socket.cxx b/io/source/acceptor/acc_socket.cxx new file mode 100644 index 000000000..d52fdc423 --- /dev/null +++ b/io/source/acceptor/acc_socket.cxx @@ -0,0 +1,349 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "acceptor.hxx" + +#include <unordered_set> + +#include <mutex> +#include <rtl/ref.hxx> +#include <com/sun/star/connection/XConnection.hpp> +#include <com/sun/star/connection/XConnectionBroadcaster.hpp> +#include <com/sun/star/connection/ConnectionSetupException.hpp> +#include <com/sun/star/io/IOException.hpp> +#include <cppuhelper/implbase.hxx> + +using namespace ::osl; +using namespace ::cppu; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::io; +using namespace ::com::sun::star::connection; + + +namespace io_acceptor { + + typedef std::unordered_set< css::uno::Reference< css::io::XStreamListener> > + XStreamListener_hash_set; + + namespace { + + class SocketConnection : public ::cppu::WeakImplHelper< + css::connection::XConnection, + css::connection::XConnectionBroadcaster> + + { + public: + explicit SocketConnection( const OUString & sConnectionDescription ); + + virtual sal_Int32 SAL_CALL read( css::uno::Sequence< sal_Int8 >& aReadBytes, + sal_Int32 nBytesToRead ) override; + virtual void SAL_CALL write( const css::uno::Sequence< sal_Int8 >& aData ) override; + virtual void SAL_CALL flush( ) override; + virtual void SAL_CALL close( ) override; + virtual OUString SAL_CALL getDescription( ) override; + + // XConnectionBroadcaster + virtual void SAL_CALL addStreamListener(const css::uno::Reference< css::io::XStreamListener>& aListener) override; + virtual void SAL_CALL removeStreamListener(const css::uno::Reference< css::io::XStreamListener>& aListener) override; + + public: + void completeConnectionString(); + + ::osl::StreamSocket m_socket; + oslInterlockedCount m_nStatus; + OUString m_sDescription; + + std::mutex _mutex; + bool _started; + bool _closed; + bool _error; + XStreamListener_hash_set _listeners; + }; + + } + + template<class T> + static void notifyListeners(SocketConnection * pCon, bool * notified, T t) + { + XStreamListener_hash_set listeners; + + { + std::unique_lock guard(pCon->_mutex); + if(!*notified) + { + *notified = true; + listeners = pCon->_listeners; + } + } + + for(auto& listener : listeners) + t(listener); + } + + static void callStarted(const Reference<XStreamListener>& xStreamListener) + { + xStreamListener->started(); + } + + namespace { + + struct callError { + const Any & any; + + explicit callError(const Any & any); + + void operator () (const Reference<XStreamListener>& xStreamListener); + }; + + } + + callError::callError(const Any & aAny) + : any(aAny) + { + } + + void callError::operator () (const Reference<XStreamListener>& xStreamListener) + { + xStreamListener->error(any); + } + + static void callClosed(const Reference<XStreamListener>& xStreamListener) + { + xStreamListener->closed(); + } + + + SocketConnection::SocketConnection( const OUString &sConnectionDescription) : + m_nStatus( 0 ), + m_sDescription( sConnectionDescription ), + _started(false), + _closed(false), + _error(false) + { + // make it unique + m_sDescription += ",uniqueValue=" ; + m_sDescription += OUString::number( + sal::static_int_cast< sal_Int64 >( + reinterpret_cast< sal_IntPtr >(&m_socket)) ); + } + + void SocketConnection::completeConnectionString() + { + m_sDescription += + ",peerPort=" + OUString::number(m_socket.getPeerPort()) + + ",peerHost=" + m_socket.getPeerHost( ) + + ",localPort=" + OUString::number( m_socket.getLocalPort() ) + + ",localHost=" + m_socket.getLocalHost(); + } + + sal_Int32 SocketConnection::read( Sequence < sal_Int8 > & aReadBytes , sal_Int32 nBytesToRead ) + { + if( ! m_nStatus ) + { + notifyListeners(this, &_started, callStarted); + + if( aReadBytes.getLength() != nBytesToRead ) + { + aReadBytes.realloc( nBytesToRead ); + } + + sal_Int32 i = m_socket.read( + aReadBytes.getArray(), aReadBytes.getLength()); + + if(i != nBytesToRead) + { + OUString message = "acc_socket.cxx:SocketConnection::read: error - " + + m_socket.getErrorAsString(); + + IOException ioException(message, static_cast<XConnection *>(this)); + + Any any; + any <<= ioException; + + notifyListeners(this, &_error, callError(any)); + + throw ioException; + } + + return i; + } + else + { + IOException ioException("acc_socket.cxx:SocketConnection::read: error - connection already closed", static_cast<XConnection *>(this)); + + Any any; + any <<= ioException; + + notifyListeners(this, &_error, callError(any)); + + throw ioException; + } + } + + void SocketConnection::write( const Sequence < sal_Int8 > &seq ) + { + if( ! m_nStatus ) + { + if( m_socket.write( seq.getConstArray() , seq.getLength() ) != seq.getLength() ) + { + OUString message = "acc_socket.cxx:SocketConnection::write: error - " + + m_socket.getErrorAsString(); + + IOException ioException(message, static_cast<XConnection *>(this)); + + Any any; + any <<= ioException; + + notifyListeners(this, &_error, callError(any)); + + throw ioException; + } + } + else + { + IOException ioException("acc_socket.cxx:SocketConnection::write: error - connection already closed", static_cast<XConnection *>(this)); + + Any any; + any <<= ioException; + + notifyListeners(this, &_error, callError(any)); + + throw ioException; + } + } + + void SocketConnection::flush( ) + { + + } + + void SocketConnection::close() + { + // ensure close is called only once + if( 1 == osl_atomic_increment( (&m_nStatus) ) ) + { + m_socket.shutdown(); + notifyListeners(this, &_closed, callClosed); + } + } + + OUString SocketConnection::getDescription() + { + return m_sDescription; + } + + + // XConnectionBroadcaster + void SAL_CALL SocketConnection::addStreamListener(const Reference<XStreamListener> & aListener) + { + std::unique_lock guard(_mutex); + + _listeners.insert(aListener); + } + + void SAL_CALL SocketConnection::removeStreamListener(const Reference<XStreamListener> & aListener) + { + std::unique_lock guard(_mutex); + + _listeners.erase(aListener); + } + + SocketAcceptor::SocketAcceptor( const OUString &sSocketName, + sal_uInt16 nPort, + bool bTcpNoDelay, + const OUString &sConnectionDescription) : + m_sSocketName( sSocketName ), + m_sConnectionDescription( sConnectionDescription ), + m_nPort( nPort ), + m_bTcpNoDelay( bTcpNoDelay ), + m_bClosed( false ) + { + } + + + void SocketAcceptor::init() + { + if( ! m_addr.setPort( m_nPort ) ) + { + throw ConnectionSetupException( + "acc_socket.cxx:SocketAcceptor::init - error - invalid tcp/ip port " + + OUString::number( m_nPort )); + } + if( ! m_addr.setHostname( m_sSocketName.pData ) ) + { + throw ConnectionSetupException( + "acc_socket.cxx:SocketAcceptor::init - error - invalid host " + m_sSocketName ); + } + m_socket.setOption( osl_Socket_OptionReuseAddr, 1); + + if(! m_socket.bind(m_addr) ) + { + throw ConnectionSetupException( + "acc_socket.cxx:SocketAcceptor::init - error - couldn't bind on " + + m_sSocketName + ":" + OUString::number(m_nPort)); + } + + if(! m_socket.listen() ) + { + throw ConnectionSetupException( + "acc_socket.cxx:SocketAcceptor::init - error - can't listen on " + + m_sSocketName + ":" + OUString::number(m_nPort) ); + } + } + + Reference< XConnection > SocketAcceptor::accept( ) + { + rtl::Reference<SocketConnection> pConn(new SocketConnection( m_sConnectionDescription )); + + if( m_socket.acceptConnection( pConn->m_socket )!= osl_Socket_Ok ) + { + // stopAccepting was called + return Reference < XConnection > (); + } + if( m_bClosed ) + { + return Reference < XConnection > (); + } + + pConn->completeConnectionString(); + ::osl::SocketAddr remoteAddr; + pConn->m_socket.getPeerAddr(remoteAddr); + OUString remoteHostname = remoteAddr.getHostname(); + // we enable tcpNoDelay for loopback connections because + // it can make a significant speed difference on linux boxes. + if( m_bTcpNoDelay || remoteHostname == "localhost" || + remoteHostname.startsWith("127.0.0.") ) + { + sal_Int32 nTcpNoDelay = sal_Int32(true); + pConn->m_socket.setOption( osl_Socket_OptionTcpNoDelay , &nTcpNoDelay, + sizeof( nTcpNoDelay ) , osl_Socket_LevelTcp ); + } + + return pConn; + } + + void SocketAcceptor::stopAccepting() + { + m_bClosed = true; + m_socket.close(); + } +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/io/source/acceptor/acceptor.cxx b/io/source/acceptor/acceptor.cxx new file mode 100644 index 000000000..af0883be9 --- /dev/null +++ b/io/source/acceptor/acceptor.cxx @@ -0,0 +1,253 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <cppuhelper/implbase.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <cppuhelper/unourl.hxx> +#include <rtl/malformeduriexception.hxx> + +#include <com/sun/star/connection/AlreadyAcceptingException.hpp> +#include <com/sun/star/connection/ConnectionSetupException.hpp> +#include <com/sun/star/connection/XAcceptor.hpp> +#include <com/sun/star/lang/IllegalArgumentException.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> + +#include "acceptor.hxx" +#include <memory> +#include <mutex> +#include <string_view> + +using namespace ::osl; +using namespace ::cppu; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::connection; + +namespace { + + class OAcceptor : public WeakImplHelper< XAcceptor, XServiceInfo > + { + public: + explicit OAcceptor(const Reference< XComponentContext > & xCtx); + virtual ~OAcceptor() override; + public: + // Methods + virtual Reference< XConnection > SAL_CALL accept( const OUString& sConnectionDescription ) override; + virtual void SAL_CALL stopAccepting( ) override; + + public: // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + virtual sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override; + + private: + std::unique_ptr<io_acceptor::PipeAcceptor> m_pPipe; + std::unique_ptr<io_acceptor::SocketAcceptor> m_pSocket; + std::mutex m_mutex; + OUString m_sLastDescription; + bool m_bInAccept; + + Reference< XMultiComponentFactory > _xSMgr; + Reference< XComponentContext > _xCtx; + Reference<XAcceptor> _xAcceptor; + }; + +} + +OAcceptor::OAcceptor( const Reference< XComponentContext > & xCtx ) + : m_bInAccept( false ) + , _xSMgr( xCtx->getServiceManager() ) + , _xCtx( xCtx ) +{} + +OAcceptor::~OAcceptor() +{ + m_pPipe.reset(); +} + +namespace { +struct BeingInAccept +{ + /// @throws AlreadyAcceptingException + BeingInAccept( bool *pFlag,std::u16string_view sConnectionDescription ) + : m_pFlag( pFlag ) + { + if( *m_pFlag ) + throw AlreadyAcceptingException( OUString::Concat("AlreadyAcceptingException :") + sConnectionDescription ); + *m_pFlag = true; + } + ~BeingInAccept() + { + *m_pFlag = false; + } + bool *m_pFlag; +}; +} + +Reference< XConnection > OAcceptor::accept( const OUString &sConnectionDescription ) +{ + // if there is a thread already accepting in this object, throw an exception. + struct BeingInAccept guard( &m_bInAccept, sConnectionDescription ); + + Reference< XConnection > r; + if( !m_sLastDescription.isEmpty() && + m_sLastDescription != sConnectionDescription ) + { + // instantiate another acceptor for different ports + throw ConnectionSetupException( "acceptor::accept called multiple times with different connection strings\n" ); + } + + if( m_sLastDescription.isEmpty() ) + { + // setup the acceptor + try + { + cppu::UnoUrlDescriptor aDesc(sConnectionDescription); + if ( aDesc.getName() == "pipe" ) + { + OUString aName( + aDesc.getParameter( + "name")); + + m_pPipe.reset(new io_acceptor::PipeAcceptor(aName, sConnectionDescription)); + + try + { + m_pPipe->init(); + } + catch( ... ) + { + { + std::unique_lock g( m_mutex ); + m_pPipe.reset(); + } + throw; + } + } + else if ( aDesc.getName() == "socket" ) + { + OUString aHost; + if (aDesc.hasParameter( + "host")) + aHost = aDesc.getParameter( + "host"); + else + aHost = "localhost"; + sal_uInt16 nPort = static_cast< sal_uInt16 >( + aDesc.getParameter( + "port"). + toInt32()); + bool bTcpNoDelay + = aDesc.getParameter( + "tcpnodelay").toInt32() != 0; + + m_pSocket.reset(new io_acceptor::SocketAcceptor( + aHost, nPort, bTcpNoDelay, sConnectionDescription)); + + try + { + m_pSocket->init(); + } + catch( ... ) + { + { + std::unique_lock g( m_mutex ); + m_pSocket.reset(); + } + throw; + } + } + else + { + OUString delegatee = "com.sun.star.connection.Acceptor." + aDesc.getName(); + _xAcceptor.set(_xSMgr->createInstanceWithContext(delegatee, _xCtx), UNO_QUERY); + + if(!_xAcceptor.is()) + throw ConnectionSetupException("Acceptor: unknown delegatee " + delegatee); + } + } + catch (const rtl::MalformedUriException & rEx) + { + throw IllegalArgumentException( + rEx.getMessage(), + Reference< XInterface > (), + 0 ); + } + m_sLastDescription = sConnectionDescription; + } + + if( m_pPipe ) + { + r = m_pPipe->accept(); + } + else if( m_pSocket ) + { + r = m_pSocket->accept(); + } + else + { + r = _xAcceptor->accept(sConnectionDescription); + } + + return r; +} + +void SAL_CALL OAcceptor::stopAccepting( ) +{ + std::unique_lock guard( m_mutex ); + + if( m_pPipe ) + { + m_pPipe->stopAccepting(); + } + else if ( m_pSocket ) + { + m_pSocket->stopAccepting(); + } + else if( _xAcceptor.is() ) + { + _xAcceptor->stopAccepting(); + } + +} + +OUString OAcceptor::getImplementationName() +{ + return "com.sun.star.comp.io.Acceptor"; +} + +sal_Bool OAcceptor::supportsService(const OUString& ServiceName) +{ + return cppu::supportsService(this, ServiceName); +} + +Sequence< OUString > OAcceptor::getSupportedServiceNames() +{ + return { "com.sun.star.connection.Acceptor" }; +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +io_OAcceptor_get_implementation( + css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const&) +{ + return cppu::acquire(new OAcceptor(context)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/io/source/acceptor/acceptor.hxx b/io/source/acceptor/acceptor.hxx new file mode 100644 index 000000000..9214a10b7 --- /dev/null +++ b/io/source/acceptor/acceptor.hxx @@ -0,0 +1,74 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <osl/pipe.hxx> +#include <osl/socket.hxx> +#include <mutex> + +#include <com/sun/star/uno/Reference.hxx> + +namespace com::sun::star::connection { class XConnection; } + +namespace io_acceptor { + + class PipeAcceptor + { + public: + PipeAcceptor( const OUString &sPipeName , const OUString &sConnectionDescription ); + + void init(); + css::uno::Reference < css::connection::XConnection > accept( ); + + void stopAccepting(); + + std::mutex m_mutex; + ::osl::Pipe m_pipe; + OUString m_sPipeName; + OUString m_sConnectionDescription; + bool m_bClosed; + }; + + class SocketAcceptor + { + public: + SocketAcceptor( const OUString & sSocketName , + sal_uInt16 nPort, + bool bTcpNoDelay, + const OUString &sConnectionDescription ); + + void init(); + css::uno::Reference < css::connection::XConnection > accept(); + + void stopAccepting(); + + ::osl::SocketAddr m_addr; + ::osl::AcceptorSocket m_socket; + OUString m_sSocketName; + OUString m_sConnectionDescription; + sal_uInt16 m_nPort; + bool m_bTcpNoDelay; + bool m_bClosed; + }; + +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/io/source/connector/connector.cxx b/io/source/connector/connector.cxx new file mode 100644 index 000000000..15720b242 --- /dev/null +++ b/io/source/connector/connector.cxx @@ -0,0 +1,178 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <osl/security.hxx> +#include <sal/log.hxx> + +#include <cppuhelper/implbase.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <cppuhelper/unourl.hxx> +#include <rtl/malformeduriexception.hxx> +#include <rtl/ref.hxx> +#include <o3tl/string_view.hxx> + +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/connection/ConnectionSetupException.hpp> +#include <com/sun/star/connection/NoConnectException.hpp> +#include <com/sun/star/connection/XConnector.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> + +#include "connector.hxx" + +using namespace ::osl; +using namespace ::cppu; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::connection; + +namespace { + + class OConnector : public WeakImplHelper< XConnector, XServiceInfo > + { + Reference< XMultiComponentFactory > _xSMgr; + Reference< XComponentContext > _xCtx; + public: + explicit OConnector(const Reference< XComponentContext > &xCtx); + + // Methods + virtual Reference< XConnection > SAL_CALL connect( + const OUString& sConnectionDescription ) override; + + public: // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + virtual sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override; + }; + +} + +OConnector::OConnector(const Reference< XComponentContext > &xCtx) + : _xSMgr( xCtx->getServiceManager() ) + , _xCtx( xCtx ) +{} + +Reference< XConnection > SAL_CALL OConnector::connect( const OUString& sConnectionDescription ) +{ + // split string into tokens + try + { + cppu::UnoUrlDescriptor aDesc(sConnectionDescription); + + Reference< XConnection > r; + if ( aDesc.getName() == "pipe" ) + { + OUString aName(aDesc.getParameter("name")); + + rtl::Reference<stoc_connector::PipeConnection> pConn(new stoc_connector::PipeConnection( sConnectionDescription )); + + if( pConn->m_pipe.create( aName.pData, osl_Pipe_OPEN, osl::Security() ) ) + { + r = pConn; + } + else + { + OUString const sMessage( + "Connector : couldn't connect to pipe \"" + aName + "\": " + + OUString::number(pConn->m_pipe.getError())); + SAL_WARN("io.connector", sMessage); + throw NoConnectException( sMessage ); + } + } + else if ( aDesc.getName() == "socket" ) + { + OUString aHost; + if (aDesc.hasParameter("host")) + aHost = aDesc.getParameter("host"); + else + aHost = "localhost"; + sal_uInt16 nPort = static_cast< sal_uInt16 >( + aDesc.getParameter("port"). + toInt32()); + bool bTcpNoDelay + = aDesc.getParameter("tcpnodelay").toInt32() != 0; + + rtl::Reference<stoc_connector::SocketConnection> pConn(new stoc_connector::SocketConnection( sConnectionDescription)); + + SocketAddr AddrTarget( aHost.pData, nPort ); + if(pConn->m_socket.connect(AddrTarget) != osl_Socket_Ok) + { + OUString sMessage("Connector : couldn't connect to socket ("); + OUString sError = pConn->m_socket.getErrorAsString(); + sMessage += sError + ")"; + throw NoConnectException( sMessage ); + } + // we enable tcpNoDelay for loopback connections because + // it can make a significant speed difference on linux boxes. + if( bTcpNoDelay || aHost == "localhost" || aHost.startsWith("127.0.0.") ) + { + sal_Int32 nTcpNoDelay = sal_Int32(true); + pConn->m_socket.setOption( osl_Socket_OptionTcpNoDelay , &nTcpNoDelay, + sizeof( nTcpNoDelay ) , osl_Socket_LevelTcp ); + } + pConn->completeConnectionString(); + r = pConn; + } + else + { + OUString delegatee= "com.sun.star.connection.Connector." + aDesc.getName(); + + Reference<XConnector> xConnector( + _xSMgr->createInstanceWithContext(delegatee, _xCtx), UNO_QUERY ); + + if(!xConnector.is()) + throw ConnectionSetupException("Connector: unknown delegatee " + delegatee); + + sal_Int32 index = sConnectionDescription.indexOf(','); + + r = xConnector->connect(OUString(o3tl::trim(sConnectionDescription.subView(index + 1)))); + } + return r; + } + catch (const rtl::MalformedUriException & rEx) + { + throw ConnectionSetupException(rEx.getMessage()); + } +} + +OUString OConnector::getImplementationName() +{ + return "com.sun.star.comp.io.Connector"; +} + +sal_Bool OConnector::supportsService(const OUString& ServiceName) +{ + return cppu::supportsService(this, ServiceName); +} + +Sequence< OUString > OConnector::getSupportedServiceNames() +{ + return { "com.sun.star.connection.Connector" }; +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +io_OConnector_get_implementation( + css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const&) +{ + return cppu::acquire(new OConnector(context)); +} + + + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/io/source/connector/connector.hxx b/io/source/connector/connector.hxx new file mode 100644 index 000000000..691fc7a88 --- /dev/null +++ b/io/source/connector/connector.hxx @@ -0,0 +1,94 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <cppuhelper/implbase.hxx> + +#include <com/sun/star/connection/XConnection.hpp> +#include <com/sun/star/connection/XConnectionBroadcaster.hpp> + +#include <unordered_set> +#include <osl/socket.hxx> +#include <osl/pipe.hxx> +#include <mutex> + +namespace stoc_connector +{ + typedef std::unordered_set< css::uno::Reference< css::io::XStreamListener> > + XStreamListener_hash_set; + + class PipeConnection : + public ::cppu::WeakImplHelper< css::connection::XConnection > + + { + public: + explicit PipeConnection( const OUString &sConnectionDescription ); + virtual ~PipeConnection() override; + + virtual sal_Int32 SAL_CALL read( css::uno::Sequence< sal_Int8 >& aReadBytes, + sal_Int32 nBytesToRead ) override; + virtual void SAL_CALL write( const css::uno::Sequence< sal_Int8 >& aData ) override; + virtual void SAL_CALL flush( ) override; + virtual void SAL_CALL close( ) override; + virtual OUString SAL_CALL getDescription( ) override; + public: + ::osl::StreamPipe m_pipe; + oslInterlockedCount m_nStatus; + OUString m_sDescription; + }; + + class SocketConnection : + public ::cppu::WeakImplHelper< css::connection::XConnection, css::connection::XConnectionBroadcaster > + + { + public: + explicit SocketConnection( const OUString & sConnectionDescription ); + virtual ~SocketConnection() override; + + virtual sal_Int32 SAL_CALL read( css::uno::Sequence< sal_Int8 >& aReadBytes, + sal_Int32 nBytesToRead ) override; + virtual void SAL_CALL write( const css::uno::Sequence< sal_Int8 >& aData ) override; + virtual void SAL_CALL flush( ) override; + virtual void SAL_CALL close( ) override; + virtual OUString SAL_CALL getDescription( ) override; + + + // XConnectionBroadcaster + virtual void SAL_CALL addStreamListener(const css::uno::Reference< css::io::XStreamListener>& aListener) override; + virtual void SAL_CALL removeStreamListener(const css::uno::Reference< css::io::XStreamListener>& aListener) override; + + public: + void completeConnectionString(); + + ::osl::ConnectorSocket m_socket; + oslInterlockedCount m_nStatus; + OUString m_sDescription; + + std::mutex _mutex; + bool _started; + bool _closed; + bool _error; + + XStreamListener_hash_set _listeners; + }; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/io/source/connector/ctr_pipe.cxx b/io/source/connector/ctr_pipe.cxx new file mode 100644 index 000000000..5ee0b70bc --- /dev/null +++ b/io/source/connector/ctr_pipe.cxx @@ -0,0 +1,97 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <sal/config.h> + +#include <com/sun/star/io/IOException.hpp> + +#include "connector.hxx" +#include <osl/pipe.hxx> + +using namespace ::osl; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::io; +using namespace ::com::sun::star::connection; + + +namespace stoc_connector { + + PipeConnection::PipeConnection( const OUString & sConnectionDescription ) : + m_nStatus( 0 ), + m_sDescription( sConnectionDescription ) + { + // make it unique + m_sDescription += ",uniqueValue="; + m_sDescription += OUString::number( + sal::static_int_cast< sal_Int64 >( + reinterpret_cast< sal_IntPtr >(&m_pipe)) ); + } + + PipeConnection::~PipeConnection() + { + } + + sal_Int32 PipeConnection::read( Sequence < sal_Int8 > & aReadBytes , sal_Int32 nBytesToRead ) + { + if( m_nStatus ) + { + throw IOException("pipe already closed"); + } + if( aReadBytes.getLength() != nBytesToRead ) + { + aReadBytes.realloc( nBytesToRead ); + } + return m_pipe.read( aReadBytes.getArray() , aReadBytes.getLength() ); + + } + + void PipeConnection::write( const Sequence < sal_Int8 > &seq ) + { + if( m_nStatus ) + { + throw IOException("pipe already closed"); + } + if( m_pipe.write( seq.getConstArray() , seq.getLength() ) != seq.getLength() ) + { + throw IOException("short write"); + } + } + + void PipeConnection::flush( ) + { + + } + + void PipeConnection::close() + { + // ensure that close is called only once + if(1 == osl_atomic_increment( (&m_nStatus) ) ) + { + m_pipe.close(); + } + } + + OUString PipeConnection::getDescription() + { + return m_sDescription; + } + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/io/source/connector/ctr_socket.cxx b/io/source/connector/ctr_socket.cxx new file mode 100644 index 000000000..dcdeef07f --- /dev/null +++ b/io/source/connector/ctr_socket.cxx @@ -0,0 +1,225 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include "connector.hxx" +#include <com/sun/star/io/IOException.hpp> + +using namespace ::osl; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::io; +using namespace ::com::sun::star::connection; + + +namespace stoc_connector { + template<class T> + static void notifyListeners(SocketConnection * pCon, bool * notified, T t) + { + XStreamListener_hash_set listeners; + + { + std::unique_lock guard(pCon->_mutex); + if(!*notified) + { + *notified = true; + listeners = pCon->_listeners; + } + } + + for(auto& listener : listeners) + t(listener); + } + + + static void callStarted(const Reference<XStreamListener>& xStreamListener) + { + xStreamListener->started(); + } + + namespace { + + struct callError { + const Any & any; + + explicit callError(const Any & any); + + void operator () (const Reference<XStreamListener>& xStreamListener); + }; + + } + + callError::callError(const Any & aAny) + : any(aAny) + { + } + + void callError::operator () (const Reference<XStreamListener>& xStreamListener) + { + xStreamListener->error(any); + } + + static void callClosed(const Reference<XStreamListener>& xStreamListener) + { + xStreamListener->closed(); + } + + + SocketConnection::SocketConnection( const OUString &sConnectionDescription ) : + m_nStatus( 0 ), + m_sDescription( sConnectionDescription ), + _started(false), + _closed(false), + _error(false) + { + // make it unique + m_sDescription += ",uniqueValue="; + m_sDescription += OUString::number( + sal::static_int_cast< sal_Int64 >( + reinterpret_cast< sal_IntPtr >(&m_socket)) ); + } + + SocketConnection::~SocketConnection() + { + } + + void SocketConnection::completeConnectionString() + { + sal_Int32 nPort; + + nPort = m_socket.getPeerPort(); + + m_sDescription += + ",peerPort=" + OUString::number( nPort ) + + ",peerHost=" + m_socket.getPeerHost() + + ",localPort=" + OUString::number( nPort ) + + ",localHost=" + m_socket.getLocalHost( ); + } + + sal_Int32 SocketConnection::read( Sequence < sal_Int8 > & aReadBytes , sal_Int32 nBytesToRead ) + { + if( ! m_nStatus ) + { + notifyListeners(this, &_started, callStarted); + + if( aReadBytes.getLength() != nBytesToRead ) + { + aReadBytes.realloc( nBytesToRead ); + } + sal_Int32 i = m_socket.read( aReadBytes.getArray() , aReadBytes.getLength() ); + + if(i != nBytesToRead && m_socket.getError() != osl_Socket_E_None) + { + OUString message = "ctr_socket.cxx:SocketConnection::read: error - " + + m_socket.getErrorAsString(); + + IOException ioException(message, static_cast<XConnection *>(this)); + + Any any; + any <<= ioException; + + notifyListeners(this, &_error, callError(any)); + + throw ioException; + } + + return i; + } + else + { + IOException ioException("ctr_socket.cxx:SocketConnection::read: error - connection already closed", static_cast<XConnection *>(this)); + + Any any; + any <<= ioException; + + notifyListeners(this, &_error, callError(any)); + + throw ioException; + } + } + + void SocketConnection::write( const Sequence < sal_Int8 > &seq ) + { + if( ! m_nStatus ) + { + if( m_socket.write( seq.getConstArray() , seq.getLength() ) != seq.getLength() ) + { + OUString message = "ctr_socket.cxx:SocketConnection::write: error - " + + m_socket.getErrorAsString(); + + IOException ioException(message, static_cast<XConnection *>(this)); + + Any any; + any <<= ioException; + + notifyListeners(this, &_error, callError(any)); + + throw ioException; + } + } + else + { + IOException ioException("ctr_socket.cxx:SocketConnection::write: error - connection already closed", static_cast<XConnection *>(this)); + + Any any; + any <<= ioException; + + notifyListeners(this, &_error, callError(any)); + + throw ioException; + } + } + + void SocketConnection::flush( ) + { + + } + + void SocketConnection::close() + { + // ensure that close is called only once + if( 1 == osl_atomic_increment( (&m_nStatus) ) ) + { + m_socket.shutdown(); + notifyListeners(this, &_closed, callClosed); + } + } + + OUString SocketConnection::getDescription() + { + return m_sDescription; + } + + + // XConnectionBroadcaster + void SAL_CALL SocketConnection::addStreamListener(const Reference<XStreamListener> & aListener) + { + std::unique_lock guard(_mutex); + + _listeners.insert(aListener); + } + + void SAL_CALL SocketConnection::removeStreamListener(const Reference<XStreamListener> & aListener) + { + std::unique_lock guard(_mutex); + + _listeners.erase(aListener); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/io/source/io.component b/io/source/io.component new file mode 100644 index 000000000..a5712c0f6 --- /dev/null +++ b/io/source/io.component @@ -0,0 +1,70 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + --> + +<component loader="com.sun.star.loader.SharedLibrary" environment="@CPPU_ENV@" + xmlns="http://openoffice.org/2010/uno-components"> + <implementation name="com.sun.star.comp.io.Pump" + constructor="io_Pump_get_implementation"> + <service name="com.sun.star.io.Pump"/> + </implementation> + <implementation name="com.sun.star.comp.io.stm.DataInputStream" + constructor="io_ODataInputStream_get_implementation"> + <service name="com.sun.star.io.DataInputStream"/> + </implementation> + <implementation name="com.sun.star.comp.io.stm.DataOutputStream" + constructor="io_ODataOutputStream_get_implementation"> + <service name="com.sun.star.io.DataOutputStream"/> + </implementation> + <implementation name="com.sun.star.comp.io.stm.MarkableInputStream" + constructor="io_OMarkableInputStream_get_implementation"> + <service name="com.sun.star.io.MarkableInputStream"/> + </implementation> + <implementation name="com.sun.star.comp.io.stm.MarkableOutputStream" + constructor="io_OMarkableOutputStream_get_implementation"> + <service name="com.sun.star.io.MarkableOutputStream"/> + </implementation> + <implementation name="com.sun.star.comp.io.stm.ObjectInputStream" + constructor="io_OObjectInputStream_get_implementation"> + <service name="com.sun.star.io.ObjectInputStream"/> + </implementation> + <implementation name="com.sun.star.comp.io.stm.ObjectOutputStream" + constructor="io_OObjectOutputStream_get_implementation"> + <service name="com.sun.star.io.ObjectOutputStream"/> + </implementation> + <implementation name="com.sun.star.comp.io.stm.Pipe" + constructor="io_OPipeImpl_get_implementation"> + <service name="com.sun.star.io.Pipe"/> + </implementation> + <implementation name="com.sun.star.comp.io.Acceptor" + constructor="io_OAcceptor_get_implementation"> + <service name="com.sun.star.connection.Acceptor"/> + </implementation> + <implementation name="com.sun.star.comp.io.Connector" + constructor="io_OConnector_get_implementation"> + <service name="com.sun.star.connection.Connector"/> + </implementation> + <implementation name="com.sun.star.comp.io.TextInputStream" + constructor="io_OTextInputStream_get_implementation"> + <service name="com.sun.star.io.TextInputStream"/> + </implementation> + <implementation name="com.sun.star.comp.io.TextOutputStream" + constructor="io_OTextOutputStream_get_implementation"> + <service name="com.sun.star.io.TextOutputStream"/> + </implementation> +</component> diff --git a/io/source/stm/odata.cxx b/io/source/stm/odata.cxx new file mode 100644 index 000000000..754cda450 --- /dev/null +++ b/io/source/stm/odata.cxx @@ -0,0 +1,1231 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <string.h> +#include <unordered_map> +#include <vector> + +#include <cppuhelper/weak.hxx> +#include <cppuhelper/implbase.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <osl/endian.h> +#include <tools/long.hxx> + +#include <com/sun/star/io/NotConnectedException.hpp> +#include <com/sun/star/io/XObjectInputStream.hpp> +#include <com/sun/star/io/XObjectOutputStream.hpp> +#include <com/sun/star/io/XActiveDataSource.hpp> +#include <com/sun/star/io/XActiveDataSink.hpp> +#include <com/sun/star/io/XMarkableStream.hpp> +#include <com/sun/star/io/XConnectable.hpp> +#include <com/sun/star/io/UnexpectedEOFException.hpp> +#include <com/sun/star/io/WrongFormatException.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> + +using namespace ::cppu; +using namespace ::osl; +using namespace ::std; +using namespace ::com::sun::star::io; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; + +namespace io_stm { + +namespace { + +class ODataInputStream : + public WeakImplHelper < + XDataInputStream, + XActiveDataSink, + XConnectable, + XServiceInfo + > +{ +public: + ODataInputStream( ) + : m_bValidStream( false ) + { + } + +public: // XInputStream + virtual sal_Int32 SAL_CALL readBytes(Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead) override; + virtual sal_Int32 SAL_CALL readSomeBytes(Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead) override; + virtual void SAL_CALL skipBytes(sal_Int32 nBytesToSkip) override; + virtual sal_Int32 SAL_CALL available() override; + virtual void SAL_CALL closeInput() override; + +public: // XDataInputStream + virtual sal_Int8 SAL_CALL readBoolean() override; + virtual sal_Int8 SAL_CALL readByte() override; + virtual sal_Unicode SAL_CALL readChar() override; + virtual sal_Int16 SAL_CALL readShort() override; + virtual sal_Int32 SAL_CALL readLong() override; + virtual sal_Int64 SAL_CALL readHyper() override; + virtual float SAL_CALL readFloat() override; + virtual double SAL_CALL readDouble() override; + virtual OUString SAL_CALL readUTF() override; + + +public: // XActiveDataSink + virtual void SAL_CALL setInputStream(const Reference< XInputStream > & aStream) override; + virtual Reference< XInputStream > SAL_CALL getInputStream() override; + +public: // XConnectable + virtual void SAL_CALL setPredecessor(const Reference < XConnectable >& aPredecessor) override; + virtual Reference < XConnectable > SAL_CALL getPredecessor() override; + virtual void SAL_CALL setSuccessor(const Reference < XConnectable >& aSuccessor) override; + virtual Reference < XConnectable > SAL_CALL getSuccessor() override ; + + +public: // XServiceInfo + OUString SAL_CALL getImplementationName() override; + Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override; + +protected: + + Reference < XConnectable > m_pred; + Reference < XConnectable > m_succ; + Reference < XInputStream > m_input; + bool m_bValidStream; +}; + +} + +// XInputStream +sal_Int32 ODataInputStream::readBytes(Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead) +{ + if( !m_bValidStream ) + { + throw NotConnectedException( ); + } + sal_Int32 nRead = m_input->readBytes( aData , nBytesToRead ); + return nRead; +} + +sal_Int32 ODataInputStream::readSomeBytes(Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead) +{ + if( !m_bValidStream ) + throw NotConnectedException( ); + sal_Int32 nRead = m_input->readSomeBytes( aData , nMaxBytesToRead ); + return nRead; +} +void ODataInputStream::skipBytes(sal_Int32 nBytesToSkip) +{ + if( !m_bValidStream ) + throw NotConnectedException( ); + m_input->skipBytes( nBytesToSkip ); +} + + +sal_Int32 ODataInputStream::available() +{ + if( !m_bValidStream ) + throw NotConnectedException( ); + sal_Int32 nAvail = m_input->available( ); + return nAvail; +} + +void ODataInputStream::closeInput() +{ + if( !m_bValidStream ) + throw NotConnectedException( ); + m_input->closeInput( ); + setInputStream( Reference< XInputStream > () ); + setPredecessor( Reference < XConnectable >() ); + setSuccessor( Reference < XConnectable >() ); + m_bValidStream = false; +} + + +//== XDataInputStream =========================================== + +// XDataInputStream +sal_Int8 ODataInputStream::readBoolean() +{ + return readByte(); +} + +sal_Int8 ODataInputStream::readByte() +{ + Sequence<sal_Int8> aTmp(1); + if( 1 != readBytes( aTmp, 1 ) ) + { + throw UnexpectedEOFException(); + } + return aTmp.getConstArray()[0]; +} + +sal_Unicode ODataInputStream::readChar() +{ + Sequence<sal_Int8> aTmp(2); + if( 2 != readBytes( aTmp, 2 ) ) + { + throw UnexpectedEOFException(); + } + + const sal_uInt8 * pBytes = reinterpret_cast<const sal_uInt8 *>(aTmp.getConstArray()); + return (static_cast<sal_Unicode>(pBytes[0]) << 8) + pBytes[1]; +} + +sal_Int16 ODataInputStream::readShort() +{ + Sequence<sal_Int8> aTmp(2); + if( 2 != readBytes( aTmp, 2 ) ) + { + throw UnexpectedEOFException(); + } + + const sal_uInt8 * pBytes = reinterpret_cast<const sal_uInt8 *>(aTmp.getConstArray()); + return (static_cast<sal_Int16>(pBytes[0]) << 8) + pBytes[1]; +} + + +sal_Int32 ODataInputStream::readLong() +{ + Sequence<sal_Int8> aTmp(4); + if( 4 != readBytes( aTmp, 4 ) ) + { + throw UnexpectedEOFException( ); + } + + const sal_uInt8 * pBytes = reinterpret_cast<const sal_uInt8 *>(aTmp.getConstArray()); + return (static_cast<sal_Int32>(pBytes[0]) << 24) + (static_cast<sal_Int32>(pBytes[1]) << 16) + (static_cast<sal_Int32>(pBytes[2]) << 8) + pBytes[3]; +} + + +sal_Int64 ODataInputStream::readHyper() +{ + Sequence<sal_Int8> aTmp(8); + if( 8 != readBytes( aTmp, 8 ) ) + { + throw UnexpectedEOFException( ); + } + + const sal_uInt8 * pBytes = reinterpret_cast<const sal_uInt8 *>(aTmp.getConstArray()); + return + (static_cast<sal_Int64>(pBytes[0]) << 56) + + (static_cast<sal_Int64>(pBytes[1]) << 48) + + (static_cast<sal_Int64>(pBytes[2]) << 40) + + (static_cast<sal_Int64>(pBytes[3]) << 32) + + (static_cast<sal_Int64>(pBytes[4]) << 24) + + (static_cast<sal_Int64>(pBytes[5]) << 16) + + (static_cast<sal_Int64>(pBytes[6]) << 8) + + pBytes[7]; +} + +float ODataInputStream::readFloat() +{ + union { float f; sal_uInt32 n; } a; + a.n = readLong(); + return a.f; +} + +double ODataInputStream::readDouble() +{ + union { double d; struct { sal_uInt32 n1; sal_uInt32 n2; } ad; } a; +#if defined OSL_LITENDIAN + a.ad.n2 = readLong(); + a.ad.n1 = readLong(); +#else + a.ad.n1 = readLong(); + a.ad.n2 = readLong(); +#endif + return a.d; +} + +OUString ODataInputStream::readUTF() +{ + sal_uInt16 nShortLen = static_cast<sal_uInt16>(readShort()); + sal_Int32 nUTFLen; + + if( (sal_uInt16(0xffff)) == nShortLen ) + { + // is interpreted as a sign, that string is longer than 64k + // incompatible to older XDataInputStream-routines, when strings are exactly 64k + nUTFLen = readLong(); + } + else + { + nUTFLen = static_cast<sal_Int32>(nShortLen); + } + + Sequence<sal_Unicode> aBuffer( nUTFLen ); + sal_Unicode * pStr = aBuffer.getArray(); + + sal_Int32 nCount = 0; + sal_Int32 nStrLen = 0; + while( nCount < nUTFLen ) + { + sal_uInt8 c = static_cast<sal_uInt8>(readByte()); + sal_uInt8 char2, char3; + switch( c >> 4 ) + { + case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: + // 0xxxxxxx + nCount++; + pStr[nStrLen++] = c; + break; + + case 12: case 13: + // 110x xxxx 10xx xxxx + nCount += 2; + if( nCount > nUTFLen ) + { + throw WrongFormatException( ); + } + + char2 = static_cast<sal_uInt8>(readByte()); + if( (char2 & 0xC0) != 0x80 ) + { + throw WrongFormatException( ); + } + + pStr[nStrLen++] = (sal_Unicode(c & 0x1F) << 6) | (char2 & 0x3F); + break; + + case 14: + // 1110 xxxx 10xx xxxx 10xx xxxx + nCount += 3; + if( nCount > nUTFLen ) + { + throw WrongFormatException( ); + } + + char2 = static_cast<sal_uInt8>(readByte()); + char3 = static_cast<sal_uInt8>(readByte()); + + if( ((char2 & 0xC0) != 0x80) || ((char3 & 0xC0) != 0x80) ) { + throw WrongFormatException( ); + } + pStr[nStrLen++] = (sal_Unicode(c & 0x0F) << 12) | + (sal_Unicode(char2 & 0x3F) << 6) | + (char3 & 0x3F); + break; + + default: + // 10xx xxxx, 1111 xxxx + throw WrongFormatException(); + //throw new UTFDataFormatException(); + } + } + return OUString( pStr, nStrLen ); +} + + +// XActiveDataSource +void ODataInputStream::setInputStream(const Reference< XInputStream > & aStream) +{ + + if( m_input != aStream ) { + m_input = aStream; + + Reference < XConnectable > pred( m_input , UNO_QUERY ); + setPredecessor( pred ); + } + + m_bValidStream = m_input.is(); +} + +Reference< XInputStream > ODataInputStream::getInputStream() +{ + return m_input; +} + + +// XDataSink +void ODataInputStream::setSuccessor( const Reference < XConnectable > &r ) +{ + /// if the references match, nothing needs to be done + if( m_succ != r ) { + /// store the reference for later use + m_succ = r; + + if( m_succ.is() ) { + /// set this instance as the sink ! + m_succ->setPredecessor( Reference< XConnectable > ( + static_cast< XConnectable * >(this) ) ); + } + } +} + +Reference < XConnectable > ODataInputStream::getSuccessor() +{ + return m_succ; +} + + +// XDataSource +void ODataInputStream::setPredecessor( const Reference < XConnectable > &r ) +{ + if( r != m_pred ) { + m_pred = r; + if( m_pred.is() ) { + m_pred->setSuccessor( Reference< XConnectable > ( + static_cast< XConnectable * >(this) ) ); + } + } +} +Reference < XConnectable > ODataInputStream::getPredecessor() +{ + return m_pred; +} + +// XServiceInfo +OUString ODataInputStream::getImplementationName() +{ + return "com.sun.star.comp.io.stm.DataInputStream"; +} + +// XServiceInfo +sal_Bool ODataInputStream::supportsService(const OUString& ServiceName) +{ + return cppu::supportsService(this, ServiceName); +} + +// XServiceInfo +Sequence< OUString > ODataInputStream::getSupportedServiceNames() +{ + return { "com.sun.star.io.DataInputStream" }; +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +io_ODataInputStream_get_implementation( + css::uno::XComponentContext* , css::uno::Sequence<css::uno::Any> const&) +{ + return cppu::acquire(new ODataInputStream()); +} + +namespace { + +class ODataOutputStream : + public WeakImplHelper < + XDataOutputStream, + XActiveDataSource, + XConnectable, + XServiceInfo > +{ +public: + ODataOutputStream() + : m_bValidStream( false ) + { + } + +public: // XOutputStream + virtual void SAL_CALL writeBytes(const Sequence< sal_Int8 >& aData) override; + virtual void SAL_CALL flush() override; + virtual void SAL_CALL closeOutput() override; + +public: // XDataOutputStream + virtual void SAL_CALL writeBoolean(sal_Bool Value) override; + virtual void SAL_CALL writeByte(sal_Int8 Value) override; + virtual void SAL_CALL writeChar(sal_Unicode Value) override; + virtual void SAL_CALL writeShort(sal_Int16 Value) override; + virtual void SAL_CALL writeLong(sal_Int32 Value) override; + virtual void SAL_CALL writeHyper(sal_Int64 Value) override; + virtual void SAL_CALL writeFloat(float Value) override; + virtual void SAL_CALL writeDouble(double Value) override; + virtual void SAL_CALL writeUTF(const OUString& Value) override; + +public: // XActiveDataSource + virtual void SAL_CALL setOutputStream(const Reference< XOutputStream > & aStream) override; + virtual Reference < XOutputStream > SAL_CALL getOutputStream() override; + +public: // XConnectable + virtual void SAL_CALL setPredecessor(const Reference < XConnectable >& aPredecessor) override; + virtual Reference < XConnectable > SAL_CALL getPredecessor() override; + virtual void SAL_CALL setSuccessor(const Reference < XConnectable >& aSuccessor) override; + virtual Reference < XConnectable > SAL_CALL getSuccessor() override; + +public: // XServiceInfo + OUString SAL_CALL getImplementationName() override; + Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override; + +protected: + Reference < XConnectable > m_succ; + Reference < XConnectable > m_pred; + Reference< XOutputStream > m_output; + bool m_bValidStream; +}; + +} + +// XOutputStream +void ODataOutputStream::writeBytes(const Sequence< sal_Int8 >& aData) +{ + if( !m_bValidStream ) + throw NotConnectedException( ); + m_output->writeBytes( aData ); +} + +void ODataOutputStream::flush() +{ + if( !m_bValidStream ) + throw NotConnectedException(); + m_output->flush(); +} + + +void ODataOutputStream::closeOutput() +{ + if( !m_bValidStream ) + throw NotConnectedException(); + m_output->closeOutput(); + setOutputStream( Reference< XOutputStream > () ); + setPredecessor( Reference < XConnectable >() ); + setSuccessor( Reference < XConnectable >() ); +} + +// XDataOutputStream +void ODataOutputStream::writeBoolean(sal_Bool Value) +{ + if( Value ) + { + writeByte( 1 ); + } + else + { + writeByte( 0 ); + } +} + + +void ODataOutputStream::writeByte(sal_Int8 Value) +{ + writeBytes( { Value } ); +} + +void ODataOutputStream::writeChar(sal_Unicode Value) +{ + writeBytes( { sal_Int8(Value >> 8), + sal_Int8(Value) } ); +} + + +void ODataOutputStream::writeShort(sal_Int16 Value) +{ + writeBytes( { sal_Int8(Value >> 8), + sal_Int8(Value) } ); +} + +void ODataOutputStream::writeLong(sal_Int32 Value) +{ + writeBytes( { sal_Int8(Value >> 24), + sal_Int8(Value >> 16), + sal_Int8(Value >> 8), + sal_Int8(Value) } ); +} + +void ODataOutputStream::writeHyper(sal_Int64 Value) +{ + writeBytes( { sal_Int8(Value >> 56), + sal_Int8(Value >> 48), + sal_Int8(Value >> 40), + sal_Int8(Value >> 32), + sal_Int8(Value >> 24), + sal_Int8(Value >> 16), + sal_Int8(Value >> 8), + sal_Int8(Value) } ); +} + + +void ODataOutputStream::writeFloat(float Value) +{ + union { float f; sal_uInt32 n; } a; + a.f = Value; + writeLong( a.n ); +} + +void ODataOutputStream::writeDouble(double Value) +{ + union { double d; struct { sal_uInt32 n1; sal_uInt32 n2; } ad; } a; + a.d = Value; +#if defined OSL_LITENDIAN + writeLong( a.ad.n2 ); + writeLong( a.ad.n1 ); +#else + writeLong( a.ad.n1 ); + writeLong( a.ad.n2 ); +#endif +} + +void ODataOutputStream::writeUTF(const OUString& Value) +{ + sal_Int32 nStrLen = Value.getLength(); + const sal_Unicode * pStr = Value.getStr(); + sal_Int32 nUTFLen = 0; + sal_Int32 i; + + for( i = 0 ; i < nStrLen ; i++ ) + { + sal_uInt16 c = pStr[i]; + if( (c >= 0x0001) && (c <= 0x007F) ) + { + nUTFLen++; + } + else if( c > 0x07FF ) + { + nUTFLen += 3; + } + else + { + nUTFLen += 2; + } + } + + + // compatibility mode for older implementations, where it was not possible + // to write blocks bigger than 64 k. Note that there is a tradeoff. Blocks, + // that are exactly 64k long can not be read by older routines when written + // with these routines and the other way round !!!!! + if( nUTFLen >= 0xFFFF ) { + writeShort( sal_Int16(-1) ); + writeLong( nUTFLen ); + } + else { + writeShort( static_cast<sal_uInt16>(nUTFLen) ); + } + for( i = 0 ; i < nStrLen ; i++ ) + { + sal_uInt16 c = pStr[i]; + if( (c >= 0x0001) && (c <= 0x007F) ) + { + writeByte(sal_Int8(c)); + } + else if( c > 0x07FF ) + { + writeByte(sal_Int8(0xE0 | ((c >> 12) & 0x0F))); + writeByte(sal_Int8(0x80 | ((c >> 6) & 0x3F))); + writeByte(sal_Int8(0x80 | ((c >> 0) & 0x3F))); + } + else + { + writeByte(sal_Int8(0xC0 | ((c >> 6) & 0x1F))); + writeByte(sal_Int8(0x80 | ((c >> 0) & 0x3F))); + } + } +} + +// XActiveDataSource +void ODataOutputStream::setOutputStream(const Reference< XOutputStream > & aStream) +{ + if( m_output != aStream ) { + m_output = aStream; + m_bValidStream = m_output.is(); + + Reference < XConnectable > succ( m_output , UNO_QUERY ); + setSuccessor( succ ); + } +} + +Reference< XOutputStream > ODataOutputStream::getOutputStream() +{ + return m_output; +} + + +// XDataSink +void ODataOutputStream::setSuccessor( const Reference < XConnectable > &r ) +{ + /// if the references match, nothing needs to be done + if( m_succ != r ) + { + /// store the reference for later use + m_succ = r; + + if( m_succ.is() ) + { + /// set this instance as the sink ! + m_succ->setPredecessor( Reference < XConnectable > ( + static_cast< XConnectable * >(this) )); + } + } +} +Reference < XConnectable > ODataOutputStream::getSuccessor() +{ + return m_succ; +} + + +// XDataSource +void ODataOutputStream::setPredecessor( const Reference < XConnectable > &r ) +{ + if( r != m_pred ) { + m_pred = r; + if( m_pred.is() ) { + m_pred->setSuccessor( Reference< XConnectable > ( + static_cast< XConnectable * >(this) )); + } + } +} +Reference < XConnectable > ODataOutputStream::getPredecessor() +{ + return m_pred; +} + + +// XServiceInfo +OUString ODataOutputStream::getImplementationName() +{ + return "com.sun.star.comp.io.stm.DataOutputStream"; +} + +// XServiceInfo +sal_Bool ODataOutputStream::supportsService(const OUString& ServiceName) +{ + return cppu::supportsService(this, ServiceName); +} + +// XServiceInfo +Sequence< OUString > ODataOutputStream::getSupportedServiceNames() +{ + return { "com.sun.star.io.DataOutputStream" }; +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +io_ODataOutputStream_get_implementation( + css::uno::XComponentContext* , css::uno::Sequence<css::uno::Any> const&) +{ + return cppu::acquire(new ODataOutputStream()); +} + +namespace { + +struct equalObjectContainer_Impl +{ + bool operator()(const Reference< XInterface > & s1, + const Reference< XInterface > & s2) const + { + return s1 == s2; + } +}; + + +struct hashObjectContainer_Impl +{ + size_t operator()(const Reference< XInterface > & xRef) const + { + return reinterpret_cast<size_t>(xRef.get()); + } +}; + +} + +typedef std::unordered_map +< + Reference< XInterface >, + sal_Int32, + hashObjectContainer_Impl, + equalObjectContainer_Impl +> ObjectContainer_Impl; + +namespace { + +class OObjectOutputStream: + public ImplInheritanceHelper< + ODataOutputStream, /* parent */ + XObjectOutputStream, XMarkableStream > +{ +public: + OObjectOutputStream() + : m_nMaxId(0) , + m_bValidMarkable(false) + { + } + +public: + // XOutputStream + virtual void SAL_CALL writeBytes(const Sequence< sal_Int8 >& aData) override + { ODataOutputStream::writeBytes( aData ); } + + virtual void SAL_CALL flush() override + { ODataOutputStream::flush(); } + + virtual void SAL_CALL closeOutput() override + { ODataOutputStream::closeOutput(); } + +public: + // XDataOutputStream + virtual void SAL_CALL writeBoolean(sal_Bool Value) override + { ODataOutputStream::writeBoolean( Value ); } + virtual void SAL_CALL writeByte(sal_Int8 Value) override + { ODataOutputStream::writeByte( Value ); } + virtual void SAL_CALL writeChar(sal_Unicode Value) override + { ODataOutputStream::writeChar( Value ); } + virtual void SAL_CALL writeShort(sal_Int16 Value) override + { ODataOutputStream::writeShort( Value ); } + virtual void SAL_CALL writeLong(sal_Int32 Value) override + { ODataOutputStream::writeLong( Value ); } + virtual void SAL_CALL writeHyper(sal_Int64 Value) override + { ODataOutputStream::writeHyper( Value ); } + virtual void SAL_CALL writeFloat(float Value) override + { ODataOutputStream::writeFloat( Value ); } + virtual void SAL_CALL writeDouble(double Value) override + { ODataOutputStream::writeDouble( Value ); } + virtual void SAL_CALL writeUTF(const OUString& Value) override + { ODataOutputStream::writeUTF( Value );} + + // XObjectOutputStream + virtual void SAL_CALL writeObject( const Reference< XPersistObject > & r ) override; + +public: // XMarkableStream + virtual sal_Int32 SAL_CALL createMark() override; + virtual void SAL_CALL deleteMark(sal_Int32 Mark) override; + virtual void SAL_CALL jumpToMark(sal_Int32 nMark) override; + virtual void SAL_CALL jumpToFurthest() override; + virtual sal_Int32 SAL_CALL offsetToMark(sal_Int32 nMark) override; + +public: // XServiceInfo + OUString SAL_CALL getImplementationName() override; + Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override; + +private: + void connectToMarkable(); +private: + ObjectContainer_Impl m_mapObject; + sal_Int32 m_nMaxId; + Reference< XMarkableStream > m_rMarkable; + bool m_bValidMarkable; +}; + +} + +void OObjectOutputStream::writeObject( const Reference< XPersistObject > & xPObj ) +{ + + connectToMarkable(); + bool bWriteObj = false; + // create Mark to write length of info + sal_uInt32 nInfoLenMark = m_rMarkable->createMark(); + + // length of the info data (is later rewritten) + OObjectOutputStream::writeShort( 0 ); + + // write the object identifier + if( xPObj.is() ) + { + Reference< XInterface > rX( xPObj , UNO_QUERY ); + + ObjectContainer_Impl::const_iterator aIt + = m_mapObject.find( rX ); + if( aIt == m_mapObject.end() ) + { + // insert new object in hash table + m_mapObject[ rX ] = ++m_nMaxId; + ODataOutputStream::writeLong( m_nMaxId ); + ODataOutputStream::writeUTF( xPObj->getServiceName() ); + bWriteObj = true; + } + else + { + ODataOutputStream::writeLong( (*aIt).second ); + ODataOutputStream::writeUTF( OUString() ); + } + } + else + { + ODataOutputStream::writeLong( 0 ); + ODataOutputStream::writeUTF( OUString() ); + } + + sal_uInt32 nObjLenMark = m_rMarkable->createMark(); + ODataOutputStream::writeLong( 0 ); + + sal_Int32 nInfoLen = m_rMarkable->offsetToMark( nInfoLenMark ); + m_rMarkable->jumpToMark( nInfoLenMark ); + // write length of the info data + ODataOutputStream::writeShort( static_cast<sal_Int16>(nInfoLen) ); + // jump to the end of the stream + m_rMarkable->jumpToFurthest(); + + if( bWriteObj ) + xPObj->write( Reference< XObjectOutputStream > ( + static_cast< XObjectOutputStream * >(this) ) ); + + sal_Int32 nObjLen = m_rMarkable->offsetToMark( nObjLenMark ) -4; + m_rMarkable->jumpToMark( nObjLenMark ); + // write length of the info data + ODataOutputStream::writeLong( nObjLen ); + // jump to the end of the stream + m_rMarkable->jumpToFurthest(); + + m_rMarkable->deleteMark( nObjLenMark ); + m_rMarkable->deleteMark( nInfoLenMark ); +} + + +void OObjectOutputStream::connectToMarkable() +{ + if( m_bValidMarkable ) + return; + + if( ! m_bValidStream ) + throw NotConnectedException(); + + // find the markable stream ! + Reference< XInterface > rTry(m_output); + while( true ) { + if( ! rTry.is() ) + { + throw NotConnectedException(); + } + Reference < XMarkableStream > markable( rTry , UNO_QUERY ); + if( markable.is() ) + { + m_rMarkable = markable; + break; + } + Reference < XActiveDataSource > source( rTry , UNO_QUERY ); + rTry = source; + } + m_bValidMarkable = true; +} + + +sal_Int32 OObjectOutputStream::createMark() +{ + connectToMarkable(); // throws an exception, if a markable is not connected ! + + return m_rMarkable->createMark(); +} + +void OObjectOutputStream::deleteMark(sal_Int32 Mark) +{ + if( ! m_bValidMarkable ) + { + throw NotConnectedException(); + } + m_rMarkable->deleteMark( Mark ); +} + +void OObjectOutputStream::jumpToMark(sal_Int32 nMark) +{ + if( ! m_bValidMarkable ) + { + throw NotConnectedException(); + } + m_rMarkable->jumpToMark( nMark ); +} + + +void OObjectOutputStream::jumpToFurthest() +{ + connectToMarkable(); + m_rMarkable->jumpToFurthest(); +} + +sal_Int32 OObjectOutputStream::offsetToMark(sal_Int32 nMark) +{ + if( ! m_bValidMarkable ) + { + throw NotConnectedException(); + } + return m_rMarkable->offsetToMark( nMark ); +} + +// XServiceInfo +OUString OObjectOutputStream::getImplementationName() +{ + return "com.sun.star.comp.io.stm.ObjectOutputStream"; +} + +// XServiceInfo +sal_Bool OObjectOutputStream::supportsService(const OUString& ServiceName) +{ + return cppu::supportsService(this, ServiceName); +} + +// XServiceInfo +Sequence< OUString > OObjectOutputStream::getSupportedServiceNames() +{ + return { "com.sun.star.io.ObjectOutputStream" }; +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +io_OObjectOutputStream_get_implementation( + css::uno::XComponentContext* , css::uno::Sequence<css::uno::Any> const&) +{ + return cppu::acquire(new OObjectOutputStream()); +} + +namespace { + +class OObjectInputStream: + public ImplInheritanceHelper< + ODataInputStream, /* parent */ + XObjectInputStream, XMarkableStream > +{ +public: + explicit OObjectInputStream( const Reference < XComponentContext > &r) + : m_rSMgr( r->getServiceManager() ) + , m_rCxt( r ) + , m_bValidMarkable(false) + { + } + +public: // XInputStream + virtual sal_Int32 SAL_CALL readBytes(Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead) override + { return ODataInputStream::readBytes( aData , nBytesToRead ); } + + virtual sal_Int32 SAL_CALL readSomeBytes(Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead) override + { return ODataInputStream::readSomeBytes( aData, nMaxBytesToRead ); } + + virtual void SAL_CALL skipBytes(sal_Int32 nBytesToSkip) override + { ODataInputStream::skipBytes( nBytesToSkip ); } + + virtual sal_Int32 SAL_CALL available() override + { return ODataInputStream::available(); } + + virtual void SAL_CALL closeInput() override + { ODataInputStream::closeInput(); } + +public: // XDataInputStream + virtual sal_Int8 SAL_CALL readBoolean() override + { return ODataInputStream::readBoolean(); } + virtual sal_Int8 SAL_CALL readByte() override + { return ODataInputStream::readByte(); } + virtual sal_Unicode SAL_CALL readChar() override + { return ODataInputStream::readChar(); } + virtual sal_Int16 SAL_CALL readShort() override + { return ODataInputStream::readShort(); } + virtual sal_Int32 SAL_CALL readLong() override + { return ODataInputStream::readLong(); } + virtual sal_Int64 SAL_CALL readHyper() override + { return ODataInputStream::readHyper(); } + virtual float SAL_CALL readFloat() override + { return ODataInputStream::readFloat(); } + virtual double SAL_CALL readDouble() override + { return ODataInputStream::readDouble(); } + virtual OUString SAL_CALL readUTF() override + { return ODataInputStream::readUTF(); } + +public: // XObjectInputStream + virtual Reference< XPersistObject > SAL_CALL readObject( ) override; + +public: // XMarkableStream + virtual sal_Int32 SAL_CALL createMark() override; + virtual void SAL_CALL deleteMark(sal_Int32 Mark) override; + virtual void SAL_CALL jumpToMark(sal_Int32 nMark) override; + virtual void SAL_CALL jumpToFurthest() override; + virtual sal_Int32 SAL_CALL offsetToMark(sal_Int32 nMark) override; + +public: // XServiceInfo + OUString SAL_CALL getImplementationName() override; + Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override; + +private: + void connectToMarkable(); +private: + Reference < XMultiComponentFactory > m_rSMgr; + Reference < XComponentContext > m_rCxt; + bool m_bValidMarkable; + Reference < XMarkableStream > m_rMarkable; + vector < Reference< XPersistObject > > m_aPersistVector; + +}; + +} + +Reference< XPersistObject > OObjectInputStream::readObject() +{ + // check if chain contains a XMarkableStream + connectToMarkable(); + + Reference< XPersistObject > xLoadedObj; + + // create Mark to skip newer versions + sal_uInt32 nMark = m_rMarkable->createMark(); + // length of the data + sal_Int32 nLen = static_cast<sal_uInt16>(ODataInputStream::readShort()); + if( nLen < 0xc ) + { + throw WrongFormatException(); + } + + // read the object identifier + sal_uInt32 nId = readLong(); + + // the name of the persist model + // MM ??? + OUString aName = readUTF(); + + // Read the length of the object + sal_Int32 nObjLen = readLong(); + if( 0 == nId && 0 != nObjLen ) + { + throw WrongFormatException(); + } + + // skip data of new version + skipBytes( nLen - m_rMarkable->offsetToMark( nMark ) ); + + bool bLoadSuccessful = true; + if( nId ) + { + if( !aName.isEmpty() ) + { + // load the object + Reference< XInterface > x = m_rSMgr->createInstanceWithContext( aName, m_rCxt ); + xLoadedObj.set( x, UNO_QUERY ); + if( xLoadedObj.is() ) + { + sal_uInt32 nSize = m_aPersistVector.size(); + if( nSize <= nId ) + { + // grow to the right size + Reference< XPersistObject > xEmpty; + m_aPersistVector.insert( m_aPersistVector.end(), static_cast<tools::Long>(nId - nSize + 1), xEmpty ); + } + + m_aPersistVector[nId] = xLoadedObj; + xLoadedObj->read( Reference< XObjectInputStream >( + static_cast< XObjectInputStream * >(this) ) ); + } + else + { + // no service with this name could be instantiated + bLoadSuccessful = false; + } + } + else { + if (nId >= m_aPersistVector.size()) + { + // id unknown, load failure ! + bLoadSuccessful = false; + } + else + { + // Object has already been read, + xLoadedObj = m_aPersistVector[nId]; + } + } + } + + // skip to the position behind the object + skipBytes( nObjLen + nLen - m_rMarkable->offsetToMark( nMark ) ); + m_rMarkable->deleteMark( nMark ); + + if( ! bLoadSuccessful ) + { + throw WrongFormatException(); + } + return xLoadedObj; +} + + +void OObjectInputStream::connectToMarkable() +{ + if( m_bValidMarkable ) return; + + if( ! m_bValidStream ) + { + throw NotConnectedException( ); + } + + // find the markable stream ! + Reference< XInterface > rTry(m_input); + while( true ) { + if( ! rTry.is() ) + { + throw NotConnectedException( ); + } + Reference< XMarkableStream > markable( rTry , UNO_QUERY ); + if( markable.is() ) + { + m_rMarkable = markable; + break; + } + Reference < XActiveDataSink > sink( rTry , UNO_QUERY ); + rTry = sink; + } + m_bValidMarkable = true; +} + +sal_Int32 OObjectInputStream::createMark() +{ + connectToMarkable(); // throws an exception, if a markable is not connected ! + + return m_rMarkable->createMark(); +} + +void OObjectInputStream::deleteMark(sal_Int32 Mark) +{ + if( ! m_bValidMarkable ) + { + throw NotConnectedException(); + } + m_rMarkable->deleteMark( Mark ); +} + +void OObjectInputStream::jumpToMark(sal_Int32 nMark) +{ + if( ! m_bValidMarkable ) + { + throw NotConnectedException(); + } + m_rMarkable->jumpToMark( nMark ); +} +void OObjectInputStream::jumpToFurthest() +{ + connectToMarkable(); + m_rMarkable->jumpToFurthest(); +} + +sal_Int32 OObjectInputStream::offsetToMark(sal_Int32 nMark) +{ + if( ! m_bValidMarkable ) + { + throw NotConnectedException(); + } + return m_rMarkable->offsetToMark( nMark ); +} + +// XServiceInfo +OUString OObjectInputStream::getImplementationName() +{ + return "com.sun.star.comp.io.stm.ObjectInputStream"; +} + +// XServiceInfo +sal_Bool OObjectInputStream::supportsService(const OUString& ServiceName) +{ + return cppu::supportsService(this, ServiceName); +} + +// XServiceInfo +Sequence< OUString > OObjectInputStream::getSupportedServiceNames() +{ + return { "com.sun.star.io.ObjectInputStream" }; +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +io_OObjectInputStream_get_implementation( + css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const&) +{ + return cppu::acquire(new OObjectInputStream(context)); +} + +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/io/source/stm/omark.cxx b/io/source/stm/omark.cxx new file mode 100644 index 000000000..3991e2c9d --- /dev/null +++ b/io/source/stm/omark.cxx @@ -0,0 +1,766 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include <map> +#include <memory> + +#include <com/sun/star/io/BufferSizeExceededException.hpp> +#include <com/sun/star/io/NotConnectedException.hpp> +#include <com/sun/star/io/XMarkableStream.hpp> +#include <com/sun/star/io/XOutputStream.hpp> +#include <com/sun/star/io/XInputStream.hpp> +#include <com/sun/star/io/XActiveDataSource.hpp> +#include <com/sun/star/io/XActiveDataSink.hpp> +#include <com/sun/star/io/XConnectable.hpp> +#include <com/sun/star/lang/IllegalArgumentException.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> + +#include <cppuhelper/weak.hxx> +#include <cppuhelper/implbase.hxx> +#include <cppuhelper/supportsservice.hxx> + +#include <osl/diagnose.h> +#include <mutex> + +using namespace ::std; +using namespace ::cppu; +using namespace ::osl; +using namespace ::com::sun::star::io; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; + +#include "streamhelper.hxx" + +namespace io_stm { + +namespace { + +/*********************** +* +* OMarkableOutputStream. +* +* This object allows to set marks in an outputstream. It is allowed to jump back to the marks and +* rewrite the same bytes. +* +* The object must buffer the data since the last mark set. Flush will not +* have any effect. As soon as the last mark has been removed, the object may write the data +* through to the chained object. +* +**********************/ +class OMarkableOutputStream : + public WeakImplHelper< XOutputStream , + XActiveDataSource , + XMarkableStream , + XConnectable, + XServiceInfo + > +{ +public: + OMarkableOutputStream( ); + +public: // XOutputStream + virtual void SAL_CALL writeBytes(const Sequence< sal_Int8 >& aData) override; + virtual void SAL_CALL flush() override; + virtual void SAL_CALL closeOutput() override; + +public: // XMarkable + virtual sal_Int32 SAL_CALL createMark() override; + virtual void SAL_CALL deleteMark(sal_Int32 Mark) override; + virtual void SAL_CALL jumpToMark(sal_Int32 nMark) override; + virtual void SAL_CALL jumpToFurthest() override; + virtual sal_Int32 SAL_CALL offsetToMark(sal_Int32 nMark) override; + +public: // XActiveDataSource + virtual void SAL_CALL setOutputStream(const Reference < XOutputStream > & aStream) override; + virtual Reference < XOutputStream > SAL_CALL getOutputStream() override; + +public: // XConnectable + virtual void SAL_CALL setPredecessor(const Reference < XConnectable > & aPredecessor) override; + virtual Reference < XConnectable > SAL_CALL getPredecessor() override; + virtual void SAL_CALL setSuccessor(const Reference < XConnectable >& aSuccessor) override; + virtual Reference< XConnectable > SAL_CALL getSuccessor() override; + +public: // XServiceInfo + OUString SAL_CALL getImplementationName() override; + Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override; + +private: + // helper methods + /// @throws NotConnectedException + /// @throws BufferSizeExceededException + void checkMarksAndFlush(); + + Reference< XConnectable > m_succ; + Reference< XConnectable > m_pred; + + Reference< XOutputStream > m_output; + bool m_bValidStream; + + std::unique_ptr<MemRingBuffer> m_pBuffer; + map<sal_Int32,sal_Int32,less< sal_Int32 > > m_mapMarks; + sal_Int32 m_nCurrentPos; + sal_Int32 m_nCurrentMark; + + std::mutex m_mutex; +}; + +} + +OMarkableOutputStream::OMarkableOutputStream( ) + : m_bValidStream(false) + , m_pBuffer( new MemRingBuffer ) + , m_nCurrentPos(0) + , m_nCurrentMark(0) +{ +} + +// XOutputStream +void OMarkableOutputStream::writeBytes(const Sequence< sal_Int8 >& aData) +{ + if( !m_bValidStream ) { + throw NotConnectedException(); + } + if( m_mapMarks.empty() && ( m_pBuffer->getSize() == 0 ) ) { + // no mark and buffer active, simple write through + m_output->writeBytes( aData ); + } + else { + std::unique_lock guard( m_mutex ); + // new data must be buffered + m_pBuffer->writeAt( m_nCurrentPos , aData ); + m_nCurrentPos += aData.getLength(); + checkMarksAndFlush(); + } + +} + +void OMarkableOutputStream::flush() +{ + Reference< XOutputStream > output; + { + std::unique_lock guard( m_mutex ); + output = m_output; + } + + // Markable cannot flush buffered data, because the data may get rewritten, + // however one can forward the flush to the chained stream to give it + // a chance to write data buffered in the chained stream. + if( output.is() ) + { + output->flush(); + } +} + +void OMarkableOutputStream::closeOutput() +{ + if( !m_bValidStream ) { + throw NotConnectedException(); + } + std::unique_lock guard( m_mutex ); + // all marks must be cleared and all + + m_mapMarks.clear(); + m_nCurrentPos = m_pBuffer->getSize(); + checkMarksAndFlush(); + + m_output->closeOutput(); + + setOutputStream( Reference< XOutputStream > () ); + setPredecessor( Reference < XConnectable >() ); + setSuccessor( Reference< XConnectable > () ); + +} + + +sal_Int32 OMarkableOutputStream::createMark() +{ + std::unique_lock guard( m_mutex ); + sal_Int32 nMark = m_nCurrentMark; + + m_mapMarks[nMark] = m_nCurrentPos; + + m_nCurrentMark ++; + return nMark; +} + +void OMarkableOutputStream::deleteMark(sal_Int32 Mark) +{ + std::unique_lock guard( m_mutex ); + map<sal_Int32,sal_Int32,less<sal_Int32> >::iterator ii = m_mapMarks.find( Mark ); + + if( ii == m_mapMarks.end() ) { + throw IllegalArgumentException( + "MarkableOutputStream::deleteMark unknown mark (" + OUString::number(Mark) + ")", + *this, 0); + } + m_mapMarks.erase( ii ); + checkMarksAndFlush(); +} + +void OMarkableOutputStream::jumpToMark(sal_Int32 nMark) +{ + std::unique_lock guard( m_mutex ); + map<sal_Int32,sal_Int32,less<sal_Int32> >::iterator ii = m_mapMarks.find( nMark ); + + if( ii == m_mapMarks.end() ) { + throw IllegalArgumentException( + "MarkableOutputStream::jumpToMark unknown mark (" + OUString::number(nMark) + ")", + *this, 0); + } + m_nCurrentPos = (*ii).second; +} + +void OMarkableOutputStream::jumpToFurthest() +{ + std::unique_lock guard( m_mutex ); + m_nCurrentPos = m_pBuffer->getSize(); + checkMarksAndFlush(); +} + +sal_Int32 OMarkableOutputStream::offsetToMark(sal_Int32 nMark) +{ + + std::unique_lock guard( m_mutex ); + map<sal_Int32,sal_Int32,less<sal_Int32> >::const_iterator ii = m_mapMarks.find( nMark ); + + if( ii == m_mapMarks.end() ) + { + throw IllegalArgumentException( + "MarkableOutputStream::offsetToMark unknown mark (" + OUString::number(nMark) + ")", + *this, 0); + } + return m_nCurrentPos - (*ii).second; +} + + +// XActiveDataSource2 +void OMarkableOutputStream::setOutputStream(const Reference < XOutputStream >& aStream) +{ + if( m_output != aStream ) { + m_output = aStream; + + Reference < XConnectable > succ( m_output , UNO_QUERY ); + setSuccessor( succ ); + } + m_bValidStream = m_output.is(); +} + +Reference< XOutputStream > OMarkableOutputStream::getOutputStream() +{ + return m_output; +} + + +void OMarkableOutputStream::setSuccessor( const Reference< XConnectable > &r ) +{ + /// if the references match, nothing needs to be done + if( m_succ != r ) { + /// store the reference for later use + m_succ = r; + + if( m_succ.is() ) { + m_succ->setPredecessor( Reference < XConnectable > ( + static_cast< XConnectable * >(this) ) ); + } + } +} +Reference <XConnectable > OMarkableOutputStream::getSuccessor() +{ + return m_succ; +} + + +// XDataSource +void OMarkableOutputStream::setPredecessor( const Reference< XConnectable > &r ) +{ + if( r != m_pred ) { + m_pred = r; + if( m_pred.is() ) { + m_pred->setSuccessor( Reference < XConnectable > ( + static_cast< XConnectable * >(this ) ) ); + } + } +} +Reference < XConnectable > OMarkableOutputStream::getPredecessor() +{ + return m_pred; +} + + +// private methods + +void OMarkableOutputStream::checkMarksAndFlush() +{ + // find the smallest mark + sal_Int32 nNextFound = m_nCurrentPos; + for (auto const& mark : m_mapMarks) + { + if( mark.second <= nNextFound ) { + nNextFound = mark.second; + } + } + + if( nNextFound ) { + // some data must be released ! + m_nCurrentPos -= nNextFound; + for (auto & mark : m_mapMarks) + { + mark.second -= nNextFound; + } + + Sequence<sal_Int8> seq(nNextFound); + m_pBuffer->readAt( 0 , seq , nNextFound ); + m_pBuffer->forgetFromStart( nNextFound ); + + // now write data through to streams + m_output->writeBytes( seq ); + } + else { + // nothing to do. There is a mark or the current cursor position, that prevents + // releasing data ! + } +} + + +// XServiceInfo +OUString OMarkableOutputStream::getImplementationName() +{ + return "com.sun.star.comp.io.stm.MarkableOutputStream"; +} + +// XServiceInfo +sal_Bool OMarkableOutputStream::supportsService(const OUString& ServiceName) +{ + return cppu::supportsService(this, ServiceName); +} + +// XServiceInfo +Sequence< OUString > OMarkableOutputStream::getSupportedServiceNames() +{ + return { "com.sun.star.io.MarkableOutputStream" }; +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +io_OMarkableOutputStream_get_implementation( + css::uno::XComponentContext* , css::uno::Sequence<css::uno::Any> const&) +{ + return cppu::acquire(new OMarkableOutputStream()); +} + + +// XMarkableInputStream + +namespace { + +class OMarkableInputStream : + public WeakImplHelper + < + XInputStream, + XActiveDataSink, + XMarkableStream, + XConnectable, + XServiceInfo + > +{ +public: + OMarkableInputStream( ); + + +public: // XInputStream + virtual sal_Int32 SAL_CALL readBytes(Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead) override ; + virtual sal_Int32 SAL_CALL readSomeBytes(Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead) override; + virtual void SAL_CALL skipBytes(sal_Int32 nBytesToSkip) override; + + virtual sal_Int32 SAL_CALL available() override; + virtual void SAL_CALL closeInput() override; + +public: // XMarkable + virtual sal_Int32 SAL_CALL createMark() override; + virtual void SAL_CALL deleteMark(sal_Int32 Mark) override; + virtual void SAL_CALL jumpToMark(sal_Int32 nMark) override; + virtual void SAL_CALL jumpToFurthest() override; + virtual sal_Int32 SAL_CALL offsetToMark(sal_Int32 nMark) override; + +public: // XActiveDataSink + virtual void SAL_CALL setInputStream(const Reference < XInputStream > & aStream) override; + virtual Reference < XInputStream > SAL_CALL getInputStream() override; + +public: // XConnectable + virtual void SAL_CALL setPredecessor(const Reference < XConnectable > & aPredecessor) override; + virtual Reference < XConnectable > SAL_CALL getPredecessor() override; + virtual void SAL_CALL setSuccessor(const Reference < XConnectable > & aSuccessor) override; + virtual Reference < XConnectable > SAL_CALL getSuccessor() override; + +public: // XServiceInfo + OUString SAL_CALL getImplementationName() override; + Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override; + +private: + void checkMarksAndFlush(); + + Reference < XConnectable > m_succ; + Reference < XConnectable > m_pred; + + Reference< XInputStream > m_input; + bool m_bValidStream; + + std::unique_ptr<MemRingBuffer> m_pBuffer; + map<sal_Int32,sal_Int32,less< sal_Int32 > > m_mapMarks; + sal_Int32 m_nCurrentPos; + sal_Int32 m_nCurrentMark; + + std::mutex m_mutex; +}; + +} + +OMarkableInputStream::OMarkableInputStream() + : m_bValidStream(false) + , m_nCurrentPos(0) + , m_nCurrentMark(0) +{ + m_pBuffer.reset( new MemRingBuffer ); +} + + +// XInputStream + +sal_Int32 OMarkableInputStream::readBytes(Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead) +{ + sal_Int32 nBytesRead; + + if( !m_bValidStream ) { + throw NotConnectedException( + "MarkableInputStream::readBytes NotConnectedException", + *this ); + } + std::unique_lock guard( m_mutex ); + if( m_mapMarks.empty() && ! m_pBuffer->getSize() ) { + // normal read ! + nBytesRead = m_input->readBytes( aData, nBytesToRead ); + } + else { + // read from buffer + sal_Int32 nRead; + + // read enough bytes into buffer + if( m_pBuffer->getSize() - m_nCurrentPos < nBytesToRead ) { + sal_Int32 nToRead = nBytesToRead - ( m_pBuffer->getSize() - m_nCurrentPos ); + nRead = m_input->readBytes( aData , nToRead ); + + OSL_ASSERT( aData.getLength() == nRead ); + + m_pBuffer->writeAt( m_pBuffer->getSize() , aData ); + + if( nRead < nToRead ) { + nBytesToRead = nBytesToRead - (nToRead-nRead); + } + } + + OSL_ASSERT( m_pBuffer->getSize() - m_nCurrentPos >= nBytesToRead ); + + m_pBuffer->readAt( m_nCurrentPos , aData , nBytesToRead ); + + m_nCurrentPos += nBytesToRead; + nBytesRead = nBytesToRead; + } + + return nBytesRead; +} + + +sal_Int32 OMarkableInputStream::readSomeBytes(Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead) +{ + + sal_Int32 nBytesRead; + if( !m_bValidStream ) { + throw NotConnectedException( + "MarkableInputStream::readSomeBytes NotConnectedException", + *this ); + } + + std::unique_lock guard( m_mutex ); + if( m_mapMarks.empty() && ! m_pBuffer->getSize() ) { + // normal read ! + nBytesRead = m_input->readSomeBytes( aData, nMaxBytesToRead ); + } + else { + // read from buffer + sal_Int32 nRead = 0; + sal_Int32 nInBuffer = m_pBuffer->getSize() - m_nCurrentPos; + sal_Int32 nAdditionalBytesToRead = std::min<sal_Int32>(nMaxBytesToRead-nInBuffer,m_input->available()); + nAdditionalBytesToRead = std::max<sal_Int32>(0 , nAdditionalBytesToRead ); + + // read enough bytes into buffer + if( 0 == nInBuffer ) { + nRead = m_input->readSomeBytes( aData , nMaxBytesToRead ); + } + else if( nAdditionalBytesToRead ) { + nRead = m_input->readBytes( aData , nAdditionalBytesToRead ); + } + + if( nRead ) { + aData.realloc( nRead ); + m_pBuffer->writeAt( m_pBuffer->getSize() , aData ); + } + + nBytesRead = std::min( nMaxBytesToRead , nInBuffer + nRead ); + + // now take everything from buffer ! + m_pBuffer->readAt( m_nCurrentPos , aData , nBytesRead ); + + m_nCurrentPos += nBytesRead; + } + + return nBytesRead; + + +} + + +void OMarkableInputStream::skipBytes(sal_Int32 nBytesToSkip) +{ + if ( nBytesToSkip < 0 ) + throw BufferSizeExceededException( + "precondition not met: XInputStream::skipBytes: non-negative integer required!", + *this + ); + + // this method is blocking + Sequence<sal_Int8> seqDummy( nBytesToSkip ); + readBytes( seqDummy , nBytesToSkip ); +} + +sal_Int32 OMarkableInputStream::available() +{ + if( !m_bValidStream ) { + throw NotConnectedException( + "MarkableInputStream::available NotConnectedException", + *this ); + } + + std::unique_lock guard( m_mutex ); + sal_Int32 nAvail = m_input->available() + ( m_pBuffer->getSize() - m_nCurrentPos ); + return nAvail; +} + + +void OMarkableInputStream::closeInput() +{ + if( !m_bValidStream ) { + throw NotConnectedException( + "MarkableInputStream::closeInput NotConnectedException", + *this ); + } + std::unique_lock guard( m_mutex ); + + m_input->closeInput(); + + setInputStream( Reference< XInputStream > () ); + setPredecessor( Reference< XConnectable > () ); + setSuccessor( Reference< XConnectable >() ); + + m_pBuffer.reset(); + m_nCurrentPos = 0; + m_nCurrentMark = 0; +} + +// XMarkable + +sal_Int32 OMarkableInputStream::createMark() +{ + std::unique_lock guard( m_mutex ); + sal_Int32 nMark = m_nCurrentMark; + + m_mapMarks[nMark] = m_nCurrentPos; + + m_nCurrentMark ++; + return nMark; +} + +void OMarkableInputStream::deleteMark(sal_Int32 Mark) +{ + std::unique_lock guard( m_mutex ); + map<sal_Int32,sal_Int32,less<sal_Int32> >::iterator ii = m_mapMarks.find( Mark ); + + if( ii == m_mapMarks.end() ) { + throw IllegalArgumentException( + "MarkableInputStream::deleteMark unknown mark (" + OUString::number(Mark) + ")", + *this , 0 ); + } + m_mapMarks.erase( ii ); + checkMarksAndFlush(); +} + +void OMarkableInputStream::jumpToMark(sal_Int32 nMark) +{ + std::unique_lock guard( m_mutex ); + map<sal_Int32,sal_Int32,less<sal_Int32> >::iterator ii = m_mapMarks.find( nMark ); + + if( ii == m_mapMarks.end() ) + { + throw IllegalArgumentException( + "MarkableInputStream::jumpToMark unknown mark (" + OUString::number(nMark) + ")", + *this , 0 ); + } + m_nCurrentPos = (*ii).second; +} + +void OMarkableInputStream::jumpToFurthest() +{ + std::unique_lock guard( m_mutex ); + m_nCurrentPos = m_pBuffer->getSize(); + checkMarksAndFlush(); +} + +sal_Int32 OMarkableInputStream::offsetToMark(sal_Int32 nMark) +{ + std::unique_lock guard( m_mutex ); + map<sal_Int32,sal_Int32,less<sal_Int32> >::const_iterator ii = m_mapMarks.find( nMark ); + + if( ii == m_mapMarks.end() ) + { + throw IllegalArgumentException( + "MarkableInputStream::offsetToMark unknown mark (" + OUString::number(nMark) + ")", + *this, 0 ); + } + return m_nCurrentPos - (*ii).second; +} + + +// XActiveDataSource +void OMarkableInputStream::setInputStream(const Reference< XInputStream > & aStream) +{ + + if( m_input != aStream ) { + m_input = aStream; + + Reference < XConnectable > pred( m_input , UNO_QUERY ); + setPredecessor( pred ); + } + + m_bValidStream = m_input.is(); + +} + +Reference< XInputStream > OMarkableInputStream::getInputStream() +{ + return m_input; +} + + +// XDataSink +void OMarkableInputStream::setSuccessor( const Reference< XConnectable > &r ) +{ + /// if the references match, nothing needs to be done + if( m_succ != r ) { + /// store the reference for later use + m_succ = r; + + if( m_succ.is() ) { + /// set this instance as the sink ! + m_succ->setPredecessor( Reference< XConnectable > ( + static_cast< XConnectable * >(this) ) ); + } + } +} + +Reference < XConnectable > OMarkableInputStream::getSuccessor() +{ + return m_succ; +} + + +// XDataSource +void OMarkableInputStream::setPredecessor( const Reference < XConnectable > &r ) +{ + if( r != m_pred ) { + m_pred = r; + if( m_pred.is() ) { + m_pred->setSuccessor( Reference< XConnectable > ( + static_cast< XConnectable * >(this) ) ); + } + } +} +Reference< XConnectable > OMarkableInputStream::getPredecessor() +{ + return m_pred; +} + + +void OMarkableInputStream::checkMarksAndFlush() +{ + // find the smallest mark + sal_Int32 nNextFound = m_nCurrentPos; + for (auto const& mark : m_mapMarks) + { + if( mark.second <= nNextFound ) { + nNextFound = mark.second; + } + } + + if( nNextFound ) { + // some data must be released ! + m_nCurrentPos -= nNextFound; + for (auto & mark : m_mapMarks) + { + mark.second -= nNextFound; + } + + m_pBuffer->forgetFromStart( nNextFound ); + + } + else { + // nothing to do. There is a mark or the current cursor position, that prevents + // releasing data ! + } +} + +// XServiceInfo +OUString OMarkableInputStream::getImplementationName() +{ + return "com.sun.star.comp.io.stm.MarkableInputStream"; +} + +// XServiceInfo +sal_Bool OMarkableInputStream::supportsService(const OUString& ServiceName) +{ + return cppu::supportsService(this, ServiceName); +} + +// XServiceInfo +Sequence< OUString > OMarkableInputStream::getSupportedServiceNames() +{ + return { "com.sun.star.io.MarkableInputStream" }; +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +io_OMarkableInputStream_get_implementation( + css::uno::XComponentContext* , css::uno::Sequence<css::uno::Any> const&) +{ + return cppu::acquire(new OMarkableInputStream()); +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/io/source/stm/opipe.cxx b/io/source/stm/opipe.cxx new file mode 100644 index 000000000..07e203bf0 --- /dev/null +++ b/io/source/stm/opipe.cxx @@ -0,0 +1,357 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <sal/config.h> + +#include <com/sun/star/io/BufferSizeExceededException.hpp> +#include <com/sun/star/io/NotConnectedException.hpp> +#include <com/sun/star/io/XPipe.hpp> +#include <com/sun/star/io/XConnectable.hpp> + +#include <com/sun/star/lang/XServiceInfo.hpp> + +#include <cppuhelper/implbase.hxx> +#include <cppuhelper/supportsservice.hxx> + +#include <osl/conditn.hxx> +#include <osl/mutex.hxx> + +#include <limits> +#include <memory> +#include <string.h> + +using namespace ::osl; +using namespace ::cppu; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::io; +using namespace ::com::sun::star::lang; + +#include "streamhelper.hxx" + +namespace com::sun::star::uno { class XComponentContext; } + +namespace io_stm{ + +namespace { + +class OPipeImpl : + public WeakImplHelper< XPipe , XConnectable , XServiceInfo > +{ +public: + OPipeImpl( ); + +public: // XInputStream + virtual sal_Int32 SAL_CALL readBytes(Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead) override; + virtual sal_Int32 SAL_CALL readSomeBytes(Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead) override; + virtual void SAL_CALL skipBytes(sal_Int32 nBytesToSkip) override; + virtual sal_Int32 SAL_CALL available() override; + virtual void SAL_CALL closeInput() override; + +public: // XOutputStream + + virtual void SAL_CALL writeBytes(const Sequence< sal_Int8 >& aData) override; + virtual void SAL_CALL flush() override; + virtual void SAL_CALL closeOutput() override; + +public: // XConnectable + virtual void SAL_CALL setPredecessor(const Reference< XConnectable >& aPredecessor) override; + virtual Reference< XConnectable > SAL_CALL getPredecessor() override; + virtual void SAL_CALL setSuccessor(const Reference < XConnectable > & aSuccessor) override; + virtual Reference < XConnectable > SAL_CALL getSuccessor() override ; + + +public: // XServiceInfo + OUString SAL_CALL getImplementationName() override; + Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override; + +private: + + Reference < XConnectable > m_succ; + Reference < XConnectable > m_pred; + + sal_Int32 m_nBytesToSkip; + + bool m_bOutputStreamClosed; + bool m_bInputStreamClosed; + + osl::Condition m_conditionBytesAvail; + Mutex m_mutexAccess; + std::unique_ptr<MemFIFO> m_pFIFO; +}; + +} + +OPipeImpl::OPipeImpl() + : m_nBytesToSkip(0 ) + , m_bOutputStreamClosed(false ) + , m_bInputStreamClosed( false ) + , m_pFIFO( new MemFIFO ) +{ +} + + + +sal_Int32 OPipeImpl::readBytes(Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead) +{ + while( true ) + { + { // start guarded section + MutexGuard guard( m_mutexAccess ); + if( m_bInputStreamClosed ) + { + throw NotConnectedException( + "Pipe::readBytes NotConnectedException", + *this ); + } + sal_Int32 nOccupiedBufferLen = m_pFIFO->getSize(); + + if( m_bOutputStreamClosed && nBytesToRead > nOccupiedBufferLen ) + { + nBytesToRead = nOccupiedBufferLen; + } + + if( nOccupiedBufferLen < nBytesToRead ) + { + // wait outside guarded section + m_conditionBytesAvail.reset(); + } + else { + // necessary bytes are available + m_pFIFO->read( aData , nBytesToRead ); + return nBytesToRead; + } + } // end guarded section + + // wait for new data outside guarded section! + m_conditionBytesAvail.wait(); + } +} + + +sal_Int32 OPipeImpl::readSomeBytes(Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead) +{ + while( true ) { + { + MutexGuard guard( m_mutexAccess ); + if( m_bInputStreamClosed ) + { + throw NotConnectedException( + "Pipe::readSomeBytes NotConnectedException", + *this ); + } + if( m_pFIFO->getSize() ) + { + sal_Int32 nSize = std::min( nMaxBytesToRead , m_pFIFO->getSize() ); + aData.realloc( nSize ); + m_pFIFO->read( aData , nSize ); + return nSize; + } + + if( m_bOutputStreamClosed ) + { + // no bytes in buffer anymore + return 0; + } + } + + m_conditionBytesAvail.wait(); + } +} + + +void OPipeImpl::skipBytes(sal_Int32 nBytesToSkip) +{ + MutexGuard guard( m_mutexAccess ); + if( m_bInputStreamClosed ) + { + throw NotConnectedException( + "Pipe::skipBytes NotConnectedException", + *this ); + } + + if( nBytesToSkip < 0 + || (nBytesToSkip + > std::numeric_limits< sal_Int32 >::max() - m_nBytesToSkip) ) + { + throw BufferSizeExceededException( + "Pipe::skipBytes BufferSizeExceededException", + *this ); + } + m_nBytesToSkip += nBytesToSkip; + + nBytesToSkip = std::min( m_pFIFO->getSize() , m_nBytesToSkip ); + m_pFIFO->skip( nBytesToSkip ); + m_nBytesToSkip -= nBytesToSkip; +} + + +sal_Int32 OPipeImpl::available() + { + MutexGuard guard( m_mutexAccess ); + if( m_bInputStreamClosed ) + { + throw NotConnectedException( + "Pipe::available NotConnectedException", + *this ); + } + return m_pFIFO->getSize(); +} + +void OPipeImpl::closeInput() +{ + MutexGuard guard( m_mutexAccess ); + + m_bInputStreamClosed = true; + + m_pFIFO.reset(); + + // readBytes may throw an exception + m_conditionBytesAvail.set(); + + setSuccessor( Reference< XConnectable > () ); +} + + +void OPipeImpl::writeBytes(const Sequence< sal_Int8 >& aData) +{ + MutexGuard guard( m_mutexAccess ); + + if( m_bOutputStreamClosed ) + { + throw NotConnectedException( + "Pipe::writeBytes NotConnectedException (outputstream)", + *this ); + } + + if( m_bInputStreamClosed ) + { + throw NotConnectedException( + "Pipe::writeBytes NotConnectedException (inputstream)", + *this ); + } + + // check skipping + sal_Int32 nLen = aData.getLength(); + if( m_nBytesToSkip && m_nBytesToSkip >= nLen ) { + // all must be skipped - forget whole call + m_nBytesToSkip -= nLen; + return; + } + + // adjust buffersize if necessary + if( m_nBytesToSkip ) + { + Sequence< sal_Int8 > seqCopy( nLen - m_nBytesToSkip ); + memcpy( seqCopy.getArray() , &( aData.getConstArray()[m_nBytesToSkip] ) , nLen-m_nBytesToSkip ); + m_pFIFO->write( seqCopy ); + } + else + { + m_pFIFO->write( aData ); + } + m_nBytesToSkip = 0; + + // readBytes may check again if enough bytes are available + m_conditionBytesAvail.set(); +} + + +void OPipeImpl::flush() +{ + // nothing to do for a pipe +} + +void OPipeImpl::closeOutput() +{ + MutexGuard guard( m_mutexAccess ); + + m_bOutputStreamClosed = true; + m_conditionBytesAvail.set(); + setPredecessor( Reference < XConnectable > () ); +} + + +void OPipeImpl::setSuccessor( const Reference < XConnectable > &r ) +{ + /// if the references match, nothing needs to be done + if( m_succ != r ) { + /// store the reference for later use + m_succ = r; + + if( m_succ.is() ) + { + m_succ->setPredecessor( + Reference< XConnectable > ( static_cast< XConnectable * >(this) ) ); + } + } +} + +Reference < XConnectable > OPipeImpl::getSuccessor() +{ + return m_succ; +} + + +// XDataSource +void OPipeImpl::setPredecessor( const Reference < XConnectable > &r ) +{ + if( r != m_pred ) { + m_pred = r; + if( m_pred.is() ) { + m_pred->setSuccessor( + Reference < XConnectable > ( static_cast< XConnectable * >(this) ) ); + } + } +} + +Reference < XConnectable > OPipeImpl::getPredecessor() +{ + return m_pred; +} + + +// XServiceInfo +OUString OPipeImpl::getImplementationName() +{ + return "com.sun.star.comp.io.stm.Pipe"; +} + +// XServiceInfo +sal_Bool OPipeImpl::supportsService(const OUString& ServiceName) +{ + return cppu::supportsService(this, ServiceName); +} + +// XServiceInfo +Sequence< OUString > OPipeImpl::getSupportedServiceNames() +{ + return { "com.sun.star.io.Pipe" }; +} + +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +io_OPipeImpl_get_implementation( + css::uno::XComponentContext* , css::uno::Sequence<css::uno::Any> const&) +{ + return cppu::acquire(new io_stm::OPipeImpl()); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/io/source/stm/opump.cxx b/io/source/stm/opump.cxx new file mode 100644 index 000000000..fc751b677 --- /dev/null +++ b/io/source/stm/opump.cxx @@ -0,0 +1,455 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include <sal/log.hxx> + +#include <com/sun/star/io/IOException.hpp> +#include <com/sun/star/io/NotConnectedException.hpp> +#include <com/sun/star/io/XActiveDataSource.hpp> +#include <com/sun/star/io/XActiveDataSink.hpp> +#include <com/sun/star/io/XActiveDataControl.hpp> +#include <com/sun/star/io/XConnectable.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> + +#include <cppuhelper/implbase.hxx> +#include <comphelper/interfacecontainer4.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <osl/thread.h> +#include <mutex> + +using namespace osl; +using namespace cppu; +using namespace com::sun::star::uno; +using namespace com::sun::star::lang; +using namespace com::sun::star::io; + +namespace io_stm { + + namespace { + + class Pump : public WeakImplHelper< + XActiveDataSource, XActiveDataSink, XActiveDataControl, XConnectable, XServiceInfo > + { + std::mutex m_aMutex; + oslThread m_aThread; + + Reference< XConnectable > m_xPred; + Reference< XConnectable > m_xSucc; + Reference< XInputStream > m_xInput; + Reference< XOutputStream > m_xOutput; + comphelper::OInterfaceContainerHelper4<XStreamListener> m_cnt; + bool m_closeFired; + + void run(); + static void static_run( void* pObject ); + + void close(); + void fireClose(); + void fireStarted(); + void fireTerminated(); + void fireError( const Any &a ); + + public: + Pump(); + virtual ~Pump() override; + + // XActiveDataSource + virtual void SAL_CALL setOutputStream( const Reference< css::io::XOutputStream >& xOutput ) override; + virtual Reference< css::io::XOutputStream > SAL_CALL getOutputStream() override; + + // XActiveDataSink + virtual void SAL_CALL setInputStream( const Reference< css::io::XInputStream >& xStream ) override; + virtual Reference< css::io::XInputStream > SAL_CALL getInputStream() override; + + // XActiveDataControl + virtual void SAL_CALL addListener( const Reference< css::io::XStreamListener >& xListener ) override; + virtual void SAL_CALL removeListener( const Reference< css::io::XStreamListener >& xListener ) override; + virtual void SAL_CALL start() override; + virtual void SAL_CALL terminate() override; + + // XConnectable + virtual void SAL_CALL setPredecessor( const Reference< css::io::XConnectable >& xPred ) override; + virtual Reference< css::io::XConnectable > SAL_CALL getPredecessor() override; + virtual void SAL_CALL setSuccessor( const Reference< css::io::XConnectable >& xSucc ) override; + virtual Reference< css::io::XConnectable > SAL_CALL getSuccessor() override; + + public: // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + virtual sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override; + }; + + } + +Pump::Pump() : m_aThread( nullptr ), + m_closeFired( false ) +{ +} + +Pump::~Pump() +{ + // exit gracefully + if( m_aThread ) + { + osl_joinWithThread( m_aThread ); + osl_destroyThread( m_aThread ); + } +} + +void Pump::fireError( const Any & exception ) +{ + std::unique_lock guard( m_aMutex ); + comphelper::OInterfaceIteratorHelper4<XStreamListener> iter( guard, m_cnt ); + guard.unlock(); + while( iter.hasMoreElements() ) + { + try + { + iter.next()->error( exception ); + } + catch ( const RuntimeException &e ) + { + SAL_WARN("io.streams","com.sun.star.comp.stoc.Pump: unexpected exception during calling listeners" << e); + } + } +} + +void Pump::fireClose() +{ + bool bFire = false; + { + std::unique_lock guard( m_aMutex ); + if( ! m_closeFired ) + { + m_closeFired = true; + bFire = true; + } + } + + if( !bFire ) + return; + + std::unique_lock guard( m_aMutex ); + comphelper::OInterfaceIteratorHelper4<XStreamListener> iter( guard, m_cnt ); + guard.unlock(); + while( iter.hasMoreElements() ) + { + try + { + iter.next()->closed( ); + } + catch ( const RuntimeException &e ) + { + SAL_WARN("io.streams","com.sun.star.comp.stoc.Pump: unexpected exception during calling listeners" << e); + } + } +} + +void Pump::fireStarted() +{ + std::unique_lock guard( m_aMutex ); + comphelper::OInterfaceIteratorHelper4<XStreamListener> iter( guard, m_cnt ); + guard.unlock(); + while( iter.hasMoreElements() ) + { + try + { + iter.next()->started( ); + } + catch ( const RuntimeException &e ) + { + SAL_WARN("io.streams","com.sun.star.comp.stoc.Pump: unexpected exception during calling listeners" << e); + } + } +} + +void Pump::fireTerminated() +{ + std::unique_lock guard( m_aMutex ); + comphelper::OInterfaceIteratorHelper4<XStreamListener> iter( guard, m_cnt ); + guard.unlock(); + while( iter.hasMoreElements() ) + { + try + { + iter.next()->terminated(); + } + catch ( const RuntimeException &e ) + { + SAL_WARN("io.streams","com.sun.star.comp.stoc.Pump: unexpected exception during calling listeners" << e); + } + } +} + + +void Pump::close() +{ + // close streams and release references + Reference< XInputStream > rInput; + Reference< XOutputStream > rOutput; + { + std::unique_lock guard( m_aMutex ); + rInput = m_xInput; + m_xInput.clear(); + + rOutput = m_xOutput; + m_xOutput.clear(); + m_xSucc.clear(); + m_xPred.clear(); + } + if( rInput.is() ) + { + try + { + rInput->closeInput(); + } + catch( Exception & ) + { + // go down calm + } + } + if( rOutput.is() ) + { + try + { + rOutput->closeOutput(); + } + catch( Exception & ) + { + // go down calm + } + } +} + +void Pump::static_run( void* pObject ) +{ + osl_setThreadName("io_stm::Pump::run()"); + static_cast<Pump*>(pObject)->run(); + static_cast<Pump*>(pObject)->release(); +} + +void Pump::run() +{ + try + { + fireStarted(); + try + { + Reference< XInputStream > rInput; + Reference< XOutputStream > rOutput; + { + std::unique_lock aGuard( m_aMutex ); + rInput = m_xInput; + rOutput = m_xOutput; + } + + if( ! rInput.is() ) + { + throw NotConnectedException( "no input stream set", static_cast<OWeakObject*>(this) ); + } + Sequence< sal_Int8 > aData; + while( rInput->readSomeBytes( aData, 65536 ) ) + { + if( ! rOutput.is() ) + { + throw NotConnectedException( "no output stream set", static_cast<OWeakObject*>(this) ); + } + rOutput->writeBytes( aData ); + osl_yieldThread(); + } + } + catch ( const IOException & e ) + { + fireError( Any( e ) ); + } + catch ( const RuntimeException & e ) + { + fireError( Any( e ) ); + } + catch ( const Exception & e ) + { + fireError( Any( e ) ); + } + + close(); + fireClose(); + } + catch ( const css::uno::Exception &e ) + { + // we are the last on the stack. + // this is to avoid crashing the program, when e.g. a bridge crashes + SAL_WARN("io.streams","com.sun.star.comp.stoc.Pump: unexpected exception during calling listeners" << e); + } +} + + +/* + * XConnectable + */ + +void Pump::setPredecessor( const Reference< XConnectable >& xPred ) +{ + std::unique_lock aGuard( m_aMutex ); + m_xPred = xPred; +} + + +Reference< XConnectable > Pump::getPredecessor() +{ + std::unique_lock aGuard( m_aMutex ); + return m_xPred; +} + + +void Pump::setSuccessor( const Reference< XConnectable >& xSucc ) +{ + std::unique_lock aGuard( m_aMutex ); + m_xSucc = xSucc; +} + + +Reference< XConnectable > Pump::getSuccessor() +{ + std::unique_lock aGuard( m_aMutex ); + return m_xSucc; +} + + +/* + * XActiveDataControl + */ + +void Pump::addListener( const Reference< XStreamListener >& xListener ) +{ + std::unique_lock aGuard( m_aMutex ); + m_cnt.addInterface( aGuard, xListener ); +} + + +void Pump::removeListener( const Reference< XStreamListener >& xListener ) +{ + std::unique_lock aGuard( m_aMutex ); + m_cnt.removeInterface( aGuard, xListener ); +} + + +void Pump::start() +{ + std::unique_lock aGuard( m_aMutex ); + m_aThread = osl_createSuspendedThread(Pump::static_run,this); + if( !m_aThread ) + { + throw RuntimeException( + "Pump::start Couldn't create worker thread", + *this); + } + + // will be released by OPump::static_run + acquire(); + osl_resumeThread( m_aThread ); + +} + + +void Pump::terminate() +{ + close(); + + // wait for the worker to die + if( m_aThread ) + osl_joinWithThread( m_aThread ); + + fireTerminated(); + fireClose(); +} + + +/* + * XActiveDataSink + */ + +void Pump::setInputStream( const Reference< XInputStream >& xStream ) +{ + std::unique_lock aGuard( m_aMutex ); + m_xInput = xStream; + Reference< XConnectable > xConnect( xStream, UNO_QUERY ); + if( xConnect.is() ) + xConnect->setSuccessor( this ); + // data transfer starts in XActiveDataControl::start +} + + +Reference< XInputStream > Pump::getInputStream() +{ + std::unique_lock aGuard( m_aMutex ); + return m_xInput; +} + + +/* + * XActiveDataSource + */ + +void Pump::setOutputStream( const Reference< XOutputStream >& xOut ) +{ + std::unique_lock aGuard( m_aMutex ); + m_xOutput = xOut; + Reference< XConnectable > xConnect( xOut, UNO_QUERY ); + if( xConnect.is() ) + xConnect->setPredecessor( this ); + // data transfer starts in XActiveDataControl::start +} + +Reference< XOutputStream > Pump::getOutputStream() +{ + std::unique_lock aGuard( m_aMutex ); + return m_xOutput; +} + +// XServiceInfo +OUString Pump::getImplementationName() +{ + return "com.sun.star.comp.io.Pump"; +} + +// XServiceInfo +sal_Bool Pump::supportsService(const OUString& ServiceName) +{ + return cppu::supportsService(this, ServiceName); +} + +// XServiceInfo +Sequence< OUString > Pump::getSupportedServiceNames() +{ + return { "com.sun.star.io.Pump" }; +} + +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +io_Pump_get_implementation( + css::uno::XComponentContext* , css::uno::Sequence<css::uno::Any> const&) +{ + return cppu::acquire(new io_stm::Pump()); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/io/source/stm/streamhelper.cxx b/io/source/stm/streamhelper.cxx new file mode 100644 index 000000000..0933ac966 --- /dev/null +++ b/io/source/stm/streamhelper.cxx @@ -0,0 +1,173 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <limits> +#include <string.h> + +#include <com/sun/star/uno/Sequence.hxx> + +#include <com/sun/star/io/BufferSizeExceededException.hpp> + +using namespace ::com::sun::star::uno; + +#include "streamhelper.hxx" + +namespace io_stm { + +void MemFIFO::write( const Sequence< sal_Int8 > &seq ) +{ + writeAt(getSize(), seq); +} + +void MemFIFO::read( Sequence<sal_Int8> &seq , sal_Int32 nBufferLen ) +{ + readAt(0, seq , nBufferLen); + forgetFromStart( nBufferLen ); +} + +void MemFIFO::skip( sal_Int32 nBytesToSkip ) +{ + forgetFromStart( nBytesToSkip ); +} + +MemRingBuffer::MemRingBuffer() : m_p(nullptr), m_nBufferLen(0), m_nStart(0), m_nOccupiedBuffer(0) +{ +} + +MemRingBuffer::~MemRingBuffer() +{ + std::free( m_p ); +} + +void MemRingBuffer::resizeBuffer( sal_Int32 nMinSize ) +{ + sal_Int32 nNewLen = 1; + + while( nMinSize > nNewLen ) { + nNewLen = nNewLen << 1; + } + + // buffer never shrinks ! + if( nNewLen < m_nBufferLen ) { + nNewLen = m_nBufferLen; + } + + if( nNewLen == m_nBufferLen ) + return; + + auto p = static_cast<sal_Int8*>(std::realloc(m_p, nNewLen)); + if (!p) + throw css::io::BufferSizeExceededException( + "MemRingBuffer::resizeBuffer BufferSizeExceededException"); + + m_p = p; + + + if( m_nStart + m_nOccupiedBuffer > m_nBufferLen ) { + memmove( &( m_p[m_nStart+(nNewLen-m_nBufferLen)]) , &(m_p[m_nStart]) , m_nBufferLen - m_nStart ); + m_nStart += nNewLen - m_nBufferLen; + } + m_nBufferLen = nNewLen; +} + + +void MemRingBuffer::readAt( sal_Int32 nPos, Sequence<sal_Int8> &seq , sal_Int32 nBytesToRead ) const +{ + if( nPos + nBytesToRead > m_nOccupiedBuffer ) { + throw css::io::BufferSizeExceededException( + "MemRingBuffer::readAt BufferSizeExceededException"); + } + + sal_Int32 nStartReadingPos = nPos + m_nStart; + if( nStartReadingPos >= m_nBufferLen ) { + nStartReadingPos -= m_nBufferLen; + } + + seq.realloc( nBytesToRead ); + + if( nStartReadingPos + nBytesToRead > m_nBufferLen ) { + sal_Int32 nDeltaLen = m_nBufferLen - nStartReadingPos; + memcpy( seq.getArray() , &(m_p[nStartReadingPos]) , nDeltaLen ); + memcpy( &(seq.getArray()[nDeltaLen]), m_p , nBytesToRead - nDeltaLen ); + } + else { + memcpy( seq.getArray() , &(m_p[nStartReadingPos]) , nBytesToRead ); + } +} + + +void MemRingBuffer::writeAt( sal_Int32 nPos, const Sequence<sal_Int8> &seq ) +{ + checkInvariants(); + const sal_Int32 nLen = seq.getLength(); + + if( nPos < 0 || nPos > std::numeric_limits< sal_Int32 >::max() - nLen ) + { + throw css::io::BufferSizeExceededException( + "MemRingBuffer::writeAt BufferSizeExceededException"); + } + + if( nPos + nLen - m_nOccupiedBuffer > 0 ) { + resizeBuffer( nPos + nLen ); + m_nOccupiedBuffer = nPos + nLen; + } + + sal_Int32 nStartWritingIndex = m_nStart + nPos; + if( nStartWritingIndex >= m_nBufferLen ) { + nStartWritingIndex -= m_nBufferLen; + } + + if( const sal_Int32 nBufferRestLen = m_nBufferLen-nStartWritingIndex; nLen > nBufferRestLen ) { + // two area copy + memcpy( &(m_p[nStartWritingIndex]) , seq.getConstArray(), nBufferRestLen ); + memcpy( m_p , &( seq.getConstArray()[nBufferRestLen] ), nLen - nBufferRestLen ); + + } + else { + // one area copy + memcpy( &( m_p[nStartWritingIndex]), seq.getConstArray() , nLen ); + } + checkInvariants(); +} + + +sal_Int32 MemRingBuffer::getSize() const noexcept +{ + return m_nOccupiedBuffer; +} + +void MemRingBuffer::forgetFromStart( sal_Int32 nBytesToForget ) +{ + checkInvariants(); + if( nBytesToForget > m_nOccupiedBuffer ) { + throw css::io::BufferSizeExceededException( + "MemRingBuffer::forgetFromStart BufferSizeExceededException"); + } + m_nStart += nBytesToForget; + if( m_nStart >= m_nBufferLen ) { + m_nStart = m_nStart - m_nBufferLen; + } + m_nOccupiedBuffer -= nBytesToForget; + checkInvariants(); +} + + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/io/source/stm/streamhelper.hxx b/io/source/stm/streamhelper.hxx new file mode 100644 index 000000000..8cacaf1f2 --- /dev/null +++ b/io/source/stm/streamhelper.hxx @@ -0,0 +1,85 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <com/sun/star/uno/Sequence.hxx> + +#include <assert.h> + +using namespace com::sun::star::uno; + +namespace io_stm +{ + +class MemRingBuffer +{ +public: + MemRingBuffer(); + virtual ~MemRingBuffer(); + + /*** + * overwrites data at given position. Size is automatically extended, when + * data is written beyond end. + ***/ + /// @throws css::io::BufferSizeExceededException + void writeAt( sal_Int32 nPos, const Sequence<sal_Int8> &); + /// @throws css::io::BufferSizeExceededException + void readAt( sal_Int32 nPos, Sequence<sal_Int8> & , sal_Int32 nBytesToRead ) const; + sal_Int32 getSize() const noexcept; + /// @throws css::io::BufferSizeExceededException + void forgetFromStart(sal_Int32 nBytesToForget); + +private: + /// @throws css::io::BufferSizeExceededException + void resizeBuffer(sal_Int32 nMinSize); + void checkInvariants() const { + assert( m_nBufferLen >= 0 ); + assert( m_nOccupiedBuffer >= 0 ); + assert( m_nOccupiedBuffer <= m_nBufferLen ); + assert( m_nStart >= 0 ); + assert( 0 == m_nStart || m_nStart < m_nBufferLen ); + (void) this; // avoid loplugin:staticmethods + } + + sal_Int8 *m_p; + sal_Int32 m_nBufferLen; + sal_Int32 m_nStart; + sal_Int32 m_nOccupiedBuffer; +}; + + +class MemFIFO : + private MemRingBuffer +{ +public: + /// @throws css::io::BufferSizeExceededException + void write( const Sequence<sal_Int8> &); + /// @throws css::io::BufferSizeExceededException + void read( Sequence<sal_Int8> & , sal_Int32 nBytesToRead ); + /// @throws css::io::BufferSizeExceededException + void skip( sal_Int32 nBytesToSkip ); + sal_Int32 getSize() const noexcept + { return MemRingBuffer::getSize(); } + +}; + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/io/test/makefile.mk b/io/test/makefile.mk new file mode 100644 index 000000000..c1d2c9649 --- /dev/null +++ b/io/test/makefile.mk @@ -0,0 +1,83 @@ +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This file incorporates work covered by the following license notice: +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed +# with this work for additional information regarding copyright +# ownership. The ASF licenses this file to you under the Apache +# License, Version 2.0 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.apache.org/licenses/LICENSE-2.0 . +# + +PRJ=.. + +PRJNAME=extensions +TARGET=workben +LIBTARGET=NO + +TARGETTYPE=CUI +ENABLE_EXCEPTIONS=TRUE + +# --- Settings ----------------------------------------------------- + +.INCLUDE : settings.mk +.IF "$(L10N_framework)"=="" +# --- Files -------------------------------------------------------- + +OBJFILES= $(OBJ)$/testcomponent.obj \ + $(OBJ)$/testconnection.obj + +UNOUCRDEP=$(SOLARBINDIR)$/udkapi.rdb +UNOUCRRDB=$(SOLARBINDIR)$/udkapi.rdb + +# output directory (one dir for each project) +UNOUCROUT=$(OUT)$/inc + +UNOTYPES = com.sun.star.connection.XConnector \ + com.sun.star.connection.XAcceptor \ + com.sun.star.registry.XImplementationRegistration \ + com.sun.star.lang.XComponent \ + com.sun.star.lang.XSingleServiceFactory \ + com.sun.star.lang.XMultiServiceFactory \ + com.sun.star.test.XSimpleTest \ + com.sun.star.lang.XSingleComponentFactory \ + com.sun.star.lang.XMultiComponentFactory + + +# +# std testcomponent +# + +APP1TARGET = testcomponent +APP1OBJS = $(OBJ)$/testcomponent.obj +APP1STDLIBS = $(SALLIB) \ + $(CPPULIB)\ + $(CPPUHELPERLIB) + +APP2TARGET = testconnection +APP2OBJS = $(OBJ)$/testconnection.obj +APP2STDLIBS = $(SALLIB) \ + $(CPPULIB) \ + $(CPPUHELPERLIB) + + + +# --- Targets ------------------------------------------------------ + +ALL : $(BIN)$/applicat.rdb \ + ALLTAR + +$(BIN)$/applicat.rdb: $(SOLARBINDIR)$/udkapi.rdb + rm -f $@ + regmerge $@ / $? + +.ENDIF # L10N_framework + +.INCLUDE : target.mk diff --git a/io/test/stm/datatest.cxx b/io/test/stm/datatest.cxx new file mode 100644 index 000000000..a085bf6d7 --- /dev/null +++ b/io/test/stm/datatest.cxx @@ -0,0 +1,1074 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <stdio.h> + +#include <com/sun/star/test/XSimpleTest.hpp> +#include <com/sun/star/io/XActiveDataSink.hpp> +#include <com/sun/star/io/XActiveDataSource.hpp> +#include <com/sun/star/io/XObjectInputStream.hpp> +#include <com/sun/star/io/XObjectOutputStream.hpp> +#include <com/sun/star/io/XMarkableStream.hpp> +#include <com/sun/star/io/XConnectable.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/lang/WrappedTargetException.hpp> +#include <com/sun/star/lang/IllegalArgumentException.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> + +#include <cppuhelper/factory.hxx> +#include <cppuhelper/implbase.hxx> + +#include <osl/conditn.hxx> + +#include <string.h> + +using namespace ::osl; +using namespace ::cppu; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::io; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::test; +using namespace ::com::sun::star::beans; +// streams + +#include "testfactreg.hxx" + +#define DATASTREAM_TEST_MAX_HANDLE 1 + +/* + * The following test class tests XDataInputStream and XDataOutputStream at equal terms, + * so when errors occur, it may be in either one implementation. + * The class also uses com.sun.star.io.pipe. If problems occur, make sure to run also the + * pipe test routines ( test.com.sun.star.io.pipe ). + */ + +class ODataStreamTest : + public WeakImplHelper< XSimpleTest > +{ +public: + explicit ODataStreamTest( const Reference < XMultiServiceFactory > & rFactory ) : + m_rFactory( rFactory ) + {} + +public: + virtual void SAL_CALL testInvariant(const OUString& TestName, const Reference < XInterface >& TestObject) + throw ( IllegalArgumentException, + RuntimeException); + + virtual sal_Int32 SAL_CALL test( const OUString& TestName, + const Reference < XInterface >& TestObject, + sal_Int32 hTestHandle) + throw ( IllegalArgumentException, + RuntimeException); + + virtual sal_Bool SAL_CALL testPassed() throw ( RuntimeException); + virtual Sequence< OUString > SAL_CALL getErrors() throw (RuntimeException); + virtual Sequence< Any > SAL_CALL getErrorExceptions() throw (RuntimeException); + virtual Sequence< OUString > SAL_CALL getWarnings() throw (RuntimeException); + +private: + void testSimple( const Reference < XDataInputStream > & , const Reference < XDataOutputStream > &); + +protected: + Sequence<Any> m_seqExceptions; + Sequence<OUString> m_seqErrors; + Sequence<OUString> m_seqWarnings; + + Reference < XMultiServiceFactory > m_rFactory; +}; + + +void ODataStreamTest::testInvariant( + const OUString& TestName, + const Reference < XInterface >& TestObject ) + throw ( IllegalArgumentException, + RuntimeException) +{ + if( OUString("com.sun.star.io.DataInputStream") == TestName ) { + Reference < XConnectable > connect( TestObject , UNO_QUERY ); + Reference < XActiveDataSink > active( TestObject , UNO_QUERY ); + Reference < XInputStream > input( TestObject , UNO_QUERY ); + Reference < XDataInputStream > dataInput( TestObject , UNO_QUERY ); + + WARNING_ASSERT( connect.is(), "XConnectable cannot be queried" ); + WARNING_ASSERT( active.is() , "XActiveDataSink cannot be queried" ); + ERROR_ASSERT( input.is() , "XInputStream cannot be queried" ); + ERROR_ASSERT( dataInput.is() , "XDataInputStream cannot be queried" ); + + + } + else if( OUString("com.sun.star.io.DataOutputStream") == TestName ) { + Reference < XConnectable > connect( TestObject , UNO_QUERY ); + Reference < XActiveDataSource > active( TestObject , UNO_QUERY ); + Reference < XOutputStream > output( TestObject , UNO_QUERY ); + Reference < XDataOutputStream > dataOutput( TestObject , UNO_QUERY ); + + WARNING_ASSERT( connect.is(), "XConnectable cannot be queried" ); + WARNING_ASSERT( active.is() , "XActiveDataSink cannot be queried" ); + ERROR_ASSERT( output.is() , "XInputStream cannot be queried" ); + ERROR_ASSERT( dataOutput.is(), "XDataInputStream cannot be queried" ); + + } + + Reference < XServiceInfo > info( TestObject, UNO_QUERY ); + ERROR_ASSERT( info.is() , "XServiceInfo not supported !" ); + if( info.is() ) + { + ERROR_ASSERT( info->supportsService( TestName ), "XServiceInfo test failed" ); + ERROR_ASSERT( ! info->supportsService("bla bluzb") , "XServiceInfo test failed" ); + } + +} + + +sal_Int32 ODataStreamTest::test( + const OUString& TestName, + const Reference < XInterface >& TestObject, + sal_Int32 hTestHandle) + throw ( IllegalArgumentException, + RuntimeException) +{ + if( OUString("com.sun.star.io.DataInputStream") == TestName || + OUString("com.sun.star.io.DataOutputStream") == TestName ) { + + try + { + if( 0 == hTestHandle ) { + testInvariant( TestName , TestObject ); + } + else { + Reference <XActiveDataSink > rSink( TestObject, UNO_QUERY ); + Reference <XActiveDataSource > rSource( TestObject , UNO_QUERY ); + + Reference < XDataInputStream > rInput( TestObject , UNO_QUERY ); + Reference < XDataOutputStream > rOutput( TestObject , UNO_QUERY ); + + + Reference < XInterface > x = m_rFactory->createInstance( + "com.sun.star.io.Pipe" ); + + Reference < XInputStream > rPipeInput( x , UNO_QUERY ); + Reference < XOutputStream > rPipeOutput( x , UNO_QUERY ); + + if( ! rSink.is() ) { + x = m_rFactory->createInstance( + "com.sun.star.io.DataInputStream" ); + rInput.set( x , UNO_QUERY); + rSink.set( x , UNO_QUERY ); + } + else if ( !rSource.is() ) + { + x = m_rFactory->createInstance( + "com.sun.star.io.DataOutputStream" ); + rOutput.set( x , UNO_QUERY ); + rSource.set( x, UNO_QUERY ); + } + + OSL_ASSERT( rPipeInput.is() ); + OSL_ASSERT( rPipeOutput.is() ); + rSink->setInputStream( rPipeInput ); + rSource->setOutputStream( rPipeOutput ); + + OSL_ASSERT( rSink->getInputStream().is() ); + OSL_ASSERT( rSource->getOutputStream().is() ); + + if( 1 == hTestHandle ) { + testSimple( rInput , rOutput ); + } + } + } + catch( const Exception & e ) + { + OString o = OUStringToOString( e.Message , RTL_TEXTENCODING_ASCII_US ); + BUILD_ERROR( 0 , o.getStr() ); + } + catch( ... ) + { + BUILD_ERROR( 0 , "unknown exception (Exception is not base class)" ); + } + + hTestHandle ++; + + if( hTestHandle >= 2) { + // all tests finished. + hTestHandle = -1; + } + } + else { + BUILD_ERROR( 0 , "service not supported by test." ); + } + return hTestHandle; +} + + +sal_Bool ODataStreamTest::testPassed() throw (RuntimeException) +{ + return m_seqErrors.getLength() == 0; +} + + +Sequence< OUString > ODataStreamTest::getErrors() throw (RuntimeException) +{ + return m_seqErrors; +} + + +Sequence< Any > ODataStreamTest::getErrorExceptions() throw (RuntimeException) +{ + return m_seqExceptions; +} + + +Sequence< OUString > ODataStreamTest::getWarnings() throw (RuntimeException) +{ + return m_seqWarnings; +} + +void ODataStreamTest::testSimple( const Reference < XDataInputStream > &rInput, + const Reference < XDataOutputStream > &rOutput ) +{ + rOutput->writeLong( 0x34ff3c ); + rOutput->writeLong( 0x34ff3d ); + rOutput->writeLong( -1027 ); + + ERROR_ASSERT( 0x34ff3c == rInput->readLong() , "long read/write mismatch" ); + ERROR_ASSERT( 0x34ff3d == rInput->readLong() , "long read/write mismatch" ); + ERROR_ASSERT( -1027 == rInput->readLong() , "long read/write mismatch" ); + + rOutput->writeByte( 0x77 ); + ERROR_ASSERT( 0x77 == rInput->readByte() , "byte read/write mismatch" ); + + rOutput->writeBoolean( 25 ); + ERROR_ASSERT( rInput->readBoolean() , "boolean read/write mismatch" ); + + rOutput->writeBoolean( sal_False ); + ERROR_ASSERT( ! rInput->readBoolean() , "boolean read/write mismatch" ); + + rOutput->writeFloat( (float) 42.42 ); + ERROR_ASSERT( rInput->readFloat() == ((float)42.42) , "float read/write mismatch" ); + + rOutput->writeDouble( (double) 42.42 ); + ERROR_ASSERT( rInput->readDouble() == 42.42 , "double read/write mismatch" ); + + rOutput->writeHyper( 0x123456789abcdefLL ); + ERROR_ASSERT( rInput->readHyper() == 0x123456789abcdefLL , "int64 read/write mismatch" ); + + rOutput->writeUTF( OUString("Live long and prosper !") ); + ERROR_ASSERT( rInput->readUTF() == "Live long and prosper !", + "UTF read/write mismatch" ); + + Sequence<sal_Unicode> wc(0x10001); + for( int i = 0 ; i < 0x10000 ; i ++ ) { + wc.getArray()[i] = L'c'; + } + wc.getArray()[0x10000] = 0; + OUString str( wc.getArray() , 0x10000 ); + rOutput->writeUTF( str ); + ERROR_ASSERT( rInput->readUTF() == str , "error reading 64k block" ); + + rOutput->closeOutput(); + try + { + rInput->readLong(); + ERROR_ASSERT( 0 , "eof-exception does not occur !" ); + } + catch ( IOException & ) + { + //ok + } + catch( ... ) + { + ERROR_ASSERT( 0 , "wrong exception after reading beyond eof" ); + } + + Sequence<sal_Int8> dummy (1); + ERROR_ASSERT( ! rInput->readBytes( dummy , 1 ), + "stream must be on eof !" ); + + rInput->closeInput(); + + try + { + rOutput->writeByte( 1 ); + ERROR_ASSERT( 0 , "writing still possible though chain must be interrupted" ); + } + catch( IOException & ) + { + // ok + } + catch( ... ) { + ERROR_ASSERT( 0 , "IOException expected, but another exception was thrown" ); + } + +} + + +/** +* for external binding +* +* +**/ +Reference < XInterface > SAL_CALL ODataStreamTest_CreateInstance( const Reference < XMultiServiceFactory > & rSMgr ) throw(Exception) +{ + ODataStreamTest *p = new ODataStreamTest( rSMgr ); + return Reference < XInterface > ( (static_cast< OWeakObject * >(p)) ); +} + +Sequence<OUString> ODataStreamTest_getSupportedServiceNames( int i) throw () +{ + Sequence<OUString> aRet { ODataStreamTest_getImplementationName( i) }; + return aRet; +} + +OUString ODataStreamTest_getServiceName( int i) throw () +{ + if( 1 == i ) { + return OUString( "test.com.sun.star.io.DataInputStream" ); + } + else { + return OUString( "test.com.sun.star.io.DataOutputStream" ); + } +} + +OUString ODataStreamTest_getImplementationName( int i) throw () +{ + if( 1 == i ) { + return OUString( + "test.com.sun.star.comp.extensions.stm.DataInputStream" ); + } + else { + return OUString( "test.com.sun.star.comp.extensions.stm.DataOutputStream" ); + } +} + +class MyPersistObject : public WeakImplHelper< XPersistObject , XPropertySet > +{ +public: + MyPersistObject( ) : m_sServiceName( OMyPersistObject_getServiceName() ) , + m_l( -392 ), + m_f( 7883.2 ), + m_d( -123923.5 ), + m_b( sal_True ), + m_byte( 42 ), + m_c( 429 ), + m_s( OUString( "foo" ) ) + {} + explicit MyPersistObject( const OUString & sServiceName ) : m_sServiceName( sServiceName ) + {} + + +public: + virtual OUString SAL_CALL getServiceName() throw (RuntimeException); + virtual void SAL_CALL write( const Reference< XObjectOutputStream >& OutStream ) + throw (IOException, RuntimeException); + virtual void SAL_CALL read(const Reference< XObjectInputStream >& InStream) + throw (IOException, RuntimeException); + +public: + + virtual Reference< XPropertySetInfo > SAL_CALL getPropertySetInfo() + throw (RuntimeException); + + virtual void SAL_CALL setPropertyValue(const OUString& aPropertyName, const Any& aValue) + throw ( UnknownPropertyException, + PropertyVetoException, + IllegalArgumentException, + WrappedTargetException, + RuntimeException); + virtual Any SAL_CALL getPropertyValue(const OUString& PropertyName) + throw ( UnknownPropertyException, + WrappedTargetException, + RuntimeException); + virtual void SAL_CALL addPropertyChangeListener( + const OUString& aPropertyName, + const Reference < XPropertyChangeListener > & xListener) + throw ( UnknownPropertyException, + WrappedTargetException, + RuntimeException); + + virtual void SAL_CALL removePropertyChangeListener( + const OUString& aPropertyName, + const Reference< XPropertyChangeListener > & aListener) + throw ( UnknownPropertyException, + WrappedTargetException, + RuntimeException); + virtual void SAL_CALL addVetoableChangeListener( + const OUString& PropertyName, + const Reference< XVetoableChangeListener > & aListener) + throw ( UnknownPropertyException, + WrappedTargetException, + RuntimeException); + + virtual void SAL_CALL removeVetoableChangeListener( + const OUString& PropertyName, + const Reference< XVetoableChangeListener >& aListener) + throw ( UnknownPropertyException, + WrappedTargetException, + RuntimeException); + +public: + sal_Int32 m_l; + float m_f; + double m_d; + sal_Bool m_b; + sal_Int8 m_byte; + sal_Unicode m_c; + OUString m_s; + Reference< XPersistObject > m_ref; + OUString m_sServiceName; +}; + + +Reference <XPropertySetInfo > MyPersistObject::getPropertySetInfo() + throw (RuntimeException) +{ + return Reference< XPropertySetInfo >(); +} + +void MyPersistObject::setPropertyValue( + const OUString& aPropertyName, + const Any& aValue) + throw ( UnknownPropertyException, + PropertyVetoException, + IllegalArgumentException, + WrappedTargetException, + RuntimeException) +{ + if( aPropertyName.equalsAscii("long") ) { + aValue >>= m_l; + } + else if ( aPropertyName.equalsAscii("float") ) { + aValue >>= m_f; + } + else if( aPropertyName.equalsAscii("double") ) { + aValue >>= m_d; + } + else if( aPropertyName.equalsAscii("bool") ) { + aValue >>= m_b; + } + else if( aPropertyName.equalsAscii("byte" ) ) { + aValue >>= m_byte; + } + else if( aPropertyName.equalsAscii("char") ) { + aValue >>= m_c; + } + else if( aPropertyName.equalsAscii("string") ) { + aValue >>= m_s; + } + else if( aPropertyName.equalsAscii("object") ) { + if( aValue.getValueType() == cppu::UnoType<XPersistObject>::get()) + { + aValue >>= m_ref; + } + else + { + m_ref = 0; + } + } +} + + +Any MyPersistObject::getPropertyValue(const OUString& aPropertyName) + throw ( UnknownPropertyException, + WrappedTargetException, + RuntimeException) +{ + Any aValue; + if( aPropertyName.equalsAscii("long" ) ) { + aValue <<= m_l; + } + else if ( aPropertyName.equalsAscii("float") ) { + aValue <<= m_f; + } + else if( aPropertyName.equalsAscii("double") ) { + aValue <<= m_d; + } + else if( aPropertyName.equalsAscii("bool") ) { + aValue <<= m_b; + } + else if( aPropertyName.equalsAscii("byte") ) { + aValue <<= m_byte; + } + else if( aPropertyName.equalsAscii("char" ) ) { + aValue <<= m_c; + } + else if( aPropertyName.equalsAscii("string") ) { + aValue <<= m_s; + } + else if( aPropertyName.equalsAscii("object" ) ) + { + aValue <<= m_ref; + } + return aValue; +} + + +void MyPersistObject::addPropertyChangeListener( + const OUString& aPropertyName, + const Reference< XPropertyChangeListener > & xListener) + throw ( UnknownPropertyException, + WrappedTargetException, + RuntimeException) +{ + +} + +void MyPersistObject::removePropertyChangeListener( + const OUString& aPropertyName, + const Reference < XPropertyChangeListener > & aListener) + throw ( UnknownPropertyException, + WrappedTargetException, + RuntimeException) +{ +} + + +void MyPersistObject::addVetoableChangeListener( + const OUString& PropertyName, + const Reference <XVetoableChangeListener >& aListener) + throw ( UnknownPropertyException, + WrappedTargetException, + RuntimeException) +{ + +} + +void MyPersistObject::removeVetoableChangeListener( + const OUString& PropertyName, + const Reference < XVetoableChangeListener > & aListener) + throw ( UnknownPropertyException, + WrappedTargetException, + RuntimeException) +{ + +} + + +OUString MyPersistObject::getServiceName() throw (RuntimeException) +{ + return m_sServiceName; +} + +void MyPersistObject::write( const Reference< XObjectOutputStream > & rOut ) + throw (IOException,RuntimeException) +{ + rOut->writeLong( m_l); + rOut->writeFloat( m_f ); + rOut->writeDouble( m_d ); + rOut->writeBoolean( m_b ); + rOut->writeByte( m_byte ); + rOut->writeChar( m_c ); + rOut->writeUTF( m_s ); + rOut->writeObject( m_ref ); +} + + +void MyPersistObject::read( const Reference< XObjectInputStream > & rIn ) + throw (IOException, RuntimeException) +{ + m_l = rIn->readLong(); + m_f = rIn->readFloat(); + m_d = rIn->readDouble(); + m_b = rIn->readBoolean(); + m_byte = rIn->readByte(); + m_c = rIn->readChar(); + m_s = rIn->readUTF(); + m_ref = rIn->readObject(); +} + +Reference < XInterface > SAL_CALL OMyPersistObject_CreateInstance( + const Reference < XMultiServiceFactory > & rSMgr ) + throw(Exception) +{ + MyPersistObject *p = new MyPersistObject( ); + return Reference < XInterface > ( (static_cast< OWeakObject * >(p)) ); +} + +Sequence<OUString> OMyPersistObject_getSupportedServiceNames( ) throw () +{ + Sequence<OUString> aRet { OMyPersistObject_getImplementationName() }; + return aRet; +} + +OUString OMyPersistObject_getServiceName( ) throw () +{ + return OUString( "test.com.sun.star.io.PersistTest" ); +} + +OUString OMyPersistObject_getImplementationName( ) throw () +{ + return OUString( "test.com.sun.star.io.PersistTest" ); +} + +class OObjectStreamTest : + public ODataStreamTest +{ +public: + explicit OObjectStreamTest( const Reference < XMultiServiceFactory > &r) : ODataStreamTest(r) {} + +public: + virtual void SAL_CALL testInvariant(const OUString& TestName, + const Reference < XInterface >& TestObject) + throw ( IllegalArgumentException, + RuntimeException); + + virtual sal_Int32 SAL_CALL test( + const OUString& TestName, + const Reference < XInterface >& TestObject, + sal_Int32 hTestHandle) + throw ( IllegalArgumentException, + RuntimeException); + + +private: + void testObject( const Reference <XObjectOutputStream > &rOut, + const Reference <XObjectInputStream> &rIn ); + +private: +}; + + +void OObjectStreamTest::testInvariant( const OUString& TestName, + const Reference < XInterface >& TestObject ) + throw ( IllegalArgumentException, RuntimeException) +{ + + if( OUString( "com.sun.star.io.ObjectInputStream" ) + == TestName ) + { + ODataStreamTest::testInvariant( TestName , TestObject ); + Reference< XObjectInputStream > dataInput( TestObject , UNO_QUERY ); + Reference< XMarkableStream > markable( TestObject , UNO_QUERY ); + ERROR_ASSERT( dataInput.is() , "XObjectInputStream cannot be queried" ); + ERROR_ASSERT( markable.is() , "XMarkableStream cannot be queried" ); + } + else if( OUString( "com.sun.star.io.ObjectOutputStream" ) + == TestName ) + { + ODataStreamTest::testInvariant( TestName , TestObject ); + Reference < XMarkableStream > markable( TestObject , UNO_QUERY ); + Reference < XObjectOutputStream > dataOutput( TestObject , UNO_QUERY ); + ERROR_ASSERT( dataOutput.is(), "XObjectOutputStream cannot be queried" ); + ERROR_ASSERT( markable.is() , "XMarkableStream cannot be queried" ); + } + + Reference < XServiceInfo > info( TestObject, UNO_QUERY ); + ERROR_ASSERT( info.is() , "XServiceInfo not supported !" ); + if( info.is() ) + { + ERROR_ASSERT( info->supportsService( TestName ), "XServiceInfo test failed" ); + ERROR_ASSERT( ! info->supportsService("bla bluzb") , "XServiceInfo test failed" ); + } + +} + +sal_Int32 OObjectStreamTest::test( const OUString& TestName, + const Reference < XInterface >& TestObject, + sal_Int32 hTestHandle) + throw ( IllegalArgumentException, + RuntimeException) +{ + if( TestName.equalsAscii("com.sun.star.io.ObjectInputStream") || + TestName.equalsAscii("com.sun.star.io.ObjectOutputStream") ) { + + try + { + if( 0 == hTestHandle ) { + testInvariant( TestName , TestObject ); + } + else if( DATASTREAM_TEST_MAX_HANDLE >= hTestHandle ) { + sal_Int32 hOldHandle = hTestHandle; + hTestHandle = ODataStreamTest::test( + OUString( "com.sun.star.io.DataInputStream" ), + TestObject , hTestHandle ); + if( hTestHandle == -1 ){ + hTestHandle = hOldHandle; + } + } + else { + + Reference<XActiveDataSink > rSink( TestObject, UNO_QUERY ); + Reference<XActiveDataSource > rSource( TestObject , UNO_QUERY ); + + Reference< XObjectInputStream > rInput( TestObject , UNO_QUERY ); + Reference< XObjectOutputStream > rOutput( TestObject , UNO_QUERY ); + + + Reference < XInterface > x = m_rFactory->createInstance( + "com.sun.star.io.Pipe" ); + + Reference <XInputStream > rPipeInput( x , UNO_QUERY ); + Reference <XOutputStream > rPipeOutput( x , UNO_QUERY ); + + x = m_rFactory->createInstance( + "com.sun.star.io.MarkableInputStream" ); + + Reference <XInputStream > markableInput( x , UNO_QUERY ); + Reference <XActiveDataSink> markableSink( x , UNO_QUERY ); + + x = m_rFactory->createInstance( "com.sun.star.io.MarkableOutputStream" ); + Reference <XOutputStream > markableOutput( x , UNO_QUERY ); + Reference <XActiveDataSource > markableSource( x , UNO_QUERY ); + + OSL_ASSERT( markableInput.is() ); + OSL_ASSERT( markableOutput.is() ); + OSL_ASSERT( markableSink.is() ); + OSL_ASSERT( markableSource.is() ); + + markableSink->setInputStream( rPipeInput ); + markableSource->setOutputStream( rPipeOutput ); + + if( ! rSink.is() ) { + x = m_rFactory->createInstance( + "com.sun.star.io.ObjectInputStream" ); + rInput.set( x , UNO_QUERY ); + rSink.set( x , UNO_QUERY ); + } + else if ( !rSource.is() ) { + x = m_rFactory->createInstance( + "com.sun.star.io.ObjectOutputStream" ); + rOutput.set( x , UNO_QUERY ); + rSource.set( x, UNO_QUERY ); + } + + OSL_ASSERT( rPipeInput.is() ); + OSL_ASSERT( rPipeOutput.is() ); + + rSink->setInputStream( markableInput ); + rSource->setOutputStream( markableOutput ); + + OSL_ASSERT( rSink->getInputStream().is() ); + OSL_ASSERT( rSource->getOutputStream().is() ); + + if( 1 + DATASTREAM_TEST_MAX_HANDLE == hTestHandle ) { + testObject( rOutput , rInput); + } + rInput->closeInput(); + rOutput->closeOutput(); + + } + } + catch( const Exception &e ) { + OString o = OUStringToOString( e.Message , RTL_TEXTENCODING_ASCII_US ); + BUILD_ERROR( 0 , o.getStr() ); + } + catch( ... ) { + BUILD_ERROR( 0 , "unknown exception (Exception is not base class)" ); + } + + hTestHandle ++; + + if( hTestHandle > 1 +DATASTREAM_TEST_MAX_HANDLE ) { + // all tests finished. + hTestHandle = -1; + } + } + else { + BUILD_ERROR( 0 , "service not supported by test." ); + } + return hTestHandle; +} + + +sal_Bool compareMyPropertySet( Reference< XPropertySet > &r1 , Reference < XPropertySet > &r2 ) +{ + sal_Bool b = sal_True; + + if( r1->getPropertyValue("long").getValueType() == cppu::UnoType<void>::get() || + r2->getPropertyValue("long").getValueType() == cppu::UnoType<void>::get() ) { + + // one of the objects is not the correct propertyset ! + fprintf( stderr, "compareMyPropertySet: 1\n" ); + return sal_False; + } + + b = b && ( r1->getPropertyValue("long") == + r2->getPropertyValue("long") ); + if( ! b ) fprintf( stderr, "compareMyPropertySet: 2\n" ); + + b = b && ( r1->getPropertyValue("float") == + r2->getPropertyValue("float") ); + if( ! b ){ + float f1(0.0); + float f2(0.0); + r1->getPropertyValue("float") >>= f1; + r2->getPropertyValue("float") >>= f2; + fprintf( stderr, "compareMyPropertySet: %f %f 3\n",f1,f2 ); + } + + b = b && ( r1->getPropertyValue("double") == + r2->getPropertyValue("double") ); + if( ! b ) fprintf( stderr, "compareMyPropertySet: 4\n" ); + + sal_Bool b1(sal_False), b2(sal_False); + Any a =r1->getPropertyValue("bool"); + a >>= b1; + a = r2->getPropertyValue("bool"); + a >>= b2; + b = b && ( (b1 && b2) || b1 == b2 ); + if( ! b ) fprintf( stderr, "compareMyPropertySet: 5\n" ); + +// b = b && r1->getPropertyValue("bool") == +// r2->getPropertyValue("bool") ); + + b = b && ( r1->getPropertyValue("byte") == + r2->getPropertyValue("byte") ); + if( ! b ) fprintf( stderr, "compareMyPropertySet: 6\n" ); + + b = b && ( r1->getPropertyValue("char") == + r2->getPropertyValue("char") ); + if( ! b ) fprintf( stderr, "compareMyPropertySet: 7\n" ); + + b = b && ( r1->getPropertyValue("string") == + r2->getPropertyValue("string")); + if( ! b ) fprintf( stderr, "compareMyPropertySet: 8\n" ); + + Any o1 = r1->getPropertyValue("object"); + Any o2 = r2->getPropertyValue("object"); + + if( o1.getValueType() == cppu::UnoType<XPersistObject>::get()) { + + if( o2.getValueType() == cppu::UnoType<XPersistObject>::get()) { + Reference < XPersistObject > rPersist1; + Reference < XPersistObject > rPersist2; + o1 >>= rPersist1; + o2 >>= rPersist2; + Reference <XPropertySet > rProp1( rPersist1 , UNO_QUERY ); + Reference < XPropertySet > rProp2( rPersist2 , UNO_QUERY ); + + if( rProp1.is() && rProp2.is() && ! ( rProp1 == rProp2 ) + &&( rProp1 != r1 )) { + b = b && compareMyPropertySet( rProp1 , rProp2 ); + } + } + else { + b = sal_False; + } + if( ! b ) fprintf( stderr, "compareMyPropertySet: 9\n" ); + } + else { + if( o2.getValueType() == cppu::UnoType<XPersistObject>::get()) { + b = sal_False; + } + if( ! b ) fprintf( stderr, "compareMyPropertySet: 10\n" ); + } + + return b; +} + +void OObjectStreamTest::testObject( const Reference< XObjectOutputStream > &rOut, + const Reference < XObjectInputStream > &rIn ) +{ + ERROR_ASSERT( rOut.is() , "no objectOutputStream" ); + ERROR_ASSERT( rIn.is() , "no objectInputStream" ); + + + // tests, if saving an object with an unknown service name allows + // reading the data behind the object ! + { + Reference < XInterface > x = * new MyPersistObject( + OUString( "bla blubs") ); + + Reference< XPersistObject > persistRef( x , UNO_QUERY ); + ERROR_ASSERT( persistRef.is() , "couldn't instantiate PersistTest object" ); + + rOut->writeObject( persistRef ); + rOut->writeLong( (sal_Int32) 0xdeadbeef ); + + ERROR_ASSERT( 0 != rIn->available() , "no data arrived at input" ); + + try + { + Reference <XPersistObject > xReadPersistRef = rIn->readObject(); + ERROR_ASSERT( 0 , "expected exception not thrown" ); + } + catch( IOException & ) + { + // all is ok + } + + ERROR_ASSERT( (sal_Int32) 0xdeadbeef == rIn->readLong() , + "wrong data after object with unknown service name." ); + } + + { + Reference < XInterface > x = m_rFactory->createInstance( + "test.com.sun.star.io.PersistTest"); + Reference< XPersistObject > persistRef( x , UNO_QUERY ); + + ERROR_ASSERT( persistRef.is() , "couldn't instantiate PersistTest object" ); + + Reference < XPropertySet > rProp( persistRef , UNO_QUERY ); + ERROR_ASSERT( rProp.is() , "test object is no property set " ); + + Any any; + sal_Int32 i = 0x83482; + any <<= i; + rProp->setPropertyValue("long", any ); + + float f = (float)42.23; + any <<= f; + rProp->setPropertyValue("float", any ); + + double d = 233.321412; + any <<= d; + rProp->setPropertyValue("double", any ); + + sal_Bool b = sal_True; + any.setValue( &b , cppu::UnoType<bool>::get() ); + rProp->setPropertyValue("bool", any ); + + sal_Int8 by = 120; + any <<= by; + rProp->setPropertyValue("byte", any ); + + sal_Unicode c = 'h'; + any.setValue( &c , cppu::UnoType<cppu::UnoCharType>::get() ); + rProp->setPropertyValue("char", any ); + + OUString str( "hi du !" ); + any <<= str; + rProp->setPropertyValue("string", any ); + + any <<= persistRef; + rProp->setPropertyValue("object", any ); + + // do read and write + rOut->writeObject( persistRef ); + ERROR_ASSERT( 0 != rIn->available() , "no data arrived at input" ); + Reference< XPersistObject > xReadPersist = rIn->readObject( ); + + Reference< XPropertySet > rPropRead( xReadPersist , UNO_QUERY ); + ERROR_ASSERT( compareMyPropertySet( rProp , rPropRead ) , "objects has not been read properly !" ); + + // destroy selfreferences + rProp->setPropertyValue("object", Any() ); + rPropRead->setPropertyValue("object", Any() ); + } + + { + Reference< XMarkableStream > markableOut( rOut , UNO_QUERY ); + ERROR_ASSERT( markableOut.is() , "markable stream cannot be queried" ); + + // do the same thing multiple times to check if + // buffering and marks work correctly + for( int i = 0 ; i < 2000 ; i ++ ) { + + Reference < XInterface > x = m_rFactory->createInstance("test.com.sun.star.io.PersistTest"); + Reference< XPersistObject > persistRef( x , UNO_QUERY ); + + Reference < XPropertySet > rProp( persistRef , UNO_QUERY ); + ERROR_ASSERT( rProp.is() , "test object is no property set " ); + + Any any; + sal_Int32 i = 0x83482; + any <<= i; + rProp->setPropertyValue("long", any ); + + float f = 42.23; + any <<= f; + rProp->setPropertyValue("float", any ); + + double d = 233.321412; + any <<= d; + rProp->setPropertyValue("double", any ); + + sal_Bool b = sal_True; + any.setValue( &b , cppu::UnoType<bool>::get() ); + rProp->setPropertyValue("bool", any ); + + sal_Int8 by = 120; + any <<= by; + rProp->setPropertyValue("byte", any ); + + sal_Unicode c = 'h'; + any.setValue( &c , cppu::UnoType<cppu::UnoCharType>::get() ); + rProp->setPropertyValue("char", any ); + + OUString str( "hi du !" ); + any <<= str; + rProp->setPropertyValue("string", any ); + + x = m_rFactory->createInstance("test.com.sun.star.io.PersistTest"); + Reference <XPersistObject > persist2ndRef( x , UNO_QUERY ); + + // Note : persist2ndRef contains coincident values, but also coincident values must be + // saved properly ! + any <<= persist2ndRef; + rProp->setPropertyValue("object", any ); + + // simply test, if markable operations and object operations do not interfere + sal_Int32 nMark = markableOut->createMark(); + + // do read and write + rOut->writeObject( persistRef ); + + // further markable tests ! + sal_Int32 nOffset = markableOut->offsetToMark( nMark ); + markableOut->jumpToMark( nMark ); + markableOut->deleteMark( nMark ); + markableOut->jumpToFurthest(); + + + ERROR_ASSERT( 0 != rIn->available() , "no data arrived at input" ); + Reference < XPersistObject > xReadPersistRef = rIn->readObject( ); + + Reference< XPropertySet > rProp1( persistRef , UNO_QUERY ); + Reference< XPropertySet > rProp2( xReadPersistRef , UNO_QUERY ); + ERROR_ASSERT( compareMyPropertySet( rProp1, rProp2) , + "objects has not been read properly !" ); + } + } +} + + +Reference < XInterface > SAL_CALL OObjectStreamTest_CreateInstance( const Reference < XMultiServiceFactory > & rSMgr ) throw(Exception) +{ + OObjectStreamTest *p = new OObjectStreamTest( rSMgr ); + return Reference < XInterface > ( (static_cast< OWeakObject * >(p)) ); +} + +Sequence<OUString> OObjectStreamTest_getSupportedServiceNames( int i) throw () +{ + Sequence<OUString> aRet { OObjectStreamTest_getImplementationName( i) }; + return aRet; +} + +OUString OObjectStreamTest_getServiceName( int i) throw () +{ + if( 1 == i ) { + return OUString( "test.com.sun.star.io.ObjectInputStream" ); + } + else { + return OUString( "test.com.sun.star.io.ObjectOutputStream"); + } +} + +OUString OObjectStreamTest_getImplementationName( int i) throw () +{ + if( 1 == i ) { + return OUString( "test.com.sun.star.comp.extensions.stm.ObjectInputStream" ); + } + else { + return OUString( "test.com.sun.star.comp.extensions.stm.ObjectOutputStream"); + } +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/io/test/stm/exports.dxp b/io/test/stm/exports.dxp new file mode 100644 index 000000000..86214860d --- /dev/null +++ b/io/test/stm/exports.dxp @@ -0,0 +1,2 @@ +component_getFactory +component_writeInfo diff --git a/io/test/stm/makefile.mk b/io/test/stm/makefile.mk new file mode 100644 index 000000000..1a7eaad0e --- /dev/null +++ b/io/test/stm/makefile.mk @@ -0,0 +1,89 @@ +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This file incorporates work covered by the following license notice: +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed +# with this work for additional information regarding copyright +# ownership. The ASF licenses this file to you under the Apache +# License, Version 2.0 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.apache.org/licenses/LICENSE-2.0 . +# +PRJ=..$/.. + +PRJNAME=io +TARGET=teststm +ENABLE_EXCEPTIONS=TRUE + +# --- Settings ----------------------------------------------------- +.INCLUDE : settings.mk +.IF "$(L10N_framework)"=="" +# --- Files -------------------------------------------------------- +UNOUCRDEP=$(SOLARBINDIR)$/udkapi.rdb +UNOUCRRDB=$(SOLARBINDIR)$/udkapi.rdb + +# output directory (one dir for each project) +UNOUCROUT=$(OUT)$/inc + +UNOTYPES = com.sun.star.test.XSimpleTest \ + com.sun.star.beans.XPropertySet \ + com.sun.star.io.UnexpectedEOFException \ + com.sun.star.io.WrongFormatException \ + com.sun.star.io.XActiveDataControl \ + com.sun.star.io.XActiveDataSink \ + com.sun.star.io.XActiveDataSource \ + com.sun.star.io.XConnectable \ + com.sun.star.io.XMarkableStream \ + com.sun.star.io.XObjectInputStream \ + com.sun.star.io.XObjectOutputStream \ + com.sun.star.lang.IllegalArgumentException \ + com.sun.star.lang.XComponent \ + com.sun.star.lang.XMultiServiceFactory \ + com.sun.star.lang.XServiceInfo \ + com.sun.star.lang.XSingleServiceFactory \ + com.sun.star.lang.XSingleComponentFactory \ + com.sun.star.lang.XMultiComponentFactory \ + com.sun.star.uno.XComponentContext \ + com.sun.star.lang.XTypeProvider \ + com.sun.star.registry.XImplementationRegistration \ + com.sun.star.registry.XRegistryKey \ + com.sun.star.test.XSimpleTest \ + com.sun.star.uno.TypeClass \ + com.sun.star.uno.XAggregation \ + com.sun.star.uno.XWeak + +SLOFILES= \ + $(SLO)$/testfactreg.obj \ + $(SLO)$/pipetest.obj \ + $(SLO)$/datatest.obj \ + $(SLO)$/marktest.obj \ + $(SLO)$/pumptest.obj + +SHL1TARGET= $(TARGET) + +SHL1STDLIBS= \ + $(SALLIB) \ + $(CPPULIB) \ + $(CPPUHELPERLIB) + +SHL1LIBS= $(SLB)$/$(TARGET).lib + +SHL1IMPLIB= i$(TARGET) + +SHL1DEPN= makefile.mk $(SHL1LIBS) +SHL1DEF= $(MISC)$/$(SHL1TARGET).def + +DEF1NAME= $(SHL1TARGET) +DEF1EXPORTFILE= exports.dxp + + +# --- Targets ------------------------------------------------------ +.ENDIF # L10N_framework + +.INCLUDE : target.mk diff --git a/io/test/stm/marktest.cxx b/io/test/stm/marktest.cxx new file mode 100644 index 000000000..fbfc20082 --- /dev/null +++ b/io/test/stm/marktest.cxx @@ -0,0 +1,644 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <com/sun/star/test/XSimpleTest.hpp> +#include <com/sun/star/io/XActiveDataSink.hpp> +#include <com/sun/star/io/XActiveDataSource.hpp> +#include <com/sun/star/io/XMarkableStream.hpp> +#include <com/sun/star/io/XConnectable.hpp> + +#include <com/sun/star/lang/XServiceInfo.hpp> + +#include <cppuhelper/factory.hxx> +#include <cppuhelper/implbase.hxx> + +#include <osl/conditn.hxx> + +using namespace ::osl; +using namespace ::cppu; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::io; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::test; +// streams + +#include "testfactreg.hxx" + + +class OMarkableOutputStreamTest : public WeakImplHelper< XSimpleTest > +{ +public: + explicit OMarkableOutputStreamTest( const Reference< XMultiServiceFactory > & rFactory ); + ~OMarkableOutputStreamTest(); + +public: // implementation names + static Sequence< OUString > getSupportedServiceNames_Static() throw (); + static OUString getImplementationName_Static() throw (); + +public: + virtual void SAL_CALL testInvariant( + const OUString& TestName, + const Reference < XInterface >& TestObject) + throw ( IllegalArgumentException, + RuntimeException) ; + + virtual sal_Int32 SAL_CALL test( const OUString& TestName, + const Reference < XInterface >& TestObject, + sal_Int32 hTestHandle) + throw ( IllegalArgumentException, RuntimeException); + virtual sal_Bool SAL_CALL testPassed() + throw ( RuntimeException); + virtual Sequence< OUString > SAL_CALL getErrors() + throw (RuntimeException); + virtual Sequence< Any > SAL_CALL getErrorExceptions() + throw (RuntimeException); + virtual Sequence< OUString > SAL_CALL getWarnings() + throw (RuntimeException); + +private: + void testSimple( const Reference< XOutputStream > &r, const Reference < XInputStream > &rInput ); + +private: + Sequence<Any> m_seqExceptions; + Sequence<OUString> m_seqErrors; + Sequence<OUString> m_seqWarnings; + Reference< XMultiServiceFactory > m_rFactory; + +}; + +OMarkableOutputStreamTest::OMarkableOutputStreamTest( const Reference< XMultiServiceFactory > &rFactory ) + : m_rFactory( rFactory ) +{ + +} + +OMarkableOutputStreamTest::~OMarkableOutputStreamTest() +{ + +} + + +void OMarkableOutputStreamTest::testInvariant( const OUString& TestName, + const Reference < XInterface >& TestObject ) + throw ( IllegalArgumentException, RuntimeException) +{ + Reference< XServiceInfo > info( TestObject, UNO_QUERY ); + ERROR_ASSERT( info.is() , "XServiceInfo not supported !" ); + if( info.is() ) + { + ERROR_ASSERT( info->supportsService( TestName ), "XServiceInfo test failed" ); + ERROR_ASSERT( ! info->supportsService( + OUString( "bla bluzb") ) , "XServiceInfo test failed" ); + } +} + + +sal_Int32 OMarkableOutputStreamTest::test( + const OUString& TestName, + const Reference < XInterface >& TestObject, + sal_Int32 hTestHandle) + throw ( IllegalArgumentException, RuntimeException) +{ + if( OUString( "com.sun.star.io.MarkableOutputStream" ) + == TestName ) { + try + { + if( 0 == hTestHandle ) + { + testInvariant( TestName , TestObject ); + } + else + { + Reference < XInterface > x = m_rFactory->createInstance("com.sun.star.io.Pipe"); + Reference< XOutputStream > rPipeOutput( x , UNO_QUERY ); + Reference < XInputStream > rPipeInput( x , UNO_QUERY ); + + Reference< XActiveDataSource > source( TestObject , UNO_QUERY ); + source->setOutputStream( rPipeOutput ); + + Reference< XOutputStream > rOutput( TestObject , UNO_QUERY ); + + OSL_ASSERT( rPipeInput.is() ); + OSL_ASSERT( rOutput.is() ); + if( 1 == hTestHandle ) { + // checks usual streaming + testSimple( rOutput , rPipeInput ); + } + } + + } + catch( const Exception &e ) + { + OString o = OUStringToOString( e.Message , RTL_TEXTENCODING_ASCII_US ); + BUILD_ERROR( 0 , o.getStr() ); + } + catch( ... ) + { + BUILD_ERROR( 0 , "unknown exception (Exception is not base class)" ); + } + + hTestHandle ++; + + if( 2 == hTestHandle ) + { + // all tests finished. + hTestHandle = -1; + } + } + else { + throw IllegalArgumentException(); + } + return hTestHandle; +} + + +sal_Bool OMarkableOutputStreamTest::testPassed() throw (RuntimeException) +{ + return m_seqErrors.getLength() == 0; +} + + +Sequence< OUString > OMarkableOutputStreamTest::getErrors() throw (RuntimeException) +{ + return m_seqErrors; +} + + +Sequence< Any > OMarkableOutputStreamTest::getErrorExceptions() throw (RuntimeException) +{ + return m_seqExceptions; +} + + +Sequence< OUString > OMarkableOutputStreamTest::getWarnings() throw (RuntimeException) +{ + return m_seqWarnings; +} + + +void OMarkableOutputStreamTest::testSimple( const Reference< XOutputStream > &rOutput , + const Reference< XInputStream > &rInput ) +{ + Reference < XMarkableStream > rMarkable( rOutput , UNO_QUERY ); + + ERROR_ASSERT( rMarkable.is() , "no MarkableStream implemented" ); + + // first check normal input/output facility + char pcStr[] = "Live long and prosper !"; + + Sequence<sal_Int8> seqWrite( strlen( pcStr )+1 ); + memcpy( seqWrite.getArray() , pcStr , seqWrite.getLength() ); + + Sequence<sal_Int8> seqRead( seqWrite.getLength() ); + + int nMax = 10,i; + + for( i = 0 ; i < nMax ; i ++ ) { + rOutput->writeBytes( seqWrite ); + rInput->readBytes( seqRead , rInput->available() ); + ERROR_ASSERT( ! strcmp( (char *) seqWrite.getArray() , (char * )seqRead.getArray() ) , + "error during read/write/skip" ); + } + + // Check buffer resizing + nMax = 3000; + for( i = 0 ; i < nMax ; i ++ ) { + rOutput->writeBytes( seqWrite ); + } + + for( i = 0 ; i < nMax ; i ++ ) { + rInput->readBytes( seqRead , seqWrite.getLength() ); + ERROR_ASSERT( ! strcmp( (char *) seqWrite.getArray() , (char * )seqRead.getArray() ) , + "error during read/write" ); + } + + // Check creating marks ! + sal_Int32 nMark = rMarkable->createMark(); + + for( i = 0 ; i < nMax ; i ++ ) { + rOutput->writeBytes( seqWrite ); + } + + ERROR_ASSERT( 0 == rInput->available() , "bytes available though mark is holded" ); + + ERROR_ASSERT( nMax*seqWrite.getLength() == rMarkable->offsetToMark( nMark ) , + "offsetToMark failure" ); + + rMarkable->deleteMark( nMark ); + ERROR_ASSERT( nMax*seqWrite.getLength() == rInput->available(),"bytes are not available though mark has been deleted" ); + + rInput->skipBytes( nMax*seqWrite.getLength() ); + ERROR_ASSERT( 0 == rInput->available(), "skip bytes failure" ); + + try + { + rMarkable->jumpToMark( nMark ); + ERROR_ASSERT( 0 , "jump to non existing mark possible !" ); + } + catch ( IllegalArgumentException & ) + { + // ok, exception was thrown + } + + // test putting marks not at the end of the stream! + ERROR_ASSERT( 0 == rInput->available(), "stream isn't clean" ); + { + Sequence< sal_Int8 > aByte(256); + + for( i = 0 ; i < 256 ; i ++ ) + { + aByte.getArray()[i] = i; + } + sal_Int32 nMark1 = rMarkable->createMark(); + + rOutput->writeBytes( aByte ); + rMarkable->jumpToMark( nMark1 ); + aByte.realloc( 10 ); + rOutput->writeBytes( aByte ); + + sal_Int32 nMark2 = rMarkable->createMark( ); + + for( i = 0 ; i < 10 ; i ++ ) + { + aByte.getArray()[i] = i+10; + } + + rOutput->writeBytes( aByte ); + + // allow the bytes to be written ! + rMarkable->jumpToFurthest(); + rMarkable->deleteMark( nMark1 ); + rMarkable->deleteMark( nMark2 ); + + ERROR_ASSERT( 256 == rInput->available(), "in between mark failure" ); + rInput->readBytes( aByte ,256); + for( i = 0 ; i < 256 ; i ++ ) + { + ERROR_ASSERT( i == ((sal_uInt8*)(aByte.getArray()))[i] , "in between mark failure" ); + } + } + + { + // now a more extensive mark test ! + Sequence<sal_Int8> as[4]; + sal_Int32 an[4]; + + for( i = 0 ; i < 4 ; i ++ ) { + as[i].realloc(1); + as[i].getArray()[0] = i; + an[i] = rMarkable->createMark(); + rOutput->writeBytes( as[i] ); + } + + // check offset to mark + for( i = 0 ; i < 4 ; i ++ ) { + ERROR_ASSERT( rMarkable->offsetToMark( an[i] ) == 4-i , "offsetToMark failure" ); + } + + rMarkable->jumpToMark( an[1] ); + ERROR_ASSERT( rMarkable->offsetToMark( an[3] ) == -2 , "offsetToMark failure" ); + + rMarkable->jumpToFurthest( ); + ERROR_ASSERT( rMarkable->offsetToMark( an[0] ) == 4 , "offsetToMark failure" ); + + // now do a rewrite ! + for( i = 0 ; i < 4 ; i ++ ) { + rMarkable->jumpToMark( an[3-i] ); + rOutput->writeBytes( as[i] ); + } + // NOTE : CursorPos 1 + + // now delete the marks ! + for( i = 0 ; i < 4 ; i ++ ) { + rMarkable->deleteMark( an[i] ); + } + ERROR_ASSERT( rInput->available() == 1 , "wrong number of bytes flushed" ); + + rMarkable->jumpToFurthest(); + + ERROR_ASSERT( rInput->available() == 4 , "wrong number of bytes flushed" ); + + rInput->readBytes( seqRead , 4 ); + + ERROR_ASSERT( 3 == seqRead.getArray()[0] , "rewrite didn't work" ); + ERROR_ASSERT( 2 == seqRead.getArray()[1] , "rewrite didn't work" ); + ERROR_ASSERT( 1 == seqRead.getArray()[2] , "rewrite didn't work" ); + ERROR_ASSERT( 0 == seqRead.getArray()[3] , "rewrite didn't work" ); + + rOutput->closeOutput(); + rInput->closeInput(); + } + +} + +/*** +* the test methods +* +****/ + + +/** +* for external binding +* +* +**/ +Reference < XInterface > SAL_CALL OMarkableOutputStreamTest_CreateInstance( const Reference< XMultiServiceFactory > & rSMgr ) throw(Exception) +{ + OMarkableOutputStreamTest *p = new OMarkableOutputStreamTest( rSMgr ); + return Reference < XInterface > ( (static_cast< OWeakObject * >(p)) ); +} + + +Sequence<OUString> OMarkableOutputStreamTest_getSupportedServiceNames() throw () +{ + Sequence<OUString> aRet { OMarkableOutputStreamTest_getImplementationName() }; + + return aRet; +} + +OUString OMarkableOutputStreamTest_getServiceName() throw () +{ + return OUString( "test.com.sun.star.io.MarkableOutputStream"); +} + +OUString OMarkableOutputStreamTest_getImplementationName() throw () +{ + return OUString( "test.com.sun.starextensions.stm.MarkableOutputStream"); +} + + +// Input stream + + +class OMarkableInputStreamTest : public WeakImplHelper< XSimpleTest > +{ +public: + explicit OMarkableInputStreamTest( const Reference< XMultiServiceFactory > & rFactory ); + ~OMarkableInputStreamTest(); + +public: // implementation names + static Sequence< OUString > getSupportedServiceNames_Static() throw () ; + static OUString getImplementationName_Static() throw () ; + +public: + virtual void SAL_CALL testInvariant( + const OUString& TestName, + const Reference < XInterface >& TestObject) + throw ( IllegalArgumentException, RuntimeException) ; + + virtual sal_Int32 SAL_CALL test( + const OUString& TestName, + const Reference < XInterface >& TestObject, + sal_Int32 hTestHandle) + throw ( IllegalArgumentException, + RuntimeException) ; + + virtual sal_Bool SAL_CALL testPassed() + throw ( RuntimeException); + virtual Sequence< OUString > SAL_CALL getErrors() + throw (RuntimeException); + virtual Sequence< Any > SAL_CALL getErrorExceptions() + throw (RuntimeException); + virtual Sequence< OUString > SAL_CALL getWarnings() + throw (RuntimeException); + +private: + void testSimple( const Reference< XOutputStream > &r, + const Reference < XInputStream > &rInput ); + +private: + Sequence<Any> m_seqExceptions; + Sequence<OUString> m_seqErrors; + Sequence<OUString> m_seqWarnings; + Reference< XMultiServiceFactory > m_rFactory; + +}; + +OMarkableInputStreamTest::OMarkableInputStreamTest( const Reference< XMultiServiceFactory > &rFactory ) + : m_rFactory( rFactory ) +{ + +} + +OMarkableInputStreamTest::~OMarkableInputStreamTest() +{ + +} + + +void OMarkableInputStreamTest::testInvariant( + const OUString& TestName, const Reference < XInterface >& TestObject ) + throw ( IllegalArgumentException, RuntimeException) +{ + if( OUString( "com.sun.star.io.MarkableInputStream") + == TestName ) { + Reference <XServiceInfo > info( TestObject, UNO_QUERY ); + ERROR_ASSERT( info.is() , "XServiceInfo not supported !" ); + if( info.is() ) + { + ERROR_ASSERT( info->supportsService( TestName ), "XServiceInfo test failed" ); + ERROR_ASSERT( + ! info->supportsService( + OUString("bla bluzb") ) , + "XServiceInfo test failed" ); + } + } + else + { + throw IllegalArgumentException(); + } +} + + +sal_Int32 OMarkableInputStreamTest::test( + const OUString& TestName, + const Reference < XInterface >& TestObject, + sal_Int32 hTestHandle) throw ( IllegalArgumentException, RuntimeException) +{ + if( OUString( "com.sun.star.io.MarkableInputStream") == TestName ) + { + try + { + if( 0 == hTestHandle ) { + testInvariant( TestName , TestObject ); + } + else { + Reference < XInterface > x = m_rFactory->createInstance("com.sun.star.io.Pipe"); + Reference< XOutputStream > rPipeOutput( x , UNO_QUERY ); + Reference < XInputStream > rPipeInput( x , UNO_QUERY ); + + Reference < XActiveDataSink > sink( TestObject , UNO_QUERY ); + sink->setInputStream( rPipeInput ); + + Reference < XInputStream > rInput( TestObject , UNO_QUERY ); + + OSL_ASSERT( rPipeOutput.is() ); + OSL_ASSERT( rInput.is() ); + if( 1 == hTestHandle ) { + // checks usual streaming + testSimple( rPipeOutput , rInput ); + } + } + + } + catch( const Exception & e ) + { + OString o = OUStringToOString( e.Message , RTL_TEXTENCODING_ASCII_US ); + BUILD_ERROR( 0 , o.getStr() ); + } + catch( ... ) + { + BUILD_ERROR( 0 , "unknown exception (Exception is not base class)" ); + } + + hTestHandle ++; + + if( 2 == hTestHandle ) { + // all tests finished. + hTestHandle = -1; + } + } + else + { + throw IllegalArgumentException(); + } + return hTestHandle; +} + + +sal_Bool OMarkableInputStreamTest::testPassed() throw (RuntimeException) +{ + return m_seqErrors.getLength() == 0; +} + + +Sequence< OUString > OMarkableInputStreamTest::getErrors() throw (RuntimeException) +{ + return m_seqErrors; +} + + +Sequence< Any > OMarkableInputStreamTest::getErrorExceptions() throw (RuntimeException) +{ + return m_seqExceptions; +} + + +Sequence< OUString > OMarkableInputStreamTest::getWarnings() throw (RuntimeException) +{ + return m_seqWarnings; +} + + +void OMarkableInputStreamTest::testSimple( const Reference< XOutputStream > &rOutput , + const Reference < XInputStream > &rInput ) +{ + Reference < XMarkableStream > rMarkable( rInput , UNO_QUERY ); + + Sequence<sal_Int8> seqWrite( 256 ); + Sequence<sal_Int8> seqRead(10); + + for( int i = 0 ; i < 256 ; i ++ ) + { + seqWrite.getArray()[i] = i; + } + + rOutput->writeBytes( seqWrite ); + ERROR_ASSERT( 256 == rInput->available() , "basic read/write failure" ); + + rInput->readBytes( seqRead , 10 ); + ERROR_ASSERT( 9 == seqRead.getArray()[9] , "basic read/write failure" ); + + sal_Int32 nMark = rMarkable->createMark(); + + rInput->skipBytes( 50 ); + ERROR_ASSERT( 256-10-50 == rInput->available() , "marking error" ); + ERROR_ASSERT( 50 == rMarkable->offsetToMark( nMark ) , "marking error" ); + + rMarkable->jumpToMark( nMark ); + ERROR_ASSERT( 256-10 == rInput->available() , "marking error" ); + + rInput->readBytes( seqRead , 10 ); + ERROR_ASSERT( 10 == seqRead.getArray()[0] , "marking error" ); + + // pos 20 + { + sal_Int32 nInBetweenMark = rMarkable->createMark( ); + rMarkable->jumpToMark( nMark ); + rMarkable->jumpToMark( nInBetweenMark ); + + rInput->readBytes( seqRead , 10 ); + ERROR_ASSERT( 20 == seqRead.getArray()[0] , "Inbetween mark failed!\n" ); + + rMarkable->deleteMark( nMark ); + + // Check if releasing the first bytes works correct. + rMarkable->jumpToMark( nInBetweenMark); + rInput->readBytes( seqRead , 10 ); + ERROR_ASSERT( 20 == seqRead.getArray()[0] , "Inbetween mark failed!\n" ); + + rMarkable->deleteMark( nInBetweenMark ); + } + + rMarkable->jumpToFurthest(); + ERROR_ASSERT( 256-10-50 == rInput->available() , "marking error" ); + + + ERROR_ASSERT( 100 == rInput->readSomeBytes( seqRead , 100 ) , "wrong results using readSomeBytes" ); + ERROR_ASSERT( 96 == rInput->readSomeBytes( seqRead , 1000) , "wrong results using readSomeBytes" ); + rOutput->closeOutput(); + rInput->closeInput(); +} + +/*** +* the test methods +* +****/ + + +/** +* for external binding +* +* +**/ +Reference < XInterface > SAL_CALL OMarkableInputStreamTest_CreateInstance( const Reference< XMultiServiceFactory > & rSMgr ) throw(Exception) +{ + OMarkableInputStreamTest *p = new OMarkableInputStreamTest( rSMgr ); + return Reference < XInterface > ( (static_cast< OWeakObject * >(p)) ); +} + + +Sequence<OUString> OMarkableInputStreamTest_getSupportedServiceNames() throw () +{ + Sequence<OUString> aRet { OMarkableInputStreamTest_getImplementationName() }; + + return aRet; +} + +OUString OMarkableInputStreamTest_getServiceName() throw () +{ + return OUString( "test.com.sun.star.io.MarkableInputStream"); +} + +OUString OMarkableInputStreamTest_getImplementationName() throw () +{ + return OUString( "test.com.sun.star.extensions.stm.MarkableInputStream" ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/io/test/stm/pipetest.cxx b/io/test/stm/pipetest.cxx new file mode 100644 index 000000000..46637f3f2 --- /dev/null +++ b/io/test/stm/pipetest.cxx @@ -0,0 +1,418 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include <com/sun/star/test/XSimpleTest.hpp> +#include <com/sun/star/io/XInputStream.hpp> +#include <com/sun/star/io/XOutputStream.hpp> +#include <com/sun/star/io/XConnectable.hpp> +#include <com/sun/star/lang/IllegalArgumentException.hpp> + +#include <com/sun/star/lang/XServiceInfo.hpp> + +#include <cppuhelper/factory.hxx> + +#include <cppuhelper/implbase.hxx> + +#include <osl/conditn.hxx> +#include <osl/thread.hxx> + +#include <string.h> + +using namespace ::osl; +using namespace ::cppu; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::io; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::test; +// streams + +#include "testfactreg.hxx" + + +class WriteToStreamThread : + public Thread +{ + +public: + + WriteToStreamThread( Reference< XOutputStream > xOutput , int iMax ) + : m_output(xOutput), m_iMax(iMax) + { + } + + virtual ~WriteToStreamThread() {} + + +protected: + + /// Working method which should be overridden. + virtual void SAL_CALL run() { + for( int i = 0 ; i < m_iMax ; i ++ ) { + m_output->writeBytes( createIntSeq(i) ); + } + m_output->closeOutput(); + } + + /** Called when run() is done. + * You might want to override it to do some cleanup. + */ + virtual void SAL_CALL onTerminated() + { + delete this; + } + + +private: + + Reference < XOutputStream > m_output; + int m_iMax; +}; + + +class OPipeTest : public WeakImplHelper < XSimpleTest > +{ +public: + explicit OPipeTest( const Reference< XMultiServiceFactory > & rFactory ); + ~OPipeTest(); + +public: // implementation names + static Sequence< OUString > getSupportedServiceNames_Static() throw(); + static OUString getImplementationName_Static() throw(); + +public: + virtual void SAL_CALL testInvariant(const OUString& TestName, const Reference < XInterface >& TestObject) + throw ( IllegalArgumentException, RuntimeException) ; + + virtual sal_Int32 SAL_CALL test( const OUString& TestName, + const Reference < XInterface >& TestObject, + sal_Int32 hTestHandle) + throw ( IllegalArgumentException, + RuntimeException); + + virtual sal_Bool SAL_CALL testPassed() throw ( RuntimeException) ; + virtual Sequence< OUString > SAL_CALL getErrors() throw (RuntimeException) ; + virtual Sequence< Any > SAL_CALL getErrorExceptions() throw (RuntimeException); + virtual Sequence< OUString > SAL_CALL getWarnings() throw (RuntimeException); + +private: + void testSimple( const Reference < XInterface > & ); + void testBufferResizing( const Reference < XInterface > & ); + void testMultithreading( const Reference < XInterface > & ); + +private: + Sequence<Any> m_seqExceptions; + Sequence<OUString> m_seqErrors; + Sequence<OUString> m_seqWarnings; + +}; + + +OPipeTest::OPipeTest( const Reference< XMultiServiceFactory > &rFactory ) +{ + +} + +OPipeTest::~OPipeTest() +{ + +} + + +void OPipeTest::testInvariant( const OUString& TestName, const Reference < XInterface >& TestObject ) + throw ( IllegalArgumentException, + RuntimeException) +{ + Reference< XServiceInfo > info( TestObject, UNO_QUERY ); + ERROR_ASSERT( info.is() , "XServiceInfo not supported !" ); + if( info.is() ) + { + ERROR_ASSERT( info->supportsService( TestName ), "XServiceInfo test failed" ); + ERROR_ASSERT( ! info->supportsService( + OUString("bla bluzb") ), "XServiceInfo test failed" ); + } + +} + + +sal_Int32 OPipeTest::test( + const OUString& TestName, + const Reference < XInterface >& TestObject, + sal_Int32 hTestHandle) + throw ( IllegalArgumentException, RuntimeException) +{ + if( OUString("com.sun.star.io.Pipe") == TestName ) { + try + { + if( 0 == hTestHandle ) { + testInvariant( TestName , TestObject ); + } + else if( 1 == hTestHandle ) { + testSimple( TestObject ); + } + else if( 2 == hTestHandle ) { + testBufferResizing( TestObject ); + } + else if( 3 == hTestHandle ) { + testMultithreading( TestObject ); + } + } + catch( const Exception & e ) + { + OString s = OUStringToOString( e.Message , RTL_TEXTENCODING_ASCII_US ); + BUILD_ERROR( 0 , s.getStr() ); + } + catch( ... ) + { + BUILD_ERROR( 0 , "unknown exception (Exception is not base class)" ); + } + + hTestHandle ++; + + if( 4 == hTestHandle ) + { + // all tests finished. + hTestHandle = -1; + } + } + else { + throw IllegalArgumentException(); + } + return hTestHandle; +} + + +sal_Bool OPipeTest::testPassed() throw (RuntimeException) +{ + return m_seqErrors.getLength() == 0; +} + + +Sequence< OUString > OPipeTest::getErrors() throw (RuntimeException) +{ + return m_seqErrors; +} + + +Sequence< Any > OPipeTest::getErrorExceptions() throw (RuntimeException) +{ + return m_seqExceptions; +} + + +Sequence< OUString > OPipeTest::getWarnings() throw (RuntimeException) +{ + return m_seqWarnings; +} + + +/*** +* the test methods +* +****/ + + +void OPipeTest::testSimple( const Reference < XInterface > &r ) +{ + + Reference< XInputStream > input( r , UNO_QUERY ); + Reference < XOutputStream > output( r , UNO_QUERY ); + + ERROR_ASSERT( input.is() , "queryInterface on XInputStream failed" ); + ERROR_ASSERT( output.is() , "queryInterface onXOutputStream failed" ); + + // basic read/write + Sequence<sal_Int8> seqWrite = createSeq( "Hallo, du Ei !" ); + + Sequence<sal_Int8> seqRead; + for( int i = 0 ; i < 5000 ; i ++ ) { + output->writeBytes( seqWrite ); + input->readBytes( seqRead , input->available() ); + + ERROR_ASSERT( ! strcmp( (char *) seqWrite.getArray() , (char * )seqRead.getArray() ) , + "error during read/write/skip" ); + ERROR_ASSERT( 0 == input->available() , + "error during read/write/skip" ); + + // available shouldn't return a negative value + input->skipBytes( seqWrite.getLength() - 5 ); + ERROR_ASSERT( 0 == input->available() , "wrong available after skip" ); + + // 5 bytes should be available + output->writeBytes( seqWrite ); + ERROR_ASSERT( 5 == input->available() , "wrong available after skip/write " ); + + input->readBytes( seqRead , 5 ); + ERROR_ASSERT( ! strcmp( (char*) seqRead.getArray() , + (char*) &( seqWrite.getArray()[seqWrite.getLength()-5] ) ), + "write/read mismatch" ); + + } + + output->writeBytes( seqWrite ); + ERROR_ASSERT( seqWrite.getLength() == input->available(), "wrong available() after write" ); + + ERROR_ASSERT( 10 == input->readSomeBytes( seqRead , 10 ) , "maximal number of bytes ignored" ); + ERROR_ASSERT( seqWrite.getLength() -10 == input->readSomeBytes( seqRead , 100 ) , + "something wrong with readSomeBytes" ); + + + output->closeOutput(); + try{ + output->writeBytes( Sequence<sal_Int8> (100) ); + ERROR_ASSERT( 0 , "writing on a closed stream does not cause an exception" ); + } + catch (IOException & ) + { + } + + ERROR_ASSERT(! input->readBytes( seqRead , 1 ), "eof not found !" ); + + input->closeInput(); + try + { + input->readBytes( seqRead , 1 ); + ERROR_ASSERT( 0 , "reading from a closed stream does not cause an exception" ); + } + catch( IOException & ) { + } + + try + { + input->available( ); + ERROR_ASSERT( 0 , "calling available from a closed stream should thrown an io exception" ); + } + catch( IOException & ) + { + + } + try + { + input->skipBytes(42 ); + ERROR_ASSERT( 0 , "calling available from a closed stream should thrown an io exception" ); + } + catch( IOException & ) + { + + } +} + +void OPipeTest::testBufferResizing( const Reference < XInterface > &r ) +{ + int i; + int iMax = 20000; + Reference< XInputStream > input( r , UNO_QUERY ); + Reference < XOutputStream > output( r , UNO_QUERY ); + + ERROR_ASSERT( input.is() , "queryInterface on XInputStream failed" ); + ERROR_ASSERT( output.is() , "queryInterface on XOutputStream failed" ); + + Sequence<sal_Int8> seqRead; + + // this is just to better check the + // internal buffers + output->writeBytes( Sequence<sal_Int8>(100) ); + Sequence< sal_Int8 > dummy; + input->readBytes( dummy , 100); + + for( i = 0 ; i < iMax ; i ++ ) { + output->writeBytes( createIntSeq( i ) ); + } + + for( i = 0 ; i < iMax ; i ++ ) { + input->readBytes( seqRead, createIntSeq(i).getLength() ); + ERROR_ASSERT( ! strcmp( (char*) seqRead.getArray() , + (char*) createIntSeq(i).getArray() ) , + "written/read mismatch\n" ); + } + + output->closeOutput(); + ERROR_ASSERT( ! input->readBytes( seqRead , 1 ) , "eof not reached !" ); + input->closeInput(); +} + + +void OPipeTest::testMultithreading( const Reference < XInterface > &r ) +{ + + int i; + int iMax = 30000; + + Reference< XInputStream > input( r , UNO_QUERY ); + Reference < XOutputStream > output( r , UNO_QUERY ); + + ERROR_ASSERT( input.is() , "queryInterface on XInputStream failed" ); + ERROR_ASSERT( output.is() , "queryInterface on XOutputStream failed" ); + + Sequence<sal_Int8> seqRead; + + // deletes itself + Thread *p = new WriteToStreamThread( output, iMax ); + + ERROR_ASSERT( p , "couldn't create thread for testing !\n" ); + + p->create(); + + for( i = 0 ; sal_True ; i ++ ) { + if( 0 == input->readBytes( seqRead, createIntSeq(i).getLength() ) ) { + // eof reached ! + break; + } + + ERROR_ASSERT( ! strcmp( (char*) seqRead.getArray() , + (char*) createIntSeq(i).getArray() ) , + "written/read mismatch\n" ); + } + + ERROR_ASSERT( i == iMax , "less elements read than written !"); + input->closeInput(); +} + + +/** +* for external binding +* +* +**/ +Reference < XInterface > SAL_CALL OPipeTest_CreateInstance( const Reference< XMultiServiceFactory> & rSMgr ) throw (Exception) +{ + OPipeTest *p = new OPipeTest( rSMgr ); + Reference< XInterface > x ( (static_cast< OWeakObject * >(p)) ); + return x; +} + + +Sequence<OUString> OPipeTest_getSupportedServiceNames() throw() +{ + Sequence<OUString> aRet { OPipeTest_getServiceName() }; + + return aRet; +} + +OUString OPipeTest_getServiceName() throw() +{ + return OUString( "test.com.sun.star.io.Pipe" ); +} + +OUString OPipeTest_getImplementationName() throw() +{ + return OUString( "test.com.sun.star.comp.extensions.stm.Pipe" ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/io/test/stm/pumptest.cxx b/io/test/stm/pumptest.cxx new file mode 100644 index 000000000..f0563153e --- /dev/null +++ b/io/test/stm/pumptest.cxx @@ -0,0 +1,430 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <stdio.h> +#include <osl/time.h> + +#include <com/sun/star/test/XSimpleTest.hpp> + +#include <com/sun/star/io/XActiveDataSource.hpp> +#include <com/sun/star/io/XActiveDataSink.hpp> +#include <com/sun/star/io/XActiveDataControl.hpp> +#include <com/sun/star/io/XConnectable.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/lang/XSingleServiceFactory.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/registry/XRegistryKey.hpp> + +#include <uno/dispatcher.h> +#include <uno/mapping.hxx> +#include <cppuhelper/implbase.hxx> +#include <cppuhelper/factory.hxx> +#include <osl/thread.hxx> +#include <list> + + +using namespace ::osl; +using namespace ::cppu; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::io; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::test; + +#include "testfactreg.hxx" + +static void mywait() +{ + osl::Thread::wait(std::chrono::microseconds(10)); + osl_yieldThread(); + osl_yieldThread(); +} + +class OPumpTest : public WeakImplHelper < XSimpleTest > +{ +public: + explicit OPumpTest( const Reference< XMultiServiceFactory > & rFactory ); + ~OPumpTest(); + +public: // implementation names + static Sequence< OUString > getSupportedServiceNames_Static() throw(); + static OUString getImplementationName_Static() throw(); + +public: + virtual void SAL_CALL testInvariant(const OUString& TestName, const Reference < XInterface >& TestObject) + throw ( IllegalArgumentException, RuntimeException) ; + + virtual sal_Int32 SAL_CALL test( const OUString& TestName, + const Reference < XInterface >& TestObject, + sal_Int32 hTestHandle) + throw ( IllegalArgumentException, + RuntimeException); + + virtual sal_Bool SAL_CALL testPassed() throw ( RuntimeException) ; + virtual Sequence< OUString > SAL_CALL getErrors() throw (RuntimeException) ; + virtual Sequence< Any > SAL_CALL getErrorExceptions() throw (RuntimeException); + virtual Sequence< OUString > SAL_CALL getWarnings() throw (RuntimeException); + +private: + void testSimple( const Reference < XInterface > & ); + void testWrongUsage( const Reference < XInterface > & ); + void testClose( const Reference< XInterface >& ); + void testTerminate( const Reference< XInterface >& ); + void testFunction( const Reference< XInterface >& ); +private: + Sequence<Any> m_seqExceptions; + Sequence<OUString> m_seqErrors; + Sequence<OUString> m_seqWarnings; + Reference< XMultiServiceFactory > m_rSmgr; + +}; + +OPumpTest::OPumpTest( const Reference< XMultiServiceFactory > &rFactory ) : + m_rSmgr( rFactory ) +{ + +} + +OPumpTest::~OPumpTest() +{ + +} + + +void OPumpTest::testInvariant( const OUString& TestName, const Reference < XInterface >& TestObject ) + throw ( IllegalArgumentException, + RuntimeException) +{ + Reference< XServiceInfo > info( TestObject, UNO_QUERY ); + ERROR_ASSERT( info.is() , "XServiceInfo not supported !" ); + if( info.is() ) + { + ERROR_ASSERT( info->supportsService( TestName ), "XServiceInfo test failed" ); + ERROR_ASSERT( ! info->supportsService( + OUString( "bla bluzb" ) ), "XServiceInfo test failed" ); + } + + Reference < XActiveDataSource > xActiveDataSource( TestObject, UNO_QUERY ); + Reference < XActiveDataSink > xActiveDataSink( TestObject, UNO_QUERY ); + Reference < XActiveDataControl > xActiveDataControl( TestObject , UNO_QUERY ); + Reference < XConnectable > xConnectable( TestObject , UNO_QUERY ); + + ERROR_ASSERT( xActiveDataSource.is() && xActiveDataSink.is() && xActiveDataControl.is () && + xConnectable.is(), "specified interface not supported" ); +} + + +sal_Int32 OPumpTest::test( + const OUString& TestName, + const Reference < XInterface >& TestObject, + sal_Int32 hTestHandle) + throw ( IllegalArgumentException, RuntimeException) +{ + if( OUString( "com.sun.star.io.Pump" ) == TestName ) { + try + { + if( 0 == hTestHandle ) { + testInvariant( TestName , TestObject ); + } + else if ( 1 == hTestHandle ) + { + testWrongUsage( TestObject); + } + else if ( 2 == hTestHandle ) + { + testClose( TestObject); + } + else if ( 3 == hTestHandle ) + { + testTerminate( TestObject ); + } + else if ( 4 == hTestHandle ) + { + testFunction( TestObject ); + } + } + catch( const Exception & e ) + { + OString s = OUStringToOString( e.Message , RTL_TEXTENCODING_ASCII_US ); + BUILD_ERROR( 0 , s.getStr() ); + } + catch( ... ) + { + BUILD_ERROR( 0 , "unknown exception (Exception is not base class)" ); + } + + hTestHandle ++; + + if( 5 == hTestHandle ) + { + // all tests finished. + hTestHandle = -1; + } + } + else { + throw IllegalArgumentException(); + } + return hTestHandle; +} + + +sal_Bool OPumpTest::testPassed() throw (RuntimeException) +{ + return m_seqErrors.getLength() == 0; +} + + +Sequence< OUString > OPumpTest::getErrors() throw (RuntimeException) +{ + return m_seqErrors; +} + + +Sequence< Any > OPumpTest::getErrorExceptions() throw (RuntimeException) +{ + return m_seqExceptions; +} + + +Sequence< OUString > OPumpTest::getWarnings() throw (RuntimeException) +{ + return m_seqWarnings; +} + + +/*** +* the test methods +* +****/ + + +void OPumpTest::testSimple( const Reference < XInterface > &r ) +{ + // jbu todo: add sensible test + +} + +class TestListener: public WeakImplHelper< XStreamListener > +{ +public: + sal_Bool m_bStarted; + sal_Bool m_bClosed; + sal_Bool m_bTerminated; + sal_Bool m_bError; + sal_Bool m_bDisposed; + TestListener() : m_bStarted (sal_False), + m_bClosed (sal_False), + m_bTerminated ( sal_False ), + m_bError( sal_False ), + m_bDisposed( sal_False ) + {} + + virtual void SAL_CALL disposing( const EventObject &obj ) throw (css::uno::RuntimeException) + { + m_bDisposed = sal_True; +// printf( "disposing called\n"); + } + + virtual void SAL_CALL started( ) throw (css::uno::RuntimeException) + { + m_bStarted = sal_True; +// printf( "started called\n"); + } + virtual void SAL_CALL closed( ) throw (css::uno::RuntimeException) + { + m_bClosed = sal_True; +// printf( "closed called\n"); + } + virtual void SAL_CALL terminated( ) throw (css::uno::RuntimeException) + { + m_bTerminated = sal_True; +// printf( "terminated called\n"); + } + virtual void SAL_CALL error( const css::uno::Any& aException ) + throw (css::uno::RuntimeException) + { + m_bError = sal_True; + Exception e; + aException >>= e; +// printf( "error called %s\n", OUStringToOString( e.Message, RTL_TEXTENCODING_ASCII_US).getStr() ); + } +}; + +class TestCase +{ +public: + TestCase( const Reference< XMultiServiceFactory > & rSMgr, + const Reference< XInterface > &r ) : m_rSmgr( rSMgr ), m_pTestListener( 0 ) + { + m_rControl.set( r, UNO_QUERY ); + + Reference< XActiveDataSource > rSource ( r, UNO_QUERY ); + Reference< XActiveDataSink > rSink( r , UNO_QUERY ); + + m_rOutSource.set( createPipe() ); + rSink->setInputStream(Reference< XInputStream> (m_rOutSource,UNO_QUERY)); + + Reference< XOutputStream > rOutSink( createPipe() ); + m_rInSink.set( rOutSink, UNO_QUERY ); + rSource->setOutputStream( rOutSink ); + + m_pTestListener = new TestListener(); + m_pTestListener->acquire(); + m_rControl->addListener( m_pTestListener ); + } + + ~TestCase() + { + if( m_pTestListener ) + m_pTestListener->release(); + } + + TestListener *m_pTestListener; + Reference< XActiveDataControl > m_rControl; + Reference< XOutputStream > m_rOutSource; + Reference< XInputStream > m_rInSink; + Reference< XMultiServiceFactory > m_rSmgr; + +private: + Reference< XOutputStream > createPipe() + { + Reference< XOutputStream > rOut( m_rSmgr->createInstance( + "com.sun.star.io.Pipe"),UNO_QUERY); + return rOut; + } +}; + + +void OPumpTest::testClose( const Reference< XInterface > &r ) +{ + TestCase t( m_rSmgr, r ); + + ERROR_ASSERT( ! t.m_pTestListener->m_bStarted , "started too early" ); + ERROR_ASSERT( ! t.m_pTestListener->m_bTerminated , "termination unexpected" ); + ERROR_ASSERT( ! t.m_pTestListener->m_bError, "unexpected error" ); + ERROR_ASSERT( ! t.m_pTestListener->m_bClosed, "unexpected close" ); + + t.m_rControl->start(); + mywait(); + + ERROR_ASSERT( t.m_pTestListener->m_bStarted , "should have been started already" ); + ERROR_ASSERT( ! t.m_pTestListener->m_bTerminated , "termination unexpected" ); + ERROR_ASSERT( ! t.m_pTestListener->m_bError, "unexpected error" ); + ERROR_ASSERT( ! t.m_pTestListener->m_bClosed, "unexpected close" ); + + Reference< XStreamListener > rListener( new TestListener() ); + t.m_rControl->addListener( rListener ); + t.m_rControl->removeListener( rListener ); + + t.m_rOutSource->closeOutput(); + mywait(); + ERROR_ASSERT( t.m_pTestListener->m_bStarted , "should have been started already" ); + ERROR_ASSERT( ! t.m_pTestListener->m_bTerminated , "should be terminated already" ); + ERROR_ASSERT( ! t.m_pTestListener->m_bError, "unexpected error" ); + ERROR_ASSERT( t.m_pTestListener->m_bClosed, "should be closed already" ); +} + +void OPumpTest::testTerminate( const Reference< XInterface > &r ) +{ + TestCase t( m_rSmgr, r ); + + ERROR_ASSERT( ! t.m_pTestListener->m_bStarted , "started too early" ); + ERROR_ASSERT( ! t.m_pTestListener->m_bTerminated , "termination unexpected" ); + ERROR_ASSERT( ! t.m_pTestListener->m_bError, "unexpected error" ); + ERROR_ASSERT( ! t.m_pTestListener->m_bClosed, "unexpected closed" ); + + t.m_rControl->start(); + mywait(); + + ERROR_ASSERT( t.m_pTestListener->m_bStarted , "should have been started already" ); + ERROR_ASSERT( ! t.m_pTestListener->m_bTerminated , "termination unexpected" ); + ERROR_ASSERT( ! t.m_pTestListener->m_bError, "unexpected error" ); + ERROR_ASSERT( ! t.m_pTestListener->m_bClosed, "unexpected closed" ); + + t.m_rControl->terminate(); + + mywait(); + ERROR_ASSERT( t.m_pTestListener->m_bStarted , "should have been started already" ); + ERROR_ASSERT( t.m_pTestListener->m_bTerminated , "should be terminated already" ); + // terminate leads to an error, that is no surprise, in fact + // one can't tell whether the error occurs because of the terminate + // call or for some other reason! +// ERROR_ASSERT( ! t.m_pTestListener->m_bError, "unexpected error" ); + ERROR_ASSERT( t.m_pTestListener->m_bClosed, "should be closed already" ); +} + +void OPumpTest::testFunction( const Reference< XInterface > &r ) +{ + TestCase t( m_rSmgr, r ); + + t.m_rControl->start(); + + t.m_rOutSource->writeBytes( Sequence< sal_Int8 > ( 5 ) ); + + Sequence< sal_Int8 > dummy; + ERROR_ASSERT( 5 == t.m_rInSink->readBytes( dummy , 5 ), "couldn't read the expected number of bytes" ); + + t.m_rOutSource->closeOutput(); + mywait(); + + ERROR_ASSERT( t.m_pTestListener->m_bStarted , "should have been started already" ); + ERROR_ASSERT( ! t.m_pTestListener->m_bTerminated , "should be terminated already" ); + ERROR_ASSERT( ! t.m_pTestListener->m_bError, "unexpected error" ); + ERROR_ASSERT( t.m_pTestListener->m_bClosed, "should be closed already" ); +} + +void OPumpTest::testWrongUsage( const Reference< XInterface > &r ) +{ + Reference< XActiveDataSource > rSource ( r, UNO_QUERY ); + Reference< XActiveDataSink > rSink( r , UNO_QUERY ); + Reference< XActiveDataControl > rControl( r, UNO_QUERY ); + + Reference< XInputStream > rIn( m_rSmgr->createInstance( + "com.sun.star.io.DataInputStream"),UNO_QUERY); + Reference< XOutputStream > rOut( m_rSmgr->createInstance( + "com.sun.star.io.DataOutputStream"),UNO_QUERY); + + rSink->setInputStream( rIn ); + rSource->setOutputStream( rOut ); + + rControl->start(); + + mywait(); +} + +Reference< XInterface > SAL_CALL OPumpTest_CreateInstance( const Reference< XMultiServiceFactory > & rSMgr ) throw( Exception ) +{ + return *new OPumpTest( rSMgr ); +} + +Sequence<OUString> OPumpTest_getSupportedServiceNames() throw() +{ + return { OPumpTest_getServiceName() }; + +} +OUString OPumpTest_getServiceName() throw() +{ + return OUString( "test.com.sun.star.io.Pump" ); +} + +OUString OPumpTest_getImplementationName() throw() +{ + return OUString( "test.com.sun.star.comp.io.Pump" ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/io/test/stm/testfactreg.cxx b/io/test/stm/testfactreg.cxx new file mode 100644 index 000000000..2250429e5 --- /dev/null +++ b/io/test/stm/testfactreg.cxx @@ -0,0 +1,199 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <stdio.h> +#include <string.h> + +#include <osl/diagnose.h> + +#include <cppuhelper/factory.hxx> + +using namespace ::cppu; +using namespace ::com::sun::star::registry; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; + +#include "testfactreg.hxx" + + +extern "C" +{ + +sal_Bool SAL_CALL component_writeInfo( + void * pServiceManager, void * pRegistryKey ) +{ + if (pRegistryKey) + { + try + { + Reference< XRegistryKey > xKey( + reinterpret_cast< XRegistryKey * >( pRegistryKey ) ); + + OUString str = "/" + + OPipeTest_getImplementationName() + + "/UNO/SERVICES"; + Reference< XRegistryKey > xNewKey = xKey->createKey( str ); + xNewKey->createKey( OPipeTest_getServiceName() ); + + str = "/" + + OPumpTest_getImplementationName() + + "/UNO/SERVICES"; + xNewKey = xKey->createKey( str ); + xNewKey->createKey( OPumpTest_getServiceName() ); + + str = "/" + + ODataStreamTest_getImplementationName(1) + + "/UNO/SERVICES"; + xNewKey = xKey->createKey( str ); + xNewKey->createKey( ODataStreamTest_getServiceName(1) ); + + str = "/" + + ODataStreamTest_getImplementationName(2) + + "/UNO/SERVICES"; + xNewKey = xKey->createKey( str ); + xNewKey->createKey( ODataStreamTest_getServiceName(2) ); + + str = "/" + + OObjectStreamTest_getImplementationName(1) + + "/UNO/SERVICES"; + xNewKey = xKey->createKey( str ); + xNewKey->createKey( OObjectStreamTest_getServiceName(1) ); + + str = "/" + + OObjectStreamTest_getImplementationName(2) + + "/UNO/SERVICES"; + xNewKey = xKey->createKey( str ); + xNewKey->createKey( OObjectStreamTest_getServiceName(2) ); + + str = "/" + + OMarkableOutputStreamTest_getImplementationName() + + "/UNO/SERVICES"; + xNewKey = xKey->createKey( str ); + xNewKey->createKey( OMarkableOutputStreamTest_getServiceName() ); + + str = "/" + + OMarkableInputStreamTest_getImplementationName() + + "/UNO/SERVICES"; + xNewKey = xKey->createKey( str ); + xNewKey->createKey( OMarkableInputStreamTest_getServiceName() ); + + str = "/" + + OMyPersistObject_getImplementationName() + + "/UNO/SERVICES"; + xNewKey = xKey->createKey( str ); + xNewKey->createKey( OMyPersistObject_getServiceName() ); + + return sal_True; + } + catch (InvalidRegistryException &) + { + OSL_FAIL( "### InvalidRegistryException!" ); + } + } + return sal_False; +} + +SAL_DLLPUBLIC_EXPORT void * SAL_CALL component_getFactory( + const char * pImplName, void * pServiceManager, void * pRegistryKey ) +{ + void * pRet = 0; + + if (pServiceManager ) + { + Reference< XSingleServiceFactory > xRet; + Reference< XMultiServiceFactory > xSMgr = + reinterpret_cast< XMultiServiceFactory * > ( pServiceManager ); + + OUString aImplementationName = OUString::createFromAscii( pImplName ); + + if (aImplementationName == OPipeTest_getImplementationName() ) + { + xRet = createSingleFactory( xSMgr, aImplementationName, + OPipeTest_CreateInstance, + OPipeTest_getSupportedServiceNames() ); + } + else if (aImplementationName == OPumpTest_getImplementationName() ) + { + xRet = createSingleFactory( xSMgr, aImplementationName, + OPumpTest_CreateInstance, + OPumpTest_getSupportedServiceNames() ); + } + + else if( aImplementationName == ODataStreamTest_getImplementationName(1) ) { + xRet = createSingleFactory( xSMgr , aImplementationName, + ODataStreamTest_CreateInstance, + ODataStreamTest_getSupportedServiceNames(1) ); + } + else if( aImplementationName == ODataStreamTest_getImplementationName(2) ) { + xRet = createSingleFactory( xSMgr , aImplementationName, + ODataStreamTest_CreateInstance, + ODataStreamTest_getSupportedServiceNames(2) ); + } + else if( aImplementationName == OObjectStreamTest_getImplementationName(1) ) { + xRet = createSingleFactory( xSMgr , aImplementationName, + OObjectStreamTest_CreateInstance, + OObjectStreamTest_getSupportedServiceNames(1) ); + } + else if( aImplementationName == OObjectStreamTest_getImplementationName(2) ) { + xRet = createSingleFactory( xSMgr , aImplementationName, + OObjectStreamTest_CreateInstance, + OObjectStreamTest_getSupportedServiceNames(2) ); + } + else if( aImplementationName == OMarkableOutputStreamTest_getImplementationName() ) { + xRet = createSingleFactory( xSMgr , aImplementationName, + OMarkableOutputStreamTest_CreateInstance, + OMarkableOutputStreamTest_getSupportedServiceNames() ); + } + else if( aImplementationName == OMarkableInputStreamTest_getImplementationName() ) { + xRet = createSingleFactory( xSMgr , aImplementationName, + OMarkableInputStreamTest_CreateInstance, + OMarkableInputStreamTest_getSupportedServiceNames() ); + } + else if( aImplementationName == OMyPersistObject_getImplementationName() ) { + xRet = createSingleFactory( xSMgr , aImplementationName, + OMyPersistObject_CreateInstance, + OMyPersistObject_getSupportedServiceNames() ); + } + if (xRet.is()) + { + xRet->acquire(); + pRet = xRet.get(); + } + } + + return pRet; +} + +} + +Sequence<sal_Int8 > createSeq( char * p ) +{ + Sequence<sal_Int8> seq( strlen( p )+1 ); + strcpy( (char * ) seq.getArray() , p ); + return seq; +} + +Sequence<sal_Int8> createIntSeq( sal_Int32 i ) +{ + char pcCount[20]; + sprintf( pcCount , "%d" , i ); + return createSeq( pcCount ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/io/test/stm/testfactreg.hxx b/io/test/stm/testfactreg.hxx new file mode 100644 index 000000000..7952867b4 --- /dev/null +++ b/io/test/stm/testfactreg.hxx @@ -0,0 +1,107 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once +#include <rtl/strbuf.hxx> + +Reference< XInterface > SAL_CALL OPipeTest_CreateInstance( const Reference< XMultiServiceFactory > & rSMgr ) throw( Exception ); +Sequence<OUString> OPipeTest_getSupportedServiceNames() throw(); +OUString OPipeTest_getServiceName() throw(); +OUString OPipeTest_getImplementationName() throw(); + +Reference< XInterface > SAL_CALL OPumpTest_CreateInstance( const Reference< XMultiServiceFactory > & rSMgr ) throw( Exception ); +Sequence<OUString> OPumpTest_getSupportedServiceNames() throw(); +OUString OPumpTest_getServiceName() throw(); +OUString OPumpTest_getImplementationName() throw(); + +Reference< XInterface > SAL_CALL ODataStreamTest_CreateInstance( const Reference< XMultiServiceFactory > & rSMgr ) throw(Exception); +Sequence<OUString> ODataStreamTest_getSupportedServiceNames( int i) throw(); +OUString ODataStreamTest_getServiceName( int i) throw(); +OUString ODataStreamTest_getImplementationName( int i) throw(); + +Reference< XInterface > SAL_CALL OMarkableOutputStreamTest_CreateInstance( const Reference< XMultiServiceFactory > & rSMgr ) throw(Exception); +Sequence<OUString> OMarkableOutputStreamTest_getSupportedServiceNames() throw(); +OUString OMarkableOutputStreamTest_getServiceName() throw(); +OUString OMarkableOutputStreamTest_getImplementationName() throw(); + +Reference< XInterface > SAL_CALL OMarkableInputStreamTest_CreateInstance( const Reference< XMultiServiceFactory > & rSMgr ) throw(Exception); +Sequence<OUString> OMarkableInputStreamTest_getSupportedServiceNames() throw(); +OUString OMarkableInputStreamTest_getServiceName() throw(); +OUString OMarkableInputStreamTest_getImplementationName() throw(); + +Reference< XInterface > SAL_CALL OObjectStreamTest_CreateInstance( const Reference< XMultiServiceFactory > & rSMgr ) throw(Exception); +Sequence<OUString> OObjectStreamTest_getSupportedServiceNames( int i) throw(); +OUString OObjectStreamTest_getServiceName( int i) throw(); +OUString OObjectStreamTest_getImplementationName( int i) throw(); + +Reference< XInterface > SAL_CALL OMyPersistObject_CreateInstance( const Reference< XMultiServiceFactory > & rSMgr ) throw(Exception); +Sequence<OUString> OMyPersistObject_getSupportedServiceNames( ) throw(); +OUString OMyPersistObject_getServiceName( ) throw(); +OUString OMyPersistObject_getImplementationName( ) throw(); + +Sequence<sal_Int8> createSeq( char * p ); +Sequence<sal_Int8> createIntSeq( sal_Int32 i ); + +#define BUILD_ERROR(expr, Message)\ + {\ + m_seqErrors.realloc( m_seqErrors.getLength() + 1 ); \ + m_seqExceptions.realloc( m_seqExceptions.getLength() + 1 ); \ + OStringBuffer str(128); \ + str.append( __FILE__ );\ + str.append( " " ); \ + str.append( "(" ); \ + str.append( OString::valueOf( (sal_Int32)__LINE__) );\ + str.append(")\n" );\ + str.append( "[ " ); \ + str.append( #expr ); \ + str.append( " ] : " ); \ + str.append( Message ); \ + m_seqErrors.getArray()[ m_seqErrors.getLength()-1] =\ + OStringToOUString( str.makeStringAndClear() , RTL_TEXTENCODING_ASCII_US ); \ + }\ + ((void)0) + + +#define WARNING_ASSERT(expr, Message) \ + if( ! (expr) ) { \ + m_seqWarnings.realloc( m_seqErrors.getLength() +1 ); \ + OStringBuffer str(128);\ + str.append( __FILE__);\ + str.append( " "); \ + str.append( "(" ); \ + str.append(OString::valueOf( (sal_Int32)__LINE__)) ;\ + str.append( ")\n");\ + str.append( "[ " ); \ + str.append( #expr ); \ + str.append( " ] : ") ; \ + str.append( Message); \ + m_seqWarnings.getArray()[ m_seqWarnings.getLength()-1] =\ + OStringToOUString( str.makeStringAndClear() , RTL_TEXTENCODING_ASCII_US ); \ + return; \ + }\ + ((void)0) + +#define ERROR_ASSERT(expr, Message) \ + if( ! (expr) ) { \ + BUILD_ERROR(expr, Message );\ + return; \ + }\ + ((void)0) + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/io/test/testcomponent.cxx b/io/test/testcomponent.cxx new file mode 100644 index 000000000..2b317c903 --- /dev/null +++ b/io/test/testcomponent.cxx @@ -0,0 +1,206 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +// testcomponent - Loads a service and its testcomponent from dlls performs a test. +// Expands the dll-names depending on the actual environment. +// Example : testcomponent com.sun.star.io.Pipe stm +// +// Therefore the testcode must exist in teststm and the testservice must be named test.com.sun.star.io.Pipe + +#include <stdio.h> +#include <com/sun/star/registry/XImplementationRegistration.hpp> +#include <com/sun/star/lang/XComponent.hpp> + +#include <com/sun/star/test/XSimpleTest.hpp> + +#include <cppuhelper/servicefactory.hxx> + +using namespace ::cppu; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::test; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::registry; + +// Needed to switch on solaris threads + +int main (int argc, char **argv) +{ + + if( argc < 3) { + printf( "usage : testcomponent service dll [additional dlls]\n" ); + exit( 0 ); + } + + // create service manager + Reference< XMultiServiceFactory > xSMgr = createRegistryServiceFactory( + OUString( "applicat.rdb" ) ); + + Reference < XImplementationRegistration > xReg; + Reference < XSimpleRegistry > xSimpleReg; + + try + { + // Create registration service + Reference < XInterface > x = xSMgr->createInstance( + "com.sun.star.registry.ImplementationRegistration" ); + xReg.set( x , UNO_QUERY ); + } + catch( Exception & ) { + printf( "Couldn't create ImplementationRegistration service\n" ); + exit(1); + } + + char szBuf[1024]; + OString sTestName; + + try + { + // Load dll for the tested component + for( int n = 2 ; n <argc ; n ++ ) { + OUString aDllName = OStringToOUString( argv[n] , RTL_TEXTENCODING_ASCII_US ); + xReg->registerImplementation( + OUString("com.sun.star.loader.SharedLibrary"), + aDllName, + xSimpleReg ); + } + } + catch( const Exception &e ) { + printf( "%s\n" , OUStringToOString( e.Message , RTL_TEXTENCODING_ASCII_US ).getStr() ); + + exit(1); + } + + + try + { + // Load dll for the test component + sTestName = "test"; + sTestName += argv[2]; + +#if defined(_WIN32) + OUString aDllName = OStringToOUString( sTestName , RTL_TEXTENCODING_ASCII_US ); +#else + OUString aDllName("lib"); + aDllName += OStringToOUString( sTestName , RTL_TEXTENCODING_ASCII_US ); + aDllName += ".so"; +#endif + + xReg->registerImplementation( + OUString("com.sun.star.loader.SharedLibrary") , + aDllName, + xSimpleReg ); + } + catch( Exception & ) + { + printf( "Couldn't reach dll %s\n" , szBuf ); + exit(1); + } + + + // Instantiate test service + sTestName = "test."; + sTestName += argv[1]; + + Reference < XInterface > xIntTest = + xSMgr->createInstance( OStringToOUString( sTestName , RTL_TEXTENCODING_ASCII_US ) ); + Reference< XSimpleTest > xTest( xIntTest , UNO_QUERY ); + + if( ! xTest.is() ) { + printf( "Couldn't instantiate test service \n" ); + exit( 1 ); + } + + + sal_Int32 nHandle = 0; + sal_Int32 nNewHandle; + sal_Int32 nErrorCount = 0; + sal_Int32 nWarningCount = 0; + + // loop until all test are performed + while( nHandle != -1 ) + { + // Instantiate service + Reference< XInterface > x = + xSMgr->createInstance( OStringToOUString( argv[1] , RTL_TEXTENCODING_ASCII_US ) ); + if( ! x.is() ) + { + printf( "Couldn't instantiate service !\n" ); + exit( 1 ); + } + + // do the test + try + { + nNewHandle = xTest->test( + OStringToOUString( argv[1] , RTL_TEXTENCODING_ASCII_US ) , x , nHandle ); + } + catch( const Exception & e ) { + OString o = OUStringToOString( e.Message, RTL_TEXTENCODING_ASCII_US ); + printf( "testcomponent : uncaught exception %s\n" , o.getStr() ); + exit(1); + } + catch( ... ) + { + printf( "testcomponent : uncaught unknown exception\n" ); + exit(1); + } + + + // print errors and warning + Sequence<OUString> seqErrors = xTest->getErrors(); + Sequence<OUString> seqWarnings = xTest->getWarnings(); + if( seqWarnings.getLength() > nWarningCount ) + { + printf( "Warnings during test %d!\n" , nHandle ); + for( ; nWarningCount < seqWarnings.getLength() ; nWarningCount ++ ) + { + OString o = OUStringToOString( + seqWarnings.getArray()[nWarningCount], RTL_TEXTENCODING_ASCII_US ); + printf( "Warning\n%s\n---------\n" , o.getStr() ); + } + } + + + if( seqErrors.getLength() > nErrorCount ) { + printf( "Errors during test %d!\n" , nHandle ); + for( ; nErrorCount < seqErrors.getLength() ; nErrorCount ++ ) + { + OString o = OUStringToOString( + seqErrors.getArray()[nErrorCount], RTL_TEXTENCODING_ASCII_US ); + printf( "%s\n" , o.getStr() ); + } + } + + nHandle = nNewHandle; + } + + if( xTest->testPassed() ) { + printf( "Test passed !\n" ); + } + else { + printf( "Test failed !\n" ); + } + + Reference <XComponent > rComp( xSMgr , UNO_QUERY ); + rComp->dispose(); + return 0; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/io/test/testconnection.cxx b/io/test/testconnection.cxx new file mode 100644 index 000000000..4131bcf74 --- /dev/null +++ b/io/test/testconnection.cxx @@ -0,0 +1,257 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <stdio.h> +#include <osl/time.h> + +#include <osl/diagnose.h> +#include <osl/thread.hxx> + +#include <com/sun/star/io/IOException.hpp> +#include <com/sun/star/lang/IllegalArgumentException.hpp> +#include <com/sun/star/lang/XComponent.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> + +#include <com/sun/star/connection/AlreadyAcceptingException.hpp> +#include <com/sun/star/connection/ConnectionSetupException.hpp> +#include <com/sun/star/connection/XConnector.hpp> +#include <com/sun/star/connection/XAcceptor.hpp> + +#include <cppuhelper/bootstrap.hxx> + +using namespace ::osl; +using namespace ::cppu; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::io; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::connection; + + +namespace { + +class MyThread : + public Thread +{ +public: + MyThread( const Reference< XAcceptor > &r , const OUString & sConnectionDescription) : + m_rAcceptor( r ), + m_sConnectionDescription( sConnectionDescription ) + {} + virtual void SAL_CALL run(); + + Reference < XAcceptor > m_rAcceptor; +private: + Reference < XConnection > m_rConnection; + OUString m_sConnectionDescription; +}; + +void doWrite( const Reference < XConnection > &r ) +{ + Sequence < sal_Int8 > seq(10); + for( sal_Int32 i = 0 ; i < 10 ; i ++ ) + { + seq.getArray()[i] = i; + } + + r->write( seq ); +} + +void doRead( const Reference < XConnection > &r ) +{ + Sequence < sal_Int8 > seq(10); + + OSL_ASSERT( 10 == r->read( seq , 10 ) ); + + for( sal_Int32 i = 0 ; i < 10 ; i ++ ) + { + OSL_ASSERT( seq.getConstArray()[i] == i ); + } +} + + +void MyThread::run() +{ + try + { + m_rConnection = m_rAcceptor->accept( m_sConnectionDescription ); + } + catch ( const Exception &e) + { + OString tmp= OUStringToOString( e.Message , RTL_TEXTENCODING_ASCII_US ); + printf( "Exception was thrown by acceptor thread: %s\n", tmp.getStr() ); + } + + if( m_rConnection.is() ) + { + try + { + doWrite( m_rConnection ); + doRead( m_rConnection ); + } + catch (... ) + { + printf( "unknown exception was thrown\n" ); + throw; + } + } + +} + + +void testConnection( const OUString &sConnectionDescription , + const Reference < XAcceptor > &rAcceptor, + const Reference < XConnector > &rConnector ) +{ + MyThread thread( rAcceptor , sConnectionDescription ); + thread.create(); + + bool bGotit = false; + Reference < XConnection > r; + + while( ! bGotit ) + { + try + { + // Why is this wait necessary ???? + osl::Thread::wait(std::chrono::seconds(1)); + r = rConnector->connect( sConnectionDescription ); + OSL_ASSERT( r.is() ); + doWrite( r ); + doRead( r ); + bGotit = true; + } + catch( ... ) + { + printf( "Couldn't connect, retrying ...\n" ); + + } + } + + r->close(); + + try + { + Sequence < sal_Int8 > seq(10); + r->write( seq ); + OSL_FAIL( "expected exception not thrown" ); + } + catch ( IOException & ) + { + // everything is ok + } + catch ( ... ) + { + OSL_FAIL( "wrong exception was thrown" ); + } + + thread.join(); +} + +} + + +int main() +{ + Reference< XMultiServiceFactory > xMgr( + defaultBootstrap_InitialComponentContext()->getServiceManager(), UNO_QUERY ); + + Reference < XAcceptor > rAcceptor( + xMgr->createInstance( "com.sun.star.connection.Acceptor" ) , UNO_QUERY ); + + Reference < XAcceptor > rAcceptorPipe( + xMgr->createInstance( "com.sun.star.connection.Acceptor" ) , UNO_QUERY ); + + Reference < XConnector > rConnector( + xMgr->createInstance("com.sun.star.connection.Connector") , UNO_QUERY ); + + + printf( "Testing sockets" ); + fflush( stdout ); + testConnection( "socket,host=localhost,port=2001", rAcceptor , rConnector ); + printf( " Done\n" ); + + printf( "Testing pipe" ); + fflush( stdout ); + testConnection( "pipe,name=bla" , rAcceptorPipe , rConnector ); + printf( " Done\n" ); + + // check, if erroneous strings make any problem + rAcceptor.set( + xMgr->createInstance("com.sun.star.connection.Acceptor"), + UNO_QUERY ); + + try + { + rAcceptor->accept( OUString() ); + OSL_FAIL( "empty connection string" ); + } + catch( IllegalArgumentException & ) + { + // everything is fine + } + catch( ... ) + { + OSL_FAIL( "unexpected akexception with empty connection string" ); + } + + try + { + rConnector->connect( OUString() ); + OSL_FAIL( "empty connection string" ); + } + catch( ConnectionSetupException & ) + { + // everything is fine + } + catch( ... ) + { + OSL_FAIL( "unexpected exception with empty connection string" ); + } + + + MyThread thread( rAcceptor , "socket,host=localhost,port=2001" ); + thread.create(); + + osl::Thread::wait(std::chrono::seconds(1)); + try + { + rAcceptor->accept( "socket,host=localhost,port=2001" ); + OSL_FAIL( "already existing exception expected" ); + } + catch( AlreadyAcceptingException & ) + { + // everything is fine + } + catch( ... ) + { + OSL_FAIL( "unknown exception, already existing exception expected" ); + } + + rAcceptor->stopAccepting(); + thread.join(); + + Reference < XComponent > rComp( xMgr , UNO_QUERY ); + if( rComp.is() ) + { + rComp->dispose(); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ios/CustomTarget_iOS_setup.mk b/ios/CustomTarget_iOS_setup.mk new file mode 100644 index 000000000..f44a15447 --- /dev/null +++ b/ios/CustomTarget_iOS_setup.mk @@ -0,0 +1,138 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + + +#- Env ------------------------------------------------------------------------ +IOSGEN = $(BUILDDIR)/workdir/CustomTarget/ios +IOSRES = $(IOSGEN)/resources +IOSDIRS = $(IOSGEN) \ + $(IOSGEN)/Debug_x86_64 \ + $(IOSGEN)/Debug_arm64 \ + $(IOSGEN)/Release_x86_64 \ + $(IOSGEN)/Release_arm64 \ + $(IOSRES) \ + $(IOSRES)/services \ + $(IOSRES)/program \ + $(IOSRES)/share \ + $(IOSRES)/config \ + $(IOSRES)/share/filter + + +#- Top level ----------------------------------------------------------------- +$(eval $(call gb_CustomTarget_CustomTarget,ios/iOS_setup)) + +$(call gb_CustomTarget_get_target,ios/iOS_setup): $(IOSGEN)/native-code.h + + +#- create directories -------------------------------------------------------- +$(IOSDIRS): + $(call gb_Output_announce,$(subst $(WORKDIR)/,,$@),$(true),MKD,2) + $(call gb_Trace_StartRange,$(subst $(WORKDIR)/,,$@),MKD) + mkdir -p $(IOSDIRS) + $(call gb_Trace_EndRange,$(subst $(WORKDIR)/,,$@),MKD) + + +#- Generate resources -------------------------------------------------------- +$(IOSGEN)/native-code.h: $(BUILDDIR)/config_host.mk \ + $(SRCDIR)/ios/CustomTarget_iOS_setup.mk \ + $(SRCDIR)/solenv/bin/native-code.py \ + $(IOSGEN) \ + $(IOSDIRS) + $(call gb_Output_announce,$(subst $(WORKDIR)/,,$@),$(true),EN2,2) + $(call gb_Trace_StartRange,$(subst $(WORKDIR)/,,$@),EN2) + $(call gb_Trace_EndRange,$(subst $(WORKDIR)/,,$@),EN2) + + # generate native-code.h (used by LibreOffice.c) + xcrun python3 $(SRCDIR)/solenv/bin/native-code.py \ + -C -g core -g writer -g calc -g draw -g edit \ + > $(IOSGEN)/native-code.h + + # copy resource files used to start/run LibreOffice + cp $(WORKDIR)/UnpackedTarball/icu/source/data/in/icudt$(ICU_MAJOR)l.dat $(IOSRES)/icudt$(ICU_MAJOR)l.dat + cp $(INSTDIR)/program/types.rdb $(IOSRES)/udkapi.rdb + cp $(INSTDIR)/program/types/offapi.rdb $(IOSRES) + cp $(INSTDIR)/program/types/oovbaapi.rdb $(IOSRES) + cp $(INSTDIR)/program/services/services.rdb $(IOSRES)/services + cp $(INSTDIR)/program/services.rdb $(IOSRES) + if test -d $(INSTDIR)/program/resource; then \ + cp -R $(INSTDIR)/program/resource $(IOSRES)/program; \ + fi + mkdir -p $(IOSRES)/share/config + cp -R $(INSTDIR)/share/config/soffice.cfg $(IOSRES)/share/config + cp $(INSTDIR)/share/filter/oox-drawingml-adj-names $(IOSRES)/share/filter + cp $(INSTDIR)/share/filter/oox-drawingml-cs-presets $(IOSRES)/share/filter + cp $(INSTDIR)/share/filter/vml-shape-types $(IOSRES)/share/filter + cp -R $(INSTDIR)/share/registry $(IOSRES)/share + cp $(INSTDIR)/share/config/*zip $(IOSRES)/share/config + cp -R $(INSTDIR)/share/liblangtag $(IOSRES)/share + cp -R $(INSTDIR)/share/theme_definitions $(IOSRES)/share + cp -R $(INSTDIR)/share/template $(IOSRES)/share + mkdir -p $(IOSRES)/share/fonts + cp -R $(INSTDIR)/share/fonts/truetype $(IOSRES)/share/fonts + cp -R $(INSTDIR)/share/gallery $(IOSRES)/share + mkdir -p $(IOSRES)/share/spell $(IOSRES)/share/thes + # Install the Swiss German dictionary and use it for Liechtenstein, too. + # Install also thesauruses. + if test -d $(INSTDIR)/share/extensions/dict-de; then \ + cp $(INSTDIR)/share/extensions/dict-de/de_CH_frami.aff $(IOSRES)/share/spell/de_CH.aff; \ + cp $(INSTDIR)/share/extensions/dict-de/de_CH_frami.dic $(IOSRES)/share/spell/de_CH.dic; \ + cp $(INSTDIR)/share/extensions/dict-de/de_CH_frami.aff $(IOSRES)/share/spell/de_LI.aff; \ + cp $(INSTDIR)/share/extensions/dict-de/de_CH_frami.dic $(IOSRES)/share/spell/de_LI.dic; \ + cp $(INSTDIR)/share/extensions/*/th_*_v2.* $(IOSRES)/share/thes; \ + cp $(INSTDIR)/share/extensions/dict-en/th_en_US_v2.dat $(IOSRES)/share/thes/th_en_GB_v2.dat; \ + cp $(INSTDIR)/share/extensions/dict-en/th_en_US_v2.idx $(IOSRES)/share/thes/th_en_GB_v2.idx; \ + fi + cp -R $(INSTDIR)/share/palette $(IOSRES)/share + cp -R $(INSTDIR)/share/fingerprint $(IOSRES)/share + cp $(SRCDIR)/ios/welcome.odt $(IOSRES) + + # Set up rc (the "inifile", fundamentalrc, unorc, bootstraprc and versionrc. + (echo '[Bootstrap]' \ + && echo 'URE_BOOTSTRAP=file://$$APP_DATA_DIR/fundamentalrc' \ + && echo 'HOME=$$SYSUSERHOME' \ + ) > $(IOSRES)/rc + + (echo '[Bootstrap]' \ + && echo 'BRAND_BASE_DIR=file://$$APP_DATA_DIR' \ + && echo 'BRAND_INI_DIR=file:://$$APP_DATA_DIR' \ + && echo 'BRAND_SHARE_SUBDIR=$(LIBO_SHARE_FOLDER)' \ + && echo 'BRAND_SHARE_RESOURCE_SUBDIR=$(LIBO_SHARE_RESOURCE_FOLDER)' \ + && echo 'CONFIGURATION_LAYERS=xcsxcu:$${BRAND_BASE_DIR}/share/registry ' \ + 'res:$${BRAND_BASE_DIR}/share/registry' \ + && echo 'LO_LIB_DIR=file://$$APP_DATA_DIR/lib/' \ + && echo 'UNO_TYPES=file://$$APP_DATA_DIR/udkapi.rdb ' \ + 'file://$$APP_DATA_DIR/offapi.rdb' \ + && echo 'UNO_SERVICES=file://$$APP_DATA_DIR/services.rdb ' \ + 'file://$$APP_DATA_DIR/services/services.rdb' \ + && echo 'OSL_SOCKET_PATH=$$APP_DATA_DIR/cache' \ + ) > $(IOSRES)/fundamentalrc; + + echo '[Bootstrap]' > $(IOSRES)/unorc + + # bootstraprc must be in $BRAND_BASE_DIR/program + (echo '[Bootstrap]' \ + && echo 'InstallMode=<installmode>' \ + && echo "ProductKey=LibreOffice $(PRODUCTVERSION)" \ + && echo 'UserInstallation=$$SYSUSERHOME' \ + ) > $(IOSRES)/program/bootstraprc + + (echo '[Version]' \ + && echo 'AllLanguages=en-US' \ + && echo "buildid=$(shell git -C $(SRCDIR) log -1 --format=%H)" \ + ) > $(IOSRES)/program/versionrc + + $(SRCDIR)/bin/lo-all-static-libs | sed -e 's/ /\ +/g' >$(IOSGEN)/ios-all-static-libs.list + +#- clean ios ----------------------------------------------------------------- +$(call gb_CustomTarget_get_clean_target,ios/iOS_setup): + $(call gb_Output_announce,$(subst $(WORKDIR)/Clean/,,$@),$(false),ENV,2) + rm -rf $(IOSRES)/* $(IOSGEN)/native-code.h $(IOSGEN) + +# vim: set noet sw=4 ts=4: diff --git a/ios/Makefile b/ios/Makefile new file mode 100644 index 000000000..0c6f47b17 --- /dev/null +++ b/ios/Makefile @@ -0,0 +1,13 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +module_directory:=$(dir $(realpath $(firstword $(MAKEFILE_LIST)))) + +include $(module_directory)/../solenv/gbuild/partial_build.mk + +# vim: set noet sw=4 ts=4: diff --git a/ios/Module_ios.mk b/ios/Module_ios.mk new file mode 100644 index 000000000..4f88bc4e9 --- /dev/null +++ b/ios/Module_ios.mk @@ -0,0 +1,19 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +$(eval $(call gb_Module_Module,ios)) + +ifeq ($(OS),iOS) + +$(eval $(call gb_Module_add_targets,ios,\ + CustomTarget_iOS_setup \ +)) + +endif + +# vim: set noet sw=4 ts=4: diff --git a/ios/README.md b/ios/README.md new file mode 100644 index 000000000..81d89ed82 --- /dev/null +++ b/ios/README.md @@ -0,0 +1,3 @@ +# LibreOffice for iOS + +LibreOffice for iOS diff --git a/ios/UnitTest/UnitTest.xcodeproj/project.pbxproj b/ios/UnitTest/UnitTest.xcodeproj/project.pbxproj new file mode 100644 index 000000000..398007d9d --- /dev/null +++ b/ios/UnitTest/UnitTest.xcodeproj/project.pbxproj @@ -0,0 +1,810 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 50; + objects = { + +/* Begin PBXBuildFile section */ + BE39ADD7215D5470000B0244 /* test.odt in Resources */ = {isa = PBXBuildFile; fileRef = BE39ADD6215D5470000B0244 /* test.odt */; }; + BE39ADEF215D5AA4000B0244 /* icudt65l.dat in Resources */ = {isa = PBXBuildFile; fileRef = BE39ADE0215D5AA3000B0244 /* icudt65l.dat */; }; + BE39ADF0215D5AA4000B0244 /* fundamentalrc in Resources */ = {isa = PBXBuildFile; fileRef = BE39ADE1215D5AA3000B0244 /* fundamentalrc */; }; + BE39ADF1215D5AA4000B0244 /* services in Resources */ = {isa = PBXBuildFile; fileRef = BE39ADE2215D5AA3000B0244 /* services */; }; + BE39ADF2215D5AA4000B0244 /* share in Resources */ = {isa = PBXBuildFile; fileRef = BE39ADE3215D5AA3000B0244 /* share */; }; + BE39ADF3215D5AA4000B0244 /* oovbaapi.rdb in Resources */ = {isa = PBXBuildFile; fileRef = BE39ADE4215D5AA3000B0244 /* oovbaapi.rdb */; }; + BE39ADF4215D5AA4000B0244 /* program in Resources */ = {isa = PBXBuildFile; fileRef = BE39ADE5215D5AA3000B0244 /* program */; }; + BE39ADF5215D5AA4000B0244 /* config in Resources */ = {isa = PBXBuildFile; fileRef = BE39ADE6215D5AA3000B0244 /* config */; }; + BE39ADF6215D5AA4000B0244 /* services.rdb in Resources */ = {isa = PBXBuildFile; fileRef = BE39ADE7215D5AA3000B0244 /* services.rdb */; }; + BE39ADF8215D5AA4000B0244 /* offapi.rdb in Resources */ = {isa = PBXBuildFile; fileRef = BE39ADE9215D5AA3000B0244 /* offapi.rdb */; }; + BE39ADF9215D5AA4000B0244 /* udkapi.rdb in Resources */ = {isa = PBXBuildFile; fileRef = BE39ADEA215D5AA3000B0244 /* udkapi.rdb */; }; + BE39ADFA215D5AA4000B0244 /* rc in Resources */ = {isa = PBXBuildFile; fileRef = BE39ADEB215D5AA3000B0244 /* rc */; }; + BE39ADFC215D5AA4000B0244 /* unorc in Resources */ = {isa = PBXBuildFile; fileRef = BE39ADED215D5AA4000B0244 /* unorc */; }; + BE39ADFD215D5AA4000B0244 /* welcome.odt in Resources */ = {isa = PBXBuildFile; fileRef = BE39ADEE215D5AA4000B0244 /* welcome.odt */; }; + BE535616215D189A0068B3B7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = BE535615215D189A0068B3B7 /* AppDelegate.m */; }; + BE535619215D189A0068B3B7 /* ViewController.mm in Sources */ = {isa = PBXBuildFile; fileRef = BE535618215D189A0068B3B7 /* ViewController.mm */; }; + BE53561C215D189A0068B3B7 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = BE53561A215D189A0068B3B7 /* Main.storyboard */; }; + BE53561E215D189E0068B3B7 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = BE53561D215D189E0068B3B7 /* Assets.xcassets */; }; + BE535621215D189E0068B3B7 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = BE53561F215D189E0068B3B7 /* LaunchScreen.storyboard */; }; + BE535624215D189E0068B3B7 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = BE535623215D189E0068B3B7 /* main.m */; }; + BE93D41D216B4ECA007A39F4 /* MobileCoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BE93D41B216B378E007A39F4 /* MobileCoreServices.framework */; }; + BEA1A6FE215D1D9700A9323B /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = BEA1A6FD215D1D9700A9323B /* libz.tbd */; }; + BEA1A700215D1D9F00A9323B /* libiconv.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = BEA1A6FF215D1D9F00A9323B /* libiconv.tbd */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + BE39ADD6215D5470000B0244 /* test.odt */ = {isa = PBXFileReference; lastKnownFileType = file; name = test.odt; path = ../../../../odk/examples/cpp/DocumentLoader/test.odt; sourceTree = "<group>"; }; + BE39ADE0215D5AA3000B0244 /* icudt65l.dat */ = {isa = PBXFileReference; lastKnownFileType = file; name = icudt65l.dat; path = ../../../../workdir/CustomTarget/ios/resources/icudt65l.dat; sourceTree = "<group>"; }; + BE39ADE1215D5AA3000B0244 /* fundamentalrc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = fundamentalrc; path = ../../../../workdir/CustomTarget/ios/resources/fundamentalrc; sourceTree = "<group>"; }; + BE39ADE2215D5AA3000B0244 /* services */ = {isa = PBXFileReference; lastKnownFileType = folder; name = services; path = ../../../../workdir/CustomTarget/ios/resources/services; sourceTree = "<group>"; }; + BE39ADE3215D5AA3000B0244 /* share */ = {isa = PBXFileReference; lastKnownFileType = folder; name = share; path = ../../../../workdir/CustomTarget/ios/resources/share; sourceTree = "<group>"; }; + BE39ADE4215D5AA3000B0244 /* oovbaapi.rdb */ = {isa = PBXFileReference; lastKnownFileType = file; name = oovbaapi.rdb; path = ../../../../workdir/CustomTarget/ios/resources/oovbaapi.rdb; sourceTree = "<group>"; }; + BE39ADE5215D5AA3000B0244 /* program */ = {isa = PBXFileReference; lastKnownFileType = folder; name = program; path = ../../../../workdir/CustomTarget/ios/resources/program; sourceTree = "<group>"; }; + BE39ADE6215D5AA3000B0244 /* config */ = {isa = PBXFileReference; lastKnownFileType = folder; name = config; path = ../../../../workdir/CustomTarget/ios/resources/config; sourceTree = "<group>"; }; + BE39ADE7215D5AA3000B0244 /* services.rdb */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; name = services.rdb; path = ../../../../workdir/CustomTarget/ios/resources/services.rdb; sourceTree = "<group>"; }; + BE39ADE9215D5AA3000B0244 /* offapi.rdb */ = {isa = PBXFileReference; lastKnownFileType = file; name = offapi.rdb; path = ../../../../workdir/CustomTarget/ios/resources/offapi.rdb; sourceTree = "<group>"; }; + BE39ADEA215D5AA3000B0244 /* udkapi.rdb */ = {isa = PBXFileReference; lastKnownFileType = file; name = udkapi.rdb; path = ../../../../workdir/CustomTarget/ios/resources/udkapi.rdb; sourceTree = "<group>"; }; + BE39ADEB215D5AA3000B0244 /* rc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = rc; path = ../../../../workdir/CustomTarget/ios/resources/rc; sourceTree = "<group>"; }; + BE39ADED215D5AA4000B0244 /* unorc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = unorc; path = ../../../../workdir/CustomTarget/ios/resources/unorc; sourceTree = "<group>"; }; + BE39ADEE215D5AA4000B0244 /* welcome.odt */ = {isa = PBXFileReference; lastKnownFileType = file; name = welcome.odt; path = ../../../../workdir/CustomTarget/ios/resources/welcome.odt; sourceTree = "<group>"; }; + BE535611215D189A0068B3B7 /* UnitTest.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = UnitTest.app; sourceTree = BUILT_PRODUCTS_DIR; }; + BE535614215D189A0068B3B7 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; }; + BE535615215D189A0068B3B7 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; }; + BE535617215D189A0068B3B7 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = "<group>"; }; + BE535618215D189A0068B3B7 /* ViewController.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = ViewController.mm; sourceTree = "<group>"; }; + BE53561B215D189A0068B3B7 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; }; + BE53561D215D189E0068B3B7 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; }; + BE535620215D189E0068B3B7 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; }; + BE535622215D189E0068B3B7 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; }; + BE535623215D189E0068B3B7 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; }; + BE93D41B216B378E007A39F4 /* MobileCoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MobileCoreServices.framework; path = System/Library/Frameworks/MobileCoreServices.framework; sourceTree = SDKROOT; }; + BEA1A6FD215D1D9700A9323B /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; }; + BEA1A6FF215D1D9F00A9323B /* libiconv.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libiconv.tbd; path = usr/lib/libiconv.tbd; sourceTree = SDKROOT; }; + BEA20D2C2163C2570032F67B /* salgdiutils.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = salgdiutils.cxx; path = ../../vcl/quartz/salgdiutils.cxx; sourceTree = "<group>"; }; + BEA20D2D2163C2570032F67B /* ctfonts.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ctfonts.cxx; path = ../../vcl/quartz/ctfonts.cxx; sourceTree = "<group>"; }; + BEA20D2E2163C2570032F67B /* utils.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = utils.cxx; path = ../../vcl/quartz/utils.cxx; sourceTree = "<group>"; }; + BEA20D2F2163C2570032F67B /* salvd.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = salvd.cxx; path = ../../vcl/quartz/salvd.cxx; sourceTree = "<group>"; }; + BEA20D302163C2570032F67B /* salgdicommon.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = salgdicommon.cxx; path = ../../vcl/quartz/salgdicommon.cxx; sourceTree = "<group>"; }; + BEA20D312163C2570032F67B /* salbmp.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = salbmp.cxx; path = ../../vcl/quartz/salbmp.cxx; sourceTree = "<group>"; }; + BEA20D322163C2570032F67B /* salgdi.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = salgdi.cxx; path = ../../vcl/quartz/salgdi.cxx; sourceTree = "<group>"; }; + BEA20D372164BAB80032F67B /* salusereventlist.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = salusereventlist.cxx; path = ../../vcl/source/app/salusereventlist.cxx; sourceTree = "<group>"; }; + BEA20D382164BAB80032F67B /* dbggui.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = dbggui.cxx; path = ../../vcl/source/app/dbggui.cxx; sourceTree = "<group>"; }; + BEA20D392164BAB80032F67B /* IconThemeInfo.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = IconThemeInfo.cxx; path = ../../vcl/source/app/IconThemeInfo.cxx; sourceTree = "<group>"; }; + BEA20D3A2164BAB80032F67B /* timer.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = timer.cxx; path = ../../vcl/source/app/timer.cxx; sourceTree = "<group>"; }; + BEA20D3B2164BAB80032F67B /* customweld.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = customweld.cxx; path = ../../vcl/source/app/customweld.cxx; sourceTree = "<group>"; }; + BEA20D3C2164BAB80032F67B /* vclevent.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = vclevent.cxx; path = ../../vcl/source/app/vclevent.cxx; sourceTree = "<group>"; }; + BEA20D3D2164BAB80032F67B /* settings.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = settings.cxx; path = ../../vcl/source/app/settings.cxx; sourceTree = "<group>"; }; + BEA20D3E2164BAB80032F67B /* salplug.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = salplug.cxx; path = ../../vcl/source/app/salplug.cxx; sourceTree = "<group>"; }; + BEA20D3F2164BAB80032F67B /* i18nhelp.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = i18nhelp.cxx; path = ../../vcl/source/app/i18nhelp.cxx; sourceTree = "<group>"; }; + BEA20D402164BAB80032F67B /* sound.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = sound.cxx; path = ../../vcl/source/app/sound.cxx; sourceTree = "<group>"; }; + BEA20D412164BAB80032F67B /* svapp.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = svapp.cxx; path = ../../vcl/source/app/svapp.cxx; sourceTree = "<group>"; }; + BEA20D422164BAB80032F67B /* idle.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = idle.cxx; path = ../../vcl/source/app/idle.cxx; sourceTree = "<group>"; }; + BEA20D432164BAB80032F67B /* help.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = help.cxx; path = ../../vcl/source/app/help.cxx; sourceTree = "<group>"; }; + BEA20D442164BAB80032F67B /* IconThemeSelector.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = IconThemeSelector.cxx; path = ../../vcl/source/app/IconThemeSelector.cxx; sourceTree = "<group>"; }; + BEA20D452164BAB80032F67B /* brand.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = brand.cxx; path = ../../vcl/source/app/brand.cxx; sourceTree = "<group>"; }; + BEA20D462164BAB80032F67B /* IconThemeScanner.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = IconThemeScanner.cxx; path = ../../vcl/source/app/IconThemeScanner.cxx; sourceTree = "<group>"; }; + BEA20D472164BAB80032F67B /* session.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = session.cxx; path = ../../vcl/source/app/session.cxx; sourceTree = "<group>"; }; + BEA20D482164BAB80032F67B /* unohelp.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = unohelp.cxx; path = ../../vcl/source/app/unohelp.cxx; sourceTree = "<group>"; }; + BEA20D492164BAB80032F67B /* svdata.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = svdata.cxx; path = ../../vcl/source/app/svdata.cxx; sourceTree = "<group>"; }; + BEA20D4A2164BAB80032F67B /* dndhelp.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = dndhelp.cxx; path = ../../vcl/source/app/dndhelp.cxx; sourceTree = "<group>"; }; + BEA20D4B2164BAB80032F67B /* salvtables.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = salvtables.cxx; path = ../../vcl/source/app/salvtables.cxx; sourceTree = "<group>"; }; + BEA20D4C2164BAB80032F67B /* scheduler.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = scheduler.cxx; path = ../../vcl/source/app/scheduler.cxx; sourceTree = "<group>"; }; + BEA20D4D2164BAB80032F67B /* ITiledRenderable.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ITiledRenderable.cxx; path = ../../vcl/source/app/ITiledRenderable.cxx; sourceTree = "<group>"; }; + BEA20D4E2164BAB80032F67B /* stdtext.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = stdtext.cxx; path = ../../vcl/source/app/stdtext.cxx; sourceTree = "<group>"; }; + BEA20D4F2164BAB80032F67B /* unohelp2.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = unohelp2.cxx; path = ../../vcl/source/app/unohelp2.cxx; sourceTree = "<group>"; }; + BEA20D502164BAB80032F67B /* svmain.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = svmain.cxx; path = ../../vcl/source/app/svmain.cxx; sourceTree = "<group>"; }; + BEA20D522164BB0D0032F67B /* iosinst.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = iosinst.cxx; path = ../../vcl/ios/iosinst.cxx; sourceTree = "<group>"; }; + BEA20D532164BB0E0032F67B /* dummies.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = dummies.cxx; path = ../../vcl/ios/dummies.cxx; sourceTree = "<group>"; }; + BEA20D652166596F0032F67B /* svpvd.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = svpvd.cxx; path = ../../vcl/headless/svpvd.cxx; sourceTree = "<group>"; }; + BEA20D662166596F0032F67B /* svpframe.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = svpframe.cxx; path = ../../vcl/headless/svpframe.cxx; sourceTree = "<group>"; }; + BEA20D672166596F0032F67B /* svpbmp.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = svpbmp.cxx; path = ../../vcl/headless/svpbmp.cxx; sourceTree = "<group>"; }; + BEA20D682166596F0032F67B /* svpcairotextrender.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = svpcairotextrender.cxx; path = ../../vcl/headless/svpcairotextrender.cxx; sourceTree = "<group>"; }; + BEA20D692166596F0032F67B /* svpgdi.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = svpgdi.cxx; path = ../../vcl/headless/svpgdi.cxx; sourceTree = "<group>"; }; + BEA20D6A2166596F0032F67B /* svpglyphcache.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = svpglyphcache.cxx; path = ../../vcl/headless/svpglyphcache.cxx; sourceTree = "<group>"; }; + BEA20D6B2166596F0032F67B /* svpinst.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = svpinst.cxx; path = ../../vcl/headless/svpinst.cxx; sourceTree = "<group>"; }; + BEA20D6C2166596F0032F67B /* svptext.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = svptext.cxx; path = ../../vcl/headless/svptext.cxx; sourceTree = "<group>"; }; + BEA20D6D2166596F0032F67B /* headlessinst.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = headlessinst.cxx; path = ../../vcl/headless/headlessinst.cxx; sourceTree = "<group>"; }; + BEA20D6E2166596F0032F67B /* svpdata.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = svpdata.cxx; path = ../../vcl/headless/svpdata.cxx; sourceTree = "<group>"; }; + BEA20D6F2166596F0032F67B /* svpdummies.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = svpdummies.cxx; path = ../../vcl/headless/svpdummies.cxx; sourceTree = "<group>"; }; + BEA20D702166596F0032F67B /* svpprn.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = svpprn.cxx; path = ../../vcl/headless/svpprn.cxx; sourceTree = "<group>"; }; + BEA20DC221678BB60032F67B /* lokcharthelper.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = lokcharthelper.cxx; path = ../../sfx2/source/view/lokcharthelper.cxx; sourceTree = "<group>"; }; + BEA20DC4216797C00032F67B /* pdffontcache.hxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = pdffontcache.hxx; path = ../../vcl/source/gdi/pdffontcache.hxx; sourceTree = "<group>"; }; + BEA20DC5216797C00032F67B /* impgraph.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = impgraph.cxx; path = ../../vcl/source/gdi/impgraph.cxx; sourceTree = "<group>"; }; + BEA20DC6216797C00032F67B /* base14.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = base14.cxx; path = ../../vcl/source/gdi/base14.cxx; sourceTree = "<group>"; }; + BEA20DC7216797C00032F67B /* bmpfast.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = bmpfast.cxx; path = ../../vcl/source/gdi/bmpfast.cxx; sourceTree = "<group>"; }; + BEA20DC8216797C00032F67B /* vectorgraphicdata.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = vectorgraphicdata.cxx; path = ../../vcl/source/gdi/vectorgraphicdata.cxx; sourceTree = "<group>"; }; + BEA20DC9216797C00032F67B /* pdfwriter_impl2.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = pdfwriter_impl2.cxx; path = ../../vcl/source/gdi/pdfwriter_impl2.cxx; sourceTree = "<group>"; }; + BEA20DCA216797C00032F67B /* mapmod.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = mapmod.cxx; path = ../../vcl/source/gdi/mapmod.cxx; sourceTree = "<group>"; }; + BEA20DCB216797C00032F67B /* bitmap3.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = bitmap3.cxx; path = ../../vcl/source/gdi/bitmap3.cxx; sourceTree = "<group>"; }; + BEA20DCC216797C00032F67B /* pdfwriter.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = pdfwriter.cxx; path = ../../vcl/source/gdi/pdfwriter.cxx; sourceTree = "<group>"; }; + BEA20DCD216797C00032F67B /* salmisc.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = salmisc.cxx; path = ../../vcl/source/gdi/salmisc.cxx; sourceTree = "<group>"; }; + BEA20DCE216797C00032F67B /* impvect.hxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = impvect.hxx; path = ../../vcl/source/gdi/impvect.hxx; sourceTree = "<group>"; }; + BEA20DCF216797C00032F67B /* oldprintadaptor.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = oldprintadaptor.cxx; path = ../../vcl/source/gdi/oldprintadaptor.cxx; sourceTree = "<group>"; }; + BEA20DD0216797C00032F67B /* extoutdevdata.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = extoutdevdata.cxx; path = ../../vcl/source/gdi/extoutdevdata.cxx; sourceTree = "<group>"; }; + BEA20DD1216797C10032F67B /* cvtgrf.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = cvtgrf.cxx; path = ../../vcl/source/gdi/cvtgrf.cxx; sourceTree = "<group>"; }; + BEA20DD2216797C10032F67B /* graphictools.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = graphictools.cxx; path = ../../vcl/source/gdi/graphictools.cxx; sourceTree = "<group>"; }; + BEA20DD3216797C10032F67B /* gdimetafiletools.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = gdimetafiletools.cxx; path = ../../vcl/source/gdi/gdimetafiletools.cxx; sourceTree = "<group>"; }; + BEA20DD4216797C10032F67B /* genVerticalOrientationData.pl */ = {isa = PBXFileReference; lastKnownFileType = text.script.perl; name = genVerticalOrientationData.pl; path = ../../vcl/source/gdi/genVerticalOrientationData.pl; sourceTree = "<group>"; }; + BEA20DD5216797C10032F67B /* bmpacc3.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = bmpacc3.cxx; path = ../../vcl/source/gdi/bmpacc3.cxx; sourceTree = "<group>"; }; + BEA20DD6216797C10032F67B /* print.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = print.cxx; path = ../../vcl/source/gdi/print.cxx; sourceTree = "<group>"; }; + BEA20DD7216797C10032F67B /* configsettings.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = configsettings.cxx; path = ../../vcl/source/gdi/configsettings.cxx; sourceTree = "<group>"; }; + BEA20DD8216797C10032F67B /* print3.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = print3.cxx; path = ../../vcl/source/gdi/print3.cxx; sourceTree = "<group>"; }; + BEA20DD9216797C10032F67B /* graph.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = graph.cxx; path = ../../vcl/source/gdi/graph.cxx; sourceTree = "<group>"; }; + BEA20DDA216797C10032F67B /* octree.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = octree.cxx; path = ../../vcl/source/gdi/octree.cxx; sourceTree = "<group>"; }; + BEA20DDB216797C10032F67B /* scrptrun.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = scrptrun.cxx; path = ../../vcl/source/gdi/scrptrun.cxx; sourceTree = "<group>"; }; + BEA20DDC216797C10032F67B /* regionband.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = regionband.cxx; path = ../../vcl/source/gdi/regionband.cxx; sourceTree = "<group>"; }; + BEA20DDD216797C10032F67B /* gdimtf.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = gdimtf.cxx; path = ../../vcl/source/gdi/gdimtf.cxx; sourceTree = "<group>"; }; + BEA20DDE216797C10032F67B /* pdfextoutdevdata.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = pdfextoutdevdata.cxx; path = ../../vcl/source/gdi/pdfextoutdevdata.cxx; sourceTree = "<group>"; }; + BEA20DDF216797C10032F67B /* pdffontcache.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = pdffontcache.cxx; path = ../../vcl/source/gdi/pdffontcache.cxx; sourceTree = "<group>"; }; + BEA20DE0216797C10032F67B /* textlayout.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = textlayout.cxx; path = ../../vcl/source/gdi/textlayout.cxx; sourceTree = "<group>"; }; + BEA20DE1216797C10032F67B /* virdev.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = virdev.cxx; path = ../../vcl/source/gdi/virdev.cxx; sourceTree = "<group>"; }; + BEA20DE2216797C10032F67B /* embeddedfontshelper.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = embeddedfontshelper.cxx; path = ../../vcl/source/gdi/embeddedfontshelper.cxx; sourceTree = "<group>"; }; + BEA20DE3216797C10032F67B /* salgdiimpl.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = salgdiimpl.cxx; path = ../../vcl/source/gdi/salgdiimpl.cxx; sourceTree = "<group>"; }; + BEA20DE4216797C10032F67B /* gfxlink.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = gfxlink.cxx; path = ../../vcl/source/gdi/gfxlink.cxx; sourceTree = "<group>"; }; + BEA20DE5216797C10032F67B /* alpha.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = alpha.cxx; path = ../../vcl/source/gdi/alpha.cxx; sourceTree = "<group>"; }; + BEA20DE6216797C10032F67B /* hatch.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = hatch.cxx; path = ../../vcl/source/gdi/hatch.cxx; sourceTree = "<group>"; }; + BEA20DE7216797C10032F67B /* svmconverter.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = svmconverter.cxx; path = ../../vcl/source/gdi/svmconverter.cxx; sourceTree = "<group>"; }; + BEA20DE8216797C10032F67B /* pngwrite.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = pngwrite.cxx; path = ../../vcl/source/gdi/pngwrite.cxx; sourceTree = "<group>"; }; + BEA20DE9216797C10032F67B /* gradient.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = gradient.cxx; path = ../../vcl/source/gdi/gradient.cxx; sourceTree = "<group>"; }; + BEA20DEA216797C10032F67B /* pngread.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = pngread.cxx; path = ../../vcl/source/gdi/pngread.cxx; sourceTree = "<group>"; }; + BEA20DEB216797C10032F67B /* salgdilayout.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = salgdilayout.cxx; path = ../../vcl/source/gdi/salgdilayout.cxx; sourceTree = "<group>"; }; + BEA20DEC216797C20032F67B /* bitmapex.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = bitmapex.cxx; path = ../../vcl/source/gdi/bitmapex.cxx; sourceTree = "<group>"; }; + BEA20DED216797C20032F67B /* lineinfo.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = lineinfo.cxx; path = ../../vcl/source/gdi/lineinfo.cxx; sourceTree = "<group>"; }; + BEA20DEE216797C20032F67B /* animate.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = animate.cxx; path = ../../vcl/source/gdi/animate.cxx; sourceTree = "<group>"; }; + BEA20DEF216797C20032F67B /* bmpacc.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = bmpacc.cxx; path = ../../vcl/source/gdi/bmpacc.cxx; sourceTree = "<group>"; }; + BEA20DF0216797C20032F67B /* pdfwriter_impl.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = pdfwriter_impl.cxx; path = ../../vcl/source/gdi/pdfwriter_impl.cxx; sourceTree = "<group>"; }; + BEA20DF1216797C20032F67B /* wall.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = wall.cxx; path = ../../vcl/source/gdi/wall.cxx; sourceTree = "<group>"; }; + BEA20DF2216797C20032F67B /* impvect.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = impvect.cxx; path = ../../vcl/source/gdi/impvect.cxx; sourceTree = "<group>"; }; + BEA20DF3216797C20032F67B /* impanmvw.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = impanmvw.cxx; path = ../../vcl/source/gdi/impanmvw.cxx; sourceTree = "<group>"; }; + BEA20DF4216797C20032F67B /* print2.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = print2.cxx; path = ../../vcl/source/gdi/print2.cxx; sourceTree = "<group>"; }; + BEA20DF5216797C20032F67B /* metaact.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = metaact.cxx; path = ../../vcl/source/gdi/metaact.cxx; sourceTree = "<group>"; }; + BEA20DF6216797C20032F67B /* CommonSalLayout.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = CommonSalLayout.cxx; path = ../../vcl/source/gdi/CommonSalLayout.cxx; sourceTree = "<group>"; }; + BEA20DF7216797C20032F67B /* pdfwriter_impl.hxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = pdfwriter_impl.hxx; path = ../../vcl/source/gdi/pdfwriter_impl.hxx; sourceTree = "<group>"; }; + BEA20DF8216797C20032F67B /* dibtools.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = dibtools.cxx; path = ../../vcl/source/gdi/dibtools.cxx; sourceTree = "<group>"; }; + BEA20DF9216797C20032F67B /* sallayout.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = sallayout.cxx; path = ../../vcl/source/gdi/sallayout.cxx; sourceTree = "<group>"; }; + BEA20DFA216797C20032F67B /* bmpacc2.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = bmpacc2.cxx; path = ../../vcl/source/gdi/bmpacc2.cxx; sourceTree = "<group>"; }; + BEA20DFB216797C20032F67B /* regband.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = regband.cxx; path = ../../vcl/source/gdi/regband.cxx; sourceTree = "<group>"; }; + BEA20DFC216797C20032F67B /* jobset.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = jobset.cxx; path = ../../vcl/source/gdi/jobset.cxx; sourceTree = "<group>"; }; + BEA20DFD216797C20032F67B /* VerticalOrientationData.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = VerticalOrientationData.cxx; path = ../../vcl/source/gdi/VerticalOrientationData.cxx; sourceTree = "<group>"; }; + BEA20DFE216797C20032F67B /* region.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = region.cxx; path = ../../vcl/source/gdi/region.cxx; sourceTree = "<group>"; }; + BEA20DFF216797C20032F67B /* salnativewidgets-none.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "salnativewidgets-none.cxx"; path = "../../vcl/source/gdi/salnativewidgets-none.cxx"; sourceTree = "<group>"; }; + BEA20E012167A47B0032F67B /* gradient.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = gradient.cxx; path = ../../vcl/source/outdev/gradient.cxx; sourceTree = "<group>"; }; + BEA20E022167A47C0032F67B /* polygon.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = polygon.cxx; path = ../../vcl/source/outdev/polygon.cxx; sourceTree = "<group>"; }; + BEA20E032167A47C0032F67B /* text.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = text.cxx; path = ../../vcl/source/outdev/text.cxx; sourceTree = "<group>"; }; + BEA20E042167A47C0032F67B /* outdevstate.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = outdevstate.cxx; path = ../../vcl/source/outdev/outdevstate.cxx; sourceTree = "<group>"; }; + BEA20E052167A47C0032F67B /* wallpaper.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = wallpaper.cxx; path = ../../vcl/source/outdev/wallpaper.cxx; sourceTree = "<group>"; }; + BEA20E062167A47C0032F67B /* line.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = line.cxx; path = ../../vcl/source/outdev/line.cxx; sourceTree = "<group>"; }; + BEA20E072167A47C0032F67B /* curvedshapes.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = curvedshapes.cxx; path = ../../vcl/source/outdev/curvedshapes.cxx; sourceTree = "<group>"; }; + BEA20E082167A47C0032F67B /* map.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = map.cxx; path = ../../vcl/source/outdev/map.cxx; sourceTree = "<group>"; }; + BEA20E092167A47C0032F67B /* clipping.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = clipping.cxx; path = ../../vcl/source/outdev/clipping.cxx; sourceTree = "<group>"; }; + BEA20E0A2167A47C0032F67B /* bitmap.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = bitmap.cxx; path = ../../vcl/source/outdev/bitmap.cxx; sourceTree = "<group>"; }; + BEA20E0B2167A47C0032F67B /* font.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = font.cxx; path = ../../vcl/source/outdev/font.cxx; sourceTree = "<group>"; }; + BEA20E0C2167A47C0032F67B /* hatch.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = hatch.cxx; path = ../../vcl/source/outdev/hatch.cxx; sourceTree = "<group>"; }; + BEA20E0D2167A47C0032F67B /* nativecontrols.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = nativecontrols.cxx; path = ../../vcl/source/outdev/nativecontrols.cxx; sourceTree = "<group>"; }; + BEA20E0E2167A47C0032F67B /* polyline.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = polyline.cxx; path = ../../vcl/source/outdev/polyline.cxx; sourceTree = "<group>"; }; + BEA20E0F2167A47C0032F67B /* rect.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = rect.cxx; path = ../../vcl/source/outdev/rect.cxx; sourceTree = "<group>"; }; + BEA20E102167A47C0032F67B /* outdevstatestack.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = outdevstatestack.cxx; path = ../../vcl/source/outdev/outdevstatestack.cxx; sourceTree = "<group>"; }; + BEA20E112167A47C0032F67B /* textline.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = textline.cxx; path = ../../vcl/source/outdev/textline.cxx; sourceTree = "<group>"; }; + BEA20E122167A47C0032F67B /* outdev.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = outdev.cxx; path = ../../vcl/source/outdev/outdev.cxx; sourceTree = "<group>"; }; + BEA20E132167A47C0032F67B /* transparent.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = transparent.cxx; path = ../../vcl/source/outdev/transparent.cxx; sourceTree = "<group>"; }; + BEA20E142167A47C0032F67B /* vclreferencebase.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = vclreferencebase.cxx; path = ../../vcl/source/outdev/vclreferencebase.cxx; sourceTree = "<group>"; }; + BEA20E152167A47C0032F67B /* mask.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = mask.cxx; path = ../../vcl/source/outdev/mask.cxx; sourceTree = "<group>"; }; + BEA20E162167A47C0032F67B /* pixel.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = pixel.cxx; path = ../../vcl/source/outdev/pixel.cxx; sourceTree = "<group>"; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + BE53560E215D189A0068B3B7 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + BE93D41D216B4ECA007A39F4 /* MobileCoreServices.framework in Frameworks */, + BEA1A700215D1D9F00A9323B /* libiconv.tbd in Frameworks */, + BEA1A6FE215D1D9700A9323B /* libz.tbd in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + BE39ADD5215D5448000B0244 /* Resources */ = { + isa = PBXGroup; + children = ( + BE39ADE6215D5AA3000B0244 /* config */, + BE39ADE1215D5AA3000B0244 /* fundamentalrc */, + BE39ADE0215D5AA3000B0244 /* icudt65l.dat */, + BE39ADE9215D5AA3000B0244 /* offapi.rdb */, + BE39ADE4215D5AA3000B0244 /* oovbaapi.rdb */, + BE39ADE5215D5AA3000B0244 /* program */, + BE39ADEB215D5AA3000B0244 /* rc */, + BE39ADE2215D5AA3000B0244 /* services */, + BE39ADE7215D5AA3000B0244 /* services.rdb */, + BE39ADE3215D5AA3000B0244 /* share */, + BE39ADEA215D5AA3000B0244 /* udkapi.rdb */, + BE39ADED215D5AA4000B0244 /* unorc */, + BE39ADEE215D5AA4000B0244 /* welcome.odt */, + BE39ADD6215D5470000B0244 /* test.odt */, + ); + path = Resources; + sourceTree = "<group>"; + }; + BE535608215D189A0068B3B7 = { + isa = PBXGroup; + children = ( + BEA20D2A2163C2210032F67B /* Core */, + BE535613215D189A0068B3B7 /* UnitTest */, + BE535612215D189A0068B3B7 /* Products */, + BEA1A6FC215D1D9700A9323B /* Frameworks */, + ); + sourceTree = "<group>"; + }; + BE535612215D189A0068B3B7 /* Products */ = { + isa = PBXGroup; + children = ( + BE535611215D189A0068B3B7 /* UnitTest.app */, + ); + name = Products; + sourceTree = "<group>"; + }; + BE535613215D189A0068B3B7 /* UnitTest */ = { + isa = PBXGroup; + children = ( + BE39ADD5215D5448000B0244 /* Resources */, + BE535614215D189A0068B3B7 /* AppDelegate.h */, + BE535615215D189A0068B3B7 /* AppDelegate.m */, + BE535617215D189A0068B3B7 /* ViewController.h */, + BE535618215D189A0068B3B7 /* ViewController.mm */, + BE53561A215D189A0068B3B7 /* Main.storyboard */, + BE53561D215D189E0068B3B7 /* Assets.xcassets */, + BE53561F215D189E0068B3B7 /* LaunchScreen.storyboard */, + BE535622215D189E0068B3B7 /* Info.plist */, + BE535623215D189E0068B3B7 /* main.m */, + ); + path = UnitTest; + sourceTree = "<group>"; + }; + BEA1A6FC215D1D9700A9323B /* Frameworks */ = { + isa = PBXGroup; + children = ( + BE93D41B216B378E007A39F4 /* MobileCoreServices.framework */, + BEA1A6FF215D1D9F00A9323B /* libiconv.tbd */, + BEA1A6FD215D1D9700A9323B /* libz.tbd */, + ); + name = Frameworks; + sourceTree = "<group>"; + }; + BEA20D2A2163C2210032F67B /* Core */ = { + isa = PBXGroup; + children = ( + BEA20DC021678B960032F67B /* sfx2 */, + BEA20D2B2163C2360032F67B /* vcl */, + ); + name = Core; + sourceTree = "<group>"; + }; + BEA20D2B2163C2360032F67B /* vcl */ = { + isa = PBXGroup; + children = ( + BEA20D342164BA8B0032F67B /* app */, + BEA20DC3216797A00032F67B /* gdi */, + BEA20D642166594D0032F67B /* headless */, + BEA20D512164BAF00032F67B /* ios */, + BEA20E002167A4550032F67B /* outdev */, + BEA20D332164BA7C0032F67B /* quartz */, + ); + name = vcl; + sourceTree = "<group>"; + }; + BEA20D332164BA7C0032F67B /* quartz */ = { + isa = PBXGroup; + children = ( + BEA20D2D2163C2570032F67B /* ctfonts.cxx */, + BEA20D312163C2570032F67B /* salbmp.cxx */, + BEA20D322163C2570032F67B /* salgdi.cxx */, + BEA20D302163C2570032F67B /* salgdicommon.cxx */, + BEA20D2C2163C2570032F67B /* salgdiutils.cxx */, + BEA20D2F2163C2570032F67B /* salvd.cxx */, + BEA20D2E2163C2570032F67B /* utils.cxx */, + ); + name = quartz; + sourceTree = "<group>"; + }; + BEA20D342164BA8B0032F67B /* app */ = { + isa = PBXGroup; + children = ( + BEA20D452164BAB80032F67B /* brand.cxx */, + BEA20D3B2164BAB80032F67B /* customweld.cxx */, + BEA20D382164BAB80032F67B /* dbggui.cxx */, + BEA20D4A2164BAB80032F67B /* dndhelp.cxx */, + BEA20D432164BAB80032F67B /* help.cxx */, + BEA20D3F2164BAB80032F67B /* i18nhelp.cxx */, + BEA20D392164BAB80032F67B /* IconThemeInfo.cxx */, + BEA20D462164BAB80032F67B /* IconThemeScanner.cxx */, + BEA20D442164BAB80032F67B /* IconThemeSelector.cxx */, + BEA20D422164BAB80032F67B /* idle.cxx */, + BEA20D4D2164BAB80032F67B /* ITiledRenderable.cxx */, + BEA20D3E2164BAB80032F67B /* salplug.cxx */, + BEA20D372164BAB80032F67B /* salusereventlist.cxx */, + BEA20D4B2164BAB80032F67B /* salvtables.cxx */, + BEA20D4C2164BAB80032F67B /* scheduler.cxx */, + BEA20D472164BAB80032F67B /* session.cxx */, + BEA20D3D2164BAB80032F67B /* settings.cxx */, + BEA20D402164BAB80032F67B /* sound.cxx */, + BEA20D4E2164BAB80032F67B /* stdtext.cxx */, + BEA20D412164BAB80032F67B /* svapp.cxx */, + BEA20D492164BAB80032F67B /* svdata.cxx */, + BEA20D502164BAB80032F67B /* svmain.cxx */, + BEA20D3A2164BAB80032F67B /* timer.cxx */, + BEA20D482164BAB80032F67B /* unohelp.cxx */, + BEA20D4F2164BAB80032F67B /* unohelp2.cxx */, + BEA20D3C2164BAB80032F67B /* vclevent.cxx */, + ); + name = app; + sourceTree = "<group>"; + }; + BEA20D512164BAF00032F67B /* ios */ = { + isa = PBXGroup; + children = ( + BEA20D532164BB0E0032F67B /* dummies.cxx */, + BEA20D522164BB0D0032F67B /* iosinst.cxx */, + ); + name = ios; + sourceTree = "<group>"; + }; + BEA20D642166594D0032F67B /* headless */ = { + isa = PBXGroup; + children = ( + BEA20D6D2166596F0032F67B /* headlessinst.cxx */, + BEA20D672166596F0032F67B /* svpbmp.cxx */, + BEA20D682166596F0032F67B /* svpcairotextrender.cxx */, + BEA20D6E2166596F0032F67B /* svpdata.cxx */, + BEA20D6F2166596F0032F67B /* svpdummies.cxx */, + BEA20D662166596F0032F67B /* svpframe.cxx */, + BEA20D692166596F0032F67B /* svpgdi.cxx */, + BEA20D6A2166596F0032F67B /* svpglyphcache.cxx */, + BEA20D6B2166596F0032F67B /* svpinst.cxx */, + BEA20D702166596F0032F67B /* svpprn.cxx */, + BEA20D6C2166596F0032F67B /* svptext.cxx */, + BEA20D652166596F0032F67B /* svpvd.cxx */, + ); + name = headless; + sourceTree = "<group>"; + }; + BEA20DC021678B960032F67B /* sfx2 */ = { + isa = PBXGroup; + children = ( + BEA20DC121678B9E0032F67B /* view */, + ); + name = sfx2; + sourceTree = "<group>"; + }; + BEA20DC121678B9E0032F67B /* view */ = { + isa = PBXGroup; + children = ( + BEA20DC221678BB60032F67B /* lokcharthelper.cxx */, + ); + name = view; + sourceTree = "<group>"; + }; + BEA20DC3216797A00032F67B /* gdi */ = { + isa = PBXGroup; + children = ( + BEA20DE5216797C10032F67B /* alpha.cxx */, + BEA20DEE216797C20032F67B /* animate.cxx */, + BEA20DC6216797C00032F67B /* base14.cxx */, + BEA20DCB216797C00032F67B /* bitmap3.cxx */, + BEA20DEC216797C20032F67B /* bitmapex.cxx */, + BEA20DEF216797C20032F67B /* bmpacc.cxx */, + BEA20DFA216797C20032F67B /* bmpacc2.cxx */, + BEA20DD5216797C10032F67B /* bmpacc3.cxx */, + BEA20DC7216797C00032F67B /* bmpfast.cxx */, + BEA20DF6216797C20032F67B /* CommonSalLayout.cxx */, + BEA20DD7216797C10032F67B /* configsettings.cxx */, + BEA20DD1216797C10032F67B /* cvtgrf.cxx */, + BEA20DF8216797C20032F67B /* dibtools.cxx */, + BEA20DE2216797C10032F67B /* embeddedfontshelper.cxx */, + BEA20DD0216797C00032F67B /* extoutdevdata.cxx */, + BEA20DD3216797C10032F67B /* gdimetafiletools.cxx */, + BEA20DDD216797C10032F67B /* gdimtf.cxx */, + BEA20DD4216797C10032F67B /* genVerticalOrientationData.pl */, + BEA20DE4216797C10032F67B /* gfxlink.cxx */, + BEA20DE9216797C10032F67B /* gradient.cxx */, + BEA20DD9216797C10032F67B /* graph.cxx */, + BEA20DD2216797C10032F67B /* graphictools.cxx */, + BEA20DE6216797C10032F67B /* hatch.cxx */, + BEA20DF3216797C20032F67B /* impanmvw.cxx */, + BEA20DC5216797C00032F67B /* impgraph.cxx */, + BEA20DF2216797C20032F67B /* impvect.cxx */, + BEA20DCE216797C00032F67B /* impvect.hxx */, + BEA20DFC216797C20032F67B /* jobset.cxx */, + BEA20DED216797C20032F67B /* lineinfo.cxx */, + BEA20DCA216797C00032F67B /* mapmod.cxx */, + BEA20DF5216797C20032F67B /* metaact.cxx */, + BEA20DDA216797C10032F67B /* octree.cxx */, + BEA20DCF216797C00032F67B /* oldprintadaptor.cxx */, + BEA20DDE216797C10032F67B /* pdfextoutdevdata.cxx */, + BEA20DDF216797C10032F67B /* pdffontcache.cxx */, + BEA20DC4216797C00032F67B /* pdffontcache.hxx */, + BEA20DF0216797C20032F67B /* pdfwriter_impl.cxx */, + BEA20DF7216797C20032F67B /* pdfwriter_impl.hxx */, + BEA20DC9216797C00032F67B /* pdfwriter_impl2.cxx */, + BEA20DCC216797C00032F67B /* pdfwriter.cxx */, + BEA20DEA216797C10032F67B /* pngread.cxx */, + BEA20DE8216797C10032F67B /* pngwrite.cxx */, + BEA20DD6216797C10032F67B /* print.cxx */, + BEA20DF4216797C20032F67B /* print2.cxx */, + BEA20DD8216797C10032F67B /* print3.cxx */, + BEA20DFB216797C20032F67B /* regband.cxx */, + BEA20DFE216797C20032F67B /* region.cxx */, + BEA20DDC216797C10032F67B /* regionband.cxx */, + BEA20DE3216797C10032F67B /* salgdiimpl.cxx */, + BEA20DEB216797C10032F67B /* salgdilayout.cxx */, + BEA20DF9216797C20032F67B /* sallayout.cxx */, + BEA20DCD216797C00032F67B /* salmisc.cxx */, + BEA20DFF216797C20032F67B /* salnativewidgets-none.cxx */, + BEA20DDB216797C10032F67B /* scrptrun.cxx */, + BEA20DE7216797C10032F67B /* svmconverter.cxx */, + BEA20DE0216797C10032F67B /* textlayout.cxx */, + BEA20DC8216797C00032F67B /* vectorgraphicdata.cxx */, + BEA20DFD216797C20032F67B /* VerticalOrientationData.cxx */, + BEA20DE1216797C10032F67B /* virdev.cxx */, + BEA20DF1216797C20032F67B /* wall.cxx */, + ); + name = gdi; + sourceTree = "<group>"; + }; + BEA20E002167A4550032F67B /* outdev */ = { + isa = PBXGroup; + children = ( + BEA20E0A2167A47C0032F67B /* bitmap.cxx */, + BEA20E092167A47C0032F67B /* clipping.cxx */, + BEA20E072167A47C0032F67B /* curvedshapes.cxx */, + BEA20E0B2167A47C0032F67B /* font.cxx */, + BEA20E012167A47B0032F67B /* gradient.cxx */, + BEA20E0C2167A47C0032F67B /* hatch.cxx */, + BEA20E062167A47C0032F67B /* line.cxx */, + BEA20E082167A47C0032F67B /* map.cxx */, + BEA20E152167A47C0032F67B /* mask.cxx */, + BEA20E0D2167A47C0032F67B /* nativecontrols.cxx */, + BEA20E122167A47C0032F67B /* outdev.cxx */, + BEA20E042167A47C0032F67B /* outdevstate.cxx */, + BEA20E102167A47C0032F67B /* outdevstatestack.cxx */, + BEA20E162167A47C0032F67B /* pixel.cxx */, + BEA20E022167A47C0032F67B /* polygon.cxx */, + BEA20E0E2167A47C0032F67B /* polyline.cxx */, + BEA20E0F2167A47C0032F67B /* rect.cxx */, + BEA20E032167A47C0032F67B /* text.cxx */, + BEA20E112167A47C0032F67B /* textline.cxx */, + BEA20E132167A47C0032F67B /* transparent.cxx */, + BEA20E142167A47C0032F67B /* vclreferencebase.cxx */, + BEA20E052167A47C0032F67B /* wallpaper.cxx */, + ); + name = outdev; + sourceTree = "<group>"; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + BE535610215D189A0068B3B7 /* UnitTest */ = { + isa = PBXNativeTarget; + buildConfigurationList = BE535627215D189E0068B3B7 /* Build configuration list for PBXNativeTarget "UnitTest" */; + buildPhases = ( + BE53560D215D189A0068B3B7 /* Sources */, + BE53560E215D189A0068B3B7 /* Frameworks */, + BE53560F215D189A0068B3B7 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = UnitTest; + productName = UnitTest; + productReference = BE535611215D189A0068B3B7 /* UnitTest.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + BE535609215D189A0068B3B7 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 1000; + ORGANIZATIONNAME = "Tor Lillqvist"; + TargetAttributes = { + BE535610215D189A0068B3B7 = { + CreatedOnToolsVersion = 10.0; + }; + }; + }; + buildConfigurationList = BE53560C215D189A0068B3B7 /* Build configuration list for PBXProject "UnitTest" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = BE535608215D189A0068B3B7; + productRefGroup = BE535612215D189A0068B3B7 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + BE535610215D189A0068B3B7 /* UnitTest */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + BE53560F215D189A0068B3B7 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + BE39ADEF215D5AA4000B0244 /* icudt65l.dat in Resources */, + BE39ADF6215D5AA4000B0244 /* services.rdb in Resources */, + BE39ADF3215D5AA4000B0244 /* oovbaapi.rdb in Resources */, + BE39ADF8215D5AA4000B0244 /* offapi.rdb in Resources */, + BE535621215D189E0068B3B7 /* LaunchScreen.storyboard in Resources */, + BE39ADF4215D5AA4000B0244 /* program in Resources */, + BE39ADF5215D5AA4000B0244 /* config in Resources */, + BE39ADD7215D5470000B0244 /* test.odt in Resources */, + BE39ADFA215D5AA4000B0244 /* rc in Resources */, + BE39ADF2215D5AA4000B0244 /* share in Resources */, + BE39ADFD215D5AA4000B0244 /* welcome.odt in Resources */, + BE53561E215D189E0068B3B7 /* Assets.xcassets in Resources */, + BE39ADF1215D5AA4000B0244 /* services in Resources */, + BE39ADFC215D5AA4000B0244 /* unorc in Resources */, + BE53561C215D189A0068B3B7 /* Main.storyboard in Resources */, + BE39ADF9215D5AA4000B0244 /* udkapi.rdb in Resources */, + BE39ADF0215D5AA4000B0244 /* fundamentalrc in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + BE53560D215D189A0068B3B7 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + BE535619215D189A0068B3B7 /* ViewController.mm in Sources */, + BE535624215D189E0068B3B7 /* main.m in Sources */, + BE535616215D189A0068B3B7 /* AppDelegate.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + BE53561A215D189A0068B3B7 /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + BE53561B215D189A0068B3B7 /* Base */, + ); + name = Main.storyboard; + sourceTree = "<group>"; + }; + BE53561F215D189E0068B3B7 /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + BE535620215D189E0068B3B7 /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = "<group>"; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + BE535625215D189E0068B3B7 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + LO_CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + LO_CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + }; + name = Debug; + }; + BE535626215D189E0068B3B7 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + LO_CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + LO_CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = iphoneos; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + BE535628215D189E0068B3B7 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + LO_CLANG_CXX_LANGUAGE_STANDARD = "c++17"; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = J4FQ687VJK; + ENABLE_BITCODE = NO; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "DISABLE_DYNLOADING=1", + "LIBO_INTERNAL_ONLY=1", + "IOS=IOS", + "$(inherited)", + ); + HEADER_SEARCH_PATHS = ( + ../../include, + ../../vcl/inc, + ../../config_host, + ../../workdir/UnoApiHeadersTarget/udkapi/comprehensive, + ../../workdir/UnoApiHeadersTarget/offapi/comprehensive, + ../../workdir/CustomTarget/ios, + ../../workdir/UnpackedTarball/cppunit/include, + ../../workdir/UnpackedTarball/boost, + ); + INFOPLIST_FILE = UnitTest/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + OTHER_LDFLAGS = ( + "-filelist", + "../../workdir/CustomTarget/ios/ios-all-static-libs.list", + ); + PRODUCT_BUNDLE_IDENTIFIER = org.libreoffice.ios.UnitTest; + PRODUCT_NAME = "$(TARGET_NAME)"; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + BE535629215D189E0068B3B7 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + LO_CLANG_CXX_LANGUAGE_STANDARD = "c++17"; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = J4FQ687VJK; + ENABLE_BITCODE = NO; + GCC_PREPROCESSOR_DEFINITIONS = ( + "IOS=IOS", + "DISABLE_DYNLOADING=1", + "LIBO_INTERNAL_ONLY=1", + ); + HEADER_SEARCH_PATHS = ( + ../../include, + ../../vcl/inc, + ../../config_host, + ../../workdir/UnoApiHeadersTarget/udkapi/comprehensive, + ../../workdir/UnoApiHeadersTarget/offapi/comprehensive, + ../../workdir/CustomTarget/ios, + ../../workdir/UnpackedTarball/cppunit/include, + ../../workdir/UnpackedTarball/boost, + ); + INFOPLIST_FILE = UnitTest/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + OTHER_LDFLAGS = ( + "-filelist", + "../../workdir/CustomTarget/ios/ios-all-static-libs.list", + ); + PRODUCT_BUNDLE_IDENTIFIER = org.libreoffice.ios.UnitTest; + PRODUCT_NAME = "$(TARGET_NAME)"; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + BE53560C215D189A0068B3B7 /* Build configuration list for PBXProject "UnitTest" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + BE535625215D189E0068B3B7 /* Debug */, + BE535626215D189E0068B3B7 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + BE535627215D189E0068B3B7 /* Build configuration list for PBXNativeTarget "UnitTest" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + BE535628215D189E0068B3B7 /* Debug */, + BE535629215D189E0068B3B7 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = BE535609215D189A0068B3B7 /* Project object */; +} diff --git a/ios/UnitTest/UnitTest/AppDelegate.h b/ios/UnitTest/UnitTest/AppDelegate.h new file mode 100644 index 000000000..a0f962c9a --- /dev/null +++ b/ios/UnitTest/UnitTest/AppDelegate.h @@ -0,0 +1,16 @@ +/* -*- Mode: ObjC; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#import <UIKit/UIKit.h> + +@interface AppDelegate : UIResponder <UIApplicationDelegate> + +@property(strong, nonatomic) UIWindow* window; + +@end diff --git a/ios/UnitTest/UnitTest/AppDelegate.m b/ios/UnitTest/UnitTest/AppDelegate.m new file mode 100644 index 000000000..56616ee77 --- /dev/null +++ b/ios/UnitTest/UnitTest/AppDelegate.m @@ -0,0 +1,52 @@ +/* -*- Mode: ObjC; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#import "AppDelegate.h" + +@interface AppDelegate () + +@end + +@implementation AppDelegate + + +- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { + // Override point for customization after application launch. + return YES; +} + + +- (void)applicationWillResignActive:(UIApplication *)application { + // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. + // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. +} + + +- (void)applicationDidEnterBackground:(UIApplication *)application { + // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. + // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. +} + + +- (void)applicationWillEnterForeground:(UIApplication *)application { + // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. +} + + +- (void)applicationDidBecomeActive:(UIApplication *)application { + // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. +} + + +- (void)applicationWillTerminate:(UIApplication *)application { + // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. +} + + +@end diff --git a/ios/UnitTest/UnitTest/Assets.xcassets/AppIcon.appiconset/Contents.json b/ios/UnitTest/UnitTest/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 000000000..d8db8d65f --- /dev/null +++ b/ios/UnitTest/UnitTest/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,98 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "3x" + }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "83.5x83.5", + "scale" : "2x" + }, + { + "idiom" : "ios-marketing", + "size" : "1024x1024", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +}
\ No newline at end of file diff --git a/ios/UnitTest/UnitTest/Assets.xcassets/Contents.json b/ios/UnitTest/UnitTest/Assets.xcassets/Contents.json new file mode 100644 index 000000000..da4a164c9 --- /dev/null +++ b/ios/UnitTest/UnitTest/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +}
\ No newline at end of file diff --git a/ios/UnitTest/UnitTest/Base.lproj/LaunchScreen.storyboard b/ios/UnitTest/UnitTest/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 000000000..bfa361294 --- /dev/null +++ b/ios/UnitTest/UnitTest/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13122.16" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM"> + <dependencies> + <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13104.12"/> + <capability name="Safe area layout guides" minToolsVersion="9.0"/> + <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/> + </dependencies> + <scenes> + <!--View Controller--> + <scene sceneID="EHf-IW-A2E"> + <objects> + <viewController id="01J-lp-oVM" sceneMemberID="viewController"> + <view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3"> + <rect key="frame" x="0.0" y="0.0" width="375" height="667"/> + <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> + <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> + <viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/> + </view> + </viewController> + <placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/> + </objects> + <point key="canvasLocation" x="53" y="375"/> + </scene> + </scenes> +</document> diff --git a/ios/UnitTest/UnitTest/Base.lproj/Main.storyboard b/ios/UnitTest/UnitTest/Base.lproj/Main.storyboard new file mode 100644 index 000000000..942f0bc45 --- /dev/null +++ b/ios/UnitTest/UnitTest/Base.lproj/Main.storyboard @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13122.16" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="BYZ-38-t0r"> + <dependencies> + <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13104.12"/> + <capability name="Safe area layout guides" minToolsVersion="9.0"/> + <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/> + </dependencies> + <scenes> + <!--View Controller--> + <scene sceneID="tne-QT-ifu"> + <objects> + <viewController id="BYZ-38-t0r" customClass="ViewController" customModuleProvider="" sceneMemberID="viewController"> + <view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC"> + <rect key="frame" x="0.0" y="0.0" width="375" height="667"/> + <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> + <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> + <viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/> + </view> + </viewController> + <placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/> + </objects> + </scene> + </scenes> +</document> diff --git a/ios/UnitTest/UnitTest/Info.plist b/ios/UnitTest/UnitTest/Info.plist new file mode 100644 index 000000000..e6a294eba --- /dev/null +++ b/ios/UnitTest/UnitTest/Info.plist @@ -0,0 +1,47 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> + <key>UIFileSharingEnabled</key> + <true/> + <key>CFBundleDevelopmentRegion</key> + <string>$(DEVELOPMENT_LANGUAGE)</string> + <key>CFBundleExecutable</key> + <string>$(EXECUTABLE_NAME)</string> + <key>CFBundleIdentifier</key> + <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string> + <key>CFBundleInfoDictionaryVersion</key> + <string>6.0</string> + <key>CFBundleName</key> + <string>$(PRODUCT_NAME)</string> + <key>CFBundlePackageType</key> + <string>APPL</string> + <key>CFBundleShortVersionString</key> + <string>1.0</string> + <key>CFBundleVersion</key> + <string>1</string> + <key>LSRequiresIPhoneOS</key> + <true/> + <key>UILaunchStoryboardName</key> + <string>LaunchScreen</string> + <key>UIMainStoryboardFile</key> + <string>Main</string> + <key>UIRequiredDeviceCapabilities</key> + <array> + <string>armv7</string> + </array> + <key>UISupportedInterfaceOrientations</key> + <array> + <string>UIInterfaceOrientationPortrait</string> + <string>UIInterfaceOrientationLandscapeLeft</string> + <string>UIInterfaceOrientationLandscapeRight</string> + </array> + <key>UISupportedInterfaceOrientations~ipad</key> + <array> + <string>UIInterfaceOrientationPortrait</string> + <string>UIInterfaceOrientationPortraitUpsideDown</string> + <string>UIInterfaceOrientationLandscapeLeft</string> + <string>UIInterfaceOrientationLandscapeRight</string> + </array> +</dict> +</plist> diff --git a/ios/UnitTest/UnitTest/ViewController.h b/ios/UnitTest/UnitTest/ViewController.h new file mode 100644 index 000000000..5fb871370 --- /dev/null +++ b/ios/UnitTest/UnitTest/ViewController.h @@ -0,0 +1,14 @@ +/* -*- Mode: ObjC; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#import <UIKit/UIKit.h> + +@interface ViewController : UIViewController + +@end diff --git a/ios/UnitTest/UnitTest/ViewController.mm b/ios/UnitTest/UnitTest/ViewController.mm new file mode 100644 index 000000000..bcdfc492a --- /dev/null +++ b/ios/UnitTest/UnitTest/ViewController.mm @@ -0,0 +1,90 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <cassert> +#include <iostream> + +#include <sal/config.h> + +#include <cppuhelper/exc_hlp.hxx> +#include <com/sun/star/ucb/InteractiveAugmentedIOException.hpp> +#include <com/sun/star/uno/Any.hxx> +#include <sfx2/app.hxx> +#include <vcl/svapp.hxx> + +#include <cppunit/CompilerOutputter.h> +#include <cppunit/TestResult.h> +#include <cppunit/TestResultCollector.h> +#include <cppunit/TestRunner.h> +#include <cppunit/TextTestProgressListener.h> + +#import <LibreOfficeKit/LibreOfficeKit.hxx> + +extern "C" { +#import <native-code.h> +} + +#include <premac.h> +#import <CoreGraphics/CoreGraphics.h> +#import "ViewController.h" +#include <postmac.h> + +@interface ViewController () + +@end + +#define CPPUNIT_PLUGIN_EXPORTED_NAME CppuMisc +#include "../../../cppuhelper/qa/misc/test_misc.cxx" + +#undef CPPUNIT_PLUGIN_EXPORTED_NAME +#define CPPUNIT_PLUGIN_EXPORTED_NAME CppuUnourl +#include "../../../cppuhelper/qa/unourl/cppu_unourl.cxx" + +#undef CPPUNIT_PLUGIN_EXPORTED_NAME +#define CPPUNIT_PLUGIN_EXPORTED_NAME BitmapTest +#include "../../../vcl/qa/cppunit/BitmapTest.cxx" + +#define main tilebench_main +#include "../../../libreofficekit/qa/tilebench/tilebench.cxx" + +@implementation ViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + + // Simplest (?) way to do all the tedious initialization + lok_init_2(nullptr, nullptr); + + { + // First run some normal cppunit tests. Seems that at least the BitmapTest needs to be run + // with the SolarMutex held. + + SolarMutexGuard solarMutexGuard; + + CppUnit::TestResult result; + + CppUnit::TextTestProgressListener logger; + result.addListener(&logger); + + CppUnit::TestResultCollector collector; + result.addListener(&collector); + + CppUnit::TestRunner runner; + runner.addTest(CppUnit::TestFactoryRegistry::getRegistry().makeTest()); + runner.run(result); + + CppUnit::CompilerOutputter outputter(&collector, std::cerr); + outputter.write(); + } + + // Then some more specific stuff + tilebench_main(0, nullptr); +} + +@end diff --git a/ios/UnitTest/UnitTest/main.m b/ios/UnitTest/UnitTest/main.m new file mode 100644 index 000000000..abfad3715 --- /dev/null +++ b/ios/UnitTest/UnitTest/main.m @@ -0,0 +1,18 @@ +/* -*- Mode: ObjC; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + + +#import <UIKit/UIKit.h> +#import "AppDelegate.h" + +int main(int argc, char * argv[]) { + @autoreleasepool { + return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); + } +} diff --git a/ios/welcome.odt b/ios/welcome.odt Binary files differnew file mode 100644 index 000000000..2da7ce6e8 --- /dev/null +++ b/ios/welcome.odt |