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