mlang: Remove superfluous pointer casts.
[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     DWORD i = 0;
507     unsigned char c1,c2;
508
509     while ((code == 0 || code == 51932) && i < count)
510     {
511         c1 = input[i];
512         if (c1 == 0x1b /* ESC */)
513         {
514             i++;
515             if (i >= count)
516                 return code;
517             c1 = input[i];
518             if (c1 == '$')
519             {
520                 i++;
521                 if (i >= count)
522                     return code;
523                 c1 = input[i];
524                 if (c1 =='B' || c1 == '@')
525                     code = 50220;
526             }
527             if (c1 == 'K')
528                 code = 50220;
529         }
530         else if (c1 >= 129)
531         {
532             i++;
533             if (i >= count)
534                 return code;
535             c2 = input[i];
536             if NOTEUC(c1,c2)
537                 code = 932;
538             else if (ISEUC(c1) && ISEUC(c2))
539                 code = 51932;
540             else if (((c1 == 142)) && HANKATA(c2))
541                 code = 51932;
542         }
543         i++;
544     }
545     return code;
546 }
547
548 static inline void jis2sjis(unsigned char *p1, unsigned char *p2)
549 {
550     unsigned char c1 = *p1;
551     unsigned char c2 = *p2;
552     int row = c1 < 95 ? 112 : 176;
553     int cell = c1 % 2 ? 31 + (c2 > 95) : 126;
554
555     *p1 = ((c1 + 1) >> 1) + row;
556     *p2 = c2 + cell;
557 }
558
559 static inline void sjis2jis(unsigned char *p1, unsigned char *p2)
560 {
561     unsigned char c1 = *p1;
562     unsigned char c2 = *p2;
563     int shift = c2 < 159;
564     int row = c1 < 160 ? 112 : 176;
565     int cell = shift ? (31 + (c2 > 127)): 126;
566
567     *p1 = ((c1 - row) << 1) - shift;
568     *p2 -= cell;
569 }
570
571 static int han2zen(unsigned char *p1, unsigned char *p2)
572 {
573     int maru = FALSE;
574     int nigori = FALSE;
575     static const unsigned char char1[] = {129,129,129,129,129,131,131,131,131,
576         131,131,131,131,131,131,129,131,131,131,131,131,131,131,131,131,131,
577         131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,
578         131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,
579         131,129,129 };
580     static const unsigned char char2[] = {66,117,118,65,69,146,64,66,68,70,
581         72,131,133,135,98,91,65,67,69,71,73,74,76,78,80,82,84,86,88,90,92,94,
582         96,99,101,103,105,106,107,108,109,110,113,116,119,122,125,126,128,
583         129,130,132,134,136,137,138,139,140,141,143,147,74,75};
584
585     if (( *p2 == 222) && ((ISNIGORI(*p1) || (*p1 == 179))))
586             nigori = TRUE;
587     else if ((*p2 == 223) && (ISMARU(*p1)))
588             maru = TRUE;
589
590     if (*p1 >= 161 && *p1 <= 223)
591     {
592         unsigned char index = *p1 - 161;
593         *p1 = char1[index];
594         *p2 = char2[index];
595     }
596
597     if (maru || nigori)
598     {
599         if (nigori)
600         {
601             if (((*p2 >= 74) && (*p2 <= 103)) || ((*p2 >= 110) && (*p2 <= 122)))
602                 (*p2)++;
603             else if ((*p1 == 131) && (*p2 == 69))
604                 *p2 = 148;
605         }
606         else if ((maru) && ((*p2 >= 110) && (*p2 <= 122)))
607             *p2+= 2;
608
609         return 1;
610     }
611
612     return 0;
613 }
614
615
616 static UINT ConvertJIS2SJIS(LPCSTR input, DWORD count, LPSTR output)
617 {
618     DWORD i = 0;
619     int j = 0;
620     unsigned char p2,p;
621     int shifted = FALSE;
622
623     while (i < count)
624     {
625         p = input[i];
626         if (p == 0x1b /* ESC */)
627         {
628             i++;
629             if (i >= count)
630                 return 0;
631             p2 = input[i];
632             if (p2 == '$' || p2 =='(')
633                 i++;
634             if (p2 == 'K' || p2 =='$')
635                 shifted = TRUE;
636             else
637                 shifted = FALSE;
638         }
639         else
640         {
641             if (shifted)
642             {
643                 i++;
644                 if (i >= count)
645                     return 0;
646                 p2 = input[i];
647                 jis2sjis(&p,&p2);
648                 output[j++]=p;
649                 output[j++]=p2;
650             }
651             else
652             {
653                 output[j++] = p;
654             }
655         }
656         i++;
657     }
658     return j;
659 }
660
661 static inline int exit_shift(LPSTR out, int c)
662 {
663     if (out)
664     {
665         out[c] = 0x1b;
666         out[c+1] = '(';
667         out[c+2] = 'B';
668     }
669     return 3;
670 }
671
672 static inline int enter_shift(LPSTR out, int c)
673 {
674     if (out)
675     {
676         out[c] = 0x1b;
677         out[c+1] = '$';
678         out[c+2] = 'B';
679     }
680     return 3;
681 }
682
683
684 static UINT ConvertSJIS2JIS(LPCSTR input, DWORD count, LPSTR output)
685 {
686     DWORD i = 0;
687     int j = 0;
688     unsigned char p2,p;
689     int shifted = FALSE;
690
691     while (i < count)
692     {
693         p = input[i] & 0xff;
694         if (p == 10 || p == 13) /* NL and CR */
695         {
696             if (shifted)
697             {
698                 shifted = FALSE;
699                 j += exit_shift(output,j);
700             }
701             if (output)
702                 output[j++] = p;
703             else
704                 j++;
705         }
706         else
707         {
708             if (SJIS1(p))
709             {
710                 i++;
711                 if (i >= count)
712                     return 0;
713                 p2 = input[i] & 0xff;
714                 if (SJIS2(p2))
715                 {
716                     sjis2jis(&p,&p2);
717                     if (!shifted)
718                     {
719                         shifted = TRUE;
720                         j+=enter_shift(output,j);
721                     }
722                 }
723
724                 if (output)
725                 {
726                     output[j++]=p;
727                     output[j++]=p2;
728                 }
729                 else
730                     j+=2;
731             }
732             else
733             {
734                 if (HANKATA(p))
735                 {
736                     if ((i+1) >= count)
737                         return 0;
738                     p2 = input[i+1] & 0xff;
739                     i+=han2zen(&p,&p2);
740                     sjis2jis(&p,&p2);
741                     if (!shifted)
742                     {
743                         shifted = TRUE;
744                         j+=enter_shift(output,j);
745                     }
746                     if (output)
747                     {
748                         output[j++]=p;
749                         output[j++]=p2;
750                     }
751                     else
752                         j+=2;
753                 }
754                 else
755                 {
756                     if (shifted)
757                     {
758                         shifted = FALSE;
759                         j += exit_shift(output,j);
760                     }
761                     if (output)
762                         output[j++]=p;
763                     else
764                         j++;
765                 }
766             }
767         }
768         i++;
769     }
770     if (shifted)
771         j += exit_shift(output,j);
772     return j;
773 }
774
775 static UINT ConvertJISJapaneseToUnicode(LPCSTR input, DWORD count,
776                                         LPWSTR output, DWORD out_count)
777 {
778     CHAR *sjis_string;
779     UINT rc = 0;
780     sjis_string = HeapAlloc(GetProcessHeap(),0,count);
781     rc = ConvertJIS2SJIS(input,count,sjis_string);
782     if (rc)
783     {
784         TRACE("%s\n",debugstr_an(sjis_string,rc));
785         if (output)
786             rc = MultiByteToWideChar(932,0,sjis_string,rc,output,out_count);
787         else
788             rc = MultiByteToWideChar(932,0,sjis_string,rc,0,0);
789     }
790     HeapFree(GetProcessHeap(),0,sjis_string);
791     return rc;
792
793 }
794
795 static UINT ConvertUnknownJapaneseToUnicode(LPCSTR input, DWORD count,
796                                             LPWSTR output, DWORD out_count)
797 {
798     CHAR *sjis_string;
799     UINT rc = 0;
800     int code = DetectJapaneseCode(input,count);
801     TRACE("Japanese code %i\n",code);
802
803     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 = ConvertJapaneseUnicodeToJIS(pSrcStr, *pcSrcSize, pDstStr,
1003                                                destsz);
1004             if (!size)
1005                 goto fail;
1006         }
1007
1008     }
1009     else
1010     {
1011         size = WideCharToMultiByte(dwEncoding, 0, pSrcStr, *pcSrcSize,
1012                                    NULL, 0, NULL, NULL);
1013         if (!size)
1014             goto fail;
1015
1016         if (pDstStr)
1017         {
1018             size = WideCharToMultiByte(dwEncoding, 0, pSrcStr, *pcSrcSize,
1019                                        pDstStr, destsz, NULL, NULL);
1020             if (!size)
1021                 goto fail;
1022         }
1023     }
1024
1025     *pcDstSize = size;
1026     return S_OK;
1027
1028 fail:
1029     *pcSrcSize = 0;
1030     *pcDstSize = 0;
1031     return E_FAIL;
1032 }
1033
1034 HRESULT WINAPI ConvertINetString(
1035     LPDWORD pdwMode,
1036     DWORD dwSrcEncoding,
1037     DWORD dwDstEncoding,
1038     LPCSTR pSrcStr,
1039     LPINT pcSrcSize,
1040     LPSTR pDstStr,
1041     LPINT pcDstSize
1042 )
1043 {
1044     TRACE("%p %d %d %s %p %p %p\n", pdwMode, dwSrcEncoding, dwDstEncoding,
1045           debugstr_a(pSrcStr), pcSrcSize, pDstStr, pcDstSize);
1046
1047     if (dwSrcEncoding == CP_UNICODE)
1048     {
1049         INT cSrcSizeW;
1050         if (pcSrcSize && *pcSrcSize != -1)
1051         {
1052             cSrcSizeW = *pcSrcSize / sizeof(WCHAR);
1053             pcSrcSize = &cSrcSizeW;
1054         }
1055         return ConvertINetUnicodeToMultiByte(pdwMode, dwDstEncoding, (LPCWSTR)pSrcStr, pcSrcSize, pDstStr, pcDstSize);
1056     }
1057     else if (dwDstEncoding == CP_UNICODE)
1058     {
1059         HRESULT hr = ConvertINetMultiByteToUnicode(pdwMode, dwSrcEncoding, pSrcStr, pcSrcSize, (LPWSTR)pDstStr, pcDstSize);
1060         *pcDstSize *= sizeof(WCHAR);
1061         return hr;
1062     }
1063     else
1064     {
1065         INT cDstSizeW;
1066         LPWSTR pDstStrW;
1067         HRESULT hr;
1068
1069         TRACE("convert %s from %d to %d\n", debugstr_a(pSrcStr), dwSrcEncoding, dwDstEncoding);
1070
1071         hr = ConvertINetMultiByteToUnicode(pdwMode, dwSrcEncoding, pSrcStr, pcSrcSize, NULL, &cDstSizeW);
1072         if (hr != S_OK)
1073             return hr;
1074
1075         pDstStrW = HeapAlloc(GetProcessHeap(), 0, cDstSizeW * sizeof(WCHAR));
1076         hr = ConvertINetMultiByteToUnicode(pdwMode, dwSrcEncoding, pSrcStr, pcSrcSize, pDstStrW, &cDstSizeW);
1077         if (hr == S_OK)
1078             hr = ConvertINetUnicodeToMultiByte(pdwMode, dwDstEncoding, pDstStrW, &cDstSizeW, pDstStr, pcDstSize);
1079
1080         HeapFree(GetProcessHeap(), 0, pDstStrW);
1081         return hr;
1082     }
1083 }
1084
1085 static HRESULT GetFamilyCodePage(
1086     UINT uiCodePage,
1087     UINT* puiFamilyCodePage)
1088 {
1089     UINT i, n;
1090
1091     TRACE("%u %p\n", uiCodePage, puiFamilyCodePage);
1092
1093     if (!puiFamilyCodePage) return S_FALSE;
1094
1095     for (i = 0; i < sizeof(mlang_data)/sizeof(mlang_data[0]); i++)
1096     {
1097         for (n = 0; n < mlang_data[i].number_of_cp; n++)
1098         {
1099             if (mlang_data[i].mime_cp_info[n].cp == uiCodePage)
1100             {
1101                 *puiFamilyCodePage = mlang_data[i].family_codepage;
1102                 return S_OK;
1103             }
1104         }
1105     }
1106
1107     return S_FALSE;
1108 }
1109
1110 HRESULT WINAPI IsConvertINetStringAvailable(
1111     DWORD dwSrcEncoding,
1112     DWORD dwDstEncoding)
1113 {
1114     UINT src_family, dst_family;
1115
1116     TRACE("%d %d\n", dwSrcEncoding, dwDstEncoding);
1117
1118     if (GetFamilyCodePage(dwSrcEncoding, &src_family) != S_OK ||
1119         GetFamilyCodePage(dwDstEncoding, &dst_family) != S_OK)
1120         return S_FALSE;
1121
1122     if (src_family == dst_family) return S_OK;
1123
1124     /* we can convert any codepage to/from unicode */
1125     if (src_family == CP_UNICODE || dst_family == CP_UNICODE) return S_OK;
1126
1127     return S_FALSE;
1128 }
1129
1130 static inline INT lcid_to_rfc1766A( LCID lcid, LPSTR rfc1766, INT len )
1131 {
1132     INT n = GetLocaleInfoA( lcid, LOCALE_SISO639LANGNAME, rfc1766, len );
1133     if (n)
1134     {
1135         rfc1766[n - 1] = '-';
1136         n += GetLocaleInfoA( lcid, LOCALE_SISO3166CTRYNAME, rfc1766 + n, len - n );
1137         LCMapStringA( LOCALE_USER_DEFAULT, LCMAP_LOWERCASE, rfc1766, n, rfc1766, len );
1138         return n;
1139     }
1140     return 0;
1141 }
1142
1143 static inline INT lcid_to_rfc1766W( LCID lcid, LPWSTR rfc1766, INT len )
1144 {
1145     INT n = GetLocaleInfoW( lcid, LOCALE_SISO639LANGNAME, rfc1766, len );
1146     INT save = n;
1147     if (n)
1148     {
1149         rfc1766[n - 1] = '-';
1150         n += GetLocaleInfoW( lcid, LOCALE_SISO3166CTRYNAME, rfc1766 + n, len - n );
1151         if (n == save)
1152             rfc1766[n - 1] = '\0';
1153         LCMapStringW( LOCALE_USER_DEFAULT, LCMAP_LOWERCASE, rfc1766, n, rfc1766, len );
1154         return n;
1155     }
1156     return 0;
1157 }
1158
1159 HRESULT WINAPI LcidToRfc1766A(
1160     LCID lcid,
1161     LPSTR pszRfc1766,
1162     INT nChar)
1163 {
1164     TRACE("%04x %p %u\n", lcid, pszRfc1766, nChar);
1165
1166     if (lcid_to_rfc1766A( lcid, pszRfc1766, nChar ))
1167         return S_OK;
1168
1169     return S_FALSE;
1170 }
1171
1172 HRESULT WINAPI LcidToRfc1766W(
1173     LCID lcid,
1174     LPWSTR pszRfc1766,
1175     INT nChar)
1176 {
1177     TRACE("%04x %p %u\n", lcid, pszRfc1766, nChar);
1178
1179     if (lcid_to_rfc1766W( lcid, pszRfc1766, nChar ))
1180         return S_OK;
1181
1182     return S_FALSE;
1183 }
1184
1185 static HRESULT lcid_from_rfc1766(IEnumRfc1766 *iface, LCID *lcid, LPCWSTR rfc1766)
1186 {
1187     RFC1766INFO info;
1188     ULONG num;
1189
1190     while (IEnumRfc1766_Next(iface, 1, &info, &num) == S_OK)
1191     {
1192         if (!strcmpW(info.wszRfc1766, rfc1766))
1193         {
1194             *lcid = info.lcid;
1195             return S_OK;
1196         }
1197         if (strlenW(rfc1766) == 2 && !memcmp(info.wszRfc1766, rfc1766, 2 * sizeof(WCHAR)))
1198         {
1199             *lcid = PRIMARYLANGID(info.lcid);
1200             return S_OK;
1201         }
1202     }
1203
1204     return E_FAIL;
1205 }
1206
1207 HRESULT WINAPI Rfc1766ToLcidW(LCID *pLocale, LPCWSTR pszRfc1766)
1208 {
1209     IEnumRfc1766 *enumrfc1766;
1210     HRESULT hr;
1211
1212     TRACE("(%p, %s)\n", pLocale, debugstr_w(pszRfc1766));
1213
1214     if (!pLocale || !pszRfc1766)
1215         return E_INVALIDARG;
1216
1217     *pLocale = 0;
1218
1219     hr = EnumRfc1766_create(0, &enumrfc1766);
1220     if (FAILED(hr))
1221         return hr;
1222
1223     hr = lcid_from_rfc1766(enumrfc1766, pLocale, pszRfc1766);
1224     IEnumRfc1766_Release(enumrfc1766);
1225
1226     return hr;
1227 }
1228
1229 HRESULT WINAPI Rfc1766ToLcidA(LCID *lcid, LPCSTR rfc1766A)
1230 {
1231     WCHAR rfc1766W[MAX_RFC1766_NAME + 1];
1232
1233     MultiByteToWideChar(CP_ACP, 0, rfc1766A, -1, rfc1766W, MAX_RFC1766_NAME);
1234     rfc1766W[MAX_RFC1766_NAME] = 0;
1235
1236     return Rfc1766ToLcidW(lcid, rfc1766W);
1237 }
1238
1239 /******************************************************************************
1240  * MLANG ClassFactory
1241  */
1242 typedef struct {
1243     IClassFactory ITF_IClassFactory;
1244
1245     LONG ref;
1246     HRESULT (*pfnCreateInstance)(IUnknown *pUnkOuter, LPVOID *ppObj);
1247 } IClassFactoryImpl;
1248
1249 struct object_creation_info
1250 {
1251     const CLSID *clsid;
1252     LPCSTR szClassName;
1253     HRESULT (*pfnCreateInstance)(IUnknown *pUnkOuter, LPVOID *ppObj);
1254 };
1255
1256 static const struct object_creation_info object_creation[] =
1257 {
1258     { &CLSID_CMultiLanguage, "CLSID_CMultiLanguage", MultiLanguage_create },
1259 };
1260
1261 static HRESULT WINAPI
1262 MLANGCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj)
1263 {
1264     IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
1265
1266     TRACE("%s\n", debugstr_guid(riid) );
1267
1268     if (IsEqualGUID(riid, &IID_IUnknown)
1269         || IsEqualGUID(riid, &IID_IClassFactory))
1270     {
1271         IClassFactory_AddRef(iface);
1272         *ppobj = This;
1273         return S_OK;
1274     }
1275
1276     WARN("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppobj);
1277     return E_NOINTERFACE;
1278 }
1279
1280 static ULONG WINAPI MLANGCF_AddRef(LPCLASSFACTORY iface)
1281 {
1282     IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
1283     return InterlockedIncrement(&This->ref);
1284 }
1285
1286 static ULONG WINAPI MLANGCF_Release(LPCLASSFACTORY iface)
1287 {
1288     IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
1289
1290     ULONG ref = InterlockedDecrement(&This->ref);
1291
1292     if (ref == 0)
1293     {
1294         TRACE("Destroying %p\n", This);
1295         HeapFree(GetProcessHeap(), 0, This);
1296     }
1297
1298     return ref;
1299 }
1300
1301 static HRESULT WINAPI MLANGCF_CreateInstance(LPCLASSFACTORY iface, LPUNKNOWN pOuter,
1302                                           REFIID riid, LPVOID *ppobj)
1303 {
1304     IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
1305     HRESULT hres;
1306     LPUNKNOWN punk;
1307     
1308     TRACE("(%p)->(%p,%s,%p)\n",This,pOuter,debugstr_guid(riid),ppobj);
1309
1310     *ppobj = NULL;
1311     hres = This->pfnCreateInstance(pOuter, (LPVOID *) &punk);
1312     if (SUCCEEDED(hres)) {
1313         hres = IUnknown_QueryInterface(punk, riid, ppobj);
1314         IUnknown_Release(punk);
1315     }
1316     TRACE("returning (%p) -> %x\n", *ppobj, hres);
1317     return hres;
1318 }
1319
1320 static HRESULT WINAPI MLANGCF_LockServer(LPCLASSFACTORY iface,BOOL dolock)
1321 {
1322     if (dolock)
1323         LockModule();
1324     else
1325         UnlockModule();
1326
1327     return S_OK;
1328 }
1329
1330 static const IClassFactoryVtbl MLANGCF_Vtbl =
1331 {
1332     MLANGCF_QueryInterface,
1333     MLANGCF_AddRef,
1334     MLANGCF_Release,
1335     MLANGCF_CreateInstance,
1336     MLANGCF_LockServer
1337 };
1338
1339 /******************************************************************
1340  *              DllGetClassObject (MLANG.@)
1341  */
1342 HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID iid, LPVOID *ppv)
1343 {
1344     unsigned int i;
1345     IClassFactoryImpl *factory;
1346
1347     TRACE("%s %s %p\n",debugstr_guid(rclsid), debugstr_guid(iid), ppv);
1348
1349     if ( !IsEqualGUID( &IID_IClassFactory, iid )
1350          && ! IsEqualGUID( &IID_IUnknown, iid) )
1351         return E_NOINTERFACE;
1352
1353     for (i=0; i < sizeof(object_creation)/sizeof(object_creation[0]); i++)
1354     {
1355         if (IsEqualGUID(object_creation[i].clsid, rclsid))
1356             break;
1357     }
1358
1359     if (i == sizeof(object_creation)/sizeof(object_creation[0]))
1360     {
1361         FIXME("%s: no class found.\n", debugstr_guid(rclsid));
1362         return CLASS_E_CLASSNOTAVAILABLE;
1363     }
1364
1365     TRACE("Creating a class factory for %s\n",object_creation[i].szClassName);
1366
1367     factory = HeapAlloc(GetProcessHeap(), 0, sizeof(*factory));
1368     if (factory == NULL) return E_OUTOFMEMORY;
1369
1370     factory->ITF_IClassFactory.lpVtbl = &MLANGCF_Vtbl;
1371     factory->ref = 1;
1372
1373     factory->pfnCreateInstance = object_creation[i].pfnCreateInstance;
1374
1375     *ppv = &(factory->ITF_IClassFactory);
1376
1377     TRACE("(%p) <- %p\n", ppv, &(factory->ITF_IClassFactory) );
1378
1379     return S_OK;
1380 }
1381
1382
1383 /******************************************************************************/
1384
1385 typedef struct tagMLang_impl
1386 {
1387     const IMLangFontLinkVtbl *vtbl_IMLangFontLink;
1388     const IMultiLanguageVtbl *vtbl_IMultiLanguage;
1389     const IMultiLanguage3Vtbl *vtbl_IMultiLanguage3;
1390     const IMLangFontLink2Vtbl *vtbl_IMLangFontLink2;
1391     const IMLangLineBreakConsoleVtbl *vtbl_IMLangLineBreakConsole;
1392     LONG ref;
1393     DWORD total_cp, total_scripts;
1394 } MLang_impl;
1395
1396 static ULONG MLang_AddRef( MLang_impl* This)
1397 {
1398     return InterlockedIncrement(&This->ref);
1399 }
1400
1401 static ULONG MLang_Release( MLang_impl* This )
1402 {
1403     ULONG ref = InterlockedDecrement(&This->ref);
1404
1405     TRACE("%p ref = %d\n", This, ref);
1406     if (ref == 0)
1407     {
1408         TRACE("Destroying %p\n", This);
1409         HeapFree(GetProcessHeap(), 0, This);
1410         UnlockModule();
1411     }
1412
1413     return ref;
1414 }
1415
1416 static HRESULT MLang_QueryInterface(
1417         MLang_impl* This,
1418         REFIID riid,
1419         void** ppvObject)
1420 {
1421     TRACE("%p -> %s\n", This, debugstr_guid(riid) );
1422
1423     if (IsEqualGUID(riid, &IID_IUnknown)
1424         || IsEqualGUID(riid, &IID_IMLangCodePages)
1425         || IsEqualGUID(riid, &IID_IMLangFontLink))
1426     {
1427         MLang_AddRef(This);
1428         TRACE("Returning IID_IMLangFontLink %p ref = %d\n", This, This->ref);
1429         *ppvObject = &(This->vtbl_IMLangFontLink);
1430         return S_OK;
1431     }
1432
1433     if (IsEqualGUID(riid, &IID_IMLangFontLink2))
1434     {
1435         MLang_AddRef(This);
1436         TRACE("Returning IID_IMLangFontLink2 %p ref = %d\n", This, This->ref);
1437         *ppvObject = &(This->vtbl_IMLangFontLink2);
1438         return S_OK;
1439     }
1440
1441     if (IsEqualGUID(riid, &IID_IMultiLanguage) )
1442     {
1443         MLang_AddRef(This);
1444         TRACE("Returning IID_IMultiLanguage %p ref = %d\n", This, This->ref);
1445         *ppvObject = &(This->vtbl_IMultiLanguage);
1446         return S_OK;
1447     }
1448
1449     if (IsEqualGUID(riid, &IID_IMultiLanguage2) )
1450     {
1451         MLang_AddRef(This);
1452         *ppvObject = &(This->vtbl_IMultiLanguage3);
1453         TRACE("Returning IID_IMultiLanguage2 %p ref = %d\n", This, This->ref);
1454         return S_OK;
1455     }
1456
1457     if (IsEqualGUID(riid, &IID_IMultiLanguage3) )
1458     {
1459         MLang_AddRef(This);
1460         *ppvObject = &(This->vtbl_IMultiLanguage3);
1461         TRACE("Returning IID_IMultiLanguage3 %p ref = %d\n", This, This->ref);
1462         return S_OK;
1463     }
1464
1465     if (IsEqualGUID(riid, &IID_IMLangLineBreakConsole))
1466     {
1467         MLang_AddRef(This);
1468         TRACE("Returning IID_IMLangLineBreakConsole %p ref = %d\n", This, This->ref);
1469         *ppvObject = &(This->vtbl_IMLangLineBreakConsole);
1470         return S_OK;
1471     }
1472
1473
1474     WARN("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppvObject);
1475     return E_NOINTERFACE;
1476 }
1477
1478 /******************************************************************************/
1479
1480 typedef struct tagEnumCodePage_impl
1481 {
1482     const IEnumCodePageVtbl *vtbl_IEnumCodePage;
1483     LONG ref;
1484     MIMECPINFO *cpinfo;
1485     DWORD total, pos;
1486 } EnumCodePage_impl;
1487
1488 static HRESULT WINAPI fnIEnumCodePage_QueryInterface(
1489         IEnumCodePage* iface,
1490         REFIID riid,
1491         void** ppvObject)
1492 {
1493     ICOM_THIS_MULTI(EnumCodePage_impl, vtbl_IEnumCodePage, iface);
1494
1495     TRACE("%p -> %s\n", This, debugstr_guid(riid) );
1496
1497     if (IsEqualGUID(riid, &IID_IUnknown)
1498         || IsEqualGUID(riid, &IID_IEnumCodePage))
1499     {
1500         IEnumCodePage_AddRef(iface);
1501         TRACE("Returning IID_IEnumCodePage %p ref = %d\n", This, This->ref);
1502         *ppvObject = &(This->vtbl_IEnumCodePage);
1503         return S_OK;
1504     }
1505
1506     WARN("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppvObject);
1507     return E_NOINTERFACE;
1508 }
1509
1510 static ULONG WINAPI fnIEnumCodePage_AddRef(
1511         IEnumCodePage* iface)
1512 {
1513     ICOM_THIS_MULTI(EnumCodePage_impl, vtbl_IEnumCodePage, iface);
1514     return InterlockedIncrement(&This->ref);
1515 }
1516
1517 static ULONG WINAPI fnIEnumCodePage_Release(
1518         IEnumCodePage* iface)
1519 {
1520     ICOM_THIS_MULTI(EnumCodePage_impl, vtbl_IEnumCodePage, iface);
1521     ULONG ref = InterlockedDecrement(&This->ref);
1522
1523     TRACE("%p ref = %d\n", This, ref);
1524     if (ref == 0)
1525     {
1526         TRACE("Destroying %p\n", This);
1527         HeapFree(GetProcessHeap(), 0, This->cpinfo);
1528         HeapFree(GetProcessHeap(), 0, This);
1529     }
1530
1531     return ref;
1532 }
1533
1534 static HRESULT WINAPI fnIEnumCodePage_Clone(
1535         IEnumCodePage* iface,
1536         IEnumCodePage** ppEnum)
1537 {
1538     ICOM_THIS_MULTI(EnumCodePage_impl, vtbl_IEnumCodePage, iface);
1539     FIXME("%p %p\n", This, ppEnum);
1540     return E_NOTIMPL;
1541 }
1542
1543 static  HRESULT WINAPI fnIEnumCodePage_Next(
1544         IEnumCodePage* iface,
1545         ULONG celt,
1546         PMIMECPINFO rgelt,
1547         ULONG* pceltFetched)
1548 {
1549     ULONG i;
1550
1551     ICOM_THIS_MULTI(EnumCodePage_impl, vtbl_IEnumCodePage, iface);
1552     TRACE("%p %u %p %p\n", This, celt, rgelt, pceltFetched);
1553
1554     if (!pceltFetched) return S_FALSE;
1555     *pceltFetched = 0;
1556
1557     if (!rgelt) return S_FALSE;
1558
1559     if (This->pos + celt > This->total)
1560         celt = This->total - This->pos;
1561
1562     if (!celt) return S_FALSE;
1563
1564     memcpy(rgelt, This->cpinfo + This->pos, celt * sizeof(MIMECPINFO));
1565     *pceltFetched = celt;
1566     This->pos += celt;
1567
1568     for (i = 0; i < celt; i++)
1569     {
1570         TRACE("#%u: %08x %u %u %s %s %s %s %s %s %d\n",
1571               i, rgelt[i].dwFlags, rgelt[i].uiCodePage,
1572               rgelt[i].uiFamilyCodePage,
1573               wine_dbgstr_w(rgelt[i].wszDescription),
1574               wine_dbgstr_w(rgelt[i].wszWebCharset),
1575               wine_dbgstr_w(rgelt[i].wszHeaderCharset),
1576               wine_dbgstr_w(rgelt[i].wszBodyCharset),
1577               wine_dbgstr_w(rgelt[i].wszFixedWidthFont),
1578               wine_dbgstr_w(rgelt[i].wszProportionalFont),
1579               rgelt[i].bGDICharset);
1580     }
1581     return S_OK;
1582 }
1583
1584 static HRESULT WINAPI fnIEnumCodePage_Reset(
1585         IEnumCodePage* iface)
1586 {
1587     ICOM_THIS_MULTI(EnumCodePage_impl, vtbl_IEnumCodePage, iface);
1588     TRACE("%p\n", This);
1589
1590     This->pos = 0;
1591     return S_OK;
1592 }
1593
1594 static  HRESULT WINAPI fnIEnumCodePage_Skip(
1595         IEnumCodePage* iface,
1596         ULONG celt)
1597 {
1598     ICOM_THIS_MULTI(EnumCodePage_impl, vtbl_IEnumCodePage, iface);
1599     TRACE("%p %u\n", This, celt);
1600
1601     if (celt >= This->total) return S_FALSE;
1602
1603     This->pos += celt;
1604     return S_OK;
1605 }
1606
1607 static const IEnumCodePageVtbl IEnumCodePage_vtbl =
1608 {
1609     fnIEnumCodePage_QueryInterface,
1610     fnIEnumCodePage_AddRef,
1611     fnIEnumCodePage_Release,
1612     fnIEnumCodePage_Clone,
1613     fnIEnumCodePage_Next,
1614     fnIEnumCodePage_Reset,
1615     fnIEnumCodePage_Skip
1616 };
1617
1618 static HRESULT EnumCodePage_create( MLang_impl* mlang, DWORD grfFlags,
1619                      LANGID LangId, IEnumCodePage** ppEnumCodePage )
1620 {
1621     EnumCodePage_impl *ecp;
1622     MIMECPINFO *cpinfo;
1623     UINT i, n;
1624
1625     TRACE("%p, %08x, %04x, %p\n", mlang, grfFlags, LangId, ppEnumCodePage);
1626
1627     if (!grfFlags) /* enumerate internal data base of encodings */
1628         grfFlags = MIMECONTF_MIME_LATEST;
1629
1630     ecp = HeapAlloc( GetProcessHeap(), 0, sizeof (EnumCodePage_impl) );
1631     ecp->vtbl_IEnumCodePage = &IEnumCodePage_vtbl;
1632     ecp->ref = 1;
1633     ecp->pos = 0;
1634     ecp->total = 0;
1635     for (i = 0; i < sizeof(mlang_data)/sizeof(mlang_data[0]); i++)
1636     {
1637         for (n = 0; n < mlang_data[i].number_of_cp; n++)
1638         {
1639             if (mlang_data[i].mime_cp_info[n].flags & grfFlags)
1640                 ecp->total++;
1641         }
1642     }
1643
1644     ecp->cpinfo = HeapAlloc(GetProcessHeap(), 0,
1645                             sizeof(MIMECPINFO) * ecp->total);
1646     cpinfo = ecp->cpinfo;
1647
1648     for (i = 0; i < sizeof(mlang_data)/sizeof(mlang_data[0]); i++)
1649     {
1650         for (n = 0; n < mlang_data[i].number_of_cp; n++)
1651         {
1652             if (mlang_data[i].mime_cp_info[n].flags & grfFlags)
1653                 fill_cp_info(&mlang_data[i], n, cpinfo++);
1654         }
1655     }
1656
1657     TRACE("enumerated %d codepages with flags %08x\n", ecp->total, grfFlags);
1658
1659     *ppEnumCodePage = (IEnumCodePage*) ecp;
1660
1661     return S_OK;
1662 }
1663
1664 /******************************************************************************/
1665
1666 typedef struct tagEnumScript_impl
1667 {
1668     const IEnumScriptVtbl *vtbl_IEnumScript;
1669     LONG ref;
1670     SCRIPTINFO *script_info;
1671     DWORD total, pos;
1672 } EnumScript_impl;
1673
1674 static HRESULT WINAPI fnIEnumScript_QueryInterface(
1675         IEnumScript* iface,
1676         REFIID riid,
1677         void** ppvObject)
1678 {
1679     ICOM_THIS_MULTI(EnumScript_impl, vtbl_IEnumScript, iface);
1680
1681     TRACE("%p -> %s\n", This, debugstr_guid(riid) );
1682
1683     if (IsEqualGUID(riid, &IID_IUnknown)
1684         || IsEqualGUID(riid, &IID_IEnumScript))
1685     {
1686         IEnumScript_AddRef(iface);
1687         TRACE("Returning IID_IEnumScript %p ref = %d\n", This, This->ref);
1688         *ppvObject = &(This->vtbl_IEnumScript);
1689         return S_OK;
1690     }
1691
1692     WARN("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppvObject);
1693     return E_NOINTERFACE;
1694 }
1695
1696 static ULONG WINAPI fnIEnumScript_AddRef(
1697         IEnumScript* iface)
1698 {
1699     ICOM_THIS_MULTI(EnumScript_impl, vtbl_IEnumScript, iface);
1700     return InterlockedIncrement(&This->ref);
1701 }
1702
1703 static ULONG WINAPI fnIEnumScript_Release(
1704         IEnumScript* iface)
1705 {
1706     ICOM_THIS_MULTI(EnumScript_impl, vtbl_IEnumScript, iface);
1707     ULONG ref = InterlockedDecrement(&This->ref);
1708
1709     TRACE("%p ref = %d\n", This, ref);
1710     if (ref == 0)
1711     {
1712         TRACE("Destroying %p\n", This);
1713         HeapFree(GetProcessHeap(), 0, This->script_info);
1714         HeapFree(GetProcessHeap(), 0, This);
1715     }
1716
1717     return ref;
1718 }
1719
1720 static HRESULT WINAPI fnIEnumScript_Clone(
1721         IEnumScript* iface,
1722         IEnumScript** ppEnum)
1723 {
1724     ICOM_THIS_MULTI(EnumScript_impl, vtbl_IEnumScript, iface);
1725     FIXME("%p %p: stub!\n", This, ppEnum);
1726     return E_NOTIMPL;
1727 }
1728
1729 static  HRESULT WINAPI fnIEnumScript_Next(
1730         IEnumScript* iface,
1731         ULONG celt,
1732         PSCRIPTINFO rgelt,
1733         ULONG* pceltFetched)
1734 {
1735     ICOM_THIS_MULTI(EnumScript_impl, vtbl_IEnumScript, iface);
1736     TRACE("%p %u %p %p\n", This, celt, rgelt, pceltFetched);
1737
1738     if (!pceltFetched || !rgelt) return E_FAIL;
1739
1740     *pceltFetched = 0;
1741
1742     if (This->pos + celt > This->total)
1743         celt = This->total - This->pos;
1744
1745     if (!celt) return S_FALSE;
1746
1747     memcpy(rgelt, This->script_info + This->pos, celt * sizeof(SCRIPTINFO));
1748     *pceltFetched = celt;
1749     This->pos += celt;
1750
1751     return S_OK;
1752 }
1753
1754 static HRESULT WINAPI fnIEnumScript_Reset(
1755         IEnumScript* iface)
1756 {
1757     ICOM_THIS_MULTI(EnumScript_impl, vtbl_IEnumScript, iface);
1758     TRACE("%p\n", This);
1759
1760     This->pos = 0;
1761     return S_OK;
1762 }
1763
1764 static  HRESULT WINAPI fnIEnumScript_Skip(
1765         IEnumScript* iface,
1766         ULONG celt)
1767 {
1768     ICOM_THIS_MULTI(EnumScript_impl, vtbl_IEnumScript, iface);
1769     TRACE("%p %u\n", This, celt);
1770
1771     if (celt >= This->total) return S_FALSE;
1772
1773     This->pos += celt;
1774     return S_OK;
1775 }
1776
1777 static const IEnumScriptVtbl IEnumScript_vtbl =
1778 {
1779     fnIEnumScript_QueryInterface,
1780     fnIEnumScript_AddRef,
1781     fnIEnumScript_Release,
1782     fnIEnumScript_Clone,
1783     fnIEnumScript_Next,
1784     fnIEnumScript_Reset,
1785     fnIEnumScript_Skip
1786 };
1787
1788 static HRESULT EnumScript_create( MLang_impl* mlang, DWORD dwFlags,
1789                      LANGID LangId, IEnumScript** ppEnumScript )
1790 {
1791     EnumScript_impl *es;
1792     UINT i;
1793
1794     TRACE("%p, %08x, %04x, %p: stub!\n", mlang, dwFlags, LangId, ppEnumScript);
1795
1796     if (!dwFlags) /* enumerate all available scripts */
1797         dwFlags = SCRIPTCONTF_SCRIPT_USER | SCRIPTCONTF_SCRIPT_HIDE | SCRIPTCONTF_SCRIPT_SYSTEM;
1798
1799     es = HeapAlloc( GetProcessHeap(), 0, sizeof (EnumScript_impl) );
1800     es->vtbl_IEnumScript = &IEnumScript_vtbl;
1801     es->ref = 1;
1802     es->pos = 0;
1803     /* do not enumerate unicode flavours */
1804     es->total = sizeof(mlang_data)/sizeof(mlang_data[0]) - 1;
1805     es->script_info = HeapAlloc(GetProcessHeap(), 0, sizeof(SCRIPTINFO) * es->total);
1806
1807     for (i = 0; i < es->total; i++)
1808     {
1809         es->script_info[i].ScriptId = i;
1810         es->script_info[i].uiCodePage = mlang_data[i].family_codepage;
1811         MultiByteToWideChar(CP_ACP, 0, mlang_data[i].description, -1,
1812             es->script_info[i].wszDescription, MAX_SCRIPT_NAME);
1813         MultiByteToWideChar(CP_ACP, 0, mlang_data[i].fixed_font, -1,
1814             es->script_info[i].wszFixedWidthFont, MAX_MIMEFACE_NAME);
1815         MultiByteToWideChar(CP_ACP, 0, mlang_data[i].proportional_font, -1,
1816             es->script_info[i].wszProportionalFont, MAX_MIMEFACE_NAME);
1817     }
1818
1819     TRACE("enumerated %d scripts with flags %08x\n", es->total, dwFlags);
1820
1821     *ppEnumScript = (IEnumScript *)es;
1822
1823     return S_OK;
1824 }
1825
1826 /******************************************************************************/
1827
1828 static HRESULT WINAPI fnIMLangFontLink_QueryInterface(
1829         IMLangFontLink* iface,
1830         REFIID riid,
1831         void** ppvObject)
1832 {
1833     ICOM_THIS_MULTI(MLang_impl, vtbl_IMLangFontLink, iface);
1834     return MLang_QueryInterface( This, riid, ppvObject );
1835 }
1836
1837 static ULONG WINAPI fnIMLangFontLink_AddRef(
1838         IMLangFontLink* iface)
1839 {
1840     ICOM_THIS_MULTI(MLang_impl, vtbl_IMLangFontLink, iface);
1841     return MLang_AddRef( This );
1842 }
1843
1844 static ULONG WINAPI fnIMLangFontLink_Release(
1845         IMLangFontLink* iface)
1846 {
1847     ICOM_THIS_MULTI(MLang_impl, vtbl_IMLangFontLink, iface);
1848     return MLang_Release( This );
1849 }
1850
1851 static HRESULT WINAPI fnIMLangFontLink_GetCharCodePages(
1852         IMLangFontLink* iface,
1853         WCHAR chSrc,
1854         DWORD* pdwCodePages)
1855 {
1856     int i;
1857     CHAR buf;
1858     BOOL used_dc;
1859     DWORD codePages;
1860
1861     *pdwCodePages = 0;
1862
1863     for (i = 0; i < sizeof(mlang_data)/sizeof(mlang_data[0]); i++)
1864     {
1865         WideCharToMultiByte(mlang_data[i].family_codepage, WC_NO_BEST_FIT_CHARS,
1866             &chSrc, 1, &buf, 1, NULL, &used_dc);
1867
1868         /* If default char is not used, current codepage include the given symbol */
1869         if (!used_dc)
1870         {
1871             IMLangFontLink_CodePageToCodePages(iface,
1872                 mlang_data[i].family_codepage, &codePages);
1873             *pdwCodePages |= codePages;
1874         }
1875     }
1876     return S_OK;
1877 }
1878
1879 static HRESULT WINAPI fnIMLangFontLink_GetStrCodePages(
1880         IMLangFontLink* iface,
1881         const WCHAR* pszSrc,
1882         long cchSrc,
1883         DWORD dwPriorityCodePages,
1884         DWORD* pdwCodePages,
1885         long* pcchCodePages)
1886 {
1887     FIXME("(pszSrc=%s, cchSrc=%ld, dwPriorityCodePages=%d) stub\n", debugstr_w(pszSrc), cchSrc, dwPriorityCodePages);
1888     *pdwCodePages = 0;
1889     *pcchCodePages = 1;
1890     return S_OK;
1891 }
1892
1893 static HRESULT WINAPI fnIMLangFontLink_CodePageToCodePages(
1894         IMLangFontLink* iface,
1895         UINT uCodePage,
1896         DWORD* pdwCodePages)
1897 {
1898     ICOM_THIS_MULTI(MLang_impl, vtbl_IMLangFontLink, iface);
1899     CHARSETINFO cs;
1900     BOOL rc; 
1901
1902     TRACE("(%p) Seeking %u\n",This, uCodePage);
1903
1904     rc = TranslateCharsetInfo((DWORD*)uCodePage, &cs, TCI_SRCCODEPAGE);
1905
1906     if (rc)
1907     {
1908         *pdwCodePages = cs.fs.fsCsb[0];
1909         TRACE("resulting CodePages 0x%x\n",*pdwCodePages);
1910         return S_OK;
1911     }
1912
1913     TRACE("CodePage Not Found\n");
1914     *pdwCodePages = 0;
1915     return E_FAIL;
1916 }
1917
1918 static HRESULT WINAPI fnIMLangFontLink_CodePagesToCodePage(
1919         IMLangFontLink* iface,
1920         DWORD dwCodePages,
1921         UINT uDefaultCodePage,
1922         UINT* puCodePage)
1923 {
1924     ICOM_THIS_MULTI(MLang_impl, vtbl_IMLangFontLink, iface);
1925     DWORD mask = 0x00000000;
1926     UINT i;
1927     CHARSETINFO cs;
1928     BOOL rc; 
1929
1930     TRACE("(%p) scanning  0x%x  default page %u\n",This, dwCodePages,
1931             uDefaultCodePage);
1932
1933     *puCodePage = 0x00000000;
1934
1935     rc = TranslateCharsetInfo((DWORD*)uDefaultCodePage, &cs, TCI_SRCCODEPAGE);
1936   
1937     if (rc && (dwCodePages & cs.fs.fsCsb[0]))
1938     {
1939         TRACE("Found Default Codepage\n");
1940         *puCodePage = uDefaultCodePage;
1941         return S_OK;
1942     }
1943
1944     
1945     for (i = 0; i < 32; i++)
1946     {
1947
1948         mask = 1 << i;
1949         if (dwCodePages & mask)
1950         {
1951             DWORD Csb[2];
1952             Csb[0] = mask;
1953             Csb[1] = 0x0;
1954             rc = TranslateCharsetInfo(Csb, &cs, TCI_SRCFONTSIG);
1955             if (!rc)
1956                 continue;
1957
1958             TRACE("Falling back to least significant found CodePage %u\n",
1959                     cs.ciACP);
1960             *puCodePage = cs.ciACP;
1961             return S_OK;
1962         }
1963     }
1964
1965     TRACE("no codepage found\n");
1966     return E_FAIL;
1967 }
1968
1969 static HRESULT WINAPI fnIMLangFontLink_GetFontCodePages(
1970         IMLangFontLink* iface,
1971         HDC hDC,
1972         HFONT hFont,
1973         DWORD* pdwCodePages)
1974 {
1975     HFONT old_font;
1976     FONTSIGNATURE fontsig;
1977     ICOM_THIS_MULTI(MLang_impl, vtbl_IMLangFontLink, iface);
1978
1979     TRACE("(%p)\n",This);
1980
1981     old_font = SelectObject(hDC,hFont);
1982     GetTextCharsetInfo(hDC,&fontsig, 0);
1983     SelectObject(hDC,old_font);
1984
1985     *pdwCodePages = fontsig.fsCsb[0];
1986     TRACE("CodePages is 0x%x\n",fontsig.fsCsb[0]);
1987
1988     return S_OK;
1989 }
1990
1991 static HRESULT WINAPI fnIMLangFontLink_MapFont(
1992         IMLangFontLink* iface,
1993         HDC hDC,
1994         DWORD dwCodePages,
1995         HFONT hSrcFont,
1996         HFONT* phDestFont)
1997 {
1998     FIXME("\n");
1999     return E_NOTIMPL;
2000 }
2001
2002 static HRESULT WINAPI fnIMLangFontLink_ReleaseFont(
2003         IMLangFontLink* iface,
2004         HFONT hFont)
2005 {
2006     FIXME("\n");
2007     return E_NOTIMPL;
2008 }
2009
2010 static HRESULT WINAPI fnIMLangFontLink_ResetFontMapping(
2011         IMLangFontLink* iface)
2012 {
2013     FIXME("\n");
2014     return E_NOTIMPL;
2015 }
2016
2017
2018 static const IMLangFontLinkVtbl IMLangFontLink_vtbl =
2019 {
2020     fnIMLangFontLink_QueryInterface,
2021     fnIMLangFontLink_AddRef,
2022     fnIMLangFontLink_Release,
2023     fnIMLangFontLink_GetCharCodePages,
2024     fnIMLangFontLink_GetStrCodePages,
2025     fnIMLangFontLink_CodePageToCodePages,
2026     fnIMLangFontLink_CodePagesToCodePage,
2027     fnIMLangFontLink_GetFontCodePages,
2028     fnIMLangFontLink_MapFont,
2029     fnIMLangFontLink_ReleaseFont,
2030     fnIMLangFontLink_ResetFontMapping,
2031 };
2032
2033 /******************************************************************************/
2034
2035 static HRESULT WINAPI fnIMultiLanguage_QueryInterface(
2036     IMultiLanguage* iface,
2037     REFIID riid,
2038     void** ppvObject)
2039 {
2040     ICOM_THIS_MULTI(MLang_impl, vtbl_IMultiLanguage, iface);
2041     return MLang_QueryInterface( This, riid, ppvObject );
2042 }
2043
2044 static ULONG WINAPI fnIMultiLanguage_AddRef( IMultiLanguage* iface )
2045 {
2046     ICOM_THIS_MULTI(MLang_impl, vtbl_IMultiLanguage, iface);
2047     return IMLangFontLink_AddRef( ((IMLangFontLink*)This) );
2048 }
2049
2050 static ULONG WINAPI fnIMultiLanguage_Release( IMultiLanguage* iface )
2051 {
2052     ICOM_THIS_MULTI(MLang_impl, vtbl_IMultiLanguage, iface);
2053     return IMLangFontLink_Release( ((IMLangFontLink*)This) );
2054 }
2055
2056 static HRESULT WINAPI fnIMultiLanguage_GetNumberOfCodePageInfo(
2057     IMultiLanguage* iface,
2058     UINT* pcCodePage)
2059 {
2060     FIXME("\n");
2061     return E_NOTIMPL;
2062 }
2063
2064 static HRESULT WINAPI fnIMultiLanguage_GetCodePageInfo(
2065     IMultiLanguage* iface,
2066     UINT uiCodePage,
2067     PMIMECPINFO pCodePageInfo)
2068 {
2069     UINT i, n;
2070
2071     ICOM_THIS_MULTI(MLang_impl, vtbl_IMultiLanguage, iface);
2072     TRACE("%p, %u, %p\n", This, uiCodePage, pCodePageInfo);
2073
2074     for (i = 0; i < sizeof(mlang_data)/sizeof(mlang_data[0]); i++)
2075     {
2076         for (n = 0; n < mlang_data[i].number_of_cp; n++)
2077         {
2078             if (mlang_data[i].mime_cp_info[n].cp == uiCodePage)
2079             {
2080                 fill_cp_info(&mlang_data[i], n, pCodePageInfo);
2081                 return S_OK;
2082             }
2083         }
2084     }
2085
2086     return S_FALSE;
2087 }
2088
2089 static HRESULT WINAPI fnIMultiLanguage_GetFamilyCodePage(
2090     IMultiLanguage* iface,
2091     UINT uiCodePage,
2092     UINT* puiFamilyCodePage)
2093 {
2094     return GetFamilyCodePage(uiCodePage, puiFamilyCodePage);
2095 }
2096
2097 static HRESULT WINAPI fnIMultiLanguage_EnumCodePages(
2098     IMultiLanguage* iface,
2099     DWORD grfFlags,
2100     IEnumCodePage** ppEnumCodePage)
2101 {
2102     ICOM_THIS_MULTI(MLang_impl, vtbl_IMultiLanguage, iface);
2103     TRACE("%p %08x %p\n", This, grfFlags, ppEnumCodePage);
2104
2105     return EnumCodePage_create( This, grfFlags, 0, ppEnumCodePage );
2106 }
2107
2108 static HRESULT WINAPI fnIMultiLanguage_GetCharsetInfo(
2109     IMultiLanguage* iface,
2110     BSTR Charset,
2111     PMIMECSETINFO pCharsetInfo)
2112 {
2113     ICOM_THIS_MULTI(MLang_impl, vtbl_IMultiLanguage, iface);
2114     return IMultiLanguage3_GetCharsetInfo((IMultiLanguage3*)&This->vtbl_IMultiLanguage3, Charset, pCharsetInfo);
2115 }
2116
2117 static HRESULT WINAPI fnIMultiLanguage_IsConvertible(
2118     IMultiLanguage* iface,
2119     DWORD dwSrcEncoding,
2120     DWORD dwDstEncoding)
2121 {
2122     return IsConvertINetStringAvailable(dwSrcEncoding, dwDstEncoding);
2123 }
2124
2125 static HRESULT WINAPI fnIMultiLanguage_ConvertString(
2126     IMultiLanguage* iface,
2127     DWORD* pdwMode,
2128     DWORD dwSrcEncoding,
2129     DWORD dwDstEncoding,
2130     BYTE* pSrcStr,
2131     UINT* pcSrcSize,
2132     BYTE* pDstStr,
2133     UINT* pcDstSize)
2134 {
2135     return ConvertINetString(pdwMode, dwSrcEncoding, dwDstEncoding,
2136         (LPCSTR)pSrcStr, (LPINT)pcSrcSize, (LPSTR)pDstStr, (LPINT)pcDstSize);
2137 }
2138
2139 static HRESULT WINAPI fnIMultiLanguage_ConvertStringToUnicode(
2140     IMultiLanguage* iface,
2141     DWORD* pdwMode,
2142     DWORD dwEncoding,
2143     CHAR* pSrcStr,
2144     UINT* pcSrcSize,
2145     WCHAR* pDstStr,
2146     UINT* pcDstSize)
2147 {
2148     return ConvertINetMultiByteToUnicode(pdwMode, dwEncoding,
2149         (LPCSTR)pSrcStr, (LPINT)pcSrcSize, pDstStr, (LPINT)pcDstSize);
2150 }
2151
2152 static HRESULT WINAPI fnIMultiLanguage_ConvertStringFromUnicode(
2153     IMultiLanguage* iface,
2154     DWORD* pdwMode,
2155     DWORD dwEncoding,
2156     WCHAR* pSrcStr,
2157     UINT* pcSrcSize,
2158     CHAR* pDstStr,
2159     UINT* pcDstSize)
2160 {
2161     return ConvertINetUnicodeToMultiByte(pdwMode, dwEncoding,
2162         pSrcStr, (LPINT)pcSrcSize, pDstStr, (LPINT)pcDstSize);
2163 }
2164
2165 static HRESULT WINAPI fnIMultiLanguage_ConvertStringReset(
2166     IMultiLanguage* iface)
2167 {
2168     FIXME("\n");
2169     return E_NOTIMPL;
2170 }
2171
2172 static HRESULT WINAPI fnIMultiLanguage_GetRfc1766FromLcid(
2173     IMultiLanguage* iface,
2174     LCID lcid,
2175     BSTR* pbstrRfc1766)
2176 {
2177     WCHAR buf[MAX_RFC1766_NAME];
2178
2179     TRACE("%p %04x %p\n", iface, lcid, pbstrRfc1766);
2180
2181     if (lcid_to_rfc1766W( lcid, buf, MAX_RFC1766_NAME ))
2182     {
2183         *pbstrRfc1766 = SysAllocString( buf );
2184         return S_OK;
2185     }
2186     return E_FAIL;
2187 }
2188
2189 static HRESULT WINAPI fnIMultiLanguage_GetLcidFromRfc1766(
2190     IMultiLanguage* iface,
2191     LCID* pLocale,
2192     BSTR bstrRfc1766)
2193 {
2194     HRESULT hr;
2195     IEnumRfc1766 *rfc1766;
2196
2197     TRACE("%p %p %s\n", iface, pLocale, debugstr_w(bstrRfc1766));
2198
2199     if (!pLocale || !bstrRfc1766)
2200         return E_INVALIDARG;
2201
2202     hr = IMultiLanguage_EnumRfc1766(iface, &rfc1766);
2203     if (FAILED(hr))
2204         return hr;
2205
2206     hr = lcid_from_rfc1766(rfc1766, pLocale, bstrRfc1766);
2207
2208     IEnumRfc1766_Release(rfc1766);
2209     return hr;
2210 }
2211
2212 /******************************************************************************/
2213
2214 typedef struct tagEnumRfc1766_impl
2215 {
2216     const IEnumRfc1766Vtbl *vtbl_IEnumRfc1766;
2217     LONG ref;
2218     RFC1766INFO *info;
2219     DWORD total, pos;
2220 } EnumRfc1766_impl;
2221
2222 static HRESULT WINAPI fnIEnumRfc1766_QueryInterface(
2223         IEnumRfc1766 *iface,
2224         REFIID riid,
2225         void** ppvObject)
2226 {
2227     ICOM_THIS_MULTI(EnumRfc1766_impl, vtbl_IEnumRfc1766, iface);
2228
2229     TRACE("%p -> %s\n", This, debugstr_guid(riid) );
2230
2231     if (IsEqualGUID(riid, &IID_IUnknown)
2232         || IsEqualGUID(riid, &IID_IEnumRfc1766))
2233     {
2234         IEnumRfc1766_AddRef(iface);
2235         TRACE("Returning IID_IEnumRfc1766 %p ref = %d\n", This, This->ref);
2236         *ppvObject = &(This->vtbl_IEnumRfc1766);
2237         return S_OK;
2238     }
2239
2240     WARN("(%p) -> (%s,%p), not found\n",This,debugstr_guid(riid),ppvObject);
2241     return E_NOINTERFACE;
2242 }
2243
2244 static ULONG WINAPI fnIEnumRfc1766_AddRef(
2245         IEnumRfc1766 *iface)
2246 {
2247     ICOM_THIS_MULTI(EnumRfc1766_impl, vtbl_IEnumRfc1766, iface);
2248     return InterlockedIncrement(&This->ref);
2249 }
2250
2251 static ULONG WINAPI fnIEnumRfc1766_Release(
2252         IEnumRfc1766 *iface)
2253 {
2254     ICOM_THIS_MULTI(EnumRfc1766_impl, vtbl_IEnumRfc1766, iface);
2255     ULONG ref = InterlockedDecrement(&This->ref);
2256
2257     TRACE("%p ref = %d\n", This, ref);
2258     if (ref == 0)
2259     {
2260         TRACE("Destroying %p\n", This);
2261         HeapFree(GetProcessHeap(), 0, This->info);
2262         HeapFree(GetProcessHeap(), 0, This);
2263     }
2264     return ref;
2265 }
2266
2267 static HRESULT WINAPI fnIEnumRfc1766_Clone(
2268         IEnumRfc1766 *iface,
2269         IEnumRfc1766 **ppEnum)
2270 {
2271     ICOM_THIS_MULTI(EnumRfc1766_impl, vtbl_IEnumRfc1766, iface);
2272     FIXME("%p %p\n", This, ppEnum);
2273     return E_NOTIMPL;
2274 }
2275
2276 static  HRESULT WINAPI fnIEnumRfc1766_Next(
2277         IEnumRfc1766 *iface,
2278         ULONG celt,
2279         PRFC1766INFO rgelt,
2280         ULONG *pceltFetched)
2281 {
2282     ULONG i;
2283
2284     ICOM_THIS_MULTI(EnumRfc1766_impl, vtbl_IEnumRfc1766, iface);
2285     TRACE("%p %u %p %p\n", This, celt, rgelt, pceltFetched);
2286
2287     if (!pceltFetched) return S_FALSE;
2288     *pceltFetched = 0;
2289
2290     if (!rgelt) return S_FALSE;
2291
2292     if (This->pos + celt > This->total)
2293         celt = This->total - This->pos;
2294
2295     if (!celt) return S_FALSE;
2296
2297     memcpy(rgelt, This->info + This->pos, celt * sizeof(RFC1766INFO));
2298     *pceltFetched = celt;
2299     This->pos += celt;
2300
2301     for (i = 0; i < celt; i++)
2302     {
2303         TRACE("#%u: %08x %s %s\n",
2304               i, rgelt[i].lcid,
2305               wine_dbgstr_w(rgelt[i].wszRfc1766),
2306               wine_dbgstr_w(rgelt[i].wszLocaleName));
2307     }
2308     return S_OK;
2309 }
2310
2311 static HRESULT WINAPI fnIEnumRfc1766_Reset(
2312         IEnumRfc1766 *iface)
2313 {
2314     ICOM_THIS_MULTI(EnumRfc1766_impl, vtbl_IEnumRfc1766, iface);
2315     TRACE("%p\n", This);
2316
2317     This->pos = 0;
2318     return S_OK;
2319 }
2320
2321 static  HRESULT WINAPI fnIEnumRfc1766_Skip(
2322         IEnumRfc1766 *iface,
2323         ULONG celt)
2324 {
2325     ICOM_THIS_MULTI(EnumRfc1766_impl, vtbl_IEnumRfc1766, iface);
2326     TRACE("%p %u\n", This, celt);
2327
2328     if (celt >= This->total) return S_FALSE;
2329
2330     This->pos += celt;
2331     return S_OK;
2332 }
2333
2334 static const IEnumRfc1766Vtbl IEnumRfc1766_vtbl =
2335 {
2336     fnIEnumRfc1766_QueryInterface,
2337     fnIEnumRfc1766_AddRef,
2338     fnIEnumRfc1766_Release,
2339     fnIEnumRfc1766_Clone,
2340     fnIEnumRfc1766_Next,
2341     fnIEnumRfc1766_Reset,
2342     fnIEnumRfc1766_Skip
2343 };
2344
2345 struct enum_locales_data
2346 {
2347     RFC1766INFO *info;
2348     DWORD total, allocated;
2349 };
2350
2351 static BOOL CALLBACK enum_locales_proc(LPWSTR locale)
2352 {
2353     WCHAR *end;
2354     struct enum_locales_data *data = TlsGetValue(MLANG_tls_index);
2355     RFC1766INFO *info;
2356
2357     TRACE("%s\n", debugstr_w(locale));
2358
2359     if (data->total >= data->allocated)
2360     {
2361         data->allocated += 32;
2362         data->info = HeapReAlloc(GetProcessHeap(), 0, data->info, data->allocated * sizeof(RFC1766INFO));
2363         if (!data->info) return FALSE;
2364     }
2365
2366     info = &data->info[data->total];
2367
2368     info->lcid = strtolW(locale, &end, 16);
2369     if (*end) /* invalid number */
2370         return FALSE;
2371
2372     info->wszRfc1766[0] = 0;
2373     lcid_to_rfc1766W( info->lcid, info->wszRfc1766, MAX_RFC1766_NAME );
2374
2375     info->wszLocaleName[0] = 0;
2376     GetLocaleInfoW(info->lcid, LOCALE_SLANGUAGE, info->wszLocaleName, MAX_LOCALE_NAME);
2377     TRACE("ISO639: %s SLANGUAGE: %s\n", wine_dbgstr_w(info->wszRfc1766), wine_dbgstr_w(info->wszLocaleName));
2378     
2379     data->total++;
2380
2381     return TRUE;
2382 }
2383
2384 static HRESULT EnumRfc1766_create(LANGID LangId, IEnumRfc1766 **ppEnum)
2385 {
2386     EnumRfc1766_impl *rfc;
2387     struct enum_locales_data data;
2388
2389     TRACE("%04x, %p\n", LangId, ppEnum);
2390
2391     rfc = HeapAlloc( GetProcessHeap(), 0, sizeof(EnumRfc1766_impl) );
2392     rfc->vtbl_IEnumRfc1766 = &IEnumRfc1766_vtbl;
2393     rfc->ref = 1;
2394     rfc->pos = 0;
2395     rfc->total = 0;
2396
2397     data.total = 0;
2398     data.allocated = 32;
2399     data.info = HeapAlloc(GetProcessHeap(), 0, data.allocated * sizeof(RFC1766INFO));
2400     if (!data.info)
2401     {
2402         HeapFree(GetProcessHeap(), 0, rfc);
2403         return S_FALSE;
2404     }
2405
2406     TlsSetValue(MLANG_tls_index, &data);
2407     EnumSystemLocalesW(enum_locales_proc, 0/*LOCALE_SUPPORTED*/);
2408     TlsSetValue(MLANG_tls_index, NULL);
2409
2410     TRACE("enumerated %d rfc1766 structures\n", data.total);
2411
2412     if (!data.total)
2413     {
2414         HeapFree(GetProcessHeap(), 0, data.info);
2415         HeapFree(GetProcessHeap(), 0, rfc);
2416         return FALSE;
2417     }
2418
2419     rfc->info = data.info;
2420     rfc->total = data.total;
2421
2422     *ppEnum = (IEnumRfc1766 *)rfc;
2423     return S_OK;
2424 }
2425
2426 static HRESULT WINAPI fnIMultiLanguage_EnumRfc1766(
2427     IMultiLanguage *iface,
2428     IEnumRfc1766 **ppEnumRfc1766)
2429 {
2430     ICOM_THIS_MULTI(MLang_impl, vtbl_IMultiLanguage, iface);
2431     TRACE("%p %p\n", This, ppEnumRfc1766);
2432
2433     return EnumRfc1766_create(0, ppEnumRfc1766);
2434 }
2435
2436 /******************************************************************************/
2437
2438 static HRESULT WINAPI fnIMultiLanguage_GetRfc1766Info(
2439     IMultiLanguage* iface,
2440     LCID Locale,
2441     PRFC1766INFO pRfc1766Info)
2442 {
2443     FIXME("\n");
2444     return E_NOTIMPL;
2445 }
2446
2447 static HRESULT WINAPI fnIMultiLanguage_CreateConvertCharset(
2448     IMultiLanguage* iface,
2449     UINT uiSrcCodePage,
2450     UINT uiDstCodePage,
2451     DWORD dwProperty,
2452     IMLangConvertCharset** ppMLangConvertCharset)
2453 {
2454     FIXME("\n");
2455     return E_NOTIMPL;
2456 }
2457
2458 static const IMultiLanguageVtbl IMultiLanguage_vtbl =
2459 {
2460     fnIMultiLanguage_QueryInterface,
2461     fnIMultiLanguage_AddRef,
2462     fnIMultiLanguage_Release,
2463     fnIMultiLanguage_GetNumberOfCodePageInfo,
2464     fnIMultiLanguage_GetCodePageInfo,
2465     fnIMultiLanguage_GetFamilyCodePage,
2466     fnIMultiLanguage_EnumCodePages,
2467     fnIMultiLanguage_GetCharsetInfo,
2468     fnIMultiLanguage_IsConvertible,
2469     fnIMultiLanguage_ConvertString,
2470     fnIMultiLanguage_ConvertStringToUnicode,
2471     fnIMultiLanguage_ConvertStringFromUnicode,
2472     fnIMultiLanguage_ConvertStringReset,
2473     fnIMultiLanguage_GetRfc1766FromLcid,
2474     fnIMultiLanguage_GetLcidFromRfc1766,
2475     fnIMultiLanguage_EnumRfc1766,
2476     fnIMultiLanguage_GetRfc1766Info,
2477     fnIMultiLanguage_CreateConvertCharset,
2478 };
2479
2480
2481 /******************************************************************************/
2482
2483 static HRESULT WINAPI fnIMultiLanguage2_QueryInterface(
2484     IMultiLanguage3* iface,
2485     REFIID riid,
2486     void** ppvObject)
2487 {
2488     ICOM_THIS_MULTI(MLang_impl, vtbl_IMultiLanguage3, iface);
2489     return MLang_QueryInterface( This, riid, ppvObject );
2490 }
2491
2492 static ULONG WINAPI fnIMultiLanguage2_AddRef( IMultiLanguage3* iface )
2493 {
2494     ICOM_THIS_MULTI(MLang_impl, vtbl_IMultiLanguage3, iface);
2495     return MLang_AddRef( This );
2496 }
2497
2498 static ULONG WINAPI fnIMultiLanguage2_Release( IMultiLanguage3* iface )
2499 {
2500     ICOM_THIS_MULTI(MLang_impl, vtbl_IMultiLanguage3, iface);
2501     return MLang_Release( This );
2502 }
2503
2504 static HRESULT WINAPI fnIMultiLanguage2_GetNumberOfCodePageInfo(
2505     IMultiLanguage3* iface,
2506     UINT* pcCodePage)
2507 {
2508     ICOM_THIS_MULTI(MLang_impl, vtbl_IMultiLanguage3, iface);
2509     TRACE("%p, %p\n", This, pcCodePage);
2510
2511     if (!pcCodePage) return S_FALSE;
2512
2513     *pcCodePage = This->total_cp;
2514     return S_OK;
2515 }
2516
2517 static void fill_cp_info(const struct mlang_data *ml_data, UINT index, MIMECPINFO *mime_cp_info)
2518 {
2519     CHARSETINFO csi;
2520
2521     if (TranslateCharsetInfo((DWORD *)ml_data->family_codepage, &csi, TCI_SRCCODEPAGE))
2522         mime_cp_info->bGDICharset = csi.ciCharset;
2523     else
2524         mime_cp_info->bGDICharset = DEFAULT_CHARSET;
2525
2526     mime_cp_info->dwFlags = ml_data->mime_cp_info[index].flags;
2527     mime_cp_info->uiCodePage = ml_data->mime_cp_info[index].cp;
2528     mime_cp_info->uiFamilyCodePage = ml_data->family_codepage;
2529     MultiByteToWideChar(CP_ACP, 0, ml_data->mime_cp_info[index].description, -1,
2530                         mime_cp_info->wszDescription, sizeof(mime_cp_info->wszDescription)/sizeof(WCHAR));
2531     MultiByteToWideChar(CP_ACP, 0, ml_data->mime_cp_info[index].web_charset, -1,
2532                         mime_cp_info->wszWebCharset, sizeof(mime_cp_info->wszWebCharset)/sizeof(WCHAR));
2533     MultiByteToWideChar(CP_ACP, 0, ml_data->mime_cp_info[index].header_charset, -1,
2534                         mime_cp_info->wszHeaderCharset, sizeof(mime_cp_info->wszHeaderCharset)/sizeof(WCHAR));
2535     MultiByteToWideChar(CP_ACP, 0, ml_data->mime_cp_info[index].body_charset, -1,
2536                         mime_cp_info->wszBodyCharset, sizeof(mime_cp_info->wszBodyCharset)/sizeof(WCHAR));
2537
2538     MultiByteToWideChar(CP_ACP, 0, ml_data->fixed_font, -1,
2539         mime_cp_info->wszFixedWidthFont, sizeof(mime_cp_info->wszFixedWidthFont)/sizeof(WCHAR));
2540     MultiByteToWideChar(CP_ACP, 0, ml_data->proportional_font, -1,
2541         mime_cp_info->wszProportionalFont, sizeof(mime_cp_info->wszProportionalFont)/sizeof(WCHAR));
2542
2543     TRACE("%08x %u %u %s %s %s %s %s %s %d\n",
2544           mime_cp_info->dwFlags, mime_cp_info->uiCodePage,
2545           mime_cp_info->uiFamilyCodePage,
2546           wine_dbgstr_w(mime_cp_info->wszDescription),
2547           wine_dbgstr_w(mime_cp_info->wszWebCharset),
2548           wine_dbgstr_w(mime_cp_info->wszHeaderCharset),
2549           wine_dbgstr_w(mime_cp_info->wszBodyCharset),
2550           wine_dbgstr_w(mime_cp_info->wszFixedWidthFont),
2551           wine_dbgstr_w(mime_cp_info->wszProportionalFont),
2552           mime_cp_info->bGDICharset);
2553 }
2554
2555 static HRESULT WINAPI fnIMultiLanguage2_GetCodePageInfo(
2556     IMultiLanguage3* iface,
2557     UINT uiCodePage,
2558     LANGID LangId,
2559     PMIMECPINFO pCodePageInfo)
2560 {
2561     UINT i, n;
2562
2563     ICOM_THIS_MULTI(MLang_impl, vtbl_IMultiLanguage3, iface);
2564     TRACE("%p, %u, %04x, %p\n", This, uiCodePage, LangId, pCodePageInfo);
2565
2566     for (i = 0; i < sizeof(mlang_data)/sizeof(mlang_data[0]); i++)
2567     {
2568         for (n = 0; n < mlang_data[i].number_of_cp; n++)
2569         {
2570             if (mlang_data[i].mime_cp_info[n].cp == uiCodePage)
2571             {
2572                 fill_cp_info(&mlang_data[i], n, pCodePageInfo);
2573                 return S_OK;
2574             }
2575         }
2576     }
2577
2578     return S_FALSE;
2579 }
2580
2581 static HRESULT WINAPI fnIMultiLanguage2_GetFamilyCodePage(
2582     IMultiLanguage3* iface,
2583     UINT uiCodePage,
2584     UINT* puiFamilyCodePage)
2585 {
2586     return GetFamilyCodePage(uiCodePage, puiFamilyCodePage);
2587 }
2588
2589 static HRESULT WINAPI fnIMultiLanguage2_EnumCodePages(
2590     IMultiLanguage3* iface,
2591     DWORD grfFlags,
2592     LANGID LangId,
2593     IEnumCodePage** ppEnumCodePage)
2594 {
2595     ICOM_THIS_MULTI(MLang_impl, vtbl_IMultiLanguage3, iface);
2596     TRACE("%p %08x %04x %p\n", This, grfFlags, LangId, ppEnumCodePage);
2597
2598     return EnumCodePage_create( This, grfFlags, LangId, ppEnumCodePage );
2599 }
2600
2601 static HRESULT WINAPI fnIMultiLanguage2_GetCharsetInfo(
2602     IMultiLanguage3* iface,
2603     BSTR Charset,
2604     PMIMECSETINFO pCharsetInfo)
2605 {
2606     UINT i, n;
2607
2608     ICOM_THIS_MULTI(MLang_impl, vtbl_IMultiLanguage3, iface);
2609     TRACE("%p %s %p\n", This, debugstr_w(Charset), pCharsetInfo);
2610
2611     if (!pCharsetInfo) return E_FAIL;
2612
2613     for (i = 0; i < sizeof(mlang_data)/sizeof(mlang_data[0]); i++)
2614     {
2615         for (n = 0; n < mlang_data[i].number_of_cp; n++)
2616         {
2617             WCHAR csetW[MAX_MIMECSET_NAME];
2618
2619             MultiByteToWideChar(CP_ACP, 0, mlang_data[i].mime_cp_info[n].web_charset, -1, csetW, MAX_MIMECSET_NAME);
2620             if (!lstrcmpiW(Charset, csetW))
2621             {
2622                 pCharsetInfo->uiCodePage = mlang_data[i].family_codepage;
2623                 pCharsetInfo->uiInternetEncoding = mlang_data[i].mime_cp_info[n].cp;
2624                 strcpyW(pCharsetInfo->wszCharset, csetW);
2625                 return S_OK;
2626             }
2627         }
2628     }
2629
2630     /* FIXME:
2631      * Since we do not support charsets like iso-2022-jp and do not have
2632      * them in our database as a primary (web_charset) encoding this loop
2633      * does an attempt to 'approximate' charset name by header_charset.
2634      */
2635     for (i = 0; i < sizeof(mlang_data)/sizeof(mlang_data[0]); i++)
2636     {
2637         for (n = 0; n < mlang_data[i].number_of_cp; n++)
2638         {
2639             WCHAR csetW[MAX_MIMECSET_NAME];
2640
2641             MultiByteToWideChar(CP_ACP, 0, mlang_data[i].mime_cp_info[n].header_charset, -1, csetW, MAX_MIMECSET_NAME);
2642             if (!lstrcmpiW(Charset, csetW))
2643             {
2644                 pCharsetInfo->uiCodePage = mlang_data[i].family_codepage;
2645                 pCharsetInfo->uiInternetEncoding = mlang_data[i].mime_cp_info[n].cp;
2646                 strcpyW(pCharsetInfo->wszCharset, csetW);
2647                 return S_OK;
2648             }
2649         }
2650     }
2651
2652     return E_FAIL;
2653 }
2654
2655 static HRESULT WINAPI fnIMultiLanguage2_IsConvertible(
2656     IMultiLanguage3* iface,
2657     DWORD dwSrcEncoding,
2658     DWORD dwDstEncoding)
2659 {
2660     return IsConvertINetStringAvailable(dwSrcEncoding, dwDstEncoding);
2661 }
2662
2663 static HRESULT WINAPI fnIMultiLanguage2_ConvertString(
2664     IMultiLanguage3* iface,
2665     DWORD* pdwMode,
2666     DWORD dwSrcEncoding,
2667     DWORD dwDstEncoding,
2668     BYTE* pSrcStr,
2669     UINT* pcSrcSize,
2670     BYTE* pDstStr,
2671     UINT* pcDstSize)
2672 {
2673     return ConvertINetString(pdwMode, dwSrcEncoding, dwDstEncoding,
2674         (LPCSTR)pSrcStr, (LPINT)pcSrcSize, (LPSTR)pDstStr, (LPINT)pcDstSize);
2675 }
2676
2677 static HRESULT WINAPI fnIMultiLanguage2_ConvertStringToUnicode(
2678     IMultiLanguage3* iface,
2679     DWORD* pdwMode,
2680     DWORD dwEncoding,
2681     CHAR* pSrcStr,
2682     UINT* pcSrcSize,
2683     WCHAR* pDstStr,
2684     UINT* pcDstSize)
2685 {
2686     return ConvertINetMultiByteToUnicode(pdwMode, dwEncoding,
2687         pSrcStr, (LPINT)pcSrcSize, pDstStr, (LPINT)pcDstSize);
2688 }
2689
2690 static HRESULT WINAPI fnIMultiLanguage2_ConvertStringFromUnicode(
2691     IMultiLanguage3* iface,
2692     DWORD* pdwMode,
2693     DWORD dwEncoding,
2694     WCHAR* pSrcStr,
2695     UINT* pcSrcSize,
2696     CHAR* pDstStr,
2697     UINT* pcDstSize)
2698 {
2699     return ConvertINetUnicodeToMultiByte(pdwMode, dwEncoding,
2700         pSrcStr, (LPINT)pcSrcSize, pDstStr, (LPINT)pcDstSize);
2701 }
2702
2703 static HRESULT WINAPI fnIMultiLanguage2_ConvertStringReset(
2704     IMultiLanguage3* iface)
2705 {
2706     FIXME("\n");
2707     return E_NOTIMPL;
2708 }
2709
2710 static HRESULT WINAPI fnIMultiLanguage2_GetRfc1766FromLcid(
2711     IMultiLanguage3* iface,
2712     LCID lcid,
2713     BSTR* pbstrRfc1766)
2714 {
2715     WCHAR buf[MAX_RFC1766_NAME];
2716
2717     TRACE("%p %04x %p\n", iface, lcid, pbstrRfc1766);
2718
2719     if (lcid_to_rfc1766W( lcid, buf, MAX_RFC1766_NAME ))
2720     {
2721         *pbstrRfc1766 = SysAllocString( buf );
2722         return S_OK;
2723     }
2724     return E_FAIL;
2725 }
2726
2727 static HRESULT WINAPI fnIMultiLanguage2_GetLcidFromRfc1766(
2728     IMultiLanguage3* iface,
2729     LCID* pLocale,
2730     BSTR bstrRfc1766)
2731 {
2732     HRESULT hr;
2733     IEnumRfc1766 *rfc1766;
2734
2735     TRACE("%p %p %s\n", iface, pLocale, debugstr_w(bstrRfc1766));
2736
2737     if (!pLocale || !bstrRfc1766)
2738         return E_INVALIDARG;
2739
2740     hr = IMultiLanguage2_EnumRfc1766(iface, 0, &rfc1766);
2741     if (FAILED(hr))
2742         return hr;
2743
2744     hr = lcid_from_rfc1766(rfc1766, pLocale, bstrRfc1766);
2745
2746     IEnumRfc1766_Release(rfc1766);
2747     return hr;
2748 }
2749
2750 static HRESULT WINAPI fnIMultiLanguage2_EnumRfc1766(
2751     IMultiLanguage3* iface,
2752     LANGID LangId,
2753     IEnumRfc1766** ppEnumRfc1766)
2754 {
2755     ICOM_THIS_MULTI(MLang_impl, vtbl_IMultiLanguage, iface);
2756     TRACE("%p %p\n", This, ppEnumRfc1766);
2757
2758     return EnumRfc1766_create(LangId, ppEnumRfc1766);
2759 }
2760
2761 static HRESULT WINAPI fnIMultiLanguage2_GetRfc1766Info(
2762     IMultiLanguage3* iface,
2763     LCID Locale,
2764     LANGID LangId,
2765     PRFC1766INFO pRfc1766Info)
2766 {
2767     FIXME("\n");
2768     return E_NOTIMPL;
2769 }
2770
2771 static HRESULT WINAPI fnIMultiLanguage2_CreateConvertCharset(
2772     IMultiLanguage3* iface,
2773     UINT uiSrcCodePage,
2774     UINT uiDstCodePage,
2775     DWORD dwProperty,
2776     IMLangConvertCharset** ppMLangConvertCharset)
2777 {
2778     FIXME("\n");
2779     return E_NOTIMPL;
2780 }
2781
2782 static HRESULT WINAPI fnIMultiLanguage2_ConvertStringInIStream(
2783     IMultiLanguage3* iface,
2784     DWORD* pdwMode,
2785     DWORD dwFlag,
2786     WCHAR* lpFallBack,
2787     DWORD dwSrcEncoding,
2788     DWORD dwDstEncoding,
2789     IStream* pstmIn,
2790     IStream* pstmOut)
2791 {
2792     char *src, *dst = NULL;
2793     INT srclen, dstlen;
2794     STATSTG stat;
2795     HRESULT hr;
2796
2797     TRACE("%p %0x8 %s %u %u %p %p\n",
2798           pdwMode, dwFlag, debugstr_w(lpFallBack), dwSrcEncoding, dwDstEncoding, pstmIn, pstmOut);
2799
2800     FIXME("dwFlag and lpFallBack not handled\n");
2801
2802     hr = IStream_Stat(pstmIn, &stat, STATFLAG_NONAME);
2803     if (FAILED(hr)) return hr;
2804
2805     if (stat.cbSize.QuadPart > MAXLONG) return E_INVALIDARG;
2806     if (!(src = HeapAlloc(GetProcessHeap(), 0, stat.cbSize.QuadPart))) return E_OUTOFMEMORY;
2807
2808     hr = IStream_Read(pstmIn, src, stat.cbSize.QuadPart, (ULONG *)&srclen);
2809     if (FAILED(hr)) goto exit;
2810
2811     hr = ConvertINetString(pdwMode, dwSrcEncoding, dwDstEncoding, src, &srclen, NULL, &dstlen);
2812     if (FAILED(hr)) goto exit;
2813
2814     if (!(dst = HeapAlloc(GetProcessHeap(), 0, dstlen)))
2815     {
2816         hr = E_OUTOFMEMORY;
2817         goto exit;
2818     }
2819     hr = ConvertINetString(pdwMode, dwSrcEncoding, dwDstEncoding, src, &srclen, dst, &dstlen);
2820     if (FAILED(hr)) goto exit;
2821
2822     hr = IStream_Write(pstmOut, dst, dstlen, NULL);
2823
2824 exit:
2825     HeapFree(GetProcessHeap(), 0, src);
2826     HeapFree(GetProcessHeap(), 0, dst);
2827     return hr;
2828 }
2829
2830 /*
2831  * TODO: handle dwFlag and lpFallBack
2832 */
2833 static HRESULT WINAPI fnIMultiLanguage2_ConvertStringToUnicodeEx(
2834     IMultiLanguage3* iface,
2835     DWORD* pdwMode,
2836     DWORD dwEncoding,
2837     CHAR* pSrcStr,
2838     UINT* pcSrcSize,
2839     WCHAR* pDstStr,
2840     UINT* pcDstSize,
2841     DWORD dwFlag,
2842     WCHAR* lpFallBack)
2843 {
2844     FIXME("\n");
2845     return ConvertINetMultiByteToUnicode(pdwMode, dwEncoding,
2846         pSrcStr, (LPINT)pcSrcSize, pDstStr, (LPINT)pcDstSize);
2847 }
2848
2849 /*****************************************************************************
2850  * MultiLanguage2::ConvertStringToUnicodeEx
2851  *
2852  * Translates the multibyte string from the specified code page to Unicode.
2853  *
2854  * PARAMS
2855  *   see ConvertStringToUnicode
2856  *   dwFlag 
2857  *   lpFallBack if dwFlag contains MLCONVCHARF_USEDEFCHAR, lpFallBack string used
2858  *              instead unconvertible characters.
2859  *
2860  * RETURNS
2861  *   S_OK     Success.
2862  *   S_FALSE  The conversion is not supported.
2863  *   E_FAIL   Some error has occurred.
2864  *
2865  * TODO: handle dwFlag and lpFallBack
2866 */
2867 static HRESULT WINAPI fnIMultiLanguage2_ConvertStringFromUnicodeEx(
2868     IMultiLanguage3* This,
2869     DWORD* pdwMode,
2870     DWORD dwEncoding,
2871     WCHAR* pSrcStr,
2872     UINT* pcSrcSize,
2873     CHAR* pDstStr,
2874     UINT* pcDstSize,
2875     DWORD dwFlag,
2876     WCHAR* lpFallBack)
2877 {
2878     FIXME("\n");
2879     return ConvertINetUnicodeToMultiByte(pdwMode, dwEncoding,
2880         pSrcStr, (LPINT)pcSrcSize, pDstStr, (LPINT)pcDstSize);
2881 }
2882
2883 static HRESULT WINAPI fnIMultiLanguage2_DetectCodepageInIStream(
2884     IMultiLanguage3* iface,
2885     DWORD dwFlag,
2886     DWORD dwPrefWinCodePage,
2887     IStream* pstmIn,
2888     DetectEncodingInfo* lpEncoding,
2889     INT* pnScores)
2890 {
2891     FIXME("\n");
2892     return E_NOTIMPL;
2893 }
2894
2895 static HRESULT WINAPI fnIMultiLanguage2_DetectInputCodepage(
2896     IMultiLanguage3* iface,
2897     DWORD dwFlag,
2898     DWORD dwPrefWinCodePage,
2899     CHAR* pSrcStr,
2900     INT* pcSrcSize,
2901     DetectEncodingInfo* lpEncoding,
2902     INT* pnScores)
2903 {
2904     FIXME("\n");
2905     return E_NOTIMPL;
2906 }
2907
2908 static HRESULT WINAPI fnIMultiLanguage2_ValidateCodePage(
2909     IMultiLanguage3* iface,
2910     UINT uiCodePage,
2911     HWND hwnd)
2912 {
2913     FIXME("%u, %p\n", uiCodePage, hwnd);
2914     return E_NOTIMPL;
2915 }
2916
2917 static HRESULT WINAPI fnIMultiLanguage2_GetCodePageDescription(
2918     IMultiLanguage3* iface,
2919     UINT uiCodePage,
2920     LCID lcid,
2921     LPWSTR lpWideCharStr,
2922     int cchWideChar)
2923 {
2924     /* Find first instance */
2925     unsigned int i,n;
2926
2927     TRACE ("%u, %04x, %p, %d\n", uiCodePage, lcid, lpWideCharStr, cchWideChar);
2928     for (i = 0; i < sizeof(mlang_data)/sizeof(mlang_data[0]); i++)
2929     {
2930         for (n = 0; n < mlang_data[i].number_of_cp; n++)
2931         {
2932             if (mlang_data[i].mime_cp_info[n].cp == uiCodePage)
2933             {
2934                 MultiByteToWideChar(CP_ACP, 0,
2935                                     mlang_data[i].mime_cp_info[n].description,
2936                                     -1, lpWideCharStr, cchWideChar);
2937                 return S_OK;
2938             }
2939         }
2940     }
2941
2942     return S_FALSE;
2943 }
2944
2945 static HRESULT WINAPI fnIMultiLanguage2_IsCodePageInstallable(
2946     IMultiLanguage3* iface,
2947     UINT uiCodePage)
2948 {
2949     FIXME("%u\n", uiCodePage);
2950     return E_NOTIMPL;
2951 }
2952
2953 static HRESULT WINAPI fnIMultiLanguage2_SetMimeDBSource(
2954     IMultiLanguage3* iface,
2955     MIMECONTF dwSource)
2956 {
2957     FIXME("0x%08x\n", dwSource);
2958     return S_OK;
2959 }
2960
2961 static HRESULT WINAPI fnIMultiLanguage2_GetNumberOfScripts(
2962     IMultiLanguage3* iface,
2963     UINT* pnScripts)
2964 {
2965     ICOM_THIS_MULTI(MLang_impl, vtbl_IMultiLanguage3, iface);
2966     TRACE("%p %p\n", This, pnScripts);
2967
2968     if (!pnScripts) return S_FALSE;
2969
2970     *pnScripts = This->total_scripts;
2971     return S_OK;
2972 }
2973
2974 static HRESULT WINAPI fnIMultiLanguage2_EnumScripts(
2975     IMultiLanguage3* iface,
2976     DWORD dwFlags,
2977     LANGID LangId,
2978     IEnumScript** ppEnumScript)
2979 {
2980     ICOM_THIS_MULTI(MLang_impl, vtbl_IMultiLanguage3, iface);
2981     TRACE("%p %08x %04x %p\n", This, dwFlags, LangId, ppEnumScript);
2982
2983     return EnumScript_create( This, dwFlags, LangId, ppEnumScript );
2984 }
2985
2986 static HRESULT WINAPI fnIMultiLanguage2_ValidateCodePageEx(
2987     IMultiLanguage3* iface,
2988     UINT uiCodePage,
2989     HWND hwnd,
2990     DWORD dwfIODControl)
2991 {
2992     ICOM_THIS_MULTI(MLang_impl, vtbl_IMultiLanguage3, iface);
2993     FIXME("%p %u %p %08x: stub!\n", This, uiCodePage, hwnd, dwfIODControl);
2994
2995     return S_FALSE;
2996 }
2997
2998 static HRESULT WINAPI fnIMultiLanguage3_DetectOutboundCodePage(
2999     IMultiLanguage3 *iface,
3000     DWORD dwFlags,
3001     LPCWSTR lpWideCharStr,
3002     UINT cchWideChar,
3003     UINT *puiPreferredCodePages,
3004     UINT nPreferredCodePages,
3005     UINT *puiDetectedCodePages,
3006     UINT *pnDetectedCodePages,
3007     WCHAR *lpSpecialChar)
3008 {
3009     ICOM_THIS_MULTI(MLang_impl, vtbl_IMultiLanguage3, iface);
3010     FIXME("(%p)->(%08x %s %u %p %u %p %p %p)\n", This, dwFlags, debugstr_w(lpWideCharStr),
3011           cchWideChar, puiPreferredCodePages, nPreferredCodePages, puiDetectedCodePages,
3012           pnDetectedCodePages, lpSpecialChar);
3013     return E_NOTIMPL;
3014 }
3015
3016 static HRESULT WINAPI fnIMultiLanguage3_DetectOutboundCodePageInIStream(
3017     IMultiLanguage3 *iface,
3018     DWORD dwFlags,
3019     IStream *pStrIn,
3020     UINT *puiPreferredCodePages,
3021     UINT nPreferredCodePages,
3022     UINT *puiDetectedCodePages,
3023     UINT *pnDetectedCodePages,
3024     WCHAR *lpSpecialChar)
3025 {
3026     ICOM_THIS_MULTI(MLang_impl, vtbl_IMultiLanguage3, iface);
3027     FIXME("(%p)->(%08x %p %p %u %p %p %p)\n", This, dwFlags, pStrIn,
3028           puiPreferredCodePages, nPreferredCodePages, puiDetectedCodePages,
3029           pnDetectedCodePages, lpSpecialChar);
3030     return E_NOTIMPL;
3031 }
3032
3033 static const IMultiLanguage3Vtbl IMultiLanguage3_vtbl =
3034 {
3035     fnIMultiLanguage2_QueryInterface,
3036     fnIMultiLanguage2_AddRef,
3037     fnIMultiLanguage2_Release,
3038     fnIMultiLanguage2_GetNumberOfCodePageInfo,
3039     fnIMultiLanguage2_GetCodePageInfo,
3040     fnIMultiLanguage2_GetFamilyCodePage,
3041     fnIMultiLanguage2_EnumCodePages,
3042     fnIMultiLanguage2_GetCharsetInfo,
3043     fnIMultiLanguage2_IsConvertible,
3044     fnIMultiLanguage2_ConvertString,
3045     fnIMultiLanguage2_ConvertStringToUnicode,
3046     fnIMultiLanguage2_ConvertStringFromUnicode,
3047     fnIMultiLanguage2_ConvertStringReset,
3048     fnIMultiLanguage2_GetRfc1766FromLcid,
3049     fnIMultiLanguage2_GetLcidFromRfc1766,
3050     fnIMultiLanguage2_EnumRfc1766,
3051     fnIMultiLanguage2_GetRfc1766Info,
3052     fnIMultiLanguage2_CreateConvertCharset,
3053     fnIMultiLanguage2_ConvertStringInIStream,
3054     fnIMultiLanguage2_ConvertStringToUnicodeEx,
3055     fnIMultiLanguage2_ConvertStringFromUnicodeEx,
3056     fnIMultiLanguage2_DetectCodepageInIStream,
3057     fnIMultiLanguage2_DetectInputCodepage,
3058     fnIMultiLanguage2_ValidateCodePage,
3059     fnIMultiLanguage2_GetCodePageDescription,
3060     fnIMultiLanguage2_IsCodePageInstallable,
3061     fnIMultiLanguage2_SetMimeDBSource,
3062     fnIMultiLanguage2_GetNumberOfScripts,
3063     fnIMultiLanguage2_EnumScripts,
3064     fnIMultiLanguage2_ValidateCodePageEx,
3065     fnIMultiLanguage3_DetectOutboundCodePage,
3066     fnIMultiLanguage3_DetectOutboundCodePageInIStream
3067 };
3068
3069 /******************************************************************************/
3070 static HRESULT WINAPI fnIMLangFontLink2_QueryInterface(
3071     IMLangFontLink2 * iface,
3072     REFIID riid,
3073     void** ppvObject)
3074 {
3075     ICOM_THIS_MULTI(MLang_impl, vtbl_IMLangFontLink2, iface);
3076     return MLang_QueryInterface( This, riid, ppvObject );
3077 }
3078
3079 static ULONG WINAPI fnIMLangFontLink2_AddRef( IMLangFontLink2* iface )
3080 {
3081     ICOM_THIS_MULTI(MLang_impl, vtbl_IMLangFontLink2, iface);
3082     return MLang_AddRef( This );
3083 }
3084
3085 static ULONG WINAPI fnIMLangFontLink2_Release( IMLangFontLink2* iface )
3086 {
3087     ICOM_THIS_MULTI(MLang_impl, vtbl_IMLangFontLink2, iface);
3088     return MLang_Release( This );
3089 }
3090
3091 static HRESULT WINAPI fnIMLangFontLink2_GetCharCodePages( IMLangFontLink2* This,
3092         WCHAR chSrc, DWORD *pdwCodePages)
3093 {
3094     FIXME("(%p)->%s %p\n",This, debugstr_wn(&chSrc,1),pdwCodePages);
3095     return E_NOTIMPL;
3096 }
3097
3098 static HRESULT WINAPI fnIMLangFontLink2_GetStrCodePages( IMLangFontLink2* This,
3099         const WCHAR *pszSrc, long cchSrc, DWORD dwPriorityCodePages,
3100         DWORD *pdwCodePages, long *pcchCodePages)
3101 {
3102     FIXME("(%p)->%s %li %x %p %p\n",This, debugstr_wn(pszSrc,cchSrc),cchSrc,dwPriorityCodePages,pdwCodePages,pcchCodePages);
3103     *pdwCodePages = 0;
3104     *pcchCodePages = 1;
3105     return S_OK;
3106 }
3107
3108 static HRESULT WINAPI fnIMLangFontLink2_CodePageToCodePages(IMLangFontLink2* This,
3109         UINT uCodePage,
3110         DWORD *pdwCodePages)
3111 {
3112     FIXME("(%p)->%i %p\n",This, uCodePage, pdwCodePages);
3113     return E_NOTIMPL;
3114 }
3115
3116 static HRESULT WINAPI fnIMLangFontLink2_CodePagesToCodePage(IMLangFontLink2* This,
3117         DWORD dwCodePages, UINT uDefaultCodePage, UINT *puCodePage)
3118 {
3119     FIXME("(%p)->%i %i %p\n",This, dwCodePages, uDefaultCodePage, puCodePage);
3120     return E_NOTIMPL;
3121 }
3122
3123 static HRESULT WINAPI fnIMLangFontLink2_GetFontCodePages(IMLangFontLink2* This,
3124         HDC hDC, HFONT hFont, DWORD *pdwCodePages)
3125 {
3126     FIXME("(%p)->%p %p %p\n",This, hDC, hFont, pdwCodePages);
3127     return E_NOTIMPL;
3128 }
3129
3130 static HRESULT WINAPI fnIMLangFontLink2_ReleaseFont(IMLangFontLink2* This,
3131         HFONT hFont)
3132 {
3133     FIXME("(%p)->%p\n",This, hFont);
3134     return E_NOTIMPL;
3135 }
3136
3137 static HRESULT WINAPI fnIMLangFontLink2_ResetFontMapping(IMLangFontLink2* This)
3138 {
3139     FIXME("(%p)->\n",This);
3140     return E_NOTIMPL;
3141 }
3142
3143 static HRESULT WINAPI fnIMLangFontLink2_MapFont(IMLangFontLink2* This,
3144         HDC hDC, DWORD dwCodePages, WCHAR chSrc, HFONT *pFont)
3145 {
3146     FIXME("(%p)->%p %i %s %p\n",This, hDC, dwCodePages, debugstr_wn(&chSrc,1), pFont);
3147     return E_NOTIMPL;
3148 }
3149
3150 static HRESULT WINAPI fnIMLangFontLink2_GetFontUnicodeRanges(IMLangFontLink2* This,
3151         HDC hDC, UINT *puiRanges, UNICODERANGE *pUranges)
3152 {
3153     FIXME("(%p)->%p %p %p\n",This, hDC, puiRanges, pUranges);
3154     return E_NOTIMPL;
3155 }
3156
3157 static HRESULT WINAPI fnIMLangFontLink2_GetScriptFontInfo(IMLangFontLink2* This,
3158         SCRIPT_ID sid, DWORD dwFlags, UINT *puiFonts,
3159         SCRIPTFONTINFO *pScriptFont)
3160 {
3161     FIXME("(%p)->%i %i %p %p\n",This, sid, dwFlags, puiFonts, pScriptFont);
3162     return E_NOTIMPL;
3163 }
3164
3165 static HRESULT WINAPI fnIMLangFontLink2_CodePageToScriptID(IMLangFontLink2* This,
3166         UINT uiCodePage, SCRIPT_ID *pSid)
3167 {
3168     FIXME("(%p)->%i %p\n",This, uiCodePage, pSid);
3169     return E_NOTIMPL;
3170 }
3171
3172 static const IMLangFontLink2Vtbl IMLangFontLink2_vtbl =
3173 {
3174     fnIMLangFontLink2_QueryInterface,
3175     fnIMLangFontLink2_AddRef,
3176     fnIMLangFontLink2_Release,
3177     fnIMLangFontLink2_GetCharCodePages,
3178     fnIMLangFontLink2_GetStrCodePages,
3179     fnIMLangFontLink2_CodePageToCodePages,
3180     fnIMLangFontLink2_CodePagesToCodePage,
3181     fnIMLangFontLink2_GetFontCodePages,
3182     fnIMLangFontLink2_ReleaseFont,
3183     fnIMLangFontLink2_ResetFontMapping,
3184     fnIMLangFontLink2_MapFont,
3185     fnIMLangFontLink2_GetFontUnicodeRanges,
3186     fnIMLangFontLink2_GetScriptFontInfo,
3187     fnIMLangFontLink2_CodePageToScriptID
3188 };
3189
3190 /******************************************************************************/
3191
3192 static HRESULT WINAPI fnIMLangLineBreakConsole_QueryInterface(
3193     IMLangLineBreakConsole* iface,
3194     REFIID riid,
3195     void** ppvObject)
3196 {
3197     ICOM_THIS_MULTI(MLang_impl, vtbl_IMLangLineBreakConsole, iface);
3198     return MLang_QueryInterface( This, riid, ppvObject );
3199 }
3200
3201 static ULONG WINAPI fnIMLangLineBreakConsole_AddRef(
3202     IMLangLineBreakConsole* iface )
3203 {
3204     ICOM_THIS_MULTI(MLang_impl, vtbl_IMLangLineBreakConsole, iface);
3205     return MLang_AddRef( This );
3206 }
3207
3208 static ULONG WINAPI fnIMLangLineBreakConsole_Release(
3209     IMLangLineBreakConsole* iface )
3210 {
3211     ICOM_THIS_MULTI(MLang_impl, vtbl_IMLangLineBreakConsole, iface);
3212     return MLang_Release( This );
3213 }
3214
3215 static HRESULT WINAPI fnIMLangLineBreakConsole_BreakLineML(
3216     IMLangLineBreakConsole* iface,
3217     IMLangString* pSrcMLStr,
3218     long lSrcPos,
3219     long lSrcLen,
3220     long cMinColumns,
3221     long cMaxColumns,
3222     long* plLineLen,
3223     long* plSkipLen)
3224 {
3225     FIXME("(%p)->%p %li %li %li %li %p %p\n", iface, pSrcMLStr, lSrcPos, lSrcLen, cMinColumns, cMaxColumns, plLineLen, plSkipLen);
3226     return E_NOTIMPL;
3227 }
3228
3229 static HRESULT WINAPI fnIMLangLineBreakConsole_BreakLineW(
3230     IMLangLineBreakConsole* iface,
3231     LCID locale,
3232     const WCHAR* pszSrc,
3233     long cchSrc,
3234     long cMaxColumns,
3235     long* pcchLine,
3236     long* pcchSkip )
3237 {
3238     FIXME("(%p)->%i %s %li %li %p %p\n", iface, locale, debugstr_wn(pszSrc,cchSrc), cchSrc, cMaxColumns, pcchLine, pcchSkip);
3239
3240     *pcchLine = cchSrc;
3241     *pcchSkip = 0;
3242     return S_OK;
3243 }
3244
3245 static HRESULT WINAPI fnIMLangLineBreakConsole_BreakLineA(
3246     IMLangLineBreakConsole* iface,
3247     LCID locale,
3248     UINT uCodePage,
3249     const CHAR* pszSrc,
3250     long cchSrc,
3251     long cMaxColumns,
3252     long* pcchLine,
3253     long* pcchSkip)
3254 {
3255     FIXME("(%p)->%i %i %s %li %li %p %p\n", iface, locale, uCodePage, debugstr_an(pszSrc,cchSrc), cchSrc, cMaxColumns, pcchLine, pcchSkip);
3256
3257     *pcchLine = cchSrc;
3258     *pcchSkip = 0;
3259     return S_OK;
3260 }
3261
3262 static const IMLangLineBreakConsoleVtbl IMLangLineBreakConsole_vtbl =
3263 {
3264     fnIMLangLineBreakConsole_QueryInterface,
3265     fnIMLangLineBreakConsole_AddRef,
3266     fnIMLangLineBreakConsole_Release,
3267     fnIMLangLineBreakConsole_BreakLineML,
3268     fnIMLangLineBreakConsole_BreakLineW,
3269     fnIMLangLineBreakConsole_BreakLineA
3270 };
3271
3272 static HRESULT MultiLanguage_create(IUnknown *pUnkOuter, LPVOID *ppObj)
3273 {
3274     MLang_impl *mlang;
3275     UINT i;
3276
3277     TRACE("Creating MultiLanguage object\n");
3278
3279     if( pUnkOuter )
3280         return CLASS_E_NOAGGREGATION;
3281
3282     mlang = HeapAlloc( GetProcessHeap(), 0, sizeof (MLang_impl) );
3283     mlang->vtbl_IMLangFontLink = &IMLangFontLink_vtbl;
3284     mlang->vtbl_IMultiLanguage = &IMultiLanguage_vtbl;
3285     mlang->vtbl_IMultiLanguage3 = &IMultiLanguage3_vtbl;
3286     mlang->vtbl_IMLangFontLink2 = &IMLangFontLink2_vtbl;
3287     mlang->vtbl_IMLangLineBreakConsole = &IMLangLineBreakConsole_vtbl;
3288
3289     mlang->total_cp = 0;
3290     for (i = 0; i < sizeof(mlang_data)/sizeof(mlang_data[0]); i++)
3291         mlang->total_cp += mlang_data[i].number_of_cp;
3292
3293     /* do not enumerate unicode flavours */
3294     mlang->total_scripts = sizeof(mlang_data)/sizeof(mlang_data[0]) - 1;
3295
3296     mlang->ref = 1;
3297     *ppObj = mlang;
3298     TRACE("returning %p\n", mlang);
3299
3300     LockModule();
3301
3302     return S_OK;
3303 }
3304
3305 /******************************************************************************/
3306
3307 HRESULT WINAPI DllCanUnloadNow(void)
3308 {
3309     return dll_count == 0 ? S_OK : S_FALSE;
3310 }
3311
3312 HRESULT WINAPI GetGlobalFontLinkObject(void)
3313 {
3314     FIXME("\n");
3315     return S_FALSE;
3316 }