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