update emoji autocorrect entries from po-files
[LibreOffice.git] / binaryurp / source / writer.cxx
blob84edbd40187d0be5c5ff336619141e3da8a3bab4
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "sal/config.h"
22 #include <exception>
23 #include <vector>
24 #include <string.h>
26 #include "com/sun/star/connection/XConnection.hpp"
27 #include "com/sun/star/lang/WrappedTargetRuntimeException.hpp"
28 #include "com/sun/star/uno/XCurrentContext.hpp"
29 #include "cppuhelper/exc_hlp.hxx"
30 #include "osl/mutex.hxx"
31 #include "uno/dispatcher.hxx"
33 #include "binaryany.hxx"
34 #include "bridge.hxx"
35 #include "currentcontext.hxx"
36 #include "specialfunctionids.hxx"
37 #include "writer.hxx"
39 namespace binaryurp {
41 Writer::Item::Item()
42 : request(false)
43 , setter(false)
44 , exception(false)
45 , setCurrentContextMode(false)
48 Writer::Item::Item(
49 rtl::ByteSequence const & theTid, OUString const & theOid,
50 css::uno::TypeDescription const & theType,
51 css::uno::TypeDescription const & theMember,
52 std::vector< BinaryAny > const & inArguments,
53 css::uno::UnoInterfaceReference const & theCurrentContext):
54 request(true), tid(theTid), oid(theOid), type(theType), member(theMember),
55 setter(false), arguments(inArguments), exception(false),
56 currentContext(theCurrentContext), setCurrentContextMode(false)
59 Writer::Item::Item(
60 rtl::ByteSequence const & theTid,
61 css::uno::TypeDescription const & theMember, bool theSetter,
62 bool theException, BinaryAny const & theReturnValue,
63 std::vector< BinaryAny > const & outArguments,
64 bool theSetCurrentContextMode):
65 request(false), tid(theTid), member(theMember), setter(theSetter),
66 arguments(outArguments), exception(theException),
67 returnValue(theReturnValue), setCurrentContextMode(theSetCurrentContextMode)
70 Writer::Writer(rtl::Reference< Bridge > const & bridge):
71 Thread("binaryurpWriter"), bridge_(bridge), marshal_(bridge, state_),
72 stop_(false)
74 OSL_ASSERT(bridge.is());
77 void Writer::sendDirectRequest(
78 rtl::ByteSequence const & tid, OUString const & oid,
79 css::uno::TypeDescription const & type,
80 css::uno::TypeDescription const & member,
81 std::vector< BinaryAny > const & inArguments)
83 OSL_ASSERT(!unblocked_.check());
84 sendRequest(
85 tid, oid, type, member, inArguments, false,
86 css::uno::UnoInterfaceReference());
89 void Writer::sendDirectReply(
90 rtl::ByteSequence const & tid, css::uno::TypeDescription const & member,
91 bool exception, BinaryAny const & returnValue,
92 std::vector< BinaryAny > const & outArguments)
94 OSL_ASSERT(!unblocked_.check());
95 sendReply(tid, member, false, exception, returnValue,outArguments);
98 void Writer::queueRequest(
99 rtl::ByteSequence const & tid, OUString const & oid,
100 css::uno::TypeDescription const & type,
101 css::uno::TypeDescription const & member,
102 std::vector< BinaryAny > const & inArguments)
104 css::uno::UnoInterfaceReference cc(current_context::get());
105 osl::MutexGuard g(mutex_);
106 queue_.push_back(Item(tid, oid, type, member, inArguments, cc));
107 items_.set();
110 void Writer::queueReply(
111 rtl::ByteSequence const & tid,
112 com::sun::star::uno::TypeDescription const & member, bool setter,
113 bool exception, BinaryAny const & returnValue,
114 std::vector< BinaryAny > const & outArguments, bool setCurrentContextMode)
116 osl::MutexGuard g(mutex_);
117 queue_.push_back(
118 Item(
119 tid, member, setter, exception, returnValue, outArguments,
120 setCurrentContextMode));
121 items_.set();
124 void Writer::unblock() {
125 // Assumes that osl::Condition::set works as a memory barrier, so that
126 // changes made by preceding sendDirectRequest/Reply calls are visible to
127 // subsequent sendRequest/Reply calls:
128 unblocked_.set();
131 void Writer::stop() {
133 osl::MutexGuard g(mutex_);
134 stop_ = true;
136 unblocked_.set();
137 items_.set();
140 Writer::~Writer() {}
142 void Writer::execute() {
143 try {
144 unblocked_.wait();
145 for (;;) {
146 items_.wait();
147 Item item;
149 osl::MutexGuard g(mutex_);
150 if (stop_) {
151 return;
153 OSL_ASSERT(!queue_.empty());
154 item = queue_.front();
155 queue_.pop_front();
156 if (queue_.empty()) {
157 items_.reset();
160 if (item.request) {
161 sendRequest(
162 item.tid, item.oid, item.type, item.member, item.arguments,
163 (item.oid != "UrpProtocolProperties" &&
164 !item.member.equals(
165 css::uno::TypeDescription(
166 "com.sun.star.uno.XInterface::release")) &&
167 bridge_->isCurrentContextMode()),
168 item.currentContext);
169 } else {
170 sendReply(
171 item.tid, item.member, item.setter, item.exception,
172 item.returnValue, item.arguments);
173 if (item.setCurrentContextMode) {
174 bridge_->setCurrentContextMode();
178 } catch (const css::uno::Exception & e) {
179 OSL_TRACE(
180 "caught UNO exception '%s'",
181 OUStringToOString(e.Message, RTL_TEXTENCODING_UTF8).getStr());
182 } catch (const std::exception & e) {
183 OSL_TRACE("caught C++ exception '%s'", e.what());
185 bridge_->terminate(false);
186 bridge_.clear();
189 void Writer::sendRequest(
190 rtl::ByteSequence const & tid, OUString const & oid,
191 css::uno::TypeDescription const & type,
192 css::uno::TypeDescription const & member,
193 std::vector< BinaryAny > const & inArguments, bool currentContextMode,
194 css::uno::UnoInterfaceReference const & currentContext)
196 OSL_ASSERT(tid.getLength() != 0 && !oid.isEmpty() && member.is());
197 css::uno::TypeDescription t(type);
198 sal_Int32 functionId = 0;
199 bool forceSynchronous = false;
200 member.makeComplete();
201 switch (member.get()->eTypeClass) {
202 case typelib_TypeClass_INTERFACE_ATTRIBUTE:
204 typelib_InterfaceAttributeTypeDescription * atd =
205 reinterpret_cast< typelib_InterfaceAttributeTypeDescription * >(
206 member.get());
207 OSL_ASSERT(atd->pInterface != 0);
208 if (!t.is()) {
209 t = css::uno::TypeDescription(&atd->pInterface->aBase);
211 t.makeComplete();
212 functionId = atd->pInterface->pMapMemberIndexToFunctionIndex[
213 atd->aBase.nPosition];
214 if (!inArguments.empty()) { // setter
215 ++functionId;
217 break;
219 case typelib_TypeClass_INTERFACE_METHOD:
221 typelib_InterfaceMethodTypeDescription * mtd =
222 reinterpret_cast< typelib_InterfaceMethodTypeDescription * >(
223 member.get());
224 assert(mtd->pInterface != 0);
225 if (!t.is()) {
226 t = css::uno::TypeDescription(&mtd->pInterface->aBase);
228 t.makeComplete();
229 functionId = mtd->pInterface->pMapMemberIndexToFunctionIndex[
230 mtd->aBase.nPosition];
231 forceSynchronous = mtd->bOneWay &&
232 functionId != SPECIAL_FUNCTION_ID_RELEASE;
233 break;
235 default:
236 OSL_ASSERT(false); // this cannot happen
237 break;
239 OSL_ASSERT(functionId >= 0);
240 if (functionId > SAL_MAX_UINT16) {
241 throw css::uno::RuntimeException("function ID too large for URP");
243 std::vector< unsigned char > buf;
244 bool newType = !(lastType_.is() && t.equals(lastType_));
245 bool newOid = oid != lastOid_;
246 bool newTid = tid != lastTid_;
247 if (newType || newOid || newTid || forceSynchronous || functionId > 0x3FFF)
248 // > 14 bit function ID
250 Marshal::write8(
251 &buf,
252 (0xC0 | (newType ? 0x20 : 0) | (newOid ? 0x10 : 0) |
253 (newTid ? 0x08 : 0) | (functionId > 0xFF ? 0x04 : 0) |
254 (forceSynchronous ? 0x01 : 0)));
255 // bit 7: LONGHEADER, bit 6: REQUEST, bit 5: NEWTYPE, bit 4: NEWOID,
256 // bit 3: NEWTID, bit 2: FUNCTIONID16, bit 0: MOREFLAGS
257 if (forceSynchronous) {
258 Marshal::write8(&buf, 0xC0); // bit 7: MUSTREPLY, bit 6: SYNCHRONOUS
260 if (functionId <= 0xFF) {
261 Marshal::write8(&buf, static_cast< sal_uInt8 >(functionId));
262 } else {
263 Marshal::write16(&buf, static_cast< sal_uInt16 >(functionId));
265 if (newType) {
266 marshal_.writeType(&buf, t);
268 if (newOid) {
269 marshal_.writeOid(&buf, oid);
271 if (newTid) {
272 marshal_.writeTid(&buf, tid);
274 } else if (functionId <= 0x3F) { // <= 6 bit function ID
275 Marshal::write8(&buf, static_cast< sal_uInt8 >(functionId));
276 // bit 7: !LONGHEADER, bit 6: !FUNCTIONID14
277 } else {
278 Marshal::write8(
279 &buf, static_cast< sal_uInt8 >(0x40 | (functionId >> 8)));
280 // bit 7: !LONGHEADER, bit 6: FUNCTIONID14
281 Marshal::write8(&buf, functionId & 0xFF);
283 if (currentContextMode) {
284 css::uno::UnoInterfaceReference cc(currentContext);
285 marshal_.writeValue(
286 &buf,
287 css::uno::TypeDescription(
288 cppu::UnoType<
289 css::uno::Reference< css::uno::XCurrentContext > >::get()),
290 BinaryAny(
291 css::uno::TypeDescription(
292 cppu::UnoType<
293 css::uno::Reference<
294 css::uno::XCurrentContext > >::get()),
295 &cc.m_pUnoI));
297 switch (member.get()->eTypeClass) {
298 case typelib_TypeClass_INTERFACE_ATTRIBUTE:
299 if (!inArguments.empty()) { // setter
300 OSL_ASSERT(inArguments.size() == 1);
301 marshal_.writeValue(
302 &buf,
303 css::uno::TypeDescription(
304 reinterpret_cast<
305 typelib_InterfaceAttributeTypeDescription * >(
306 member.get())->
307 pAttributeTypeRef),
308 inArguments.front());
310 break;
311 case typelib_TypeClass_INTERFACE_METHOD:
313 typelib_InterfaceMethodTypeDescription * mtd =
314 reinterpret_cast< typelib_InterfaceMethodTypeDescription * >(
315 member.get());
316 std::vector< BinaryAny >::const_iterator i(inArguments.begin());
317 for (sal_Int32 j = 0; j != mtd->nParams; ++j) {
318 if (mtd->pParams[j].bIn) {
319 marshal_.writeValue(
320 &buf,
321 css::uno::TypeDescription(mtd->pParams[j].pTypeRef),
322 *i++);
325 OSL_ASSERT(i == inArguments.end());
326 break;
328 default:
329 OSL_ASSERT(false); // this cannot happen
330 break;
332 sendMessage(buf);
333 lastType_ = t;
334 lastOid_ = oid;
335 lastTid_ = tid;
338 void Writer::sendReply(
339 rtl::ByteSequence const & tid,
340 com::sun::star::uno::TypeDescription const & member, bool setter,
341 bool exception, BinaryAny const & returnValue,
342 std::vector< BinaryAny > const & outArguments)
344 OSL_ASSERT(tid.getLength() != 0 && member.is() && member.get()->bComplete);
345 std::vector< unsigned char > buf;
346 bool newTid = tid != lastTid_;
347 Marshal::write8(&buf, 0x80 | (exception ? 0x20 : 0) | (newTid ? 0x08 : 0));
348 // bit 7: LONGHEADER; bit 6: !REQUEST; bit 5: EXCEPTION; bit 3: NEWTID
349 if (newTid) {
350 marshal_.writeTid(&buf, tid);
352 if (exception) {
353 marshal_.writeValue(
354 &buf,
355 css::uno::TypeDescription(cppu::UnoType< css::uno::Any >::get()),
356 returnValue);
357 } else {
358 switch (member.get()->eTypeClass) {
359 case typelib_TypeClass_INTERFACE_ATTRIBUTE:
360 if (!setter) {
361 marshal_.writeValue(
362 &buf,
363 css::uno::TypeDescription(
364 reinterpret_cast<
365 typelib_InterfaceAttributeTypeDescription * >(
366 member.get())->
367 pAttributeTypeRef),
368 returnValue);
370 break;
371 case typelib_TypeClass_INTERFACE_METHOD:
373 typelib_InterfaceMethodTypeDescription * mtd =
374 reinterpret_cast<
375 typelib_InterfaceMethodTypeDescription * >(
376 member.get());
377 marshal_.writeValue(
378 &buf, css::uno::TypeDescription(mtd->pReturnTypeRef),
379 returnValue);
380 std::vector< BinaryAny >::const_iterator i(
381 outArguments.begin());
382 for (sal_Int32 j = 0; j != mtd->nParams; ++j) {
383 if (mtd->pParams[j].bOut) {
384 marshal_.writeValue(
385 &buf,
386 css::uno::TypeDescription(mtd->pParams[j].pTypeRef),
387 *i++);
390 OSL_ASSERT(i == outArguments.end());
391 break;
393 default:
394 OSL_ASSERT(false); // this cannot happen
395 break;
398 sendMessage(buf);
399 lastTid_ = tid;
400 bridge_->decrementCalls();
403 void Writer::sendMessage(std::vector< unsigned char > const & buffer) {
404 std::vector< unsigned char > header;
405 if (buffer.size() > SAL_MAX_UINT32) {
406 throw css::uno::RuntimeException(
407 "message too large for URP");
409 Marshal::write32(&header, static_cast< sal_uInt32 >(buffer.size()));
410 Marshal::write32(&header, 1);
411 OSL_ASSERT(!buffer.empty());
412 unsigned char const * p = &buffer[0];
413 std::vector< unsigned char >::size_type n = buffer.size();
414 OSL_ASSERT(header.size() <= SAL_MAX_INT32 && SAL_MAX_INT32 <= SAL_MAX_SIZE);
415 sal_Size k = SAL_MAX_INT32 - header.size();
416 if (n < k) {
417 k = static_cast< sal_Size >(n);
419 css::uno::Sequence< sal_Int8 > s(
420 static_cast< sal_Int32 >(header.size() + k));
421 OSL_ASSERT(!header.empty());
422 memcpy(
423 s.getArray(), &header[0], static_cast< sal_Size >(header.size()));
424 for (;;) {
425 memcpy(s.getArray() + s.getLength() - k, p, k);
426 try {
427 bridge_->getConnection()->write(s);
428 } catch (const css::io::IOException & e) {
429 css::uno::Any exc(cppu::getCaughtException());
430 throw css::lang::WrappedTargetRuntimeException(
431 "Binary URP write raised IO exception: " + e.Message,
432 css::uno::Reference< css::uno::XInterface >(), exc);
434 n = static_cast< std::vector< unsigned char >::size_type >(n - k);
435 if (n == 0) {
436 break;
438 p += k;
439 k = SAL_MAX_INT32;
440 if (n < k) {
441 k = static_cast< sal_Size >(n);
443 s.realloc(k);
449 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */