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