user32/tests: Add some tests for UpdateLayeredWindow.
[wine] / dlls / mlang / mlang.c
1 /*
2  *    MLANG Class Factory
3  *
4  * Copyright 2002 Lionel Ulmer
5  * Copyright 2003,2004 Mike McCormack
6  * Copyright 2004,2005 Dmitry Timoshkov
7  * Copyright 2009 Detlef Riekenberg
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22  */
23
24 #include "config.h"
25
26 #include <stdarg.h>
27 #include <stdio.h>
28
29 #define COBJMACROS
30
31 #include "windef.h"
32 #include "winbase.h"
33 #include "wingdi.h"
34 #include "winuser.h"
35 #include "ole2.h"
36 #include "objbase.h"
37 #include "rpcproxy.h"
38 #include "mlang.h"
39
40 #include "wine/unicode.h"
41 #include "wine/debug.h"
42
43 WINE_DEFAULT_DEBUG_CHANNEL(mlang);
44
45 #include "initguid.h"
46
47 #define CP_UNICODE 1200
48
49 static HRESULT MultiLanguage_create(IUnknown *pUnkOuter, LPVOID *ppObj);
50 static HRESULT EnumRfc1766_create(LANGID LangId, IEnumRfc1766 **ppEnum);
51
52 static HINSTANCE instance;
53 static DWORD MLANG_tls_index; /* to store various per thead data */
54
55 /* FIXME:
56  * Under what circumstances HKEY_CLASSES_ROOT\MIME\Database\Codepage and
57  * HKEY_CLASSES_ROOT\MIME\Database\Charset are used?
58  */
59
60 typedef struct
61 {
62     const char *description;
63     UINT cp;
64     DWORD flags;
65     const char *web_charset;
66     const char *header_charset;
67     const char *body_charset;
68 } MIME_CP_INFO;
69
70 /* These data are based on the codepage info in libs/unicode/cpmap.pl */
71 /* FIXME: Add 28604 (Celtic), 28606 (Balkan) */
72
73 static const MIME_CP_INFO arabic_cp[] =
74 {
75     { "Arabic (864)",
76       864, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID_NLS |
77            MIMECONTF_MIME_LATEST,
78       "ibm864", "ibm864", "ibm864" },
79     { "Arabic (1006)",
80       1006, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID_NLS |
81             MIMECONTF_MIME_LATEST,
82       "ibm1006", "ibm1006", "ibm1006" },
83     { "Arabic (Windows)",
84       1256, MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_IMPORT |
85             MIMECONTF_SAVABLE_MAILNEWS | MIMECONTF_SAVABLE_BROWSER |
86             MIMECONTF_EXPORT | MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
87       "windows-1256", "windows-1256", "windows-1256" },
88     { "Arabic (ISO)",
89       28596, MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_MINIMAL |
90              MIMECONTF_IMPORT | MIMECONTF_SAVABLE_MAILNEWS |
91              MIMECONTF_SAVABLE_BROWSER | MIMECONTF_EXPORT |
92              MIMECONTF_VALID_NLS | MIMECONTF_MIME_IE4 | MIMECONTF_MIME_LATEST,
93       "iso-8859-6", "iso-8859-6", "iso-8859-6" }
94 };
95 static const MIME_CP_INFO baltic_cp[] =
96 {
97     { "Baltic (DOS)",
98       775, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID |
99            MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
100       "ibm775", "ibm775", "ibm775" },
101     { "Baltic (Windows)",
102       1257, MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_MINIMAL |
103             MIMECONTF_IMPORT | MIMECONTF_SAVABLE_MAILNEWS |
104             MIMECONTF_SAVABLE_BROWSER | MIMECONTF_EXPORT | MIMECONTF_VALID |
105             MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
106       "windows-1257", "windows-1257", "windows-1257" },
107     { "Baltic (ISO)",
108       28594, MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_IMPORT |
109              MIMECONTF_SAVABLE_MAILNEWS | MIMECONTF_SAVABLE_BROWSER |
110              MIMECONTF_EXPORT | MIMECONTF_VALID | MIMECONTF_VALID_NLS |
111              MIMECONTF_MIME_LATEST,
112       "iso-8859-4", "iso-8859-4", "iso-8859-4" },
113     { "Estonian (ISO)",
114       28603, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID |
115              MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
116       "iso-8859-13", "iso-8859-13", "iso-8859-13" }
117 };
118 static const MIME_CP_INFO chinese_simplified_cp[] =
119 {
120     { "Chinese Simplified (GB2312)",
121       936, MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_MINIMAL |
122            MIMECONTF_IMPORT | MIMECONTF_SAVABLE_MAILNEWS |
123            MIMECONTF_SAVABLE_BROWSER | MIMECONTF_EXPORT | MIMECONTF_VALID_NLS |
124            MIMECONTF_MIME_IE4 | MIMECONTF_MIME_LATEST,
125       "gb2312", "gb2312", "gb2312" }
126 };
127 static const MIME_CP_INFO chinese_traditional_cp[] =
128 {
129     { "Chinese Traditional (Big5)",
130       950, MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_MINIMAL |
131            MIMECONTF_IMPORT | MIMECONTF_SAVABLE_MAILNEWS |
132            MIMECONTF_SAVABLE_BROWSER | MIMECONTF_EXPORT |
133            MIMECONTF_VALID_NLS | MIMECONTF_MIME_IE4 | MIMECONTF_MIME_LATEST,
134       "big5", "big5", "big5" }
135 };
136 static const MIME_CP_INFO central_european_cp[] =
137 {
138     { "Central European (DOS)",
139       852, MIMECONTF_BROWSER | MIMECONTF_IMPORT | MIMECONTF_SAVABLE_BROWSER |
140            MIMECONTF_EXPORT | MIMECONTF_VALID | MIMECONTF_VALID_NLS |
141            MIMECONTF_MIME_IE4 | MIMECONTF_MIME_LATEST,
142       "ibm852", "ibm852", "ibm852" },
143     { "Central European (Windows)",
144       1250, MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_IMPORT |
145             MIMECONTF_SAVABLE_MAILNEWS | MIMECONTF_SAVABLE_BROWSER |
146             MIMECONTF_EXPORT | MIMECONTF_VALID | MIMECONTF_VALID_NLS |
147             MIMECONTF_MIME_LATEST,
148       "windows-1250", "windows-1250", "windows-1250" },
149     { "Central European (Mac)",
150       10029, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID |
151              MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
152       "x-mac-ce", "x-mac-ce", "x-mac-ce" },
153     { "Central European (ISO)",
154       28592, MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_MINIMAL |
155              MIMECONTF_IMPORT | MIMECONTF_SAVABLE_MAILNEWS |
156              MIMECONTF_SAVABLE_BROWSER | MIMECONTF_EXPORT | MIMECONTF_VALID |
157              MIMECONTF_VALID_NLS | MIMECONTF_MIME_IE4 | MIMECONTF_MIME_LATEST,
158       "iso-8859-2", "iso-8859-2", "iso-8859-2" }
159 };
160 static const MIME_CP_INFO cyrillic_cp[] =
161 {
162     { "OEM Cyrillic",
163       855, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID |
164            MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
165       "ibm855", "ibm855", "ibm855" },
166     { "Cyrillic (DOS)",
167       866, MIMECONTF_BROWSER | MIMECONTF_IMPORT | MIMECONTF_SAVABLE_BROWSER |
168            MIMECONTF_EXPORT | MIMECONTF_VALID_NLS | MIMECONTF_MIME_IE4 |
169            MIMECONTF_MIME_LATEST,
170       "cp866", "cp866", "cp866" },
171 #if 0 /* Windows has 20866 as an official code page for KOI8-R */
172     { "Cyrillic (KOI8-R)",
173       878, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID |
174            MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
175       "koi8-r", "koi8-r", "koi8-r" },
176 #endif
177     { "Cyrillic (Windows)",
178       1251, MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_IMPORT |
179             MIMECONTF_SAVABLE_MAILNEWS | MIMECONTF_SAVABLE_BROWSER |
180             MIMECONTF_EXPORT | MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
181       "windows-1251", "windows-1251", "windows-1251" },
182     { "Cyrillic (Mac)",
183       10007, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID_NLS |
184              MIMECONTF_MIME_LATEST,
185       "x-mac-cyrillic", "x-mac-cyrillic", "x-mac-cyrillic" },
186     { "Cyrillic (KOI8-R)",
187       20866, MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_MINIMAL |
188              MIMECONTF_IMPORT | MIMECONTF_SAVABLE_MAILNEWS |
189              MIMECONTF_SAVABLE_BROWSER | MIMECONTF_EXPORT |
190              MIMECONTF_VALID_NLS | MIMECONTF_MIME_IE4 | MIMECONTF_MIME_LATEST,
191       "koi8-r", "koi8-r", "koi8-r" },
192     { "Cyrillic (KOI8-U)",
193       21866, MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_MINIMAL |
194              MIMECONTF_IMPORT | MIMECONTF_SAVABLE_MAILNEWS |
195              MIMECONTF_SAVABLE_BROWSER | MIMECONTF_EXPORT |
196              MIMECONTF_VALID_NLS | MIMECONTF_MIME_IE4 | MIMECONTF_MIME_LATEST,
197       "koi8-u", "koi8-u", "koi8-u" },
198     { "Cyrillic (ISO)",
199       28595, MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_MINIMAL |
200              MIMECONTF_IMPORT | MIMECONTF_SAVABLE_MAILNEWS |
201              MIMECONTF_SAVABLE_BROWSER | MIMECONTF_EXPORT |
202              MIMECONTF_VALID_NLS | MIMECONTF_MIME_IE4 | MIMECONTF_MIME_LATEST,
203       "iso-8859-5", "iso-8859-5", "iso-8859-5" }
204 };
205 static const MIME_CP_INFO greek_cp[] =
206 {
207     { "Greek (DOS)",
208       737, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID_NLS |
209            MIMECONTF_MIME_LATEST,
210       "ibm737", "ibm737", "ibm737" },
211     { "Greek, Modern (DOS)",
212       869, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID_NLS |
213            MIMECONTF_MIME_LATEST,
214       "ibm869", "ibm869", "ibm869" },
215     { "IBM EBCDIC (Greek Modern)",
216       875, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID_NLS |
217            MIMECONTF_MIME_LATEST,
218       "cp875", "cp875", "cp875" },
219     { "Greek (Windows)",
220       1253, MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_IMPORT |
221             MIMECONTF_SAVABLE_MAILNEWS | MIMECONTF_SAVABLE_BROWSER |
222             MIMECONTF_EXPORT | MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
223       "windows-1253", "windows-1253", "windows-1253" },
224     { "Greek (Mac)",
225       10006, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID_NLS |
226              MIMECONTF_MIME_LATEST,
227       "x-mac-greek", "x-mac-greek", "x-mac-greek" },
228     { "Greek (ISO)",
229       28597, MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_MINIMAL |
230              MIMECONTF_IMPORT | MIMECONTF_SAVABLE_MAILNEWS |
231              MIMECONTF_SAVABLE_BROWSER | MIMECONTF_EXPORT |
232              MIMECONTF_VALID_NLS | MIMECONTF_MIME_IE4 | MIMECONTF_MIME_LATEST,
233       "iso-8859-7", "iso-8859-7", "iso-8859-7" }
234 };
235 static const MIME_CP_INFO hebrew_cp[] =
236 {
237     { "Hebrew (424)",
238       424, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID_NLS |
239            MIMECONTF_MIME_LATEST,
240       "ibm424", "ibm424", "ibm424" },
241     { "Hebrew (856)",
242       856, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID_NLS |
243            MIMECONTF_MIME_LATEST,
244       "cp856", "cp856", "cp856" },
245     { "Hebrew (DOS)",
246       862, MIMECONTF_BROWSER | MIMECONTF_MINIMAL | MIMECONTF_IMPORT |
247            MIMECONTF_SAVABLE_BROWSER | MIMECONTF_EXPORT | MIMECONTF_VALID_NLS |
248            MIMECONTF_MIME_LATEST,
249       "dos-862", "dos-862", "dos-862" },
250     { "Hebrew (Windows)",
251       1255, MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_IMPORT |
252             MIMECONTF_SAVABLE_MAILNEWS | MIMECONTF_SAVABLE_BROWSER |
253             MIMECONTF_EXPORT | MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
254       "windows-1255", "windows-1255", "windows-1255" },
255     { "Hebrew (ISO-Visual)",
256       28598, MIMECONTF_BROWSER | MIMECONTF_MINIMAL | MIMECONTF_IMPORT |
257              MIMECONTF_SAVABLE_BROWSER | MIMECONTF_EXPORT |
258              MIMECONTF_VALID_NLS | MIMECONTF_MIME_IE4 | MIMECONTF_MIME_LATEST,
259       "iso-8859-8", "iso-8859-8", "iso-8859-8" }
260 };
261 static const MIME_CP_INFO japanese_cp[] =
262 {
263     { "Japanese (Auto-Select)",
264       50932, MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_MINIMAL |
265              MIMECONTF_IMPORT | MIMECONTF_VALID | MIMECONTF_VALID_NLS |
266              MIMECONTF_MIME_IE4 | MIMECONTF_MIME_LATEST,
267       "_autodetect", "_autodetect", "_autodetect" },
268     { "Japanese (EUC)",
269       51932, MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_MINIMAL |
270              MIMECONTF_IMPORT | MIMECONTF_SAVABLE_MAILNEWS |
271              MIMECONTF_SAVABLE_BROWSER | MIMECONTF_EXPORT | MIMECONTF_VALID |
272              MIMECONTF_VALID_NLS | MIMECONTF_MIME_IE4 | MIMECONTF_MIME_LATEST,
273       "euc-jp", "euc-jp", "euc-jp" },
274     { "Japanese (JIS)",
275       50220, MIMECONTF_IMPORT | MIMECONTF_MAILNEWS | MIMECONTF_EXPORT |
276              MIMECONTF_SAVABLE_MAILNEWS | MIMECONTF_VALID_NLS |
277              MIMECONTF_PRIVCONVERTER | MIMECONTF_MIME_LATEST |
278              MIMECONTF_MIME_IE4,
279       "iso-2022-jp","iso-2022-jp","iso-2022-jp"},
280     { "Japanese (JIS 0208-1990 and 0212-1990)",
281       20932, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID_NLS |
282              MIMECONTF_VALID | MIMECONTF_PRIVCONVERTER | MIMECONTF_MIME_LATEST,
283       "EUC-JP","EUC-JP","EUC-JP"},
284     { "Japanese (JIS-Allow 1 byte Kana)",
285       50221, MIMECONTF_MAILNEWS | MIMECONTF_EXPORT | MIMECONTF_SAVABLE_BROWSER |
286              MIMECONTF_SAVABLE_MAILNEWS | MIMECONTF_VALID_NLS |
287              MIMECONTF_VALID | MIMECONTF_PRIVCONVERTER | MIMECONTF_MIME_LATEST,
288       "csISO2022JP","iso-2022-jp","iso-2022-jp"},
289     { "Japanese (JIS-Allow 1 byte Kana - SO/SI)",
290       50222, MIMECONTF_EXPORT | MIMECONTF_VALID_NLS | MIMECONTF_VALID |
291              MIMECONTF_PRIVCONVERTER | MIMECONTF_MIME_LATEST,
292       "iso-2022-jp","iso-2022-jp","iso-2022-jp"},
293     { "Japanese (Mac)",
294       10001, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID_NLS |
295              MIMECONTF_VALID | MIMECONTF_PRIVCONVERTER | MIMECONTF_MIME_LATEST,
296       "x-mac-japanese","x-mac-japanese","x-mac-japanese"},
297     { "Japanese (Shift-JIS)",
298       932, MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_MINIMAL |
299            MIMECONTF_IMPORT | MIMECONTF_SAVABLE_MAILNEWS |
300            MIMECONTF_SAVABLE_BROWSER | MIMECONTF_EXPORT | MIMECONTF_VALID |
301            MIMECONTF_VALID_NLS | MIMECONTF_MIME_IE4 | MIMECONTF_MIME_LATEST,
302       "shift_jis", "iso-2022-jp", "iso-2022-jp" }
303 };
304 static const MIME_CP_INFO korean_cp[] =
305 {
306     { "Korean",
307       949, MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_MINIMAL |
308            MIMECONTF_IMPORT | MIMECONTF_SAVABLE_MAILNEWS |
309            MIMECONTF_SAVABLE_BROWSER | MIMECONTF_EXPORT | MIMECONTF_VALID_NLS |
310            MIMECONTF_MIME_LATEST,
311       "ks_c_5601-1987", "ks_c_5601-1987", "ks_c_5601-1987" }
312 };
313 static const MIME_CP_INFO thai_cp[] =
314 {
315     { "Thai (Windows)",
316       874, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_MIME_LATEST,
317       "ibm-thai", "ibm-thai", "ibm-thai" }
318 };
319 static const MIME_CP_INFO turkish_cp[] =
320 {
321     { "Turkish (DOS)",
322       857, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID |
323            MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
324       "ibm857", "ibm857", "ibm857" },
325     { "IBM EBCDIC (Turkish Latin-5)",
326       1026, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID |
327             MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
328       "ibm1026", "ibm1026", "ibm1026" },
329     { "Turkish (Windows)",
330       1254, MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_MINIMAL |
331             MIMECONTF_IMPORT | MIMECONTF_SAVABLE_MAILNEWS |
332             MIMECONTF_SAVABLE_BROWSER | MIMECONTF_EXPORT | MIMECONTF_VALID |
333             MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
334       "windows-1254", "windows-1254", "windows-1254" },
335     { "Turkish (Mac)",
336       10081, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID |
337              MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
338       "x-mac-turkish", "x-mac-turkish", "x-mac-turkish" },
339     { "Latin 3 (ISO)",
340       28593, MIMECONTF_MAILNEWS | MIMECONTF_IMPORT |
341              MIMECONTF_SAVABLE_MAILNEWS | MIMECONTF_EXPORT | MIMECONTF_VALID |
342              MIMECONTF_VALID_NLS | MIMECONTF_MIME_IE4 | MIMECONTF_MIME_LATEST,
343       "iso-8859-3", "iso-8859-3", "iso-8859-3" },
344     { "Turkish (ISO)",
345       28599, MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_MINIMAL |
346              MIMECONTF_IMPORT | MIMECONTF_SAVABLE_MAILNEWS |
347              MIMECONTF_SAVABLE_BROWSER | MIMECONTF_EXPORT | MIMECONTF_VALID |
348              MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
349       "iso-8859-9", "iso-8859-9", "iso-8859-9" }
350 };
351 static const MIME_CP_INFO vietnamese_cp[] =
352 {
353     { "Vietnamese (Windows)",
354       1258, MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_IMPORT |
355             MIMECONTF_SAVABLE_MAILNEWS | MIMECONTF_SAVABLE_BROWSER |
356             MIMECONTF_EXPORT | MIMECONTF_VALID_NLS | MIMECONTF_MIME_IE4 |
357             MIMECONTF_MIME_LATEST,
358       "windows-1258", "windows-1258", "windows-1258" }
359 };
360 static const MIME_CP_INFO western_cp[] =
361 {
362     { "IBM EBCDIC (US-Canada)",
363       37, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID |
364           MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
365       "ibm037", "ibm037", "ibm037" },
366     { "OEM United States",
367       437, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID |
368            MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
369       "ibm437", "ibm437", "ibm437" },
370     { "IBM EBCDIC (International)",
371       500, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID |
372            MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
373       "ibm500", "ibm500", "ibm500" },
374     { "Western European (DOS)",
375       850, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID |
376            MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
377       "ibm850", "ibm850", "ibm850" },
378     { "Portuguese (DOS)",
379       860, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID |
380            MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
381       "ibm860", "ibm860", "ibm860" },
382     { "Icelandic (DOS)",
383       861, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID |
384            MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
385       "ibm861", "ibm861", "ibm861" },
386     { "French Canadian (DOS)",
387       863, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID |
388            MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
389       "ibm863", "ibm863", "ibm863" },
390     { "Nordic (DOS)",
391       865, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID |
392            MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
393       "ibm865", "ibm865", "ibm865" },
394     { "Western European (Windows)",
395       1252, MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_MINIMAL |
396             MIMECONTF_IMPORT | MIMECONTF_SAVABLE_MAILNEWS |
397             MIMECONTF_SAVABLE_BROWSER | MIMECONTF_EXPORT | MIMECONTF_VALID |
398             MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
399       "windows-1252", "windows-1252", "iso-8859-1" },
400     { "Western European (Mac)",
401       10000, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID |
402              MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
403       "macintosh", "macintosh", "macintosh" },
404     { "Icelandic (Mac)",
405       10079, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID |
406              MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
407       "x-mac-icelandic", "x-mac-icelandic", "x-mac-icelandic" },
408     { "US-ASCII",
409       20127, MIMECONTF_MAILNEWS | MIMECONTF_IMPORT | MIMECONTF_EXPORT |
410              MIMECONTF_SAVABLE_MAILNEWS | MIMECONTF_VALID |
411              MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
412       "us-ascii", "us-ascii", "us-ascii" },
413     { "Western European (ISO)",
414       28591, MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_IMPORT |
415              MIMECONTF_SAVABLE_MAILNEWS | MIMECONTF_SAVABLE_BROWSER |
416              MIMECONTF_EXPORT | MIMECONTF_VALID | MIMECONTF_VALID_NLS |
417              MIMECONTF_MIME_LATEST,
418       "iso-8859-1", "iso-8859-1", "iso-8859-1" },
419     { "Latin 9 (ISO)",
420       28605, MIMECONTF_MAILNEWS | MIMECONTF_IMPORT |
421              MIMECONTF_SAVABLE_MAILNEWS | MIMECONTF_SAVABLE_BROWSER |
422              MIMECONTF_EXPORT | MIMECONTF_VALID | MIMECONTF_VALID_NLS |
423              MIMECONTF_MIME_LATEST,
424       "iso-8859-15", "iso-8859-15", "iso-8859-15" }
425 };
426 static const MIME_CP_INFO unicode_cp[] =
427 {
428     { "Unicode",
429       CP_UNICODE, MIMECONTF_MINIMAL | MIMECONTF_IMPORT |
430                   MIMECONTF_SAVABLE_BROWSER | MIMECONTF_EXPORT |
431                   MIMECONTF_VALID | MIMECONTF_VALID_NLS | MIMECONTF_MIME_IE4 |
432                   MIMECONTF_MIME_LATEST,
433       "unicode", "unicode", "unicode" },
434     { "Unicode (UTF-7)",
435       CP_UTF7, MIMECONTF_MAILNEWS | MIMECONTF_IMPORT |
436                MIMECONTF_SAVABLE_MAILNEWS | MIMECONTF_EXPORT | MIMECONTF_VALID |
437                MIMECONTF_VALID_NLS | MIMECONTF_MIME_IE4 | MIMECONTF_MIME_LATEST,
438       "utf-7", "utf-7", "utf-7" },
439     { "Unicode (UTF-8)",
440       CP_UTF8, MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_IMPORT |
441                MIMECONTF_SAVABLE_MAILNEWS | MIMECONTF_SAVABLE_BROWSER |
442                MIMECONTF_EXPORT | MIMECONTF_VALID | MIMECONTF_VALID_NLS |
443                MIMECONTF_MIME_IE4 | MIMECONTF_MIME_LATEST,
444       "utf-8", "utf-8", "utf-8" }
445 };
446
447 static const struct mlang_data
448 {
449     const char *description;
450     UINT family_codepage;
451     UINT number_of_cp;
452     const MIME_CP_INFO *mime_cp_info;
453     const char *fixed_font;
454     const char *proportional_font;
455     SCRIPT_ID sid;
456 } mlang_data[] =
457 {
458     { "Arabic",1256,sizeof(arabic_cp)/sizeof(arabic_cp[0]),arabic_cp,
459       "Courier","Arial", sidArabic }, /* FIXME */
460     { "Baltic",1257,sizeof(baltic_cp)/sizeof(baltic_cp[0]),baltic_cp,
461       "Courier","Arial", sidAsciiLatin }, /* FIXME */
462     { "Chinese Simplified",936,sizeof(chinese_simplified_cp)/sizeof(chinese_simplified_cp[0]),chinese_simplified_cp,
463       "Courier","Arial", sidHan }, /* FIXME */
464     { "Chinese Traditional",950,sizeof(chinese_traditional_cp)/sizeof(chinese_traditional_cp[0]),chinese_traditional_cp,
465       "Courier","Arial", sidBopomofo }, /* FIXME */
466     { "Central European",1250,sizeof(central_european_cp)/sizeof(central_european_cp[0]),central_european_cp,
467       "Courier","Arial", sidAsciiLatin }, /* FIXME */
468     { "Cyrillic",1251,sizeof(cyrillic_cp)/sizeof(cyrillic_cp[0]),cyrillic_cp,
469       "Courier","Arial", sidCyrillic }, /* FIXME */
470     { "Greek",1253,sizeof(greek_cp)/sizeof(greek_cp[0]),greek_cp,
471       "Courier","Arial", sidGreek }, /* FIXME */
472     { "Hebrew",1255,sizeof(hebrew_cp)/sizeof(hebrew_cp[0]),hebrew_cp,
473       "Courier","Arial", sidHebrew }, /* FIXME */
474     { "Japanese",932,sizeof(japanese_cp)/sizeof(japanese_cp[0]),japanese_cp,
475       "MS Gothic","MS PGothic", sidKana },
476     { "Korean",949,sizeof(korean_cp)/sizeof(korean_cp[0]),korean_cp,
477       "Courier","Arial", sidHangul }, /* FIXME */
478     { "Thai",874,sizeof(thai_cp)/sizeof(thai_cp[0]),thai_cp,
479       "Courier","Arial", sidThai }, /* FIXME */
480     { "Turkish",1254,sizeof(turkish_cp)/sizeof(turkish_cp[0]),turkish_cp,
481       "Courier","Arial", sidAsciiLatin }, /* FIXME */
482     { "Vietnamese",1258,sizeof(vietnamese_cp)/sizeof(vietnamese_cp[0]),vietnamese_cp,
483       "Courier","Arial", sidAsciiLatin }, /* FIXME */
484     { "Western European",1252,sizeof(western_cp)/sizeof(western_cp[0]),western_cp,
485       "Courier","Arial", sidAsciiLatin }, /* FIXME */
486     { "Unicode",CP_UNICODE,sizeof(unicode_cp)/sizeof(unicode_cp[0]),unicode_cp,
487       "Courier","Arial" } /* FIXME */
488 };
489
490 static void fill_cp_info(const struct mlang_data *ml_data, UINT index, MIMECPINFO *mime_cp_info);
491
492 static LONG dll_count;
493
494 /*
495  * Japanese Detection and Converstion Functions
496  */
497
498 #define HANKATA(A)  ((A >= 161) && (A <= 223))
499 #define ISEUC(A)    ((A >= 161) && (A <= 254))
500 #define NOTEUC(A,B) (((A >= 129) && (A <= 159)) && ((B >= 64) && (B <= 160)))
501 #define SJIS1(A)    (((A >= 129) && (A <= 159)) || ((A >= 224) && (A <= 239)))
502 #define SJIS2(A)    ((A >= 64) && (A <= 252))
503 #define ISMARU(A)   ((A >= 202) && (A <= 206))
504 #define ISNIGORI(A) (((A >= 182) && (A <= 196)) || ((A >= 202) && (A <= 206)))
505
506 static UINT DetectJapaneseCode(LPCSTR input, DWORD count)
507 {
508     UINT code = 0;
509     DWORD i = 0;
510     unsigned char c1,c2;
511
512     while ((code == 0 || code == 51932) && i < count)
513     {
514         c1 = input[i];
515         if (c1 == 0x1b /* ESC */)
516         {
517             i++;
518             if (i >= count)
519                 return code;
520             c1 = input[i];
521             if (c1 == '$')
522             {
523                 i++;
524                 if (i >= count)
525                     return code;
526                 c1 = input[i];
527                 if (c1 =='B' || c1 == '@')
528                     code = 50220;
529             }
530             if (c1 == 'K')
531                 code = 50220;
532         }
533         else if (c1 >= 129)
534         {
535             i++;
536             if (i >= count)
537                 return code;
538             c2 = input[i];
539             if NOTEUC(c1,c2)
540                 code = 932;
541             else if (ISEUC(c1) && ISEUC(c2))
542                 code = 51932;
543             else if (((c1 == 142)) && HANKATA(c2))
544                 code = 51932;
545         }
546         i++;
547     }
548     return code;
549 }
550
551 static inline void jis2sjis(unsigned char *p1, unsigned char *p2)
552 {
553     unsigned char c1 = *p1;
554     unsigned char c2 = *p2;
555     int row = c1 < 95 ? 112 : 176;
556     int cell = c1 % 2 ? 31 + (c2 > 95) : 126;
557
558     *p1 = ((c1 + 1) >> 1) + row;
559     *p2 = c2 + cell;
560 }
561
562 static inline void sjis2jis(unsigned char *p1, unsigned char *p2)
563 {
564     unsigned char c1 = *p1;
565     unsigned char c2 = *p2;
566     int shift = c2 < 159;
567     int row = c1 < 160 ? 112 : 176;
568     int cell = shift ? (31 + (c2 > 127)): 126;
569
570     *p1 = ((c1 - row) << 1) - shift;
571     *p2 -= cell;
572 }
573
574 static int han2zen(unsigned char *p1, unsigned char *p2)
575 {
576     int maru = FALSE;
577     int nigori = FALSE;
578     static const unsigned char char1[] = {129,129,129,129,129,131,131,131,131,
579         131,131,131,131,131,131,129,131,131,131,131,131,131,131,131,131,131,
580         131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,
581         131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,
582         131,129,129 };
583     static const unsigned char char2[] = {66,117,118,65,69,146,64,66,68,70,
584         72,131,133,135,98,91,65,67,69,71,73,74,76,78,80,82,84,86,88,90,92,94,
585         96,99,101,103,105,106,107,108,109,110,113,116,119,122,125,126,128,
586         129,130,132,134,136,137,138,139,140,141,143,147,74,75};
587
588     if (( *p2 == 222) && ((ISNIGORI(*p1) || (*p1 == 179))))
589             nigori = TRUE;
590     else if ((*p2 == 223) && (ISMARU(*p1)))
591             maru = TRUE;
592
593     if (*p1 >= 161 && *p1 <= 223)
594     {
595         unsigned char index = *p1 - 161;
596         *p1 = char1[index];
597         *p2 = char2[index];
598     }
599
600     if (maru || nigori)
601     {
602         if (nigori)
603         {
604             if (((*p2 >= 74) && (*p2 <= 103)) || ((*p2 >= 110) && (*p2 <= 122)))
605                 (*p2)++;
606             else if ((*p1 == 131) && (*p2 == 69))
607                 *p2 = 148;
608         }
609         else if ((maru) && ((*p2 >= 110) && (*p2 <= 122)))
610             *p2+= 2;
611
612         return 1;
613     }
614
615     return 0;
616 }
617
618
619 static UINT ConvertJIS2SJIS(LPCSTR input, DWORD count, LPSTR output)
620 {
621     DWORD i = 0;
622     int j = 0;
623     unsigned char p2,p;
624     int shifted = FALSE;
625
626     while (i < count)
627     {
628         p = input[i];
629         if (p == 0x1b /* ESC */)
630         {
631             i++;
632             if (i >= count)
633                 return 0;
634             p2 = input[i];
635             if (p2 == '$' || p2 =='(')
636                 i++;
637             if (p2 == 'K' || p2 =='$')
638                 shifted = TRUE;
639             else
640                 shifted = FALSE;
641         }
642         else
643         {
644             if (shifted)
645             {
646                 i++;
647                 if (i >= count)
648                     return 0;
649                 p2 = input[i];
650                 jis2sjis(&p,&p2);
651                 output[j++]=p;
652                 output[j++]=p2;
653             }
654             else
655             {
656                 output[j++] = p;
657             }
658         }
659         i++;
660     }
661     return j;
662 }
663
664 static inline int exit_shift(LPSTR out, int c)
665 {
666     if (out)
667     {
668         out[c] = 0x1b;
669         out[c+1] = '(';
670         out[c+2] = 'B';
671     }
672     return 3;
673 }
674
675 static inline int enter_shift(LPSTR out, int c)
676 {
677     if (out)
678     {
679         out[c] = 0x1b;
680         out[c+1] = '$';
681         out[c+2] = 'B';
682     }
683     return 3;
684 }
685
686
687 static UINT ConvertSJIS2JIS(LPCSTR input, DWORD count, LPSTR output)
688 {
689     DWORD i = 0;
690     int j = 0;
691     unsigned char p2,p;
692     int shifted = FALSE;
693
694     while (i < count)
695     {
696         p = input[i] & 0xff;
697         if (p == 10 || p == 13) /* NL and CR */
698         {
699             if (shifted)
700             {
701                 shifted = FALSE;
702                 j += exit_shift(output,j);
703             }
704             if (output)
705                 output[j++] = p;
706             else
707                 j++;
708         }
709         else
710         {
711             if (SJIS1(p))
712             {
713                 i++;
714                 if (i >= count)
715                     return 0;
716                 p2 = input[i] & 0xff;
717                 if (SJIS2(p2))
718                 {
719                     sjis2jis(&p,&p2);
720                     if (!shifted)
721                     {
722                         shifted = TRUE;
723                         j+=enter_shift(output,j);
724                     }
725                 }
726
727                 if (output)
728                 {
729                     output[j++]=p;
730                     output[j++]=p2;
731                 }
732                 else
733                     j+=2;
734             }
735             else
736             {
737                 if (HANKATA(p))
738                 {
739                     if ((i+1) >= count)
740                         return 0;
741                     p2 = input[i+1] & 0xff;
742                     i+=han2zen(&p,&p2);
743                     sjis2jis(&p,&p2);
744                     if (!shifted)
745                     {
746                         shifted = TRUE;
747                         j+=enter_shift(output,j);
748                     }
749                     if (output)
750                     {
751                         output[j++]=p;
752                         output[j++]=p2;
753                     }
754                     else
755                         j+=2;
756                 }
757                 else
758                 {
759                     if (shifted)
760                     {
761                         shifted = FALSE;
762                         j += exit_shift(output,j);
763                     }
764                     if (output)
765                         output[j++]=p;
766                     else
767                         j++;
768                 }
769             }
770         }
771         i++;
772     }
773     if (shifted)
774         j += exit_shift(output,j);
775     return j;
776 }
777
778 static UINT ConvertJISJapaneseToUnicode(LPCSTR input, DWORD count,
779                                         LPWSTR output, DWORD out_count)
780 {
781     CHAR *sjis_string;
782     UINT rc = 0;
783     sjis_string = HeapAlloc(GetProcessHeap(),0,count);
784     rc = ConvertJIS2SJIS(input,count,sjis_string);
785     if (rc)
786     {
787         TRACE("%s\n",debugstr_an(sjis_string,rc));
788         if (output)
789             rc = MultiByteToWideChar(932,0,sjis_string,rc,output,out_count);
790         else
791             rc = MultiByteToWideChar(932,0,sjis_string,rc,0,0);
792     }
793     HeapFree(GetProcessHeap(),0,sjis_string);
794     return rc;
795
796 }
797
798 static UINT ConvertUnknownJapaneseToUnicode(LPCSTR input, DWORD count,
799                                             LPWSTR output, DWORD out_count)
800 {
801     CHAR *sjis_string;
802     UINT rc = 0;
803     int code = DetectJapaneseCode(input,count);
804     TRACE("Japanese code %i\n",code);
805
806     switch (code)
807     {
808     case 0:
809         if (output)
810             rc = MultiByteToWideChar(CP_ACP,0,input,count,output,out_count);
811         else
812             rc = MultiByteToWideChar(CP_ACP,0,input,count,0,0);
813         break;
814
815     case 932:
816         if (output)
817             rc = MultiByteToWideChar(932,0,input,count,output,out_count);
818         else
819             rc = MultiByteToWideChar(932,0,input,count,0,0);
820         break;
821
822     case 51932:
823         if (output)
824             rc = MultiByteToWideChar(20932,0,input,count,output,out_count);
825         else
826             rc = MultiByteToWideChar(20932,0,input,count,0,0);
827         break;
828
829     case 50220:
830         sjis_string = HeapAlloc(GetProcessHeap(),0,count);
831         rc = ConvertJIS2SJIS(input,count,sjis_string);
832         if (rc)
833         {
834             TRACE("%s\n",debugstr_an(sjis_string,rc));
835             if (output)
836                 rc = MultiByteToWideChar(932,0,sjis_string,rc,output,out_count);
837             else
838                 rc = MultiByteToWideChar(932,0,sjis_string,rc,0,0);
839         }
840         HeapFree(GetProcessHeap(),0,sjis_string);
841         break;
842     }
843     return rc;
844 }
845
846 static UINT ConvertJapaneseUnicodeToJIS(LPCWSTR input, DWORD count,
847                                         LPSTR output, DWORD out_count)
848 {
849     CHAR *sjis_string;
850     INT len;
851     UINT rc = 0;
852
853     len = WideCharToMultiByte(932,0,input,count,0,0,NULL,NULL);
854     sjis_string = HeapAlloc(GetProcessHeap(),0,len);
855     WideCharToMultiByte(932,0,input,count,sjis_string,len,NULL,NULL);
856     TRACE("%s\n",debugstr_an(sjis_string,len));
857
858     rc = ConvertSJIS2JIS(sjis_string, len, NULL);
859     if (out_count >= rc)
860     {
861         ConvertSJIS2JIS(sjis_string, len, output);
862     }
863     HeapFree(GetProcessHeap(),0,sjis_string);
864     return rc;
865
866 }
867
868 /*
869  * Dll lifetime tracking declaration
870  */
871 static void LockModule(void)
872 {
873     InterlockedIncrement(&dll_count);
874 }
875
876 static void UnlockModule(void)
877 {
878     InterlockedDecrement(&dll_count);
879 }
880
881 BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpv)
882 {
883     switch(fdwReason) {
884         case DLL_PROCESS_ATTACH:
885             instance = hInstDLL;
886             MLANG_tls_index = TlsAlloc();
887             DisableThreadLibraryCalls(hInstDLL);
888             break;
889         case DLL_PROCESS_DETACH:
890             TlsFree(MLANG_tls_index);
891             break;
892     }
893     return TRUE;
894 }
895
896 HRESULT WINAPI ConvertINetMultiByteToUnicode(
897     LPDWORD pdwMode,
898     DWORD dwEncoding,
899     LPCSTR pSrcStr,
900     LPINT pcSrcSize,
901     LPWSTR pDstStr,
902     LPINT pcDstSize)
903 {
904     INT src_len = -1;
905
906     TRACE("%p %d %s %p %p %p\n", pdwMode, dwEncoding,
907           debugstr_a(pSrcStr), pcSrcSize, pDstStr, pcDstSize);
908
909     if (!pcDstSize)
910         return E_FAIL;
911
912     if (!pcSrcSize)
913         pcSrcSize = &src_len;
914
915     if (!*pcSrcSize)
916     {
917         *pcDstSize = 0;
918         return S_OK;
919     }
920
921     /* forwarding euc-jp to EUC-JP */
922     if (dwEncoding == 51932)
923         dwEncoding = 20932;
924
925     switch (dwEncoding)
926     {
927     case CP_UNICODE:
928         if (*pcSrcSize == -1)
929             *pcSrcSize = lstrlenW((LPCWSTR)pSrcStr);
930         *pcDstSize = min(*pcSrcSize, *pcDstSize);
931         *pcSrcSize *= sizeof(WCHAR);
932         if (pDstStr)
933             memmove(pDstStr, pSrcStr, *pcDstSize * sizeof(WCHAR));
934         break;
935
936     case 50220:
937     case 50221:
938     case 50222:
939         *pcDstSize = ConvertJISJapaneseToUnicode(pSrcStr,*pcSrcSize,pDstStr,*pcDstSize);
940         break;
941     case 50932:
942         *pcDstSize = ConvertUnknownJapaneseToUnicode(pSrcStr,*pcSrcSize,pDstStr,*pcDstSize);
943         break;
944
945     default:
946         if (*pcSrcSize == -1)
947             *pcSrcSize = lstrlenA(pSrcStr);
948
949         if (pDstStr)
950             *pcDstSize = MultiByteToWideChar(dwEncoding, 0, pSrcStr, *pcSrcSize, pDstStr, *pcDstSize);
951         else
952             *pcDstSize = MultiByteToWideChar(dwEncoding, 0, pSrcStr, *pcSrcSize, NULL, 0);
953         break;
954     }
955     
956     if (!*pcDstSize)
957         return E_FAIL;
958
959     return S_OK;
960 }
961
962 HRESULT WINAPI ConvertINetUnicodeToMultiByte(
963     LPDWORD pdwMode,
964     DWORD dwEncoding,
965     LPCWSTR pSrcStr,
966     LPINT pcSrcSize,
967     LPSTR pDstStr,
968     LPINT pcDstSize)
969 {
970     INT destsz, size;
971     INT src_len = -1;
972
973     TRACE("%p %d %s %p %p %p\n", pdwMode, dwEncoding,
974           debugstr_w(pSrcStr), pcSrcSize, pDstStr, pcDstSize);
975
976     if (!pcDstSize)
977         return S_OK;
978
979     if (!pcSrcSize)
980         pcSrcSize = &src_len;
981
982     destsz = (pDstStr) ? *pcDstSize : 0;
983     *pcDstSize = 0;
984
985     if (!pSrcStr || !*pcSrcSize)
986         return S_OK;
987
988     if (*pcSrcSize == -1)
989         *pcSrcSize = lstrlenW(pSrcStr);
990
991     /* forwarding euc-jp to EUC-JP */
992     if (dwEncoding == 51932)
993         dwEncoding = 20932;
994
995     if (dwEncoding == CP_UNICODE)
996     {
997         if (*pcSrcSize == -1)
998             *pcSrcSize = lstrlenW(pSrcStr);
999
1000         size = min(*pcSrcSize, destsz) * sizeof(WCHAR);
1001         if (pDstStr)
1002             memmove(pDstStr, pSrcStr, size);
1003
1004         if (size >= destsz)
1005             goto fail;
1006     }
1007     else if (dwEncoding == 50220 || dwEncoding == 50221 || dwEncoding == 50222)
1008     {
1009         size = ConvertJapaneseUnicodeToJIS(pSrcStr, *pcSrcSize, NULL, 0);
1010         if (!size)
1011             goto fail;
1012
1013         if (pDstStr)
1014         {
1015             size = ConvertJapaneseUnicodeToJIS(pSrcStr, *pcSrcSize, pDstStr,
1016                                                destsz);
1017             if (!size)
1018                 goto fail;
1019         }
1020
1021     }
1022     else
1023     {
1024         size = WideCharToMultiByte(dwEncoding, 0, pSrcStr, *pcSrcSize,
1025                                    NULL, 0, NULL, NULL);
1026         if (!size)
1027             goto fail;
1028
1029         if (pDstStr)
1030         {
1031             size = WideCharToMultiByte(dwEncoding, 0, pSrcStr, *pcSrcSize,
1032                                        pDstStr, destsz, NULL, NULL);
1033             if (!size)
1034                 goto fail;
1035         }
1036     }
1037
1038     *pcDstSize = size;
1039     return S_OK;
1040
1041 fail:
1042     *pcSrcSize = 0;
1043     *pcDstSize = 0;
1044     return E_FAIL;
1045 }
1046
1047 HRESULT WINAPI ConvertINetString(
1048     LPDWORD pdwMode,
1049     DWORD dwSrcEncoding,
1050     DWORD dwDstEncoding,
1051     LPCSTR pSrcStr,
1052     LPINT pcSrcSize,
1053     LPSTR pDstStr,
1054     LPINT pcDstSize
1055 )
1056 {
1057     TRACE("%p %d %d %s %p %p %p\n", pdwMode, dwSrcEncoding, dwDstEncoding,
1058           debugstr_a(pSrcStr), pcSrcSize, pDstStr, pcDstSize);
1059
1060     if (dwSrcEncoding == CP_UNICODE)
1061     {
1062         INT cSrcSizeW;
1063         if (pcSrcSize && *pcSrcSize != -1)
1064         {
1065             cSrcSizeW = *pcSrcSize / sizeof(WCHAR);
1066             pcSrcSize = &cSrcSizeW;
1067         }
1068         return ConvertINetUnicodeToMultiByte(pdwMode, dwDstEncoding, (LPCWSTR)pSrcStr, pcSrcSize, pDstStr, pcDstSize);
1069     }
1070     else if (dwDstEncoding == CP_UNICODE)
1071     {
1072         HRESULT hr = ConvertINetMultiByteToUnicode(pdwMode, dwSrcEncoding, pSrcStr, pcSrcSize, (LPWSTR)pDstStr, pcDstSize);
1073         *pcDstSize *= sizeof(WCHAR);
1074         return hr;
1075     }
1076     else
1077     {
1078         INT cDstSizeW;
1079         LPWSTR pDstStrW;
1080         HRESULT hr;
1081
1082         TRACE("convert %s from %d to %d\n", debugstr_a(pSrcStr), dwSrcEncoding, dwDstEncoding);
1083
1084         hr = ConvertINetMultiByteToUnicode(pdwMode, dwSrcEncoding, pSrcStr, pcSrcSize, NULL, &cDstSizeW);
1085         if (hr != S_OK)
1086             return hr;
1087
1088         pDstStrW = HeapAlloc(GetProcessHeap(), 0, cDstSizeW * sizeof(WCHAR));
1089         hr = ConvertINetMultiByteToUnicode(pdwMode, dwSrcEncoding, pSrcStr, pcSrcSize, pDstStrW, &cDstSizeW);
1090         if (hr == S_OK)
1091             hr = ConvertINetUnicodeToMultiByte(pdwMode, dwDstEncoding, pDstStrW, &cDstSizeW, pDstStr, pcDstSize);
1092
1093         HeapFree(GetProcessHeap(), 0, pDstStrW);
1094         return hr;
1095     }
1096 }
1097
1098 static HRESULT GetFamilyCodePage(
1099     UINT uiCodePage,
1100     UINT* puiFamilyCodePage)
1101 {
1102     UINT i, n;
1103
1104     TRACE("%u %p\n", uiCodePage, puiFamilyCodePage);
1105
1106     if (!puiFamilyCodePage) return S_FALSE;
1107
1108     for (i = 0; i < sizeof(mlang_data)/sizeof(mlang_data[0]); i++)
1109     {
1110         for (n = 0; n < mlang_data[i].number_of_cp; n++)
1111         {
1112             if (mlang_data[i].mime_cp_info[n].cp == uiCodePage)
1113             {
1114                 *puiFamilyCodePage = mlang_data[i].family_codepage;
1115                 return S_OK;
1116             }
1117         }
1118     }
1119
1120     return S_FALSE;
1121 }
1122
1123 HRESULT WINAPI IsConvertINetStringAvailable(
1124     DWORD dwSrcEncoding,
1125     DWORD dwDstEncoding)
1126 {
1127     UINT src_family, dst_family;
1128
1129     TRACE("%d %d\n", dwSrcEncoding, dwDstEncoding);
1130
1131     if (GetFamilyCodePage(dwSrcEncoding, &src_family) != S_OK ||
1132         GetFamilyCodePage(dwDstEncoding, &dst_family) != S_OK)
1133         return S_FALSE;
1134
1135     if (src_family == dst_family) return S_OK;
1136
1137     /* we can convert any codepage to/from unicode */
1138     if (src_family == CP_UNICODE || dst_family == CP_UNICODE) return S_OK;
1139
1140     return S_FALSE;
1141 }
1142
1143 static inline HRESULT lcid_to_rfc1766A( LCID lcid, LPSTR rfc1766, INT len )
1144 {
1145     CHAR buffer[MAX_RFC1766_NAME];
1146     INT n = GetLocaleInfoA(lcid, LOCALE_SISO639LANGNAME, buffer, MAX_RFC1766_NAME);
1147     INT i;
1148
1149     if (n)
1150     {
1151         i = PRIMARYLANGID(lcid);
1152         if ((((i == LANG_ENGLISH) || (i == LANG_CHINESE) || (i == LANG_ARABIC)) &&
1153             (SUBLANGID(lcid) == SUBLANG_DEFAULT)) ||
1154             (SUBLANGID(lcid) > SUBLANG_DEFAULT)) {
1155
1156             buffer[n - 1] = '-';
1157             i = GetLocaleInfoA(lcid, LOCALE_SISO3166CTRYNAME, buffer + n, MAX_RFC1766_NAME - n);
1158             if (!i)
1159                 buffer[n - 1] = '\0';
1160         }
1161         else
1162             i = 0;
1163
1164         LCMapStringA( LOCALE_USER_DEFAULT, LCMAP_LOWERCASE, buffer, n + i, rfc1766, len );
1165         return ((n + i) > len) ? E_INVALIDARG : S_OK;
1166     }
1167     return E_FAIL;
1168 }
1169
1170 static inline HRESULT lcid_to_rfc1766W( LCID lcid, LPWSTR rfc1766, INT len )
1171 {
1172     WCHAR buffer[MAX_RFC1766_NAME];
1173     INT n = GetLocaleInfoW(lcid, LOCALE_SISO639LANGNAME, buffer, MAX_RFC1766_NAME);
1174     INT i;
1175
1176     if (n)
1177     {
1178         i = PRIMARYLANGID(lcid);
1179         if ((((i == LANG_ENGLISH) || (i == LANG_CHINESE) || (i == LANG_ARABIC)) &&
1180             (SUBLANGID(lcid) == SUBLANG_DEFAULT)) ||
1181             (SUBLANGID(lcid) > SUBLANG_DEFAULT)) {
1182
1183             buffer[n - 1] = '-';
1184             i = GetLocaleInfoW(lcid, LOCALE_SISO3166CTRYNAME, buffer + n, MAX_RFC1766_NAME - n);
1185             if (!i)
1186                 buffer[n - 1] = '\0';
1187         }
1188         else
1189             i = 0;
1190
1191         LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE, buffer, n + i, rfc1766, len);
1192         return ((n + i) > len) ? E_INVALIDARG : S_OK;
1193     }
1194     return E_FAIL;
1195 }
1196
1197 HRESULT WINAPI LcidToRfc1766A(
1198     LCID lcid,
1199     LPSTR pszRfc1766,
1200     INT nChar)
1201 {
1202     TRACE("%04x %p %u\n", lcid, pszRfc1766, nChar);
1203     if (!pszRfc1766)
1204         return E_INVALIDARG;
1205
1206     return lcid_to_rfc1766A(lcid, pszRfc1766, nChar);
1207 }
1208
1209 HRESULT WINAPI LcidToRfc1766W(
1210     LCID lcid,
1211     LPWSTR pszRfc1766,
1212     INT nChar)
1213 {
1214     TRACE("%04x %p %u\n", lcid, pszRfc1766, nChar);
1215     if (!pszRfc1766)
1216         return E_INVALIDARG;
1217
1218     return lcid_to_rfc1766W(lcid, pszRfc1766, nChar);
1219 }
1220
1221 static HRESULT lcid_from_rfc1766(IEnumRfc1766 *iface, LCID *lcid, LPCWSTR rfc1766)
1222 {
1223     RFC1766INFO info;
1224     ULONG num;
1225
1226     while (IEnumRfc1766_Next(iface, 1, &info, &num) == S_OK)
1227     {
1228         if (!strcmpiW(info.wszRfc1766, rfc1766))
1229         {
1230             *lcid = info.lcid;
1231             return S_OK;
1232         }
1233         if (strlenW(rfc1766) == 2 && !memcmp(info.wszRfc1766, rfc1766, 2 * sizeof(WCHAR)))
1234         {
1235             *lcid = PRIMARYLANGID(info.lcid);
1236             return S_OK;
1237         }
1238     }
1239
1240     return E_FAIL;
1241 }
1242
1243 HRESULT WINAPI Rfc1766ToLcidW(LCID *pLocale, LPCWSTR pszRfc1766)
1244 {
1245     IEnumRfc1766 *enumrfc1766;
1246     HRESULT hr;
1247
1248     TRACE("(%p, %s)\n", pLocale, debugstr_w(pszRfc1766));
1249
1250     if (!pLocale || !pszRfc1766)
1251         return E_INVALIDARG;
1252
1253     hr = EnumRfc1766_create(0, &enumrfc1766);
1254     if (FAILED(hr))
1255         return hr;
1256
1257     hr = lcid_from_rfc1766(enumrfc1766, pLocale, pszRfc1766);
1258     IEnumRfc1766_Release(enumrfc1766);
1259
1260     return hr;
1261 }
1262
1263 HRESULT WINAPI Rfc1766ToLcidA(LCID *lcid, LPCSTR rfc1766A)
1264 {
1265     WCHAR rfc1766W[MAX_RFC1766_NAME + 1];
1266
1267     if (!rfc1766A)
1268         return E_INVALIDARG;
1269
1270     MultiByteToWideChar(CP_ACP, 0, rfc1766A, -1, rfc1766W, MAX_RFC1766_NAME);
1271     rfc1766W[MAX_RFC1766_NAME] = 0;
1272
1273     return Rfc1766ToLcidW(lcid, rfc1766W);
1274 }
1275
1276 /******************************************************************************
1277  * MLANG ClassFactory
1278  */
1279 typedef struct {
1280     IClassFactory IClassFactory_iface;
1281     LONG ref;
1282     HRESULT (*pfnCreateInstance)(IUnknown *pUnkOuter, LPVOID *ppObj);
1283 } IClassFactoryImpl;
1284
1285 static inline IClassFactoryImpl *impl_from_IClassFactory(IClassFactory *iface)
1286 {
1287     return CONTAINING_RECORD(iface, IClassFactoryImpl, IClassFactory_iface);
1288 }
1289
1290 struct object_creation_info
1291 {
1292     const CLSID *clsid;
1293     LPCSTR szClassName;
1294     HRESULT (*pfnCreateInstance)(IUnknown *pUnkOuter, LPVOID *ppObj);
1295 };
1296
1297 static const struct object_creation_info object_creation[] =
1298 {
1299     { &CLSID_CMultiLanguage, "CLSID_CMultiLanguage", MultiLanguage_create },
1300 };
1301
1302 static HRESULT WINAPI MLANGCF_QueryInterface(IClassFactory *iface, REFIID riid, void **ppobj)
1303 {
1304     TRACE("%s\n", debugstr_guid(riid) );
1305
1306     if (IsEqualGUID(riid, &IID_IUnknown)
1307         || IsEqualGUID(riid, &IID_IClassFactory))
1308     {
1309         IClassFactory_AddRef(iface);
1310         *ppobj = iface;
1311         return S_OK;
1312     }
1313
1314     *ppobj = NULL;
1315     WARN("(%p)->(%s,%p), not found\n", iface, debugstr_guid(riid), ppobj);
1316     return E_NOINTERFACE;
1317 }
1318
1319 static ULONG WINAPI MLANGCF_AddRef(IClassFactory *iface)
1320 {
1321     IClassFactoryImpl *This = impl_from_IClassFactory(iface);
1322     return InterlockedIncrement(&This->ref);
1323 }
1324
1325 static ULONG WINAPI MLANGCF_Release(IClassFactory *iface)
1326 {
1327     IClassFactoryImpl *This = impl_from_IClassFactory(iface);
1328     ULONG ref = InterlockedDecrement(&This->ref);
1329
1330     if (ref == 0)
1331     {
1332         TRACE("Destroying %p\n", This);
1333         HeapFree(GetProcessHeap(), 0, This);
1334     }
1335
1336     return ref;
1337 }
1338
1339 static HRESULT WINAPI MLANGCF_CreateInstance(IClassFactory *iface, IUnknown *pOuter,
1340         REFIID riid, void **ppobj)
1341 {
1342     IClassFactoryImpl *This = impl_from_IClassFactory(iface);
1343     HRESULT hres;
1344     LPUNKNOWN punk;
1345     
1346     TRACE("(%p)->(%p,%s,%p)\n",This,pOuter,debugstr_guid(riid),ppobj);
1347
1348     *ppobj = NULL;
1349     hres = This->pfnCreateInstance(pOuter, (LPVOID *) &punk);
1350     if (SUCCEEDED(hres)) {
1351         hres = IUnknown_QueryInterface(punk, riid, ppobj);
1352         IUnknown_Release(punk);
1353     }
1354     TRACE("returning (%p) -> %x\n", *ppobj, hres);
1355     return hres;
1356 }
1357
1358 static HRESULT WINAPI MLANGCF_LockServer(IClassFactory *iface, BOOL dolock)
1359 {
1360     if (dolock)
1361         LockModule();
1362     else
1363         UnlockModule();
1364
1365     return S_OK;
1366 }
1367
1368 static const IClassFactoryVtbl MLANGCF_Vtbl =
1369 {
1370     MLANGCF_QueryInterface,
1371     MLANGCF_AddRef,
1372     MLANGCF_Release,
1373     MLANGCF_CreateInstance,
1374     MLANGCF_LockServer
1375 };
1376
1377 /******************************************************************
1378  *              DllGetClassObject (MLANG.@)
1379  */
1380 HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID iid, LPVOID *ppv)
1381 {
1382     unsigned int i;
1383     IClassFactoryImpl *factory;
1384
1385     TRACE("%s %s %p\n",debugstr_guid(rclsid), debugstr_guid(iid), ppv);
1386
1387     if ( !IsEqualGUID( &IID_IClassFactory, iid )
1388          && ! IsEqualGUID( &IID_IUnknown, iid) )
1389         return E_NOINTERFACE;
1390
1391     for (i=0; i < sizeof(object_creation)/sizeof(object_creation[0]); i++)
1392     {
1393         if (IsEqualGUID(object_creation[i].clsid, rclsid))
1394             break;
1395     }
1396
1397     if (i == sizeof(object_creation)/sizeof(object_creation[0]))
1398     {
1399         FIXME("%s: no class found.\n", debugstr_guid(rclsid));
1400         return CLASS_E_CLASSNOTAVAILABLE;
1401     }
1402
1403     TRACE("Creating a class factory for %s\n",object_creation[i].szClassName);
1404
1405     factory = HeapAlloc(GetProcessHeap(), 0, sizeof(*factory));
1406     if (factory == NULL) return E_OUTOFMEMORY;
1407
1408     factory->IClassFactory_iface.lpVtbl = &MLANGCF_Vtbl;
1409     factory->ref = 1;
1410
1411     factory->pfnCreateInstance = object_creation[i].pfnCreateInstance;
1412
1413     *ppv = &factory->IClassFactory_iface;
1414
1415     TRACE("(%p) <- %p\n", ppv, &factory->IClassFactory_iface);
1416
1417     return S_OK;
1418 }
1419
1420
1421 /******************************************************************************/
1422
1423 typedef struct tagMLang_impl
1424 {
1425     IMLangFontLink IMLangFontLink_iface;
1426     IMultiLanguage IMultiLanguage_iface;
1427     IMultiLanguage3 IMultiLanguage3_iface;
1428     IMLangFontLink2 IMLangFontLink2_iface;
1429     IMLangLineBreakConsole IMLangLineBreakConsole_iface;
1430     LONG ref;
1431     DWORD total_cp, total_scripts;
1432 } MLang_impl;
1433
1434 static ULONG MLang_AddRef( MLang_impl* This)
1435 {
1436     return InterlockedIncrement(&This->ref);
1437 }
1438
1439 static ULONG MLang_Release( MLang_impl* This )
1440 {
1441     ULONG ref = InterlockedDecrement(&This->ref);
1442
1443     TRACE("%p ref = %d\n", This, ref);
1444     if (ref == 0)
1445     {
1446         TRACE("Destroying %p\n", This);
1447         HeapFree(GetProcessHeap(), 0, This);
1448         UnlockModule();
1449     }
1450
1451     return ref;
1452 }
1453
1454 static HRESULT MLang_QueryInterface(
1455         MLang_impl* This,
1456         REFIID riid,
1457         void** ppvObject)
1458 {
1459     TRACE("%p -> %s\n", This, debugstr_guid(riid) );
1460
1461     if (IsEqualGUID(riid, &IID_IUnknown)
1462         || IsEqualGUID(riid, &IID_IMLangCodePages)
1463         || IsEqualGUID(riid, &IID_IMLangFontLink))
1464     {
1465         MLang_AddRef(This);
1466         TRACE("Returning IID_IMLangFontLink %p ref = %d\n", This, This->ref);
1467         *ppvObject = &This->IMLangFontLink_iface;
1468         return S_OK;
1469     }
1470
1471     if (IsEqualGUID(riid, &IID_IMLangFontLink2))
1472     {
1473         MLang_AddRef(This);
1474         TRACE("Returning IID_IMLangFontLink2 %p ref = %d\n", This, This->ref);
1475         *ppvObject = &This->IMLangFontLink2_iface;
1476         return S_OK;
1477     }
1478
1479     if (IsEqualGUID(riid, &IID_IMultiLanguage) )
1480     {
1481         MLang_AddRef(This);
1482         TRACE("Returning IID_IMultiLanguage %p ref = %d\n", This, This->ref);
1483         *ppvObject = &This->IMultiLanguage_iface;
1484         return S_OK;
1485     }
1486
1487     if (IsEqualGUID(riid, &IID_IMultiLanguage2) )
1488     {
1489         MLang_AddRef(This);
1490         *ppvObject = &This->IMultiLanguage3_iface;
1491         TRACE("Returning IID_IMultiLanguage2 %p ref = %d\n", This, This->ref);
1492         return S_OK;
1493     }
1494
1495     if (IsEqualGUID(riid, &IID_IMultiLanguage3) )
1496     {
1497         MLang_AddRef(This);
1498         *ppvObject = &This->IMultiLanguage3_iface;
1499         TRACE("Returning IID_IMultiLanguage3 %p ref = %d\n", This, This->ref);
1500         return S_OK;
1501     }
1502
1503     if (IsEqualGUID(riid, &IID_IMLangLineBreakConsole))
1504     {
1505         MLang_AddRef(This);
1506         TRACE("Returning IID_IMLangLineBreakConsole %p ref = %d\n", This, This->ref);
1507         *ppvObject = &This->IMLangLineBreakConsole_iface;
1508         return S_OK;
1509     }
1510
1511
1512     WARN("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppvObject);
1513     return E_NOINTERFACE;
1514 }
1515
1516 /******************************************************************************/
1517
1518 typedef struct tagEnumCodePage_impl
1519 {
1520     IEnumCodePage IEnumCodePage_iface;
1521     LONG ref;
1522     MIMECPINFO *cpinfo;
1523     DWORD total, pos;
1524 } EnumCodePage_impl;
1525
1526 static inline EnumCodePage_impl *impl_from_IEnumCodePage( IEnumCodePage *iface )
1527 {
1528     return CONTAINING_RECORD( iface, EnumCodePage_impl, IEnumCodePage_iface );
1529 }
1530
1531 static HRESULT WINAPI fnIEnumCodePage_QueryInterface(
1532         IEnumCodePage* iface,
1533         REFIID riid,
1534         void** ppvObject)
1535 {
1536     EnumCodePage_impl *This = impl_from_IEnumCodePage( iface );
1537
1538     TRACE("%p -> %s\n", This, debugstr_guid(riid) );
1539
1540     if (IsEqualGUID(riid, &IID_IUnknown)
1541         || IsEqualGUID(riid, &IID_IEnumCodePage))
1542     {
1543         IEnumCodePage_AddRef(iface);
1544         TRACE("Returning IID_IEnumCodePage %p ref = %d\n", This, This->ref);
1545         *ppvObject = &This->IEnumCodePage_iface;
1546         return S_OK;
1547     }
1548
1549     WARN("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppvObject);
1550     return E_NOINTERFACE;
1551 }
1552
1553 static ULONG WINAPI fnIEnumCodePage_AddRef(
1554         IEnumCodePage* iface)
1555 {
1556     EnumCodePage_impl *This = impl_from_IEnumCodePage( iface );
1557     return InterlockedIncrement(&This->ref);
1558 }
1559
1560 static ULONG WINAPI fnIEnumCodePage_Release(
1561         IEnumCodePage* iface)
1562 {
1563     EnumCodePage_impl *This = impl_from_IEnumCodePage( iface );
1564     ULONG ref = InterlockedDecrement(&This->ref);
1565
1566     TRACE("%p ref = %d\n", This, ref);
1567     if (ref == 0)
1568     {
1569         TRACE("Destroying %p\n", This);
1570         HeapFree(GetProcessHeap(), 0, This->cpinfo);
1571         HeapFree(GetProcessHeap(), 0, This);
1572     }
1573
1574     return ref;
1575 }
1576
1577 static HRESULT WINAPI fnIEnumCodePage_Clone(
1578         IEnumCodePage* iface,
1579         IEnumCodePage** ppEnum)
1580 {
1581     EnumCodePage_impl *This = impl_from_IEnumCodePage( iface );
1582     FIXME("%p %p\n", This, ppEnum);
1583     return E_NOTIMPL;
1584 }
1585
1586 static  HRESULT WINAPI fnIEnumCodePage_Next(
1587         IEnumCodePage* iface,
1588         ULONG celt,
1589         PMIMECPINFO rgelt,
1590         ULONG* pceltFetched)
1591 {
1592     ULONG i;
1593     EnumCodePage_impl *This = impl_from_IEnumCodePage( iface );
1594
1595     TRACE("%p %u %p %p\n", This, celt, rgelt, pceltFetched);
1596
1597     if (!pceltFetched) return S_FALSE;
1598     *pceltFetched = 0;
1599
1600     if (!rgelt) return S_FALSE;
1601
1602     if (This->pos + celt > This->total)
1603         celt = This->total - This->pos;
1604
1605     if (!celt) return S_FALSE;
1606
1607     memcpy(rgelt, This->cpinfo + This->pos, celt * sizeof(MIMECPINFO));
1608     *pceltFetched = celt;
1609     This->pos += celt;
1610
1611     for (i = 0; i < celt; i++)
1612     {
1613         TRACE("#%u: %08x %u %u %s %s %s %s %s %s %d\n",
1614               i, rgelt[i].dwFlags, rgelt[i].uiCodePage,
1615               rgelt[i].uiFamilyCodePage,
1616               wine_dbgstr_w(rgelt[i].wszDescription),
1617               wine_dbgstr_w(rgelt[i].wszWebCharset),
1618               wine_dbgstr_w(rgelt[i].wszHeaderCharset),
1619               wine_dbgstr_w(rgelt[i].wszBodyCharset),
1620               wine_dbgstr_w(rgelt[i].wszFixedWidthFont),
1621               wine_dbgstr_w(rgelt[i].wszProportionalFont),
1622               rgelt[i].bGDICharset);
1623     }
1624     return S_OK;
1625 }
1626
1627 static HRESULT WINAPI fnIEnumCodePage_Reset(
1628         IEnumCodePage* iface)
1629 {
1630     EnumCodePage_impl *This = impl_from_IEnumCodePage( iface );
1631
1632     TRACE("%p\n", This);
1633
1634     This->pos = 0;
1635     return S_OK;
1636 }
1637
1638 static  HRESULT WINAPI fnIEnumCodePage_Skip(
1639         IEnumCodePage* iface,
1640         ULONG celt)
1641 {
1642     EnumCodePage_impl *This = impl_from_IEnumCodePage( iface );
1643
1644     TRACE("%p %u\n", This, celt);
1645
1646     if (celt >= This->total) return S_FALSE;
1647
1648     This->pos += celt;
1649     return S_OK;
1650 }
1651
1652 static const IEnumCodePageVtbl IEnumCodePage_vtbl =
1653 {
1654     fnIEnumCodePage_QueryInterface,
1655     fnIEnumCodePage_AddRef,
1656     fnIEnumCodePage_Release,
1657     fnIEnumCodePage_Clone,
1658     fnIEnumCodePage_Next,
1659     fnIEnumCodePage_Reset,
1660     fnIEnumCodePage_Skip
1661 };
1662
1663 static HRESULT EnumCodePage_create( MLang_impl* mlang, DWORD grfFlags,
1664                      LANGID LangId, IEnumCodePage** ppEnumCodePage )
1665 {
1666     EnumCodePage_impl *ecp;
1667     MIMECPINFO *cpinfo;
1668     UINT i, n;
1669
1670     TRACE("%p, %08x, %04x, %p\n", mlang, grfFlags, LangId, ppEnumCodePage);
1671
1672     if (!grfFlags) /* enumerate internal data base of encodings */
1673         grfFlags = MIMECONTF_MIME_LATEST;
1674
1675     ecp = HeapAlloc( GetProcessHeap(), 0, sizeof (EnumCodePage_impl) );
1676     ecp->IEnumCodePage_iface.lpVtbl = &IEnumCodePage_vtbl;
1677     ecp->ref = 1;
1678     ecp->pos = 0;
1679     ecp->total = 0;
1680     for (i = 0; i < sizeof(mlang_data)/sizeof(mlang_data[0]); i++)
1681     {
1682         for (n = 0; n < mlang_data[i].number_of_cp; n++)
1683         {
1684             if (mlang_data[i].mime_cp_info[n].flags & grfFlags)
1685                 ecp->total++;
1686         }
1687     }
1688
1689     ecp->cpinfo = HeapAlloc(GetProcessHeap(), 0,
1690                             sizeof(MIMECPINFO) * ecp->total);
1691     cpinfo = ecp->cpinfo;
1692
1693     for (i = 0; i < sizeof(mlang_data)/sizeof(mlang_data[0]); i++)
1694     {
1695         for (n = 0; n < mlang_data[i].number_of_cp; n++)
1696         {
1697             if (mlang_data[i].mime_cp_info[n].flags & grfFlags)
1698                 fill_cp_info(&mlang_data[i], n, cpinfo++);
1699         }
1700     }
1701
1702     TRACE("enumerated %d codepages with flags %08x\n", ecp->total, grfFlags);
1703
1704     *ppEnumCodePage = &ecp->IEnumCodePage_iface;
1705
1706     return S_OK;
1707 }
1708
1709 /******************************************************************************/
1710
1711 typedef struct tagEnumScript_impl
1712 {
1713     IEnumScript IEnumScript_iface;
1714     LONG ref;
1715     SCRIPTINFO *script_info;
1716     DWORD total, pos;
1717 } EnumScript_impl;
1718
1719 static inline EnumScript_impl *impl_from_IEnumScript( IEnumScript *iface )
1720 {
1721     return CONTAINING_RECORD( iface, EnumScript_impl, IEnumScript_iface );
1722 }
1723
1724 static HRESULT WINAPI fnIEnumScript_QueryInterface(
1725         IEnumScript* iface,
1726         REFIID riid,
1727         void** ppvObject)
1728 {
1729     EnumScript_impl *This = impl_from_IEnumScript( iface );
1730
1731     TRACE("%p -> %s\n", This, debugstr_guid(riid) );
1732
1733     if (IsEqualGUID(riid, &IID_IUnknown)
1734         || IsEqualGUID(riid, &IID_IEnumScript))
1735     {
1736         IEnumScript_AddRef(iface);
1737         TRACE("Returning IID_IEnumScript %p ref = %d\n", This, This->ref);
1738         *ppvObject = &This->IEnumScript_iface;
1739         return S_OK;
1740     }
1741
1742     WARN("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppvObject);
1743     return E_NOINTERFACE;
1744 }
1745
1746 static ULONG WINAPI fnIEnumScript_AddRef(
1747         IEnumScript* iface)
1748 {
1749     EnumScript_impl *This = impl_from_IEnumScript( iface );
1750     return InterlockedIncrement(&This->ref);
1751 }
1752
1753 static ULONG WINAPI fnIEnumScript_Release(
1754         IEnumScript* iface)
1755 {
1756     EnumScript_impl *This = impl_from_IEnumScript( iface );
1757     ULONG ref = InterlockedDecrement(&This->ref);
1758
1759     TRACE("%p ref = %d\n", This, ref);
1760     if (ref == 0)
1761     {
1762         TRACE("Destroying %p\n", This);
1763         HeapFree(GetProcessHeap(), 0, This->script_info);
1764         HeapFree(GetProcessHeap(), 0, This);
1765     }
1766
1767     return ref;
1768 }
1769
1770 static HRESULT WINAPI fnIEnumScript_Clone(
1771         IEnumScript* iface,
1772         IEnumScript** ppEnum)
1773 {
1774     EnumScript_impl *This = impl_from_IEnumScript( iface );
1775     FIXME("%p %p: stub!\n", This, ppEnum);
1776     return E_NOTIMPL;
1777 }
1778
1779 static  HRESULT WINAPI fnIEnumScript_Next(
1780         IEnumScript* iface,
1781         ULONG celt,
1782         PSCRIPTINFO rgelt,
1783         ULONG* pceltFetched)
1784 {
1785     EnumScript_impl *This = impl_from_IEnumScript( iface );
1786
1787     TRACE("%p %u %p %p\n", This, celt, rgelt, pceltFetched);
1788
1789     if (!pceltFetched || !rgelt) return E_FAIL;
1790
1791     *pceltFetched = 0;
1792
1793     if (This->pos + celt > This->total)
1794         celt = This->total - This->pos;
1795
1796     if (!celt) return S_FALSE;
1797
1798     memcpy(rgelt, This->script_info + This->pos, celt * sizeof(SCRIPTINFO));
1799     *pceltFetched = celt;
1800     This->pos += celt;
1801
1802     return S_OK;
1803 }
1804
1805 static HRESULT WINAPI fnIEnumScript_Reset(
1806         IEnumScript* iface)
1807 {
1808     EnumScript_impl *This = impl_from_IEnumScript( iface );
1809
1810     TRACE("%p\n", This);
1811
1812     This->pos = 0;
1813     return S_OK;
1814 }
1815
1816 static  HRESULT WINAPI fnIEnumScript_Skip(
1817         IEnumScript* iface,
1818         ULONG celt)
1819 {
1820     EnumScript_impl *This = impl_from_IEnumScript( iface );
1821
1822     TRACE("%p %u\n", This, celt);
1823
1824     if (celt >= This->total) return S_FALSE;
1825
1826     This->pos += celt;
1827     return S_OK;
1828 }
1829
1830 static const IEnumScriptVtbl IEnumScript_vtbl =
1831 {
1832     fnIEnumScript_QueryInterface,
1833     fnIEnumScript_AddRef,
1834     fnIEnumScript_Release,
1835     fnIEnumScript_Clone,
1836     fnIEnumScript_Next,
1837     fnIEnumScript_Reset,
1838     fnIEnumScript_Skip
1839 };
1840
1841 static HRESULT EnumScript_create( MLang_impl* mlang, DWORD dwFlags,
1842                      LANGID LangId, IEnumScript** ppEnumScript )
1843 {
1844     EnumScript_impl *es;
1845     UINT i;
1846
1847     TRACE("%p, %08x, %04x, %p: stub!\n", mlang, dwFlags, LangId, ppEnumScript);
1848
1849     if (!dwFlags) /* enumerate all available scripts */
1850         dwFlags = SCRIPTCONTF_SCRIPT_USER | SCRIPTCONTF_SCRIPT_HIDE | SCRIPTCONTF_SCRIPT_SYSTEM;
1851
1852     es = HeapAlloc( GetProcessHeap(), 0, sizeof (EnumScript_impl) );
1853     es->IEnumScript_iface.lpVtbl = &IEnumScript_vtbl;
1854     es->ref = 1;
1855     es->pos = 0;
1856     /* do not enumerate unicode flavours */
1857     es->total = sizeof(mlang_data)/sizeof(mlang_data[0]) - 1;
1858     es->script_info = HeapAlloc(GetProcessHeap(), 0, sizeof(SCRIPTINFO) * es->total);
1859
1860     for (i = 0; i < es->total; i++)
1861     {
1862         es->script_info[i].ScriptId = i;
1863         es->script_info[i].uiCodePage = mlang_data[i].family_codepage;
1864         MultiByteToWideChar(CP_ACP, 0, mlang_data[i].description, -1,
1865             es->script_info[i].wszDescription, MAX_SCRIPT_NAME);
1866         MultiByteToWideChar(CP_ACP, 0, mlang_data[i].fixed_font, -1,
1867             es->script_info[i].wszFixedWidthFont, MAX_MIMEFACE_NAME);
1868         MultiByteToWideChar(CP_ACP, 0, mlang_data[i].proportional_font, -1,
1869             es->script_info[i].wszProportionalFont, MAX_MIMEFACE_NAME);
1870     }
1871
1872     TRACE("enumerated %d scripts with flags %08x\n", es->total, dwFlags);
1873
1874     *ppEnumScript = &es->IEnumScript_iface;
1875
1876     return S_OK;
1877 }
1878
1879 /******************************************************************************/
1880
1881 static inline MLang_impl *impl_from_IMLangFontLink( IMLangFontLink *iface )
1882 {
1883     return CONTAINING_RECORD( iface, MLang_impl, IMLangFontLink_iface );
1884 }
1885
1886 static HRESULT WINAPI fnIMLangFontLink_QueryInterface(
1887         IMLangFontLink* iface,
1888         REFIID riid,
1889         void** ppvObject)
1890 {
1891     MLang_impl *This = impl_from_IMLangFontLink( iface );
1892     return MLang_QueryInterface( This, riid, ppvObject );
1893 }
1894
1895 static ULONG WINAPI fnIMLangFontLink_AddRef(
1896         IMLangFontLink* iface)
1897 {
1898     MLang_impl *This = impl_from_IMLangFontLink( iface );
1899     return MLang_AddRef( This );
1900 }
1901
1902 static ULONG WINAPI fnIMLangFontLink_Release(
1903         IMLangFontLink* iface)
1904 {
1905     MLang_impl *This = impl_from_IMLangFontLink( iface );
1906     return MLang_Release( This );
1907 }
1908
1909 static HRESULT WINAPI fnIMLangFontLink_GetCharCodePages(
1910         IMLangFontLink* iface,
1911         WCHAR chSrc,
1912         DWORD* pdwCodePages)
1913 {
1914     int i;
1915     CHAR buf;
1916     BOOL used_dc;
1917     DWORD codePages;
1918
1919     *pdwCodePages = 0;
1920
1921     for (i = 0; i < sizeof(mlang_data)/sizeof(mlang_data[0]); i++)
1922     {
1923         WideCharToMultiByte(mlang_data[i].family_codepage, WC_NO_BEST_FIT_CHARS,
1924             &chSrc, 1, &buf, 1, NULL, &used_dc);
1925
1926         /* If default char is not used, current codepage include the given symbol */
1927         if (!used_dc)
1928         {
1929             IMLangFontLink_CodePageToCodePages(iface,
1930                 mlang_data[i].family_codepage, &codePages);
1931             *pdwCodePages |= codePages;
1932         }
1933     }
1934     return S_OK;
1935 }
1936
1937 static HRESULT WINAPI fnIMLangFontLink_GetStrCodePages(
1938         IMLangFontLink* iface,
1939         const WCHAR* pszSrc,
1940         LONG cchSrc,
1941         DWORD dwPriorityCodePages,
1942         DWORD* pdwCodePages,
1943         LONG* pcchCodePages)
1944 {
1945     LONG i;
1946     DWORD cps = 0;
1947
1948     TRACE("(%p)->%s %d %x %p %p\n", iface, debugstr_wn(pszSrc, cchSrc), cchSrc, dwPriorityCodePages, pdwCodePages, pcchCodePages);
1949
1950     if (pdwCodePages) *pdwCodePages = 0;
1951     if (pcchCodePages) *pcchCodePages = 0;
1952
1953     if (!pszSrc || !cchSrc || cchSrc < 0)
1954         return E_INVALIDARG;
1955
1956     for (i = 0; i < cchSrc; i++)
1957     {
1958         DWORD cp;
1959         HRESULT ret;
1960
1961         ret = fnIMLangFontLink_GetCharCodePages(iface, pszSrc[i], &cp);
1962         if (ret != S_OK) return E_FAIL;
1963
1964         if (!cps) cps = cp;
1965         else cps &= cp;
1966
1967         /* FIXME: not tested */
1968         if (dwPriorityCodePages & cps) break;
1969     }
1970
1971     if (pdwCodePages) *pdwCodePages = cps;
1972     if (pcchCodePages) *pcchCodePages = min( i + 1, cchSrc );
1973     return S_OK;
1974 }
1975
1976 static HRESULT WINAPI fnIMLangFontLink_CodePageToCodePages(
1977         IMLangFontLink* iface,
1978         UINT uCodePage,
1979         DWORD* pdwCodePages)
1980 {
1981     MLang_impl *This = impl_from_IMLangFontLink( iface );
1982     CHARSETINFO cs;
1983     BOOL rc; 
1984
1985     TRACE("(%p) Seeking %u\n",This, uCodePage);
1986
1987     rc = TranslateCharsetInfo((DWORD*)(DWORD_PTR)uCodePage, &cs, TCI_SRCCODEPAGE);
1988
1989     if (rc)
1990     {
1991         *pdwCodePages = cs.fs.fsCsb[0];
1992         TRACE("resulting CodePages 0x%x\n",*pdwCodePages);
1993         return S_OK;
1994     }
1995
1996     TRACE("CodePage Not Found\n");
1997     *pdwCodePages = 0;
1998     return E_FAIL;
1999 }
2000
2001 static HRESULT WINAPI fnIMLangFontLink_CodePagesToCodePage(
2002         IMLangFontLink* iface,
2003         DWORD dwCodePages,
2004         UINT uDefaultCodePage,
2005         UINT* puCodePage)
2006 {
2007     MLang_impl *This = impl_from_IMLangFontLink( iface );
2008     DWORD mask = 0x00000000;
2009     UINT i;
2010     CHARSETINFO cs;
2011     BOOL rc; 
2012
2013     TRACE("(%p) scanning  0x%x  default page %u\n",This, dwCodePages,
2014             uDefaultCodePage);
2015
2016     *puCodePage = 0x00000000;
2017
2018     rc = TranslateCharsetInfo((DWORD*)(DWORD_PTR)uDefaultCodePage, &cs,
2019                               TCI_SRCCODEPAGE);
2020
2021     if (rc && (dwCodePages & cs.fs.fsCsb[0]))
2022     {
2023         TRACE("Found Default Codepage\n");
2024         *puCodePage = uDefaultCodePage;
2025         return S_OK;
2026     }
2027
2028     
2029     for (i = 0; i < 32; i++)
2030     {
2031
2032         mask = 1 << i;
2033         if (dwCodePages & mask)
2034         {
2035             DWORD Csb[2];
2036             Csb[0] = mask;
2037             Csb[1] = 0x0;
2038             rc = TranslateCharsetInfo(Csb, &cs, TCI_SRCFONTSIG);
2039             if (!rc)
2040                 continue;
2041
2042             TRACE("Falling back to least significant found CodePage %u\n",
2043                     cs.ciACP);
2044             *puCodePage = cs.ciACP;
2045             return S_OK;
2046         }
2047     }
2048
2049     TRACE("no codepage found\n");
2050     return E_FAIL;
2051 }
2052
2053 static HRESULT WINAPI fnIMLangFontLink_GetFontCodePages(
2054         IMLangFontLink* iface,
2055         HDC hDC,
2056         HFONT hFont,
2057         DWORD* pdwCodePages)
2058 {
2059     HFONT old_font;
2060     FONTSIGNATURE fontsig;
2061     MLang_impl *This = impl_from_IMLangFontLink( iface );
2062
2063     TRACE("(%p)\n",This);
2064
2065     old_font = SelectObject(hDC,hFont);
2066     GetTextCharsetInfo(hDC,&fontsig, 0);
2067     SelectObject(hDC,old_font);
2068
2069     *pdwCodePages = fontsig.fsCsb[0];
2070     TRACE("CodePages is 0x%x\n",fontsig.fsCsb[0]);
2071
2072     return S_OK;
2073 }
2074
2075 static HRESULT WINAPI fnIMLangFontLink_MapFont(
2076         IMLangFontLink* iface,
2077         HDC hDC,
2078         DWORD dwCodePages,
2079         HFONT hSrcFont,
2080         HFONT* phDestFont)
2081 {
2082     FIXME("\n");
2083     return E_NOTIMPL;
2084 }
2085
2086 static HRESULT WINAPI fnIMLangFontLink_ReleaseFont(
2087         IMLangFontLink* iface,
2088         HFONT hFont)
2089 {
2090     FIXME("\n");
2091     return E_NOTIMPL;
2092 }
2093
2094 static HRESULT WINAPI fnIMLangFontLink_ResetFontMapping(
2095         IMLangFontLink* iface)
2096 {
2097     FIXME("\n");
2098     return E_NOTIMPL;
2099 }
2100
2101
2102 static const IMLangFontLinkVtbl IMLangFontLink_vtbl =
2103 {
2104     fnIMLangFontLink_QueryInterface,
2105     fnIMLangFontLink_AddRef,
2106     fnIMLangFontLink_Release,
2107     fnIMLangFontLink_GetCharCodePages,
2108     fnIMLangFontLink_GetStrCodePages,
2109     fnIMLangFontLink_CodePageToCodePages,
2110     fnIMLangFontLink_CodePagesToCodePage,
2111     fnIMLangFontLink_GetFontCodePages,
2112     fnIMLangFontLink_MapFont,
2113     fnIMLangFontLink_ReleaseFont,
2114     fnIMLangFontLink_ResetFontMapping,
2115 };
2116
2117 /******************************************************************************/
2118
2119 static inline MLang_impl *impl_from_IMultiLanguage( IMultiLanguage *iface )
2120 {
2121     return CONTAINING_RECORD( iface, MLang_impl, IMultiLanguage_iface );
2122 }
2123
2124 static HRESULT WINAPI fnIMultiLanguage_QueryInterface(
2125     IMultiLanguage* iface,
2126     REFIID riid,
2127     void** ppvObject)
2128 {
2129     MLang_impl *This = impl_from_IMultiLanguage( iface );
2130     return MLang_QueryInterface( This, riid, ppvObject );
2131 }
2132
2133 static ULONG WINAPI fnIMultiLanguage_AddRef( IMultiLanguage* iface )
2134 {
2135     MLang_impl *This = impl_from_IMultiLanguage( iface );
2136     return IMLangFontLink_AddRef( &This->IMLangFontLink_iface );
2137 }
2138
2139 static ULONG WINAPI fnIMultiLanguage_Release( IMultiLanguage* iface )
2140 {
2141     MLang_impl *This = impl_from_IMultiLanguage( iface );
2142     return IMLangFontLink_Release( &This->IMLangFontLink_iface );
2143 }
2144
2145 static HRESULT WINAPI fnIMultiLanguage_GetNumberOfCodePageInfo(
2146     IMultiLanguage* iface,
2147     UINT* pcCodePage)
2148 {
2149     MLang_impl *This = impl_from_IMultiLanguage( iface );
2150
2151     TRACE("(%p, %p)\n", This, pcCodePage);
2152
2153     if (!pcCodePage) return E_INVALIDARG;
2154
2155     *pcCodePage = This->total_cp;
2156     return S_OK;
2157 }
2158
2159 static HRESULT WINAPI fnIMultiLanguage_GetCodePageInfo(
2160     IMultiLanguage* iface,
2161     UINT uiCodePage,
2162     PMIMECPINFO pCodePageInfo)
2163 {
2164     UINT i, n;
2165     MLang_impl *This = impl_from_IMultiLanguage( iface );
2166
2167     TRACE("%p, %u, %p\n", This, uiCodePage, pCodePageInfo);
2168
2169     for (i = 0; i < sizeof(mlang_data)/sizeof(mlang_data[0]); i++)
2170     {
2171         for (n = 0; n < mlang_data[i].number_of_cp; n++)
2172         {
2173             if (mlang_data[i].mime_cp_info[n].cp == uiCodePage)
2174             {
2175                 fill_cp_info(&mlang_data[i], n, pCodePageInfo);
2176                 return S_OK;
2177             }
2178         }
2179     }
2180
2181     return S_FALSE;
2182 }
2183
2184 static HRESULT WINAPI fnIMultiLanguage_GetFamilyCodePage(
2185     IMultiLanguage* iface,
2186     UINT uiCodePage,
2187     UINT* puiFamilyCodePage)
2188 {
2189     return GetFamilyCodePage(uiCodePage, puiFamilyCodePage);
2190 }
2191
2192 static HRESULT WINAPI fnIMultiLanguage_EnumCodePages(
2193     IMultiLanguage* iface,
2194     DWORD grfFlags,
2195     IEnumCodePage** ppEnumCodePage)
2196 {
2197     MLang_impl *This = impl_from_IMultiLanguage( iface );
2198
2199     TRACE("%p %08x %p\n", This, grfFlags, ppEnumCodePage);
2200
2201     return EnumCodePage_create( This, grfFlags, 0, ppEnumCodePage );
2202 }
2203
2204 static HRESULT WINAPI fnIMultiLanguage_GetCharsetInfo(
2205     IMultiLanguage* iface,
2206     BSTR Charset,
2207     PMIMECSETINFO pCharsetInfo)
2208 {
2209     MLang_impl *This = impl_from_IMultiLanguage( iface );
2210     return IMultiLanguage3_GetCharsetInfo( &This->IMultiLanguage3_iface, Charset, pCharsetInfo );
2211 }
2212
2213 static HRESULT WINAPI fnIMultiLanguage_IsConvertible(
2214     IMultiLanguage* iface,
2215     DWORD dwSrcEncoding,
2216     DWORD dwDstEncoding)
2217 {
2218     return IsConvertINetStringAvailable(dwSrcEncoding, dwDstEncoding);
2219 }
2220
2221 static HRESULT WINAPI fnIMultiLanguage_ConvertString(
2222     IMultiLanguage* iface,
2223     DWORD* pdwMode,
2224     DWORD dwSrcEncoding,
2225     DWORD dwDstEncoding,
2226     BYTE* pSrcStr,
2227     UINT* pcSrcSize,
2228     BYTE* pDstStr,
2229     UINT* pcDstSize)
2230 {
2231     return ConvertINetString(pdwMode, dwSrcEncoding, dwDstEncoding,
2232         (LPCSTR)pSrcStr, (LPINT)pcSrcSize, (LPSTR)pDstStr, (LPINT)pcDstSize);
2233 }
2234
2235 static HRESULT WINAPI fnIMultiLanguage_ConvertStringToUnicode(
2236     IMultiLanguage* iface,
2237     DWORD* pdwMode,
2238     DWORD dwEncoding,
2239     CHAR* pSrcStr,
2240     UINT* pcSrcSize,
2241     WCHAR* pDstStr,
2242     UINT* pcDstSize)
2243 {
2244     return ConvertINetMultiByteToUnicode(pdwMode, dwEncoding,
2245         (LPCSTR)pSrcStr, (LPINT)pcSrcSize, pDstStr, (LPINT)pcDstSize);
2246 }
2247
2248 static HRESULT WINAPI fnIMultiLanguage_ConvertStringFromUnicode(
2249     IMultiLanguage* iface,
2250     DWORD* pdwMode,
2251     DWORD dwEncoding,
2252     WCHAR* pSrcStr,
2253     UINT* pcSrcSize,
2254     CHAR* pDstStr,
2255     UINT* pcDstSize)
2256 {
2257     return ConvertINetUnicodeToMultiByte(pdwMode, dwEncoding,
2258         pSrcStr, (LPINT)pcSrcSize, pDstStr, (LPINT)pcDstSize);
2259 }
2260
2261 static HRESULT WINAPI fnIMultiLanguage_ConvertStringReset(
2262     IMultiLanguage* iface)
2263 {
2264     FIXME("\n");
2265     return E_NOTIMPL;
2266 }
2267
2268 static HRESULT WINAPI fnIMultiLanguage_GetRfc1766FromLcid(
2269     IMultiLanguage* iface,
2270     LCID lcid,
2271     BSTR* pbstrRfc1766)
2272 {
2273     WCHAR buf[MAX_RFC1766_NAME];
2274
2275     TRACE("%p %04x %p\n", iface, lcid, pbstrRfc1766);
2276     if (!pbstrRfc1766)
2277         return E_INVALIDARG;
2278
2279     if (!lcid_to_rfc1766W( lcid, buf, MAX_RFC1766_NAME ))
2280     {
2281         *pbstrRfc1766 = SysAllocString( buf );
2282         return S_OK;
2283     }
2284     return E_FAIL;
2285 }
2286
2287 static HRESULT WINAPI fnIMultiLanguage_GetLcidFromRfc1766(
2288     IMultiLanguage* iface,
2289     LCID* pLocale,
2290     BSTR bstrRfc1766)
2291 {
2292     HRESULT hr;
2293     IEnumRfc1766 *rfc1766;
2294
2295     TRACE("%p %p %s\n", iface, pLocale, debugstr_w(bstrRfc1766));
2296
2297     if (!pLocale || !bstrRfc1766)
2298         return E_INVALIDARG;
2299
2300     hr = IMultiLanguage_EnumRfc1766(iface, &rfc1766);
2301     if (FAILED(hr))
2302         return hr;
2303
2304     hr = lcid_from_rfc1766(rfc1766, pLocale, bstrRfc1766);
2305
2306     IEnumRfc1766_Release(rfc1766);
2307     return hr;
2308 }
2309
2310 /******************************************************************************/
2311
2312 typedef struct tagEnumRfc1766_impl
2313 {
2314     IEnumRfc1766 IEnumRfc1766_iface;
2315     LONG ref;
2316     RFC1766INFO *info;
2317     DWORD total, pos;
2318 } EnumRfc1766_impl;
2319
2320 static inline EnumRfc1766_impl *impl_from_IEnumRfc1766( IEnumRfc1766 *iface )
2321 {
2322     return CONTAINING_RECORD( iface, EnumRfc1766_impl, IEnumRfc1766_iface );
2323 }
2324
2325 static HRESULT WINAPI fnIEnumRfc1766_QueryInterface(
2326         IEnumRfc1766 *iface,
2327         REFIID riid,
2328         void** ppvObject)
2329 {
2330     EnumRfc1766_impl *This = impl_from_IEnumRfc1766( iface );
2331
2332     TRACE("%p -> %s\n", This, debugstr_guid(riid) );
2333
2334     if (IsEqualGUID(riid, &IID_IUnknown)
2335         || IsEqualGUID(riid, &IID_IEnumRfc1766))
2336     {
2337         IEnumRfc1766_AddRef(iface);
2338         TRACE("Returning IID_IEnumRfc1766 %p ref = %d\n", This, This->ref);
2339         *ppvObject = &This->IEnumRfc1766_iface;
2340         return S_OK;
2341     }
2342
2343     WARN("(%p) -> (%s,%p), not found\n",This,debugstr_guid(riid),ppvObject);
2344     return E_NOINTERFACE;
2345 }
2346
2347 static ULONG WINAPI fnIEnumRfc1766_AddRef(
2348         IEnumRfc1766 *iface)
2349 {
2350     EnumRfc1766_impl *This = impl_from_IEnumRfc1766( iface );
2351     return InterlockedIncrement(&This->ref);
2352 }
2353
2354 static ULONG WINAPI fnIEnumRfc1766_Release(
2355         IEnumRfc1766 *iface)
2356 {
2357     EnumRfc1766_impl *This = impl_from_IEnumRfc1766( iface );
2358     ULONG ref = InterlockedDecrement(&This->ref);
2359
2360     TRACE("%p ref = %d\n", This, ref);
2361     if (ref == 0)
2362     {
2363         TRACE("Destroying %p\n", This);
2364         HeapFree(GetProcessHeap(), 0, This->info);
2365         HeapFree(GetProcessHeap(), 0, This);
2366     }
2367     return ref;
2368 }
2369
2370 static HRESULT WINAPI fnIEnumRfc1766_Clone(
2371         IEnumRfc1766 *iface,
2372         IEnumRfc1766 **ppEnum)
2373 {
2374     EnumRfc1766_impl *This = impl_from_IEnumRfc1766( iface );
2375
2376     FIXME("%p %p\n", This, ppEnum);
2377     return E_NOTIMPL;
2378 }
2379
2380 static  HRESULT WINAPI fnIEnumRfc1766_Next(
2381         IEnumRfc1766 *iface,
2382         ULONG celt,
2383         PRFC1766INFO rgelt,
2384         ULONG *pceltFetched)
2385 {
2386     ULONG i;
2387     EnumRfc1766_impl *This = impl_from_IEnumRfc1766( iface );
2388
2389     TRACE("%p %u %p %p\n", This, celt, rgelt, pceltFetched);
2390
2391     if (!pceltFetched) return S_FALSE;
2392     *pceltFetched = 0;
2393
2394     if (!rgelt) return S_FALSE;
2395
2396     if (This->pos + celt > This->total)
2397         celt = This->total - This->pos;
2398
2399     if (!celt) return S_FALSE;
2400
2401     memcpy(rgelt, This->info + This->pos, celt * sizeof(RFC1766INFO));
2402     *pceltFetched = celt;
2403     This->pos += celt;
2404
2405     for (i = 0; i < celt; i++)
2406     {
2407         TRACE("#%u: %08x %s %s\n",
2408               i, rgelt[i].lcid,
2409               wine_dbgstr_w(rgelt[i].wszRfc1766),
2410               wine_dbgstr_w(rgelt[i].wszLocaleName));
2411     }
2412     return S_OK;
2413 }
2414
2415 static HRESULT WINAPI fnIEnumRfc1766_Reset(
2416         IEnumRfc1766 *iface)
2417 {
2418     EnumRfc1766_impl *This = impl_from_IEnumRfc1766( iface );
2419
2420     TRACE("%p\n", This);
2421
2422     This->pos = 0;
2423     return S_OK;
2424 }
2425
2426 static  HRESULT WINAPI fnIEnumRfc1766_Skip(
2427         IEnumRfc1766 *iface,
2428         ULONG celt)
2429 {
2430     EnumRfc1766_impl *This = impl_from_IEnumRfc1766( iface );
2431
2432     TRACE("%p %u\n", This, celt);
2433
2434     if (celt >= This->total) return S_FALSE;
2435
2436     This->pos += celt;
2437     return S_OK;
2438 }
2439
2440 static const IEnumRfc1766Vtbl IEnumRfc1766_vtbl =
2441 {
2442     fnIEnumRfc1766_QueryInterface,
2443     fnIEnumRfc1766_AddRef,
2444     fnIEnumRfc1766_Release,
2445     fnIEnumRfc1766_Clone,
2446     fnIEnumRfc1766_Next,
2447     fnIEnumRfc1766_Reset,
2448     fnIEnumRfc1766_Skip
2449 };
2450
2451 struct enum_locales_data
2452 {
2453     RFC1766INFO *info;
2454     DWORD total, allocated;
2455 };
2456
2457 static BOOL CALLBACK enum_locales_proc(LPWSTR locale)
2458 {
2459     WCHAR *end;
2460     struct enum_locales_data *data = TlsGetValue(MLANG_tls_index);
2461     RFC1766INFO *info;
2462
2463     TRACE("%s\n", debugstr_w(locale));
2464
2465     if (data->total >= data->allocated)
2466     {
2467         data->allocated += 32;
2468         data->info = HeapReAlloc(GetProcessHeap(), 0, data->info, data->allocated * sizeof(RFC1766INFO));
2469         if (!data->info) return FALSE;
2470     }
2471
2472     info = &data->info[data->total];
2473
2474     info->lcid = strtolW(locale, &end, 16);
2475     if (*end) /* invalid number */
2476         return FALSE;
2477
2478     info->wszRfc1766[0] = 0;
2479     lcid_to_rfc1766W( info->lcid, info->wszRfc1766, MAX_RFC1766_NAME );
2480
2481     info->wszLocaleName[0] = 0;
2482     GetLocaleInfoW(info->lcid, LOCALE_SLANGUAGE, info->wszLocaleName, MAX_LOCALE_NAME);
2483     TRACE("ISO639: %s SLANGUAGE: %s\n", wine_dbgstr_w(info->wszRfc1766), wine_dbgstr_w(info->wszLocaleName));
2484     
2485     data->total++;
2486
2487     return TRUE;
2488 }
2489
2490 static HRESULT EnumRfc1766_create(LANGID LangId, IEnumRfc1766 **ppEnum)
2491 {
2492     EnumRfc1766_impl *rfc;
2493     struct enum_locales_data data;
2494
2495     TRACE("%04x, %p\n", LangId, ppEnum);
2496
2497     rfc = HeapAlloc( GetProcessHeap(), 0, sizeof(EnumRfc1766_impl) );
2498     rfc->IEnumRfc1766_iface.lpVtbl = &IEnumRfc1766_vtbl;
2499     rfc->ref = 1;
2500     rfc->pos = 0;
2501     rfc->total = 0;
2502
2503     data.total = 0;
2504     data.allocated = 160;
2505     data.info = HeapAlloc(GetProcessHeap(), 0, data.allocated * sizeof(RFC1766INFO));
2506     if (!data.info)
2507     {
2508         HeapFree(GetProcessHeap(), 0, rfc);
2509         return E_OUTOFMEMORY;
2510     }
2511
2512     TlsSetValue(MLANG_tls_index, &data);
2513     EnumSystemLocalesW(enum_locales_proc, 0/*LOCALE_SUPPORTED*/);
2514     TlsSetValue(MLANG_tls_index, NULL);
2515
2516     TRACE("enumerated %d rfc1766 structures\n", data.total);
2517
2518     if (!data.total)
2519     {
2520         HeapFree(GetProcessHeap(), 0, data.info);
2521         HeapFree(GetProcessHeap(), 0, rfc);
2522         return E_FAIL;
2523     }
2524
2525     rfc->info = data.info;
2526     rfc->total = data.total;
2527
2528     *ppEnum = &rfc->IEnumRfc1766_iface;
2529     return S_OK;
2530 }
2531
2532 static HRESULT WINAPI fnIMultiLanguage_EnumRfc1766(
2533     IMultiLanguage *iface,
2534     IEnumRfc1766 **ppEnumRfc1766)
2535 {
2536     MLang_impl *This = impl_from_IMultiLanguage( iface );
2537
2538     TRACE("%p %p\n", This, ppEnumRfc1766);
2539
2540     return EnumRfc1766_create(0, ppEnumRfc1766);
2541 }
2542
2543 /******************************************************************************/
2544
2545 static HRESULT WINAPI fnIMultiLanguage_GetRfc1766Info(
2546     IMultiLanguage* iface,
2547     LCID Locale,
2548     PRFC1766INFO pRfc1766Info)
2549 {
2550     LCTYPE type = LOCALE_SLANGUAGE;
2551
2552     TRACE("(%p, 0x%04x, %p)\n", iface, Locale, pRfc1766Info);
2553
2554     if (!pRfc1766Info)
2555         return E_INVALIDARG;
2556
2557     if ((PRIMARYLANGID(Locale) == LANG_ENGLISH) ||
2558         (PRIMARYLANGID(Locale) == LANG_CHINESE) ||
2559         (PRIMARYLANGID(Locale) == LANG_ARABIC)) {
2560
2561         if (!SUBLANGID(Locale))
2562             type = LOCALE_SENGLANGUAGE; /* suppress country */
2563     }
2564     else
2565     {
2566         if (!SUBLANGID(Locale)) {
2567             TRACE("SUBLANGID missing in 0x%04x\n", Locale);
2568             return E_FAIL;
2569         }
2570     }
2571
2572     pRfc1766Info->lcid = Locale;
2573     pRfc1766Info->wszRfc1766[0] = 0;
2574     pRfc1766Info->wszLocaleName[0] = 0;
2575
2576     if ((!lcid_to_rfc1766W(Locale, pRfc1766Info->wszRfc1766, MAX_RFC1766_NAME)) &&
2577         (GetLocaleInfoW(Locale, type, pRfc1766Info->wszLocaleName, MAX_LOCALE_NAME) > 0))
2578             return S_OK;
2579
2580     /* Locale not supported */
2581     return E_INVALIDARG;
2582 }
2583
2584 static HRESULT WINAPI fnIMultiLanguage_CreateConvertCharset(
2585     IMultiLanguage* iface,
2586     UINT uiSrcCodePage,
2587     UINT uiDstCodePage,
2588     DWORD dwProperty,
2589     IMLangConvertCharset** ppMLangConvertCharset)
2590 {
2591     FIXME("\n");
2592     return E_NOTIMPL;
2593 }
2594
2595 static const IMultiLanguageVtbl IMultiLanguage_vtbl =
2596 {
2597     fnIMultiLanguage_QueryInterface,
2598     fnIMultiLanguage_AddRef,
2599     fnIMultiLanguage_Release,
2600     fnIMultiLanguage_GetNumberOfCodePageInfo,
2601     fnIMultiLanguage_GetCodePageInfo,
2602     fnIMultiLanguage_GetFamilyCodePage,
2603     fnIMultiLanguage_EnumCodePages,
2604     fnIMultiLanguage_GetCharsetInfo,
2605     fnIMultiLanguage_IsConvertible,
2606     fnIMultiLanguage_ConvertString,
2607     fnIMultiLanguage_ConvertStringToUnicode,
2608     fnIMultiLanguage_ConvertStringFromUnicode,
2609     fnIMultiLanguage_ConvertStringReset,
2610     fnIMultiLanguage_GetRfc1766FromLcid,
2611     fnIMultiLanguage_GetLcidFromRfc1766,
2612     fnIMultiLanguage_EnumRfc1766,
2613     fnIMultiLanguage_GetRfc1766Info,
2614     fnIMultiLanguage_CreateConvertCharset,
2615 };
2616
2617
2618 /******************************************************************************/
2619
2620 static inline MLang_impl *impl_from_IMultiLanguage3( IMultiLanguage3 *iface )
2621 {
2622     return CONTAINING_RECORD( iface, MLang_impl, IMultiLanguage3_iface );
2623 }
2624
2625 static HRESULT WINAPI fnIMultiLanguage2_QueryInterface(
2626     IMultiLanguage3* iface,
2627     REFIID riid,
2628     void** ppvObject)
2629 {
2630     MLang_impl *This = impl_from_IMultiLanguage3( iface );
2631     return MLang_QueryInterface( This, riid, ppvObject );
2632 }
2633
2634 static ULONG WINAPI fnIMultiLanguage2_AddRef( IMultiLanguage3* iface )
2635 {
2636     MLang_impl *This = impl_from_IMultiLanguage3( iface );
2637     return MLang_AddRef( This );
2638 }
2639
2640 static ULONG WINAPI fnIMultiLanguage2_Release( IMultiLanguage3* iface )
2641 {
2642     MLang_impl *This = impl_from_IMultiLanguage3( iface );
2643     return MLang_Release( This );
2644 }
2645
2646 static HRESULT WINAPI fnIMultiLanguage2_GetNumberOfCodePageInfo(
2647     IMultiLanguage3* iface,
2648     UINT* pcCodePage)
2649 {
2650     MLang_impl *This = impl_from_IMultiLanguage3( iface );
2651
2652     TRACE("%p, %p\n", This, pcCodePage);
2653
2654     if (!pcCodePage) return E_INVALIDARG;
2655
2656     *pcCodePage = This->total_cp;
2657     return S_OK;
2658 }
2659
2660 static void fill_cp_info(const struct mlang_data *ml_data, UINT index, MIMECPINFO *mime_cp_info)
2661 {
2662     CHARSETINFO csi;
2663
2664     if (TranslateCharsetInfo((DWORD*)(DWORD_PTR)ml_data->family_codepage, &csi,
2665                              TCI_SRCCODEPAGE))
2666         mime_cp_info->bGDICharset = csi.ciCharset;
2667     else
2668         mime_cp_info->bGDICharset = DEFAULT_CHARSET;
2669
2670     mime_cp_info->dwFlags = ml_data->mime_cp_info[index].flags;
2671     mime_cp_info->uiCodePage = ml_data->mime_cp_info[index].cp;
2672     mime_cp_info->uiFamilyCodePage = ml_data->family_codepage;
2673     MultiByteToWideChar(CP_ACP, 0, ml_data->mime_cp_info[index].description, -1,
2674                         mime_cp_info->wszDescription, sizeof(mime_cp_info->wszDescription)/sizeof(WCHAR));
2675     MultiByteToWideChar(CP_ACP, 0, ml_data->mime_cp_info[index].web_charset, -1,
2676                         mime_cp_info->wszWebCharset, sizeof(mime_cp_info->wszWebCharset)/sizeof(WCHAR));
2677     MultiByteToWideChar(CP_ACP, 0, ml_data->mime_cp_info[index].header_charset, -1,
2678                         mime_cp_info->wszHeaderCharset, sizeof(mime_cp_info->wszHeaderCharset)/sizeof(WCHAR));
2679     MultiByteToWideChar(CP_ACP, 0, ml_data->mime_cp_info[index].body_charset, -1,
2680                         mime_cp_info->wszBodyCharset, sizeof(mime_cp_info->wszBodyCharset)/sizeof(WCHAR));
2681
2682     MultiByteToWideChar(CP_ACP, 0, ml_data->fixed_font, -1,
2683         mime_cp_info->wszFixedWidthFont, sizeof(mime_cp_info->wszFixedWidthFont)/sizeof(WCHAR));
2684     MultiByteToWideChar(CP_ACP, 0, ml_data->proportional_font, -1,
2685         mime_cp_info->wszProportionalFont, sizeof(mime_cp_info->wszProportionalFont)/sizeof(WCHAR));
2686
2687     TRACE("%08x %u %u %s %s %s %s %s %s %d\n",
2688           mime_cp_info->dwFlags, mime_cp_info->uiCodePage,
2689           mime_cp_info->uiFamilyCodePage,
2690           wine_dbgstr_w(mime_cp_info->wszDescription),
2691           wine_dbgstr_w(mime_cp_info->wszWebCharset),
2692           wine_dbgstr_w(mime_cp_info->wszHeaderCharset),
2693           wine_dbgstr_w(mime_cp_info->wszBodyCharset),
2694           wine_dbgstr_w(mime_cp_info->wszFixedWidthFont),
2695           wine_dbgstr_w(mime_cp_info->wszProportionalFont),
2696           mime_cp_info->bGDICharset);
2697 }
2698
2699 static HRESULT WINAPI fnIMultiLanguage2_GetCodePageInfo(
2700     IMultiLanguage3* iface,
2701     UINT uiCodePage,
2702     LANGID LangId,
2703     PMIMECPINFO pCodePageInfo)
2704 {
2705     UINT i, n;
2706     MLang_impl *This = impl_from_IMultiLanguage3( iface );
2707
2708     TRACE("%p, %u, %04x, %p\n", This, uiCodePage, LangId, pCodePageInfo);
2709
2710     for (i = 0; i < sizeof(mlang_data)/sizeof(mlang_data[0]); i++)
2711     {
2712         for (n = 0; n < mlang_data[i].number_of_cp; n++)
2713         {
2714             if (mlang_data[i].mime_cp_info[n].cp == uiCodePage)
2715             {
2716                 fill_cp_info(&mlang_data[i], n, pCodePageInfo);
2717                 return S_OK;
2718             }
2719         }
2720     }
2721
2722     return S_FALSE;
2723 }
2724
2725 static HRESULT WINAPI fnIMultiLanguage2_GetFamilyCodePage(
2726     IMultiLanguage3* iface,
2727     UINT uiCodePage,
2728     UINT* puiFamilyCodePage)
2729 {
2730     return GetFamilyCodePage(uiCodePage, puiFamilyCodePage);
2731 }
2732
2733 static HRESULT WINAPI fnIMultiLanguage2_EnumCodePages(
2734     IMultiLanguage3* iface,
2735     DWORD grfFlags,
2736     LANGID LangId,
2737     IEnumCodePage** ppEnumCodePage)
2738 {
2739     MLang_impl *This = impl_from_IMultiLanguage3( iface );
2740
2741     TRACE("%p %08x %04x %p\n", This, grfFlags, LangId, ppEnumCodePage);
2742
2743     return EnumCodePage_create( This, grfFlags, LangId, ppEnumCodePage );
2744 }
2745
2746 static HRESULT WINAPI fnIMultiLanguage2_GetCharsetInfo(
2747     IMultiLanguage3* iface,
2748     BSTR Charset,
2749     PMIMECSETINFO pCharsetInfo)
2750 {
2751     UINT i, n;
2752     MLang_impl *This = impl_from_IMultiLanguage3( iface );
2753
2754     TRACE("%p %s %p\n", This, debugstr_w(Charset), pCharsetInfo);
2755
2756     if (!pCharsetInfo) return E_FAIL;
2757
2758     for (i = 0; i < sizeof(mlang_data)/sizeof(mlang_data[0]); i++)
2759     {
2760         for (n = 0; n < mlang_data[i].number_of_cp; n++)
2761         {
2762             WCHAR csetW[MAX_MIMECSET_NAME];
2763
2764             MultiByteToWideChar(CP_ACP, 0, mlang_data[i].mime_cp_info[n].web_charset, -1, csetW, MAX_MIMECSET_NAME);
2765             if (!lstrcmpiW(Charset, csetW))
2766             {
2767                 pCharsetInfo->uiCodePage = mlang_data[i].family_codepage;
2768                 pCharsetInfo->uiInternetEncoding = mlang_data[i].mime_cp_info[n].cp;
2769                 strcpyW(pCharsetInfo->wszCharset, csetW);
2770                 return S_OK;
2771             }
2772         }
2773     }
2774
2775     /* FIXME:
2776      * Since we do not support charsets like iso-2022-jp and do not have
2777      * them in our database as a primary (web_charset) encoding this loop
2778      * does an attempt to 'approximate' charset name by header_charset.
2779      */
2780     for (i = 0; i < sizeof(mlang_data)/sizeof(mlang_data[0]); i++)
2781     {
2782         for (n = 0; n < mlang_data[i].number_of_cp; n++)
2783         {
2784             WCHAR csetW[MAX_MIMECSET_NAME];
2785
2786             MultiByteToWideChar(CP_ACP, 0, mlang_data[i].mime_cp_info[n].header_charset, -1, csetW, MAX_MIMECSET_NAME);
2787             if (!lstrcmpiW(Charset, csetW))
2788             {
2789                 pCharsetInfo->uiCodePage = mlang_data[i].family_codepage;
2790                 pCharsetInfo->uiInternetEncoding = mlang_data[i].mime_cp_info[n].cp;
2791                 strcpyW(pCharsetInfo->wszCharset, csetW);
2792                 return S_OK;
2793             }
2794         }
2795     }
2796
2797     return E_FAIL;
2798 }
2799
2800 static HRESULT WINAPI fnIMultiLanguage2_IsConvertible(
2801     IMultiLanguage3* iface,
2802     DWORD dwSrcEncoding,
2803     DWORD dwDstEncoding)
2804 {
2805     return IsConvertINetStringAvailable(dwSrcEncoding, dwDstEncoding);
2806 }
2807
2808 static HRESULT WINAPI fnIMultiLanguage2_ConvertString(
2809     IMultiLanguage3* iface,
2810     DWORD* pdwMode,
2811     DWORD dwSrcEncoding,
2812     DWORD dwDstEncoding,
2813     BYTE* pSrcStr,
2814     UINT* pcSrcSize,
2815     BYTE* pDstStr,
2816     UINT* pcDstSize)
2817 {
2818     return ConvertINetString(pdwMode, dwSrcEncoding, dwDstEncoding,
2819         (LPCSTR)pSrcStr, (LPINT)pcSrcSize, (LPSTR)pDstStr, (LPINT)pcDstSize);
2820 }
2821
2822 static HRESULT WINAPI fnIMultiLanguage2_ConvertStringToUnicode(
2823     IMultiLanguage3* iface,
2824     DWORD* pdwMode,
2825     DWORD dwEncoding,
2826     CHAR* pSrcStr,
2827     UINT* pcSrcSize,
2828     WCHAR* pDstStr,
2829     UINT* pcDstSize)
2830 {
2831     return ConvertINetMultiByteToUnicode(pdwMode, dwEncoding,
2832         pSrcStr, (LPINT)pcSrcSize, pDstStr, (LPINT)pcDstSize);
2833 }
2834
2835 static HRESULT WINAPI fnIMultiLanguage2_ConvertStringFromUnicode(
2836     IMultiLanguage3* iface,
2837     DWORD* pdwMode,
2838     DWORD dwEncoding,
2839     WCHAR* pSrcStr,
2840     UINT* pcSrcSize,
2841     CHAR* pDstStr,
2842     UINT* pcDstSize)
2843 {
2844     return ConvertINetUnicodeToMultiByte(pdwMode, dwEncoding,
2845         pSrcStr, (LPINT)pcSrcSize, pDstStr, (LPINT)pcDstSize);
2846 }
2847
2848 static HRESULT WINAPI fnIMultiLanguage2_ConvertStringReset(
2849     IMultiLanguage3* iface)
2850 {
2851     FIXME("\n");
2852     return E_NOTIMPL;
2853 }
2854
2855 static HRESULT WINAPI fnIMultiLanguage2_GetRfc1766FromLcid(
2856     IMultiLanguage3* iface,
2857     LCID lcid,
2858     BSTR* pbstrRfc1766)
2859 {
2860     WCHAR buf[MAX_RFC1766_NAME];
2861
2862     TRACE("%p %04x %p\n", iface, lcid, pbstrRfc1766);
2863     if (!pbstrRfc1766)
2864         return E_INVALIDARG;
2865
2866     if (!lcid_to_rfc1766W( lcid, buf, MAX_RFC1766_NAME ))
2867     {
2868         *pbstrRfc1766 = SysAllocString( buf );
2869         return S_OK;
2870     }
2871     return E_FAIL;
2872 }
2873
2874 static HRESULT WINAPI fnIMultiLanguage2_GetLcidFromRfc1766(
2875     IMultiLanguage3* iface,
2876     LCID* pLocale,
2877     BSTR bstrRfc1766)
2878 {
2879     HRESULT hr;
2880     IEnumRfc1766 *rfc1766;
2881
2882     TRACE("%p %p %s\n", iface, pLocale, debugstr_w(bstrRfc1766));
2883
2884     if (!pLocale || !bstrRfc1766)
2885         return E_INVALIDARG;
2886
2887     hr = IMultiLanguage3_EnumRfc1766(iface, 0, &rfc1766);
2888     if (FAILED(hr))
2889         return hr;
2890
2891     hr = lcid_from_rfc1766(rfc1766, pLocale, bstrRfc1766);
2892
2893     IEnumRfc1766_Release(rfc1766);
2894     return hr;
2895 }
2896
2897 static HRESULT WINAPI fnIMultiLanguage2_EnumRfc1766(
2898     IMultiLanguage3* iface,
2899     LANGID LangId,
2900     IEnumRfc1766** ppEnumRfc1766)
2901 {
2902     MLang_impl *This = impl_from_IMultiLanguage3( iface );
2903
2904     TRACE("%p %p\n", This, ppEnumRfc1766);
2905
2906     return EnumRfc1766_create(LangId, ppEnumRfc1766);
2907 }
2908
2909 static HRESULT WINAPI fnIMultiLanguage2_GetRfc1766Info(
2910     IMultiLanguage3* iface,
2911     LCID Locale,
2912     LANGID LangId,
2913     PRFC1766INFO pRfc1766Info)
2914 {
2915     static LANGID last_lang = -1;
2916     LCTYPE type = LOCALE_SLANGUAGE;
2917
2918     TRACE("(%p, 0x%04x, 0x%04x, %p)\n", iface, Locale, LangId, pRfc1766Info);
2919
2920     if (!pRfc1766Info)
2921         return E_INVALIDARG;
2922
2923     if ((PRIMARYLANGID(Locale) == LANG_ENGLISH) ||
2924         (PRIMARYLANGID(Locale) == LANG_CHINESE) ||
2925         (PRIMARYLANGID(Locale) == LANG_ARABIC)) {
2926
2927         if (!SUBLANGID(Locale))
2928             type = LOCALE_SENGLANGUAGE; /* suppress country */
2929     }
2930     else
2931     {
2932         if (!SUBLANGID(Locale)) {
2933             TRACE("SUBLANGID missing in 0x%04x\n", Locale);
2934             return E_FAIL;
2935         }
2936     }
2937
2938     pRfc1766Info->lcid = Locale;
2939     pRfc1766Info->wszRfc1766[0] = 0;
2940     pRfc1766Info->wszLocaleName[0] = 0;
2941
2942     if ((PRIMARYLANGID(LangId) != LANG_ENGLISH) &&
2943         (last_lang != LangId)) {
2944         FIXME("Only English names supported (requested: 0x%04x)\n", LangId);
2945         last_lang = LangId;
2946     }
2947
2948     if ((!lcid_to_rfc1766W(Locale, pRfc1766Info->wszRfc1766, MAX_RFC1766_NAME)) &&
2949         (GetLocaleInfoW(Locale, type, pRfc1766Info->wszLocaleName, MAX_LOCALE_NAME) > 0))
2950             return S_OK;
2951
2952     /* Locale not supported */
2953     return E_INVALIDARG;
2954 }
2955
2956 static HRESULT WINAPI fnIMultiLanguage2_CreateConvertCharset(
2957     IMultiLanguage3* iface,
2958     UINT uiSrcCodePage,
2959     UINT uiDstCodePage,
2960     DWORD dwProperty,
2961     IMLangConvertCharset** ppMLangConvertCharset)
2962 {
2963     FIXME("\n");
2964     return E_NOTIMPL;
2965 }
2966
2967 static HRESULT WINAPI fnIMultiLanguage2_ConvertStringInIStream(
2968     IMultiLanguage3* iface,
2969     DWORD* pdwMode,
2970     DWORD dwFlag,
2971     WCHAR* lpFallBack,
2972     DWORD dwSrcEncoding,
2973     DWORD dwDstEncoding,
2974     IStream* pstmIn,
2975     IStream* pstmOut)
2976 {
2977     char *src, *dst = NULL;
2978     INT srclen, dstlen;
2979     STATSTG stat;
2980     HRESULT hr;
2981
2982     TRACE("%p %0x8 %s %u %u %p %p\n",
2983           pdwMode, dwFlag, debugstr_w(lpFallBack), dwSrcEncoding, dwDstEncoding, pstmIn, pstmOut);
2984
2985     FIXME("dwFlag and lpFallBack not handled\n");
2986
2987     hr = IStream_Stat(pstmIn, &stat, STATFLAG_NONAME);
2988     if (FAILED(hr)) return hr;
2989
2990     if (stat.cbSize.QuadPart > MAXLONG) return E_INVALIDARG;
2991     if (!(src = HeapAlloc(GetProcessHeap(), 0, stat.cbSize.QuadPart))) return E_OUTOFMEMORY;
2992
2993     hr = IStream_Read(pstmIn, src, stat.cbSize.QuadPart, (ULONG *)&srclen);
2994     if (FAILED(hr)) goto exit;
2995
2996     hr = ConvertINetString(pdwMode, dwSrcEncoding, dwDstEncoding, src, &srclen, NULL, &dstlen);
2997     if (FAILED(hr)) goto exit;
2998
2999     if (!(dst = HeapAlloc(GetProcessHeap(), 0, dstlen)))
3000     {
3001         hr = E_OUTOFMEMORY;
3002         goto exit;
3003     }
3004     hr = ConvertINetString(pdwMode, dwSrcEncoding, dwDstEncoding, src, &srclen, dst, &dstlen);
3005     if (FAILED(hr)) goto exit;
3006
3007     hr = IStream_Write(pstmOut, dst, dstlen, NULL);
3008
3009 exit:
3010     HeapFree(GetProcessHeap(), 0, src);
3011     HeapFree(GetProcessHeap(), 0, dst);
3012     return hr;
3013 }
3014
3015 static HRESULT WINAPI fnIMultiLanguage2_ConvertStringToUnicodeEx(
3016     IMultiLanguage3* iface,
3017     DWORD* pdwMode,
3018     DWORD dwEncoding,
3019     CHAR* pSrcStr,
3020     UINT* pcSrcSize,
3021     WCHAR* pDstStr,
3022     UINT* pcDstSize,
3023     DWORD dwFlag,
3024     WCHAR* lpFallBack)
3025 {
3026     if (dwFlag || lpFallBack)
3027         FIXME("Ignoring dwFlag (0x%x/%d) and lpFallBack (%p)\n",
3028                 dwFlag, dwFlag, lpFallBack);
3029
3030     return ConvertINetMultiByteToUnicode(pdwMode, dwEncoding,
3031         pSrcStr, (LPINT)pcSrcSize, pDstStr, (LPINT)pcDstSize);
3032 }
3033
3034 /*****************************************************************************
3035  * MultiLanguage2::ConvertStringToUnicodeEx
3036  *
3037  * Translates the multibyte string from the specified code page to Unicode.
3038  *
3039  * PARAMS
3040  *   see ConvertStringToUnicode
3041  *   dwFlag 
3042  *   lpFallBack if dwFlag contains MLCONVCHARF_USEDEFCHAR, lpFallBack string used
3043  *              instead unconvertible characters.
3044  *
3045  * RETURNS
3046  *   S_OK     Success.
3047  *   S_FALSE  The conversion is not supported.
3048  *   E_FAIL   Some error has occurred.
3049  *
3050  * TODO: handle dwFlag and lpFallBack
3051 */
3052 static HRESULT WINAPI fnIMultiLanguage2_ConvertStringFromUnicodeEx(
3053     IMultiLanguage3* This,
3054     DWORD* pdwMode,
3055     DWORD dwEncoding,
3056     WCHAR* pSrcStr,
3057     UINT* pcSrcSize,
3058     CHAR* pDstStr,
3059     UINT* pcDstSize,
3060     DWORD dwFlag,
3061     WCHAR* lpFallBack)
3062 {
3063     FIXME("\n");
3064     return ConvertINetUnicodeToMultiByte(pdwMode, dwEncoding,
3065         pSrcStr, (LPINT)pcSrcSize, pDstStr, (LPINT)pcDstSize);
3066 }
3067
3068 static HRESULT WINAPI fnIMultiLanguage2_DetectCodepageInIStream(
3069     IMultiLanguage3* iface,
3070     DWORD dwFlag,
3071     DWORD dwPrefWinCodePage,
3072     IStream* pstmIn,
3073     DetectEncodingInfo* lpEncoding,
3074     INT* pnScores)
3075 {
3076     FIXME("\n");
3077     return E_NOTIMPL;
3078 }
3079
3080 static HRESULT WINAPI fnIMultiLanguage2_DetectInputCodepage(
3081     IMultiLanguage3* iface,
3082     DWORD dwFlag,
3083     DWORD dwPrefWinCodePage,
3084     CHAR* pSrcStr,
3085     INT* pcSrcSize,
3086     DetectEncodingInfo* lpEncoding,
3087     INT* pnScores)
3088 {
3089     FIXME("\n");
3090     return E_NOTIMPL;
3091 }
3092
3093 static HRESULT WINAPI fnIMultiLanguage2_ValidateCodePage(
3094     IMultiLanguage3* iface,
3095     UINT uiCodePage,
3096     HWND hwnd)
3097 {
3098     return IMultiLanguage3_ValidateCodePageEx(iface,uiCodePage,hwnd,0);
3099 }
3100
3101 static HRESULT WINAPI fnIMultiLanguage2_GetCodePageDescription(
3102     IMultiLanguage3* iface,
3103     UINT uiCodePage,
3104     LCID lcid,
3105     LPWSTR lpWideCharStr,
3106     int cchWideChar)
3107 {
3108     /* Find first instance */
3109     unsigned int i,n;
3110
3111     TRACE ("%u, %04x, %p, %d\n", uiCodePage, lcid, lpWideCharStr, cchWideChar);
3112     for (i = 0; i < sizeof(mlang_data)/sizeof(mlang_data[0]); i++)
3113     {
3114         for (n = 0; n < mlang_data[i].number_of_cp; n++)
3115         {
3116             if (mlang_data[i].mime_cp_info[n].cp == uiCodePage)
3117             {
3118                 MultiByteToWideChar(CP_ACP, 0,
3119                                     mlang_data[i].mime_cp_info[n].description,
3120                                     -1, lpWideCharStr, cchWideChar);
3121                 return S_OK;
3122             }
3123         }
3124     }
3125
3126     return S_FALSE;
3127 }
3128
3129 static HRESULT WINAPI fnIMultiLanguage2_IsCodePageInstallable(
3130     IMultiLanguage3* iface,
3131     UINT uiCodePage)
3132 {
3133     TRACE("%u\n", uiCodePage);
3134
3135     /* FIXME: the installable set is usually larger than the set of valid codepages */
3136     return IMultiLanguage3_ValidateCodePageEx(iface, uiCodePage, NULL, CPIOD_PEEK);
3137 }
3138
3139 static HRESULT WINAPI fnIMultiLanguage2_SetMimeDBSource(
3140     IMultiLanguage3* iface,
3141     MIMECONTF dwSource)
3142 {
3143     FIXME("0x%08x\n", dwSource);
3144     return S_OK;
3145 }
3146
3147 static HRESULT WINAPI fnIMultiLanguage2_GetNumberOfScripts(
3148     IMultiLanguage3* iface,
3149     UINT* pnScripts)
3150 {
3151     MLang_impl *This = impl_from_IMultiLanguage3( iface );
3152
3153     TRACE("%p %p\n", This, pnScripts);
3154
3155     if (!pnScripts) return S_FALSE;
3156
3157     *pnScripts = This->total_scripts;
3158     return S_OK;
3159 }
3160
3161 static HRESULT WINAPI fnIMultiLanguage2_EnumScripts(
3162     IMultiLanguage3* iface,
3163     DWORD dwFlags,
3164     LANGID LangId,
3165     IEnumScript** ppEnumScript)
3166 {
3167     MLang_impl *This = impl_from_IMultiLanguage3( iface );
3168
3169     TRACE("%p %08x %04x %p\n", This, dwFlags, LangId, ppEnumScript);
3170
3171     return EnumScript_create( This, dwFlags, LangId, ppEnumScript );
3172 }
3173
3174 static HRESULT WINAPI fnIMultiLanguage2_ValidateCodePageEx(
3175     IMultiLanguage3* iface,
3176     UINT uiCodePage,
3177     HWND hwnd,
3178     DWORD dwfIODControl)
3179 {
3180     int i;
3181     MLang_impl *This = impl_from_IMultiLanguage3( iface );
3182
3183     TRACE("%p %u %p %08x\n", This, uiCodePage, hwnd, dwfIODControl);
3184
3185     /* quick check for kernel32 supported code pages */
3186     if (IsValidCodePage(uiCodePage))
3187         return S_OK;
3188
3189     /* check for mlang supported code pages */
3190     for (i = 0; i < sizeof(mlang_data)/sizeof(mlang_data[0]); i++)
3191     {
3192         int n;
3193         for (n = 0; n < mlang_data[i].number_of_cp; n++)
3194         {
3195             if (mlang_data[i].mime_cp_info[n].cp == uiCodePage)
3196                 return S_OK;
3197         }
3198     }
3199
3200     if (dwfIODControl != CPIOD_PEEK)
3201         FIXME("Request to install codepage language pack not handled\n");
3202
3203     return S_FALSE;
3204 }
3205
3206 static HRESULT WINAPI fnIMultiLanguage3_DetectOutboundCodePage(
3207     IMultiLanguage3 *iface,
3208     DWORD dwFlags,
3209     LPCWSTR lpWideCharStr,
3210     UINT cchWideChar,
3211     UINT *puiPreferredCodePages,
3212     UINT nPreferredCodePages,
3213     UINT *puiDetectedCodePages,
3214     UINT *pnDetectedCodePages,
3215     WCHAR *lpSpecialChar)
3216 {
3217     MLang_impl *This = impl_from_IMultiLanguage3( iface );
3218
3219     FIXME("(%p)->(%08x %s %u %p %u %p %p %p)\n", This, dwFlags, debugstr_w(lpWideCharStr),
3220           cchWideChar, puiPreferredCodePages, nPreferredCodePages, puiDetectedCodePages,
3221           pnDetectedCodePages, lpSpecialChar);
3222     return E_NOTIMPL;
3223 }
3224
3225 static HRESULT WINAPI fnIMultiLanguage3_DetectOutboundCodePageInIStream(
3226     IMultiLanguage3 *iface,
3227     DWORD dwFlags,
3228     IStream *pStrIn,
3229     UINT *puiPreferredCodePages,
3230     UINT nPreferredCodePages,
3231     UINT *puiDetectedCodePages,
3232     UINT *pnDetectedCodePages,
3233     WCHAR *lpSpecialChar)
3234 {
3235     MLang_impl *This = impl_from_IMultiLanguage3( iface );
3236
3237     FIXME("(%p)->(%08x %p %p %u %p %p %p)\n", This, dwFlags, pStrIn,
3238           puiPreferredCodePages, nPreferredCodePages, puiDetectedCodePages,
3239           pnDetectedCodePages, lpSpecialChar);
3240     return E_NOTIMPL;
3241 }
3242
3243 static const IMultiLanguage3Vtbl IMultiLanguage3_vtbl =
3244 {
3245     fnIMultiLanguage2_QueryInterface,
3246     fnIMultiLanguage2_AddRef,
3247     fnIMultiLanguage2_Release,
3248     fnIMultiLanguage2_GetNumberOfCodePageInfo,
3249     fnIMultiLanguage2_GetCodePageInfo,
3250     fnIMultiLanguage2_GetFamilyCodePage,
3251     fnIMultiLanguage2_EnumCodePages,
3252     fnIMultiLanguage2_GetCharsetInfo,
3253     fnIMultiLanguage2_IsConvertible,
3254     fnIMultiLanguage2_ConvertString,
3255     fnIMultiLanguage2_ConvertStringToUnicode,
3256     fnIMultiLanguage2_ConvertStringFromUnicode,
3257     fnIMultiLanguage2_ConvertStringReset,
3258     fnIMultiLanguage2_GetRfc1766FromLcid,
3259     fnIMultiLanguage2_GetLcidFromRfc1766,
3260     fnIMultiLanguage2_EnumRfc1766,
3261     fnIMultiLanguage2_GetRfc1766Info,
3262     fnIMultiLanguage2_CreateConvertCharset,
3263     fnIMultiLanguage2_ConvertStringInIStream,
3264     fnIMultiLanguage2_ConvertStringToUnicodeEx,
3265     fnIMultiLanguage2_ConvertStringFromUnicodeEx,
3266     fnIMultiLanguage2_DetectCodepageInIStream,
3267     fnIMultiLanguage2_DetectInputCodepage,
3268     fnIMultiLanguage2_ValidateCodePage,
3269     fnIMultiLanguage2_GetCodePageDescription,
3270     fnIMultiLanguage2_IsCodePageInstallable,
3271     fnIMultiLanguage2_SetMimeDBSource,
3272     fnIMultiLanguage2_GetNumberOfScripts,
3273     fnIMultiLanguage2_EnumScripts,
3274     fnIMultiLanguage2_ValidateCodePageEx,
3275     fnIMultiLanguage3_DetectOutboundCodePage,
3276     fnIMultiLanguage3_DetectOutboundCodePageInIStream
3277 };
3278
3279 /******************************************************************************/
3280
3281 static inline MLang_impl *impl_from_IMLangFontLink2( IMLangFontLink2 *iface )
3282 {
3283     return CONTAINING_RECORD( iface, MLang_impl, IMLangFontLink2_iface );
3284 }
3285
3286 static HRESULT WINAPI fnIMLangFontLink2_QueryInterface(
3287     IMLangFontLink2 * iface,
3288     REFIID riid,
3289     void** ppvObject)
3290 {
3291     MLang_impl *This = impl_from_IMLangFontLink2( iface );
3292     return MLang_QueryInterface( This, riid, ppvObject );
3293 }
3294
3295 static ULONG WINAPI fnIMLangFontLink2_AddRef( IMLangFontLink2* iface )
3296 {
3297     MLang_impl *This = impl_from_IMLangFontLink2( iface );
3298     return MLang_AddRef( This );
3299 }
3300
3301 static ULONG WINAPI fnIMLangFontLink2_Release( IMLangFontLink2* iface )
3302 {
3303     MLang_impl *This = impl_from_IMLangFontLink2( iface );
3304     return MLang_Release( This );
3305 }
3306
3307 static HRESULT WINAPI fnIMLangFontLink2_GetCharCodePages( IMLangFontLink2* This,
3308         WCHAR chSrc, DWORD *pdwCodePages)
3309 {
3310     FIXME("(%p)->%s %p\n",This, debugstr_wn(&chSrc,1),pdwCodePages);
3311     return E_NOTIMPL;
3312 }
3313
3314 static HRESULT WINAPI fnIMLangFontLink2_GetStrCodePages( IMLangFontLink2* This,
3315         const WCHAR *pszSrc, LONG cchSrc, DWORD dwPriorityCodePages,
3316         DWORD *pdwCodePages, LONG *pcchCodePages)
3317 {
3318     return fnIMLangFontLink_GetStrCodePages((IMLangFontLink *)This,
3319             pszSrc, cchSrc, dwPriorityCodePages, pdwCodePages, pcchCodePages);
3320 }
3321
3322 static HRESULT WINAPI fnIMLangFontLink2_CodePageToCodePages(IMLangFontLink2* This,
3323         UINT uCodePage,
3324         DWORD *pdwCodePages)
3325 {
3326     FIXME("(%p)->%i %p\n",This, uCodePage, pdwCodePages);
3327     return E_NOTIMPL;
3328 }
3329
3330 static HRESULT WINAPI fnIMLangFontLink2_CodePagesToCodePage(IMLangFontLink2* This,
3331         DWORD dwCodePages, UINT uDefaultCodePage, UINT *puCodePage)
3332 {
3333     FIXME("(%p)->%i %i %p\n",This, dwCodePages, uDefaultCodePage, puCodePage);
3334     return E_NOTIMPL;
3335 }
3336
3337 static HRESULT WINAPI fnIMLangFontLink2_GetFontCodePages(IMLangFontLink2* This,
3338         HDC hDC, HFONT hFont, DWORD *pdwCodePages)
3339 {
3340     FIXME("(%p)->%p %p %p\n",This, hDC, hFont, pdwCodePages);
3341     return E_NOTIMPL;
3342 }
3343
3344 static HRESULT WINAPI fnIMLangFontLink2_ReleaseFont(IMLangFontLink2* This,
3345         HFONT hFont)
3346 {
3347     FIXME("(%p)->%p\n",This, hFont);
3348     return E_NOTIMPL;
3349 }
3350
3351 static HRESULT WINAPI fnIMLangFontLink2_ResetFontMapping(IMLangFontLink2* This)
3352 {
3353     FIXME("(%p)->\n",This);
3354     return E_NOTIMPL;
3355 }
3356
3357 static HRESULT WINAPI fnIMLangFontLink2_MapFont(IMLangFontLink2* This,
3358         HDC hDC, DWORD dwCodePages, WCHAR chSrc, HFONT *pFont)
3359 {
3360     FIXME("(%p)->%p %i %s %p\n",This, hDC, dwCodePages, debugstr_wn(&chSrc,1), pFont);
3361     return E_NOTIMPL;
3362 }
3363
3364 static HRESULT WINAPI fnIMLangFontLink2_GetFontUnicodeRanges(IMLangFontLink2* This,
3365         HDC hDC, UINT *puiRanges, UNICODERANGE *pUranges)
3366 {
3367     DWORD size;
3368     GLYPHSET *gs;
3369
3370     TRACE("(%p)->%p %p %p\n", This, hDC, puiRanges, pUranges);
3371
3372     if (!puiRanges) return E_INVALIDARG;
3373     if (!(size = GetFontUnicodeRanges(hDC, NULL))) return E_FAIL;
3374     if (!(gs = HeapAlloc(GetProcessHeap(), 0, size))) return E_OUTOFMEMORY;
3375
3376     GetFontUnicodeRanges(hDC, gs);
3377     *puiRanges = gs->cRanges;
3378     if (pUranges)
3379     {
3380         UINT i;
3381         for (i = 0; i < gs->cRanges; i++)
3382         {
3383             if (i >= *puiRanges) break;
3384             pUranges[i].wcFrom = gs->ranges[i].wcLow;
3385             pUranges[i].wcTo   = gs->ranges[i].wcLow + gs->ranges[i].cGlyphs;
3386         }
3387         *puiRanges = i;
3388     }
3389     HeapFree(GetProcessHeap(), 0, gs);
3390     return S_OK;
3391 }
3392
3393 static HRESULT WINAPI fnIMLangFontLink2_GetScriptFontInfo(IMLangFontLink2* This,
3394         SCRIPT_ID sid, DWORD dwFlags, UINT *puiFonts,
3395         SCRIPTFONTINFO *pScriptFont)
3396 {
3397     UINT i, j;
3398
3399     TRACE("(%p)->%u %x %p %p\n", This, sid, dwFlags, puiFonts, pScriptFont);
3400
3401     if (!dwFlags) dwFlags = SCRIPTCONTF_PROPORTIONAL_FONT;
3402
3403     for (i = 0, j = 0; i < sizeof(mlang_data)/sizeof(mlang_data[0]); i++)
3404     {
3405         if (sid == mlang_data[i].sid)
3406         {
3407             if (pScriptFont)
3408             {
3409                 if (j >= *puiFonts) break;
3410
3411                 pScriptFont[j].scripts = 1 << mlang_data[i].sid;
3412                 if (dwFlags == SCRIPTCONTF_FIXED_FONT)
3413                 {
3414                     MultiByteToWideChar(CP_ACP, 0, mlang_data[i].fixed_font, -1,
3415                         pScriptFont[j].wszFont, MAX_MIMEFACE_NAME);
3416                 }
3417                 else if (dwFlags == SCRIPTCONTF_PROPORTIONAL_FONT)
3418                 {
3419                     MultiByteToWideChar(CP_ACP, 0, mlang_data[i].proportional_font, -1,
3420                         pScriptFont[j].wszFont, MAX_MIMEFACE_NAME);
3421                 }
3422             }
3423             j++;
3424         }
3425     }
3426     *puiFonts = j;
3427     return S_OK;
3428 }
3429
3430 static HRESULT WINAPI fnIMLangFontLink2_CodePageToScriptID(IMLangFontLink2* This,
3431         UINT uiCodePage, SCRIPT_ID *pSid)
3432 {
3433     UINT i;
3434
3435     TRACE("(%p)->%i %p\n", This, uiCodePage, pSid);
3436
3437     if (uiCodePage == CP_UNICODE) return E_FAIL;
3438
3439     for (i = 0; i < sizeof(mlang_data)/sizeof(mlang_data[0]); i++)
3440     {
3441         if (uiCodePage == mlang_data[i].family_codepage)
3442         {
3443             if (pSid) *pSid = mlang_data[i].sid;
3444             return S_OK;
3445         }
3446     }
3447     return E_FAIL;
3448 }
3449
3450 static const IMLangFontLink2Vtbl IMLangFontLink2_vtbl =
3451 {
3452     fnIMLangFontLink2_QueryInterface,
3453     fnIMLangFontLink2_AddRef,
3454     fnIMLangFontLink2_Release,
3455     fnIMLangFontLink2_GetCharCodePages,
3456     fnIMLangFontLink2_GetStrCodePages,
3457     fnIMLangFontLink2_CodePageToCodePages,
3458     fnIMLangFontLink2_CodePagesToCodePage,
3459     fnIMLangFontLink2_GetFontCodePages,
3460     fnIMLangFontLink2_ReleaseFont,
3461     fnIMLangFontLink2_ResetFontMapping,
3462     fnIMLangFontLink2_MapFont,
3463     fnIMLangFontLink2_GetFontUnicodeRanges,
3464     fnIMLangFontLink2_GetScriptFontInfo,
3465     fnIMLangFontLink2_CodePageToScriptID
3466 };
3467
3468 /******************************************************************************/
3469
3470 static inline MLang_impl *impl_from_IMLangLineBreakConsole( IMLangLineBreakConsole *iface )
3471 {
3472     return CONTAINING_RECORD( iface, MLang_impl, IMLangLineBreakConsole_iface );
3473 }
3474
3475 static HRESULT WINAPI fnIMLangLineBreakConsole_QueryInterface(
3476     IMLangLineBreakConsole* iface,
3477     REFIID riid,
3478     void** ppvObject)
3479 {
3480     MLang_impl *This = impl_from_IMLangLineBreakConsole( iface );
3481     return MLang_QueryInterface( This, riid, ppvObject );
3482 }
3483
3484 static ULONG WINAPI fnIMLangLineBreakConsole_AddRef(
3485     IMLangLineBreakConsole* iface )
3486 {
3487     MLang_impl *This = impl_from_IMLangLineBreakConsole( iface );
3488     return MLang_AddRef( This );
3489 }
3490
3491 static ULONG WINAPI fnIMLangLineBreakConsole_Release(
3492     IMLangLineBreakConsole* iface )
3493 {
3494     MLang_impl *This = impl_from_IMLangLineBreakConsole( iface );
3495     return MLang_Release( This );
3496 }
3497
3498 static HRESULT WINAPI fnIMLangLineBreakConsole_BreakLineML(
3499     IMLangLineBreakConsole* iface,
3500     IMLangString* pSrcMLStr,
3501     LONG lSrcPos,
3502     LONG lSrcLen,
3503     LONG cMinColumns,
3504     LONG cMaxColumns,
3505     LONG* plLineLen,
3506     LONG* plSkipLen)
3507 {
3508     FIXME("(%p)->%p %i %i %i %i %p %p\n", iface, pSrcMLStr, lSrcPos, lSrcLen, cMinColumns, cMaxColumns, plLineLen, plSkipLen);
3509     return E_NOTIMPL;
3510 }
3511
3512 static HRESULT WINAPI fnIMLangLineBreakConsole_BreakLineW(
3513     IMLangLineBreakConsole* iface,
3514     LCID locale,
3515     const WCHAR* pszSrc,
3516     LONG cchSrc,
3517     LONG cMaxColumns,
3518     LONG* pcchLine,
3519     LONG* pcchSkip )
3520 {
3521     FIXME("(%p)->%i %s %i %i %p %p\n", iface, locale, debugstr_wn(pszSrc,cchSrc), cchSrc, cMaxColumns, pcchLine, pcchSkip);
3522
3523     *pcchLine = cchSrc;
3524     *pcchSkip = 0;
3525     return S_OK;
3526 }
3527
3528 static HRESULT WINAPI fnIMLangLineBreakConsole_BreakLineA(
3529     IMLangLineBreakConsole* iface,
3530     LCID locale,
3531     UINT uCodePage,
3532     const CHAR* pszSrc,
3533     LONG cchSrc,
3534     LONG cMaxColumns,
3535     LONG* pcchLine,
3536     LONG* pcchSkip)
3537 {
3538     FIXME("(%p)->%i %i %s %i %i %p %p\n", iface, locale, uCodePage, debugstr_an(pszSrc,cchSrc), cchSrc, cMaxColumns, pcchLine, pcchSkip);
3539
3540     *pcchLine = cchSrc;
3541     *pcchSkip = 0;
3542     return S_OK;
3543 }
3544
3545 static const IMLangLineBreakConsoleVtbl IMLangLineBreakConsole_vtbl =
3546 {
3547     fnIMLangLineBreakConsole_QueryInterface,
3548     fnIMLangLineBreakConsole_AddRef,
3549     fnIMLangLineBreakConsole_Release,
3550     fnIMLangLineBreakConsole_BreakLineML,
3551     fnIMLangLineBreakConsole_BreakLineW,
3552     fnIMLangLineBreakConsole_BreakLineA
3553 };
3554
3555 static HRESULT MultiLanguage_create(IUnknown *pUnkOuter, LPVOID *ppObj)
3556 {
3557     MLang_impl *mlang;
3558     UINT i;
3559
3560     TRACE("Creating MultiLanguage object\n");
3561
3562     if( pUnkOuter )
3563         return CLASS_E_NOAGGREGATION;
3564
3565     mlang = HeapAlloc( GetProcessHeap(), 0, sizeof (MLang_impl) );
3566     mlang->IMLangFontLink_iface.lpVtbl = &IMLangFontLink_vtbl;
3567     mlang->IMultiLanguage_iface.lpVtbl = &IMultiLanguage_vtbl;
3568     mlang->IMultiLanguage3_iface.lpVtbl = &IMultiLanguage3_vtbl;
3569     mlang->IMLangFontLink2_iface.lpVtbl = &IMLangFontLink2_vtbl;
3570     mlang->IMLangLineBreakConsole_iface.lpVtbl = &IMLangLineBreakConsole_vtbl;
3571
3572     mlang->total_cp = 0;
3573     for (i = 0; i < sizeof(mlang_data)/sizeof(mlang_data[0]); i++)
3574         mlang->total_cp += mlang_data[i].number_of_cp;
3575
3576     /* do not enumerate unicode flavours */
3577     mlang->total_scripts = sizeof(mlang_data)/sizeof(mlang_data[0]) - 1;
3578
3579     mlang->ref = 1;
3580     *ppObj = mlang;
3581     TRACE("returning %p\n", mlang);
3582
3583     LockModule();
3584
3585     return S_OK;
3586 }
3587
3588 /******************************************************************************/
3589
3590 HRESULT WINAPI DllCanUnloadNow(void)
3591 {
3592     return dll_count == 0 ? S_OK : S_FALSE;
3593 }
3594
3595
3596 /***********************************************************************
3597  *              DllRegisterServer (MLANG.@)
3598  */
3599 HRESULT WINAPI DllRegisterServer(void)
3600 {
3601     return __wine_register_resources( instance );
3602 }
3603
3604 /***********************************************************************
3605  *              DllUnregisterServer (MLANG.@)
3606  */
3607 HRESULT WINAPI DllUnregisterServer(void)
3608 {
3609     return __wine_unregister_resources( instance );
3610 }
3611
3612 HRESULT WINAPI GetGlobalFontLinkObject(void **unknown)
3613 {
3614     if (!unknown) return E_INVALIDARG;
3615
3616     FIXME("%p: stub\n", unknown);
3617
3618     return S_FALSE;
3619 }