blob: f95f89f060cb5fa5972c173a4c1c4cb5afcc01ac [file] [log] [blame]
Alexandre Julliardf7bf7ef2000-06-10 04:42:33 +00001/*
2 * Code page functions
3 *
4 * Copyright 2000 Alexandre Julliard
Alexandre Julliard0799c1a2002-03-09 23:29:33 +00005 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Alexandre Julliardf7bf7ef2000-06-10 04:42:33 +000019 */
20
21#include <assert.h>
22#include <stdio.h>
Alexandre Julliard6ce25702000-07-11 22:08:43 +000023#include <stdlib.h>
James Juranf4d5fef2001-01-26 20:43:40 +000024#include <string.h>
Alexandre Julliardf7bf7ef2000-06-10 04:42:33 +000025
26#include "winbase.h"
27#include "winerror.h"
28#include "winnls.h"
29#include "wine/unicode.h"
Alexandre Julliard66e31832002-08-15 23:18:47 +000030#include "thread.h"
Alexandre Julliard0799c1a2002-03-09 23:29:33 +000031#include "wine/debug.h"
Alexandre Julliardf7bf7ef2000-06-10 04:42:33 +000032
Alexandre Julliard0799c1a2002-03-09 23:29:33 +000033WINE_DEFAULT_DEBUG_CHANNEL(string);
Alexandre Julliardf7bf7ef2000-06-10 04:42:33 +000034
35/* current code pages */
Alexandre Julliardf7bf7ef2000-06-10 04:42:33 +000036static const union cptable *ansi_cptable;
37static const union cptable *oem_cptable;
38static const union cptable *mac_cptable;
Alexandre Julliard66e31832002-08-15 23:18:47 +000039static LCID default_lcid = MAKELCID( MAKELANGID(LANG_ENGLISH,SUBLANG_DEFAULT), SORT_DEFAULT );
Alexandre Julliard6ce25702000-07-11 22:08:43 +000040
41/* setup default codepage info before we can get at the locale stuff */
42static void init_codepages(void)
43{
Alexandre Julliard25fe3612003-03-21 21:30:51 +000044 ansi_cptable = wine_cp_get_table( 1252 );
45 oem_cptable = wine_cp_get_table( 437 );
46 mac_cptable = wine_cp_get_table( 10000 );
Alexandre Julliard6ce25702000-07-11 22:08:43 +000047 assert( ansi_cptable );
48 assert( oem_cptable );
49 assert( mac_cptable );
50}
Alexandre Julliardf7bf7ef2000-06-10 04:42:33 +000051
52/* find the table for a given codepage, handling CP_ACP etc. pseudo-codepages */
53static const union cptable *get_codepage_table( unsigned int codepage )
54{
55 const union cptable *ret = NULL;
56
Alexandre Julliard6ce25702000-07-11 22:08:43 +000057 if (!ansi_cptable) init_codepages();
Alexandre Julliardf7bf7ef2000-06-10 04:42:33 +000058
59 switch(codepage)
60 {
Alexandre Julliard66e31832002-08-15 23:18:47 +000061 case CP_ACP:
62 return ansi_cptable;
63 case CP_OEMCP:
64 return oem_cptable;
65 case CP_MACCP:
66 return mac_cptable;
Alexandre Julliardf7bf7ef2000-06-10 04:42:33 +000067 case CP_UTF7:
68 case CP_UTF8:
69 break;
Alexandre Julliard66e31832002-08-15 23:18:47 +000070 case CP_THREAD_ACP:
71 if (!(codepage = NtCurrentTeb()->code_page)) return ansi_cptable;
72 /* fall through */
Alexandre Julliardf7bf7ef2000-06-10 04:42:33 +000073 default:
Alexandre Julliard6ce25702000-07-11 22:08:43 +000074 if (codepage == ansi_cptable->info.codepage) return ansi_cptable;
75 if (codepage == oem_cptable->info.codepage) return oem_cptable;
76 if (codepage == mac_cptable->info.codepage) return mac_cptable;
Alexandre Julliard25fe3612003-03-21 21:30:51 +000077 ret = wine_cp_get_table( codepage );
Alexandre Julliardf7bf7ef2000-06-10 04:42:33 +000078 break;
79 }
80 return ret;
81}
82
Alexandre Julliard6ce25702000-07-11 22:08:43 +000083/* initialize default code pages from locale info */
84/* FIXME: should be done in init_codepages, but it can't right now */
85/* since it needs KERNEL32 to be loaded for the locale info. */
Alexandre Julliard66e31832002-08-15 23:18:47 +000086void CODEPAGE_Init( UINT ansi, UINT oem, UINT mac, LCID lcid )
Alexandre Julliard6ce25702000-07-11 22:08:43 +000087{
Alexandre Julliard996c0bf2001-12-05 22:14:57 +000088 extern void __wine_init_codepages( const union cptable *ansi, const union cptable *oem );
Alexandre Julliard6ce25702000-07-11 22:08:43 +000089 const union cptable *table;
Alexandre Julliard6ce25702000-07-11 22:08:43 +000090
Alexandre Julliard66e31832002-08-15 23:18:47 +000091 default_lcid = lcid;
Alexandre Julliard6ce25702000-07-11 22:08:43 +000092 if (!ansi_cptable) init_codepages(); /* just in case */
Alexandre Julliard996c0bf2001-12-05 22:14:57 +000093
Alexandre Julliard25fe3612003-03-21 21:30:51 +000094 if ((table = wine_cp_get_table( ansi ))) ansi_cptable = table;
95 if ((table = wine_cp_get_table( oem ))) oem_cptable = table;
96 if ((table = wine_cp_get_table( mac ))) mac_cptable = table;
Alexandre Julliard996c0bf2001-12-05 22:14:57 +000097 __wine_init_codepages( ansi_cptable, oem_cptable );
Alexandre Julliard6ce25702000-07-11 22:08:43 +000098
99 TRACE( "ansi=%03d oem=%03d mac=%03d\n", ansi_cptable->info.codepage,
100 oem_cptable->info.codepage, mac_cptable->info.codepage );
101}
102
Alexandre Julliardf7bf7ef2000-06-10 04:42:33 +0000103/******************************************************************************
Patrik Stridvall3ca98232001-06-20 23:03:14 +0000104 * GetACP (KERNEL32.@)
Alexandre Julliardf7bf7ef2000-06-10 04:42:33 +0000105 *
106 * RETURNS
107 * Current ANSI code-page identifier, default if no current defined
108 */
109UINT WINAPI GetACP(void)
110{
Alexandre Julliard66e31832002-08-15 23:18:47 +0000111 if (!ansi_cptable) return 1252;
Alexandre Julliard6ce25702000-07-11 22:08:43 +0000112 return ansi_cptable->info.codepage;
Alexandre Julliardf7bf7ef2000-06-10 04:42:33 +0000113}
114
115
116/***********************************************************************
Patrik Stridvall3ca98232001-06-20 23:03:14 +0000117 * GetOEMCP (KERNEL32.@)
Alexandre Julliardf7bf7ef2000-06-10 04:42:33 +0000118 */
119UINT WINAPI GetOEMCP(void)
120{
Alexandre Julliard66e31832002-08-15 23:18:47 +0000121 if (!oem_cptable) return 437;
Alexandre Julliard6ce25702000-07-11 22:08:43 +0000122 return oem_cptable->info.codepage;
Alexandre Julliardf7bf7ef2000-06-10 04:42:33 +0000123}
124
125
126/***********************************************************************
Patrik Stridvall3ca98232001-06-20 23:03:14 +0000127 * IsValidCodePage (KERNEL32.@)
Alexandre Julliardf7bf7ef2000-06-10 04:42:33 +0000128 */
129BOOL WINAPI IsValidCodePage( UINT codepage )
130{
Alexandre Julliardac90ba92002-06-25 00:24:36 +0000131 switch(codepage) {
132 case CP_SYMBOL:
133 return FALSE;
134 case CP_UTF7:
135 case CP_UTF8:
136 return TRUE;
137 default:
Alexandre Julliard25fe3612003-03-21 21:30:51 +0000138 return wine_cp_get_table( codepage ) != NULL;
Alexandre Julliardac90ba92002-06-25 00:24:36 +0000139 }
Alexandre Julliardf7bf7ef2000-06-10 04:42:33 +0000140}
141
142
143/***********************************************************************
Alexandre Julliard66e31832002-08-15 23:18:47 +0000144 * GetUserDefaultLangID (KERNEL32.@)
145 */
146LANGID WINAPI GetUserDefaultLangID(void)
147{
148 return LANGIDFROMLCID(default_lcid);
149}
150
151
152/***********************************************************************
153 * GetSystemDefaultLangID (KERNEL32.@)
154 */
155LANGID WINAPI GetSystemDefaultLangID(void)
156{
157 return GetUserDefaultLangID();
158}
159
160
161/***********************************************************************
162 * GetUserDefaultLCID (KERNEL32.@)
163 */
164LCID WINAPI GetUserDefaultLCID(void)
165{
166 return default_lcid;
167}
168
169
170/***********************************************************************
171 * GetSystemDefaultLCID (KERNEL32.@)
172 */
173LCID WINAPI GetSystemDefaultLCID(void)
174{
175 return GetUserDefaultLCID();
176}
177
178
179/***********************************************************************
Steve Lustbader2fbd4a02002-10-07 18:27:06 +0000180 * GetUserDefaultUILanguage (KERNEL32.@)
181 */
182LANGID WINAPI GetUserDefaultUILanguage(void)
183{
184 return GetUserDefaultLangID();
185}
186
187
188/***********************************************************************
189 * GetSystemDefaultUILanguage (KERNEL32.@)
190 */
191LANGID WINAPI GetSystemDefaultUILanguage(void)
192{
193 return GetSystemDefaultLangID();
194}
195
196
197/***********************************************************************
Patrik Stridvall3ca98232001-06-20 23:03:14 +0000198 * IsDBCSLeadByteEx (KERNEL32.@)
Alexandre Julliardf7bf7ef2000-06-10 04:42:33 +0000199 */
200BOOL WINAPI IsDBCSLeadByteEx( UINT codepage, BYTE testchar )
201{
202 const union cptable *table = get_codepage_table( codepage );
203 return table && is_dbcs_leadbyte( table, testchar );
204}
205
206
207/***********************************************************************
Patrik Stridvall3ca98232001-06-20 23:03:14 +0000208 * IsDBCSLeadByte (KERNEL32.@)
Patrik Stridvall044855c2001-07-11 18:56:41 +0000209 * IsDBCSLeadByte (KERNEL.207)
Alexandre Julliardf7bf7ef2000-06-10 04:42:33 +0000210 */
211BOOL WINAPI IsDBCSLeadByte( BYTE testchar )
212{
Alexandre Julliard66e31832002-08-15 23:18:47 +0000213 if (!ansi_cptable) return FALSE;
Alexandre Julliardf7bf7ef2000-06-10 04:42:33 +0000214 return is_dbcs_leadbyte( ansi_cptable, testchar );
215}
216
217
218/***********************************************************************
Patrik Stridvall3ca98232001-06-20 23:03:14 +0000219 * GetCPInfo (KERNEL32.@)
Alexandre Julliardf7bf7ef2000-06-10 04:42:33 +0000220 */
221BOOL WINAPI GetCPInfo( UINT codepage, LPCPINFO cpinfo )
222{
223 const union cptable *table = get_codepage_table( codepage );
224
Vincent Béron9a624912002-05-31 23:06:46 +0000225 if (!table)
Alexandre Julliardf7bf7ef2000-06-10 04:42:33 +0000226 {
227 SetLastError( ERROR_INVALID_PARAMETER );
228 return FALSE;
229 }
230 if (table->info.def_char & 0xff00)
231 {
232 cpinfo->DefaultChar[0] = table->info.def_char & 0xff00;
233 cpinfo->DefaultChar[1] = table->info.def_char & 0x00ff;
234 }
235 else
236 {
237 cpinfo->DefaultChar[0] = table->info.def_char & 0xff;
238 cpinfo->DefaultChar[1] = 0;
239 }
240 if ((cpinfo->MaxCharSize = table->info.char_size) == 2)
241 memcpy( cpinfo->LeadByte, table->dbcs.lead_bytes, sizeof(cpinfo->LeadByte) );
242 else
243 cpinfo->LeadByte[0] = cpinfo->LeadByte[1] = 0;
244
245 return TRUE;
246}
247
248
249/***********************************************************************
Patrik Stridvall3ca98232001-06-20 23:03:14 +0000250 * EnumSystemCodePagesA (KERNEL32.@)
Alexandre Julliardf7bf7ef2000-06-10 04:42:33 +0000251 */
252BOOL WINAPI EnumSystemCodePagesA( CODEPAGE_ENUMPROCA lpfnCodePageEnum, DWORD flags )
253{
254 const union cptable *table;
255 char buffer[10];
256 int index = 0;
257
258 for (;;)
259 {
Alexandre Julliard25fe3612003-03-21 21:30:51 +0000260 if (!(table = wine_cp_enum_table( index++ ))) break;
Alexandre Julliardf7bf7ef2000-06-10 04:42:33 +0000261 sprintf( buffer, "%d", table->info.codepage );
262 if (!lpfnCodePageEnum( buffer )) break;
263 }
264 return TRUE;
265}
266
267
268/***********************************************************************
Patrik Stridvall3ca98232001-06-20 23:03:14 +0000269 * EnumSystemCodePagesW (KERNEL32.@)
Alexandre Julliardf7bf7ef2000-06-10 04:42:33 +0000270 */
271BOOL WINAPI EnumSystemCodePagesW( CODEPAGE_ENUMPROCW lpfnCodePageEnum, DWORD flags )
272{
273 const union cptable *table;
274 WCHAR buffer[10], *p;
275 int page, index = 0;
276
277 for (;;)
278 {
Alexandre Julliard25fe3612003-03-21 21:30:51 +0000279 if (!(table = wine_cp_enum_table( index++ ))) break;
Alexandre Julliardf7bf7ef2000-06-10 04:42:33 +0000280 p = buffer + sizeof(buffer)/sizeof(WCHAR);
281 *--p = 0;
282 page = table->info.codepage;
283 do
284 {
285 *--p = '0' + (page % 10);
286 page /= 10;
287 } while( page );
288 if (!lpfnCodePageEnum( p )) break;
289 }
290 return TRUE;
291}
292
293
294/***********************************************************************
Patrik Stridvall3ca98232001-06-20 23:03:14 +0000295 * MultiByteToWideChar (KERNEL32.@)
Alexandre Julliardf7bf7ef2000-06-10 04:42:33 +0000296 *
297 * PARAMS
298 * page [in] Codepage character set to convert from
299 * flags [in] Character mapping flags
300 * src [in] Source string buffer
301 * srclen [in] Length of source string buffer
302 * dst [in] Destination buffer
303 * dstlen [in] Length of destination buffer
304 *
305 * NOTES
306 * The returned length includes the null terminator character.
307 *
308 * RETURNS
309 * Success: If dstlen > 0, number of characters written to destination
310 * buffer. If dstlen == 0, number of characters needed to do
311 * conversion.
312 * Failure: 0. Occurs if not enough space is available.
313 *
314 * ERRORS
315 * ERROR_INSUFFICIENT_BUFFER
316 * ERROR_INVALID_PARAMETER
317 * ERROR_NO_UNICODE_TRANSLATION
318 *
319 */
320INT WINAPI MultiByteToWideChar( UINT page, DWORD flags, LPCSTR src, INT srclen,
321 LPWSTR dst, INT dstlen )
322{
323 const union cptable *table;
324 int ret;
325
Wolfgang Schwotzerd9b8f9b2000-07-28 23:58:48 +0000326 if (!src || (!dst && dstlen))
327 {
328 SetLastError( ERROR_INVALID_PARAMETER );
329 return 0;
330 }
331
Dmitry Timoshkov3139b922002-10-04 17:42:27 +0000332 if (srclen < 0) srclen = strlen(src) + 1;
Alexandre Julliardf7bf7ef2000-06-10 04:42:33 +0000333
Alexandre Julliardf7bf7ef2000-06-10 04:42:33 +0000334 if (flags & MB_USEGLYPHCHARS) FIXME("MB_USEGLYPHCHARS not supported\n");
335
Alexandre Julliardaea78532000-08-11 00:44:33 +0000336 switch(page)
337 {
338 case CP_UTF7:
339 FIXME("UTF not supported\n");
340 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
341 return 0;
342 case CP_UTF8:
Alexandre Julliard25fe3612003-03-21 21:30:51 +0000343 ret = wine_utf8_mbstowcs( flags, src, srclen, dst, dstlen );
Alexandre Julliardaea78532000-08-11 00:44:33 +0000344 break;
345 default:
346 if (!(table = get_codepage_table( page )))
347 {
348 SetLastError( ERROR_INVALID_PARAMETER );
349 return 0;
350 }
Alexandre Julliard25fe3612003-03-21 21:30:51 +0000351 ret = wine_cp_mbstowcs( table, flags, src, srclen, dst, dstlen );
Alexandre Julliardaea78532000-08-11 00:44:33 +0000352 break;
353 }
Alexandre Julliardf7bf7ef2000-06-10 04:42:33 +0000354
355 if (ret < 0)
356 {
357 switch(ret)
358 {
359 case -1: SetLastError( ERROR_INSUFFICIENT_BUFFER ); break;
360 case -2: SetLastError( ERROR_NO_UNICODE_TRANSLATION ); break;
361 }
362 ret = 0;
363 }
364 return ret;
365}
366
367
368/***********************************************************************
Patrik Stridvall3ca98232001-06-20 23:03:14 +0000369 * WideCharToMultiByte (KERNEL32.@)
Alexandre Julliardf7bf7ef2000-06-10 04:42:33 +0000370 *
371 * PARAMS
372 * page [in] Codepage character set to convert to
373 * flags [in] Character mapping flags
374 * src [in] Source string buffer
375 * srclen [in] Length of source string buffer
376 * dst [in] Destination buffer
377 * dstlen [in] Length of destination buffer
378 * defchar [in] Default character to use for conversion if no exact
379 * conversion can be made
380 * used [out] Set if default character was used in the conversion
381 *
382 * NOTES
383 * The returned length includes the null terminator character.
384 *
385 * RETURNS
386 * Success: If dstlen > 0, number of characters written to destination
387 * buffer. If dstlen == 0, number of characters needed to do
388 * conversion.
389 * Failure: 0. Occurs if not enough space is available.
390 *
391 * ERRORS
392 * ERROR_INSUFFICIENT_BUFFER
393 * ERROR_INVALID_PARAMETER
394 */
395INT WINAPI WideCharToMultiByte( UINT page, DWORD flags, LPCWSTR src, INT srclen,
396 LPSTR dst, INT dstlen, LPCSTR defchar, BOOL *used )
397{
398 const union cptable *table;
399 int ret, used_tmp;
400
Wolfgang Schwotzerd9b8f9b2000-07-28 23:58:48 +0000401 if (!src || (!dst && dstlen))
402 {
403 SetLastError( ERROR_INVALID_PARAMETER );
404 return 0;
405 }
406
Dmitry Timoshkov3139b922002-10-04 17:42:27 +0000407 if (srclen < 0) srclen = strlenW(src) + 1;
Alexandre Julliardf7bf7ef2000-06-10 04:42:33 +0000408
Alexandre Julliardaea78532000-08-11 00:44:33 +0000409 switch(page)
410 {
411 case CP_UTF7:
412 FIXME("UTF-7 not supported\n");
413 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
414 return 0;
415 case CP_UTF8:
Alexandre Julliard25fe3612003-03-21 21:30:51 +0000416 ret = wine_utf8_wcstombs( src, srclen, dst, dstlen );
Alexandre Julliardaea78532000-08-11 00:44:33 +0000417 break;
418 default:
419 if (!(table = get_codepage_table( page )))
420 {
421 SetLastError( ERROR_INVALID_PARAMETER );
422 return 0;
423 }
Alexandre Julliard25fe3612003-03-21 21:30:51 +0000424 ret = wine_cp_wcstombs( table, flags, src, srclen, dst, dstlen,
425 defchar, used ? &used_tmp : NULL );
Alexandre Julliardaea78532000-08-11 00:44:33 +0000426 if (used) *used = used_tmp;
427 break;
428 }
Alexandre Julliardf7bf7ef2000-06-10 04:42:33 +0000429
430 if (ret == -1)
431 {
432 SetLastError( ERROR_INSUFFICIENT_BUFFER );
433 ret = 0;
434 }
435 return ret;
436}