blob: 9f32e2d50eb48d0af90073df2281b91c43aa35b5 [file] [log] [blame]
/**************************************************************
*
* 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
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_cli_ure.hxx"
#include "climaker_share.h"
#include "rtl/string.hxx"
#include "rtl/ustrbuf.hxx"
#include "com/sun/star/reflection/XIndirectTypeDescription.hpp"
#include "com/sun/star/reflection/XStructTypeDescription.hpp"
#include "com/sun/star/reflection/XInterfaceTypeDescription2.hpp"
#include "com/sun/star/reflection/XInterfaceMethodTypeDescription.hpp"
#include "com/sun/star/reflection/XInterfaceAttributeTypeDescription.hpp"
#include "com/sun/star/reflection/XInterfaceAttributeTypeDescription2.hpp"
#include <vector>
using namespace ::System::Reflection;
using namespace ::rtl;
using namespace ::com::sun::star;
using namespace ::com::sun::star::uno;
namespace climaker
{
System::String* mapUnoPolymorphicName(System::String* unoName);
//------------------------------------------------------------------------------
static inline ::System::String * to_cts_name(
OUString const & uno_name )
{
OUStringBuffer buf( 7 + uno_name.getLength() );
buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("unoidl.") );
buf.append( uno_name );
return ustring_to_String( buf.makeStringAndClear() );
}
//------------------------------------------------------------------------------
static inline ::System::Object * to_cli_constant( Any const & value )
{
switch (value.getValueTypeClass())
{
case TypeClass_CHAR:
return __box
((::System::Char) *reinterpret_cast< sal_Unicode const * >(
value.getValue() ));
case TypeClass_BOOLEAN:
return __box
((::System::Boolean)
sal_False != *reinterpret_cast< sal_Bool const * >(
value.getValue() ));
case TypeClass_BYTE:
return __box
((::System::Byte) *reinterpret_cast< sal_Int8 const * >(
value.getValue() ));
case TypeClass_SHORT:
return __box
((::System::Int16) *reinterpret_cast< sal_Int16 const * >(
value.getValue() ));
case TypeClass_UNSIGNED_SHORT:
return __box
((::System::UInt16) *reinterpret_cast< sal_uInt16 const * >(
value.getValue() ));
case TypeClass_LONG:
return __box
((::System::Int32) *reinterpret_cast< sal_Int32 const * >(
value.getValue() ));
case TypeClass_UNSIGNED_LONG:
return __box
((::System::UInt32) *reinterpret_cast< sal_uInt32 const * >(
value.getValue() ));
case TypeClass_HYPER:
return __box
((::System::Int64) *reinterpret_cast< sal_Int64 const * >(
value.getValue() ));
case TypeClass_UNSIGNED_HYPER:
return __box
((::System::UInt64) *reinterpret_cast< sal_uInt64 const * >(
value.getValue() ));
case TypeClass_FLOAT:
return __box
((::System::Single) *reinterpret_cast< float const * >(
value.getValue() ));
case TypeClass_DOUBLE:
return __box
((::System::Double) *reinterpret_cast< double const * >(
value.getValue() ));
default:
throw RuntimeException(
OUSTR("unexpected constant type ") +
value.getValueType().getTypeName(),
Reference< XInterface >() );
}
}
//------------------------------------------------------------------------------
static inline void emit_ldarg( Emit::ILGenerator * code, ::System::Int32 index )
{
switch (index)
{
case 0:
code->Emit( Emit::OpCodes::Ldarg_0 );
break;
case 1:
code->Emit( Emit::OpCodes::Ldarg_1 );
break;
case 2:
code->Emit( Emit::OpCodes::Ldarg_2 );
break;
case 3:
code->Emit( Emit::OpCodes::Ldarg_3 );
break;
default:
if (index < 0x100)
code->Emit( Emit::OpCodes::Ldarg_S, (::System::Byte) index );
else if (index < 0x8000)
code->Emit( Emit::OpCodes::Ldarg_S, (::System::Int16) index );
else
code->Emit( Emit::OpCodes::Ldarg, index );
break;
}
}
void polymorphicStructNameToStructName(::System::String ** sPolyName)
{
if ((*sPolyName)->EndsWith(S">") == false)
return;
int index = (*sPolyName)->IndexOf('<');
OSL_ASSERT(index != -1);
*sPolyName = (*sPolyName)->Substring(0, index);
}
System::String* mapUnoTypeName(System::String * typeName)
{
::System::Text::StringBuilder* buf= new System::Text::StringBuilder();
::System::String * sUnoName = ::System::String::Copy(typeName);
//determine if the type is a sequence and its dimensions
int dims= 0;
if (typeName->StartsWith(S"["))//if (usUnoName[0] == '[')
{
int index= 1;
while (true)
{
if (typeName->get_Chars(index++) == ']')//if (usUnoName[index++] == ']')
dims++;
if (typeName->get_Chars(index++) != '[')//usUnoName[index++] != '[')
break;
}
sUnoName = sUnoName->Substring(index - 1);//usUnoName = usUnoName.copy(index - 1);
}
if (sUnoName->Equals(const_cast<System::String*>(Constants::sUnoBool)))
buf->Append(const_cast<System::String*>(Constants::sBoolean));
else if (sUnoName->Equals(const_cast<System::String*>(Constants::sUnoChar)))
buf->Append(const_cast<System::String*>(Constants::sChar));
else if (sUnoName->Equals(const_cast<System::String*>(Constants::sUnoByte)))
buf->Append(const_cast<System::String*>(Constants::sByte));
else if (sUnoName->Equals(const_cast<System::String*>(Constants::sUnoShort)))
buf->Append(const_cast<System::String*>(Constants::sInt16));
else if (sUnoName->Equals(const_cast<System::String*>(Constants::sUnoUShort)))
buf->Append(const_cast<System::String*>(Constants::sUInt16));
else if (sUnoName->Equals(const_cast<System::String*>(Constants::sUnoLong)))
buf->Append(const_cast<System::String*>(Constants::sInt32));
else if (sUnoName->Equals(const_cast<System::String*>(Constants::sUnoULong)))
buf->Append(const_cast<System::String*>(Constants::sUInt32));
else if (sUnoName->Equals(const_cast<System::String*>(Constants::sUnoHyper)))
buf->Append(const_cast<System::String*>(Constants::sInt64));
else if (sUnoName->Equals(const_cast<System::String*>(Constants::sUnoUHyper)))
buf->Append(const_cast<System::String*>(Constants::sUInt64));
else if (sUnoName->Equals(const_cast<System::String*>(Constants::sUnoFloat)))
buf->Append(const_cast<System::String*>(Constants::sSingle));
else if (sUnoName->Equals(const_cast<System::String*>(Constants::sUnoDouble)))
buf->Append(const_cast<System::String*>(Constants::sDouble));
else if (sUnoName->Equals(const_cast<System::String*>(Constants::sUnoString)))
buf->Append(const_cast<System::String*>(Constants::sString));
else if (sUnoName->Equals(const_cast<System::String*>(Constants::sUnoVoid)))
buf->Append(const_cast<System::String*>(Constants::sVoid));
else if (sUnoName->Equals(const_cast<System::String*>(Constants::sUnoType)))
buf->Append(const_cast<System::String*>(Constants::sType));
else if (sUnoName->Equals(const_cast<System::String*>(Constants::sUnoXInterface)))
buf->Append(const_cast<System::String*>(Constants::sObject));
else if (sUnoName->Equals(const_cast<System::String*>(Constants::sUnoAny)))
{
buf->Append(const_cast<System::String*>(Constants::sAny));
}
else
{
//put "unoidl." at the beginning
buf->Append(const_cast<System::String*>(Constants::sUnoidl));
buf->Append(mapUnoPolymorphicName(sUnoName));
}
// apend []
for (;dims--;)
buf->Append(const_cast<System::String*>(Constants::sBrackets));
return buf->ToString();
}
/** For example, there is a uno type
com.sun.star.Foo<char, long>.
The values in the type list
are uno types and are replaced by cli types, such as System.Char,
System.Int32, etc.
Strings can be as complicated as this
test.MyStruct<char,test.MyStruct<long, []string>>
*/
System::String* mapUnoPolymorphicName(System::String* unoName)
{
int index = unoName->IndexOf('<');
if (index == -1)
return unoName;
System::Text::StringBuilder * builder =
new System::Text::StringBuilder(unoName->Substring(0, index +1 ));
//Find the first occurrence of ','
//If the parameter is a polymorphic struct then we neede to ignore everything
//between the brackets because it can also contain commas
//get the type list within < and >
int endIndex = unoName->Length - 1;
index++;
int cur = index;
int countParams = 0;
while (cur <= endIndex)
{
System::Char c = unoName->Chars[cur];
if (c == ',' || c == '>')
{
//insert a comma if needed
if (countParams != 0)
builder->Append(S",");
countParams++;
System::String * sParam = unoName->Substring(index, cur - index);
//skip the comma
cur++;
//the the index to the beginning of the next param
index = cur;
builder->Append(mapUnoTypeName(sParam));
}
else if (c == '<')
{
cur++;
//continue until the matching '>'
int numNested = 0;
for (;;cur++)
{
System::Char curChar = unoName->Chars[cur];
if (curChar == '<')
{
numNested ++;
}
else if (curChar == '>')
{
if (numNested > 0)
numNested--;
else
break;
}
}
}
cur++;
}
builder->Append((System::Char) '>');
return builder->ToString();
}
//______________________________________________________________________________
Assembly * TypeEmitter::type_resolve(
::System::Object *, ::System::ResolveEventArgs * args )
{
::System::String * cts_name = args->get_Name();
::System::Type * ret_type = m_module_builder->GetType(
cts_name, false /* no exc */ );
if (0 == ret_type)
{
iface_entry * entry = dynamic_cast< iface_entry * >(
m_incomplete_ifaces->get_Item( cts_name ) );
if (0 != entry)
ret_type = entry->m_type_builder;
}
if (0 == ret_type)
{
sal_Int32 len = m_extra_assemblies->get_Length();
for ( sal_Int32 pos = 0; pos < len; ++pos )
{
ret_type = m_extra_assemblies[ pos ]->GetType(
cts_name, false /* no exc */ );
if (0 != ret_type)
{
if (g_verbose)
{
::System::Console::WriteLine(
"> resolving type {0} from {1}.",
cts_name, ret_type->get_Assembly()->get_FullName() );
}
break;
}
}
}
if (0 != ret_type)
return ret_type->get_Assembly();
return 0;
}
//______________________________________________________________________________
::System::Type * TypeEmitter::get_type(
::System::String * cts_name, bool throw_exc )
{
::System::Type * ret_type = m_module_builder->GetType( cts_name, false );
//We get the type from the ModuleBuilder even if the type is not complete
//but have been defined.
//if (ret_type == 0)
//{
// iface_entry * entry = dynamic_cast< iface_entry * >(
// m_incomplete_ifaces->get_Item( cts_name ) );
// if (0 != entry)
// ret_type = entry->m_type_builder;
//}
//try the cli_basetypes assembly
if (ret_type == 0)
{
::System::Text::StringBuilder * builder = new ::System::Text::StringBuilder(cts_name);
builder->Append(S",cli_basetypes");
ret_type = ::System::Type::GetType(builder->ToString());
}
if (ret_type == 0)
{
try
{
// may call on type_resolve()
return ::System::Type::GetType( cts_name, throw_exc );
}
catch (::System::Exception* exc)
{
//If the type is not found one may have forgotten to specify assemblies with
//additional types
::System::Text::StringBuilder * sb = new ::System::Text::StringBuilder();
sb->Append(new ::System::String(S"\nThe type "));
sb->Append(cts_name);
sb->Append(new ::System::String(S" \n could not be found. Did you forget to " \
S"specify an additional assembly with the --reference option?\n"));
if (throw_exc)
throw new ::System::Exception(sb->ToString(), exc);
}
}
else
{
return ret_type;
}
}
//______________________________________________________________________________
::System::Type * TypeEmitter::get_type_Exception()
{
if (0 == m_type_Exception)
{
m_type_Exception = get_type(
S"unoidl.com.sun.star.uno.Exception", false /* no exc */ );
if (0 == m_type_Exception)
{
// define hardcoded type unoidl.com.sun.star.uno.Exception
Emit::TypeBuilder * type_builder =
m_module_builder->DefineType(
S"unoidl.com.sun.star.uno.Exception",
(TypeAttributes) (TypeAttributes::Public |
TypeAttributes::BeforeFieldInit |
TypeAttributes::AnsiClass),
__typeof (::System::Exception) );
Emit::FieldBuilder * field_Context = type_builder->DefineField(
S"Context", __typeof (::System::Object),
FieldAttributes::Public );
// default .ctor
type_builder->DefineDefaultConstructor( c_ctor_method_attr );
// .ctor
::System::Type * param_types[] =
new ::System::Type *[ 2 ];
param_types[ 0 ] = __typeof (::System::String);
param_types[ 1 ] = __typeof (::System::Object);
Emit::ConstructorBuilder * ctor_builder =
type_builder->DefineConstructor(
c_ctor_method_attr, CallingConventions::Standard,
param_types );
ctor_builder->DefineParameter(
1, ParameterAttributes::In, S"Message" );
ctor_builder->DefineParameter(
2, ParameterAttributes::In, S"Context" );
Emit::ILGenerator * code = ctor_builder->GetILGenerator();
code->Emit( Emit::OpCodes::Ldarg_0 );
code->Emit( Emit::OpCodes::Ldarg_1 );
param_types = new ::System::Type * [ 1 ];
param_types[ 0 ] = __typeof (::System::String);
code->Emit(
Emit::OpCodes::Call,
__typeof (::System::Exception)
->GetConstructor( param_types ) );
code->Emit( Emit::OpCodes::Ldarg_0 );
code->Emit( Emit::OpCodes::Ldarg_2 );
code->Emit( Emit::OpCodes::Stfld, field_Context );
code->Emit( Emit::OpCodes::Ret );
if (g_verbose)
{
::System::Console::WriteLine(
"> emitting exception type "
"unoidl.com.sun.star.uno.Exception" );
}
m_type_Exception = type_builder->CreateType();
}
}
return m_type_Exception;
}
//______________________________________________________________________________
::System::Type * TypeEmitter::get_type_RuntimeException()
{
if (0 == m_type_RuntimeException)
{
m_type_RuntimeException = get_type(
S"unoidl.com.sun.star.uno.RuntimeException", false /* no exc */ );
if (0 == m_type_RuntimeException)
{
// define hardcoded type unoidl.com.sun.star.uno.RuntimeException
::System::Type * type_Exception = get_type_Exception();
Emit::TypeBuilder * type_builder =
m_module_builder->DefineType(
S"unoidl.com.sun.star.uno.RuntimeException",
(TypeAttributes) (TypeAttributes::Public |
TypeAttributes::BeforeFieldInit |
TypeAttributes::AnsiClass),
type_Exception );
// default .ctor
type_builder->DefineDefaultConstructor( c_ctor_method_attr );
// .ctor
::System::Type * param_types [] =
new ::System::Type * [ 2 ];
param_types[ 0 ] = __typeof (::System::String);
param_types[ 1 ] = __typeof (::System::Object);
Emit::ConstructorBuilder * ctor_builder =
type_builder->DefineConstructor(
c_ctor_method_attr, CallingConventions::Standard,
param_types );
ctor_builder->DefineParameter(
1, ParameterAttributes::In, S"Message" );
ctor_builder->DefineParameter(
2, ParameterAttributes::In, S"Context" );
Emit::ILGenerator * code = ctor_builder->GetILGenerator();
code->Emit( Emit::OpCodes::Ldarg_0 );
code->Emit( Emit::OpCodes::Ldarg_1 );
code->Emit( Emit::OpCodes::Ldarg_2 );
code->Emit(
Emit::OpCodes::Call,
type_Exception->GetConstructor( param_types ) );
code->Emit( Emit::OpCodes::Ret );
if (g_verbose)
{
::System::Console::WriteLine(
"> emitting exception type "
"unoidl.com.sun.star.uno.RuntimeException" );
}
m_type_RuntimeException = type_builder->CreateType();
}
}
return m_type_RuntimeException;
}
//______________________________________________________________________________
::System::Type * TypeEmitter::get_type(
Reference< reflection::XConstantTypeDescription > const & xType )
{
::System::String * cts_name = to_cts_name( xType->getName() );
::System::Type * ret_type = get_type( cts_name, false /* no exc */ );
if (0 == ret_type)
{
Reference< reflection::XConstantTypeDescription > xConstant(
xType, UNO_QUERY_THROW );
::System::Object * constant =
to_cli_constant( xConstant->getConstantValue() );
Emit::TypeBuilder * type_builder =
m_module_builder->DefineType(
cts_name,
(TypeAttributes) (TypeAttributes::Public |
TypeAttributes::Sealed |
TypeAttributes::BeforeFieldInit |
TypeAttributes::AnsiClass) );
Emit::FieldBuilder * field_builder = type_builder->DefineField(
cts_name->Substring( cts_name->LastIndexOf( '.' ) +1 ),
constant->GetType(),
(FieldAttributes) (FieldAttributes::Public |
FieldAttributes::Static |
FieldAttributes::Literal) );
field_builder->SetConstant( constant );
if (g_verbose)
{
::System::Console::WriteLine(
"> emitting constant type {0}", cts_name );
}
ret_type = type_builder->CreateType();
}
return ret_type;
}
//______________________________________________________________________________
::System::Type * TypeEmitter::get_type(
Reference< reflection::XConstantsTypeDescription > const & xType )
{
::System::String * cts_name = to_cts_name( xType->getName() );
::System::Type * ret_type = get_type( cts_name, false /* no exc */ );
if (0 == ret_type)
{
Emit::TypeBuilder * type_builder =
m_module_builder->DefineType(
cts_name,
(TypeAttributes) (TypeAttributes::Public |
TypeAttributes::Sealed |
TypeAttributes::BeforeFieldInit |
TypeAttributes::AnsiClass) );
Sequence< Reference<
reflection::XConstantTypeDescription > > seq_constants(
xType->getConstants() );
Reference< reflection::XConstantTypeDescription > const * constants =
seq_constants.getConstArray();
sal_Int32 constants_length = seq_constants.getLength();
for ( sal_Int32 constants_pos = 0;
constants_pos < constants_length; ++constants_pos )
{
Reference<
reflection::XConstantTypeDescription > const & xConstant =
constants[ constants_pos ];
::System::Object * constant =
to_cli_constant( xConstant->getConstantValue() );
::System::String * uno_name =
ustring_to_String( xConstant->getName() );
Emit::FieldBuilder * field_builder = type_builder->DefineField(
uno_name->Substring( uno_name->LastIndexOf( '.' ) +1 ),
constant->GetType(),
(FieldAttributes) (FieldAttributes::Public |
FieldAttributes::Static |
FieldAttributes::Literal) );
field_builder->SetConstant( constant );
}
if (g_verbose)
{
::System::Console::WriteLine(
"> emitting constants group type {0}", cts_name );
}
ret_type = type_builder->CreateType();
}
return ret_type;
}
//______________________________________________________________________________
::System::Type * TypeEmitter::get_type(
Reference< reflection::XEnumTypeDescription > const & xType )
{
::System::String * cts_name = to_cts_name( xType->getName() );
::System::Type * ret_type = get_type( cts_name, false /* no exc */ );
if (0 == ret_type)
{
// Emit::EnumBuilder * enum_builder =
// m_module_builder->DefineEnum(
// cts_name,
// (TypeAttributes) (TypeAttributes::Public |
// // TypeAttributes::Sealed |
// TypeAttributes::AnsiClass),
// __typeof (::System::Int32) );
// workaround enum builder bug
Emit::TypeBuilder * enum_builder =
m_module_builder->DefineType(
cts_name,
(TypeAttributes) (TypeAttributes::Public |
TypeAttributes::Sealed),
__typeof (::System::Enum) );
enum_builder->DefineField(
S"value__", __typeof (::System::Int32),
(FieldAttributes) (FieldAttributes::Private |
FieldAttributes::SpecialName |
FieldAttributes::RTSpecialName) );
Sequence< OUString > seq_enum_names( xType->getEnumNames() );
Sequence< sal_Int32 > seq_enum_values( xType->getEnumValues() );
sal_Int32 enum_length = seq_enum_names.getLength();
OSL_ASSERT( enum_length == seq_enum_values.getLength() );
OUString const * enum_names = seq_enum_names.getConstArray();
sal_Int32 const * enum_values = seq_enum_values.getConstArray();
for ( sal_Int32 enum_pos = 0; enum_pos < enum_length; ++enum_pos )
{
// enum_builder->DefineLiteral(
// ustring_to_String( enum_names[ enum_pos ] ),
// __box ((::System::Int32) enum_values[ enum_pos ]) );
Emit::FieldBuilder * field_builder =
enum_builder->DefineField(
ustring_to_String( enum_names[ enum_pos ] ),
enum_builder,
(FieldAttributes) (FieldAttributes::Public |
FieldAttributes::Static |
FieldAttributes::Literal) );
field_builder->SetConstant(
__box ((::System::Int32) enum_values[ enum_pos ]) );
}
if (g_verbose)
{
::System::Console::WriteLine(
"> emitting enum type {0}", cts_name );
}
ret_type = enum_builder->CreateType();
}
return ret_type;
}
//______________________________________________________________________________
::System::Type * TypeEmitter::get_type(
Reference< reflection::XCompoundTypeDescription > const & xType )
{
OUString uno_name( xType->getName() );
if (TypeClass_EXCEPTION == xType->getTypeClass())
{
if (uno_name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM(
"com.sun.star.uno.Exception") ))
{
return get_type_Exception();
}
if (uno_name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM(
"com.sun.star.uno.RuntimeException") ))
{
return get_type_RuntimeException();
}
}
::System::String * cts_name = to_cts_name( uno_name );
// if the struct is an instantiated polymorpic struct then we create the simple struct name
// For example:
// void func ([in] PolyStruct<boolean> arg);
//PolyStruct<boolean> will be converted to PolyStruct
polymorphicStructNameToStructName( & cts_name);
::System::Type * ret_type = get_type( cts_name, false /* no exc */ );
if (0 == ret_type)
{
Reference< reflection::XCompoundTypeDescription > xBaseType(
xType->getBaseType(), UNO_QUERY );
::System::Type * base_type = (xBaseType.is()
? get_type( xBaseType )
: __typeof (::System::Object));
Emit::TypeBuilder * type_builder =
m_module_builder->DefineType(
cts_name,
(TypeAttributes) (TypeAttributes::Public |
TypeAttributes::BeforeFieldInit |
TypeAttributes::AnsiClass),
base_type );
// insert to be completed
struct_entry * entry = new struct_entry();
xType->acquire();
entry->m_xType = xType.get();
entry->m_type_builder = type_builder;
entry->m_base_type = base_type;
m_incomplete_structs->Add( cts_name, entry );
// type is incomplete
ret_type = type_builder;
}
//In case of an instantiated polymorphic struct we want to return a
//uno.PolymorphicType (inherits Type) rather then Type. This is neaded for constructing
//the service code. We can only do that if the struct is completed.
if (m_generated_structs->get_Item(cts_name))
{
Reference< reflection::XStructTypeDescription> xStructTypeDesc(
xType, UNO_QUERY);
if (xStructTypeDesc.is())
{
Sequence< Reference< reflection::XTypeDescription > > seqTypeArgs = xStructTypeDesc->getTypeArguments();
sal_Int32 numTypes = seqTypeArgs.getLength();
if (numTypes > 0)
{
//it is an instantiated polymorphic struct
::System::String * sCliName = mapUnoTypeName(ustring_to_String(xType->getName()));
ret_type = ::uno::PolymorphicType::GetType(ret_type, sCliName);
}
}
}
return ret_type;
}
//______________________________________________________________________________
::System::Type * TypeEmitter::get_type(
Reference< reflection::XInterfaceTypeDescription2 > const & xType )
{
OUString uno_name( xType->getName() );
if (uno_name.equalsAsciiL(
RTL_CONSTASCII_STRINGPARAM("com.sun.star.uno.XInterface") ))
{
return __typeof (::System::Object);
}
::System::String * cts_name = to_cts_name( xType->getName() );
::System::Type * ret_type = get_type( cts_name, false /* no exc */ );
if (0 == ret_type)
{
Emit::TypeBuilder * type_builder;
TypeAttributes attr = (TypeAttributes) (TypeAttributes::Public |
TypeAttributes::Interface |
TypeAttributes::Abstract |
TypeAttributes::AnsiClass);
std::vector<Reference<reflection::XInterfaceTypeDescription2> > vecBaseTypes;
Sequence<Reference< reflection::XTypeDescription > > seqBaseTypes =
xType->getBaseTypes();
if (seqBaseTypes.getLength() > 0)
{
for (int i = 0; i < seqBaseTypes.getLength(); i++)
{
Reference<reflection::XInterfaceTypeDescription2> xIfaceTd =
resolveInterfaceTypedef(seqBaseTypes[i]);
if (xIfaceTd->getName().equalsAsciiL(
RTL_CONSTASCII_STRINGPARAM("com.sun.star.uno.XInterface") ) == sal_False)
{
vecBaseTypes.push_back(xIfaceTd);
}
}
::System::Type * base_interfaces [] =
new ::System::Type * [ vecBaseTypes.size() ];
typedef std::vector<Reference<reflection::XInterfaceTypeDescription2> >::const_iterator it;
int index = 0;
for (it i = vecBaseTypes.begin(); i != vecBaseTypes.end(); i++, index++)
base_interfaces[ index ] = get_type( *i );
type_builder = m_module_builder->DefineType(
cts_name, attr, 0, base_interfaces );
}
else
{
::System::Console::WriteLine(
"warning: IDL interface {0} is not derived from "
"com.sun.star.uno.XInterface!",
ustring_to_String( uno_name ) );
type_builder = m_module_builder->DefineType( cts_name, attr );
}
// insert to be completed
iface_entry * entry = new iface_entry();
xType->acquire();
entry->m_xType = xType.get();
entry->m_type_builder = type_builder;
m_incomplete_ifaces->Add( cts_name, entry );
// type is incomplete
ret_type = type_builder;
}
return ret_type;
}
//______________________________________________________________________________
::System::Type * TypeEmitter::get_type(
Reference< reflection::XServiceTypeDescription2 > const & xType )
{
if (xType->isSingleInterfaceBased() == sal_False)
return NULL;
System::String * cts_name = to_cts_name( xType->getName() );
System::Type * ret_type = get_type( cts_name, false /* no exc */ );
if (ret_type != NULL)
return ret_type;
TypeAttributes attr = (TypeAttributes) (TypeAttributes::Public |
TypeAttributes::Sealed |
TypeAttributes::BeforeFieldInit |
TypeAttributes::AnsiClass);
Emit::TypeBuilder * type_builder = m_module_builder->DefineType(
cts_name, attr);
// insert to be completed
service_entry * entry = new service_entry();
xType->acquire();
entry->m_xType = xType.get();
entry->m_type_builder = type_builder;
m_incomplete_services->Add(cts_name,entry );
return type_builder;
}
::System::Type * TypeEmitter::get_type(
Reference<reflection::XSingletonTypeDescription2 > const & xType )
{
if (xType->isInterfaceBased() == sal_False)
return NULL;
::System::String* cts_name = to_cts_name( xType->getName() );
::System::Type * ret_type = get_type( cts_name, false /* no exc */ );
if (ret_type != NULL)
return ret_type;
TypeAttributes attr = static_cast<TypeAttributes>(
TypeAttributes::Public |
TypeAttributes::Sealed |
TypeAttributes::BeforeFieldInit |
TypeAttributes::AnsiClass);
Emit::TypeBuilder * type_builder = m_module_builder->DefineType(
cts_name, attr);
// insert to be completed
singleton_entry * entry = new singleton_entry();
xType->acquire();
entry->m_xType = xType.get();
entry->m_type_builder = type_builder;
m_incomplete_singletons->Add(cts_name,entry );
return type_builder;
}
//______________________________________________________________________________
::System::Type * TypeEmitter::complete_iface_type( iface_entry * entry )
{
Emit::TypeBuilder * type_builder = entry->m_type_builder;
reflection::XInterfaceTypeDescription2 * xType = entry->m_xType;
Sequence<Reference< reflection::XTypeDescription > > seqBaseTypes( xType->getBaseTypes() );
if (seqBaseTypes.getLength() > 0)
{
for (int i = 0; i < seqBaseTypes.getLength(); i++)
{
//make sure we get the interface rather then a typedef
Reference<reflection::XInterfaceTypeDescription2> aBaseType =
resolveInterfaceTypedef( seqBaseTypes[i]);
if (aBaseType->getName().equalsAsciiL(
RTL_CONSTASCII_STRINGPARAM("com.sun.star.uno.XInterface") ) == sal_False)
{
::System::String * basetype_name = to_cts_name( aBaseType->getName() );
iface_entry * base_entry = dynamic_cast< iface_entry * >(
m_incomplete_ifaces->get_Item( basetype_name ) );
if (0 != base_entry)
{
// complete uncompleted base type first
complete_iface_type( base_entry );
}
}
}
}
Sequence<
Reference< reflection::XInterfaceMemberTypeDescription > > seq_members(
xType->getMembers() );
Reference< reflection::XInterfaceMemberTypeDescription > const * members =
seq_members.getConstArray();
sal_Int32 members_length = seq_members.getLength();
for ( sal_Int32 members_pos = 0;
members_pos < members_length; ++members_pos )
{
Reference<
reflection::XInterfaceMemberTypeDescription > const & xMember =
members[ members_pos ];
Sequence< Reference< reflection::XTypeDescription > > seq_exceptions;
Emit::MethodBuilder * method_builder;
const MethodAttributes c_method_attr = (MethodAttributes)
(MethodAttributes::Public |
MethodAttributes::Abstract |
MethodAttributes::Virtual |
MethodAttributes::NewSlot |
MethodAttributes::HideBySig);
//#if defined(_MSC_VER) && (_MSC_VER < 1400)
// MethodAttributes::Instance);
//#else
// Instance);
//#endif
if (TypeClass_INTERFACE_METHOD == xMember->getTypeClass())
{
Reference< reflection::XInterfaceMethodTypeDescription > xMethod(
xMember, UNO_QUERY_THROW );
Sequence<
Reference< reflection::XMethodParameter > > seq_parameters(
xMethod->getParameters() );
sal_Int32 params_length = seq_parameters.getLength();
::System::Type * param_types [] =
new ::System::Type * [ params_length ];
Reference< reflection::XMethodParameter > const * parameters =
seq_parameters.getConstArray();
// first determine all types
//Make the first param type as return type
sal_Int32 params_pos = 0;
for ( ; params_pos < params_length; ++params_pos )
{
Reference< reflection::XMethodParameter > const & xParam =
parameters[ params_pos ];
::System::Type * param_type = get_type( xParam->getType() );
::System::String * param_type_name = param_type->get_FullName();
if (xParam->isOut())
{
param_type = get_type(
::System::String::Concat(
param_type_name, S"&" ), true );
}
param_types[ xParam->getPosition() ] = param_type;
}
// create method
// if (tb)
// method_builder = type_builder->DefineMethod(
// ustring_to_String( xMethod->getMemberName() ),
// c_method_attr, tb,
// param_types );
// else
method_builder = type_builder->DefineMethod(
ustring_to_String( xMethod->getMemberName() ),
c_method_attr, get_type( xMethod->getReturnType() ),
param_types );
// then define parameter infos
params_pos = 0;
for ( ; params_pos < params_length; ++params_pos )
{
Reference< reflection::XMethodParameter > const & xParam =
parameters[ params_pos ];
long param_flags = 0;
if (xParam->isIn())
param_flags |= ParameterAttributes::In;
if (xParam->isOut())
param_flags |= ParameterAttributes::Out;
OSL_ASSERT( 0 != param_flags );
method_builder->DefineParameter(
xParam->getPosition() +1 /* starts with 1 */,
(ParameterAttributes) param_flags,
ustring_to_String( xParam->getName() ) );
}
//Apply attribute TypeParametersAttribute to return value if it
//is a parameterized Type. Currently only structs can have parameters.
Reference<reflection::XStructTypeDescription> xReturnStruct(
xMethod->getReturnType(), UNO_QUERY);
if (xReturnStruct.is())
{
Sequence<Reference<reflection::XTypeDescription> > seq_type_args =
xReturnStruct->getTypeArguments();
if (seq_type_args.getLength() != 0)
{
//get th ctor of the attribute
::System::Type * arCtor[] = {::System::Type::GetType(S"System.Type[]")};
//Get the arguments for the attribute's ctor
Reference<reflection::XTypeDescription> const * arXTypeArgs =
seq_type_args.getConstArray();
int numTypes = seq_type_args.getLength();
::System::Type * arCtsTypes[] = new ::System::Type*[numTypes];
for (int i = 0; i < numTypes; i++)
arCtsTypes[i] = get_type(arXTypeArgs[i]);
::System::Object * arArgs[] = {arCtsTypes};
Emit::CustomAttributeBuilder * attrBuilder =
new Emit::CustomAttributeBuilder(
__typeof(::uno::TypeArgumentsAttribute)
->GetConstructor( arCtor),
arArgs);
method_builder->SetCustomAttribute(attrBuilder);
}
}
//define UNO exception attribute (exceptions)--------------------------------------
Emit::CustomAttributeBuilder* attrBuilder =
get_iface_method_exception_attribute(xMethod);
if (attrBuilder != NULL)
method_builder->SetCustomAttribute(attrBuilder);
// oneway attribute
if (xMethod->isOneway())
{
::System::Type * arCtorOneway[] = new ::System::Type*[0];
::System::Object * arArgs[] = new ::System::Object*[0];
Emit::CustomAttributeBuilder * attrBuilder =
new Emit::CustomAttributeBuilder(
__typeof(::uno::OnewayAttribute)->GetConstructor( arCtorOneway),
arArgs);
method_builder->SetCustomAttribute(attrBuilder);
}
}
else // attribute
{
OSL_ASSERT(
TypeClass_INTERFACE_ATTRIBUTE == xMember->getTypeClass() );
Reference<
reflection::XInterfaceAttributeTypeDescription2 > xAttribute(
xMember, UNO_QUERY_THROW );
const MethodAttributes c_property_method_attr = (MethodAttributes)
(c_method_attr | MethodAttributes::SpecialName);
::System::Type * attribute_type = get_type( xAttribute->getType() );
::System::Type * parameters [] =
new ::System::Type * [ 0 ];
Emit::PropertyBuilder * property_builder =
type_builder->DefineProperty(
ustring_to_String( xAttribute->getMemberName() ),
PropertyAttributes::None,
attribute_type, parameters );
//set BoundAttribute, if necessary
if (xAttribute->isBound())
{
ConstructorInfo * ctorBoundAttr =
__typeof(::uno::BoundAttribute)->GetConstructor(
new System::Type*[0]);
Emit::CustomAttributeBuilder * attrBuilderBound =
new Emit::CustomAttributeBuilder(
ctorBoundAttr, new ::System::Object*[0]);
property_builder->SetCustomAttribute(attrBuilderBound);
}
// getter
Emit::MethodBuilder * method_builder =
type_builder->DefineMethod(
ustring_to_String( OUSTR("get_") +
xAttribute->getMemberName() ),
c_property_method_attr, attribute_type, parameters );
//define UNO exception attribute (exceptions)--------------------------------------
Emit::CustomAttributeBuilder* attrBuilder =
get_exception_attribute(xAttribute->getGetExceptions());
if (attrBuilder != NULL)
method_builder->SetCustomAttribute(attrBuilder);
property_builder->SetGetMethod( method_builder );
if (! xAttribute->isReadOnly())
{
// setter
parameters = new ::System::Type * [ 1 ];
parameters[ 0 ] = attribute_type;
method_builder =
type_builder->DefineMethod(
ustring_to_String( OUSTR("set_") +
xAttribute->getMemberName() ),
c_property_method_attr, 0, parameters );
// define parameter info
method_builder->DefineParameter(
1 /* starts with 1 */, ParameterAttributes::In, S"value" );
//define UNO exception attribute (exceptions)--------------------------------------
Emit::CustomAttributeBuilder* attrBuilder =
get_exception_attribute(xAttribute->getSetExceptions());
if (attrBuilder != NULL)
method_builder->SetCustomAttribute(attrBuilder);
property_builder->SetSetMethod( method_builder );
}
}
}
// remove from incomplete types map
::System::String * cts_name = type_builder->get_FullName();
m_incomplete_ifaces->Remove( cts_name );
xType->release();
if (g_verbose)
{
::System::Console::WriteLine(
"> emitting interface type {0}", cts_name );
}
return type_builder->CreateType();
}
::System::Type * TypeEmitter::complete_struct_type( struct_entry * entry )
{
OSL_ASSERT(entry);
::System::String * cts_name = entry->m_type_builder->get_FullName();
//Polymorphic struct, define uno.TypeParametersAttribute
//A polymorphic struct cannot have a basetype.
//When we create the template of the struct then we have no exact types
//and the name does not contain a parameter list
Sequence< OUString > seq_type_parameters;
Reference< reflection::XStructTypeDescription> xStructTypeDesc(
entry->m_xType, UNO_QUERY);
if (xStructTypeDesc.is())
{
seq_type_parameters = xStructTypeDesc->getTypeParameters();
int numTypes = 0;
if ((numTypes = seq_type_parameters.getLength()) > 0)
{
::System::Object * aArg[] = new ::System::Object*[numTypes];
for (int i = 0; i < numTypes; i++)
aArg[i] = ustring_to_String(seq_type_parameters.getConstArray()[i]);
::System::Object * args[] = {aArg};
::System::Type * arTypesCtor[] =
{::System::Type::GetType(S"System.String[]")};
Emit::CustomAttributeBuilder * attrBuilder =
new Emit::CustomAttributeBuilder(
__typeof(::uno::TypeParametersAttribute)->GetConstructor(arTypesCtor),
args);
entry->m_type_builder->SetCustomAttribute(attrBuilder);
}
}
// optional: lookup base type whether generated entry of this session
struct_entry * base_type_entry = 0;
if (0 != entry->m_base_type)
{
//ToDo maybe get from incomplete structs
base_type_entry =
dynamic_cast< struct_entry * >(
m_generated_structs->get_Item(
entry->m_base_type->get_FullName() ) );
}
// members
Sequence< Reference< reflection::XTypeDescription > > seq_members(
entry->m_xType->getMemberTypes() );
Sequence< OUString > seq_member_names( entry->m_xType->getMemberNames() );
sal_Int32 members_length = seq_members.getLength();
OSL_ASSERT( seq_member_names.getLength() == members_length );
//check if we have a XTypeDescription for every member. If not then the user may
//have forgotten to specify additional rdbs with the --extra option.
Reference< reflection::XTypeDescription > const * pseq_members =
seq_members.getConstArray();
OUString const * pseq_member_names =
seq_member_names.getConstArray();
for (int i = 0; i < members_length; i++)
{
const OUString sType(entry->m_xType->getName());
const OUString sMemberName(pseq_member_names[i]);
if ( ! pseq_members[i].is())
throw RuntimeException(OUSTR("Missing type description . Check if you need to " \
"specify additional RDBs with the --extra option. Type missing for: ") + sType +
OUSTR("::") + sMemberName,0);
}
sal_Int32 all_members_length = 0;
sal_Int32 member_pos;
sal_Int32 type_param_pos = 0;
// collect base types; wrong order
::System::Collections::ArrayList * base_types_list =
new ::System::Collections::ArrayList( 3 /* initial capacity */ );
for (::System::Type * base_type_pos = entry->m_base_type;
! base_type_pos->Equals( __typeof (::System::Object) );
base_type_pos = base_type_pos->get_BaseType() )
{
base_types_list->Add( base_type_pos );
if (base_type_pos->Equals( __typeof (::System::Exception) ))
{
// special Message member
all_members_length += 1;
break; // don't include System.Exception base classes
}
else
{
//ensure the base type is complete. Otherwise GetFields won't work
get_complete_struct(base_type_pos->get_FullName());
all_members_length +=
base_type_pos->GetFields(
(BindingFlags) (BindingFlags::Instance |
BindingFlags::Public |
BindingFlags::DeclaredOnly) )
->get_Length();
}
}
// create all_members arrays; right order
::System::String * all_member_names[] =
new ::System::String * [all_members_length + members_length ];
::System::Type * all_param_types[] =
new ::System::Type * [all_members_length + members_length ];
member_pos = 0;
for ( sal_Int32 pos = base_types_list->get_Count(); pos--; )
{
::System::Type * base_type = __try_cast< ::System::Type * >(
base_types_list->get_Item( pos ) );
if (base_type->Equals( __typeof (::System::Exception) ))
{
all_member_names[ member_pos ] = S"Message";
all_param_types[ member_pos ] = __typeof (::System::String);
++member_pos;
}
else
{
::System::String * base_type_name = base_type->get_FullName();
//ToDo m_generated_structs?
struct_entry * entry =
dynamic_cast< struct_entry * >(
m_generated_structs->get_Item( base_type_name ) );
if (0 == entry)
{
// complete type
FieldInfo * fields [] =
base_type->GetFields(
(BindingFlags) (BindingFlags::Instance |
BindingFlags::Public |
BindingFlags::DeclaredOnly) );
sal_Int32 len = fields->get_Length();
for ( sal_Int32 pos = 0; pos < len; ++pos )
{
FieldInfo * field = fields[ pos ];
all_member_names[ member_pos ] = field->get_Name();
all_param_types[ member_pos ] = field->get_FieldType();
++member_pos;
}
}
else // generated during this session:
// members may be incomplete ifaces
{
sal_Int32 len = entry->m_member_names->get_Length();
for ( sal_Int32 pos = 0; pos < len; ++pos )
{
all_member_names[ member_pos ] =
entry->m_member_names[ pos ];
all_param_types[ member_pos ] =
entry->m_param_types[ pos ];
++member_pos;
}
}
}
}
OSL_ASSERT( all_members_length == member_pos );
// build up entry
// struct_entry * entry = new struct_entry();
entry->m_member_names = new ::System::String * [ members_length ];
entry->m_param_types = new ::System::Type * [ members_length ];
// add members
Emit::FieldBuilder * members[] = new Emit::FieldBuilder * [ members_length ];
//Reference< reflection::XTypeDescription > const * pseq_members =
// seq_members.getConstArray();
//OUString const * pseq_member_names =
// seq_member_names.getConstArray();
int curParamIndex = 0; //count the fields which have parameterized types
for ( member_pos = 0; member_pos < members_length; ++member_pos )
{
::System::String * field_name =
ustring_to_String( pseq_member_names[ member_pos ] );
::System::Type * field_type;
//Special handling of struct parameter types
bool bParameterizedType = false;
if (pseq_members[ member_pos ]->getTypeClass() == TypeClass_UNKNOWN)
{
bParameterizedType = true;
if (type_param_pos < seq_type_parameters.getLength())
{
field_type = __typeof(::System::Object);
type_param_pos++;
}
else
{
throw RuntimeException(
OUSTR("unexpected member type in ") + entry->m_xType->getName(),
Reference< XInterface >() );
}
}
else
{
field_type =
get_type( pseq_members[ member_pos ] );
}
members[ member_pos ] =
entry->m_type_builder->DefineField(
field_name, field_type, FieldAttributes::Public );
//parameterized type (polymorphic struct) ?
if (bParameterizedType && xStructTypeDesc.is())
{
//get the name
OSL_ASSERT(seq_type_parameters.getLength() > curParamIndex);
::System::String* sTypeName = ustring_to_String(
seq_type_parameters.getConstArray()[curParamIndex++]);
::System::Object * args[] = {sTypeName};
//set ParameterizedTypeAttribute
::System::Type * arCtorTypes[] = {__typeof(::System::String)};
Emit::CustomAttributeBuilder * attrBuilder =
new Emit::CustomAttributeBuilder(
__typeof(::uno::ParameterizedTypeAttribute)
->GetConstructor(arCtorTypes),
args);
members[member_pos]->SetCustomAttribute(attrBuilder);
}
// add to all_members
all_member_names[ all_members_length + member_pos ] = field_name;
all_param_types[ all_members_length + member_pos ] = field_type;
// add to entry
entry->m_member_names[ member_pos ] = field_name;
entry->m_param_types[ member_pos ] = field_type;
}
all_members_length += members_length;
// default .ctor
Emit::ConstructorBuilder * ctor_builder =
entry->m_type_builder->DefineConstructor(
c_ctor_method_attr, CallingConventions::Standard,
new ::System::Type * [ 0 ] );
Emit::ILGenerator * code = ctor_builder->GetILGenerator();
code->Emit( Emit::OpCodes::Ldarg_0 );
code->Emit(
Emit::OpCodes::Call,
0 == base_type_entry
? entry->m_base_type->GetConstructor( new ::System::Type * [ 0 ] )
: base_type_entry->m_default_ctor );
// default initialize members
for ( member_pos = 0; member_pos < members_length; ++member_pos )
{
FieldInfo * field = members[ member_pos ];
::System::Type * field_type = field->get_FieldType();
// ::System::Type * new_field_type = m_module_builder->GetType(field_type->FullName, false);
// default initialize:
// string, type, enum, sequence, struct, exception, any
if (field_type->Equals( __typeof (::System::String) ))
{
code->Emit( Emit::OpCodes::Ldarg_0 );
code->Emit( Emit::OpCodes::Ldstr, S"" );
code->Emit( Emit::OpCodes::Stfld, field );
}
else if (field_type->Equals( __typeof (::System::Type) ))
{
code->Emit( Emit::OpCodes::Ldarg_0 );
code->Emit(
Emit::OpCodes::Ldtoken, __typeof (::System::Void) );
code->Emit(
Emit::OpCodes::Call, m_method_info_Type_GetTypeFromHandle );
code->Emit( Emit::OpCodes::Stfld, field );
}
else if (field_type->get_IsArray())
{
//Find the value type. In case of sequence<sequence< ... > > find the actual value type
::System::Type * value = field_type;
while ((value = value->GetElementType())->get_IsArray());
//If the value type is a struct then make sure it is fully created.
get_complete_struct(value->get_FullName());
code->Emit( Emit::OpCodes::Ldarg_0 );
code->Emit( Emit::OpCodes::Ldc_I4_0 );
code->Emit(
Emit::OpCodes::Newarr, field_type->GetElementType() );
code->Emit( Emit::OpCodes::Stfld, field );
}
else if (field_type->get_IsValueType())
{
if (field_type->get_FullName()->Equals( S"uno.Any" ))
{
code->Emit( Emit::OpCodes::Ldarg_0 );
code->Emit( Emit::OpCodes::Ldsfld, __typeof(::uno::Any)->GetField(S"VOID"));
code->Emit( Emit::OpCodes::Stfld, field );
}
}
else if (field_type->get_IsClass())
{
/* may be XInterface */
if (! field_type->Equals( __typeof (::System::Object) ))
{
// struct, exception
//make sure the struct is already complete.
get_complete_struct(field_type->get_FullName());
code->Emit( Emit::OpCodes::Ldarg_0 );
code->Emit(
Emit::OpCodes::Newobj,
//GetConstructor requies that the member types of the object which is to be constructed are already known.
field_type->GetConstructor(
new ::System::Type * [ 0 ] ) );
code->Emit( Emit::OpCodes::Stfld, field );
}
}
}
code->Emit( Emit::OpCodes::Ret );
entry->m_default_ctor = ctor_builder;
// parameterized .ctor including all base members
ctor_builder = entry->m_type_builder->DefineConstructor(
c_ctor_method_attr, CallingConventions::Standard, all_param_types );
for ( member_pos = 0; member_pos < all_members_length; ++member_pos )
{
ctor_builder->DefineParameter(
member_pos +1 /* starts with 1 */, ParameterAttributes::In,
all_member_names[ member_pos ] );
}
code = ctor_builder->GetILGenerator();
// call base .ctor
code->Emit( Emit::OpCodes::Ldarg_0 ); // push this
sal_Int32 base_members_length = all_members_length - members_length;
::System::Type * param_types [] =
new ::System::Type * [ base_members_length ];
for ( member_pos = 0; member_pos < base_members_length; ++member_pos )
{
emit_ldarg( code, member_pos +1 );
param_types[ member_pos ] = all_param_types[ member_pos ];
}
code->Emit(
Emit::OpCodes::Call,
0 == base_type_entry
? entry->m_base_type->GetConstructor( param_types )
: base_type_entry->m_ctor );
// initialize members
for ( member_pos = 0; member_pos < members_length; ++member_pos )
{
code->Emit( Emit::OpCodes::Ldarg_0 ); // push this
emit_ldarg( code, member_pos + base_members_length +1 );
code->Emit( Emit::OpCodes::Stfld, members[ member_pos ] );
}
code->Emit( Emit::OpCodes::Ret );
entry->m_ctor = ctor_builder;
if (g_verbose)
{
::System::Console::WriteLine(
"> emitting {0} type {1}",
TypeClass_STRUCT == entry->m_xType->getTypeClass()
? S"struct"
: S"exception",
cts_name);
}
// new entry
m_generated_structs->Add(cts_name, entry );
::System::Type * ret_type = entry->m_type_builder->CreateType();
// remove from incomplete types map
m_incomplete_structs->Remove( cts_name );
entry->m_xType->release();
if (g_verbose)
{
::System::Console::WriteLine(
"> emitting struct type {0}", cts_name);
}
return ret_type;
}
//Examples of generated code
// public static XWeak constructor1(XComponentContext ctx)
// {
// XMultiComponentFactory factory = ctx.getServiceManager();
// if (factory == null)
// throw new com.sun.star.uno.DeploymentException("bla", null);
// return (XWeak) factory.createInstanceWithContext("service_specifier", ctx);
// }
// public static XWeak constructor2(XComponentContext ctx, int a, int b, Any c)
// {
// XMultiComponentFactory factory = ctx.getServiceManager();
// if (factory == null)
// throw new com.sun.star.uno.DeploymentException("bla", null);
// Any[] arAny = new Any[3];
// arAny[0] = new Any(typeof(int), a);
// arAny[1] = new Any(typeof(int), b);
// arAny[2] = new Any(c.Type, c.Value);
// return (XWeak) factory.createInstanceWithArgumentsAndContext("service_specifier", arAny, ctx);
// }
// Notice that a any parameter is NOT wrapped by another any. Instead the new any is created with the type and value
// of the parameter.
// public static XWeak constructor3(XComponentContext ctx, params Any[] c)
// {
// XMultiComponentFactory factory = ctx.getServiceManager();
// if (factory == null)
// throw new com.sun.star.uno.DeploymentException("bla", null);
// return (XWeak) factory.createInstanceWithArgumentsAndContext("service_specifier", c, ctx);
// }
::System::Type * TypeEmitter::complete_service_type(service_entry * entry)
{
Emit::TypeBuilder * type_builder = entry->m_type_builder;
reflection::XServiceTypeDescription2 * xServiceType = entry->m_xType;
//Create the private default constructor
Emit::ConstructorBuilder* ctor_builder =
type_builder->DefineConstructor(
(MethodAttributes) (MethodAttributes::Private |
MethodAttributes::HideBySig |
MethodAttributes::SpecialName |
MethodAttributes::RTSpecialName),
CallingConventions::Standard, NULL);
Emit::ILGenerator* ilGen = ctor_builder->GetILGenerator();
ilGen->Emit( Emit::OpCodes::Ldarg_0 ); // push this
ilGen->Emit(
Emit::OpCodes::Call,
type_builder->BaseType->GetConstructor(new ::System::Type*[0]));
ilGen->Emit( Emit::OpCodes::Ret );
//Create the service constructors.
//obtain the interface which makes up this service, it is the return
//type of the constructor functions
Reference<reflection::XInterfaceTypeDescription2> xIfaceType(
xServiceType->getInterface(), UNO_QUERY);
if (xIfaceType.is () == sal_False)
xIfaceType = resolveInterfaceTypedef(xServiceType->getInterface());
System::Type * retType = get_type(xIfaceType);
//Create the ConstructorInfo for a DeploymentException
::System::Type * typeDeploymentExc =
get_type(S"unoidl.com.sun.star.uno.DeploymentException", true);
::System::Type * arTypeCtor[] = {__typeof(::System::String),
__typeof(::System::Object)};
::System::Reflection::ConstructorInfo * ctorDeploymentException =
typeDeploymentExc->GetConstructor(arTypeCtor);
Sequence<Reference<reflection::XServiceConstructorDescription> > seqCtors =
xServiceType->getConstructors();
::System::Type * type_uno_exception = get_type(S"unoidl.com.sun.star.uno.Exception", true);
for (int i = seqCtors.getLength() - 1; i >= 0; i--)
{
bool bParameterArray = false;
::System::Type * typeAny = __typeof(::uno::Any);
const Reference<reflection::XServiceConstructorDescription> & ctorDes =
seqCtors[i];
//obtain the parameter types
Sequence<Reference<reflection::XParameter> > seqParams =
ctorDes->getParameters();
Reference<reflection::XParameter> const * arXParams = seqParams.getConstArray();
sal_Int32 cParams = seqParams.getLength();
::System::Type * arTypeParameters[] = new ::System::Type* [cParams + 1];
arTypeParameters[0] = get_type(S"unoidl.com.sun.star.uno.XComponentContext", true);
for (int iparam = 0; iparam != cParams; iparam++)
{
if (arXParams[iparam]->isRestParameter())
arTypeParameters[iparam + 1] = __typeof(::uno::Any[]);
else
arTypeParameters[iparam + 1] = get_type(arXParams[iparam]->getType());
}
//The array arTypeParameters can contain:
//System.Type and uno.PolymorphicType.
//Passing PolymorphicType to MethodBuilder.DefineMethod will cause a problem.
//The exception will read something like no on information for parameter # d
//Maybe we need no override another Type method in PolymorphicType ...
//Until we have figured this out, we will create another array of System.Type which
//we pass on to DefineMethod.
::System::Type * arParamTypes[] = new ::System::Type * [cParams + 1];
// arParamTypes[0] = get_type(S"unoidl.com.sun.star.uno.XComponentContext", true);
for (int i = 0; i < cParams + 1; i++)
{
::uno::PolymorphicType * pT = dynamic_cast< ::uno::PolymorphicType * >(arTypeParameters[i]);
if (pT)
arParamTypes[i] = pT->OriginalType;
else
arParamTypes[i] = arTypeParameters[i];
}
//define method
System::String * ctorName;
if (ctorDes->isDefaultConstructor())
ctorName = new ::System::String(S"create");
else
ctorName = ustring_to_String(ctorDes->getName());
Emit::MethodBuilder* method_builder = type_builder->DefineMethod(
ctorName,
static_cast<MethodAttributes>(MethodAttributes::Public | MethodAttributes::HideBySig |
MethodAttributes::Static),
retType,
// arTypeParameters);
arParamTypes);
//define UNO exception attribute (exceptions)--------------------------------------
Emit::CustomAttributeBuilder* attrBuilder = get_service_exception_attribute(ctorDes);
if (attrBuilder != NULL)
method_builder->SetCustomAttribute(attrBuilder);
//-------------------------------------------------------------
//define parameter attributes (paramarray), names etc.
//The first parameter is the XComponentContext, which cannot be obtained
//from reflection.
//The context is not part of the idl description
method_builder->DefineParameter(
1, ParameterAttributes::In, S"the_context");
Emit::ParameterBuilder * arParameterBuilder[] =
new Emit::ParameterBuilder * [cParams];
for (int iparam = 0; iparam != cParams; iparam++)
{
Reference<reflection::XParameter> const & aParam = arXParams[iparam];
::System::String * sParamName = ustring_to_String(aParam->getName());
arParameterBuilder[iparam] = method_builder->DefineParameter(
iparam + 2, ParameterAttributes::In, sParamName);
if (aParam->isRestParameter())
{
bParameterArray = true;
//set the ParameterArrayAttribute
::System::Reflection::ConstructorInfo* ctor_info =
__typeof(System::ParamArrayAttribute)->GetConstructor(
new ::System::Type*[0]);
Emit::CustomAttributeBuilder * attr_builder =
new Emit::CustomAttributeBuilder(ctor_info, new ::System::Object*[0]);
arParameterBuilder[iparam]->SetCustomAttribute(attr_builder);
break;
}
}
Emit::ILGenerator * ilGen = method_builder->GetILGenerator();
//Define locals ---------------------------------
//XMultiComponentFactory
Emit::LocalBuilder* local_factory =
ilGen->DeclareLocal(
get_type(S"unoidl.com.sun.star.lang.XMultiComponentFactory", true));
//The return type
Emit::LocalBuilder* local_return_val =
ilGen->DeclareLocal(retType);
//Obtain the XMultiComponentFactory and throw an exception if we do not get one
ilGen->Emit(Emit::OpCodes::Ldarg_0);
::System::Reflection::MethodInfo * methodGetServiceManager = get_type(
S"unoidl.com.sun.star.uno.XComponentContext", true)
->GetMethod(S"getServiceManager");
ilGen->Emit(Emit::OpCodes::Callvirt, methodGetServiceManager);
ilGen->Emit(Emit::OpCodes::Stloc, local_factory);
ilGen->Emit(Emit::OpCodes::Ldloc, local_factory);
Emit::Label label1 = ilGen->DefineLabel();
ilGen->Emit(Emit::OpCodes::Brtrue, label1);
//The string for the exception
::System::Text::StringBuilder * strbuilder = new ::System::Text::StringBuilder(256);
strbuilder->Append(S"The service ");
strbuilder->Append(to_cts_name(xServiceType->getName()));
strbuilder->Append(S" could not be created. The context failed to supply the service manager.");
ilGen->Emit(Emit::OpCodes::Ldstr, strbuilder->ToString());
ilGen->Emit(Emit::OpCodes::Ldarg_0);
ilGen->Emit(Emit::OpCodes::Newobj, ctorDeploymentException);
ilGen->Emit(Emit::OpCodes::Throw);
ilGen->MarkLabel(label1);
//We create a try/ catch around the createInstanceWithContext, etc. functions
//There are 3 cases
//1. function do not specify exceptions. Then RuntimeExceptions are retrhown and other
// exceptions produce a DeploymentException.
//2. function specify Exception. Then all exceptions fly through
//3. function specifies exceptions but no Exception. Then these are rethrown
// and other exceptions, except RuntimeException, produce a deployment exception.
//In case there are no parameters we call
//XMultiComponentFactory.createInstanceWithContext
::System::Collections::ArrayList * arExceptionTypes =
get_service_ctor_method_exceptions_reduced(ctorDes->getExceptions());
if (arExceptionTypes->Contains(
type_uno_exception) == false)
{
ilGen->BeginExceptionBlock();
}
if (cParams == 0)
{
ilGen->Emit(Emit::OpCodes::Ldloc, local_factory);
ilGen->Emit(Emit::OpCodes::Ldstr, ustring_to_String(xServiceType->getName()));
ilGen->Emit(Emit::OpCodes::Ldarg_0);
::System::Reflection::MethodInfo * methodCreate =
local_factory->get_LocalType()->GetMethod(S"createInstanceWithContext");
ilGen->Emit(Emit::OpCodes::Callvirt, methodCreate);
}
else if(bParameterArray)
{
//Service constructor with parameter array
ilGen->Emit(Emit::OpCodes::Ldloc, local_factory);
ilGen->Emit(Emit::OpCodes::Ldstr, ustring_to_String(xServiceType->getName()));
ilGen->Emit(Emit::OpCodes::Ldarg_1);
ilGen->Emit(Emit::OpCodes::Ldarg_0);
::System::Reflection::MethodInfo * methodCreate =
local_factory->get_LocalType()->GetMethod(S"createInstanceWithArgumentsAndContext");
ilGen->Emit(Emit::OpCodes::Callvirt, methodCreate);
}
else
{
// Any param1, Any param2, etc.
// For each parameter,except the component context, and parameter array
// and Any is created.
Emit::LocalBuilder * arLocalAny[] = new Emit::LocalBuilder* [cParams];
for (int iParam = 0; iParam < cParams; iParam ++)
{
arLocalAny[iParam] = ilGen->DeclareLocal(typeAny);
}
//Any[]. This array is filled with the created Anys which contain the parameters
//and the values contained in the parameter array
Emit::LocalBuilder * local_anyParams =
ilGen->DeclareLocal(__typeof(::uno::Any[]));
//Create the Any for every argument, except for the parameter array
//arLocalAny contains the LocalBuilder for all these parameters.
//we call the ctor Any(Type, Object)
//If the parameter is an Any then the Any is created with Any(param.Type, param.Value);
::System::Type * arTypesCtorAny[] = {__typeof(::System::Type),
__typeof(::System::Object)};
::System::Reflection::ConstructorInfo * ctorAny =
typeAny->GetConstructor( arTypesCtorAny);
::System::Reflection::MethodInfo * methodAnyGetType =
typeAny->GetProperty(S"Type")->GetGetMethod();
::System::Reflection::MethodInfo * methodAnyGetValue =
typeAny->GetProperty(S"Value")->GetGetMethod();
for (int i = 0; i < arLocalAny->Length; i ++)
{
//check if the parameter is a polymorphic struct
::uno::PolymorphicType *polyType = dynamic_cast< ::uno::PolymorphicType* >(arTypeParameters[i+1]);
//arTypeParameters[i+1] = polyType->OriginalType;
if (polyType)
{
//It is a polymorphic struct
//Load the uninitialized local Any on which we will call the ctor
ilGen->Emit(Emit::OpCodes::Ldloca, arLocalAny[i]);
// Call PolymorphicType PolymorphicType::GetType(Type t, String polyName)
// Prepare the first parameter
ilGen->Emit(Emit::OpCodes::Ldtoken, polyType->get_OriginalType());
::System::Type * arTypeParams[] = {__typeof(::System::RuntimeTypeHandle)};
ilGen->Emit(Emit::OpCodes::Call,
__typeof(::System::Type)->GetMethod(
S"GetTypeFromHandle", arTypeParams));
// Prepare the second parameter
ilGen->Emit(Emit::OpCodes::Ldstr, polyType->get_PolymorphicName());
// Make the actual call
::System::Type * arTypeParam_GetType[] = {
__typeof(::System::Type), __typeof(::System::String) };
ilGen->Emit(Emit::OpCodes::Call,
__typeof(::uno::PolymorphicType)->GetMethod(new System::String(S"GetType"),
arTypeParam_GetType));
//Stack is: localAny, PolymorphicType
//Call Any::Any(Type, Object)
//Prepare the second parameter for the any ctor
ilGen->Emit(Emit::OpCodes::Ldarg, i + 1);
// if the parameter is a value type then we need to box it, because
// the Any ctor takes an Object
if (arTypeParameters[i+1]->IsValueType)
ilGen->Emit(Emit::OpCodes::Box, arTypeParameters[i+1]);
ilGen->Emit(Emit::OpCodes::Call, ctorAny);
}
else if (arTypeParameters[i+1] == typeAny)
{
//Create the call new Any(param.Type,param,Value)
//Stack must be Any,Type,Value
//First load the Any which is to be constructed
ilGen->Emit(Emit::OpCodes::Ldloca, arLocalAny[i]);
//Load the Type, which is obtained by calling param.Type
ilGen->Emit(Emit::OpCodes::Ldarga, i + 1);
ilGen->Emit(Emit::OpCodes::Call, methodAnyGetType);
//Load the Value, which is obtained by calling param.Value
ilGen->Emit(Emit::OpCodes::Ldarga, i + 1);
ilGen->Emit(Emit::OpCodes::Call, methodAnyGetValue);
//Call the Any ctor.
ilGen->Emit(Emit::OpCodes::Call, ctorAny);
}
else
{
ilGen->Emit(Emit::OpCodes::Ldloca, arLocalAny[i]);
ilGen->Emit(Emit::OpCodes::Ldtoken, arTypeParameters[i+1]);
::System::Type * arTypeParams[] = {__typeof(::System::RuntimeTypeHandle)};
ilGen->Emit(Emit::OpCodes::Call,
__typeof(::System::Type)->GetMethod(
S"GetTypeFromHandle", arTypeParams));
ilGen->Emit(Emit::OpCodes::Ldarg, i + 1);
// if the parameter is a value type then we need to box it, because
// the Any ctor takes an Object
if (arTypeParameters[i+1]->IsValueType)
ilGen->Emit(Emit::OpCodes::Box, arTypeParameters[i+1]);
ilGen->Emit(Emit::OpCodes::Call, ctorAny);
}
}
//Create the Any[] that is passed to the
//createInstanceWithContext[AndArguments] function
ilGen->Emit(Emit::OpCodes::Ldc_I4, arLocalAny->Length);
ilGen->Emit(Emit::OpCodes::Newarr, typeAny);
ilGen->Emit(Emit::OpCodes::Stloc, local_anyParams);
//Assign all anys created from the parameters
//array to the Any[]
for (int i = 0; i < arLocalAny->Length; i++)
{
ilGen->Emit(Emit::OpCodes::Ldloc, local_anyParams);
ilGen->Emit(Emit::OpCodes::Ldc_I4, i);
ilGen->Emit(Emit::OpCodes::Ldelema, typeAny);
ilGen->Emit(Emit::OpCodes::Ldloc, arLocalAny[i]);
ilGen->Emit(Emit::OpCodes::Stobj, typeAny);
}
// call createInstanceWithContextAndArguments
ilGen->Emit(Emit::OpCodes::Ldloc, local_factory);
ilGen->Emit(Emit::OpCodes::Ldstr, ustring_to_String(xServiceType->getName()));
ilGen->Emit(Emit::OpCodes::Ldloc, local_anyParams);
ilGen->Emit(Emit::OpCodes::Ldarg_0);
::System::Reflection::MethodInfo * methodCreate =
local_factory->get_LocalType()->GetMethod(S"createInstanceWithArgumentsAndContext");
ilGen->Emit(Emit::OpCodes::Callvirt, methodCreate);
}
//cast the object returned by the functions createInstanceWithContext or
//createInstanceWithArgumentsAndContext to the interface type
ilGen->Emit(Emit::OpCodes::Castclass, retType);
ilGen->Emit(Emit::OpCodes::Stloc, local_return_val);
//catch exceptions thrown by createInstanceWithArgumentsAndContext and createInstanceWithContext
if (arExceptionTypes->Contains(type_uno_exception) == false)
{
// catch (unoidl.com.sun.star.uno.RuntimeException) {throw;}
ilGen->BeginCatchBlock(get_type(S"unoidl.com.sun.star.uno.RuntimeException", true));
ilGen->Emit(Emit::OpCodes::Pop);
ilGen->Emit(Emit::OpCodes::Rethrow);
//catch and rethrow all other defined Exceptions
for (int i = 0; i < arExceptionTypes->Count; i++)
{
::System::Type * excType = __try_cast< ::System::Type* >(
arExceptionTypes->get_Item(i));
if (excType->IsInstanceOfType(
get_type(S"unoidl.com.sun.star.uno.RuntimeException", true)))
{// we have a catch for RuntimeException already defined
continue;
}
//catch Exception and rethrow
ilGen->BeginCatchBlock(excType);
ilGen->Emit(Emit::OpCodes::Pop);
ilGen->Emit(Emit::OpCodes::Rethrow);
}
//catch (unoidl.com.sun.star.uno.Exception) {throw DeploymentException...}
ilGen->BeginCatchBlock(type_uno_exception);
//Define the local variabe that keeps the exception
Emit::LocalBuilder * local_exception = ilGen->DeclareLocal(
type_uno_exception);
//Store the exception
ilGen->Emit(Emit::OpCodes::Stloc, local_exception);
//prepare the construction of the exception
strbuilder = new ::System::Text::StringBuilder(256);
strbuilder->Append(S"The context (com.sun.star.uno.XComponentContext) failed to supply the service ");
strbuilder->Append(to_cts_name(xServiceType->getName()));
strbuilder->Append(S": ");
ilGen->Emit(Emit::OpCodes::Ldstr, strbuilder->ToString());
//add to the string the Exception.Message
ilGen->Emit(Emit::OpCodes::Ldloc, local_exception);
ilGen->Emit(Emit::OpCodes::Callvirt,
type_uno_exception->GetProperty(S"Message")->GetGetMethod());
::System::Type * arConcatParams [] = {__typeof(System::String),
__typeof(System::String)};
ilGen->Emit(Emit::OpCodes::Call,
__typeof(System::String)->GetMethod(S"Concat", arConcatParams));
//load contex argument
ilGen->Emit(Emit::OpCodes::Ldarg_0);
ilGen->Emit(Emit::OpCodes::Newobj, ctorDeploymentException);
ilGen->Emit(Emit::OpCodes::Throw);//Exception(typeDeploymentExc);
ilGen->EndExceptionBlock();
}
//Check if the service instance was create and throw a exception if not.
Emit::Label label_service_created = ilGen->DefineLabel();
ilGen->Emit(Emit::OpCodes::Ldloc, local_return_val);
ilGen->Emit(Emit::OpCodes::Brtrue_S, label_service_created);
strbuilder = new ::System::Text::StringBuilder(256);
strbuilder->Append(S"The context (com.sun.star.uno.XComponentContext) failed to supply the service ");
strbuilder->Append(to_cts_name(xServiceType->getName()));
strbuilder->Append(S".");
ilGen->Emit(Emit::OpCodes::Ldstr, strbuilder->ToString());
ilGen->Emit(Emit::OpCodes::Ldarg_0);
ilGen->Emit(Emit::OpCodes::Newobj, ctorDeploymentException);
ilGen->Emit(Emit::OpCodes::Throw);//Exception(typeDeploymentExc);
ilGen->MarkLabel(label_service_created);
ilGen->Emit(Emit::OpCodes::Ldloc, local_return_val);
ilGen->Emit(Emit::OpCodes::Ret);
}
// remove from incomplete types map
::System::String * cts_name = type_builder->get_FullName();
m_incomplete_services->Remove( cts_name );
xServiceType->release();
if (g_verbose)
{
::System::Console::WriteLine(
"> emitting service type {0}", cts_name );
}
return type_builder->CreateType();
}
Emit::CustomAttributeBuilder* TypeEmitter::get_service_exception_attribute(
const Reference<reflection::XServiceConstructorDescription> & ctorDes )
{
return get_exception_attribute(ctorDes->getExceptions());
}
Emit::CustomAttributeBuilder* TypeEmitter::get_iface_method_exception_attribute(
const Reference< reflection::XInterfaceMethodTypeDescription >& xMethod )
{
const Sequence<Reference<reflection::XTypeDescription> > seqTD = xMethod->getExceptions();
int len = seqTD.getLength();
Sequence<Reference<reflection::XCompoundTypeDescription> > seqCTD(len);
Reference<reflection::XCompoundTypeDescription> * arCTD = seqCTD.getArray();
for (int i = 0; i < len; i++)
arCTD[i] = Reference<reflection::XCompoundTypeDescription>(seqTD[i], UNO_QUERY_THROW);
return get_exception_attribute(seqCTD);
}
Emit::CustomAttributeBuilder* TypeEmitter::get_exception_attribute(
const Sequence<Reference< reflection::XCompoundTypeDescription > >& seq_exceptionsTd )
{
Emit::CustomAttributeBuilder * attr_builder = NULL;
Reference< reflection::XCompoundTypeDescription > const * exceptions =
seq_exceptionsTd.getConstArray();
::System::Type * arTypesCtor[] = {::System::Type::GetType(S"System.Type[]")};
ConstructorInfo * ctor_ExceptionAttribute =
__typeof(::uno::ExceptionAttribute)->GetConstructor(arTypesCtor);
sal_Int32 exc_length = seq_exceptionsTd.getLength();
if (exc_length != 0) // opt
{
::System::Type * exception_types [] =
new ::System::Type * [ exc_length ];
for ( sal_Int32 exc_pos = 0; exc_pos < exc_length; ++exc_pos )
{
Reference< reflection::XCompoundTypeDescription > const & xExc =
exceptions[ exc_pos ];
exception_types[ exc_pos ] = get_type( xExc );
}
::System::Object * args [] = {exception_types};
attr_builder = new Emit::CustomAttributeBuilder(
ctor_ExceptionAttribute, args );
}
return attr_builder;
}
::System::Type * TypeEmitter::complete_singleton_type(singleton_entry * entry)
{
Emit::TypeBuilder * type_builder = entry->m_type_builder;
reflection::XSingletonTypeDescription2 * xSingletonType = entry->m_xType;
::System::String* sSingletonName = to_cts_name(xSingletonType->getName());
//Create the private default constructor
Emit::ConstructorBuilder* ctor_builder =
type_builder->DefineConstructor(
static_cast<MethodAttributes>(MethodAttributes::Private |
MethodAttributes::HideBySig |
MethodAttributes::SpecialName |
MethodAttributes::RTSpecialName),
CallingConventions::Standard, NULL);
Emit::ILGenerator* ilGen = ctor_builder->GetILGenerator();
ilGen->Emit( Emit::OpCodes::Ldarg_0 ); // push this
ilGen->Emit(
Emit::OpCodes::Call,
type_builder->BaseType->GetConstructor(new ::System::Type*[0]));
ilGen->Emit( Emit::OpCodes::Ret );
//obtain the interface which makes up this service, it is the return
//type of the constructor functions
Reference<reflection::XInterfaceTypeDescription2> xIfaceType(
xSingletonType->getInterface(), UNO_QUERY);
if (xIfaceType.is () == sal_False)
xIfaceType = resolveInterfaceTypedef(xSingletonType->getInterface());
System::Type * retType = get_type(xIfaceType);
//define method
::System::Type * arTypeParameters[] = {get_type(S"unoidl.com.sun.star.uno.XComponentContext", true)};
Emit::MethodBuilder* method_builder = type_builder->DefineMethod(
new System::String(S"get"),
static_cast<MethodAttributes>(MethodAttributes::Public | MethodAttributes::HideBySig |
MethodAttributes::Static),
retType,
arTypeParameters);
// method_builder->SetCustomAttribute(get_service_ctor_method_attribute(ctorDes));
//The first parameter is the XComponentContext, which cannot be obtained
//from reflection.
//The context is not part of the idl description
method_builder->DefineParameter(1, ParameterAttributes::In, S"the_context");
ilGen = method_builder->GetILGenerator();
//Define locals ---------------------------------
// Any, returned by XComponentContext.getValueByName
Emit::LocalBuilder* local_any =
ilGen->DeclareLocal(__typeof(::uno::Any));
//Call XContext::getValueByName
ilGen->Emit(Emit::OpCodes::Ldarg_0);
// build the singleton name : /singleton/unoidl.com.sun.star.XXX
::System::Text::StringBuilder* sBuilder =
new ::System::Text::StringBuilder(S"/singletons/");
sBuilder->Append(sSingletonName);
ilGen->Emit(Emit::OpCodes::Ldstr, sBuilder->ToString());
::System::Reflection::MethodInfo * methodGetValueByName =
get_type(S"unoidl.com.sun.star.uno.XComponentContext", true)->GetMethod(S"getValueByName");
ilGen->Emit(Emit::OpCodes::Callvirt, methodGetValueByName);
ilGen->Emit(Emit::OpCodes::Stloc_0);
//Contains the returned Any a value?
ilGen->Emit(Emit::OpCodes::Ldloca_S, local_any);
::System::Reflection::MethodInfo * methodHasValue =
__typeof(::uno::Any)->GetMethod(S"hasValue");
ilGen->Emit(Emit::OpCodes::Call, methodHasValue);
//If not, then throw an DeploymentException
Emit::Label label_singleton_exists = ilGen->DefineLabel();
ilGen->Emit(Emit::OpCodes::Brtrue_S, label_singleton_exists);
sBuilder = new ::System::Text::StringBuilder(
S"Component context fails to supply singleton ");
sBuilder->Append(sSingletonName);
sBuilder->Append(S" of type ");
sBuilder->Append(retType->FullName);
sBuilder->Append(S".");
ilGen->Emit(Emit::OpCodes::Ldstr, sBuilder->ToString());
ilGen->Emit(Emit::OpCodes::Ldarg_0);
::System::Type * arTypesCtorDeploymentException[] = {
__typeof(::System::String), __typeof(::System::Object)};
ilGen->Emit(Emit::OpCodes::Newobj,
get_type(S"unoidl.com.sun.star.uno.DeploymentException",true)
->GetConstructor(arTypesCtorDeploymentException));
ilGen->Emit(Emit::OpCodes::Throw);
ilGen->MarkLabel(label_singleton_exists);
//Cast the singleton contained in the Any to the expected interface and return it.
ilGen->Emit(Emit::OpCodes::Ldloca_S, local_any);
ilGen->Emit(Emit::OpCodes::Call, __typeof(::uno::Any)->GetProperty(S"Value")->GetGetMethod());
ilGen->Emit(Emit::OpCodes::Castclass, retType);
ilGen->Emit(Emit::OpCodes::Ret);
// remove from incomplete types map
::System::String * cts_name = type_builder->get_FullName();
m_incomplete_singletons->Remove( cts_name );
xSingletonType->release();
if (g_verbose)
{
::System::Console::WriteLine(
"> emitting singleton type {0}", cts_name );
}
return type_builder->CreateType();
}
//______________________________________________________________________________
::System::Type * TypeEmitter::get_type(
Reference< reflection::XTypeDescription > const & xType )
{
switch (xType->getTypeClass())
{
case TypeClass_VOID:
return __typeof (::System::Void);
case TypeClass_CHAR:
return __typeof (::System::Char);
case TypeClass_BOOLEAN:
return __typeof (::System::Boolean);
case TypeClass_BYTE:
return __typeof (::System::Byte);
case TypeClass_SHORT:
return __typeof (::System::Int16);
case TypeClass_UNSIGNED_SHORT:
return __typeof (::System::UInt16);
case TypeClass_LONG:
return __typeof (::System::Int32);
case TypeClass_UNSIGNED_LONG:
return __typeof (::System::UInt32);
case TypeClass_HYPER:
return __typeof (::System::Int64);
case TypeClass_UNSIGNED_HYPER:
return __typeof (::System::UInt64);
case TypeClass_FLOAT:
return __typeof (::System::Single);
case TypeClass_DOUBLE:
return __typeof (::System::Double);
case TypeClass_STRING:
return __typeof (::System::String);
case TypeClass_TYPE:
return __typeof (::System::Type);
case TypeClass_ANY:
return __typeof(::uno::Any);
case TypeClass_ENUM:
return get_type( Reference< reflection::XEnumTypeDescription >(
xType, UNO_QUERY_THROW ) );
case TypeClass_TYPEDEF:
// unwind typedefs
return get_type(
Reference< reflection::XIndirectTypeDescription >(
xType, UNO_QUERY_THROW )->getReferencedType() );
case TypeClass_STRUCT:
case TypeClass_EXCEPTION:
return get_type(
Reference< reflection::XCompoundTypeDescription >(
xType, UNO_QUERY_THROW ) );
case TypeClass_SEQUENCE:
{
::System::Type * element_type = get_type(
Reference< reflection::XIndirectTypeDescription >(
xType, UNO_QUERY_THROW )->getReferencedType() );
::System::Type * retType = get_type(
::System::String::Concat(
element_type->get_FullName(), S"[]" ), true );
::uno::PolymorphicType * pt = dynamic_cast< ::uno::PolymorphicType * >(element_type);
if (pt)
{
::System::String * sName = ::System::String::Concat(pt->PolymorphicName, S"[]");
retType = ::uno::PolymorphicType::GetType(retType, sName);
}
return retType;
}
case TypeClass_INTERFACE:
return get_type(
Reference< reflection::XInterfaceTypeDescription2 >(
xType, UNO_QUERY_THROW ) );
case TypeClass_CONSTANT:
return get_type(
Reference< reflection::XConstantTypeDescription >(
xType, UNO_QUERY_THROW ) );
case TypeClass_CONSTANTS:
return get_type(
Reference< reflection::XConstantsTypeDescription >(
xType, UNO_QUERY_THROW ) );
case TypeClass_SERVICE:
return get_type(
Reference< reflection::XServiceTypeDescription2 >(
xType, UNO_QUERY_THROW) );
case TypeClass_SINGLETON:
return get_type(
Reference< reflection::XSingletonTypeDescription2 >(
xType, UNO_QUERY_THROW) );
case TypeClass_MODULE:
// ignore these
return 0;
default:
throw RuntimeException(
OUSTR("unexpected type ") + xType->getName(),
Reference< XInterface >() );
}
}
//______________________________________________________________________________
::System::Type * TypeEmitter::get_complete_struct( ::System::String * sName)
{
struct_entry * pStruct = __try_cast< struct_entry *>(
m_incomplete_structs->get_Item(sName));
if (pStruct)
{
complete_struct_type(pStruct);
}
//get_type will asked the module builder for the type or otherwise all known assemblies.
return get_type(sName, true);
}
void TypeEmitter::Dispose()
{
while (true)
{
::System::Collections::IDictionaryEnumerator * enumerator =
m_incomplete_ifaces->GetEnumerator();
if (! enumerator->MoveNext())
break;
complete_iface_type(
__try_cast< iface_entry * >( enumerator->get_Value() ) );
}
while (true)
{
::System::Collections::IDictionaryEnumerator * enumerator =
m_incomplete_structs->GetEnumerator();
if (! enumerator->MoveNext())
break;
complete_struct_type(
__try_cast< struct_entry * >( enumerator->get_Value() ) );
}
while (true)
{
::System::Collections::IDictionaryEnumerator * enumerator =
m_incomplete_services->GetEnumerator();
if (! enumerator->MoveNext())
break;
complete_service_type(
__try_cast< service_entry * >( enumerator->get_Value() ) );
}
while (true)
{
::System::Collections::IDictionaryEnumerator * enumerator =
m_incomplete_singletons->GetEnumerator();
if (! enumerator->MoveNext())
break;
complete_singleton_type(
__try_cast< singleton_entry * >( enumerator->get_Value() ) );
}
}
//______________________________________________________________________________
TypeEmitter::TypeEmitter(
::System::Reflection::Emit::ModuleBuilder * module_builder,
::System::Reflection::Assembly * extra_assemblies [] )
: m_module_builder( module_builder ),
m_extra_assemblies( extra_assemblies ),
m_method_info_Type_GetTypeFromHandle( 0 ),
m_type_Exception( 0 ),
m_type_RuntimeException( 0 ),
m_incomplete_ifaces( new ::System::Collections::Hashtable() ),
m_incomplete_structs( new ::System::Collections::Hashtable() ),
m_incomplete_services(new ::System::Collections::Hashtable() ),
m_incomplete_singletons(new ::System::Collections::Hashtable() ),
m_generated_structs( new ::System::Collections::Hashtable() )
{
::System::Type * param_types[] = new ::System::Type * [ 1 ];
param_types[ 0 ] = __typeof (::System::RuntimeTypeHandle);
m_method_info_Type_GetTypeFromHandle =
__typeof (::System::Type)
->GetMethod( "GetTypeFromHandle", param_types );
}
::System::Collections::ArrayList * TypeEmitter::get_service_ctor_method_exceptions_reduced(
const Sequence<Reference<reflection::XCompoundTypeDescription> > & seqExceptionsTd)
{
if (seqExceptionsTd.getLength() == 0)
return new ::System::Collections::ArrayList();
::System::Collections::ArrayList * arTypes = new ::System::Collections::ArrayList();
for (int i = 0; i < seqExceptionsTd.getLength(); i++)
arTypes->Add(get_type(to_cts_name(seqExceptionsTd[i]->getName()), true));
int start = 0;
while (true)
{
bool bRemove = false;
for (int i = start; i < arTypes->Count; i++)
{
::System::Type * t = __try_cast< ::System::Type* >(arTypes->get_Item(i));
for (int j = 0; j < arTypes->Count; j++)
{
if (t->IsSubclassOf(__try_cast< ::System::Type* >(arTypes->get_Item(j))))
{
arTypes->RemoveAt(i);
bRemove = true;
break;
}
}
if (bRemove)
break;
start++;
}
if (bRemove == false)
break;
}
return arTypes;
}
css::uno::Reference< css::reflection::XInterfaceTypeDescription2 >
resolveInterfaceTypedef(
const css::uno::Reference<css::reflection::XTypeDescription>& type)
{
Reference<reflection::XInterfaceTypeDescription2>
xIfaceTd(type, UNO_QUERY);
if (xIfaceTd.is())
return xIfaceTd;
Reference<reflection::XIndirectTypeDescription> xIndTd(
type, UNO_QUERY);
if (xIndTd.is() == sal_False)
throw css::uno::Exception(
OUSTR("resolveInterfaceTypedef was called with an invalid argument"), 0);
return resolveInterfaceTypedef(xIndTd->getReferencedType());
}
}