Arkadiusz Hiler : msvcirt: Correct the behavior of filebuf::setbuf().

Alexandre Julliard julliard at winehq.org
Fri Sep 4 15:47:31 CDT 2020


Module: wine
Branch: master
Commit: f4bb6abebc17a9ba1307eccb0f7764bcf01f3cd1
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=f4bb6abebc17a9ba1307eccb0f7764bcf01f3cd1

Author: Arkadiusz Hiler <ahiler at codeweavers.com>
Date:   Fri Sep  4 12:42:39 2020 +0300

msvcirt: Correct the behavior of filebuf::setbuf().

While implementing ifstream::setbuf() it turned out that filebuf::setbuf(),
behaves a bit different on Windows than our implementation.

It seems to reimplement streambuf::setbuf() with a very minor difference - it
doesn't ever set unbuffered to 0 and allows to change the underlying buffer as
long as the file is not opened.

Signed-off-by: Arkadiusz Hiler <ahiler at codeweavers.com>
Signed-off-by: Piotr Caban <piotr at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/msvcirt/msvcirt.c       | 22 ++++++++++++----
 dlls/msvcirt/tests/msvcirt.c | 60 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 77 insertions(+), 5 deletions(-)

diff --git a/dlls/msvcirt/msvcirt.c b/dlls/msvcirt/msvcirt.c
index 7e1d9977b7..744d8bc943 100644
--- a/dlls/msvcirt/msvcirt.c
+++ b/dlls/msvcirt/msvcirt.c
@@ -1175,16 +1175,28 @@ streampos __thiscall filebuf_seekoff(filebuf *this, streamoff offset, ios_seek_d
 DEFINE_THISCALL_WRAPPER(filebuf_setbuf, 12)
 streambuf* __thiscall filebuf_setbuf(filebuf *this, char *buffer, int length)
 {
-    streambuf *ret;
-
     TRACE("(%p %p %d)\n", this, buffer, length);
-    if (this->base.base != NULL)
+
+    if (filebuf_is_open(this) && this->base.base != NULL)
         return NULL;
 
     streambuf_lock(&this->base);
-    ret = streambuf_setbuf(&this->base, buffer, length);
+
+    if (buffer == NULL || !length) {
+        this->base.unbuffered = 1;
+    } else {
+        if (this->base.allocated) {
+            MSVCRT_operator_delete(this->base.base);
+            this->base.allocated = 0;
+        }
+
+        this->base.base = buffer;
+        this->base.ebuf = buffer + length;
+    }
+
     streambuf_unlock(&this->base);
-    return ret;
+
+    return &this->base;
 }
 
 /* ?setmode at filebuf@@QAEHH at Z */
diff --git a/dlls/msvcirt/tests/msvcirt.c b/dlls/msvcirt/tests/msvcirt.c
index 4f9f859a86..48f1514483 100644
--- a/dlls/msvcirt/tests/msvcirt.c
+++ b/dlls/msvcirt/tests/msvcirt.c
@@ -1168,16 +1168,22 @@ static void test_streambuf(void)
     sb.do_lock = -1;
 
     /* setb */
+    sb.unbuffered = 1;
     call_func4(p_streambuf_setb, &sb, reserve, reserve+16, 0);
+    ok(sb.unbuffered == 1, "wrong unbuffered value, expected 1 got %d\n", sb.unbuffered);
     ok(sb.base == reserve, "wrong base pointer, expected %p got %p\n", reserve, sb.base);
     ok(sb.ebuf == reserve+16, "wrong ebuf pointer, expected %p got %p\n", reserve+16, sb.ebuf);
     call_func4(p_streambuf_setb, &sb, reserve, reserve+16, 4);
+    ok(sb.unbuffered == 1, "wrong unbuffered value, expected 1 got %d\n", sb.unbuffered);
     ok(sb.allocated == 4, "wrong allocate value, expected 4 got %d\n", sb.allocated);
     sb.allocated = 0;
+    sb.unbuffered = 0;
     call_func4(p_streambuf_setb, &sb, NULL, NULL, 3);
+    ok(sb.unbuffered == 0, "wrong unbuffered value, expected 0 got %d\n", sb.unbuffered);
     ok(sb.allocated == 3, "wrong allocate value, expected 3 got %d\n", sb.allocated);
 
     /* setbuf */
+    sb.unbuffered = 0;
     psb = call_func3(p_streambuf_setbuf, &sb, NULL, 5);
     ok(psb == &sb, "wrong return value, expected %p got %p\n", &sb, psb);
     ok(sb.allocated == 3, "wrong allocate value, expected 3 got %d\n", sb.allocated);
@@ -1659,21 +1665,75 @@ static void test_filebuf(void)
 
     /* setbuf */
     fb1.base.do_lock = 0;
+    fb1.fd = -1; /* closed */
+    ok(fb1.base.allocated == 0, "wrong allocate value, expected 0 got %d\n", fb1.base.allocated);
+    ok(fb1.base.unbuffered == 0, "wrong unbuffered value, expected 0 got %d\n", fb1.base.unbuffered);
+    ok(fb1.fd == -1, "wrong fd, expected -1 got %d\n", fb1.fd);
+    fb1.base.unbuffered = 1;
     pret = (filebuf*) call_func3(p_filebuf_setbuf, &fb1, read_buffer, 16);
     ok(pret == &fb1, "wrong return, expected %p got %p\n", &fb1, pret);
     ok(fb1.base.allocated == 0, "wrong allocate value, expected 0 got %d\n", fb1.base.allocated);
+    ok(fb1.base.unbuffered == 1, "wrong unbuffered value, expected 1 got %d\n", fb1.base.unbuffered);
     ok(fb1.base.base == read_buffer, "wrong buffer, expected %p got %p\n", read_buffer, fb1.base.base);
     ok(fb1.base.pbase == NULL, "wrong put area, expected %p got %p\n", NULL, fb1.base.pbase);
+    ok(fb1.base.allocated == 0, "wrong allocate value, expected 0 got %d\n", fb1.base.allocated);
+    pret = (filebuf*) call_func3(p_filebuf_setbuf, &fb1, read_buffer + 8, 8);
+    ok(pret == &fb1, "wrong return, expected %p got %p\n", NULL, pret);
+    ok(fb1.base.allocated == 0, "wrong allocate value, expected 0 got %d\n", fb1.base.allocated);
+    ok(fb1.base.unbuffered == 1, "wrong unbuffered value, expected 1 got %d\n", fb1.base.unbuffered);
+    ok(fb1.base.base == read_buffer + 8, "wrong buffer, expected %p got %p\n", read_buffer + 8, fb1.base.base);
+    ok(fb1.base.pbase == NULL, "wrong put area, expected %p got %p\n", NULL, fb1.base.pbase);
+    fb1.base.unbuffered = 0;
+    pret = (filebuf*) call_func3(p_filebuf_setbuf, &fb1, NULL, 0);
+    ok(fb1.base.allocated == 0, "wrong allocate value, expected 0 got %d\n", fb1.base.allocated);
+    ok(fb1.base.unbuffered == 1, "wrong unbuffered value, expected 1 got %d\n", fb1.base.unbuffered);
+    ok(fb1.base.base == read_buffer + 8, "wrong buffer, expected %p got %p\n", read_buffer + 8, fb1.base.base);
+    ok(fb1.base.pbase == NULL, "wrong put area, expected %p got %p\n", NULL, fb1.base.pbase);
+    ok((int) call_func1(p_streambuf_doallocate, &fb1.base) == 1, "failed to allocate buffer\n");
+    ok(fb1.base.allocated == 1, "wrong allocate value, expected 1 got %d\n", fb1.base.allocated);
+    ok(fb1.base.unbuffered == 1, "wrong unbuffered value, expected 1 got %d\n", fb1.base.unbuffered);
+    ok(fb1.base.base != NULL, "wrong buffer, expected not NULL got %p\n", fb1.base.base);
+    pret = (filebuf*) call_func3(p_filebuf_setbuf, &fb1, read_buffer + 2, 14);
+    ok(pret == &fb1, "wrong return, expected %p got %p\n", &fb1, pret);
+    ok(fb1.base.allocated == 0, "wrong allocate value, expected 0 got %d\n", fb1.base.allocated);
+    ok(fb1.base.unbuffered == 1, "wrong unbuffered value, expected 1 got %d\n", fb1.base.unbuffered);
+    ok(fb1.base.base == read_buffer + 2, "wrong buffer, expected %p got %p\n", read_buffer + 2, fb1.base.base);
+    ok(fb1.base.pbase == NULL, "wrong put area, expected %p got %p\n", NULL, fb1.base.pbase);
+    ok(fb1.base.allocated == 0, "wrong allocate value, expected 0 got %d\n", fb1.base.allocated);
+    fb1.fd = 1; /* opened */
+    fb1.base.unbuffered = 1;
+    fb1.base.base = fb1.base.ebuf = NULL;
+    pret = (filebuf*) call_func3(p_filebuf_setbuf, &fb1, read_buffer, 16);
+    ok(pret == &fb1, "wrong return, expected %p got %p\n", &fb1, pret);
+    ok(fb1.base.allocated == 0, "wrong allocate value, expected 0 got %d\n", fb1.base.allocated);
+    ok(fb1.base.unbuffered == 1, "wrong unbuffered value, expected 1 got %d\n", fb1.base.unbuffered);
+    ok(fb1.base.base == read_buffer, "wrong buffer, expected %p got %p\n", read_buffer, fb1.base.base);
+    ok(fb1.base.pbase == NULL, "wrong put area, expected %p got %p\n", NULL, fb1.base.pbase);
+    pret = (filebuf*) call_func3(p_filebuf_setbuf, &fb1, read_buffer + 8, 8);
+    ok(pret == NULL, "wrong return, expected %p got %p\n", NULL, pret);
+    ok(fb1.base.allocated == 0, "wrong allocate value, expected 0 got %d\n", fb1.base.allocated);
+    ok(fb1.base.unbuffered == 1, "wrong unbuffered value, expected 1 got %d\n", fb1.base.unbuffered);
+    ok(fb1.base.base == read_buffer, "wrong buffer, expected %p got %p\n", read_buffer, fb1.base.base);
+    ok(fb1.base.pbase == NULL, "wrong put area, expected %p got %p\n", NULL, fb1.base.pbase);
+    fb1.base.unbuffered = 0;
+    pret = (filebuf*) call_func3(p_filebuf_setbuf, &fb1, NULL, 0);
+    ok(fb1.base.allocated == 0, "wrong allocate value, expected 0 got %d\n", fb1.base.allocated);
+    ok(fb1.base.unbuffered == 0, "wrong unbuffered value, expected 0 got %d\n", fb1.base.unbuffered);
+    ok(fb1.base.base == read_buffer, "wrong buffer, expected %p got %p\n", read_buffer, fb1.base.base);
+    ok(fb1.base.pbase == NULL, "wrong put area, expected %p got %p\n", NULL, fb1.base.pbase);
+    fb1.base.unbuffered = 1;
     fb1.base.pbase = fb1.base.pptr = fb1.base.base;
     fb1.base.epptr = fb1.base.ebuf;
     fb1.base.do_lock = -1;
     pret = (filebuf*) call_func3(p_filebuf_setbuf, &fb1, read_buffer, 16);
     ok(pret == NULL, "wrong return, expected %p got %p\n", NULL, pret);
     ok(fb1.base.allocated == 0, "wrong allocate value, expected 0 got %d\n", fb1.base.allocated);
+    ok(fb1.base.unbuffered == 1, "wrong unbuffered value, expected 1 got %d\n", fb1.base.unbuffered);
     ok(fb1.base.base == read_buffer, "wrong buffer, expected %p got %p\n", read_buffer, fb1.base.base);
     ok(fb1.base.pbase == read_buffer, "wrong put area, expected %p got %p\n", read_buffer, fb1.base.pbase);
     fb1.base.base = fb1.base.ebuf = NULL;
     fb1.base.do_lock = 0;
+    fb1.base.unbuffered = 0;
     pret = (filebuf*) call_func3(p_filebuf_setbuf, &fb1, read_buffer, 0);
     ok(pret == &fb1, "wrong return, expected %p got %p\n", &fb1, pret);
     ok(fb1.base.allocated == 0, "wrong allocate value, expected 0 got %d\n", fb1.base.allocated);




More information about the wine-cvs mailing list