1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_cli_ure.hxx"
26 
27 #include <stdio.h>
28 #include <vector>
29 #include <memory>
30 
31 #include "climaker_share.h"
32 
33 #include "sal/main.h"
34 #include "osl/process.h"
35 #include "osl/file.hxx"
36 #include "osl/thread.h"
37 #include "rtl/ustrbuf.hxx"
38 #include "cppuhelper/shlib.hxx"
39 #include "cppuhelper/bootstrap.hxx"
40 #include "com/sun/star/lang/XInitialization.hpp"
41 #include "com/sun/star/lang/XSingleComponentFactory.hpp"
42 #include "com/sun/star/lang/XComponent.hpp"
43 #include "com/sun/star/container/XHierarchicalNameAccess.hpp"
44 #include "com/sun/star/container/XSet.hpp"
45 #include "com/sun/star/reflection/XTypeDescriptionEnumerationAccess.hpp"
46 #include "com/sun/star/registry/XSimpleRegistry.hpp"
47 
48 using namespace ::std;
49 using namespace ::System::Reflection;
50 
51 
52 using namespace ::rtl;
53 using namespace ::osl;
54 using namespace ::com::sun::star;
55 using namespace ::com::sun::star::uno;
56 
57 namespace climaker
58 {
59 
60 //------------------------------------------------------------------------------
61 static char const s_usingText [] =
62 "\n"
63 "using: climaker <switches> [registry-file-1 registry-file-2 ...]\n"
64 "\n"
65 "switches:\n"
66 " -O, --out <output-file>       output assembly file;\n"
67 "                               defaults to cli_unotypes.dll if more than one\n"
68 "                               registry-file is given, else <registry-file>.dll\n"
69 " -T, --types                   types to be generated (if none is given,\n"
70 "   <type1[;type2;...]>         then all types of given registries are emitted\n"
71 " -X, --extra <rdb-file>        additional rdb to saturate referenced types in\n"
72 "                               given registry file(s); these types will not be\n"
73 "                               emitted into the output assembly file\n"
74 " -r, --reference               reference metadata from assembly file\n"
75 "   <assembly-file>\n"
76 " -k, --keyfile                 keyfile needed for strong name\n"
77 " --assembly-version <version>  sets assembly version\n"
78 " --assembly-description <text> sets assembly description text\n"
79 " --assembly-product <text>     sets assembly product name\n"
80 " --assembly-company <text>     sets assembly company\n"
81 " --assembly-copyright <text>   sets assembly copyright\n"
82 " --assembly-trademark <text>   sets assembly trademark\n"
83 " -v, --verbose                 verbose output to stdout\n"
84 " -h, --help                    this message\n"
85 "\n"
86 "example: climaker --out cli_mytypes.dll \\\n"
87 "                  --reference cli_uretypes.dll \\\n"
88 "                  --extra types.rdb \\\n"
89 "                  mytypes.rdb\n"
90 "\n";
91 
92 struct OptionInfo
93 {
94     char const * m_name;
95     sal_uInt32 m_name_length;
96     sal_Unicode m_short_option;
97     bool m_has_argument;
98 };
99 
100 bool g_verbose = false;
101 
102 //------------------------------------------------------------------------------
103 static const OptionInfo s_option_infos [] = {
104     { RTL_CONSTASCII_STRINGPARAM("out"), 'O', true },
105     { RTL_CONSTASCII_STRINGPARAM("types"), 'T', true },
106     { RTL_CONSTASCII_STRINGPARAM("extra"), 'X', true },
107     { RTL_CONSTASCII_STRINGPARAM("reference"), 'r', true },
108     { RTL_CONSTASCII_STRINGPARAM("keyfile"), 'k', true },
109     { RTL_CONSTASCII_STRINGPARAM("delaySign"), 'd', true },
110     { RTL_CONSTASCII_STRINGPARAM("assembly-version"), '\0', true },
111     { RTL_CONSTASCII_STRINGPARAM("assembly-description"), '\0', true },
112     { RTL_CONSTASCII_STRINGPARAM("assembly-product"), '\0', true },
113     { RTL_CONSTASCII_STRINGPARAM("assembly-company"), '\0', true },
114     { RTL_CONSTASCII_STRINGPARAM("assembly-copyright"), '\0', true },
115     { RTL_CONSTASCII_STRINGPARAM("assembly-trademark"), '\0', true },
116     { RTL_CONSTASCII_STRINGPARAM("verbose"), 'v', false },
117     { RTL_CONSTASCII_STRINGPARAM("help"), 'h', false }
118 };
119 
120 //==============================================================================
get_option_info(OUString const & opt,sal_Unicode copt='\\0')121 static OptionInfo const * get_option_info(
122     OUString const & opt, sal_Unicode copt = '\0' )
123 {
124     for ( sal_Int32 pos = 0;
125           pos < (sizeof (s_option_infos) / sizeof (OptionInfo));
126           ++pos )
127     {
128         OptionInfo const & option_info = s_option_infos[ pos ];
129 
130         if (opt.getLength() > 0)
131         {
132             if (opt.equalsAsciiL(
133                     option_info.m_name, option_info.m_name_length ) &&
134                 (copt == '\0' || copt == option_info.m_short_option))
135             {
136                 return &option_info;
137             }
138         }
139         else
140         {
141             OSL_ASSERT( copt != '\0' );
142             if (copt == option_info.m_short_option)
143             {
144                 return &option_info;
145             }
146         }
147     }
148     OSL_ENSURE(
149         0, OUStringToOString( opt, osl_getThreadTextEncoding() ).getStr() );
150     return 0;
151 }
152 
153 //==============================================================================
is_option(OptionInfo const * option_info,sal_uInt32 * pIndex)154 static bool is_option(
155     OptionInfo const * option_info, sal_uInt32 * pIndex )
156 {
157     OSL_ASSERT( option_info != 0 );
158     if (osl_getCommandArgCount() <= *pIndex)
159         return false;
160 
161     OUString arg;
162     osl_getCommandArg( *pIndex, &arg.pData );
163     sal_Int32 len = arg.getLength();
164 
165     if (len < 2 || arg[ 0 ] != '-')
166         return false;
167 
168     if (len == 2 && arg[ 1 ] == option_info->m_short_option)
169     {
170         ++(*pIndex);
171 #if OSL_DEBUG_LEVEL > 1
172         OSL_TRACE(
173             __FILE__": identified option \'%c\'", option_info->m_short_option );
174 #endif
175         return true;
176     }
177     if (arg[ 1 ] == '-' && rtl_ustr_ascii_compare(
178             arg.pData->buffer + 2, option_info->m_name ) == 0)
179     {
180         ++(*pIndex);
181 #if OSL_DEBUG_LEVEL > 1
182         OSL_TRACE( __FILE__": identified option \'%s\'", option_info->m_name );
183 #endif
184         return true;
185     }
186     return false;
187 }
188 
189 //==============================================================================
read_option(bool * flag,OptionInfo const * option_info,sal_uInt32 * pIndex)190 static inline bool read_option(
191     bool * flag, OptionInfo const * option_info, sal_uInt32 * pIndex )
192 {
193     bool ret = is_option( option_info, pIndex );
194     if (ret)
195         *flag = true;
196     return ret;
197 }
198 
199 //==============================================================================
read_argument(OUString * pValue,OptionInfo const * option_info,sal_uInt32 * pIndex)200 static bool read_argument(
201     OUString * pValue, OptionInfo const * option_info, sal_uInt32 * pIndex )
202 {
203     if (is_option( option_info, pIndex ))
204     {
205         if (*pIndex < osl_getCommandArgCount())
206         {
207             osl_getCommandArg( *pIndex, &pValue->pData );
208             ++(*pIndex);
209 #if OSL_DEBUG_LEVEL > 1
210             OString cstr_val(
211                 OUStringToOString( *pValue, osl_getThreadTextEncoding() ) );
212             OSL_TRACE( __FILE__": argument value: %s\n", cstr_val.getStr() );
213 #endif
214             return true;
215         }
216         --(*pIndex);
217     }
218     return false;
219 }
220 
221 //==============================================================================
path_get_working_dir()222 static OUString const & path_get_working_dir()
223 {
224     static OUString s_workingDir;
225     if (! s_workingDir.getLength())
226         osl_getProcessWorkingDir( &s_workingDir.pData );
227     return s_workingDir;
228 }
229 
230 //==============================================================================
path_make_absolute_file_url(OUString const & path)231 static OUString path_make_absolute_file_url( OUString const & path )
232 {
233     OUString file_url;
234     oslFileError rc = osl_getFileURLFromSystemPath(
235         path.pData, &file_url.pData );
236     if (osl_File_E_None == rc)
237     {
238         OUString abs;
239         rc = osl_getAbsoluteFileURL(
240             path_get_working_dir().pData, file_url.pData, &abs.pData );
241         if (osl_File_E_None == rc)
242         {
243             return abs;
244         }
245         else
246         {
247             throw RuntimeException(
248                 OUSTR("cannot make absolute: ") + file_url,
249                 Reference< XInterface >() );
250         }
251     }
252     else
253     {
254         throw RuntimeException(
255             OUSTR("cannot get file url from system path: ") + path,
256             Reference< XInterface >() );
257     }
258 }
259 
260 //==============================================================================
open_registries(vector<OUString> const & registries,Reference<XComponentContext> xContext)261 Reference< registry::XSimpleRegistry > open_registries(
262     vector< OUString > const & registries,
263     Reference< XComponentContext > xContext )
264 {
265     if (registries.empty())
266     {
267         throw RuntimeException(
268             OUSTR("no registries given!"),
269             Reference< XInterface >() );
270     }
271 
272     Reference< registry::XSimpleRegistry > xSimReg;
273     for ( size_t nPos = registries.size(); nPos--; )
274     {
275         Reference< registry::XSimpleRegistry > xReg(
276             xContext->getServiceManager()->createInstanceWithContext(
277                 OUSTR("com.sun.star.registry.SimpleRegistry"), xContext ),
278             UNO_QUERY_THROW );
279         xReg->open( registries[ nPos ], sal_True, sal_False );
280         if (! xReg->isValid())
281         {
282             throw RuntimeException(
283                 OUSTR("invalid registry: ") + registries[ nPos ],
284                 Reference< XInterface >() );
285         }
286 
287         if (xSimReg.is()) // nest?
288         {
289             Reference< registry::XSimpleRegistry > xNested(
290                 xContext->getServiceManager()->createInstanceWithContext(
291                     OUSTR("com.sun.star.registry.NestedRegistry"), xContext ),
292                 UNO_QUERY_THROW );
293             Reference< lang::XInitialization > xInit(
294                 xNested, UNO_QUERY_THROW );
295             Sequence< Any > args( 2 );
296             args[ 0 ] <<= xReg;
297             args[ 1 ] <<= xSimReg;
298             xInit->initialize( args );
299             xSimReg = xNested;
300         }
301         else
302         {
303             xSimReg = xReg;
304         }
305     }
306 
307     return xSimReg;
308 }
309 
310 }
311 
312 using namespace ::climaker;
313 
314 //##############################################################################
SAL_IMPLEMENT_MAIN()315 SAL_IMPLEMENT_MAIN()
316 {
317     sal_uInt32 nCount = osl_getCommandArgCount();
318     if (0 == nCount)
319     {
320         printf( s_usingText );
321         return 0;
322     }
323 
324 	int ret = 0;
325     Reference< XComponentContext > xContext;
326 
327 	try
328 	{
329         OptionInfo const * info_help =
330             get_option_info( OUSTR("help") );
331         OptionInfo const * info_verbose =
332             get_option_info( OUSTR("verbose") );
333         OptionInfo const * info_out =
334             get_option_info( OUSTR("out") );
335         OptionInfo const * info_types =
336             get_option_info( OUSTR("types") );
337         OptionInfo const * info_reference =
338             get_option_info( OUSTR("reference") );
339         OptionInfo const * info_extra =
340             get_option_info( OUSTR("extra") );
341         OptionInfo const * info_keyfile =
342             get_option_info( OUSTR("keyfile") );
343         OptionInfo const * info_delaySign =
344             get_option_info( OUSTR("delaySign") );
345         OptionInfo const * info_version =
346             get_option_info( OUSTR("assembly-version") );
347         OptionInfo const * info_product =
348             get_option_info( OUSTR("assembly-product") );
349         OptionInfo const * info_description =
350             get_option_info( OUSTR("assembly-description") );
351         OptionInfo const * info_company =
352             get_option_info( OUSTR("assembly-company") );
353         OptionInfo const * info_copyright =
354             get_option_info( OUSTR("assembly-copyright") );
355         OptionInfo const * info_trademark =
356             get_option_info( OUSTR("assembly-trademark") );
357 
358         OUString output;
359         vector< OUString > mandatory_registries;
360         vector< OUString > extra_registries;
361         vector< OUString > extra_assemblies;
362         vector< OUString > explicit_types;
363         OUString version, product, description, company, copyright, trademark,
364             keyfile, delaySign;
365 
366         OUString cmd_arg;
367 		for ( sal_uInt32 nPos = 0; nPos < nCount; )
368 		{
369             // options
370 			if (is_option( info_help, &nPos ))
371 			{
372                 printf( s_usingText );
373                 return 0;
374 			}
375 			else if (read_argument( &cmd_arg, info_types, &nPos ))
376 			{
377                 sal_Int32 index = 0;
378                 do
379                 {
380                     explicit_types.push_back(
381                         cmd_arg.getToken( 0, ';', index ) );
382                 }
383                 while (index >= 0);
384 			}
385             else if (read_argument( &cmd_arg, info_extra, &nPos ))
386             {
387                 extra_registries.push_back(
388                     path_make_absolute_file_url( cmd_arg ) );
389             }
390             else if (read_argument( &cmd_arg, info_reference, &nPos ))
391             {
392                 extra_assemblies.push_back(
393                     path_make_absolute_file_url( cmd_arg ) );
394             }
395             else if (!read_option( &g_verbose, info_verbose, &nPos ) &&
396                      !read_argument( &output, info_out, &nPos ) &&
397                      !read_argument( &version, info_version, &nPos ) &&
398                      !read_argument( &description, info_description, &nPos ) &&
399                      !read_argument( &product, info_product, &nPos ) &&
400                      !read_argument( &company, info_company, &nPos ) &&
401                      !read_argument( &copyright, info_copyright, &nPos ) &&
402                      !read_argument( &trademark, info_trademark, &nPos ) &&
403                      !read_argument( &keyfile, info_keyfile, &nPos ) &&
404                      !read_argument( &delaySign, info_delaySign, &nPos ))
405             {
406                 if ( osl_getCommandArg( nPos, &cmd_arg.pData ) !=
407                      osl_Process_E_None )
408                 {
409                     OSL_ASSERT( false );
410                 }
411                 ++nPos;
412                 cmd_arg = cmd_arg.trim();
413                 if (cmd_arg.getLength() > 0)
414                 {
415                     if (cmd_arg[ 0 ] == '-') // is option
416                     {
417                         OptionInfo const * option_info = 0;
418                         if (cmd_arg.getLength() > 2 &&
419                             cmd_arg[ 1 ] == '-')
420                         {
421                             // long option
422                             option_info = get_option_info(
423                                 cmd_arg.copy( 2 ), '\0' );
424                         }
425                         else if (cmd_arg.getLength() == 2 &&
426                                  cmd_arg[ 1 ] != '-')
427                         {
428                             // short option
429                             option_info = get_option_info(
430                                 OUString(), cmd_arg[ 1 ] );
431                         }
432                         if (option_info == 0)
433                         {
434                             OUStringBuffer buf;
435                             buf.appendAscii(
436                                 RTL_CONSTASCII_STRINGPARAM("unknown option ") );
437                             buf.append( cmd_arg );
438                             buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(
439                                                  "!  Use climaker --help "
440                                                  "to print all options.") );
441                             throw RuntimeException(
442                                 buf.makeStringAndClear(),
443                                 Reference< XInterface >() );
444                         }
445                         else
446                         {
447                             OSL_ENSURE( 0, "unhandled valid option?!" );
448                             if (option_info->m_has_argument)
449                                 ++nPos;
450                         }
451                     }
452                     else
453                     {
454                         mandatory_registries.push_back(
455                             path_make_absolute_file_url( cmd_arg ) );
456                     }
457                 }
458             }
459         }
460 
461         // bootstrap uno
462         xContext = ::cppu::bootstrap_InitialComponentContext(
463             Reference< registry::XSimpleRegistry >() );
464         Reference< container::XHierarchicalNameAccess > xTDmgr(
465             xContext->getValueByName(
466                 OUSTR("/singletons/com.sun.star.reflection."
467                       "theTypeDescriptionManager") ),
468             UNO_QUERY_THROW );
469 
470         // get rdb tdprovider factory
471         Reference< lang::XSingleComponentFactory > xTDprov_factory(
472             ::cppu::loadSharedLibComponentFactory(
473                 OUSTR("bootstrap.uno" SAL_DLLEXTENSION), OUString(),
474                 OUSTR("com.sun.star.comp.stoc.RegistryTypeDescriptionProvider"),
475                 Reference< lang::XMultiServiceFactory >(
476                     xContext->getServiceManager(), UNO_QUERY ),
477                 Reference< registry::XRegistryKey >() ), UNO_QUERY );
478         if (! xTDprov_factory.is())
479         {
480             throw RuntimeException(
481                 OUSTR("cannot get registry typedescription provider: "
482                       "bootstrap.uno" SAL_DLLEXTENSION "!"),
483                 Reference< XInterface >() );
484         }
485 
486         // create registry td provider for mandatory registry files
487         Any arg( makeAny( open_registries( mandatory_registries, xContext ) ) );
488         Reference< XInterface > xTD_provider(
489             xTDprov_factory->createInstanceWithArgumentsAndContext(
490                 Sequence< Any >( &arg, 1 ), xContext ) );
491         // insert provider to tdmgr
492         Reference< container::XSet > xSet( xTDmgr, UNO_QUERY_THROW );
493         Any provider( makeAny( xTD_provider ) );
494         xSet->insert( provider );
495         OSL_ASSERT( xSet->has( provider ) );
496         if (! extra_registries.empty())
497         {
498             arg = makeAny( open_registries( extra_registries, xContext ) );
499             provider = makeAny(
500                 xTDprov_factory->createInstanceWithArgumentsAndContext(
501                     Sequence< Any >( &arg, 1 ), xContext ) );
502             xSet->insert( provider );
503             OSL_ASSERT( xSet->has( provider ) );
504         }
505 
506         if (0 == output.getLength()) // no output file specified
507         {
508             // if only one rdb has been given, then take rdb name
509             if (1 == mandatory_registries.size())
510             {
511                 output = mandatory_registries[ 0 ];
512                 output = output.copy( output.lastIndexOf( '/' ) +1 );
513                 sal_Int32 dot = output.lastIndexOf( '.' );
514                 if (dot > 0)
515                     output = output.copy( 0, dot );
516             }
517             else
518             {
519                 output = OUSTR("cli_unotypes");
520             }
521         }
522         output = path_make_absolute_file_url( output );
523         sal_Int32 slash = output.lastIndexOf( '/' );
524         OUString sys_output_dir;
525         if (FileBase::E_None != FileBase::getSystemPathFromFileURL(
526                 output.copy( 0, slash ), sys_output_dir ))
527         {
528             throw RuntimeException(
529                 OUSTR("cannot get system path from file url ") +
530                 output.copy( 0, slash ),
531                 Reference< XInterface >() );
532         }
533         OUString filename( output.copy( slash +1 ) );
534         sal_Int32 dot = filename.lastIndexOf( '.' );
535         OUString name( filename );
536         if (dot < 0) // has no extension
537             filename += OUSTR(".dll");
538         else
539             name = name.copy( 0, dot );
540         ::System::String * output_dir = ustring_to_String( sys_output_dir );
541         ::System::String * output_file = ustring_to_String( filename );
542 
543         //Get the key pair for making a strong name
544         StrongNameKeyPair* kp = NULL;
545         if (keyfile.getLength() > 0)
546         {
547             ::System::String * sKeyFile = ustring_to_String(keyfile);
548             try {
549                 System::IO::FileStream* fs = new System::IO::FileStream(
550                     sKeyFile, System::IO::FileMode::Open);
551                 kp = new StrongNameKeyPair(fs);
552                 fs->Close();
553             }
554             catch (System::IO::FileNotFoundException * )
555             {
556                 throw Exception(OUSTR("Could not find the keyfile. Verify the --keyfile argument!"), 0);
557             }
558         }
559         else
560         {
561             if (g_verbose)
562             {
563                 ::System::Console::Write(
564                     S"> no key file specified. Cannot create strong name!\n");
565             }
566         }
567         // setup assembly info: xxx todo set more? e.g. avoid strong versioning
568         AssemblyName * assembly_name = new AssemblyName();
569         assembly_name->set_CodeBase( output_dir );
570         assembly_name->set_Name( name.getStr() );
571         if (kp != NULL)
572             assembly_name->set_KeyPair(kp);
573 
574         if (version.getLength() != 0)
575         {
576             assembly_name->set_Version(
577                 new ::System::Version( ustring_to_String( version ) ) );
578         }
579 
580         // app domain
581         ::System::AppDomain * current_appdomain =
582               ::System::AppDomain::get_CurrentDomain();
583         // target assembly
584         Emit::AssemblyBuilder * assembly_builder =
585             current_appdomain->DefineDynamicAssembly(
586                 assembly_name, Emit::AssemblyBuilderAccess::Save, output_dir );
587         if (product.getLength() != 0)
588         {
589             ::System::Type * params __gc [] = new ::System::Type * __gc [ 1 ];
590             ::System::Object * args __gc [] = new ::System::Object * __gc [ 1 ];
591             params[ 0 ] = __typeof (::System::String);
592             args[ 0 ] = ustring_to_String( product );
593             assembly_builder->SetCustomAttribute(
594                 new Emit::CustomAttributeBuilder(
595                     __typeof (AssemblyProductAttribute)->GetConstructor(
596                         params ), args ) );
597         }
598         if (description.getLength() != 0)
599         {
600             ::System::Type * params __gc [] = new ::System::Type * __gc [ 1 ];
601             ::System::Object * args __gc [] = new ::System::Object * __gc [ 1 ];
602             params[ 0 ] = __typeof (::System::String);
603             args[ 0 ] = ustring_to_String( description );
604             assembly_builder->SetCustomAttribute(
605                 new Emit::CustomAttributeBuilder(
606                     __typeof (AssemblyDescriptionAttribute)->GetConstructor(
607                         params ), args ) );
608         }
609         if (company.getLength() != 0)
610         {
611             ::System::Type * params __gc [] = new ::System::Type * __gc [ 1 ];
612             ::System::Object * args __gc [] = new ::System::Object * __gc [ 1 ];
613             params[ 0 ] = __typeof (::System::String);
614             args[ 0 ] = ustring_to_String( company );
615             assembly_builder->SetCustomAttribute(
616                 new Emit::CustomAttributeBuilder(
617                     __typeof (AssemblyCompanyAttribute)->GetConstructor(
618                         params ), args ) );
619         }
620         if (copyright.getLength() != 0)
621         {
622             ::System::Type * params __gc [] = new ::System::Type * __gc [ 1 ];
623             ::System::Object * args __gc [] = new ::System::Object * __gc [ 1 ];
624             params[ 0 ] = __typeof (::System::String);
625             args[ 0 ] = ustring_to_String( copyright );
626             assembly_builder->SetCustomAttribute(
627                 new Emit::CustomAttributeBuilder(
628                     __typeof (AssemblyCopyrightAttribute)->GetConstructor(
629                         params ), args ) );
630         }
631         if (trademark.getLength() != 0)
632         {
633             ::System::Type * params __gc [] = new ::System::Type * __gc [ 1 ];
634             ::System::Object * args __gc [] = new ::System::Object * __gc [ 1 ];
635             params[ 0 ] = __typeof (::System::String);
636             args[ 0 ] = ustring_to_String( trademark );
637             assembly_builder->SetCustomAttribute(
638                 new Emit::CustomAttributeBuilder(
639                     __typeof (AssemblyTrademarkAttribute)->GetConstructor(
640                         params ), args ) );
641         }
642 
643         // load extra assemblies
644         Assembly * assemblies __gc [] =
645             new Assembly * __gc [ extra_assemblies.size() ];
646         for ( size_t pos = 0; pos < extra_assemblies.size(); ++pos )
647         {
648             assemblies[ pos ] = Assembly::LoadFrom(
649                 ustring_to_String( extra_assemblies[ pos ] ) );
650         }
651 
652         // type emitter
653         TypeEmitter * type_emitter = new TypeEmitter(
654             assembly_builder->DefineDynamicModule( output_file ), assemblies );
655         // add handler resolving assembly's types
656         ::System::ResolveEventHandler * type_resolver =
657               new ::System::ResolveEventHandler(
658                   type_emitter, &TypeEmitter::type_resolve );
659         current_appdomain->add_TypeResolve( type_resolver );
660 
661         // and emit types to it
662         if (explicit_types.empty())
663         {
664             Reference< reflection::XTypeDescriptionEnumeration > xTD_enum(
665                 Reference< reflection::XTypeDescriptionEnumerationAccess >(
666                     xTD_provider, UNO_QUERY_THROW )
667                   ->createTypeDescriptionEnumeration(
668                       OUString() /* all IDL modules */,
669                       Sequence< TypeClass >() /* all classes of types */,
670                       reflection::TypeDescriptionSearchDepth_INFINITE ) );
671             while (xTD_enum->hasMoreElements())
672             {
673                 type_emitter->get_type( xTD_enum->nextTypeDescription() );
674             }
675         }
676         else
677         {
678             Reference< container::XHierarchicalNameAccess > xHNA(
679                 xTD_provider, UNO_QUERY_THROW );
680             for ( size_t nPos = explicit_types.size(); nPos--; )
681             {
682                 type_emitter->get_type(
683                     Reference< reflection::XTypeDescription >(
684                         xHNA->getByHierarchicalName( explicit_types[ nPos ] ),
685                         UNO_QUERY_THROW ) );
686             }
687         }
688         type_emitter->Dispose();
689 
690         if (g_verbose)
691         {
692             ::System::Console::Write(
693                 S"> saving assembly {0}{1}{2}...",
694                 output_dir,
695                 new ::System::String(
696                     ::System::IO::Path::DirectorySeparatorChar, 1 ),
697                 output_file );
698         }
699         assembly_builder->Save( output_file );
700         if (g_verbose)
701         {
702             ::System::Console::WriteLine( S"ok." );
703         }
704         current_appdomain->remove_TypeResolve( type_resolver );
705 	}
706 	catch (Exception & exc)
707 	{
708         OString msg(
709             OUStringToOString( exc.Message, osl_getThreadTextEncoding() ) );
710         fprintf(
711             stderr, "\n> error: %s\n> dying abnormally...\n", msg.getStr() );
712         ret = 1;
713 	}
714 	catch (::System::Exception * exc)
715 	{
716         OString msg( OUStringToOString(
717                          String_to_ustring( exc->ToString() ),
718                          osl_getThreadTextEncoding() ) );
719         fprintf(
720             stderr,
721             "\n> error: .NET exception occured: %s\n> dying abnormally...",
722             msg.getStr() );
723         ret = 1;
724 	}
725 
726     try
727     {
728         Reference< lang::XComponent > xComp( xContext, UNO_QUERY );
729         if (xComp.is())
730             xComp->dispose();
731     }
732 	catch (Exception & exc)
733 	{
734         OString msg(
735             OUStringToOString( exc.Message, osl_getThreadTextEncoding() ) );
736         fprintf(
737             stderr,
738             "\n> error disposing component context: %s\n"
739             "> dying abnormally...\n",
740             msg.getStr() );
741 		ret = 1;
742 	}
743 
744 	return ret;
745 }
746