[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