From: Paul Gofman pgofman@codeweavers.com
--- dlls/msvcp140/msvcp140.spec | 6 +-- dlls/msvcp140/tests/msvcp140.c | 81 +++++++++++++++++++++++++++++++++- dlls/msvcp90/locale.c | 46 ++++++++++--------- dlls/msvcp90/msvcp90.h | 6 +++ 4 files changed, 115 insertions(+), 24 deletions(-)
diff --git a/dlls/msvcp140/msvcp140.spec b/dlls/msvcp140/msvcp140.spec index 600cbfa345c..0a8af0ec04b 100644 --- a/dlls/msvcp140/msvcp140.spec +++ b/dlls/msvcp140/msvcp140.spec @@ -175,9 +175,9 @@ @ cdecl -arch=arm ??0?$codecvt@_SDU_Mbstatet@@@std@@QAA@ABV_Locinfo@1@I@Z(ptr ptr long) codecvt_char16_ctor_locinfo @ thiscall -arch=i386 ??0?$codecvt@_SDU_Mbstatet@@@std@@QAE@ABV_Locinfo@1@I@Z(ptr ptr long) codecvt_char16_ctor_locinfo @ cdecl -arch=win64 ??0?$codecvt@_SDU_Mbstatet@@@std@@QEAA@AEBV_Locinfo@1@_K@Z(ptr ptr long) codecvt_char16_ctor_locinfo -@ cdecl -arch=arm ??0?$codecvt@_SDU_Mbstatet@@@std@@QAA@ABV_Locinfo@1@KW4_Codecvt_mode@1@I@Z(ptr long long long) codecvt_char16_ctor_mode -@ thiscall -arch=i386 ??0?$codecvt@_SDU_Mbstatet@@@std@@QAE@ABV_Locinfo@1@KW4_Codecvt_mode@1@I@Z(ptr long long long) codecvt_char16_ctor_mode -@ cdecl -arch=win64 ??0?$codecvt@_SDU_Mbstatet@@@std@@QEAA@AEBV_Locinfo@1@KW4_Codecvt_mode@1@_K@Z(ptr long long long) codecvt_char16_ctor_mode +@ cdecl -arch=arm ??0?$codecvt@_SDU_Mbstatet@@@std@@QAA@ABV_Locinfo@1@KW4_Codecvt_mode@1@I@Z(ptr ptr long long long) codecvt_char16_ctor_mode +@ thiscall -arch=i386 ??0?$codecvt@_SDU_Mbstatet@@@std@@QAE@ABV_Locinfo@1@KW4_Codecvt_mode@1@I@Z(ptr ptr long long long) codecvt_char16_ctor_mode +@ cdecl -arch=win64 ??0?$codecvt@_SDU_Mbstatet@@@std@@QEAA@AEBV_Locinfo@1@KW4_Codecvt_mode@1@_K@Z(ptr ptr long long long) codecvt_char16_ctor_mode @ cdecl -arch=arm ??0?$codecvt@_SDU_Mbstatet@@@std@@QAA@I@Z(ptr long) codecvt_char16_ctor_refs @ thiscall -arch=i386 ??0?$codecvt@_SDU_Mbstatet@@@std@@QAE@I@Z(ptr long) codecvt_char16_ctor_refs @ cdecl -arch=win64 ??0?$codecvt@_SDU_Mbstatet@@@std@@QEAA@_K@Z(ptr long) codecvt_char16_ctor_refs diff --git a/dlls/msvcp140/tests/msvcp140.c b/dlls/msvcp140/tests/msvcp140.c index b1ab13fe80b..8660ac27f1d 100644 --- a/dlls/msvcp140/tests/msvcp140.c +++ b/dlls/msvcp140/tests/msvcp140.c @@ -89,6 +89,8 @@ struct thiscall_thunk
static void * (WINAPI *call_thiscall_func1)( void *func, void *this ); static void * (WINAPI *call_thiscall_func2)( void *func, void *this, const void *a ); +static void * (WINAPI *call_thiscall_func5)( void *func, void *this, const void *a, const void *b, + const void *c, const void *d );
static void init_thiscall_thunk(void) { @@ -101,16 +103,20 @@ static void init_thiscall_thunk(void) thunk->jmp_edx = 0xe2ff; /* jmp *%edx */ call_thiscall_func1 = (void *)thunk; call_thiscall_func2 = (void *)thunk; + call_thiscall_func5 = (void *)thunk; }
#define call_func1(func,_this) call_thiscall_func1(func,_this) -#define call_func2(func,_this,a) call_thiscall_func2(func,_this,a) +#define call_func2(func,_this,a) call_thiscall_func2(func,_this,(const void*)(a)) +#define call_func5(func,_this,a,b,c,d) call_thiscall_func5(func,_this,(const void*)(a),(const void*)(b), \ + (const void*)(c), (const void*)(d))
#else
#define init_thiscall_thunk() #define call_func1(func,_this) func(_this) #define call_func2(func,_this,a) func(_this,a) +#define call_func5(func,_this,a,b,c,d) func(_this,a,b,c,d)
#endif /* __i386__ */ typedef unsigned char MSVCP_bool; @@ -284,6 +290,40 @@ static int (__cdecl *p__unlink)(const char*);
static BOOLEAN (WINAPI *pCreateSymbolicLinkW)(const WCHAR *, const WCHAR *, DWORD);
+typedef void (*vtable_ptr)(void); +typedef SIZE_T MSVCP_size_t; + +/* class locale::facet */ +typedef struct { + const vtable_ptr *vtable; + unsigned int refs; +} locale_facet; + +/* class codecvt_base */ +typedef struct { + locale_facet facet; +} codecvt_base; + +typedef enum convert_mode +{ + consume_header = 4, + generate_header = 2, + little_endian = 1 +} codecvt_convert_mode; + +/* class codecvt<char16> */ +typedef struct { + codecvt_base base; + unsigned int max_code; + codecvt_convert_mode convert_mode; +} codecvt_char16; + +static codecvt_char16 *(__thiscall * p_codecvt_char16_ctor)(codecvt_char16 *this); +static codecvt_char16 *(__thiscall * p_codecvt_char16_ctor_refs)(codecvt_char16 *this, size_t refs); +static codecvt_char16 * (__thiscall * p_codecvt_char16_ctor_mode)(codecvt_char16 *this, void *locinfo, + ULONG max_code, codecvt_convert_mode mode, size_t refs); +static void (__thiscall * p_codecvt_char16_dtor)(codecvt_char16 *this); + static HMODULE msvcp; #define SETNOFAIL(x,y) x = (void*)GetProcAddress(msvcp,y) #define SET(x,y) do { SETNOFAIL(x,y); ok(x != NULL, "Export '%s' not found\n", y); } while(0) @@ -323,6 +363,10 @@ static BOOL init(void)
SET(p__Fiopen_wchar, "?_Fiopen@std@@YAPEAU_iobuf@@PEB_WHH@Z"); SET(p__Fiopen, "?_Fiopen@std@@YAPEAU_iobuf@@PEBDHH@Z"); + SET(p_codecvt_char16_ctor, "??_F?$codecvt@_SDU_Mbstatet@@@std@@QEAAXXZ"); + SET(p_codecvt_char16_ctor_refs, "??0?$codecvt@_SDU_Mbstatet@@@std@@QEAA@_K@Z"); + SET(p_codecvt_char16_ctor_mode, "??0?$codecvt@_SDU_Mbstatet@@@std@@QEAA@AEBV_Locinfo@1@KW4_Codecvt_mode@1@_K@Z"); + SET(p_codecvt_char16_dtor, "??1?$codecvt@_SDU_Mbstatet@@@std@@MEAA@XZ"); } else { #ifdef __arm__ SET(p_task_continuation_context_ctor, "??0task_continuation_context@Concurrency@@AAA@XZ"); @@ -336,6 +380,10 @@ static BOOL init(void) SET(p__TaskEventLogger__LogTaskExecutionCompleted, "?_LogTaskExecutionCompleted@_TaskEventLogger@details@Concurrency@@QAAXXZ"); SET(p__TaskEventLogger__LogWorkItemCompleted, "?_LogWorkItemCompleted@_TaskEventLogger@details@Concurrency@@QAAXXZ"); SET(p__TaskEventLogger__LogWorkItemStarted, "?_LogWorkItemStarted@_TaskEventLogger@details@Concurrency@@QAAXXZ"); + SET(p_codecvt_char16_ctor, "??_F?$codecvt@_SDU_Mbstatet@@@std@@QAAXXZ"); + SET(p_codecvt_char16_ctor_refs, "??0?$codecvt@_SDU_Mbstatet@@@std@@QAA@I@Z"); + SET(p_codecvt_char16_ctor_mode, "??0?$codecvt@_SDU_Mbstatet@@@std@@QAA@ABV_Locinfo@1@KW4_Codecvt_mode@1@I@Z"); + SET(p_codecvt_char16_dtor, "??1?$codecvt@_SDU_Mbstatet@@@std@@MAA@XZ(ptr)"); #else SET(p_task_continuation_context_ctor, "??0task_continuation_context@Concurrency@@AAE@XZ"); SET(p__ContextCallback__Assign, "?_Assign@_ContextCallback@details@Concurrency@@AAEXPAX@Z"); @@ -348,6 +396,10 @@ static BOOL init(void) SET(p__TaskEventLogger__LogTaskExecutionCompleted, "?_LogTaskExecutionCompleted@_TaskEventLogger@details@Concurrency@@QAEXXZ"); SET(p__TaskEventLogger__LogWorkItemCompleted, "?_LogWorkItemCompleted@_TaskEventLogger@details@Concurrency@@QAEXXZ"); SET(p__TaskEventLogger__LogWorkItemStarted, "?_LogWorkItemStarted@_TaskEventLogger@details@Concurrency@@QAEXXZ"); + SET(p_codecvt_char16_ctor, "??_F?$codecvt@_SDU_Mbstatet@@@std@@QAEXXZ"); + SET(p_codecvt_char16_ctor_refs, "??0?$codecvt@_SDU_Mbstatet@@@std@@QAE@I@Z"); + SET(p_codecvt_char16_ctor_mode, "??0?$codecvt@_SDU_Mbstatet@@@std@@QAE@ABV_Locinfo@1@KW4_Codecvt_mode@1@I@Z"); + SET(p_codecvt_char16_dtor, "??1?$codecvt@_SDU_Mbstatet@@@std@@MAE@XZ"); #endif SET(p__Schedule_chore, "?_Schedule_chore@details@Concurrency@@YAHPAU_Threadpool_chore@12@@Z"); SET(p__Reschedule_chore, "?_Reschedule_chore@details@Concurrency@@YAHPBU_Threadpool_chore@12@@Z"); @@ -1810,6 +1862,32 @@ static void test__Fiopen(void) p_setlocale(LC_ALL, "C"); }
+void test_codecvt_char16(void) +{ + codecvt_char16 this; + + memset(&this, 0xcc, sizeof(this)); + call_func1(p_codecvt_char16_ctor, &this); + ok(!this.base.facet.refs, "got %u.\n", this.base.facet.refs); + ok(this.convert_mode == consume_header, "got %#x.\n", this.max_code); + ok(this.max_code == MAX_UCSCHAR, "got %#x.\n", this.max_code); + call_func1(p_codecvt_char16_dtor, &this); + + memset(&this, 0xcc, sizeof(this)); + call_func2(p_codecvt_char16_ctor_refs, &this, 12); + ok(this.base.facet.refs == 12, "got %u.\n", this.base.facet.refs); + ok(this.convert_mode == consume_header, "got %#x.\n", this.max_code); + ok(this.max_code == MAX_UCSCHAR, "got %#x.\n", this.max_code); + call_func1(p_codecvt_char16_dtor, &this); + + memset(&this, 0xcc, sizeof(this)); + call_func5(p_codecvt_char16_ctor_mode, &this, (void *)0xdeadbeef, 0x55, 0x44, 12); + ok(this.base.facet.refs == 12, "got %#x.\n", this.base.facet.refs); + ok(this.convert_mode == 0x44, "got %#x.\n", this.convert_mode); + ok(this.max_code == 0x55, "got %#x.\n", this.max_code); + call_func1(p_codecvt_char16_dtor, &this); +} + START_TEST(msvcp140) { if(!init()) return; @@ -1839,5 +1917,6 @@ START_TEST(msvcp140) test_Copy_file(); test__Mtx(); test__Fiopen(); + test_codecvt_char16(); FreeLibrary(msvcp); } diff --git a/dlls/msvcp90/locale.c b/dlls/msvcp90/locale.c index 192ee8b98ef..f01fb7da60a 100644 --- a/dlls/msvcp90/locale.c +++ b/dlls/msvcp90/locale.c @@ -4006,6 +4006,22 @@ void __thiscall codecvt_char16__Init(codecvt_char16 *this, const _Locinfo *locin FIXME("(%p %p) stub\n", this, locinfo); }
+/* ??0?$codecvt@_SDU_Mbstatet@@@std@@QAA@ABV_Locinfo@1@KW4_Codecvt_mode@1@I@Z */ +/* ??0?$codecvt@_SDU_Mbstatet@@@std@@QAE@ABV_Locinfo@1@KW4_Codecvt_mode@1@I@Z */ +/* ??0?$codecvt@_SDU_Mbstatet@@@std@@QEAA@AEBV_Locinfo@1@KW4_Codecvt_mode@1@_K@Z */ +DEFINE_THISCALL_WRAPPER(codecvt_char16_ctor_mode, 16) +codecvt_char16* __thiscall codecvt_char16_ctor_mode(codecvt_char16 *this, const _Locinfo *locinfo, + ULONG max_code, codecvt_convert_mode mode, size_t refs) +{ + TRACE("(%p %ld %d %Iu)\n", this, max_code, mode, refs); + + codecvt_base_ctor_refs(&this->base, refs); + this->base.facet.vtable = &codecvt_char16_vtable; + this->convert_mode = mode; + this->max_code = max_code; + return this; +} + /* ??0?$codecvt@_SDU_Mbstatet@@@std@@QAA@ABV_Locinfo@1@I@Z */ /* ??0?$codecvt@_SDU_Mbstatet@@@std@@QAE@ABV_Locinfo@1@I@Z */ /* ??0?$codecvt@_SDU_Mbstatet@@@std@@QEAA@AEBV_Locinfo@1@_K@Z */ @@ -4013,39 +4029,28 @@ DEFINE_THISCALL_WRAPPER(codecvt_char16_ctor_locinfo, 12) codecvt_char16* __thiscall codecvt_char16_ctor_locinfo(codecvt_char16 *this, const _Locinfo *locinfo, size_t refs) { - FIXME("(%p %p %Iu) stub\n", this, locinfo, refs); - return NULL; + TRACE("(%p %p %Iu)\n", this, locinfo, refs); + return codecvt_char16_ctor_mode(this, locinfo, MAX_UCSCHAR, consume_header, refs); }
/* ??0?$codecvt@_SDU_Mbstatet@@@std@@QAA@I@Z */ /* ??0?$codecvt@_SDU_Mbstatet@@@std@@QAE@I@Z */ /* ??0?$codecvt@_SDU_Mbstatet@@@std@@QEAA@_K@Z */ DEFINE_THISCALL_WRAPPER(codecvt_char16_ctor_refs, 8) -codecvt_char* __thiscall codecvt_char16_ctor_refs(codecvt_char16 *this, size_t refs) +codecvt_char16* __thiscall codecvt_char16_ctor_refs(codecvt_char16 *this, size_t refs) { - FIXME("(%p %Iu) stub\n", this, refs); - return NULL; -} - -/* ??0?$codecvt@_SDU_Mbstatet@@@std@@QAA@ABV_Locinfo@1@KW4_Codecvt_mode@1@I@Z */ -/* ??0?$codecvt@_SDU_Mbstatet@@@std@@QAE@ABV_Locinfo@1@KW4_Codecvt_mode@1@I@Z */ -/* ??0?$codecvt@_SDU_Mbstatet@@@std@@QEAA@AEBV_Locinfo@1@KW4_Codecvt_mode@1@_K@Z */ -DEFINE_THISCALL_WRAPPER(codecvt_char16_ctor_mode, 16) -codecvt_char16* __thiscall codecvt_char16_ctor_mode(codecvt_char16 *this, - ULONG max_code, codecvt_convert_mode mode, size_t refs) -{ - FIXME("(%p %ld %d %Iu) stub\n", this, max_code, mode, refs); - return NULL; + TRACE("(%p %Iu)\n", this, refs); + return codecvt_char16_ctor_locinfo(this, NULL, refs); }
/* ??_F?$codecvt@_SDU_Mbstatet@@@std@@QAAXXZ */ /* ??_F?$codecvt@_SDU_Mbstatet@@@std@@QAEXXZ */ /* ??_F?$codecvt@_SDU_Mbstatet@@@std@@QEAAXXZ */ DEFINE_THISCALL_WRAPPER(codecvt_char16_ctor, 4) -codecvt_char* __thiscall codecvt_char16_ctor(codecvt_char16 *this) +codecvt_char16* __thiscall codecvt_char16_ctor(codecvt_char16 *this) { - FIXME("(%p) stub\n", this); - return NULL; + TRACE("(%p)\n", this); + return codecvt_char16_ctor_refs(this, 0); }
/* ??1?$codecvt@_SDU_Mbstatet@@@std@@MAA@XZ */ @@ -4054,7 +4059,8 @@ codecvt_char* __thiscall codecvt_char16_ctor(codecvt_char16 *this) DEFINE_THISCALL_WRAPPER(codecvt_char16_dtor, 4) void __thiscall codecvt_char16_dtor(codecvt_char16 *this) { - FIXME("(%p) stub\n", this); + TRACE("(%p)\n", this); + codecvt_base_dtor(&this->base); }
DEFINE_THISCALL_WRAPPER(codecvt_char16_vector_dtor, 8) diff --git a/dlls/msvcp90/msvcp90.h b/dlls/msvcp90/msvcp90.h index b6e20826ff7..e5134f4634c 100644 --- a/dlls/msvcp90/msvcp90.h +++ b/dlls/msvcp90/msvcp90.h @@ -194,7 +194,11 @@ _Yarn_wchar* __thiscall _Yarn_wchar_op_assign_cstr(_Yarn_wchar*, const wchar_t*) /* class locale::facet */ typedef struct { const vtable_ptr *vtable; +#if _MSVCP_VER >= 110 + unsigned int refs; +#else size_t refs; +#endif } locale_facet;
typedef enum { @@ -248,6 +252,8 @@ typedef enum convert_mode /* class codecvt<char16> */ typedef struct { codecvt_base base; + unsigned int max_code; + codecvt_convert_mode convert_mode; } codecvt_char16;
/* class codecvt<char32> */
From: Paul Gofman pgofman@codeweavers.com
--- dlls/msvcp140/tests/msvcp140.c | 253 ++++++++++++++++++++++++++++++++- dlls/msvcp90/locale.c | 86 ++++++++++- 2 files changed, 335 insertions(+), 4 deletions(-)
diff --git a/dlls/msvcp140/tests/msvcp140.c b/dlls/msvcp140/tests/msvcp140.c index 8660ac27f1d..b2efa8ea58b 100644 --- a/dlls/msvcp140/tests/msvcp140.c +++ b/dlls/msvcp140/tests/msvcp140.c @@ -20,6 +20,7 @@ #include <stdio.h> #include <locale.h> #include <share.h> +#include <uchar.h>
#include "windef.h" #include "winbase.h" @@ -91,6 +92,8 @@ static void * (WINAPI *call_thiscall_func1)( void *func, void *this ); static void * (WINAPI *call_thiscall_func2)( void *func, void *this, const void *a ); static void * (WINAPI *call_thiscall_func5)( void *func, void *this, const void *a, const void *b, const void *c, const void *d ); +static void * (WINAPI *call_thiscall_func8)( void *func, void *this, const void *a, const void *b, + const void *c, const void *d, const void *e, const void *f, const void *g );
static void init_thiscall_thunk(void) { @@ -104,12 +107,15 @@ static void init_thiscall_thunk(void) call_thiscall_func1 = (void *)thunk; call_thiscall_func2 = (void *)thunk; call_thiscall_func5 = (void *)thunk; + call_thiscall_func8 = (void *)thunk; }
#define call_func1(func,_this) call_thiscall_func1(func,_this) #define call_func2(func,_this,a) call_thiscall_func2(func,_this,(const void*)(a)) #define call_func5(func,_this,a,b,c,d) call_thiscall_func5(func,_this,(const void*)(a),(const void*)(b), \ (const void*)(c), (const void*)(d)) +#define call_func8(func,_this,a,b,c,d,e,f,g) call_thiscall_func8(func,_this,(const void*)(a),(const void*)(b), \ + (const void*)(c), (const void*)(d), (const void*)(e), (const void*)(f), (const void*)(g))
#else
@@ -117,6 +123,7 @@ static void init_thiscall_thunk(void) #define call_func1(func,_this) func(_this) #define call_func2(func,_this,a) func(_this,a) #define call_func5(func,_this,a,b,c,d) func(_this,a,b,c,d) +#define call_func8(func,_this,a,b,c,d,e,f,g) func(_this,a,b,c,d,e,f,g)
#endif /* __i386__ */ typedef unsigned char MSVCP_bool; @@ -318,11 +325,26 @@ typedef struct { codecvt_convert_mode convert_mode; } codecvt_char16;
+typedef struct { + int wchar; + unsigned short byte, state; +} _Mbstatet; + +typedef enum { + CODECVT_ok = 0, + CODECVT_partial = 1, + CODECVT_error = 2, + CODECVT_noconv = 3 +} codecvt_base_result; + static codecvt_char16 *(__thiscall * p_codecvt_char16_ctor)(codecvt_char16 *this); static codecvt_char16 *(__thiscall * p_codecvt_char16_ctor_refs)(codecvt_char16 *this, size_t refs); static codecvt_char16 * (__thiscall * p_codecvt_char16_ctor_mode)(codecvt_char16 *this, void *locinfo, ULONG max_code, codecvt_convert_mode mode, size_t refs); static void (__thiscall * p_codecvt_char16_dtor)(codecvt_char16 *this); +static int (__thiscall * p_codecvt_char16_do_out)(const codecvt_char16 *this, _Mbstatet *state, + const char16_t *from, const char16_t *from_end, const char16_t **from_next, + char *to, char *to_end, char **to_next);
static HMODULE msvcp; #define SETNOFAIL(x,y) x = (void*)GetProcAddress(msvcp,y) @@ -367,6 +389,7 @@ static BOOL init(void) SET(p_codecvt_char16_ctor_refs, "??0?$codecvt@_SDU_Mbstatet@@@std@@QEAA@_K@Z"); SET(p_codecvt_char16_ctor_mode, "??0?$codecvt@_SDU_Mbstatet@@@std@@QEAA@AEBV_Locinfo@1@KW4_Codecvt_mode@1@_K@Z"); SET(p_codecvt_char16_dtor, "??1?$codecvt@_SDU_Mbstatet@@@std@@MEAA@XZ"); + SET(p_codecvt_char16_do_out, "?do_out@?$codecvt@_SDU_Mbstatet@@@std@@MEBAHAEAU_Mbstatet@@PEB_S1AEAPEB_SPEAD3AEAPEAD@Z"); } else { #ifdef __arm__ SET(p_task_continuation_context_ctor, "??0task_continuation_context@Concurrency@@AAA@XZ"); @@ -384,6 +407,7 @@ static BOOL init(void) SET(p_codecvt_char16_ctor_refs, "??0?$codecvt@_SDU_Mbstatet@@@std@@QAA@I@Z"); SET(p_codecvt_char16_ctor_mode, "??0?$codecvt@_SDU_Mbstatet@@@std@@QAA@ABV_Locinfo@1@KW4_Codecvt_mode@1@I@Z"); SET(p_codecvt_char16_dtor, "??1?$codecvt@_SDU_Mbstatet@@@std@@MAA@XZ(ptr)"); + SET(p_codecvt_char16_do_out, "?do_out@?$codecvt@_SDU_Mbstatet@@@std@@MBAHAAU_Mbstatet@@PB_S1AAPB_SPAD3AAPAD@Z"); #else SET(p_task_continuation_context_ctor, "??0task_continuation_context@Concurrency@@AAE@XZ"); SET(p__ContextCallback__Assign, "?_Assign@_ContextCallback@details@Concurrency@@AAEXPAX@Z"); @@ -400,6 +424,7 @@ static BOOL init(void) SET(p_codecvt_char16_ctor_refs, "??0?$codecvt@_SDU_Mbstatet@@@std@@QAE@I@Z"); SET(p_codecvt_char16_ctor_mode, "??0?$codecvt@_SDU_Mbstatet@@@std@@QAE@ABV_Locinfo@1@KW4_Codecvt_mode@1@I@Z"); SET(p_codecvt_char16_dtor, "??1?$codecvt@_SDU_Mbstatet@@@std@@MAE@XZ"); + SET(p_codecvt_char16_do_out, "?do_out@?$codecvt@_SDU_Mbstatet@@@std@@MBEHAAU_Mbstatet@@PB_S1AAPB_SPAD3AAPAD@Z"); #endif SET(p__Schedule_chore, "?_Schedule_chore@details@Concurrency@@YAHPAU_Threadpool_chore@12@@Z"); SET(p__Reschedule_chore, "?_Reschedule_chore@details@Concurrency@@YAHPBU_Threadpool_chore@12@@Z"); @@ -1862,9 +1887,42 @@ static void test__Fiopen(void) p_setlocale(LC_ALL, "C"); }
+static const char bom_header[] = { 0xef, 0xbb, 0xbf }; + void test_codecvt_char16(void) { + static const struct + { + const WCHAR *wstr; + const char *str; + int short_output; + } + tests[] = + { + { L"\xfeff", "\xef\xbb\xbf" }, + { L"\xfffe", "\xef\xbf\xbe" }, + { L"\xfeff""a", "\xef\xbb\xbf""a", 1 }, + { L"abc", "abc", 1 }, + { L"\x2a8", "\xca\xa8" }, + { L"\xd83d\xdcd8\xd83d\xde79", "\xf0\x9f\x93\x98\xf0\x9f\x99\xb9", 3 }, + { L"\x08a4", "\xe0\xa2\xa4", }, + { L"\x01a7", "\xc6\xa7", }, + { L"\x01a7\x08a4", "\xc6\xa7\xe0\xa2\xa4", 3}, + }; + static DWORD test_flags[] = + { + 0, + consume_header, + generate_header, + consume_header | generate_header, + }; + char16_t str16[16], *str16_ptr = NULL; + char buffer[256], *str_ptr = NULL; codecvt_char16 this; + unsigned int i, j, len, wlen; + char str[16], expect_str[16]; + _Mbstatet state; + int ret;
memset(&this, 0xcc, sizeof(this)); call_func1(p_codecvt_char16_ctor, &this); @@ -1881,11 +1939,202 @@ void test_codecvt_char16(void) call_func1(p_codecvt_char16_dtor, &this);
memset(&this, 0xcc, sizeof(this)); - call_func5(p_codecvt_char16_ctor_mode, &this, (void *)0xdeadbeef, 0x55, 0x44, 12); + call_func5(p_codecvt_char16_ctor_mode, &this, (void *)0xdeadbeef, 0xffffffff, 0x44, 12); ok(this.base.facet.refs == 12, "got %#x.\n", this.base.facet.refs); ok(this.convert_mode == 0x44, "got %#x.\n", this.convert_mode); - ok(this.max_code == 0x55, "got %#x.\n", this.max_code); + ok(this.max_code == 0xffffffff, "got %#x.\n", this.max_code); call_func1(p_codecvt_char16_dtor, &this); + + for (j = 0; j < ARRAY_SIZE(test_flags); ++j) + { + winetest_push_context("flags %#lx", test_flags[j]); + memset(buffer, 0xcc, sizeof(buffer)); + call_func5(p_codecvt_char16_ctor_mode, &this, (void *)0xdeadbeef, MAX_UCSCHAR, test_flags[j], 0); + + str16[0] = 'a'; + memset(&state, 0, sizeof(state)); + ret = (int)call_func8(p_codecvt_char16_do_out, &this, &state, str16, str16 + 1, (const char16_t **)&str16_ptr, + str, str, &str_ptr); + ok(ret == CODECVT_partial, "got %d.\n", ret); + ok(str16_ptr - str16 == 0, "got %Id.\n", str16_ptr - str16); + ok(str_ptr - str == 0, "got %Id.\n", str_ptr - str); + ok(state.wchar == 0, "got %#x.\n", state.wchar); + + memset(&state, 0, sizeof(state)); + ret = (int)call_func8(p_codecvt_char16_do_out, &this, &state, str16, str16, (const char16_t **)&str16_ptr, str, + str, &str_ptr); + ok(ret == CODECVT_partial, "got %d.\n", ret); + ok(str16_ptr - str16 == 0, "got %Id.\n", str16_ptr - str16); + ok(str_ptr - str == 0, "got %Id.\n", str_ptr - str); + ok(state.wchar == 0, "got %#x.\n", state.wchar); + + wcscpy(str16, L"\xd83d\xdcd8\xd83d\xde79"); + + memset(&state, 0, sizeof(state)); + memset(str, 0, sizeof(str)); + ret = (int)call_func8(p_codecvt_char16_do_out, &this, &state, str16, str16 + 1, (const char16_t **)&str16_ptr, + str, str + 1, &str_ptr); + if (test_flags[j] & generate_header) + { + ok(ret == CODECVT_partial, "got %d.\n", ret); + ok(str16_ptr - str16 == 0, "got %Id.\n", str16_ptr - str16); + ok(str_ptr - str == 0, "got %Id.\n", str_ptr - str); + ok(state.wchar == 0, "got %#x.\n", state.wchar); + } + else + { + ok(ret == CODECVT_ok, "got %d.\n", ret); + ok(str16_ptr - str16 == 1, "got %Id.\n", str16_ptr - str16); + ok(!strcmp(str, "\xf0"), "got %s.\n", debugstr_a(str)); + ok(str_ptr - str == 1, "got %Id.\n", str_ptr - str); + ok(state.wchar == 0x7d, "got %#x.\n", state.wchar); + } + + memset(&state, 0, sizeof(state)); + memset(str, 0, sizeof(str)); + ret = (int)call_func8(p_codecvt_char16_do_out, &this, &state, str16, str16 + 1, (const char16_t **)&str16_ptr, + str, str + 2, &str_ptr); + if (test_flags[j] & generate_header) + { + ok(ret == CODECVT_partial, "got %d.\n", ret); + ok(str16_ptr - str16 == 0, "got %Id.\n", str16_ptr - str16); + ok(str_ptr - str == 0, "got %Id.\n", str_ptr - str); + ok(state.wchar == 0, "got %#x.\n", state.wchar); + } + else + { + ok(ret == CODECVT_ok, "got %d.\n", ret); + ok(str16_ptr - str16 == 1, "got %Id.\n", str16_ptr - str16); + ok(!strcmp(str, "\xf0"), "got %s.\n", debugstr_a(str)); + ok(str_ptr - str == 1, "got %Id.\n", str_ptr - str); + ok(state.wchar == 0x7d, "got %#x.\n", state.wchar); + } + + memset(&state, 0, sizeof(state)); + memset(str, 0, sizeof(str)); + ret = (int)call_func8(p_codecvt_char16_do_out, &this, &state, str16, str16 + 1, (const char16_t **)&str16_ptr, + str, str + 3, &str_ptr); + if (test_flags[j] & generate_header) + { + ok(ret == CODECVT_partial, "got %d.\n", ret); + ok(str16_ptr - str16 == 0, "got %Id.\n", str16_ptr - str16); + ok(str_ptr - str == 0, "got %Id.\n", str_ptr - str); + ok(state.wchar == 0, "got %#x.\n", state.wchar); + } + else + { + ok(ret == CODECVT_ok, "got %d.\n", ret); + ok(str16_ptr - str16 == 1, "got %Id.\n", str16_ptr - str16); + ok(!strcmp(str, "\xf0"), "got %s.\n", debugstr_a(str)); + ok(str_ptr - str == 1, "got %Id.\n", str_ptr - str); + ok(state.wchar == 0x7d, "got %#x.\n", state.wchar); + } + + memset(&state, 0, sizeof(state)); + memset(str, 0, sizeof(str)); + ret = (int)call_func8(p_codecvt_char16_do_out, &this, &state, str16, str16 + 1, (const char16_t **)&str16_ptr, + str, str + 4, &str_ptr); + ok(ret == CODECVT_ok, "got %d.\n", ret); + ok(str16_ptr - str16 == 1, "got %Id.\n", str16_ptr - str16); + if (test_flags[j] & generate_header) + { + ok(!strcmp(str, "\xef\xbb\xbf\xf0"), "got %s.\n", debugstr_a(str)); + ok(str_ptr - str == 4, "got %Id.\n", str_ptr - str); + } + else + { + ok(!strcmp(str, "\xf0"), "got %s.\n", debugstr_a(str)); + ok(str_ptr - str == 1, "got %Id.\n", str_ptr - str); + } + ok(state.wchar == 0x7d, "got %#x.\n", state.wchar); + ret = (int)call_func8(p_codecvt_char16_do_out, &this, &state, str16_ptr, str16 + wcslen(str16), + (const char16_t **)&str16_ptr, str, str + 8, &str_ptr); + ok(ret == CODECVT_ok, "got %d.\n", ret); + ok(str16_ptr - str16 == 4, "got %Id.\n", str16_ptr - str16); + ok(str_ptr - str == 7, "got %Id.\n", str_ptr - str); + ok(!strcmp(str, "\x9f\x93\x98\xf0\x9f\x99\xb9"), "got %s.\n", debugstr_a(str)); + ok(state.wchar == 1, "got %#x.\n", state.wchar); + + memset(&state, 0, sizeof(state)); + memset(str, 0, sizeof(str)); + ret = (int)call_func8(p_codecvt_char16_do_out, &this, &state, str16, str16 + 1, (const char16_t **)&str16_ptr, + str, str + 3, &str_ptr); + if (test_flags[j] & generate_header) + { + ok(ret == CODECVT_partial, "got %d.\n", ret); + ok(str16_ptr - str16 == 0, "got %Id.\n", str16_ptr - str16); + ok(str_ptr - str == 0, "got %Id.\n", str_ptr - str); + ok(state.wchar == 0, "got %#x.\n", state.wchar); + } + else + { + ok(ret == CODECVT_ok, "got %d.\n", ret); + ok(str16_ptr - str16 == 1, "got %Id.\n", str16_ptr - str16); + ok(!strcmp(str, "\xf0"), "got %s.\n", debugstr_a(str)); + ok(str_ptr - str == 1, "got %Id.\n", str_ptr - str); + ok(state.wchar == 0x7d, "got %#x.\n", state.wchar); + } + + for (i = 0; i < ARRAY_SIZE(tests); ++i) + { + winetest_push_context("test %u", i); + wcscpy(str16, tests[i].wstr); + wlen = wcslen(str16); + len = strlen(tests[i].str); + memset(&state, 0, sizeof(state)); + if (test_flags[j] & generate_header) + { + ret = (int)call_func8(p_codecvt_char16_do_out, &this, &state, str16, str16 + wlen, + (const char16_t **)&str16_ptr, str, str + len + 3, &str_ptr); + ok(ret == CODECVT_ok, "got %d.\n", ret); + ok(str16_ptr - str16 == wlen, "got %Id, expected %u.\n", str16_ptr - str16, wlen); + ok(str_ptr - str == len + 3, "got %Id, expected %u.\n", str_ptr - str, len + 3); + memcpy(expect_str, bom_header, sizeof(bom_header)); + strcpy(expect_str + sizeof(bom_header), tests[i].str); + ok(!strncmp(str, expect_str, len + 3), "got %s, expected %s.\n", debugstr_an(str, len), + debugstr_an(expect_str, len + 3)); + + memset(&state, 0, sizeof(state)); + ret = (int)call_func8(p_codecvt_char16_do_out, &this, &state, str16, str16 + wlen, + (const char16_t **)&str16_ptr, str, str + 2, &str_ptr); + ok(ret == CODECVT_partial, "got %d.\n", ret); + ok(str16_ptr - str16 == 0, "got %Id, expected %u.\n", str16_ptr - str16, 0); + ok(str_ptr - str == 0, "got %Id, expected %u.\n", str_ptr - str, 0); + } + else + { + ret = (int)call_func8(p_codecvt_char16_do_out, &this, &state, str16, str16 + wlen, + (const char16_t **)&str16_ptr, str, str + len, &str_ptr); + ok(ret == CODECVT_ok, "got %d.\n", ret); + ok(str16_ptr - str16 == wlen, "got %Id, expected %u.\n", str16_ptr - str16, wlen); + ok(str_ptr - str == len, "got %Id, expected %u.\n", str_ptr - str, len); + ok(!strncmp(str, tests[i].str, len), "got %s, expected %s.\n", + debugstr_an(str, len), debugstr_an(tests[i].str, len)); + + ret = (int)call_func8(p_codecvt_char16_do_out, &this, &state, str16, str16 + wlen, + (const char16_t **)&str16_ptr, str, str + len - 1, &str_ptr); + if (tests[i].short_output) + { + ok(ret == CODECVT_ok, "got %d.\n", ret); + ok(str16_ptr - str16 == wlen - 1, "got %Id, expected %u.\n", str16_ptr - str16, wlen - 1); + ok(str_ptr - str == len - tests[i].short_output, "got %Id, expected %u.\n", + str_ptr - str, len - tests[i].short_output); + ok(!strncmp(str, tests[i].str, len - 1), "got %s, expected %s.\n", + debugstr_an(str, len - 1), debugstr_an(tests[i].str, len - 1)); + } + else + { + ok(ret == CODECVT_partial, "got %d.\n", ret); + ok(str16_ptr - str16 == 0, "got %Id, expected %u.\n", str16_ptr - str16, 0); + ok(str_ptr - str == 0, "got %Id, expected %u.\n", str_ptr - str, 0); + } + } + + winetest_pop_context(); + } + call_func1(p_codecvt_char16_dtor, &this); + winetest_pop_context(); + } }
START_TEST(msvcp140) diff --git a/dlls/msvcp90/locale.c b/dlls/msvcp90/locale.c index f01fb7da60a..730de5724b9 100644 --- a/dlls/msvcp90/locale.c +++ b/dlls/msvcp90/locale.c @@ -4193,9 +4193,91 @@ int __thiscall codecvt_char16_do_out(const codecvt_char16 *this, _Mbstatet *stat const char16_t *from, const char16_t *from_end, const char16_t **from_next, char *to, char *to_end, char **to_next) { - FIXME("(%p %p %p %p %p %p %p %p) stub\n", this, state, from, + static const char bom_header[] = { 0xef, 0xbb, 0xbf }; + unsigned int ch, out_len; + BOOL surrogate; + + TRACE("(%p %p %p %p %p %p %p %p)\n", this, state, from, from_end, from_next, to, to_end, to_next); - return 0; + + if (this->convert_mode & ~(generate_header | consume_header)) + FIXME("convert_mode %#x.\n", this->convert_mode); + + *from_next = from; + *to_next = to; + + while(*from_next != from_end && *to_next != to_end) + { + surrogate = FALSE; + + if ((ch = MBSTATET_TO_INT(state)) & ~1) + { + if (!IS_LOW_SURROGATE(**from_next)) + return CODECVT_error; + ch = (ch << 10) + (**from_next & 0x3ff); + } + else if (IS_HIGH_SURROGATE(**from_next)) + { + surrogate = TRUE; + ch = 0x10000 + ((**from_next & 0x3ff) << 10); + } + else + { + ch = **from_next; + } + + if (ch < 0x80 || surrogate) + out_len = 1; + else if (ch < 0x800) + out_len = 2; + else + out_len = 3; + + if (this->convert_mode & generate_header && !MBSTATET_TO_INT(state)) + { + if (out_len + sizeof(bom_header) > to_end - *to_next) + break; + memcpy(*to_next, bom_header, sizeof(bom_header)); + *to_next += sizeof(bom_header); + } + else if (out_len > to_end - *to_next) + break; + + ++*from_next; + if (surrogate) + { + MBSTATET_TO_INT(state) = ((ch - 0x10000) >> 10) + 0x40; + *(*to_next)++ = 0xf0 | (ch >> 18); + continue; + } + if (ch < 0x80) + { + *(*to_next)++ = ch; + } + else if (ch < 0x800) + { + *(*to_next)++ = 0xc0 | (ch >> 6); + *(*to_next)++ = 0x80 | (ch & 0x3f); + } + else if (ch < 0x10000) + { + *(*to_next)++ = 0xe0 | (ch >> 12); + *(*to_next)++ = 0x80 | ((ch >> 6) & 0x3f); + *(*to_next)++ = 0x80 | (ch & 0x3f); + } + else + { + *(*to_next)++ = 0x80 | ((ch >> 12) & 0x3f); + *(*to_next)++ = 0x80 | ((ch >> 6) & 0x3f); + *(*to_next)++ = 0x80 | (ch & 0x3f); + } + MBSTATET_TO_INT(state) = 1; + } + + if (*from_next != from) + return CODECVT_ok; + + return CODECVT_partial; }
/* ?out@?$codecvt@_SDU_Mbstatet@@@std@@QBAHAAU_Mbstatet@@PB_S1AAPB_SPAD3AAPAD@Z */
From: Paul Gofman pgofman@codeweavers.com
--- dlls/msvcp140/tests/msvcp140.c | 238 +++++++++++++++++++++++++++++++++ dlls/msvcp90/locale.c | 122 ++++++++++++++++- 2 files changed, 358 insertions(+), 2 deletions(-)
diff --git a/dlls/msvcp140/tests/msvcp140.c b/dlls/msvcp140/tests/msvcp140.c index b2efa8ea58b..a6ced5db904 100644 --- a/dlls/msvcp140/tests/msvcp140.c +++ b/dlls/msvcp140/tests/msvcp140.c @@ -345,6 +345,9 @@ static void (__thiscall * p_codecvt_char16_dtor)(codecvt_char16 *this); static int (__thiscall * p_codecvt_char16_do_out)(const codecvt_char16 *this, _Mbstatet *state, const char16_t *from, const char16_t *from_end, const char16_t **from_next, char *to, char *to_end, char **to_next); +static int (__thiscall * p_codecvt_char16_do_in)(const codecvt_char16 *this, _Mbstatet *state, + const char *from, const char *from_end, const char **from_next, + char16_t *to, char16_t *to_end, char16_t **to_next);
static HMODULE msvcp; #define SETNOFAIL(x,y) x = (void*)GetProcAddress(msvcp,y) @@ -390,6 +393,7 @@ static BOOL init(void) SET(p_codecvt_char16_ctor_mode, "??0?$codecvt@_SDU_Mbstatet@@@std@@QEAA@AEBV_Locinfo@1@KW4_Codecvt_mode@1@_K@Z"); SET(p_codecvt_char16_dtor, "??1?$codecvt@_SDU_Mbstatet@@@std@@MEAA@XZ"); SET(p_codecvt_char16_do_out, "?do_out@?$codecvt@_SDU_Mbstatet@@@std@@MEBAHAEAU_Mbstatet@@PEB_S1AEAPEB_SPEAD3AEAPEAD@Z"); + SET(p_codecvt_char16_do_in, "?do_in@?$codecvt@_SDU_Mbstatet@@@std@@MEBAHAEAU_Mbstatet@@PEBD1AEAPEBDPEA_S3AEAPEA_S@Z"); } else { #ifdef __arm__ SET(p_task_continuation_context_ctor, "??0task_continuation_context@Concurrency@@AAA@XZ"); @@ -408,6 +412,7 @@ static BOOL init(void) SET(p_codecvt_char16_ctor_mode, "??0?$codecvt@_SDU_Mbstatet@@@std@@QAA@ABV_Locinfo@1@KW4_Codecvt_mode@1@I@Z"); SET(p_codecvt_char16_dtor, "??1?$codecvt@_SDU_Mbstatet@@@std@@MAA@XZ(ptr)"); SET(p_codecvt_char16_do_out, "?do_out@?$codecvt@_SDU_Mbstatet@@@std@@MBAHAAU_Mbstatet@@PB_S1AAPB_SPAD3AAPAD@Z"); + SET(p_codecvt_char16_do_in, "?do_in@?$codecvt@_SDU_Mbstatet@@@std@@MBAHAAU_Mbstatet@@PBD1AAPBDPA_S3AAPA_S@Z"); #else SET(p_task_continuation_context_ctor, "??0task_continuation_context@Concurrency@@AAE@XZ"); SET(p__ContextCallback__Assign, "?_Assign@_ContextCallback@details@Concurrency@@AAEXPAX@Z"); @@ -425,6 +430,7 @@ static BOOL init(void) SET(p_codecvt_char16_ctor_mode, "??0?$codecvt@_SDU_Mbstatet@@@std@@QAE@ABV_Locinfo@1@KW4_Codecvt_mode@1@I@Z"); SET(p_codecvt_char16_dtor, "??1?$codecvt@_SDU_Mbstatet@@@std@@MAE@XZ"); SET(p_codecvt_char16_do_out, "?do_out@?$codecvt@_SDU_Mbstatet@@@std@@MBEHAAU_Mbstatet@@PB_S1AAPB_SPAD3AAPAD@Z"); + SET(p_codecvt_char16_do_in, "?do_in@?$codecvt@_SDU_Mbstatet@@@std@@MBEHAAU_Mbstatet@@PBD1AAPBDPA_S3AAPA_S@Z"); #endif SET(p__Schedule_chore, "?_Schedule_chore@details@Concurrency@@YAHPAU_Threadpool_chore@12@@Z"); SET(p__Reschedule_chore, "?_Reschedule_chore@details@Concurrency@@YAHPBU_Threadpool_chore@12@@Z"); @@ -1889,6 +1895,11 @@ static void test__Fiopen(void)
static const char bom_header[] = { 0xef, 0xbb, 0xbf };
+static BOOL str_has_bom_header(const char *str) +{ + return !strncmp(str, bom_header, sizeof(bom_header)); +} + void test_codecvt_char16(void) { static const struct @@ -2075,6 +2086,203 @@ void test_codecvt_char16(void) ok(state.wchar == 0x7d, "got %#x.\n", state.wchar); }
+ strcpy(str, "abc"); + + memset(&state, 0, sizeof(state)); + memset(str16, 0, sizeof(str16)); + ret = (int)call_func8(p_codecvt_char16_do_in, &this, &state, str, str + 3, (const char **)&str_ptr, + str16, str16 + 2, &str16_ptr); + ok(ret == CODECVT_ok, "got %d.\n", ret); + ok(str16_ptr - str16 == 2, "got %Id.\n", str16_ptr - str16); + ok(!wcscmp(str16, L"ab"), "got %s.\n", debugstr_w(str16)); + ok(str_ptr - str == 2, "got %Id.\n", str_ptr - str); + ok(state.wchar == 1, "got %#x.\n", state.wchar); + + ret = (int)call_func8(p_codecvt_char16_do_in, &this, &state, str, str + 2, (const char **)&str_ptr, + str16, str16 + 3, &str16_ptr); + ok(ret == CODECVT_ok, "got %d.\n", ret); + ok(str16_ptr - str16 == 2, "got %Id.\n", str16_ptr - str16); + ok(!wcscmp(str16, L"ab"), "got %s.\n", debugstr_w(str16)); + ok(str_ptr - str == 2, "got %Id.\n", str_ptr - str); + ok(state.wchar == 1, "got %#x.\n", state.wchar); + + strcpy(str, "\xf0\x92\x80\x92"); + + memset(&state, 0, sizeof(state)); + memset(str16, 0, sizeof(str16)); + ret = (int)call_func8(p_codecvt_char16_do_in, &this, &state, str, str + 4, (const char **)&str_ptr, + str16, str16 + 2, &str16_ptr); + ok(ret == CODECVT_ok, "got %d.\n", ret); + ok(str16_ptr - str16 == 2, "got %Id.\n", str16_ptr - str16); + ok(!wcscmp(str16, L"\xd808\xdc12"), "got %s.\n", debugstr_w(str16)); + ok(str_ptr - str == 4, "got %Id.\n", str_ptr - str); + ok(state.wchar == 1, "got %#x.\n", state.wchar); + + ret = (int)call_func8(p_codecvt_char16_do_in, &this, &state, str, str + 1, (const char **)&str_ptr, + str16, str16 + 2, &str16_ptr); + ok(ret == CODECVT_partial, "got %d.\n", ret); + ok(str16_ptr - str16 == 0, "got %Id.\n", str16_ptr - str16); + ok(!wcscmp(str16, L"\xd808\xdc12"), "got %s.\n", debugstr_w(str16)); + ok(str_ptr - str == 0, "got %Id.\n", str_ptr - str); + ok(state.wchar == 1, "got %#x.\n", state.wchar); + + ret = (int)call_func8(p_codecvt_char16_do_in, &this, &state, str, str + 2, (const char **)&str_ptr, + str16, str16 + 2, &str16_ptr); + ok(ret == CODECVT_partial, "got %d.\n", ret); + ok(str16_ptr - str16 == 0, "got %Id.\n", str16_ptr - str16); + ok(!wcscmp(str16, L"\xd808\xdc12"), "got %s.\n", debugstr_w(str16)); + ok(str_ptr - str == 0, "got %Id.\n", str_ptr - str); + ok(state.wchar == 1, "got %#x.\n", state.wchar); + + memset(&state, 0, sizeof(state)); + memset(str16, 0, sizeof(str16)); + ret = (int)call_func8(p_codecvt_char16_do_in, &this, &state, str, str + 3, (const char **)&str_ptr, + str16, str16 + 1, &str16_ptr); + ok(ret == CODECVT_ok, "got %d.\n", ret); + ok(str16_ptr - str16 == 1, "got %Id.\n", str16_ptr - str16); + ok(!wcscmp(str16, L"\xd808"), "got %s.\n", debugstr_w(str16)); + ok(str_ptr - str == 3, "got %Id.\n", str_ptr - str); + ok(state.wchar == 0xdc00, "got %#x.\n", state.wchar); + + memset(&state, 0, sizeof(state)); + memset(str16, 0, sizeof(str16)); + ret = (int)call_func8(p_codecvt_char16_do_in, &this, &state, str, str + 4, (const char **)&str_ptr, + str16, str16 , &str16_ptr); + ok(ret == CODECVT_partial, "got %d.\n", ret); + ok(str16_ptr - str16 == 0, "got %Id.\n", str16_ptr - str16); + ok(str_ptr - str == 0, "got %Id.\n", str_ptr - str); + ok(state.wchar == 0, "got %#x.\n", state.wchar); + + memset(&state, 0, sizeof(state)); + memset(str16, 0, sizeof(str16)); + ret = (int)call_func8(p_codecvt_char16_do_in, &this, &state, str, str + 4, (const char **)&str_ptr, + str16, str16 + 1, &str16_ptr); + ok(ret == CODECVT_ok, "got %d.\n", ret); + ok(str16_ptr - str16 == 1, "got %Id.\n", str16_ptr - str16); + ok(!wcscmp(str16, L"\xd808"), "got %s.\n", debugstr_w(str16)); + ok(str_ptr - str == 3, "got %Id.\n", str_ptr - str); + ok(state.wchar == 0xdc00, "got %#x.\n", state.wchar); + + memset(&state, 0, sizeof(state)); + memset(str16, 0, sizeof(str16)); + ret = (int)call_func8(p_codecvt_char16_do_in, &this, &state, str, str + 3, (const char **)&str_ptr, + str16, str16 + 2, &str16_ptr); + ok(ret == CODECVT_ok, "got %d.\n", ret); + ok(str16_ptr - str16 == 1, "got %Id.\n", str16_ptr - str16); + ok(!wcscmp(str16, L"\xd808"), "got %s.\n", debugstr_w(str16)); + ok(str_ptr - str == 3, "got %Id.\n", str_ptr - str); + ok(state.wchar == 0xdc00, "got %#x.\n", state.wchar); + + ret = (int)call_func8(p_codecvt_char16_do_in, &this, &state, str + 3, str + 4, (const char **)&str_ptr, + str16, str16 + 2, &str16_ptr); + ok(ret == CODECVT_ok, "got %d.\n", ret); + ok(str16_ptr - str16 == 1, "got %Id.\n", str16_ptr - str16); + ok(!wcscmp(str16, L"\xdc12"), "got %s.\n", debugstr_w(str16)); + ok(str_ptr - str == 4, "got %Id.\n", str_ptr - str); + ok(state.wchar == 1, "got %#x.\n", state.wchar); + + strcpy(str, "\xf0\x92\x80\x92"); + memset(&state, 0, sizeof(state)); + memset(str16, 0, sizeof(str16)); + ret = (int)call_func8(p_codecvt_char16_do_in, &this, &state, str, str + 4, (const char **)&str_ptr, + str16, str16 + 1, &str16_ptr); + ok(ret == CODECVT_ok, "got %d.\n", ret); + ok(str16_ptr - str16 == 1, "got %Id.\n", str16_ptr - str16); + ok(!wcscmp(str16, L"\xd808"), "got %s.\n", debugstr_w(str16)); + ok(str_ptr - str == 3, "got %Id.\n", str_ptr - str); + ok(state.wchar == 0xdc00, "got %#x.\n", state.wchar); + ret = (int)call_func8(p_codecvt_char16_do_in, &this, &state, str + 3, str + 4, (const char **)&str_ptr, + str16, str16 + 1, &str16_ptr); + ok(ret == CODECVT_ok, "got %d.\n", ret); + ok(str16_ptr - str16 == 1, "got %Id.\n", str16_ptr - str16); + ok(!wcscmp(str16, L"\xdc12"), "got %s.\n", debugstr_w(str16)); + ok(str_ptr - str == 4, "got %Id.\n", str_ptr - str); + ok(state.wchar == 1, "got %#x.\n", state.wchar); + + strcpy(str, "\xe0\xa1\x93"); + memset(&state, 0, sizeof(state)); + memset(str16, 0, sizeof(str16)); + ret = (int)call_func8(p_codecvt_char16_do_in, &this, &state, str, str + 3, (const char **)&str_ptr, + str16, str16 + 1, &str16_ptr); + ok(ret == CODECVT_ok, "got %d.\n", ret); + ok(str16_ptr - str16 == 1, "got %Id.\n", str16_ptr - str16); + ok(!wcscmp(str16, L"\x0853"), "got %s.\n", debugstr_w(str16)); + ok(str_ptr - str == 3, "got %Id.\n", str_ptr - str); + ok(state.wchar == 1, "got %#x.\n", state.wchar); + + strcpy(str, "\xe0\xa1\x93"); + memset(&state, 0, sizeof(state)); + memset(str16, 0, sizeof(str16)); + ret = (int)call_func8(p_codecvt_char16_do_in, &this, &state, str, str + 3, (const char **)&str_ptr, + str16, str16, &str16_ptr); + ok(ret == CODECVT_partial, "got %d.\n", ret); + ok(str16_ptr - str16 == 0, "got %Id.\n", str16_ptr - str16); + ok(str_ptr - str == 0, "got %Id.\n", str_ptr - str); + ok(state.wchar == 0, "got %#x.\n", state.wchar); + + strcpy(str, "\xe0\xa1\x93"); + memset(&state, 0, sizeof(state)); + memset(str16, 0, sizeof(str16)); + ret = (int)call_func8(p_codecvt_char16_do_in, &this, &state, str, str + 2, (const char **)&str_ptr, + str16, str16 + 2, &str16_ptr); + ok(ret == CODECVT_partial, "got %d.\n", ret); + ok(str16_ptr - str16 == 0, "got %Id.\n", str16_ptr - str16); + ok(str_ptr - str == 0, "got %Id.\n", str_ptr - str); + ok(state.wchar == 0, "got %#x.\n", state.wchar); + + strcpy(str, "\xf0\xff\xff\xff"); + memset(&state, 0, sizeof(state)); + memset(str16, 0, sizeof(str16)); + ret = (int)call_func8(p_codecvt_char16_do_in, &this, &state, str, str + 2, (const char **)&str_ptr, + str16, str16 + 4, &str16_ptr); + ok(ret == CODECVT_partial, "got %d.\n", ret); + ok(str16_ptr - str16 == 0, "got %Id.\n", str16_ptr - str16); + ok(str_ptr - str == 0, "got %Id.\n", str_ptr - str); + ok(state.wchar == 0, "got %#x.\n", state.wchar); + + strcpy(str, "\xf0\xff\xff\xff"); + memset(&state, 0, sizeof(state)); + memset(str16, 0, sizeof(str16)); + ret = (int)call_func8(p_codecvt_char16_do_in, &this, &state, str, str + 3, (const char **)&str_ptr, + str16, str16 + 4, &str16_ptr); + ok(ret == CODECVT_error, "got %d.\n", ret); + ok(str16_ptr - str16 == 0, "got %Id.\n", str16_ptr - str16); + ok(str_ptr - str == 1, "got %Id.\n", str_ptr - str); + ok(state.wchar == 0, "got %#x.\n", state.wchar); + + strcpy(str, "\xf0\x82\x80\x92"); + + memset(&state, 0, sizeof(state)); + memset(str16, 0, sizeof(str16)); + ret = (int)call_func8(p_codecvt_char16_do_in, &this, &state, str, str + 4, (const char **)&str_ptr, + str16, str16 + 2, &str16_ptr); + ok(ret == CODECVT_ok, "got %d.\n", ret); + ok(str16_ptr - str16 == 1, "got %Id.\n", str16_ptr - str16); + ok(!wcscmp(str16, L"\x2012"), "got %s.\n", debugstr_w(str16)); + ok(str_ptr - str == 4, "got %Id.\n", str_ptr - str); + ok(state.wchar == 1, "got %#x.\n", state.wchar); + + strcpy(str, "\xf0\xff\xff\xff"); + memset(&state, 0, sizeof(state)); + memset(str16, 0, sizeof(str16)); + ret = (int)call_func8(p_codecvt_char16_do_in, &this, &state, str, str + 4, (const char **)&str_ptr, + str16, str16 + 4, &str16_ptr); + ok(ret == CODECVT_error, "got %d.\n", ret); + ok(str16_ptr - str16 == 0, "got %Id.\n", str16_ptr - str16); + ok(str_ptr - str == 1, "got %Id.\n", str_ptr - str); + ok(state.wchar == 0, "got %#x.\n", state.wchar); + + strcpy(str, "\xed\xa0\x80"); + memset(&state, 0, sizeof(state)); + memset(str16, 0, sizeof(str16)); + ret = (int)call_func8(p_codecvt_char16_do_in, &this, &state, str, str + 3, (const char **)&str_ptr, + str16, str16 + 4, &str16_ptr); + ok(ret == CODECVT_ok, "got %d.\n", ret); + ok(str16_ptr - str16 == 1, "got %Id.\n", str16_ptr - str16); + ok(!wcscmp(str16, L"\xd800"), "got %s.\n", debugstr_w(str16)); + ok(str_ptr - str == 3, "got %Id.\n", str_ptr - str); + ok(state.wchar == 1, "got %#x.\n", state.wchar); + for (i = 0; i < ARRAY_SIZE(tests); ++i) { winetest_push_context("test %u", i); @@ -2129,6 +2337,36 @@ void test_codecvt_char16(void) ok(str_ptr - str == 0, "got %Id, expected %u.\n", str_ptr - str, 0); } } + strcpy(str, tests[i].str); + memset(&state, 0, sizeof(state)); + + ret = (int)call_func8(p_codecvt_char16_do_in, &this, &state, str, str + len, (const char **)&str_ptr, + str16, str16 + wlen + 10, &str16_ptr); + if (test_flags[j] & consume_header && str_has_bom_header(str)) + { + if (strlen(str) == sizeof(bom_header)) + { + ok(ret == CODECVT_partial, "got %d.\n", ret); + ok(str_ptr - str == 0, "got %Id.\n", str_ptr - str); + ok(str16_ptr - str16 == 0, "got %Id.\n", str16_ptr - str16); + } + else + { + ok(ret == CODECVT_ok, "got %d.\n", ret); + ok(str_ptr - str == len, "got %Id.\n", str_ptr - str); + ok(str16_ptr - str16 == wlen - 1, "got %Id.\n", str16_ptr - str16); + ok(!wcsncmp(str16, tests[i].wstr + 1, wlen - 1), "got %s, expected %s.\n", + debugstr_wn(str16, wlen), debugstr_wn(tests[i].wstr, wlen)); + } + } + else + { + ok(ret == CODECVT_ok, "got %d.\n", ret); + ok(str_ptr - str == len, "got %Id, expected %u.\n", str_ptr - str, len); + ok(str16_ptr - str16 == wlen, "got %Id, expected %u.\n", str16_ptr - str16, wlen); + ok(!wcsncmp(str16, tests[i].wstr, wlen), "got %s, expected %s.\n", + debugstr_wn(str16, wlen), debugstr_wn(tests[i].wstr, wlen)); + }
winetest_pop_context(); } diff --git a/dlls/msvcp90/locale.c b/dlls/msvcp90/locale.c index 730de5724b9..2b9844910c8 100644 --- a/dlls/msvcp90/locale.c +++ b/dlls/msvcp90/locale.c @@ -4125,9 +4125,127 @@ int __thiscall codecvt_char16_do_in(const codecvt_char16 *this, _Mbstatet *state const char *from, const char *from_end, const char **from_next, char16_t *to, char16_t *to_end, char16_t **to_next) { - FIXME("(%p %p %p %p %p %p %p %p) stub\n", this, state, from, + static const char utf8_length[128] = + { + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x80-0x8f */ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x90-0x9f */ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xa0-0xaf */ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xb0-0xbf */ + 0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2, /* 0xc0-0xcf */ + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, /* 0xd0-0xdf */ + 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, /* 0xe0-0xef */ + 4,4,4,4,4,0,0,0,0,0,0,0,0,0,0,0 /* 0xf0-0xff */ + }; + /* first byte mask depending on UTF-8 sequence length */ + static const unsigned char utf8_mask[4] = { 0x7f, 0x1f, 0x0f, 0x07 }; + + unsigned int res, len; + unsigned char ch; + const char *end; + BOOL fourbyte; + + TRACE("(%p %p %p %p %p %p %p %p)\n", this, state, from, from_end, from_next, to, to_end, to_next); - return 0; + + if (this->convert_mode & ~(generate_header | consume_header)) + FIXME("convert_mode %#x.\n", this->convert_mode); + + *from_next = from; + *to_next = to; + + while (*from_next != from_end && *to_next != to_end) + { + fourbyte = FALSE; + ch = **from_next; + if ((res = MBSTATET_TO_INT(state)) & ~1) + { + ch = ch ^ 0x80; + if (ch >= 0x40) + return CODECVT_error; + res |= ch; + ++*from_next; + MBSTATET_TO_INT(state) = 1; + } + else if (ch < 0x80) + { + res = ch; + ++*from_next; + } + else + { + if (!(len = utf8_length[ch - 0x80])) + { + ++*from_next; + return CODECVT_error; + } + + if (from_end - *from_next < min(len, 3)) + break; + ++*from_next; + res = ch & utf8_mask[len - 1]; + end = *from_next + len - 1; + switch (len) + { + case 4: + if ((ch = end[-3] ^ 0x80) >= 0x40) + return CODECVT_error; + res = (res << 6) | ch; + fourbyte = TRUE; + /* fallthrough */ + case 3: + if ((ch = end[-2] ^ 0x80) >= 0x40) + return CODECVT_error; + res = (res << 6) | ch; + ++*from_next; + /* fallthrough */ + case 2: + if (len == 4) + ch = 0; + else if ((ch = end[-1] ^ 0x80) >= 0x40) + return CODECVT_error; + res = (res << 6) | ch; + ++*from_next; + break; + } + } + + if (res > this->max_code) + return CODECVT_error; + + if (fourbyte) + { + if (res > 0x10000) + { + res -= 0x10000; + MBSTATET_TO_INT(state) = 0xdc00 | (res & 0x3ff); + res = 0xd800 | (res >> 10); + } + else + { + MBSTATET_TO_INT(state) = res; + continue; + } + } + if (!MBSTATET_TO_INT(state)) + { + MBSTATET_TO_INT(state) = 1; + if (this->convert_mode & consume_header && res == 0xfeff) + { + if (*from_next == from_end) + { + *from_next = from; + break; + } + continue; + } + } + *(*to_next)++ = res; + } + + if (*from_next != from) + return CODECVT_ok; + + return CODECVT_partial; }
/* ?in@?$codecvt@_SDU_Mbstatet@@@std@@QBAHAAU_Mbstatet@@PBD1AAPBDPA_S3AAPA_S@Z */
From: Paul Gofman pgofman@codeweavers.com
--- dlls/msvcp90/locale.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/dlls/msvcp90/locale.c b/dlls/msvcp90/locale.c index 2b9844910c8..a856bcb1d26 100644 --- a/dlls/msvcp90/locale.c +++ b/dlls/msvcp90/locale.c @@ -3876,7 +3876,7 @@ int __thiscall codecvt_wchar_do_out(const codecvt_wchar *this, _Mbstatet *state, case -1: return CODECVT_error; default: - if(size > from_end-*from_next) { + if(size > to_end - *to_next) { *state = old_state; return CODECVT_partial; }
On Wed Apr 2 11:21:43 2025 +0000, Paul Gofman wrote:
Is that 'this2' vs 'this' comparison? I wasn't getting any test failures, which Windows is that?
Yes, that's the failing test. It doesn't depend on Windows version. The tests were ok for regular constructors (mangled name starting with `??0`). I guess return value of "default constructor closure" is void and RAX contains kind of random data.
This merge request was approved by Piotr Caban.