msvcrt: Set correct date and time format for C locale.
[wine] / dlls / msvcrt / cpp.c
1 /*
2  * msvcrt.dll C++ objects
3  *
4  * Copyright 2000 Jon Griffiths
5  * Copyright 2003, 2004 Alexandre Julliard
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22 #include "config.h"
23 #include "wine/port.h"
24
25 #include <stdarg.h>
26
27 #include "windef.h"
28 #include "winternl.h"
29 #include "wine/exception.h"
30 #include "wine/debug.h"
31 #include "msvcrt.h"
32 #include "cppexcept.h"
33 #include "mtdll.h"
34
35 WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
36
37 typedef exception bad_cast;
38 typedef exception bad_typeid;
39 typedef exception __non_rtti_object;
40
41 typedef struct _rtti_base_descriptor
42 {
43   const type_info *type_descriptor;
44   int num_base_classes;
45   this_ptr_offsets offsets;    /* offsets for computing the this pointer */
46   unsigned int attributes;
47 } rtti_base_descriptor;
48
49 typedef struct _rtti_base_array
50 {
51   const rtti_base_descriptor *bases[3]; /* First element is the class itself */
52 } rtti_base_array;
53
54 typedef struct _rtti_object_hierarchy
55 {
56   unsigned int signature;
57   unsigned int attributes;
58   int array_len; /* Size of the array pointed to by 'base_classes' */
59   const rtti_base_array *base_classes;
60 } rtti_object_hierarchy;
61
62 typedef struct _rtti_object_locator
63 {
64   unsigned int signature;
65   int base_class_offset;
66   unsigned int flags;
67   const type_info *type_descriptor;
68   const rtti_object_hierarchy *type_hierarchy;
69 } rtti_object_locator;
70
71
72 #ifdef __i386__  /* thiscall functions are i386-specific */
73
74 #define THISCALL(func) __thiscall_ ## func
75 #define THISCALL_NAME(func) __ASM_NAME("__thiscall_" #func)
76 #define __thiscall __stdcall
77 #define DEFINE_THISCALL_WRAPPER(func,args) \
78     extern void THISCALL(func)(void); \
79     __ASM_GLOBAL_FUNC(__thiscall_ ## func, \
80                       "popl %eax\n\t" \
81                       "pushl %ecx\n\t" \
82                       "pushl %eax\n\t" \
83                       "jmp " __ASM_NAME(#func) __ASM_STDCALL(args) )
84 #else /* __i386__ */
85
86 #define THISCALL(func) func
87 #define THISCALL_NAME(func) __ASM_NAME(#func)
88 #define __thiscall __cdecl
89 #define DEFINE_THISCALL_WRAPPER(func,args) /* nothing */
90
91 #endif /* __i386__ */
92
93 extern const vtable_ptr MSVCRT_exception_vtable;
94 extern const vtable_ptr MSVCRT_bad_typeid_vtable;
95 extern const vtable_ptr MSVCRT_bad_cast_vtable;
96 extern const vtable_ptr MSVCRT___non_rtti_object_vtable;
97 extern const vtable_ptr MSVCRT_type_info_vtable;
98
99 /* get the vtable pointer for a C++ object */
100 static inline const vtable_ptr *get_vtable( void *obj )
101 {
102     return *(const vtable_ptr **)obj;
103 }
104
105 static inline const rtti_object_locator *get_obj_locator( void *cppobj )
106 {
107     const vtable_ptr *vtable = get_vtable( cppobj );
108     return (const rtti_object_locator *)vtable[-1];
109 }
110
111 static void dump_obj_locator( const rtti_object_locator *ptr )
112 {
113     int i;
114     const rtti_object_hierarchy *h = ptr->type_hierarchy;
115
116     TRACE( "%p: sig=%08x base_offset=%08x flags=%08x type=%p %s hierarchy=%p\n",
117            ptr, ptr->signature, ptr->base_class_offset, ptr->flags,
118            ptr->type_descriptor, dbgstr_type_info(ptr->type_descriptor), ptr->type_hierarchy );
119     TRACE( "  hierarchy: sig=%08x attr=%08x len=%d base classes=%p\n",
120            h->signature, h->attributes, h->array_len, h->base_classes );
121     for (i = 0; i < h->array_len; i++)
122     {
123         TRACE( "    base class %p: num %d off %d,%d,%d attr %08x type %p %s\n",
124                h->base_classes->bases[i],
125                h->base_classes->bases[i]->num_base_classes,
126                h->base_classes->bases[i]->offsets.this_offset,
127                h->base_classes->bases[i]->offsets.vbase_descr,
128                h->base_classes->bases[i]->offsets.vbase_offset,
129                h->base_classes->bases[i]->attributes,
130                h->base_classes->bases[i]->type_descriptor,
131                dbgstr_type_info(h->base_classes->bases[i]->type_descriptor) );
132     }
133 }
134
135 /* Internal common ctor for exception */
136 static void EXCEPTION_ctor(exception *_this, const char** name)
137 {
138   _this->vtable = &MSVCRT_exception_vtable;
139   if (*name)
140   {
141     unsigned int name_len = strlen(*name) + 1;
142     _this->name = MSVCRT_malloc(name_len);
143     memcpy(_this->name, *name, name_len);
144     _this->do_free = TRUE;
145   }
146   else
147   {
148     _this->name = NULL;
149     _this->do_free = FALSE;
150   }
151 }
152
153 /******************************************************************
154  *              ??0exception@@QAE@ABQBD@Z (MSVCRT.@)
155  */
156 DEFINE_THISCALL_WRAPPER(MSVCRT_exception_ctor,8)
157 exception * __thiscall MSVCRT_exception_ctor(exception * _this, const char ** name)
158 {
159   TRACE("(%p,%s)\n", _this, *name);
160   EXCEPTION_ctor(_this, name);
161   return _this;
162 }
163
164 /******************************************************************
165  *              ??0exception@@QAE@ABQBDH@Z (MSVCRT.@)
166  */
167 DEFINE_THISCALL_WRAPPER(MSVCRT_exception_ctor_noalloc,12)
168 exception * __thiscall MSVCRT_exception_ctor_noalloc(exception * _this, char ** name, int noalloc)
169 {
170   TRACE("(%p,%s)\n", _this, *name);
171   _this->vtable = &MSVCRT_exception_vtable;
172   _this->name = *name;
173   _this->do_free = FALSE;
174   return _this;
175 }
176
177 /******************************************************************
178  *              ??0exception@@QAE@ABV0@@Z (MSVCRT.@)
179  */
180 DEFINE_THISCALL_WRAPPER(MSVCRT_exception_copy_ctor,8)
181 exception * __thiscall MSVCRT_exception_copy_ctor(exception * _this, const exception * rhs)
182 {
183   TRACE("(%p,%p)\n", _this, rhs);
184
185   if (!rhs->do_free)
186   {
187     _this->vtable = &MSVCRT_exception_vtable;
188     _this->name = rhs->name;
189     _this->do_free = FALSE;
190   }
191   else
192     EXCEPTION_ctor(_this, (const char**)&rhs->name);
193   TRACE("name = %s\n", _this->name);
194   return _this;
195 }
196
197 /******************************************************************
198  *              ??0exception@@QAE@XZ (MSVCRT.@)
199  */
200 DEFINE_THISCALL_WRAPPER(MSVCRT_exception_default_ctor,4)
201 exception * __thiscall MSVCRT_exception_default_ctor(exception * _this)
202 {
203   static const char* empty = NULL;
204
205   TRACE("(%p)\n", _this);
206   EXCEPTION_ctor(_this, &empty);
207   return _this;
208 }
209
210 /******************************************************************
211  *              ??1exception@@UAE@XZ (MSVCRT.@)
212  */
213 DEFINE_THISCALL_WRAPPER(MSVCRT_exception_dtor,4)
214 void __thiscall MSVCRT_exception_dtor(exception * _this)
215 {
216   TRACE("(%p)\n", _this);
217   _this->vtable = &MSVCRT_exception_vtable;
218   if (_this->do_free) MSVCRT_free(_this->name);
219 }
220
221 /******************************************************************
222  *              ??4exception@@QAEAAV0@ABV0@@Z (MSVCRT.@)
223  */
224 DEFINE_THISCALL_WRAPPER(MSVCRT_exception_opequals,8)
225 exception * __thiscall MSVCRT_exception_opequals(exception * _this, const exception * rhs)
226 {
227   TRACE("(%p %p)\n", _this, rhs);
228   if (_this != rhs)
229   {
230       MSVCRT_exception_dtor(_this);
231       MSVCRT_exception_copy_ctor(_this, rhs);
232   }
233   TRACE("name = %s\n", _this->name);
234   return _this;
235 }
236
237 /******************************************************************
238  *              ??_Eexception@@UAEPAXI@Z (MSVCRT.@)
239  */
240 DEFINE_THISCALL_WRAPPER(MSVCRT_exception_vector_dtor,8)
241 void * __thiscall MSVCRT_exception_vector_dtor(exception * _this, unsigned int flags)
242 {
243     TRACE("(%p %x)\n", _this, flags);
244     if (flags & 2)
245     {
246         /* we have an array, with the number of elements stored before the first object */
247         int i, *ptr = (int *)_this - 1;
248
249         for (i = *ptr - 1; i >= 0; i--) MSVCRT_exception_dtor(_this + i);
250         MSVCRT_operator_delete(ptr);
251     }
252     else
253     {
254         MSVCRT_exception_dtor(_this);
255         if (flags & 1) MSVCRT_operator_delete(_this);
256     }
257     return _this;
258 }
259
260 /******************************************************************
261  *              ??_Gexception@@UAEPAXI@Z (MSVCRT.@)
262  */
263 DEFINE_THISCALL_WRAPPER(MSVCRT_exception_scalar_dtor,8)
264 void * __thiscall MSVCRT_exception_scalar_dtor(exception * _this, unsigned int flags)
265 {
266     TRACE("(%p %x)\n", _this, flags);
267     MSVCRT_exception_dtor(_this);
268     if (flags & 1) MSVCRT_operator_delete(_this);
269     return _this;
270 }
271
272 /******************************************************************
273  *              ?what@exception@@UBEPBDXZ (MSVCRT.@)
274  */
275 DEFINE_THISCALL_WRAPPER(MSVCRT_what_exception,4)
276 const char * __thiscall MSVCRT_what_exception(exception * _this)
277 {
278   TRACE("(%p) returning %s\n", _this, _this->name);
279   return _this->name ? _this->name : "Unknown exception";
280 }
281
282 /******************************************************************
283  *              ??0bad_typeid@@QAE@ABV0@@Z (MSVCRT.@)
284  */
285 DEFINE_THISCALL_WRAPPER(MSVCRT_bad_typeid_copy_ctor,8)
286 bad_typeid * __thiscall MSVCRT_bad_typeid_copy_ctor(bad_typeid * _this, const bad_typeid * rhs)
287 {
288   TRACE("(%p %p)\n", _this, rhs);
289   MSVCRT_exception_copy_ctor(_this, rhs);
290   _this->vtable = &MSVCRT_bad_typeid_vtable;
291   return _this;
292 }
293
294 /******************************************************************
295  *              ??0bad_typeid@@QAE@PBD@Z (MSVCRT.@)
296  */
297 DEFINE_THISCALL_WRAPPER(MSVCRT_bad_typeid_ctor,8)
298 bad_typeid * __thiscall MSVCRT_bad_typeid_ctor(bad_typeid * _this, const char * name)
299 {
300   TRACE("(%p %s)\n", _this, name);
301   EXCEPTION_ctor(_this, &name);
302   _this->vtable = &MSVCRT_bad_typeid_vtable;
303   return _this;
304 }
305
306 /******************************************************************
307  *              ??_Fbad_typeid@@QAEXXZ (MSVCRT.@)
308  */
309 DEFINE_THISCALL_WRAPPER(MSVCRT_bad_typeid_default_ctor,4)
310 bad_typeid * __thiscall MSVCRT_bad_typeid_default_ctor(bad_typeid * _this)
311 {
312   return MSVCRT_bad_typeid_ctor( _this, "bad typeid" );
313 }
314
315 /******************************************************************
316  *              ??1bad_typeid@@UAE@XZ (MSVCRT.@)
317  */
318 DEFINE_THISCALL_WRAPPER(MSVCRT_bad_typeid_dtor,4)
319 void __thiscall MSVCRT_bad_typeid_dtor(bad_typeid * _this)
320 {
321   TRACE("(%p)\n", _this);
322   MSVCRT_exception_dtor(_this);
323 }
324
325 /******************************************************************
326  *              ??4bad_typeid@@QAEAAV0@ABV0@@Z (MSVCRT.@)
327  */
328 DEFINE_THISCALL_WRAPPER(MSVCRT_bad_typeid_opequals,8)
329 bad_typeid * __thiscall MSVCRT_bad_typeid_opequals(bad_typeid * _this, const bad_typeid * rhs)
330 {
331   TRACE("(%p %p)\n", _this, rhs);
332   MSVCRT_exception_opequals(_this, rhs);
333   return _this;
334 }
335
336 /******************************************************************
337  *              ??_Ebad_typeid@@UAEPAXI@Z (MSVCRT.@)
338  */
339 DEFINE_THISCALL_WRAPPER(MSVCRT_bad_typeid_vector_dtor,8)
340 void * __thiscall MSVCRT_bad_typeid_vector_dtor(bad_typeid * _this, unsigned int flags)
341 {
342     TRACE("(%p %x)\n", _this, flags);
343     if (flags & 2)
344     {
345         /* we have an array, with the number of elements stored before the first object */
346         int i, *ptr = (int *)_this - 1;
347
348         for (i = *ptr - 1; i >= 0; i--) MSVCRT_bad_typeid_dtor(_this + i);
349         MSVCRT_operator_delete(ptr);
350     }
351     else
352     {
353         MSVCRT_bad_typeid_dtor(_this);
354         if (flags & 1) MSVCRT_operator_delete(_this);
355     }
356     return _this;
357 }
358
359 /******************************************************************
360  *              ??_Gbad_typeid@@UAEPAXI@Z (MSVCRT.@)
361  */
362 DEFINE_THISCALL_WRAPPER(MSVCRT_bad_typeid_scalar_dtor,8)
363 void * __thiscall MSVCRT_bad_typeid_scalar_dtor(bad_typeid * _this, unsigned int flags)
364 {
365     TRACE("(%p %x)\n", _this, flags);
366     MSVCRT_bad_typeid_dtor(_this);
367     if (flags & 1) MSVCRT_operator_delete(_this);
368     return _this;
369 }
370
371 /******************************************************************
372  *              ??0__non_rtti_object@@QAE@ABV0@@Z (MSVCRT.@)
373  */
374 DEFINE_THISCALL_WRAPPER(MSVCRT___non_rtti_object_copy_ctor,8)
375 __non_rtti_object * __thiscall MSVCRT___non_rtti_object_copy_ctor(__non_rtti_object * _this,
376                                                                  const __non_rtti_object * rhs)
377 {
378   TRACE("(%p %p)\n", _this, rhs);
379   MSVCRT_bad_typeid_copy_ctor(_this, rhs);
380   _this->vtable = &MSVCRT___non_rtti_object_vtable;
381   return _this;
382 }
383
384 /******************************************************************
385  *              ??0__non_rtti_object@@QAE@PBD@Z (MSVCRT.@)
386  */
387 DEFINE_THISCALL_WRAPPER(MSVCRT___non_rtti_object_ctor,8)
388 __non_rtti_object * __thiscall MSVCRT___non_rtti_object_ctor(__non_rtti_object * _this,
389                                                             const char * name)
390 {
391   TRACE("(%p %s)\n", _this, name);
392   EXCEPTION_ctor(_this, &name);
393   _this->vtable = &MSVCRT___non_rtti_object_vtable;
394   return _this;
395 }
396
397 /******************************************************************
398  *              ??1__non_rtti_object@@UAE@XZ (MSVCRT.@)
399  */
400 DEFINE_THISCALL_WRAPPER(MSVCRT___non_rtti_object_dtor,4)
401 void __thiscall MSVCRT___non_rtti_object_dtor(__non_rtti_object * _this)
402 {
403   TRACE("(%p)\n", _this);
404   MSVCRT_bad_typeid_dtor(_this);
405 }
406
407 /******************************************************************
408  *              ??4__non_rtti_object@@QAEAAV0@ABV0@@Z (MSVCRT.@)
409  */
410 DEFINE_THISCALL_WRAPPER(MSVCRT___non_rtti_object_opequals,8)
411 __non_rtti_object * __thiscall MSVCRT___non_rtti_object_opequals(__non_rtti_object * _this,
412                                                                 const __non_rtti_object *rhs)
413 {
414   TRACE("(%p %p)\n", _this, rhs);
415   MSVCRT_bad_typeid_opequals(_this, rhs);
416   return _this;
417 }
418
419 /******************************************************************
420  *              ??_E__non_rtti_object@@UAEPAXI@Z (MSVCRT.@)
421  */
422 DEFINE_THISCALL_WRAPPER(MSVCRT___non_rtti_object_vector_dtor,8)
423 void * __thiscall MSVCRT___non_rtti_object_vector_dtor(__non_rtti_object * _this, unsigned int flags)
424 {
425     TRACE("(%p %x)\n", _this, flags);
426     if (flags & 2)
427     {
428         /* we have an array, with the number of elements stored before the first object */
429         int i, *ptr = (int *)_this - 1;
430
431         for (i = *ptr - 1; i >= 0; i--) MSVCRT___non_rtti_object_dtor(_this + i);
432         MSVCRT_operator_delete(ptr);
433     }
434     else
435     {
436         MSVCRT___non_rtti_object_dtor(_this);
437         if (flags & 1) MSVCRT_operator_delete(_this);
438     }
439     return _this;
440 }
441
442 /******************************************************************
443  *              ??_G__non_rtti_object@@UAEPAXI@Z (MSVCRT.@)
444  */
445 DEFINE_THISCALL_WRAPPER(MSVCRT___non_rtti_object_scalar_dtor,8)
446 void * __thiscall MSVCRT___non_rtti_object_scalar_dtor(__non_rtti_object * _this, unsigned int flags)
447 {
448   TRACE("(%p %x)\n", _this, flags);
449   MSVCRT___non_rtti_object_dtor(_this);
450   if (flags & 1) MSVCRT_operator_delete(_this);
451   return _this;
452 }
453
454 /******************************************************************
455  *              ??0bad_cast@@AAE@PBQBD@Z (MSVCRT.@)
456  *              ??0bad_cast@@QAE@ABQBD@Z (MSVCRT.@)
457  */
458 DEFINE_THISCALL_WRAPPER(MSVCRT_bad_cast_ctor,8)
459 bad_cast * __thiscall MSVCRT_bad_cast_ctor(bad_cast * _this, const char ** name)
460 {
461   TRACE("(%p %s)\n", _this, *name);
462   EXCEPTION_ctor(_this, name);
463   _this->vtable = &MSVCRT_bad_cast_vtable;
464   return _this;
465 }
466
467 /******************************************************************
468  *              ??0bad_cast@@QAE@ABV0@@Z (MSVCRT.@)
469  */
470 DEFINE_THISCALL_WRAPPER(MSVCRT_bad_cast_copy_ctor,8)
471 bad_cast * __thiscall MSVCRT_bad_cast_copy_ctor(bad_cast * _this, const bad_cast * rhs)
472 {
473   TRACE("(%p %p)\n", _this, rhs);
474   MSVCRT_exception_copy_ctor(_this, rhs);
475   _this->vtable = &MSVCRT_bad_cast_vtable;
476   return _this;
477 }
478
479 /******************************************************************
480  *              ??0bad_cast@@QAE@PBD@Z (MSVCRT.@)
481  */
482 DEFINE_THISCALL_WRAPPER(MSVCRT_bad_cast_ctor_charptr,8)
483 bad_cast * __thiscall MSVCRT_bad_cast_ctor_charptr(bad_cast * _this, const char * name)
484 {
485   TRACE("(%p %s)\n", _this, name);
486   EXCEPTION_ctor(_this, &name);
487   _this->vtable = &MSVCRT_bad_cast_vtable;
488   return _this;
489 }
490
491 /******************************************************************
492  *              ??_Fbad_cast@@QAEXXZ (MSVCRT.@)
493  */
494 DEFINE_THISCALL_WRAPPER(MSVCRT_bad_cast_default_ctor,4)
495 bad_cast * __thiscall MSVCRT_bad_cast_default_ctor(bad_cast * _this)
496 {
497   return MSVCRT_bad_cast_ctor_charptr( _this, "bad cast" );
498 }
499
500 /******************************************************************
501  *              ??1bad_cast@@UAE@XZ (MSVCRT.@)
502  */
503 DEFINE_THISCALL_WRAPPER(MSVCRT_bad_cast_dtor,4)
504 void __thiscall MSVCRT_bad_cast_dtor(bad_cast * _this)
505 {
506   TRACE("(%p)\n", _this);
507   MSVCRT_exception_dtor(_this);
508 }
509
510 /******************************************************************
511  *              ??4bad_cast@@QAEAAV0@ABV0@@Z (MSVCRT.@)
512  */
513 DEFINE_THISCALL_WRAPPER(MSVCRT_bad_cast_opequals,8)
514 bad_cast * __thiscall MSVCRT_bad_cast_opequals(bad_cast * _this, const bad_cast * rhs)
515 {
516   TRACE("(%p %p)\n", _this, rhs);
517   MSVCRT_exception_opequals(_this, rhs);
518   return _this;
519 }
520
521 /******************************************************************
522  *              ??_Ebad_cast@@UAEPAXI@Z (MSVCRT.@)
523  */
524 DEFINE_THISCALL_WRAPPER(MSVCRT_bad_cast_vector_dtor,8)
525 void * __thiscall MSVCRT_bad_cast_vector_dtor(bad_cast * _this, unsigned int flags)
526 {
527     TRACE("(%p %x)\n", _this, flags);
528     if (flags & 2)
529     {
530         /* we have an array, with the number of elements stored before the first object */
531         int i, *ptr = (int *)_this - 1;
532
533         for (i = *ptr - 1; i >= 0; i--) MSVCRT_bad_cast_dtor(_this + i);
534         MSVCRT_operator_delete(ptr);
535     }
536     else
537     {
538         MSVCRT_bad_cast_dtor(_this);
539         if (flags & 1) MSVCRT_operator_delete(_this);
540     }
541     return _this;
542 }
543
544 /******************************************************************
545  *              ??_Gbad_cast@@UAEPAXI@Z (MSVCRT.@)
546  */
547 DEFINE_THISCALL_WRAPPER(MSVCRT_bad_cast_scalar_dtor,8)
548 void * __thiscall MSVCRT_bad_cast_scalar_dtor(bad_cast * _this, unsigned int flags)
549 {
550   TRACE("(%p %x)\n", _this, flags);
551   MSVCRT_bad_cast_dtor(_this);
552   if (flags & 1) MSVCRT_operator_delete(_this);
553   return _this;
554 }
555
556 /******************************************************************
557  *              ??8type_info@@QBEHABV0@@Z (MSVCRT.@)
558  */
559 DEFINE_THISCALL_WRAPPER(MSVCRT_type_info_opequals_equals,8)
560 int __thiscall MSVCRT_type_info_opequals_equals(type_info * _this, const type_info * rhs)
561 {
562     int ret = !strcmp(_this->mangled + 1, rhs->mangled + 1);
563     TRACE("(%p %p) returning %d\n", _this, rhs, ret);
564     return ret;
565 }
566
567 /******************************************************************
568  *              ??9type_info@@QBEHABV0@@Z (MSVCRT.@)
569  */
570 DEFINE_THISCALL_WRAPPER(MSVCRT_type_info_opnot_equals,8)
571 int __thiscall MSVCRT_type_info_opnot_equals(type_info * _this, const type_info * rhs)
572 {
573     int ret = !!strcmp(_this->mangled + 1, rhs->mangled + 1);
574     TRACE("(%p %p) returning %d\n", _this, rhs, ret);
575     return ret;
576 }
577
578 /******************************************************************
579  *              ?before@type_info@@QBEHABV1@@Z (MSVCRT.@)
580  */
581 DEFINE_THISCALL_WRAPPER(MSVCRT_type_info_before,8)
582 int __thiscall MSVCRT_type_info_before(type_info * _this, const type_info * rhs)
583 {
584     int ret = strcmp(_this->mangled + 1, rhs->mangled + 1) < 0;
585     TRACE("(%p %p) returning %d\n", _this, rhs, ret);
586     return ret;
587 }
588
589 /******************************************************************
590  *              ??1type_info@@UAE@XZ (MSVCRT.@)
591  */
592 DEFINE_THISCALL_WRAPPER(MSVCRT_type_info_dtor,4)
593 void __thiscall MSVCRT_type_info_dtor(type_info * _this)
594 {
595   TRACE("(%p)\n", _this);
596   MSVCRT_free(_this->name);
597 }
598
599 /******************************************************************
600  *              ?name@type_info@@QBEPBDXZ (MSVCRT.@)
601  */
602 DEFINE_THISCALL_WRAPPER(MSVCRT_type_info_name,4)
603 const char * __thiscall MSVCRT_type_info_name(type_info * _this)
604 {
605   if (!_this->name)
606   {
607     /* Create and set the demangled name */
608     /* Note: mangled name in type_info struct always starts with a '.', while
609      * it isn't valid for mangled name.
610      * Is this '.' really part of the mangled name, or has it some other meaning ?
611      */
612     char* name = __unDName(0, _this->mangled + 1, 0,
613                            MSVCRT_malloc, MSVCRT_free, 0x2800);
614     if (name)
615     {
616       unsigned int len = strlen(name);
617
618       /* It seems _unDName may leave blanks at the end of the demangled name */
619       while (len && name[--len] == ' ')
620         name[len] = '\0';
621
622       if (InterlockedCompareExchangePointer((void**)&_this->name, name, NULL))
623       {
624         /* Another thread set this member since we checked above - use it */
625         MSVCRT_free(name);
626       }
627     }
628   }
629   TRACE("(%p) returning %s\n", _this, _this->name);
630   return _this->name;
631 }
632
633 /******************************************************************
634  *              ?raw_name@type_info@@QBEPBDXZ (MSVCRT.@)
635  */
636 DEFINE_THISCALL_WRAPPER(MSVCRT_type_info_raw_name,4)
637 const char * __thiscall MSVCRT_type_info_raw_name(type_info * _this)
638 {
639   TRACE("(%p) returning %s\n", _this, _this->mangled);
640   return _this->mangled;
641 }
642
643 /* Unexported */
644 DEFINE_THISCALL_WRAPPER(MSVCRT_type_info_vector_dtor,8)
645 void * __thiscall MSVCRT_type_info_vector_dtor(type_info * _this, unsigned int flags)
646 {
647     TRACE("(%p %x)\n", _this, flags);
648     if (flags & 2)
649     {
650         /* we have an array, with the number of elements stored before the first object */
651         int i, *ptr = (int *)_this - 1;
652
653         for (i = *ptr - 1; i >= 0; i--) MSVCRT_type_info_dtor(_this + i);
654         MSVCRT_operator_delete(ptr);
655     }
656     else
657     {
658         MSVCRT_type_info_dtor(_this);
659         if (flags & 1) MSVCRT_operator_delete(_this);
660     }
661     return _this;
662 }
663
664 /* vtables */
665
666 #ifdef _WIN64
667
668 #define __ASM_VTABLE(name,funcs) \
669     __asm__(".data\n" \
670             "\t.align 8\n" \
671             "\t.quad " __ASM_NAME(#name "_rtti") "\n" \
672             "\t.globl " __ASM_NAME("MSVCRT_" #name "_vtable") "\n" \
673             __ASM_NAME("MSVCRT_" #name "_vtable") ":\n" \
674             "\t.quad " THISCALL_NAME(MSVCRT_ ## name ## _vector_dtor) "\n" \
675             funcs "\n\t.text");
676
677 #define __ASM_EXCEPTION_VTABLE(name) \
678     __ASM_VTABLE(name, "\t.quad " THISCALL_NAME(MSVCRT_what_exception) )
679
680 #else
681
682 #define __ASM_VTABLE(name,funcs) \
683     __asm__(".data\n" \
684             "\t.align 4\n" \
685             "\t.long " __ASM_NAME(#name "_rtti") "\n" \
686             "\t.globl " __ASM_NAME("MSVCRT_" #name "_vtable") "\n" \
687             __ASM_NAME("MSVCRT_" #name "_vtable") ":\n" \
688             "\t.long " THISCALL_NAME(MSVCRT_ ## name ## _vector_dtor) "\n" \
689             funcs "\n\t.text");
690
691 #define __ASM_EXCEPTION_VTABLE(name) \
692     __ASM_VTABLE(name, "\t.long " THISCALL_NAME(MSVCRT_what_exception) )
693
694 #endif /* _WIN64 */
695
696 #ifndef __GNUC__
697 void __asm_dummy_vtables(void) {
698 #endif
699
700 __ASM_VTABLE(type_info,"")
701 __ASM_EXCEPTION_VTABLE(exception)
702 __ASM_EXCEPTION_VTABLE(bad_typeid)
703 __ASM_EXCEPTION_VTABLE(bad_cast)
704 __ASM_EXCEPTION_VTABLE(__non_rtti_object)
705
706 #ifndef __GNUC__
707 }
708 #endif
709
710 /* Static RTTI for exported objects */
711
712 #define DEFINE_RTTI_DATA(name, base_classes, cl1, cl2, mangled_name) \
713 static const type_info name ## _type_info = { \
714     &MSVCRT_type_info_vtable, \
715     NULL, \
716     mangled_name \
717 }; \
718 \
719 static const rtti_base_descriptor name ## _rtti_base_descriptor = { \
720     &name ##_type_info, \
721     base_classes, \
722     { 0, -1, 0}, \
723     0 \
724 }; \
725 \
726 static const rtti_base_array name ## _rtti_base_array = { \
727     { \
728         &name ## _rtti_base_descriptor, \
729         cl1, \
730         cl2  \
731     } \
732 }; \
733 \
734 static const rtti_object_hierarchy name ## _hierarchy = { \
735     0, \
736     0, \
737     base_classes+1, \
738     &name ## _rtti_base_array \
739 }; \
740 \
741 const rtti_object_locator name ## _rtti = { \
742     0, \
743     0, \
744     0, \
745     &name ## _type_info, \
746     &name ## _hierarchy \
747 }
748
749 #define DEFINE_EXCEPTION_TYPE_INFO(name, base_classes, cl1, cl2) \
750 static const cxx_type_info name ## _cxx_type_info = \
751 { \
752     0, \
753     &name ## _type_info, \
754     { 0, -1, 0 }, \
755     sizeof(name), \
756     (cxx_copy_ctor)THISCALL(MSVCRT_ ## name ## _copy_ctor) \
757 }; \
758 \
759 static const cxx_type_info_table name ## _type_info_table = \
760 { \
761     base_classes+1, \
762     { \
763         &name ## _cxx_type_info, \
764         cl2, \
765         cl1 \
766     } \
767 }; \
768 \
769 const cxx_exception_type name ## _exception_type = \
770 { \
771     0, \
772     (void *)THISCALL(MSVCRT_ ## name ## _dtor), \
773     NULL, \
774     &name ## _type_info_table \
775 }
776
777 DEFINE_RTTI_DATA( type_info, 0, NULL, NULL, ".?AVtype_info@@" );
778 DEFINE_RTTI_DATA( exception, 0, NULL, NULL, ".?AVexception@@" );
779 DEFINE_RTTI_DATA( bad_typeid, 1, &exception_rtti_base_descriptor, NULL, ".?AVbad_typeid@@" );
780 DEFINE_RTTI_DATA( bad_cast, 1, &exception_rtti_base_descriptor, NULL, ".?AVbad_cast@@" );
781 DEFINE_RTTI_DATA( __non_rtti_object, 2, &bad_typeid_rtti_base_descriptor, &exception_rtti_base_descriptor, ".?AV__non_rtti_object@@" );
782
783 DEFINE_EXCEPTION_TYPE_INFO( exception, 0, NULL, NULL );
784 DEFINE_EXCEPTION_TYPE_INFO( bad_typeid, 1, &exception_cxx_type_info, NULL );
785 DEFINE_EXCEPTION_TYPE_INFO( bad_cast, 1, &exception_cxx_type_info, NULL );
786 DEFINE_EXCEPTION_TYPE_INFO( __non_rtti_object, 2, &bad_typeid_cxx_type_info, &exception_cxx_type_info );
787
788
789 /******************************************************************
790  *              ?set_terminate@@YAP6AXXZP6AXXZ@Z (MSVCRT.@)
791  *
792  * Install a handler to be called when terminate() is called.
793  *
794  * PARAMS
795  *  func [I] Handler function to install
796  *
797  * RETURNS
798  *  The previously installed handler function, if any.
799  */
800 MSVCRT_terminate_function CDECL MSVCRT_set_terminate(MSVCRT_terminate_function func)
801 {
802     thread_data_t *data = msvcrt_get_thread_data();
803     MSVCRT_terminate_function previous = data->terminate_handler;
804     TRACE("(%p) returning %p\n",func,previous);
805     data->terminate_handler = func;
806     return previous;
807 }
808
809 /******************************************************************
810  *              _get_terminate (MSVCRT.@)
811  */
812 MSVCRT_terminate_function CDECL MSVCRT__get_terminate(void)
813 {
814     thread_data_t *data = msvcrt_get_thread_data();
815     TRACE("returning %p\n", data->terminate_handler);
816     return data->terminate_handler;
817 }
818
819 /******************************************************************
820  *              ?set_unexpected@@YAP6AXXZP6AXXZ@Z (MSVCRT.@)
821  *
822  * Install a handler to be called when unexpected() is called.
823  *
824  * PARAMS
825  *  func [I] Handler function to install
826  *
827  * RETURNS
828  *  The previously installed handler function, if any.
829  */
830 MSVCRT_unexpected_function CDECL MSVCRT_set_unexpected(MSVCRT_unexpected_function func)
831 {
832     thread_data_t *data = msvcrt_get_thread_data();
833     MSVCRT_unexpected_function previous = data->unexpected_handler;
834     TRACE("(%p) returning %p\n",func,previous);
835     data->unexpected_handler = func;
836     return previous;
837 }
838
839 /******************************************************************
840  *              _get_unexpected (MSVCRT.@)
841  */
842 MSVCRT_unexpected_function CDECL MSVCRT__get_unexpected(void)
843 {
844     thread_data_t *data = msvcrt_get_thread_data();
845     TRACE("returning %p\n", data->unexpected_handler);
846     return data->unexpected_handler;
847 }
848
849 /******************************************************************
850  *              ?_set_se_translator@@YAP6AXIPAU_EXCEPTION_POINTERS@@@ZP6AXI0@Z@Z  (MSVCRT.@)
851  */
852 MSVCRT__se_translator_function CDECL MSVCRT__set_se_translator(MSVCRT__se_translator_function func)
853 {
854     thread_data_t *data = msvcrt_get_thread_data();
855     MSVCRT__se_translator_function previous = data->se_translator;
856     TRACE("(%p) returning %p\n",func,previous);
857     data->se_translator = func;
858     return previous;
859 }
860
861 /******************************************************************
862  *              ?terminate@@YAXXZ (MSVCRT.@)
863  *
864  * Default handler for an unhandled exception.
865  *
866  * PARAMS
867  *  None.
868  *
869  * RETURNS
870  *  This function does not return. Either control resumes from any
871  *  handler installed by calling set_terminate(), or (by default) abort()
872  *  is called.
873  */
874 void CDECL MSVCRT_terminate(void)
875 {
876     thread_data_t *data = msvcrt_get_thread_data();
877     if (data->terminate_handler) data->terminate_handler();
878     MSVCRT_abort();
879 }
880
881 /******************************************************************
882  *              ?unexpected@@YAXXZ (MSVCRT.@)
883  */
884 void CDECL MSVCRT_unexpected(void)
885 {
886     thread_data_t *data = msvcrt_get_thread_data();
887     if (data->unexpected_handler) data->unexpected_handler();
888     MSVCRT_terminate();
889 }
890
891
892 /******************************************************************
893  *              __RTtypeid (MSVCRT.@)
894  *
895  * Retrieve the Run Time Type Information (RTTI) for a C++ object.
896  *
897  * PARAMS
898  *  cppobj [I] C++ object to get type information for.
899  *
900  * RETURNS
901  *  Success: A type_info object describing cppobj.
902  *  Failure: If the object to be cast has no RTTI, a __non_rtti_object
903  *           exception is thrown. If cppobj is NULL, a bad_typeid exception
904  *           is thrown. In either case, this function does not return.
905  *
906  * NOTES
907  *  This function is usually called by compiler generated code as a result
908  *  of using one of the C++ dynamic cast statements.
909  */
910 const type_info* CDECL MSVCRT___RTtypeid(void *cppobj)
911 {
912     const type_info *ret;
913
914     if (!cppobj)
915     {
916         bad_typeid e;
917         MSVCRT_bad_typeid_ctor( &e, "Attempted a typeid of NULL pointer!" );
918         _CxxThrowException( &e, &bad_typeid_exception_type );
919         return NULL;
920     }
921
922     __TRY
923     {
924         const rtti_object_locator *obj_locator = get_obj_locator( cppobj );
925         ret = obj_locator->type_descriptor;
926     }
927     __EXCEPT_PAGE_FAULT
928     {
929         __non_rtti_object e;
930         MSVCRT___non_rtti_object_ctor( &e, "Bad read pointer - no RTTI data!" );
931         _CxxThrowException( &e, &bad_typeid_exception_type );
932         return NULL;
933     }
934     __ENDTRY
935     return ret;
936 }
937
938 /******************************************************************
939  *              __RTDynamicCast (MSVCRT.@)
940  *
941  * Dynamically cast a C++ object to one of its base classes.
942  *
943  * PARAMS
944  *  cppobj   [I] Any C++ object to cast
945  *  unknown  [I] Reserved, set to 0
946  *  src      [I] type_info object describing cppobj
947  *  dst      [I] type_info object describing the base class to cast to
948  *  do_throw [I] TRUE = throw an exception if the cast fails, FALSE = don't
949  *
950  * RETURNS
951  *  Success: The address of cppobj, cast to the object described by dst.
952  *  Failure: NULL, If the object to be cast has no RTTI, or dst is not a
953  *           valid cast for cppobj. If do_throw is TRUE, a bad_cast exception
954  *           is thrown and this function does not return.
955  *
956  * NOTES
957  *  This function is usually called by compiler generated code as a result
958  *  of using one of the C++ dynamic cast statements.
959  */
960 void* CDECL MSVCRT___RTDynamicCast(void *cppobj, int unknown,
961                                    type_info *src, type_info *dst,
962                                    int do_throw)
963 {
964     void *ret;
965
966     if (!cppobj) return NULL;
967
968     TRACE("obj: %p unknown: %d src: %p %s dst: %p %s do_throw: %d)\n",
969           cppobj, unknown, src, dbgstr_type_info(src), dst, dbgstr_type_info(dst), do_throw);
970
971     /* To cast an object at runtime:
972      * 1.Find out the true type of the object from the typeinfo at vtable[-1]
973      * 2.Search for the destination type in the class hierarchy
974      * 3.If destination type is found, return base object address + dest offset
975      *   Otherwise, fail the cast
976      *
977      * FIXME: the unknown parameter doesn't seem to be used for anything
978      */
979     __TRY
980     {
981         int i;
982         const rtti_object_locator *obj_locator = get_obj_locator( cppobj );
983         const rtti_object_hierarchy *obj_bases = obj_locator->type_hierarchy;
984         const rtti_base_descriptor * const* base_desc = obj_bases->base_classes->bases;
985
986         if (TRACE_ON(msvcrt)) dump_obj_locator(obj_locator);
987
988         ret = NULL;
989         for (i = 0; i < obj_bases->array_len; i++)
990         {
991             const type_info *typ = base_desc[i]->type_descriptor;
992
993             if (!strcmp(typ->mangled, dst->mangled))
994             {
995                 /* compute the correct this pointer for that base class */
996                 void *this_ptr = (char *)cppobj - obj_locator->base_class_offset;
997                 ret = get_this_pointer( &base_desc[i]->offsets, this_ptr );
998                 break;
999             }
1000         }
1001         /* VC++ sets do_throw to 1 when the result of a dynamic_cast is assigned
1002          * to a reference, since references cannot be NULL.
1003          */
1004         if (!ret && do_throw)
1005         {
1006             const char *msg = "Bad dynamic_cast!";
1007             bad_cast e;
1008             MSVCRT_bad_cast_ctor( &e, &msg );
1009             _CxxThrowException( &e, &bad_cast_exception_type );
1010         }
1011     }
1012     __EXCEPT_PAGE_FAULT
1013     {
1014         __non_rtti_object e;
1015         MSVCRT___non_rtti_object_ctor( &e, "Access violation - no RTTI data!" );
1016         _CxxThrowException( &e, &bad_typeid_exception_type );
1017         return NULL;
1018     }
1019     __ENDTRY
1020     return ret;
1021 }
1022
1023
1024 /******************************************************************
1025  *              __RTCastToVoid (MSVCRT.@)
1026  *
1027  * Dynamically cast a C++ object to a void*.
1028  *
1029  * PARAMS
1030  *  cppobj [I] The C++ object to cast
1031  *
1032  * RETURNS
1033  *  Success: The base address of the object as a void*.
1034  *  Failure: NULL, if cppobj is NULL or has no RTTI.
1035  *
1036  * NOTES
1037  *  This function is usually called by compiler generated code as a result
1038  *  of using one of the C++ dynamic cast statements.
1039  */
1040 void* CDECL MSVCRT___RTCastToVoid(void *cppobj)
1041 {
1042     void *ret;
1043
1044     if (!cppobj) return NULL;
1045
1046     __TRY
1047     {
1048         const rtti_object_locator *obj_locator = get_obj_locator( cppobj );
1049         ret = (char *)cppobj - obj_locator->base_class_offset;
1050     }
1051     __EXCEPT_PAGE_FAULT
1052     {
1053         __non_rtti_object e;
1054         MSVCRT___non_rtti_object_ctor( &e, "Access violation - no RTTI data!" );
1055         _CxxThrowException( &e, &bad_typeid_exception_type );
1056         return NULL;
1057     }
1058     __ENDTRY
1059     return ret;
1060 }
1061
1062
1063 /*********************************************************************
1064  *              _CxxThrowException (MSVCRT.@)
1065  */
1066 void WINAPI _CxxThrowException( exception *object, const cxx_exception_type *type )
1067 {
1068     ULONG_PTR args[3];
1069
1070     args[0] = CXX_FRAME_MAGIC_VC6;
1071     args[1] = (ULONG_PTR)object;
1072     args[2] = (ULONG_PTR)type;
1073     RaiseException( CXX_EXCEPTION, EH_NONCONTINUABLE, 3, args );
1074 }