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.
Test for how streambuf::setb() and both setbuf()s affect value of unbuffered are also included.
Signed-off-by: Arkadiusz Hiler ahiler@codeweavers.com ---
v2: * styling - inline opening curly bracked with if statements * ok() messages consistency with the actual checks
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 7e1d9977b78..744d8bc943a 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@filebuf@@QAEHH@Z */ diff --git a/dlls/msvcirt/tests/msvcirt.c b/dlls/msvcirt/tests/msvcirt.c index 4f9f859a861..a21ac20267c 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);