1*54c06456SAndrew Rist /**************************************************************
2cdf0e10cSrcweir *
3*54c06456SAndrew Rist * Licensed to the Apache Software Foundation (ASF) under one
4*54c06456SAndrew Rist * or more contributor license agreements. See the NOTICE file
5*54c06456SAndrew Rist * distributed with this work for additional information
6*54c06456SAndrew Rist * regarding copyright ownership. The ASF licenses this file
7*54c06456SAndrew Rist * to you under the Apache License, Version 2.0 (the
8*54c06456SAndrew Rist * "License"); you may not use this file except in compliance
9*54c06456SAndrew Rist * with the License. You may obtain a copy of the License at
10*54c06456SAndrew Rist *
11*54c06456SAndrew Rist * http://www.apache.org/licenses/LICENSE-2.0
12*54c06456SAndrew Rist *
13*54c06456SAndrew Rist * Unless required by applicable law or agreed to in writing,
14*54c06456SAndrew Rist * software distributed under the License is distributed on an
15*54c06456SAndrew Rist * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16*54c06456SAndrew Rist * KIND, either express or implied. See the License for the
17*54c06456SAndrew Rist * specific language governing permissions and limitations
18*54c06456SAndrew Rist * under the License.
19*54c06456SAndrew Rist *
20*54c06456SAndrew Rist *************************************************************/
21*54c06456SAndrew Rist
22*54c06456SAndrew Rist
23cdf0e10cSrcweir
24cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove
25cdf0e10cSrcweir #include "precompiled_cli_ure.hxx"
26cdf0e10cSrcweir
27cdf0e10cSrcweir #include <vcclr.h>
28cdf0e10cSrcweir //ToDo: remove when build with .NET 2
29cdf0e10cSrcweir #pragma warning(push, 1)
30cdf0e10cSrcweir #include <windows.h>
31cdf0e10cSrcweir #include "uno/environment.hxx"
32cdf0e10cSrcweir #pragma warning(pop)
33cdf0e10cSrcweir #include "rtl/unload.h"
34cdf0e10cSrcweir #include "uno/lbnames.h"
35cdf0e10cSrcweir #include "uno/mapping.hxx"
36cdf0e10cSrcweir #include "typelib/typedescription.hxx"
37cdf0e10cSrcweir #include "rtl/ustring.hxx"
38cdf0e10cSrcweir
39cdf0e10cSrcweir #include "cli_bridge.h"
40cdf0e10cSrcweir #include "cli_proxy.h"
41cdf0e10cSrcweir namespace srr= System::Runtime::Remoting;
42cdf0e10cSrcweir namespace srrp= System::Runtime::Remoting::Proxies;
43cdf0e10cSrcweir #using <mscorlib.dll>
44cdf0e10cSrcweir #if defined(_MSC_VER) && (_MSC_VER < 1400)
45cdf0e10cSrcweir #include <_vcclrit.h>
46cdf0e10cSrcweir #endif
47cdf0e10cSrcweir
48cdf0e10cSrcweir namespace cssu= com::sun::star::uno;
49cdf0e10cSrcweir
50cdf0e10cSrcweir
51cdf0e10cSrcweir namespace sri= System::Runtime::InteropServices;
52cdf0e10cSrcweir using namespace rtl;
53cdf0e10cSrcweir
54cdf0e10cSrcweir namespace cli_uno
55cdf0e10cSrcweir {
56cdf0e10cSrcweir
57cdf0e10cSrcweir extern "C"
58cdf0e10cSrcweir {
Mapping_acquire(uno_Mapping * mapping)59cdf0e10cSrcweir void SAL_CALL Mapping_acquire( uno_Mapping * mapping )
60cdf0e10cSrcweir SAL_THROW_EXTERN_C()
61cdf0e10cSrcweir {
62cdf0e10cSrcweir Mapping const * that = static_cast< Mapping const * >( mapping );
63cdf0e10cSrcweir that->m_bridge->acquire();
64cdf0e10cSrcweir }
65cdf0e10cSrcweir //--------------------------------------------------------------------------------------------------
Mapping_release(uno_Mapping * mapping)66cdf0e10cSrcweir void SAL_CALL Mapping_release( uno_Mapping * mapping )
67cdf0e10cSrcweir SAL_THROW_EXTERN_C()
68cdf0e10cSrcweir {
69cdf0e10cSrcweir Mapping const * that = static_cast< Mapping const * >( mapping );
70cdf0e10cSrcweir that->m_bridge->release();
71cdf0e10cSrcweir }
72cdf0e10cSrcweir
73cdf0e10cSrcweir
74cdf0e10cSrcweir //--------------------------------------------------------------------------------------------------
Mapping_cli2uno(uno_Mapping * mapping,void ** ppOut,void * pIn,typelib_InterfaceTypeDescription * td)75cdf0e10cSrcweir void SAL_CALL Mapping_cli2uno(
76cdf0e10cSrcweir uno_Mapping * mapping, void ** ppOut,
77cdf0e10cSrcweir void * pIn, typelib_InterfaceTypeDescription * td )
78cdf0e10cSrcweir SAL_THROW_EXTERN_C()
79cdf0e10cSrcweir {
80cdf0e10cSrcweir uno_Interface ** ppUnoI = (uno_Interface **)ppOut;
81cdf0e10cSrcweir intptr_t cliI = (intptr_t)pIn;
82cdf0e10cSrcweir
83cdf0e10cSrcweir OSL_ENSURE( ppUnoI && td, "### null ptr!" );
84cdf0e10cSrcweir
85cdf0e10cSrcweir if (0 != *ppUnoI)
86cdf0e10cSrcweir {
87cdf0e10cSrcweir uno_Interface * pUnoI = *(uno_Interface **)ppUnoI;
88cdf0e10cSrcweir (*pUnoI->release)( pUnoI );
89cdf0e10cSrcweir *ppUnoI = 0;
90cdf0e10cSrcweir }
91cdf0e10cSrcweir try
92cdf0e10cSrcweir {
93cdf0e10cSrcweir Mapping const * that = static_cast< Mapping const * >( mapping );
94cdf0e10cSrcweir Bridge * bridge = that->m_bridge;
95cdf0e10cSrcweir
96cdf0e10cSrcweir if (0 != cliI)
97cdf0e10cSrcweir {
98cdf0e10cSrcweir System::Object* cliObj= sri::GCHandle::op_Explicit(cliI).Target;
99cdf0e10cSrcweir (*ppOut)= bridge->map_cli2uno(cliObj, (typelib_TypeDescription*) td);
100cdf0e10cSrcweir }
101cdf0e10cSrcweir }
102cdf0e10cSrcweir catch (BridgeRuntimeError & err)
103cdf0e10cSrcweir {
104cdf0e10cSrcweir #if OSL_DEBUG_LEVEL >= 1
105cdf0e10cSrcweir OString cstr_msg(
106cdf0e10cSrcweir OUStringToOString(
107cdf0e10cSrcweir OUSTR("[cli_uno bridge error] ") + err.m_message, RTL_TEXTENCODING_ASCII_US ) );
108cdf0e10cSrcweir OSL_ENSURE( 0, cstr_msg.getStr() );
109cdf0e10cSrcweir #else
110cdf0e10cSrcweir (void) err; // unused
111cdf0e10cSrcweir #endif
112cdf0e10cSrcweir }
113cdf0e10cSrcweir }
114cdf0e10cSrcweir //--------------------------------------------------------------------------------------------------
Mapping_uno2cli(uno_Mapping * mapping,void ** ppOut,void * pIn,typelib_InterfaceTypeDescription * td)115cdf0e10cSrcweir void SAL_CALL Mapping_uno2cli(
116cdf0e10cSrcweir uno_Mapping * mapping, void ** ppOut,
117cdf0e10cSrcweir void * pIn, typelib_InterfaceTypeDescription * td )
118cdf0e10cSrcweir SAL_THROW_EXTERN_C()
119cdf0e10cSrcweir {
120cdf0e10cSrcweir try
121cdf0e10cSrcweir {
122cdf0e10cSrcweir OSL_ENSURE( td && ppOut, "### null ptr!" );
123cdf0e10cSrcweir OSL_ENSURE( (sizeof(System::Char) == sizeof(sal_Unicode))
124cdf0e10cSrcweir && (sizeof(System::Boolean) == sizeof(sal_Bool))
125cdf0e10cSrcweir && (sizeof(System::SByte) == sizeof(sal_Int8))
126cdf0e10cSrcweir && (sizeof(System::Int16) == sizeof(sal_Int16))
127cdf0e10cSrcweir && (sizeof(System::UInt16) == sizeof(sal_uInt16))
128cdf0e10cSrcweir && (sizeof(System::Int32) == sizeof(sal_Int32))
129cdf0e10cSrcweir && (sizeof(System::UInt32) == sizeof(sal_uInt32))
130cdf0e10cSrcweir && (sizeof(System::Int64) == sizeof(sal_Int64))
131cdf0e10cSrcweir && (sizeof(System::UInt64) == sizeof(sal_uInt64))
132cdf0e10cSrcweir && (sizeof(System::Single) == sizeof(float))
133cdf0e10cSrcweir && (sizeof(System::Double) == sizeof(double)),
134cdf0e10cSrcweir "[cli_uno bridge] incompatible .NET data types");
135cdf0e10cSrcweir intptr_t * ppDNetI = (intptr_t *)ppOut;
136cdf0e10cSrcweir uno_Interface * pUnoI = (uno_Interface *)pIn;
137cdf0e10cSrcweir
138cdf0e10cSrcweir Mapping const * that = static_cast< Mapping const * >( mapping );
139cdf0e10cSrcweir Bridge * bridge = that->m_bridge;
140cdf0e10cSrcweir
141cdf0e10cSrcweir if (0 != *ppDNetI)
142cdf0e10cSrcweir {
143cdf0e10cSrcweir sri::GCHandle::op_Explicit(ppDNetI).Free();
144cdf0e10cSrcweir }
145cdf0e10cSrcweir
146cdf0e10cSrcweir if (0 != pUnoI)
147cdf0e10cSrcweir {
148cdf0e10cSrcweir System::Object* cliI= bridge->map_uno2cli(pUnoI, td);
149cdf0e10cSrcweir intptr_t ptr= NULL;
150cdf0e10cSrcweir if(cliI)
151cdf0e10cSrcweir {
152cdf0e10cSrcweir ptr= sri::GCHandle::op_Explicit(sri::GCHandle::Alloc(cliI))
153cdf0e10cSrcweir #ifdef _WIN32
154cdf0e10cSrcweir .ToInt32();
155cdf0e10cSrcweir #else /* defined(_WIN64) */ .ToInt64();
156cdf0e10cSrcweir #endif
157cdf0e10cSrcweir }
158cdf0e10cSrcweir (*ppOut)= reinterpret_cast<void*>(ptr);
159cdf0e10cSrcweir }
160cdf0e10cSrcweir }
161cdf0e10cSrcweir catch (BridgeRuntimeError & err)
162cdf0e10cSrcweir {
163cdf0e10cSrcweir #if OSL_DEBUG_LEVEL >= 1
164cdf0e10cSrcweir rtl::OString cstr_msg(
165cdf0e10cSrcweir rtl::OUStringToOString(
166cdf0e10cSrcweir OUSTR("[cli_uno bridge error] ") + err.m_message, RTL_TEXTENCODING_ASCII_US ) );
167cdf0e10cSrcweir OSL_ENSURE( 0, cstr_msg.getStr() );
168cdf0e10cSrcweir #else
169cdf0e10cSrcweir (void) err; // unused
170cdf0e10cSrcweir #endif
171cdf0e10cSrcweir }
172cdf0e10cSrcweir }
173cdf0e10cSrcweir
174cdf0e10cSrcweir //__________________________________________________________________________________________________
Bridge_free(uno_Mapping * mapping)175cdf0e10cSrcweir void SAL_CALL Bridge_free( uno_Mapping * mapping )
176cdf0e10cSrcweir SAL_THROW_EXTERN_C()
177cdf0e10cSrcweir {
178cdf0e10cSrcweir Mapping * that = static_cast< Mapping * >( mapping );
179cdf0e10cSrcweir delete that->m_bridge;
180cdf0e10cSrcweir }
181cdf0e10cSrcweir
182cdf0e10cSrcweir } //extern C
183cdf0e10cSrcweir } //namespace
184cdf0e10cSrcweir
185cdf0e10cSrcweir namespace cli_uno
186cdf0e10cSrcweir {
187cdf0e10cSrcweir
188cdf0e10cSrcweir //__________________________________________________________________________________________________
189cdf0e10cSrcweir /** ToDo
190cdf0e10cSrcweir I doubt that the the case that the ref count raises from 0 to 1
191cdf0e10cSrcweir can occur. uno_ext_getMapping returns an acquired mapping. Every time
192cdf0e10cSrcweir that function is called then a new mapping is created. Following the
193cdf0e10cSrcweir rules of ref counted objects, then if the ref count is null noone has
194cdf0e10cSrcweir a reference to the object anymore. Hence noone can call acquire. If someone
195cdf0e10cSrcweir calls acquire then they must have kept an unacquired pointer which is
196cdf0e10cSrcweir illegal.
197cdf0e10cSrcweir */
acquire() const198cdf0e10cSrcweir void Bridge::acquire() const SAL_THROW( () )
199cdf0e10cSrcweir {
200cdf0e10cSrcweir if (1 == osl_incrementInterlockedCount( &m_ref ))
201cdf0e10cSrcweir {
202cdf0e10cSrcweir if (m_registered_cli2uno)
203cdf0e10cSrcweir {
204cdf0e10cSrcweir uno_Mapping * mapping = const_cast<Mapping*>(&m_cli2uno);
205cdf0e10cSrcweir uno_registerMapping(
206cdf0e10cSrcweir & const_cast<uno_Mapping*>(mapping), Bridge_free, m_uno_cli_env, (uno_Environment *)m_uno_env, 0 );
207cdf0e10cSrcweir }
208cdf0e10cSrcweir else
209cdf0e10cSrcweir {
210cdf0e10cSrcweir uno_Mapping * mapping = const_cast<Mapping*>(&m_uno2cli);
211cdf0e10cSrcweir uno_registerMapping(
212cdf0e10cSrcweir &mapping, Bridge_free, (uno_Environment *)m_uno_env, m_uno_cli_env, 0 );
213cdf0e10cSrcweir }
214cdf0e10cSrcweir }
215cdf0e10cSrcweir }
216cdf0e10cSrcweir //__________________________________________________________________________________________________
release() const217cdf0e10cSrcweir void Bridge::release() const SAL_THROW( () )
218cdf0e10cSrcweir {
219cdf0e10cSrcweir if (! osl_decrementInterlockedCount( &m_ref ))
220cdf0e10cSrcweir {
221cdf0e10cSrcweir uno_revokeMapping(
222cdf0e10cSrcweir m_registered_cli2uno
223cdf0e10cSrcweir ? const_cast<Mapping*>(&m_cli2uno)
224cdf0e10cSrcweir : const_cast<Mapping*>(&m_uno2cli) );
225cdf0e10cSrcweir }
226cdf0e10cSrcweir }
227cdf0e10cSrcweir //__________________________________________________________________________________________________
Bridge(uno_Environment * uno_cli_env,uno_ExtEnvironment * uno_env,bool registered_cli2uno)228cdf0e10cSrcweir Bridge::Bridge(
229cdf0e10cSrcweir uno_Environment * uno_cli_env, uno_ExtEnvironment * uno_env,
230cdf0e10cSrcweir bool registered_cli2uno )
231cdf0e10cSrcweir : m_ref( 1 ),
232cdf0e10cSrcweir m_uno_env( uno_env ),
233cdf0e10cSrcweir m_uno_cli_env( uno_cli_env ),
234cdf0e10cSrcweir m_registered_cli2uno( registered_cli2uno )
235cdf0e10cSrcweir {
236cdf0e10cSrcweir OSL_ASSERT( 0 != m_uno_cli_env && 0 != m_uno_env );
237cdf0e10cSrcweir (*((uno_Environment *)m_uno_env)->acquire)( (uno_Environment *)m_uno_env );
238cdf0e10cSrcweir (*m_uno_cli_env->acquire)( m_uno_cli_env );
239cdf0e10cSrcweir
240cdf0e10cSrcweir // cli2uno
241cdf0e10cSrcweir m_cli2uno.acquire = Mapping_acquire;
242cdf0e10cSrcweir m_cli2uno.release = Mapping_release;
243cdf0e10cSrcweir m_cli2uno.mapInterface = Mapping_cli2uno;
244cdf0e10cSrcweir m_cli2uno.m_bridge = this;
245cdf0e10cSrcweir // uno2cli
246cdf0e10cSrcweir m_uno2cli.acquire = Mapping_acquire;
247cdf0e10cSrcweir m_uno2cli.release = Mapping_release;
248cdf0e10cSrcweir m_uno2cli.mapInterface = Mapping_uno2cli;
249cdf0e10cSrcweir m_uno2cli.m_bridge = this;
250cdf0e10cSrcweir
251cdf0e10cSrcweir }
252cdf0e10cSrcweir
253cdf0e10cSrcweir //__________________________________________________________________________________________________
~Bridge()254cdf0e10cSrcweir Bridge::~Bridge() SAL_THROW( () )
255cdf0e10cSrcweir {
256cdf0e10cSrcweir //System::GC::Collect();
257cdf0e10cSrcweir (*m_uno_cli_env->release)( m_uno_cli_env );
258cdf0e10cSrcweir (*((uno_Environment *)m_uno_env)->release)( (uno_Environment *)m_uno_env );
259cdf0e10cSrcweir }
260cdf0e10cSrcweir
261cdf0e10cSrcweir
262cdf0e10cSrcweir
263cdf0e10cSrcweir } //namespace cli_uno
264cdf0e10cSrcweir
265cdf0e10cSrcweir extern "C"
266cdf0e10cSrcweir {
267cdf0e10cSrcweir
268cdf0e10cSrcweir namespace cli_uno
269cdf0e10cSrcweir {
270cdf0e10cSrcweir //--------------------------------------------------------------------------------------------------
cli_env_disposing(uno_Environment * uno_cli_env)271cdf0e10cSrcweir void SAL_CALL cli_env_disposing( uno_Environment * uno_cli_env )
272cdf0e10cSrcweir SAL_THROW_EXTERN_C()
273cdf0e10cSrcweir {
274cdf0e10cSrcweir uno_cli_env->pContext = 0;
275cdf0e10cSrcweir }
276cdf0e10cSrcweir
277cdf0e10cSrcweir //##################################################################################################
uno_initEnvironment(uno_Environment * uno_cli_env)278cdf0e10cSrcweir void SAL_CALL uno_initEnvironment( uno_Environment * uno_cli_env )
279cdf0e10cSrcweir SAL_THROW_EXTERN_C()
280cdf0e10cSrcweir {
281cdf0e10cSrcweir //ToDo: remove when compiled with .NET 2
282cdf0e10cSrcweir #if defined(_MSC_VER) && (_MSC_VER < 1400)
283cdf0e10cSrcweir __crt_dll_initialize();
284cdf0e10cSrcweir #endif
285cdf0e10cSrcweir
286cdf0e10cSrcweir uno_cli_env->environmentDisposing= cli_env_disposing;
287cdf0e10cSrcweir uno_cli_env->pExtEnv = 0;
288cdf0e10cSrcweir //Set the console to print Trace messages
289cdf0e10cSrcweir #if OSL_DEBUG_LEVEL >= 1
290cdf0e10cSrcweir System::Diagnostics::Trace::get_Listeners()->
291cdf0e10cSrcweir Add( new System::Diagnostics::TextWriterTraceListener(System::Console::get_Out()));
292cdf0e10cSrcweir #endif
293cdf0e10cSrcweir OSL_ASSERT( 0 == uno_cli_env->pContext );
294cdf0e10cSrcweir
295cdf0e10cSrcweir // We let the Cli_environment leak, since there is no good point where we could destruct it.
296cdf0e10cSrcweir //dispose is not used because we would have then also synchronize the calls to proxies. If the
297cdf0e10cSrcweir //Cli_environment is disposed, we must prevent all calls, otherwise we may crash at points
298cdf0e10cSrcweir //where g_cli_env is accessed.
299cdf0e10cSrcweir //When we compile the bridge with .NET 2 then we can again hold g_cli_env as a static gcroot
300cdf0e10cSrcweir //member in a unmanaged class, such as Bridge.
301cdf0e10cSrcweir CliEnvHolder::g_cli_env = new Cli_environment();
302cdf0e10cSrcweir }
303cdf0e10cSrcweir //##################################################################################################
uno_ext_getMapping(uno_Mapping ** ppMapping,uno_Environment * pFrom,uno_Environment * pTo)304cdf0e10cSrcweir void SAL_CALL uno_ext_getMapping(
305cdf0e10cSrcweir uno_Mapping ** ppMapping, uno_Environment * pFrom, uno_Environment * pTo )
306cdf0e10cSrcweir SAL_THROW_EXTERN_C()
307cdf0e10cSrcweir {
308cdf0e10cSrcweir OSL_ASSERT( 0 != ppMapping && 0 != pFrom && 0 != pTo );
309cdf0e10cSrcweir if (*ppMapping)
310cdf0e10cSrcweir {
311cdf0e10cSrcweir (*(*ppMapping)->release)( *ppMapping );
312cdf0e10cSrcweir *ppMapping = 0;
313cdf0e10cSrcweir }
314cdf0e10cSrcweir
315cdf0e10cSrcweir
316cdf0e10cSrcweir OUString const & from_env_typename = *reinterpret_cast< OUString const * >(
317cdf0e10cSrcweir &pFrom->pTypeName );
318cdf0e10cSrcweir OUString const & to_env_typename = *reinterpret_cast< OUString const * >(
319cdf0e10cSrcweir &pTo->pTypeName );
320cdf0e10cSrcweir
321cdf0e10cSrcweir uno_Mapping * mapping = 0;
322cdf0e10cSrcweir
323cdf0e10cSrcweir try
324cdf0e10cSrcweir {
325cdf0e10cSrcweir if (from_env_typename.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM(UNO_LB_CLI) ) &&
326cdf0e10cSrcweir to_env_typename.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM(UNO_LB_UNO) ))
327cdf0e10cSrcweir {
328cdf0e10cSrcweir Bridge * bridge = new Bridge( pFrom, pTo->pExtEnv, true ); // ref count = 1
329cdf0e10cSrcweir mapping = &bridge->m_cli2uno;
330cdf0e10cSrcweir uno_registerMapping(
331cdf0e10cSrcweir &mapping, Bridge_free, pFrom, (uno_Environment *)pTo->pExtEnv, 0 );
332cdf0e10cSrcweir }
333cdf0e10cSrcweir else if (from_env_typename.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM(UNO_LB_UNO) ) &&
334cdf0e10cSrcweir to_env_typename.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM(UNO_LB_CLI) ))
335cdf0e10cSrcweir {
336cdf0e10cSrcweir Bridge * bridge = new Bridge( pTo, pFrom->pExtEnv, false ); // ref count = 1
337cdf0e10cSrcweir mapping = &bridge->m_uno2cli;
338cdf0e10cSrcweir uno_registerMapping(
339cdf0e10cSrcweir &mapping, Bridge_free, (uno_Environment *)pFrom->pExtEnv, pTo, 0 );
340cdf0e10cSrcweir }
341cdf0e10cSrcweir }
342cdf0e10cSrcweir catch (BridgeRuntimeError & err)
343cdf0e10cSrcweir {
344cdf0e10cSrcweir #if OSL_DEBUG_LEVEL >= 1
345cdf0e10cSrcweir OString cstr_msg(
346cdf0e10cSrcweir OUStringToOString(
347cdf0e10cSrcweir OUSTR("[cli_uno bridge error] ") + err.m_message, RTL_TEXTENCODING_ASCII_US ) );
348cdf0e10cSrcweir OSL_ENSURE( 0, cstr_msg.getStr() );
349cdf0e10cSrcweir #else
350cdf0e10cSrcweir (void) err; // unused
351cdf0e10cSrcweir #endif
352cdf0e10cSrcweir }
353cdf0e10cSrcweir *ppMapping = mapping;
354cdf0e10cSrcweir }
355cdf0e10cSrcweir
356cdf0e10cSrcweir
357cdf0e10cSrcweir //##################################################################################################
component_canUnload(TimeValue *)358cdf0e10cSrcweir sal_Bool SAL_CALL component_canUnload( TimeValue * )
359cdf0e10cSrcweir SAL_THROW_EXTERN_C()
360cdf0e10cSrcweir {
361cdf0e10cSrcweir return true;
362cdf0e10cSrcweir }
363cdf0e10cSrcweir
364cdf0e10cSrcweir }
365cdf0e10cSrcweir }
366