mpr: Tweak a label so it matches the one in wininet.
[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 ITF_IClassFactory;
1281
1282     LONG ref;
1283     HRESULT (*pfnCreateInstance)(IUnknown *pUnkOuter, LPVOID *ppObj);
1284 } IClassFactoryImpl;
1285
1286 struct object_creation_info
1287 {
1288     const CLSID *clsid;
1289     LPCSTR szClassName;
1290     HRESULT (*pfnCreateInstance)(IUnknown *pUnkOuter, LPVOID *ppObj);
1291 };
1292
1293 static const struct object_creation_info object_creation[] =
1294 {
1295     { &CLSID_CMultiLanguage, "CLSID_CMultiLanguage", MultiLanguage_create },
1296 };
1297
1298 static HRESULT WINAPI
1299 MLANGCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj)
1300 {
1301     IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
1302
1303     TRACE("%s\n", debugstr_guid(riid) );
1304
1305     if (IsEqualGUID(riid, &IID_IUnknown)
1306         || IsEqualGUID(riid, &IID_IClassFactory))
1307     {
1308         IClassFactory_AddRef(iface);
1309         *ppobj = This;
1310         return S_OK;
1311     }
1312
1313     WARN("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppobj);
1314     return E_NOINTERFACE;
1315 }
1316
1317 static ULONG WINAPI MLANGCF_AddRef(LPCLASSFACTORY iface)
1318 {
1319     IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
1320     return InterlockedIncrement(&This->ref);
1321 }
1322
1323 static ULONG WINAPI MLANGCF_Release(LPCLASSFACTORY iface)
1324 {
1325     IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
1326
1327     ULONG ref = InterlockedDecrement(&This->ref);
1328
1329     if (ref == 0)
1330     {
1331         TRACE("Destroying %p\n", This);
1332         HeapFree(GetProcessHeap(), 0, This);
1333     }
1334
1335     return ref;
1336 }
1337
1338 static HRESULT WINAPI MLANGCF_CreateInstance(LPCLASSFACTORY iface, LPUNKNOWN pOuter,
1339                                           REFIID riid, LPVOID *ppobj)
1340 {
1341     IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
1342     HRESULT hres;
1343     LPUNKNOWN punk;
1344     
1345     TRACE("(%p)->(%p,%s,%p)\n",This,pOuter,debugstr_guid(riid),ppobj);
1346
1347     *ppobj = NULL;
1348     hres = This->pfnCreateInstance(pOuter, (LPVOID *) &punk);
1349     if (SUCCEEDED(hres)) {
1350         hres = IUnknown_QueryInterface(punk, riid, ppobj);
1351         IUnknown_Release(punk);
1352     }
1353     TRACE("returning (%p) -> %x\n", *ppobj, hres);
1354     return hres;
1355 }
1356
1357 static HRESULT WINAPI MLANGCF_LockServer(LPCLASSFACTORY iface,BOOL dolock)
1358 {
1359     if (dolock)
1360         LockModule();
1361     else
1362         UnlockModule();
1363
1364     return S_OK;
1365 }
1366
1367 static const IClassFactoryVtbl MLANGCF_Vtbl =
1368 {
1369     MLANGCF_QueryInterface,
1370     MLANGCF_AddRef,
1371     MLANGCF_Release,
1372     MLANGCF_CreateInstance,
1373     MLANGCF_LockServer
1374 };
1375
1376 /******************************************************************
1377  *              DllGetClassObject (MLANG.@)
1378  */
1379 HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID iid, LPVOID *ppv)
1380 {
1381     unsigned int i;
1382     IClassFactoryImpl *factory;
1383
1384     TRACE("%s %s %p\n",debugstr_guid(rclsid), debugstr_guid(iid), ppv);
1385
1386     if ( !IsEqualGUID( &IID_IClassFactory, iid )
1387          && ! IsEqualGUID( &IID_IUnknown, iid) )
1388         return E_NOINTERFACE;
1389
1390     for (i=0; i < sizeof(object_creation)/sizeof(object_creation[0]); i++)
1391     {
1392         if (IsEqualGUID(object_creation[i].clsid, rclsid))
1393             break;
1394     }
1395
1396     if (i == sizeof(object_creation)/sizeof(object_creation[0]))
1397     {
1398         FIXME("%s: no class found.\n", debugstr_guid(rclsid));
1399         return CLASS_E_CLASSNOTAVAILABLE;
1400     }
1401
1402     TRACE("Creating a class factory for %s\n",object_creation[i].szClassName);
1403
1404     factory = HeapAlloc(GetProcessHeap(), 0, sizeof(*factory));
1405     if (factory == NULL) return E_OUTOFMEMORY;
1406
1407     factory->ITF_IClassFactory.lpVtbl = &MLANGCF_Vtbl;
1408     factory->ref = 1;
1409
1410     factory->pfnCreateInstance = object_creation[i].pfnCreateInstance;
1411
1412     *ppv = &(factory->ITF_IClassFactory);
1413
1414     TRACE("(%p) <- %p\n", ppv, &(factory->ITF_IClassFactory) );
1415
1416     return S_OK;
1417 }
1418
1419
1420 /******************************************************************************/
1421
1422 typedef struct tagMLang_impl
1423 {
1424     IMLangFontLink IMLangFontLink_iface;
1425     IMultiLanguage IMultiLanguage_iface;
1426     IMultiLanguage3 IMultiLanguage3_iface;
1427     IMLangFontLink2 IMLangFontLink2_iface;
1428     IMLangLineBreakConsole IMLangLineBreakConsole_iface;
1429     LONG ref;
1430     DWORD total_cp, total_scripts;
1431 } MLang_impl;
1432
1433 static ULONG MLang_AddRef( MLang_impl* This)
1434 {
1435     return InterlockedIncrement(&This->ref);
1436 }
1437
1438 static ULONG MLang_Release( MLang_impl* This )
1439 {
1440     ULONG ref = InterlockedDecrement(&This->ref);
1441
1442     TRACE("%p ref = %d\n", This, ref);
1443     if (ref == 0)
1444     {
1445         TRACE("Destroying %p\n", This);
1446         HeapFree(GetProcessHeap(), 0, This);
1447         UnlockModule();
1448     }
1449
1450     return ref;
1451 }
1452
1453 static HRESULT MLang_QueryInterface(
1454         MLang_impl* This,
1455         REFIID riid,
1456         void** ppvObject)
1457 {
1458     TRACE("%p -> %s\n", This, debugstr_guid(riid) );
1459
1460     if (IsEqualGUID(riid, &IID_IUnknown)
1461         || IsEqualGUID(riid, &IID_IMLangCodePages)
1462         || IsEqualGUID(riid, &IID_IMLangFontLink))
1463     {
1464         MLang_AddRef(This);
1465         TRACE("Returning IID_IMLangFontLink %p ref = %d\n", This, This->ref);
1466         *ppvObject = &This->IMLangFontLink_iface;
1467         return S_OK;
1468     }
1469
1470     if (IsEqualGUID(riid, &IID_IMLangFontLink2))
1471     {
1472         MLang_AddRef(This);
1473         TRACE("Returning IID_IMLangFontLink2 %p ref = %d\n", This, This->ref);
1474         *ppvObject = &This->IMLangFontLink2_iface;
1475         return S_OK;
1476     }
1477
1478     if (IsEqualGUID(riid, &IID_IMultiLanguage) )
1479     {
1480         MLang_AddRef(This);
1481         TRACE("Returning IID_IMultiLanguage %p ref = %d\n", This, This->ref);
1482         *ppvObject = &This->IMultiLanguage_iface;
1483         return S_OK;
1484     }
1485
1486     if (IsEqualGUID(riid, &IID_IMultiLanguage2) )
1487     {
1488         MLang_AddRef(This);
1489         *ppvObject = &This->IMultiLanguage3_iface;
1490         TRACE("Returning IID_IMultiLanguage2 %p ref = %d\n", This, This->ref);
1491         return S_OK;
1492     }
1493
1494     if (IsEqualGUID(riid, &IID_IMultiLanguage3) )
1495     {
1496         MLang_AddRef(This);
1497         *ppvObject = &This->IMultiLanguage3_iface;
1498         TRACE("Returning IID_IMultiLanguage3 %p ref = %d\n", This, This->ref);
1499         return S_OK;
1500     }
1501
1502     if (IsEqualGUID(riid, &IID_IMLangLineBreakConsole))
1503     {
1504         MLang_AddRef(This);
1505         TRACE("Returning IID_IMLangLineBreakConsole %p ref = %d\n", This, This->ref);
1506         *ppvObject = &This->IMLangLineBreakConsole_iface;
1507         return S_OK;
1508     }
1509
1510
1511     WARN("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppvObject);
1512     return E_NOINTERFACE;
1513 }
1514
1515 /******************************************************************************/
1516
1517 typedef struct tagEnumCodePage_impl
1518 {
1519     IEnumCodePage IEnumCodePage_iface;
1520     LONG ref;
1521     MIMECPINFO *cpinfo;
1522     DWORD total, pos;
1523 } EnumCodePage_impl;
1524
1525 static inline EnumCodePage_impl *impl_from_IEnumCodePage( IEnumCodePage *iface )
1526 {
1527     return CONTAINING_RECORD( iface, EnumCodePage_impl, IEnumCodePage_iface );
1528 }
1529
1530 static HRESULT WINAPI fnIEnumCodePage_QueryInterface(
1531         IEnumCodePage* iface,
1532         REFIID riid,
1533         void** ppvObject)
1534 {
1535     EnumCodePage_impl *This = impl_from_IEnumCodePage( iface );
1536
1537     TRACE("%p -> %s\n", This, debugstr_guid(riid) );
1538
1539     if (IsEqualGUID(riid, &IID_IUnknown)
1540         || IsEqualGUID(riid, &IID_IEnumCodePage))
1541     {
1542         IEnumCodePage_AddRef(iface);
1543         TRACE("Returning IID_IEnumCodePage %p ref = %d\n", This, This->ref);
1544         *ppvObject = &This->IEnumCodePage_iface;
1545         return S_OK;
1546     }
1547
1548     WARN("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppvObject);
1549     return E_NOINTERFACE;
1550 }
1551
1552 static ULONG WINAPI fnIEnumCodePage_AddRef(
1553         IEnumCodePage* iface)
1554 {
1555     EnumCodePage_impl *This = impl_from_IEnumCodePage( iface );
1556     return InterlockedIncrement(&This->ref);
1557 }
1558
1559 static ULONG WINAPI fnIEnumCodePage_Release(
1560         IEnumCodePage* iface)
1561 {
1562     EnumCodePage_impl *This = impl_from_IEnumCodePage( iface );
1563     ULONG ref = InterlockedDecrement(&This->ref);
1564
1565     TRACE("%p ref = %d\n", This, ref);
1566     if (ref == 0)
1567     {
1568         TRACE("Destroying %p\n", This);
1569         HeapFree(GetProcessHeap(), 0, This->cpinfo);
1570         HeapFree(GetProcessHeap(), 0, This);
1571     }
1572
1573     return ref;
1574 }
1575
1576 static HRESULT WINAPI fnIEnumCodePage_Clone(
1577         IEnumCodePage* iface,
1578         IEnumCodePage** ppEnum)
1579 {
1580     EnumCodePage_impl *This = impl_from_IEnumCodePage( iface );
1581     FIXME("%p %p\n", This, ppEnum);
1582     return E_NOTIMPL;
1583 }
1584
1585 static  HRESULT WINAPI fnIEnumCodePage_Next(
1586         IEnumCodePage* iface,
1587         ULONG celt,
1588         PMIMECPINFO rgelt,
1589         ULONG* pceltFetched)
1590 {
1591     ULONG i;
1592     EnumCodePage_impl *This = impl_from_IEnumCodePage( iface );
1593
1594     TRACE("%p %u %p %p\n", This, celt, rgelt, pceltFetched);
1595
1596     if (!pceltFetched) return S_FALSE;
1597     *pceltFetched = 0;
1598
1599     if (!rgelt) return S_FALSE;
1600
1601     if (This->pos + celt > This->total)
1602         celt = This->total - This->pos;
1603
1604     if (!celt) return S_FALSE;
1605
1606     memcpy(rgelt, This->cpinfo + This->pos, celt * sizeof(MIMECPINFO));
1607     *pceltFetched = celt;
1608     This->pos += celt;
1609
1610     for (i = 0; i < celt; i++)
1611     {
1612         TRACE("#%u: %08x %u %u %s %s %s %s %s %s %d\n",
1613               i, rgelt[i].dwFlags, rgelt[i].uiCodePage,
1614               rgelt[i].uiFamilyCodePage,
1615               wine_dbgstr_w(rgelt[i].wszDescription),
1616               wine_dbgstr_w(rgelt[i].wszWebCharset),
1617               wine_dbgstr_w(rgelt[i].wszHeaderCharset),
1618               wine_dbgstr_w(rgelt[i].wszBodyCharset),
1619               wine_dbgstr_w(rgelt[i].wszFixedWidthFont),
1620               wine_dbgstr_w(rgelt[i].wszProportionalFont),
1621               rgelt[i].bGDICharset);
1622     }
1623     return S_OK;
1624 }
1625
1626 static HRESULT WINAPI fnIEnumCodePage_Reset(
1627         IEnumCodePage* iface)
1628 {
1629     EnumCodePage_impl *This = impl_from_IEnumCodePage( iface );
1630
1631     TRACE("%p\n", This);
1632
1633     This->pos = 0;
1634     return S_OK;
1635 }
1636
1637 static  HRESULT WINAPI fnIEnumCodePage_Skip(
1638         IEnumCodePage* iface,
1639         ULONG celt)
1640 {
1641     EnumCodePage_impl *This = impl_from_IEnumCodePage( iface );
1642
1643     TRACE("%p %u\n", This, celt);
1644
1645     if (celt >= This->total) return S_FALSE;
1646
1647     This->pos += celt;
1648     return S_OK;
1649 }
1650
1651 static const IEnumCodePageVtbl IEnumCodePage_vtbl =
1652 {
1653     fnIEnumCodePage_QueryInterface,
1654     fnIEnumCodePage_AddRef,
1655     fnIEnumCodePage_Release,
1656     fnIEnumCodePage_Clone,
1657     fnIEnumCodePage_Next,
1658     fnIEnumCodePage_Reset,
1659     fnIEnumCodePage_Skip
1660 };
1661
1662 static HRESULT EnumCodePage_create( MLang_impl* mlang, DWORD grfFlags,
1663                      LANGID LangId, IEnumCodePage** ppEnumCodePage )
1664 {
1665     EnumCodePage_impl *ecp;
1666     MIMECPINFO *cpinfo;
1667     UINT i, n;
1668
1669     TRACE("%p, %08x, %04x, %p\n", mlang, grfFlags, LangId, ppEnumCodePage);
1670
1671     if (!grfFlags) /* enumerate internal data base of encodings */
1672         grfFlags = MIMECONTF_MIME_LATEST;
1673
1674     ecp = HeapAlloc( GetProcessHeap(), 0, sizeof (EnumCodePage_impl) );
1675     ecp->IEnumCodePage_iface.lpVtbl = &IEnumCodePage_vtbl;
1676     ecp->ref = 1;
1677     ecp->pos = 0;
1678     ecp->total = 0;
1679     for (i = 0; i < sizeof(mlang_data)/sizeof(mlang_data[0]); i++)
1680     {
1681         for (n = 0; n < mlang_data[i].number_of_cp; n++)
1682         {
1683             if (mlang_data[i].mime_cp_info[n].flags & grfFlags)
1684                 ecp->total++;
1685         }
1686     }
1687
1688     ecp->cpinfo = HeapAlloc(GetProcessHeap(), 0,
1689                             sizeof(MIMECPINFO) * ecp->total);
1690     cpinfo = ecp->cpinfo;
1691
1692     for (i = 0; i < sizeof(mlang_data)/sizeof(mlang_data[0]); i++)
1693     {
1694         for (n = 0; n < mlang_data[i].number_of_cp; n++)
1695         {
1696             if (mlang_data[i].mime_cp_info[n].flags & grfFlags)
1697                 fill_cp_info(&mlang_data[i], n, cpinfo++);
1698         }
1699     }
1700
1701     TRACE("enumerated %d codepages with flags %08x\n", ecp->total, grfFlags);
1702
1703     *ppEnumCodePage = &ecp->IEnumCodePage_iface;
1704
1705     return S_OK;
1706 }
1707
1708 /******************************************************************************/
1709
1710 typedef struct tagEnumScript_impl
1711 {
1712     IEnumScript IEnumScript_iface;
1713     LONG ref;
1714     SCRIPTINFO *script_info;
1715     DWORD total, pos;
1716 } EnumScript_impl;
1717
1718 static inline EnumScript_impl *impl_from_IEnumScript( IEnumScript *iface )
1719 {
1720     return CONTAINING_RECORD( iface, EnumScript_impl, IEnumScript_iface );
1721 }
1722
1723 static HRESULT WINAPI fnIEnumScript_QueryInterface(
1724         IEnumScript* iface,
1725         REFIID riid,
1726         void** ppvObject)
1727 {
1728     EnumScript_impl *This = impl_from_IEnumScript( iface );
1729
1730     TRACE("%p -> %s\n", This, debugstr_guid(riid) );
1731
1732     if (IsEqualGUID(riid, &IID_IUnknown)
1733         || IsEqualGUID(riid, &IID_IEnumScript))
1734     {
1735         IEnumScript_AddRef(iface);
1736         TRACE("Returning IID_IEnumScript %p ref = %d\n", This, This->ref);
1737         *ppvObject = &This->IEnumScript_iface;
1738         return S_OK;
1739     }
1740
1741     WARN("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppvObject);
1742     return E_NOINTERFACE;
1743 }
1744
1745 static ULONG WINAPI fnIEnumScript_AddRef(
1746         IEnumScript* iface)
1747 {
1748     EnumScript_impl *This = impl_from_IEnumScript( iface );
1749     return InterlockedIncrement(&This->ref);
1750 }
1751
1752 static ULONG WINAPI fnIEnumScript_Release(
1753         IEnumScript* iface)
1754 {
1755     EnumScript_impl *This = impl_from_IEnumScript( iface );
1756     ULONG ref = InterlockedDecrement(&This->ref);
1757
1758     TRACE("%p ref = %d\n", This, ref);
1759     if (ref == 0)
1760     {
1761         TRACE("Destroying %p\n", This);
1762         HeapFree(GetProcessHeap(), 0, This->script_info);
1763         HeapFree(GetProcessHeap(), 0, This);
1764     }
1765
1766     return ref;
1767 }
1768
1769 static HRESULT WINAPI fnIEnumScript_Clone(
1770         IEnumScript* iface,
1771         IEnumScript** ppEnum)
1772 {
1773     EnumScript_impl *This = impl_from_IEnumScript( iface );
1774     FIXME("%p %p: stub!\n", This, ppEnum);
1775     return E_NOTIMPL;
1776 }
1777
1778 static  HRESULT WINAPI fnIEnumScript_Next(
1779         IEnumScript* iface,
1780         ULONG celt,
1781         PSCRIPTINFO rgelt,
1782         ULONG* pceltFetched)
1783 {
1784     EnumScript_impl *This = impl_from_IEnumScript( iface );
1785
1786     TRACE("%p %u %p %p\n", This, celt, rgelt, pceltFetched);
1787
1788     if (!pceltFetched || !rgelt) return E_FAIL;
1789
1790     *pceltFetched = 0;
1791
1792     if (This->pos + celt > This->total)
1793         celt = This->total - This->pos;
1794
1795     if (!celt) return S_FALSE;
1796
1797     memcpy(rgelt, This->script_info + This->pos, celt * sizeof(SCRIPTINFO));
1798     *pceltFetched = celt;
1799     This->pos += celt;
1800
1801     return S_OK;
1802 }
1803
1804 static HRESULT WINAPI fnIEnumScript_Reset(
1805         IEnumScript* iface)
1806 {
1807     EnumScript_impl *This = impl_from_IEnumScript( iface );
1808
1809     TRACE("%p\n", This);
1810
1811     This->pos = 0;
1812     return S_OK;
1813 }
1814
1815 static  HRESULT WINAPI fnIEnumScript_Skip(
1816         IEnumScript* iface,
1817         ULONG celt)
1818 {
1819     EnumScript_impl *This = impl_from_IEnumScript( iface );
1820
1821     TRACE("%p %u\n", This, celt);
1822
1823     if (celt >= This->total) return S_FALSE;
1824
1825     This->pos += celt;
1826     return S_OK;
1827 }
1828
1829 static const IEnumScriptVtbl IEnumScript_vtbl =
1830 {
1831     fnIEnumScript_QueryInterface,
1832     fnIEnumScript_AddRef,
1833     fnIEnumScript_Release,
1834     fnIEnumScript_Clone,
1835     fnIEnumScript_Next,
1836     fnIEnumScript_Reset,
1837     fnIEnumScript_Skip
1838 };
1839
1840 static HRESULT EnumScript_create( MLang_impl* mlang, DWORD dwFlags,
1841                      LANGID LangId, IEnumScript** ppEnumScript )
1842 {
1843     EnumScript_impl *es;
1844     UINT i;
1845
1846     TRACE("%p, %08x, %04x, %p: stub!\n", mlang, dwFlags, LangId, ppEnumScript);
1847
1848     if (!dwFlags) /* enumerate all available scripts */
1849         dwFlags = SCRIPTCONTF_SCRIPT_USER | SCRIPTCONTF_SCRIPT_HIDE | SCRIPTCONTF_SCRIPT_SYSTEM;
1850
1851     es = HeapAlloc( GetProcessHeap(), 0, sizeof (EnumScript_impl) );
1852     es->IEnumScript_iface.lpVtbl = &IEnumScript_vtbl;
1853     es->ref = 1;
1854     es->pos = 0;
1855     /* do not enumerate unicode flavours */
1856     es->total = sizeof(mlang_data)/sizeof(mlang_data[0]) - 1;
1857     es->script_info = HeapAlloc(GetProcessHeap(), 0, sizeof(SCRIPTINFO) * es->total);
1858
1859     for (i = 0; i < es->total; i++)
1860     {
1861         es->script_info[i].ScriptId = i;
1862         es->script_info[i].uiCodePage = mlang_data[i].family_codepage;
1863         MultiByteToWideChar(CP_ACP, 0, mlang_data[i].description, -1,
1864             es->script_info[i].wszDescription, MAX_SCRIPT_NAME);
1865         MultiByteToWideChar(CP_ACP, 0, mlang_data[i].fixed_font, -1,
1866             es->script_info[i].wszFixedWidthFont, MAX_MIMEFACE_NAME);
1867         MultiByteToWideChar(CP_ACP, 0, mlang_data[i].proportional_font, -1,
1868             es->script_info[i].wszProportionalFont, MAX_MIMEFACE_NAME);
1869     }
1870
1871     TRACE("enumerated %d scripts with flags %08x\n", es->total, dwFlags);
1872
1873     *ppEnumScript = &es->IEnumScript_iface;
1874
1875     return S_OK;
1876 }
1877
1878 /******************************************************************************/
1879
1880 static inline MLang_impl *impl_from_IMLangFontLink( IMLangFontLink *iface )
1881 {
1882     return CONTAINING_RECORD( iface, MLang_impl, IMLangFontLink_iface );
1883 }
1884
1885 static HRESULT WINAPI fnIMLangFontLink_QueryInterface(
1886         IMLangFontLink* iface,
1887         REFIID riid,
1888         void** ppvObject)
1889 {
1890     MLang_impl *This = impl_from_IMLangFontLink( iface );
1891     return MLang_QueryInterface( This, riid, ppvObject );
1892 }
1893
1894 static ULONG WINAPI fnIMLangFontLink_AddRef(
1895         IMLangFontLink* iface)
1896 {
1897     MLang_impl *This = impl_from_IMLangFontLink( iface );
1898     return MLang_AddRef( This );
1899 }
1900
1901 static ULONG WINAPI fnIMLangFontLink_Release(
1902         IMLangFontLink* iface)
1903 {
1904     MLang_impl *This = impl_from_IMLangFontLink( iface );
1905     return MLang_Release( This );
1906 }
1907
1908 static HRESULT WINAPI fnIMLangFontLink_GetCharCodePages(
1909         IMLangFontLink* iface,
1910         WCHAR chSrc,
1911         DWORD* pdwCodePages)
1912 {
1913     int i;
1914     CHAR buf;
1915     BOOL used_dc;
1916     DWORD codePages;
1917
1918     *pdwCodePages = 0;
1919
1920     for (i = 0; i < sizeof(mlang_data)/sizeof(mlang_data[0]); i++)
1921     {
1922         WideCharToMultiByte(mlang_data[i].family_codepage, WC_NO_BEST_FIT_CHARS,
1923             &chSrc, 1, &buf, 1, NULL, &used_dc);
1924
1925         /* If default char is not used, current codepage include the given symbol */
1926         if (!used_dc)
1927         {
1928             IMLangFontLink_CodePageToCodePages(iface,
1929                 mlang_data[i].family_codepage, &codePages);
1930             *pdwCodePages |= codePages;
1931         }
1932     }
1933     return S_OK;
1934 }
1935
1936 static HRESULT WINAPI fnIMLangFontLink_GetStrCodePages(
1937         IMLangFontLink* iface,
1938         const WCHAR* pszSrc,
1939         LONG cchSrc,
1940         DWORD dwPriorityCodePages,
1941         DWORD* pdwCodePages,
1942         LONG* pcchCodePages)
1943 {
1944     LONG i;
1945     DWORD cps = 0;
1946
1947     TRACE("(%p)->%s %d %x %p %p\n", iface, debugstr_wn(pszSrc, cchSrc), cchSrc, dwPriorityCodePages, pdwCodePages, pcchCodePages);
1948
1949     if (pdwCodePages) *pdwCodePages = 0;
1950     if (pcchCodePages) *pcchCodePages = 0;
1951
1952     if (!pszSrc || !cchSrc || cchSrc < 0)
1953         return E_INVALIDARG;
1954
1955     for (i = 0; i < cchSrc; i++)
1956     {
1957         DWORD cp;
1958         HRESULT ret;
1959
1960         ret = fnIMLangFontLink_GetCharCodePages(iface, pszSrc[i], &cp);
1961         if (ret != S_OK) return E_FAIL;
1962
1963         if (!cps) cps = cp;
1964         else cps &= cp;
1965
1966         /* FIXME: not tested */
1967         if (dwPriorityCodePages & cps) break;
1968     }
1969
1970     if (pdwCodePages) *pdwCodePages = cps;
1971     if (pcchCodePages) *pcchCodePages = min( i + 1, cchSrc );
1972     return S_OK;
1973 }
1974
1975 static HRESULT WINAPI fnIMLangFontLink_CodePageToCodePages(
1976         IMLangFontLink* iface,
1977         UINT uCodePage,
1978         DWORD* pdwCodePages)
1979 {
1980     MLang_impl *This = impl_from_IMLangFontLink( iface );
1981     CHARSETINFO cs;
1982     BOOL rc; 
1983
1984     TRACE("(%p) Seeking %u\n",This, uCodePage);
1985
1986     rc = TranslateCharsetInfo((DWORD*)(DWORD_PTR)uCodePage, &cs, TCI_SRCCODEPAGE);
1987
1988     if (rc)
1989     {
1990         *pdwCodePages = cs.fs.fsCsb[0];
1991         TRACE("resulting CodePages 0x%x\n",*pdwCodePages);
1992         return S_OK;
1993     }
1994
1995     TRACE("CodePage Not Found\n");
1996     *pdwCodePages = 0;
1997     return E_FAIL;
1998 }
1999
2000 static HRESULT WINAPI fnIMLangFontLink_CodePagesToCodePage(
2001         IMLangFontLink* iface,
2002         DWORD dwCodePages,
2003         UINT uDefaultCodePage,
2004         UINT* puCodePage)
2005 {
2006     MLang_impl *This = impl_from_IMLangFontLink( iface );
2007     DWORD mask = 0x00000000;
2008     UINT i;
2009     CHARSETINFO cs;
2010     BOOL rc; 
2011
2012     TRACE("(%p) scanning  0x%x  default page %u\n",This, dwCodePages,
2013             uDefaultCodePage);
2014
2015     *puCodePage = 0x00000000;
2016
2017     rc = TranslateCharsetInfo((DWORD*)(DWORD_PTR)uDefaultCodePage, &cs,
2018                               TCI_SRCCODEPAGE);
2019
2020     if (rc && (dwCodePages & cs.fs.fsCsb[0]))
2021     {
2022         TRACE("Found Default Codepage\n");
2023         *puCodePage = uDefaultCodePage;
2024         return S_OK;
2025     }
2026
2027     
2028     for (i = 0; i < 32; i++)
2029     {
2030
2031         mask = 1 << i;
2032         if (dwCodePages & mask)
2033         {
2034             DWORD Csb[2];
2035             Csb[0] = mask;
2036             Csb[1] = 0x0;
2037             rc = TranslateCharsetInfo(Csb, &cs, TCI_SRCFONTSIG);
2038             if (!rc)
2039                 continue;
2040
2041             TRACE("Falling back to least significant found CodePage %u\n",
2042                     cs.ciACP);
2043             *puCodePage = cs.ciACP;
2044             return S_OK;
2045         }
2046     }
2047
2048     TRACE("no codepage found\n");
2049     return E_FAIL;
2050 }
2051
2052 static HRESULT WINAPI fnIMLangFontLink_GetFontCodePages(
2053         IMLangFontLink* iface,
2054         HDC hDC,
2055         HFONT hFont,
2056         DWORD* pdwCodePages)
2057 {
2058     HFONT old_font;
2059     FONTSIGNATURE fontsig;
2060     MLang_impl *This = impl_from_IMLangFontLink( iface );
2061
2062     TRACE("(%p)\n",This);
2063
2064     old_font = SelectObject(hDC,hFont);
2065     GetTextCharsetInfo(hDC,&fontsig, 0);
2066     SelectObject(hDC,old_font);
2067
2068     *pdwCodePages = fontsig.fsCsb[0];
2069     TRACE("CodePages is 0x%x\n",fontsig.fsCsb[0]);
2070
2071     return S_OK;
2072 }
2073
2074 static HRESULT WINAPI fnIMLangFontLink_MapFont(
2075         IMLangFontLink* iface,
2076         HDC hDC,
2077         DWORD dwCodePages,
2078         HFONT hSrcFont,
2079         HFONT* phDestFont)
2080 {
2081     FIXME("\n");
2082     return E_NOTIMPL;
2083 }
2084
2085 static HRESULT WINAPI fnIMLangFontLink_ReleaseFont(
2086         IMLangFontLink* iface,
2087         HFONT hFont)
2088 {
2089     FIXME("\n");
2090     return E_NOTIMPL;
2091 }
2092
2093 static HRESULT WINAPI fnIMLangFontLink_ResetFontMapping(
2094         IMLangFontLink* iface)
2095 {
2096     FIXME("\n");
2097     return E_NOTIMPL;
2098 }
2099
2100
2101 static const IMLangFontLinkVtbl IMLangFontLink_vtbl =
2102 {
2103     fnIMLangFontLink_QueryInterface,
2104     fnIMLangFontLink_AddRef,
2105     fnIMLangFontLink_Release,
2106     fnIMLangFontLink_GetCharCodePages,
2107     fnIMLangFontLink_GetStrCodePages,
2108     fnIMLangFontLink_CodePageToCodePages,
2109     fnIMLangFontLink_CodePagesToCodePage,
2110     fnIMLangFontLink_GetFontCodePages,
2111     fnIMLangFontLink_MapFont,
2112     fnIMLangFontLink_ReleaseFont,
2113     fnIMLangFontLink_ResetFontMapping,
2114 };
2115
2116 /******************************************************************************/
2117
2118 static inline MLang_impl *impl_from_IMultiLanguage( IMultiLanguage *iface )
2119 {
2120     return CONTAINING_RECORD( iface, MLang_impl, IMultiLanguage_iface );
2121 }
2122
2123 static HRESULT WINAPI fnIMultiLanguage_QueryInterface(
2124     IMultiLanguage* iface,
2125     REFIID riid,
2126     void** ppvObject)
2127 {
2128     MLang_impl *This = impl_from_IMultiLanguage( iface );
2129     return MLang_QueryInterface( This, riid, ppvObject );
2130 }
2131
2132 static ULONG WINAPI fnIMultiLanguage_AddRef( IMultiLanguage* iface )
2133 {
2134     MLang_impl *This = impl_from_IMultiLanguage( iface );
2135     return IMLangFontLink_AddRef( &This->IMLangFontLink_iface );
2136 }
2137
2138 static ULONG WINAPI fnIMultiLanguage_Release( IMultiLanguage* iface )
2139 {
2140     MLang_impl *This = impl_from_IMultiLanguage( iface );
2141     return IMLangFontLink_Release( &This->IMLangFontLink_iface );
2142 }
2143
2144 static HRESULT WINAPI fnIMultiLanguage_GetNumberOfCodePageInfo(
2145     IMultiLanguage* iface,
2146     UINT* pcCodePage)
2147 {
2148     MLang_impl *This = impl_from_IMultiLanguage( iface );
2149
2150     TRACE("(%p, %p)\n", This, pcCodePage);
2151
2152     if (!pcCodePage) return E_INVALIDARG;
2153
2154     *pcCodePage = This->total_cp;
2155     return S_OK;
2156 }
2157
2158 static HRESULT WINAPI fnIMultiLanguage_GetCodePageInfo(
2159     IMultiLanguage* iface,
2160     UINT uiCodePage,
2161     PMIMECPINFO pCodePageInfo)
2162 {
2163     UINT i, n;
2164     MLang_impl *This = impl_from_IMultiLanguage( iface );
2165
2166     TRACE("%p, %u, %p\n", This, uiCodePage, pCodePageInfo);
2167
2168     for (i = 0; i < sizeof(mlang_data)/sizeof(mlang_data[0]); i++)
2169     {
2170         for (n = 0; n < mlang_data[i].number_of_cp; n++)
2171         {
2172             if (mlang_data[i].mime_cp_info[n].cp == uiCodePage)
2173             {
2174                 fill_cp_info(&mlang_data[i], n, pCodePageInfo);
2175                 return S_OK;
2176             }
2177         }
2178     }
2179
2180     return S_FALSE;
2181 }
2182
2183 static HRESULT WINAPI fnIMultiLanguage_GetFamilyCodePage(
2184     IMultiLanguage* iface,
2185     UINT uiCodePage,
2186     UINT* puiFamilyCodePage)
2187 {
2188     return GetFamilyCodePage(uiCodePage, puiFamilyCodePage);
2189 }
2190
2191 static HRESULT WINAPI fnIMultiLanguage_EnumCodePages(
2192     IMultiLanguage* iface,
2193     DWORD grfFlags,
2194     IEnumCodePage** ppEnumCodePage)
2195 {
2196     MLang_impl *This = impl_from_IMultiLanguage( iface );
2197
2198     TRACE("%p %08x %p\n", This, grfFlags, ppEnumCodePage);
2199
2200     return EnumCodePage_create( This, grfFlags, 0, ppEnumCodePage );
2201 }
2202
2203 static HRESULT WINAPI fnIMultiLanguage_GetCharsetInfo(
2204     IMultiLanguage* iface,
2205     BSTR Charset,
2206     PMIMECSETINFO pCharsetInfo)
2207 {
2208     MLang_impl *This = impl_from_IMultiLanguage( iface );
2209     return IMultiLanguage3_GetCharsetInfo( &This->IMultiLanguage3_iface, Charset, pCharsetInfo );
2210 }
2211
2212 static HRESULT WINAPI fnIMultiLanguage_IsConvertible(
2213     IMultiLanguage* iface,
2214     DWORD dwSrcEncoding,
2215     DWORD dwDstEncoding)
2216 {
2217     return IsConvertINetStringAvailable(dwSrcEncoding, dwDstEncoding);
2218 }
2219
2220 static HRESULT WINAPI fnIMultiLanguage_ConvertString(
2221     IMultiLanguage* iface,
2222     DWORD* pdwMode,
2223     DWORD dwSrcEncoding,
2224     DWORD dwDstEncoding,
2225     BYTE* pSrcStr,
2226     UINT* pcSrcSize,
2227     BYTE* pDstStr,
2228     UINT* pcDstSize)
2229 {
2230     return ConvertINetString(pdwMode, dwSrcEncoding, dwDstEncoding,
2231         (LPCSTR)pSrcStr, (LPINT)pcSrcSize, (LPSTR)pDstStr, (LPINT)pcDstSize);
2232 }
2233
2234 static HRESULT WINAPI fnIMultiLanguage_ConvertStringToUnicode(
2235     IMultiLanguage* iface,
2236     DWORD* pdwMode,
2237     DWORD dwEncoding,
2238     CHAR* pSrcStr,
2239     UINT* pcSrcSize,
2240     WCHAR* pDstStr,
2241     UINT* pcDstSize)
2242 {
2243     return ConvertINetMultiByteToUnicode(pdwMode, dwEncoding,
2244         (LPCSTR)pSrcStr, (LPINT)pcSrcSize, pDstStr, (LPINT)pcDstSize);
2245 }
2246
2247 static HRESULT WINAPI fnIMultiLanguage_ConvertStringFromUnicode(
2248     IMultiLanguage* iface,
2249     DWORD* pdwMode,
2250     DWORD dwEncoding,
2251     WCHAR* pSrcStr,
2252     UINT* pcSrcSize,
2253     CHAR* pDstStr,
2254     UINT* pcDstSize)
2255 {
2256     return ConvertINetUnicodeToMultiByte(pdwMode, dwEncoding,
2257         pSrcStr, (LPINT)pcSrcSize, pDstStr, (LPINT)pcDstSize);
2258 }
2259
2260 static HRESULT WINAPI fnIMultiLanguage_ConvertStringReset(
2261     IMultiLanguage* iface)
2262 {
2263     FIXME("\n");
2264     return E_NOTIMPL;
2265 }
2266
2267 static HRESULT WINAPI fnIMultiLanguage_GetRfc1766FromLcid(
2268     IMultiLanguage* iface,
2269     LCID lcid,
2270     BSTR* pbstrRfc1766)
2271 {
2272     WCHAR buf[MAX_RFC1766_NAME];
2273
2274     TRACE("%p %04x %p\n", iface, lcid, pbstrRfc1766);
2275     if (!pbstrRfc1766)
2276         return E_INVALIDARG;
2277
2278     if (!lcid_to_rfc1766W( lcid, buf, MAX_RFC1766_NAME ))
2279     {
2280         *pbstrRfc1766 = SysAllocString( buf );
2281         return S_OK;
2282     }
2283     return E_FAIL;
2284 }
2285
2286 static HRESULT WINAPI fnIMultiLanguage_GetLcidFromRfc1766(
2287     IMultiLanguage* iface,
2288     LCID* pLocale,
2289     BSTR bstrRfc1766)
2290 {
2291     HRESULT hr;
2292     IEnumRfc1766 *rfc1766;
2293
2294     TRACE("%p %p %s\n", iface, pLocale, debugstr_w(bstrRfc1766));
2295
2296     if (!pLocale || !bstrRfc1766)
2297         return E_INVALIDARG;
2298
2299     hr = IMultiLanguage_EnumRfc1766(iface, &rfc1766);
2300     if (FAILED(hr))
2301         return hr;
2302
2303     hr = lcid_from_rfc1766(rfc1766, pLocale, bstrRfc1766);
2304
2305     IEnumRfc1766_Release(rfc1766);
2306     return hr;
2307 }
2308
2309 /******************************************************************************/
2310
2311 typedef struct tagEnumRfc1766_impl
2312 {
2313     IEnumRfc1766 IEnumRfc1766_iface;
2314     LONG ref;
2315     RFC1766INFO *info;
2316     DWORD total, pos;
2317 } EnumRfc1766_impl;
2318
2319 static inline EnumRfc1766_impl *impl_from_IEnumRfc1766( IEnumRfc1766 *iface )
2320 {
2321     return CONTAINING_RECORD( iface, EnumRfc1766_impl, IEnumRfc1766_iface );
2322 }
2323
2324 static HRESULT WINAPI fnIEnumRfc1766_QueryInterface(
2325         IEnumRfc1766 *iface,
2326         REFIID riid,
2327         void** ppvObject)
2328 {
2329     EnumRfc1766_impl *This = impl_from_IEnumRfc1766( iface );
2330
2331     TRACE("%p -> %s\n", This, debugstr_guid(riid) );
2332
2333     if (IsEqualGUID(riid, &IID_IUnknown)
2334         || IsEqualGUID(riid, &IID_IEnumRfc1766))
2335     {
2336         IEnumRfc1766_AddRef(iface);
2337         TRACE("Returning IID_IEnumRfc1766 %p ref = %d\n", This, This->ref);
2338         *ppvObject = &This->IEnumRfc1766_iface;
2339         return S_OK;
2340     }
2341
2342     WARN("(%p) -> (%s,%p), not found\n",This,debugstr_guid(riid),ppvObject);
2343     return E_NOINTERFACE;
2344 }
2345
2346 static ULONG WINAPI fnIEnumRfc1766_AddRef(
2347         IEnumRfc1766 *iface)
2348 {
2349     EnumRfc1766_impl *This = impl_from_IEnumRfc1766( iface );
2350     return InterlockedIncrement(&This->ref);
2351 }
2352
2353 static ULONG WINAPI fnIEnumRfc1766_Release(
2354         IEnumRfc1766 *iface)
2355 {
2356     EnumRfc1766_impl *This = impl_from_IEnumRfc1766( iface );
2357     ULONG ref = InterlockedDecrement(&This->ref);
2358
2359     TRACE("%p ref = %d\n", This, ref);
2360     if (ref == 0)
2361     {
2362         TRACE("Destroying %p\n", This);
2363         HeapFree(GetProcessHeap(), 0, This->info);
2364         HeapFree(GetProcessHeap(), 0, This);
2365     }
2366     return ref;
2367 }
2368
2369 static HRESULT WINAPI fnIEnumRfc1766_Clone(
2370         IEnumRfc1766 *iface,
2371         IEnumRfc1766 **ppEnum)
2372 {
2373     EnumRfc1766_impl *This = impl_from_IEnumRfc1766( iface );
2374
2375     FIXME("%p %p\n", This, ppEnum);
2376     return E_NOTIMPL;
2377 }
2378
2379 static  HRESULT WINAPI fnIEnumRfc1766_Next(
2380         IEnumRfc1766 *iface,
2381         ULONG celt,
2382         PRFC1766INFO rgelt,
2383         ULONG *pceltFetched)
2384 {
2385     ULONG i;
2386     EnumRfc1766_impl *This = impl_from_IEnumRfc1766( iface );
2387
2388     TRACE("%p %u %p %p\n", This, celt, rgelt, pceltFetched);
2389
2390     if (!pceltFetched) return S_FALSE;
2391     *pceltFetched = 0;
2392
2393     if (!rgelt) return S_FALSE;
2394
2395     if (This->pos + celt > This->total)
2396         celt = This->total - This->pos;
2397
2398     if (!celt) return S_FALSE;
2399
2400     memcpy(rgelt, This->info + This->pos, celt * sizeof(RFC1766INFO));
2401     *pceltFetched = celt;
2402     This->pos += celt;
2403
2404     for (i = 0; i < celt; i++)
2405     {
2406         TRACE("#%u: %08x %s %s\n",
2407               i, rgelt[i].lcid,
2408               wine_dbgstr_w(rgelt[i].wszRfc1766),
2409               wine_dbgstr_w(rgelt[i].wszLocaleName));
2410     }
2411     return S_OK;
2412 }
2413
2414 static HRESULT WINAPI fnIEnumRfc1766_Reset(
2415         IEnumRfc1766 *iface)
2416 {
2417     EnumRfc1766_impl *This = impl_from_IEnumRfc1766( iface );
2418
2419     TRACE("%p\n", This);
2420
2421     This->pos = 0;
2422     return S_OK;
2423 }
2424
2425 static  HRESULT WINAPI fnIEnumRfc1766_Skip(
2426         IEnumRfc1766 *iface,
2427         ULONG celt)
2428 {
2429     EnumRfc1766_impl *This = impl_from_IEnumRfc1766( iface );
2430
2431     TRACE("%p %u\n", This, celt);
2432
2433     if (celt >= This->total) return S_FALSE;
2434
2435     This->pos += celt;
2436     return S_OK;
2437 }
2438
2439 static const IEnumRfc1766Vtbl IEnumRfc1766_vtbl =
2440 {
2441     fnIEnumRfc1766_QueryInterface,
2442     fnIEnumRfc1766_AddRef,
2443     fnIEnumRfc1766_Release,
2444     fnIEnumRfc1766_Clone,
2445     fnIEnumRfc1766_Next,
2446     fnIEnumRfc1766_Reset,
2447     fnIEnumRfc1766_Skip
2448 };
2449
2450 struct enum_locales_data
2451 {
2452     RFC1766INFO *info;
2453     DWORD total, allocated;
2454 };
2455
2456 static BOOL CALLBACK enum_locales_proc(LPWSTR locale)
2457 {
2458     WCHAR *end;
2459     struct enum_locales_data *data = TlsGetValue(MLANG_tls_index);
2460     RFC1766INFO *info;
2461
2462     TRACE("%s\n", debugstr_w(locale));
2463
2464     if (data->total >= data->allocated)
2465     {
2466         data->allocated += 32;
2467         data->info = HeapReAlloc(GetProcessHeap(), 0, data->info, data->allocated * sizeof(RFC1766INFO));
2468         if (!data->info) return FALSE;
2469     }
2470
2471     info = &data->info[data->total];
2472
2473     info->lcid = strtolW(locale, &end, 16);
2474     if (*end) /* invalid number */
2475         return FALSE;
2476
2477     info->wszRfc1766[0] = 0;
2478     lcid_to_rfc1766W( info->lcid, info->wszRfc1766, MAX_RFC1766_NAME );
2479
2480     info->wszLocaleName[0] = 0;
2481     GetLocaleInfoW(info->lcid, LOCALE_SLANGUAGE, info->wszLocaleName, MAX_LOCALE_NAME);
2482     TRACE("ISO639: %s SLANGUAGE: %s\n", wine_dbgstr_w(info->wszRfc1766), wine_dbgstr_w(info->wszLocaleName));
2483     
2484     data->total++;
2485
2486     return TRUE;
2487 }
2488
2489 static HRESULT EnumRfc1766_create(LANGID LangId, IEnumRfc1766 **ppEnum)
2490 {
2491     EnumRfc1766_impl *rfc;
2492     struct enum_locales_data data;
2493
2494     TRACE("%04x, %p\n", LangId, ppEnum);
2495
2496     rfc = HeapAlloc( GetProcessHeap(), 0, sizeof(EnumRfc1766_impl) );
2497     rfc->IEnumRfc1766_iface.lpVtbl = &IEnumRfc1766_vtbl;
2498     rfc->ref = 1;
2499     rfc->pos = 0;
2500     rfc->total = 0;
2501
2502     data.total = 0;
2503     data.allocated = 160;
2504     data.info = HeapAlloc(GetProcessHeap(), 0, data.allocated * sizeof(RFC1766INFO));
2505     if (!data.info)
2506     {
2507         HeapFree(GetProcessHeap(), 0, rfc);
2508         return E_OUTOFMEMORY;
2509     }
2510
2511     TlsSetValue(MLANG_tls_index, &data);
2512     EnumSystemLocalesW(enum_locales_proc, 0/*LOCALE_SUPPORTED*/);
2513     TlsSetValue(MLANG_tls_index, NULL);
2514
2515     TRACE("enumerated %d rfc1766 structures\n", data.total);
2516
2517     if (!data.total)
2518     {
2519         HeapFree(GetProcessHeap(), 0, data.info);
2520         HeapFree(GetProcessHeap(), 0, rfc);
2521         return E_FAIL;
2522     }
2523
2524     rfc->info = data.info;
2525     rfc->total = data.total;
2526
2527     *ppEnum = &rfc->IEnumRfc1766_iface;
2528     return S_OK;
2529 }
2530
2531 static HRESULT WINAPI fnIMultiLanguage_EnumRfc1766(
2532     IMultiLanguage *iface,
2533     IEnumRfc1766 **ppEnumRfc1766)
2534 {
2535     MLang_impl *This = impl_from_IMultiLanguage( iface );
2536
2537     TRACE("%p %p\n", This, ppEnumRfc1766);
2538
2539     return EnumRfc1766_create(0, ppEnumRfc1766);
2540 }
2541
2542 /******************************************************************************/
2543
2544 static HRESULT WINAPI fnIMultiLanguage_GetRfc1766Info(
2545     IMultiLanguage* iface,
2546     LCID Locale,
2547     PRFC1766INFO pRfc1766Info)
2548 {
2549     LCTYPE type = LOCALE_SLANGUAGE;
2550
2551     TRACE("(%p, 0x%04x, %p)\n", iface, Locale, pRfc1766Info);
2552
2553     if (!pRfc1766Info)
2554         return E_INVALIDARG;
2555
2556     if ((PRIMARYLANGID(Locale) == LANG_ENGLISH) ||
2557         (PRIMARYLANGID(Locale) == LANG_CHINESE) ||
2558         (PRIMARYLANGID(Locale) == LANG_ARABIC)) {
2559
2560         if (!SUBLANGID(Locale))
2561             type = LOCALE_SENGLANGUAGE; /* suppress country */
2562     }
2563     else
2564     {
2565         if (!SUBLANGID(Locale)) {
2566             TRACE("SUBLANGID missing in 0x%04x\n", Locale);
2567             return E_FAIL;
2568         }
2569     }
2570
2571     pRfc1766Info->lcid = Locale;
2572     pRfc1766Info->wszRfc1766[0] = 0;
2573     pRfc1766Info->wszLocaleName[0] = 0;
2574
2575     if ((!lcid_to_rfc1766W(Locale, pRfc1766Info->wszRfc1766, MAX_RFC1766_NAME)) &&
2576         (GetLocaleInfoW(Locale, type, pRfc1766Info->wszLocaleName, MAX_LOCALE_NAME) > 0))
2577             return S_OK;
2578
2579     /* Locale not supported */
2580     return E_INVALIDARG;
2581 }
2582
2583 static HRESULT WINAPI fnIMultiLanguage_CreateConvertCharset(
2584     IMultiLanguage* iface,
2585     UINT uiSrcCodePage,
2586     UINT uiDstCodePage,
2587     DWORD dwProperty,
2588     IMLangConvertCharset** ppMLangConvertCharset)
2589 {
2590     FIXME("\n");
2591     return E_NOTIMPL;
2592 }
2593
2594 static const IMultiLanguageVtbl IMultiLanguage_vtbl =
2595 {
2596     fnIMultiLanguage_QueryInterface,
2597     fnIMultiLanguage_AddRef,
2598     fnIMultiLanguage_Release,
2599     fnIMultiLanguage_GetNumberOfCodePageInfo,
2600     fnIMultiLanguage_GetCodePageInfo,
2601     fnIMultiLanguage_GetFamilyCodePage,
2602     fnIMultiLanguage_EnumCodePages,
2603     fnIMultiLanguage_GetCharsetInfo,
2604     fnIMultiLanguage_IsConvertible,
2605     fnIMultiLanguage_ConvertString,
2606     fnIMultiLanguage_ConvertStringToUnicode,
2607     fnIMultiLanguage_ConvertStringFromUnicode,
2608     fnIMultiLanguage_ConvertStringReset,
2609     fnIMultiLanguage_GetRfc1766FromLcid,
2610     fnIMultiLanguage_GetLcidFromRfc1766,
2611     fnIMultiLanguage_EnumRfc1766,
2612     fnIMultiLanguage_GetRfc1766Info,
2613     fnIMultiLanguage_CreateConvertCharset,
2614 };
2615
2616
2617 /******************************************************************************/
2618
2619 static inline MLang_impl *impl_from_IMultiLanguage3( IMultiLanguage3 *iface )
2620 {
2621     return CONTAINING_RECORD( iface, MLang_impl, IMultiLanguage3_iface );
2622 }
2623
2624 static HRESULT WINAPI fnIMultiLanguage2_QueryInterface(
2625     IMultiLanguage3* iface,
2626     REFIID riid,
2627     void** ppvObject)
2628 {
2629     MLang_impl *This = impl_from_IMultiLanguage3( iface );
2630     return MLang_QueryInterface( This, riid, ppvObject );
2631 }
2632
2633 static ULONG WINAPI fnIMultiLanguage2_AddRef( IMultiLanguage3* iface )
2634 {
2635     MLang_impl *This = impl_from_IMultiLanguage3( iface );
2636     return MLang_AddRef( This );
2637 }
2638
2639 static ULONG WINAPI fnIMultiLanguage2_Release( IMultiLanguage3* iface )
2640 {
2641     MLang_impl *This = impl_from_IMultiLanguage3( iface );
2642     return MLang_Release( This );
2643 }
2644
2645 static HRESULT WINAPI fnIMultiLanguage2_GetNumberOfCodePageInfo(
2646     IMultiLanguage3* iface,
2647     UINT* pcCodePage)
2648 {
2649     MLang_impl *This = impl_from_IMultiLanguage3( iface );
2650
2651     TRACE("%p, %p\n", This, pcCodePage);
2652
2653     if (!pcCodePage) return E_INVALIDARG;
2654
2655     *pcCodePage = This->total_cp;
2656     return S_OK;
2657 }
2658
2659 static void fill_cp_info(const struct mlang_data *ml_data, UINT index, MIMECPINFO *mime_cp_info)
2660 {
2661     CHARSETINFO csi;
2662
2663     if (TranslateCharsetInfo((DWORD*)(DWORD_PTR)ml_data->family_codepage, &csi,
2664                              TCI_SRCCODEPAGE))
2665         mime_cp_info->bGDICharset = csi.ciCharset;
2666     else
2667         mime_cp_info->bGDICharset = DEFAULT_CHARSET;
2668
2669     mime_cp_info->dwFlags = ml_data->mime_cp_info[index].flags;
2670     mime_cp_info->uiCodePage = ml_data->mime_cp_info[index].cp;
2671     mime_cp_info->uiFamilyCodePage = ml_data->family_codepage;
2672     MultiByteToWideChar(CP_ACP, 0, ml_data->mime_cp_info[index].description, -1,
2673                         mime_cp_info->wszDescription, sizeof(mime_cp_info->wszDescription)/sizeof(WCHAR));
2674     MultiByteToWideChar(CP_ACP, 0, ml_data->mime_cp_info[index].web_charset, -1,
2675                         mime_cp_info->wszWebCharset, sizeof(mime_cp_info->wszWebCharset)/sizeof(WCHAR));
2676     MultiByteToWideChar(CP_ACP, 0, ml_data->mime_cp_info[index].header_charset, -1,
2677                         mime_cp_info->wszHeaderCharset, sizeof(mime_cp_info->wszHeaderCharset)/sizeof(WCHAR));
2678     MultiByteToWideChar(CP_ACP, 0, ml_data->mime_cp_info[index].body_charset, -1,
2679                         mime_cp_info->wszBodyCharset, sizeof(mime_cp_info->wszBodyCharset)/sizeof(WCHAR));
2680
2681     MultiByteToWideChar(CP_ACP, 0, ml_data->fixed_font, -1,
2682         mime_cp_info->wszFixedWidthFont, sizeof(mime_cp_info->wszFixedWidthFont)/sizeof(WCHAR));
2683     MultiByteToWideChar(CP_ACP, 0, ml_data->proportional_font, -1,
2684         mime_cp_info->wszProportionalFont, sizeof(mime_cp_info->wszProportionalFont)/sizeof(WCHAR));
2685
2686     TRACE("%08x %u %u %s %s %s %s %s %s %d\n",
2687           mime_cp_info->dwFlags, mime_cp_info->uiCodePage,
2688           mime_cp_info->uiFamilyCodePage,
2689           wine_dbgstr_w(mime_cp_info->wszDescription),
2690           wine_dbgstr_w(mime_cp_info->wszWebCharset),
2691           wine_dbgstr_w(mime_cp_info->wszHeaderCharset),
2692           wine_dbgstr_w(mime_cp_info->wszBodyCharset),
2693           wine_dbgstr_w(mime_cp_info->wszFixedWidthFont),
2694           wine_dbgstr_w(mime_cp_info->wszProportionalFont),
2695           mime_cp_info->bGDICharset);
2696 }
2697
2698 static HRESULT WINAPI fnIMultiLanguage2_GetCodePageInfo(
2699     IMultiLanguage3* iface,
2700     UINT uiCodePage,
2701     LANGID LangId,
2702     PMIMECPINFO pCodePageInfo)
2703 {
2704     UINT i, n;
2705     MLang_impl *This = impl_from_IMultiLanguage3( iface );
2706
2707     TRACE("%p, %u, %04x, %p\n", This, uiCodePage, LangId, pCodePageInfo);
2708
2709     for (i = 0; i < sizeof(mlang_data)/sizeof(mlang_data[0]); i++)
2710     {
2711         for (n = 0; n < mlang_data[i].number_of_cp; n++)
2712         {
2713             if (mlang_data[i].mime_cp_info[n].cp == uiCodePage)
2714             {
2715                 fill_cp_info(&mlang_data[i], n, pCodePageInfo);
2716                 return S_OK;
2717             }
2718         }
2719     }
2720
2721     return S_FALSE;
2722 }
2723
2724 static HRESULT WINAPI fnIMultiLanguage2_GetFamilyCodePage(
2725     IMultiLanguage3* iface,
2726     UINT uiCodePage,
2727     UINT* puiFamilyCodePage)
2728 {
2729     return GetFamilyCodePage(uiCodePage, puiFamilyCodePage);
2730 }
2731
2732 static HRESULT WINAPI fnIMultiLanguage2_EnumCodePages(
2733     IMultiLanguage3* iface,
2734     DWORD grfFlags,
2735     LANGID LangId,
2736     IEnumCodePage** ppEnumCodePage)
2737 {
2738     MLang_impl *This = impl_from_IMultiLanguage3( iface );
2739
2740     TRACE("%p %08x %04x %p\n", This, grfFlags, LangId, ppEnumCodePage);
2741
2742     return EnumCodePage_create( This, grfFlags, LangId, ppEnumCodePage );
2743 }
2744
2745 static HRESULT WINAPI fnIMultiLanguage2_GetCharsetInfo(
2746     IMultiLanguage3* iface,
2747     BSTR Charset,
2748     PMIMECSETINFO pCharsetInfo)
2749 {
2750     UINT i, n;
2751     MLang_impl *This = impl_from_IMultiLanguage3( iface );
2752
2753     TRACE("%p %s %p\n", This, debugstr_w(Charset), pCharsetInfo);
2754
2755     if (!pCharsetInfo) return E_FAIL;
2756
2757     for (i = 0; i < sizeof(mlang_data)/sizeof(mlang_data[0]); i++)
2758     {
2759         for (n = 0; n < mlang_data[i].number_of_cp; n++)
2760         {
2761             WCHAR csetW[MAX_MIMECSET_NAME];
2762
2763             MultiByteToWideChar(CP_ACP, 0, mlang_data[i].mime_cp_info[n].web_charset, -1, csetW, MAX_MIMECSET_NAME);
2764             if (!lstrcmpiW(Charset, csetW))
2765             {
2766                 pCharsetInfo->uiCodePage = mlang_data[i].family_codepage;
2767                 pCharsetInfo->uiInternetEncoding = mlang_data[i].mime_cp_info[n].cp;
2768                 strcpyW(pCharsetInfo->wszCharset, csetW);
2769                 return S_OK;
2770             }
2771         }
2772     }
2773
2774     /* FIXME:
2775      * Since we do not support charsets like iso-2022-jp and do not have
2776      * them in our database as a primary (web_charset) encoding this loop
2777      * does an attempt to 'approximate' charset name by header_charset.
2778      */
2779     for (i = 0; i < sizeof(mlang_data)/sizeof(mlang_data[0]); i++)
2780     {
2781         for (n = 0; n < mlang_data[i].number_of_cp; n++)
2782         {
2783             WCHAR csetW[MAX_MIMECSET_NAME];
2784
2785             MultiByteToWideChar(CP_ACP, 0, mlang_data[i].mime_cp_info[n].header_charset, -1, csetW, MAX_MIMECSET_NAME);
2786             if (!lstrcmpiW(Charset, csetW))
2787             {
2788                 pCharsetInfo->uiCodePage = mlang_data[i].family_codepage;
2789                 pCharsetInfo->uiInternetEncoding = mlang_data[i].mime_cp_info[n].cp;
2790                 strcpyW(pCharsetInfo->wszCharset, csetW);
2791                 return S_OK;
2792             }
2793         }
2794     }
2795
2796     return E_FAIL;
2797 }
2798
2799 static HRESULT WINAPI fnIMultiLanguage2_IsConvertible(
2800     IMultiLanguage3* iface,
2801     DWORD dwSrcEncoding,
2802     DWORD dwDstEncoding)
2803 {
2804     return IsConvertINetStringAvailable(dwSrcEncoding, dwDstEncoding);
2805 }
2806
2807 static HRESULT WINAPI fnIMultiLanguage2_ConvertString(
2808     IMultiLanguage3* iface,
2809     DWORD* pdwMode,
2810     DWORD dwSrcEncoding,
2811     DWORD dwDstEncoding,
2812     BYTE* pSrcStr,
2813     UINT* pcSrcSize,
2814     BYTE* pDstStr,
2815     UINT* pcDstSize)
2816 {
2817     return ConvertINetString(pdwMode, dwSrcEncoding, dwDstEncoding,
2818         (LPCSTR)pSrcStr, (LPINT)pcSrcSize, (LPSTR)pDstStr, (LPINT)pcDstSize);
2819 }
2820
2821 static HRESULT WINAPI fnIMultiLanguage2_ConvertStringToUnicode(
2822     IMultiLanguage3* iface,
2823     DWORD* pdwMode,
2824     DWORD dwEncoding,
2825     CHAR* pSrcStr,
2826     UINT* pcSrcSize,
2827     WCHAR* pDstStr,
2828     UINT* pcDstSize)
2829 {
2830     return ConvertINetMultiByteToUnicode(pdwMode, dwEncoding,
2831         pSrcStr, (LPINT)pcSrcSize, pDstStr, (LPINT)pcDstSize);
2832 }
2833
2834 static HRESULT WINAPI fnIMultiLanguage2_ConvertStringFromUnicode(
2835     IMultiLanguage3* iface,
2836     DWORD* pdwMode,
2837     DWORD dwEncoding,
2838     WCHAR* pSrcStr,
2839     UINT* pcSrcSize,
2840     CHAR* pDstStr,
2841     UINT* pcDstSize)
2842 {
2843     return ConvertINetUnicodeToMultiByte(pdwMode, dwEncoding,
2844         pSrcStr, (LPINT)pcSrcSize, pDstStr, (LPINT)pcDstSize);
2845 }
2846
2847 static HRESULT WINAPI fnIMultiLanguage2_ConvertStringReset(
2848     IMultiLanguage3* iface)
2849 {
2850     FIXME("\n");
2851     return E_NOTIMPL;
2852 }
2853
2854 static HRESULT WINAPI fnIMultiLanguage2_GetRfc1766FromLcid(
2855     IMultiLanguage3* iface,
2856     LCID lcid,
2857     BSTR* pbstrRfc1766)
2858 {
2859     WCHAR buf[MAX_RFC1766_NAME];
2860
2861     TRACE("%p %04x %p\n", iface, lcid, pbstrRfc1766);
2862     if (!pbstrRfc1766)
2863         return E_INVALIDARG;
2864
2865     if (!lcid_to_rfc1766W( lcid, buf, MAX_RFC1766_NAME ))
2866     {
2867         *pbstrRfc1766 = SysAllocString( buf );
2868         return S_OK;
2869     }
2870     return E_FAIL;
2871 }
2872
2873 static HRESULT WINAPI fnIMultiLanguage2_GetLcidFromRfc1766(
2874     IMultiLanguage3* iface,
2875     LCID* pLocale,
2876     BSTR bstrRfc1766)
2877 {
2878     HRESULT hr;
2879     IEnumRfc1766 *rfc1766;
2880
2881     TRACE("%p %p %s\n", iface, pLocale, debugstr_w(bstrRfc1766));
2882
2883     if (!pLocale || !bstrRfc1766)
2884         return E_INVALIDARG;
2885
2886     hr = IMultiLanguage2_EnumRfc1766(iface, 0, &rfc1766);
2887     if (FAILED(hr))
2888         return hr;
2889
2890     hr = lcid_from_rfc1766(rfc1766, pLocale, bstrRfc1766);
2891
2892     IEnumRfc1766_Release(rfc1766);
2893     return hr;
2894 }
2895
2896 static HRESULT WINAPI fnIMultiLanguage2_EnumRfc1766(
2897     IMultiLanguage3* iface,
2898     LANGID LangId,
2899     IEnumRfc1766** ppEnumRfc1766)
2900 {
2901     MLang_impl *This = impl_from_IMultiLanguage3( iface );
2902
2903     TRACE("%p %p\n", This, ppEnumRfc1766);
2904
2905     return EnumRfc1766_create(LangId, ppEnumRfc1766);
2906 }
2907
2908 static HRESULT WINAPI fnIMultiLanguage2_GetRfc1766Info(
2909     IMultiLanguage3* iface,
2910     LCID Locale,
2911     LANGID LangId,
2912     PRFC1766INFO pRfc1766Info)
2913 {
2914     static LANGID last_lang = -1;
2915     LCTYPE type = LOCALE_SLANGUAGE;
2916
2917     TRACE("(%p, 0x%04x, 0x%04x, %p)\n", iface, Locale, LangId, pRfc1766Info);
2918
2919     if (!pRfc1766Info)
2920         return E_INVALIDARG;
2921
2922     if ((PRIMARYLANGID(Locale) == LANG_ENGLISH) ||
2923         (PRIMARYLANGID(Locale) == LANG_CHINESE) ||
2924         (PRIMARYLANGID(Locale) == LANG_ARABIC)) {
2925
2926         if (!SUBLANGID(Locale))
2927             type = LOCALE_SENGLANGUAGE; /* suppress country */
2928     }
2929     else
2930     {
2931         if (!SUBLANGID(Locale)) {
2932             TRACE("SUBLANGID missing in 0x%04x\n", Locale);
2933             return E_FAIL;
2934         }
2935     }
2936
2937     pRfc1766Info->lcid = Locale;
2938     pRfc1766Info->wszRfc1766[0] = 0;
2939     pRfc1766Info->wszLocaleName[0] = 0;
2940
2941     if ((PRIMARYLANGID(LangId) != LANG_ENGLISH) &&
2942         (last_lang != LangId)) {
2943         FIXME("Only English names supported (requested: 0x%04x)\n", LangId);
2944         last_lang = LangId;
2945     }
2946
2947     if ((!lcid_to_rfc1766W(Locale, pRfc1766Info->wszRfc1766, MAX_RFC1766_NAME)) &&
2948         (GetLocaleInfoW(Locale, type, pRfc1766Info->wszLocaleName, MAX_LOCALE_NAME) > 0))
2949             return S_OK;
2950
2951     /* Locale not supported */
2952     return E_INVALIDARG;
2953 }
2954
2955 static HRESULT WINAPI fnIMultiLanguage2_CreateConvertCharset(
2956     IMultiLanguage3* iface,
2957     UINT uiSrcCodePage,
2958     UINT uiDstCodePage,
2959     DWORD dwProperty,
2960     IMLangConvertCharset** ppMLangConvertCharset)
2961 {
2962     FIXME("\n");
2963     return E_NOTIMPL;
2964 }
2965
2966 static HRESULT WINAPI fnIMultiLanguage2_ConvertStringInIStream(
2967     IMultiLanguage3* iface,
2968     DWORD* pdwMode,
2969     DWORD dwFlag,
2970     WCHAR* lpFallBack,
2971     DWORD dwSrcEncoding,
2972     DWORD dwDstEncoding,
2973     IStream* pstmIn,
2974     IStream* pstmOut)
2975 {
2976     char *src, *dst = NULL;
2977     INT srclen, dstlen;
2978     STATSTG stat;
2979     HRESULT hr;
2980
2981     TRACE("%p %0x8 %s %u %u %p %p\n",
2982           pdwMode, dwFlag, debugstr_w(lpFallBack), dwSrcEncoding, dwDstEncoding, pstmIn, pstmOut);
2983
2984     FIXME("dwFlag and lpFallBack not handled\n");
2985
2986     hr = IStream_Stat(pstmIn, &stat, STATFLAG_NONAME);
2987     if (FAILED(hr)) return hr;
2988
2989     if (stat.cbSize.QuadPart > MAXLONG) return E_INVALIDARG;
2990     if (!(src = HeapAlloc(GetProcessHeap(), 0, stat.cbSize.QuadPart))) return E_OUTOFMEMORY;
2991
2992     hr = IStream_Read(pstmIn, src, stat.cbSize.QuadPart, (ULONG *)&srclen);
2993     if (FAILED(hr)) goto exit;
2994
2995     hr = ConvertINetString(pdwMode, dwSrcEncoding, dwDstEncoding, src, &srclen, NULL, &dstlen);
2996     if (FAILED(hr)) goto exit;
2997
2998     if (!(dst = HeapAlloc(GetProcessHeap(), 0, dstlen)))
2999     {
3000         hr = E_OUTOFMEMORY;
3001         goto exit;
3002     }
3003     hr = ConvertINetString(pdwMode, dwSrcEncoding, dwDstEncoding, src, &srclen, dst, &dstlen);
3004     if (FAILED(hr)) goto exit;
3005
3006     hr = IStream_Write(pstmOut, dst, dstlen, NULL);
3007
3008 exit:
3009     HeapFree(GetProcessHeap(), 0, src);
3010     HeapFree(GetProcessHeap(), 0, dst);
3011     return hr;
3012 }
3013
3014 static HRESULT WINAPI fnIMultiLanguage2_ConvertStringToUnicodeEx(
3015     IMultiLanguage3* iface,
3016     DWORD* pdwMode,
3017     DWORD dwEncoding,
3018     CHAR* pSrcStr,
3019     UINT* pcSrcSize,
3020     WCHAR* pDstStr,
3021     UINT* pcDstSize,
3022     DWORD dwFlag,
3023     WCHAR* lpFallBack)
3024 {
3025     if (dwFlag || lpFallBack)
3026         FIXME("Ignoring dwFlag (0x%x/%d) and lpFallBack (%p)\n",
3027                 dwFlag, dwFlag, lpFallBack);
3028
3029     return ConvertINetMultiByteToUnicode(pdwMode, dwEncoding,
3030         pSrcStr, (LPINT)pcSrcSize, pDstStr, (LPINT)pcDstSize);
3031 }
3032
3033 /*****************************************************************************
3034  * MultiLanguage2::ConvertStringToUnicodeEx
3035  *
3036  * Translates the multibyte string from the specified code page to Unicode.
3037  *
3038  * PARAMS
3039  *   see ConvertStringToUnicode
3040  *   dwFlag 
3041  *   lpFallBack if dwFlag contains MLCONVCHARF_USEDEFCHAR, lpFallBack string used
3042  *              instead unconvertible characters.
3043  *
3044  * RETURNS
3045  *   S_OK     Success.
3046  *   S_FALSE  The conversion is not supported.
3047  *   E_FAIL   Some error has occurred.
3048  *
3049  * TODO: handle dwFlag and lpFallBack
3050 */
3051 static HRESULT WINAPI fnIMultiLanguage2_ConvertStringFromUnicodeEx(
3052     IMultiLanguage3* This,
3053     DWORD* pdwMode,
3054     DWORD dwEncoding,
3055     WCHAR* pSrcStr,
3056     UINT* pcSrcSize,
3057     CHAR* pDstStr,
3058     UINT* pcDstSize,
3059     DWORD dwFlag,
3060     WCHAR* lpFallBack)
3061 {
3062     FIXME("\n");
3063     return ConvertINetUnicodeToMultiByte(pdwMode, dwEncoding,
3064         pSrcStr, (LPINT)pcSrcSize, pDstStr, (LPINT)pcDstSize);
3065 }
3066
3067 static HRESULT WINAPI fnIMultiLanguage2_DetectCodepageInIStream(
3068     IMultiLanguage3* iface,
3069     DWORD dwFlag,
3070     DWORD dwPrefWinCodePage,
3071     IStream* pstmIn,
3072     DetectEncodingInfo* lpEncoding,
3073     INT* pnScores)
3074 {
3075     FIXME("\n");
3076     return E_NOTIMPL;
3077 }
3078
3079 static HRESULT WINAPI fnIMultiLanguage2_DetectInputCodepage(
3080     IMultiLanguage3* iface,
3081     DWORD dwFlag,
3082     DWORD dwPrefWinCodePage,
3083     CHAR* pSrcStr,
3084     INT* pcSrcSize,
3085     DetectEncodingInfo* lpEncoding,
3086     INT* pnScores)
3087 {
3088     FIXME("\n");
3089     return E_NOTIMPL;
3090 }
3091
3092 static HRESULT WINAPI fnIMultiLanguage2_ValidateCodePage(
3093     IMultiLanguage3* iface,
3094     UINT uiCodePage,
3095     HWND hwnd)
3096 {
3097     return IMultiLanguage2_ValidateCodePageEx(iface,uiCodePage,hwnd,0);
3098 }
3099
3100 static HRESULT WINAPI fnIMultiLanguage2_GetCodePageDescription(
3101     IMultiLanguage3* iface,
3102     UINT uiCodePage,
3103     LCID lcid,
3104     LPWSTR lpWideCharStr,
3105     int cchWideChar)
3106 {
3107     /* Find first instance */
3108     unsigned int i,n;
3109
3110     TRACE ("%u, %04x, %p, %d\n", uiCodePage, lcid, lpWideCharStr, cchWideChar);
3111     for (i = 0; i < sizeof(mlang_data)/sizeof(mlang_data[0]); i++)
3112     {
3113         for (n = 0; n < mlang_data[i].number_of_cp; n++)
3114         {
3115             if (mlang_data[i].mime_cp_info[n].cp == uiCodePage)
3116             {
3117                 MultiByteToWideChar(CP_ACP, 0,
3118                                     mlang_data[i].mime_cp_info[n].description,
3119                                     -1, lpWideCharStr, cchWideChar);
3120                 return S_OK;
3121             }
3122         }
3123     }
3124
3125     return S_FALSE;
3126 }
3127
3128 static HRESULT WINAPI fnIMultiLanguage2_IsCodePageInstallable(
3129     IMultiLanguage3* iface,
3130     UINT uiCodePage)
3131 {
3132     TRACE("%u\n", uiCodePage);
3133
3134     /* FIXME: the installable set is usually larger than the set of valid codepages */
3135     return IMultiLanguage2_ValidateCodePageEx(iface, uiCodePage, NULL, CPIOD_PEEK);
3136 }
3137
3138 static HRESULT WINAPI fnIMultiLanguage2_SetMimeDBSource(
3139     IMultiLanguage3* iface,
3140     MIMECONTF dwSource)
3141 {
3142     FIXME("0x%08x\n", dwSource);
3143     return S_OK;
3144 }
3145
3146 static HRESULT WINAPI fnIMultiLanguage2_GetNumberOfScripts(
3147     IMultiLanguage3* iface,
3148     UINT* pnScripts)
3149 {
3150     MLang_impl *This = impl_from_IMultiLanguage3( iface );
3151
3152     TRACE("%p %p\n", This, pnScripts);
3153
3154     if (!pnScripts) return S_FALSE;
3155
3156     *pnScripts = This->total_scripts;
3157     return S_OK;
3158 }
3159
3160 static HRESULT WINAPI fnIMultiLanguage2_EnumScripts(
3161     IMultiLanguage3* iface,
3162     DWORD dwFlags,
3163     LANGID LangId,
3164     IEnumScript** ppEnumScript)
3165 {
3166     MLang_impl *This = impl_from_IMultiLanguage3( iface );
3167
3168     TRACE("%p %08x %04x %p\n", This, dwFlags, LangId, ppEnumScript);
3169
3170     return EnumScript_create( This, dwFlags, LangId, ppEnumScript );
3171 }
3172
3173 static HRESULT WINAPI fnIMultiLanguage2_ValidateCodePageEx(
3174     IMultiLanguage3* iface,
3175     UINT uiCodePage,
3176     HWND hwnd,
3177     DWORD dwfIODControl)
3178 {
3179     int i;
3180     MLang_impl *This = impl_from_IMultiLanguage3( iface );
3181
3182     TRACE("%p %u %p %08x\n", This, uiCodePage, hwnd, dwfIODControl);
3183
3184     /* quick check for kernel32 supported code pages */
3185     if (IsValidCodePage(uiCodePage))
3186         return S_OK;
3187
3188     /* check for mlang supported code pages */
3189     for (i = 0; i < sizeof(mlang_data)/sizeof(mlang_data[0]); i++)
3190     {
3191         int n;
3192         for (n = 0; n < mlang_data[i].number_of_cp; n++)
3193         {
3194             if (mlang_data[i].mime_cp_info[n].cp == uiCodePage)
3195                 return S_OK;
3196         }
3197     }
3198
3199     if (dwfIODControl != CPIOD_PEEK)
3200         FIXME("Request to install codepage language pack not handled\n");
3201
3202     return S_FALSE;
3203 }
3204
3205 static HRESULT WINAPI fnIMultiLanguage3_DetectOutboundCodePage(
3206     IMultiLanguage3 *iface,
3207     DWORD dwFlags,
3208     LPCWSTR lpWideCharStr,
3209     UINT cchWideChar,
3210     UINT *puiPreferredCodePages,
3211     UINT nPreferredCodePages,
3212     UINT *puiDetectedCodePages,
3213     UINT *pnDetectedCodePages,
3214     WCHAR *lpSpecialChar)
3215 {
3216     MLang_impl *This = impl_from_IMultiLanguage3( iface );
3217
3218     FIXME("(%p)->(%08x %s %u %p %u %p %p %p)\n", This, dwFlags, debugstr_w(lpWideCharStr),
3219           cchWideChar, puiPreferredCodePages, nPreferredCodePages, puiDetectedCodePages,
3220           pnDetectedCodePages, lpSpecialChar);
3221     return E_NOTIMPL;
3222 }
3223
3224 static HRESULT WINAPI fnIMultiLanguage3_DetectOutboundCodePageInIStream(
3225     IMultiLanguage3 *iface,
3226     DWORD dwFlags,
3227     IStream *pStrIn,
3228     UINT *puiPreferredCodePages,
3229     UINT nPreferredCodePages,
3230     UINT *puiDetectedCodePages,
3231     UINT *pnDetectedCodePages,
3232     WCHAR *lpSpecialChar)
3233 {
3234     MLang_impl *This = impl_from_IMultiLanguage3( iface );
3235
3236     FIXME("(%p)->(%08x %p %p %u %p %p %p)\n", This, dwFlags, pStrIn,
3237           puiPreferredCodePages, nPreferredCodePages, puiDetectedCodePages,
3238           pnDetectedCodePages, lpSpecialChar);
3239     return E_NOTIMPL;
3240 }
3241
3242 static const IMultiLanguage3Vtbl IMultiLanguage3_vtbl =
3243 {
3244     fnIMultiLanguage2_QueryInterface,
3245     fnIMultiLanguage2_AddRef,
3246     fnIMultiLanguage2_Release,
3247     fnIMultiLanguage2_GetNumberOfCodePageInfo,
3248     fnIMultiLanguage2_GetCodePageInfo,
3249     fnIMultiLanguage2_GetFamilyCodePage,
3250     fnIMultiLanguage2_EnumCodePages,
3251     fnIMultiLanguage2_GetCharsetInfo,
3252     fnIMultiLanguage2_IsConvertible,
3253     fnIMultiLanguage2_ConvertString,
3254     fnIMultiLanguage2_ConvertStringToUnicode,
3255     fnIMultiLanguage2_ConvertStringFromUnicode,
3256     fnIMultiLanguage2_ConvertStringReset,
3257     fnIMultiLanguage2_GetRfc1766FromLcid,
3258     fnIMultiLanguage2_GetLcidFromRfc1766,
3259     fnIMultiLanguage2_EnumRfc1766,
3260     fnIMultiLanguage2_GetRfc1766Info,
3261     fnIMultiLanguage2_CreateConvertCharset,
3262     fnIMultiLanguage2_ConvertStringInIStream,
3263     fnIMultiLanguage2_ConvertStringToUnicodeEx,
3264     fnIMultiLanguage2_ConvertStringFromUnicodeEx,
3265     fnIMultiLanguage2_DetectCodepageInIStream,
3266     fnIMultiLanguage2_DetectInputCodepage,
3267     fnIMultiLanguage2_ValidateCodePage,
3268     fnIMultiLanguage2_GetCodePageDescription,
3269     fnIMultiLanguage2_IsCodePageInstallable,
3270     fnIMultiLanguage2_SetMimeDBSource,
3271     fnIMultiLanguage2_GetNumberOfScripts,
3272     fnIMultiLanguage2_EnumScripts,
3273     fnIMultiLanguage2_ValidateCodePageEx,
3274     fnIMultiLanguage3_DetectOutboundCodePage,
3275     fnIMultiLanguage3_DetectOutboundCodePageInIStream
3276 };
3277
3278 /******************************************************************************/
3279
3280 static inline MLang_impl *impl_from_IMLangFontLink2( IMLangFontLink2 *iface )
3281 {
3282     return CONTAINING_RECORD( iface, MLang_impl, IMLangFontLink2_iface );
3283 }
3284
3285 static HRESULT WINAPI fnIMLangFontLink2_QueryInterface(
3286     IMLangFontLink2 * iface,
3287     REFIID riid,
3288     void** ppvObject)
3289 {
3290     MLang_impl *This = impl_from_IMLangFontLink2( iface );
3291     return MLang_QueryInterface( This, riid, ppvObject );
3292 }
3293
3294 static ULONG WINAPI fnIMLangFontLink2_AddRef( IMLangFontLink2* iface )
3295 {
3296     MLang_impl *This = impl_from_IMLangFontLink2( iface );
3297     return MLang_AddRef( This );
3298 }
3299
3300 static ULONG WINAPI fnIMLangFontLink2_Release( IMLangFontLink2* iface )
3301 {
3302     MLang_impl *This = impl_from_IMLangFontLink2( iface );
3303     return MLang_Release( This );
3304 }
3305
3306 static HRESULT WINAPI fnIMLangFontLink2_GetCharCodePages( IMLangFontLink2* This,
3307         WCHAR chSrc, DWORD *pdwCodePages)
3308 {
3309     FIXME("(%p)->%s %p\n",This, debugstr_wn(&chSrc,1),pdwCodePages);
3310     return E_NOTIMPL;
3311 }
3312
3313 static HRESULT WINAPI fnIMLangFontLink2_GetStrCodePages( IMLangFontLink2* This,
3314         const WCHAR *pszSrc, LONG cchSrc, DWORD dwPriorityCodePages,
3315         DWORD *pdwCodePages, LONG *pcchCodePages)
3316 {
3317     return fnIMLangFontLink_GetStrCodePages((IMLangFontLink *)This,
3318             pszSrc, cchSrc, dwPriorityCodePages, pdwCodePages, pcchCodePages);
3319 }
3320
3321 static HRESULT WINAPI fnIMLangFontLink2_CodePageToCodePages(IMLangFontLink2* This,
3322         UINT uCodePage,
3323         DWORD *pdwCodePages)
3324 {
3325     FIXME("(%p)->%i %p\n",This, uCodePage, pdwCodePages);
3326     return E_NOTIMPL;
3327 }
3328
3329 static HRESULT WINAPI fnIMLangFontLink2_CodePagesToCodePage(IMLangFontLink2* This,
3330         DWORD dwCodePages, UINT uDefaultCodePage, UINT *puCodePage)
3331 {
3332     FIXME("(%p)->%i %i %p\n",This, dwCodePages, uDefaultCodePage, puCodePage);
3333     return E_NOTIMPL;
3334 }
3335
3336 static HRESULT WINAPI fnIMLangFontLink2_GetFontCodePages(IMLangFontLink2* This,
3337         HDC hDC, HFONT hFont, DWORD *pdwCodePages)
3338 {
3339     FIXME("(%p)->%p %p %p\n",This, hDC, hFont, pdwCodePages);
3340     return E_NOTIMPL;
3341 }
3342
3343 static HRESULT WINAPI fnIMLangFontLink2_ReleaseFont(IMLangFontLink2* This,
3344         HFONT hFont)
3345 {
3346     FIXME("(%p)->%p\n",This, hFont);
3347     return E_NOTIMPL;
3348 }
3349
3350 static HRESULT WINAPI fnIMLangFontLink2_ResetFontMapping(IMLangFontLink2* This)
3351 {
3352     FIXME("(%p)->\n",This);
3353     return E_NOTIMPL;
3354 }
3355
3356 static HRESULT WINAPI fnIMLangFontLink2_MapFont(IMLangFontLink2* This,
3357         HDC hDC, DWORD dwCodePages, WCHAR chSrc, HFONT *pFont)
3358 {
3359     FIXME("(%p)->%p %i %s %p\n",This, hDC, dwCodePages, debugstr_wn(&chSrc,1), pFont);
3360     return E_NOTIMPL;
3361 }
3362
3363 static HRESULT WINAPI fnIMLangFontLink2_GetFontUnicodeRanges(IMLangFontLink2* This,
3364         HDC hDC, UINT *puiRanges, UNICODERANGE *pUranges)
3365 {
3366     DWORD size;
3367     GLYPHSET *gs;
3368
3369     TRACE("(%p)->%p %p %p\n", This, hDC, puiRanges, pUranges);
3370
3371     if (!puiRanges) return E_INVALIDARG;
3372     if (!(size = GetFontUnicodeRanges(hDC, NULL))) return E_FAIL;
3373     if (!(gs = HeapAlloc(GetProcessHeap(), 0, size))) return E_OUTOFMEMORY;
3374
3375     GetFontUnicodeRanges(hDC, gs);
3376     *puiRanges = gs->cRanges;
3377     if (pUranges)
3378     {
3379         UINT i;
3380         for (i = 0; i < gs->cRanges; i++)
3381         {
3382             if (i >= *puiRanges) break;
3383             pUranges[i].wcFrom = gs->ranges[i].wcLow;
3384             pUranges[i].wcTo   = gs->ranges[i].wcLow + gs->ranges[i].cGlyphs;
3385         }
3386         *puiRanges = i;
3387     }
3388     HeapFree(GetProcessHeap(), 0, gs);
3389     return S_OK;
3390 }
3391
3392 static HRESULT WINAPI fnIMLangFontLink2_GetScriptFontInfo(IMLangFontLink2* This,
3393         SCRIPT_ID sid, DWORD dwFlags, UINT *puiFonts,
3394         SCRIPTFONTINFO *pScriptFont)
3395 {
3396     UINT i, j;
3397
3398     TRACE("(%p)->%u %x %p %p\n", This, sid, dwFlags, puiFonts, pScriptFont);
3399
3400     if (!dwFlags) dwFlags = SCRIPTCONTF_PROPORTIONAL_FONT;
3401
3402     for (i = 0, j = 0; i < sizeof(mlang_data)/sizeof(mlang_data[0]); i++)
3403     {
3404         if (sid == mlang_data[i].sid)
3405         {
3406             if (pScriptFont)
3407             {
3408                 if (j >= *puiFonts) break;
3409
3410                 pScriptFont[j].scripts = 1 << mlang_data[i].sid;
3411                 if (dwFlags == SCRIPTCONTF_FIXED_FONT)
3412                 {
3413                     MultiByteToWideChar(CP_ACP, 0, mlang_data[i].fixed_font, -1,
3414                         pScriptFont[j].wszFont, MAX_MIMEFACE_NAME);
3415                 }
3416                 else if (dwFlags == SCRIPTCONTF_PROPORTIONAL_FONT)
3417                 {
3418                     MultiByteToWideChar(CP_ACP, 0, mlang_data[i].proportional_font, -1,
3419                         pScriptFont[j].wszFont, MAX_MIMEFACE_NAME);
3420                 }
3421             }
3422             j++;
3423         }
3424     }
3425     *puiFonts = j;
3426     return S_OK;
3427 }
3428
3429 static HRESULT WINAPI fnIMLangFontLink2_CodePageToScriptID(IMLangFontLink2* This,
3430         UINT uiCodePage, SCRIPT_ID *pSid)
3431 {
3432     UINT i;
3433
3434     TRACE("(%p)->%i %p\n", This, uiCodePage, pSid);
3435
3436     if (uiCodePage == CP_UNICODE) return E_FAIL;
3437
3438     for (i = 0; i < sizeof(mlang_data)/sizeof(mlang_data[0]); i++)
3439     {
3440         if (uiCodePage == mlang_data[i].family_codepage)
3441         {
3442             if (pSid) *pSid = mlang_data[i].sid;
3443             return S_OK;
3444         }
3445     }
3446     return E_FAIL;
3447 }
3448
3449 static const IMLangFontLink2Vtbl IMLangFontLink2_vtbl =
3450 {
3451     fnIMLangFontLink2_QueryInterface,
3452     fnIMLangFontLink2_AddRef,
3453     fnIMLangFontLink2_Release,
3454     fnIMLangFontLink2_GetCharCodePages,
3455     fnIMLangFontLink2_GetStrCodePages,
3456     fnIMLangFontLink2_CodePageToCodePages,
3457     fnIMLangFontLink2_CodePagesToCodePage,
3458     fnIMLangFontLink2_GetFontCodePages,
3459     fnIMLangFontLink2_ReleaseFont,
3460     fnIMLangFontLink2_ResetFontMapping,
3461     fnIMLangFontLink2_MapFont,
3462     fnIMLangFontLink2_GetFontUnicodeRanges,
3463     fnIMLangFontLink2_GetScriptFontInfo,
3464     fnIMLangFontLink2_CodePageToScriptID
3465 };
3466
3467 /******************************************************************************/
3468
3469 static inline MLang_impl *impl_from_IMLangLineBreakConsole( IMLangLineBreakConsole *iface )
3470 {
3471     return CONTAINING_RECORD( iface, MLang_impl, IMLangLineBreakConsole_iface );
3472 }
3473
3474 static HRESULT WINAPI fnIMLangLineBreakConsole_QueryInterface(
3475     IMLangLineBreakConsole* iface,
3476     REFIID riid,
3477     void** ppvObject)
3478 {
3479     MLang_impl *This = impl_from_IMLangLineBreakConsole( iface );
3480     return MLang_QueryInterface( This, riid, ppvObject );
3481 }
3482
3483 static ULONG WINAPI fnIMLangLineBreakConsole_AddRef(
3484     IMLangLineBreakConsole* iface )
3485 {
3486     MLang_impl *This = impl_from_IMLangLineBreakConsole( iface );
3487     return MLang_AddRef( This );
3488 }
3489
3490 static ULONG WINAPI fnIMLangLineBreakConsole_Release(
3491     IMLangLineBreakConsole* iface )
3492 {
3493     MLang_impl *This = impl_from_IMLangLineBreakConsole( iface );
3494     return MLang_Release( This );
3495 }
3496
3497 static HRESULT WINAPI fnIMLangLineBreakConsole_BreakLineML(
3498     IMLangLineBreakConsole* iface,
3499     IMLangString* pSrcMLStr,
3500     LONG lSrcPos,
3501     LONG lSrcLen,
3502     LONG cMinColumns,
3503     LONG cMaxColumns,
3504     LONG* plLineLen,
3505     LONG* plSkipLen)
3506 {
3507     FIXME("(%p)->%p %i %i %i %i %p %p\n", iface, pSrcMLStr, lSrcPos, lSrcLen, cMinColumns, cMaxColumns, plLineLen, plSkipLen);
3508     return E_NOTIMPL;
3509 }
3510
3511 static HRESULT WINAPI fnIMLangLineBreakConsole_BreakLineW(
3512     IMLangLineBreakConsole* iface,
3513     LCID locale,
3514     const WCHAR* pszSrc,
3515     LONG cchSrc,
3516     LONG cMaxColumns,
3517     LONG* pcchLine,
3518     LONG* pcchSkip )
3519 {
3520     FIXME("(%p)->%i %s %i %i %p %p\n", iface, locale, debugstr_wn(pszSrc,cchSrc), cchSrc, cMaxColumns, pcchLine, pcchSkip);
3521
3522     *pcchLine = cchSrc;
3523     *pcchSkip = 0;
3524     return S_OK;
3525 }
3526
3527 static HRESULT WINAPI fnIMLangLineBreakConsole_BreakLineA(
3528     IMLangLineBreakConsole* iface,
3529     LCID locale,
3530     UINT uCodePage,
3531     const CHAR* pszSrc,
3532     LONG cchSrc,
3533     LONG cMaxColumns,
3534     LONG* pcchLine,
3535     LONG* pcchSkip)
3536 {
3537     FIXME("(%p)->%i %i %s %i %i %p %p\n", iface, locale, uCodePage, debugstr_an(pszSrc,cchSrc), cchSrc, cMaxColumns, pcchLine, pcchSkip);
3538
3539     *pcchLine = cchSrc;
3540     *pcchSkip = 0;
3541     return S_OK;
3542 }
3543
3544 static const IMLangLineBreakConsoleVtbl IMLangLineBreakConsole_vtbl =
3545 {
3546     fnIMLangLineBreakConsole_QueryInterface,
3547     fnIMLangLineBreakConsole_AddRef,
3548     fnIMLangLineBreakConsole_Release,
3549     fnIMLangLineBreakConsole_BreakLineML,
3550     fnIMLangLineBreakConsole_BreakLineW,
3551     fnIMLangLineBreakConsole_BreakLineA
3552 };
3553
3554 static HRESULT MultiLanguage_create(IUnknown *pUnkOuter, LPVOID *ppObj)
3555 {
3556     MLang_impl *mlang;
3557     UINT i;
3558
3559     TRACE("Creating MultiLanguage object\n");
3560
3561     if( pUnkOuter )
3562         return CLASS_E_NOAGGREGATION;
3563
3564     mlang = HeapAlloc( GetProcessHeap(), 0, sizeof (MLang_impl) );
3565     mlang->IMLangFontLink_iface.lpVtbl = &IMLangFontLink_vtbl;
3566     mlang->IMultiLanguage_iface.lpVtbl = &IMultiLanguage_vtbl;
3567     mlang->IMultiLanguage3_iface.lpVtbl = &IMultiLanguage3_vtbl;
3568     mlang->IMLangFontLink2_iface.lpVtbl = &IMLangFontLink2_vtbl;
3569     mlang->IMLangLineBreakConsole_iface.lpVtbl = &IMLangLineBreakConsole_vtbl;
3570
3571     mlang->total_cp = 0;
3572     for (i = 0; i < sizeof(mlang_data)/sizeof(mlang_data[0]); i++)
3573         mlang->total_cp += mlang_data[i].number_of_cp;
3574
3575     /* do not enumerate unicode flavours */
3576     mlang->total_scripts = sizeof(mlang_data)/sizeof(mlang_data[0]) - 1;
3577
3578     mlang->ref = 1;
3579     *ppObj = mlang;
3580     TRACE("returning %p\n", mlang);
3581
3582     LockModule();
3583
3584     return S_OK;
3585 }
3586
3587 /******************************************************************************/
3588
3589 HRESULT WINAPI DllCanUnloadNow(void)
3590 {
3591     return dll_count == 0 ? S_OK : S_FALSE;
3592 }
3593
3594
3595 /***********************************************************************
3596  *              DllRegisterServer (MLANG.@)
3597  */
3598 HRESULT WINAPI DllRegisterServer(void)
3599 {
3600     return __wine_register_resources( instance );
3601 }
3602
3603 /***********************************************************************
3604  *              DllUnregisterServer (MLANG.@)
3605  */
3606 HRESULT WINAPI DllUnregisterServer(void)
3607 {
3608     return __wine_unregister_resources( instance );
3609 }
3610
3611 HRESULT WINAPI GetGlobalFontLinkObject(void **unknown)
3612 {
3613     if (!unknown) return E_INVALIDARG;
3614
3615     FIXME("%p: stub\n", unknown);
3616
3617     return S_FALSE;
3618 }