diff options
author | sb <sb@openoffice.org> | 2011-01-26 09:26:59 +0100 |
---|---|---|
committer | sb <sb@openoffice.org> | 2011-01-26 09:26:59 +0100 |
commit | 64fadec021c3742d2b45009d632c6fe66b33b13c (patch) | |
tree | ea6b9a55f673ceda0a93ab1a8a0eb45f1cd894ad /binaryurp | |
parent | 22d90133cb7a35854e800ce54c26296154a15d2a (diff) |
sb138: #i116038# fresh implementation of binary URP bridge
Diffstat (limited to 'binaryurp')
38 files changed, 6144 insertions, 0 deletions
diff --git a/binaryurp/prj/build.lst b/binaryurp/prj/build.lst new file mode 100644 index 000000000..230b323f0 --- /dev/null +++ b/binaryurp/prj/build.lst @@ -0,0 +1,3 @@ +bu binaryurp : BOOST:boost LIBXSLT:libxslt cppu cppuhelper offuh sal salhelper stlport NULL +bu binaryurp\source nmake - all bu_source NULL +bu binaryurp\qa nmake - all bu_qa bu_source NULL diff --git a/binaryurp/prj/d.lst b/binaryurp/prj/d.lst new file mode 100644 index 000000000..48ebd3be8 --- /dev/null +++ b/binaryurp/prj/d.lst @@ -0,0 +1,4 @@ +..\%__SRC%\bin\binaryurp.uno.dll %_DEST%\bin%_EXT%\binaryurp.uno.dll +..\%__SRC%\lib\binaryurp.uno.dylib %_DEST%\lib%_EXT%\binaryurp.uno.dylib +..\%__SRC%\lib\binaryurp.uno.so %_DEST%\lib%_EXT%\binaryurp.uno.so +..\%__SRC%\misc\binaryurp.component %_DEST%\xml%_EXT%\binaryurp.component diff --git a/binaryurp/qa/makefile.mk b/binaryurp/qa/makefile.mk new file mode 100644 index 000000000..14b80c86c --- /dev/null +++ b/binaryurp/qa/makefile.mk @@ -0,0 +1,77 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2011 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#***********************************************************************/ + +PRJ = .. +PRJNAME = binaryurp +TARGET = qa + +ENABLE_EXCEPTIONS = TRUE + +.INCLUDE: settings.mk + +CFLAGSCXX += $(CPPUNIT_CFLAGS) + +DLLPRE = + +SLOFILES = $(SLO)/test-cache.obj $(SLO)/test-unmarshal.obj + +SHL1IMPLIB = i$(SHL1TARGET) +SHL1OBJS = $(SLO)/test-cache.obj +SHL1RPATH = NONE +SHL1STDLIBS = $(CPPUNITLIB) $(SALLIB) +SHL1TARGET = test-cache +SHL1VERSIONMAP = version.map +DEF1NAME = $(SHL1TARGET) + +SHL2IMPLIB = i$(SHL2TARGET) +SHL2OBJS = \ + $(SLO)/test-unmarshal.obj \ + $(SLO)/binaryany.obj \ + $(SLO)/bridge.obj \ + $(SLO)/bridgefactory.obj \ + $(SLO)/currentcontext.obj \ + $(SLO)/incomingrequest.obj \ + $(SLO)/lessoperators.obj \ + $(SLO)/marshal.obj \ + $(SLO)/outgoingrequests.obj \ + $(SLO)/proxy.obj \ + $(SLO)/reader.obj \ + $(SLO)/unmarshal.obj \ + $(SLO)/writer.obj +SHL2RPATH = NONE +SHL2STDLIBS = \ + $(CPPUHELPERLIB) \ + $(CPPULIB) \ + $(CPPUNITLIB) \ + $(SALHELPERLIB) \ + $(SALLIB) +SHL2TARGET = test-unmarshal +SHL2VERSIONMAP = version.map +DEF2NAME = $(SHL2TARGET) + +.INCLUDE: target.mk +.INCLUDE: _cppunit.mk diff --git a/binaryurp/qa/test-cache.cxx b/binaryurp/qa/test-cache.cxx new file mode 100644 index 000000000..f9a3946c0 --- /dev/null +++ b/binaryurp/qa/test-cache.cxx @@ -0,0 +1,84 @@ +/************************************************************************* +* +* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +* +* Copyright 2000, 2011 Oracle and/or its affiliates. +* +* OpenOffice.org - a multi-platform office productivity suite +* +* This file is part of OpenOffice.org. +* +* OpenOffice.org is free software: you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License version 3 +* only, as published by the Free Software Foundation. +* +* OpenOffice.org is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Lesser General Public License version 3 for more details +* (a copy is included in the LICENSE file that accompanied this code). +* +* You should have received a copy of the GNU Lesser General Public License +* version 3 along with OpenOffice.org. If not, see +* <http://www.openoffice.org/license.html> +* for a copy of the LGPLv3 License. +* +************************************************************************/ + +#include "sal/config.h" + +#include "cppunit/TestAssert.h" +#include "cppunit/TestFixture.h" +#include "cppunit/extensions/HelperMacros.h" +#include "cppunit/plugin/TestPlugIn.h" + +#include "../source/cache.hxx" + +namespace { + +class Test: public CppUnit::TestFixture { +private: + CPPUNIT_TEST_SUITE(Test); + CPPUNIT_TEST(testNothingLostFromLruList); + CPPUNIT_TEST_SUITE_END(); + + void testNothingLostFromLruList(); +}; + +// cf. jurt/test/com/sun/star/lib/uno/protocols/urp/Cache_Test.java: +void Test::testNothingLostFromLruList() { + int a[8]; + for (int i = 0; i != sizeof a / sizeof a[0]; ++i) { + for (int j = 0; j != i; ++j) { + a[j] = 0; + } + for (;;) { + binaryurp::Cache< int > c(4); + for (int k = 0; k != i; ++k) { + bool f; + c.add(a[k], &f); + } + bool f; + CPPUNIT_ASSERT_EQUAL( + 6, + c.add(-1, &f) + c.add(-2, &f) + c.add(-3, &f) + c.add(-4, &f)); + int j = i - 1; + while (j >= 0 && a[j] == 3) { + --j; + } + if (j < 0) { + break; + } + ++a[j]; + for (int k = j + 1; k != i; ++k) { + a[k] = 0; + } + } + } +} + +CPPUNIT_TEST_SUITE_REGISTRATION(Test); + +} + +CPPUNIT_PLUGIN_IMPLEMENT(); diff --git a/binaryurp/qa/test-unmarshal.cxx b/binaryurp/qa/test-unmarshal.cxx new file mode 100644 index 000000000..3d3c1795a --- /dev/null +++ b/binaryurp/qa/test-unmarshal.cxx @@ -0,0 +1,112 @@ +/************************************************************************* +* +* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +* +* Copyright 2000, 2011 Oracle and/or its affiliates. +* +* OpenOffice.org - a multi-platform office productivity suite +* +* This file is part of OpenOffice.org. +* +* OpenOffice.org is free software: you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License version 3 +* only, as published by the Free Software Foundation. +* +* OpenOffice.org is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Lesser General Public License version 3 for more details +* (a copy is included in the LICENSE file that accompanied this code). +* +* You should have received a copy of the GNU Lesser General Public License +* version 3 along with OpenOffice.org. If not, see +* <http://www.openoffice.org/license.html> +* for a copy of the LGPLv3 License. +* +************************************************************************/ + +#include "sal/config.h" + +#include "com/sun/star/io/IOException.hpp" +#include "com/sun/star/uno/Sequence.hxx" +#include "cppu/unotype.hxx" +#include "cppunit/TestAssert.h" +#include "cppunit/TestFixture.h" +#include "cppunit/extensions/HelperMacros.h" +#include "cppunit/plugin/TestPlugIn.h" +#include "rtl/ref.hxx" +#include "rtl/string.h" +#include "sal/types.h" +#include "typelib/typedescription.hxx" + +#include "../source/bridge.hxx" +#include "../source/cache.hxx" +#include "../source/readerstate.hxx" +#include "../source/unmarshal.hxx" + +namespace { + +namespace css = com::sun::star; + +class Test: public CppUnit::TestFixture { +private: + CPPUNIT_TEST_SUITE(Test); + CPPUNIT_TEST(testTypeOfBooleanSequence); + CPPUNIT_TEST(testTypeOfVoidSequence); + CPPUNIT_TEST_SUITE_END(); + + void testTypeOfBooleanSequence(); + + void testTypeOfVoidSequence(); +}; + +void Test::testTypeOfBooleanSequence() { + binaryurp::ReaderState state; + css::uno::Sequence< sal_Int8 > buf(13); + buf[0] = static_cast< sal_Int8 >(20 | 0x80); // sequence type | cache flag + buf[1] = static_cast< sal_Int8 >(binaryurp::cache::ignore >> 8); + buf[2] = static_cast< sal_Int8 >(binaryurp::cache::ignore & 0xFF); + buf[3] = RTL_CONSTASCII_LENGTH("[]boolean"); + buf[4] = '['; + buf[5] = ']'; + buf[6] = 'b'; + buf[7] = 'o'; + buf[8] = 'o'; + buf[9] = 'l'; + buf[10] = 'e'; + buf[11] = 'a'; + buf[12] = 'n'; + binaryurp::Unmarshal m(rtl::Reference< binaryurp::Bridge >(), state, buf); + css::uno::TypeDescription t(m.readType()); + CPPUNIT_ASSERT( + t.equals( + css::uno::TypeDescription( + cppu::UnoType< css::uno::Sequence< bool > >::get()))); + m.done(); +} + +void Test::testTypeOfVoidSequence() { + binaryurp::ReaderState state; + css::uno::Sequence< sal_Int8 > buf(10); + buf[0] = static_cast< sal_Int8 >(20 | 0x80); // sequence type | cache flag + buf[1] = static_cast< sal_Int8 >(binaryurp::cache::ignore >> 8); + buf[2] = static_cast< sal_Int8 >(binaryurp::cache::ignore & 0xFF); + buf[3] = RTL_CONSTASCII_LENGTH("[]void"); + buf[4] = '['; + buf[5] = ']'; + buf[6] = 'v'; + buf[7] = 'o'; + buf[8] = 'i'; + buf[9] = 'd'; + binaryurp::Unmarshal m(rtl::Reference< binaryurp::Bridge >(), state, buf); + try { + m.readType(); + CPPUNIT_FAIL("exception expected"); + } catch (css::io::IOException &) {} +} + +CPPUNIT_TEST_SUITE_REGISTRATION(Test); + +} + +CPPUNIT_PLUGIN_IMPLEMENT(); diff --git a/binaryurp/qa/version.map b/binaryurp/qa/version.map new file mode 100644 index 000000000..ef2ab497c --- /dev/null +++ b/binaryurp/qa/version.map @@ -0,0 +1,34 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2011 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#***********************************************************************/ + +UDK_3_0_0 { + global: + cppunitTestPlugIn; + + local: + *; +}; diff --git a/binaryurp/source/binaryany.cxx b/binaryurp/source/binaryany.cxx new file mode 100644 index 000000000..c5b8b1a3c --- /dev/null +++ b/binaryurp/source/binaryany.cxx @@ -0,0 +1,98 @@ +/************************************************************************* +* +* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +* +* Copyright 2000, 2011 Oracle and/or its affiliates. +* +* OpenOffice.org - a multi-platform office productivity suite +* +* This file is part of OpenOffice.org. +* +* OpenOffice.org is free software: you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License version 3 +* only, as published by the Free Software Foundation. +* +* OpenOffice.org is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Lesser General Public License version 3 for more details +* (a copy is included in the LICENSE file that accompanied this code). +* +* You should have received a copy of the GNU Lesser General Public License +* version 3 along with OpenOffice.org. If not, see +* <http://www.openoffice.org/license.html> +* for a copy of the LGPLv3 License. +* +************************************************************************/ + +#include "sal/config.h" + +#include "osl/diagnose.h" +#include "typelib/typeclass.h" +#include "typelib/typedescription.hxx" +#include "uno/any2.h" + +#include "binaryany.hxx" + +namespace binaryurp { + +namespace { + +namespace css = com::sun::star; + +} + +BinaryAny::BinaryAny() throw () { + uno_any_construct(&data_, 0, 0, 0); +} + +BinaryAny::BinaryAny(css::uno::TypeDescription const & type, void * value) + throw () +{ + OSL_ASSERT(type.is()); + uno_any_construct(&data_, value, type.get(), 0); +} + +BinaryAny::BinaryAny(uno_Any const & raw) throw () { + OSL_ASSERT(raw.pType != 0); + data_.pType = raw.pType; + typelib_typedescriptionreference_acquire(data_.pType); + data_.pData = raw.pData == &raw.pReserved ? &data_.pReserved : raw.pData; + data_.pReserved = raw.pReserved; +} + +BinaryAny::BinaryAny(BinaryAny const & other) throw () { + uno_type_any_construct(&data_, other.data_.pData, other.data_.pType, 0); +} + +BinaryAny::~BinaryAny() throw () { + uno_any_destruct(&data_, 0); +} + +BinaryAny & BinaryAny::operator =(BinaryAny const & other) throw () { + if (&other != this) { + uno_type_any_assign(&data_, other.data_.pData, other.data_.pType, 0, 0); + } + return *this; +} + +uno_Any * BinaryAny::get() throw () { + return &data_; +} + +css::uno::TypeDescription BinaryAny::getType() const throw () { + return css::uno::TypeDescription(data_.pType); +} + +void * BinaryAny::getValue(css::uno::TypeDescription const & type) const + throw () +{ + OSL_ASSERT( + type.is() && + (type.get()->eTypeClass == typelib_TypeClass_ANY || + type.equals(css::uno::TypeDescription(data_.pType)))); + return type.get()->eTypeClass == typelib_TypeClass_ANY + ? &data_ : data_.pData; +} + +} diff --git a/binaryurp/source/binaryany.hxx b/binaryurp/source/binaryany.hxx new file mode 100644 index 000000000..4dd6112b5 --- /dev/null +++ b/binaryurp/source/binaryany.hxx @@ -0,0 +1,73 @@ +/************************************************************************* +* +* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +* +* Copyright 2000, 2011 Oracle and/or its affiliates. +* +* OpenOffice.org - a multi-platform office productivity suite +* +* This file is part of OpenOffice.org. +* +* OpenOffice.org is free software: you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License version 3 +* only, as published by the Free Software Foundation. +* +* OpenOffice.org is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Lesser General Public License version 3 for more details +* (a copy is included in the LICENSE file that accompanied this code). +* +* You should have received a copy of the GNU Lesser General Public License +* version 3 along with OpenOffice.org. If not, see +* <http://www.openoffice.org/license.html> +* for a copy of the LGPLv3 License. +* +************************************************************************/ + +#ifndef INCLUDED_BINARYURP_SOURCE_BINARYANY_HXX +#define INCLUDED_BINARYURP_SOURCE_BINARYANY_HXX + +#include "sal/config.h" + +#include "uno/any2.h" + +namespace com { namespace sun { namespace star { namespace uno { + class TypeDescription; +} } } } + +namespace binaryurp { + +class BinaryAny { +public: + BinaryAny() throw (); + + BinaryAny(com::sun::star::uno::TypeDescription const & type, void * value) + throw (); + + explicit BinaryAny(uno_Any const & raw) throw (); + // takes over raw.pData (but copies raw.pType); raw must not be passed + // to uno_any_destruct + + BinaryAny(BinaryAny const & other) throw (); + + ~BinaryAny() throw (); + + BinaryAny & operator =(BinaryAny const & other) throw (); + + uno_Any * get() throw (); + + com::sun::star::uno::TypeDescription getType() const throw (); + + void * getValue(com::sun::star::uno::TypeDescription const & type) const + throw (); + +private: + mutable uno_Any data_; + // mutable so that getValue() can return a non-const void *, as in turn + // required at various places in binary UNO +}; + +} + +#endif diff --git a/binaryurp/source/binaryurp.component b/binaryurp/source/binaryurp.component new file mode 100644 index 000000000..19554bcc0 --- /dev/null +++ b/binaryurp/source/binaryurp.component @@ -0,0 +1,34 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!--********************************************************************** +* +* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +* +* Copyright 2000, 2011 Oracle and/or its affiliates. +* +* OpenOffice.org - a multi-platform office productivity suite +* +* This file is part of OpenOffice.org. +* +* OpenOffice.org is free software: you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License version 3 +* only, as published by the Free Software Foundation. +* +* OpenOffice.org is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Lesser General Public License version 3 for more details +* (a copy is included in the LICENSE file that accompanied this code). +* +* You should have received a copy of the GNU Lesser General Public License +* version 3 along with OpenOffice.org. If not, see +* <http://www.openoffice.org/license.html> +* for a copy of the LGPLv3 License. +* +**********************************************************************--> + +<component loader="com.sun.star.loader.SharedLibrary" + xmlns="http://openoffice.org/2010/uno-components"> + <implementation name="com.sun.star.comp.bridge.BridgeFactory"> + <service name="com.sun.star.bridge.BridgeFactory"/> + </implementation> +</component> diff --git a/binaryurp/source/bridge.cxx b/binaryurp/source/bridge.cxx new file mode 100644 index 000000000..dcf77662c --- /dev/null +++ b/binaryurp/source/bridge.cxx @@ -0,0 +1,978 @@ +/************************************************************************* +* +* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +* +* Copyright 2000, 2011 Oracle and/or its affiliates. +* +* OpenOffice.org - a multi-platform office productivity suite +* +* This file is part of OpenOffice.org. +* +* OpenOffice.org is free software: you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License version 3 +* only, as published by the Free Software Foundation. +* +* OpenOffice.org is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Lesser General Public License version 3 for more details +* (a copy is included in the LICENSE file that accompanied this code). +* +* You should have received a copy of the GNU Lesser General Public License +* version 3 along with OpenOffice.org. If not, see +* <http://www.openoffice.org/license.html> +* for a copy of the LGPLv3 License. +* +************************************************************************/ + +#include "sal/config.h" + +#include <algorithm> +#include <cstddef> +#include <limits> +#include <memory> +#include <vector> + +#include "boost/noncopyable.hpp" +#include "com/sun/star/bridge/InvalidProtocolChangeException.hpp" +#include "com/sun/star/bridge/XBridge.hpp" +#include "com/sun/star/bridge/XInstanceProvider.hpp" +#include "com/sun/star/bridge/XProtocolProperties.hpp" +#include "com/sun/star/connection/XConnection.hpp" +#include "com/sun/star/io/IOException.hpp" +#include "com/sun/star/lang/DisposedException.hpp" +#include "com/sun/star/lang/EventObject.hpp" +#include "com/sun/star/lang/XEventListener.hpp" +#include "com/sun/star/uno/Reference.hxx" +#include "com/sun/star/uno/RuntimeException.hpp" +#include "com/sun/star/uno/Sequence.hxx" +#include "com/sun/star/uno/XInterface.hpp" +#include "cppuhelper/exc_hlp.hxx" +#include "cppuhelper/weak.hxx" +#include "osl/diagnose.h" +#include "osl/mutex.hxx" +#include "osl/thread.hxx" +#include "rtl/byteseq.hxx" +#include "rtl/random.h" +#include "rtl/ref.hxx" +#include "rtl/textenc.h" +#include "rtl/ustrbuf.hxx" +#include "rtl/ustring.h" +#include "rtl/ustring.hxx" +#include "sal/types.h" +#include "typelib/typeclass.h" +#include "typelib/typedescription.h" +#include "typelib/typedescription.hxx" +#include "uno/dispatcher.hxx" +#include "uno/environment.hxx" +#include "uno/lbnames.h" + +#include "binaryany.hxx" +#include "bridge.hxx" +#include "bridgefactory.hxx" +#include "incomingreply.hxx" +#include "lessoperators.hxx" +#include "outgoingrequest.hxx" +#include "outgoingrequests.hxx" +#include "proxy.hxx" +#include "reader.hxx" + +namespace binaryurp { + +namespace { + +namespace css = com::sun::star; + +sal_Int32 random() { + sal_Int32 n; + rtlRandomPool pool = rtl_random_createPool(); + rtl_random_getBytes(pool, &n, sizeof n); + rtl_random_destroyPool(pool); + return n; +} + +extern "C" void SAL_CALL freeProxyCallback(uno_ExtEnvironment *, void * pProxy) +{ + OSL_ASSERT(pProxy != 0); + static_cast< Proxy * >(pProxy)->do_free(); +} + +void joinThread(osl::Thread * thread) { + OSL_ASSERT(thread != 0); + if (thread->getIdentifier() != osl::Thread::getCurrentIdentifier()) { + thread->join(); + } +} + +class AttachThread: private boost::noncopyable { +public: + explicit AttachThread(uno_ThreadPool threadPool); + + ~AttachThread(); + + rtl::ByteSequence getTid() throw (); + +private: + uno_ThreadPool threadPool_; + rtl::ByteSequence tid_; +}; + +AttachThread::AttachThread(uno_ThreadPool threadPool): threadPool_(threadPool) { + sal_Sequence * s = 0; + uno_getIdOfCurrentThread(&s); + tid_ = rtl::ByteSequence(s, rtl::BYTESEQ_NOACQUIRE); + uno_threadpool_attach(threadPool_); +} + +AttachThread::~AttachThread() { + uno_threadpool_detach(threadPool_); + uno_releaseIdFromCurrentThread(); +} + +rtl::ByteSequence AttachThread::getTid() throw () { + return tid_; +} + +class PopOutgoingRequest: private boost::noncopyable { +public: + PopOutgoingRequest( + OutgoingRequests & requests, rtl::ByteSequence const & tid, + OutgoingRequest const & request); + + ~PopOutgoingRequest(); + + void clear(); + +private: + OutgoingRequests & requests_; + rtl::ByteSequence tid_; + bool cleared_; +}; + +PopOutgoingRequest::PopOutgoingRequest( + OutgoingRequests & requests, rtl::ByteSequence const & tid, + OutgoingRequest const & request): + requests_(requests), tid_(tid), cleared_(false) +{ + requests_.push(tid_, request); +} + +PopOutgoingRequest::~PopOutgoingRequest() { + if (!cleared_) { + requests_.pop(tid_); + } +} + +void PopOutgoingRequest::clear() { + cleared_ = true; +} + +} + +struct Bridge::SubStub { + com::sun::star::uno::UnoInterfaceReference object; + + sal_uInt32 references; +}; + +Bridge::Bridge( + rtl::Reference< BridgeFactory > const & factory, rtl::OUString const & name, + css::uno::Reference< css::connection::XConnection > const & connection, + css::uno::Reference< css::bridge::XInstanceProvider > const & provider): + factory_(factory), name_(name), connection_(connection), + provider_(provider), + binaryUno_(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(UNO_LB_UNO))), + cppToBinaryMapping_( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM(CPPU_CURRENT_LANGUAGE_BINDING_NAME)), + rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(UNO_LB_UNO))), + binaryToCppMapping_( + rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(UNO_LB_UNO)), + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM(CPPU_CURRENT_LANGUAGE_BINDING_NAME))), + protPropTid_( + reinterpret_cast< sal_Int8 const * >(".UrpProtocolPropertiesTid"), + RTL_CONSTASCII_LENGTH(".UrpProtocolPropertiesTid")), + protPropOid_(RTL_CONSTASCII_USTRINGPARAM("UrpProtocolProperties")), + protPropType_( + cppu::UnoType< + css::uno::Reference< css::bridge::XProtocolProperties > >::get()), + protPropRequest_( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "com.sun.star.bridge.XProtocolProperties::requestChange"))), + protPropCommit_( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "com.sun.star.bridge.XProtocolProperties::commitChange"))), + threadPool_(0), currentContextMode_(false), proxies_(0), calls_(0), + normalCall_(false), activeCalls_(0), terminated_(false), + mode_(MODE_REQUESTED) +{ + OSL_ASSERT(factory.is() && connection.is()); + if (!binaryUno_.is()) { + throw css::uno::RuntimeException( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM("URP: no binary UNO environment")), + css::uno::Reference< css::uno::XInterface >()); + } + if (!(cppToBinaryMapping_.is() && binaryToCppMapping_.is())) { + throw css::uno::RuntimeException( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM("URP: no C++ UNO mapping")), + css::uno::Reference< css::uno::XInterface >()); + } + passive_.set(); +} + +void Bridge::start() { + OSL_ASSERT(threadPool_ == 0 && !writer_.is() && !reader_.is()); + threadPool_ = uno_threadpool_create(); + OSL_ASSERT(threadPool_ != 0); + writer_.set(new Writer(this)); + writer_->create(); + reader_.set(new Reader(this)); + reader_->create(); +} + +void Bridge::terminate() { + rtl::Reference< Reader > r; + rtl::Reference< Writer > w; + Listeners ls; + { + osl::MutexGuard g(mutex_); + if (terminated_) { + return; + } + std::swap(reader_, r); + std::swap(writer_, w); + ls.swap(listeners_); + terminated_ = true; + } + try { + connection_->close(); + } catch (css::io::IOException & e) { + OSL_TRACE( + OSL_LOG_PREFIX "caught IO exception '%s'", + rtl::OUStringToOString(e.Message, RTL_TEXTENCODING_UTF8).getStr()); + } + OSL_ASSERT(w.is()); + w->stop(); + joinThread(r.get()); + joinThread(w.get()); + OSL_ASSERT(threadPool_ != 0); + uno_threadpool_dispose(threadPool_); + Stubs s; + { + osl::MutexGuard g(mutex_); + s.swap(stubs_); + } + for (Stubs::iterator i(s.begin()); i != s.end(); ++i) { + for (Stub::iterator j(i->second.begin()); j != i->second.end(); ++j) { + binaryUno_.get()->pExtEnv->revokeInterface( + binaryUno_.get()->pExtEnv, j->second.object.get()); + } + } + factory_->removeBridge(this); + for (Listeners::iterator i(ls.begin()); i != ls.end(); ++i) { + try { + (*i)->disposing( + css::lang::EventObject( + static_cast< cppu::OWeakObject * >(this))); + } catch (css::uno::RuntimeException & e) { + OSL_TRACE( + OSL_LOG_PREFIX "caught runtime exception '%s'", + rtl::OUStringToOString( + e.Message, RTL_TEXTENCODING_UTF8).getStr()); + } + } +} + +css::uno::Reference< css::connection::XConnection > Bridge::getConnection() + const +{ + return connection_; +} + +css::uno::Reference< css::bridge::XInstanceProvider > Bridge::getProvider() + const +{ + return provider_; +} + +css::uno::Mapping & Bridge::getCppToBinaryMapping() { + return cppToBinaryMapping_; +} + +BinaryAny Bridge::mapCppToBinaryAny(css::uno::Any const & cppAny) { + css::uno::Any in(cppAny); + BinaryAny out; + out.~BinaryAny(); + uno_copyAndConvertData( + out.get(), &in, + css::uno::TypeDescription(cppu::UnoType< css::uno::Any >::get()).get(), + cppToBinaryMapping_.get()); + return out; +} + +uno_ThreadPool Bridge::getThreadPool() const { + OSL_ASSERT(threadPool_ != 0); + return threadPool_; +} + +rtl::Reference< Writer > Bridge::getWriter() { + osl::MutexGuard g(mutex_); + if (terminated_) { + throw css::lang::DisposedException( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "Binary URP bridge already disposed")), + static_cast< cppu::OWeakObject * >(this)); + } + OSL_ASSERT(writer_.is()); + return writer_; +} + +css::uno::UnoInterfaceReference Bridge::registerIncomingInterface( + rtl::OUString const & oid, css::uno::TypeDescription const & type) +{ + OSL_ASSERT(type.is()); + if (oid.getLength() == 0) { + return css::uno::UnoInterfaceReference(); + } + css::uno::UnoInterfaceReference obj(findStub(oid, type)); + if (!obj.is()) { + binaryUno_.get()->pExtEnv->getRegisteredInterface( + binaryUno_.get()->pExtEnv, + reinterpret_cast< void ** >(&obj.m_pUnoI), oid.pData, + reinterpret_cast< typelib_InterfaceTypeDescription * >(type.get())); + if (obj.is()) { + makeReleaseCall(oid, type); + } else { + obj.set(new Proxy(this, oid, type), SAL_NO_ACQUIRE); + { + osl::MutexGuard g(mutex_); + OSL_ASSERT( + proxies_ < std::numeric_limits< std::size_t >::max()); + ++proxies_; + } + binaryUno_.get()->pExtEnv->registerProxyInterface( + binaryUno_.get()->pExtEnv, + reinterpret_cast< void ** >(&obj.m_pUnoI), &freeProxyCallback, + oid.pData, + reinterpret_cast< typelib_InterfaceTypeDescription * >( + type.get())); + } + } + return obj; +} + +rtl::OUString Bridge::registerOutgoingInterface( + css::uno::UnoInterfaceReference const & object, + css::uno::TypeDescription const & type) +{ + OSL_ASSERT(type.is()); + if (!object.is()) { + return rtl::OUString(); + } + rtl::OUString oid; + if (!Proxy::isProxy(this, object, &oid)) { + binaryUno_.get()->pExtEnv->getObjectIdentifier( + binaryUno_.get()->pExtEnv, &oid.pData, object.get()); + osl::MutexGuard g(mutex_); + Stubs::iterator i(stubs_.find(oid)); + Stub newStub; + Stub * stub = i == stubs_.end() ? &newStub : &i->second; + Stub::iterator j(stub->find(type)); + //TODO: Release sub-stub if it is not successfully sent to remote side + // (otherwise, stub will leak until terminate()): + if (j == stub->end()) { + j = stub->insert(Stub::value_type(type, SubStub())).first; + if (stub == &newStub) { + i = stubs_.insert(Stubs::value_type(oid, Stub())).first; + std::swap(i->second, newStub); + j = i->second.find(type); + OSL_ASSERT(j != i->second.end()); + } + j->second.object = object; + j->second.references = 1; + binaryUno_.get()->pExtEnv->registerInterface( + binaryUno_.get()->pExtEnv, + reinterpret_cast< void ** >(&j->second.object.m_pUnoI), + oid.pData, + reinterpret_cast< typelib_InterfaceTypeDescription * >( + type.get())); + } else { + OSL_ASSERT(stub != &newStub); + if (j->second.references == SAL_MAX_UINT32) { + throw css::uno::RuntimeException( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "URP: stub reference count overflow")), + css::uno::Reference< css::uno::XInterface >()); + } + ++j->second.references; + } + } + return oid; +} + +css::uno::UnoInterfaceReference Bridge::findStub( + rtl::OUString const & oid, css::uno::TypeDescription const & type) +{ + OSL_ASSERT(oid.getLength() != 0 && type.is()); + osl::MutexGuard g(mutex_); + Stubs::iterator i(stubs_.find(oid)); + if (i != stubs_.end()) { + Stub::iterator j(i->second.find(type)); + if (j != i->second.end()) { + return j->second.object; + } + for (j = i->second.begin(); j != i->second.end(); ++j) { + if (typelib_typedescription_isAssignableFrom( + type.get(), j->first.get())) + { + return j->second.object; + } + } + } + return css::uno::UnoInterfaceReference(); +} + +void Bridge::releaseStub( + rtl::OUString const & oid, css::uno::TypeDescription const & type) +{ + OSL_ASSERT(oid.getLength() != 0 && type.is()); + css::uno::UnoInterfaceReference obj; + bool unused; + { + osl::MutexGuard g(mutex_); + Stubs::iterator i(stubs_.find(oid)); + if (i == stubs_.end()) { + throw css::uno::RuntimeException( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM("URP: release unknown stub")), + css::uno::Reference< css::uno::XInterface >()); + } + Stub::iterator j(i->second.find(type)); + if (j == i->second.end()) { + throw css::uno::RuntimeException( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM("URP: release unknown stub")), + css::uno::Reference< css::uno::XInterface >()); + } + OSL_ASSERT(j->second.references > 0); + --j->second.references; + if (j->second.references == 0) { + obj = j->second.object; + i->second.erase(j); + if (i->second.empty()) { + stubs_.erase(i); + } + } + unused = becameUnused(); + } + if (obj.is()) { + binaryUno_.get()->pExtEnv->revokeInterface( + binaryUno_.get()->pExtEnv, obj.get()); + } + terminateWhenUnused(unused); +} + +void Bridge::resurrectProxy(Proxy & proxy) { + uno_Interface * p = &proxy; + binaryUno_.get()->pExtEnv->registerProxyInterface( + binaryUno_.get()->pExtEnv, + reinterpret_cast< void ** >(&p), &freeProxyCallback, + proxy.getOid().pData, + reinterpret_cast< typelib_InterfaceTypeDescription * >( + proxy.getType().get())); + OSL_ASSERT(p == &proxy); +} + +void Bridge::revokeProxy(Proxy & proxy) { + binaryUno_.get()->pExtEnv->revokeInterface( + binaryUno_.get()->pExtEnv, &proxy); +} + +void Bridge::freeProxy(Proxy & proxy) { + try { + makeReleaseCall(proxy.getOid(), proxy.getType()); + } catch (css::uno::RuntimeException & e) { + OSL_TRACE( + OSL_LOG_PREFIX "caught runtime exception '%s'", + rtl::OUStringToOString(e.Message, RTL_TEXTENCODING_UTF8).getStr()); + } catch (std::exception & e) { + OSL_TRACE(OSL_LOG_PREFIX "caught C++ exception '%s'", e.what()); + } + bool unused; + { + osl::MutexGuard g(mutex_); + OSL_ASSERT(proxies_ > 0); + --proxies_; + unused = becameUnused(); + } + terminateWhenUnused(unused); +} + +void Bridge::incrementCalls(bool normalCall) throw () { + osl::MutexGuard g(mutex_); + OSL_ASSERT(calls_ < std::numeric_limits< std::size_t >::max()); + ++calls_; + normalCall_ |= normalCall; +} + +void Bridge::decrementCalls() { + bool unused; + { + osl::MutexGuard g(mutex_); + OSL_ASSERT(calls_ > 0); + --calls_; + unused = becameUnused(); + } + terminateWhenUnused(unused); +} + +void Bridge::incrementActiveCalls() throw () { + osl::MutexGuard g(mutex_); + OSL_ASSERT( + activeCalls_ <= calls_ && + activeCalls_ < std::numeric_limits< std::size_t >::max()); + ++activeCalls_; + passive_.reset(); +} + +void Bridge::decrementActiveCalls() throw () { + osl::MutexGuard g(mutex_); + OSL_ASSERT(activeCalls_ <= calls_ && activeCalls_ > 0); + --activeCalls_; + if (activeCalls_ == 0) { + passive_.set(); + } +} + +bool Bridge::makeCall( + rtl::OUString const & oid, css::uno::TypeDescription const & member, + bool setter, std::vector< BinaryAny > const & inArguments, + BinaryAny * returnValue, std::vector< BinaryAny > * outArguments) +{ + std::auto_ptr< IncomingReply > resp; + { + AttachThread att(threadPool_); + PopOutgoingRequest pop( + outgoingRequests_, att.getTid(), + OutgoingRequest(OutgoingRequest::KIND_NORMAL, member, setter)); + sendRequest( + att.getTid(), oid, css::uno::TypeDescription(), member, + inArguments); + pop.clear(); + incrementCalls(true); + incrementActiveCalls(); + void * job; + uno_threadpool_enter(threadPool_, &job); + resp.reset(static_cast< IncomingReply * >(job)); + decrementActiveCalls(); + decrementCalls(); + } + if (resp.get() == 0) { + throw css::lang::DisposedException( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "Binary URP bridge disposed during call")), + static_cast< cppu::OWeakObject * >(this)); + } + *returnValue = resp->returnValue; + if (!resp->exception) { + *outArguments = resp->outArguments; + } + return resp->exception; +} + +void Bridge::sendRequestChangeRequest() { + OSL_ASSERT(mode_ == MODE_REQUESTED); + random_ = random(); + std::vector< BinaryAny > a; + a.push_back( + BinaryAny( + css::uno::TypeDescription(cppu::UnoType< sal_Int32 >::get()), + &random_)); + sendProtPropRequest(OutgoingRequest::KIND_REQUEST_CHANGE, a); +} + +void Bridge::handleRequestChangeReply( + bool exception, BinaryAny const & returnValue) +{ + throwException(exception, returnValue); + sal_Int32 n = *static_cast< sal_Int32 * >( + returnValue.getValue( + css::uno::TypeDescription(cppu::UnoType< sal_Int32 >::get()))); + sal_Int32 exp = 0; + switch (mode_) { + case MODE_REQUESTED: + case MODE_REPLY_1: + exp = 1; + break; + case MODE_REPLY_MINUS1: + exp = -1; + mode_ = MODE_REQUESTED; + break; + case MODE_REPLY_0: + exp = 0; + mode_ = MODE_WAIT; + break; + default: + OSL_ASSERT(false); // this cannot happen + break; + } + if (n != exp) { + throw css::uno::RuntimeException( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "URP: requestChange reply with unexpected return value" + " received")), + static_cast< cppu::OWeakObject * >(this)); + } + decrementCalls(); + switch (exp) { + case -1: + sendRequestChangeRequest(); + break; + case 0: + break; + case 1: + sendCommitChangeRequest(); + break; + default: + OSL_ASSERT(false); // this cannot happen + break; + } +} + +void Bridge::handleCommitChangeReply( + bool exception, BinaryAny const & returnValue) +{ + bool ccMode = true; + try { + throwException(exception, returnValue); + } catch (css::bridge::InvalidProtocolChangeException &) { + ccMode = false; + } + if (ccMode) { + setCurrentContextMode(); + } + OSL_ASSERT(mode_ == MODE_REQUESTED || mode_ == MODE_REPLY_1); + mode_ = MODE_NORMAL; + getWriter()->unblock(); + decrementCalls(); +} + +void Bridge::handleRequestChangeRequest( + rtl::ByteSequence const & tid, std::vector< BinaryAny > const & inArguments) +{ + OSL_ASSERT(inArguments.size() == 1); + switch (mode_) { + case MODE_REQUESTED: + { + sal_Int32 n2 = *static_cast< sal_Int32 * >( + inArguments[0].getValue( + css::uno::TypeDescription( + cppu::UnoType< sal_Int32 >::get()))); + sal_Int32 ret; + if (n2 > random_) { + ret = 1; + mode_ = MODE_REPLY_0; + } else if (n2 == random_) { + ret = -1; + mode_ = MODE_REPLY_MINUS1; + } else { + ret = 0; + mode_ = MODE_REPLY_1; + } + getWriter()->sendDirectReply( + tid, protPropRequest_, false, + BinaryAny( + css::uno::TypeDescription( + cppu::UnoType< sal_Int32 >::get()), + &ret), + std::vector< BinaryAny >()); + break; + } + case MODE_NORMAL: + { + mode_ = MODE_NORMAL_WAIT; + sal_Int32 ret = 1; + getWriter()->queueReply( + tid, protPropRequest_, false, false, + BinaryAny( + css::uno::TypeDescription( + cppu::UnoType< sal_Int32 >::get()), + &ret), + std::vector< BinaryAny >(), false); + break; + } + default: + throw css::uno::RuntimeException( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "URP: unexpected requestChange request received")), + static_cast< cppu::OWeakObject * >(this)); + } +} + +void Bridge::handleCommitChangeRequest( + rtl::ByteSequence const & tid, std::vector< BinaryAny > const & inArguments) +{ + bool ccMode = false; + bool exc = false; + BinaryAny ret; + OSL_ASSERT(inArguments.size() == 1); + css::uno::Sequence< css::bridge::ProtocolProperty > s; + OSL_VERIFY(mapBinaryToCppAny(inArguments[0]) >>= s); + for (sal_Int32 i = 0; i != s.getLength(); ++i) { + if (s[i].Name.equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM("CurrentContext"))) + { + ccMode = true; + } else { + ccMode = false; + exc = true; + ret = mapCppToBinaryAny( + css::uno::makeAny( + css::bridge::InvalidProtocolChangeException( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "InvalidProtocolChangeException")), + css::uno::Reference< css::uno::XInterface >(), s[i], + 1))); + break; + } + } + switch (mode_) { + case MODE_WAIT: + getWriter()->sendDirectReply( + tid, protPropCommit_, exc, ret, std::vector< BinaryAny >()); + if (ccMode) { + setCurrentContextMode(); + mode_ = MODE_NORMAL; + getWriter()->unblock(); + } else { + mode_ = MODE_REQUESTED; + sendRequestChangeRequest(); + } + break; + case MODE_NORMAL_WAIT: + getWriter()->queueReply( + tid, protPropCommit_, false, false, ret, std::vector< BinaryAny >(), + ccMode); + mode_ = MODE_NORMAL; + break; + default: + throw css::uno::RuntimeException( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "URP: unexpected commitChange request received")), + static_cast< cppu::OWeakObject * >(this)); + } +} + +OutgoingRequest Bridge::lastOutgoingRequest(rtl::ByteSequence const & tid) { + OutgoingRequest req(outgoingRequests_.top(tid)); + outgoingRequests_.pop(tid); + return req; +} + +bool Bridge::isProtocolPropertiesRequest( + rtl::OUString const & oid, css::uno::TypeDescription const & type) const +{ + return oid == protPropOid_ && type.equals(protPropType_); +} + +void Bridge::setCurrentContextMode() { + osl::MutexGuard g(mutex_); + currentContextMode_ = true; +} + +bool Bridge::isCurrentContextMode() { + osl::MutexGuard g(mutex_); + return currentContextMode_; +} + +Bridge::~Bridge() { + if (threadPool_ != 0) { + uno_threadpool_destroy(threadPool_); + } +} + +css::uno::Reference< css::uno::XInterface > Bridge::getInstance( + rtl::OUString const & sInstanceName) throw (css::uno::RuntimeException) +{ + if (sInstanceName.getLength() == 0) { + throw css::uno::RuntimeException( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "XBridge::getInstance sInstanceName must be non-empty")), + static_cast< cppu::OWeakObject * >(this)); + } + for (sal_Int32 i = 0; i != sInstanceName.getLength(); ++i) { + if (sInstanceName[i] > 0x7F) { + throw css::io::IOException( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "XBridge::getInstance sInstanceName contains non-ASCII" + " character")), + css::uno::Reference< css::uno::XInterface >()); + } + } + css::uno::TypeDescription ifc( + cppu::UnoType< css::uno::Reference< css::uno::XInterface > >::get()); + typelib_TypeDescription * p = ifc.get(); + std::vector< BinaryAny > inArgs; + inArgs.push_back( + BinaryAny( + css::uno::TypeDescription(cppu::UnoType< css::uno::Type >::get()), + &p)); + BinaryAny ret; + std::vector< BinaryAny> outArgs; + bool exc = makeCall( + sInstanceName, + css::uno::TypeDescription( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "com.sun.star.uno.XInterface::queryInterface"))), + false, inArgs, &ret, &outArgs); + throwException(exc, ret); + return css::uno::Reference< css::uno::XInterface >( + static_cast< css::uno::XInterface * >( + binaryToCppMapping_.mapInterface( + *static_cast< uno_Interface ** >(ret.getValue(ifc)), + ifc.get())), + css::uno::UNO_REF_NO_ACQUIRE); +} + +rtl::OUString Bridge::getName() throw (css::uno::RuntimeException) { + return name_; +} + +rtl::OUString Bridge::getDescription() throw (css::uno::RuntimeException) { + rtl::OUStringBuffer b(name_); + b.append(sal_Unicode(':')); + b.append(connection_->getDescription()); + return b.makeStringAndClear(); +} + +void Bridge::dispose() throw (css::uno::RuntimeException) { + terminate(); + // OOo expects dispose to not return while there are still remote calls in + // progress; an external protocol must ensure that dispose is not called + // from within an incoming or outgoing remote call, as passive_.wait() would + // otherwise deadlock: + passive_.wait(); +} + +void Bridge::addEventListener( + css::uno::Reference< css::lang::XEventListener > const & xListener) + throw (css::uno::RuntimeException) +{ + OSL_ASSERT(xListener.is()); + { + osl::MutexGuard g(mutex_); + if (!terminated_) { + listeners_.push_back(xListener); + return; + } + } + xListener->disposing( + css::lang::EventObject(static_cast< cppu::OWeakObject * >(this))); +} + +void Bridge::removeEventListener( + css::uno::Reference< css::lang::XEventListener > const & aListener) + throw (css::uno::RuntimeException) +{ + osl::MutexGuard g(mutex_); + Listeners::iterator i( + std::find(listeners_.begin(), listeners_.end(), aListener)); + if (i != listeners_.end()) { + listeners_.erase(i); + } +} + +void Bridge::sendCommitChangeRequest() { + OSL_ASSERT(mode_ == MODE_REQUESTED || mode_ == MODE_REPLY_1); + css::uno::Sequence< css::bridge::ProtocolProperty > s(1); + s[0].Name = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("CurrentContext")); + std::vector< BinaryAny > a; + a.push_back(mapCppToBinaryAny(css::uno::makeAny(s))); + sendProtPropRequest(OutgoingRequest::KIND_COMMIT_CHANGE, a); +} + +void Bridge::sendProtPropRequest( + OutgoingRequest::Kind kind, std::vector< BinaryAny > const & inArguments) +{ + OSL_ASSERT( + kind == OutgoingRequest::KIND_REQUEST_CHANGE || + kind == OutgoingRequest::KIND_COMMIT_CHANGE); + incrementCalls(false); + css::uno::TypeDescription member( + kind == OutgoingRequest::KIND_REQUEST_CHANGE + ? protPropRequest_ : protPropCommit_); + PopOutgoingRequest pop( + outgoingRequests_, protPropTid_, OutgoingRequest(kind, member, false)); + getWriter()->sendDirectRequest( + protPropTid_, protPropOid_, protPropType_, member, inArguments); + pop.clear(); +} + +void Bridge::makeReleaseCall( + rtl::OUString const & oid, css::uno::TypeDescription const & type) +{ + AttachThread att(threadPool_); + sendRequest( + att.getTid(), oid, type, + css::uno::TypeDescription( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "com.sun.star.uno.XInterface::release"))), + std::vector< BinaryAny >()); +} + +void Bridge::sendRequest( + rtl::ByteSequence const & tid, rtl::OUString const & oid, + css::uno::TypeDescription const & type, + css::uno::TypeDescription const & member, + std::vector< BinaryAny > const & inArguments) +{ + getWriter()->queueRequest(tid, oid, type, member, inArguments); +} + +void Bridge::throwException(bool exception, BinaryAny const & value) { + if (exception) { + cppu::throwException(mapBinaryToCppAny(value)); + } +} + +css::uno::Any Bridge::mapBinaryToCppAny(BinaryAny const & binaryAny) { + BinaryAny in(binaryAny); + css::uno::Any out; + out.~Any(); + uno_copyAndConvertData( + &out, in.get(), + css::uno::TypeDescription(cppu::UnoType< css::uno::Any >::get()).get(), + binaryToCppMapping_.get()); + return out; +} + +bool Bridge::becameUnused() const { + return stubs_.empty() && proxies_ == 0 && calls_ == 0 && normalCall_; +} + +void Bridge::terminateWhenUnused(bool unused) { + if (unused) { + // That the current thread considers the bridge unused implies that it + // is not within an incoming or outgoing remote call (so calling + // terminate cannot lead to deadlock): + terminate(); + } +} + +} diff --git a/binaryurp/source/bridge.hxx b/binaryurp/source/bridge.hxx new file mode 100644 index 000000000..73e32aac0 --- /dev/null +++ b/binaryurp/source/bridge.hxx @@ -0,0 +1,287 @@ +/************************************************************************* +* +* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +* +* Copyright 2000, 2011 Oracle and/or its affiliates. +* +* OpenOffice.org - a multi-platform office productivity suite +* +* This file is part of OpenOffice.org. +* +* OpenOffice.org is free software: you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License version 3 +* only, as published by the Free Software Foundation. +* +* OpenOffice.org is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Lesser General Public License version 3 for more details +* (a copy is included in the LICENSE file that accompanied this code). +* +* You should have received a copy of the GNU Lesser General Public License +* version 3 along with OpenOffice.org. If not, see +* <http://www.openoffice.org/license.html> +* for a copy of the LGPLv3 License. +* +************************************************************************/ + +#ifndef INCLUDED_BINARYURP_SOURCE_BRIDGE_HXX +#define INCLUDED_BINARYURP_SOURCE_BRIDGE_HXX + +#include "sal/config.h" + +#include <cstddef> +#include <list> +#include <map> +#include <vector> + +#include "boost/noncopyable.hpp" +#include "com/sun/star/bridge/XBridge.hpp" +#include "com/sun/star/lang/XComponent.hpp" +#include "com/sun/star/uno/Reference.hxx" +#include "com/sun/star/uno/RuntimeException.hpp" +#include "cppuhelper/implbase2.hxx" +#include "osl/conditn.hxx" +#include "osl/mutex.hxx" +#include "rtl/ref.hxx" +#include "rtl/ustring.hxx" +#include "sal/types.h" +#include "uno/environment.hxx" +#include "uno/mapping.hxx" +#include "uno/threadpool.h" + +#include "outgoingrequest.hxx" +#include "outgoingrequests.hxx" +#include "writer.hxx" + +namespace binaryurp { + class BinaryAny; + class BridgeFactory; + class Proxy; + class Reader; +} +namespace com { namespace sun { namespace star { + namespace bridge { class XInstanceProvider; } + namespace connection { class XConnection; } + namespace lang { class XEventListener; } + namespace uno { + class Any; + class TypeDescription; + class UnoInterfaceReference; + class XInterface; + } +} } } +namespace rtl { class ByteSequence; } + +namespace binaryurp { + +class Bridge: + public cppu::WeakImplHelper2< + com::sun::star::bridge::XBridge, com::sun::star::lang::XComponent >, + private boost::noncopyable +{ +public: + Bridge( + rtl::Reference< BridgeFactory > const & factory, + rtl::OUString const & name, + com::sun::star::uno::Reference< + com::sun::star::connection::XConnection > const & connection, + com::sun::star::uno::Reference< + com::sun::star::bridge::XInstanceProvider > const & provider); + + void start(); + + // Internally waits for all incoming and outgoing remote calls to terminate, + // so must not be called from within such a call: + void terminate(); + + com::sun::star::uno::Reference< com::sun::star::connection::XConnection > + getConnection() const; + + com::sun::star::uno::Reference< com::sun::star::bridge::XInstanceProvider > + getProvider() const; + + com::sun::star::uno::Mapping & getCppToBinaryMapping(); + + BinaryAny mapCppToBinaryAny(com::sun::star::uno::Any const & cppAny); + + uno_ThreadPool getThreadPool() const; + + rtl::Reference< Writer > getWriter(); + + com::sun::star::uno::UnoInterfaceReference registerIncomingInterface( + rtl::OUString const & oid, + com::sun::star::uno::TypeDescription const & type); + + rtl::OUString registerOutgoingInterface( + com::sun::star::uno::UnoInterfaceReference const & object, + com::sun::star::uno::TypeDescription const & type); + + com::sun::star::uno::UnoInterfaceReference findStub( + rtl::OUString const & oid, + com::sun::star::uno::TypeDescription const & type); + + void releaseStub( + rtl::OUString const & oid, + com::sun::star::uno::TypeDescription const & type); + + void resurrectProxy(Proxy & proxy); + + void revokeProxy(Proxy & proxy); + + void freeProxy(Proxy & proxy); + + void incrementCalls(bool normalCall) throw (); + + void decrementCalls(); + + void incrementActiveCalls() throw (); + + void decrementActiveCalls() throw (); + + bool makeCall( + rtl::OUString const & oid, + com::sun::star::uno::TypeDescription const & member, bool setter, + std::vector< BinaryAny > const & inArguments, BinaryAny * returnValue, + std::vector< BinaryAny > * outArguments); + + // Only called from reader_ thread: + void sendRequestChangeRequest(); + + // Only called from reader_ thread: + void handleRequestChangeReply( + bool exception, BinaryAny const & returnValue); + + // Only called from reader_ thread: + void handleCommitChangeReply(bool exception, BinaryAny const & returnValue); + + // Only called from reader_ thread: + void handleRequestChangeRequest( + rtl::ByteSequence const & tid, + std::vector< BinaryAny > const & inArguments); + + // Only called from reader_ thread: + void handleCommitChangeRequest( + rtl::ByteSequence const & tid, + std::vector< BinaryAny > const & inArguments); + + OutgoingRequest lastOutgoingRequest(rtl::ByteSequence const & tid); + + bool isProtocolPropertiesRequest( + rtl::OUString const & oid, + com::sun::star::uno::TypeDescription const & type) const; + + void setCurrentContextMode(); + + bool isCurrentContextMode(); + +private: + virtual ~Bridge(); + + virtual com::sun::star::uno::Reference< com::sun::star::uno::XInterface > + SAL_CALL getInstance(rtl::OUString const & sInstanceName) + throw (com::sun::star::uno::RuntimeException); + + virtual rtl::OUString SAL_CALL getName() + throw (com::sun::star::uno::RuntimeException); + + virtual rtl::OUString SAL_CALL getDescription() + throw (com::sun::star::uno::RuntimeException); + + virtual void SAL_CALL dispose() + throw (com::sun::star::uno::RuntimeException); + + virtual void SAL_CALL addEventListener( + com::sun::star::uno::Reference< com::sun::star::lang::XEventListener > + const & xListener) + throw (com::sun::star::uno::RuntimeException); + + virtual void SAL_CALL removeEventListener( + com::sun::star::uno::Reference< com::sun::star::lang::XEventListener > + const & aListener) + throw (com::sun::star::uno::RuntimeException); + + // Only called from reader_ thread: + void sendCommitChangeRequest(); + + // Only called from reader_ thread: + void sendProtPropRequest( + OutgoingRequest::Kind kind, + std::vector< BinaryAny > const & inArguments); + + void makeReleaseCall( + rtl::OUString const & oid, + com::sun::star::uno::TypeDescription const & type); + + void sendRequest( + rtl::ByteSequence const & tid, rtl::OUString const & oid, + com::sun::star::uno::TypeDescription const & type, + com::sun::star::uno::TypeDescription const & member, + std::vector< BinaryAny > const & inArguments); + + void throwException(bool exception, BinaryAny const & value); + + com::sun::star::uno::Any mapBinaryToCppAny(BinaryAny const & binaryAny); + + bool becameUnused() const; + + void terminateWhenUnused(bool unused); + + typedef + std::list< + com::sun::star::uno::Reference< + com::sun::star::lang::XEventListener > > + Listeners; + + struct SubStub; + + typedef std::map< com::sun::star::uno::TypeDescription, SubStub > Stub; + + typedef std::map< rtl::OUString, Stub > Stubs; + + enum Mode { + MODE_REQUESTED, MODE_REPLY_MINUS1, MODE_REPLY_0, MODE_REPLY_1, + MODE_WAIT, MODE_NORMAL, MODE_NORMAL_WAIT }; + + rtl::Reference< BridgeFactory > factory_; + rtl::OUString name_; + com::sun::star::uno::Reference< com::sun::star::connection::XConnection > + connection_; + com::sun::star::uno::Reference< com::sun::star::bridge::XInstanceProvider > + provider_; + com::sun::star::uno::Environment binaryUno_; + com::sun::star::uno::Mapping cppToBinaryMapping_; + com::sun::star::uno::Mapping binaryToCppMapping_; + rtl::ByteSequence protPropTid_; + rtl::OUString protPropOid_; + com::sun::star::uno::TypeDescription protPropType_; + com::sun::star::uno::TypeDescription protPropRequest_; + com::sun::star::uno::TypeDescription protPropCommit_; + uno_ThreadPool threadPool_; + OutgoingRequests outgoingRequests_; + + osl::Mutex mutex_; + Listeners listeners_; + rtl::Reference< Writer > writer_; + rtl::Reference< Reader > reader_; + bool currentContextMode_; + Stubs stubs_; + std::size_t proxies_; + std::size_t calls_; + bool normalCall_; + std::size_t activeCalls_; + osl::Condition passive_; + // to guarantee that passive_ is eventually set (to avoid deadlock, see + // dispose), activeCalls_ only counts those calls for which it can be + // guaranteed that incrementActiveCalls is indeed followed by + // decrementActiveCalls, without an intervening exception + bool terminated_; + + // Only accessed from reader_ thread: + Mode mode_; + sal_Int32 random_; +}; + +} + +#endif diff --git a/binaryurp/source/bridgefactory.cxx b/binaryurp/source/bridgefactory.cxx new file mode 100644 index 000000000..16bd9cf1b --- /dev/null +++ b/binaryurp/source/bridgefactory.cxx @@ -0,0 +1,232 @@ +/************************************************************************* +* +* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +* +* Copyright 2000, 2011 Oracle and/or its affiliates. +* +* OpenOffice.org - a multi-platform office productivity suite +* +* This file is part of OpenOffice.org. +* +* OpenOffice.org is free software: you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License version 3 +* only, as published by the Free Software Foundation. +* +* OpenOffice.org is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Lesser General Public License version 3 for more details +* (a copy is included in the LICENSE file that accompanied this code). +* +* You should have received a copy of the GNU Lesser General Public License +* version 3 along with OpenOffice.org. If not, see +* <http://www.openoffice.org/license.html> +* for a copy of the LGPLv3 License. +* +************************************************************************/ + +#include "sal/config.h" + +#include <algorithm> + +#include "com/sun/star/connection/XConnection.hpp" +#include "com/sun/star/uno/Exception.hpp" +#include "com/sun/star/uno/Reference.hxx" +#include "com/sun/star/uno/RuntimeException.hpp" +#include "com/sun/star/uno/XComponentContext.hpp" +#include "com/sun/star/uno/XInterface.hpp" +#include "cppuhelper/factory.hxx" +#include "cppuhelper/implementationentry.hxx" +#include "osl/diagnose.h" +#include "rtl/ref.hxx" +#include "sal/types.h" +#include "uno/lbnames.h" + +#include "bridge.hxx" +#include "bridgefactory.hxx" + +namespace binaryurp { + +namespace { + +namespace css = com::sun::star; + +} + +css::uno::Reference< css::uno::XInterface > BridgeFactory::static_create( + css::uno::Reference< css::uno::XComponentContext > const & xContext) + SAL_THROW((css::uno::Exception)) +{ + return static_cast< cppu::OWeakObject * >(new BridgeFactory(xContext)); +} + +rtl::OUString BridgeFactory::static_getImplementationName() { + return rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "com.sun.star.comp.bridge.BridgeFactory")); +} + +css::uno::Sequence< rtl::OUString > +BridgeFactory::static_getSupportedServiceNames() { + rtl::OUString name( + RTL_CONSTASCII_USTRINGPARAM("com.sun.star.bridge.BridgeFactory")); + return css::uno::Sequence< rtl::OUString >(&name, 1); +} + +void BridgeFactory::removeBridge( + css::uno::Reference< css::bridge::XBridge > const & bridge) +{ + OSL_ASSERT(bridge.is()); + rtl::OUString n(bridge->getName()); + osl::MutexGuard g(*this); + if (n.getLength() == 0) { + BridgeList::iterator i( + std::find(unnamed_.begin(), unnamed_.end(), bridge)); + if (i != unnamed_.end()) { + unnamed_.erase(i); + } + } else { + BridgeMap::iterator i(named_.find(n)); + if (i != named_.end() && i->second == bridge) { + named_.erase(i); + } + } +} + +BridgeFactory::BridgeFactory( + css::uno::Reference< css::uno::XComponentContext > const & context): + BridgeFactoryBase(*static_cast< osl::Mutex * >(this)), context_(context) +{ + OSL_ASSERT(context.is()); +} + +BridgeFactory::~BridgeFactory() {} + +rtl::OUString BridgeFactory::getImplementationName() + throw (css::uno::RuntimeException) +{ + return static_getImplementationName(); +} + +sal_Bool BridgeFactory::supportsService(rtl::OUString const & ServiceName) + throw (css::uno::RuntimeException) +{ + css::uno::Sequence< rtl::OUString > s(getSupportedServiceNames()); + for (sal_Int32 i = 0; i != s.getLength(); ++i) { + if (ServiceName == s[i]) { + return true; + } + } + return false; +} + +css::uno::Sequence< rtl::OUString > BridgeFactory::getSupportedServiceNames() + throw (css::uno::RuntimeException) +{ + return static_getSupportedServiceNames(); +} + +css::uno::Reference< css::bridge::XBridge > BridgeFactory::createBridge( + rtl::OUString const & sName, rtl::OUString const & sProtocol, + css::uno::Reference< css::connection::XConnection > const & aConnection, + css::uno::Reference< css::bridge::XInstanceProvider > const & + anInstanceProvider) + throw ( + css::bridge::BridgeExistsException, css::lang::IllegalArgumentException, + css::uno::RuntimeException) +{ + rtl::Reference< Bridge > b; + { + osl::MutexGuard g(*this); + if (named_.find(sName) != named_.end()) { + throw css::bridge::BridgeExistsException( + sName, static_cast< cppu::OWeakObject * >(this)); + } + if (!(sProtocol.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("urp")) && + aConnection.is())) + { + throw css::lang::IllegalArgumentException( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "BridgeFactory::createBridge: sProtocol != urp ||" + " aConnection == null")), + static_cast< cppu::OWeakObject * >(this), -1); + } + b.set(new Bridge(this, sName, aConnection, anInstanceProvider)); + if (sName.getLength() == 0) { + unnamed_.push_back( + css::uno::Reference< css::bridge::XBridge >(b.get())); + } else { + named_[sName] = b.get(); + } + } + b->start(); + return css::uno::Reference< css::bridge::XBridge >(b.get()); +} + +css::uno::Reference< css::bridge::XBridge > BridgeFactory::getBridge( + rtl::OUString const & sName) throw (css::uno::RuntimeException) +{ + osl::MutexGuard g(*this); + BridgeMap::iterator i(named_.find(sName)); + return i == named_.end() + ? css::uno::Reference< css::bridge::XBridge >() : i->second; +} + +css::uno::Sequence< css::uno::Reference< css::bridge::XBridge > > +BridgeFactory::getExistingBridges() throw (css::uno::RuntimeException) { + osl::MutexGuard g(*this); + if (unnamed_.size() > SAL_MAX_INT32) { + throw css::uno::RuntimeException( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "BridgeFactory::getExistingBridges: too many")), + static_cast< cppu::OWeakObject * >(this)); + } + sal_Int32 n = static_cast< sal_Int32 >(unnamed_.size()); + if (named_.size() > static_cast< sal_uInt32 >(SAL_MAX_INT32 - n)) { + throw css::uno::RuntimeException( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "BridgeFactory::getExistingBridges: too many")), + static_cast< cppu::OWeakObject * >(this)); + } + n = static_cast< sal_Int32 >(n + named_.size()); + css::uno::Sequence< css::uno::Reference< css::bridge::XBridge > > s(n); + sal_Int32 i = 0; + for (BridgeList::iterator j(unnamed_.begin()); j != unnamed_.end(); ++j) { + s[i++] = *j; + } + for (BridgeMap::iterator j(named_.begin()); j != named_.end(); ++j) { + s[i++] = j->second; + } + return s; +} + +} + +namespace { + +static cppu::ImplementationEntry const services[] = { + { &binaryurp::BridgeFactory::static_create, + &binaryurp::BridgeFactory::static_getImplementationName, + &binaryurp::BridgeFactory::static_getSupportedServiceNames, + &cppu::createSingleComponentFactory, 0, 0 }, + { 0, 0, 0, 0, 0, 0 } +}; + +} + +extern "C" SAL_DLLPUBLIC_EXPORT void * SAL_CALL component_getFactory( + char const * pImplName, void * pServiceManager, void * pRegistryKey) +{ + return cppu::component_getFactoryHelper( + pImplName, pServiceManager, pRegistryKey, services); +} + +extern "C" SAL_DLLPUBLIC_EXPORT void SAL_CALL +component_getImplementationEnvironment( + char const ** ppEnvTypeName, uno_Environment **) +{ + *ppEnvTypeName = CPPU_CURRENT_LANGUAGE_BINDING_NAME; +} diff --git a/binaryurp/source/bridgefactory.hxx b/binaryurp/source/bridgefactory.hxx new file mode 100755 index 000000000..af6499d61 --- /dev/null +++ b/binaryurp/source/bridgefactory.hxx @@ -0,0 +1,144 @@ +/************************************************************************* +* +* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +* +* Copyright 2000, 2011 Oracle and/or its affiliates. +* +* OpenOffice.org - a multi-platform office productivity suite +* +* This file is part of OpenOffice.org. +* +* OpenOffice.org is free software: you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License version 3 +* only, as published by the Free Software Foundation. +* +* OpenOffice.org is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Lesser General Public License version 3 for more details +* (a copy is included in the LICENSE file that accompanied this code). +* +* You should have received a copy of the GNU Lesser General Public License +* version 3 along with OpenOffice.org. If not, see +* <http://www.openoffice.org/license.html> +* for a copy of the LGPLv3 License. +* +************************************************************************/ + +#ifndef INCLUDED_BINARYURP_SOURCE_BRIDGEFACTORY_HXX +#define INCLUDED_BINARYURP_SOURCE_BRIDGEFACTORY_HXX + +#include "sal/config.h" + +#include <list> +#include <map> + +#include "boost/noncopyable.hpp" +#include "com/sun/star/bridge/XBridgeFactory.hpp" +#include "com/sun/star/lang/XServiceInfo.hpp" +#include "com/sun/star/uno/Exception.hpp" +#include "com/sun/star/uno/Reference.hxx" +#include "com/sun/star/uno/RuntimeException.hpp" +#include "cppuhelper/compbase2.hxx" +#include "sal/types.h" + +namespace com { namespace sun { namespace star { + namespace connection { class XConnection; } + namespace uno { + class XComponentContext; + class XInterface; + } +} } } + +namespace binaryurp { + +// That BridgeFactory derives from XComponent appears to be a historic mistake; +// the implementation does not care about a disposed state: + +typedef + cppu::WeakComponentImplHelper2< + com::sun::star::lang::XServiceInfo, + com::sun::star::bridge::XBridgeFactory > + BridgeFactoryBase; + +class BridgeFactory: + private osl::Mutex, public BridgeFactoryBase, private boost::noncopyable +{ +public: + static com::sun::star::uno::Reference< com::sun::star::uno::XInterface > + SAL_CALL static_create( + com::sun::star::uno::Reference< com::sun::star::uno::XComponentContext > + const & xContext) + SAL_THROW((com::sun::star::uno::Exception)); + + static rtl::OUString SAL_CALL static_getImplementationName(); + + static com::sun::star::uno::Sequence< rtl::OUString > SAL_CALL + static_getSupportedServiceNames(); + + void removeBridge( + com::sun::star::uno::Reference< com::sun::star::bridge::XBridge > + const & bridge); + + using BridgeFactoryBase::acquire; + using BridgeFactoryBase::release; + +private: + explicit BridgeFactory( + com::sun::star::uno::Reference< com::sun::star::uno::XComponentContext > + const & context); + + virtual ~BridgeFactory(); + + virtual rtl::OUString SAL_CALL getImplementationName() + throw (com::sun::star::uno::RuntimeException); + + virtual sal_Bool SAL_CALL supportsService(rtl::OUString const & ServiceName) + throw (com::sun::star::uno::RuntimeException); + + virtual com::sun::star::uno::Sequence< rtl::OUString > SAL_CALL + getSupportedServiceNames() throw (com::sun::star::uno::RuntimeException); + + virtual com::sun::star::uno::Reference< com::sun::star::bridge::XBridge > + SAL_CALL createBridge( + rtl::OUString const & sName, rtl::OUString const & sProtocol, + com::sun::star::uno::Reference< + com::sun::star::connection::XConnection > const & aConnection, + com::sun::star::uno::Reference< + com::sun::star::bridge::XInstanceProvider > const & + anInstanceProvider) + throw ( + com::sun::star::bridge::BridgeExistsException, + com::sun::star::lang::IllegalArgumentException, + com::sun::star::uno::RuntimeException); + + virtual com::sun::star::uno::Reference< com::sun::star::bridge::XBridge > + SAL_CALL getBridge( + rtl::OUString const & sName) + throw (com::sun::star::uno::RuntimeException); + + virtual + com::sun::star::uno::Sequence< + com::sun::star::uno::Reference< com::sun::star::bridge::XBridge > > + SAL_CALL getExistingBridges() throw (com::sun::star::uno::RuntimeException); + + typedef + std::list< + com::sun::star::uno::Reference< com::sun::star::bridge::XBridge > > + BridgeList; + + typedef + std::map< + rtl::OUString, + com::sun::star::uno::Reference< com::sun::star::bridge::XBridge > > + BridgeMap; + + com::sun::star::uno::Reference< com::sun::star::uno::XComponentContext > + context_; + BridgeList unnamed_; + BridgeMap named_; +}; + +} + +#endif diff --git a/binaryurp/source/cache.hxx b/binaryurp/source/cache.hxx new file mode 100755 index 000000000..118b8a07b --- /dev/null +++ b/binaryurp/source/cache.hxx @@ -0,0 +1,134 @@ +/************************************************************************* +* +* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +* +* Copyright 2000, 2011 Oracle and/or its affiliates. +* +* OpenOffice.org - a multi-platform office productivity suite +* +* This file is part of OpenOffice.org. +* +* OpenOffice.org is free software: you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License version 3 +* only, as published by the Free Software Foundation. +* +* OpenOffice.org is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Lesser General Public License version 3 for more details +* (a copy is included in the LICENSE file that accompanied this code). +* +* You should have received a copy of the GNU Lesser General Public License +* version 3 along with OpenOffice.org. If not, see +* <http://www.openoffice.org/license.html> +* for a copy of the LGPLv3 License. +* +************************************************************************/ + +#ifndef INCLUDED_BINARYURP_SOURCE_CACHE_HXX +#define INCLUDED_BINARYURP_SOURCE_CACHE_HXX + +#include "sal/config.h" + +#include <cstddef> +#include <map> + +#include "boost/noncopyable.hpp" +#include "osl/diagnose.h" +#include "sal/types.h" + +namespace binaryurp { + +namespace cache { + +enum { size = 256, ignore = 0xFFFF }; + +} + +template< typename T > class Cache: private boost::noncopyable { +public: + explicit Cache(std::size_t size): + size_(size), first_(map_.end()), last_(map_.end()) + { + OSL_ASSERT(size < cache::ignore); + } + + sal_uInt16 add(T const & content, bool * found) { + OSL_ASSERT(found != 0); + typename Map::iterator i(map_.find(content)); + *found = i != map_.end(); + if (i == map_.end()) { + typename Map::size_type n = map_.size(); + if (n < size_) { + i = + (map_.insert( + typename Map::value_type( + content, + Entry( + static_cast< sal_uInt16 >(n), map_.end(), + first_)))). + first; + if (first_ == map_.end()) { + last_ = i; + } else { + first_->second.prev = i; + } + first_ = i; + } else if (last_ != map_.end()) { + i = + (map_.insert( + typename Map::value_type( + content, + Entry(last_->second.index, map_.end(), first_)))). + first; + first_->second.prev = i; + first_ = i; + typename Map::iterator j(last_); + last_ = last_->second.prev; + last_->second.next = map_.end(); + map_.erase(j); + } else { + // Reached iff size_ == 0: + return cache::ignore; + } + } else if (i != first_) { + // Move to front (reached only if size_ > 1): + i->second.prev->second.next = i->second.next; + if (i->second.next == map_.end()) { + last_ = i->second.prev; + } else { + i->second.next->second.prev = i->second.prev; + } + i->second.prev = map_.end(); + i->second.next = first_; + first_->second.prev = i; + first_ = i; + } + return i->second.index; + } + +private: + struct Entry; + + typedef std::map< T, Entry > Map; + + struct Entry { + sal_uInt16 index; + typename Map::iterator prev; + typename Map::iterator next; + + Entry( + sal_uInt16 theIndex, typename Map::iterator thePrev, + typename Map::iterator theNext): + index(theIndex), prev(thePrev), next(theNext) {} + }; + + std::size_t size_; + Map map_; + typename Map::iterator first_; + typename Map::iterator last_; +}; + +} + +#endif diff --git a/binaryurp/source/currentcontext.cxx b/binaryurp/source/currentcontext.cxx new file mode 100644 index 000000000..aed9640d8 --- /dev/null +++ b/binaryurp/source/currentcontext.cxx @@ -0,0 +1,80 @@ +/************************************************************************* +* +* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +* +* Copyright 2000, 2011 Oracle and/or its affiliates. +* +* OpenOffice.org - a multi-platform office productivity suite +* +* This file is part of OpenOffice.org. +* +* OpenOffice.org is free software: you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License version 3 +* only, as published by the Free Software Foundation. +* +* OpenOffice.org is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Lesser General Public License version 3 for more details +* (a copy is included in the LICENSE file that accompanied this code). +* +* You should have received a copy of the GNU Lesser General Public License +* version 3 along with OpenOffice.org. If not, see +* <http://www.openoffice.org/license.html> +* for a copy of the LGPLv3 License. +* +************************************************************************/ + +#include "sal/config.h" + +#include "com/sun/star/uno/Reference.hxx" +#include "com/sun/star/uno/RuntimeException.hpp" +#include "com/sun/star/uno/XInterface.hpp" +#include "rtl/ustring.h" +#include "rtl/ustring.hxx" +#include "uno/current_context.h" +#include "uno/dispatcher.hxx" +#include "uno/lbnames.h" + +#include "currentcontext.hxx" + +namespace binaryurp { + +namespace { + +namespace css = com::sun::star; + +} + +namespace current_context { + +css::uno::UnoInterfaceReference get() { + css::uno::UnoInterfaceReference cc; + if (!uno_getCurrentContext( + reinterpret_cast< void ** >(&cc.m_pUnoI), + rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(UNO_LB_UNO)).pData, 0)) + { + throw css::uno::RuntimeException( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM("uno_getCurrentContext failed")), + css::uno::Reference< css::uno::XInterface >()); + } + return cc; +} + +void set(css::uno::UnoInterfaceReference const & value) { + css::uno::UnoInterfaceReference cc(value); + if (!uno_setCurrentContext( + cc.m_pUnoI, + rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(UNO_LB_UNO)).pData, 0)) + { + throw css::uno::RuntimeException( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM("uno_setCurrentContext failed")), + css::uno::Reference< css::uno::XInterface >()); + } +} + +} + +} diff --git a/binaryurp/source/currentcontext.hxx b/binaryurp/source/currentcontext.hxx new file mode 100644 index 000000000..558d9ac04 --- /dev/null +++ b/binaryurp/source/currentcontext.hxx @@ -0,0 +1,49 @@ +/************************************************************************* +* +* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +* +* Copyright 2000, 2011 Oracle and/or its affiliates. +* +* OpenOffice.org - a multi-platform office productivity suite +* +* This file is part of OpenOffice.org. +* +* OpenOffice.org is free software: you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License version 3 +* only, as published by the Free Software Foundation. +* +* OpenOffice.org is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Lesser General Public License version 3 for more details +* (a copy is included in the LICENSE file that accompanied this code). +* +* You should have received a copy of the GNU Lesser General Public License +* version 3 along with OpenOffice.org. If not, see +* <http://www.openoffice.org/license.html> +* for a copy of the LGPLv3 License. +* +************************************************************************/ + +#ifndef INCLUDED_BINARYURP_SOURCE_CURRENTCONTEXT_HXX +#define INCLUDED_BINARYURP_SOURCE_CURRENTCONTEXT_HXX + +#include "sal/config.h" + +namespace com { namespace sun { namespace star { namespace uno { + class UnoInterfaceReference; +} } } } + +namespace binaryurp { + +namespace current_context { + +com::sun::star::uno::UnoInterfaceReference get(); + +void set(com::sun::star::uno::UnoInterfaceReference const & value); + +} + +} + +#endif diff --git a/binaryurp/source/incomingreply.hxx b/binaryurp/source/incomingreply.hxx new file mode 100644 index 000000000..654542f70 --- /dev/null +++ b/binaryurp/source/incomingreply.hxx @@ -0,0 +1,58 @@ +/************************************************************************* +* +* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +* +* Copyright 2000, 2011 Oracle and/or its affiliates. +* +* OpenOffice.org - a multi-platform office productivity suite +* +* This file is part of OpenOffice.org. +* +* OpenOffice.org is free software: you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License version 3 +* only, as published by the Free Software Foundation. +* +* OpenOffice.org is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Lesser General Public License version 3 for more details +* (a copy is included in the LICENSE file that accompanied this code). +* +* You should have received a copy of the GNU Lesser General Public License +* version 3 along with OpenOffice.org. If not, see +* <http://www.openoffice.org/license.html> +* for a copy of the LGPLv3 License. +* +************************************************************************/ + +#ifndef INCLUDED_BINARYURP_SOURCE_INCOMINGREPLY_HXX +#define INCLUDED_BINARYURP_SOURCE_INCOMINGREPLY_HXX + +#include "sal/config.h" + +#include <vector> + +#include "boost/noncopyable.hpp" + +#include "binaryany.hxx" + +namespace binaryurp { + +struct IncomingReply: private boost::noncopyable { + IncomingReply( + bool theException, BinaryAny const & theReturnValue, + std::vector< BinaryAny > const & theOutArguments): + exception(theException), returnValue(theReturnValue), + outArguments(theOutArguments) + {} + + bool exception; + + BinaryAny returnValue; + + std::vector< BinaryAny > outArguments; +}; + +} + +#endif diff --git a/binaryurp/source/incomingrequest.cxx b/binaryurp/source/incomingrequest.cxx new file mode 100644 index 000000000..646a868f6 --- /dev/null +++ b/binaryurp/source/incomingrequest.cxx @@ -0,0 +1,300 @@ +/************************************************************************* +* +* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +* +* Copyright 2000, 2011 Oracle and/or its affiliates. +* +* OpenOffice.org - a multi-platform office productivity suite +* +* This file is part of OpenOffice.org. +* +* OpenOffice.org is free software: you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License version 3 +* only, as published by the Free Software Foundation. +* +* OpenOffice.org is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Lesser General Public License version 3 for more details +* (a copy is included in the LICENSE file that accompanied this code). +* +* You should have received a copy of the GNU Lesser General Public License +* version 3 along with OpenOffice.org. If not, see +* <http://www.openoffice.org/license.html> +* for a copy of the LGPLv3 License. +* +************************************************************************/ + +#include "sal/config.h" + +#include <list> +#include <vector> + +#include "boost/noncopyable.hpp" +#include "com/sun/star/bridge/XInstanceProvider.hpp" +#include "cppuhelper/exc_hlp.hxx" +#include "rtl/byteseq.hxx" +#include "rtl/ref.hxx" +#include "rtl/ustring.hxx" +#include "sal/types.h" +#include "typelib/typedescription.hxx" +#include "uno/dispatcher.hxx" + +#include "binaryany.hxx" +#include "bridge.hxx" +#include "currentcontext.hxx" +#include "incomingrequest.hxx" +#include "specialfunctionids.hxx" + +namespace binaryurp { + +namespace { + +namespace css = com::sun::star; + +} + +IncomingRequest::IncomingRequest( + rtl::Reference< Bridge > const & bridge, rtl::ByteSequence const & tid, + rtl::OUString const & oid, css::uno::UnoInterfaceReference const & object, + css::uno::TypeDescription const & type, sal_uInt16 functionId, + bool synchronous, css::uno::TypeDescription const & member, bool setter, + std::vector< BinaryAny > const & inArguments, bool currentContextMode, + css::uno::UnoInterfaceReference const & currentContext): + bridge_(bridge), tid_(tid), oid_(oid), object_(object), type_(type), + functionId_(functionId), synchronous_(synchronous), member_(member), + setter_(setter), inArguments_(inArguments), + currentContextMode_(currentContextMode), currentContext_(currentContext) +{ + OSL_ASSERT(bridge.is() && member.is() && member.get()->bComplete); +} + +IncomingRequest::~IncomingRequest() {} + +void IncomingRequest::execute() const { + BinaryAny ret; + std::vector< BinaryAny > outArgs; + bool isExc; + try { + bool resetCc = false; + css::uno::UnoInterfaceReference oldCc; + if (currentContextMode_) { + oldCc = current_context::get(); + current_context::set(currentContext_); + resetCc = true; + } + try { + try { + isExc = !execute_throw(&ret, &outArgs); + } catch (std::exception & e) { + throw css::uno::RuntimeException( + (rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM("caught C++ exception: ")) + + rtl::OStringToOUString( + rtl::OString(e.what()), RTL_TEXTENCODING_ASCII_US)), + css::uno::Reference< css::uno::XInterface >()); + // best-effort string conversion + } + } catch (css::uno::RuntimeException &) { + css::uno::Any exc(cppu::getCaughtException()); + ret = bridge_->mapCppToBinaryAny(exc); + isExc = true; + } + if (resetCc) { + current_context::set(oldCc); + } + } catch (css::uno::RuntimeException &) { + css::uno::Any exc(cppu::getCaughtException()); + ret = bridge_->mapCppToBinaryAny(exc); + isExc = true; + } + if (synchronous_) { + bridge_->decrementActiveCalls(); + try { + bridge_->getWriter()->queueReply( + tid_, member_, setter_, isExc, ret, outArgs, false); + return; + } catch (css::uno::RuntimeException & e) { + OSL_TRACE( + OSL_LOG_PREFIX "caught UNO runtime exception '%s'", + (rtl::OUStringToOString(e.Message, RTL_TEXTENCODING_UTF8). + getStr())); + } catch (std::exception & e) { + OSL_TRACE(OSL_LOG_PREFIX "caught C++ exception '%s'", e.what()); + } + bridge_->terminate(); + } else { + if (isExc) { + OSL_TRACE(OSL_LOG_PREFIX "oneway method raised exception"); + } + bridge_->decrementCalls(); + } +} + +bool IncomingRequest::execute_throw( + BinaryAny * returnValue, std::vector< BinaryAny > * outArguments) const +{ + OSL_ASSERT( + returnValue != 0 && + returnValue->getType().equals( + css::uno::TypeDescription( + cppu::UnoType< cppu::UnoVoidType >::get())) && + outArguments != 0 && outArguments->empty()); + bool isExc = false; + switch (functionId_) { + case SPECIAL_FUNCTION_ID_RESERVED: + OSL_ASSERT(false); // this cannot happen + break; + case SPECIAL_FUNCTION_ID_RELEASE: + bridge_->releaseStub(oid_, type_); + break; + case SPECIAL_FUNCTION_ID_QUERY_INTERFACE: + if (!object_.is()) { + css::uno::Reference< css::uno::XInterface > ifc; + css::uno::Reference< css::bridge::XInstanceProvider > prov( + bridge_->getProvider()); + if (prov.is()) { + try { + ifc = prov->getInstance(oid_); + } catch (css::container::NoSuchElementException & e) { + OSL_TRACE( + (OSL_LOG_PREFIX "initial element '%s':" + " NoSuchElementException '%s'"), + (rtl::OUStringToOString(oid_, RTL_TEXTENCODING_UTF8). + getStr()), + (rtl::OUStringToOString( + e.Message, RTL_TEXTENCODING_UTF8). + getStr())); + } + } + if (ifc.is()) { + css::uno::UnoInterfaceReference unoIfc( + static_cast< uno_Interface * >( + bridge_->getCppToBinaryMapping().mapInterface( + ifc.get(), + (css::uno::TypeDescription( + cppu::UnoType< + css::uno::Reference< + css::uno::XInterface > >::get()). + get()))), + SAL_NO_ACQUIRE); + *returnValue = BinaryAny( + css::uno::TypeDescription( + cppu::UnoType< + css::uno::Reference< + css::uno::XInterface > >::get()), + &unoIfc.m_pUnoI); + } + break; + } + // fall through + default: + { + OSL_ASSERT(object_.is()); + css::uno::TypeDescription retType; + std::list< std::vector< char > > outBufs; + std::vector< void * > args; + switch (member_.get()->eTypeClass) { + case typelib_TypeClass_INTERFACE_ATTRIBUTE: + { + css::uno::TypeDescription t( + reinterpret_cast< + typelib_InterfaceAttributeTypeDescription * >( + member_.get())-> + pAttributeTypeRef); + if (setter_) { + OSL_ASSERT(inArguments_.size() == 1); + args.push_back(inArguments_[0].getValue(t)); + } else { + OSL_ASSERT(inArguments_.empty()); + retType = t; + } + break; + } + case typelib_TypeClass_INTERFACE_METHOD: + { + typelib_InterfaceMethodTypeDescription * mtd = + reinterpret_cast< + typelib_InterfaceMethodTypeDescription * >( + member_.get()); + retType = css::uno::TypeDescription(mtd->pReturnTypeRef); + std::vector< BinaryAny >::const_iterator i( + inArguments_.begin()); + for (sal_Int32 j = 0; j != mtd->nParams; ++j) { + void * p; + if (mtd->pParams[j].bIn) { + p = i++->getValue( + css::uno::TypeDescription( + mtd->pParams[j].pTypeRef)); + } else { + outBufs.push_back( + std::vector< char >( + css::uno::TypeDescription( + mtd->pParams[j].pTypeRef). + get()->nSize)); + p = &outBufs.back()[0]; + } + args.push_back(p); + if (mtd->pParams[j].bOut) { + outArguments->push_back(BinaryAny()); + } + } + OSL_ASSERT(i == inArguments_.end()); + break; + } + default: + OSL_ASSERT(false); // this cannot happen + break; + } + std::vector< char > retBuf(retType.is() ? retType.get()->nSize : 0); + uno_Any exc; + uno_Any * pexc = &exc; + (*object_.get()->pDispatcher)( + object_.get(), member_.get(), retBuf.empty() ? 0 : &retBuf[0], + args.empty() ? 0 : &args[0], &pexc); + isExc = pexc != 0; + if (isExc) { + *returnValue = BinaryAny( + css::uno::TypeDescription( + cppu::UnoType< css::uno::Any >::get()), + &exc); + uno_any_destruct(&exc, 0); + } else { + if (!retBuf.empty()) { + *returnValue = BinaryAny(retType, &retBuf[0]); + uno_destructData(&retBuf[0], retType.get(), 0); + } + if (!outArguments->empty()) { + OSL_ASSERT( + member_.get()->eTypeClass == + typelib_TypeClass_INTERFACE_METHOD); + typelib_InterfaceMethodTypeDescription * mtd = + reinterpret_cast< + typelib_InterfaceMethodTypeDescription * >( + member_.get()); + std::vector< BinaryAny >::iterator i(outArguments->begin()); + std::list< std::vector< char > >::iterator j( + outBufs.begin()); + for (sal_Int32 k = 0; k != mtd->nParams; ++k) { + if (mtd->pParams[k].bOut) { + *i++ = BinaryAny( + css::uno::TypeDescription( + mtd->pParams[k].pTypeRef), + args[k]); + } + if (!mtd->pParams[k].bIn) { + uno_type_destructData( + &(*j++)[0], mtd->pParams[k].pTypeRef, 0); + } + } + OSL_ASSERT(i == outArguments->end()); + OSL_ASSERT(j == outBufs.end()); + } + } + break; + } + } + return !isExc; +} + +} diff --git a/binaryurp/source/incomingrequest.hxx b/binaryurp/source/incomingrequest.hxx new file mode 100644 index 000000000..ead7067f8 --- /dev/null +++ b/binaryurp/source/incomingrequest.hxx @@ -0,0 +1,86 @@ +/************************************************************************* +* +* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +* +* Copyright 2000, 2011 Oracle and/or its affiliates. +* +* OpenOffice.org - a multi-platform office productivity suite +* +* This file is part of OpenOffice.org. +* +* OpenOffice.org is free software: you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License version 3 +* only, as published by the Free Software Foundation. +* +* OpenOffice.org is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Lesser General Public License version 3 for more details +* (a copy is included in the LICENSE file that accompanied this code). +* +* You should have received a copy of the GNU Lesser General Public License +* version 3 along with OpenOffice.org. If not, see +* <http://www.openoffice.org/license.html> +* for a copy of the LGPLv3 License. +* +************************************************************************/ + +#ifndef INCLUDED_BINARYURP_SOURCE_INCOMINGREQUEST_HXX +#define INCLUDED_BINARYURP_SOURCE_INCOMINGREQUEST_HXX + +#include "sal/config.h" + +#include <vector> + +#include "boost/noncopyable.hpp" +#include "rtl/byteseq.hxx" +#include "rtl/ref.hxx" +#include "rtl/ustring.hxx" +#include "sal/types.h" +#include "typelib/typedescription.hxx" +#include "uno/dispatcher.hxx" + +namespace binaryurp { + class BinaryAny; + class Bridge; +} + +namespace binaryurp { + +class IncomingRequest: private boost::noncopyable { +public: + IncomingRequest( + rtl::Reference< Bridge > const & bridge, rtl::ByteSequence const & tid, + rtl::OUString const & oid, + com::sun::star::uno::UnoInterfaceReference const & object, + com::sun::star::uno::TypeDescription const & type, + sal_uInt16 functionId, bool synchronous, + com::sun::star::uno::TypeDescription const & member, bool setter, + std::vector< BinaryAny > const & inArguments, bool currentContextMode, + com::sun::star::uno::UnoInterfaceReference const & currentContext); + + ~IncomingRequest(); + + void execute() const; + +private: + bool execute_throw( + BinaryAny * returnValue, std::vector< BinaryAny > * outArguments) const; + + rtl::Reference< Bridge > bridge_; + rtl::ByteSequence tid_; + rtl::OUString oid_; // initial object queryInterface; release + com::sun::star::uno::UnoInterfaceReference object_; + com::sun::star::uno::TypeDescription type_; + sal_uInt16 functionId_; + bool synchronous_; + com::sun::star::uno::TypeDescription member_; + bool setter_; + std::vector< BinaryAny > inArguments_; + bool currentContextMode_; + com::sun::star::uno::UnoInterfaceReference currentContext_; +}; + +} + +#endif diff --git a/binaryurp/source/lessoperators.cxx b/binaryurp/source/lessoperators.cxx new file mode 100644 index 000000000..354118625 --- /dev/null +++ b/binaryurp/source/lessoperators.cxx @@ -0,0 +1,71 @@ +/************************************************************************* +* +* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +* +* Copyright 2000, 2011 Oracle and/or its affiliates. +* +* OpenOffice.org - a multi-platform office productivity suite +* +* This file is part of OpenOffice.org. +* +* OpenOffice.org is free software: you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License version 3 +* only, as published by the Free Software Foundation. +* +* OpenOffice.org is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Lesser General Public License version 3 for more details +* (a copy is included in the LICENSE file that accompanied this code). +* +* You should have received a copy of the GNU Lesser General Public License +* version 3 along with OpenOffice.org. If not, see +* <http://www.openoffice.org/license.html> +* for a copy of the LGPLv3 License. +* +************************************************************************/ + +#include "sal/config.h" + +#include <algorithm> + +#include "osl/diagnose.h" +#include "rtl/byteseq.hxx" +#include "rtl/ustring.hxx" +#include "sal/types.h" +#include "typelib/typeclass.h" +#include "typelib/typedescription.hxx" + +#include "lessoperators.hxx" + +namespace com { namespace sun { namespace star { namespace uno { + +bool operator <(TypeDescription const & left, TypeDescription const & right) { + OSL_ASSERT(left.is() && right.is()); + typelib_TypeClass tc1 = left.get()->eTypeClass; + typelib_TypeClass tc2 = right.get()->eTypeClass; + return tc1 < tc2 || + (tc1 == tc2 && + (rtl::OUString(left.get()->pTypeName) < + rtl::OUString(right.get()->pTypeName))); +} + +} } } } + +namespace rtl { + +bool operator <(ByteSequence const & left, ByteSequence const & right) { + for (sal_Int32 i = 0; i != std::min(left.getLength(), right.getLength()); + ++i) + { + if (left[i] < right[i]) { + return true; + } + if (right[i] < left[i]) { + return false; + } + } + return left.getLength() < right.getLength(); +} + +} diff --git a/binaryurp/source/lessoperators.hxx b/binaryurp/source/lessoperators.hxx new file mode 100644 index 000000000..014f0f4d5 --- /dev/null +++ b/binaryurp/source/lessoperators.hxx @@ -0,0 +1,50 @@ +/************************************************************************* +* +* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +* +* Copyright 2000, 2011 Oracle and/or its affiliates. +* +* OpenOffice.org - a multi-platform office productivity suite +* +* This file is part of OpenOffice.org. +* +* OpenOffice.org is free software: you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License version 3 +* only, as published by the Free Software Foundation. +* +* OpenOffice.org is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Lesser General Public License version 3 for more details +* (a copy is included in the LICENSE file that accompanied this code). +* +* You should have received a copy of the GNU Lesser General Public License +* version 3 along with OpenOffice.org. If not, see +* <http://www.openoffice.org/license.html> +* for a copy of the LGPLv3 License. +* +************************************************************************/ + +#ifndef INCLUDED_BINARYURP_SOURCE_LESSOPERATORS_HXX +#define INCLUDED_BINARYURP_SOURCE_LESSOPERATORS_HXX + +#include "sal/config.h" + +namespace com { namespace sun { namespace star { namespace uno { + class TypeDescription; +} } } } +namespace rtl { class ByteSequence; } + +namespace com { namespace sun { namespace star { namespace uno { + +bool operator <(TypeDescription const & left, TypeDescription const & right); + +} } } } + +namespace rtl { + +bool operator <(ByteSequence const & left, ByteSequence const & right); + +} + +#endif diff --git a/binaryurp/source/makefile.mk b/binaryurp/source/makefile.mk new file mode 100644 index 000000000..ca9e7c72b --- /dev/null +++ b/binaryurp/source/makefile.mk @@ -0,0 +1,69 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2011 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#***********************************************************************/ + +PRJ = .. +PRJNAME = binaryurp +TARGET = binaryurp + +ENABLE_EXCEPTIONS = TRUE +VISIBILITY_HIDDEN = TRUE + +.INCLUDE: settings.mk + +DLLPRE = + +SLOFILES = \ + $(SLO)/binaryany.obj \ + $(SLO)/bridge.obj \ + $(SLO)/bridgefactory.obj \ + $(SLO)/currentcontext.obj \ + $(SLO)/incomingrequest.obj \ + $(SLO)/lessoperators.obj \ + $(SLO)/marshal.obj \ + $(SLO)/outgoingrequests.obj \ + $(SLO)/proxy.obj \ + $(SLO)/reader.obj \ + $(SLO)/unmarshal.obj \ + $(SLO)/writer.obj + +SHL1IMPLIB = i$(SHL1TARGET) +SHL1OBJS = $(SLOFILES) +SHL1RPATH = URELIB +SHL1STDLIBS = $(CPPUHELPERLIB) $(CPPULIB) $(SALHELPERLIB) $(SALLIB) +SHL1TARGET = binaryurp.uno +SHL1USE_EXPORTS = name +DEF1NAME = $(SHL1TARGET) + +.INCLUDE: target.mk + +ALLTAR : $(MISC)/binaryurp.component + +$(MISC)/binaryurp.component .ERRREMOVE : $(SOLARENV)/bin/createcomponent.xslt \ + binaryurp.component + $(XSLTPROC) --nonet --stringparam uri \ + '$(COMPONENTPREFIX_URE_NATIVE)$(SHL1TARGETN:f)' -o $@ \ + $(SOLARENV)/bin/createcomponent.xslt binaryurp.component diff --git a/binaryurp/source/marshal.cxx b/binaryurp/source/marshal.cxx new file mode 100644 index 000000000..ce520382e --- /dev/null +++ b/binaryurp/source/marshal.cxx @@ -0,0 +1,314 @@ +/************************************************************************* +* +* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +* +* Copyright 2000, 2011 Oracle and/or its affiliates. +* +* OpenOffice.org - a multi-platform office productivity suite +* +* This file is part of OpenOffice.org. +* +* OpenOffice.org is free software: you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License version 3 +* only, as published by the Free Software Foundation. +* +* OpenOffice.org is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Lesser General Public License version 3 for more details +* (a copy is included in the LICENSE file that accompanied this code). +* +* You should have received a copy of the GNU Lesser General Public License +* version 3 along with OpenOffice.org. If not, see +* <http://www.openoffice.org/license.html> +* for a copy of the LGPLv3 License. +* +************************************************************************/ + +#include "sal/config.h" + +#include <vector> + +#include "boost/noncopyable.hpp" +#include "com/sun/star/uno/Reference.hxx" +#include "com/sun/star/uno/RuntimeException.hpp" +#include "com/sun/star/uno/Sequence.hxx" +#include "com/sun/star/uno/XInterface.hpp" +#include "cppu/unotype.hxx" +#include "osl/diagnose.h" +#include "rtl/byteseq.hxx" +#include "rtl/string.hxx" +#include "rtl/textcvt.h" +#include "rtl/textenc.h" +#include "rtl/ustring.h" +#include "rtl/ustring.hxx" +#include "sal/types.h" +#include "typelib/typeclass.h" +#include "typelib/typedescription.h" +#include "typelib/typedescription.hxx" +#include "uno/dispatcher.hxx" + +#include "binaryany.hxx" +#include "bridge.hxx" +#include "cache.hxx" +#include "lessoperators.hxx" +#include "marshal.hxx" + +namespace binaryurp { + +namespace { + +namespace css = com::sun::star; + +void write64(std::vector< unsigned char > * buffer, sal_uInt64 value) { + Marshal::write8(buffer, value >> 56); + Marshal::write8(buffer, (value >> 48) & 0xFF); + Marshal::write8(buffer, (value >> 40) & 0xFF); + Marshal::write8(buffer, (value >> 32) & 0xFF); + Marshal::write8(buffer, (value >> 24) & 0xFF); + Marshal::write8(buffer, (value >> 16) & 0xFF); + Marshal::write8(buffer, (value >> 8) & 0xFF); + Marshal::write8(buffer, value & 0xFF); +} + +void writeCompressed(std::vector< unsigned char > * buffer, sal_uInt32 value) { + if (value < 0xFF) { + Marshal::write8(buffer, static_cast< sal_uInt8 >(value)); + } else { + Marshal::write8(buffer, 0xFF); + Marshal::write32(buffer, value); + } +} + +void writeString( + std::vector< unsigned char > * buffer, rtl::OUString const & value) +{ + OSL_ASSERT(buffer != 0); + rtl::OString v; + if (!value.convertToString( + &v, RTL_TEXTENCODING_UTF8, + (RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR | + RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR))) + { + throw css::uno::RuntimeException( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "UNO string contains invalid UTF-16 sequence")), + css::uno::Reference< css::uno::XInterface >()); + } + writeCompressed(buffer, static_cast< sal_uInt32 >(v.getLength())); + buffer->insert(buffer->end(), v.getStr(), v.getStr() + v.getLength()); +} + +} + +Marshal::Marshal(rtl::Reference< Bridge > const & bridge, WriterState & state): + bridge_(bridge), state_(state) +{ + OSL_ASSERT(bridge.is()); +} + +Marshal::~Marshal() {} + +void Marshal::write8(std::vector< unsigned char > * buffer, sal_uInt8 value) { + OSL_ASSERT(buffer != 0); + buffer->push_back(value); +} + +void Marshal::write16(std::vector< unsigned char > * buffer, sal_uInt16 value) { + write8(buffer, value >> 8); + write8(buffer, value & 0xFF); +} + +void Marshal::write32(std::vector< unsigned char > * buffer, sal_uInt32 value) { + write8(buffer, value >> 24); + write8(buffer, (value >> 16) & 0xFF); + write8(buffer, (value >> 8) & 0xFF); + write8(buffer, value & 0xFF); +} + +void Marshal::writeValue( + std::vector< unsigned char > * buffer, + css::uno::TypeDescription const & type, BinaryAny const & value) +{ + OSL_ASSERT( + type.is() && + (type.get()->eTypeClass == typelib_TypeClass_ANY || + value.getType().equals(type))); + writeValue(buffer, type, value.getValue(type)); +} + +void Marshal::writeType( + std::vector< unsigned char > * buffer, + css::uno::TypeDescription const & value) +{ + value.makeComplete(); + OSL_ASSERT(value.is()); + typelib_TypeClass tc = value.get()->eTypeClass; + if (tc <= typelib_TypeClass_ANY) { + write8(buffer, static_cast< sal_uInt8 >(tc)); + } else { + bool found; + sal_uInt16 idx = state_.typeCache.add(value, &found); + if (found) { + write8(buffer, static_cast< sal_uInt8 >(tc)); + write16(buffer, idx); + } else { + write8(buffer, static_cast< sal_uInt8 >(tc) | 0x80); + write16(buffer, idx); + writeString(buffer, rtl::OUString(value.get()->pTypeName)); + } + } +} + +void Marshal::writeOid( + std::vector< unsigned char > * buffer, rtl::OUString const & oid) +{ + bool found; + sal_uInt16 idx; + if (oid.getLength() == 0) { + found = true; + idx = cache::ignore; + } else { + idx = state_.oidCache.add(oid, &found); + } + if (found) { + write8(buffer, 0); + } else { + writeString(buffer, oid); + } + write16(buffer, idx); +} + +void Marshal::writeTid( + std::vector< unsigned char > * buffer, rtl::ByteSequence const & tid) +{ + bool found; + sal_uInt16 idx = state_.tidCache.add(tid, &found); + if (found) { + write8(buffer, 0); + } else { + sal_Sequence * p = tid.getHandle(); + writeValue( + buffer, + css::uno::TypeDescription( + cppu::UnoType< css::uno::Sequence< sal_Int8 > >::get()), &p); + } + write16(buffer, idx); +} + +void Marshal::writeValue( + std::vector< unsigned char > * buffer, + css::uno::TypeDescription const & type, void const * value) +{ + OSL_ASSERT(buffer != 0 && type.is()); + type.makeComplete(); + switch (type.get()->eTypeClass) { + case typelib_TypeClass_VOID: + break; + case typelib_TypeClass_BOOLEAN: + OSL_ASSERT(*static_cast< sal_uInt8 const * >(value) <= 1); + // fall through + case typelib_TypeClass_BYTE: + write8(buffer, *static_cast< sal_uInt8 const * >(value)); + break; + case typelib_TypeClass_SHORT: + case typelib_TypeClass_UNSIGNED_SHORT: + case typelib_TypeClass_CHAR: + write16(buffer, *static_cast< sal_uInt16 const * >(value)); + break; + case typelib_TypeClass_LONG: + case typelib_TypeClass_UNSIGNED_LONG: + case typelib_TypeClass_FLOAT: + case typelib_TypeClass_ENUM: + write32(buffer, *static_cast< sal_uInt32 const * >(value)); + break; + case typelib_TypeClass_HYPER: + case typelib_TypeClass_UNSIGNED_HYPER: + case typelib_TypeClass_DOUBLE: + write64(buffer, *static_cast< sal_uInt64 const * >(value)); + break; + case typelib_TypeClass_STRING: + writeString( + buffer, + rtl::OUString(*static_cast< rtl_uString * const * >(value))); + break; + case typelib_TypeClass_TYPE: + writeType( + buffer, + css::uno::TypeDescription( + *static_cast< typelib_TypeDescriptionReference * const * >( + value))); + break; + case typelib_TypeClass_ANY: + { + uno_Any const * p = static_cast< uno_Any const * >(value); + css::uno::TypeDescription t(p->pType); + writeType(buffer, t); + writeValue(buffer, t, p->pData); + break; + } + case typelib_TypeClass_SEQUENCE: + { + sal_Sequence * p = *static_cast< sal_Sequence * const * >(value); + writeCompressed(buffer, static_cast< sal_uInt32 >(p->nElements)); + css::uno::TypeDescription ctd( + reinterpret_cast< typelib_IndirectTypeDescription * >( + type.get())-> + pType); + OSL_ASSERT(ctd.is()); + if (ctd.get()->eTypeClass == typelib_TypeClass_BYTE) { + buffer->insert( + buffer->end(), p->elements, p->elements + p->nElements); + } else { + for (sal_Int32 i = 0; i != p->nElements; ++i) { + writeValue(buffer, ctd, p->elements + i * ctd.get()->nSize); + } + } + break; + } + case typelib_TypeClass_STRUCT: + case typelib_TypeClass_EXCEPTION: + writeMemberValues(buffer, type, value); + break; + case typelib_TypeClass_INTERFACE: + writeOid( + buffer, + bridge_->registerOutgoingInterface( + css::uno::UnoInterfaceReference( + *static_cast< uno_Interface * const * >(value)), + type)); + break; + default: + OSL_ASSERT(false); // this cannot happen + break; + } +} + +void Marshal::writeMemberValues( + std::vector< unsigned char > * buffer, + css::uno::TypeDescription const & type, void const * aggregateValue) +{ + OSL_ASSERT( + type.is() && + (type.get()->eTypeClass == typelib_TypeClass_STRUCT || + type.get()->eTypeClass == typelib_TypeClass_EXCEPTION) && + aggregateValue != 0); + type.makeComplete(); + typelib_CompoundTypeDescription * ctd = + reinterpret_cast< typelib_CompoundTypeDescription * >(type.get()); + if (ctd->pBaseTypeDescription != 0) { + writeMemberValues( + buffer, + css::uno::TypeDescription(&ctd->pBaseTypeDescription->aBase), + aggregateValue); + } + for (sal_Int32 i = 0; i != ctd->nMembers; ++i) { + writeValue( + buffer, css::uno::TypeDescription(ctd->ppTypeRefs[i]), + (static_cast< char const * >(aggregateValue) + + ctd->pMemberOffsets[i])); + } +} + +} diff --git a/binaryurp/source/marshal.hxx b/binaryurp/source/marshal.hxx new file mode 100755 index 000000000..a922ec100 --- /dev/null +++ b/binaryurp/source/marshal.hxx @@ -0,0 +1,95 @@ +/************************************************************************* +* +* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +* +* Copyright 2000, 2011 Oracle and/or its affiliates. +* +* OpenOffice.org - a multi-platform office productivity suite +* +* This file is part of OpenOffice.org. +* +* OpenOffice.org is free software: you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License version 3 +* only, as published by the Free Software Foundation. +* +* OpenOffice.org is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Lesser General Public License version 3 for more details +* (a copy is included in the LICENSE file that accompanied this code). +* +* You should have received a copy of the GNU Lesser General Public License +* version 3 along with OpenOffice.org. If not, see +* <http://www.openoffice.org/license.html> +* for a copy of the LGPLv3 License. +* +************************************************************************/ + +#ifndef INCLUDED_BINARYURP_SOURCE_MARSHAL_HXX +#define INCLUDED_BINARYURP_SOURCE_MARSHAL_HXX + +#include "sal/config.h" + +#include <vector> + +#include "boost/noncopyable.hpp" +#include "rtl/byteseq.hxx" +#include "rtl/ref.hxx" +#include "rtl/ustring.hxx" +#include "sal/types.h" +#include "typelib/typedescription.hxx" + +namespace binaryurp { + class BinaryAny; + class Bridge; + struct WriterState; +} + +namespace binaryurp { + +class Marshal: private boost::noncopyable { +public: + Marshal(rtl::Reference< Bridge > const & bridge, WriterState & state); + + ~Marshal(); + + static void write8(std::vector< unsigned char > * buffer, sal_uInt8 value); + + static void write16( + std::vector< unsigned char > * buffer, sal_uInt16 value); + + static void write32( + std::vector< unsigned char > * buffer, sal_uInt32 value); + + void writeValue( + std::vector< unsigned char > * buffer, + com::sun::star::uno::TypeDescription const & type, + BinaryAny const & value); + + void writeType( + std::vector< unsigned char > * buffer, + com::sun::star::uno::TypeDescription const & value); + + void writeOid( + std::vector< unsigned char > * buffer, rtl::OUString const & oid); + + void writeTid( + std::vector< unsigned char > * buffer, rtl::ByteSequence const & tid); + +private: + void writeValue( + std::vector< unsigned char > * buffer, + com::sun::star::uno::TypeDescription const & type, void const * value); + + void writeMemberValues( + std::vector< unsigned char > * buffer, + com::sun::star::uno::TypeDescription const & type, + void const * aggregateValue); + + rtl::Reference< Bridge > bridge_; + WriterState & state_; +}; + +} + +#endif diff --git a/binaryurp/source/outgoingrequest.hxx b/binaryurp/source/outgoingrequest.hxx new file mode 100644 index 000000000..7fe67bf96 --- /dev/null +++ b/binaryurp/source/outgoingrequest.hxx @@ -0,0 +1,55 @@ +/************************************************************************* +* +* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +* +* Copyright 2000, 2011 Oracle and/or its affiliates. +* +* OpenOffice.org - a multi-platform office productivity suite +* +* This file is part of OpenOffice.org. +* +* OpenOffice.org is free software: you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License version 3 +* only, as published by the Free Software Foundation. +* +* OpenOffice.org is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Lesser General Public License version 3 for more details +* (a copy is included in the LICENSE file that accompanied this code). +* +* You should have received a copy of the GNU Lesser General Public License +* version 3 along with OpenOffice.org. If not, see +* <http://www.openoffice.org/license.html> +* for a copy of the LGPLv3 License. +* +************************************************************************/ + +#ifndef INCLUDED_BINARYURP_SOURCE_OUTGOINGREQUEST_HXX +#define INCLUDED_BINARYURP_SOURCE_OUTGOINGREQUEST_HXX + +#include "sal/config.h" + +#include "typelib/typedescription.hxx" + +namespace binaryurp { + +struct OutgoingRequest { + enum Kind { KIND_NORMAL, KIND_REQUEST_CHANGE, KIND_COMMIT_CHANGE }; + + OutgoingRequest( + Kind theKind, com::sun::star::uno::TypeDescription const & theMember, + bool theSetter): + kind(theKind), member(theMember), setter(theSetter) + {} + + Kind kind; + + com::sun::star::uno::TypeDescription member; + + bool setter; +}; + +} + +#endif diff --git a/binaryurp/source/outgoingrequests.cxx b/binaryurp/source/outgoingrequests.cxx new file mode 100644 index 000000000..388b77554 --- /dev/null +++ b/binaryurp/source/outgoingrequests.cxx @@ -0,0 +1,80 @@ +/************************************************************************* +* +* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +* +* Copyright 2000, 2011 Oracle and/or its affiliates. +* +* OpenOffice.org - a multi-platform office productivity suite +* +* This file is part of OpenOffice.org. +* +* OpenOffice.org is free software: you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License version 3 +* only, as published by the Free Software Foundation. +* +* OpenOffice.org is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Lesser General Public License version 3 for more details +* (a copy is included in the LICENSE file that accompanied this code). +* +* You should have received a copy of the GNU Lesser General Public License +* version 3 along with OpenOffice.org. If not, see +* <http://www.openoffice.org/license.html> +* for a copy of the LGPLv3 License. +* +************************************************************************/ + +#include "sal/config.h" + +#include "com/sun/star/uno/RuntimeException.hpp" +#include "rtl/byteseq.hxx" +#include "osl/mutex.hxx" + +#include "lessoperators.hxx" +#include "outgoingrequest.hxx" +#include "outgoingrequests.hxx" + +namespace binaryurp { + +namespace { + +namespace css = com::sun::star; + +} + +OutgoingRequests::OutgoingRequests() {} + +OutgoingRequests::~OutgoingRequests() {} + +void OutgoingRequests::push( + rtl::ByteSequence const & tid, OutgoingRequest const & request) +{ + osl::MutexGuard g(mutex_); + map_[tid].push_back(request); +} + +OutgoingRequest OutgoingRequests::top(rtl::ByteSequence const & tid) { + osl::MutexGuard g(mutex_); + Map::iterator i(map_.find(tid)); + if (i == map_.end()) { + throw css::uno::RuntimeException( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM("URP: reply for unknown TID")), + css::uno::Reference< css::uno::XInterface >()); + } + OSL_ASSERT(!i->second.empty()); + return i->second.back(); +} + +void OutgoingRequests::pop(rtl::ByteSequence const & tid) throw () { + osl::MutexGuard g(mutex_); + Map::iterator i(map_.find(tid)); + OSL_ASSERT(i != map_.end()); + i->second.pop_back(); + if (i->second.empty()) { + map_.erase(i); + } +} + +} diff --git a/binaryurp/source/outgoingrequests.hxx b/binaryurp/source/outgoingrequests.hxx new file mode 100644 index 000000000..92ee622bf --- /dev/null +++ b/binaryurp/source/outgoingrequests.hxx @@ -0,0 +1,65 @@ +/************************************************************************* +* +* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +* +* Copyright 2000, 2011 Oracle and/or its affiliates. +* +* OpenOffice.org - a multi-platform office productivity suite +* +* This file is part of OpenOffice.org. +* +* OpenOffice.org is free software: you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License version 3 +* only, as published by the Free Software Foundation. +* +* OpenOffice.org is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Lesser General Public License version 3 for more details +* (a copy is included in the LICENSE file that accompanied this code). +* +* You should have received a copy of the GNU Lesser General Public License +* version 3 along with OpenOffice.org. If not, see +* <http://www.openoffice.org/license.html> +* for a copy of the LGPLv3 License. +* +************************************************************************/ + +#ifndef INCLUDED_BINARYURP_SOURCE_OUTGOINGREQUESTS_HXX +#define INCLUDED_BINARYURP_SOURCE_OUTGOINGREQUESTS_HXX + +#include "sal/config.h" + +#include <map> +#include <vector> + +#include "boost/noncopyable.hpp" +#include "osl/mutex.hxx" + +namespace binaryurp { struct OutgoingRequest; } +namespace rtl { class ByteSequence; } + +namespace binaryurp { + +class OutgoingRequests: private boost::noncopyable { +public: + OutgoingRequests(); + + ~OutgoingRequests(); + + void push(rtl::ByteSequence const & tid, OutgoingRequest const & request); + + OutgoingRequest top(rtl::ByteSequence const & tid); + + void pop(rtl::ByteSequence const & tid) throw (); + +private: + typedef std::map< rtl::ByteSequence, std::vector< OutgoingRequest > > Map; + + osl::Mutex mutex_; + Map map_; +}; + +} + +#endif diff --git a/binaryurp/source/proxy.cxx b/binaryurp/source/proxy.cxx new file mode 100644 index 000000000..876199e7b --- /dev/null +++ b/binaryurp/source/proxy.cxx @@ -0,0 +1,260 @@ +/************************************************************************* +* +* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +* +* Copyright 2000, 2011 Oracle and/or its affiliates. +* +* OpenOffice.org - a multi-platform office productivity suite +* +* This file is part of OpenOffice.org. +* +* OpenOffice.org is free software: you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License version 3 +* only, as published by the Free Software Foundation. +* +* OpenOffice.org is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Lesser General Public License version 3 for more details +* (a copy is included in the LICENSE file that accompanied this code). +* +* You should have received a copy of the GNU Lesser General Public License +* version 3 along with OpenOffice.org. If not, see +* <http://www.openoffice.org/license.html> +* for a copy of the LGPLv3 License. +* +************************************************************************/ + +#include "sal/config.h" + +#include <exception> +#include <vector> + +#include "cppuhelper/exc_hlp.hxx" +#include "osl/diagnose.h" +#include "rtl/ref.hxx" +#include "rtl/ustring.hxx" +#include "sal/types.h" +#include "typelib/typedescription.h" +#include "typelib/typedescription.hxx" +#include "uno/any2.h" +#include "uno/dispatcher.h" +#include "uno/dispatcher.hxx" + +#include "binaryany.hxx" +#include "bridge.hxx" +#include "proxy.hxx" + +namespace binaryurp { + +namespace { + +namespace css = com::sun::star; + +extern "C" void SAL_CALL proxy_acquireInterface(uno_Interface * pInterface) { + OSL_ASSERT(pInterface != 0); + static_cast< Proxy * >(pInterface)->do_acquire(); +} + +extern "C" void SAL_CALL proxy_releaseInterface(uno_Interface * pInterface) { + OSL_ASSERT(pInterface != 0); + static_cast< Proxy * >(pInterface)->do_release(); +} + +extern "C" void SAL_CALL proxy_dispatchInterface( + uno_Interface * pUnoI, typelib_TypeDescription const * pMemberType, + void * pReturn, void ** pArgs, uno_Any ** ppException) +{ + OSL_ASSERT(pUnoI != 0); + static_cast< Proxy * >(pUnoI)->do_dispatch( + pMemberType, pReturn, pArgs, ppException); +} + +} + +Proxy::Proxy( + rtl::Reference< Bridge > const & bridge, rtl::OUString const & oid, + css::uno::TypeDescription const & type): + bridge_(bridge), oid_(oid), type_(type), references_(1) +{ + OSL_ASSERT(bridge.is()); + acquire = &proxy_acquireInterface; + release = &proxy_releaseInterface; + pDispatcher = &proxy_dispatchInterface; +} + +rtl::OUString Proxy::getOid() const { + return oid_; +} + +css::uno::TypeDescription Proxy::getType() const { + return type_; +} + +void Proxy::do_acquire() { + if (osl_incrementInterlockedCount(&references_) == 1) { + bridge_->resurrectProxy(*this); + } +} + +void Proxy::do_release() { + if (osl_decrementInterlockedCount(&references_) == 0) { + bridge_->revokeProxy(*this); + } +} + +void Proxy::do_free() { + bridge_->freeProxy(*this); + delete this; +} + +void Proxy::do_dispatch( + typelib_TypeDescription const * member, void * returnValue, + void ** arguments, uno_Any ** exception) const +{ + try { + try { + do_dispatch_throw(member, returnValue, arguments, exception); + } catch (std::exception & e) { + throw css::uno::RuntimeException( + (rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM("caught C++ exception: ")) + + rtl::OStringToOUString( + rtl::OString(e.what()), RTL_TEXTENCODING_ASCII_US)), + css::uno::Reference< css::uno::XInterface >()); + // best-effort string conversion + } + } catch (css::uno::RuntimeException &) { + css::uno::Any exc(cppu::getCaughtException()); + uno_copyAndConvertData( + *exception, &exc, + (css::uno::TypeDescription(cppu::UnoType< css::uno::Any >::get()). + get()), + bridge_->getCppToBinaryMapping().get()); + } +} + +bool Proxy::isProxy( + rtl::Reference< Bridge > const & bridge, + css::uno::UnoInterfaceReference const & object, rtl::OUString * oid) +{ + OSL_ASSERT(object.is()); + return object.m_pUnoI->acquire == &proxy_acquireInterface && + static_cast< Proxy * >(object.m_pUnoI)->isProxy(bridge, oid); +} + +Proxy::~Proxy() {} + +void Proxy::do_dispatch_throw( + typelib_TypeDescription const * member, void * returnValue, + void ** arguments, uno_Any ** exception) const +{ + //TODO: Optimize queryInterface: + OSL_ASSERT(member != 0); + bool setter = false; + std::vector< BinaryAny > inArgs; + switch (member->eTypeClass) { + case typelib_TypeClass_INTERFACE_ATTRIBUTE: + setter = returnValue == 0; + if (setter) { + inArgs.push_back( + BinaryAny( + css::uno::TypeDescription( + reinterpret_cast< + typelib_InterfaceAttributeTypeDescription const * >( + member)-> + pAttributeTypeRef), + arguments[0])); + } + break; + case typelib_TypeClass_INTERFACE_METHOD: + { + typelib_InterfaceMethodTypeDescription const * mtd = + reinterpret_cast< + typelib_InterfaceMethodTypeDescription const * >(member); + for (sal_Int32 i = 0; i != mtd->nParams; ++i) { + if (mtd->pParams[i].bIn) { + inArgs.push_back( + BinaryAny( + css::uno::TypeDescription(mtd->pParams[i].pTypeRef), + arguments[i])); + } + } + break; + } + default: + OSL_ASSERT(false); // this cannot happen + break; + } + BinaryAny ret; + std::vector< BinaryAny > outArgs; + if (bridge_->makeCall( + oid_, + css::uno::TypeDescription( + const_cast< typelib_TypeDescription * >(member)), + setter, inArgs, &ret, &outArgs)) + { + OSL_ASSERT( + ret.getType().get()->eTypeClass == typelib_TypeClass_EXCEPTION); + uno_any_construct( + *exception, ret.getValue(ret.getType()), ret.getType().get(), 0); + } else { + switch (member->eTypeClass) { + case typelib_TypeClass_INTERFACE_ATTRIBUTE: + if (!setter) { + css::uno::TypeDescription t( + reinterpret_cast< + typelib_InterfaceAttributeTypeDescription const * >( + member)-> + pAttributeTypeRef); + uno_copyData(returnValue, ret.getValue(t), t.get(), 0); + } + break; + case typelib_TypeClass_INTERFACE_METHOD: + { + typelib_InterfaceMethodTypeDescription const * mtd = + reinterpret_cast< + typelib_InterfaceMethodTypeDescription const * >( + member); + css::uno::TypeDescription t(mtd->pReturnTypeRef); + if (t.get()->eTypeClass != typelib_TypeClass_VOID) { + uno_copyData(returnValue, ret.getValue(t), t.get(), 0); + } + std::vector< BinaryAny >::iterator i(outArgs.begin()); + for (sal_Int32 j = 0; j != mtd->nParams; ++j) { + if (mtd->pParams[j].bOut) { + css::uno::TypeDescription pt(mtd->pParams[j].pTypeRef); + if (mtd->pParams[j].bIn) { + uno_assignData( + arguments[j], pt.get(), i++->getValue(pt), + pt.get(), 0, 0, 0); + } else { + uno_copyData( + arguments[j], i++->getValue(pt), pt.get(), 0); + } + } + } + OSL_ASSERT(i == outArgs.end()); + break; + } + default: + OSL_ASSERT(false); // this cannot happen + break; + } + *exception = 0; + } +} + +bool Proxy::isProxy( + rtl::Reference< Bridge > const & bridge, rtl::OUString * oid) const +{ + OSL_ASSERT(oid != 0); + if (bridge == bridge_) { + *oid = oid_; + return true; + } else { + return false; + } +} + +} diff --git a/binaryurp/source/proxy.hxx b/binaryurp/source/proxy.hxx new file mode 100644 index 000000000..c67ab4eb5 --- /dev/null +++ b/binaryurp/source/proxy.hxx @@ -0,0 +1,92 @@ +/************************************************************************* +* +* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +* +* Copyright 2000, 2011 Oracle and/or its affiliates. +* +* OpenOffice.org - a multi-platform office productivity suite +* +* This file is part of OpenOffice.org. +* +* OpenOffice.org is free software: you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License version 3 +* only, as published by the Free Software Foundation. +* +* OpenOffice.org is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Lesser General Public License version 3 for more details +* (a copy is included in the LICENSE file that accompanied this code). +* +* You should have received a copy of the GNU Lesser General Public License +* version 3 along with OpenOffice.org. If not, see +* <http://www.openoffice.org/license.html> +* for a copy of the LGPLv3 License. +* +************************************************************************/ + +#ifndef INCLUDED_BINARYURP_SOURCE_PROXY_HXX +#define INCLUDED_BINARYURP_SOURCE_PROXY_HXX + +#include "sal/config.h" + +#include "boost/noncopyable.hpp" +#include "osl/interlck.h" +#include "rtl/ref.hxx" +#include "rtl/ustring.hxx" +#include "typelib/typedescription.h" +#include "typelib/typedescription.hxx" +#include "uno/any2.h" +#include "uno/dispatcher.h" + +namespace binaryurp { class Bridge; } +namespace com { namespace sun { namespace star { namespace uno { + class UnoInterfaceReference; +} } } } + +namespace binaryurp { + +class Proxy: public uno_Interface, private boost::noncopyable { +public: + Proxy( + rtl::Reference< Bridge > const & bridge, rtl::OUString const & oid, + com::sun::star::uno::TypeDescription const & type); + + rtl::OUString getOid() const; + + com::sun::star::uno::TypeDescription getType() const; + + void do_acquire(); + + void do_release(); + + void do_free(); + + void do_dispatch( + typelib_TypeDescription const * member, void * returnValue, + void ** arguments, uno_Any ** exception) const; + + static bool isProxy( + rtl::Reference< Bridge > const & bridge, + com::sun::star::uno::UnoInterfaceReference const & object, + rtl::OUString * oid); + +private: + ~Proxy(); + + void do_dispatch_throw( + typelib_TypeDescription const * member, void * returnValue, + void ** arguments, uno_Any ** exception) const; + + bool isProxy(rtl::Reference< Bridge > const & bridge, rtl::OUString * oid) + const; + + rtl::Reference< Bridge > bridge_; + rtl::OUString oid_; + com::sun::star::uno::TypeDescription type_; + oslInterlockedCount references_; +}; + +} + +#endif diff --git a/binaryurp/source/reader.cxx b/binaryurp/source/reader.cxx new file mode 100755 index 000000000..7ffdb34fe --- /dev/null +++ b/binaryurp/source/reader.cxx @@ -0,0 +1,552 @@ +/************************************************************************* +* +* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +* +* Copyright 2000, 2011 Oracle and/or its affiliates. +* +* OpenOffice.org - a multi-platform office productivity suite +* +* This file is part of OpenOffice.org. +* +* OpenOffice.org is free software: you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License version 3 +* only, as published by the Free Software Foundation. +* +* OpenOffice.org is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Lesser General Public License version 3 for more details +* (a copy is included in the LICENSE file that accompanied this code). +* +* You should have received a copy of the GNU Lesser General Public License +* version 3 along with OpenOffice.org. If not, see +* <http://www.openoffice.org/license.html> +* for a copy of the LGPLv3 License. +* +************************************************************************/ + +#include "sal/config.h" + +#include <exception> +#include <memory> +#include <vector> + +#include "com/sun/star/connection/XConnection.hpp" +#include "com/sun/star/io/IOException.hpp" +#include "com/sun/star/uno/Any.hxx" +#include "com/sun/star/uno/Exception.hpp" +#include "com/sun/star/uno/Reference.hxx" +#include "com/sun/star/uno/RuntimeException.hpp" +#include "com/sun/star/uno/Sequence.hxx" +#include "com/sun/star/uno/Type.hxx" +#include "com/sun/star/uno/XCurrentContext.hpp" +#include "com/sun/star/uno/XInterface.hpp" +#include "cppu/unotype.hxx" +#include "osl/diagnose.h" +#include "rtl/byteseq.h" +#include "rtl/string.h" +#include "rtl/textenc.h" +#include "rtl/ustring.h" +#include "rtl/ustring.hxx" +#include "sal/types.h" +#include "typelib/typeclass.h" +#include "typelib/typedescription.h" +#include "typelib/typedescription.hxx" +#include "uno/lbnames.h" + +#include "binaryany.hxx" +#include "bridge.hxx" +#include "incomingreply.hxx" +#include "incomingrequest.hxx" +#include "outgoingrequest.hxx" +#include "reader.hxx" +#include "specialfunctionids.hxx" +#include "unmarshal.hxx" + +namespace binaryurp { + +namespace { + +namespace css = com::sun::star; + +css::uno::Sequence< sal_Int8 > read( + css::uno::Reference< css::connection::XConnection > const & connection, + sal_uInt32 size, bool eofOk) +{ + OSL_ASSERT(connection.is()); + if (size > SAL_MAX_INT32) { + throw css::uno::RuntimeException( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "binaryurp::Reader: block size too large")), + css::uno::Reference< css::uno::XInterface >()); + } + css::uno::Sequence< sal_Int8 > buf; + sal_Int32 n = connection->read(buf, static_cast< sal_Int32 >(size)); + if (n == 0 && eofOk) { + return css::uno::Sequence< sal_Int8 >(); + } + if (n != static_cast< sal_Int32 >(size)) { + throw css::io::IOException( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "binaryurp::Reader: premature end of input")), + css::uno::Reference< css::uno::XInterface >()); + } + OSL_ASSERT(buf.getLength() == static_cast< sal_Int32 >(size)); + return buf; +} + +extern "C" void SAL_CALL request(void * pThreadSpecificData) { + OSL_ASSERT(pThreadSpecificData != 0); + std::auto_ptr< IncomingRequest >( + static_cast< IncomingRequest * >(pThreadSpecificData))-> + execute(); +} + +} + +Reader::Reader(rtl::Reference< Bridge > const & bridge): bridge_(bridge) { + OSL_ASSERT(bridge.is()); + acquire(); +} + +Reader::~Reader() {} + +void Reader::run() { + try { + bridge_->sendRequestChangeRequest(); + css::uno::Reference< css::connection::XConnection > con( + bridge_->getConnection()); + for (;;) { + css::uno::Sequence< sal_Int8 > s(read(con, 8, true)); + if (s.getLength() == 0) { + break; + } + Unmarshal header(bridge_, state_, s); + sal_uInt32 size = header.read32(); + sal_uInt32 count = header.read32(); + header.done(); + if (count == 0) { + throw css::io::IOException( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "binaryurp::Reader: block with zero message count" + " received")), + css::uno::Reference< css::uno::XInterface >()); + } + Unmarshal block(bridge_, state_, read(con, size, false)); + for (sal_uInt32 i = 0; i != count; ++i) { + readMessage(block); + } + block.done(); + } + } catch (css::uno::Exception & e) { + OSL_TRACE( + OSL_LOG_PREFIX "caught UNO exception '%s'", + rtl::OUStringToOString(e.Message, RTL_TEXTENCODING_UTF8).getStr()); + } catch (std::exception & e) { + OSL_TRACE(OSL_LOG_PREFIX "caught C++ exception '%s'", e.what()); + } + bridge_->terminate(); +} + +void Reader::onTerminated() { + release(); +} + +void Reader::readMessage(Unmarshal & unmarshal) { + sal_uInt8 flags1 = unmarshal.read8(); + bool newType; + bool newOid; + bool newTid; + bool forceSynchronous; + sal_uInt16 functionId; + if ((flags1 & 0x80) != 0) { // bit 7: LONGHEADER + if ((flags1 & 0x40) == 0) { // bit 6: REQUEST + readReplyMessage(unmarshal, flags1); + return; + } + newType = (flags1 & 0x20) != 0; // bit 5: NEWTYPE + newOid = (flags1 & 0x10) != 0; // bit 4: NEWOID + newTid = (flags1 & 0x08) != 0; // bit 3: NEWTID + if ((flags1 & 0x01) != 0) { // bit 0: MOREFLAGSS + sal_uInt8 flags2 = unmarshal.read8(); + forceSynchronous = (flags2 & 0x80) != 0; // bit 7: MUSTREPLY + if (((flags2 & 0x40) != 0) != forceSynchronous) { + // bit 6: SYNCHRONOUS + throw css::uno::RuntimeException( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "URP: request message with MUSTREPLY != SYNCHRONOUS" + " received")), + css::uno::Reference< css::uno::XInterface >()); + } + } else { + forceSynchronous = false; + } + functionId = ((flags1 & 0x04) != 0) // bit 2: FUNCTIONID16 + ? unmarshal.read16() : unmarshal.read8(); + } else { + newType = false; + newOid = false; + newTid = false; + forceSynchronous = false; + functionId = ((flags1 & 0x40) != 0) // bit 6: FUNCTIONID14 + ? ((flags1 & 0x3F) << 8) | unmarshal.read8() : flags1 & 0x3F; + } + css::uno::TypeDescription type; + if (newType) { + type = unmarshal.readType(); + lastType_ = type; + } else { + if (!lastType_.is()) { + throw css::uno::RuntimeException( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "URP: request message with NEWTYPE received when last" + " interface type has not yet been set")), + css::uno::Reference< css::uno::XInterface >()); + } + type = lastType_; + } + rtl::OUString oid; + if (newOid) { + oid = unmarshal.readOid(); + if (oid.getLength() == 0) { + throw css::io::IOException( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "binaryurp::Unmarshal: emtpy OID")), + css::uno::Reference< css::uno::XInterface >()); + } + lastOid_ = oid; + } else { + if (lastOid_.getLength() == 0) { + throw css::uno::RuntimeException( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "URP: request message with NEWOID received when last" + " OID has not yet been set")), + css::uno::Reference< css::uno::XInterface >()); + } + oid = lastOid_; + } + rtl::ByteSequence tid(getTid(unmarshal, newTid)); + lastTid_ = tid; + type.makeComplete(); + if (type.get()->eTypeClass != typelib_TypeClass_INTERFACE) { + throw css::uno::RuntimeException( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "URP: request message with non-interface interface type" + " received")), + css::uno::Reference< css::uno::XInterface >()); + } + typelib_InterfaceTypeDescription * itd = + reinterpret_cast< typelib_InterfaceTypeDescription * >(type.get()); + if (functionId >= itd->nMapFunctionIndexToMemberIndex) { + throw css::uno::RuntimeException( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "URP: request message with unknown function ID received")), + css::uno::Reference< css::uno::XInterface >()); + } + sal_Int32 memberId = itd->pMapFunctionIndexToMemberIndex[functionId]; + css::uno::TypeDescription memberTd(itd->ppAllMembers[memberId]); + memberTd.makeComplete(); + OSL_ASSERT(memberTd.is()); + bool protProps = bridge_->isProtocolPropertiesRequest(oid, type); + bool ccMode = !protProps && functionId != SPECIAL_FUNCTION_ID_RELEASE && + bridge_->isCurrentContextMode(); + css::uno::UnoInterfaceReference cc; + if (ccMode) { + css::uno::TypeDescription t( + cppu::UnoType< css::uno::Reference< css::uno::XCurrentContext > >:: + get()); + cc.set( + *static_cast< uno_Interface ** >( + unmarshal.readValue(t).getValue(t))); + } + bool synchronous; + if (memberTd.get()->eTypeClass == typelib_TypeClass_INTERFACE_METHOD && + (reinterpret_cast< typelib_InterfaceMethodTypeDescription * >( + memberTd.get())-> + bOneWay)) + { + synchronous = forceSynchronous; + } else { + if (forceSynchronous) { + throw css::uno::RuntimeException( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "URP: synchronous request message with non-oneway" + " function ID received")), + css::uno::Reference< css::uno::XInterface >()); + } + synchronous = true; + } + bool setter = false; + std::vector< BinaryAny > inArgs; + switch (memberTd.get()->eTypeClass) { + case typelib_TypeClass_INTERFACE_ATTRIBUTE: + setter = itd->pMapMemberIndexToFunctionIndex[memberId] != functionId; + // pMapMemberIndexToFunctionIndex contains function index of + // attribute getter + if (setter) { + inArgs.push_back( + unmarshal.readValue( + css::uno::TypeDescription( + reinterpret_cast< + typelib_InterfaceAttributeTypeDescription * >( + memberTd.get())-> + pAttributeTypeRef))); + } + break; + case typelib_TypeClass_INTERFACE_METHOD: + { + typelib_InterfaceMethodTypeDescription * mtd = + reinterpret_cast< typelib_InterfaceMethodTypeDescription * >( + memberTd.get()); + for (sal_Int32 i = 0; i != mtd->nParams; ++i) { + if (mtd->pParams[i].bIn) { + inArgs.push_back( + unmarshal.readValue( + css::uno::TypeDescription( + mtd->pParams[i].pTypeRef))); + } + } + break; + } + default: + OSL_ASSERT(false); // this cannot happen + break; + } + bridge_->incrementCalls( + !protProps && functionId != SPECIAL_FUNCTION_ID_RELEASE); + if (protProps) { + switch (functionId) { + case SPECIAL_FUNCTION_ID_REQUEST_CHANGE: + bridge_->handleRequestChangeRequest(tid, inArgs); + break; + case SPECIAL_FUNCTION_ID_COMMIT_CHANGE: + bridge_->handleCommitChangeRequest(tid, inArgs); + break; + default: + throw css::uno::RuntimeException( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "URP: request message with UrpProtocolProperties OID" + " and unknown function ID received")), + css::uno::Reference< css::uno::XInterface >()); + } + } else { + css::uno::UnoInterfaceReference obj; + switch (functionId) { + case SPECIAL_FUNCTION_ID_QUERY_INTERFACE: + obj = bridge_->findStub(oid, type); + if (!obj.is()) { + OSL_ASSERT( + inArgs.size() == 1 + && inArgs[0].getType().equals( + css::uno::TypeDescription( + cppu::UnoType< css::uno::Type >::get()))); + if (!(type.equals( + css::uno::TypeDescription( + cppu::UnoType< + css::uno::Reference< + css::uno::XInterface > >::get())) + && (css::uno::TypeDescription( + *static_cast< + typelib_TypeDescriptionReference ** >( + inArgs[0].getValue(inArgs[0].getType()))). + equals( + css::uno::TypeDescription( + cppu::UnoType< + css::uno::Reference< + css::uno::XInterface > >::get()))))) + { + throw css::uno::RuntimeException( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "URP: queryInterface request message with" + " unknown OID received")), + css::uno::Reference< css::uno::XInterface >()); + } + } + break; + case SPECIAL_FUNCTION_ID_RESERVED: + throw css::uno::RuntimeException( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "URP: request message with unknown function ID 1" + " received")), + css::uno::Reference< css::uno::XInterface >()); + case SPECIAL_FUNCTION_ID_RELEASE: + break; + default: + obj = bridge_->findStub(oid, type); + if (!obj.is()) { + throw css::uno::RuntimeException( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "URP: request message with unknown OID received")), + css::uno::Reference< css::uno::XInterface >()); + } + break; + } + std::auto_ptr< IncomingRequest > req( + new IncomingRequest( + bridge_, tid, oid, obj, type, functionId, synchronous, memberTd, + setter, inArgs, ccMode, cc)); + if (synchronous) { + bridge_->incrementActiveCalls(); + } + uno_threadpool_putJob( + bridge_->getThreadPool(), tid.getHandle(), req.get(), &request, + !synchronous); + req.release(); + } +} + +void Reader::readReplyMessage(Unmarshal & unmarshal, sal_uInt8 flags1) { + rtl::ByteSequence tid(getTid(unmarshal, (flags1 & 0x08) != 0)); + // bit 3: NEWTID + lastTid_ = tid; + OutgoingRequest req(bridge_->lastOutgoingRequest(tid)); + bool exc = (flags1 & 0x20) != 0; // bit 5: EXCEPTION + BinaryAny ret; + std::vector< BinaryAny > outArgs; + if (exc) { + ret = unmarshal.readValue( + css::uno::TypeDescription(cppu::UnoType< css::uno::Any >::get())); + if (!typelib_typedescription_isAssignableFrom( + (css::uno::TypeDescription( + cppu::UnoType< css::uno::RuntimeException >::get()). + get()), + ret.getType().get())) + { + sal_Int32 n = 0; + typelib_TypeDescriptionReference ** p = 0; + switch (req.member.get()->eTypeClass) { + case typelib_TypeClass_INTERFACE_ATTRIBUTE: + { + typelib_InterfaceAttributeTypeDescription * atd = + reinterpret_cast< + typelib_InterfaceAttributeTypeDescription * >( + req.member.get()); + n = req.setter ? atd->nSetExceptions : atd->nGetExceptions; + p = req.setter + ? atd->ppSetExceptions : atd->ppGetExceptions; + break; + } + case typelib_TypeClass_INTERFACE_METHOD: + { + typelib_InterfaceMethodTypeDescription * mtd = + reinterpret_cast< + typelib_InterfaceMethodTypeDescription * >( + req.member.get()); + n = mtd->nExceptions; + p = mtd->ppExceptions; + break; + } + default: + OSL_ASSERT(false); // this cannot happen + break; + } + bool ok = false; + for (sal_Int32 i = 0; i != n; ++i) { + if (typelib_typedescriptionreference_isAssignableFrom( + p[i], + reinterpret_cast< typelib_TypeDescriptionReference * >( + ret.getType().get()))) + { + ok = true; + break; + } + } + if (!ok) { + throw css::uno::RuntimeException( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "URP: reply message with bad exception type" + " received")), + css::uno::Reference< css::uno::XInterface >()); + } + } + } else { + switch (req.member.get()->eTypeClass) { + case typelib_TypeClass_INTERFACE_ATTRIBUTE: + if (!req.setter) { + ret = unmarshal.readValue( + css::uno::TypeDescription( + reinterpret_cast< + typelib_InterfaceAttributeTypeDescription * >( + req.member.get())-> + pAttributeTypeRef)); + } + break; + case typelib_TypeClass_INTERFACE_METHOD: + { + typelib_InterfaceMethodTypeDescription * mtd = + reinterpret_cast< + typelib_InterfaceMethodTypeDescription * >( + req.member.get()); + ret = unmarshal.readValue( + css::uno::TypeDescription(mtd->pReturnTypeRef)); + for (sal_Int32 i = 0; i != mtd->nParams; ++i) { + if (mtd->pParams[i].bOut) { + outArgs.push_back( + unmarshal.readValue( + css::uno::TypeDescription( + mtd->pParams[i].pTypeRef))); + } + } + break; + } + default: + OSL_ASSERT(false); // this cannot happen + break; + } + } + switch (req.kind) { + case OutgoingRequest::KIND_NORMAL: + { + std::auto_ptr< IncomingReply > resp( + new IncomingReply(exc, ret, outArgs)); + uno_threadpool_putJob( + bridge_->getThreadPool(), tid.getHandle(), resp.get(), 0, + false); + resp.release(); + break; + } + case OutgoingRequest::KIND_REQUEST_CHANGE: + OSL_ASSERT(outArgs.empty()); + bridge_->handleRequestChangeReply(exc, ret); + break; + case OutgoingRequest::KIND_COMMIT_CHANGE: + OSL_ASSERT(outArgs.empty()); + bridge_->handleCommitChangeReply(exc, ret); + break; + default: + OSL_ASSERT(false); // this cannot happen + break; + } +} + +rtl::ByteSequence Reader::getTid(Unmarshal & unmarshal, bool newTid) const { + if (newTid) { + return unmarshal.readTid(); + } + if (lastTid_.getLength() == 0) { + throw css::uno::RuntimeException( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "URP: message with NEWTID received when last TID has not" + " yet been set")), + css::uno::Reference< css::uno::XInterface >()); + } + return lastTid_; +} + +} diff --git a/binaryurp/source/reader.hxx b/binaryurp/source/reader.hxx new file mode 100644 index 000000000..37d0b9462 --- /dev/null +++ b/binaryurp/source/reader.hxx @@ -0,0 +1,89 @@ +/************************************************************************* +* +* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +* +* Copyright 2000, 2011 Oracle and/or its affiliates. +* +* OpenOffice.org - a multi-platform office productivity suite +* +* This file is part of OpenOffice.org. +* +* OpenOffice.org is free software: you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License version 3 +* only, as published by the Free Software Foundation. +* +* OpenOffice.org is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Lesser General Public License version 3 for more details +* (a copy is included in the LICENSE file that accompanied this code). +* +* You should have received a copy of the GNU Lesser General Public License +* version 3 along with OpenOffice.org. If not, see +* <http://www.openoffice.org/license.html> +* for a copy of the LGPLv3 License. +* +************************************************************************/ + +#ifndef INCLUDED_BINARYURP_SOURCE_READER_HXX +#define INCLUDED_BINARYURP_SOURCE_READER_HXX + +#include "sal/config.h" + +#include <cstddef> + +#include "boost/noncopyable.hpp" +#include "osl/thread.hxx" +#include "rtl/byteseq.hxx" +#include "rtl/ref.hxx" +#include "rtl/ustring.hxx" +#include "sal/types.h" +#include "salhelper/simplereferenceobject.hxx" +#include "typelib/typedescription.hxx" + +#include "readerstate.hxx" + +namespace binaryurp { + class BinaryAny; + class Bridge; + class Unmarshal; +} + +namespace binaryurp { + +class Reader: + public osl::Thread, public salhelper::SimpleReferenceObject, + private boost::noncopyable +{ +public: + static void * operator new(std::size_t size) + { return Thread::operator new(size); } + + static void operator delete(void * pointer) + { Thread::operator delete(pointer); } + + explicit Reader(rtl::Reference< Bridge > const & bridge); + +private: + virtual ~Reader(); + + virtual void SAL_CALL run(); + + virtual void SAL_CALL onTerminated(); + + void readMessage(Unmarshal & unmarshal); + + void readReplyMessage(Unmarshal & unmarshal, sal_uInt8 flags1); + + rtl::ByteSequence getTid(Unmarshal & unmarshal, bool newTid) const; + + rtl::Reference< Bridge > bridge_; + com::sun::star::uno::TypeDescription lastType_; + rtl::OUString lastOid_; + rtl::ByteSequence lastTid_; + ReaderState state_; +}; + +} + +#endif diff --git a/binaryurp/source/readerstate.hxx b/binaryurp/source/readerstate.hxx new file mode 100644 index 000000000..ef7ed4d71 --- /dev/null +++ b/binaryurp/source/readerstate.hxx @@ -0,0 +1,52 @@ +/************************************************************************* +* +* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +* +* Copyright 2000, 2011 Oracle and/or its affiliates. +* +* OpenOffice.org - a multi-platform office productivity suite +* +* This file is part of OpenOffice.org. +* +* OpenOffice.org is free software: you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License version 3 +* only, as published by the Free Software Foundation. +* +* OpenOffice.org is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Lesser General Public License version 3 for more details +* (a copy is included in the LICENSE file that accompanied this code). +* +* You should have received a copy of the GNU Lesser General Public License +* version 3 along with OpenOffice.org. If not, see +* <http://www.openoffice.org/license.html> +* for a copy of the LGPLv3 License. +* +************************************************************************/ + +#ifndef INCLUDED_BINARYURP_SOURCE_READERSTATE_HXX +#define INCLUDED_BINARYURP_SOURCE_READERSTATE_HXX + +#include "sal/config.h" + +#include "boost/noncopyable.hpp" +#include "rtl/byteseq.hxx" +#include "rtl/ustring.hxx" +#include "typelib/typedescription.hxx" + +#include "cache.hxx" + +namespace binaryurp { + +struct ReaderState: private boost::noncopyable { + com::sun::star::uno::TypeDescription typeCache[cache::size]; + + rtl::OUString oidCache[cache::size]; + + rtl::ByteSequence tidCache[cache::size]; +}; + +} + +#endif diff --git a/binaryurp/source/specialfunctionids.hxx b/binaryurp/source/specialfunctionids.hxx new file mode 100644 index 000000000..a2a59791b --- /dev/null +++ b/binaryurp/source/specialfunctionids.hxx @@ -0,0 +1,49 @@ +/************************************************************************* +* +* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +* +* Copyright 2000, 2011 Oracle and/or its affiliates. +* +* OpenOffice.org - a multi-platform office productivity suite +* +* This file is part of OpenOffice.org. +* +* OpenOffice.org is free software: you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License version 3 +* only, as published by the Free Software Foundation. +* +* OpenOffice.org is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Lesser General Public License version 3 for more details +* (a copy is included in the LICENSE file that accompanied this code). +* +* You should have received a copy of the GNU Lesser General Public License +* version 3 along with OpenOffice.org. If not, see +* <http://www.openoffice.org/license.html> +* for a copy of the LGPLv3 License. +* +************************************************************************/ + +#ifndef INCLUDED_BINARYURP_SOURCE_SPECIALFUNCTIONIDS_HXX +#define INCLUDED_BINARYURP_SOURCE_SPECIALFUNCTIONIDS_HXX + +#include "sal/config.h" + +namespace binaryurp { + +enum SpecialFunctionIds { + SPECIAL_FUNCTION_ID_QUERY_INTERFACE = 0, + + SPECIAL_FUNCTION_ID_RESERVED = 1, + + SPECIAL_FUNCTION_ID_RELEASE = 2, + + SPECIAL_FUNCTION_ID_REQUEST_CHANGE = 4, + + SPECIAL_FUNCTION_ID_COMMIT_CHANGE = 5 +}; + +} + +#endif diff --git a/binaryurp/source/unmarshal.cxx b/binaryurp/source/unmarshal.cxx new file mode 100755 index 000000000..62f8683e3 --- /dev/null +++ b/binaryurp/source/unmarshal.cxx @@ -0,0 +1,563 @@ +/************************************************************************* +* +* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +* +* Copyright 2000, 2011 Oracle and/or its affiliates. +* +* OpenOffice.org - a multi-platform office productivity suite +* +* This file is part of OpenOffice.org. +* +* OpenOffice.org is free software: you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License version 3 +* only, as published by the Free Software Foundation. +* +* OpenOffice.org is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Lesser General Public License version 3 for more details +* (a copy is included in the LICENSE file that accompanied this code). +* +* You should have received a copy of the GNU Lesser General Public License +* version 3 along with OpenOffice.org. If not, see +* <http://www.openoffice.org/license.html> +* for a copy of the LGPLv3 License. +* +************************************************************************/ + +#include "sal/config.h" + +#include <cstdlib> +#include <new> +#include <vector> + +#include "boost/noncopyable.hpp" +#include "com/sun/star/io/IOException.hpp" +#include "com/sun/star/uno/Reference.hxx" +#include "com/sun/star/uno/RuntimeException.hpp" +#include "com/sun/star/uno/Sequence.hxx" +#include "com/sun/star/uno/XInterface.hpp" +#include "cppu/unotype.hxx" +#include "osl/diagnose.h" +#include "rtl/byteseq.hxx" +#include "rtl/ref.hxx" +#include "rtl/textcvt.h" +#include "rtl/textenc.h" +#include "rtl/ustring.h" +#include "rtl/ustring.hxx" +#include "sal/types.h" +#include "typelib/typeclass.h" +#include "typelib/typedescription.h" +#include "typelib/typedescription.hxx" +#include "uno/any2.h" +#include "uno/data.h" +#include "uno/dispatcher.hxx" + +#include "binaryany.hxx" +#include "bridge.hxx" +#include "cache.hxx" +#include "readerstate.hxx" +#include "unmarshal.hxx" + +namespace binaryurp { + +namespace { + +namespace css = com::sun::star; + +void * allocate(sal_Size size) { + void * p = rtl_allocateMemory(size); + if (p == 0) { + throw std::bad_alloc(); + } + return p; +} + +std::vector< BinaryAny >::iterator copyMemberValues( + css::uno::TypeDescription const & type, + std::vector< BinaryAny >::iterator const & it, void * buffer) throw () +{ + OSL_ASSERT( + type.is() && + (type.get()->eTypeClass == typelib_TypeClass_STRUCT || + type.get()->eTypeClass == typelib_TypeClass_EXCEPTION) && + buffer != 0); + type.makeComplete(); + std::vector< BinaryAny >::iterator i(it); + typelib_CompoundTypeDescription * ctd = + reinterpret_cast< typelib_CompoundTypeDescription * >(type.get()); + if (ctd->pBaseTypeDescription != 0) { + i = copyMemberValues( + css::uno::TypeDescription(&ctd->pBaseTypeDescription->aBase), i, + buffer); + } + for (sal_Int32 j = 0; j != ctd->nMembers; ++j) { + uno_type_copyData( + static_cast< char * >(buffer) + ctd->pMemberOffsets[j], + const_cast< void * >( + i++->getValue(css::uno::TypeDescription(ctd->ppTypeRefs[j]))), + ctd->ppTypeRefs[j], 0); + } + return i; +} + +} + +Unmarshal::Unmarshal( + rtl::Reference< Bridge > const & bridge, ReaderState & state, + css::uno::Sequence< sal_Int8 > const & buffer): + bridge_(bridge), state_(state), buffer_(buffer) +{ + data_ = reinterpret_cast< sal_uInt8 const * >(buffer_.getConstArray()); + end_ = data_ + buffer_.getLength(); +} + +Unmarshal::~Unmarshal() {} + +sal_uInt8 Unmarshal::read8() { + check(1); + return *data_++; +} + +sal_uInt16 Unmarshal::read16() { + check(2); + sal_uInt16 n = static_cast< sal_uInt16 >(*data_++) << 8; + return n | *data_++; +} + +sal_uInt32 Unmarshal::read32() { + check(4); + sal_uInt32 n = static_cast< sal_uInt32 >(*data_++) << 24; + n |= static_cast< sal_uInt32 >(*data_++) << 16; + n |= static_cast< sal_uInt32 >(*data_++) << 8; + return n | *data_++; +} + +css::uno::TypeDescription Unmarshal::readType() { + sal_uInt8 flags = read8(); + typelib_TypeClass tc = static_cast< typelib_TypeClass >(flags & 0x7F); + switch (tc) { + case typelib_TypeClass_VOID: + case typelib_TypeClass_BOOLEAN: + case typelib_TypeClass_BYTE: + case typelib_TypeClass_SHORT: + case typelib_TypeClass_UNSIGNED_SHORT: + case typelib_TypeClass_LONG: + case typelib_TypeClass_UNSIGNED_LONG: + case typelib_TypeClass_HYPER: + case typelib_TypeClass_UNSIGNED_HYPER: + case typelib_TypeClass_FLOAT: + case typelib_TypeClass_DOUBLE: + case typelib_TypeClass_CHAR: + case typelib_TypeClass_STRING: + case typelib_TypeClass_TYPE: + case typelib_TypeClass_ANY: + if ((flags & 0x80) != 0) { + throw css::io::IOException( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "binaryurp::Unmarshal: cache flag of simple type is" + " set")), + css::uno::Reference< css::uno::XInterface >()); + } + return css::uno::TypeDescription( + *typelib_static_type_getByTypeClass( + static_cast< typelib_TypeClass >(tc))); + case typelib_TypeClass_SEQUENCE: + case typelib_TypeClass_ENUM: + case typelib_TypeClass_STRUCT: + case typelib_TypeClass_EXCEPTION: + case typelib_TypeClass_INTERFACE: + { + sal_uInt16 idx = readCacheIndex(); + if ((flags & 0x80) == 0) { + if (idx == cache::ignore || !state_.typeCache[idx].is()) { + throw css::io::IOException( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "binaryurp::Unmarshal: unknown type cache" + " index")), + css::uno::Reference< css::uno::XInterface >()); + } + return state_.typeCache[idx]; + } else { + css::uno::TypeDescription t(readString()); + if (!t.is() || + t.get()->eTypeClass != static_cast< typelib_TypeClass >(tc)) + { + throw css::io::IOException( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "binaryurp::Unmarshal: type with unknown" + " name")), + css::uno::Reference< css::uno::XInterface >()); + } + for (css::uno::TypeDescription t2(t); + t2.get()->eTypeClass == typelib_TypeClass_SEQUENCE;) + { + t2.makeComplete(); + t2 = css::uno::TypeDescription( + reinterpret_cast< typelib_IndirectTypeDescription * >( + t2.get())->pType); + if (!t2.is()) { + throw css::io::IOException( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "binaryurp::Unmarshal: sequence type with" + " unknown component type")), + css::uno::Reference< css::uno::XInterface >()); + } + switch (t2.get()->eTypeClass) { + case typelib_TypeClass_VOID: + case typelib_TypeClass_EXCEPTION: + throw css::io::IOException( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "binaryurp::Unmarshal: sequence type with" + " bad component type")), + css::uno::Reference< css::uno::XInterface >()); + default: + break; + } + } + if (idx != cache::ignore) { + state_.typeCache[idx] = t; + } + return t; + } + } + default: + throw css::io::IOException( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "binaryurp::Unmarshal: type of unknown type class")), + css::uno::Reference< css::uno::XInterface >()); + } +} + +rtl::OUString Unmarshal::readOid() { + rtl::OUString oid(readString()); + for (sal_Int32 i = 0; i != oid.getLength(); ++i) { + if (oid[i] > 0x7F) { + throw css::io::IOException( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "binaryurp::Unmarshal: OID contains non-ASCII" + " character")), + css::uno::Reference< css::uno::XInterface >()); + } + } + sal_uInt16 idx = readCacheIndex(); + if (oid.getLength() == 0 && idx != cache::ignore) { + if (state_.oidCache[idx].getLength() == 0) { + throw css::io::IOException( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "binaryurp::Unmarshal: unknown OID cache index")), + css::uno::Reference< css::uno::XInterface >()); + } + return state_.oidCache[idx]; + } + if (idx != cache::ignore) { + state_.oidCache[idx] = oid; + } + return oid; +} + +rtl::ByteSequence Unmarshal::readTid() { + rtl::ByteSequence tid( + *static_cast< sal_Sequence * const * >( + readSequence( + css::uno::TypeDescription( + cppu::UnoType< css::uno::Sequence< sal_Int8 > >::get())). + getValue( + css::uno::TypeDescription( + cppu::UnoType< css::uno::Sequence< sal_Int8 > >::get())))); + sal_uInt16 idx = readCacheIndex(); + if (tid.getLength() == 0) { + if (idx == cache::ignore || state_.tidCache[idx].getLength() == 0) { + throw css::io::IOException( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "binaryurp::Unmarshal: unknown TID cache index")), + css::uno::Reference< css::uno::XInterface >()); + } + return state_.tidCache[idx]; + } + if (idx != cache::ignore) { + state_.tidCache[idx] = tid; + } + return tid; +} + +BinaryAny Unmarshal::readValue(css::uno::TypeDescription const & type) { + OSL_ASSERT(type.is()); + switch (type.get()->eTypeClass) { + default: + std::abort(); // this cannot happen + // pseudo fall-through to avoid compiler warnings + case typelib_TypeClass_VOID: + return BinaryAny(); + case typelib_TypeClass_BOOLEAN: + { + sal_uInt8 v = read8(); + if (v > 1) { + throw css::io::IOException( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "binaryurp::Unmarshal: boolean of unknown value")), + css::uno::Reference< css::uno::XInterface >()); + } + return BinaryAny(type, &v); + } + case typelib_TypeClass_BYTE: + { + sal_uInt8 v = read8(); + return BinaryAny(type, &v); + } + case typelib_TypeClass_SHORT: + case typelib_TypeClass_UNSIGNED_SHORT: + case typelib_TypeClass_CHAR: + { + sal_uInt16 v = read16(); + return BinaryAny(type, &v); + } + case typelib_TypeClass_LONG: + case typelib_TypeClass_UNSIGNED_LONG: + case typelib_TypeClass_FLOAT: + { + sal_uInt32 v = read32(); + return BinaryAny(type, &v); + } + case typelib_TypeClass_HYPER: + case typelib_TypeClass_UNSIGNED_HYPER: + case typelib_TypeClass_DOUBLE: + { + sal_uInt64 v = read64(); + return BinaryAny(type, &v); + } + case typelib_TypeClass_STRING: + { + rtl::OUString v(readString()); + return BinaryAny(type, &v.pData); + } + case typelib_TypeClass_TYPE: + { + css::uno::TypeDescription v(readType()); + typelib_TypeDescription * p = v.get(); + return BinaryAny(type, &p); + } + case typelib_TypeClass_ANY: + { + css::uno::TypeDescription t(readType()); + if (t.get()->eTypeClass == typelib_TypeClass_ANY) { + throw css::io::IOException( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "binaryurp::Unmarshal: any of type ANY")), + css::uno::Reference< css::uno::XInterface >()); + } + return readValue(t); + } + case typelib_TypeClass_SEQUENCE: + type.makeComplete(); + return readSequence(type); + case typelib_TypeClass_ENUM: + { + sal_Int32 v = static_cast< sal_Int32 >(read32()); + type.makeComplete(); + typelib_EnumTypeDescription * etd = + reinterpret_cast< typelib_EnumTypeDescription * >(type.get()); + bool found = false; + for (sal_Int32 i = 0; i != etd->nEnumValues; ++i) { + if (etd->pEnumValues[i] == v) { + found = true; + break; + } + } + if (!found) { + throw css::io::IOException( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "binaryurp::Unmarshal: unknown enum value")), + css::uno::Reference< css::uno::XInterface >()); + } + return BinaryAny(type, &v); + } + case typelib_TypeClass_STRUCT: + case typelib_TypeClass_EXCEPTION: + { + std::vector< BinaryAny > as; + readMemberValues(type, &as); + void * buf = allocate(type.get()->nSize); + copyMemberValues(type, as.begin(), buf); + uno_Any raw; + raw.pType = reinterpret_cast< typelib_TypeDescriptionReference * >( + type.get()); + raw.pData = buf; + raw.pReserved = 0; + return BinaryAny(raw); + } + case typelib_TypeClass_INTERFACE: + { + css::uno::UnoInterfaceReference obj( + bridge_->registerIncomingInterface(readOid(), type)); + return BinaryAny(type, &obj.m_pUnoI); + } + } +} + +void Unmarshal::done() const { + if (data_ != end_) { + throw css::io::IOException( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "binaryurp::Unmarshal: block contains excess data")), + css::uno::Reference< css::uno::XInterface >()); + } +} + +void Unmarshal::check(sal_Int32 size) const { + if (end_ - data_ < size) { + throw css::io::IOException( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "binaryurp::Unmarshal: trying to read past end of block")), + css::uno::Reference< css::uno::XInterface >()); + } +} + +sal_uInt32 Unmarshal::readCompressed() { + sal_uInt8 n = read8(); + return n == 0xFF ? read32() : n; +} + +sal_uInt16 Unmarshal::readCacheIndex() { + sal_uInt16 idx = read16(); + if (idx >= cache::size && idx != cache::ignore) { + throw css::io::IOException( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "binaryurp::Unmarshal: cache index out of range")), + css::uno::Reference< css::uno::XInterface >()); + } + return idx; +} + +sal_uInt64 Unmarshal::read64() { + check(8); + sal_uInt64 n = static_cast< sal_uInt64 >(*data_++) << 56; + n |= static_cast< sal_uInt64 >(*data_++) << 48; + n |= static_cast< sal_uInt64 >(*data_++) << 40; + n |= static_cast< sal_uInt64 >(*data_++) << 32; + n |= static_cast< sal_uInt64 >(*data_++) << 24; + n |= static_cast< sal_uInt64 >(*data_++) << 16; + n |= static_cast< sal_uInt64 >(*data_++) << 8; + return n | *data_++; +} + +rtl::OUString Unmarshal::readString() { + sal_uInt32 n = readCompressed(); + if (n > SAL_MAX_INT32) { + throw css::uno::RuntimeException( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "binaryurp::Unmarshal: string size too large")), + css::uno::Reference< css::uno::XInterface >()); + } + check(static_cast< sal_Int32 >(n)); + rtl::OUString s; + if (!rtl_convertStringToUString( + &s.pData, reinterpret_cast< char const * >(data_), + static_cast< sal_Int32 >(n), RTL_TEXTENCODING_UTF8, + (RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR | + RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR | + RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR))) + { + throw css::io::IOException( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "binaryurp::Unmarshal: string does not contain UTF-8")), + css::uno::Reference< css::uno::XInterface >()); + } + data_ += n; + return s; +} + +BinaryAny Unmarshal::readSequence(css::uno::TypeDescription const & type) { + OSL_ASSERT( + type.is() && type.get()->eTypeClass == typelib_TypeClass_SEQUENCE); + sal_uInt32 n = readCompressed(); + if (n > SAL_MAX_INT32) { + throw css::uno::RuntimeException( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "binaryurp::Unmarshal: sequence size too large")), + css::uno::Reference< css::uno::XInterface >()); + } + if (n == 0) { + return BinaryAny(type, 0); + } + css::uno::TypeDescription ctd( + reinterpret_cast< typelib_IndirectTypeDescription * >( + type.get())->pType); + if (ctd.get()->eTypeClass == typelib_TypeClass_BYTE) { + check(static_cast< sal_Int32 >(n)); + rtl::ByteSequence s( + reinterpret_cast< sal_Int8 const * >(data_), + static_cast< sal_Int32 >(n)); + data_ += n; + sal_Sequence * p = s.getHandle(); + return BinaryAny(type, &p); + } + std::vector< BinaryAny > as; + for (sal_uInt32 i = 0; i != n; ++i) { + as.push_back(readValue(ctd)); + } + OSL_ASSERT(ctd.get()->nSize >= 0); + sal_uInt64 size = static_cast< sal_uInt64 >(n) * + static_cast< sal_uInt64 >(ctd.get()->nSize); + // sal_uInt32 * sal_Int32 -> sal_uInt64 cannot overflow + if (size > SAL_MAX_SIZE - SAL_SEQUENCE_HEADER_SIZE) { + throw css::uno::RuntimeException( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "binaryurp::Unmarshal: sequence size too large")), + css::uno::Reference< css::uno::XInterface >()); + } + void * buf = allocate( + SAL_SEQUENCE_HEADER_SIZE + static_cast< sal_Size >(size)); + static_cast< sal_Sequence * >(buf)->nRefCount = 0; + static_cast< sal_Sequence * >(buf)->nElements = + static_cast< sal_Int32 >(n); + for (sal_uInt32 i = 0; i != n; ++i) { + uno_copyData( + static_cast< sal_Sequence * >(buf)->elements + i * ctd.get()->nSize, + const_cast< void * >(as[i].getValue(ctd)), ctd.get(), 0); + } + return BinaryAny(type, reinterpret_cast< sal_Sequence ** >(&buf)); +} + +void Unmarshal::readMemberValues( + css::uno::TypeDescription const & type, std::vector< BinaryAny > * values) +{ + OSL_ASSERT( + type.is() && + (type.get()->eTypeClass == typelib_TypeClass_STRUCT || + type.get()->eTypeClass == typelib_TypeClass_EXCEPTION) && + values != 0); + type.makeComplete(); + typelib_CompoundTypeDescription * ctd = + reinterpret_cast< typelib_CompoundTypeDescription * >(type.get()); + if (ctd->pBaseTypeDescription != 0) { + readMemberValues( + css::uno::TypeDescription(&ctd->pBaseTypeDescription->aBase), + values); + } + for (sal_Int32 i = 0; i != ctd->nMembers; ++i) { + values->push_back( + readValue(css::uno::TypeDescription(ctd->ppTypeRefs[i]))); + } +} + +} diff --git a/binaryurp/source/unmarshal.hxx b/binaryurp/source/unmarshal.hxx new file mode 100644 index 000000000..33a4aafec --- /dev/null +++ b/binaryurp/source/unmarshal.hxx @@ -0,0 +1,106 @@ +/************************************************************************* +* +* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +* +* Copyright 2000, 2011 Oracle and/or its affiliates. +* +* OpenOffice.org - a multi-platform office productivity suite +* +* This file is part of OpenOffice.org. +* +* OpenOffice.org is free software: you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License version 3 +* only, as published by the Free Software Foundation. +* +* OpenOffice.org is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Lesser General Public License version 3 for more details +* (a copy is included in the LICENSE file that accompanied this code). +* +* You should have received a copy of the GNU Lesser General Public License +* version 3 along with OpenOffice.org. If not, see +* <http://www.openoffice.org/license.html> +* for a copy of the LGPLv3 License. +* +************************************************************************/ + +#ifndef INCLUDED_BINARYURP_SOURCE_UNMARSHAL_HXX +#define INCLUDED_BINARYURP_SOURCE_UNMARSHAL_HXX + +#include "sal/config.h" + +#include <vector> + +#include "boost/noncopyable.hpp" +#include "com/sun/star/uno/Sequence.hxx" +#include "rtl/ref.hxx" +#include "sal/types.h" +#include "typelib/typedescription.hxx" + +namespace binaryurp { + class BinaryAny; + class Bridge; + struct ReaderState; +} +namespace com { namespace sun { namespace star { namespace uno { + class TypeDescription; +} } } } +namespace rtl { + class ByteSequecne; + class OUString; +} + +namespace binaryurp { + +class Unmarshal: private boost::noncopyable { +public: + Unmarshal( + rtl::Reference< Bridge > const & bridge, ReaderState & state, + com::sun::star::uno::Sequence< sal_Int8 > const & buffer); + + ~Unmarshal(); + + sal_uInt8 read8(); + + sal_uInt16 read16(); + + sal_uInt32 read32(); + + com::sun::star::uno::TypeDescription readType(); + + rtl::OUString readOid(); + + rtl::ByteSequence readTid(); + + BinaryAny readValue(com::sun::star::uno::TypeDescription const & type); + + void done() const; + +private: + void check(sal_Int32 size) const; + + sal_uInt32 readCompressed(); + + sal_uInt16 readCacheIndex(); + + sal_uInt64 read64(); + + rtl::OUString readString(); + + BinaryAny readSequence(com::sun::star::uno::TypeDescription const & type); + + void readMemberValues( + com::sun::star::uno::TypeDescription const & type, + std::vector< BinaryAny > * values); + + rtl::Reference< Bridge > bridge_; + ReaderState & state_; + com::sun::star::uno::Sequence< sal_Int8 > buffer_; + sal_uInt8 const * data_; + sal_uInt8 const * end_; +}; + +} + +#endif diff --git a/binaryurp/source/writer.cxx b/binaryurp/source/writer.cxx new file mode 100755 index 000000000..439b7dba8 --- /dev/null +++ b/binaryurp/source/writer.cxx @@ -0,0 +1,475 @@ +/************************************************************************* +* +* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +* +* Copyright 2000, 2011 Oracle and/or its affiliates. +* +* OpenOffice.org - a multi-platform office productivity suite +* +* This file is part of OpenOffice.org. +* +* OpenOffice.org is free software: you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License version 3 +* only, as published by the Free Software Foundation. +* +* OpenOffice.org is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Lesser General Public License version 3 for more details +* (a copy is included in the LICENSE file that accompanied this code). +* +* You should have received a copy of the GNU Lesser General Public License +* version 3 along with OpenOffice.org. If not, see +* <http://www.openoffice.org/license.html> +* for a copy of the LGPLv3 License. +* +************************************************************************/ + +#include "sal/config.h" + +#include <exception> +#include <vector> + +#include "com/sun/star/connection/XConnection.hpp" +#include "com/sun/star/lang/WrappedTargetRuntimeException.hpp" +#include "com/sun/star/uno/XCurrentContext.hpp" +#include "cppuhelper/exc_hlp.hxx" +#include "osl/mutex.hxx" +#include "rtl/memory.h" +#include "uno/dispatcher.hxx" + +#include "binaryany.hxx" +#include "bridge.hxx" +#include "currentcontext.hxx" +#include "specialfunctionids.hxx" +#include "writer.hxx" + +namespace binaryurp { + +namespace { + +namespace css = com::sun::star; + +bool isProtocolPropertyMessage(rtl::OUString const & oid) { + return oid.equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM("UrpProtocolProperties")); +} + +} + +Writer::Item::Item() {} + +Writer::Item::Item( + rtl::ByteSequence const & theTid, rtl::OUString const & theOid, + css::uno::TypeDescription const & theType, + css::uno::TypeDescription const & theMember, + std::vector< BinaryAny > const & inArguments, + css::uno::UnoInterfaceReference const & theCurrentContext): + request(true), tid(theTid), oid(theOid), type(theType), member(theMember), + arguments(inArguments), currentContext(theCurrentContext) +{} + +Writer::Item::Item( + rtl::ByteSequence const & theTid, + css::uno::TypeDescription const & theMember, bool theSetter, + bool theException, BinaryAny const & theReturnValue, + std::vector< BinaryAny > const & outArguments, + bool theSetCurrentContextMode): + request(false), tid(theTid), member(theMember), setter(theSetter), + arguments(outArguments), exception(theException), + returnValue(theReturnValue), setCurrentContextMode(theSetCurrentContextMode) +{} + +Writer::Writer(rtl::Reference< Bridge > const & bridge): + bridge_(bridge), marshal_(bridge, state_), stop_(false) +{ + OSL_ASSERT(bridge.is()); + acquire(); +} + +void Writer::sendDirectRequest( + rtl::ByteSequence const & tid, rtl::OUString const & oid, + css::uno::TypeDescription const & type, + css::uno::TypeDescription const & member, + std::vector< BinaryAny > const & inArguments) +{ + OSL_ASSERT(!unblocked_.check()); + sendRequest( + tid, oid, type, member, inArguments, false, + css::uno::UnoInterfaceReference()); +} + +void Writer::sendDirectReply( + rtl::ByteSequence const & tid, css::uno::TypeDescription const & member, + bool exception, BinaryAny const & returnValue, + std::vector< BinaryAny > const & outArguments) +{ + OSL_ASSERT(!unblocked_.check()); + sendReply(tid, member, false, exception, returnValue,outArguments); +} + +void Writer::queueRequest( + rtl::ByteSequence const & tid, rtl::OUString const & oid, + css::uno::TypeDescription const & type, + css::uno::TypeDescription const & member, + std::vector< BinaryAny > const & inArguments) +{ + css::uno::UnoInterfaceReference cc(current_context::get()); + osl::MutexGuard g(mutex_); + queue_.push_back(Item(tid, oid, type, member, inArguments, cc)); + items_.set(); +} + +void Writer::queueReply( + rtl::ByteSequence const & tid, + com::sun::star::uno::TypeDescription const & member, bool setter, + bool exception, BinaryAny const & returnValue, + std::vector< BinaryAny > const & outArguments, bool setCurrentContextMode) +{ + osl::MutexGuard g(mutex_); + queue_.push_back( + Item( + tid, member, setter, exception, returnValue, outArguments, + setCurrentContextMode)); + items_.set(); +} + +void Writer::unblock() { + // Assumes that osl::Condition::set works as a memory barrier, so that + // changes made by preceeding sendDirectRequest/Reply calls are visible to + // subsequent sendRequest/Reply calls: + unblocked_.set(); +} + +void Writer::stop() { + { + osl::MutexGuard g(mutex_); + stop_ = true; + } + unblocked_.set(); + items_.set(); +} + +Writer::~Writer() {} + +void Writer::run() { + try { + unblocked_.wait(); + for (;;) { + items_.wait(); + Item item; + { + osl::MutexGuard g(mutex_); + if (stop_) { + return; + } + OSL_ASSERT(!queue_.empty()); + item = queue_.front(); + queue_.pop_front(); + if (queue_.empty()) { + items_.reset(); + } + } + if (item.request) { + sendRequest( + item.tid, item.oid, item.type, item.member, item.arguments, + (!item.oid.equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM("UrpProtocolProperties")) && + !item.member.equals( + css::uno::TypeDescription( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "com.sun.star.uno.XInterface::" + "release")))) && + bridge_->isCurrentContextMode()), + item.currentContext); + } else { + sendReply( + item.tid, item.member, item.setter, item.exception, + item.returnValue, item.arguments); + if (item.setCurrentContextMode) { + bridge_->setCurrentContextMode(); + } + } + } + } catch (css::uno::Exception & e) { + OSL_TRACE( + OSL_LOG_PREFIX "caught UNO exception '%s'", + rtl::OUStringToOString(e.Message, RTL_TEXTENCODING_UTF8).getStr()); + } catch (std::exception & e) { + OSL_TRACE(OSL_LOG_PREFIX "caught C++ exception '%s'", e.what()); + } + bridge_->terminate(); +} + +void Writer::onTerminated() { + release(); +} + +void Writer::sendRequest( + rtl::ByteSequence const & tid, rtl::OUString const & oid, + css::uno::TypeDescription const & type, + css::uno::TypeDescription const & member, + std::vector< BinaryAny > const & inArguments, bool currentContextMode, + css::uno::UnoInterfaceReference const & currentContext) +{ + OSL_ASSERT(tid.getLength() != 0 && oid.getLength() != 0 && member.is()); + css::uno::TypeDescription t(type); + sal_Int32 functionId = 0; + bool forceSynchronous = false; + member.makeComplete(); + switch (member.get()->eTypeClass) { + case typelib_TypeClass_INTERFACE_ATTRIBUTE: + { + typelib_InterfaceAttributeTypeDescription * atd = + reinterpret_cast< typelib_InterfaceAttributeTypeDescription * >( + member.get()); + OSL_ASSERT(atd->pInterface != 0); + if (!t.is()) { + t = css::uno::TypeDescription(&atd->pInterface->aBase); + } + t.makeComplete(); + functionId = atd->pInterface->pMapMemberIndexToFunctionIndex[ + atd->aBase.nPosition]; + if (!inArguments.empty()) { // setter + ++functionId; + } + break; + } + case typelib_TypeClass_INTERFACE_METHOD: + { + typelib_InterfaceMethodTypeDescription * mtd = + reinterpret_cast< typelib_InterfaceMethodTypeDescription * >( + member.get()); + OSL_ASSERT(mtd->pInterface != 0); + if (!t.is()) { + t = css::uno::TypeDescription(&mtd->pInterface->aBase); + } + t.makeComplete(); + functionId = mtd->pInterface->pMapMemberIndexToFunctionIndex[ + mtd->aBase.nPosition]; + forceSynchronous = mtd->bOneWay && + functionId != SPECIAL_FUNCTION_ID_RELEASE; + break; + } + default: + OSL_ASSERT(false); // this cannot happen + break; + } + OSL_ASSERT(functionId >= 0); + if (functionId > SAL_MAX_UINT16) { + throw css::uno::RuntimeException( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM("function ID too large for URP")), + css::uno::Reference< css::uno::XInterface >()); + } + std::vector< unsigned char > buf; + bool newType = !(lastType_.is() && t.equals(lastType_)); + bool newOid = oid != lastOid_; + bool newTid = tid != lastTid_; + if (newType || newOid || newTid || forceSynchronous || functionId > 0x3FFF) + // > 14 bit function ID + { + Marshal::write8( + &buf, + (0xC0 | (newType ? 0x20 : 0) | (newOid ? 0x10 : 0) | + (newTid ? 0x08 : 0) | (functionId > 0xFF ? 0x04 : 0) | + (forceSynchronous ? 0x01 : 0))); + // bit 7: LONGHEADER, bit 6: REQUEST, bit 5: NEWTYPE, bit 4: NEWOID, + // bit 3: NEWTID, bit 2: FUNCTIONID16, bit 0: MOREFLAGS + if (forceSynchronous) { + Marshal::write8(&buf, 0xC0); // bit 7: MUSTREPLY, bit 6: SYNCHRONOUS + } + if (functionId <= 0xFF) { + Marshal::write8(&buf, static_cast< sal_uInt8 >(functionId)); + } else { + Marshal::write16(&buf, static_cast< sal_uInt16 >(functionId)); + } + if (newType) { + marshal_.writeType(&buf, t); + } + if (newOid) { + marshal_.writeOid(&buf, oid); + } + if (newTid) { + marshal_.writeTid(&buf, tid); + } + } else if (functionId <= 0x3F) { // <= 6 bit function ID + Marshal::write8(&buf, static_cast< sal_uInt8 >(functionId)); + // bit 7: !LONGHEADER, bit 6: !FUNCTIONID14 + } else { + Marshal::write8( + &buf, static_cast< sal_uInt8 >(0x40 | (functionId >> 8))); + // bit 7: !LONGHEADER, bit 6: FUNCTIONID14 + Marshal::write8(&buf, functionId & 0xFF); + } + if (currentContextMode) { + css::uno::UnoInterfaceReference cc(currentContext); + marshal_.writeValue( + &buf, + css::uno::TypeDescription( + cppu::UnoType< + css::uno::Reference< css::uno::XCurrentContext > >::get()), + BinaryAny( + css::uno::TypeDescription( + cppu::UnoType< + css::uno::Reference< + css::uno::XCurrentContext > >::get()), + &cc.m_pUnoI)); + } + switch (member.get()->eTypeClass) { + case typelib_TypeClass_INTERFACE_ATTRIBUTE: + if (!inArguments.empty()) { // setter + OSL_ASSERT(inArguments.size() == 1); + marshal_.writeValue( + &buf, + css::uno::TypeDescription( + reinterpret_cast< + typelib_InterfaceAttributeTypeDescription * >( + member.get())-> + pAttributeTypeRef), + inArguments.front()); + } + break; + case typelib_TypeClass_INTERFACE_METHOD: + { + typelib_InterfaceMethodTypeDescription * mtd = + reinterpret_cast< typelib_InterfaceMethodTypeDescription * >( + member.get()); + std::vector< BinaryAny >::const_iterator i(inArguments.begin()); + for (sal_Int32 j = 0; j != mtd->nParams; ++j) { + if (mtd->pParams[j].bIn) { + marshal_.writeValue( + &buf, + css::uno::TypeDescription(mtd->pParams[j].pTypeRef), + *i++); + } + } + OSL_ASSERT(i == inArguments.end()); + break; + } + default: + OSL_ASSERT(false); // this cannot happen + break; + } + sendMessage(buf); + lastType_ = t; + lastOid_ = oid; + lastTid_ = tid; +} + +void Writer::sendReply( + rtl::ByteSequence const & tid, + com::sun::star::uno::TypeDescription const & member, bool setter, + bool exception, BinaryAny const & returnValue, + std::vector< BinaryAny > const & outArguments) +{ + OSL_ASSERT(tid.getLength() != 0 && member.is() && member.get()->bComplete); + std::vector< unsigned char > buf; + bool newTid = tid != lastTid_; + Marshal::write8(&buf, 0x80 | (exception ? 0x20 : 0) | (newTid ? 0x08 : 0)); + // bit 7: LONGHEADER; bit 6: !REQUEST; bit 5: EXCEPTION; bit 3: NEWTID + if (newTid) { + marshal_.writeTid(&buf, tid); + } + if (exception) { + marshal_.writeValue( + &buf, + css::uno::TypeDescription(cppu::UnoType< css::uno::Any >::get()), + returnValue); + } else { + switch (member.get()->eTypeClass) { + case typelib_TypeClass_INTERFACE_ATTRIBUTE: + if (!setter) { + marshal_.writeValue( + &buf, + css::uno::TypeDescription( + reinterpret_cast< + typelib_InterfaceAttributeTypeDescription * >( + member.get())-> + pAttributeTypeRef), + returnValue); + } + break; + case typelib_TypeClass_INTERFACE_METHOD: + { + typelib_InterfaceMethodTypeDescription * mtd = + reinterpret_cast< + typelib_InterfaceMethodTypeDescription * >( + member.get()); + marshal_.writeValue( + &buf, css::uno::TypeDescription(mtd->pReturnTypeRef), + returnValue); + std::vector< BinaryAny >::const_iterator i( + outArguments.begin()); + for (sal_Int32 j = 0; j != mtd->nParams; ++j) { + if (mtd->pParams[j].bOut) { + marshal_.writeValue( + &buf, + css::uno::TypeDescription(mtd->pParams[j].pTypeRef), + *i++); + } + } + OSL_ASSERT(i == outArguments.end()); + break; + } + default: + OSL_ASSERT(false); // this cannot happen + break; + } + } + sendMessage(buf); + lastTid_ = tid; + bridge_->decrementCalls(); +} + +void Writer::sendMessage(std::vector< unsigned char > const & buffer) { + std::vector< unsigned char > header; + if (buffer.size() > SAL_MAX_UINT32) { + throw css::uno::RuntimeException( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM("message too large for URP")), + css::uno::Reference< css::uno::XInterface >()); + } + Marshal::write32(&header, static_cast< sal_uInt32 >(buffer.size())); + Marshal::write32(&header, 1); + OSL_ASSERT(!buffer.empty()); + unsigned char const * p = &buffer[0]; + std::vector< unsigned char >::size_type n = buffer.size(); + OSL_ASSERT(header.size() <= SAL_MAX_INT32 && SAL_MAX_INT32 <= SAL_MAX_SIZE); + sal_Size k = SAL_MAX_INT32 - header.size(); + if (n < k) { + k = static_cast< sal_Size >(n); + } + css::uno::Sequence< sal_Int8 > s( + static_cast< sal_Int32 >(header.size() + k)); + OSL_ASSERT(!header.empty()); + rtl_copyMemory( + s.getArray(), &header[0], static_cast< sal_Size >(header.size())); + for (;;) { + rtl_copyMemory(s.getArray() + s.getLength() - k, p, k); + try { + bridge_->getConnection()->write(s); + } catch (css::io::IOException & e) { + css::uno::Any exc(cppu::getCaughtException()); + throw css::lang::WrappedTargetRuntimeException( + (rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "Binary URP write raised IO exception: ")) + + e.Message), + css::uno::Reference< css::uno::XInterface >(), exc); + } + n = static_cast< std::vector< unsigned char >::size_type >(n - k); + if (n == 0) { + break; + } + p += k; + k = SAL_MAX_INT32; + if (n < k) { + k = static_cast< sal_Size >(n); + } + s.realloc(k); + } +} + +} diff --git a/binaryurp/source/writer.hxx b/binaryurp/source/writer.hxx new file mode 100644 index 000000000..fe5dba2cc --- /dev/null +++ b/binaryurp/source/writer.hxx @@ -0,0 +1,185 @@ +/************************************************************************* +* +* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +* +* Copyright 2000, 2011 Oracle and/or its affiliates. +* +* OpenOffice.org - a multi-platform office productivity suite +* +* This file is part of OpenOffice.org. +* +* OpenOffice.org is free software: you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License version 3 +* only, as published by the Free Software Foundation. +* +* OpenOffice.org is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Lesser General Public License version 3 for more details +* (a copy is included in the LICENSE file that accompanied this code). +* +* You should have received a copy of the GNU Lesser General Public License +* version 3 along with OpenOffice.org. If not, see +* <http://www.openoffice.org/license.html> +* for a copy of the LGPLv3 License. +* +************************************************************************/ + +#ifndef INCLUDED_BINARYURP_SOURCE_WRITER_HXX +#define INCLUDED_BINARYURP_SOURCE_WRITER_HXX + +#include "sal/config.h" + +#include <cstddef> +#include <deque> +#include <vector> + +#include "boost/noncopyable.hpp" +#include "osl/conditn.hxx" +#include "osl/mutex.hxx" +#include "osl/thread.hxx" +#include "rtl/byteseq.hxx" +#include "rtl/ref.hxx" +#include "rtl/ustring.hxx" +#include "sal/types.h" +#include "salhelper/simplereferenceobject.hxx" +#include "typelib/typedescription.hxx" +#include "uno/dispatcher.hxx" + +#include "binaryany.hxx" +#include "marshal.hxx" +#include "writerstate.hxx" + +namespace binaryurp { class Bridge; } + +namespace binaryurp { + +class Writer: + public osl::Thread, public salhelper::SimpleReferenceObject, + private boost::noncopyable +{ +public: + static void * operator new(std::size_t size) + { return Thread::operator new(size); } + + static void operator delete(void * pointer) + { Thread::operator delete(pointer); } + + explicit Writer(rtl::Reference< Bridge > const & bridge); + + // Only called from Bridge::reader_ thread, and only before Bridge::writer_ + // thread is unblocked: + void sendDirectRequest( + rtl::ByteSequence const & tid, rtl::OUString const & oid, + com::sun::star::uno::TypeDescription const & type, + com::sun::star::uno::TypeDescription const & member, + std::vector< BinaryAny > const & inArguments); + + // Only called from Bridge::reader_ thread, and only before Bridge::writer_ + // thread is unblocked: + void sendDirectReply( + rtl::ByteSequence const & tid, + com::sun::star::uno::TypeDescription const & member, + bool exception, BinaryAny const & returnValue, + std::vector< BinaryAny > const & outArguments); + + void queueRequest( + rtl::ByteSequence const & tid, rtl::OUString const & oid, + com::sun::star::uno::TypeDescription const & type, + com::sun::star::uno::TypeDescription const & member, + std::vector< BinaryAny > const & inArguments); + + void queueReply( + rtl::ByteSequence const & tid, + com::sun::star::uno::TypeDescription const & member, bool setter, + bool exception, BinaryAny const & returnValue, + std::vector< BinaryAny > const & outArguments, + bool setCurrentContextMode); + + void unblock(); + + void stop(); + +private: + virtual ~Writer(); + + virtual void SAL_CALL run(); + + virtual void SAL_CALL onTerminated(); + + void sendRequest( + rtl::ByteSequence const & tid, rtl::OUString const & oid, + com::sun::star::uno::TypeDescription const & type, + com::sun::star::uno::TypeDescription const & member, + std::vector< BinaryAny > const & inArguments, bool currentContextMode, + com::sun::star::uno::UnoInterfaceReference const & currentContext); + + void sendReply( + rtl::ByteSequence const & tid, + com::sun::star::uno::TypeDescription const & member, bool setter, + bool exception, BinaryAny const & returnValue, + std::vector< BinaryAny > const & outArguments); + + void sendMessage(std::vector< unsigned char > const & buffer); + + struct Item { + Item(); + + // Request: + Item( + rtl::ByteSequence const & theTid, rtl::OUString const & theOid, + com::sun::star::uno::TypeDescription const & theType, + com::sun::star::uno::TypeDescription const & theMember, + std::vector< BinaryAny > const & inArguments, + com::sun::star::uno::UnoInterfaceReference const & + theCurrentContext); + + // Reply: + Item( + rtl::ByteSequence const & theTid, + com::sun::star::uno::TypeDescription const & theMember, + bool theSetter, bool theException, BinaryAny const & theReturnValue, + std::vector< BinaryAny > const & outArguments, + bool theSetCurrentContextMode); + + bool request; + + rtl::ByteSequence tid; // request + reply + + rtl::OUString oid; // request + + com::sun::star::uno::TypeDescription type; // request + + com::sun::star::uno::TypeDescription member; // request + reply + + bool setter; // reply + + std::vector< BinaryAny > arguments; + // request: inArguments; reply: outArguments + + bool exception; // reply + + BinaryAny returnValue; // reply + + com::sun::star::uno::UnoInterfaceReference currentContext; // request + + bool setCurrentContextMode; // reply + }; + + rtl::Reference< Bridge > bridge_; + WriterState state_; + Marshal marshal_; + com::sun::star::uno::TypeDescription lastType_; + rtl::OUString lastOid_; + rtl::ByteSequence lastTid_; + osl::Condition unblocked_; + osl::Condition items_; + + osl::Mutex mutex_; + std::deque< Item > queue_; + bool stop_; +}; + +} + +#endif diff --git a/binaryurp/source/writerstate.hxx b/binaryurp/source/writerstate.hxx new file mode 100644 index 000000000..cbb0208ba --- /dev/null +++ b/binaryurp/source/writerstate.hxx @@ -0,0 +1,55 @@ +/************************************************************************* +* +* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +* +* Copyright 2000, 2011 Oracle and/or its affiliates. +* +* OpenOffice.org - a multi-platform office productivity suite +* +* This file is part of OpenOffice.org. +* +* OpenOffice.org is free software: you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License version 3 +* only, as published by the Free Software Foundation. +* +* OpenOffice.org is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Lesser General Public License version 3 for more details +* (a copy is included in the LICENSE file that accompanied this code). +* +* You should have received a copy of the GNU Lesser General Public License +* version 3 along with OpenOffice.org. If not, see +* <http://www.openoffice.org/license.html> +* for a copy of the LGPLv3 License. +* +************************************************************************/ + +#ifndef INCLUDED_BINARYURP_SOURCE_WRITERSTATE_HXX +#define INCLUDED_BINARYURP_SOURCE_WRITERSTATE_HXX + +#include "sal/config.h" + +#include "boost/noncopyable.hpp" +#include "rtl/byteseq.hxx" +#include "rtl/ustring.hxx" +#include "typelib/typedescription.hxx" + +#include "cache.hxx" + +namespace binaryurp { + +struct WriterState: private boost::noncopyable { + WriterState(): + typeCache(cache::size), oidCache(cache::size), tidCache(cache::size) {} + + Cache< com::sun::star::uno::TypeDescription > typeCache; + + Cache< rtl::OUString > oidCache; + + Cache< rtl::ByteSequence > tidCache; +}; + +} + +#endif |