[v2 02/10] msvcirt: Implement ostream constructors/destructors
Iván Matellanes
matellanesivan at gmail.com
Tue Jun 14 09:40:16 CDT 2016
v2: Correct behaviour when virt_init == FALSE and more tests.
Signed-off-by: Iván Matellanes <matellanes.ivan at gmail.com>
---
dlls/msvcirt/msvcirt.c | 105 ++++++++++++++++++++++++----
dlls/msvcirt/tests/msvcirt.c | 158 ++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 248 insertions(+), 15 deletions(-)
diff --git a/dlls/msvcirt/msvcirt.c b/dlls/msvcirt/msvcirt.c
index 784b84a..6358e94 100644
--- a/dlls/msvcirt/msvcirt.c
+++ b/dlls/msvcirt/msvcirt.c
@@ -2229,12 +2229,40 @@ int __cdecl ios_xalloc(void)
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 at PAVstreambuf@@@Z */
/* ??0ostream@@QEAA at PEAVstreambuf@@@Z */
DEFINE_THISCALL_WRAPPER(ostream_sb_ctor, 12)
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;
}
@@ -2243,8 +2271,7 @@ ostream* __thiscall ostream_sb_ctor(ostream *this, streambuf *sb, BOOL virt_init
DEFINE_THISCALL_WRAPPER(ostream_copy_ctor, 12)
ostream* __thiscall ostream_copy_ctor(ostream *this, const ostream *copy, BOOL virt_init)
{
- FIXME("(%p %p %d) stub\n", this, copy, virt_init);
- return this;
+ return ostream_sb_ctor(this, ostream_get_ios(copy)->sb, virt_init);
}
/* ??0ostream@@IAE at XZ */
@@ -2252,7 +2279,18 @@ ostream* __thiscall ostream_copy_ctor(ostream *this, const ostream *copy, BOOL v
DEFINE_THISCALL_WRAPPER(ostream_ctor, 8)
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;
}
@@ -2261,7 +2299,9 @@ ostream* __thiscall ostream_ctor(ostream *this, BOOL virt_init)
DEFINE_THISCALL_WRAPPER(ostream_dtor, 4)
void __thiscall ostream_dtor(ios *base)
{
- FIXME("(%p) stub\n", base);
+ ostream *this = ios_to_ostream(base);
+
+ TRACE("(%p)\n", this);
}
/* ??4ostream@@IAEAAV0 at PAVstreambuf@@@Z */
@@ -2269,7 +2309,18 @@ void __thiscall ostream_dtor(ios *base)
DEFINE_THISCALL_WRAPPER(ostream_assign_sb, 8)
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;
}
@@ -2278,8 +2329,11 @@ ostream* __thiscall ostream_assign_sb(ostream *this, streambuf *sb)
DEFINE_THISCALL_WRAPPER(ostream_assign, 8)
ostream* __thiscall ostream_assign(ostream *this, const ostream *rhs)
{
- FIXME("(%p %p) stub\n", this, rhs);
- return this;
+ ios *base_rhs = ostream_get_ios(rhs);
+
+ TRACE("(%p %p)\n", this, rhs);
+
+ return ostream_assign_sb(this, base_rhs->sb);
}
/* ??_Dostream@@QAEXXZ */
@@ -2287,23 +2341,48 @@ ostream* __thiscall ostream_assign(ostream *this, const ostream *rhs)
DEFINE_THISCALL_WRAPPER(ostream_vbase_dtor, 4)
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 at Z */
DEFINE_THISCALL_WRAPPER(ostream_vector_dtor, 8)
ostream* __thiscall ostream_vector_dtor(ios *base, unsigned int flags)
{
- FIXME("(%p %x) stub\n", base, flags);
- return NULL;
+ ostream *this = ios_to_ostream(base);
+
+ 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 at Z */
DEFINE_THISCALL_WRAPPER(ostream_scalar_dtor, 8)
ostream* __thiscall ostream_scalar_dtor(ios *base, unsigned int flags)
{
- FIXME("(%p %x) stub\n", base, flags);
- return NULL;
+ ostream *this = ios_to_ostream(base);
+
+ TRACE("(%p %x)\n", this, flags);
+
+ ostream_vbase_dtor(this);
+ if (flags & 1) MSVCRT_operator_delete(this);
+ return this;
}
/* ?flush at ostream@@QAEAAV1 at XZ */
diff --git a/dlls/msvcirt/tests/msvcirt.c b/dlls/msvcirt/tests/msvcirt.c
index 27ca169..f17c2ef 100644
--- a/dlls/msvcirt/tests/msvcirt.c
+++ b/dlls/msvcirt/tests/msvcirt.c
@@ -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
* modify it under the terms of the GNU Lesser General Public
@@ -140,7 +140,9 @@ typedef struct {
/* class ostream */
typedef struct _ostream {
- const vtable_ptr *vtable;
+ const int *vbtable;
+ int unknown;
+ ios base_ios; /* virtually inherited */
} ostream;
#undef __thiscall
@@ -251,6 +253,15 @@ static void** (*__thiscall p_ios_pword)(const ios*, int);
static int (*__cdecl p_ios_xalloc)(void);
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 */
#ifdef __i386__
@@ -407,6 +418,14 @@ static BOOL init(void)
SET(p_ios_clear, "?clear at ios@@QEAAXH at Z");
SET(p_ios_iword, "?iword at ios@@QEBAAEAJH at Z");
SET(p_ios_pword, "?pword at ios@@QEBAAEAPEAXH at Z");
+
+ SET(p_ostream_copy_ctor, "??0ostream@@IEAA at AEBV0@@Z");
+ SET(p_ostream_sb_ctor, "??0ostream@@QEAA at PEAVstreambuf@@@Z");
+ SET(p_ostream_ctor, "??0ostream@@IEAA at XZ");
+ SET(p_ostream_dtor, "??1ostream@@UEAA at XZ");
+ SET(p_ostream_assign, "??4ostream@@IEAAAEAV0 at AEBV0@@Z");
+ SET(p_ostream_assign_sb, "??4ostream@@IEAAAEAV0 at PEAVstreambuf@@@Z");
+ SET(p_ostream_vbase_dtor, "??_Dostream@@QEAAXXZ");
} else {
p_operator_new = (void*)GetProcAddress(msvcrt, "??2 at YAPAXI@Z");
p_operator_delete = (void*)GetProcAddress(msvcrt, "??3 at YAXPAX@Z");
@@ -494,6 +513,14 @@ static BOOL init(void)
SET(p_ios_clear, "?clear at ios@@QAEXH at Z");
SET(p_ios_iword, "?iword at ios@@QBEAAJH at Z");
SET(p_ios_pword, "?pword at ios@@QBEAAPAXH at Z");
+
+ SET(p_ostream_copy_ctor, "??0ostream@@IAE at ABV0@@Z");
+ SET(p_ostream_sb_ctor, "??0ostream@@QAE at PAVstreambuf@@@Z");
+ SET(p_ostream_ctor, "??0ostream@@IAE at XZ");
+ SET(p_ostream_dtor, "??1ostream@@UAE at XZ");
+ SET(p_ostream_assign, "??4ostream@@IAEAAV0 at ABV0@@Z");
+ SET(p_ostream_assign_sb, "??4ostream@@IAEAAV0 at PAVstreambuf@@@Z");
+ SET(p_ostream_vbase_dtor, "??_Dostream@@QAEXXZ");
}
SET(p_ios_static_lock, "?x_lockc at ios@@0U_CRT_CRITICAL_SECTION@@A");
SET(p_ios_lockc, "?lockc at ios@@KAXXZ");
@@ -2479,6 +2506,132 @@ static void test_ios(void)
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)
{
if(!init())
@@ -2489,6 +2642,7 @@ START_TEST(msvcirt)
test_strstreambuf();
test_stdiobuf();
test_ios();
+ test_ostream();
FreeLibrary(msvcrt);
FreeLibrary(msvcirt);
--
2.7.4
More information about the wine-patches
mailing list