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 <stdio.h>
29 #include <string.h>
30 #include <dlfcn.h>
31 #include <cxxabi.h>
32 #include <hash_map>
33 
34 #include <rtl/strbuf.hxx>
35 #include <rtl/ustrbuf.hxx>
36 #include <osl/diagnose.h>
37 #include <osl/mutex.hxx>
38 
39 #include <com/sun/star/uno/genfunc.hxx>
40 #include "com/sun/star/uno/RuntimeException.hpp"
41 #include <typelib/typedescription.hxx>
42 #include <uno/any2.h>
43 
44 #include "share.hxx"
45 
46 
47 using namespace ::std;
48 using namespace ::osl;
49 using namespace ::rtl;
50 using namespace ::com::sun::star::uno;
51 using namespace ::__cxxabiv1;
52 
53 extern sal_Int32 * pHack;
54 extern sal_Int32 nHack;
55 
56 namespace CPPU_CURRENT_NAMESPACE
57 {
58     void dummy_can_throw_anything( char const * )
59     {
60     }
61 
62     //===================================================================
63     static OUString toUNOname( char const * p ) SAL_THROW( () )
64     {
65 #if OSL_DEBUG_LEVEL > 1
66         char const * start = p;
67 #endif
68 
69         // example: N3com3sun4star4lang24IllegalArgumentExceptionE
70 
71         OUStringBuffer buf( 64 );
72         OSL_ASSERT( 'N' == *p );
73         ++p; // skip N
74 
75         while ('E' != *p)
76         {
77             // read chars count
78             long n = (*p++ - '0');
79             while ('0' <= *p && '9' >= *p)
80             {
81                 n *= 10;
82                 n += (*p++ - '0');
83             }
84             buf.appendAscii( p, n );
85             p += n;
86             if ('E' != *p)
87                 buf.append( (sal_Unicode)'.' );
88         }
89 
90 #if OSL_DEBUG_LEVEL > 1
91         OUString ret( buf.makeStringAndClear() );
92         OString c_ret( OUStringToOString( ret, RTL_TEXTENCODING_ASCII_US ) );
93         fprintf( stderr, "> toUNOname(): %s => %s\n", start, c_ret.getStr() );
94         return ret;
95 #else
96         return buf.makeStringAndClear();
97 #endif
98     }
99 
100     //=====================================================================
101     class RTTI
102     {
103         typedef hash_map< OUString, type_info *, OUStringHash > t_rtti_map;
104 
105         Mutex m_mutex;
106         t_rtti_map m_rttis;
107         t_rtti_map m_generatedRttis;
108 
109         void * m_hApp;
110 
111     public:
112         RTTI() SAL_THROW( () );
113         ~RTTI() SAL_THROW( () );
114 
115         type_info * getRTTI(typelib_CompoundTypeDescription *) SAL_THROW( () );
116     };
117     //____________________________________________________________________
118     RTTI::RTTI() SAL_THROW( () )
119         : m_hApp( dlopen( 0, RTLD_LAZY ) )
120     {
121     }
122     //____________________________________________________________________
123     RTTI::~RTTI() SAL_THROW( () )
124     {
125         dlclose( m_hApp );
126     }
127 
128     //____________________________________________________________________
129     type_info * RTTI::getRTTI( typelib_CompoundTypeDescription *pTypeDescr ) SAL_THROW( () )
130     {
131         type_info * rtti;
132 
133         OUString const & unoName = *(OUString const *)&pTypeDescr->aBase.pTypeName;
134 
135         MutexGuard guard( m_mutex );
136         t_rtti_map::const_iterator iRttiFind( m_rttis.find( unoName ) );
137         if (iRttiFind == m_rttis.end())
138         {
139             // RTTI symbol
140             OStringBuffer buf( 64 );
141             buf.append( RTL_CONSTASCII_STRINGPARAM("_ZTIN") );
142             sal_Int32 index = 0;
143             do
144             {
145                 OUString token( unoName.getToken( 0, '.', index ) );
146                 buf.append( token.getLength() );
147                 OString c_token( OUStringToOString( token, RTL_TEXTENCODING_ASCII_US ) );
148                 buf.append( c_token );
149             }
150             while (index >= 0);
151             buf.append( 'E' );
152 
153             OString symName( buf.makeStringAndClear() );
154             rtti = (type_info *)dlsym( m_hApp, symName.getStr() );
155 
156             if (rtti)
157             {
158                 pair< t_rtti_map::iterator, bool > insertion(
159                     m_rttis.insert( t_rtti_map::value_type( unoName, rtti ) ) );
160                 OSL_ENSURE( insertion.second, "### inserting new rtti failed?!" );
161             }
162             else
163             {
164                 // try to lookup the symbol in the generated rtti map
165                 t_rtti_map::const_iterator iFind( m_generatedRttis.find( unoName ) );
166                 if (iFind == m_generatedRttis.end())
167                 {
168                     // we must generate it !
169                     // symbol and rtti-name is nearly identical,
170                     // the symbol is prefixed with _ZTI
171                     char const * rttiName = symName.getStr() +4;
172 #if OSL_DEBUG_LEVEL > 1
173                     fprintf( stderr,"generated rtti for %s\n", rttiName );
174 #endif
175                     if (pTypeDescr->pBaseTypeDescription)
176                     {
177                         // ensure availability of base
178                         type_info * base_rtti = getRTTI(
179                             (typelib_CompoundTypeDescription *)pTypeDescr->pBaseTypeDescription );
180                         rtti = new __si_class_type_info(
181                             strdup( rttiName ), (__class_type_info *)base_rtti );
182                     }
183                     else
184                     {
185                         // this class has no base class
186                         rtti = new __class_type_info( strdup( rttiName ) );
187                     }
188 
189                     pair< t_rtti_map::iterator, bool > insertion(
190                         m_generatedRttis.insert( t_rtti_map::value_type( unoName, rtti ) ) );
191                     OSL_ENSURE( insertion.second, "### inserting new generated rtti failed?!" );
192                 }
193                 else // taking already generated rtti
194                 {
195                     rtti = iFind->second;
196                 }
197             }
198         }
199         else
200         {
201             rtti = iRttiFind->second;
202         }
203 
204         return rtti;
205     }
206 
207     //------------------------------------------------------------------
208     static void deleteException( void * pExc )
209     {
210         __cxa_exception const * header = ((__cxa_exception const *)pExc - 1);
211         typelib_TypeDescription * pTD = 0;
212         OUString unoName( toUNOname( header->exceptionType->name() ) );
213         ::typelib_typedescription_getByName( &pTD, unoName.pData );
214         OSL_ENSURE( pTD, "### unknown exception type! leaving out destruction => leaking!!!" );
215         if (pTD)
216         {
217             ::uno_destructData( pExc, pTD, cpp_release );
218             ::typelib_typedescription_release( pTD );
219         }
220     }
221 
222     //==================================================================
223     void raiseException( uno_Any * pUnoExc, uno_Mapping * pUno2Cpp )
224     {
225 #if OSL_DEBUG_LEVEL > 1
226         OString cstr(
227             OUStringToOString(
228                 *reinterpret_cast< OUString const * >( &pUnoExc->pType->pTypeName ),
229                 RTL_TEXTENCODING_ASCII_US ) );
230         fprintf( stderr, "> uno exception occured: %s\n", cstr.getStr() );
231 #endif
232         void * pCppExc;
233         type_info * rtti;
234 
235         {
236         // construct cpp exception object
237         typelib_TypeDescription * pTypeDescr = 0;
238         TYPELIB_DANGER_GET( &pTypeDescr, pUnoExc->pType );
239         OSL_ASSERT( pTypeDescr );
240         if (! pTypeDescr)
241         {
242             throw RuntimeException(
243                 OUString( RTL_CONSTASCII_USTRINGPARAM("cannot get typedescription for type ") ) +
244                 *reinterpret_cast< OUString const * >( &pUnoExc->pType->pTypeName ),
245                 Reference< XInterface >() );
246         }
247 
248         pCppExc = __cxa_allocate_exception( pTypeDescr->nSize );
249         ::uno_copyAndConvertData( pCppExc, pUnoExc->pData, pTypeDescr, pUno2Cpp );
250 
251         // destruct uno exception
252         ::uno_any_destruct( pUnoExc, 0 );
253         // avoiding locked counts
254         static RTTI * s_rtti = 0;
255         if (! s_rtti)
256         {
257             MutexGuard guard( Mutex::getGlobalMutex() );
258             if (! s_rtti)
259             {
260 #ifdef LEAK_STATIC_DATA
261                 s_rtti = new RTTI();
262 #else
263                 static RTTI rtti_data;
264                 s_rtti = &rtti_data;
265 #endif
266             }
267         }
268         rtti = (type_info *)s_rtti->getRTTI( (typelib_CompoundTypeDescription *) pTypeDescr );
269         TYPELIB_DANGER_RELEASE( pTypeDescr );
270         OSL_ENSURE( rtti, "### no rtti for throwing exception!" );
271         if (! rtti)
272         {
273             throw RuntimeException(
274                 OUString( RTL_CONSTASCII_USTRINGPARAM("no rtti for type ") ) +
275                 *reinterpret_cast< OUString const * >( &pUnoExc->pType->pTypeName ),
276                 Reference< XInterface >() );
277         }
278         }
279 
280 
281 	__cxa_throw( pCppExc, rtti, deleteException );
282     }
283 
284     static void* getAdjustedPtr(__cxa_exception* header)
285     {
286         return header->adjustedPtr;
287     }
288 
289     //===================================================================
290     void fillUnoException( __cxa_exception * header, uno_Any * pUnoExc, uno_Mapping * pCpp2Uno )
291     {
292         if (! header)
293         {
294             RuntimeException aRE(
295                 OUString( RTL_CONSTASCII_USTRINGPARAM("no exception header!") ),
296                 Reference< XInterface >() );
297             Type const & rType = ::getCppuType( &aRE );
298             uno_type_any_constructAndConvert( pUnoExc, &aRE, rType.getTypeLibType(), pCpp2Uno );
299 #if OSL_DEBUG_LEVEL > 0
300             OString cstr( OUStringToOString( aRE.Message, RTL_TEXTENCODING_ASCII_US ) );
301             OSL_ENSURE( 0, cstr.getStr() );
302 #endif
303             return;
304         }
305 
306         typelib_TypeDescription * pExcTypeDescr = 0;
307         OUString unoName( toUNOname( header->exceptionType->name() ) );
308 #if OSL_DEBUG_LEVEL > 1
309         OString cstr_unoName( OUStringToOString( unoName, RTL_TEXTENCODING_ASCII_US ) );
310         fprintf( stderr, "> c++ exception occured: %s\n", cstr_unoName.getStr() );
311 #endif
312         typelib_typedescription_getByName( &pExcTypeDescr, unoName.pData );
313         if (0 == pExcTypeDescr)
314         {
315             RuntimeException aRE(
316                 OUString( RTL_CONSTASCII_USTRINGPARAM("exception type not found: ") ) + unoName,
317                 Reference< XInterface >() );
318             Type const & rType = ::getCppuType( &aRE );
319             uno_type_any_constructAndConvert( pUnoExc, &aRE, rType.getTypeLibType(), pCpp2Uno );
320 #if OSL_DEBUG_LEVEL > 0
321             OString cstr( OUStringToOString( aRE.Message, RTL_TEXTENCODING_ASCII_US ) );
322             OSL_ENSURE( 0, cstr.getStr() );
323 #endif
324         }
325         else
326         {
327             // construct uno exception any
328             uno_any_constructAndConvert( pUnoExc, getAdjustedPtr(header), pExcTypeDescr, pCpp2Uno );
329             typelib_typedescription_release( pExcTypeDescr );
330         }
331     }
332 }
333 
334 /* vi:set tabstop=4 shiftwidth=4 expandtab: */
335