1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 #include "precompiled_bridges.hxx"
29 #include "sal/config.h"
30 
31 #include <cstddef>
32 #include <cstring>
33 #include <map>
34 #include <utility>
35 #include <vector>
36 
37 #include "bridges/cpp_uno/shared/arraypointer.hxx"
38 #include "com/sun/star/uno/Reference.hxx"
39 #include "com/sun/star/uno/RuntimeException.hpp"
40 #include "com/sun/star/uno/XInterface.hpp"
41 #include "com/sun/star/uno/genfunc.hxx"
42 #include "osl/diagnose.h"
43 #include "osl/mutex.hxx"
44 #include "rtl/strbuf.hxx"
45 #include "rtl/string.hxx"
46 #include "rtl/textenc.h"
47 #include "rtl/ustring.h"
48 #include "rtl/ustring.hxx"
49 #include "sal/types.h"
50 #include "typelib/typeclass.h"
51 #include "typelib/typedescription.h"
52 #include "uno/any2.h"
53 #include "uno/data.h"
54 #include "uno/mapping.h"
55 
56 #include "exceptions.hxx"
57 #include "flushcode.hxx"
58 
59 namespace {
60 
61 namespace css = com::sun::star;
62 
63 typedef void (* Function)(void *);
64 
65 Function toFunction(void * pointer) {
66 #pragma disable_warn
67     return reinterpret_cast< Function >(pointer);
68 #pragma enable_warn
69 }
70 
71 bool toUnoName(char const * rttiName, rtl::OUString * unoName) {
72     rtl::OStringBuffer buf;
73     for (;;) {
74         char const * p = std::strchr(rttiName, ':');
75         if (p == NULL) {
76             buf.append(rttiName);
77             break;
78         }
79         if (p - rttiName > SAL_MAX_INT32) {
80             return false;
81         }
82         buf.append(rttiName, sal::static_int_cast< sal_Int32 >(p - rttiName));
83         buf.append(".");
84         while (*p == ':') {
85             ++p;
86         }
87         rttiName = p;
88     }
89     *unoName = rtl::OStringToOUString(
90         buf.makeStringAndClear(), RTL_TEXTENCODING_UTF8);
91         //TODO: check conversion failure
92     return true;
93 }
94 
95 class NistHash {
96 public:
97     NistHash(rtl::OString const & text);
98 
99     sal_uInt32 hashdata[5];
100 
101 private:
102     static sal_uInt32 f1(sal_uInt32 x, sal_uInt32 y, sal_uInt32 z)
103     { return z ^ (x & (y ^ z)); }
104 
105     static sal_uInt32 f2(sal_uInt32 x, sal_uInt32 y, sal_uInt32 z)
106     { return x ^ y ^ z; }
107 
108     static sal_uInt32 f3(sal_uInt32 x, sal_uInt32 y, sal_uInt32 z)
109     { return (x & y) + (z & (x ^ y)); }
110 
111     static sal_uInt32 rotl(sal_uInt32 value, sal_uInt32 bits)
112     { return (value << bits) | (value >> (32 - bits)); }
113 
114     sal_uInt32 expand_nostore(sal_uInt32 index) {
115         return data[index & 15] ^ data[(index - 14) & 15] ^
116             data[(index - 8) & 15] ^ data[(index - 3) & 15];
117     }
118 
119     sal_uInt32 expand_store(sal_uInt32 index) {
120         return data[index & 15] ^= data[(index - 14) & 15] ^
121             data[(index - 8) & 15] ^ data[(index - 3) & 15];
122     }
123 
124     void subRound(
125         sal_uInt32 a, sal_uInt32 & b, sal_uInt32 c, sal_uInt32 d,
126         sal_uInt32 & e, sal_uInt32 constant, sal_uInt32 datum,
127         sal_uInt32 function)
128     {
129         e += rotl(a, 5);
130         switch (function) {
131             case 1:
132                 e += f1(b, c, d);
133                 break;
134             case 2:
135             case 4:
136                 e += f2(b, c, d);
137                 break;
138             case 3:
139                 e += f3(b, c, d);
140                 break;
141         }
142         e += constant + datum;
143         b = rotl(b, 30);
144     }
145 
146     void transform();
147 
148     sal_uInt32 data[16];
149 };
150 
151 NistHash::NistHash(rtl::OString const & text) {
152     hashdata[0] = 0x67452301;
153     hashdata[1] = 0xefcdab89;
154     hashdata[2] = 0x98badcfe;
155     hashdata[3] = 0x10325476;
156     hashdata[4] = 0xc3d2e1f0;
157     char const * p = text.getStr();
158     sal_Int32 n = text.getLength();
159     while (n >= sizeof data) {
160         std::memcpy(data, p, sizeof data);
161         p += sizeof data;
162         n -= sizeof data;
163         transform();
164     }
165     std::memcpy(data, p, n);
166     reinterpret_cast< unsigned char *>(data)[n++] = 0x80;
167     if (n > sizeof data - 8) {
168         std::memset(reinterpret_cast< char * >(data) + n, 0, sizeof data - n);
169         transform();
170         std::memset(data, 0, sizeof data  - 8);
171     } else {
172         std::memset(
173             reinterpret_cast< char * >(data) + n, 0, sizeof data - 8 - n);
174     }
175     data[14] = 0;
176     data[15] = text.getLength() << 3;
177     transform();
178 }
179 
180 void NistHash::transform() {
181     sal_uInt32 const K2 = 0x5A827999;
182     sal_uInt32 const K3 = 0x6ED9EBA1;
183     sal_uInt32 const K5 = 0x8F1BBCDC;
184     sal_uInt32 const K10 = 0xCA62C1D6;
185     sal_uInt32 a = hashdata[0];
186     sal_uInt32 b = hashdata[1];
187     sal_uInt32 c = hashdata[2];
188     sal_uInt32 d = hashdata[3];
189     sal_uInt32 e = hashdata[4];
190     subRound(a, b, c, d, e, K2, data[ 0], 1);
191     subRound(e, a, b, c, d, K2, data[ 1], 1);
192     subRound(d, e, a, b, c, K2, data[ 2], 1);
193     subRound(c, d, e, a, b, K2, data[ 3], 1);
194     subRound(b, c, d, e, a, K2, data[ 4], 1);
195     subRound(a, b, c, d, e, K2, data[ 5], 1);
196     subRound(e, a, b, c, d, K2, data[ 6], 1);
197     subRound(d, e, a, b, c, K2, data[ 7], 1);
198     subRound(c, d, e, a, b, K2, data[ 8], 1);
199     subRound(b, c, d, e, a, K2, data[ 9], 1);
200     subRound(a, b, c, d, e, K2, data[10], 1);
201     subRound(e, a, b, c, d, K2, data[11], 1);
202     subRound(d, e, a, b, c, K2, data[12], 1);
203     subRound(c, d, e, a, b, K2, data[13], 1);
204     subRound(b, c, d, e, a, K2, data[14], 1);
205     subRound(a, b, c, d, e, K2, data[15], 1);
206     subRound(e, a, b, c, d, K2, expand_store(16), 1);
207     subRound(d, e, a, b, c, K2, expand_store(17), 1);
208     subRound(c, d, e, a, b, K2, expand_store(18), 1);
209     subRound(b, c, d, e, a, K2, expand_store(19), 1);
210     subRound(a, b, c, d, e, K3, expand_store(20), 2);
211     subRound(e, a, b, c, d, K3, expand_store(21), 2);
212     subRound(d, e, a, b, c, K3, expand_store(22), 2);
213     subRound(c, d, e, a, b, K3, expand_store(23), 2);
214     subRound(b, c, d, e, a, K3, expand_store(24), 2);
215     subRound(a, b, c, d, e, K3, expand_store(25), 2);
216     subRound(e, a, b, c, d, K3, expand_store(26), 2);
217     subRound(d, e, a, b, c, K3, expand_store(27), 2);
218     subRound(c, d, e, a, b, K3, expand_store(28), 2);
219     subRound(b, c, d, e, a, K3, expand_store(29), 2);
220     subRound(a, b, c, d, e, K3, expand_store(30), 2);
221     subRound(e, a, b, c, d, K3, expand_store(31), 2);
222     subRound(d, e, a, b, c, K3, expand_store(32), 2);
223     subRound(c, d, e, a, b, K3, expand_store(33), 2);
224     subRound(b, c, d, e, a, K3, expand_store(34), 2);
225     subRound(a, b, c, d, e, K3, expand_store(35), 2);
226     subRound(e, a, b, c, d, K3, expand_store(36), 2);
227     subRound(d, e, a, b, c, K3, expand_store(37), 2);
228     subRound(c, d, e, a, b, K3, expand_store(38), 2);
229     subRound(b, c, d, e, a, K3, expand_store(39), 2);
230     subRound(a, b, c, d, e, K5, expand_store(40), 3);
231     subRound(e, a, b, c, d, K5, expand_store(41), 3);
232     subRound(d, e, a, b, c, K5, expand_store(42), 3);
233     subRound(c, d, e, a, b, K5, expand_store(43), 3);
234     subRound(b, c, d, e, a, K5, expand_store(44), 3);
235     subRound(a, b, c, d, e, K5, expand_store(45), 3);
236     subRound(e, a, b, c, d, K5, expand_store(46), 3);
237     subRound(d, e, a, b, c, K5, expand_store(47), 3);
238     subRound(c, d, e, a, b, K5, expand_store(48), 3);
239     subRound(b, c, d, e, a, K5, expand_store(49), 3);
240     subRound(a, b, c, d, e, K5, expand_store(50), 3);
241     subRound(e, a, b, c, d, K5, expand_store(51), 3);
242     subRound(d, e, a, b, c, K5, expand_store(52), 3);
243     subRound(c, d, e, a, b, K5, expand_store(53), 3);
244     subRound(b, c, d, e, a, K5, expand_store(54), 3);
245     subRound(a, b, c, d, e, K5, expand_store(55), 3);
246     subRound(e, a, b, c, d, K5, expand_store(56), 3);
247     subRound(d, e, a, b, c, K5, expand_store(57), 3);
248     subRound(c, d, e, a, b, K5, expand_store(58), 3);
249     subRound(b, c, d, e, a, K5, expand_store(59), 3);
250     subRound(a, b, c, d, e, K10, expand_store(60), 4);
251     subRound(e, a, b, c, d, K10, expand_store(61), 4);
252     subRound(d, e, a, b, c, K10, expand_store(62), 4);
253     subRound(c, d, e, a, b, K10, expand_store(63), 4);
254     subRound(b, c, d, e, a, K10, expand_store(64), 4);
255     subRound(a, b, c, d, e, K10, expand_store(65), 4);
256     subRound(e, a, b, c, d, K10, expand_store(66), 4);
257     subRound(d, e, a, b, c, K10, expand_store(67), 4);
258     subRound(c, d, e, a, b, K10, expand_store(68), 4);
259     subRound(b, c, d, e, a, K10, expand_store(69), 4);
260     subRound(a, b, c, d, e, K10, expand_store(70), 4);
261     subRound(e, a, b, c, d, K10, expand_store(71), 4);
262     subRound(d, e, a, b, c, K10, expand_store(72), 4);
263     subRound(c, d, e, a, b, K10, expand_store(73), 4);
264     subRound(b, c, d, e, a, K10, expand_store(74), 4);
265     subRound(a, b, c, d, e, K10, expand_store(75), 4);
266     subRound(e, a, b, c, d, K10, expand_store(76), 4);
267     subRound(d, e, a, b, c, K10, expand_nostore(77), 4);
268     subRound(c, d, e, a, b, K10, expand_nostore(78), 4);
269     subRound(b, c, d, e, a, K10, expand_nostore(79), 4);
270     hashdata[0] += a;
271     hashdata[1] += b;
272     hashdata[2] += c;
273     hashdata[3] += d;
274     hashdata[4] += e;
275 }
276 
277 class RttiMap {
278 public:
279     static __Crun::static_type_info const * get(
280         typelib_CompoundTypeDescription const * type);
281 
282 private:
283     RttiMap(); // not defined
284     RttiMap(RttiMap &); // not defined
285     ~RttiMap(); // not defined
286     void operator =(RttiMap &); // not defined
287 
288     struct Data {
289         __Crun::static_type_info * info;
290         rtl::OString cppName;
291         std::vector< __Crun::class_base_descr > bases;
292     };
293     typedef std::map< rtl::OUString, Data > Map;
294 
295     static void toCppNames(
296         rtl::OUString const & unoName, rtl::OString * cppName,
297         rtl::OString * rttiName);
298 
299     static Data const & get_(typelib_CompoundTypeDescription const * type);
300 
301     static osl::Mutex m_mutex;
302     static Map * m_map;
303 };
304 
305 osl::Mutex RttiMap::m_mutex;
306 RttiMap::Map * RttiMap::m_map;
307 
308 __Crun::static_type_info const * RttiMap::get(
309     typelib_CompoundTypeDescription const * type)
310 {
311     osl::MutexGuard g(m_mutex);
312     if (m_map == NULL) {
313         m_map = new Map; // leaked
314     }
315     return get_(type).info;
316 }
317 
318 void RttiMap::toCppNames(
319     rtl::OUString const & unoName, rtl::OString * cppName,
320     rtl::OString * rttiName)
321 {
322     OSL_ASSERT(cppName != NULL && rttiName != NULL);
323     rtl::OStringBuffer bc;
324     rtl::OStringBuffer br;
325     br.append("__1n");
326     for (sal_Int32 i = 0; i != -1;) {
327         rtl::OUString tok(unoName.getToken(0, '.', i));
328         bc.append(rtl::OUStringToOString(tok, RTL_TEXTENCODING_UTF8));
329             // conversion should never fail, as tok should be well-formed ASCII
330         if (i != -1) {
331             bc.append("::");
332         }
333         sal_Int32 len = tok.getLength();
334         sal_Int32 pos = br.getLength();
335         for (sal_Int32 n = len / 26; n > 0; n /= 26) {
336             br.insert(pos, static_cast< char >('a' + (n % 26)));
337         }
338         br.append(static_cast< char >('A' + (len % 26)));
339         for (sal_Int32 j = 0; j < len; ++j) {
340             sal_Unicode c = tok[j];
341             OSL_ASSERT(
342                 c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' ||
343                 c >= 'a' && c <= 'z');
344             if (c == 'Q') {
345                 br.append("QdD");
346             } else {
347                 br.append(static_cast< char >(c));
348             }
349         }
350     }
351     br.append('_');
352     *cppName = bc.makeStringAndClear();
353     *rttiName = br.makeStringAndClear();
354 }
355 
356 RttiMap::Data const & RttiMap::get_(
357     typelib_CompoundTypeDescription const * type)
358 {
359     rtl::OUString name(type->aBase.pTypeName);
360     Map::iterator it(m_map->find(name));
361     if (it == m_map->end()) {
362         it = m_map->insert(std::make_pair(name, Data())).first;
363         Data & data = it->second;
364         rtl::OString rttiName;
365         toCppNames(name, &data.cppName, &rttiName);
366         data.info = new __Crun::static_type_info;
367         data.info->ty_name = data.cppName.getStr() -
368             reinterpret_cast< char * >(&data.info->ty_name);
369         data.info->reserved = 0;
370         NistHash hash(rttiName);
371         data.info->type_hash[0] = hash.hashdata[0];
372         data.info->type_hash[1] = hash.hashdata[1];
373         data.info->type_hash[2] = hash.hashdata[2];
374         data.info->type_hash[3] = hash.hashdata[3];
375         data.info->flags = 0;
376         data.info->cv_qualifiers = 0;
377         if (type->pBaseTypeDescription != NULL) {
378             data.bases = get_(type->pBaseTypeDescription).bases;
379             OSL_ASSERT(!data.bases.empty());
380             data.bases.back().offset = 0;
381         }
382         __Crun::class_base_descr last;
383         last.type_hash[0] = data.info->type_hash[0];
384         last.type_hash[1] = data.info->type_hash[1];
385         last.type_hash[2] = data.info->type_hash[2];
386         last.type_hash[3] = data.info->type_hash[3];
387         last.offset = 0x8000000000000000;
388         data.bases.push_back(last);
389         data.info->base_table = reinterpret_cast< char * >(&data.bases[0]) -
390             reinterpret_cast< char * >(&data.info->base_table);
391     }
392     return it->second;
393 }
394 
395 void deleteException(
396     void * exception, unsigned int * thunk, typelib_TypeDescription * type)
397 {
398     uno_destructData(
399         exception, type,
400         reinterpret_cast< uno_ReleaseFunc >(css::uno::cpp_release));
401     typelib_typedescription_release(type);
402     delete[] thunk;
403 }
404 
405 }
406 
407 namespace bridges { namespace cpp_uno { namespace cc5_solaris_sparc64 {
408 
409 void raiseException(uno_Any * exception, uno_Mapping * unoToCpp) {
410     bridges::cpp_uno::shared::ArrayPointer< unsigned long > thunkPtr(
411         new unsigned long[4]);
412     typelib_TypeDescription * type = NULL;
413     typelib_typedescriptionreference_getDescription(&type, exception->pType);
414     __Crun::static_type_info const * rtti = RttiMap::get(
415         reinterpret_cast< typelib_CompoundTypeDescription * >(type));
416     void * exc = __Crun::ex_alloc(type->nSize);
417     uno_copyAndConvertData(exc, exception->pData, type, unoToCpp);
418     uno_any_destruct(exception, NULL);
419     unsigned long * thunk = thunkPtr.release();
420     // 0*4: rd %pc, %o1:
421     // 1*4: ldx %o1, (6-0)*4, %o3:
422     thunk[0] = 0x93414000D65A6018;
423     // 2*4: jmpl %o3, %g0, %g0:
424     // 3*4: ldx %o1, (4-0)*4, %o2:
425     thunk[1] = 0x81C2C000D45A6010;
426     // 4*4: .xword type:
427     thunk[2] = reinterpret_cast< unsigned long >(type);
428     // 6*4: .xword deleteException:
429     thunk[3] = reinterpret_cast< unsigned long >(deleteException);
430     flushCode(thunk, thunk + 4);
431     __Crun::ex_throw(exc, rtti, toFunction(thunk));
432 }
433 
434 void fillUnoException(
435     void * cppException, char const * cppName, uno_Any * unoException,
436     uno_Mapping * cppToUno)
437 {
438     rtl::OUString name;
439     typelib_TypeDescription * type = NULL;
440     if (toUnoName(cppName, &name)) {
441         typelib_typedescription_getByName(&type, name.pData);
442     }
443     if (type == NULL || type->eTypeClass != typelib_TypeClass_EXCEPTION) {
444         css::uno::RuntimeException exc(
445             (rtl::OUString(
446                 RTL_CONSTASCII_USTRINGPARAM("Not a UNO exception type: ")) +
447              name),
448             css::uno::Reference< css::uno::XInterface >());
449         uno_type_any_constructAndConvert(
450             unoException, &exc, getCppuType(&exc).getTypeLibType(), cppToUno);
451     } else {
452         uno_any_constructAndConvert(unoException, cppException, type, cppToUno);
453     }
454     if (type != NULL) {
455         typelib_typedescription_release(type);
456     }
457 }
458 
459 } } }
460