msvcirt: Implement ostream constructors/destructors.

Signed-off-by: Iván Matellanes <matellanes.ivan@gmail.com>
Signed-off-by: Piotr Caban <piotr@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Iván Matellanes 2016-06-14 15:40:16 +01:00 committed by Alexandre Julliard
parent c5075c057c
commit cf1f23379b
2 changed files with 248 additions and 15 deletions

View File

@ -2229,12 +2229,40 @@ int __cdecl ios_xalloc(void)
return ret; return ret;
} }
static inline ios* ostream_get_ios(const ostream *this)
{
return (ios*)((char*)this + this->vbtable[1]);
}
static inline ios* ostream_to_ios(const ostream *this)
{
return (ios*)((char*)this + ostream_vbtable[1]);
}
static inline ostream* ios_to_ostream(const ios *base)
{
return (ostream*)((char*)base - ostream_vbtable[1]);
}
/* ??0ostream@@QAE@PAVstreambuf@@@Z */ /* ??0ostream@@QAE@PAVstreambuf@@@Z */
/* ??0ostream@@QEAA@PEAVstreambuf@@@Z */ /* ??0ostream@@QEAA@PEAVstreambuf@@@Z */
DEFINE_THISCALL_WRAPPER(ostream_sb_ctor, 12) DEFINE_THISCALL_WRAPPER(ostream_sb_ctor, 12)
ostream* __thiscall ostream_sb_ctor(ostream *this, streambuf *sb, BOOL virt_init) ostream* __thiscall ostream_sb_ctor(ostream *this, streambuf *sb, BOOL virt_init)
{ {
FIXME("(%p %p %d) stub\n", this, sb, virt_init); ios *base;
TRACE("(%p %p %d)\n", this, sb, virt_init);
if (virt_init) {
this->vbtable = ostream_vbtable;
base = ostream_get_ios(this);
ios_sb_ctor(base, sb);
} else {
base = ostream_get_ios(this);
ios_init(base, sb);
}
base->vtable = &MSVCP_ostream_vtable;
this->unknown = 0;
return this; return this;
} }
@ -2243,8 +2271,7 @@ ostream* __thiscall ostream_sb_ctor(ostream *this, streambuf *sb, BOOL virt_init
DEFINE_THISCALL_WRAPPER(ostream_copy_ctor, 12) DEFINE_THISCALL_WRAPPER(ostream_copy_ctor, 12)
ostream* __thiscall ostream_copy_ctor(ostream *this, const ostream *copy, BOOL virt_init) ostream* __thiscall ostream_copy_ctor(ostream *this, const ostream *copy, BOOL virt_init)
{ {
FIXME("(%p %p %d) stub\n", this, copy, virt_init); return ostream_sb_ctor(this, ostream_get_ios(copy)->sb, virt_init);
return this;
} }
/* ??0ostream@@IAE@XZ */ /* ??0ostream@@IAE@XZ */
@ -2252,7 +2279,18 @@ ostream* __thiscall ostream_copy_ctor(ostream *this, const ostream *copy, BOOL v
DEFINE_THISCALL_WRAPPER(ostream_ctor, 8) DEFINE_THISCALL_WRAPPER(ostream_ctor, 8)
ostream* __thiscall ostream_ctor(ostream *this, BOOL virt_init) ostream* __thiscall ostream_ctor(ostream *this, BOOL virt_init)
{ {
FIXME("(%p %d) stub\n", this, virt_init); ios *base;
TRACE("(%p %d)\n", this, virt_init);
if (virt_init) {
this->vbtable = ostream_vbtable;
base = ostream_get_ios(this);
ios_ctor(base);
} else
base = ostream_get_ios(this);
base->vtable = &MSVCP_ostream_vtable;
this->unknown = 0;
return this; return this;
} }
@ -2261,7 +2299,9 @@ ostream* __thiscall ostream_ctor(ostream *this, BOOL virt_init)
DEFINE_THISCALL_WRAPPER(ostream_dtor, 4) DEFINE_THISCALL_WRAPPER(ostream_dtor, 4)
void __thiscall ostream_dtor(ios *base) void __thiscall ostream_dtor(ios *base)
{ {
FIXME("(%p) stub\n", base); ostream *this = ios_to_ostream(base);
TRACE("(%p)\n", this);
} }
/* ??4ostream@@IAEAAV0@PAVstreambuf@@@Z */ /* ??4ostream@@IAEAAV0@PAVstreambuf@@@Z */
@ -2269,7 +2309,18 @@ void __thiscall ostream_dtor(ios *base)
DEFINE_THISCALL_WRAPPER(ostream_assign_sb, 8) DEFINE_THISCALL_WRAPPER(ostream_assign_sb, 8)
ostream* __thiscall ostream_assign_sb(ostream *this, streambuf *sb) ostream* __thiscall ostream_assign_sb(ostream *this, streambuf *sb)
{ {
FIXME("(%p %p) stub\n", this, sb); ios *base = ostream_get_ios(this);
TRACE("(%p %p)\n", this, sb);
ios_init(base, sb);
base->state &= IOSTATE_badbit;
base->delbuf = 0;
base->tie = NULL;
base->flags = 0;
base->precision = 6;
base->fill = ' ';
base->width = 0;
return this; return this;
} }
@ -2278,8 +2329,11 @@ ostream* __thiscall ostream_assign_sb(ostream *this, streambuf *sb)
DEFINE_THISCALL_WRAPPER(ostream_assign, 8) DEFINE_THISCALL_WRAPPER(ostream_assign, 8)
ostream* __thiscall ostream_assign(ostream *this, const ostream *rhs) ostream* __thiscall ostream_assign(ostream *this, const ostream *rhs)
{ {
FIXME("(%p %p) stub\n", this, rhs); ios *base_rhs = ostream_get_ios(rhs);
return this;
TRACE("(%p %p)\n", this, rhs);
return ostream_assign_sb(this, base_rhs->sb);
} }
/* ??_Dostream@@QAEXXZ */ /* ??_Dostream@@QAEXXZ */
@ -2287,23 +2341,48 @@ ostream* __thiscall ostream_assign(ostream *this, const ostream *rhs)
DEFINE_THISCALL_WRAPPER(ostream_vbase_dtor, 4) DEFINE_THISCALL_WRAPPER(ostream_vbase_dtor, 4)
void __thiscall ostream_vbase_dtor(ostream *this) void __thiscall ostream_vbase_dtor(ostream *this)
{ {
FIXME("(%p) stub\n", this); ios *base = ostream_to_ios(this);
TRACE("(%p)\n", this);
ostream_dtor(base);
ios_dtor(base);
} }
/* ??_Eostream@@UAEPAXI@Z */ /* ??_Eostream@@UAEPAXI@Z */
DEFINE_THISCALL_WRAPPER(ostream_vector_dtor, 8) DEFINE_THISCALL_WRAPPER(ostream_vector_dtor, 8)
ostream* __thiscall ostream_vector_dtor(ios *base, unsigned int flags) ostream* __thiscall ostream_vector_dtor(ios *base, unsigned int flags)
{ {
FIXME("(%p %x) stub\n", base, flags); ostream *this = ios_to_ostream(base);
return NULL;
TRACE("(%p %x)\n", this, flags);
if (flags & 2) {
/* we have an array, with the number of elements stored before the first object */
INT_PTR i, *ptr = (INT_PTR *)this-1;
for (i = *ptr-1; i >= 0; i--)
ostream_vbase_dtor(this+i);
MSVCRT_operator_delete(ptr);
} else {
ostream_vbase_dtor(this);
if (flags & 1)
MSVCRT_operator_delete(this);
}
return this;
} }
/* ??_Gostream@@UAEPAXI@Z */ /* ??_Gostream@@UAEPAXI@Z */
DEFINE_THISCALL_WRAPPER(ostream_scalar_dtor, 8) DEFINE_THISCALL_WRAPPER(ostream_scalar_dtor, 8)
ostream* __thiscall ostream_scalar_dtor(ios *base, unsigned int flags) ostream* __thiscall ostream_scalar_dtor(ios *base, unsigned int flags)
{ {
FIXME("(%p %x) stub\n", base, flags); ostream *this = ios_to_ostream(base);
return NULL;
TRACE("(%p %x)\n", this, flags);
ostream_vbase_dtor(this);
if (flags & 1) MSVCRT_operator_delete(this);
return this;
} }
/* ?flush@ostream@@QAEAAV1@XZ */ /* ?flush@ostream@@QAEAAV1@XZ */

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2015 Iván Matellanes * Copyright 2015-2016 Iván Matellanes
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
@ -140,7 +140,9 @@ typedef struct {
/* class ostream */ /* class ostream */
typedef struct _ostream { typedef struct _ostream {
const vtable_ptr *vtable; const int *vbtable;
int unknown;
ios base_ios; /* virtually inherited */
} ostream; } ostream;
#undef __thiscall #undef __thiscall
@ -251,6 +253,15 @@ static void** (*__thiscall p_ios_pword)(const ios*, int);
static int (*__cdecl p_ios_xalloc)(void); static int (*__cdecl p_ios_xalloc)(void);
static int *p_ios_fLockcInit; static int *p_ios_fLockcInit;
/* ostream */
static ostream* (*__thiscall p_ostream_copy_ctor)(ostream*, const ostream*, BOOL);
static ostream* (*__thiscall p_ostream_sb_ctor)(ostream*, streambuf*, BOOL);
static ostream* (*__thiscall p_ostream_ctor)(ostream*, BOOL);
static void (*__thiscall p_ostream_dtor)(ios*);
static ostream* (*__thiscall p_ostream_assign)(ostream*, const ostream*);
static ostream* (*__thiscall p_ostream_assign_sb)(ostream*, streambuf*);
static void (*__thiscall p_ostream_vbase_dtor)(ostream*);
/* Emulate a __thiscall */ /* Emulate a __thiscall */
#ifdef __i386__ #ifdef __i386__
@ -407,6 +418,14 @@ static BOOL init(void)
SET(p_ios_clear, "?clear@ios@@QEAAXH@Z"); SET(p_ios_clear, "?clear@ios@@QEAAXH@Z");
SET(p_ios_iword, "?iword@ios@@QEBAAEAJH@Z"); SET(p_ios_iword, "?iword@ios@@QEBAAEAJH@Z");
SET(p_ios_pword, "?pword@ios@@QEBAAEAPEAXH@Z"); SET(p_ios_pword, "?pword@ios@@QEBAAEAPEAXH@Z");
SET(p_ostream_copy_ctor, "??0ostream@@IEAA@AEBV0@@Z");
SET(p_ostream_sb_ctor, "??0ostream@@QEAA@PEAVstreambuf@@@Z");
SET(p_ostream_ctor, "??0ostream@@IEAA@XZ");
SET(p_ostream_dtor, "??1ostream@@UEAA@XZ");
SET(p_ostream_assign, "??4ostream@@IEAAAEAV0@AEBV0@@Z");
SET(p_ostream_assign_sb, "??4ostream@@IEAAAEAV0@PEAVstreambuf@@@Z");
SET(p_ostream_vbase_dtor, "??_Dostream@@QEAAXXZ");
} else { } else {
p_operator_new = (void*)GetProcAddress(msvcrt, "??2@YAPAXI@Z"); p_operator_new = (void*)GetProcAddress(msvcrt, "??2@YAPAXI@Z");
p_operator_delete = (void*)GetProcAddress(msvcrt, "??3@YAXPAX@Z"); p_operator_delete = (void*)GetProcAddress(msvcrt, "??3@YAXPAX@Z");
@ -494,6 +513,14 @@ static BOOL init(void)
SET(p_ios_clear, "?clear@ios@@QAEXH@Z"); SET(p_ios_clear, "?clear@ios@@QAEXH@Z");
SET(p_ios_iword, "?iword@ios@@QBEAAJH@Z"); SET(p_ios_iword, "?iword@ios@@QBEAAJH@Z");
SET(p_ios_pword, "?pword@ios@@QBEAAPAXH@Z"); SET(p_ios_pword, "?pword@ios@@QBEAAPAXH@Z");
SET(p_ostream_copy_ctor, "??0ostream@@IAE@ABV0@@Z");
SET(p_ostream_sb_ctor, "??0ostream@@QAE@PAVstreambuf@@@Z");
SET(p_ostream_ctor, "??0ostream@@IAE@XZ");
SET(p_ostream_dtor, "??1ostream@@UAE@XZ");
SET(p_ostream_assign, "??4ostream@@IAEAAV0@ABV0@@Z");
SET(p_ostream_assign_sb, "??4ostream@@IAEAAV0@PAVstreambuf@@@Z");
SET(p_ostream_vbase_dtor, "??_Dostream@@QAEXXZ");
} }
SET(p_ios_static_lock, "?x_lockc@ios@@0U_CRT_CRITICAL_SECTION@@A"); SET(p_ios_static_lock, "?x_lockc@ios@@0U_CRT_CRITICAL_SECTION@@A");
SET(p_ios_lockc, "?lockc@ios@@KAXXZ"); SET(p_ios_lockc, "?lockc@ios@@KAXXZ");
@ -2479,6 +2506,132 @@ static void test_ios(void)
CloseHandle(thread); CloseHandle(thread);
} }
static void test_ostream(void) {
ostream os1, os2, *pos;
filebuf fb1, *pfb;
const char filename1[] = "test1";
memset(&os1, 0xab, sizeof(ostream));
memset(&os2, 0xab, sizeof(ostream));
memset(&fb1, 0xab, sizeof(filebuf));
/* constructors/destructors */
pos = (ostream*) call_func2(p_ostream_ctor, &os1, TRUE);
ok(pos == &os1, "wrong return, expected %p got %p\n", &os1, pos);
ok(os1.unknown == 0, "expected 0 got %d\n", os1.unknown);
ok(os1.base_ios.sb == NULL, "expected %p got %p\n", NULL, os1.base_ios.sb);
ok(os1.base_ios.state == IOSTATE_badbit, "expected %d got %d\n", IOSTATE_badbit, os1.base_ios.state);
call_func1(p_ostream_vbase_dtor, &os1);
pos = (ostream*) call_func3(p_ostream_sb_ctor, &os1, (streambuf*) &fb1, TRUE);
ok(pos == &os1, "wrong return, expected %p got %p\n", &os1, pos);
ok(os1.unknown == 0, "expected 0 got %d\n", os1.unknown);
ok(os1.base_ios.sb == (streambuf*) &fb1, "expected %p got %p\n", &fb1, os1.base_ios.sb);
ok(os1.base_ios.state == IOSTATE_goodbit, "expected %d got %d\n", IOSTATE_goodbit, os1.base_ios.state);
ok(fb1.base.allocated == 0xabababab, "expected %d got %d\n", 0xabababab, fb1.base.allocated);
call_func1(p_filebuf_ctor, &fb1);
pfb = (filebuf*) call_func4(p_filebuf_open, &fb1, filename1, OPENMODE_out, filebuf_openprot);
ok(pfb == &fb1, "wrong return, expected %p got %p\n", &fb1, pfb);
ok(fb1.base.allocated == 1, "expected %d got %d\n", 1, fb1.base.allocated);
call_func1(p_ostream_vbase_dtor, &os1);
ok(os1.base_ios.sb == NULL, "expected %p got %p\n", NULL, os1.base_ios.sb);
ok(os1.base_ios.state == IOSTATE_badbit, "expected %d got %d\n", IOSTATE_badbit, os1.base_ios.state);
memset(&os1.base_ios, 0xab, sizeof(ios));
os1.unknown = 0xabababab;
pos = (ostream*) call_func2(p_ostream_ctor, &os1, FALSE);
ok(pos == &os1, "wrong return, expected %p got %p\n", &os1, pos);
ok(os1.unknown == 0, "expected 0 got %d\n", os1.unknown);
ok(os1.base_ios.sb == os2.base_ios.sb, "expected %p got %p\n", os2.base_ios.sb, os1.base_ios.sb);
ok(os1.base_ios.state == 0xabababab, "expected %d got %d\n", 0xabababab, os1.base_ios.state);
call_func1(p_ostream_dtor, &os1.base_ios);
os1.unknown = 0xabababab;
os1.base_ios.state = 0xabababab | IOSTATE_badbit;
os1.base_ios.delbuf = 0;
pos = (ostream*) call_func3(p_ostream_sb_ctor, &os1, (streambuf*) &fb1, FALSE);
ok(pos == &os1, "wrong return, expected %p got %p\n", &os1, pos);
ok(os1.unknown == 0, "expected 0 got %d\n", os1.unknown);
ok(os1.base_ios.sb == (streambuf*) &fb1, "expected %p got %p\n", &fb1, os1.base_ios.sb);
ok(os1.base_ios.state == 0xabababab, "expected %d got %d\n", 0xabababab, os1.base_ios.state);
call_func1(p_ostream_dtor, &os1.base_ios);
memset(&os1, 0xab, sizeof(ostream));
pos = (ostream*) call_func3(p_ostream_sb_ctor, &os1, NULL, TRUE);
ok(pos == &os1, "wrong return, expected %p got %p\n", &os1, pos);
ok(os1.unknown == 0, "expected 0 got %d\n", os1.unknown);
ok(os1.base_ios.sb == NULL, "expected %p got %p\n", NULL, os1.base_ios.sb);
ok(os1.base_ios.state == IOSTATE_badbit, "expected %d got %d\n", IOSTATE_badbit, os1.base_ios.state);
call_func1(p_ostream_vbase_dtor, &os1);
os1.unknown = 0xcdcdcdcd;
memset(&os1.base_ios, 0xcd, sizeof(ios));
memset(&os2, 0xab, sizeof(ostream));
os2.vbtable = os1.vbtable;
os2.base_ios.delbuf = 0;
os2.base_ios.tie = &os2;
pos = (ostream*) call_func3(p_ostream_copy_ctor, &os2, &os1, FALSE);
ok(pos == &os2, "wrong return, expected %p got %p\n", &os2, pos);
ok(os2.unknown == 0, "expected 0 got %d\n", os2.unknown);
ok(os2.base_ios.sb == os1.base_ios.sb, "expected %p got %p\n", os1.base_ios.sb, os2.base_ios.sb);
ok(os2.base_ios.state == 0xabababab, "expected %d got %d\n", 0xabababab, os2.base_ios.state);
ok(os2.base_ios.delbuf == 0, "expected 0 got %d\n", os2.base_ios.delbuf);
ok(os2.base_ios.tie == &os2, "expected %p got %p\n", &os2, os2.base_ios.tie);
ok(os2.base_ios.flags == 0xabababab, "expected %x got %x\n", 0xabababab, os2.base_ios.flags);
ok(os2.base_ios.precision == 0xabababab, "expected %d got %d\n", 0xabababab, os2.base_ios.precision);
ok(os2.base_ios.fill == (char) 0xab, "expected -85 got %d\n", os2.base_ios.fill);
ok(os2.base_ios.width == 0xabababab, "expected %d got %d\n", 0xabababab, os2.base_ios.width);
call_func1(p_ostream_dtor, &os2.base_ios);
pos = (ostream*) call_func3(p_ostream_copy_ctor, &os2, &os1, TRUE);
ok(pos == &os2, "wrong return, expected %p got %p\n", &os2, pos);
ok(os2.unknown == 0, "expected 0 got %d\n", os2.unknown);
ok(os2.base_ios.sb == os1.base_ios.sb, "expected %p got %p\n", os1.base_ios.sb, os2.base_ios.sb);
ok(os2.base_ios.state == IOSTATE_goodbit, "expected %d got %d\n", IOSTATE_goodbit, os2.base_ios.state);
ok(os2.base_ios.delbuf == 0, "expected 0 got %d\n", os2.base_ios.delbuf);
ok(os2.base_ios.tie == NULL, "expected %p got %p\n", NULL, os2.base_ios.tie);
ok(os2.base_ios.flags == 0, "expected 0 got %x\n", os2.base_ios.flags);
ok(os2.base_ios.precision == 6, "expected 6 got %d\n", os2.base_ios.precision);
ok(os2.base_ios.fill == ' ', "expected 32 got %d\n", os2.base_ios.fill);
ok(os2.base_ios.width == 0, "expected 0 got %d\n", os2.base_ios.width);
/* assignment */
pos = (ostream*) call_func2(p_ostream_ctor, &os1, TRUE);
ok(pos == &os1, "wrong return, expected %p got %p\n", &os1, pos);
os1.unknown = 0xabababab;
os1.base_ios.state = 0xabababab;
os1.base_ios.special[0] = 0xabababab;
os1.base_ios.delbuf = 0xabababab;
os1.base_ios.tie = (ostream*) 0xabababab;
os1.base_ios.flags = 0xabababab;
os1.base_ios.precision = 0xabababab;
os1.base_ios.width = 0xabababab;
pos = (ostream*) call_func2(p_ostream_assign_sb, &os1, (streambuf*) &fb1);
ok(pos == &os1, "wrong return, expected %p got %p\n", &os1, pos);
ok(os1.unknown == 0xabababab, "expected 0 got %d\n", os1.unknown);
ok(os1.base_ios.sb == (streambuf*) &fb1, "expected %p got %p\n", &fb1, os1.base_ios.sb);
ok(os1.base_ios.state == IOSTATE_goodbit, "expected %d got %d\n", IOSTATE_goodbit, os1.base_ios.state);
ok(os1.base_ios.special[0] == 0xabababab, "expected %d got %d\n", 0xabababab, os1.base_ios.fill);
ok(os1.base_ios.delbuf == 0, "expected 0 got %d\n", os1.base_ios.delbuf);
ok(os1.base_ios.tie == NULL, "expected %p got %p\n", NULL, os1.base_ios.tie);
ok(os1.base_ios.flags == 0, "expected 0 got %x\n", os1.base_ios.flags);
ok(os1.base_ios.precision == 6, "expected 6 got %d\n", os1.base_ios.precision);
ok(os1.base_ios.width == 0, "expected 0 got %d\n", os1.base_ios.width);
os1.base_ios.state = 0x8000;
pos = (ostream*) call_func2(p_ostream_assign_sb, &os1, NULL);
ok(pos == &os1, "wrong return, expected %p got %p\n", &os1, pos);
ok(os1.base_ios.sb == NULL, "expected %p got %p\n", NULL, os1.base_ios.sb);
ok(os1.base_ios.state == IOSTATE_badbit, "expected %d got %d\n", IOSTATE_badbit, os1.base_ios.state);
os2.unknown = 0xcdcdcdcd;
os2.base_ios.state = 0xcdcdcdcd;
os2.base_ios.special[0] = 0xcdcdcdcd;
pos = (ostream*) call_func2(p_ostream_assign, &os2, &os1);
ok(pos == &os2, "wrong return, expected %p got %p\n", &os2, pos);
ok(os2.unknown == 0xcdcdcdcd, "expected 0 got %d\n", os2.unknown);
ok(os2.base_ios.sb == NULL, "expected %p got %p\n", NULL, os2.base_ios.sb);
ok(os2.base_ios.state == IOSTATE_badbit, "expected %d got %d\n", IOSTATE_badbit, os2.base_ios.state);
ok(os2.base_ios.special[0] == 0xcdcdcdcd, "expected %d got %d\n", 0xcdcdcdcd, os2.base_ios.fill);
call_func1(p_ostream_vbase_dtor, &os1);
call_func1(p_ostream_vbase_dtor, &os2);
call_func1(p_filebuf_dtor, &fb1);
ok(_unlink(filename1) == 0, "Couldn't unlink file named '%s'\n", filename1);
}
START_TEST(msvcirt) START_TEST(msvcirt)
{ {
if(!init()) if(!init())
@ -2489,6 +2642,7 @@ START_TEST(msvcirt)
test_strstreambuf(); test_strstreambuf();
test_stdiobuf(); test_stdiobuf();
test_ios(); test_ios();
test_ostream();
FreeLibrary(msvcrt); FreeLibrary(msvcrt);
FreeLibrary(msvcirt); FreeLibrary(msvcirt);