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