jscript: Fix typos in comments, add missing ones.
[wine] / dlls / mlang / tests / mlang.c
1 /*
2  * Unit test suite for MLANG APIs.
3  *
4  * Copyright 2004 Dmitry Timoshkov
5  * Copyright 2009 Detlef Riekenberg
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22 #define COBJMACROS
23
24 #include <stdarg.h>
25 #include <stdio.h>
26
27 #include "windef.h"
28 #include "winbase.h"
29 #include "winerror.h"
30 #include "initguid.h"
31 #include "mlang.h"
32
33 #include "wine/test.h"
34
35 #ifndef CP_UNICODE
36 #define CP_UNICODE 1200
37 #endif
38
39 #if 0
40 #define DUMP_CP_INFO
41 #define DUMP_SCRIPT_INFO
42
43 #if defined DUMP_CP_INFO || defined DUMP_SCRIPT_INFO
44 #include "wine/debug.h"
45 #endif
46 #endif /* 0 */
47
48 static BOOL (WINAPI *pGetCPInfoExA)(UINT, DWORD, LPCPINFOEXA);
49 static HRESULT (WINAPI *pConvertINetMultiByteToUnicode)(LPDWORD, DWORD, LPCSTR,
50                                                         LPINT, LPWSTR, LPINT);
51 static HRESULT (WINAPI *pConvertINetUnicodeToMultiByte)(LPDWORD, DWORD, LPCWSTR,
52                                                         LPINT, LPSTR, LPINT);
53 typedef struct lcid_tag_table {
54     LPCSTR rfc1766;
55     LCID lcid;
56     HRESULT hr;
57     LCID broken_lcid;
58     LPCSTR broken_rfc;
59 } lcid_table_entry;
60
61 /* en, ar and zh use SUBLANG_NEUTRAL for the rfc1766 name without the country
62    all others suppress the country with SUBLANG_DEFAULT.
63    For 3 letter language codes, the rfc1766 is too small for the country */
64
65 static const lcid_table_entry  lcid_table[] = {
66     {"e",     -1,       E_FAIL},
67     {"",      -1,       E_FAIL},
68     {"-",     -1,       E_FAIL},
69     {"e-",    -1,       E_FAIL},
70
71     {"ar",    1,        S_OK},
72     {"zh",    4,        S_OK},
73
74     {"de",    0x0407,   S_OK},
75     {"de-ch", 0x0807,   S_OK},
76     {"de-at", 0x0c07,   S_OK},
77     {"de-lu", 0x1007,   S_OK},
78     {"de-li", 0x1407,   S_OK},
79
80     {"en",    9,        S_OK},
81     {"en-gb", 0x809,    S_OK},
82     {"en-GB", 0x809,    S_OK},
83     {"EN-GB", 0x809,    S_OK},
84     {"en-US", 0x409,    S_OK},
85     {"en-us", 0x409,    S_OK},
86
87     {"fr",    0x040c,   S_OK},
88     {"fr-be", 0x080c,   S_OK},
89     {"fr-ca", 0x0c0c,   S_OK},
90     {"fr-ch", 0x100c,   S_OK},
91     {"fr-lu", 0x140c,   S_OK},
92     {"fr-mc", 0x180c,   S_OK, 0x040c, "fr"},
93
94     {"it",    0x0410,   S_OK},
95     {"it-ch", 0x0810,   S_OK},
96
97     {"nl",    0x0413,   S_OK},
98     {"nl-be", 0x0813,   S_OK},
99     {"pl",    0x0415,   S_OK},
100     {"ru",    0x0419,   S_OK},
101
102     {"kok",   0x0457,   S_OK, 0x0412, "x-kok"}
103
104 };
105
106 #define TODO_NAME 1
107
108 typedef struct info_table_tag {
109     LCID lcid;
110     LANGID lang;
111     DWORD todo;
112     LPCSTR rfc1766;
113     LPCWSTR localename;
114     LPCWSTR broken_name;
115 } info_table_entry;
116
117 static const WCHAR de_en[] =   {'E','n','g','l','i','s','c','h',0};
118 static const WCHAR de_enca[] = {'E','n','g','l','i','s','c','h',' ',
119                                 '(','K','a','n','a','d','a',')',0};
120 static const WCHAR de_engb[] = {'E','n','g','l','i','s','c','h',' ',
121                                 '(','G','r','o',0xDF,'b','r','i','t','a','n','n','i','e','n',')',0};
122 static const WCHAR de_engb2[] ={'E','n','g','l','i','s','c','h',' ',
123                                 '(','V','e','r','e','i','n','i','g','t','e','s',' ',
124                                 'K',0xF6,'n','i','g','r','e','i','c',0};
125 static const WCHAR de_enus[] = {'E','n','g','l','i','s','c','h',' ',
126                                 '(','U','S','A',')',0};
127 static const WCHAR de_de[] =   {'D','e','u','t','s','c','h',' ',
128                                 '(','D','e','u','t','s','c','h','l','a','n','d',')',0};
129 static const WCHAR de_deat[] = {'D','e','u','t','s','c','h',' ',
130                                 '(',0xD6,'s','t','e','r','r','e','i','c','h',')',0};
131 static const WCHAR de_dech[] = {'D','e','u','t','s','c','h',' ',
132                                 '(','S','c','h','w','e','i','z',')',0};
133
134 static const WCHAR en_en[] =   {'E','n','g','l','i','s','h',0};
135 static const WCHAR en_enca[] = {'E','n','g','l','i','s','h',' ',
136                                 '(','C','a','n','a','d','a',')',0};
137 static const WCHAR en_engb[] = {'E','n','g','l','i','s','h',' ',
138                                 '(','U','n','i','t','e','d',' ','K','i','n','g','d','o','m',')',0};
139 static const WCHAR en_enus[] = {'E','n','g','l','i','s','h',' ',
140                                 '(','U','n','i','t','e','d',' ','S','t','a','t','e','s',')',0};
141 static const WCHAR en_de[] =   {'G','e','r','m','a','n',' ',
142                                 '(','G','e','r','m','a','n','y',')',0};
143 static const WCHAR en_deat[] = {'G','e','r','m','a','n',' ',
144                                 '(','A','u','s','t','r','i','a',')',0};
145 static const WCHAR en_dech[] = {'G','e','r','m','a','n',' ',
146                                 '(','S','w','i','t','z','e','r','l','a','n','d',')',0};
147
148 static const WCHAR fr_en[] =   {'A','n','g','l','a','i','s',0};
149 static const WCHAR fr_enca[] = {'A','n','g','l','a','i','s',' ',
150                                 '(','C','a','n','a','d','a',')',0};
151 static const WCHAR fr_engb[] = {'A','n','g','l','a','i','s',' ',
152                                 '(','R','o','y','a','u','m','e','-','U','n','i',')',0};
153 static const WCHAR fr_enus[] = {'A','n','g','l','a','i','s',' ',
154                                 '(',0xC9, 't','a','t','s','-','U','n','i','s',')',0};
155 static const WCHAR fr_enus2[] ={'A','n','g','l','a','i','s',' ',
156                                 '(','U','.','S','.',')',0};
157 static const WCHAR fr_de[] =   {'A','l','l','e','m','a','n','d',' ',
158                                 '(','A','l','l','e','m','a','g','n','e',')',0};
159 static const WCHAR fr_de2[] =  {'A','l','l','e','m','a','n','d',' ',
160                                 '(','S','t','a','n','d','a','r','d',')',0};
161 static const WCHAR fr_deat[] = {'A','l','l','e','m','a','n','d',' ',
162                                 '(','A','u','t','r','i','c','h','e',')',0};
163 static const WCHAR fr_dech[] = {'A','l','l','e','m','a','n','d',' ',
164                                 '(','S','u','i','s','s','e',')',0};
165
166 static const info_table_entry  info_table[] = {
167     {MAKELANGID(LANG_ENGLISH, SUBLANG_NEUTRAL),        MAKELANGID(LANG_ENGLISH, SUBLANG_NEUTRAL),
168          0, "en", en_en},
169     {MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT),        MAKELANGID(LANG_ENGLISH, SUBLANG_NEUTRAL),
170          0, "en-us", en_enus},
171     {MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_UK),     MAKELANGID(LANG_ENGLISH, SUBLANG_NEUTRAL),
172          0, "en-gb", en_engb},
173     {MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),     MAKELANGID(LANG_ENGLISH, SUBLANG_NEUTRAL),
174          0, "en-us", en_enus},
175     {MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_CAN),    MAKELANGID(LANG_ENGLISH, SUBLANG_NEUTRAL),
176          0, "en-ca", en_enca},
177
178     {MAKELANGID(LANG_GERMAN, SUBLANG_DEFAULT),         MAKELANGID(LANG_ENGLISH, SUBLANG_NEUTRAL),
179          0, "de", en_de},
180     {MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN),          MAKELANGID(LANG_ENGLISH, SUBLANG_NEUTRAL),
181          0, "de", en_de},
182     {MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN_SWISS),    MAKELANGID(LANG_ENGLISH, SUBLANG_NEUTRAL),
183          0, "de-ch", en_dech},
184     {MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN_AUSTRIAN), MAKELANGID(LANG_ENGLISH, SUBLANG_NEUTRAL),
185          0, "de-at", en_deat},
186
187     {MAKELANGID(LANG_ENGLISH, SUBLANG_NEUTRAL),        MAKELANGID(LANG_GERMAN, SUBLANG_DEFAULT),
188          TODO_NAME, "en", de_en},
189     {MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT),        MAKELANGID(LANG_GERMAN, SUBLANG_DEFAULT),
190          TODO_NAME, "en-us", de_enus},
191     {MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_UK),     MAKELANGID(LANG_GERMAN, SUBLANG_DEFAULT),
192          TODO_NAME, "en-gb", de_engb, de_engb2},
193     {MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),     MAKELANGID(LANG_GERMAN, SUBLANG_DEFAULT),
194          TODO_NAME, "en-us", de_enus},
195     {MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_CAN),    MAKELANGID(LANG_GERMAN, SUBLANG_DEFAULT),
196          TODO_NAME, "en-ca", de_enca},
197
198     {MAKELANGID(LANG_GERMAN, SUBLANG_DEFAULT),         MAKELANGID(LANG_GERMAN, SUBLANG_DEFAULT),
199          TODO_NAME, "de", de_de},
200     {MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN),          MAKELANGID(LANG_GERMAN, SUBLANG_DEFAULT),
201          TODO_NAME, "de",de_de},
202     {MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN_SWISS),    MAKELANGID(LANG_GERMAN, SUBLANG_DEFAULT),
203          TODO_NAME, "de-ch", de_dech},
204     {MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN_AUSTRIAN), MAKELANGID(LANG_GERMAN, SUBLANG_DEFAULT),
205          TODO_NAME, "de-at", de_deat},
206
207     {MAKELANGID(LANG_ENGLISH, SUBLANG_NEUTRAL),        MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT),
208          TODO_NAME, "en", fr_en},
209     {MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT),        MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT),
210          TODO_NAME, "en-us", fr_enus, fr_enus2},
211     {MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_UK),     MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT),
212          TODO_NAME, "en-gb", fr_engb},
213     {MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),     MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT),
214          TODO_NAME, "en-us", fr_enus, fr_enus2},
215     {MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_CAN),    MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT),
216          TODO_NAME, "en-ca", fr_enca},
217
218     {MAKELANGID(LANG_GERMAN, SUBLANG_DEFAULT),         MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT),
219          TODO_NAME, "de", fr_de, fr_de2},
220     {MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN),          MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT),
221          TODO_NAME, "de", fr_de, fr_de2},
222     {MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN_SWISS),    MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT),
223          TODO_NAME, "de-ch", fr_dech},
224     {MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN_AUSTRIAN), MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT),
225          TODO_NAME, "de-at", fr_deat}
226
227 };
228
229 static BOOL init_function_ptrs(void)
230 {
231     HMODULE hMlang;
232
233     hMlang = LoadLibraryA("mlang.dll");
234     if (!hMlang)
235     {
236         skip("mlang not available\n");
237         return FALSE;
238     }
239
240     pConvertINetMultiByteToUnicode = (void *)GetProcAddress(hMlang, "ConvertINetMultiByteToUnicode");
241     pConvertINetUnicodeToMultiByte = (void *)GetProcAddress(hMlang, "ConvertINetUnicodeToMultiByte");
242
243     pGetCPInfoExA = (void *)GetProcAddress(GetModuleHandleA("kernel32.dll"), "GetCPInfoExA");
244
245     return TRUE;
246 }
247
248 #define ok_w2(format, szString1, szString2) \
249 \
250     if (lstrcmpW((szString1), (szString2)) != 0) \
251     { \
252         CHAR string1[256], string2[256]; \
253         WideCharToMultiByte(CP_ACP, 0, (szString1), -1, string1, 256, NULL, NULL); \
254         WideCharToMultiByte(CP_ACP, 0, (szString2), -1, string2, 256, NULL, NULL); \
255         ok(0, (format), string1, string2); \
256     }
257
258 /* lstrcmpW is not supported on Win9x! */
259 static int mylstrcmpW(const WCHAR* str1, const WCHAR* str2)
260 {
261     if (!str2) return 1;
262     while (*str1 && *str1==*str2) {
263         str1++;
264         str2++;
265     }
266     return *str1-*str2;
267 }
268
269 /* lstrcpyW is not supported on Win95 */
270 static void mylstrcpyW(WCHAR* str1, const WCHAR* str2)
271 {
272     while (str2 && *str2) {
273         *str1 = *str2;
274         str1++;
275         str2++;
276     }
277     *str1 = '\0';
278 }
279
280 #define DEBUGSTR_W_MAXLEN 64
281
282 static CHAR * debugstr_w(const WCHAR * strW)
283 {
284     static CHAR buffers[DEBUGSTR_W_MAXLEN * 2];
285     static DWORD pos = 0;
286     CHAR * strA;
287     DWORD len = DEBUGSTR_W_MAXLEN - 4;
288
289     strA = &buffers[pos];
290
291     *strA++ = 'L';
292     *strA++ = '"';
293
294     while (*strW && (len > 4)) {
295         if ((*strW < ' ') || (*strW > 126)) {
296             sprintf(strA, "\\%04x", *strW);
297             strA +=5;
298             len -=5;
299         }
300         else
301         {
302             *strA++ = *strW;
303             len--;
304         }
305         strW++;
306     }
307     *strA++ = '"';
308     *strA = '\0';
309
310     strA = &buffers[pos];
311     pos += DEBUGSTR_W_MAXLEN;
312     if (pos >= sizeof(buffers)) pos = 0;
313
314     return strA;
315
316 }
317
318 static void test_multibyte_to_unicode_translations(IMultiLanguage2 *iML2)
319 {
320     /* these APIs are broken regarding constness of the input buffer */
321     char stringA[] = "Just a test string\0"; /* double 0 for CP_UNICODE tests */
322     WCHAR stringW[] = {'J','u','s','t',' ','a',' ','t','e','s','t',' ','s','t','r','i','n','g',0};
323     char bufA[256];
324     WCHAR bufW[256];
325     UINT lenA, lenW, expected_len;
326     HRESULT ret;
327
328     /* IMultiLanguage2_ConvertStringToUnicode tests */
329
330     memset(bufW, 'x', sizeof(bufW));
331     lenA = 0;
332     lenW = sizeof(bufW)/sizeof(bufW[0]);
333     ret = IMultiLanguage2_ConvertStringToUnicode(iML2, NULL, 1252, stringA, &lenA, bufW, &lenW);
334     ok(ret == S_OK, "IMultiLanguage2_ConvertStringToUnicode failed: %08x\n", ret);
335     ok(lenA == 0, "expected lenA 0, got %u\n", lenA);
336     ok(lenW == 0, "expected lenW 0, got %u\n", lenW);
337
338     memset(bufW, 'x', sizeof(bufW));
339     lenA = -1;
340     lenW = sizeof(bufW)/sizeof(bufW[0]);
341     ret = IMultiLanguage2_ConvertStringToUnicode(iML2, NULL, 1252, stringA, &lenA, bufW, &lenW);
342     ok(ret == S_OK, "IMultiLanguage2_ConvertStringToUnicode failed: %08x\n", ret);
343     ok(lenA == lstrlenA(stringA), "expected lenA %u, got %u\n", lstrlenA(stringA), lenA);
344     ok(lenW == lstrlenW(stringW), "expected lenW %u, got %u\n", lstrlenW(stringW), lenW);
345     if (lenW < sizeof(bufW)/sizeof(bufW[0])) {
346        /* can only happen if the convert call fails */
347        ok(bufW[lenW] != 0, "buf should not be 0 terminated\n");
348        bufW[lenW] = 0; /* -1 doesn't include 0 terminator */
349     }
350     ok(!lstrcmpW(bufW, stringW), "bufW/stringW mismatch\n");
351
352     memset(bufW, 'x', sizeof(bufW));
353     lenA = -1;
354     lenW = 5;
355     ret = IMultiLanguage2_ConvertStringToUnicode(iML2, NULL, 1252, stringA, &lenA, bufW, &lenW);
356     ok(ret == E_FAIL, "IMultiLanguage2_ConvertStringToUnicode should fail: %08x\n", ret);
357     ok(lenW == 0, "expected lenW 0, got %u\n", lenW);
358     /* still has to do partial conversion */
359     ok(!memcmp(bufW, stringW, 5 * sizeof(WCHAR)), "bufW/stringW mismatch\n");
360
361     memset(bufW, 'x', sizeof(bufW));
362     lenA = -1;
363     lenW = sizeof(bufW)/sizeof(bufW[0]);
364     ret = IMultiLanguage2_ConvertStringToUnicode(iML2, NULL, CP_UNICODE, stringA, &lenA, bufW, &lenW);
365     ok(ret == S_OK, "IMultiLanguage2_ConvertStringToUnicode failed: %08x\n", ret);
366     ok(lenA == lstrlenA(stringA), "expected lenA %u, got %u\n", lstrlenA(stringA), lenA);
367     ok(lenW == lstrlenW(stringW)/(int)sizeof(WCHAR), "wrong lenW %u\n", lenW);
368     ok(bufW[lenW] != 0, "buf should not be 0 terminated\n");
369     bufW[lenW] = 0; /* -1 doesn't include 0 terminator */
370     ok(!lstrcmpA((LPCSTR)bufW, stringA), "bufW/stringA mismatch\n");
371
372     memset(bufW, 'x', sizeof(bufW));
373     lenA = lstrlenA(stringA);
374     lenW = 0;
375     ret = IMultiLanguage2_ConvertStringToUnicode(iML2, NULL, 1252, stringA, &lenA, NULL, &lenW);
376     ok(ret == S_OK, "IMultiLanguage2_ConvertStringToUnicode failed: %08x\n", ret);
377     ok(lenA == lstrlenA(stringA), "expected lenA %u, got %u\n", lstrlenA(stringA), lenA);
378     expected_len = MultiByteToWideChar(1252, 0, stringA, lenA, NULL, 0);
379     ok(lenW == expected_len, "expected lenW %u, got %u\n", expected_len, lenW);
380
381     memset(bufW, 'x', sizeof(bufW));
382     lenA = lstrlenA(stringA);
383     lenW = sizeof(bufW)/sizeof(bufW[0]);
384     ret = pConvertINetMultiByteToUnicode(NULL, 1252, stringA, (INT *)&lenA, NULL, (INT *)&lenW);
385     ok(ret == S_OK, "ConvertINetMultiByteToUnicode failed: %08x\n", ret);
386     ok(lenA == lstrlenA(stringA), "expected lenA %u, got %u\n", lstrlenA(stringA), lenA);
387     expected_len = MultiByteToWideChar(1252, 0, stringA, lenA, NULL, 0);
388     ok(lenW == expected_len, "expected lenW %u, got %u\n", expected_len, lenW);
389
390     memset(bufW, 'x', sizeof(bufW));
391     lenA = lstrlenA(stringA);
392     lenW = 0;
393     ret = pConvertINetMultiByteToUnicode(NULL, 1252, stringA, (INT *)&lenA, NULL, (INT *)&lenW);
394     ok(ret == S_OK, "ConvertINetMultiByteToUnicode failed: %08x\n", ret);
395     ok(lenA == lstrlenA(stringA), "expected lenA %u, got %u\n", lstrlenA(stringA), lenA);
396     expected_len = MultiByteToWideChar(1252, 0, stringA, lenA, NULL, 0);
397     ok(lenW == expected_len, "expected lenW %u, got %u\n", expected_len, lenW);
398
399     /* IMultiLanguage2_ConvertStringFromUnicode tests */
400
401     memset(bufA, 'x', sizeof(bufA));
402     lenW = 0;
403     lenA = sizeof(bufA);
404     ret = IMultiLanguage2_ConvertStringFromUnicode(iML2, NULL, 1252, stringW, &lenW, bufA, &lenA);
405     ok(ret == S_OK, "IMultiLanguage2_ConvertStringFromUnicode failed: %08x\n", ret);
406     ok(lenA == 0, "expected lenA 0, got %u\n", lenA);
407     ok(lenW == 0, "expected lenW 0, got %u\n", lenW);
408
409     memset(bufA, 'x', sizeof(bufA));
410     lenW = -1;
411     lenA = sizeof(bufA);
412     ret = IMultiLanguage2_ConvertStringFromUnicode(iML2, NULL, 1252, stringW, &lenW, bufA, &lenA);
413     ok(ret == S_OK, "IMultiLanguage2_ConvertStringFromUnicode failed: %08x\n", ret);
414     ok(lenA == lstrlenA(stringA), "expected lenA %u, got %u\n", lstrlenA(stringA), lenA);
415     ok(lenW == lstrlenW(stringW), "expected lenW %u, got %u\n", lstrlenW(stringW), lenW);
416     ok(bufA[lenA] != 0, "buf should not be 0 terminated\n");
417     bufA[lenA] = 0; /* -1 doesn't include 0 terminator */
418     ok(!lstrcmpA(bufA, stringA), "bufA/stringA mismatch\n");
419
420     memset(bufA, 'x', sizeof(bufA));
421     lenW = -1;
422     lenA = 5;
423     ret = IMultiLanguage2_ConvertStringFromUnicode(iML2, NULL, 1252, stringW, &lenW, bufA, &lenA);
424     ok(ret == E_FAIL, "IMultiLanguage2_ConvertStringFromUnicode should fail: %08x\n", ret);
425     ok(lenA == 0, "expected lenA 0, got %u\n", lenA);
426     /* still has to do partial conversion */
427     ok(!memcmp(bufA, stringA, 5), "bufW/stringW mismatch\n");
428
429     memset(bufA, 'x', sizeof(bufA));
430     lenW = -1;
431     lenA = sizeof(bufA);
432     ret = IMultiLanguage2_ConvertStringFromUnicode(iML2, NULL, CP_UNICODE, stringW, &lenW, bufA, &lenA);
433     ok(ret == S_OK, "IMultiLanguage2_ConvertStringFromUnicode failed: %08x\n", ret);
434     ok(lenA == lstrlenA(stringA) * (int)sizeof(WCHAR), "wrong lenA %u\n", lenA);
435     ok(lenW == lstrlenW(stringW), "expected lenW %u, got %u\n", lstrlenW(stringW), lenW);
436     ok(bufA[lenA] != 0 && bufA[lenA+1] != 0, "buf should not be 0 terminated\n");
437     bufA[lenA] = 0; /* -1 doesn't include 0 terminator */
438     bufA[lenA+1] = 0; /* sizeof(WCHAR) */
439     ok(!lstrcmpW((LPCWSTR)bufA, stringW), "bufA/stringW mismatch\n");
440
441     memset(bufA, 'x', sizeof(bufA));
442     lenW = lstrlenW(stringW);
443     lenA = 0;
444     ret = IMultiLanguage2_ConvertStringFromUnicode(iML2, NULL, 1252, stringW, &lenW, NULL, &lenA);
445     ok(ret == S_OK, "IMultiLanguage2_ConvertStringFromUnicode failed: %08x\n", ret);
446     ok(lenW == lstrlenW(stringW), "expected lenW %u, got %u\n", lstrlenW(stringW), lenW);
447     expected_len = WideCharToMultiByte(1252, 0, stringW, lenW, NULL, 0, NULL, NULL);
448     ok(lenA == expected_len, "expected lenA %u, got %u\n", expected_len, lenA);
449 }
450
451 static void cpinfo_cmp(MIMECPINFO *cpinfo1, MIMECPINFO *cpinfo2)
452 {
453     ok(cpinfo1->dwFlags == cpinfo2->dwFlags, "dwFlags mismatch: %08x != %08x\n", cpinfo1->dwFlags, cpinfo2->dwFlags);
454     ok(cpinfo1->uiCodePage == cpinfo2->uiCodePage, "uiCodePage mismatch: %u != %u\n", cpinfo1->uiCodePage, cpinfo2->uiCodePage);
455     ok(cpinfo1->uiFamilyCodePage == cpinfo2->uiFamilyCodePage, "uiFamilyCodePage mismatch: %u != %u\n", cpinfo1->uiFamilyCodePage, cpinfo2->uiFamilyCodePage);
456     ok(!lstrcmpW(cpinfo1->wszDescription, cpinfo2->wszDescription), "wszDescription mismatch\n");
457     ok(!lstrcmpW(cpinfo1->wszWebCharset, cpinfo2->wszWebCharset), "wszWebCharset mismatch\n");
458     ok(!lstrcmpW(cpinfo1->wszHeaderCharset, cpinfo2->wszHeaderCharset), "wszHeaderCharset mismatch\n");
459     ok(!lstrcmpW(cpinfo1->wszBodyCharset, cpinfo2->wszBodyCharset), "wszBodyCharset mismatch\n");
460     ok(!lstrcmpW(cpinfo1->wszFixedWidthFont, cpinfo2->wszFixedWidthFont), "wszFixedWidthFont mismatch\n");
461     ok(!lstrcmpW(cpinfo1->wszProportionalFont, cpinfo2->wszProportionalFont), "wszProportionalFont mismatch\n");
462     ok(cpinfo1->bGDICharset == cpinfo2->bGDICharset, "bGDICharset mismatch: %d != %d\n", cpinfo1->bGDICharset, cpinfo2->bGDICharset);
463 }
464
465 #ifdef DUMP_CP_INFO
466 static const char *dump_mime_flags(DWORD flags)
467 {
468     static char buf[1024];
469
470     buf[0] = 0;
471
472     if (flags & MIMECONTF_MAILNEWS) strcat(buf, " MIMECONTF_MAILNEWS");
473     if (flags & MIMECONTF_BROWSER) strcat(buf, " MIMECONTF_BROWSER");
474     if (flags & MIMECONTF_MINIMAL) strcat(buf, " MIMECONTF_MINIMAL");
475     if (flags & MIMECONTF_IMPORT) strcat(buf, " MIMECONTF_IMPORT");
476     if (flags & MIMECONTF_SAVABLE_MAILNEWS) strcat(buf, " MIMECONTF_SAVABLE_MAILNEWS");
477     if (flags & MIMECONTF_SAVABLE_BROWSER) strcat(buf, " MIMECONTF_SAVABLE_BROWSER");
478     if (flags & MIMECONTF_EXPORT) strcat(buf, " MIMECONTF_EXPORT");
479     if (flags & MIMECONTF_PRIVCONVERTER) strcat(buf, " MIMECONTF_PRIVCONVERTER");
480     if (flags & MIMECONTF_VALID) strcat(buf, " MIMECONTF_VALID");
481     if (flags & MIMECONTF_VALID_NLS) strcat(buf, " MIMECONTF_VALID_NLS");
482     if (flags & MIMECONTF_MIME_IE4) strcat(buf, " MIMECONTF_MIME_IE4");
483     if (flags & MIMECONTF_MIME_LATEST) strcat(buf, " MIMECONTF_MIME_LATEST");
484     if (flags & MIMECONTF_MIME_REGISTRY) strcat(buf, " MIMECONTF_MIME_REGISTRY");
485
486     return buf;
487 }
488 #endif
489
490 static HRESULT check_convertible(IMultiLanguage2 *iML2, UINT from, UINT to)
491 {
492     CHAR convert[MAX_PATH];
493     BYTE dest[MAX_PATH];
494     HRESULT hr;
495     UINT srcsz, destsz;
496
497     static WCHAR strW[] = {'a','b','c',0};
498
499     /* Check to see if the target codepage has these characters or not */
500     if (from != CP_UTF8)
501     {
502         BOOL fDefaultChar;
503         char ch[10];
504         int cb;
505         cb = WideCharToMultiByte( from, WC_NO_BEST_FIT_CHARS | WC_COMPOSITECHECK | WC_DEFAULTCHAR,
506                                   strW, 3, ch, sizeof(ch), NULL, &fDefaultChar);
507
508         if(cb == 0 || fDefaultChar)
509         {
510             trace("target codepage %i does not contain 'abc'\n",from);
511             return E_FAIL;
512         }
513     }
514
515     srcsz = lstrlenW(strW) + 1;
516     destsz = MAX_PATH;
517     hr = IMultiLanguage2_ConvertStringFromUnicode(iML2, NULL, from, strW,
518                                                   &srcsz, convert, &destsz);
519     if (hr != S_OK)
520         return S_FALSE;
521
522     srcsz = -1;
523     destsz = MAX_PATH;
524     hr = IMultiLanguage2_ConvertString(iML2, NULL, from, to, (BYTE *)convert,
525                                        &srcsz, dest, &destsz);
526     if (hr != S_OK)
527         return S_FALSE;
528
529     return S_OK;
530 }
531
532 static void test_EnumCodePages(IMultiLanguage2 *iML2, DWORD flags)
533 {
534     IEnumCodePage *iEnumCP = NULL;
535     MIMECPINFO *cpinfo;
536     MIMECPINFO cpinfo2;
537     HRESULT ret;
538     ULONG i, n;
539     UINT total;
540
541     total = 0;
542     ret = IMultiLanguage2_GetNumberOfCodePageInfo(iML2, &total);
543     ok(ret == S_OK && total != 0, "IMultiLanguage2_GetNumberOfCodePageInfo: expected S_OK/!0, got %08x/%u\n", ret, total);
544
545     trace("total mlang supported codepages %u\n", total);
546
547     ret = IMultiLanguage2_EnumCodePages(iML2, flags, LANG_NEUTRAL, &iEnumCP);
548     ok(ret == S_OK && iEnumCP, "IMultiLanguage2_EnumCodePages: expected S_OK/!NULL, got %08x/%p\n", ret, iEnumCP);
549
550     ret = IEnumCodePage_Reset(iEnumCP);
551     ok(ret == S_OK, "IEnumCodePage_Reset: expected S_OK, got %08x\n", ret);
552     n = 65536;
553     ret = IEnumCodePage_Next(iEnumCP, 0, NULL, &n);
554     if (ret == S_FALSE)
555         ok(n == 0 && ret == S_FALSE, "IEnumCodePage_Next: expected 0/S_FALSE, got %u/%08x\n", n, ret);
556     else if (ret == E_FAIL)
557         ok(n == 65536 && ret == E_FAIL, "IEnumCodePage_Next: expected 65536/E_FAIL, got %u/%08x\n", n, ret);
558     ret = IEnumCodePage_Next(iEnumCP, 0, NULL, NULL);
559     if (ret == S_FALSE)
560         ok(ret == S_FALSE, "IEnumCodePage_Next: expected S_FALSE, got %08x\n", ret);
561     else if (ret == E_FAIL)
562         ok(n == 65536 && ret == E_FAIL, "IEnumCodePage_Next: expected 65536/E_FAIL, got %u/%08x\n", n, ret);
563
564     cpinfo = HeapAlloc(GetProcessHeap(), 0, sizeof(*cpinfo) * total * 2);
565
566     n = total * 2;
567     ret = IEnumCodePage_Next(iEnumCP, 0, cpinfo, &n);
568     ok(ret == S_FALSE && n == 0, "IEnumCodePage_Next: expected S_FALSE/0, got %08x/%u\n", ret, n);
569
570     n = total * 2;
571     ret = IEnumCodePage_Next(iEnumCP, n, cpinfo, &n);
572     ok(ret == S_OK && n != 0, "IEnumCodePage_Next: expected S_OK/!0, got %08x/%u\n", ret, n);
573
574     trace("flags %08x, enumerated codepages %u\n", flags, n);
575
576     if (!flags)
577     {
578         ok(n == total, "IEnumCodePage_Next: expected %u, got %u\n", total, n);
579
580         flags = MIMECONTF_MIME_LATEST;
581     }
582
583     total = n;
584
585     for (i = 0; i < n; i++)
586     {
587         CHARSETINFO csi;
588         MIMECSETINFO mcsi;
589         HRESULT convertible = S_OK;
590         static const WCHAR autoW[] = {'_','a','u','t','o',0};
591         static const WCHAR feffW[] = {'u','n','i','c','o','d','e','F','E','F','F',0};
592
593 #ifdef DUMP_CP_INFO
594         trace("MIMECPINFO #%u:\n"
595               "dwFlags %08x %s\n"
596               "uiCodePage %u\n"
597               "uiFamilyCodePage %u\n"
598               "wszDescription %s\n"
599               "wszWebCharset %s\n"
600               "wszHeaderCharset %s\n"
601               "wszBodyCharset %s\n"
602               "wszFixedWidthFont %s\n"
603               "wszProportionalFont %s\n"
604               "bGDICharset %d\n\n",
605               i,
606               cpinfo[i].dwFlags, dump_mime_flags(cpinfo[i].dwFlags),
607               cpinfo[i].uiCodePage,
608               cpinfo[i].uiFamilyCodePage,
609               wine_dbgstr_w(cpinfo[i].wszDescription),
610               wine_dbgstr_w(cpinfo[i].wszWebCharset),
611               wine_dbgstr_w(cpinfo[i].wszHeaderCharset),
612               wine_dbgstr_w(cpinfo[i].wszBodyCharset),
613               wine_dbgstr_w(cpinfo[i].wszFixedWidthFont),
614               wine_dbgstr_w(cpinfo[i].wszProportionalFont),
615               cpinfo[i].bGDICharset);
616 #endif
617         ok(cpinfo[i].dwFlags & flags, "enumerated flags %08x do not include requested %08x\n", cpinfo[i].dwFlags, flags);
618
619         if (TranslateCharsetInfo((DWORD *)(INT_PTR)cpinfo[i].uiFamilyCodePage, &csi, TCI_SRCCODEPAGE))
620             ok(cpinfo[i].bGDICharset == csi.ciCharset, "%d != %d\n", cpinfo[i].bGDICharset, csi.ciCharset);
621         else
622             if (winetest_debug > 1)
623                 trace("TranslateCharsetInfo failed for cp %u\n", cpinfo[i].uiFamilyCodePage);
624
625 #ifdef DUMP_CP_INFO
626         trace("%u: codepage %u family %u\n", i, cpinfo[i].uiCodePage, cpinfo[i].uiFamilyCodePage);
627 #endif
628         /* Win95 does not support UTF-7 */
629         if (cpinfo[i].uiCodePage == CP_UTF7) continue;
630
631         /* support files for some codepages might be not installed, or
632          * the codepage is just an alias.
633          */
634         if (IsValidCodePage(cpinfo[i].uiCodePage))
635         {
636             ret = IMultiLanguage2_IsConvertible(iML2, cpinfo[i].uiCodePage, CP_UNICODE);
637             ok(ret == S_OK, "IMultiLanguage2_IsConvertible(%u -> CP_UNICODE) = %08x\n", cpinfo[i].uiCodePage, ret);
638             ret = IMultiLanguage2_IsConvertible(iML2, CP_UNICODE, cpinfo[i].uiCodePage);
639             ok(ret == S_OK, "IMultiLanguage2_IsConvertible(CP_UNICODE -> %u) = %08x\n", cpinfo[i].uiCodePage, ret);
640
641             convertible = check_convertible(iML2, cpinfo[i].uiCodePage, CP_UTF8);
642             if (convertible != E_FAIL)
643             {
644                 ret = IMultiLanguage2_IsConvertible(iML2, cpinfo[i].uiCodePage, CP_UTF8);
645                 ok(ret == convertible, "IMultiLanguage2_IsConvertible(%u -> CP_UTF8) = %08x\n", cpinfo[i].uiCodePage, ret);
646                 ret = IMultiLanguage2_IsConvertible(iML2, CP_UTF8, cpinfo[i].uiCodePage);
647                 ok(ret == convertible, "IMultiLanguage2_IsConvertible(CP_UTF8 -> %u) = %08x\n", cpinfo[i].uiCodePage, ret);
648             }
649         }
650         else
651             if (winetest_debug > 1)
652                 trace("IsValidCodePage failed for cp %u\n", cpinfo[i].uiCodePage);
653
654     if (memcmp(cpinfo[i].wszWebCharset,feffW,sizeof(WCHAR)*11)==0)
655         skip("Legacy windows bug returning invalid charset of unicodeFEFF\n");
656     else
657     {
658         ret = IMultiLanguage2_GetCharsetInfo(iML2, cpinfo[i].wszWebCharset, &mcsi);
659         /* _autoxxx charsets are a fake and GetCharsetInfo fails for them */
660         if (memcmp(cpinfo[i].wszWebCharset, autoW, 5 * sizeof(WCHAR)))
661         {
662             ok (ret == S_OK, "IMultiLanguage2_GetCharsetInfo failed: %08x\n", ret);
663 #ifdef DUMP_CP_INFO
664             trace("%s: %u %u %s\n", wine_dbgstr_w(cpinfo[i].wszWebCharset), mcsi.uiCodePage, mcsi.uiInternetEncoding, wine_dbgstr_w(mcsi.wszCharset));
665 #endif
666             ok(!lstrcmpiW(cpinfo[i].wszWebCharset, mcsi.wszCharset),
667 #ifdef DUMP_CP_INFO
668                     "%s != %s\n",
669             wine_dbgstr_w(cpinfo[i].wszWebCharset), wine_dbgstr_w(mcsi.wszCharset));
670 #else
671                     "wszWebCharset mismatch\n");
672 #endif
673
674         if (0)
675         {
676             /* native mlang returns completely messed up encodings in some cases */
677             ok(mcsi.uiInternetEncoding == cpinfo[i].uiCodePage || mcsi.uiInternetEncoding == cpinfo[i].uiFamilyCodePage,
678             "%u != %u || %u\n", mcsi.uiInternetEncoding, cpinfo[i].uiCodePage, cpinfo[i].uiFamilyCodePage);
679             ok(mcsi.uiCodePage == cpinfo[i].uiCodePage || mcsi.uiCodePage == cpinfo[i].uiFamilyCodePage,
680             "%u != %u || %u\n", mcsi.uiCodePage, cpinfo[i].uiCodePage, cpinfo[i].uiFamilyCodePage);
681             }
682         }
683     }
684
685     if (memcmp(cpinfo[i].wszHeaderCharset,feffW,sizeof(WCHAR)*11)==0)
686         skip("Legacy windows bug returning invalid charset of unicodeFEFF\n");
687     else
688     {
689         ret = IMultiLanguage2_GetCharsetInfo(iML2, cpinfo[i].wszHeaderCharset, &mcsi);
690         /* _autoxxx charsets are a fake and GetCharsetInfo fails for them */
691         if (memcmp(cpinfo[i].wszHeaderCharset, autoW, 5 * sizeof(WCHAR)))
692         {
693             ok (ret == S_OK, "IMultiLanguage2_GetCharsetInfo failed: %08x\n", ret);
694 #ifdef DUMP_CP_INFO
695             trace("%s: %u %u %s\n", wine_dbgstr_w(cpinfo[i].wszHeaderCharset), mcsi.uiCodePage, mcsi.uiInternetEncoding, wine_dbgstr_w(mcsi.wszCharset));
696 #endif
697             ok(!lstrcmpiW(cpinfo[i].wszHeaderCharset, mcsi.wszCharset),
698 #ifdef DUMP_CP_INFO
699                     "%s != %s\n",
700             wine_dbgstr_w(cpinfo[i].wszHeaderCharset), wine_dbgstr_w(mcsi.wszCharset));
701 #else
702                     "wszHeaderCharset mismatch\n");
703 #endif
704
705         if (0)
706         {
707             /* native mlang returns completely messed up encodings in some cases */
708             ok(mcsi.uiInternetEncoding == cpinfo[i].uiCodePage || mcsi.uiInternetEncoding == cpinfo[i].uiFamilyCodePage,
709             "%u != %u || %u\n", mcsi.uiInternetEncoding, cpinfo[i].uiCodePage, cpinfo[i].uiFamilyCodePage);
710             ok(mcsi.uiCodePage == cpinfo[i].uiCodePage || mcsi.uiCodePage == cpinfo[i].uiFamilyCodePage,
711             "%u != %u || %u\n", mcsi.uiCodePage, cpinfo[i].uiCodePage, cpinfo[i].uiFamilyCodePage);
712         }
713         }
714     }
715
716     if (memcmp(cpinfo[i].wszBodyCharset,feffW,sizeof(WCHAR)*11)==0)
717         skip("Legacy windows bug returning invalid charset of unicodeFEFF\n");
718     else
719     {
720         ret = IMultiLanguage2_GetCharsetInfo(iML2, cpinfo[i].wszBodyCharset, &mcsi);
721         /* _autoxxx charsets are a fake and GetCharsetInfo fails for them */
722         if (memcmp(cpinfo[i].wszBodyCharset, autoW, 5 * sizeof(WCHAR)))
723         {
724             ok (ret == S_OK, "IMultiLanguage2_GetCharsetInfo failed: %08x\n", ret);
725 #ifdef DUMP_CP_INFO
726             trace("%s: %u %u %s\n", wine_dbgstr_w(cpinfo[i].wszBodyCharset), mcsi.uiCodePage, mcsi.uiInternetEncoding, wine_dbgstr_w(mcsi.wszCharset));
727 #endif
728             ok(!lstrcmpiW(cpinfo[i].wszBodyCharset, mcsi.wszCharset),
729 #ifdef DUMP_CP_INFO
730                     "%s != %s\n",
731             wine_dbgstr_w(cpinfo[i].wszBodyCharset), wine_dbgstr_w(mcsi.wszCharset));
732 #else
733                     "wszBodyCharset mismatch\n");
734 #endif
735
736         if (0)
737         {
738             /* native mlang returns completely messed up encodings in some cases */
739             ok(mcsi.uiInternetEncoding == cpinfo[i].uiCodePage || mcsi.uiInternetEncoding == cpinfo[i].uiFamilyCodePage,
740             "%u != %u || %u\n", mcsi.uiInternetEncoding, cpinfo[i].uiCodePage, cpinfo[i].uiFamilyCodePage);
741             ok(mcsi.uiCodePage == cpinfo[i].uiCodePage || mcsi.uiCodePage == cpinfo[i].uiFamilyCodePage,
742             "%u != %u || %u\n", mcsi.uiCodePage, cpinfo[i].uiCodePage, cpinfo[i].uiFamilyCodePage);
743         }
744         }
745     }
746     }
747
748     /* now IEnumCodePage_Next should fail, since pointer is at the end */
749     n = 1;
750     ret = IEnumCodePage_Next(iEnumCP, 1, &cpinfo2, &n);
751     ok(ret == S_FALSE && n == 0, "IEnumCodePage_Next: expected S_FALSE/0, got %08x/%u\n", ret, n);
752
753     ret = IEnumCodePage_Reset(iEnumCP);
754     ok(ret == S_OK, "IEnumCodePage_Reset: expected S_OK, got %08x\n", ret);
755     n = 0;
756     ret = IEnumCodePage_Next(iEnumCP, 1, &cpinfo2, &n);
757     ok(n == 1 && ret == S_OK, "IEnumCodePage_Next: expected 1/S_OK, got %u/%08x\n", n, ret);
758     cpinfo_cmp(&cpinfo[0], &cpinfo2);
759
760     if (0)
761     {
762     /* Due to a bug in MS' implementation of IEnumCodePage_Skip
763      * it's not used here.
764      */
765     ret = IEnumCodePage_Skip(iEnumCP, 1);
766     ok(ret == S_OK, "IEnumCodePage_Skip: expected S_OK, got %08x\n", ret);
767     }
768     for (i = 0; i < total - 1; i++)
769     {
770         n = 0;
771         ret = IEnumCodePage_Next(iEnumCP, 1, &cpinfo2, &n);
772         ok(n == 1 && ret == S_OK, "IEnumCodePage_Next: expected 1/S_OK, got %u/%08x\n", n, ret);
773         cpinfo_cmp(&cpinfo[i + 1], &cpinfo2);
774     }
775
776     HeapFree(GetProcessHeap(), 0, cpinfo);
777     IEnumCodePage_Release(iEnumCP);
778 }
779
780 static void scriptinfo_cmp(SCRIPTINFO *sinfo1, SCRIPTINFO *sinfo2)
781 {
782     ok(sinfo1->ScriptId == sinfo2->ScriptId, "ScriptId mismatch: %d != %d\n", sinfo1->ScriptId, sinfo2->ScriptId);
783     ok(sinfo1->uiCodePage == sinfo2->uiCodePage, "uiCodePage mismatch: %u != %u\n", sinfo1->uiCodePage, sinfo2->uiCodePage);
784     ok(!lstrcmpW(sinfo1->wszDescription, sinfo2->wszDescription), "wszDescription mismatch\n");
785     ok(!lstrcmpW(sinfo1->wszFixedWidthFont, sinfo2->wszFixedWidthFont), "wszFixedWidthFont mismatch\n");
786     ok(!lstrcmpW(sinfo1->wszProportionalFont, sinfo2->wszProportionalFont), "wszProportionalFont mismatch\n");
787 }
788
789 static void test_EnumScripts(IMultiLanguage2 *iML2, DWORD flags)
790 {
791     IEnumScript *iEnumScript = NULL;
792     SCRIPTINFO *sinfo;
793     SCRIPTINFO sinfo2;
794     HRESULT ret;
795     ULONG i, n;
796     UINT total;
797
798     total = 0;
799     ret = IMultiLanguage2_GetNumberOfScripts(iML2, &total);
800     ok(ret == S_OK && total != 0, "IMultiLanguage2_GetNumberOfScripts: expected S_OK/!0, got %08x/%u\n", ret, total);
801
802     trace("total mlang supported scripts %u\n", total);
803
804     ret = IMultiLanguage2_EnumScripts(iML2, flags, LANG_NEUTRAL, &iEnumScript);
805     ok(ret == S_OK && iEnumScript, "IMultiLanguage2_EnumScripts: expected S_OK/!NULL, got %08x/%p\n", ret, iEnumScript);
806
807     ret = IEnumScript_Reset(iEnumScript);
808     ok(ret == S_OK, "IEnumScript_Reset: expected S_OK, got %08x\n", ret);
809     n = 65536;
810     ret = IEnumScript_Next(iEnumScript, 0, NULL, &n);
811     ok(n == 65536 && ret == E_FAIL, "IEnumScript_Next: expected 65536/E_FAIL, got %u/%08x\n", n, ret);
812     ret = IEnumScript_Next(iEnumScript, 0, NULL, NULL);
813     ok(ret == E_FAIL, "IEnumScript_Next: expected E_FAIL, got %08x\n", ret);
814
815     sinfo = HeapAlloc(GetProcessHeap(), 0, sizeof(*sinfo) * total * 2);
816
817     n = total * 2;
818     ret = IEnumScript_Next(iEnumScript, 0, sinfo, &n);
819     ok(ret == S_FALSE && n == 0, "IEnumScript_Next: expected S_FALSE/0, got %08x/%u\n", ret, n);
820
821     n = total * 2;
822     ret = IEnumScript_Next(iEnumScript, n, sinfo, &n);
823     ok(ret == S_OK && n != 0, "IEnumScript_Next: expected S_OK, got %08x/%u\n", ret, n);
824
825     trace("flags %08x, enumerated scripts %u\n", flags, n);
826
827     if (!flags)
828     {
829         ok(n == total, "IEnumScript_Next: expected %u, got %u\n", total, n);
830         flags = SCRIPTCONTF_SCRIPT_USER | SCRIPTCONTF_SCRIPT_HIDE | SCRIPTCONTF_SCRIPT_SYSTEM;
831     }
832
833     total = n;
834
835     for (i = 0; pGetCPInfoExA && i < n; i++)
836     {
837 #ifdef DUMP_SCRIPT_INFO
838         trace("SCRIPTINFO #%u:\n"
839               "ScriptId %08x\n"
840               "uiCodePage %u\n"
841               "wszDescription %s\n"
842               "wszFixedWidthFont %s\n"
843               "wszProportionalFont %s\n\n",
844               i,
845               sinfo[i].ScriptId,
846               sinfo[i].uiCodePage,
847               wine_dbgstr_w(sinfo[i].wszDescription),
848               wine_dbgstr_w(sinfo[i].wszFixedWidthFont),
849               wine_dbgstr_w(sinfo[i].wszProportionalFont));
850         trace("%u codepage %u\n", i, sinfo[i].uiCodePage);
851 #endif
852     }
853
854     /* now IEnumScript_Next should fail, since pointer is at the end */
855     n = 1;
856     ret = IEnumScript_Next(iEnumScript, 1, &sinfo2, &n);
857     ok(ret == S_FALSE && n == 0, "IEnumScript_Next: expected S_FALSE/0, got %08x/%u\n", ret, n);
858
859     ret = IEnumScript_Reset(iEnumScript);
860     ok(ret == S_OK, "IEnumScript_Reset: expected S_OK, got %08x\n", ret);
861     n = 0;
862     ret = IEnumScript_Next(iEnumScript, 1, &sinfo2, &n);
863     ok(n == 1 && ret == S_OK, "IEnumScript_Next: expected 1/S_OK, got %u/%08x\n", n, ret);
864     scriptinfo_cmp(&sinfo[0], &sinfo2);
865
866     if (0)
867     {
868     /* Due to a bug in MS' implementation of IEnumScript_Skip
869      * it's not used here.
870      */
871     ret = IEnumScript_Skip(iEnumScript, 1);
872     ok(ret == S_OK, "IEnumScript_Skip: expected S_OK, got %08x\n", ret);
873     }
874     for (i = 0; i < total - 1; i++)
875     {
876         n = 0;
877         ret = IEnumScript_Next(iEnumScript, 1, &sinfo2, &n);
878         ok(n == 1 && ret == S_OK, "IEnumScript_Next: expected 1/S_OK, got %u/%08x\n", n, ret);
879         scriptinfo_cmp(&sinfo[i + 1], &sinfo2);
880     }
881
882     HeapFree(GetProcessHeap(), 0, sinfo);
883     IEnumScript_Release(iEnumScript);
884 }
885
886 static void IMLangFontLink_Test(IMLangFontLink* iMLFL)
887 {
888     DWORD dwCodePages, dwManyCodePages;
889     DWORD dwCmpCodePages;
890     UINT CodePage;
891     static const WCHAR str[3] = { 'd', 0x0436, 0xff90 };
892     LONG processed;
893     HRESULT ret;
894
895     dwCodePages = ~0u;
896     ret = IMLangFontLink_CodePageToCodePages(iMLFL, -1, &dwCodePages);
897     ok(ret == E_FAIL, "IMLangFontLink_CodePageToCodePages should fail: %x\n", ret);
898     ok(dwCodePages == 0, "expected 0, got %u\n", dwCodePages);
899
900     dwCodePages = 0;
901     ret = IMLangFontLink_CodePageToCodePages(iMLFL, 932, &dwCodePages);
902     ok(ret == S_OK, "IMLangFontLink_CodePageToCodePages error %x\n", ret);
903     ok(dwCodePages == FS_JISJAPAN, "expected FS_JISJAPAN, got %08x\n", dwCodePages);
904     CodePage = 0;
905     ret = IMLangFontLink_CodePagesToCodePage(iMLFL, dwCodePages, 1035, &CodePage);
906     ok(ret == S_OK, "IMLangFontLink_CodePagesToCodePage error %x\n", ret);
907     ok(CodePage == 932, "Incorrect CodePage Returned (%i)\n",CodePage);
908
909     dwManyCodePages = 0;
910     ret = IMLangFontLink_CodePageToCodePages(iMLFL, 1252, &dwManyCodePages);
911     ok(ret == S_OK, "IMLangFontLink_CodePageToCodePages error %x\n", ret);
912     ok(dwManyCodePages == FS_LATIN1, "expected FS_LATIN1, got %08x\n", dwManyCodePages);
913     dwCodePages = 0;
914     ret = IMLangFontLink_CodePageToCodePages(iMLFL, 1256, &dwCodePages);
915     ok(ret == S_OK, "IMLangFontLink_CodePageToCodePages error %x\n", ret);
916     ok(dwCodePages == FS_ARABIC, "expected FS_ARABIC, got %08x\n", dwCodePages);
917     dwManyCodePages |= dwCodePages;
918     ret = IMLangFontLink_CodePageToCodePages(iMLFL, 874, &dwCodePages);
919     ok(ret == S_OK, "IMLangFontLink_CodePageToCodePages error %x\n", ret);
920     ok(dwCodePages == FS_THAI, "expected FS_THAI, got %08x\n", dwCodePages);
921     dwManyCodePages |= dwCodePages;
922
923     ret = IMLangFontLink_CodePagesToCodePage(iMLFL, dwManyCodePages, 1256, &CodePage);
924     ok(ret == S_OK, "IMLangFontLink_CodePagesToCodePage error %x\n", ret);
925     ok(CodePage == 1256, "Incorrect CodePage Returned (%i)\n",CodePage);
926
927     ret = IMLangFontLink_CodePagesToCodePage(iMLFL, dwManyCodePages, 936, &CodePage);
928     ok(ret == S_OK, "IMLangFontLink_CodePagesToCodePage error %x\n", ret);
929     ok(CodePage == 1252, "Incorrect CodePage Returned (%i)\n",CodePage);
930
931     /* Tests for GetCharCodePages */
932
933     /* Latin 1 */
934     dwCmpCodePages = FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC | FS_GREEK | FS_TURKISH
935         | FS_HEBREW | FS_ARABIC | FS_BALTIC | FS_VIETNAMESE | FS_THAI
936         | FS_JISJAPAN | FS_CHINESESIMP | FS_WANSUNG | FS_CHINESETRAD;
937     ret = IMLangFontLink_GetCharCodePages(iMLFL, 'd', &dwCodePages);
938     ok(ret == S_OK, "IMLangFontLink_GetCharCodePages error %x\n", ret);
939     ok(dwCodePages == dwCmpCodePages, "expected %x, got %x\n", dwCmpCodePages, dwCodePages);
940
941     dwCodePages = 0;
942     processed = 0;
943     ret = IMLangFontLink_GetStrCodePages(iMLFL, &str[0], 1, 0, &dwCodePages, &processed);
944     ok(ret == S_OK, "IMLangFontLink_GetStrCodePages error %x\n", ret);
945     ok(dwCodePages == dwCmpCodePages, "expected %x, got %x\n", dwCmpCodePages, dwCodePages);
946     ok(processed == 1, "expected 1, got %d\n", processed);
947
948     /* Cyrillic */
949     dwCmpCodePages = FS_CYRILLIC | FS_JISJAPAN | FS_CHINESESIMP | FS_WANSUNG;
950     ret = IMLangFontLink_GetCharCodePages(iMLFL, 0x0436, &dwCodePages);
951     ok(ret == S_OK, "IMLangFontLink_GetCharCodePages error %x\n", ret);
952     ok(dwCodePages == dwCmpCodePages, "expected %x, got %x\n", dwCmpCodePages, dwCodePages);
953
954     dwCodePages = 0;
955     processed = 0;
956     ret = IMLangFontLink_GetStrCodePages(iMLFL, &str[1], 1, 0, &dwCodePages, &processed);
957     ok(ret == S_OK, "IMLangFontLink_GetStrCodePages error %x\n", ret);
958     ok(dwCodePages == dwCmpCodePages, "expected %x, got %x\n", dwCmpCodePages, dwCodePages);
959     ok(processed == 1, "expected 1, got %d\n", processed);
960
961     /* Japanese */
962     dwCmpCodePages =  FS_JISJAPAN;
963     ret = IMLangFontLink_GetCharCodePages(iMLFL, 0xff90, &dwCodePages);
964     ok(ret == S_OK, "IMLangFontLink_GetCharCodePages error %x\n", ret);
965     ok(dwCodePages == dwCmpCodePages, "expected %x, got %x\n", dwCmpCodePages, dwCodePages);
966
967     dwCodePages = 0;
968     processed = 0;
969     ret = IMLangFontLink_GetStrCodePages(iMLFL, &str[2], 1, 0, &dwCodePages, &processed);
970     ok(ret == S_OK, "IMLangFontLink_GetStrCodePages error %x\n", ret);
971     ok(dwCodePages == dwCmpCodePages, "expected %x, got %x\n", dwCmpCodePages, dwCodePages);
972     ok(processed == 1, "expected 1, got %d\n", processed);
973
974     dwCmpCodePages = FS_CYRILLIC | FS_JISJAPAN | FS_CHINESESIMP | FS_WANSUNG;
975     dwCodePages = 0;
976     processed = 0;
977     ret = IMLangFontLink_GetStrCodePages(iMLFL, str, 2, 0, &dwCodePages, &processed);
978     ok(ret == S_OK, "IMLangFontLink_GetStrCodePages error %x\n", ret);
979     ok(dwCodePages == dwCmpCodePages, "expected %x, got %x\n", dwCmpCodePages, dwCodePages);
980     ok(processed == 2, "expected 2, got %d\n", processed);
981
982     dwCmpCodePages = FS_JISJAPAN;
983     dwCodePages = 0;
984     processed = 0;
985     ret = IMLangFontLink_GetStrCodePages(iMLFL, str, 3, 0, &dwCodePages, &processed);
986     ok(ret == S_OK, "IMLangFontLink_GetStrCodePages error %x\n", ret);
987     ok(dwCodePages == dwCmpCodePages, "expected %x, got %x\n", dwCmpCodePages, dwCodePages);
988     ok(processed == 3, "expected 3, got %d\n", processed);
989
990     dwCodePages = 0xffff;
991     processed = -1;
992     ret = IMLangFontLink_GetStrCodePages(iMLFL, &str[2], 1, 0, &dwCodePages, &processed);
993     ok(ret == S_OK, "IMLangFontLink_GetStrCodePages error %x\n", ret);
994     ok(dwCodePages == dwCmpCodePages, "expected %x, got %x\n", dwCmpCodePages, dwCodePages);
995     ok(processed == 1, "expected 0, got %d\n", processed);
996
997     ret = IMLangFontLink_GetStrCodePages(iMLFL, &str[2], 1, 0, NULL, NULL);
998     ok(ret == S_OK, "IMLangFontLink_GetStrCodePages error %x\n", ret);
999
1000     dwCodePages = 0xffff;
1001     processed = -1;
1002     ret = IMLangFontLink_GetStrCodePages(iMLFL, str, -1, 0, &dwCodePages, &processed);
1003     ok(ret == E_INVALIDARG, "IMLangFontLink_GetStrCodePages should fail: %x\n", ret);
1004     ok(dwCodePages == 0, "expected %x, got %x\n", dwCmpCodePages, dwCodePages);
1005     ok(processed == 0, "expected 0, got %d\n", processed);
1006
1007     dwCodePages = 0xffff;
1008     processed = -1;
1009     ret = IMLangFontLink_GetStrCodePages(iMLFL, NULL, 1, 0, &dwCodePages, &processed);
1010     ok(ret == E_INVALIDARG, "IMLangFontLink_GetStrCodePages should fail: %x\n", ret);
1011     ok(dwCodePages == 0, "expected %x, got %x\n", dwCmpCodePages, dwCodePages);
1012     ok(processed == 0, "expected 0, got %d\n", processed);
1013
1014     dwCodePages = 0xffff;
1015     processed = -1;
1016     ret = IMLangFontLink_GetStrCodePages(iMLFL, str, 0, 0, &dwCodePages, &processed);
1017     ok(ret == E_INVALIDARG, "IMLangFontLink_GetStrCodePages should fail: %x\n", ret);
1018     ok(dwCodePages == 0, "expected %x, got %x\n", dwCmpCodePages, dwCodePages);
1019     ok(processed == 0, "expected 0, got %d\n", processed);
1020 }
1021
1022 /* copied from libs/wine/string.c */
1023 static WCHAR *strstrW(const WCHAR *str, const WCHAR *sub)
1024 {
1025     while (*str)
1026     {
1027         const WCHAR *p1 = str, *p2 = sub;
1028         while (*p1 && *p2 && *p1 == *p2) { p1++; p2++; }
1029         if (!*p2) return (WCHAR *)str;
1030         str++;
1031     }
1032     return NULL;
1033 }
1034
1035 static void test_rfc1766(IMultiLanguage2 *iML2)
1036 {
1037     IEnumRfc1766 *pEnumRfc1766;
1038     RFC1766INFO info;
1039     ULONG n;
1040     HRESULT ret;
1041     BSTR rfcstr;
1042
1043     ret = IMultiLanguage2_EnumRfc1766(iML2, LANG_NEUTRAL, &pEnumRfc1766);
1044     ok(ret == S_OK, "IMultiLanguage2_EnumRfc1766 error %08x\n", ret);
1045
1046     while (1)
1047     {
1048         ret = IEnumRfc1766_Next(pEnumRfc1766, 1, &info, &n);
1049         if (ret != S_OK) break;
1050
1051 #ifdef DUMP_CP_INFO
1052         trace("lcid %04x rfc_name %s locale_name %s\n",
1053               info.lcid, wine_dbgstr_w(info.wszRfc1766), wine_dbgstr_w(info.wszLocaleName));
1054 #endif
1055
1056         ok(n == 1, "couldn't fetch 1 RFC1766INFO structure\n");
1057
1058         /* verify the Rfc1766 value */
1059         ret = IMultiLanguage2_GetRfc1766FromLcid(iML2, info.lcid, &rfcstr);
1060         ok(ret == S_OK, "Expected S_OK, got %08x\n", ret);
1061
1062         /* not an exact 1:1 correspondence between lcid and rfc1766 in the
1063          * mlang database, e.g., nb-no -> 1044 -> no */
1064         ok(strstrW(info.wszRfc1766, rfcstr) != NULL,
1065            "Expected matching locale names\n");
1066
1067         SysFreeString(rfcstr);
1068     }
1069     IEnumRfc1766_Release(pEnumRfc1766);
1070 }
1071
1072 static void test_GetLcidFromRfc1766(IMultiLanguage2 *iML2)
1073 {
1074     WCHAR rfc1766W[MAX_RFC1766_NAME + 1];
1075     LCID lcid;
1076     HRESULT ret;
1077     DWORD i;
1078
1079     static WCHAR en[] = { 'e','n',0 };
1080     static WCHAR en_them[] = { 'e','n','-','t','h','e','m',0 };
1081     static WCHAR english[] = { 'e','n','g','l','i','s','h',0 };
1082
1083
1084     for(i = 0; i < sizeof(lcid_table) / sizeof(lcid_table[0]); i++) {
1085         lcid = -1;
1086         MultiByteToWideChar(CP_ACP, 0, lcid_table[i].rfc1766, -1, rfc1766W, MAX_RFC1766_NAME);
1087         ret = IMultiLanguage2_GetLcidFromRfc1766(iML2, &lcid, rfc1766W);
1088
1089         /* IE <6.0 guess 0x412 (ko) from "kok" */
1090         ok((ret == lcid_table[i].hr) ||
1091             broken(lcid_table[i].broken_lcid && (ret == S_FALSE)),
1092             "#%02d: HRESULT 0x%x (expected 0x%x)\n", i, ret, lcid_table[i].hr);
1093
1094         ok((lcid == lcid_table[i].lcid) ||
1095             broken(lcid == lcid_table[i].broken_lcid),   /* IE <6.0 */
1096             "#%02d: got LCID 0x%x (expected 0x%x)\n", i, lcid, lcid_table[i].lcid);
1097     }
1098
1099
1100     ret = IMultiLanguage2_GetLcidFromRfc1766(iML2, NULL, en);
1101     ok(ret == E_INVALIDARG, "GetLcidFromRfc1766 returned: %08x\n", ret);
1102
1103     ret = IMultiLanguage2_GetLcidFromRfc1766(iML2, &lcid, NULL);
1104     ok(ret == E_INVALIDARG, "GetLcidFromRfc1766 returned: %08x\n", ret);
1105
1106     ret = IMultiLanguage2_GetLcidFromRfc1766(iML2, &lcid, en_them);
1107     ok((ret == E_FAIL || ret == S_FALSE), "GetLcidFromRfc1766 returned: %08x\n", ret);
1108     if (ret == S_FALSE)
1109     {
1110         BSTR rfcstr;
1111         static WCHAR en[] = {'e','n',0};
1112
1113         ret = IMultiLanguage2_GetRfc1766FromLcid(iML2, lcid, &rfcstr);
1114         ok(ret == S_OK, "Expected S_OK, got %08x\n", ret);
1115         ok_w2("Expected \"%s\",  got \"%s\"n", en, rfcstr);
1116     }
1117
1118     ret = IMultiLanguage2_GetLcidFromRfc1766(iML2, &lcid, english);
1119     ok((ret == E_FAIL || ret == S_FALSE), "GetLcidFromRfc1766 returned: %08x\n", ret);
1120     if (ret == S_FALSE)
1121     {
1122         BSTR rfcstr;
1123         static WCHAR en[] = {'e','n',0};
1124
1125         ret = IMultiLanguage2_GetRfc1766FromLcid(iML2, lcid, &rfcstr);
1126         ok(ret == S_OK, "Expected S_OK, got %08x\n", ret);
1127         ok_w2("Expected \"%s\",  got \"%s\"n", en, rfcstr);
1128     }
1129
1130 }
1131
1132 static void test_Rfc1766ToLcid(void)
1133 {
1134     LCID lcid;
1135     HRESULT ret;
1136     DWORD i;
1137
1138     for(i = 0; i < sizeof(lcid_table) / sizeof(lcid_table[0]); i++) {
1139         lcid = -1;
1140         ret = Rfc1766ToLcidA(&lcid, lcid_table[i].rfc1766);
1141
1142         /* IE <6.0 guess 0x412 (ko) from "kok" */
1143         ok( (ret == lcid_table[i].hr) ||
1144             broken(lcid_table[i].broken_lcid && (ret == S_FALSE)),
1145             "#%02d: HRESULT 0x%x (expected 0x%x)\n", i, ret, lcid_table[i].hr);
1146
1147         ok( (lcid == lcid_table[i].lcid) ||
1148             broken(lcid == lcid_table[i].broken_lcid),  /* IE <6.0 */
1149             "#%02d: got LCID 0x%x (expected 0x%x)\n", i, lcid, lcid_table[i].lcid);
1150
1151     }
1152
1153     ret = Rfc1766ToLcidA(&lcid, NULL);
1154     ok(ret == E_INVALIDARG, "got 0x%08x (expected E_INVALIDARG)\n", ret);
1155
1156     ret = Rfc1766ToLcidA(NULL, "en");
1157     ok(ret == E_INVALIDARG, "got 0x%08x (expected E_INVALIDARG)\n", ret);
1158
1159 }
1160
1161 static void test_GetNumberOfCodePageInfo(IMultiLanguage2 *iML2)
1162 {
1163     HRESULT hr;
1164     UINT value;
1165
1166     value = 0xdeadbeef;
1167     hr = IMultiLanguage2_GetNumberOfCodePageInfo(iML2, &value);
1168     ok( (hr == S_OK) && value,
1169         "got 0x%x with %d (expected S_OK with '!= 0')\n", hr, value);
1170
1171     hr = IMultiLanguage2_GetNumberOfCodePageInfo(iML2, NULL);
1172     ok(hr == E_INVALIDARG, "got 0x%x (expected E_INVALIDARG)\n", hr);
1173
1174 }
1175
1176 static void test_GetRfc1766FromLcid(IMultiLanguage2 *iML2)
1177 {
1178     CHAR expected[MAX_RFC1766_NAME];
1179     CHAR buffer[MAX_RFC1766_NAME + 1];
1180     DWORD i;
1181     HRESULT hr;
1182     BSTR rfcstr;
1183
1184     for(i = 0; i < sizeof(lcid_table) / sizeof(lcid_table[0]); i++) {
1185         buffer[0] = '\0';
1186
1187         rfcstr = NULL;
1188         hr = IMultiLanguage2_GetRfc1766FromLcid(iML2, lcid_table[i].lcid, &rfcstr);
1189         ok(hr == lcid_table[i].hr,
1190             "#%02d: HRESULT 0x%x (expected 0x%x)\n", i, hr, lcid_table[i].hr);
1191
1192         if (hr != S_OK)
1193             continue;   /* no result-string created */
1194
1195         WideCharToMultiByte(CP_ACP, 0, rfcstr, -1, buffer, sizeof(buffer), NULL, NULL);
1196         LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE, lcid_table[i].rfc1766,
1197                     lstrlenA(lcid_table[i].rfc1766) + 1, expected, MAX_RFC1766_NAME);
1198
1199         /* IE <6.0 return "x-kok" for LCID 0x457 ("kok") */
1200         ok( (!lstrcmpA(buffer, expected)) ||
1201             broken(!lstrcmpA(buffer, lcid_table[i].broken_rfc)),
1202             "#%02d: got '%s' (expected '%s')\n", i, buffer, expected);
1203
1204         SysFreeString(rfcstr);
1205     }
1206
1207     hr = IMultiLanguage2_GetRfc1766FromLcid(iML2, MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), NULL);
1208     ok(hr == E_INVALIDARG, "got 0x%x (expected E_INVALIDARG)\n", hr);
1209 }
1210
1211 static void test_LcidToRfc1766(void)
1212 {
1213     CHAR expected[MAX_RFC1766_NAME];
1214     CHAR buffer[MAX_RFC1766_NAME * 2];
1215     HRESULT hr;
1216     DWORD i;
1217
1218     for(i = 0; i < sizeof(lcid_table) / sizeof(lcid_table[0]); i++) {
1219
1220         memset(buffer, '#', sizeof(buffer)-1);
1221         buffer[sizeof(buffer)-1] = '\0';
1222
1223         hr = LcidToRfc1766A(lcid_table[i].lcid, buffer, MAX_RFC1766_NAME);
1224
1225         /* IE <5.0 does not recognize 0x180c (fr-mc) and 0x457 (kok) */
1226         ok( (hr == lcid_table[i].hr) ||
1227             broken(lcid_table[i].broken_lcid && (hr == E_FAIL)),
1228             "#%02d: HRESULT 0x%x (expected 0x%x)\n", i, hr, lcid_table[i].hr);
1229
1230         if (hr != S_OK)
1231             continue;
1232
1233         LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE, lcid_table[i].rfc1766,
1234                     lstrlenA(lcid_table[i].rfc1766) + 1, expected, MAX_RFC1766_NAME);
1235
1236         /* IE <6.0 return "x-kok" for LCID 0x457 ("kok") */
1237         /* IE <5.0 return "fr" for LCID 0x180c ("fr-mc") */
1238         ok( (!lstrcmpA(buffer, expected)) ||
1239             broken(!lstrcmpA(buffer, lcid_table[i].broken_rfc)),
1240             "#%02d: got '%s' (expected '%s')\n", i, buffer, expected);
1241
1242     }
1243
1244     memset(buffer, '#', sizeof(buffer)-1);
1245     buffer[sizeof(buffer)-1] = '\0';
1246     hr = LcidToRfc1766A(-1, buffer, MAX_RFC1766_NAME);
1247     ok(hr == E_FAIL, "got 0x%08x and '%s' (expected E_FAIL)\n", hr, buffer);
1248
1249     hr = LcidToRfc1766A(LANG_ENGLISH, NULL, MAX_RFC1766_NAME);
1250     ok(hr == E_INVALIDARG, "got 0x%08x (expected E_INVALIDARG)\n", hr);
1251
1252     memset(buffer, '#', sizeof(buffer)-1);
1253     buffer[sizeof(buffer)-1] = '\0';
1254     hr = LcidToRfc1766A(LANG_ENGLISH, buffer, -1);
1255     ok(hr == E_INVALIDARG, "got 0x%08x and '%s' (expected E_INVALIDARG)\n", hr, buffer);
1256
1257     memset(buffer, '#', sizeof(buffer)-1);
1258     buffer[sizeof(buffer)-1] = '\0';
1259     hr = LcidToRfc1766A(LANG_ENGLISH, buffer, 0);
1260     ok(hr == E_INVALIDARG, "got 0x%08x and '%s' (expected E_INVALIDARG)\n", hr, buffer);
1261
1262 }
1263
1264 static void test_GetRfc1766Info(IMultiLanguage2 *iML2)
1265 {
1266     WCHAR short_broken_name[MAX_LOCALE_NAME];
1267     CHAR rfc1766A[MAX_RFC1766_NAME + 1];
1268     BYTE buffer[sizeof(RFC1766INFO) + 4];
1269     PRFC1766INFO prfc = (RFC1766INFO *) buffer;
1270     HRESULT ret;
1271     DWORD i;
1272
1273     for(i = 0; i < sizeof(info_table) / sizeof(info_table[0]); i++) {
1274         memset(buffer, 'x', sizeof(RFC1766INFO) + 2);
1275         buffer[sizeof(buffer) -1] = 0;
1276         buffer[sizeof(buffer) -2] = 0;
1277
1278         ret = IMultiLanguage2_GetRfc1766Info(iML2, info_table[i].lcid, info_table[i].lang, prfc);
1279         WideCharToMultiByte(CP_ACP, 0, prfc->wszRfc1766, -1, rfc1766A, MAX_RFC1766_NAME, NULL, NULL);
1280         ok(ret == S_OK, "#%02d: got 0x%x (expected S_OK)\n", i, ret);
1281         ok(prfc->lcid == info_table[i].lcid,
1282             "#%02d: got 0x%04x (expected 0x%04x)\n", i, prfc->lcid, info_table[i].lcid);
1283
1284         ok(!lstrcmpA(rfc1766A, info_table[i].rfc1766),
1285             "#%02d: got '%s' (expected '%s')\n", i, rfc1766A, info_table[i].rfc1766);
1286
1287         /* Some IE versions truncate an oversized name one character to short */
1288         mylstrcpyW(short_broken_name, info_table[i].broken_name);
1289         short_broken_name[MAX_LOCALE_NAME - 2] = '\0';
1290
1291         if (info_table[i].todo & TODO_NAME) {
1292             todo_wine
1293             ok( (!mylstrcmpW(prfc->wszLocaleName, info_table[i].localename)) ||
1294                 broken(!mylstrcmpW(prfc->wszLocaleName, info_table[i].broken_name)) || /* IE < 6.0 */
1295                 broken(!mylstrcmpW(prfc->wszLocaleName, short_broken_name)),
1296                 "#%02d: got %s (expected %s)\n", i,
1297                 debugstr_w(prfc->wszLocaleName), debugstr_w(info_table[i].localename));
1298         }
1299         else
1300             ok( (!mylstrcmpW(prfc->wszLocaleName, info_table[i].localename)) ||
1301                 broken(!mylstrcmpW(prfc->wszLocaleName, info_table[i].broken_name)) || /* IE < 6.0 */
1302                 broken(!mylstrcmpW(prfc->wszLocaleName, short_broken_name)),
1303                 "#%02d: got %s (expected %s)\n", i,
1304                 debugstr_w(prfc->wszLocaleName), debugstr_w(info_table[i].localename));
1305
1306     }
1307
1308     /* SUBLANG_NEUTRAL only allowed for english, arabic, chinese */
1309     ret = IMultiLanguage2_GetRfc1766Info(iML2, MAKELANGID(LANG_GERMAN, SUBLANG_NEUTRAL), LANG_ENGLISH, prfc);
1310     ok(ret == E_FAIL, "got 0x%x (expected E_FAIL)\n", ret);
1311
1312     ret = IMultiLanguage2_GetRfc1766Info(iML2, MAKELANGID(LANG_ITALIAN, SUBLANG_NEUTRAL), LANG_ENGLISH, prfc);
1313     ok(ret == E_FAIL, "got 0x%x (expected E_FAIL)\n", ret);
1314
1315     /* NULL not allowed */
1316     ret = IMultiLanguage2_GetRfc1766Info(iML2, 0, LANG_ENGLISH, prfc);
1317     ok(ret == E_FAIL, "got 0x%x (expected E_FAIL)\n", ret);
1318
1319     ret = IMultiLanguage2_GetRfc1766Info(iML2, LANG_ENGLISH, LANG_ENGLISH, NULL);
1320     ok(ret == E_INVALIDARG, "got 0x%x (expected E_INVALIDARG)\n", ret);
1321 }
1322
1323 static void test_IMultiLanguage2_ConvertStringFromUnicode(IMultiLanguage2 *iML2)
1324 {
1325     CHAR dest[MAX_PATH];
1326     CHAR invariate[MAX_PATH];
1327     UINT srcsz, destsz;
1328     HRESULT hr;
1329
1330     static WCHAR src[] = {'a','b','c',0};
1331
1332     memset(invariate, 'x', sizeof(invariate));
1333
1334     /* pSrcStr NULL */
1335     memset(dest, 'x', sizeof(dest));
1336     srcsz = lstrlenW(src) + 1;
1337     destsz = sizeof(dest);
1338     hr = IMultiLanguage2_ConvertStringFromUnicode(iML2, NULL, 1252, NULL,
1339                                                   &srcsz, dest, &destsz);
1340     ok(hr == S_OK || hr == E_FAIL,"expected S_OK or E_FAIL, got %08x\n",hr);
1341     if (hr == S_OK)
1342     {
1343         ok(srcsz == lstrlenW(src) + 1,
1344            "Expected %u, got %u\n", lstrlenW(src) + 1, srcsz);
1345     }
1346     else if (hr == E_FAIL)
1347     {
1348         ok(srcsz == 0,
1349            "Expected %u, got %u\n", 0, srcsz);
1350     }
1351
1352     ok(!memcmp(dest, invariate, sizeof(dest)),
1353        "Expected dest to be unchanged, got %s\n", dest);
1354     ok(destsz == 0, "Expected 0, got %u\n", destsz);
1355
1356     /* pcSrcSize NULL */
1357     memset(dest, 'x', sizeof(dest));
1358     destsz = sizeof(dest);
1359     hr = IMultiLanguage2_ConvertStringFromUnicode(iML2, NULL, 1252, src,
1360                                                   NULL, dest, &destsz);
1361     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1362     ok(!strncmp(dest, "abc", 3),
1363        "Expected first three chars to be \"abc\"\n");
1364     ok(!memcmp(&dest[3], invariate, sizeof(dest) - 3),
1365        "Expected rest of dest to be unchanged, got %s\n", dest);
1366     ok(destsz == lstrlenW(src),
1367        "Expected %u, got %u\n", lstrlenW(src), destsz);
1368
1369     /* both pSrcStr and pcSrcSize NULL */
1370     memset(dest, 'x', sizeof(dest));
1371     destsz = sizeof(dest);
1372     hr = IMultiLanguage2_ConvertStringFromUnicode(iML2, NULL, 1252, NULL,
1373                                                   NULL, dest, &destsz);
1374     ok(hr == S_OK || hr == E_FAIL, "Expected S_OK or E_FAIL, got %08x\n", hr);
1375     ok(!memcmp(dest, invariate, sizeof(dest)),
1376        "Expected dest to be unchanged, got %s\n", dest);
1377     ok(destsz == 0, "Expected 0, got %u\n", destsz);
1378
1379     /* pDstStr NULL */
1380     memset(dest, 'x', sizeof(dest));
1381     srcsz = lstrlenW(src) + 1;
1382     destsz = sizeof(dest);
1383     hr = IMultiLanguage2_ConvertStringFromUnicode(iML2, NULL, 1252, src,
1384                                                   &srcsz, NULL, &destsz);
1385     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1386     ok(srcsz == lstrlenW(src) + 1,
1387        "Expected %u, got %u\n", lstrlenW(src) + 1, srcsz);
1388     ok(destsz == lstrlenW(src) + 1,
1389        "Expected %u, got %u\n", lstrlenW(src) + 1, srcsz);
1390
1391     /* pcDstSize NULL */
1392     memset(dest, 'x', sizeof(dest));
1393     hr = IMultiLanguage2_ConvertStringFromUnicode(iML2, NULL, 1252, src,
1394                                                   &srcsz, dest, NULL);
1395     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1396     ok(srcsz == lstrlenW(src) + 1,
1397        "Expected %u, got %u\n", lstrlenW(src) + 1, srcsz);
1398     ok(!memcmp(dest, invariate, sizeof(dest)),
1399        "Expected dest to be unchanged, got %s\n", dest);
1400
1401     /* pcSrcSize is 0 */
1402     memset(dest, 'x', sizeof(dest));
1403     srcsz = 0;
1404     destsz = sizeof(dest);
1405     hr = IMultiLanguage2_ConvertStringFromUnicode(iML2, NULL, 1252, src,
1406                                                   &srcsz, dest, &destsz);
1407     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1408     ok(srcsz == 0, "Expected 0, got %u\n", srcsz);
1409     ok(!memcmp(dest, invariate, sizeof(dest)),
1410        "Expected dest to be unchanged, got %s\n", dest);
1411     ok(destsz == 0, "Expected 0, got %u\n", destsz);
1412
1413     /* pcSrcSize does not include NULL terminator */
1414     memset(dest, 'x', sizeof(dest));
1415     srcsz = lstrlenW(src);
1416     destsz = sizeof(dest);
1417     hr = IMultiLanguage2_ConvertStringFromUnicode(iML2, NULL, 1252, src,
1418                                                   &srcsz, dest, &destsz);
1419     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1420     ok(srcsz == lstrlenW(src),
1421        "Expected %u, got %u\n", lstrlenW(src), srcsz);
1422     ok(!strncmp(dest, "abc", 3), "Expected first three chars to be \"abc\"\n");
1423     ok(!memcmp(&dest[3], invariate, sizeof(dest) - 3),
1424        "Expected rest of dest to be unchanged, got %s\n", dest);
1425     ok(destsz == lstrlenW(src),
1426        "Expected %u, got %u\n", lstrlenW(src), destsz);
1427
1428     /* pcSrcSize includes NULL terminator */
1429     memset(dest, 'x', sizeof(dest));
1430     srcsz = lstrlenW(src) + 1;
1431     destsz = sizeof(dest);
1432     hr = IMultiLanguage2_ConvertStringFromUnicode(iML2, NULL, 1252, src,
1433                                                   &srcsz, dest, &destsz);
1434     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1435     ok(srcsz == lstrlenW(src) + 1, "Expected 3, got %u\n", srcsz);
1436     ok(!lstrcmpA(dest, "abc"), "Expected \"abc\", got \"%s\"\n", dest);
1437     ok(destsz == lstrlenW(src) + 1,
1438        "Expected %u, got %u\n", lstrlenW(src) + 1, destsz);
1439
1440     /* pcSrcSize is -1 */
1441     memset(dest, 'x', sizeof(dest));
1442     srcsz = -1;
1443     destsz = sizeof(dest);
1444     hr = IMultiLanguage2_ConvertStringFromUnicode(iML2, NULL, 1252, src,
1445                                                   &srcsz, dest, &destsz);
1446     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1447     ok(srcsz == lstrlenW(src),
1448        "Expected %u, got %u\n", lstrlenW(src), srcsz);
1449     ok(!strncmp(dest, "abc", 3), "Expected first three chars to be \"abc\"\n");
1450     ok(!memcmp(&dest[3], invariate, sizeof(dest) - 3),
1451        "Expected rest of dest to be unchanged, got %s\n", dest);
1452     ok(destsz == lstrlenW(src),
1453        "Expected %u, got %u\n", lstrlenW(src), destsz);
1454
1455     /* pcDstSize is 0 */
1456     memset(dest, 'x', sizeof(dest));
1457     srcsz = lstrlenW(src) + 1;
1458     destsz = 0;
1459     hr = IMultiLanguage2_ConvertStringFromUnicode(iML2, NULL, 1252, src,
1460                                                   &srcsz, dest, &destsz);
1461     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1462     ok(srcsz == lstrlenW(src) + 1,
1463        "Expected %u, got %u\n", lstrlenW(src) + 1, srcsz);
1464     ok(!memcmp(dest, invariate, sizeof(dest)),
1465        "Expected dest to be unchanged, got %s\n", dest);
1466     ok(destsz == lstrlenW(src) + 1,
1467        "Expected %u, got %u\n", lstrlenW(src) + 1, destsz);
1468
1469     /* pcDstSize is not large enough */
1470     memset(dest, 'x', sizeof(dest));
1471     srcsz = lstrlenW(src) + 1;
1472     destsz = lstrlenW(src);
1473     hr = IMultiLanguage2_ConvertStringFromUnicode(iML2, NULL, 1252, src,
1474                                                   &srcsz, dest, &destsz);
1475     ok(hr == E_FAIL, "Expected E_FAIL, got %08x\n", hr);
1476     ok(srcsz == 0, "Expected 0, got %u\n", srcsz);
1477     ok(!strncmp(dest, "abc", 3), "Expected first three chars to be \"abc\"\n");
1478     ok(!memcmp(&dest[3], invariate, sizeof(dest) - 3),
1479        "Expected rest of dest to be unchanged, got %s\n", dest);
1480     ok(destsz == 0, "Expected 0, got %u\n", srcsz);
1481
1482     /* pcDstSize (bytes) does not leave room for NULL terminator */
1483     memset(dest, 'x', sizeof(dest));
1484     srcsz = lstrlenW(src) + 1;
1485     destsz = lstrlenW(src) * sizeof(WCHAR);
1486     hr = IMultiLanguage2_ConvertStringFromUnicode(iML2, NULL, 1252, src,
1487                                                   &srcsz, dest, &destsz);
1488     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1489     ok(srcsz == lstrlenW(src) + 1,
1490        "Expected %u, got %u\n", lstrlenW(src) + 1, srcsz);
1491     ok(!lstrcmpA(dest, "abc"), "Expected \"abc\", got \"%s\"\n", dest);
1492     ok(destsz == lstrlenW(src) + 1,
1493        "Expected %u, got %u\n", lstrlenW(src) + 1, destsz);
1494 }
1495
1496 static void test_ConvertINetUnicodeToMultiByte(void)
1497 {
1498     CHAR dest[MAX_PATH];
1499     CHAR invariate[MAX_PATH];
1500     INT srcsz, destsz;
1501     HRESULT hr;
1502
1503     static WCHAR src[] = {'a','b','c',0};
1504
1505     memset(invariate, 'x', sizeof(invariate));
1506
1507     /* lpSrcStr NULL */
1508     memset(dest, 'x', sizeof(dest));
1509     srcsz = lstrlenW(src) + 1;
1510     destsz = sizeof(dest);
1511     hr = pConvertINetUnicodeToMultiByte(NULL, 1252, NULL, &srcsz, dest, &destsz);
1512     ok(hr == S_OK || hr == E_FAIL, "Expected S_OK or E_FAIL, got %08x\n", hr);
1513     if (hr == S_OK)
1514         ok(srcsz == lstrlenW(src) + 1,
1515            "Expected %u, got %u\n", lstrlenW(src) + 1, srcsz);
1516     else if (hr == E_FAIL)
1517         ok(srcsz == 0,
1518            "Expected %u, got %u\n", 0, srcsz);
1519     ok(!memcmp(dest, invariate, sizeof(dest)),
1520        "Expected dest to be unchanged, got %s\n", dest);
1521     ok(destsz == 0, "Expected 0, got %u\n", destsz);
1522
1523     /* lpnWideCharCount NULL */
1524     memset(dest, 'x', sizeof(dest));
1525     destsz = sizeof(dest);
1526     hr = pConvertINetUnicodeToMultiByte(NULL, 1252, src, NULL, dest, &destsz);
1527     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1528     ok(!strncmp(dest, "abc", 3),
1529        "Expected first three chars to be \"abc\"\n");
1530     ok(!memcmp(&dest[3], invariate, sizeof(dest) - 3),
1531        "Expected rest of dest to be unchanged, got %s\n", dest);
1532     ok(destsz == lstrlenW(src),
1533        "Expected %u, got %u\n", lstrlenW(src), destsz);
1534
1535     /* both lpSrcStr and lpnWideCharCount NULL */
1536     memset(dest, 'x', sizeof(dest));
1537     destsz = sizeof(dest);
1538     hr = pConvertINetUnicodeToMultiByte(NULL, 1252, NULL, NULL, dest, &destsz);
1539     ok(hr == S_OK || hr == E_FAIL, "Expected S_OK or E_FAIL, got %08x\n", hr);
1540     ok(!memcmp(dest, invariate, sizeof(dest)),
1541        "Expected dest to be unchanged, got %s\n", dest);
1542     ok(destsz == 0, "Expected 0, got %u\n", destsz);
1543
1544     /* lpDstStr NULL */
1545     memset(dest, 'x', sizeof(dest));
1546     srcsz = lstrlenW(src) + 1;
1547     destsz = sizeof(dest);
1548     hr = pConvertINetUnicodeToMultiByte(NULL, 1252, src, &srcsz, NULL, &destsz);
1549     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1550     ok(srcsz == lstrlenW(src) + 1,
1551        "Expected %u, got %u\n", lstrlenW(src) + 1, srcsz);
1552     ok(destsz == lstrlenW(src) + 1,
1553        "Expected %u, got %u\n", lstrlenW(src) + 1, srcsz);
1554
1555     /* lpnMultiCharCount NULL */
1556     memset(dest, 'x', sizeof(dest));
1557     hr = pConvertINetUnicodeToMultiByte(NULL, 1252, src, &srcsz, dest, NULL);
1558     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1559     ok(srcsz == lstrlenW(src) + 1,
1560        "Expected %u, got %u\n", lstrlenW(src) + 1, srcsz);
1561     ok(!memcmp(dest, invariate, sizeof(dest)),
1562        "Expected dest to be unchanged, got %s\n", dest);
1563
1564     /* lpnWideCharCount is 0 */
1565     memset(dest, 'x', sizeof(dest));
1566     srcsz = 0;
1567     destsz = sizeof(dest);
1568     hr = pConvertINetUnicodeToMultiByte(NULL, 1252, src, &srcsz, dest, &destsz);
1569     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1570     ok(srcsz == 0, "Expected 0, got %u\n", srcsz);
1571     ok(!memcmp(dest, invariate, sizeof(dest)),
1572        "Expected dest to be unchanged, got %s\n", dest);
1573     ok(destsz == 0, "Expected 0, got %u\n", destsz);
1574
1575     /* lpnWideCharCount does not include NULL terminator */
1576     memset(dest, 'x', sizeof(dest));
1577     srcsz = lstrlenW(src);
1578     destsz = sizeof(dest);
1579     hr = pConvertINetUnicodeToMultiByte(NULL, 1252, src, &srcsz, dest, &destsz);
1580     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1581     ok(srcsz == lstrlenW(src),
1582        "Expected %u, got %u\n", lstrlenW(src), srcsz);
1583     ok(!strncmp(dest, "abc", 3), "Expected first three chars to be \"abc\"\n");
1584     ok(!memcmp(&dest[3], invariate, sizeof(dest) - 3),
1585        "Expected rest of dest to be unchanged, got %s\n", dest);
1586     ok(destsz == lstrlenW(src),
1587        "Expected %u, got %u\n", lstrlenW(src), destsz);
1588
1589     /* lpnWideCharCount includes NULL terminator */
1590     memset(dest, 'x', sizeof(dest));
1591     srcsz = lstrlenW(src) + 1;
1592     destsz = sizeof(dest);
1593     hr = pConvertINetUnicodeToMultiByte(NULL, 1252, src, &srcsz, dest, &destsz);
1594     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1595     ok(srcsz == lstrlenW(src) + 1, "Expected 3, got %u\n", srcsz);
1596     ok(!lstrcmpA(dest, "abc"), "Expected \"abc\", got \"%s\"\n", dest);
1597     ok(destsz == lstrlenW(src) + 1,
1598        "Expected %u, got %u\n", lstrlenW(src) + 1, destsz);
1599
1600     /* lpnWideCharCount is -1 */
1601     memset(dest, 'x', sizeof(dest));
1602     srcsz = -1;
1603     destsz = sizeof(dest);
1604     hr = pConvertINetUnicodeToMultiByte(NULL, 1252, src, &srcsz, dest, &destsz);
1605     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1606     ok(srcsz == lstrlenW(src),
1607        "Expected %u, got %u\n", lstrlenW(src), srcsz);
1608     ok(!strncmp(dest, "abc", 3), "Expected first three chars to be \"abc\"\n");
1609     ok(!memcmp(&dest[3], invariate, sizeof(dest) - 3),
1610        "Expected rest of dest to be unchanged, got %s\n", dest);
1611     ok(destsz == lstrlenW(src),
1612        "Expected %u, got %u\n", lstrlenW(src), destsz);
1613
1614     /* lpnMultiCharCount is 0 */
1615     memset(dest, 'x', sizeof(dest));
1616     srcsz = lstrlenW(src) + 1;
1617     destsz = 0;
1618     hr = pConvertINetUnicodeToMultiByte(NULL, 1252, src, &srcsz, dest, &destsz);
1619     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1620     ok(srcsz == lstrlenW(src) + 1,
1621        "Expected %u, got %u\n", lstrlenW(src) + 1, srcsz);
1622     ok(!memcmp(dest, invariate, sizeof(dest)),
1623        "Expected dest to be unchanged, got %s\n", dest);
1624     ok(destsz == lstrlenW(src) + 1,
1625        "Expected %u, got %u\n", lstrlenW(src) + 1, destsz);
1626
1627     /* lpnMultiCharCount is not large enough */
1628     memset(dest, 'x', sizeof(dest));
1629     srcsz = lstrlenW(src) + 1;
1630     destsz = lstrlenW(src);
1631     hr = pConvertINetUnicodeToMultiByte(NULL, 1252, src, &srcsz, dest, &destsz);
1632     ok(hr == E_FAIL, "Expected E_FAIL, got %08x\n", hr);
1633     ok(srcsz == 0, "Expected 0, got %u\n", srcsz);
1634     ok(!strncmp(dest, "abc", 3), "Expected first three chars to be \"abc\"\n");
1635     ok(!memcmp(&dest[3], invariate, sizeof(dest) - 3),
1636        "Expected rest of dest to be unchanged, got %s\n", dest);
1637     ok(destsz == 0, "Expected 0, got %u\n", srcsz);
1638
1639     /* lpnMultiCharCount (bytes) does not leave room for NULL terminator */
1640     memset(dest, 'x', sizeof(dest));
1641     srcsz = lstrlenW(src) + 1;
1642     destsz = lstrlenW(src) * sizeof(WCHAR);
1643     hr = pConvertINetUnicodeToMultiByte(NULL, 1252, src, &srcsz, dest, &destsz);
1644     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1645     ok(srcsz == lstrlenW(src) + 1,
1646        "Expected %u, got %u\n", lstrlenW(src) + 1, srcsz);
1647     ok(!lstrcmpA(dest, "abc"), "Expected \"abc\", got \"%s\"\n", dest);
1648     ok(destsz == lstrlenW(src) + 1,
1649        "Expected %u, got %u\n", lstrlenW(src) + 1, destsz);
1650 }
1651
1652 static void test_JapaneseConversion(void)
1653 {
1654     /* Data */
1655     static WCHAR unc_jp[9][12] = {
1656   {9,0x31,0x20,0x3042,0x3044,0x3046,0x3048,0x304a,0x000d,0x000a},
1657   {9,0x31,0x20,0x30a2,0x30a4,0x30a6,0x30a8,0x30aa,0x000d,0x000a},
1658   {9,0x31,0x20,0xff71,0xff72,0xff73,0xff74,0xff75,0x000d,0x000a},
1659   {9,0x31,0x20,0x3041,0x3043,0x3045,0x3047,0x3049,0x000d,0x000a},
1660   {9,0x31,0x20,0x30a1,0x30a3,0x30a5,0x30a7,0x30a9,0x000d,0x000a},
1661   {9,0x31,0x20,0xff67,0xff68,0xff69,0xff6a,0xff6b,0x000d,0x000a},
1662   {9,0x31,0x20,0x300c,0x65e5,0x672c,0x8a9e,0x300d,0x000d,0x000a},
1663   {7,0x31,0x20,0x25c7,0x25c7,0x3012,0x000d,0x000a},
1664   {11,0x31,0x20,0x203b,0x3010,0x0074,0x0065,0x0073,0x0074,0x3011,0x000d,0x000a}
1665     };
1666     static CHAR jis_jp[9][27] = {
1667   {20,0x31,0x20,0x1b,0x24,0x42,0x24,0x22,0x24,0x24,0x24,0x26,0x24,0x28,
1668       0x24,0x2a,0x1b,0x28,0x42,0x0d,0x0a},
1669   {20,0x31,0x20,0x1b,0x24,0x42,0x25,0x22,0x25,0x24,0x25,0x26,0x25,0x28,
1670       0x25,0x2a,0x1b,0x28,0x42,0x0d,0x0a},
1671   {20,0x31,0x20,0x1b,0x24,0x42,0x25,0x22,0x25,0x24,0x25,0x26,0x25,0x28,
1672       0x25,0x2a,0x1b,0x28,0x42,0x0d,0x0a},
1673   {20,0x31,0x20,0x1b,0x24,0x42,0x24,0x21,0x24,0x23,0x24,0x25,0x24,0x27,
1674       0x24,0x29,0x1b,0x28,0x42,0x0d,0x0a},
1675   {20,0x31,0x20,0x1b,0x24,0x42,0x25,0x21,0x25,0x23,0x25,0x25,0x25,0x27,
1676       0x25,0x29,0x1b,0x28,0x42,0x0d,0x0a},
1677   {20,0x31,0x20,0x1b,0x24,0x42,0x25,0x21,0x25,0x23,0x25,0x25,0x25,0x27,
1678       0x25,0x29,0x1b,0x28,0x42,0x0d,0x0a},
1679   {20,0x31,0x20,0x1b,0x24,0x42,0x21,0x56,0x46,0x7c,0x4b,0x5c,0x38,0x6c,
1680       0x21,0x57,0x1b,0x28,0x42,0x0d,0x0a},
1681   {16,0x31,0x20,0x1b,0x24,0x42,0x21,0x7e,0x21,0x7e,0x22,0x29,0x1b,0x28,
1682       0x42,0x0d,0x0a},
1683   {26,0x31,0x20,0x1b,0x24,0x42,0x22,0x28,0x21,0x5a,0x1b,0x28,0x42,0x74,
1684       0x65,0x73,0x74,0x1b,0x24,0x42,0x21,0x5b,0x1b,0x28,0x42,0x0d,0x0a}
1685     };
1686     static CHAR sjis_jp[9][15] = {
1687   {14,0x31,0x20,0x82,0xa0,0x82,0xa2,0x82,0xa4,0x82,0xa6,0x82,0xa8,0x0d,0x0a},
1688   {14,0x31,0x20,0x83,0x41,0x83,0x43,0x83,0x45,0x83,0x47,0x83,0x49,0x0d,0x0a},
1689   {9,0x31,0x20,0xb1,0xb2,0xb3,0xb4,0xb5,0x0d,0x0a},
1690   {14,0x31,0x20,0x82,0x9f,0x82,0xa1,0x82,0xa3,0x82,0xa5,0x82,0xa7,0x0d,0x0a},
1691   {14,0x31,0x20,0x83,0x40,0x83,0x42,0x83,0x44,0x83,0x46,0x83,0x48,0x0d,0x0a},
1692   {9,0x31,0x20,0xa7,0xa8,0xa9,0xaa,0xab,0x0d,0x0a},
1693   {14,0x31,0x20,0x81,0x75,0x93,0xfa,0x96,0x7b,0x8c,0xea,0x81,0x76,0x0d,0x0a},
1694   {10,0x31,0x20,0x81,0x9e,0x81,0x9e,0x81,0xa7,0x0d,0x0a},
1695   {14,0x31,0x20,0x81,0xa6,0x81,0x79,0x74,0x65,0x73,0x74,0x81,0x7a,0x0d,0x0a}
1696     };
1697     static CHAR euc_jp[9][15] = {
1698   {14,0x31,0x20,0xa4,0xa2,0xa4,0xa4,0xa4,0xa6,0xa4,0xa8,0xa4,0xaa,0x0d,0x0a},
1699   {14,0x31,0x20,0xa5,0xa2,0xa5,0xa4,0xa5,0xa6,0xa5,0xa8,0xa5,0xaa,0x0d,0x0a},
1700   {14,0x31,0x20,0x8e,0xb1,0x8e,0xb2,0x8e,0xb3,0x8e,0xb4,0x8e,0xb5,0x0d,0x0a},
1701   {14,0x31,0x20,0xa4,0xa1,0xa4,0xa3,0xa4,0xa5,0xa4,0xa7,0xa4,0xa9,0x0d,0x0a},
1702   {14,0x31,0x20,0xa5,0xa1,0xa5,0xa3,0xa5,0xa5,0xa5,0xa7,0xa5,0xa9,0x0d,0x0a},
1703   {14,0x31,0x20,0x8e,0xa7,0x8e,0xa8,0x8e,0xa9,0x8e,0xaa,0x8e,0xab,0x0d,0x0a},
1704   {14,0x31,0x20,0xa1,0xd6,0xc6,0xfc,0xcb,0xdc,0xb8,0xec,0xa1,0xd7,0x0d,0x0a},
1705   {10,0x31,0x20,0xa1,0xfe,0xa1,0xfe,0xa2,0xa9,0x0d,0x0a},
1706   {14,0x31,0x20,0xa2,0xa8,0xa1,0xda,0x74,0x65,0x73,0x74,0xa1,0xdb,0x0d,0x0a}
1707     };
1708
1709     INT srcsz, destsz;
1710     INT i;
1711     HRESULT hr;
1712     CHAR output[30];
1713     WCHAR outputW[30];
1714     int outlen;
1715
1716     /* test unc->jis */
1717     for (i = 0; i < 9; i++)
1718     {
1719         int j;
1720         destsz = 30;
1721         outlen = jis_jp[i][0];
1722         srcsz = unc_jp[i][0];
1723         hr = pConvertINetUnicodeToMultiByte(NULL, 50220, &unc_jp[i][1], &srcsz, output, &destsz);
1724         if (hr == S_FALSE)
1725         {
1726             skip("Code page identifier 50220 is not supported\n");
1727             break;
1728         }
1729         ok(hr == S_OK,"(%i) Expected S_OK, got %08x\n", i, hr);
1730         ok(destsz == outlen, "(%i) Expected %i, got %i\n",i,outlen,destsz);
1731         ok(srcsz == unc_jp[i][0],"(%i) Expected %i, got %i\n",i,unc_jp[i][0],srcsz);
1732         ok(memcmp(output,&jis_jp[i][1],destsz)==0,"(%i) Strings do not match\n",i);
1733
1734         /* and back */
1735         srcsz = outlen;
1736         destsz = 30;
1737         hr = pConvertINetMultiByteToUnicode(NULL, 50220, output, &srcsz, outputW,&destsz);
1738
1739         /*
1740          * JIS does not have hankata so it get automatically converted to
1741          * zenkata. this means that strings 1 and 2 are identical as well as
1742          * strings 4 and 5.
1743          */
1744         j = i;
1745         if (i == 2) j = 1;
1746         if (i == 5) j = 4;
1747
1748         ok(hr == S_OK,"(%i) Expected S_OK, got %08x\n",i, hr);
1749         ok(destsz == unc_jp[j][0],"(%i) Expected %i, got %i\n",i,unc_jp[j][0],destsz);
1750         ok(srcsz == outlen,"(%i) Expected %i, got %i\n",i,outlen,srcsz);
1751         ok(memcmp(outputW,&unc_jp[j][1],destsz)==0,"(%i) Strings do not match\n",i);
1752     }
1753
1754     /* test unc->sjis */
1755     for (i = 0; i < 9; i++)
1756     {
1757         destsz = 30;
1758         outlen = sjis_jp[i][0];
1759         srcsz = unc_jp[i][0];
1760
1761         hr = pConvertINetUnicodeToMultiByte(NULL, 932, &unc_jp[i][1], &srcsz, output, &destsz);
1762         if (hr == S_FALSE)
1763         {
1764             skip("Code page identifier 932 is not supported\n");
1765             break;
1766         }
1767         ok(hr == S_OK,"(%i) Expected S_OK, got %08x\n",i,hr);
1768         ok(destsz == outlen,"(%i) Expected %i, got %i\n",i,outlen,destsz);
1769         ok(srcsz == unc_jp[i][0],"(%i) Expected %i, got %i\n",i,unc_jp[i][0],srcsz);
1770         ok(memcmp(output,&sjis_jp[i][1],outlen)==0,"(%i) Strings do not match\n",i);
1771
1772         srcsz = outlen;
1773         destsz = 30;
1774         hr = pConvertINetMultiByteToUnicode(NULL, 932, output, &srcsz, outputW,&destsz);
1775
1776         ok(hr == S_OK,"(%i) Expected S_OK, got %08x\n", i, hr);
1777         ok(destsz == unc_jp[i][0],"(%i) Expected %i, got %i\n",i,unc_jp[i][0],destsz);
1778         ok(srcsz == outlen,"(%i) Expected %i, got %i\n",i,outlen,srcsz);
1779         ok(memcmp(outputW,&unc_jp[i][1],destsz)==0,"(%i) Strings do not match\n",i);
1780     }
1781
1782     /* test unc->euc */
1783     for (i = 0; i < 9; i++)
1784     {
1785         destsz = 30;
1786         outlen = euc_jp[i][0];
1787         srcsz = unc_jp[i][0];
1788
1789         hr = pConvertINetUnicodeToMultiByte(NULL, 51932, &unc_jp[i][1], &srcsz, output, &destsz);
1790         if (hr == S_FALSE)
1791         {
1792             skip("Code page identifier 51932 is not supported\n");
1793             break;
1794         }
1795         ok(hr == S_OK, "(%i) Expected S_OK, got %08x\n",i,hr);
1796         ok(destsz == outlen, "(%i) Expected %i, got %i\n",i,outlen,destsz);
1797         ok(srcsz == unc_jp[i][0],"(%i) Expected %i, got %i\n",i,unc_jp[i][0],destsz);
1798         ok(memcmp(output,&euc_jp[i][1],outlen)==0,"(%i) Strings do not match\n",i);
1799
1800         srcsz = outlen;
1801         destsz = 30;
1802         hr = pConvertINetMultiByteToUnicode(NULL, 51932, output, &srcsz, outputW,&destsz);
1803
1804         ok(hr == S_OK,"(%i) Expected S_OK, got %08x\n",i,hr);
1805         ok(destsz == unc_jp[i][0],"(%i) Expected %i, got %i\n",i,unc_jp[i][0],destsz);
1806         ok(srcsz == outlen,"(%i) Expected %i, got %i\n",i,outlen,srcsz);
1807         ok(memcmp(outputW,&unc_jp[i][1],destsz)==0,"(%i) Strings do not match\n",i);
1808     }
1809
1810     /* Japanese autodetect */
1811     i = 0;
1812     destsz = 30;
1813     srcsz = jis_jp[i][0];
1814     hr = pConvertINetMultiByteToUnicode(NULL, 50932, &jis_jp[i][1], &srcsz, outputW, &destsz);
1815     if (hr == S_FALSE)
1816     {
1817         skip("Code page identifier 50932 is not supported\n");
1818         return;
1819     }
1820     ok(hr == S_OK,"(%i) Expected S_OK, got %08x\n",i,hr);
1821     ok(destsz == unc_jp[i][0],"(%i) Expected %i, got %i\n",i,unc_jp[i][0],destsz);
1822     ok(srcsz == jis_jp[i][0],"(%i) Expected %i, got %i\n",i,jis_jp[i][0],srcsz);
1823     ok(memcmp(outputW,&unc_jp[i][1],destsz)==0,"(%i) Strings do not match\n",i);
1824
1825     i = 1;
1826     destsz = 30;
1827     srcsz = sjis_jp[i][0];
1828     hr = pConvertINetMultiByteToUnicode(NULL, 50932, &sjis_jp[i][1], &srcsz, outputW, &destsz);
1829     ok(hr == S_OK,"(%i) Expected S_OK, got %08x\n",i,hr);
1830     ok(destsz == unc_jp[i][0],"(%i) Expected %i, got %i\n",i,unc_jp[i][0],destsz);
1831     ok(srcsz == sjis_jp[i][0],"(%i) Expected %i, got %i\n",i,sjis_jp[i][0],srcsz);
1832     ok(memcmp(outputW,&unc_jp[i][1],destsz)==0,"(%i) Strings do not match\n",i);
1833 }
1834
1835 static void test_GetScriptFontInfo(IMLangFontLink2 *font_link)
1836 {
1837     HRESULT hr;
1838     UINT nfonts;
1839     SCRIPTFONTINFO sfi[1];
1840
1841     nfonts = 0;
1842     hr = IMLangFontLink2_GetScriptFontInfo(font_link, sidLatin, 0, &nfonts, NULL);
1843     ok(hr == S_OK, "GetScriptFontInfo failed %u\n", GetLastError());
1844     ok(nfonts, "unexpected result\n");
1845
1846     nfonts = 0;
1847     hr = IMLangFontLink2_GetScriptFontInfo(font_link, sidLatin, SCRIPTCONTF_FIXED_FONT, &nfonts, NULL);
1848     ok(hr == S_OK, "GetScriptFontInfo failed %u\n", GetLastError());
1849     ok(nfonts, "unexpected result\n");
1850
1851     nfonts = 0;
1852     hr = IMLangFontLink2_GetScriptFontInfo(font_link, sidLatin, SCRIPTCONTF_PROPORTIONAL_FONT, &nfonts, NULL);
1853     ok(hr == S_OK, "GetScriptFontInfo failed %u\n", GetLastError());
1854     ok(nfonts, "unexpected result\n");
1855
1856     nfonts = 1;
1857     memset(sfi, 0, sizeof(sfi));
1858     hr = IMLangFontLink2_GetScriptFontInfo(font_link, sidLatin, SCRIPTCONTF_FIXED_FONT, &nfonts, sfi);
1859     ok(hr == S_OK, "GetScriptFontInfo failed %u\n", GetLastError());
1860     ok(nfonts == 1, "got %u, expected 1\n", nfonts);
1861     ok(sfi[0].scripts != 0, "unexpected result\n");
1862     ok(sfi[0].wszFont[0], "unexpected result\n");
1863
1864     nfonts = 1;
1865     memset(sfi, 0, sizeof(sfi));
1866     hr = IMLangFontLink2_GetScriptFontInfo(font_link, sidLatin, SCRIPTCONTF_PROPORTIONAL_FONT, &nfonts, sfi);
1867     ok(hr == S_OK, "GetScriptFontInfo failed %u\n", GetLastError());
1868     ok(nfonts == 1, "got %u, expected 1\n", nfonts);
1869     ok(sfi[0].scripts != 0, "unexpected result\n");
1870     ok(sfi[0].wszFont[0], "unexpected result\n");
1871 }
1872
1873 START_TEST(mlang)
1874 {
1875     IMultiLanguage  *iML = NULL;
1876     IMultiLanguage2 *iML2 = NULL;
1877     IMLangFontLink  *iMLFL = NULL;
1878     IMLangFontLink2 *iMLFL2 = NULL;
1879     HRESULT ret;
1880
1881     if (!init_function_ptrs())
1882         return;
1883
1884     CoInitialize(NULL);
1885     test_Rfc1766ToLcid();
1886     test_LcidToRfc1766();
1887
1888     test_ConvertINetUnicodeToMultiByte();
1889     test_JapaneseConversion();
1890
1891
1892     trace("IMultiLanguage\n");
1893     ret = CoCreateInstance(&CLSID_CMultiLanguage, NULL, CLSCTX_INPROC_SERVER,
1894                            &IID_IMultiLanguage, (void **)&iML);
1895     if (ret != S_OK || !iML) return;
1896
1897     test_GetNumberOfCodePageInfo((IMultiLanguage2 *)iML);
1898     IMultiLanguage_Release(iML);
1899
1900
1901     /* IMultiLanguage2 (IE5.0 and above) */
1902     trace("IMultiLanguage2\n");
1903     ret = CoCreateInstance(&CLSID_CMultiLanguage, NULL, CLSCTX_INPROC_SERVER,
1904                            &IID_IMultiLanguage2, (void **)&iML2);
1905     if (ret != S_OK || !iML2) return;
1906
1907     test_rfc1766(iML2);
1908     test_GetLcidFromRfc1766(iML2);
1909     test_GetRfc1766FromLcid(iML2);
1910     test_GetRfc1766Info(iML2);
1911     test_GetNumberOfCodePageInfo(iML2);
1912
1913     test_EnumCodePages(iML2, 0);
1914     test_EnumCodePages(iML2, MIMECONTF_MIME_LATEST);
1915     test_EnumCodePages(iML2, MIMECONTF_BROWSER);
1916     test_EnumCodePages(iML2, MIMECONTF_MINIMAL);
1917     test_EnumCodePages(iML2, MIMECONTF_VALID);
1918     /* FIXME: why MIMECONTF_MIME_REGISTRY returns 0 of supported codepages? */
1919     /*test_EnumCodePages(iML2, MIMECONTF_MIME_REGISTRY);*/
1920
1921     test_EnumScripts(iML2, 0);
1922     test_EnumScripts(iML2, SCRIPTCONTF_SCRIPT_USER);
1923     test_EnumScripts(iML2, SCRIPTCONTF_SCRIPT_USER | SCRIPTCONTF_SCRIPT_HIDE | SCRIPTCONTF_SCRIPT_SYSTEM);
1924
1925     ret = IMultiLanguage2_IsConvertible(iML2, CP_UTF8, CP_UNICODE);
1926     ok(ret == S_OK, "IMultiLanguage2_IsConvertible(CP_UTF8 -> CP_UNICODE) = %08x\n", ret);
1927     ret = IMultiLanguage2_IsConvertible(iML2, CP_UNICODE, CP_UTF8);
1928     ok(ret == S_OK, "IMultiLanguage2_IsConvertible(CP_UNICODE -> CP_UTF8) = %08x\n", ret);
1929
1930     test_multibyte_to_unicode_translations(iML2);
1931     test_IMultiLanguage2_ConvertStringFromUnicode(iML2);
1932
1933     IMultiLanguage2_Release(iML2);
1934
1935
1936     /* IMLangFontLink */
1937     ret = CoCreateInstance(&CLSID_CMultiLanguage, NULL, CLSCTX_INPROC_SERVER,
1938                            &IID_IMLangFontLink, (void **)&iMLFL);
1939     if (ret != S_OK || !iMLFL) return;
1940
1941     IMLangFontLink_Test(iMLFL);
1942     IMLangFontLink_Release(iMLFL);
1943
1944     /* IMLangFontLink2 */
1945     ret = CoCreateInstance(&CLSID_CMultiLanguage, NULL, CLSCTX_INPROC_SERVER,
1946                            &IID_IMLangFontLink2, (void **)&iMLFL2);
1947     if (ret != S_OK || !iMLFL2) return;
1948
1949     test_GetScriptFontInfo(iMLFL2);
1950     IMLangFontLink2_Release(iMLFL2);
1951
1952     CoUninitialize();
1953 }