summaryrefslogtreecommitdiffstats
path: root/binaryurp
diff options
context:
space:
mode:
Diffstat (limited to 'binaryurp')
-rw-r--r--binaryurp/CppunitTest_binaryurp_test-cache.mk22
-rw-r--r--binaryurp/CppunitTest_binaryurp_test-unmarshal.mk33
-rw-r--r--binaryurp/IwyuFilter_binaryurp.yaml34
-rw-r--r--binaryurp/Library_binaryurp.mk40
-rw-r--r--binaryurp/Makefile7
-rw-r--r--binaryurp/Module_binaryurp.mk21
-rw-r--r--binaryurp/README.md8
-rw-r--r--binaryurp/qa/test-cache.cxx81
-rw-r--r--binaryurp/qa/test-unmarshal.cxx94
-rw-r--r--binaryurp/source/binaryany.cxx114
-rw-r--r--binaryurp/source/binaryany.hxx66
-rw-r--r--binaryurp/source/binaryurp.component26
-rw-r--r--binaryurp/source/bridge.cxx1054
-rw-r--r--binaryurp/source/bridge.hxx281
-rw-r--r--binaryurp/source/bridgefactory.cxx192
-rw-r--r--binaryurp/source/bridgefactory.hxx115
-rw-r--r--binaryurp/source/cache.hxx95
-rw-r--r--binaryurp/source/currentcontext.cxx55
-rw-r--r--binaryurp/source/currentcontext.hxx36
-rw-r--r--binaryurp/source/incomingreply.hxx52
-rw-r--r--binaryurp/source/incomingrequest.cxx286
-rw-r--r--binaryurp/source/incomingrequest.hxx79
-rw-r--r--binaryurp/source/lessoperators.cxx65
-rw-r--r--binaryurp/source/lessoperators.hxx39
-rw-r--r--binaryurp/source/marshal.cxx300
-rw-r--r--binaryurp/source/marshal.hxx88
-rw-r--r--binaryurp/source/outgoingrequest.hxx47
-rw-r--r--binaryurp/source/outgoingrequests.cxx67
-rw-r--r--binaryurp/source/outgoingrequests.hxx63
-rw-r--r--binaryurp/source/proxy.cxx239
-rw-r--r--binaryurp/source/proxy.hxx85
-rw-r--r--binaryurp/source/reader.cxx480
-rw-r--r--binaryurp/source/reader.hxx65
-rw-r--r--binaryurp/source/readerstate.hxx47
-rw-r--r--binaryurp/source/specialfunctionids.hxx40
-rw-r--r--binaryurp/source/unmarshal.cxx491
-rw-r--r--binaryurp/source/unmarshal.hxx93
-rw-r--r--binaryurp/source/writer.cxx455
-rw-r--r--binaryurp/source/writer.hxx150
-rw-r--r--binaryurp/source/writerstate.hxx49
40 files changed, 5654 insertions, 0 deletions
diff --git a/binaryurp/CppunitTest_binaryurp_test-cache.mk b/binaryurp/CppunitTest_binaryurp_test-cache.mk
new file mode 100644
index 000000000..97f5b78f0
--- /dev/null
+++ b/binaryurp/CppunitTest_binaryurp_test-cache.mk
@@ -0,0 +1,22 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+$(eval $(call gb_CppunitTest_CppunitTest,binaryurp_test-cache))
+
+$(eval $(call gb_CppunitTest_use_external,binaryurp_test-cache,boost_headers))
+
+$(eval $(call gb_CppunitTest_use_libraries,binaryurp_test-cache,\
+ sal \
+))
+
+$(eval $(call gb_CppunitTest_add_exception_objects,binaryurp_test-cache,\
+ binaryurp/qa/test-cache \
+))
+
+# vim: set noet sw=4 ts=4:
diff --git a/binaryurp/CppunitTest_binaryurp_test-unmarshal.mk b/binaryurp/CppunitTest_binaryurp_test-unmarshal.mk
new file mode 100644
index 000000000..11c70f5b9
--- /dev/null
+++ b/binaryurp/CppunitTest_binaryurp_test-unmarshal.mk
@@ -0,0 +1,33 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+$(eval $(call gb_CppunitTest_CppunitTest,binaryurp_test-unmarshal))
+
+$(eval $(call gb_CppunitTest_use_external,binaryurp_test-unmarshal,boost_headers))
+
+$(eval $(call gb_CppunitTest_use_libraries,binaryurp_test-unmarshal,\
+ cppu \
+ cppuhelper \
+ sal \
+ salhelper \
+))
+
+$(eval $(call gb_CppunitTest_use_library_objects,binaryurp_test-unmarshal,\
+ binaryurp \
+))
+
+$(eval $(call gb_CppunitTest_use_api,binaryurp_test-unmarshal,\
+ udkapi \
+))
+
+$(eval $(call gb_CppunitTest_add_exception_objects,binaryurp_test-unmarshal,\
+ binaryurp/qa/test-unmarshal \
+))
+
+# vim: set noet sw=4 ts=4:
diff --git a/binaryurp/IwyuFilter_binaryurp.yaml b/binaryurp/IwyuFilter_binaryurp.yaml
new file mode 100644
index 000000000..49e10617c
--- /dev/null
+++ b/binaryurp/IwyuFilter_binaryurp.yaml
@@ -0,0 +1,34 @@
+---
+assumeFilename: binaryurp/source/bridge.cxx
+excludelist:
+ binaryurp/source/marshal.hxx:
+ # Don't propose hxx -> h change in URE libs
+ - rtl/byteseq.hxx
+ binaryurp/source/reader.hxx:
+ # Don't propose hxx -> h change in URE libs
+ - rtl/byteseq.hxx
+ binaryurp/source/incomingrequest.hxx:
+ # Don't propose hxx -> h change in URE libs
+ - rtl/byteseq.hxx
+ binaryurp/source/lessoperators.cxx:
+ # Don't propose hxx -> h change in URE libs
+ - rtl/byteseq.hxx
+ binaryurp/source/outgoingrequests.cxx:
+ # Don't propose hxx -> h change in URE libs
+ - rtl/byteseq.hxx
+ # Actually needed
+ - lessoperators.hxx
+ binaryurp/source/bridgefactory.cxx:
+ # Actually needed
+ - com/sun/star/connection/XConnection.hpp
+ - com/sun/star/uno/XComponentContext.hpp
+ - com/sun/star/uno/XInterface.hpp
+ binaryurp/source/bridge.cxx:
+ # Actually needed
+ - com/sun/star/bridge/XInstanceProvider.hpp
+ - com/sun/star/connection/XConnection.hpp
+ - com/sun/star/lang/XEventListener.hpp
+ - com/sun/star/uno/XInterface.hpp
+ binaryurp/source/unmarshal.cxx:
+ # Actually used
+ - vector
diff --git a/binaryurp/Library_binaryurp.mk b/binaryurp/Library_binaryurp.mk
new file mode 100644
index 000000000..439f1f7d4
--- /dev/null
+++ b/binaryurp/Library_binaryurp.mk
@@ -0,0 +1,40 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+$(eval $(call gb_Library_Library,binaryurp))
+
+$(eval $(call gb_Library_set_componentfile,binaryurp,binaryurp/source/binaryurp,ure/services))
+
+$(eval $(call gb_Library_use_udk_api,binaryurp))
+
+$(eval $(call gb_Library_use_external,binaryurp,boost_headers))
+
+$(eval $(call gb_Library_use_libraries,binaryurp,\
+ cppu \
+ cppuhelper \
+ sal \
+ salhelper \
+))
+
+$(eval $(call gb_Library_add_exception_objects,binaryurp,\
+ binaryurp/source/binaryany \
+ binaryurp/source/bridge \
+ binaryurp/source/bridgefactory \
+ binaryurp/source/currentcontext \
+ binaryurp/source/incomingrequest \
+ binaryurp/source/lessoperators \
+ binaryurp/source/marshal \
+ binaryurp/source/outgoingrequests \
+ binaryurp/source/proxy \
+ binaryurp/source/reader \
+ binaryurp/source/unmarshal \
+ binaryurp/source/writer \
+))
+
+# vim: set noet sw=4 ts=4:
diff --git a/binaryurp/Makefile b/binaryurp/Makefile
new file mode 100644
index 000000000..ccb1c85a0
--- /dev/null
+++ b/binaryurp/Makefile
@@ -0,0 +1,7 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+
+module_directory:=$(dir $(realpath $(firstword $(MAKEFILE_LIST))))
+
+include $(module_directory)/../solenv/gbuild/partial_build.mk
+
+# vim: set noet sw=4 ts=4:
diff --git a/binaryurp/Module_binaryurp.mk b/binaryurp/Module_binaryurp.mk
new file mode 100644
index 000000000..fcfd303f0
--- /dev/null
+++ b/binaryurp/Module_binaryurp.mk
@@ -0,0 +1,21 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+$(eval $(call gb_Module_Module,binaryurp))
+
+$(eval $(call gb_Module_add_targets,binaryurp,\
+ Library_binaryurp \
+))
+
+$(eval $(call gb_Module_add_check_targets,binaryurp,\
+ CppunitTest_binaryurp_test-cache \
+ CppunitTest_binaryurp_test-unmarshal \
+))
+
+# vim: set noet sw=4 ts=4:
diff --git a/binaryurp/README.md b/binaryurp/README.md
new file mode 100644
index 000000000..ac26bec06
--- /dev/null
+++ b/binaryurp/README.md
@@ -0,0 +1,8 @@
+# UNO Remote Protocol (URP)
+
+UNO provides a binary protocol called the UNO Remote Protocol (URP) that provides
+a bridge between UNO environments. This bridge allows processes and objects
+to send method calls and to receive return values. UNO objects in different
+environments are connected by way of this interprocess bridge. The underlying
+connection is made through a socket or pipe. Remote UNO objects are connected
+by means of TCP/IP using the high-level protocol of the URP.
diff --git a/binaryurp/qa/test-cache.cxx b/binaryurp/qa/test-cache.cxx
new file mode 100644
index 000000000..c4696f783
--- /dev/null
+++ b/binaryurp/qa/test-cache.cxx
@@ -0,0 +1,81 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <cstddef>
+
+#include <sal/types.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 (std::size_t i = 0; i != std::size(a); ++i) {
+ for (std::size_t j = 0; j != i; ++j) {
+ a[j] = 0;
+ }
+ for (;;) {
+ binaryurp::Cache< int > c(4);
+ for (std::size_t 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));
+ std::size_t j = i;
+ while (j != 0 && a[j - 1] == 3) {
+ --j;
+ }
+ if (j == 0) {
+ break;
+ }
+ ++a[j - 1];
+ for (std::size_t k = j; k != i; ++k) {
+ a[k] = 0;
+ }
+ }
+ }
+}
+
+CPPUNIT_TEST_SUITE_REGISTRATION(Test);
+
+}
+
+CPPUNIT_PLUGIN_IMPLEMENT();
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/binaryurp/qa/test-unmarshal.cxx b/binaryurp/qa/test-unmarshal.cxx
new file mode 100644
index 000000000..df3a96d8f
--- /dev/null
+++ b/binaryurp/qa/test-unmarshal.cxx
@@ -0,0 +1,94 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#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 {
+
+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{
+ static_cast<sal_Int8>(static_cast<sal_uInt8>(20 | 0x80)),
+ // sequence type | cache flag
+ static_cast<sal_Int8>(
+ static_cast<sal_uInt8>(binaryurp::cache::ignore >> 8)),
+ static_cast<sal_Int8>(
+ static_cast<sal_uInt8>(binaryurp::cache::ignore & 0xFF)),
+ RTL_CONSTASCII_LENGTH("[]boolean"),
+ '[', ']', 'b', 'o', 'o', 'l', 'e', 'a', '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{
+ static_cast<sal_Int8>(static_cast<sal_uInt8>(20 | 0x80)),
+ // sequence type | cache flag
+ static_cast<sal_Int8>(
+ static_cast<sal_uInt8>(binaryurp::cache::ignore >> 8)),
+ static_cast<sal_Int8>(
+ static_cast<sal_uInt8>(binaryurp::cache::ignore & 0xFF)),
+ RTL_CONSTASCII_LENGTH("[]void"), '[', ']', 'v', 'o', 'i', 'd' };
+ binaryurp::Unmarshal m(rtl::Reference< binaryurp::Bridge >(), state, buf);
+ try {
+ m.readType();
+ CPPUNIT_FAIL("exception expected");
+ } catch (const css::io::IOException &) {}
+}
+
+CPPUNIT_TEST_SUITE_REGISTRATION(Test);
+
+}
+
+CPPUNIT_PLUGIN_IMPLEMENT();
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/binaryurp/source/binaryany.cxx b/binaryurp/source/binaryany.cxx
new file mode 100644
index 000000000..7f6e14a6f
--- /dev/null
+++ b/binaryurp/source/binaryany.cxx
@@ -0,0 +1,114 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <cassert>
+#include <utility>
+
+#include <typelib/typeclass.h>
+#include <typelib/typedescription.hxx>
+#include <uno/any2.h>
+
+#include "binaryany.hxx"
+
+namespace binaryurp {
+
+namespace {
+
+// Cf. com::sun::star::uno::Any move ctor in
+// include/com/sun/star/uno/Any.hxx:
+void moveInternals(uno_Any & from, uno_Any & to) {
+ uno_any_construct(&to, nullptr, nullptr, nullptr);
+ std::swap(from.pType, to.pType);
+ std::swap(from.pData, to.pData);
+ std::swap(from.pReserved, to.pReserved);
+ if (to.pData == &from.pReserved) {
+ to.pData = &to.pReserved;
+ }
+ // This leaves to.pData (where "to" is now VOID) dangling to somewhere (cf.
+ // CONSTRUCT_EMPTY_ANY, cppu/source/uno/prim.hxx), but what's relevant is
+ // only that it isn't a nullptr (as e.g. >>= -> uno_type_assignData ->
+ // _assignData takes a null pSource to mean "construct a default value").
+}
+
+}
+
+BinaryAny::BinaryAny() noexcept {
+ uno_any_construct(&data_, nullptr, nullptr, nullptr);
+}
+
+BinaryAny::BinaryAny(css::uno::TypeDescription const & type, void * value)
+ noexcept
+{
+ assert(type.is());
+ uno_any_construct(&data_, value, type.get(), nullptr);
+}
+
+BinaryAny::BinaryAny(uno_Any const & raw) noexcept {
+ assert(raw.pType != nullptr);
+ 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) noexcept {
+ uno_type_any_construct(&data_, other.data_.pData, other.data_.pType, nullptr);
+}
+
+BinaryAny::BinaryAny(BinaryAny && other) noexcept {
+ moveInternals(other.data_, data_);
+}
+
+BinaryAny::~BinaryAny() noexcept {
+ uno_any_destruct(&data_, nullptr);
+}
+
+BinaryAny & BinaryAny::operator =(BinaryAny const & other) noexcept {
+ if (&other != this) {
+ uno_type_any_assign(&data_, other.data_.pData, other.data_.pType, nullptr, nullptr);
+ }
+ return *this;
+}
+
+BinaryAny & BinaryAny::operator =(BinaryAny && other) noexcept {
+ uno_any_destruct(&data_, nullptr);
+ moveInternals(other.data_, data_);
+ return *this;
+}
+
+css::uno::TypeDescription BinaryAny::getType() const noexcept {
+ return css::uno::TypeDescription(data_.pType);
+}
+
+void * BinaryAny::getValue(css::uno::TypeDescription const & type) const
+ noexcept
+{
+ assert(type.is());
+ assert(
+ type.get()->eTypeClass == typelib_TypeClass_ANY ||
+ type.equals(css::uno::TypeDescription(data_.pType)));
+ return type.get()->eTypeClass == typelib_TypeClass_ANY
+ ? &data_ : data_.pData;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/binaryurp/source/binaryany.hxx b/binaryurp/source/binaryany.hxx
new file mode 100644
index 000000000..c04fe8f86
--- /dev/null
+++ b/binaryurp/source/binaryany.hxx
@@ -0,0 +1,66 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <uno/any2.h>
+
+namespace com::sun::star::uno { class TypeDescription; }
+
+namespace binaryurp {
+
+class BinaryAny {
+public:
+ BinaryAny() noexcept;
+
+ BinaryAny(com::sun::star::uno::TypeDescription const & type, void * value)
+ noexcept;
+
+ explicit BinaryAny(uno_Any const & raw) noexcept;
+ // takes over raw.pData (but copies raw.pType); raw must not be passed
+ // to uno_any_destruct
+
+ BinaryAny(BinaryAny const & other) noexcept;
+
+ BinaryAny(BinaryAny && other) noexcept;
+
+ ~BinaryAny() noexcept;
+
+ BinaryAny & operator =(BinaryAny const & other) noexcept;
+
+ BinaryAny & operator =(BinaryAny && other) noexcept;
+
+ uno_Any& get() noexcept { return data_; }
+
+ com::sun::star::uno::TypeDescription getType() const noexcept;
+
+ void * getValue(com::sun::star::uno::TypeDescription const & type) const
+ noexcept;
+
+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
+};
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/binaryurp/source/binaryurp.component b/binaryurp/source/binaryurp.component
new file mode 100644
index 000000000..b5b0f4da1
--- /dev/null
+++ b/binaryurp/source/binaryurp.component
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ -->
+
+<component loader="com.sun.star.loader.SharedLibrary" environment="@CPPU_ENV@"
+ xmlns="http://openoffice.org/2010/uno-components">
+ <implementation name="com.sun.star.comp.bridge.BridgeFactory"
+ constructor="com_sun_star_comp_bridge_BridgeFactory_get_implementation" single-instance="true">
+ <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..7d73d6dd7
--- /dev/null
+++ b/binaryurp/source/bridge.cxx
@@ -0,0 +1,1054 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <algorithm>
+#include <cassert>
+#include <cstddef>
+#include <limits>
+#include <memory>
+#include <utility>
+#include <vector>
+
+#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/mutex.hxx>
+#include <osl/thread.hxx>
+#include <rtl/byteseq.hxx>
+#include <rtl/random.h>
+#include <rtl/ref.hxx>
+#include <rtl/string.h>
+#include <rtl/ustring.hxx>
+#include <sal/log.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 {
+
+sal_Int32 random() {
+ sal_Int32 n;
+ rtlRandomPool pool = rtl_random_createPool();
+ rtl_random_getBytes(pool, &n, sizeof n);
+ rtl_random_destroyPool(pool);
+ return n;
+}
+
+OUString toString(css::uno::TypeDescription const & type) {
+ typelib_TypeDescription * d = type.get();
+ assert(d != nullptr && d->pTypeName != nullptr);
+ return OUString(d->pTypeName);
+}
+
+extern "C" void freeProxyCallback(
+ SAL_UNUSED_PARAMETER uno_ExtEnvironment *, void * pProxy)
+{
+ assert(pProxy != nullptr);
+ static_cast< Proxy * >(pProxy)->do_free();
+}
+
+bool isThread(salhelper::Thread * thread) {
+ assert(thread != nullptr);
+ return osl::Thread::getCurrentIdentifier() == thread->getIdentifier();
+}
+
+class AttachThread {
+public:
+ explicit AttachThread(uno_ThreadPool threadPool);
+
+ ~AttachThread();
+
+ const rtl::ByteSequence& getTid() const noexcept { return tid_;}
+
+private:
+ AttachThread(const AttachThread&) = delete;
+ AttachThread& operator=(const AttachThread&) = delete;
+
+ uno_ThreadPool threadPool_;
+ rtl::ByteSequence tid_;
+};
+
+AttachThread::AttachThread(uno_ThreadPool threadPool): threadPool_(threadPool) {
+ sal_Sequence * s = nullptr;
+ uno_getIdOfCurrentThread(&s);
+ tid_ = rtl::ByteSequence(s, rtl::BYTESEQ_NOACQUIRE);
+ uno_threadpool_attach(threadPool_);
+}
+
+AttachThread::~AttachThread() {
+ uno_threadpool_detach(threadPool_);
+ uno_releaseIdFromCurrentThread();
+}
+
+
+class PopOutgoingRequest {
+public:
+ PopOutgoingRequest(
+ OutgoingRequests & requests, rtl::ByteSequence tid,
+ OutgoingRequest const & request);
+
+ ~PopOutgoingRequest();
+
+ void clear();
+
+private:
+ PopOutgoingRequest(const PopOutgoingRequest&) = delete;
+ PopOutgoingRequest& operator=(const PopOutgoingRequest&) = delete;
+
+ OutgoingRequests & requests_;
+ rtl::ByteSequence tid_;
+ bool cleared_;
+};
+
+PopOutgoingRequest::PopOutgoingRequest(
+ OutgoingRequests & requests, rtl::ByteSequence tid,
+ OutgoingRequest const & request):
+ requests_(requests), tid_(std::move(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, OUString name,
+ css::uno::Reference< css::connection::XConnection > const & connection,
+ css::uno::Reference< css::bridge::XInstanceProvider > provider):
+ factory_(factory), name_(std::move(name)), connection_(connection),
+ provider_(std::move(provider)),
+ binaryUno_(UNO_LB_UNO),
+ cppToBinaryMapping_(CPPU_CURRENT_LANGUAGE_BINDING_NAME, UNO_LB_UNO),
+ binaryToCppMapping_(UNO_LB_UNO, CPPU_CURRENT_LANGUAGE_BINDING_NAME),
+ protPropTid_(
+ reinterpret_cast< sal_Int8 const * >(".UrpProtocolPropertiesTid"),
+ RTL_CONSTASCII_LENGTH(".UrpProtocolPropertiesTid")),
+ protPropOid_("UrpProtocolProperties"),
+ protPropType_(
+ cppu::UnoType<
+ css::uno::Reference< css::bridge::XProtocolProperties > >::get()),
+ protPropRequest_("com.sun.star.bridge.XProtocolProperties::requestChange"),
+ protPropCommit_("com.sun.star.bridge.XProtocolProperties::commitChange"),
+ state_(STATE_INITIAL), threadPool_(nullptr), currentContextMode_(false),
+ proxies_(0), calls_(0), normalCall_(false), activeCalls_(0),
+ mode_(MODE_REQUESTED)
+{
+ assert(factory.is() && connection.is());
+ if (!binaryUno_.is()) {
+ throw css::uno::RuntimeException("URP: no binary UNO environment");
+ }
+ if (!(cppToBinaryMapping_.is() && binaryToCppMapping_.is())) {
+ throw css::uno::RuntimeException("URP: no C++ UNO mapping");
+ }
+ passive_.set();
+ // coverity[uninit_member] - random_ is set in due course by the reader_ thread's state machine
+}
+
+void Bridge::start() {
+ rtl::Reference r(new Reader(this));
+ rtl::Reference w(new Writer(this));
+ {
+ std::lock_guard g(mutex_);
+ assert(
+ state_ == STATE_INITIAL && threadPool_ == nullptr && !writer_.is() &&
+ !reader_.is());
+ threadPool_ = uno_threadpool_create();
+ assert(threadPool_ != nullptr);
+ reader_ = r;
+ writer_ = w;
+ state_ = STATE_STARTED;
+ }
+ // It is important to call reader_->launch() last here; both
+ // Writer::execute and Reader::execute can call Bridge::terminate, but
+ // Writer::execute is initially blocked in unblocked_.wait() until
+ // Reader::execute has called bridge_->sendRequestChangeRequest(), so
+ // effectively only reader_->launch() can lead to an early call to
+ // Bridge::terminate
+ w->launch();
+ r->launch();
+}
+
+void Bridge::terminate(bool final) {
+ uno_ThreadPool tp;
+ // Make sure function-local variables (Stubs s, etc.) are destroyed before
+ // the final uno_threadpool_destroy/threadPool_ = 0:
+ {
+ rtl::Reference< Reader > r;
+ rtl::Reference< Writer > w;
+ bool joinW;
+ Listeners ls;
+ {
+ std::unique_lock g(mutex_);
+ switch (state_) {
+ case STATE_INITIAL: // via ~Bridge -> dispose -> terminate
+ case STATE_FINAL:
+ return;
+ case STATE_STARTED:
+ break;
+ case STATE_TERMINATED:
+ if (final) {
+ g.unlock();
+ terminated_.wait();
+ {
+ std::lock_guard g2(mutex_);
+ tp = threadPool_;
+ threadPool_ = nullptr;
+ if (reader_.is()) {
+ if (!isThread(reader_.get())) {
+ r = reader_;
+ }
+ reader_.clear();
+ }
+ if (writer_.is()) {
+ if (!isThread(writer_.get())) {
+ w = writer_;
+ }
+ writer_.clear();
+ }
+ state_ = STATE_FINAL;
+ }
+ assert(!(r.is() && w.is()));
+ if (r.is()) {
+ r->join();
+ } else if (w.is()) {
+ w->join();
+ }
+ if (tp != nullptr) {
+ uno_threadpool_destroy(tp);
+ }
+ }
+ return;
+ }
+ tp = threadPool_;
+ assert(!(final && isThread(reader_.get())));
+ if (!isThread(reader_.get())) {
+ std::swap(reader_, r);
+ }
+ w = writer_;
+ joinW = !isThread(writer_.get());
+ assert(!final || joinW);
+ if (joinW) {
+ writer_.clear();
+ }
+ ls.swap(listeners_);
+ state_ = final ? STATE_FINAL : STATE_TERMINATED;
+ }
+ try {
+ connection_->close();
+ } catch (const css::io::IOException & e) {
+ SAL_INFO("binaryurp", "caught IO exception '" << e << '\'');
+ }
+ assert(w.is());
+ w->stop();
+ if (r.is()) {
+ r->join();
+ }
+ if (joinW) {
+ w->join();
+ }
+ assert(tp != nullptr);
+ uno_threadpool_dispose(tp);
+ Stubs s;
+ {
+ std::lock_guard g(mutex_);
+ s.swap(stubs_);
+ }
+ for (auto & stub : s)
+ {
+ for (auto & item : stub.second)
+ {
+ SAL_INFO(
+ "binaryurp",
+ "stub '" << stub.first << "', '" << toString(item.first)
+ << "' still mapped at Bridge::terminate");
+ binaryUno_.get()->pExtEnv->revokeInterface(
+ binaryUno_.get()->pExtEnv, item.second.object.get());
+ }
+ }
+ factory_->removeBridge(this);
+ for (auto const& listener : ls)
+ {
+ try {
+ listener->disposing(
+ css::lang::EventObject(
+ static_cast< cppu::OWeakObject * >(this)));
+ } catch (const css::uno::RuntimeException & e) {
+ SAL_WARN("binaryurp", "caught " << e);
+ }
+ }
+ }
+ if (final) {
+ uno_threadpool_destroy(tp);
+ }
+ {
+ std::lock_guard g(mutex_);
+ if (final) {
+ threadPool_ = nullptr;
+ }
+ }
+ terminated_.set();
+}
+
+
+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() {
+ std::lock_guard g(mutex_);
+ checkDisposed();
+ assert(threadPool_ != nullptr);
+ return threadPool_;
+}
+
+rtl::Reference< Writer > Bridge::getWriter() {
+ std::lock_guard g(mutex_);
+ checkDisposed();
+ assert(writer_.is());
+ return writer_;
+}
+
+css::uno::UnoInterfaceReference Bridge::registerIncomingInterface(
+ OUString const & oid, css::uno::TypeDescription const & type)
+{
+ assert(type.is());
+ if (oid.isEmpty()) {
+ 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);
+ {
+ std::lock_guard g(mutex_);
+ 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;
+}
+
+OUString Bridge::registerOutgoingInterface(
+ css::uno::UnoInterfaceReference const & object,
+ css::uno::TypeDescription const & type)
+{
+ assert(type.is());
+ if (!object.is()) {
+ return OUString();
+ }
+ OUString oid;
+ if (!Proxy::isProxy(this, object, &oid)) {
+ binaryUno_.get()->pExtEnv->getObjectIdentifier(
+ binaryUno_.get()->pExtEnv, &oid.pData, object.get());
+ std::lock_guard 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->emplace(type, SubStub()).first;
+ if (stub == &newStub) {
+ i = stubs_.emplace(oid, Stub()).first;
+ std::swap(i->second, newStub);
+ j = i->second.find(type);
+ 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 {
+ assert(stub != &newStub);
+ if (j->second.references == SAL_MAX_UINT32) {
+ throw css::uno::RuntimeException(
+ "URP: stub reference count overflow");
+ }
+ ++j->second.references;
+ }
+ }
+ return oid;
+}
+
+css::uno::UnoInterfaceReference Bridge::findStub(
+ OUString const & oid, css::uno::TypeDescription const & type)
+{
+ assert(!oid.isEmpty() && type.is());
+ std::lock_guard 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 (auto const& item : i->second)
+ {
+ if (typelib_typedescription_isAssignableFrom(
+ type.get(), item.first.get()))
+ {
+ return item.second.object;
+ }
+ }
+ }
+ return css::uno::UnoInterfaceReference();
+}
+
+void Bridge::releaseStub(
+ OUString const & oid, css::uno::TypeDescription const & type)
+{
+ assert(!oid.isEmpty() && type.is());
+ css::uno::UnoInterfaceReference obj;
+ bool unused;
+ {
+ std::lock_guard g(mutex_);
+ Stubs::iterator i(stubs_.find(oid));
+ if (i == stubs_.end()) {
+ throw css::uno::RuntimeException("URP: release unknown stub");
+ }
+ Stub::iterator j(i->second.find(type));
+ if (j == i->second.end()) {
+ throw css::uno::RuntimeException("URP: release unknown stub");
+ }
+ 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()));
+ 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 (const css::uno::RuntimeException & e) {
+ SAL_INFO(
+ "binaryurp", "caught runtime exception '" << e << '\'');
+ } catch (const std::exception & e) {
+ SAL_WARN("binaryurp", "caught C++ exception '" << e.what() << '\'');
+ }
+ bool unused;
+ {
+ std::lock_guard g(mutex_);
+ assert(proxies_ > 0);
+ --proxies_;
+ unused = becameUnused();
+ }
+ terminateWhenUnused(unused);
+}
+
+void Bridge::incrementCalls(bool normalCall) noexcept {
+ std::lock_guard g(mutex_);
+ assert(calls_ < std::numeric_limits< std::size_t >::max());
+ ++calls_;
+ normalCall_ |= normalCall;
+}
+
+void Bridge::decrementCalls() {
+ bool unused;
+ {
+ std::lock_guard g(mutex_);
+ assert(calls_ > 0);
+ --calls_;
+ unused = becameUnused();
+ }
+ terminateWhenUnused(unused);
+}
+
+void Bridge::incrementActiveCalls() noexcept {
+ std::lock_guard g(mutex_);
+ assert(
+ activeCalls_ <= calls_ &&
+ activeCalls_ < std::numeric_limits< std::size_t >::max());
+ ++activeCalls_;
+ passive_.reset();
+}
+
+void Bridge::decrementActiveCalls() noexcept {
+ std::lock_guard g(mutex_);
+ assert(activeCalls_ <= calls_ && activeCalls_ > 0);
+ --activeCalls_;
+ if (activeCalls_ == 0) {
+ passive_.set();
+ }
+}
+
+bool Bridge::makeCall(
+ OUString const & oid, css::uno::TypeDescription const & member,
+ bool setter, std::vector< BinaryAny >&& inArguments,
+ BinaryAny * returnValue, std::vector< BinaryAny > * outArguments)
+{
+ std::unique_ptr< IncomingReply > resp;
+ {
+ uno_ThreadPool tp = getThreadPool();
+ AttachThread att(tp);
+ PopOutgoingRequest pop(
+ outgoingRequests_, att.getTid(),
+ OutgoingRequest(OutgoingRequest::KIND_NORMAL, member, setter));
+ sendRequest(
+ att.getTid(), oid, css::uno::TypeDescription(), member,
+ std::move(inArguments));
+ pop.clear();
+ incrementCalls(true);
+ incrementActiveCalls();
+ void * job;
+ uno_threadpool_enter(tp, &job);
+ resp.reset(static_cast< IncomingReply * >(job));
+ decrementActiveCalls();
+ decrementCalls();
+ }
+ if (resp == nullptr)
+ {
+ throw css::lang::DisposedException(
+ "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() {
+ assert(mode_ == MODE_REQUESTED);
+ random_ = random();
+ std::vector< BinaryAny > a;
+ a.emplace_back(
+ css::uno::TypeDescription(cppu::UnoType< sal_Int32 >::get()),
+ &random_);
+ sendProtPropRequest(OutgoingRequest::KIND_REQUEST_CHANGE, a);
+}
+
+void Bridge::handleRequestChangeReply(
+ bool exception, BinaryAny const & returnValue)
+{
+ try {
+ throwException(exception, returnValue);
+ } catch (css::uno::RuntimeException & e) {
+ // Before OOo 2.2, Java URP would throw a RuntimeException when
+ // receiving a requestChange message (see i#35277 "Java URP: Support
+ // Manipulation of Protocol Properties"):
+ if (mode_ != MODE_REQUESTED) {
+ throw;
+ }
+ SAL_WARN(
+ "binaryurp",
+ "requestChange caught " << e << " in state 'requested'");
+ mode_ = MODE_NORMAL;
+ getWriter()->unblock();
+ decrementCalls();
+ return;
+ }
+ 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:
+ assert(false); // this cannot happen
+ break;
+ }
+ if (n != exp) {
+ throw css::uno::RuntimeException(
+ "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:
+ assert(false); // this cannot happen
+ break;
+ }
+}
+
+void Bridge::handleCommitChangeReply(
+ bool exception, BinaryAny const & returnValue)
+{
+ bool bCcMode = true;
+ try {
+ throwException(exception, returnValue);
+ } catch (const css::bridge::InvalidProtocolChangeException &) {
+ bCcMode = false;
+ }
+ if (bCcMode) {
+ setCurrentContextMode();
+ }
+ 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)
+{
+ 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(
+ "URP: unexpected requestChange request received",
+ static_cast< cppu::OWeakObject * >(this));
+ }
+}
+
+void Bridge::handleCommitChangeRequest(
+ rtl::ByteSequence const & tid, std::vector< BinaryAny > const & inArguments)
+{
+ bool bCcMode = false;
+ bool bExc = false;
+ BinaryAny ret;
+ assert(inArguments.size() == 1);
+ css::uno::Sequence< css::bridge::ProtocolProperty > s;
+ [[maybe_unused]] bool ok = (mapBinaryToCppAny(inArguments[0]) >>= s);
+ assert(ok);
+ for (const auto & pp : std::as_const(s)) {
+ if (pp.Name == "CurrentContext") {
+ bCcMode = true;
+ } else {
+ bCcMode = false;
+ bExc = true;
+ ret = mapCppToBinaryAny(
+ css::uno::Any(
+ css::bridge::InvalidProtocolChangeException(
+ "InvalidProtocolChangeException",
+ css::uno::Reference< css::uno::XInterface >(), pp,
+ 1)));
+ break;
+ }
+ }
+ switch (mode_) {
+ case MODE_WAIT:
+ getWriter()->sendDirectReply(
+ tid, protPropCommit_, bExc, ret, std::vector< BinaryAny >());
+ if (bCcMode) {
+ 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 >(),
+ bCcMode);
+ mode_ = MODE_NORMAL;
+ break;
+ default:
+ throw css::uno::RuntimeException(
+ "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(
+ std::u16string_view oid, css::uno::TypeDescription const & type) const
+{
+ return oid == protPropOid_ && type.equals(protPropType_);
+}
+
+void Bridge::setCurrentContextMode() {
+ std::lock_guard g(mutex_);
+ currentContextMode_ = true;
+}
+
+bool Bridge::isCurrentContextMode() {
+ std::lock_guard g(mutex_);
+ return currentContextMode_;
+}
+
+Bridge::~Bridge() {
+#if OSL_DEBUG_LEVEL > 0
+ {
+ std::lock_guard g(mutex_);
+ SAL_WARN_IF(
+ state_ == STATE_STARTED || state_ == STATE_TERMINATED, "binaryurp",
+ "undisposed bridge \"" << name_ <<"\" in state " << state_
+ << ", potential deadlock ahead");
+ }
+#endif
+ dispose();
+}
+
+css::uno::Reference< css::uno::XInterface > Bridge::getInstance(
+ OUString const & sInstanceName)
+{
+ if (sInstanceName.isEmpty()) {
+ throw css::uno::RuntimeException(
+ "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::uno::RuntimeException(
+ "XBridge::getInstance sInstanceName contains non-ASCII"
+ " character");
+ }
+ }
+ css::uno::TypeDescription ifc(cppu::UnoType<css::uno::XInterface>::get());
+ typelib_TypeDescription * p = ifc.get();
+ std::vector< BinaryAny > inArgs;
+ inArgs.emplace_back(
+ css::uno::TypeDescription(cppu::UnoType< css::uno::Type >::get()),
+ &p);
+ BinaryAny ret;
+ std::vector< BinaryAny> outArgs;
+ bool bExc = makeCall(
+ sInstanceName,
+ css::uno::TypeDescription(
+ "com.sun.star.uno.XInterface::queryInterface"),
+ false, std::move(inArgs), &ret, &outArgs);
+ throwException(bExc, ret);
+ auto const t = ret.getType();
+ if (t.get()->eTypeClass == typelib_TypeClass_VOID) {
+ return {};
+ }
+ if (!t.equals(ifc)) {
+ throw css::uno::RuntimeException(
+ "initial object queryInterface for OID \"" + sInstanceName + "\" returned ANY of type "
+ + OUString::unacquired(&t.get()->pTypeName));
+ }
+ auto const val = *static_cast< uno_Interface ** >(ret.getValue(ifc));
+ if (val == nullptr) {
+ throw css::uno::RuntimeException(
+ "initial object queryInterface for OID \"" + sInstanceName
+ + "\" returned null css.uno.XInterface ANY");
+ }
+ return css::uno::Reference< css::uno::XInterface >(
+ static_cast< css::uno::XInterface * >(
+ binaryToCppMapping_.mapInterface(
+ val,
+ ifc.get())),
+ SAL_NO_ACQUIRE);
+}
+
+OUString Bridge::getName() {
+ return name_;
+}
+
+OUString Bridge::getDescription() {
+ OUString b = name_ + ":" + connection_->getDescription();
+ return b;
+}
+
+void Bridge::dispose() {
+ // For terminate(true) not to deadlock, an external protocol must ensure
+ // that dispose is not called from a thread pool worker thread (that dispose
+ // is never called from the reader or writer thread is already ensured
+ // internally):
+ terminate(true);
+ // 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)
+{
+ assert(xListener.is());
+ {
+ std::lock_guard g(mutex_);
+ assert(state_ != STATE_INITIAL);
+ if (state_ == STATE_STARTED) {
+ 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)
+{
+ std::lock_guard g(mutex_);
+ Listeners::iterator i(
+ std::find(listeners_.begin(), listeners_.end(), aListener));
+ if (i != listeners_.end()) {
+ listeners_.erase(i);
+ }
+}
+
+void Bridge::sendCommitChangeRequest() {
+ assert(mode_ == MODE_REQUESTED || mode_ == MODE_REPLY_1);
+ css::uno::Sequence< css::bridge::ProtocolProperty > s(1);
+ s.getArray()[0].Name = "CurrentContext";
+ std::vector< BinaryAny > a { mapCppToBinaryAny(css::uno::Any(s)) };
+ sendProtPropRequest(OutgoingRequest::KIND_COMMIT_CHANGE, a);
+}
+
+void Bridge::sendProtPropRequest(
+ OutgoingRequest::Kind kind, std::vector< BinaryAny > const & inArguments)
+{
+ 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(
+ OUString const & oid, css::uno::TypeDescription const & type)
+{
+ //HACK to decouple the processing of release calls from all other threads. Normally, sending
+ // the release request should use the current thread's TID (via AttachThread), which would cause
+ // that asynchronous request to be processed by a physical thread that is paired with the
+ // physical thread processing the normal synchronous call stack (see ThreadIdHashMap in
+ // cppu/source/threadpool/threadpool.hxx). However, that can lead to deadlock when a thread
+ // illegally makes a synchronous UNO call with the SolarMutex locked (e.g.,
+ // SfxBaseModel::postEvent_Impl in sfx2/source/doc/sfxbasemodel.cxx doing documentEventOccurred
+ // and notifyEvent calls), and while that call is on the stack the remote side sends back some
+ // release request on the same logical UNO thread for an object that wants to acquire the
+ // SolarMutex in its destructor (e.g., SwXTextDocument in sw/inc/unotxdoc.hxx holding its
+ // m_pImpl via an sw::UnoImplPtr). While the correct approach would be to not make UNO calls
+ // with the SolarMutex (or any other mutex) locked, fixing that would probably be a heroic
+ // effort. So for now live with this hack, hoping that it does not introduce any new issues of
+ // its own:
+ static auto const tid = [] {
+ static sal_Int8 const id[] = {'r', 'e', 'l', 'e', 'a', 's', 'e', 'h', 'a', 'c', 'k'};
+ return rtl::ByteSequence(id, std::size(id));
+ }();
+ sendRequest(
+ tid, oid, type,
+ css::uno::TypeDescription("com.sun.star.uno.XInterface::release"),
+ std::vector< BinaryAny >());
+}
+
+void Bridge::sendRequest(
+ rtl::ByteSequence const & tid, OUString const & oid,
+ css::uno::TypeDescription const & type,
+ css::uno::TypeDescription const & member,
+ std::vector< BinaryAny >&& inArguments)
+{
+ getWriter()->queueRequest(tid, oid, type, member, std::move(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(false);
+ }
+}
+
+void Bridge::checkDisposed() {
+ assert(state_ != STATE_INITIAL);
+ if (state_ != STATE_STARTED) {
+ throw css::lang::DisposedException(
+ "Binary URP bridge already disposed",
+ static_cast< cppu::OWeakObject * >(this));
+ }
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/binaryurp/source/bridge.hxx b/binaryurp/source/bridge.hxx
new file mode 100644
index 000000000..9da6640fa
--- /dev/null
+++ b/binaryurp/source/bridge.hxx
@@ -0,0 +1,281 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <cstddef>
+#include <map>
+#include <mutex>
+#include <vector>
+
+#include <com/sun/star/bridge/XBridge.hpp>
+#include <com/sun/star/lang/XComponent.hpp>
+#include <com/sun/star/uno/Reference.hxx>
+#include <cppuhelper/implbase.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::sun::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::WeakImplHelper<
+ com::sun::star::bridge::XBridge, com::sun::star::lang::XComponent >
+{
+public:
+ Bridge(
+ rtl::Reference< BridgeFactory > const & factory,
+ OUString name,
+ com::sun::star::uno::Reference<
+ com::sun::star::connection::XConnection > const & connection,
+ com::sun::star::uno::Reference<
+ com::sun::star::bridge::XInstanceProvider > provider);
+
+ void start();
+
+ // Internally waits for all incoming and outgoing remote calls to terminate,
+ // so must not be called from within such a call; when final is true, also
+ // joins all remaining threads (reader, writer, and worker threads from the
+ // thread pool), so must not be called with final set to true from such a
+ // thread:
+ void terminate(bool final);
+
+ const com::sun::star::uno::Reference< com::sun::star::connection::XConnection >&
+ getConnection() const { return connection_;}
+
+ const com::sun::star::uno::Reference< com::sun::star::bridge::XInstanceProvider >&
+ getProvider() const { return provider_;}
+
+ com::sun::star::uno::Mapping & getCppToBinaryMapping() { return cppToBinaryMapping_;}
+
+ BinaryAny mapCppToBinaryAny(com::sun::star::uno::Any const & cppAny);
+
+ uno_ThreadPool getThreadPool();
+
+ rtl::Reference< Writer > getWriter();
+
+ com::sun::star::uno::UnoInterfaceReference registerIncomingInterface(
+ OUString const & oid,
+ com::sun::star::uno::TypeDescription const & type);
+
+ OUString registerOutgoingInterface(
+ com::sun::star::uno::UnoInterfaceReference const & object,
+ com::sun::star::uno::TypeDescription const & type);
+
+ com::sun::star::uno::UnoInterfaceReference findStub(
+ OUString const & oid,
+ com::sun::star::uno::TypeDescription const & type);
+
+ void releaseStub(
+ 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) noexcept;
+
+ void decrementCalls();
+
+ void incrementActiveCalls() noexcept;
+
+ void decrementActiveCalls() noexcept;
+
+ bool makeCall(
+ OUString const & oid,
+ com::sun::star::uno::TypeDescription const & member, bool setter,
+ std::vector< BinaryAny >&& 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(
+ std::u16string_view oid,
+ com::sun::star::uno::TypeDescription const & type) const;
+
+ void setCurrentContextMode();
+
+ bool isCurrentContextMode();
+
+private:
+ Bridge(const Bridge&) = delete;
+ Bridge& operator=(const Bridge&) = delete;
+
+ virtual ~Bridge() override;
+
+ virtual com::sun::star::uno::Reference< com::sun::star::uno::XInterface >
+ SAL_CALL getInstance(OUString const & sInstanceName) override;
+
+ virtual OUString SAL_CALL getName() override;
+
+ virtual OUString SAL_CALL getDescription() override;
+
+ virtual void SAL_CALL dispose() override;
+
+ virtual void SAL_CALL addEventListener(
+ com::sun::star::uno::Reference< com::sun::star::lang::XEventListener >
+ const & xListener) override;
+
+ virtual void SAL_CALL removeEventListener(
+ com::sun::star::uno::Reference< com::sun::star::lang::XEventListener >
+ const & aListener) override;
+
+ // Only called from reader_ thread:
+ void sendCommitChangeRequest();
+
+ // Only called from reader_ thread:
+ void sendProtPropRequest(
+ OutgoingRequest::Kind kind,
+ std::vector< BinaryAny > const & inArguments);
+
+ void makeReleaseCall(
+ OUString const & oid,
+ com::sun::star::uno::TypeDescription const & type);
+
+ void sendRequest(
+ rtl::ByteSequence const & tid, OUString const & oid,
+ com::sun::star::uno::TypeDescription const & type,
+ com::sun::star::uno::TypeDescription const & member,
+ std::vector< BinaryAny >&& inArguments);
+
+ void throwException(bool exception, BinaryAny const & value);
+
+ com::sun::star::uno::Any mapBinaryToCppAny(BinaryAny const & binaryAny);
+
+ bool becameUnused() const;
+
+ void terminateWhenUnused(bool unused);
+
+ // Must only be called with mutex_ locked:
+ void checkDisposed();
+
+ typedef
+ std::vector<
+ 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< OUString, Stub > Stubs;
+
+ enum State { STATE_INITIAL, STATE_STARTED, STATE_TERMINATED, STATE_FINAL };
+
+ enum Mode {
+ MODE_REQUESTED, MODE_REPLY_MINUS1, MODE_REPLY_0, MODE_REPLY_1,
+ MODE_WAIT, MODE_NORMAL, MODE_NORMAL_WAIT };
+
+ rtl::Reference< BridgeFactory > factory_;
+ 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_;
+ OUString protPropOid_;
+ com::sun::star::uno::TypeDescription protPropType_;
+ com::sun::star::uno::TypeDescription protPropRequest_;
+ com::sun::star::uno::TypeDescription protPropCommit_;
+ OutgoingRequests outgoingRequests_;
+ 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
+ osl::Condition terminated_;
+
+ std::mutex mutex_;
+ State state_;
+ Listeners listeners_;
+ uno_ThreadPool threadPool_;
+ 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_;
+
+ // Only accessed from reader_ thread:
+ Mode mode_;
+ sal_Int32 random_;
+};
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/binaryurp/source/bridgefactory.cxx b/binaryurp/source/bridgefactory.cxx
new file mode 100644
index 000000000..a2dd1fa97
--- /dev/null
+++ b/binaryurp/source/bridgefactory.cxx
@@ -0,0 +1,192 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <algorithm>
+#include <cassert>
+
+#include <com/sun/star/bridge/BridgeExistsException.hpp>
+#include <com/sun/star/connection/XConnection.hpp>
+#include <com/sun/star/lang/IllegalArgumentException.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/supportsservice.hxx>
+#include <o3tl/safeint.hxx>
+#include <rtl/ref.hxx>
+#include <sal/log.hxx>
+#include <sal/types.h>
+
+#include "bridge.hxx"
+#include "bridgefactory.hxx"
+
+namespace binaryurp {
+
+void BridgeFactory::removeBridge(
+ css::uno::Reference< css::bridge::XBridge > const & bridge)
+{
+ assert(bridge.is());
+ OUString n(bridge->getName());
+ osl::MutexGuard g(m_aMutex);
+ if (n.isEmpty())
+ {
+ unnamed_.erase(std::remove(unnamed_.begin(), unnamed_.end(), bridge), unnamed_.end());
+ }
+ else
+ {
+ BridgeMap::iterator i(named_.find(n));
+ if (i != named_.end() && i->second == bridge)
+ named_.erase(i);
+ }
+}
+
+BridgeFactory::BridgeFactory():
+ BridgeFactoryBase(m_aMutex)
+{
+}
+
+BridgeFactory::~BridgeFactory() {}
+
+OUString BridgeFactory::getImplementationName()
+{
+ return "com.sun.star.comp.bridge.BridgeFactory";
+}
+
+sal_Bool BridgeFactory::supportsService(OUString const & ServiceName)
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+css::uno::Sequence< OUString > BridgeFactory::getSupportedServiceNames()
+{
+ return { "com.sun.star.bridge.BridgeFactory" };
+}
+
+css::uno::Reference< css::bridge::XBridge > BridgeFactory::createBridge(
+ OUString const & sName, OUString const & sProtocol,
+ css::uno::Reference< css::connection::XConnection > const & aConnection,
+ css::uno::Reference< css::bridge::XInstanceProvider > const &
+ anInstanceProvider)
+{
+ rtl::Reference< Bridge > b;
+ {
+ osl::MutexGuard g(m_aMutex);
+ if (rBHelper.bDisposed) {
+ throw css::lang::DisposedException(
+ "BridgeFactory disposed",
+ static_cast< cppu::OWeakObject * >(this));
+ }
+ if (named_.find(sName) != named_.end()) {
+ throw css::bridge::BridgeExistsException(
+ sName, static_cast< cppu::OWeakObject * >(this));
+ }
+ if (sProtocol != "urp" || !aConnection.is()) {
+ throw css::lang::IllegalArgumentException(
+ ("BridgeFactory::createBridge: sProtocol != urp ||"
+ " aConnection == null"),
+ static_cast< cppu::OWeakObject * >(this), -1);
+ }
+ b.set(new Bridge(this, sName, aConnection, anInstanceProvider));
+ if (sName.isEmpty()) {
+ unnamed_.emplace_back(b.get());
+ } else {
+ named_[sName] = b.get();
+ }
+ }
+ b->start();
+ return b;
+}
+
+css::uno::Reference< css::bridge::XBridge > BridgeFactory::getBridge(
+ OUString const & sName)
+{
+ osl::MutexGuard g(m_aMutex);
+ 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() {
+ osl::MutexGuard g(m_aMutex);
+ if (unnamed_.size() > SAL_MAX_INT32) {
+ throw css::uno::RuntimeException(
+ "BridgeFactory::getExistingBridges: too many",
+ static_cast< cppu::OWeakObject * >(this));
+ }
+ sal_Int32 n = static_cast< sal_Int32 >(unnamed_.size());
+ if (named_.size() > o3tl::make_unsigned(SAL_MAX_INT32 - n)) {
+ throw css::uno::RuntimeException(
+ "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);
+ auto r = asNonConstRange(s);
+ sal_Int32 i = 0;
+ for (auto const& item : unnamed_)
+ r[i++] = item;
+
+ for (auto const& item : named_)
+ r[i++] = item.second;
+
+ return s;
+}
+
+void BridgeFactory::disposing() {
+ BridgeVector l1;
+ BridgeMap l2;
+ {
+ osl::MutexGuard g(m_aMutex);
+ l1.swap(unnamed_);
+ l2.swap(named_);
+ }
+ for (auto const& item : l1)
+ {
+ try {
+ css::uno::Reference<css::lang::XComponent>(
+ item, css::uno::UNO_QUERY_THROW)->dispose();
+ } catch (css::uno::Exception & e) {
+ SAL_WARN("binaryurp", "ignoring " << e);
+ }
+ }
+ for (auto const& item : l2)
+ {
+ try {
+ css::uno::Reference<css::lang::XComponent>(
+ item.second, css::uno::UNO_QUERY_THROW)->dispose();
+ } catch (css::uno::Exception & e) {
+ SAL_WARN("binaryurp", "ignoring " << e);
+ }
+ }
+}
+
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_bridge_BridgeFactory_get_implementation(
+ css::uno::XComponentContext* , css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new binaryurp::BridgeFactory);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/binaryurp/source/bridgefactory.hxx b/binaryurp/source/bridgefactory.hxx
new file mode 100644
index 000000000..590238960
--- /dev/null
+++ b/binaryurp/source/bridgefactory.hxx
@@ -0,0 +1,115 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <vector>
+#include <map>
+
+#include <com/sun/star/bridge/XBridgeFactory2.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/uno/Reference.hxx>
+#include <cppuhelper/basemutex.hxx>
+#include <cppuhelper/compbase.hxx>
+#include <sal/types.h>
+
+namespace com::sun::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::WeakComponentImplHelper<
+ com::sun::star::lang::XServiceInfo,
+ com::sun::star::bridge::XBridgeFactory2 >
+ BridgeFactoryBase;
+
+class BridgeFactory : private cppu::BaseMutex, public BridgeFactoryBase
+{
+public:
+ void removeBridge(
+ com::sun::star::uno::Reference< com::sun::star::bridge::XBridge >
+ const & bridge);
+
+ using BridgeFactoryBase::acquire;
+ using BridgeFactoryBase::release;
+
+ BridgeFactory(const BridgeFactory&) = delete;
+ BridgeFactory& operator=(const BridgeFactory&) = delete;
+
+ BridgeFactory();
+
+ virtual ~BridgeFactory() override;
+
+private:
+ virtual OUString SAL_CALL getImplementationName() override;
+
+ virtual sal_Bool SAL_CALL supportsService(OUString const & ServiceName) override;
+
+ virtual com::sun::star::uno::Sequence< OUString > SAL_CALL
+ getSupportedServiceNames() override;
+
+ virtual com::sun::star::uno::Reference< com::sun::star::bridge::XBridge >
+ SAL_CALL createBridge(
+ OUString const & sName, 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) override;
+
+ virtual com::sun::star::uno::Reference< com::sun::star::bridge::XBridge >
+ SAL_CALL getBridge(
+ OUString const & sName) override;
+
+ virtual
+ com::sun::star::uno::Sequence<
+ com::sun::star::uno::Reference< com::sun::star::bridge::XBridge > >
+ SAL_CALL getExistingBridges() override;
+
+ void SAL_CALL disposing() override;
+
+ typedef
+ std::vector<
+ com::sun::star::uno::Reference< com::sun::star::bridge::XBridge > >
+ BridgeVector;
+
+ typedef
+ std::map<
+ OUString,
+ com::sun::star::uno::Reference< com::sun::star::bridge::XBridge > >
+ BridgeMap;
+
+ BridgeVector unnamed_;
+ BridgeMap named_;
+};
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/binaryurp/source/cache.hxx b/binaryurp/source/cache.hxx
new file mode 100644
index 000000000..bd8648efd
--- /dev/null
+++ b/binaryurp/source/cache.hxx
@@ -0,0 +1,95 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <cassert>
+#include <cstddef>
+#include <map>
+#include <list>
+
+#include <sal/types.h>
+
+namespace binaryurp {
+
+namespace cache {
+
+enum { size = 256, ignore = 0xFFFF };
+
+}
+
+template< typename T > class Cache {
+public:
+ typedef sal_uInt16 IdxType;
+
+ explicit Cache(std::size_t size):
+ size_(size)
+ {
+ assert(size < cache::ignore);
+ }
+
+ IdxType add( const T& rContent, bool* pbFound) {
+ assert( pbFound != nullptr);
+ if( !size_) {
+ *pbFound = false;
+ return cache::ignore;
+ }
+ // try to insert into the map
+ list_.push_front( rContent); // create a temp entry
+ auto const [it, inserted] = map_.emplace( list_.begin(), 0 );
+ *pbFound = !inserted;
+
+ if( !inserted) { // insertion not needed => found the entry
+ list_.pop_front(); // remove the temp entry
+ list_.splice( list_.begin(), list_, it->first); // the found entry is moved to front
+ return it->second;
+ }
+
+ // test insertion successful => it was new so we keep it
+ IdxType n = static_cast<IdxType>( map_.size() - 1);
+ if( n >= size_) { // cache full => replace the LRU entry
+ // find the least recently used element in the map
+ typename LruItMap::iterator lru = map_.find( --list_.end());
+ n = lru->second;
+ map_.erase( lru); // remove it from the map
+ list_.pop_back(); // remove from the list
+ }
+ it->second = n;
+ return n;
+ }
+
+private:
+ Cache(const Cache&) = delete;
+ Cache& operator=(const Cache&) = delete;
+
+ typedef std::list<T> LruList; // last recently used list
+ typedef typename LruList::iterator LruListIt;
+ struct CmpT{ bool operator()( const LruListIt& rA, const LruListIt& rB) const { return (*rA<*rB);}};
+ typedef std::map< LruListIt, IdxType, CmpT > LruItMap; // a map into a LruList
+
+ std::size_t size_;
+ LruItMap map_;
+ LruList list_;
+};
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/binaryurp/source/currentcontext.cxx b/binaryurp/source/currentcontext.cxx
new file mode 100644
index 000000000..acaf606d2
--- /dev/null
+++ b/binaryurp/source/currentcontext.cxx
@@ -0,0 +1,55 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <com/sun/star/uno/RuntimeException.hpp>
+#include <rtl/ustring.hxx>
+#include <uno/current_context.h>
+#include <uno/dispatcher.hxx>
+#include <uno/lbnames.h>
+
+#include "currentcontext.hxx"
+
+namespace binaryurp::current_context {
+
+css::uno::UnoInterfaceReference get() {
+ css::uno::UnoInterfaceReference cc;
+ if (!uno_getCurrentContext(
+ reinterpret_cast< void ** >(&cc.m_pUnoI),
+ OUString(UNO_LB_UNO).pData, nullptr))
+ {
+ throw css::uno::RuntimeException("uno_getCurrentContext failed");
+ }
+ return cc;
+}
+
+void set(css::uno::UnoInterfaceReference const & value) {
+ css::uno::UnoInterfaceReference cc(value);
+ if (!uno_setCurrentContext(
+ cc.m_pUnoI,
+ OUString(UNO_LB_UNO).pData, nullptr))
+ {
+ throw css::uno::RuntimeException("uno_setCurrentContext failed");
+ }
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/binaryurp/source/currentcontext.hxx b/binaryurp/source/currentcontext.hxx
new file mode 100644
index 000000000..b5f55a824
--- /dev/null
+++ b/binaryurp/source/currentcontext.hxx
@@ -0,0 +1,36 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+namespace com::sun::star::uno
+{
+class UnoInterfaceReference;
+}
+
+namespace binaryurp::current_context
+{
+com::sun::star::uno::UnoInterfaceReference get();
+
+void set(com::sun::star::uno::UnoInterfaceReference const& value);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/binaryurp/source/incomingreply.hxx b/binaryurp/source/incomingreply.hxx
new file mode 100644
index 000000000..c2f5353ff
--- /dev/null
+++ b/binaryurp/source/incomingreply.hxx
@@ -0,0 +1,52 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <utility>
+#include <vector>
+
+#include "binaryany.hxx"
+
+namespace binaryurp {
+
+struct IncomingReply {
+private:
+ IncomingReply(const IncomingReply&) = delete;
+ IncomingReply& operator=(const IncomingReply&) = delete;
+public:
+ IncomingReply(
+ bool theException, BinaryAny theReturnValue,
+ std::vector< BinaryAny >&& theOutArguments):
+ exception(theException), returnValue(std::move(theReturnValue)),
+ outArguments(std::move(theOutArguments))
+ {}
+
+ bool exception;
+
+ BinaryAny returnValue;
+
+ std::vector< BinaryAny > outArguments;
+};
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/binaryurp/source/incomingrequest.cxx b/binaryurp/source/incomingrequest.cxx
new file mode 100644
index 000000000..6f4107693
--- /dev/null
+++ b/binaryurp/source/incomingrequest.cxx
@@ -0,0 +1,286 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <cassert>
+#include <utility>
+#include <vector>
+
+#include <com/sun/star/bridge/XInstanceProvider.hpp>
+#include <com/sun/star/container/NoSuchElementException.hpp>
+#include <cppuhelper/exc_hlp.hxx>
+#include <o3tl/runtimetooustring.hxx>
+#include <rtl/byteseq.hxx>
+#include <rtl/ref.hxx>
+#include <rtl/ustring.hxx>
+#include <sal/log.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 {
+
+IncomingRequest::IncomingRequest(
+ rtl::Reference< Bridge > const & bridge, rtl::ByteSequence tid,
+ OUString oid, css::uno::UnoInterfaceReference object,
+ css::uno::TypeDescription type, sal_uInt16 functionId,
+ bool synchronous, css::uno::TypeDescription const & member, bool setter,
+ std::vector< BinaryAny >&& inArguments, bool currentContextMode,
+ css::uno::UnoInterfaceReference currentContext):
+ bridge_(bridge), tid_(std::move(tid)), oid_(std::move(oid)), object_(std::move(object)), type_(std::move(type)),
+ member_(member), currentContext_(std::move(currentContext)),
+ inArguments_(std::move(inArguments)), functionId_(functionId),
+ synchronous_(synchronous), setter_(setter), currentContextMode_(currentContextMode)
+{
+ assert(bridge.is());
+ assert(member.is());
+ assert(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 (const std::exception & e) {
+ throw css::uno::RuntimeException(
+ "caught C++ exception: "
+ + o3tl::runtimeToOUString(e.what()));
+ }
+ } catch (const css::uno::RuntimeException &) {
+ css::uno::Any exc(cppu::getCaughtException());
+ ret = bridge_->mapCppToBinaryAny(exc);
+ isExc = true;
+ }
+ if (resetCc) {
+ current_context::set(oldCc);
+ }
+ } catch (const 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, std::move(outArgs), false);
+ return;
+ } catch (const css::uno::RuntimeException & e) {
+ SAL_INFO("binaryurp", "caught " << e);
+ } catch (const std::exception & e) {
+ SAL_INFO("binaryurp", "caught C++ exception " << e.what());
+ }
+ bridge_->terminate(false);
+ } else {
+ if (isExc) {
+ SAL_INFO("binaryurp", "oneway method raised exception");
+ }
+ bridge_->decrementCalls();
+ }
+}
+
+static size_t size_t_round(size_t val)
+{
+ return (val + (sizeof(size_t)-1)) & ~(sizeof(size_t)-1);
+}
+
+bool IncomingRequest::execute_throw(
+ BinaryAny * returnValue, std::vector< BinaryAny > * outArguments) const
+{
+ assert(returnValue != nullptr);
+ assert(
+ returnValue->getType().equals(
+ css::uno::TypeDescription(cppu::UnoType<void>::get())));
+ assert(outArguments != nullptr);
+ assert(outArguments->empty());
+ bool isExc = false;
+ switch (functionId_) {
+ case SPECIAL_FUNCTION_ID_RESERVED:
+ 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 (const css::container::NoSuchElementException & e) {
+ SAL_INFO("binaryurp", "initial element " << oid_ << ": " << e);
+ }
+ }
+ 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;
+ }
+ [[fallthrough]];
+ default:
+ {
+ assert(object_.is());
+ css::uno::TypeDescription retType;
+ std::vector< 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_) {
+ assert(inArguments_.size() == 1);
+ args.push_back(inArguments_[0].getValue(t));
+ } else {
+ 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.emplace_back(size_t_round(
+ css::uno::TypeDescription(
+ mtd->pParams[j].pTypeRef).
+ get()->nSize));
+ p = outBufs.back().data();
+ }
+ args.push_back(p);
+ if (mtd->pParams[j].bOut) {
+ outArguments->push_back(BinaryAny());
+ }
+ }
+ assert(i == inArguments_.end());
+ break;
+ }
+ default:
+ assert(false); // this cannot happen
+ break;
+ }
+ size_t nSize = 0;
+ if (retType.is())
+ nSize = size_t_round(retType.get()->nSize);
+ std::vector< char > retBuf(nSize);
+ uno_Any exc;
+ uno_Any * pexc = &exc;
+ (*object_.get()->pDispatcher)(
+ object_.get(), member_.get(), retBuf.empty() ? nullptr : retBuf.data(),
+ args.empty() ? nullptr : args.data(), &pexc);
+ isExc = pexc != nullptr;
+ if (isExc) {
+ *returnValue = BinaryAny(
+ css::uno::TypeDescription(
+ cppu::UnoType< css::uno::Any >::get()),
+ &exc);
+ uno_any_destruct(&exc, nullptr);
+ } else {
+ if (!retBuf.empty()) {
+ *returnValue = BinaryAny(retType, retBuf.data());
+ uno_destructData(retBuf.data(), retType.get(), nullptr);
+ }
+ if (!outArguments->empty()) {
+ 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::vector< 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++)->data(), mtd->pParams[k].pTypeRef, nullptr);
+ }
+ }
+ assert(i == outArguments->end());
+ assert(j == outBufs.end());
+ }
+ }
+ break;
+ }
+ }
+ return !isExc;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/binaryurp/source/incomingrequest.hxx b/binaryurp/source/incomingrequest.hxx
new file mode 100644
index 000000000..faff4f5a5
--- /dev/null
+++ b/binaryurp/source/incomingrequest.hxx
@@ -0,0 +1,79 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <vector>
+
+#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:
+ IncomingRequest(const IncomingRequest&) = delete;
+ IncomingRequest& operator=(const IncomingRequest&) = delete;
+public:
+ IncomingRequest(
+ rtl::Reference< Bridge > const & bridge, rtl::ByteSequence tid,
+ OUString oid,
+ com::sun::star::uno::UnoInterfaceReference object,
+ com::sun::star::uno::TypeDescription type,
+ sal_uInt16 functionId, bool synchronous,
+ com::sun::star::uno::TypeDescription const & member, bool setter,
+ std::vector< BinaryAny >&& inArguments, bool currentContextMode,
+ com::sun::star::uno::UnoInterfaceReference currentContext);
+
+ ~IncomingRequest();
+
+ void execute() const;
+
+private:
+ bool execute_throw(
+ BinaryAny * returnValue, std::vector< BinaryAny > * outArguments) const;
+
+ rtl::Reference< Bridge > bridge_;
+ rtl::ByteSequence tid_;
+ OUString oid_; // initial object queryInterface; release
+ com::sun::star::uno::UnoInterfaceReference object_;
+ com::sun::star::uno::TypeDescription type_;
+ com::sun::star::uno::TypeDescription member_;
+ com::sun::star::uno::UnoInterfaceReference currentContext_;
+ std::vector< BinaryAny > inArguments_;
+ sal_uInt16 functionId_;
+ bool synchronous_;
+ bool setter_;
+ bool currentContextMode_;
+};
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/binaryurp/source/lessoperators.cxx b/binaryurp/source/lessoperators.cxx
new file mode 100644
index 000000000..acab81175
--- /dev/null
+++ b/binaryurp/source/lessoperators.cxx
@@ -0,0 +1,65 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <algorithm>
+#include <cassert>
+
+#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::sun::star::uno {
+
+bool operator <(TypeDescription const & left, TypeDescription const & right) {
+ assert(left.is() && right.is());
+ typelib_TypeClass tc1 = left.get()->eTypeClass;
+ typelib_TypeClass tc2 = right.get()->eTypeClass;
+ return tc1 < tc2 ||
+ (tc1 == tc2 &&
+ (OUString::unacquired(&left.get()->pTypeName) <
+ OUString::unacquired(&right.get()->pTypeName)));
+}
+
+}
+
+namespace rtl {
+
+bool operator <(ByteSequence const & left, ByteSequence const & right) {
+ const sal_Int32 nLen = std::min( left.getLength(), right.getLength());
+ for( sal_Int32 i = 0; i < nLen; ++i )
+ {
+ if (left[i] < right[i]) {
+ return true;
+ }
+ if (right[i] < left[i]) {
+ return false;
+ }
+ }
+ return left.getLength() < right.getLength();
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/binaryurp/source/lessoperators.hxx b/binaryurp/source/lessoperators.hxx
new file mode 100644
index 000000000..306710de6
--- /dev/null
+++ b/binaryurp/source/lessoperators.hxx
@@ -0,0 +1,39 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+namespace com::sun::star::uno { class TypeDescription; }
+namespace rtl { class ByteSequence; }
+
+namespace com::sun::star::uno {
+
+bool operator <(TypeDescription const & left, TypeDescription const & right);
+
+}
+
+namespace rtl {
+
+bool operator <(ByteSequence const & left, ByteSequence const & right);
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/binaryurp/source/marshal.cxx b/binaryurp/source/marshal.cxx
new file mode 100644
index 000000000..7d60cbf4d
--- /dev/null
+++ b/binaryurp/source/marshal.cxx
@@ -0,0 +1,300 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <cassert>
+#include <vector>
+
+#include <com/sun/star/uno/RuntimeException.hpp>
+#include <com/sun/star/uno/Sequence.hxx>
+#include <cppu/unotype.hxx>
+#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 {
+
+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, OUString const & value)
+{
+ assert(buffer != nullptr);
+ OString v;
+ if (!value.convertToString(
+ &v, RTL_TEXTENCODING_UTF8,
+ (RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR |
+ RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR)))
+ {
+ throw css::uno::RuntimeException(
+ "UNO string contains invalid UTF-16 sequence");
+ }
+ 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)
+{
+ assert(bridge.is());
+}
+
+Marshal::~Marshal() {}
+
+void Marshal::write8(std::vector< unsigned char > * buffer, sal_uInt8 value) {
+ assert(buffer != nullptr);
+ 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)
+{
+ 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();
+ 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, OUString(value.get()->pTypeName));
+ }
+ }
+}
+
+void Marshal::writeOid(
+ std::vector< unsigned char > * buffer, OUString const & oid)
+{
+ bool found;
+ sal_uInt16 idx;
+ if ( oid.isEmpty() ) {
+ 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)
+{
+ assert(buffer != nullptr && type.is());
+ type.makeComplete();
+ switch (type.get()->eTypeClass) {
+ case typelib_TypeClass_VOID:
+ break;
+ case typelib_TypeClass_BOOLEAN:
+ assert(*static_cast< sal_uInt8 const * >(value) <= 1);
+ [[fallthrough]];
+ 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,
+ 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);
+ 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:
+ assert(false); // this cannot happen
+ break;
+ }
+}
+
+void Marshal::writeMemberValues(
+ std::vector< unsigned char > * buffer,
+ css::uno::TypeDescription const & type, void const * aggregateValue)
+{
+ assert(
+ type.is() &&
+ (type.get()->eTypeClass == typelib_TypeClass_STRUCT ||
+ type.get()->eTypeClass == typelib_TypeClass_EXCEPTION) &&
+ aggregateValue != nullptr);
+ type.makeComplete();
+ typelib_CompoundTypeDescription * ctd =
+ reinterpret_cast< typelib_CompoundTypeDescription * >(type.get());
+ if (ctd->pBaseTypeDescription != nullptr) {
+ 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]));
+ }
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/binaryurp/source/marshal.hxx b/binaryurp/source/marshal.hxx
new file mode 100644
index 000000000..93930e356
--- /dev/null
+++ b/binaryurp/source/marshal.hxx
@@ -0,0 +1,88 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <vector>
+
+#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 {
+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, OUString const & oid);
+
+ void writeTid(
+ std::vector< unsigned char > * buffer, rtl::ByteSequence const & tid);
+
+private:
+ Marshal(const Marshal&) = delete;
+ Marshal& operator=(const Marshal&) = delete;
+
+ 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_;
+};
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/binaryurp/source/outgoingrequest.hxx b/binaryurp/source/outgoingrequest.hxx
new file mode 100644
index 000000000..efa673eac
--- /dev/null
+++ b/binaryurp/source/outgoingrequest.hxx
@@ -0,0 +1,47 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <typelib/typedescription.hxx>
+#include <utility>
+
+namespace binaryurp {
+
+struct OutgoingRequest {
+ enum Kind { KIND_NORMAL, KIND_REQUEST_CHANGE, KIND_COMMIT_CHANGE };
+
+ OutgoingRequest(
+ Kind theKind, com::sun::star::uno::TypeDescription theMember,
+ bool theSetter):
+ member(std::move(theMember)), kind(theKind), setter(theSetter)
+ {}
+
+ com::sun::star::uno::TypeDescription member;
+
+ Kind kind;
+
+ bool setter;
+};
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/binaryurp/source/outgoingrequests.cxx b/binaryurp/source/outgoingrequests.cxx
new file mode 100644
index 000000000..3cdc80e82
--- /dev/null
+++ b/binaryurp/source/outgoingrequests.cxx
@@ -0,0 +1,67 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <cassert>
+
+#include <com/sun/star/uno/RuntimeException.hpp>
+#include <rtl/byteseq.hxx>
+
+#include "lessoperators.hxx"
+#include "outgoingrequest.hxx"
+#include "outgoingrequests.hxx"
+
+namespace binaryurp {
+
+OutgoingRequests::OutgoingRequests() {}
+
+OutgoingRequests::~OutgoingRequests() {}
+
+void OutgoingRequests::push(
+ rtl::ByteSequence const & tid, OutgoingRequest const & request)
+{
+ std::scoped_lock g(mutex_);
+ map_[tid].push_back(request);
+}
+
+OutgoingRequest OutgoingRequests::top(rtl::ByteSequence const & tid) {
+ std::scoped_lock g(mutex_);
+ Map::iterator i(map_.find(tid));
+ if (i == map_.end()) {
+ throw css::uno::RuntimeException(
+ "URP: reply for unknown TID");
+ }
+ assert(!i->second.empty());
+ return i->second.back();
+}
+
+void OutgoingRequests::pop(rtl::ByteSequence const & tid) noexcept {
+ std::scoped_lock g(mutex_);
+ Map::iterator i(map_.find(tid));
+ assert(i != map_.end());
+ i->second.pop_back();
+ if (i->second.empty()) {
+ map_.erase(i);
+ }
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/binaryurp/source/outgoingrequests.hxx b/binaryurp/source/outgoingrequests.hxx
new file mode 100644
index 000000000..698b6db9e
--- /dev/null
+++ b/binaryurp/source/outgoingrequests.hxx
@@ -0,0 +1,63 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <map>
+#include <mutex>
+#include <vector>
+
+namespace binaryurp
+{
+struct OutgoingRequest;
+}
+namespace rtl
+{
+class ByteSequence;
+}
+
+namespace binaryurp
+{
+class OutgoingRequests
+{
+public:
+ OutgoingRequests();
+
+ ~OutgoingRequests();
+
+ void push(rtl::ByteSequence const& tid, OutgoingRequest const& request);
+
+ OutgoingRequest top(rtl::ByteSequence const& tid);
+
+ void pop(rtl::ByteSequence const& tid) noexcept;
+
+private:
+ OutgoingRequests(const OutgoingRequests&) = delete;
+ OutgoingRequests& operator=(const OutgoingRequests&) = delete;
+
+ typedef std::map<rtl::ByteSequence, std::vector<OutgoingRequest>> Map;
+
+ std::mutex mutex_;
+ Map map_;
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/binaryurp/source/proxy.cxx b/binaryurp/source/proxy.cxx
new file mode 100644
index 000000000..49705e06a
--- /dev/null
+++ b/binaryurp/source/proxy.cxx
@@ -0,0 +1,239 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <cassert>
+#include <exception>
+#include <utility>
+#include <vector>
+
+#include <cppuhelper/exc_hlp.hxx>
+#include <o3tl/runtimetooustring.hxx>
+#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 {
+
+extern "C" void proxy_acquireInterface(uno_Interface * pInterface) {
+ assert(pInterface != nullptr);
+ static_cast< Proxy * >(pInterface)->do_acquire();
+}
+
+extern "C" void proxy_releaseInterface(uno_Interface * pInterface) {
+ assert(pInterface != nullptr);
+ static_cast< Proxy * >(pInterface)->do_release();
+}
+
+extern "C" void proxy_dispatchInterface(
+ uno_Interface * pUnoI, typelib_TypeDescription const * pMemberType,
+ void * pReturn, void ** pArgs, uno_Any ** ppException)
+{
+ assert(pUnoI != nullptr);
+ static_cast< Proxy * >(pUnoI)->do_dispatch(
+ pMemberType, pReturn, pArgs, ppException);
+}
+
+}
+
+Proxy::Proxy(
+ rtl::Reference< Bridge > const & bridge, OUString oid,
+ css::uno::TypeDescription type):
+ bridge_(bridge), oid_(std::move(oid)), type_(std::move(type)), references_(1)
+{
+ assert(bridge.is());
+ acquire = &proxy_acquireInterface;
+ release = &proxy_releaseInterface;
+ pDispatcher = &proxy_dispatchInterface;
+}
+
+
+void Proxy::do_acquire() {
+ if (++references_ == 1) {
+ bridge_->resurrectProxy(*this);
+ }
+}
+
+void Proxy::do_release() {
+ if (--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 (const std::exception & e) {
+ throw css::uno::RuntimeException(
+ "caught C++ exception: " + o3tl::runtimeToOUString(e.what()));
+ }
+ } catch (const 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, OUString * oid)
+{
+ 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:
+ assert(member != nullptr);
+ bool bSetter = false;
+ std::vector< BinaryAny > inArgs;
+ switch (member->eTypeClass) {
+ case typelib_TypeClass_INTERFACE_ATTRIBUTE:
+ bSetter = returnValue == nullptr;
+ if (bSetter) {
+ inArgs.emplace_back(
+ 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.emplace_back(
+ css::uno::TypeDescription(mtd->pParams[i].pTypeRef),
+ arguments[i]);
+ }
+ }
+ break;
+ }
+ default:
+ assert(false); // this cannot happen
+ break;
+ }
+ BinaryAny ret;
+ std::vector< BinaryAny > outArgs;
+ if (bridge_->makeCall(
+ oid_,
+ css::uno::TypeDescription(
+ const_cast< typelib_TypeDescription * >(member)),
+ bSetter, std::move(inArgs), &ret, &outArgs))
+ {
+ assert(ret.getType().get()->eTypeClass == typelib_TypeClass_EXCEPTION);
+ uno_any_construct(
+ *exception, ret.getValue(ret.getType()), ret.getType().get(), nullptr);
+ } else {
+ switch (member->eTypeClass) {
+ case typelib_TypeClass_INTERFACE_ATTRIBUTE:
+ if (!bSetter) {
+ css::uno::TypeDescription t(
+ reinterpret_cast<
+ typelib_InterfaceAttributeTypeDescription const * >(
+ member)->
+ pAttributeTypeRef);
+ uno_copyData(returnValue, ret.getValue(t), t.get(), nullptr);
+ }
+ 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(), nullptr);
+ }
+ 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) {
+ (void) uno_assignData(
+ arguments[j], pt.get(), i++->getValue(pt),
+ pt.get(), nullptr, nullptr, nullptr);
+ } else {
+ uno_copyData(
+ arguments[j], i++->getValue(pt), pt.get(), nullptr);
+ }
+ }
+ }
+ assert(i == outArgs.end());
+ break;
+ }
+ default:
+ assert(false); // this cannot happen
+ break;
+ }
+ *exception = nullptr;
+ }
+}
+
+bool Proxy::isProxy(
+ rtl::Reference< Bridge > const & bridge, OUString * oid) const
+{
+ assert(oid != nullptr);
+ if (bridge == bridge_) {
+ *oid = oid_;
+ return true;
+ } else {
+ return false;
+ }
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/binaryurp/source/proxy.hxx b/binaryurp/source/proxy.hxx
new file mode 100644
index 000000000..4e1fa3656
--- /dev/null
+++ b/binaryurp/source/proxy.hxx
@@ -0,0 +1,85 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <atomic>
+#include <cstddef>
+
+#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::sun::star::uno { class UnoInterfaceReference; }
+
+namespace binaryurp {
+
+class Proxy: public uno_Interface {
+public:
+ Proxy(
+ rtl::Reference< Bridge > const & bridge, OUString oid,
+ com::sun::star::uno::TypeDescription type);
+
+ const OUString& getOid() const { return oid_;}
+
+ const com::sun::star::uno::TypeDescription& getType() const { return type_;}
+
+ 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,
+ OUString * oid);
+
+private:
+ Proxy(const Proxy&) = delete;
+ Proxy& operator=(const Proxy&) = delete;
+
+ ~Proxy();
+
+ void do_dispatch_throw(
+ typelib_TypeDescription const * member, void * returnValue,
+ void ** arguments, uno_Any ** exception) const;
+
+ bool isProxy(rtl::Reference< Bridge > const & bridge, OUString * oid)
+ const;
+
+ rtl::Reference< Bridge > bridge_;
+ OUString oid_;
+ com::sun::star::uno::TypeDescription type_;
+ std::atomic<std::size_t> references_;
+};
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/binaryurp/source/reader.cxx b/binaryurp/source/reader.cxx
new file mode 100644
index 000000000..cbd18f1d8
--- /dev/null
+++ b/binaryurp/source/reader.cxx
@@ -0,0 +1,480 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <cassert>
+#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 <o3tl/safeint.hxx>
+#include <rtl/byteseq.h>
+#include <rtl/ustring.hxx>
+#include <sal/log.hxx>
+#include <sal/types.h>
+#include <typelib/typeclass.h>
+#include <typelib/typedescription.h>
+#include <typelib/typedescription.hxx>
+
+#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 {
+
+css::uno::Sequence< sal_Int8 > read(
+ css::uno::Reference< css::connection::XConnection > const & connection,
+ sal_uInt32 size, bool eofOk)
+{
+ assert(connection.is());
+ if (size > SAL_MAX_INT32) {
+ throw css::uno::RuntimeException(
+ "binaryurp::Reader: block size too large");
+ }
+ 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 (o3tl::make_unsigned(n) != size) {
+ throw css::io::IOException(
+ "binaryurp::Reader: premature end of input");
+ }
+ assert(o3tl::make_unsigned(buf.getLength()) == size);
+ return buf;
+}
+
+extern "C" void request(void * pThreadSpecificData) {
+ assert(pThreadSpecificData != nullptr);
+ std::unique_ptr< IncomingRequest >(
+ static_cast< IncomingRequest * >(pThreadSpecificData))->
+ execute();
+}
+
+}
+
+Reader::Reader(rtl::Reference< Bridge > const & bridge):
+ Thread("binaryurpReader"), bridge_(bridge)
+{
+ assert(bridge.is());
+}
+
+Reader::~Reader() {}
+
+void Reader::execute() {
+ 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.hasElements()) {
+ 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(
+ "binaryurp::Reader: block with zero message count received");
+ }
+ Unmarshal block(bridge_, state_, read(con, size, false));
+ for (sal_uInt32 i = 0; i != count; ++i) {
+ readMessage(block);
+ }
+ block.done();
+ }
+ } catch (const css::uno::Exception & e) {
+ SAL_WARN("binaryurp", "caught UNO exception '" << e << '\'');
+ } catch (const std::exception & e) {
+ SAL_WARN("binaryurp", "caught C++ exception '" << e.what() << '\'');
+ }
+ bridge_->terminate(false);
+ bridge_.clear();
+}
+
+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(
+ "URP: request message with MUSTREPLY != SYNCHRONOUS"
+ " received");
+ }
+ } 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(
+ "URP: request message with NEWTYPE received when last"
+ " interface type has not yet been set");
+ }
+ type = lastType_;
+ }
+ OUString oid;
+ if (newOid) {
+ oid = unmarshal.readOid();
+ if (oid.isEmpty()) {
+ throw css::io::IOException(
+ "binaryurp::Unmarshal: empty OID");
+ }
+ lastOid_ = oid;
+ } else {
+ if (lastOid_.isEmpty()) {
+ throw css::uno::RuntimeException(
+ "URP: request message with NEWOID received when last OID has"
+ " not yet been set");
+ }
+ oid = lastOid_;
+ }
+ rtl::ByteSequence tid(getTid(unmarshal, newTid));
+ lastTid_ = tid;
+ type.makeComplete();
+ if (type.get()->eTypeClass != typelib_TypeClass_INTERFACE) {
+ throw css::uno::RuntimeException(
+ "URP: request message with non-interface interface type received");
+ }
+ typelib_InterfaceTypeDescription * itd =
+ reinterpret_cast< typelib_InterfaceTypeDescription * >(type.get());
+ if (functionId >= itd->nMapFunctionIndexToMemberIndex) {
+ throw css::uno::RuntimeException(
+ "URP: request message with unknown function ID received");
+ }
+ sal_Int32 memberId = itd->pMapFunctionIndexToMemberIndex[functionId];
+ css::uno::TypeDescription memberTd(itd->ppAllMembers[memberId]);
+ memberTd.makeComplete();
+ 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::XCurrentContext>::get());
+ cc.set(
+ *static_cast< uno_Interface ** >(
+ unmarshal.readValue(t).getValue(t)));
+ }
+ bool oneWay =
+ memberTd.get()->eTypeClass == typelib_TypeClass_INTERFACE_METHOD &&
+ (reinterpret_cast< typelib_InterfaceMethodTypeDescription * >(
+ memberTd.get())->
+ bOneWay);
+ SAL_INFO_IF(
+ !oneWay && forceSynchronous, "binaryurp",
+ ("superfluous MUSTREPLY/SYNCHRONOUS ignored in request message with"
+ " non-oneway function ID"));
+ bool synchronous = !oneWay || forceSynchronous;
+ bool bSetter = false;
+ std::vector< BinaryAny > inArgs;
+ switch (memberTd.get()->eTypeClass) {
+ case typelib_TypeClass_INTERFACE_ATTRIBUTE:
+ bSetter = itd->pMapMemberIndexToFunctionIndex[memberId] != functionId;
+ // pMapMemberIndexToFunctionIndex contains function index of
+ // attribute getter
+ if (bSetter) {
+ 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:
+ 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(
+ "URP: request message with UrpProtocolProperties OID and"
+ " unknown function ID received");
+ }
+ } else {
+ css::uno::UnoInterfaceReference obj;
+ switch (functionId) {
+ case SPECIAL_FUNCTION_ID_QUERY_INTERFACE:
+ obj = bridge_->findStub(oid, type);
+ if (!obj.is()) {
+ 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(
+ "URP: queryInterface request message with unknown OID '"
+ + oid + "' received");
+ }
+ }
+ break;
+ case SPECIAL_FUNCTION_ID_RESERVED:
+ throw css::uno::RuntimeException(
+ "URP: request message with unknown function ID 1 received");
+ case SPECIAL_FUNCTION_ID_RELEASE:
+ break;
+ default:
+ obj = bridge_->findStub(oid, type);
+ if (!obj.is()) {
+ throw css::uno::RuntimeException(
+ "URP: request message with unknown OID received");
+ }
+ break;
+ }
+ std::unique_ptr< IncomingRequest > req(
+ new IncomingRequest(
+ bridge_, tid, oid, obj, type, functionId, synchronous, memberTd,
+ bSetter, std::move(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 = nullptr;
+ 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:
+ assert(false); // this cannot happen
+ break;
+ }
+ bool bOk = false;
+ for (sal_Int32 i = 0; i != n; ++i) {
+ if (typelib_typedescriptionreference_isAssignableFrom(
+ p[i],
+ reinterpret_cast< typelib_TypeDescriptionReference * >(
+ ret.getType().get())))
+ {
+ bOk = true;
+ break;
+ }
+ }
+ if (!bOk) {
+ throw css::uno::RuntimeException(
+ "URP: reply message with bad exception type received");
+ }
+ }
+ } 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:
+ assert(false); // this cannot happen
+ break;
+ }
+ }
+ switch (req.kind) {
+ case OutgoingRequest::KIND_NORMAL:
+ {
+ std::unique_ptr< IncomingReply > resp(
+ new IncomingReply(exc, ret, std::move(outArgs)));
+ uno_threadpool_putJob(
+ bridge_->getThreadPool(), tid.getHandle(), resp.get(), nullptr,
+ false);
+ resp.release();
+ break;
+ }
+ case OutgoingRequest::KIND_REQUEST_CHANGE:
+ assert(outArgs.empty());
+ bridge_->handleRequestChangeReply(exc, ret);
+ break;
+ case OutgoingRequest::KIND_COMMIT_CHANGE:
+ assert(outArgs.empty());
+ bridge_->handleCommitChangeReply(exc, ret);
+ break;
+ default:
+ 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(
+ "URP: message with NEWTID received when last TID has not yet been"
+ " set");
+ }
+ return lastTid_;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/binaryurp/source/reader.hxx b/binaryurp/source/reader.hxx
new file mode 100644
index 000000000..2f3ec0dd9
--- /dev/null
+++ b/binaryurp/source/reader.hxx
@@ -0,0 +1,65 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <rtl/byteseq.hxx>
+#include <rtl/ref.hxx>
+#include <rtl/ustring.hxx>
+#include <sal/types.h>
+#include <salhelper/thread.hxx>
+#include <typelib/typedescription.hxx>
+
+#include "readerstate.hxx"
+
+namespace binaryurp
+{
+class Bridge;
+class Unmarshal;
+}
+
+namespace binaryurp
+{
+class Reader : public salhelper::Thread
+{
+public:
+ explicit Reader(rtl::Reference<Bridge> const& bridge);
+
+private:
+ virtual ~Reader() override;
+
+ virtual void execute() override;
+
+ 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_;
+ OUString lastOid_;
+ rtl::ByteSequence lastTid_;
+ ReaderState state_;
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/binaryurp/source/readerstate.hxx b/binaryurp/source/readerstate.hxx
new file mode 100644
index 000000000..a93a45dfc
--- /dev/null
+++ b/binaryurp/source/readerstate.hxx
@@ -0,0 +1,47 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <rtl/byteseq.hxx>
+#include <rtl/ustring.hxx>
+#include <typelib/typedescription.hxx>
+
+#include "cache.hxx"
+
+namespace binaryurp
+{
+struct ReaderState
+{
+private:
+ ReaderState(const ReaderState&) = delete;
+ ReaderState& operator=(const ReaderState&) = delete;
+
+public:
+ ReaderState() {}
+
+ com::sun::star::uno::TypeDescription typeCache[cache::size];
+ OUString oidCache[cache::size];
+ rtl::ByteSequence tidCache[cache::size];
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/binaryurp/source/specialfunctionids.hxx b/binaryurp/source/specialfunctionids.hxx
new file mode 100644
index 000000000..e2b6ae0f8
--- /dev/null
+++ b/binaryurp/source/specialfunctionids.hxx
@@ -0,0 +1,40 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <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
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/binaryurp/source/unmarshal.cxx b/binaryurp/source/unmarshal.cxx
new file mode 100644
index 000000000..7d943d37b
--- /dev/null
+++ b/binaryurp/source/unmarshal.cxx
@@ -0,0 +1,491 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <cassert>
+#include <cstdlib>
+#include <new>
+#include <utility>
+#include <vector>
+
+#include <com/sun/star/io/IOException.hpp>
+#include <com/sun/star/uno/RuntimeException.hpp>
+#include <com/sun/star/uno/Sequence.hxx>
+#include <cppu/unotype.hxx>
+#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 {
+
+void * allocate(sal_Size size) {
+ void * p = std::malloc(size);
+ if (p == nullptr) {
+ throw std::bad_alloc();
+ }
+ return p;
+}
+
+std::vector< BinaryAny >::iterator copyMemberValues(
+ css::uno::TypeDescription const & type,
+ std::vector< BinaryAny >::iterator const & it, void * buffer) noexcept
+{
+ assert(
+ type.is() &&
+ (type.get()->eTypeClass == typelib_TypeClass_STRUCT ||
+ type.get()->eTypeClass == typelib_TypeClass_EXCEPTION) &&
+ buffer != nullptr);
+ type.makeComplete();
+ std::vector< BinaryAny >::iterator i(it);
+ typelib_CompoundTypeDescription * ctd =
+ reinterpret_cast< typelib_CompoundTypeDescription * >(type.get());
+ if (ctd->pBaseTypeDescription != nullptr) {
+ 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],
+ i++->getValue(css::uno::TypeDescription(ctd->ppTypeRefs[j])),
+ ctd->ppTypeRefs[j], nullptr);
+ }
+ return i;
+}
+
+}
+
+Unmarshal::Unmarshal(
+ rtl::Reference< Bridge > bridge, ReaderState & state,
+ css::uno::Sequence< sal_Int8 > const & buffer):
+ bridge_(std::move(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(
+ "binaryurp::Unmarshal: cache flag of simple type is set");
+ }
+ return css::uno::TypeDescription(
+ *typelib_static_type_getByTypeClass(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(
+ "binaryurp::Unmarshal: unknown type cache index");
+ }
+ return state_.typeCache[idx];
+ } else {
+ OUString const str(readString());
+ css::uno::TypeDescription t(str);
+ if (!t.is() || t.get()->eTypeClass != tc) {
+
+ throw css::io::IOException(
+ "binaryurp::Unmarshal: type with unknown name: " + str);
+ }
+ 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(
+ "binaryurp::Unmarshal: sequence type with unknown"
+ " component type");
+ }
+ switch (t2.get()->eTypeClass) {
+ case typelib_TypeClass_VOID:
+ case typelib_TypeClass_EXCEPTION:
+ throw css::io::IOException(
+ "binaryurp::Unmarshal: sequence type with bad"
+ " component type");
+ default:
+ break;
+ }
+ }
+ if (idx != cache::ignore) {
+ state_.typeCache[idx] = t;
+ }
+ return t;
+ }
+ }
+ default:
+ throw css::io::IOException(
+ "binaryurp::Unmarshal: type of unknown type class");
+ }
+}
+
+OUString Unmarshal::readOid() {
+ OUString oid(readString());
+ for (sal_Int32 i = 0; i != oid.getLength(); ++i) {
+ if (oid[i] > 0x7F) {
+ throw css::io::IOException(
+ "binaryurp::Unmarshal: OID contains non-ASCII character");
+ }
+ }
+ sal_uInt16 idx = readCacheIndex();
+ if (oid.isEmpty() && idx != cache::ignore) {
+ if (state_.oidCache[idx].isEmpty()) {
+ throw css::io::IOException(
+ "binaryurp::Unmarshal: unknown OID cache index");
+ }
+ 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(
+ "binaryurp::Unmarshal: unknown TID cache index");
+ }
+ return state_.tidCache[idx];
+ }
+ if (idx != cache::ignore) {
+ state_.tidCache[idx] = tid;
+ }
+ return tid;
+}
+
+BinaryAny Unmarshal::readValue(css::uno::TypeDescription const & type) {
+ 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(
+ "binaryurp::Unmarshal: boolean of unknown value");
+ }
+ 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:
+ {
+ 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(
+ "binaryurp::Unmarshal: any of type ANY");
+ }
+ 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 bFound = false;
+ for (sal_Int32 i = 0; i != etd->nEnumValues; ++i) {
+ if (etd->pEnumValues[i] == v) {
+ bFound = true;
+ break;
+ }
+ }
+ if (!bFound) {
+ throw css::io::IOException(
+ "binaryurp::Unmarshal: unknown enum value");
+ }
+ 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 = nullptr;
+ 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(
+ "binaryurp::Unmarshal: block contains excess data");
+ }
+}
+
+void Unmarshal::check(sal_Int32 size) const {
+ if (end_ - data_ < size) {
+ throw css::io::IOException(
+ "binaryurp::Unmarshal: trying to read past end of block");
+ }
+}
+
+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(
+ "binaryurp::Unmarshal: cache index out of range");
+ }
+ 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_++;
+}
+
+OUString Unmarshal::readString() {
+ sal_uInt32 n = readCompressed();
+ if (n > SAL_MAX_INT32) {
+ throw css::uno::RuntimeException(
+ "binaryurp::Unmarshal: string size too large");
+ }
+ check(static_cast< sal_Int32 >(n));
+ 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(
+ "binaryurp::Unmarshal: string does not contain UTF-8");
+ }
+ data_ += n;
+ return s;
+}
+
+BinaryAny Unmarshal::readSequence(css::uno::TypeDescription const & type) {
+ assert(type.is() && type.get()->eTypeClass == typelib_TypeClass_SEQUENCE);
+ sal_uInt32 n = readCompressed();
+ if (n > SAL_MAX_INT32) {
+ throw css::uno::RuntimeException(
+ "binaryurp::Unmarshal: sequence size too large");
+ }
+ if (n == 0) {
+ return BinaryAny(type, nullptr);
+ }
+ 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;
+ as.reserve(n);
+ for (sal_uInt32 i = 0; i != n; ++i) {
+ as.push_back(readValue(ctd));
+ }
+ 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(
+ "binaryurp::Unmarshal: sequence size too large");
+ }
+ 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,
+ as[i].getValue(ctd), ctd.get(), nullptr);
+ }
+ return BinaryAny(type, &buf);
+}
+
+void Unmarshal::readMemberValues(
+ css::uno::TypeDescription const & type, std::vector< BinaryAny > * values)
+{
+ assert(
+ type.is() &&
+ (type.get()->eTypeClass == typelib_TypeClass_STRUCT ||
+ type.get()->eTypeClass == typelib_TypeClass_EXCEPTION) &&
+ values != nullptr);
+ type.makeComplete();
+ typelib_CompoundTypeDescription * ctd =
+ reinterpret_cast< typelib_CompoundTypeDescription * >(type.get());
+ if (ctd->pBaseTypeDescription != nullptr) {
+ readMemberValues(
+ css::uno::TypeDescription(&ctd->pBaseTypeDescription->aBase),
+ values);
+ }
+ values->reserve(values->size() + ctd->nMembers);
+ for (sal_Int32 i = 0; i != ctd->nMembers; ++i) {
+ values->push_back(
+ readValue(css::uno::TypeDescription(ctd->ppTypeRefs[i])));
+ }
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/binaryurp/source/unmarshal.hxx b/binaryurp/source/unmarshal.hxx
new file mode 100644
index 000000000..1972c30d0
--- /dev/null
+++ b/binaryurp/source/unmarshal.hxx
@@ -0,0 +1,93 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <vector>
+
+#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::sun::star::uno { class TypeDescription; }
+
+namespace binaryurp {
+
+class Unmarshal {
+public:
+ Unmarshal(
+ rtl::Reference< Bridge > 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();
+
+ OUString readOid();
+
+ rtl::ByteSequence readTid();
+
+ BinaryAny readValue(com::sun::star::uno::TypeDescription const & type);
+
+ void done() const;
+
+private:
+ Unmarshal(const Unmarshal&) = delete;
+ Unmarshal& operator=(const Unmarshal&) = delete;
+
+ void check(sal_Int32 size) const;
+
+ sal_uInt32 readCompressed();
+
+ sal_uInt16 readCacheIndex();
+
+ sal_uInt64 read64();
+
+ 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_;
+};
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/binaryurp/source/writer.cxx b/binaryurp/source/writer.cxx
new file mode 100644
index 000000000..539d8a2c5
--- /dev/null
+++ b/binaryurp/source/writer.cxx
@@ -0,0 +1,455 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <cassert>
+#include <cstddef>
+#include <cstring>
+#include <exception>
+#include <limits>
+#include <utility>
+#include <vector>
+
+#include <com/sun/star/connection/XConnection.hpp>
+#include <com/sun/star/io/IOException.hpp>
+#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
+#include <com/sun/star/uno/XCurrentContext.hpp>
+#include <cppuhelper/exc_hlp.hxx>
+#include <sal/log.hxx>
+#include <uno/dispatcher.hxx>
+
+#include "binaryany.hxx"
+#include "bridge.hxx"
+#include "currentcontext.hxx"
+#include "specialfunctionids.hxx"
+#include "writer.hxx"
+
+namespace binaryurp {
+
+Writer::Item::Item()
+ : request(false)
+ , setter(false)
+ , exception(false)
+ , setCurrentContextMode(false)
+{}
+
+Writer::Item::Item(
+ rtl::ByteSequence theTid, OUString theOid,
+ css::uno::TypeDescription theType,
+ css::uno::TypeDescription theMember,
+ std::vector< BinaryAny >&& inArguments,
+ css::uno::UnoInterfaceReference theCurrentContext):
+ tid(std::move(theTid)), oid(std::move(theOid)), type(std::move(theType)), member(std::move(theMember)),
+ currentContext(std::move(theCurrentContext)), arguments(std::move(inArguments)),
+ request(true), setter(false), exception(false), setCurrentContextMode(false)
+{}
+
+Writer::Item::Item(
+ rtl::ByteSequence theTid,
+ css::uno::TypeDescription theMember, bool theSetter,
+ bool theException, BinaryAny theReturnValue,
+ std::vector< BinaryAny >&& outArguments,
+ bool theSetCurrentContextMode):
+ tid(std::move(theTid)), member(std::move(theMember)),
+ returnValue(std::move(theReturnValue)), arguments(std::move(outArguments)),
+ request(false), setter(theSetter),
+ exception(theException), setCurrentContextMode(theSetCurrentContextMode)
+{}
+
+Writer::Writer(rtl::Reference< Bridge > const & bridge):
+ Thread("binaryurpWriter"), bridge_(bridge), marshal_(bridge, state_),
+ stop_(false)
+{
+ assert(bridge.is());
+}
+
+void Writer::sendDirectRequest(
+ rtl::ByteSequence const & tid, OUString const & oid,
+ css::uno::TypeDescription const & type,
+ css::uno::TypeDescription const & member,
+ std::vector< BinaryAny > const & inArguments)
+{
+ 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)
+{
+ assert(!unblocked_.check());
+ sendReply(tid, member, false, exception, returnValue,outArguments);
+}
+
+void Writer::queueRequest(
+ rtl::ByteSequence const & tid, OUString const & oid,
+ css::uno::TypeDescription const & type,
+ css::uno::TypeDescription const & member,
+ std::vector< BinaryAny >&& inArguments)
+{
+ css::uno::UnoInterfaceReference cc(current_context::get());
+ std::lock_guard g(mutex_);
+ queue_.emplace_back(tid, oid, type, member, std::move(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 >&& outArguments, bool setCurrentContextMode)
+{
+ std::lock_guard g(mutex_);
+ queue_.emplace_back(
+ tid, member, setter, exception, returnValue, std::move(outArguments),
+ setCurrentContextMode);
+ items_.set();
+}
+
+void Writer::unblock() {
+ // Assumes that osl::Condition::set works as a memory barrier, so that
+ // changes made by preceding sendDirectRequest/Reply calls are visible to
+ // subsequent sendRequest/Reply calls:
+ unblocked_.set();
+}
+
+void Writer::stop() {
+ {
+ std::lock_guard g(mutex_);
+ stop_ = true;
+ }
+ unblocked_.set();
+ items_.set();
+}
+
+Writer::~Writer() {}
+
+void Writer::execute() {
+ try {
+ unblocked_.wait();
+ for (;;) {
+ items_.wait();
+ Item item;
+ {
+ std::lock_guard g(mutex_);
+ if (stop_) {
+ return;
+ }
+ 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 != "UrpProtocolProperties" &&
+ !item.member.equals(
+ css::uno::TypeDescription(
+ "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 (const css::uno::Exception & e) {
+ SAL_INFO("binaryurp", "caught " << e);
+ } catch (const std::exception & e) {
+ SAL_INFO("binaryurp", "caught C++ exception " << e.what());
+ }
+ bridge_->terminate(false);
+ bridge_.clear();
+}
+
+void Writer::sendRequest(
+ rtl::ByteSequence const & tid, 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)
+{
+ assert(tid.getLength() != 0);
+ assert(!oid.isEmpty());
+ assert(member.is());
+ css::uno::TypeDescription t(type);
+ sal_Int32 functionId = 0;
+ bool bForceSynchronous = false;
+ member.makeComplete();
+ switch (member.get()->eTypeClass) {
+ case typelib_TypeClass_INTERFACE_ATTRIBUTE:
+ {
+ typelib_InterfaceAttributeTypeDescription * atd =
+ reinterpret_cast< typelib_InterfaceAttributeTypeDescription * >(
+ member.get());
+ assert(atd->pInterface != nullptr);
+ 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());
+ assert(mtd->pInterface != nullptr);
+ if (!t.is()) {
+ t = css::uno::TypeDescription(&mtd->pInterface->aBase);
+ }
+ t.makeComplete();
+ functionId = mtd->pInterface->pMapMemberIndexToFunctionIndex[
+ mtd->aBase.nPosition];
+ bForceSynchronous = mtd->bOneWay &&
+ functionId != SPECIAL_FUNCTION_ID_RELEASE;
+ break;
+ }
+ default:
+ assert(false); // this cannot happen
+ break;
+ }
+ assert(functionId >= 0);
+ if (functionId > SAL_MAX_UINT16) {
+ throw css::uno::RuntimeException("function ID too large for URP");
+ }
+ std::vector< unsigned char > buf;
+ bool newType = !(lastType_.is() && t.equals(lastType_));
+ bool newOid = oid != lastOid_;
+ bool newTid = tid != lastTid_;
+ if (newType || newOid || newTid || bForceSynchronous || functionId > 0x3FFF)
+ // > 14 bit function ID
+ {
+ Marshal::write8(
+ &buf,
+ (0xC0 | (newType ? 0x20 : 0) | (newOid ? 0x10 : 0) |
+ (newTid ? 0x08 : 0) | (functionId > 0xFF ? 0x04 : 0) |
+ (bForceSynchronous ? 0x01 : 0)));
+ // bit 7: LONGHEADER, bit 6: REQUEST, bit 5: NEWTYPE, bit 4: NEWOID,
+ // bit 3: NEWTID, bit 2: FUNCTIONID16, bit 0: MOREFLAGS
+ if (bForceSynchronous) {
+ 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
+ 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++);
+ }
+ }
+ assert(i == inArguments.end());
+ break;
+ }
+ default:
+ 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)
+{
+ assert(tid.getLength() != 0);
+ assert(member.is());
+ assert(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++);
+ }
+ }
+ assert(i == outArguments.end());
+ break;
+ }
+ default:
+ 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(
+ "message too large for URP");
+ }
+ Marshal::write32(&header, static_cast< sal_uInt32 >(buffer.size()));
+ Marshal::write32(&header, 1);
+ assert(!buffer.empty());
+ unsigned char const * p = buffer.data();
+ std::vector< unsigned char >::size_type n = buffer.size();
+ assert(header.size() <= SAL_MAX_INT32);
+ /*static_*/assert(SAL_MAX_INT32 <= std::numeric_limits<std::size_t>::max());
+ std::size_t k = SAL_MAX_INT32 - header.size();
+ if (n < k) {
+ k = n;
+ }
+ css::uno::Sequence<sal_Int8> s(header.size() + k);
+ assert(!header.empty());
+ std::memcpy(s.getArray(), header.data(), header.size());
+ for (;;) {
+ std::memcpy(s.getArray() + s.getLength() - k, p, k);
+ try {
+ bridge_->getConnection()->write(s);
+ } catch (const css::io::IOException & e) {
+ css::uno::Any exc(cppu::getCaughtException());
+ throw css::lang::WrappedTargetRuntimeException(
+ "Binary URP write raised IO exception: " + e.Message,
+ css::uno::Reference< css::uno::XInterface >(), exc);
+ }
+ n -= k;
+ if (n == 0) {
+ break;
+ }
+ p += k;
+ k = SAL_MAX_INT32;
+ if (n < k) {
+ k = n;
+ }
+ s.realloc(k);
+ }
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/binaryurp/source/writer.hxx b/binaryurp/source/writer.hxx
new file mode 100644
index 000000000..e2061502a
--- /dev/null
+++ b/binaryurp/source/writer.hxx
@@ -0,0 +1,150 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <deque>
+#include <mutex>
+#include <vector>
+
+#include <osl/conditn.hxx>
+#include <rtl/byteseq.hxx>
+#include <rtl/ref.hxx>
+#include <rtl/ustring.hxx>
+#include <salhelper/thread.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 salhelper::Thread
+{
+public:
+ 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, 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, OUString const & oid,
+ com::sun::star::uno::TypeDescription const & type,
+ com::sun::star::uno::TypeDescription const & member,
+ std::vector< BinaryAny >&& inArguments);
+
+ void queueReply(
+ rtl::ByteSequence const & tid,
+ com::sun::star::uno::TypeDescription const & member, bool setter,
+ bool exception, BinaryAny const & returnValue,
+ std::vector< BinaryAny >&& outArguments,
+ bool setCurrentContextMode);
+
+ void unblock();
+
+ void stop();
+
+private:
+ virtual ~Writer() override;
+
+ virtual void execute() override;
+
+ void sendRequest(
+ rtl::ByteSequence const & tid, 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 theTid, OUString theOid,
+ com::sun::star::uno::TypeDescription theType,
+ com::sun::star::uno::TypeDescription theMember,
+ std::vector< BinaryAny >&& inArguments,
+ com::sun::star::uno::UnoInterfaceReference theCurrentContext);
+
+ // Reply:
+ Item(
+ rtl::ByteSequence theTid,
+ com::sun::star::uno::TypeDescription theMember,
+ bool theSetter, bool theException, BinaryAny theReturnValue,
+ std::vector< BinaryAny >&& outArguments,
+ bool theSetCurrentContextMode);
+
+ rtl::ByteSequence tid; // request + reply
+ OUString oid; // request
+ com::sun::star::uno::TypeDescription type; // request
+ com::sun::star::uno::TypeDescription member; // request + reply
+ com::sun::star::uno::UnoInterfaceReference currentContext; // request
+ BinaryAny returnValue; // reply
+ std::vector< BinaryAny > arguments; // request: inArguments; reply: outArguments
+ bool request;
+ bool setter; // reply
+ bool exception; // reply
+ bool setCurrentContextMode; // reply
+ };
+
+ rtl::Reference< Bridge > bridge_;
+ WriterState state_;
+ Marshal marshal_;
+ com::sun::star::uno::TypeDescription lastType_;
+ OUString lastOid_;
+ rtl::ByteSequence lastTid_;
+ osl::Condition unblocked_;
+ osl::Condition items_;
+
+ std::mutex mutex_;
+ std::deque< Item > queue_;
+ bool stop_;
+};
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/binaryurp/source/writerstate.hxx b/binaryurp/source/writerstate.hxx
new file mode 100644
index 000000000..72477ad17
--- /dev/null
+++ b/binaryurp/source/writerstate.hxx
@@ -0,0 +1,49 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <rtl/byteseq.hxx>
+#include <rtl/ustring.hxx>
+#include <typelib/typedescription.hxx>
+
+#include "cache.hxx"
+
+namespace binaryurp {
+
+struct WriterState {
+private:
+ WriterState(const WriterState&) = delete;
+ WriterState& operator=(const WriterState&) = delete;
+public:
+ WriterState():
+ typeCache(cache::size), oidCache(cache::size), tidCache(cache::size) {}
+
+ Cache< com::sun::star::uno::TypeDescription > typeCache;
+
+ Cache< OUString > oidCache;
+
+ Cache< rtl::ByteSequence > tidCache;
+};
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */