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 /* #define DUMP_CP_INFO */ 40 /* #define DUMP_SCRIPT_INFO */ 41 42 static BOOL (WINAPI *pGetCPInfoExA)(UINT, DWORD, LPCPINFOEXA); 43 static HRESULT (WINAPI *pConvertINetMultiByteToUnicode)(LPDWORD, DWORD, LPCSTR, 44 LPINT, LPWSTR, LPINT); 45 static HRESULT (WINAPI *pConvertINetUnicodeToMultiByte)(LPDWORD, DWORD, LPCWSTR, 46 LPINT, LPSTR, LPINT); 47 static HRESULT (WINAPI *pRfc1766ToLcidA)(LCID *, LPCSTR); 48 static HRESULT (WINAPI *pLcidToRfc1766A)(LCID, LPSTR, INT); 49 50 typedef struct lcid_tag_table { 51 LPCSTR rfc1766; 52 LCID lcid; 53 HRESULT hr; 54 LCID broken_lcid; 55 LPCSTR broken_rfc; 56 } lcid_table_entry; 57 58 /* en, ar and zh use SUBLANG_NEUTRAL for the rfc1766 name without the country 59 all others suppress the country with SUBLANG_DEFAULT. 60 For 3 letter language codes, the rfc1766 is too small for the country */ 61 62 static const lcid_table_entry lcid_table[] = { 63 {"e", -1, E_FAIL}, 64 {"", -1, E_FAIL}, 65 {"-", -1, E_FAIL}, 66 {"e-", -1, E_FAIL}, 67 68 {"ar", 1, S_OK}, 69 {"zh", 4, S_OK}, 70 71 {"de", 0x0407, S_OK}, 72 {"de-ch", 0x0807, S_OK}, 73 {"de-at", 0x0c07, S_OK}, 74 {"de-lu", 0x1007, S_OK}, 75 {"de-li", 0x1407, S_OK}, 76 77 {"en", 9, S_OK}, 78 {"en-gb", 0x809, S_OK}, 79 {"en-GB", 0x809, S_OK}, 80 {"EN-GB", 0x809, S_OK}, 81 {"en-US", 0x409, S_OK}, 82 {"en-us", 0x409, S_OK}, 83 84 {"fr", 0x040c, S_OK}, 85 {"fr-be", 0x080c, S_OK}, 86 {"fr-ca", 0x0c0c, S_OK}, 87 {"fr-ch", 0x100c, S_OK}, 88 {"fr-lu", 0x140c, S_OK}, 89 {"fr-mc", 0x180c, S_OK, 0x040c, "fr"}, 90 91 {"it", 0x0410, S_OK}, 92 {"it-ch", 0x0810, S_OK}, 93 94 {"nl", 0x0413, S_OK}, 95 {"nl-be", 0x0813, S_OK}, 96 {"pl", 0x0415, S_OK}, 97 {"ru", 0x0419, S_OK}, 98 99 {"kok", 0x0457, S_OK, 0x0412, "x-kok"} 100 101 }; 102 103 #define TODO_NAME 1 104 105 typedef struct info_table_tag { 106 LCID lcid; 107 LANGID lang; 108 DWORD todo; 109 LPCSTR rfc1766; 110 LPCWSTR localename; 111 LPCWSTR broken_name; 112 } info_table_entry; 113 114 static const WCHAR de_en[] = {'E','n','g','l','i','s','c','h',0}; 115 static const WCHAR de_enca[] = {'E','n','g','l','i','s','c','h',' ', 116 '(','K','a','n','a','d','a',')',0}; 117 static const WCHAR de_engb[] = {'E','n','g','l','i','s','c','h',' ', 118 '(','G','r','o',0xDF,'b','r','i','t','a','n','n','i','e','n',')',0}; 119 static const WCHAR de_engb2[] ={'E','n','g','l','i','s','c','h',' ', 120 '(','V','e','r','e','i','n','i','g','t','e','s',' ', 121 'K',0xF6,'n','i','g','r','e','i','c',0}; 122 static const WCHAR de_enus[] = {'E','n','g','l','i','s','c','h',' ', 123 '(','U','S','A',')',0}; 124 static const WCHAR de_enus2[] ={'E','n','g','l','i','s','c','h',' ', 125 '(','V','e','r','e','i','n','i','g','t','e',' ', 126 'S','t','a','a','t','e','n',')',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, de_enus2}, 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, de_enus2}, 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 struct cpinfo_test_data 230 { 231 MIMECPINFO cpinfo; 232 233 BOOL todo_GetCodePageInfo; 234 BOOL todo_dwFlags; 235 BOOL todo_uiFamilyCodePage; 236 BOOL todo_wszDescription; 237 BOOL todo_wszWebCharset; 238 BOOL todo_wszHeaderCharset; 239 BOOL todo_wszBodyCharset; 240 BOOL todo_wszFixedWidthFont; 241 BOOL todo_wszProportionalFont; 242 }; 243 244 static const struct cpinfo_test_data iml2_cpinfo_data[] = 245 { 246 /* 0. Chinese Simplified (Auto-Select) */ 247 { 248 { 249 MIMECONTF_IMPORT | MIMECONTF_VALID | MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST, 250 50936, 936, {'C','h','i','n','e','s','e',' ','S','i','m','p','l','i','f','i','e','d',' ','(','A','u','t','o','-','S','e','l','e','c','t',')',0}, 251 {'_','a','u','t','o','d','e','t','e','c','t','_','c','h','s',0}, 252 {'_','a','u','t','o','d','e','t','e','c','t','_','c','h','s',0}, 253 {'_','a','u','t','o','d','e','t','e','c','t','_','c','h','s',0}, 254 {'S','i','m','s','u','n',0}, 255 {'S','i','m','s','u','n',0}, 134 256 }, 257 }, 258 /* 1. Chinese Simplified (GB2312) */ 259 { 260 { 261 MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_MINIMAL | MIMECONTF_IMPORT | 262 MIMECONTF_SAVABLE_MAILNEWS | MIMECONTF_SAVABLE_BROWSER | MIMECONTF_EXPORT | MIMECONTF_VALID | 263 MIMECONTF_VALID_NLS | MIMECONTF_MIME_IE4 | MIMECONTF_MIME_LATEST, 264 936, 936, {'C','h','i','n','e','s','e',' ','S','i','m','p','l','i','f','i','e','d',' ','(','G','B','2','3','1','2',')',0}, 265 {'g','b','2','3','1','2',0}, 266 {'g','b','2','3','1','2',0}, 267 {'g','b','2','3','1','2',0}, 268 {'S','i','m','s','u','n',0}, 269 {'S','i','m','s','u','n',0}, 134 270 }, 271 }, 272 /* 2. Chinese Simplified (GB2312-80) */ 273 { 274 { 275 MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID | MIMECONTF_VALID_NLS | 276 MIMECONTF_MIME_LATEST, 277 20936, 936, {'C','h','i','n','e','s','e',' ','S','i','m','p','l','i','f','i','e','d',' ','(','G','B','2','3','1','2','-','8','0',')',0}, 278 {'x','-','c','p','2','0','9','3','6',0}, 279 {'x','-','c','p','2','0','9','3','6',0}, 280 {'x','-','c','p','2','0','9','3','6',0}, 281 {'S','i','m','s','u','n',0}, 282 {'S','i','m','s','u','n',0}, 134 283 }, 284 }, 285 /* 3. Chinese Simplified (HZ) */ 286 { 287 { 288 MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_IMPORT | MIMECONTF_SAVABLE_MAILNEWS | 289 MIMECONTF_SAVABLE_BROWSER | MIMECONTF_EXPORT | MIMECONTF_VALID | MIMECONTF_VALID_NLS | 290 MIMECONTF_MIME_IE4 | MIMECONTF_MIME_LATEST, 291 52936, 936, {'C','h','i','n','e','s','e',' ','S','i','m','p','l','i','f','i','e','d',' ','(','H','Z',')',0}, 292 {'h','z','-','g','b','-','2','3','1','2',0}, 293 {'h','z','-','g','b','-','2','3','1','2',0}, 294 {'h','z','-','g','b','-','2','3','1','2',0}, 295 {'S','i','m','s','u','n',0}, 296 {'S','i','m','s','u','n',0}, 134 297 }, 298 }, 299 /* 4. Chinese Simplified (GB18030) */ 300 { 301 { 302 MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_MINIMAL | MIMECONTF_IMPORT | 303 MIMECONTF_SAVABLE_MAILNEWS | MIMECONTF_SAVABLE_BROWSER | MIMECONTF_EXPORT | MIMECONTF_VALID | 304 MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST, 305 54936, 936, {'C','h','i','n','e','s','e',' ','S','i','m','p','l','i','f','i','e','d',' ','(','G','B','1','8','0','3','0',')',0}, 306 {'G','B','1','8','0','3','0',0}, 307 {'G','B','1','8','0','3','0',0}, 308 {'G','B','1','8','0','3','0',0}, 309 {'S','i','m','s','u','n',0}, 310 {'S','i','m','s','u','n',0}, 134 311 }, 312 }, 313 /* 5. Chinese Traditional (Auto-Select) */ 314 { 315 { 316 MIMECONTF_IMPORT | MIMECONTF_VALID | MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST, 317 50950, 950, {'C','h','i','n','e','s','e',' ','T','r','a','d','i','t','i','o','n','a','l',' ','(','A','u','t','o','-','S','e','l','e','c','t',')',0}, 318 {'_','a','u','t','o','d','e','t','e','c','t','_','c','h','t',0}, 319 {'_','a','u','t','o','d','e','t','e','c','t','_','c','h','t',0}, 320 {'_','a','u','t','o','d','e','t','e','c','t','_','c','h','t',0}, 321 {'M','i','n','g','L','i','u',0}, 322 {'N','e','w',' ','M','i','n','g','L','i','u',0}, 136 323 }, 324 }, 325 /* 6. Chinese Traditional (Big5) */ 326 { 327 { 328 MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_MINIMAL | MIMECONTF_IMPORT | 329 MIMECONTF_SAVABLE_MAILNEWS | MIMECONTF_SAVABLE_BROWSER | MIMECONTF_EXPORT | MIMECONTF_VALID | 330 MIMECONTF_VALID_NLS | MIMECONTF_MIME_IE4 | MIMECONTF_MIME_LATEST, 331 950, 950, {'C','h','i','n','e','s','e',' ','T','r','a','d','i','t','i','o','n','a','l',' ','(','B','i','g','5',')',0}, 332 {'b','i','g','5',0}, 333 {'b','i','g','5',0}, 334 {'b','i','g','5',0}, 335 {'M','i','n','g','L','i','u',0}, 336 {'N','e','w',' ','M','i','n','g','L','i','u',0}, 136 337 }, 338 }, 339 /* 7. Chinese Traditional (CNS) */ 340 { 341 { 342 MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID | MIMECONTF_VALID_NLS | 343 MIMECONTF_MIME_LATEST, 344 20000, 950, {'C','h','i','n','e','s','e',' ','T','r','a','d','i','t','i','o','n','a','l',' ','(','C','N','S',')',0}, 345 {'x','-','C','h','i','n','e','s','e','-','C','N','S',0}, 346 {'x','-','C','h','i','n','e','s','e','-','C','N','S',0}, 347 {'x','-','C','h','i','n','e','s','e','-','C','N','S',0}, 348 {'M','i','n','g','L','i','u',0}, 349 {'N','e','w',' ','M','i','n','g','L','i','u',0}, 136 350 }, 351 }, 352 /* 8. Arabic (Windows) */ 353 { 354 { 355 MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_IMPORT | MIMECONTF_SAVABLE_MAILNEWS | 356 MIMECONTF_SAVABLE_BROWSER | MIMECONTF_EXPORT | MIMECONTF_VALID | MIMECONTF_VALID_NLS | 357 MIMECONTF_MIME_LATEST, 358 1256, 1256, {'A','r','a','b','i','c',' ','(','W','i','n','d','o','w','s',')',0}, 359 {'w','i','n','d','o','w','s','-','1','2','5','6',0}, 360 {'w','i','n','d','o','w','s','-','1','2','5','6',0}, 361 {'w','i','n','d','o','w','s','-','1','2','5','6',0}, 362 {'S','i','m','p','l','i','f','i','e','d',' ','A','r','a','b','i','c',' ','F','i','x','e','d',0}, 363 {'S','i','m','p','l','i','f','i','e','d',' ','A','r','a','b','i','c',0}, 178 364 }, 365 }, 366 /* 9. Baltic (Windows) */ 367 { 368 { 369 MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_MINIMAL | MIMECONTF_IMPORT | 370 MIMECONTF_SAVABLE_MAILNEWS | MIMECONTF_SAVABLE_BROWSER | MIMECONTF_EXPORT | MIMECONTF_VALID | 371 MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST, 372 1257, 1257, {'B','a','l','t','i','c',' ','(','W','i','n','d','o','w','s',')',0}, 373 {'w','i','n','d','o','w','s','-','1','2','5','7',0}, 374 {'w','i','n','d','o','w','s','-','1','2','5','7',0}, 375 {'w','i','n','d','o','w','s','-','1','2','5','7',0}, 376 {'C','o','u','r','i','e','r',' ','N','e','w',0}, 377 {'A','r','i','a','l',0}, 186 378 }, 379 }, 380 /* 10. Central European (Windows) */ 381 { 382 { 383 MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_IMPORT | MIMECONTF_SAVABLE_MAILNEWS | 384 MIMECONTF_SAVABLE_BROWSER | MIMECONTF_EXPORT | MIMECONTF_VALID | MIMECONTF_VALID_NLS | 385 MIMECONTF_MIME_LATEST, 386 1250, 1250, {'C','e','n','t','r','a','l',' ','E','u','r','o','p','e','a','n',' ','(','W','i','n','d','o','w','s',')',0}, 387 {'w','i','n','d','o','w','s','-','1','2','5','0',0}, 388 {'w','i','n','d','o','w','s','-','1','2','5','0',0}, 389 {'i','s','o','-','8','8','5','9','-','2',0}, 390 {'C','o','u','r','i','e','r',' ','N','e','w',0}, 391 {'A','r','i','a','l',0}, 238 392 }, 393 FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE 394 }, 395 /* 11. Cyrillic (Windows) */ 396 { 397 { 398 MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_IMPORT | MIMECONTF_SAVABLE_MAILNEWS | 399 MIMECONTF_SAVABLE_BROWSER | MIMECONTF_EXPORT | MIMECONTF_VALID | MIMECONTF_VALID_NLS | 400 MIMECONTF_MIME_LATEST, 401 1251, 1251, {'C','y','r','i','l','l','i','c',' ','(','W','i','n','d','o','w','s',')',0}, 402 {'w','i','n','d','o','w','s','-','1','2','5','1',0}, 403 {'w','i','n','d','o','w','s','-','1','2','5','1',0}, 404 {'k','o','i','8','-','r',0}, 405 {'C','o','u','r','i','e','r',' ','N','e','w',0}, 406 {'A','r','i','a','l',0}, 204 407 }, 408 FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE 409 }, 410 /* 12. Greek (Windows) */ 411 { 412 { 413 MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_IMPORT | MIMECONTF_SAVABLE_MAILNEWS | 414 MIMECONTF_SAVABLE_BROWSER | MIMECONTF_EXPORT | MIMECONTF_VALID | MIMECONTF_VALID_NLS | 415 MIMECONTF_MIME_LATEST, 416 1253, 1253, {'G','r','e','e','k',' ','(','W','i','n','d','o','w','s',')',0}, 417 {'w','i','n','d','o','w','s','-','1','2','5','3',0}, 418 {'w','i','n','d','o','w','s','-','1','2','5','3',0}, 419 {'i','s','o','-','8','8','5','9','-','7',0}, 420 {'C','o','u','r','i','e','r',' ','N','e','w',0}, 421 {'A','r','i','a','l',0}, 161 422 }, 423 FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE 424 }, 425 /* 13. Hebrew (Windows) */ 426 { 427 { 428 MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_IMPORT | MIMECONTF_SAVABLE_MAILNEWS | 429 MIMECONTF_SAVABLE_BROWSER | MIMECONTF_EXPORT | MIMECONTF_VALID | MIMECONTF_VALID_NLS | 430 MIMECONTF_MIME_LATEST, 431 1255, 1255, {'H','e','b','r','e','w',' ','(','W','i','n','d','o','w','s',')',0}, 432 {'w','i','n','d','o','w','s','-','1','2','5','5',0}, 433 {'w','i','n','d','o','w','s','-','1','2','5','5',0}, 434 {'w','i','n','d','o','w','s','-','1','2','5','5',0}, 435 {'M','i','r','i','a','m',' ','F','i','x','e','d',0}, 436 {'D','a','v','i','d',0}, 177 437 }, 438 }, 439 /* 14. Japanese (Shift-JIS) */ 440 { 441 { 442 MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_MINIMAL | MIMECONTF_IMPORT | 443 MIMECONTF_SAVABLE_MAILNEWS | MIMECONTF_SAVABLE_BROWSER | MIMECONTF_EXPORT | MIMECONTF_VALID | 444 MIMECONTF_VALID_NLS | MIMECONTF_MIME_IE4 | MIMECONTF_MIME_LATEST, 445 932, 932, {'J','a','p','a','n','e','s','e',' ','(','S','h','i','f','t','-','J','I','S',')',0}, 446 {'s','h','i','f','t','_','j','i','s',0}, 447 {'i','s','o','-','2','0','2','2','-','j','p',0}, 448 {'i','s','o','-','2','0','2','2','-','j','p',0}, 449 {'M','S',' ','G','o','t','h','i','c',0}, 450 {'M','S',' ','P','G','o','t','h','i','c',0}, 128 451 } 452 }, 453 /* 15. Korean */ 454 { 455 { 456 MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_MINIMAL | MIMECONTF_IMPORT | 457 MIMECONTF_SAVABLE_MAILNEWS | MIMECONTF_SAVABLE_BROWSER | MIMECONTF_EXPORT | MIMECONTF_VALID | 458 MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST, 459 949, 949, {'K','o','r','e','a','n',0}, 460 {'k','s','_','c','_','5','6','0','1','-','1','9','8','7',0}, 461 {'k','s','_','c','_','5','6','0','1','-','1','9','8','7',0}, 462 {'k','s','_','c','_','5','6','0','1','-','1','9','8','7',0}, 463 {'G','u','l','i','m','C','h','e',0}, 464 {'G','u','l','i','m',0}, 129 465 }, 466 }, 467 /* 16. Thai (Windows) */ 468 { 469 { 470 MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_MINIMAL | MIMECONTF_IMPORT | 471 MIMECONTF_SAVABLE_MAILNEWS | MIMECONTF_SAVABLE_BROWSER | MIMECONTF_EXPORT | MIMECONTF_VALID | 472 MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST, 473 874, 874, {'T','h','a','i',' ','(','W','i','n','d','o','w','s',')',0}, 474 {'w','i','n','d','o','w','s','-','8','7','4',0}, 475 {'w','i','n','d','o','w','s','-','8','7','4',0}, 476 {'w','i','n','d','o','w','s','-','8','7','4',0}, 477 {'T','a','h','o','m','a',0}, 478 {'T','a','h','o','m','a',0}, 222 479 }, 480 FALSE, TRUE, FALSE, FALSE, TRUE, TRUE, TRUE 481 }, 482 /* 17. Turkish (Windows) */ 483 { 484 { 485 MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_MINIMAL | MIMECONTF_IMPORT | 486 MIMECONTF_SAVABLE_MAILNEWS | MIMECONTF_SAVABLE_BROWSER | MIMECONTF_EXPORT | MIMECONTF_VALID | 487 MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST, 488 1254, 1254, {'T','u','r','k','i','s','h',' ','(','W','i','n','d','o','w','s',')',0}, 489 {'w','i','n','d','o','w','s','-','1','2','5','4',0}, 490 {'w','i','n','d','o','w','s','-','1','2','5','4',0}, 491 {'i','s','o','-','8','8','5','9','-','9',0}, 492 {'C','o','u','r','i','e','r',' ','N','e','w',0}, 493 {'A','r','i','a','l',0}, 162 494 }, 495 FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE 496 }, 497 /* 18. Vietnamese (Windows) */ 498 { 499 { 500 MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_IMPORT | MIMECONTF_SAVABLE_MAILNEWS | 501 MIMECONTF_SAVABLE_BROWSER | MIMECONTF_EXPORT | MIMECONTF_VALID | MIMECONTF_VALID_NLS | 502 MIMECONTF_MIME_IE4 | MIMECONTF_MIME_LATEST, 503 1258, 1258, {'V','i','e','t','n','a','m','e','s','e',' ','(','W','i','n','d','o','w','s',')',0}, 504 {'w','i','n','d','o','w','s','-','1','2','5','8',0}, 505 {'w','i','n','d','o','w','s','-','1','2','5','8',0}, 506 {'w','i','n','d','o','w','s','-','1','2','5','8',0}, 507 {'C','o','u','r','i','e','r',' ','N','e','w',0}, 508 {'A','r','i','a','l',0}, 163 509 }, 510 }, 511 /* 19. Western European (Windows) */ 512 { 513 { 514 MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_MINIMAL | MIMECONTF_IMPORT | 515 MIMECONTF_SAVABLE_MAILNEWS | MIMECONTF_SAVABLE_BROWSER | MIMECONTF_EXPORT | MIMECONTF_VALID | 516 MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST, 517 1252, 1252, {'W','e','s','t','e','r','n',' ','E','u','r','o','p','e','a','n',' ','(','W','i','n','d','o','w','s',')',0}, 518 {'W','i','n','d','o','w','s','-','1','2','5','2',0}, 519 {'W','i','n','d','o','w','s','-','1','2','5','2',0}, 520 {'i','s','o','-','8','8','5','9','-','1',0}, 521 {'C','o','u','r','i','e','r',' ','N','e','w',0}, 522 {'A','r','i','a','l',0}, 0 523 }, 524 FALSE, FALSE, FALSE, FALSE, TRUE, TRUE 525 }, 526 /* 20. Unicode */ 527 { 528 { 529 MIMECONTF_MINIMAL | MIMECONTF_IMPORT | MIMECONTF_SAVABLE_BROWSER | MIMECONTF_EXPORT | 530 MIMECONTF_VALID | MIMECONTF_VALID_NLS | MIMECONTF_MIME_IE4 | MIMECONTF_MIME_LATEST, 531 1200, 1200, {'U','n','i','c','o','d','e',0}, 532 {'u','n','i','c','o','d','e',0}, 533 {'u','n','i','c','o','d','e',0}, 534 {'u','n','i','c','o','d','e',0}, 535 {'C','o','u','r','i','e','r',' ','N','e','w',0}, 536 {'A','r','i','a','l',0}, 1 537 }, 538 } 539 }; 540 541 static BOOL init_function_ptrs(void) 542 { 543 HMODULE hMlang; 544 545 hMlang = GetModuleHandleA("mlang.dll"); 546 pConvertINetMultiByteToUnicode = (void *)GetProcAddress(hMlang, "ConvertINetMultiByteToUnicode"); 547 pConvertINetUnicodeToMultiByte = (void *)GetProcAddress(hMlang, "ConvertINetUnicodeToMultiByte"); 548 pRfc1766ToLcidA = (void *)GetProcAddress(hMlang, "Rfc1766ToLcidA"); 549 pLcidToRfc1766A = (void *)GetProcAddress(hMlang, "LcidToRfc1766A"); 550 551 pGetCPInfoExA = (void *)GetProcAddress(GetModuleHandleA("kernel32.dll"), "GetCPInfoExA"); 552 553 return TRUE; 554 } 555 556 #define ok_w2(format, szString1, szString2) \ 557 \ 558 if (lstrcmpW((szString1), (szString2)) != 0) \ 559 { \ 560 CHAR string1[256], string2[256]; \ 561 WideCharToMultiByte(CP_ACP, 0, (szString1), -1, string1, 256, NULL, NULL); \ 562 WideCharToMultiByte(CP_ACP, 0, (szString2), -1, string2, 256, NULL, NULL); \ 563 ok(0, (format), string1, string2); \ 564 } 565 566 static void test_multibyte_to_unicode_translations(IMultiLanguage2 *iML2) 567 { 568 /* these APIs are broken regarding constness of the input buffer */ 569 char stringA[] = "Just a test string\0"; /* double 0 for CP_UNICODE tests */ 570 WCHAR stringW[] = {'J','u','s','t',' ','a',' ','t','e','s','t',' ','s','t','r','i','n','g',0}; 571 char bufA[256]; 572 WCHAR bufW[256]; 573 UINT lenA, lenW, expected_len; 574 HRESULT ret; 575 576 /* IMultiLanguage2_ConvertStringToUnicode tests */ 577 578 memset(bufW, 'x', sizeof(bufW)); 579 lenA = 0; 580 lenW = sizeof(bufW)/sizeof(bufW[0]); 581 ret = IMultiLanguage2_ConvertStringToUnicode(iML2, NULL, 1252, stringA, &lenA, bufW, &lenW); 582 ok(ret == S_OK, "IMultiLanguage2_ConvertStringToUnicode failed: %08x\n", ret); 583 ok(lenA == 0, "expected lenA 0, got %u\n", lenA); 584 ok(lenW == 0, "expected lenW 0, got %u\n", lenW); 585 586 memset(bufW, 'x', sizeof(bufW)); 587 lenA = -1; 588 lenW = sizeof(bufW)/sizeof(bufW[0]); 589 ret = IMultiLanguage2_ConvertStringToUnicode(iML2, NULL, 1252, stringA, &lenA, bufW, &lenW); 590 ok(ret == S_OK, "IMultiLanguage2_ConvertStringToUnicode failed: %08x\n", ret); 591 ok(lenA == lstrlenA(stringA), "expected lenA %u, got %u\n", lstrlenA(stringA), lenA); 592 ok(lenW == lstrlenW(stringW), "expected lenW %u, got %u\n", lstrlenW(stringW), lenW); 593 if (lenW < sizeof(bufW)/sizeof(bufW[0])) { 594 /* can only happen if the convert call fails */ 595 ok(bufW[lenW] != 0, "buf should not be 0 terminated\n"); 596 bufW[lenW] = 0; /* -1 doesn't include 0 terminator */ 597 } 598 ok(!lstrcmpW(bufW, stringW), "bufW/stringW mismatch\n"); 599 600 memset(bufW, 'x', sizeof(bufW)); 601 lenA = -1; 602 lenW = 5; 603 ret = IMultiLanguage2_ConvertStringToUnicode(iML2, NULL, 1252, stringA, &lenA, bufW, &lenW); 604 ok(ret == E_FAIL, "IMultiLanguage2_ConvertStringToUnicode should fail: %08x\n", ret); 605 ok(lenW == 0, "expected lenW 0, got %u\n", lenW); 606 /* still has to do partial conversion */ 607 ok(!memcmp(bufW, stringW, 5 * sizeof(WCHAR)), "bufW/stringW mismatch\n"); 608 609 memset(bufW, 'x', sizeof(bufW)); 610 lenA = -1; 611 lenW = sizeof(bufW)/sizeof(bufW[0]); 612 ret = IMultiLanguage2_ConvertStringToUnicode(iML2, NULL, CP_UNICODE, stringA, &lenA, bufW, &lenW); 613 ok(ret == S_OK, "IMultiLanguage2_ConvertStringToUnicode failed: %08x\n", ret); 614 ok(lenA == lstrlenA(stringA), "expected lenA %u, got %u\n", lstrlenA(stringA), lenA); 615 ok(lenW == lstrlenW(stringW)/(int)sizeof(WCHAR), "wrong lenW %u\n", lenW); 616 ok(bufW[lenW] != 0, "buf should not be 0 terminated\n"); 617 bufW[lenW] = 0; /* -1 doesn't include 0 terminator */ 618 ok(!lstrcmpA((LPCSTR)bufW, stringA), "bufW/stringA mismatch\n"); 619 620 memset(bufW, 'x', sizeof(bufW)); 621 lenA = lstrlenA(stringA); 622 lenW = 0; 623 ret = IMultiLanguage2_ConvertStringToUnicode(iML2, NULL, 1252, stringA, &lenA, NULL, &lenW); 624 ok(ret == S_OK, "IMultiLanguage2_ConvertStringToUnicode failed: %08x\n", ret); 625 ok(lenA == lstrlenA(stringA), "expected lenA %u, got %u\n", lstrlenA(stringA), lenA); 626 expected_len = MultiByteToWideChar(1252, 0, stringA, lenA, NULL, 0); 627 ok(lenW == expected_len, "expected lenW %u, got %u\n", expected_len, lenW); 628 629 memset(bufW, 'x', sizeof(bufW)); 630 lenA = lstrlenA(stringA); 631 lenW = sizeof(bufW)/sizeof(bufW[0]); 632 ret = pConvertINetMultiByteToUnicode(NULL, 1252, stringA, (INT *)&lenA, NULL, (INT *)&lenW); 633 ok(ret == S_OK, "ConvertINetMultiByteToUnicode failed: %08x\n", ret); 634 ok(lenA == lstrlenA(stringA), "expected lenA %u, got %u\n", lstrlenA(stringA), lenA); 635 expected_len = MultiByteToWideChar(1252, 0, stringA, lenA, NULL, 0); 636 ok(lenW == expected_len, "expected lenW %u, got %u\n", expected_len, lenW); 637 638 memset(bufW, 'x', sizeof(bufW)); 639 lenA = lstrlenA(stringA); 640 lenW = 0; 641 ret = pConvertINetMultiByteToUnicode(NULL, 1252, stringA, (INT *)&lenA, NULL, (INT *)&lenW); 642 ok(ret == S_OK, "ConvertINetMultiByteToUnicode failed: %08x\n", ret); 643 ok(lenA == lstrlenA(stringA), "expected lenA %u, got %u\n", lstrlenA(stringA), lenA); 644 expected_len = MultiByteToWideChar(1252, 0, stringA, lenA, NULL, 0); 645 ok(lenW == expected_len, "expected lenW %u, got %u\n", expected_len, lenW); 646 647 /* IMultiLanguage2_ConvertStringFromUnicode tests */ 648 649 memset(bufA, 'x', sizeof(bufA)); 650 lenW = 0; 651 lenA = sizeof(bufA); 652 ret = IMultiLanguage2_ConvertStringFromUnicode(iML2, NULL, 1252, stringW, &lenW, bufA, &lenA); 653 ok(ret == S_OK, "IMultiLanguage2_ConvertStringFromUnicode failed: %08x\n", ret); 654 ok(lenA == 0, "expected lenA 0, got %u\n", lenA); 655 ok(lenW == 0, "expected lenW 0, got %u\n", lenW); 656 657 memset(bufA, 'x', sizeof(bufA)); 658 lenW = -1; 659 lenA = sizeof(bufA); 660 ret = IMultiLanguage2_ConvertStringFromUnicode(iML2, NULL, 1252, stringW, &lenW, bufA, &lenA); 661 ok(ret == S_OK, "IMultiLanguage2_ConvertStringFromUnicode failed: %08x\n", ret); 662 ok(lenA == lstrlenA(stringA), "expected lenA %u, got %u\n", lstrlenA(stringA), lenA); 663 ok(lenW == lstrlenW(stringW), "expected lenW %u, got %u\n", lstrlenW(stringW), lenW); 664 ok(bufA[lenA] != 0, "buf should not be 0 terminated\n"); 665 bufA[lenA] = 0; /* -1 doesn't include 0 terminator */ 666 ok(!lstrcmpA(bufA, stringA), "bufA/stringA mismatch\n"); 667 668 memset(bufA, 'x', sizeof(bufA)); 669 lenW = -1; 670 lenA = 5; 671 ret = IMultiLanguage2_ConvertStringFromUnicode(iML2, NULL, 1252, stringW, &lenW, bufA, &lenA); 672 ok(ret == E_FAIL, "IMultiLanguage2_ConvertStringFromUnicode should fail: %08x\n", ret); 673 ok(lenA == 0, "expected lenA 0, got %u\n", lenA); 674 /* still has to do partial conversion */ 675 ok(!memcmp(bufA, stringA, 5), "bufW/stringW mismatch\n"); 676 677 memset(bufA, 'x', sizeof(bufA)); 678 lenW = -1; 679 lenA = sizeof(bufA); 680 ret = IMultiLanguage2_ConvertStringFromUnicode(iML2, NULL, CP_UNICODE, stringW, &lenW, bufA, &lenA); 681 ok(ret == S_OK, "IMultiLanguage2_ConvertStringFromUnicode failed: %08x\n", ret); 682 ok(lenA == lstrlenA(stringA) * (int)sizeof(WCHAR), "wrong lenA %u\n", lenA); 683 ok(lenW == lstrlenW(stringW), "expected lenW %u, got %u\n", lstrlenW(stringW), lenW); 684 ok(bufA[lenA] != 0 && bufA[lenA+1] != 0, "buf should not be 0 terminated\n"); 685 bufA[lenA] = 0; /* -1 doesn't include 0 terminator */ 686 bufA[lenA+1] = 0; /* sizeof(WCHAR) */ 687 ok(!lstrcmpW((LPCWSTR)bufA, stringW), "bufA/stringW mismatch\n"); 688 689 memset(bufA, 'x', sizeof(bufA)); 690 lenW = lstrlenW(stringW); 691 lenA = 0; 692 ret = IMultiLanguage2_ConvertStringFromUnicode(iML2, NULL, 1252, stringW, &lenW, NULL, &lenA); 693 ok(ret == S_OK, "IMultiLanguage2_ConvertStringFromUnicode failed: %08x\n", ret); 694 ok(lenW == lstrlenW(stringW), "expected lenW %u, got %u\n", lstrlenW(stringW), lenW); 695 expected_len = WideCharToMultiByte(1252, 0, stringW, lenW, NULL, 0, NULL, NULL); 696 ok(lenA == expected_len, "expected lenA %u, got %u\n", expected_len, lenA); 697 } 698 699 static void cpinfo_cmp(MIMECPINFO *cpinfo1, MIMECPINFO *cpinfo2) 700 { 701 ok(cpinfo1->dwFlags == cpinfo2->dwFlags, "dwFlags mismatch: %08x != %08x\n", cpinfo1->dwFlags, cpinfo2->dwFlags); 702 ok(cpinfo1->uiCodePage == cpinfo2->uiCodePage, "uiCodePage mismatch: %u != %u\n", cpinfo1->uiCodePage, cpinfo2->uiCodePage); 703 ok(cpinfo1->uiFamilyCodePage == cpinfo2->uiFamilyCodePage, "uiFamilyCodePage mismatch: %u != %u\n", cpinfo1->uiFamilyCodePage, cpinfo2->uiFamilyCodePage); 704 ok(!lstrcmpW(cpinfo1->wszDescription, cpinfo2->wszDescription), "wszDescription mismatch\n"); 705 ok(!lstrcmpW(cpinfo1->wszWebCharset, cpinfo2->wszWebCharset), "wszWebCharset mismatch\n"); 706 ok(!lstrcmpW(cpinfo1->wszHeaderCharset, cpinfo2->wszHeaderCharset), "wszHeaderCharset mismatch\n"); 707 ok(!lstrcmpW(cpinfo1->wszBodyCharset, cpinfo2->wszBodyCharset), "wszBodyCharset mismatch\n"); 708 ok(!lstrcmpW(cpinfo1->wszFixedWidthFont, cpinfo2->wszFixedWidthFont), "wszFixedWidthFont mismatch\n"); 709 ok(!lstrcmpW(cpinfo1->wszProportionalFont, cpinfo2->wszProportionalFont), "wszProportionalFont mismatch\n"); 710 ok(cpinfo1->bGDICharset == cpinfo2->bGDICharset, "bGDICharset mismatch: %d != %d\n", cpinfo1->bGDICharset, cpinfo2->bGDICharset); 711 } 712 713 #ifdef DUMP_CP_INFO 714 static const char *dump_mime_flags(DWORD flags) 715 { 716 static char buf[1024]; 717 718 buf[0] = 0; 719 720 if (flags & MIMECONTF_MAILNEWS) strcat(buf, " MIMECONTF_MAILNEWS"); 721 if (flags & MIMECONTF_BROWSER) strcat(buf, " MIMECONTF_BROWSER"); 722 if (flags & MIMECONTF_MINIMAL) strcat(buf, " MIMECONTF_MINIMAL"); 723 if (flags & MIMECONTF_IMPORT) strcat(buf, " MIMECONTF_IMPORT"); 724 if (flags & MIMECONTF_SAVABLE_MAILNEWS) strcat(buf, " MIMECONTF_SAVABLE_MAILNEWS"); 725 if (flags & MIMECONTF_SAVABLE_BROWSER) strcat(buf, " MIMECONTF_SAVABLE_BROWSER"); 726 if (flags & MIMECONTF_EXPORT) strcat(buf, " MIMECONTF_EXPORT"); 727 if (flags & MIMECONTF_PRIVCONVERTER) strcat(buf, " MIMECONTF_PRIVCONVERTER"); 728 if (flags & MIMECONTF_VALID) strcat(buf, " MIMECONTF_VALID"); 729 if (flags & MIMECONTF_VALID_NLS) strcat(buf, " MIMECONTF_VALID_NLS"); 730 if (flags & MIMECONTF_MIME_IE4) strcat(buf, " MIMECONTF_MIME_IE4"); 731 if (flags & MIMECONTF_MIME_LATEST) strcat(buf, " MIMECONTF_MIME_LATEST"); 732 if (flags & MIMECONTF_MIME_REGISTRY) strcat(buf, " MIMECONTF_MIME_REGISTRY"); 733 734 return buf; 735 } 736 #endif 737 738 static HRESULT check_convertible(IMultiLanguage2 *iML2, UINT from, UINT to) 739 { 740 CHAR convert[MAX_PATH]; 741 BYTE dest[MAX_PATH]; 742 HRESULT hr; 743 UINT srcsz, destsz; 744 745 static WCHAR strW[] = {'a','b','c',0}; 746 747 /* Check to see if the target codepage has these characters or not */ 748 if (from != CP_UTF8) 749 { 750 BOOL fDefaultChar; 751 char ch[10]; 752 int cb; 753 cb = WideCharToMultiByte( from, WC_NO_BEST_FIT_CHARS | WC_COMPOSITECHECK | WC_DEFAULTCHAR, 754 strW, 3, ch, sizeof(ch), NULL, &fDefaultChar); 755 756 if(cb == 0 || fDefaultChar) 757 { 758 trace("target codepage %i does not contain 'abc'\n",from); 759 return E_FAIL; 760 } 761 } 762 763 srcsz = lstrlenW(strW) + 1; 764 destsz = MAX_PATH; 765 hr = IMultiLanguage2_ConvertStringFromUnicode(iML2, NULL, from, strW, 766 &srcsz, convert, &destsz); 767 if (hr != S_OK) 768 return S_FALSE; 769 770 srcsz = -1; 771 destsz = MAX_PATH; 772 hr = IMultiLanguage2_ConvertString(iML2, NULL, from, to, (BYTE *)convert, 773 &srcsz, dest, &destsz); 774 if (hr != S_OK) 775 return S_FALSE; 776 777 return S_OK; 778 } 779 780 static void test_EnumCodePages(IMultiLanguage2 *iML2, DWORD flags) 781 { 782 IEnumCodePage *iEnumCP = NULL; 783 MIMECPINFO *cpinfo; 784 MIMECPINFO cpinfo2; 785 HRESULT ret; 786 ULONG i, n; 787 UINT total; 788 789 total = 0; 790 ret = IMultiLanguage2_GetNumberOfCodePageInfo(iML2, &total); 791 ok(ret == S_OK && total != 0, "IMultiLanguage2_GetNumberOfCodePageInfo: expected S_OK/!0, got %08x/%u\n", ret, total); 792 793 trace("total mlang supported codepages %u\n", total); 794 795 ret = IMultiLanguage2_EnumCodePages(iML2, flags, LANG_NEUTRAL, &iEnumCP); 796 ok(ret == S_OK && iEnumCP, "IMultiLanguage2_EnumCodePages: expected S_OK/!NULL, got %08x/%p\n", ret, iEnumCP); 797 798 ret = IEnumCodePage_Reset(iEnumCP); 799 ok(ret == S_OK, "IEnumCodePage_Reset: expected S_OK, got %08x\n", ret); 800 n = 65536; 801 ret = IEnumCodePage_Next(iEnumCP, 0, NULL, &n); 802 ok(ret == S_FALSE || ret == E_FAIL, 803 "IEnumCodePage_Next: expected S_FALSE or E_FAIL, got %08x\n", ret); 804 if (ret == S_FALSE) 805 ok(n == 0, "IEnumCodePage_Next: expected 0/S_FALSE, got %u/%08x\n", n, ret); 806 else if (ret == E_FAIL) 807 ok(n == 65536, "IEnumCodePage_Next: expected 65536/E_FAIL, got %u/%08x\n", n, ret); 808 ret = IEnumCodePage_Next(iEnumCP, 0, NULL, NULL); 809 ok(ret == S_FALSE || ret == E_FAIL, 810 "IEnumCodePage_Next: expected S_FALSE or E_FAIL, got %08x\n", ret); 811 812 cpinfo = HeapAlloc(GetProcessHeap(), 0, sizeof(*cpinfo) * total * 2); 813 814 n = total * 2; 815 ret = IEnumCodePage_Next(iEnumCP, 0, cpinfo, &n); 816 ok(ret == S_FALSE && n == 0, "IEnumCodePage_Next: expected S_FALSE/0, got %08x/%u\n", ret, n); 817 818 n = total * 2; 819 ret = IEnumCodePage_Next(iEnumCP, n, cpinfo, &n); 820 ok(ret == S_OK && n != 0, "IEnumCodePage_Next: expected S_OK/!0, got %08x/%u\n", ret, n); 821 822 trace("flags %08x, enumerated codepages %u\n", flags, n); 823 824 if (!flags) 825 { 826 ok(n == total, "IEnumCodePage_Next: expected %u, got %u\n", total, n); 827 828 flags = MIMECONTF_MIME_LATEST; 829 } 830 831 total = n; 832 833 for (i = 0; i < n; i++) 834 { 835 CHARSETINFO csi; 836 MIMECSETINFO mcsi; 837 HRESULT convertible = S_OK; 838 static const WCHAR autoW[] = {'_','a','u','t','o',0}; 839 static const WCHAR feffW[] = {'u','n','i','c','o','d','e','F','E','F','F',0}; 840 841 #ifdef DUMP_CP_INFO 842 trace("MIMECPINFO #%u:\n" 843 "dwFlags %08x %s\n" 844 "uiCodePage %u\n" 845 "uiFamilyCodePage %u\n" 846 "wszDescription %s\n" 847 "wszWebCharset %s\n" 848 "wszHeaderCharset %s\n" 849 "wszBodyCharset %s\n" 850 "wszFixedWidthFont %s\n" 851 "wszProportionalFont %s\n" 852 "bGDICharset %d\n\n", 853 i, 854 cpinfo[i].dwFlags, dump_mime_flags(cpinfo[i].dwFlags), 855 cpinfo[i].uiCodePage, 856 cpinfo[i].uiFamilyCodePage, 857 wine_dbgstr_w(cpinfo[i].wszDescription), 858 wine_dbgstr_w(cpinfo[i].wszWebCharset), 859 wine_dbgstr_w(cpinfo[i].wszHeaderCharset), 860 wine_dbgstr_w(cpinfo[i].wszBodyCharset), 861 wine_dbgstr_w(cpinfo[i].wszFixedWidthFont), 862 wine_dbgstr_w(cpinfo[i].wszProportionalFont), 863 cpinfo[i].bGDICharset); 864 #endif 865 ok(cpinfo[i].dwFlags & flags, "enumerated flags %08x do not include requested %08x\n", cpinfo[i].dwFlags, flags); 866 867 if (TranslateCharsetInfo((DWORD *)(INT_PTR)cpinfo[i].uiFamilyCodePage, &csi, TCI_SRCCODEPAGE)) 868 ok(cpinfo[i].bGDICharset == csi.ciCharset, "%d != %d\n", cpinfo[i].bGDICharset, csi.ciCharset); 869 else 870 if (winetest_debug > 1) 871 trace("TranslateCharsetInfo failed for cp %u\n", cpinfo[i].uiFamilyCodePage); 872 873 #ifdef DUMP_CP_INFO 874 trace("%u: codepage %u family %u\n", i, cpinfo[i].uiCodePage, cpinfo[i].uiFamilyCodePage); 875 #endif 876 877 /* support files for some codepages might be not installed, or 878 * the codepage is just an alias. 879 */ 880 if (IsValidCodePage(cpinfo[i].uiCodePage)) 881 { 882 ret = IMultiLanguage2_IsConvertible(iML2, cpinfo[i].uiCodePage, CP_UNICODE); 883 ok(ret == S_OK, "IMultiLanguage2_IsConvertible(%u -> CP_UNICODE) = %08x\n", cpinfo[i].uiCodePage, ret); 884 ret = IMultiLanguage2_IsConvertible(iML2, CP_UNICODE, cpinfo[i].uiCodePage); 885 ok(ret == S_OK, "IMultiLanguage2_IsConvertible(CP_UNICODE -> %u) = %08x\n", cpinfo[i].uiCodePage, ret); 886 887 convertible = check_convertible(iML2, cpinfo[i].uiCodePage, CP_UTF8); 888 if (convertible != E_FAIL) 889 { 890 ret = IMultiLanguage2_IsConvertible(iML2, cpinfo[i].uiCodePage, CP_UTF8); 891 ok(ret == convertible, "IMultiLanguage2_IsConvertible(%u -> CP_UTF8) = %08x\n", cpinfo[i].uiCodePage, ret); 892 ret = IMultiLanguage2_IsConvertible(iML2, CP_UTF8, cpinfo[i].uiCodePage); 893 ok(ret == convertible, "IMultiLanguage2_IsConvertible(CP_UTF8 -> %u) = %08x\n", cpinfo[i].uiCodePage, ret); 894 } 895 } 896 else 897 if (winetest_debug > 1) 898 trace("IsValidCodePage failed for cp %u\n", cpinfo[i].uiCodePage); 899 900 if (memcmp(cpinfo[i].wszWebCharset,feffW,sizeof(WCHAR)*11)==0) 901 skip("Legacy windows bug returning invalid charset of unicodeFEFF\n"); 902 else 903 { 904 ret = IMultiLanguage2_GetCharsetInfo(iML2, cpinfo[i].wszWebCharset, &mcsi); 905 /* _autoxxx charsets are a fake and GetCharsetInfo fails for them */ 906 if (memcmp(cpinfo[i].wszWebCharset, autoW, 5 * sizeof(WCHAR))) 907 { 908 ok (ret == S_OK, "IMultiLanguage2_GetCharsetInfo failed: %08x\n", ret); 909 #ifdef DUMP_CP_INFO 910 trace("%s: %u %u %s\n", wine_dbgstr_w(cpinfo[i].wszWebCharset), mcsi.uiCodePage, mcsi.uiInternetEncoding, wine_dbgstr_w(mcsi.wszCharset)); 911 #endif 912 ok(!lstrcmpiW(cpinfo[i].wszWebCharset, mcsi.wszCharset), "%s != %s\n", 913 wine_dbgstr_w(cpinfo[i].wszWebCharset), wine_dbgstr_w(mcsi.wszCharset)); 914 915 if (0) 916 { 917 /* native mlang returns completely messed up encodings in some cases */ 918 ok(mcsi.uiInternetEncoding == cpinfo[i].uiCodePage || mcsi.uiInternetEncoding == cpinfo[i].uiFamilyCodePage, 919 "%u != %u || %u\n", mcsi.uiInternetEncoding, cpinfo[i].uiCodePage, cpinfo[i].uiFamilyCodePage); 920 ok(mcsi.uiCodePage == cpinfo[i].uiCodePage || mcsi.uiCodePage == cpinfo[i].uiFamilyCodePage, 921 "%u != %u || %u\n", mcsi.uiCodePage, cpinfo[i].uiCodePage, cpinfo[i].uiFamilyCodePage); 922 } 923 } 924 } 925 926 if (memcmp(cpinfo[i].wszHeaderCharset,feffW,sizeof(WCHAR)*11)==0) 927 skip("Legacy windows bug returning invalid charset of unicodeFEFF\n"); 928 else 929 { 930 ret = IMultiLanguage2_GetCharsetInfo(iML2, cpinfo[i].wszHeaderCharset, &mcsi); 931 /* _autoxxx charsets are a fake and GetCharsetInfo fails for them */ 932 if (memcmp(cpinfo[i].wszHeaderCharset, autoW, 5 * sizeof(WCHAR))) 933 { 934 ok (ret == S_OK, "IMultiLanguage2_GetCharsetInfo failed: %08x\n", ret); 935 #ifdef DUMP_CP_INFO 936 trace("%s: %u %u %s\n", wine_dbgstr_w(cpinfo[i].wszHeaderCharset), mcsi.uiCodePage, mcsi.uiInternetEncoding, wine_dbgstr_w(mcsi.wszCharset)); 937 #endif 938 ok(!lstrcmpiW(cpinfo[i].wszHeaderCharset, mcsi.wszCharset), "%s != %s\n", 939 wine_dbgstr_w(cpinfo[i].wszHeaderCharset), wine_dbgstr_w(mcsi.wszCharset)); 940 941 if (0) 942 { 943 /* native mlang returns completely messed up encodings in some cases */ 944 ok(mcsi.uiInternetEncoding == cpinfo[i].uiCodePage || mcsi.uiInternetEncoding == cpinfo[i].uiFamilyCodePage, 945 "%u != %u || %u\n", mcsi.uiInternetEncoding, cpinfo[i].uiCodePage, cpinfo[i].uiFamilyCodePage); 946 ok(mcsi.uiCodePage == cpinfo[i].uiCodePage || mcsi.uiCodePage == cpinfo[i].uiFamilyCodePage, 947 "%u != %u || %u\n", mcsi.uiCodePage, cpinfo[i].uiCodePage, cpinfo[i].uiFamilyCodePage); 948 } 949 } 950 } 951 952 if (memcmp(cpinfo[i].wszBodyCharset,feffW,sizeof(WCHAR)*11)==0) 953 skip("Legacy windows bug returning invalid charset of unicodeFEFF\n"); 954 else 955 { 956 ret = IMultiLanguage2_GetCharsetInfo(iML2, cpinfo[i].wszBodyCharset, &mcsi); 957 /* _autoxxx charsets are a fake and GetCharsetInfo fails for them */ 958 if (memcmp(cpinfo[i].wszBodyCharset, autoW, 5 * sizeof(WCHAR))) 959 { 960 ok (ret == S_OK, "IMultiLanguage2_GetCharsetInfo failed: %08x\n", ret); 961 #ifdef DUMP_CP_INFO 962 trace("%s: %u %u %s\n", wine_dbgstr_w(cpinfo[i].wszBodyCharset), mcsi.uiCodePage, mcsi.uiInternetEncoding, wine_dbgstr_w(mcsi.wszCharset)); 963 #endif 964 ok(!lstrcmpiW(cpinfo[i].wszBodyCharset, mcsi.wszCharset), "%s != %s\n", 965 wine_dbgstr_w(cpinfo[i].wszBodyCharset), wine_dbgstr_w(mcsi.wszCharset)); 966 967 if (0) 968 { 969 /* native mlang returns completely messed up encodings in some cases */ 970 ok(mcsi.uiInternetEncoding == cpinfo[i].uiCodePage || mcsi.uiInternetEncoding == cpinfo[i].uiFamilyCodePage, 971 "%u != %u || %u\n", mcsi.uiInternetEncoding, cpinfo[i].uiCodePage, cpinfo[i].uiFamilyCodePage); 972 ok(mcsi.uiCodePage == cpinfo[i].uiCodePage || mcsi.uiCodePage == cpinfo[i].uiFamilyCodePage, 973 "%u != %u || %u\n", mcsi.uiCodePage, cpinfo[i].uiCodePage, cpinfo[i].uiFamilyCodePage); 974 } 975 } 976 } 977 } 978 979 /* now IEnumCodePage_Next should fail, since pointer is at the end */ 980 n = 1; 981 ret = IEnumCodePage_Next(iEnumCP, 1, &cpinfo2, &n); 982 ok(ret == S_FALSE && n == 0, "IEnumCodePage_Next: expected S_FALSE/0, got %08x/%u\n", ret, n); 983 984 ret = IEnumCodePage_Reset(iEnumCP); 985 ok(ret == S_OK, "IEnumCodePage_Reset: expected S_OK, got %08x\n", ret); 986 n = 0; 987 ret = IEnumCodePage_Next(iEnumCP, 1, &cpinfo2, &n); 988 ok(n == 1 && ret == S_OK, "IEnumCodePage_Next: expected 1/S_OK, got %u/%08x\n", n, ret); 989 cpinfo_cmp(cpinfo, &cpinfo2); 990 991 if (0) 992 { 993 /* Due to a bug in MS' implementation of IEnumCodePage_Skip 994 * it's not used here. 995 */ 996 ret = IEnumCodePage_Skip(iEnumCP, 1); 997 ok(ret == S_OK, "IEnumCodePage_Skip: expected S_OK, got %08x\n", ret); 998 } 999 for (i = 0; i < total - 1; i++) 1000 { 1001 n = 0; 1002 ret = IEnumCodePage_Next(iEnumCP, 1, &cpinfo2, &n); 1003 ok(n == 1 && ret == S_OK, "IEnumCodePage_Next: expected 1/S_OK, got %u/%08x\n", n, ret); 1004 cpinfo_cmp(&cpinfo[i + 1], &cpinfo2); 1005 } 1006 1007 HeapFree(GetProcessHeap(), 0, cpinfo); 1008 IEnumCodePage_Release(iEnumCP); 1009 } 1010 1011 static void test_GetCharsetInfo_other(IMultiLanguage *ml) 1012 { 1013 WCHAR asciiW[] = {'a','s','c','i','i',0}; 1014 WCHAR iso88591_1W[] = {'I','S','O','-','8','8','5','9','-','1',0}; 1015 WCHAR iso88591_1retW[] = {'i','s','o','-','8','8','5','9','-','1',0}; 1016 WCHAR iso88591_2W[] = {'I','S','O','8','8','5','9','-','1',0}; 1017 WCHAR iso88591_2retW[] = {'i','s','o','8','8','5','9','-','1',0}; 1018 WCHAR iso88591_3W[] = {'I','S','O','8','8','5','9','1',0}; 1019 WCHAR iso88591_4W[] = {'I','S','O','-','8','8','5','9','1',0}; 1020 WCHAR iso88591_5W[] = {'I','S','O','8','8','-','5','9','1',0}; 1021 WCHAR iso88591_6W[] = {'-','I','S','O','8','8','5','9','1',0}; 1022 WCHAR iso88591_7W[] = {' ','I','S','O','-','8','8','5','9','-','1',0}; 1023 struct other { 1024 int todo; 1025 HRESULT hr; 1026 WCHAR* charset; 1027 WCHAR* ret_charset; 1028 } other[] = { 1029 { 0, S_OK, asciiW, asciiW }, 1030 { 0, S_OK, iso88591_1W, iso88591_1retW }, 1031 { 1, S_OK, iso88591_2W, iso88591_2retW }, 1032 { 0, E_FAIL, iso88591_3W, 0 }, 1033 { 0, E_FAIL, iso88591_4W, 0 }, 1034 { 0, E_FAIL, iso88591_5W, 0 }, 1035 { 0, E_FAIL, iso88591_6W, 0 }, 1036 { 0, E_FAIL, iso88591_7W, 0 }, 1037 }; 1038 MIMECSETINFO info; 1039 HRESULT hr; 1040 int i; 1041 1042 for (i = 0; i < sizeof(other)/sizeof(*other); i++) 1043 { 1044 hr = IMultiLanguage_GetCharsetInfo(ml, other[i].charset, &info); 1045 1046 todo_wine_if(other[i].todo) 1047 ok(hr == other[i].hr, "#%d: got %08x, expected %08x\n", i, hr, other[i].hr); 1048 1049 if (hr == S_OK) 1050 todo_wine_if(other[i].todo) 1051 ok(!lstrcmpW(info.wszCharset, other[i].ret_charset), "#%d: got %s, expected %s\n", 1052 i, wine_dbgstr_w(info.wszCharset), wine_dbgstr_w(other[i].ret_charset)); 1053 } 1054 } 1055 1056 static void scriptinfo_cmp(SCRIPTINFO *sinfo1, SCRIPTINFO *sinfo2) 1057 { 1058 ok(sinfo1->ScriptId == sinfo2->ScriptId, "ScriptId mismatch: %d != %d\n", sinfo1->ScriptId, sinfo2->ScriptId); 1059 ok(sinfo1->uiCodePage == sinfo2->uiCodePage, "uiCodePage mismatch: %u != %u\n", sinfo1->uiCodePage, sinfo2->uiCodePage); 1060 ok(!lstrcmpW(sinfo1->wszDescription, sinfo2->wszDescription), "wszDescription mismatch\n"); 1061 ok(!lstrcmpW(sinfo1->wszFixedWidthFont, sinfo2->wszFixedWidthFont), "wszFixedWidthFont mismatch\n"); 1062 ok(!lstrcmpW(sinfo1->wszProportionalFont, sinfo2->wszProportionalFont), "wszProportionalFont mismatch\n"); 1063 } 1064 1065 static void test_EnumScripts(IMultiLanguage2 *iML2, DWORD flags) 1066 { 1067 IEnumScript *iEnumScript = NULL; 1068 SCRIPTINFO *sinfo; 1069 SCRIPTINFO sinfo2; 1070 HRESULT ret; 1071 ULONG i, n; 1072 UINT total; 1073 1074 total = 0; 1075 ret = IMultiLanguage2_GetNumberOfScripts(iML2, &total); 1076 ok(ret == S_OK && total != 0, "IMultiLanguage2_GetNumberOfScripts: expected S_OK/!0, got %08x/%u\n", ret, total); 1077 1078 trace("total mlang supported scripts %u\n", total); 1079 1080 ret = IMultiLanguage2_EnumScripts(iML2, flags, LANG_NEUTRAL, &iEnumScript); 1081 ok(ret == S_OK && iEnumScript, "IMultiLanguage2_EnumScripts: expected S_OK/!NULL, got %08x/%p\n", ret, iEnumScript); 1082 1083 ret = IEnumScript_Reset(iEnumScript); 1084 ok(ret == S_OK, "IEnumScript_Reset: expected S_OK, got %08x\n", ret); 1085 n = 65536; 1086 ret = IEnumScript_Next(iEnumScript, 0, NULL, &n); 1087 ok(n == 65536 && ret == E_FAIL, "IEnumScript_Next: expected 65536/E_FAIL, got %u/%08x\n", n, ret); 1088 ret = IEnumScript_Next(iEnumScript, 0, NULL, NULL); 1089 ok(ret == E_FAIL, "IEnumScript_Next: expected E_FAIL, got %08x\n", ret); 1090 1091 sinfo = HeapAlloc(GetProcessHeap(), 0, sizeof(*sinfo) * total * 2); 1092 1093 n = total * 2; 1094 ret = IEnumScript_Next(iEnumScript, 0, sinfo, &n); 1095 ok(ret == S_FALSE && n == 0, "IEnumScript_Next: expected S_FALSE/0, got %08x/%u\n", ret, n); 1096 1097 n = total * 2; 1098 ret = IEnumScript_Next(iEnumScript, n, sinfo, &n); 1099 ok(ret == S_OK && n != 0, "IEnumScript_Next: expected S_OK, got %08x/%u\n", ret, n); 1100 1101 trace("flags %08x, enumerated scripts %u\n", flags, n); 1102 1103 if (!flags) 1104 { 1105 ok(n == total, "IEnumScript_Next: expected %u, got %u\n", total, n); 1106 } 1107 1108 total = n; 1109 1110 for (i = 0; pGetCPInfoExA && i < n; i++) 1111 { 1112 #ifdef DUMP_SCRIPT_INFO 1113 trace("SCRIPTINFO #%u:\n" 1114 "ScriptId %08x\n" 1115 "uiCodePage %u\n" 1116 "wszDescription %s\n" 1117 "wszFixedWidthFont %s\n" 1118 "wszProportionalFont %s\n\n", 1119 i, 1120 sinfo[i].ScriptId, 1121 sinfo[i].uiCodePage, 1122 wine_dbgstr_w(sinfo[i].wszDescription), 1123 wine_dbgstr_w(sinfo[i].wszFixedWidthFont), 1124 wine_dbgstr_w(sinfo[i].wszProportionalFont)); 1125 trace("%u codepage %u\n", i, sinfo[i].uiCodePage); 1126 #endif 1127 } 1128 1129 /* now IEnumScript_Next should fail, since pointer is at the end */ 1130 n = 1; 1131 ret = IEnumScript_Next(iEnumScript, 1, &sinfo2, &n); 1132 ok(ret == S_FALSE && n == 0, "IEnumScript_Next: expected S_FALSE/0, got %08x/%u\n", ret, n); 1133 1134 ret = IEnumScript_Reset(iEnumScript); 1135 ok(ret == S_OK, "IEnumScript_Reset: expected S_OK, got %08x\n", ret); 1136 n = 0; 1137 ret = IEnumScript_Next(iEnumScript, 1, &sinfo2, &n); 1138 ok(n == 1 && ret == S_OK, "IEnumScript_Next: expected 1/S_OK, got %u/%08x\n", n, ret); 1139 scriptinfo_cmp(sinfo, &sinfo2); 1140 1141 if (0) 1142 { 1143 /* Due to a bug in MS' implementation of IEnumScript_Skip 1144 * it's not used here. 1145 */ 1146 ret = IEnumScript_Skip(iEnumScript, 1); 1147 ok(ret == S_OK, "IEnumScript_Skip: expected S_OK, got %08x\n", ret); 1148 } 1149 for (i = 0; i < total - 1; i++) 1150 { 1151 n = 0; 1152 ret = IEnumScript_Next(iEnumScript, 1, &sinfo2, &n); 1153 ok(n == 1 && ret == S_OK, "IEnumScript_Next: expected 1/S_OK, got %u/%08x\n", n, ret); 1154 scriptinfo_cmp(&sinfo[i + 1], &sinfo2); 1155 } 1156 1157 HeapFree(GetProcessHeap(), 0, sinfo); 1158 IEnumScript_Release(iEnumScript); 1159 } 1160 1161 static void IMLangFontLink_Test(IMLangFontLink* iMLFL) 1162 { 1163 DWORD dwCodePages, dwManyCodePages; 1164 DWORD dwCmpCodePages; 1165 UINT CodePage; 1166 static const WCHAR str[] = { 'd', 0x0436, 0xff90 }; 1167 LONG processed; 1168 HRESULT ret; 1169 1170 dwCodePages = ~0u; 1171 ret = IMLangFontLink_CodePageToCodePages(iMLFL, -1, &dwCodePages); 1172 ok(ret == E_FAIL, "IMLangFontLink_CodePageToCodePages should fail: %x\n", ret); 1173 ok(dwCodePages == 0, "expected 0, got %u\n", dwCodePages); 1174 1175 dwCodePages = 0; 1176 ret = IMLangFontLink_CodePageToCodePages(iMLFL, 932, &dwCodePages); 1177 ok(ret == S_OK, "IMLangFontLink_CodePageToCodePages error %x\n", ret); 1178 ok(dwCodePages == FS_JISJAPAN, "expected FS_JISJAPAN, got %08x\n", dwCodePages); 1179 CodePage = 0; 1180 ret = IMLangFontLink_CodePagesToCodePage(iMLFL, dwCodePages, 1035, &CodePage); 1181 ok(ret == S_OK, "IMLangFontLink_CodePagesToCodePage error %x\n", ret); 1182 ok(CodePage == 932, "Incorrect CodePage Returned (%i)\n",CodePage); 1183 1184 dwManyCodePages = 0; 1185 ret = IMLangFontLink_CodePageToCodePages(iMLFL, 1252, &dwManyCodePages); 1186 ok(ret == S_OK, "IMLangFontLink_CodePageToCodePages error %x\n", ret); 1187 ok(dwManyCodePages == FS_LATIN1, "expected FS_LATIN1, got %08x\n", dwManyCodePages); 1188 dwCodePages = 0; 1189 ret = IMLangFontLink_CodePageToCodePages(iMLFL, 1256, &dwCodePages); 1190 ok(ret == S_OK, "IMLangFontLink_CodePageToCodePages error %x\n", ret); 1191 ok(dwCodePages == FS_ARABIC, "expected FS_ARABIC, got %08x\n", dwCodePages); 1192 dwManyCodePages |= dwCodePages; 1193 ret = IMLangFontLink_CodePageToCodePages(iMLFL, 874, &dwCodePages); 1194 ok(ret == S_OK, "IMLangFontLink_CodePageToCodePages error %x\n", ret); 1195 ok(dwCodePages == FS_THAI, "expected FS_THAI, got %08x\n", dwCodePages); 1196 dwManyCodePages |= dwCodePages; 1197 1198 ret = IMLangFontLink_CodePagesToCodePage(iMLFL, dwManyCodePages, 1256, &CodePage); 1199 ok(ret == S_OK, "IMLangFontLink_CodePagesToCodePage error %x\n", ret); 1200 ok(CodePage == 1256, "Incorrect CodePage Returned (%i)\n",CodePage); 1201 1202 ret = IMLangFontLink_CodePagesToCodePage(iMLFL, dwManyCodePages, 936, &CodePage); 1203 ok(ret == S_OK, "IMLangFontLink_CodePagesToCodePage error %x\n", ret); 1204 ok(CodePage == 1252, "Incorrect CodePage Returned (%i)\n",CodePage); 1205 1206 /* Tests for GetCharCodePages */ 1207 1208 /* Latin 1 */ 1209 dwCmpCodePages = FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC | FS_GREEK | FS_TURKISH 1210 | FS_HEBREW | FS_ARABIC | FS_BALTIC | FS_VIETNAMESE | FS_THAI 1211 | FS_JISJAPAN | FS_CHINESESIMP | FS_WANSUNG | FS_CHINESETRAD; 1212 ret = IMLangFontLink_GetCharCodePages(iMLFL, 'd', &dwCodePages); 1213 ok(ret == S_OK, "IMLangFontLink_GetCharCodePages error %x\n", ret); 1214 ok(dwCodePages == dwCmpCodePages, "expected %x, got %x\n", dwCmpCodePages, dwCodePages); 1215 1216 dwCodePages = 0; 1217 processed = 0; 1218 ret = IMLangFontLink_GetStrCodePages(iMLFL, str, 1, 0, &dwCodePages, &processed); 1219 ok(ret == S_OK, "IMLangFontLink_GetStrCodePages error %x\n", ret); 1220 ok(dwCodePages == dwCmpCodePages, "expected %x, got %x\n", dwCmpCodePages, dwCodePages); 1221 ok(processed == 1, "expected 1, got %d\n", processed); 1222 1223 /* Cyrillic */ 1224 dwCmpCodePages = FS_CYRILLIC | FS_JISJAPAN | FS_CHINESESIMP | FS_WANSUNG; 1225 ret = IMLangFontLink_GetCharCodePages(iMLFL, 0x0436, &dwCodePages); 1226 ok(ret == S_OK, "IMLangFontLink_GetCharCodePages error %x\n", ret); 1227 ok(dwCodePages == dwCmpCodePages, "expected %x, got %x\n", dwCmpCodePages, dwCodePages); 1228 1229 dwCodePages = 0; 1230 processed = 0; 1231 ret = IMLangFontLink_GetStrCodePages(iMLFL, &str[1], 1, 0, &dwCodePages, &processed); 1232 ok(ret == S_OK, "IMLangFontLink_GetStrCodePages error %x\n", ret); 1233 ok(dwCodePages == dwCmpCodePages, "expected %x, got %x\n", dwCmpCodePages, dwCodePages); 1234 ok(processed == 1, "expected 1, got %d\n", processed); 1235 1236 /* Japanese */ 1237 dwCmpCodePages = FS_JISJAPAN; 1238 ret = IMLangFontLink_GetCharCodePages(iMLFL, 0xff90, &dwCodePages); 1239 ok(ret == S_OK, "IMLangFontLink_GetCharCodePages error %x\n", ret); 1240 ok(dwCodePages == dwCmpCodePages, "expected %x, got %x\n", dwCmpCodePages, dwCodePages); 1241 1242 dwCodePages = 0; 1243 processed = 0; 1244 ret = IMLangFontLink_GetStrCodePages(iMLFL, &str[2], 1, 0, &dwCodePages, &processed); 1245 ok(ret == S_OK, "IMLangFontLink_GetStrCodePages error %x\n", ret); 1246 ok(dwCodePages == dwCmpCodePages, "expected %x, got %x\n", dwCmpCodePages, dwCodePages); 1247 ok(processed == 1, "expected 1, got %d\n", processed); 1248 1249 dwCmpCodePages = FS_CYRILLIC | FS_JISJAPAN | FS_CHINESESIMP | FS_WANSUNG; 1250 dwCodePages = 0; 1251 processed = 0; 1252 ret = IMLangFontLink_GetStrCodePages(iMLFL, str, 2, 0, &dwCodePages, &processed); 1253 ok(ret == S_OK, "IMLangFontLink_GetStrCodePages error %x\n", ret); 1254 ok(dwCodePages == dwCmpCodePages, "expected %x, got %x\n", dwCmpCodePages, dwCodePages); 1255 ok(processed == 2, "expected 2, got %d\n", processed); 1256 1257 dwCmpCodePages = FS_JISJAPAN; 1258 dwCodePages = 0; 1259 processed = 0; 1260 ret = IMLangFontLink_GetStrCodePages(iMLFL, str, 3, 0, &dwCodePages, &processed); 1261 ok(ret == S_OK, "IMLangFontLink_GetStrCodePages error %x\n", ret); 1262 ok(dwCodePages == dwCmpCodePages, "expected %x, got %x\n", dwCmpCodePages, dwCodePages); 1263 ok(processed == 3, "expected 3, got %d\n", processed); 1264 1265 dwCodePages = 0xffff; 1266 processed = -1; 1267 ret = IMLangFontLink_GetStrCodePages(iMLFL, &str[2], 1, 0, &dwCodePages, &processed); 1268 ok(ret == S_OK, "IMLangFontLink_GetStrCodePages error %x\n", ret); 1269 ok(dwCodePages == dwCmpCodePages, "expected %x, got %x\n", dwCmpCodePages, dwCodePages); 1270 ok(processed == 1, "expected 0, got %d\n", processed); 1271 1272 ret = IMLangFontLink_GetStrCodePages(iMLFL, &str[2], 1, 0, NULL, NULL); 1273 ok(ret == S_OK, "IMLangFontLink_GetStrCodePages error %x\n", ret); 1274 1275 dwCodePages = 0xffff; 1276 processed = -1; 1277 ret = IMLangFontLink_GetStrCodePages(iMLFL, str, -1, 0, &dwCodePages, &processed); 1278 ok(ret == E_INVALIDARG, "IMLangFontLink_GetStrCodePages should fail: %x\n", ret); 1279 ok(dwCodePages == 0, "expected %x, got %x\n", dwCmpCodePages, dwCodePages); 1280 ok(processed == 0, "expected 0, got %d\n", processed); 1281 1282 dwCodePages = 0xffff; 1283 processed = -1; 1284 ret = IMLangFontLink_GetStrCodePages(iMLFL, NULL, 1, 0, &dwCodePages, &processed); 1285 ok(ret == E_INVALIDARG, "IMLangFontLink_GetStrCodePages should fail: %x\n", ret); 1286 ok(dwCodePages == 0, "expected %x, got %x\n", dwCmpCodePages, dwCodePages); 1287 ok(processed == 0, "expected 0, got %d\n", processed); 1288 1289 dwCodePages = 0xffff; 1290 processed = -1; 1291 ret = IMLangFontLink_GetStrCodePages(iMLFL, str, 0, 0, &dwCodePages, &processed); 1292 ok(ret == E_INVALIDARG, "IMLangFontLink_GetStrCodePages should fail: %x\n", ret); 1293 ok(dwCodePages == 0, "expected %x, got %x\n", dwCmpCodePages, dwCodePages); 1294 ok(processed == 0, "expected 0, got %d\n", processed); 1295 } 1296 1297 /* copied from libs/wine/string.c */ 1298 static WCHAR *strstrW(const WCHAR *str, const WCHAR *sub) 1299 { 1300 while (*str) 1301 { 1302 const WCHAR *p1 = str, *p2 = sub; 1303 while (*p1 && *p2 && *p1 == *p2) { p1++; p2++; } 1304 if (!*p2) return (WCHAR *)str; 1305 str++; 1306 } 1307 return NULL; 1308 } 1309 1310 static void test_rfc1766(IMultiLanguage2 *iML2) 1311 { 1312 IEnumRfc1766 *pEnumRfc1766; 1313 RFC1766INFO info; 1314 ULONG n; 1315 HRESULT ret; 1316 BSTR rfcstr; 1317 1318 ret = IMultiLanguage2_EnumRfc1766(iML2, LANG_NEUTRAL, &pEnumRfc1766); 1319 ok(ret == S_OK, "IMultiLanguage2_EnumRfc1766 error %08x\n", ret); 1320 1321 while (1) 1322 { 1323 ret = IEnumRfc1766_Next(pEnumRfc1766, 1, &info, &n); 1324 if (ret != S_OK) break; 1325 1326 #ifdef DUMP_CP_INFO 1327 trace("lcid %04x rfc_name %s locale_name %s\n", 1328 info.lcid, wine_dbgstr_w(info.wszRfc1766), wine_dbgstr_w(info.wszLocaleName)); 1329 #endif 1330 1331 ok(n == 1, "couldn't fetch 1 RFC1766INFO structure\n"); 1332 1333 /* verify the Rfc1766 value */ 1334 ret = IMultiLanguage2_GetRfc1766FromLcid(iML2, info.lcid, &rfcstr); 1335 ok(ret == S_OK, "Expected S_OK, got %08x\n", ret); 1336 1337 /* not an exact 1:1 correspondence between lcid and rfc1766 in the 1338 * mlang database, e.g., nb-no -> 1044 -> no */ 1339 ok(strstrW(info.wszRfc1766, rfcstr) != NULL, 1340 "Expected matching locale names\n"); 1341 1342 SysFreeString(rfcstr); 1343 } 1344 IEnumRfc1766_Release(pEnumRfc1766); 1345 } 1346 1347 static void test_GetLcidFromRfc1766(IMultiLanguage2 *iML2) 1348 { 1349 WCHAR rfc1766W[MAX_RFC1766_NAME + 1]; 1350 LCID lcid; 1351 HRESULT ret; 1352 DWORD i; 1353 1354 static WCHAR en[] = { 'e','n',0 }; 1355 static WCHAR en_them[] = { 'e','n','-','t','h','e','m',0 }; 1356 static WCHAR english[] = { 'e','n','g','l','i','s','h',0 }; 1357 1358 1359 for(i = 0; i < sizeof(lcid_table) / sizeof(lcid_table[0]); i++) { 1360 lcid = -1; 1361 MultiByteToWideChar(CP_ACP, 0, lcid_table[i].rfc1766, -1, rfc1766W, MAX_RFC1766_NAME); 1362 ret = IMultiLanguage2_GetLcidFromRfc1766(iML2, &lcid, rfc1766W); 1363 1364 /* IE <6.0 guess 0x412 (ko) from "kok" */ 1365 ok((ret == lcid_table[i].hr) || 1366 broken(lcid_table[i].broken_lcid && (ret == S_FALSE)), 1367 "#%02d: HRESULT 0x%x (expected 0x%x)\n", i, ret, lcid_table[i].hr); 1368 1369 ok((lcid == lcid_table[i].lcid) || 1370 broken(lcid == lcid_table[i].broken_lcid), /* IE <6.0 */ 1371 "#%02d: got LCID 0x%x (expected 0x%x)\n", i, lcid, lcid_table[i].lcid); 1372 } 1373 1374 1375 ret = IMultiLanguage2_GetLcidFromRfc1766(iML2, NULL, en); 1376 ok(ret == E_INVALIDARG, "GetLcidFromRfc1766 returned: %08x\n", ret); 1377 1378 ret = IMultiLanguage2_GetLcidFromRfc1766(iML2, &lcid, NULL); 1379 ok(ret == E_INVALIDARG, "GetLcidFromRfc1766 returned: %08x\n", ret); 1380 1381 ret = IMultiLanguage2_GetLcidFromRfc1766(iML2, &lcid, en_them); 1382 ok((ret == E_FAIL || ret == S_FALSE), "GetLcidFromRfc1766 returned: %08x\n", ret); 1383 if (ret == S_FALSE) 1384 { 1385 BSTR rfcstr; 1386 static WCHAR en[] = {'e','n',0}; 1387 1388 ret = IMultiLanguage2_GetRfc1766FromLcid(iML2, lcid, &rfcstr); 1389 ok(ret == S_OK, "Expected S_OK, got %08x\n", ret); 1390 ok_w2("Expected \"%s\", got \"%s\"n", en, rfcstr); 1391 } 1392 1393 ret = IMultiLanguage2_GetLcidFromRfc1766(iML2, &lcid, english); 1394 ok((ret == E_FAIL || ret == S_FALSE), "GetLcidFromRfc1766 returned: %08x\n", ret); 1395 if (ret == S_FALSE) 1396 { 1397 BSTR rfcstr; 1398 static WCHAR en[] = {'e','n',0}; 1399 1400 ret = IMultiLanguage2_GetRfc1766FromLcid(iML2, lcid, &rfcstr); 1401 ok(ret == S_OK, "Expected S_OK, got %08x\n", ret); 1402 ok_w2("Expected \"%s\", got \"%s\"n", en, rfcstr); 1403 } 1404 1405 } 1406 1407 static void test_Rfc1766ToLcid(void) 1408 { 1409 LCID lcid; 1410 HRESULT ret; 1411 DWORD i; 1412 1413 for(i = 0; i < sizeof(lcid_table) / sizeof(lcid_table[0]); i++) { 1414 lcid = -1; 1415 ret = pRfc1766ToLcidA(&lcid, lcid_table[i].rfc1766); 1416 1417 /* IE <6.0 guess 0x412 (ko) from "kok" */ 1418 ok( (ret == lcid_table[i].hr) || 1419 broken(lcid_table[i].broken_lcid && (ret == S_FALSE)), 1420 "#%02d: HRESULT 0x%x (expected 0x%x)\n", i, ret, lcid_table[i].hr); 1421 1422 ok( (lcid == lcid_table[i].lcid) || 1423 broken(lcid == lcid_table[i].broken_lcid), /* IE <6.0 */ 1424 "#%02d: got LCID 0x%x (expected 0x%x)\n", i, lcid, lcid_table[i].lcid); 1425 } 1426 1427 ret = pRfc1766ToLcidA(&lcid, NULL); 1428 ok(ret == E_INVALIDARG, "got 0x%08x (expected E_INVALIDARG)\n", ret); 1429 1430 ret = pRfc1766ToLcidA(NULL, "en"); 1431 ok(ret == E_INVALIDARG, "got 0x%08x (expected E_INVALIDARG)\n", ret); 1432 } 1433 1434 static void test_GetNumberOfCodePageInfo(IMultiLanguage2 *iML2) 1435 { 1436 HRESULT hr; 1437 UINT value; 1438 1439 value = 0xdeadbeef; 1440 hr = IMultiLanguage2_GetNumberOfCodePageInfo(iML2, &value); 1441 ok( (hr == S_OK) && value, 1442 "got 0x%x with %d (expected S_OK with '!= 0')\n", hr, value); 1443 1444 hr = IMultiLanguage2_GetNumberOfCodePageInfo(iML2, NULL); 1445 ok(hr == E_INVALIDARG, "got 0x%x (expected E_INVALIDARG)\n", hr); 1446 1447 } 1448 1449 static void test_GetRfc1766FromLcid(IMultiLanguage2 *iML2) 1450 { 1451 CHAR expected[MAX_RFC1766_NAME]; 1452 CHAR buffer[MAX_RFC1766_NAME + 1]; 1453 DWORD i; 1454 HRESULT hr; 1455 BSTR rfcstr; 1456 1457 for(i = 0; i < sizeof(lcid_table) / sizeof(lcid_table[0]); i++) { 1458 buffer[0] = '\0'; 1459 1460 rfcstr = NULL; 1461 hr = IMultiLanguage2_GetRfc1766FromLcid(iML2, lcid_table[i].lcid, &rfcstr); 1462 ok(hr == lcid_table[i].hr, 1463 "#%02d: HRESULT 0x%x (expected 0x%x)\n", i, hr, lcid_table[i].hr); 1464 1465 if (hr != S_OK) 1466 continue; /* no result-string created */ 1467 1468 WideCharToMultiByte(CP_ACP, 0, rfcstr, -1, buffer, sizeof(buffer), NULL, NULL); 1469 LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE, lcid_table[i].rfc1766, 1470 lstrlenA(lcid_table[i].rfc1766) + 1, expected, MAX_RFC1766_NAME); 1471 1472 /* IE <6.0 return "x-kok" for LCID 0x457 ("kok") */ 1473 ok( (!lstrcmpA(buffer, expected)) || 1474 broken(!lstrcmpA(buffer, lcid_table[i].broken_rfc)), 1475 "#%02d: got '%s' (expected '%s')\n", i, buffer, expected); 1476 1477 SysFreeString(rfcstr); 1478 } 1479 1480 hr = IMultiLanguage2_GetRfc1766FromLcid(iML2, MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), NULL); 1481 ok(hr == E_INVALIDARG, "got 0x%x (expected E_INVALIDARG)\n", hr); 1482 } 1483 1484 static void test_LcidToRfc1766(void) 1485 { 1486 CHAR expected[MAX_RFC1766_NAME]; 1487 CHAR buffer[MAX_RFC1766_NAME * 2]; 1488 HRESULT hr; 1489 DWORD i; 1490 1491 for(i = 0; i < sizeof(lcid_table) / sizeof(lcid_table[0]); i++) { 1492 1493 memset(buffer, '#', sizeof(buffer)-1); 1494 buffer[sizeof(buffer)-1] = '\0'; 1495 1496 hr = pLcidToRfc1766A(lcid_table[i].lcid, buffer, MAX_RFC1766_NAME); 1497 1498 /* IE <5.0 does not recognize 0x180c (fr-mc) and 0x457 (kok) */ 1499 ok( (hr == lcid_table[i].hr) || 1500 broken(lcid_table[i].broken_lcid && (hr == E_FAIL)), 1501 "#%02d: HRESULT 0x%x (expected 0x%x)\n", i, hr, lcid_table[i].hr); 1502 1503 if (hr != S_OK) 1504 continue; 1505 1506 LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE, lcid_table[i].rfc1766, 1507 lstrlenA(lcid_table[i].rfc1766) + 1, expected, MAX_RFC1766_NAME); 1508 1509 /* IE <6.0 return "x-kok" for LCID 0x457 ("kok") */ 1510 /* IE <5.0 return "fr" for LCID 0x180c ("fr-mc") */ 1511 ok( (!lstrcmpA(buffer, expected)) || 1512 broken(!lstrcmpA(buffer, lcid_table[i].broken_rfc)), 1513 "#%02d: got '%s' (expected '%s')\n", i, buffer, expected); 1514 1515 } 1516 1517 memset(buffer, '#', sizeof(buffer)-1); 1518 buffer[sizeof(buffer)-1] = '\0'; 1519 hr = pLcidToRfc1766A(-1, buffer, MAX_RFC1766_NAME); 1520 ok(hr == E_FAIL, "got 0x%08x and '%s' (expected E_FAIL)\n", hr, buffer); 1521 1522 hr = pLcidToRfc1766A(LANG_ENGLISH, NULL, MAX_RFC1766_NAME); 1523 ok(hr == E_INVALIDARG, "got 0x%08x (expected E_INVALIDARG)\n", hr); 1524 1525 memset(buffer, '#', sizeof(buffer)-1); 1526 buffer[sizeof(buffer)-1] = '\0'; 1527 hr = pLcidToRfc1766A(LANG_ENGLISH, buffer, -1); 1528 ok(hr == E_INVALIDARG, "got 0x%08x and '%s' (expected E_INVALIDARG)\n", hr, buffer); 1529 1530 memset(buffer, '#', sizeof(buffer)-1); 1531 buffer[sizeof(buffer)-1] = '\0'; 1532 hr = pLcidToRfc1766A(LANG_ENGLISH, buffer, 0); 1533 ok(hr == E_INVALIDARG, "got 0x%08x and '%s' (expected E_INVALIDARG)\n", hr, buffer); 1534 } 1535 1536 static void test_GetRfc1766Info(IMultiLanguage2 *iML2) 1537 { 1538 WCHAR short_broken_name[MAX_LOCALE_NAME]; 1539 CHAR rfc1766A[MAX_RFC1766_NAME + 1]; 1540 BYTE buffer[sizeof(RFC1766INFO) + 4]; 1541 PRFC1766INFO prfc = (RFC1766INFO *) buffer; 1542 HRESULT ret; 1543 DWORD i; 1544 1545 for(i = 0; i < sizeof(info_table) / sizeof(info_table[0]); i++) { 1546 memset(buffer, 'x', sizeof(RFC1766INFO) + 2); 1547 buffer[sizeof(buffer) -1] = 0; 1548 buffer[sizeof(buffer) -2] = 0; 1549 1550 ret = IMultiLanguage2_GetRfc1766Info(iML2, info_table[i].lcid, info_table[i].lang, prfc); 1551 WideCharToMultiByte(CP_ACP, 0, prfc->wszRfc1766, -1, rfc1766A, MAX_RFC1766_NAME, NULL, NULL); 1552 ok(ret == S_OK, "#%02d: got 0x%x (expected S_OK)\n", i, ret); 1553 ok(prfc->lcid == info_table[i].lcid, 1554 "#%02d: got 0x%04x (expected 0x%04x)\n", i, prfc->lcid, info_table[i].lcid); 1555 1556 ok(!lstrcmpA(rfc1766A, info_table[i].rfc1766), 1557 "#%02d: got '%s' (expected '%s')\n", i, rfc1766A, info_table[i].rfc1766); 1558 1559 /* Some IE versions truncate an oversized name one character too short */ 1560 if (info_table[i].broken_name) { 1561 lstrcpyW(short_broken_name, info_table[i].broken_name); 1562 short_broken_name[MAX_LOCALE_NAME - 2] = 0; 1563 } 1564 1565 todo_wine_if (info_table[i].todo & TODO_NAME) { 1566 ok( (!lstrcmpW(prfc->wszLocaleName, info_table[i].localename)) || 1567 (info_table[i].broken_name && ( 1568 broken(!lstrcmpW(prfc->wszLocaleName, info_table[i].broken_name)) || /* IE < 6.0 */ 1569 broken(!lstrcmpW(prfc->wszLocaleName, short_broken_name)))), 1570 "#%02d: got %s (expected %s)\n", i, 1571 wine_dbgstr_w(prfc->wszLocaleName), wine_dbgstr_w(info_table[i].localename)); 1572 } 1573 } 1574 1575 /* SUBLANG_NEUTRAL only allowed for English, Arabic, Chinese */ 1576 ret = IMultiLanguage2_GetRfc1766Info(iML2, MAKELANGID(LANG_GERMAN, SUBLANG_NEUTRAL), LANG_ENGLISH, prfc); 1577 ok(ret == E_FAIL, "got 0x%x (expected E_FAIL)\n", ret); 1578 1579 ret = IMultiLanguage2_GetRfc1766Info(iML2, MAKELANGID(LANG_ITALIAN, SUBLANG_NEUTRAL), LANG_ENGLISH, prfc); 1580 ok(ret == E_FAIL, "got 0x%x (expected E_FAIL)\n", ret); 1581 1582 /* NULL not allowed */ 1583 ret = IMultiLanguage2_GetRfc1766Info(iML2, 0, LANG_ENGLISH, prfc); 1584 ok(ret == E_FAIL, "got 0x%x (expected E_FAIL)\n", ret); 1585 1586 ret = IMultiLanguage2_GetRfc1766Info(iML2, LANG_ENGLISH, LANG_ENGLISH, NULL); 1587 ok(ret == E_INVALIDARG, "got 0x%x (expected E_INVALIDARG)\n", ret); 1588 } 1589 1590 static void test_IMultiLanguage2_ConvertStringFromUnicode(IMultiLanguage2 *iML2) 1591 { 1592 CHAR dest[MAX_PATH]; 1593 CHAR invariate[MAX_PATH]; 1594 UINT srcsz, destsz; 1595 HRESULT hr; 1596 1597 static WCHAR src[] = {'a','b','c',0}; 1598 1599 memset(invariate, 'x', sizeof(invariate)); 1600 1601 /* pSrcStr NULL */ 1602 memset(dest, 'x', sizeof(dest)); 1603 srcsz = lstrlenW(src) + 1; 1604 destsz = sizeof(dest); 1605 hr = IMultiLanguage2_ConvertStringFromUnicode(iML2, NULL, 1252, NULL, 1606 &srcsz, dest, &destsz); 1607 ok(hr == S_OK || hr == E_FAIL,"expected S_OK or E_FAIL, got %08x\n",hr); 1608 if (hr == S_OK) 1609 { 1610 ok(srcsz == lstrlenW(src) + 1, 1611 "Expected %u, got %u\n", lstrlenW(src) + 1, srcsz); 1612 } 1613 else if (hr == E_FAIL) 1614 { 1615 ok(srcsz == 0, 1616 "Expected %u, got %u\n", 0, srcsz); 1617 } 1618 1619 ok(!memcmp(dest, invariate, sizeof(dest)), 1620 "Expected dest to be unchanged, got %s\n", dest); 1621 ok(destsz == 0, "Expected 0, got %u\n", destsz); 1622 1623 /* pcSrcSize NULL */ 1624 memset(dest, 'x', sizeof(dest)); 1625 destsz = sizeof(dest); 1626 hr = IMultiLanguage2_ConvertStringFromUnicode(iML2, NULL, 1252, src, 1627 NULL, dest, &destsz); 1628 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); 1629 ok(!strncmp(dest, "abc", 3), 1630 "Expected first three chars to be \"abc\"\n"); 1631 ok(!memcmp(&dest[3], invariate, sizeof(dest) - 3), 1632 "Expected rest of dest to be unchanged, got %s\n", dest); 1633 ok(destsz == lstrlenW(src), 1634 "Expected %u, got %u\n", lstrlenW(src), destsz); 1635 1636 /* both pSrcStr and pcSrcSize NULL */ 1637 memset(dest, 'x', sizeof(dest)); 1638 destsz = sizeof(dest); 1639 hr = IMultiLanguage2_ConvertStringFromUnicode(iML2, NULL, 1252, NULL, 1640 NULL, dest, &destsz); 1641 ok(hr == S_OK || hr == E_FAIL, "Expected S_OK or E_FAIL, got %08x\n", hr); 1642 ok(!memcmp(dest, invariate, sizeof(dest)), 1643 "Expected dest to be unchanged, got %s\n", dest); 1644 ok(destsz == 0, "Expected 0, got %u\n", destsz); 1645 1646 /* pDstStr NULL */ 1647 memset(dest, 'x', sizeof(dest)); 1648 srcsz = lstrlenW(src) + 1; 1649 destsz = sizeof(dest); 1650 hr = IMultiLanguage2_ConvertStringFromUnicode(iML2, NULL, 1252, src, 1651 &srcsz, NULL, &destsz); 1652 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); 1653 ok(srcsz == lstrlenW(src) + 1, 1654 "Expected %u, got %u\n", lstrlenW(src) + 1, srcsz); 1655 ok(destsz == lstrlenW(src) + 1, 1656 "Expected %u, got %u\n", lstrlenW(src) + 1, srcsz); 1657 1658 /* pcDstSize NULL */ 1659 memset(dest, 'x', sizeof(dest)); 1660 hr = IMultiLanguage2_ConvertStringFromUnicode(iML2, NULL, 1252, src, 1661 &srcsz, dest, NULL); 1662 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); 1663 ok(srcsz == lstrlenW(src) + 1, 1664 "Expected %u, got %u\n", lstrlenW(src) + 1, srcsz); 1665 ok(!memcmp(dest, invariate, sizeof(dest)), 1666 "Expected dest to be unchanged, got %s\n", dest); 1667 1668 /* pcSrcSize is 0 */ 1669 memset(dest, 'x', sizeof(dest)); 1670 srcsz = 0; 1671 destsz = sizeof(dest); 1672 hr = IMultiLanguage2_ConvertStringFromUnicode(iML2, NULL, 1252, src, 1673 &srcsz, dest, &destsz); 1674 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); 1675 ok(srcsz == 0, "Expected 0, got %u\n", srcsz); 1676 ok(!memcmp(dest, invariate, sizeof(dest)), 1677 "Expected dest to be unchanged, got %s\n", dest); 1678 ok(destsz == 0, "Expected 0, got %u\n", destsz); 1679 1680 /* pcSrcSize does not include NULL terminator */ 1681 memset(dest, 'x', sizeof(dest)); 1682 srcsz = lstrlenW(src); 1683 destsz = sizeof(dest); 1684 hr = IMultiLanguage2_ConvertStringFromUnicode(iML2, NULL, 1252, src, 1685 &srcsz, dest, &destsz); 1686 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); 1687 ok(srcsz == lstrlenW(src), 1688 "Expected %u, got %u\n", lstrlenW(src), srcsz); 1689 ok(!strncmp(dest, "abc", 3), "Expected first three chars to be \"abc\"\n"); 1690 ok(!memcmp(&dest[3], invariate, sizeof(dest) - 3), 1691 "Expected rest of dest to be unchanged, got %s\n", dest); 1692 ok(destsz == lstrlenW(src), 1693 "Expected %u, got %u\n", lstrlenW(src), destsz); 1694 1695 /* pcSrcSize includes NULL terminator */ 1696 memset(dest, 'x', sizeof(dest)); 1697 srcsz = lstrlenW(src) + 1; 1698 destsz = sizeof(dest); 1699 hr = IMultiLanguage2_ConvertStringFromUnicode(iML2, NULL, 1252, src, 1700 &srcsz, dest, &destsz); 1701 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); 1702 ok(srcsz == lstrlenW(src) + 1, "Expected 3, got %u\n", srcsz); 1703 ok(!lstrcmpA(dest, "abc"), "Expected \"abc\", got \"%s\"\n", dest); 1704 ok(destsz == lstrlenW(src) + 1, 1705 "Expected %u, got %u\n", lstrlenW(src) + 1, destsz); 1706 1707 /* pcSrcSize is -1 */ 1708 memset(dest, 'x', sizeof(dest)); 1709 srcsz = -1; 1710 destsz = sizeof(dest); 1711 hr = IMultiLanguage2_ConvertStringFromUnicode(iML2, NULL, 1252, src, 1712 &srcsz, dest, &destsz); 1713 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); 1714 ok(srcsz == lstrlenW(src), 1715 "Expected %u, got %u\n", lstrlenW(src), srcsz); 1716 ok(!strncmp(dest, "abc", 3), "Expected first three chars to be \"abc\"\n"); 1717 ok(!memcmp(&dest[3], invariate, sizeof(dest) - 3), 1718 "Expected rest of dest to be unchanged, got %s\n", dest); 1719 ok(destsz == lstrlenW(src), 1720 "Expected %u, got %u\n", lstrlenW(src), destsz); 1721 1722 /* pcDstSize is 0 */ 1723 memset(dest, 'x', sizeof(dest)); 1724 srcsz = lstrlenW(src) + 1; 1725 destsz = 0; 1726 hr = IMultiLanguage2_ConvertStringFromUnicode(iML2, NULL, 1252, src, 1727 &srcsz, dest, &destsz); 1728 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); 1729 ok(srcsz == lstrlenW(src) + 1, 1730 "Expected %u, got %u\n", lstrlenW(src) + 1, srcsz); 1731 ok(!memcmp(dest, invariate, sizeof(dest)), 1732 "Expected dest to be unchanged, got %s\n", dest); 1733 ok(destsz == lstrlenW(src) + 1, 1734 "Expected %u, got %u\n", lstrlenW(src) + 1, destsz); 1735 1736 /* pcDstSize is not large enough */ 1737 memset(dest, 'x', sizeof(dest)); 1738 srcsz = lstrlenW(src) + 1; 1739 destsz = lstrlenW(src); 1740 hr = IMultiLanguage2_ConvertStringFromUnicode(iML2, NULL, 1252, src, 1741 &srcsz, dest, &destsz); 1742 ok(hr == E_FAIL, "Expected E_FAIL, got %08x\n", hr); 1743 ok(srcsz == 0, "Expected 0, got %u\n", srcsz); 1744 ok(!strncmp(dest, "abc", 3), "Expected first three chars to be \"abc\"\n"); 1745 ok(!memcmp(&dest[3], invariate, sizeof(dest) - 3), 1746 "Expected rest of dest to be unchanged, got %s\n", dest); 1747 ok(destsz == 0, "Expected 0, got %u\n", srcsz); 1748 1749 /* pcDstSize (bytes) does not leave room for NULL terminator */ 1750 memset(dest, 'x', sizeof(dest)); 1751 srcsz = lstrlenW(src) + 1; 1752 destsz = lstrlenW(src) * sizeof(WCHAR); 1753 hr = IMultiLanguage2_ConvertStringFromUnicode(iML2, NULL, 1252, src, 1754 &srcsz, dest, &destsz); 1755 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); 1756 ok(srcsz == lstrlenW(src) + 1, 1757 "Expected %u, got %u\n", lstrlenW(src) + 1, srcsz); 1758 ok(!lstrcmpA(dest, "abc"), "Expected \"abc\", got \"%s\"\n", dest); 1759 ok(destsz == lstrlenW(src) + 1, 1760 "Expected %u, got %u\n", lstrlenW(src) + 1, destsz); 1761 } 1762 1763 static void test_ConvertINetUnicodeToMultiByte(void) 1764 { 1765 CHAR dest[MAX_PATH]; 1766 CHAR invariate[MAX_PATH]; 1767 INT srcsz, destsz; 1768 HRESULT hr; 1769 1770 static WCHAR src[] = {'a','b','c',0}; 1771 1772 memset(invariate, 'x', sizeof(invariate)); 1773 1774 /* lpSrcStr NULL */ 1775 memset(dest, 'x', sizeof(dest)); 1776 srcsz = lstrlenW(src) + 1; 1777 destsz = sizeof(dest); 1778 hr = pConvertINetUnicodeToMultiByte(NULL, 1252, NULL, &srcsz, dest, &destsz); 1779 ok(hr == S_OK || hr == E_FAIL, "Expected S_OK or E_FAIL, got %08x\n", hr); 1780 if (hr == S_OK) 1781 ok(srcsz == lstrlenW(src) + 1, 1782 "Expected %u, got %u\n", lstrlenW(src) + 1, srcsz); 1783 else if (hr == E_FAIL) 1784 ok(srcsz == 0, 1785 "Expected %u, got %u\n", 0, srcsz); 1786 ok(!memcmp(dest, invariate, sizeof(dest)), 1787 "Expected dest to be unchanged, got %s\n", dest); 1788 ok(destsz == 0, "Expected 0, got %u\n", destsz); 1789 1790 /* lpnWideCharCount NULL */ 1791 memset(dest, 'x', sizeof(dest)); 1792 destsz = sizeof(dest); 1793 hr = pConvertINetUnicodeToMultiByte(NULL, 1252, src, NULL, dest, &destsz); 1794 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); 1795 ok(!strncmp(dest, "abc", 3), 1796 "Expected first three chars to be \"abc\"\n"); 1797 ok(!memcmp(&dest[3], invariate, sizeof(dest) - 3), 1798 "Expected rest of dest to be unchanged, got %s\n", dest); 1799 ok(destsz == lstrlenW(src), 1800 "Expected %u, got %u\n", lstrlenW(src), destsz); 1801 1802 /* both lpSrcStr and lpnWideCharCount NULL */ 1803 memset(dest, 'x', sizeof(dest)); 1804 destsz = sizeof(dest); 1805 hr = pConvertINetUnicodeToMultiByte(NULL, 1252, NULL, NULL, dest, &destsz); 1806 ok(hr == S_OK || hr == E_FAIL, "Expected S_OK or E_FAIL, got %08x\n", hr); 1807 ok(!memcmp(dest, invariate, sizeof(dest)), 1808 "Expected dest to be unchanged, got %s\n", dest); 1809 ok(destsz == 0, "Expected 0, got %u\n", destsz); 1810 1811 /* lpDstStr NULL */ 1812 memset(dest, 'x', sizeof(dest)); 1813 srcsz = lstrlenW(src) + 1; 1814 destsz = sizeof(dest); 1815 hr = pConvertINetUnicodeToMultiByte(NULL, 1252, src, &srcsz, NULL, &destsz); 1816 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); 1817 ok(srcsz == lstrlenW(src) + 1, 1818 "Expected %u, got %u\n", lstrlenW(src) + 1, srcsz); 1819 ok(destsz == lstrlenW(src) + 1, 1820 "Expected %u, got %u\n", lstrlenW(src) + 1, srcsz); 1821 1822 /* lpnMultiCharCount NULL */ 1823 memset(dest, 'x', sizeof(dest)); 1824 hr = pConvertINetUnicodeToMultiByte(NULL, 1252, src, &srcsz, dest, NULL); 1825 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); 1826 ok(srcsz == lstrlenW(src) + 1, 1827 "Expected %u, got %u\n", lstrlenW(src) + 1, srcsz); 1828 ok(!memcmp(dest, invariate, sizeof(dest)), 1829 "Expected dest to be unchanged, got %s\n", dest); 1830 1831 /* lpnWideCharCount is 0 */ 1832 memset(dest, 'x', sizeof(dest)); 1833 srcsz = 0; 1834 destsz = sizeof(dest); 1835 hr = pConvertINetUnicodeToMultiByte(NULL, 1252, src, &srcsz, dest, &destsz); 1836 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); 1837 ok(srcsz == 0, "Expected 0, got %u\n", srcsz); 1838 ok(!memcmp(dest, invariate, sizeof(dest)), 1839 "Expected dest to be unchanged, got %s\n", dest); 1840 ok(destsz == 0, "Expected 0, got %u\n", destsz); 1841 1842 /* lpnWideCharCount does not include NULL terminator */ 1843 memset(dest, 'x', sizeof(dest)); 1844 srcsz = lstrlenW(src); 1845 destsz = sizeof(dest); 1846 hr = pConvertINetUnicodeToMultiByte(NULL, 1252, src, &srcsz, dest, &destsz); 1847 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); 1848 ok(srcsz == lstrlenW(src), 1849 "Expected %u, got %u\n", lstrlenW(src), srcsz); 1850 ok(!strncmp(dest, "abc", 3), "Expected first three chars to be \"abc\"\n"); 1851 ok(!memcmp(&dest[3], invariate, sizeof(dest) - 3), 1852 "Expected rest of dest to be unchanged, got %s\n", dest); 1853 ok(destsz == lstrlenW(src), 1854 "Expected %u, got %u\n", lstrlenW(src), destsz); 1855 1856 /* lpnWideCharCount includes NULL terminator */ 1857 memset(dest, 'x', sizeof(dest)); 1858 srcsz = lstrlenW(src) + 1; 1859 destsz = sizeof(dest); 1860 hr = pConvertINetUnicodeToMultiByte(NULL, 1252, src, &srcsz, dest, &destsz); 1861 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); 1862 ok(srcsz == lstrlenW(src) + 1, "Expected 3, got %u\n", srcsz); 1863 ok(!lstrcmpA(dest, "abc"), "Expected \"abc\", got \"%s\"\n", dest); 1864 ok(destsz == lstrlenW(src) + 1, 1865 "Expected %u, got %u\n", lstrlenW(src) + 1, destsz); 1866 1867 /* lpnWideCharCount is -1 */ 1868 memset(dest, 'x', sizeof(dest)); 1869 srcsz = -1; 1870 destsz = sizeof(dest); 1871 hr = pConvertINetUnicodeToMultiByte(NULL, 1252, src, &srcsz, dest, &destsz); 1872 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); 1873 ok(srcsz == lstrlenW(src), 1874 "Expected %u, got %u\n", lstrlenW(src), srcsz); 1875 ok(!strncmp(dest, "abc", 3), "Expected first three chars to be \"abc\"\n"); 1876 ok(!memcmp(&dest[3], invariate, sizeof(dest) - 3), 1877 "Expected rest of dest to be unchanged, got %s\n", dest); 1878 ok(destsz == lstrlenW(src), 1879 "Expected %u, got %u\n", lstrlenW(src), destsz); 1880 1881 /* lpnMultiCharCount is 0 */ 1882 memset(dest, 'x', sizeof(dest)); 1883 srcsz = lstrlenW(src) + 1; 1884 destsz = 0; 1885 hr = pConvertINetUnicodeToMultiByte(NULL, 1252, src, &srcsz, dest, &destsz); 1886 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); 1887 ok(srcsz == lstrlenW(src) + 1, 1888 "Expected %u, got %u\n", lstrlenW(src) + 1, srcsz); 1889 ok(!memcmp(dest, invariate, sizeof(dest)), 1890 "Expected dest to be unchanged, got %s\n", dest); 1891 ok(destsz == lstrlenW(src) + 1, 1892 "Expected %u, got %u\n", lstrlenW(src) + 1, destsz); 1893 1894 /* lpnMultiCharCount is not large enough */ 1895 memset(dest, 'x', sizeof(dest)); 1896 srcsz = lstrlenW(src) + 1; 1897 destsz = lstrlenW(src); 1898 hr = pConvertINetUnicodeToMultiByte(NULL, 1252, src, &srcsz, dest, &destsz); 1899 ok(hr == E_FAIL, "Expected E_FAIL, got %08x\n", hr); 1900 ok(srcsz == 0, "Expected 0, got %u\n", srcsz); 1901 ok(!strncmp(dest, "abc", 3), "Expected first three chars to be \"abc\"\n"); 1902 ok(!memcmp(&dest[3], invariate, sizeof(dest) - 3), 1903 "Expected rest of dest to be unchanged, got %s\n", dest); 1904 ok(destsz == 0, "Expected 0, got %u\n", srcsz); 1905 1906 /* lpnMultiCharCount (bytes) does not leave room for NULL terminator */ 1907 memset(dest, 'x', sizeof(dest)); 1908 srcsz = lstrlenW(src) + 1; 1909 destsz = lstrlenW(src) * sizeof(WCHAR); 1910 hr = pConvertINetUnicodeToMultiByte(NULL, 1252, src, &srcsz, dest, &destsz); 1911 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); 1912 ok(srcsz == lstrlenW(src) + 1, 1913 "Expected %u, got %u\n", lstrlenW(src) + 1, srcsz); 1914 ok(!lstrcmpA(dest, "abc"), "Expected \"abc\", got \"%s\"\n", dest); 1915 ok(destsz == lstrlenW(src) + 1, 1916 "Expected %u, got %u\n", lstrlenW(src) + 1, destsz); 1917 } 1918 1919 static void test_JapaneseConversion(void) 1920 { 1921 /* Data */ 1922 static WCHAR unc_jp[9][12] = { 1923 {9,0x31,0x20,0x3042,0x3044,0x3046,0x3048,0x304a,0x000d,0x000a}, 1924 {9,0x31,0x20,0x30a2,0x30a4,0x30a6,0x30a8,0x30aa,0x000d,0x000a}, 1925 {9,0x31,0x20,0xff71,0xff72,0xff73,0xff74,0xff75,0x000d,0x000a}, 1926 {9,0x31,0x20,0x3041,0x3043,0x3045,0x3047,0x3049,0x000d,0x000a}, 1927 {9,0x31,0x20,0x30a1,0x30a3,0x30a5,0x30a7,0x30a9,0x000d,0x000a}, 1928 {9,0x31,0x20,0xff67,0xff68,0xff69,0xff6a,0xff6b,0x000d,0x000a}, 1929 {9,0x31,0x20,0x300c,0x65e5,0x672c,0x8a9e,0x300d,0x000d,0x000a}, 1930 {7,0x31,0x20,0x25c7,0x25c7,0x3012,0x000d,0x000a}, 1931 {11,0x31,0x20,0x203b,0x3010,0x0074,0x0065,0x0073,0x0074,0x3011,0x000d,0x000a} 1932 }; 1933 static CHAR jis_jp[9][27] = { 1934 {20,0x31,0x20,0x1b,0x24,0x42,0x24,0x22,0x24,0x24,0x24,0x26,0x24,0x28, 1935 0x24,0x2a,0x1b,0x28,0x42,0x0d,0x0a}, 1936 {20,0x31,0x20,0x1b,0x24,0x42,0x25,0x22,0x25,0x24,0x25,0x26,0x25,0x28, 1937 0x25,0x2a,0x1b,0x28,0x42,0x0d,0x0a}, 1938 {20,0x31,0x20,0x1b,0x24,0x42,0x25,0x22,0x25,0x24,0x25,0x26,0x25,0x28, 1939 0x25,0x2a,0x1b,0x28,0x42,0x0d,0x0a}, 1940 {20,0x31,0x20,0x1b,0x24,0x42,0x24,0x21,0x24,0x23,0x24,0x25,0x24,0x27, 1941 0x24,0x29,0x1b,0x28,0x42,0x0d,0x0a}, 1942 {20,0x31,0x20,0x1b,0x24,0x42,0x25,0x21,0x25,0x23,0x25,0x25,0x25,0x27, 1943 0x25,0x29,0x1b,0x28,0x42,0x0d,0x0a}, 1944 {20,0x31,0x20,0x1b,0x24,0x42,0x25,0x21,0x25,0x23,0x25,0x25,0x25,0x27, 1945 0x25,0x29,0x1b,0x28,0x42,0x0d,0x0a}, 1946 {20,0x31,0x20,0x1b,0x24,0x42,0x21,0x56,0x46,0x7c,0x4b,0x5c,0x38,0x6c, 1947 0x21,0x57,0x1b,0x28,0x42,0x0d,0x0a}, 1948 {16,0x31,0x20,0x1b,0x24,0x42,0x21,0x7e,0x21,0x7e,0x22,0x29,0x1b,0x28, 1949 0x42,0x0d,0x0a}, 1950 {26,0x31,0x20,0x1b,0x24,0x42,0x22,0x28,0x21,0x5a,0x1b,0x28,0x42,0x74, 1951 0x65,0x73,0x74,0x1b,0x24,0x42,0x21,0x5b,0x1b,0x28,0x42,0x0d,0x0a} 1952 }; 1953 static CHAR sjis_jp[9][15] = { 1954 {14,0x31,0x20,0x82,0xa0,0x82,0xa2,0x82,0xa4,0x82,0xa6,0x82,0xa8,0x0d,0x0a}, 1955 {14,0x31,0x20,0x83,0x41,0x83,0x43,0x83,0x45,0x83,0x47,0x83,0x49,0x0d,0x0a}, 1956 {9,0x31,0x20,0xb1,0xb2,0xb3,0xb4,0xb5,0x0d,0x0a}, 1957 {14,0x31,0x20,0x82,0x9f,0x82,0xa1,0x82,0xa3,0x82,0xa5,0x82,0xa7,0x0d,0x0a}, 1958 {14,0x31,0x20,0x83,0x40,0x83,0x42,0x83,0x44,0x83,0x46,0x83,0x48,0x0d,0x0a}, 1959 {9,0x31,0x20,0xa7,0xa8,0xa9,0xaa,0xab,0x0d,0x0a}, 1960 {14,0x31,0x20,0x81,0x75,0x93,0xfa,0x96,0x7b,0x8c,0xea,0x81,0x76,0x0d,0x0a}, 1961 {10,0x31,0x20,0x81,0x9e,0x81,0x9e,0x81,0xa7,0x0d,0x0a}, 1962 {14,0x31,0x20,0x81,0xa6,0x81,0x79,0x74,0x65,0x73,0x74,0x81,0x7a,0x0d,0x0a} 1963 }; 1964 static CHAR euc_jp[9][15] = { 1965 {14,0x31,0x20,0xa4,0xa2,0xa4,0xa4,0xa4,0xa6,0xa4,0xa8,0xa4,0xaa,0x0d,0x0a}, 1966 {14,0x31,0x20,0xa5,0xa2,0xa5,0xa4,0xa5,0xa6,0xa5,0xa8,0xa5,0xaa,0x0d,0x0a}, 1967 {14,0x31,0x20,0x8e,0xb1,0x8e,0xb2,0x8e,0xb3,0x8e,0xb4,0x8e,0xb5,0x0d,0x0a}, 1968 {14,0x31,0x20,0xa4,0xa1,0xa4,0xa3,0xa4,0xa5,0xa4,0xa7,0xa4,0xa9,0x0d,0x0a}, 1969 {14,0x31,0x20,0xa5,0xa1,0xa5,0xa3,0xa5,0xa5,0xa5,0xa7,0xa5,0xa9,0x0d,0x0a}, 1970 {14,0x31,0x20,0x8e,0xa7,0x8e,0xa8,0x8e,0xa9,0x8e,0xaa,0x8e,0xab,0x0d,0x0a}, 1971 {14,0x31,0x20,0xa1,0xd6,0xc6,0xfc,0xcb,0xdc,0xb8,0xec,0xa1,0xd7,0x0d,0x0a}, 1972 {10,0x31,0x20,0xa1,0xfe,0xa1,0xfe,0xa2,0xa9,0x0d,0x0a}, 1973 {14,0x31,0x20,0xa2,0xa8,0xa1,0xda,0x74,0x65,0x73,0x74,0xa1,0xdb,0x0d,0x0a} 1974 }; 1975 1976 INT srcsz, destsz; 1977 INT i; 1978 HRESULT hr; 1979 CHAR output[30]; 1980 WCHAR outputW[30]; 1981 int outlen; 1982 1983 /* test unc->jis */ 1984 for (i = 0; i < 9; i++) 1985 { 1986 int j; 1987 destsz = 30; 1988 outlen = jis_jp[i][0]; 1989 srcsz = unc_jp[i][0]; 1990 hr = pConvertINetUnicodeToMultiByte(NULL, 50220, &unc_jp[i][1], &srcsz, output, &destsz); 1991 if (hr == S_FALSE) 1992 { 1993 skip("Code page identifier 50220 is not supported\n"); 1994 break; 1995 } 1996 ok(hr == S_OK,"(%i) Expected S_OK, got %08x\n", i, hr); 1997 ok(destsz == outlen, "(%i) Expected %i, got %i\n",i,outlen,destsz); 1998 ok(srcsz == unc_jp[i][0],"(%i) Expected %i, got %i\n",i,unc_jp[i][0],srcsz); 1999 ok(memcmp(output,&jis_jp[i][1],destsz)==0,"(%i) Strings do not match\n",i); 2000 2001 /* and back */ 2002 srcsz = outlen; 2003 destsz = 30; 2004 hr = pConvertINetMultiByteToUnicode(NULL, 50220, output, &srcsz, outputW,&destsz); 2005 2006 /* 2007 * JIS does not have hankata so it get automatically converted to 2008 * zenkata. this means that strings 1 and 2 are identical as well as 2009 * strings 4 and 5. 2010 */ 2011 j = i; 2012 if (i == 2) j = 1; 2013 if (i == 5) j = 4; 2014 2015 ok(hr == S_OK,"(%i) Expected S_OK, got %08x\n",i, hr); 2016 ok(destsz == unc_jp[j][0],"(%i) Expected %i, got %i\n",i,unc_jp[j][0],destsz); 2017 ok(srcsz == outlen,"(%i) Expected %i, got %i\n",i,outlen,srcsz); 2018 ok(memcmp(outputW,&unc_jp[j][1],destsz)==0,"(%i) Strings do not match\n",i); 2019 } 2020 2021 /* test unc->sjis */ 2022 for (i = 0; i < 9; i++) 2023 { 2024 destsz = 30; 2025 outlen = sjis_jp[i][0]; 2026 srcsz = unc_jp[i][0]; 2027 2028 hr = pConvertINetUnicodeToMultiByte(NULL, 932, &unc_jp[i][1], &srcsz, output, &destsz); 2029 if (hr == S_FALSE) 2030 { 2031 skip("Code page identifier 932 is not supported\n"); 2032 break; 2033 } 2034 ok(hr == S_OK,"(%i) Expected S_OK, got %08x\n",i,hr); 2035 ok(destsz == outlen,"(%i) Expected %i, got %i\n",i,outlen,destsz); 2036 ok(srcsz == unc_jp[i][0],"(%i) Expected %i, got %i\n",i,unc_jp[i][0],srcsz); 2037 ok(memcmp(output,&sjis_jp[i][1],outlen)==0,"(%i) Strings do not match\n",i); 2038 2039 srcsz = outlen; 2040 destsz = 30; 2041 hr = pConvertINetMultiByteToUnicode(NULL, 932, output, &srcsz, outputW,&destsz); 2042 2043 ok(hr == S_OK,"(%i) Expected S_OK, got %08x\n", i, hr); 2044 ok(destsz == unc_jp[i][0],"(%i) Expected %i, got %i\n",i,unc_jp[i][0],destsz); 2045 ok(srcsz == outlen,"(%i) Expected %i, got %i\n",i,outlen,srcsz); 2046 ok(memcmp(outputW,&unc_jp[i][1],destsz)==0,"(%i) Strings do not match\n",i); 2047 } 2048 2049 /* test unc->euc */ 2050 for (i = 0; i < 9; i++) 2051 { 2052 destsz = 30; 2053 outlen = euc_jp[i][0]; 2054 srcsz = unc_jp[i][0]; 2055 2056 hr = pConvertINetUnicodeToMultiByte(NULL, 51932, &unc_jp[i][1], &srcsz, output, &destsz); 2057 if (hr == S_FALSE) 2058 { 2059 skip("Code page identifier 51932 is not supported\n"); 2060 break; 2061 } 2062 ok(hr == S_OK, "(%i) Expected S_OK, got %08x\n",i,hr); 2063 ok(destsz == outlen, "(%i) Expected %i, got %i\n",i,outlen,destsz); 2064 ok(srcsz == unc_jp[i][0],"(%i) Expected %i, got %i\n",i,unc_jp[i][0],destsz); 2065 ok(memcmp(output,&euc_jp[i][1],outlen)==0,"(%i) Strings do not match\n",i); 2066 2067 srcsz = outlen; 2068 destsz = 30; 2069 hr = pConvertINetMultiByteToUnicode(NULL, 51932, output, &srcsz, outputW,&destsz); 2070 2071 ok(hr == S_OK,"(%i) Expected S_OK, got %08x\n",i,hr); 2072 ok(destsz == unc_jp[i][0],"(%i) Expected %i, got %i\n",i,unc_jp[i][0],destsz); 2073 ok(srcsz == outlen,"(%i) Expected %i, got %i\n",i,outlen,srcsz); 2074 ok(memcmp(outputW,&unc_jp[i][1],destsz)==0,"(%i) Strings do not match\n",i); 2075 } 2076 2077 /* Japanese autodetect */ 2078 i = 0; 2079 destsz = 30; 2080 srcsz = jis_jp[i][0]; 2081 hr = pConvertINetMultiByteToUnicode(NULL, 50932, &jis_jp[i][1], &srcsz, outputW, &destsz); 2082 if (hr == S_FALSE) 2083 { 2084 skip("Code page identifier 50932 is not supported\n"); 2085 return; 2086 } 2087 ok(hr == S_OK,"(%i) Expected S_OK, got %08x\n",i,hr); 2088 ok(destsz == unc_jp[i][0],"(%i) Expected %i, got %i\n",i,unc_jp[i][0],destsz); 2089 ok(srcsz == jis_jp[i][0],"(%i) Expected %i, got %i\n",i,jis_jp[i][0],srcsz); 2090 ok(memcmp(outputW,&unc_jp[i][1],destsz)==0,"(%i) Strings do not match\n",i); 2091 2092 i = 1; 2093 destsz = 30; 2094 srcsz = sjis_jp[i][0]; 2095 hr = pConvertINetMultiByteToUnicode(NULL, 50932, &sjis_jp[i][1], &srcsz, outputW, &destsz); 2096 ok(hr == S_OK,"(%i) Expected S_OK, got %08x\n",i,hr); 2097 ok(destsz == unc_jp[i][0],"(%i) Expected %i, got %i\n",i,unc_jp[i][0],destsz); 2098 ok(srcsz == sjis_jp[i][0],"(%i) Expected %i, got %i\n",i,sjis_jp[i][0],srcsz); 2099 ok(memcmp(outputW,&unc_jp[i][1],destsz)==0,"(%i) Strings do not match\n",i); 2100 } 2101 2102 static void test_GetScriptFontInfo(IMLangFontLink2 *font_link) 2103 { 2104 HRESULT hr; 2105 UINT nfonts; 2106 SCRIPTFONTINFO sfi[1]; 2107 2108 nfonts = 0; 2109 hr = IMLangFontLink2_GetScriptFontInfo(font_link, sidAsciiLatin, 0, &nfonts, NULL); 2110 ok(hr == S_OK, "GetScriptFontInfo failed %u\n", GetLastError()); 2111 ok(nfonts, "unexpected result\n"); 2112 2113 nfonts = 0; 2114 hr = IMLangFontLink2_GetScriptFontInfo(font_link, sidAsciiLatin, SCRIPTCONTF_FIXED_FONT, &nfonts, NULL); 2115 ok(hr == S_OK, "GetScriptFontInfo failed %u\n", GetLastError()); 2116 ok(nfonts, "unexpected result\n"); 2117 2118 nfonts = 0; 2119 hr = IMLangFontLink2_GetScriptFontInfo(font_link, sidAsciiLatin, SCRIPTCONTF_PROPORTIONAL_FONT, &nfonts, NULL); 2120 ok(hr == S_OK, "GetScriptFontInfo failed %u\n", GetLastError()); 2121 ok(nfonts, "unexpected result\n"); 2122 2123 nfonts = 1; 2124 memset(sfi, 0, sizeof(sfi)); 2125 hr = IMLangFontLink2_GetScriptFontInfo(font_link, sidAsciiLatin, SCRIPTCONTF_FIXED_FONT, &nfonts, sfi); 2126 ok(hr == S_OK, "GetScriptFontInfo failed %u\n", GetLastError()); 2127 ok(nfonts == 1, "got %u, expected 1\n", nfonts); 2128 ok(sfi[0].scripts != 0, "unexpected result\n"); 2129 ok(sfi[0].wszFont[0], "unexpected result\n"); 2130 2131 nfonts = 1; 2132 memset(sfi, 0, sizeof(sfi)); 2133 hr = IMLangFontLink2_GetScriptFontInfo(font_link, sidAsciiLatin, SCRIPTCONTF_PROPORTIONAL_FONT, &nfonts, sfi); 2134 ok(hr == S_OK, "GetScriptFontInfo failed %u\n", GetLastError()); 2135 ok(nfonts == 1, "got %u, expected 1\n", nfonts); 2136 ok(sfi[0].scripts != 0, "unexpected result\n"); 2137 ok(sfi[0].wszFont[0], "unexpected result\n"); 2138 } 2139 2140 static void test_CodePageToScriptID(IMLangFontLink2 *font_link) 2141 { 2142 HRESULT hr; 2143 UINT i; 2144 SCRIPT_ID sid; 2145 static const struct 2146 { 2147 UINT cp; 2148 SCRIPT_ID sid; 2149 HRESULT hr; 2150 } 2151 cp_sid[] = 2152 { 2153 {874, sidThai}, 2154 {932, sidKana}, 2155 {936, sidHan}, 2156 {949, sidHangul}, 2157 {950, sidBopomofo}, 2158 {1250, sidAsciiLatin}, 2159 {1251, sidCyrillic}, 2160 {1252, sidAsciiLatin}, 2161 {1253, sidGreek}, 2162 {1254, sidAsciiLatin}, 2163 {1255, sidHebrew}, 2164 {1256, sidArabic}, 2165 {1257, sidAsciiLatin}, 2166 {1258, sidAsciiLatin}, 2167 {CP_UNICODE, 0, E_FAIL} 2168 }; 2169 2170 for (i = 0; i < sizeof(cp_sid)/sizeof(cp_sid[0]); i++) 2171 { 2172 hr = IMLangFontLink2_CodePageToScriptID(font_link, cp_sid[i].cp, &sid); 2173 ok(hr == cp_sid[i].hr, "%u CodePageToScriptID failed 0x%08x %u\n", i, hr, GetLastError()); 2174 if (SUCCEEDED(hr)) 2175 { 2176 ok(sid == cp_sid[i].sid, 2177 "%u got sid %u for codepage %u, expected %u\n", i, sid, cp_sid[i].cp, cp_sid[i].sid); 2178 } 2179 } 2180 } 2181 2182 static void test_GetFontUnicodeRanges(IMLangFontLink2 *font_link) 2183 { 2184 HRESULT hr; 2185 UINT count; 2186 HFONT hfont, old_hfont; 2187 LOGFONTA lf; 2188 HDC hdc; 2189 UNICODERANGE *ur; 2190 2191 hdc = CreateCompatibleDC(0); 2192 memset(&lf, 0, sizeof(lf)); 2193 lstrcpyA(lf.lfFaceName, "Arial"); 2194 hfont = CreateFontIndirectA(&lf); 2195 old_hfont = SelectObject(hdc, hfont); 2196 2197 count = 0; 2198 hr = IMLangFontLink2_GetFontUnicodeRanges(font_link, NULL, &count, NULL); 2199 ok(hr == E_FAIL, "expected E_FAIL, got 0x%08x\n", hr); 2200 2201 hr = IMLangFontLink2_GetFontUnicodeRanges(font_link, hdc, NULL, NULL); 2202 ok(hr == E_INVALIDARG, "expected E_FAIL, got 0x%08x\n", hr); 2203 2204 count = 0; 2205 hr = IMLangFontLink2_GetFontUnicodeRanges(font_link, hdc, &count, NULL); 2206 ok(hr == S_OK, "expected S_OK, got 0x%08x\n", hr); 2207 ok(count, "expected count > 0\n"); 2208 2209 ur = HeapAlloc(GetProcessHeap(), 0, sizeof(*ur) * count); 2210 2211 hr = IMLangFontLink2_GetFontUnicodeRanges(font_link, hdc, &count, ur); 2212 ok(hr == S_OK, "expected S_OK, got 0x%08x\n", hr); 2213 2214 count--; 2215 hr = IMLangFontLink2_GetFontUnicodeRanges(font_link, hdc, &count, ur); 2216 ok(hr == S_OK, "expected S_OK, got 0x%08x\n", hr); 2217 2218 HeapFree(GetProcessHeap(), 0, ur); 2219 2220 SelectObject(hdc, old_hfont); 2221 DeleteObject(hfont); 2222 DeleteDC(hdc); 2223 } 2224 2225 static void test_IsCodePageInstallable(IMultiLanguage2 *ml2) 2226 { 2227 UINT i; 2228 HRESULT hr; 2229 2230 for (i = 0; i < 0xffff; i++) 2231 { 2232 hr = IMultiLanguage2_IsCodePageInstallable(ml2, i); 2233 2234 /* it would be better to use IMultiLanguage2_ValidateCodePageEx here but that brings 2235 * up an installation dialog on some platforms, even when specifying CPIOD_PEEK. 2236 */ 2237 if (IsValidCodePage(i)) 2238 ok(hr == S_OK || 2239 broken(hr == S_FALSE) || /* win2k */ 2240 broken(hr == E_INVALIDARG), /* win2k */ 2241 "code page %u is valid but not installable 0x%08x\n", i, hr); 2242 } 2243 } 2244 2245 static void test_GetGlobalFontLinkObject(void) 2246 { 2247 HRESULT ret; 2248 void *unknown; 2249 2250 ret = GetGlobalFontLinkObject(NULL); 2251 ok(ret == E_INVALIDARG, "expected E_INVALIDARG got %#x\n", ret); 2252 2253 unknown = (void *)0xdeadbeef; 2254 ret = GetGlobalFontLinkObject(&unknown); 2255 todo_wine { 2256 ok(ret == S_OK, "expected S_OK got %#x\n", ret); 2257 ok(unknown != NULL && unknown != (void *)0xdeadbeef, 2258 "GetGlobalFontLinkObject() returned %p\n", unknown); 2259 } 2260 } 2261 2262 static void test_IMLangConvertCharset(IMultiLanguage *ml) 2263 { 2264 IMLangConvertCharset *convert; 2265 WCHAR strW[] = {'a','b','c','d',0}; 2266 UINT cp, src_size, dst_size; 2267 char strA[] = "abcd"; 2268 WCHAR buffW[20]; 2269 HRESULT hr; 2270 2271 hr = IMultiLanguage_CreateConvertCharset(ml, CP_ACP, CP_UTF8, 0, &convert); 2272 todo_wine 2273 ok(hr == S_FALSE, "expected S_FALSE got 0x%08x\n", hr); 2274 2275 hr = IMLangConvertCharset_GetSourceCodePage(convert, NULL); 2276 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr); 2277 2278 cp = CP_UTF8; 2279 hr = IMLangConvertCharset_GetSourceCodePage(convert, &cp); 2280 ok(hr == S_OK, "expected S_OK got 0x%08x\n", hr); 2281 ok(cp == CP_ACP, "got %d\n", cp); 2282 2283 hr = IMLangConvertCharset_GetDestinationCodePage(convert, NULL); 2284 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr); 2285 2286 cp = CP_ACP; 2287 hr = IMLangConvertCharset_GetDestinationCodePage(convert, &cp); 2288 ok(hr == S_OK, "expected S_OK got 0x%08x\n", hr); 2289 ok(cp == CP_UTF8, "got %d\n", cp); 2290 2291 /* DoConversionToUnicode */ 2292 hr = IMLangConvertCharset_Initialize(convert, CP_UTF8, CP_UNICODE, 0); 2293 ok(hr == S_OK, "expected S_OK got 0x%08x\n", hr); 2294 2295 hr = IMLangConvertCharset_DoConversionToUnicode(convert, NULL, NULL, NULL, NULL); 2296 ok(hr == E_FAIL || broken(hr == S_OK) /* win2k */, "got 0x%08x\n", hr); 2297 2298 src_size = -1; 2299 dst_size = 20; 2300 buffW[0] = 0; 2301 buffW[4] = 4; 2302 hr = IMLangConvertCharset_DoConversionToUnicode(convert, strA, &src_size, buffW, &dst_size); 2303 ok(hr == S_OK, "got 0x%08x\n", hr); 2304 ok(!memcmp(buffW, strW, 4*sizeof(WCHAR)), "got converted string %s\n", wine_dbgstr_wn(buffW, dst_size)); 2305 ok(dst_size == 4, "got %d\n", dst_size); 2306 ok(buffW[4] == 4, "got %d\n", buffW[4]); 2307 ok(src_size == 4, "got %d\n", src_size); 2308 2309 src_size = -1; 2310 dst_size = 0; 2311 buffW[0] = 1; 2312 hr = IMLangConvertCharset_DoConversionToUnicode(convert, strA, &src_size, buffW, &dst_size); 2313 ok(hr == S_OK, "got 0x%08x\n", hr); 2314 ok(buffW[0] == 1, "got %d\n", buffW[0]); 2315 ok(dst_size == 4, "got %d\n", dst_size); 2316 ok(src_size == 4, "got %d\n", src_size); 2317 2318 hr = IMLangConvertCharset_Initialize(convert, CP_UNICODE, CP_UNICODE, 0); 2319 ok(hr == S_OK, "expected S_OK got 0x%08x\n", hr); 2320 2321 IMLangConvertCharset_Release(convert); 2322 } 2323 2324 static const char stream_data[] = "VCARD2.1test;test"; 2325 static ULONG stream_pos; 2326 2327 static HRESULT WINAPI stream_QueryInterface(IStream *iface, REFIID riid, void **obj) 2328 { 2329 ok(FALSE, "unexpected call\n"); 2330 return E_NOINTERFACE; 2331 } 2332 2333 static ULONG WINAPI stream_AddRef(IStream *iface) 2334 { 2335 ok(FALSE, "unexpected call\n"); 2336 return 2; 2337 } 2338 2339 static ULONG WINAPI stream_Release(IStream *iface) 2340 { 2341 ok(FALSE, "unexpected call\n"); 2342 return 1; 2343 } 2344 2345 static HRESULT WINAPI stream_Read(IStream *iface, void *buf, ULONG len, ULONG *read) 2346 { 2347 ULONG size; 2348 2349 if (stream_pos == sizeof(stream_data) - 1) 2350 { 2351 *read = 0; 2352 return S_FALSE; 2353 } 2354 size = min(sizeof(stream_data) - 1 - stream_pos, len); 2355 memcpy(buf, stream_data + stream_pos, size); 2356 stream_pos += size; 2357 *read = size; 2358 return S_OK; 2359 } 2360 2361 static HRESULT WINAPI stream_Write(IStream *iface, const void *buf, ULONG len, ULONG *written) 2362 { 2363 ok(FALSE, "unexpected call\n"); 2364 return E_NOTIMPL; 2365 } 2366 2367 static HRESULT WINAPI stream_Seek(IStream *iface, LARGE_INTEGER move, DWORD origin, 2368 ULARGE_INTEGER *newpos) 2369 { 2370 if (origin == STREAM_SEEK_SET) 2371 stream_pos = move.QuadPart; 2372 else if (origin == STREAM_SEEK_CUR) 2373 stream_pos += move.QuadPart; 2374 else if (origin == STREAM_SEEK_END) 2375 stream_pos = sizeof(stream_data) - 1 - move.QuadPart; 2376 2377 if (newpos) newpos->QuadPart = stream_pos; 2378 return S_OK; 2379 } 2380 2381 static HRESULT WINAPI stream_SetSize(IStream *iface, ULARGE_INTEGER newsize) 2382 { 2383 ok(FALSE, "unexpected call\n"); 2384 return E_NOTIMPL; 2385 } 2386 2387 static HRESULT WINAPI stream_CopyTo(IStream *iface, IStream *stream, ULARGE_INTEGER len, 2388 ULARGE_INTEGER *read, ULARGE_INTEGER *written) 2389 { 2390 ok(FALSE, "unexpected call\n"); 2391 return E_NOTIMPL; 2392 } 2393 2394 static HRESULT WINAPI stream_Commit(IStream *iface, DWORD flags) 2395 { 2396 ok(FALSE, "unexpected call\n"); 2397 return E_NOTIMPL; 2398 } 2399 2400 static HRESULT WINAPI stream_Revert(IStream *iface) 2401 { 2402 ok(FALSE, "unexpected call\n"); 2403 return E_NOTIMPL; 2404 } 2405 2406 static HRESULT WINAPI stream_LockRegion(IStream *iface, ULARGE_INTEGER offset, 2407 ULARGE_INTEGER len, DWORD locktype) 2408 { 2409 ok(FALSE, "unexpected call\n"); 2410 return E_NOTIMPL; 2411 } 2412 2413 static HRESULT WINAPI stream_UnlockRegion(IStream *iface, ULARGE_INTEGER offset, 2414 ULARGE_INTEGER len, DWORD locktype) 2415 { 2416 ok(FALSE, "unexpected call\n"); 2417 return E_NOTIMPL; 2418 } 2419 2420 static HRESULT WINAPI stream_Stat(IStream *iface, STATSTG *stg, DWORD flag) 2421 { 2422 ok(FALSE, "unexpected call\n"); 2423 return E_NOTIMPL; 2424 } 2425 2426 static HRESULT WINAPI stream_Clone(IStream *iface, IStream **stream) 2427 { 2428 ok(FALSE, "unexpected call\n"); 2429 return E_NOTIMPL; 2430 } 2431 2432 static /* const */ IStreamVtbl stream_vtbl = 2433 { 2434 stream_QueryInterface, 2435 stream_AddRef, 2436 stream_Release, 2437 stream_Read, 2438 stream_Write, 2439 stream_Seek, 2440 stream_SetSize, 2441 stream_CopyTo, 2442 stream_Commit, 2443 stream_Revert, 2444 stream_LockRegion, 2445 stream_UnlockRegion, 2446 stream_Stat, 2447 stream_Clone 2448 }; 2449 2450 static IStream test_stream = { &stream_vtbl }; 2451 2452 static void test_DetectOutboundCodePageInIStream(IMultiLanguage3 *ml) 2453 { 2454 HRESULT hr; 2455 UINT nb_detected, detected[4]; 2456 UINT preferred[] = {1250,1251,1252,65001}; 2457 UINT preferred2[] = {1250,1251,1252}; 2458 2459 nb_detected = 0; 2460 memset(detected, 0, sizeof(detected)); 2461 hr = IMultiLanguage3_DetectOutboundCodePageInIStream(ml, 2462 MLDETECTF_PRESERVE_ORDER, &test_stream, preferred, 2463 sizeof(preferred)/sizeof(preferred[0]), detected, &nb_detected, NULL); 2464 ok(hr == E_INVALIDARG, "got %08x\n", hr); 2465 2466 nb_detected = 1; 2467 memset(detected, 0, sizeof(detected)); 2468 hr = IMultiLanguage3_DetectOutboundCodePageInIStream(ml, 2469 MLDETECTF_PRESERVE_ORDER, &test_stream, preferred, 2470 sizeof(preferred)/sizeof(preferred[0]), NULL, &nb_detected, NULL); 2471 ok(hr == E_INVALIDARG, "got %08x\n", hr); 2472 2473 nb_detected = 1; 2474 memset(detected, 0, sizeof(detected)); 2475 hr = IMultiLanguage3_DetectOutboundCodePageInIStream(ml, 2476 MLDETECTF_PRESERVE_ORDER, &test_stream, preferred, 2477 sizeof(preferred)/sizeof(preferred[0]), detected, &nb_detected, NULL); 2478 ok(hr == S_OK, "got %08x\n", hr); 2479 ok(nb_detected == 1, "got %u\n", nb_detected); 2480 ok(detected[0] == 65001, "got %u\n", detected[0]); 2481 2482 nb_detected = 2; 2483 memset(detected, 0, sizeof(detected)); 2484 hr = IMultiLanguage3_DetectOutboundCodePageInIStream(ml, 2485 MLDETECTF_PRESERVE_ORDER, &test_stream, preferred, 2486 sizeof(preferred)/sizeof(preferred[0]), detected, &nb_detected, NULL); 2487 ok(hr == S_OK, "got %08x\n", hr); 2488 todo_wine ok(nb_detected == 2, "got %u\n", nb_detected); 2489 ok(detected[0] == 65001, "got %u\n", detected[0]); 2490 todo_wine ok(detected[1] == 65000, "got %u\n", detected[1]); 2491 2492 nb_detected = 3; 2493 memset(detected, 0, sizeof(detected)); 2494 hr = IMultiLanguage3_DetectOutboundCodePageInIStream(ml, 2495 MLDETECTF_PRESERVE_ORDER, &test_stream, preferred, 2496 sizeof(preferred)/sizeof(preferred[0]), detected, &nb_detected, NULL); 2497 ok(hr == S_OK, "got %08x\n", hr); 2498 todo_wine ok(nb_detected == 3, "got %u\n", nb_detected); 2499 ok(detected[0] == 65001, "got %u\n", detected[0]); 2500 todo_wine ok(detected[1] == 65000, "got %u\n", detected[1]); 2501 todo_wine ok(detected[2] == 1200, "got %u\n", detected[2]); 2502 2503 nb_detected = 4; 2504 memset(detected, 0, sizeof(detected)); 2505 hr = IMultiLanguage3_DetectOutboundCodePageInIStream(ml, 2506 MLDETECTF_PRESERVE_ORDER, &test_stream, preferred, 2507 sizeof(preferred)/sizeof(preferred[0]), detected, &nb_detected, NULL); 2508 ok(hr == S_OK, "got %08x\n", hr); 2509 todo_wine ok(nb_detected == 3, "got %u\n", nb_detected); 2510 ok(detected[0] == 65001, "got %u\n", detected[0]); 2511 todo_wine ok(detected[1] == 65000, "got %u\n", detected[1]); 2512 todo_wine ok(detected[2] == 1200, "got %u\n", detected[2]); 2513 ok(detected[3] == 0, "got %u\n", detected[3]); 2514 2515 nb_detected = 3; 2516 memset(detected, 0, sizeof(detected)); 2517 hr = IMultiLanguage3_DetectOutboundCodePageInIStream(ml, 2518 MLDETECTF_PRESERVE_ORDER, &test_stream, preferred2, 2519 sizeof(preferred2)/sizeof(preferred2[0]), detected, &nb_detected, NULL); 2520 ok(hr == S_OK, "got %08x\n", hr); 2521 todo_wine ok(nb_detected == 3, "got %u\n", nb_detected); 2522 ok(detected[0] == 65001, "got %u\n", detected[0]); 2523 todo_wine ok(detected[1] == 65000, "got %u\n", detected[1]); 2524 todo_wine ok(detected[2] == 1200, "got %u\n", detected[2]); 2525 } 2526 2527 static void test_GetCodePageInfo(IMultiLanguage2 *iML2) 2528 { 2529 static const DWORD VALID_MASK = (DWORD)(~(MIMECONTF_VALID_NLS | MIMECONTF_VALID)); 2530 2531 const struct cpinfo_test_data *test_data = NULL; 2532 UINT test_data_num; 2533 MIMECPINFO cpinfo_cmp; 2534 MIMECPINFO cpinfo; 2535 UINT i; 2536 HRESULT ret; 2537 2538 test_data = iml2_cpinfo_data; 2539 test_data_num = sizeof(iml2_cpinfo_data) / sizeof(iml2_cpinfo_data[0]); 2540 for (i = 0; i < test_data_num; i++) 2541 { 2542 ret = IMultiLanguage2_GetCodePageInfo(iML2, test_data[i].cpinfo.uiCodePage, LANG_NEUTRAL, &cpinfo); 2543 todo_wine_if(test_data[i].todo_GetCodePageInfo) 2544 ok(ret == S_OK, "%d: IMultiLanguage2_GetCodePageInfo failed: 0x%08x.\n", i, ret); 2545 2546 if (ret == S_OK) 2547 { 2548 cpinfo_cmp = test_data[i].cpinfo; 2549 todo_wine_if(test_data[i].todo_dwFlags) 2550 ok((cpinfo.dwFlags == cpinfo_cmp.dwFlags ) || 2551 /* some code pages are not installed on the Wine Test Bot */ 2552 ((cpinfo.dwFlags & VALID_MASK) == (cpinfo_cmp.dwFlags & VALID_MASK)), 2553 "%d: got wrong dwFlags expected 0x%x return 0x%x.\n", 2554 i, cpinfo_cmp.dwFlags, cpinfo.dwFlags); 2555 ok(cpinfo.uiCodePage == cpinfo_cmp.uiCodePage, 2556 "%d: got wrong uiCodePage expected %u return %u.\n", 2557 i, cpinfo_cmp.uiCodePage, cpinfo.uiCodePage); 2558 todo_wine_if(test_data[i].todo_uiFamilyCodePage) 2559 ok(cpinfo.uiFamilyCodePage == cpinfo_cmp.uiFamilyCodePage, 2560 "%d: got wrong uiFamilyCodePage expected %u return %u.\n", 2561 i, cpinfo_cmp.uiFamilyCodePage, cpinfo.uiFamilyCodePage); 2562 2563 todo_wine_if(test_data[i].todo_wszWebCharset) 2564 ok(!lstrcmpW(cpinfo.wszWebCharset, cpinfo_cmp.wszWebCharset), 2565 "%d: got wrong wszWebCharset expected %s return %s.\n", 2566 i, wine_dbgstr_w(cpinfo_cmp.wszWebCharset), wine_dbgstr_w(cpinfo.wszWebCharset)); 2567 todo_wine_if(test_data[i].todo_wszHeaderCharset) 2568 ok(!lstrcmpW(cpinfo.wszHeaderCharset, cpinfo_cmp.wszHeaderCharset), 2569 "%d: got wrong wszHeaderCharset expected %s return %s.\n", 2570 i, wine_dbgstr_w(cpinfo_cmp.wszHeaderCharset), wine_dbgstr_w(cpinfo.wszHeaderCharset)); 2571 todo_wine_if(test_data[i].todo_wszBodyCharset) 2572 ok(!lstrcmpW(cpinfo.wszBodyCharset, cpinfo_cmp.wszBodyCharset), 2573 "%d: got wrong wszBodyCharset expected %s return %s.\n", 2574 i, wine_dbgstr_w(cpinfo_cmp.wszBodyCharset), wine_dbgstr_w(cpinfo.wszBodyCharset)); 2575 2576 if ((PRIMARYLANGID(LANGIDFROMLCID(GetSystemDefaultLCID())) != LANG_ENGLISH) || 2577 (PRIMARYLANGID(LANGIDFROMLCID(GetThreadLocale())) != LANG_ENGLISH)) 2578 { 2579 /* FIXME: Windows returns description and font name in system's language */ 2580 skip("Non-English locale\n"); 2581 } 2582 else 2583 { 2584 todo_wine_if(test_data[i].todo_wszDescription) 2585 ok(!lstrcmpW(cpinfo.wszDescription, cpinfo_cmp.wszDescription), 2586 "%d: got wrong wszDescription expected %s return %s.\n", 2587 i, wine_dbgstr_w(cpinfo_cmp.wszDescription), wine_dbgstr_w(cpinfo.wszDescription)); 2588 todo_wine_if(test_data[i].todo_wszFixedWidthFont) 2589 ok(!lstrcmpW(cpinfo.wszFixedWidthFont, cpinfo_cmp.wszFixedWidthFont), 2590 "%d: got wrong wszFixedWidthFont expected %s return %s.\n", 2591 i, wine_dbgstr_w(cpinfo_cmp.wszFixedWidthFont), wine_dbgstr_w(cpinfo.wszFixedWidthFont)); 2592 todo_wine_if(test_data[i].todo_wszProportionalFont) 2593 ok(!lstrcmpW(cpinfo.wszProportionalFont, cpinfo_cmp.wszProportionalFont), 2594 "%d: got wrong wszProportionalFont expected %s return %s.\n", 2595 i, wine_dbgstr_w(cpinfo_cmp.wszProportionalFont), wine_dbgstr_w(cpinfo.wszProportionalFont)); 2596 } 2597 } 2598 } 2599 } 2600 2601 static void test_MapFont(IMLangFontLink *font_link, IMLangFontLink2 *font_link2) 2602 { 2603 HFONT old_font = NULL; 2604 HFONT new_font = NULL; 2605 HFONT last_font = NULL; 2606 HFONT font1 = NULL; 2607 HFONT font2 = NULL; 2608 DWORD codepages; 2609 DWORD font_codepages; 2610 HRESULT ret; 2611 HDC hdc; 2612 WCHAR ch; 2613 2614 hdc = GetDC(NULL); 2615 codepages = FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC | FS_GREEK | FS_TURKISH | 2616 FS_HEBREW | FS_ARABIC | FS_BALTIC | FS_VIETNAMESE | FS_THAI | 2617 FS_JISJAPAN | FS_CHINESESIMP | FS_WANSUNG | FS_CHINESETRAD; 2618 old_font = GetCurrentObject(hdc, OBJ_FONT); 2619 ch = 0xfeed; 2620 2621 /* Tests for IMLangFontLink */ 2622 2623 ret = IMLangFontLink_ResetFontMapping(font_link); 2624 ok(ret == S_OK, "IMLangFontLink_ResetFontMapping: expected S_OK, got %08x\n", ret); 2625 2626 ret = IMLangFontLink_MapFont(font_link, NULL, 0, NULL, NULL); 2627 ok(ret == E_FAIL, "IMLangFontLink_MapFont: expected E_FAIL, got %08x\n", ret); 2628 ret = IMLangFontLink_MapFont(font_link, NULL, codepages, old_font, &new_font); 2629 ok(ret == E_FAIL, "IMLangFontLink_MapFont: expected E_FAIL, got %08x\n", ret); 2630 ret = IMLangFontLink_MapFont(font_link, hdc, codepages, NULL, &new_font); 2631 ok(ret == E_FAIL, "IMLangFontLink_MapFont: expected E_FAIL, got %08x\n", ret); 2632 2633 ret = IMLangFontLink_MapFont(font_link, hdc, codepages, old_font, NULL); 2634 ok(ret == S_OK, "IMLangFontLink_MapFont: expected S_OK, got %08x\n", ret); 2635 ret = IMLangFontLink_MapFont(font_link, hdc, codepages, old_font, &new_font); 2636 ok(ret == S_OK && new_font != NULL, "IMLangFontLink_MapFont: expected S_OK/!NULL, got %08x/%p\n", ret, new_font); 2637 last_font = new_font; 2638 ret = IMLangFontLink_MapFont(font_link, hdc, codepages, old_font, &new_font); 2639 ok(ret == S_OK && new_font == last_font, "IMLangFontLink_MapFont: expected S_OK/%p, got %08x/%p\n", last_font, ret, new_font); 2640 2641 ret = IMLangFontLink_ReleaseFont(font_link, NULL); 2642 ok(ret == E_FAIL, "IMLangFontLink_ReleaseFont: expected E_FAIL, got %08x\n", ret); 2643 ret = IMLangFontLink_ReleaseFont(font_link, new_font); 2644 ok(ret == S_OK, "IMLangFontLink_ReleaseFont: expected S_OK, got %08x\n", ret); 2645 ret = IMLangFontLink_ResetFontMapping(font_link); 2646 ok(ret == S_OK, "IMLangFontLink_ResetFontMapping: expected S_OK, got %08x\n", ret); 2647 2648 /* Tests for IMLangFontLink2 */ 2649 2650 ret = IMLangFontLink2_ResetFontMapping(font_link2); 2651 ok(ret == S_OK, "IMLangFontLink2_ResetFontMapping: expected S_OK, got %08x\n", ret); 2652 2653 ret = IMLangFontLink2_MapFont(font_link2, NULL, 0, 0, NULL); 2654 ok(ret == E_FAIL, "IMLangFontLink2_MapFont: expected E_FAIL, got %08x\n", ret); 2655 ret = IMLangFontLink2_MapFont(font_link2, NULL, codepages, ch, &new_font); 2656 ok(ret == E_FAIL, "IMLangFontLink2_MapFont: expected E_FAIL, got %08x\n", ret); 2657 ret = IMLangFontLink2_MapFont(font_link2, hdc, 0, 0, NULL); 2658 ok(ret == E_INVALIDARG, "IMLangFontLink2_MapFont: expected E_INVALIDARG, got %08x\n", ret); 2659 ret = IMLangFontLink2_MapFont(font_link2, hdc, 0, ch, NULL); 2660 ok(ret == E_INVALIDARG, "IMLangFontLink2_MapFont: expected E_INVALIDARG, got %08x\n", ret); 2661 2662 ret = IMLangFontLink2_MapFont(font_link2, hdc, 0, ch, &new_font); 2663 todo_wine 2664 ok(ret == S_OK || broken(ret == E_FAIL), /* got E_FAIL on winxp and win2k */ 2665 "IMLangFontLink2_MapFont: expected S_OK || E_FAIL, got %08x\n", ret); 2666 ret = IMLangFontLink2_MapFont(font_link2, hdc, codepages, 0, NULL); 2667 ok(ret == S_OK, "IMLangFontLink2_MapFont: expected S_OK, got %08x\n", ret); 2668 ret = IMLangFontLink2_MapFont(font_link2, hdc, codepages, 0, &new_font); 2669 ok(ret == S_OK && new_font != NULL, "IMLangFontLink2_MapFont: expected S_OK/!NULL, got %08x/%p\n", ret, new_font); 2670 last_font = new_font; 2671 ret = IMLangFontLink2_MapFont(font_link2, hdc, codepages, 0, &new_font); 2672 ok(ret == S_OK && new_font == last_font, "IMLangFontLink2_MapFont: expected S_OK/%p, got %08x/%p\n", last_font, ret, new_font); 2673 2674 ret = IMLangFontLink2_ReleaseFont(font_link2, NULL); 2675 ok(ret == E_FAIL, "IMLangFontLink2_ReleaseFont: expected E_FAIL, got %08x\n", ret); 2676 ret = IMLangFontLink2_ReleaseFont(font_link2, new_font); 2677 ok(ret == S_OK, "IMLangFontLink2_ReleaseFont: expected S_OK, got %08x\n", ret); 2678 ret = IMLangFontLink2_ResetFontMapping(font_link2); 2679 ok(ret == S_OK, "IMLangFontLink2_ResetFontMapping: expected S_OK, got %08x\n", ret); 2680 2681 /* Show that the font cache is global */ 2682 ret = IMLangFontLink_MapFont(font_link, hdc, codepages, old_font, &font1); 2683 ok(ret == S_OK, "MapFont() failed, hr %#x.\n", ret); 2684 ret = IMLangFontLink2_MapFont(font_link2, hdc, codepages, 0, &font2); 2685 ok(ret == S_OK, "MapFont() failed, hr %#x.\n", ret); 2686 ok(font1 != NULL && font2 != NULL, "expected !NULL/!NULL, got %p/%p\n", font1, font2); 2687 ok(font1 == font2, "expected equal, got not equal\n"); 2688 2689 IMLangFontLink_GetFontCodePages(font_link, hdc, font1, &font_codepages); 2690 ok((codepages & (~font_codepages)) != 0 && (codepages & font_codepages) != 0, 2691 "code pages of font is incorrect\n"); 2692 2693 IMLangFontLink_ResetFontMapping(font_link); 2694 IMLangFontLink2_ResetFontMapping(font_link2); 2695 ReleaseDC(NULL, hdc); 2696 } 2697 2698 START_TEST(mlang) 2699 { 2700 IMultiLanguage *iML = NULL; 2701 IMultiLanguage2 *iML2 = NULL; 2702 IMultiLanguage3 *iML3 = NULL; 2703 IMLangFontLink *iMLFL = NULL; 2704 IMLangFontLink2 *iMLFL2 = NULL; 2705 HRESULT ret; 2706 2707 if (!init_function_ptrs()) 2708 return; 2709 2710 CoInitialize(NULL); 2711 test_Rfc1766ToLcid(); 2712 test_LcidToRfc1766(); 2713 2714 test_ConvertINetUnicodeToMultiByte(); 2715 test_JapaneseConversion(); 2716 2717 test_GetGlobalFontLinkObject(); 2718 2719 trace("IMultiLanguage\n"); 2720 ret = CoCreateInstance(&CLSID_CMultiLanguage, NULL, CLSCTX_INPROC_SERVER, 2721 &IID_IMultiLanguage, (void **)&iML); 2722 if (ret != S_OK || !iML) return; 2723 2724 test_GetNumberOfCodePageInfo((IMultiLanguage2 *)iML); 2725 test_IMLangConvertCharset(iML); 2726 test_GetCharsetInfo_other(iML); 2727 IMultiLanguage_Release(iML); 2728 2729 2730 /* IMultiLanguage2 (IE5.0 and above) */ 2731 trace("IMultiLanguage2\n"); 2732 ret = CoCreateInstance(&CLSID_CMultiLanguage, NULL, CLSCTX_INPROC_SERVER, 2733 &IID_IMultiLanguage2, (void **)&iML2); 2734 if (ret != S_OK || !iML2) return; 2735 2736 test_rfc1766(iML2); 2737 test_GetLcidFromRfc1766(iML2); 2738 test_GetRfc1766FromLcid(iML2); 2739 test_GetRfc1766Info(iML2); 2740 test_GetNumberOfCodePageInfo(iML2); 2741 test_GetCodePageInfo(iML2); 2742 2743 test_EnumCodePages(iML2, 0); 2744 test_EnumCodePages(iML2, MIMECONTF_MIME_LATEST); 2745 test_EnumCodePages(iML2, MIMECONTF_BROWSER); 2746 test_EnumCodePages(iML2, MIMECONTF_MINIMAL); 2747 test_EnumCodePages(iML2, MIMECONTF_VALID); 2748 /* FIXME: why MIMECONTF_MIME_REGISTRY returns 0 of supported codepages? */ 2749 /*test_EnumCodePages(iML2, MIMECONTF_MIME_REGISTRY);*/ 2750 2751 test_EnumScripts(iML2, 0); 2752 test_EnumScripts(iML2, SCRIPTCONTF_SCRIPT_USER); 2753 test_EnumScripts(iML2, SCRIPTCONTF_SCRIPT_USER | SCRIPTCONTF_SCRIPT_HIDE | SCRIPTCONTF_SCRIPT_SYSTEM); 2754 2755 ret = IMultiLanguage2_IsConvertible(iML2, CP_UTF8, CP_UNICODE); 2756 ok(ret == S_OK, "IMultiLanguage2_IsConvertible(CP_UTF8 -> CP_UNICODE) = %08x\n", ret); 2757 ret = IMultiLanguage2_IsConvertible(iML2, CP_UNICODE, CP_UTF8); 2758 ok(ret == S_OK, "IMultiLanguage2_IsConvertible(CP_UNICODE -> CP_UTF8) = %08x\n", ret); 2759 2760 test_multibyte_to_unicode_translations(iML2); 2761 test_IMultiLanguage2_ConvertStringFromUnicode(iML2); 2762 2763 test_IsCodePageInstallable(iML2); 2764 2765 IMultiLanguage2_Release(iML2); 2766 2767 2768 /* IMLangFontLink */ 2769 ret = CoCreateInstance(&CLSID_CMultiLanguage, NULL, CLSCTX_INPROC_SERVER, 2770 &IID_IMLangFontLink, (void **)&iMLFL); 2771 if (ret != S_OK || !iMLFL) return; 2772 2773 IMLangFontLink_Test(iMLFL); 2774 2775 /* IMLangFontLink2 */ 2776 ret = CoCreateInstance(&CLSID_CMultiLanguage, NULL, CLSCTX_INPROC_SERVER, 2777 &IID_IMLangFontLink2, (void **)&iMLFL2); 2778 if (ret != S_OK || !iMLFL2) return; 2779 2780 test_GetScriptFontInfo(iMLFL2); 2781 test_GetFontUnicodeRanges(iMLFL2); 2782 test_CodePageToScriptID(iMLFL2); 2783 test_MapFont(iMLFL, iMLFL2); 2784 2785 IMLangFontLink_Release(iMLFL); 2786 IMLangFontLink2_Release(iMLFL2); 2787 2788 trace("IMultiLanguage3\n"); 2789 ret = CoCreateInstance(&CLSID_CMultiLanguage, NULL, CLSCTX_INPROC_SERVER, 2790 &IID_IMultiLanguage3, (void **)&iML3); 2791 if (ret == S_OK) 2792 { 2793 test_DetectOutboundCodePageInIStream(iML3); 2794 IMultiLanguage3_Release(iML3); 2795 } 2796 2797 CoUninitialize(); 2798 } 2799