Rewrote codepage support to use the new codepage tables.
[wine] / memory / codepage.c
1 /*
2  * Code page functions
3  *
4  * Copyright 2000 Alexandre Julliard
5  */
6
7 #include <assert.h>
8 #include <stdio.h>
9
10 #include "winbase.h"
11 #include "winerror.h"
12 #include "winnls.h"
13 #include "wine/unicode.h"
14 #include "debugtools.h"
15
16 DEFAULT_DEBUG_CHANNEL(string);
17
18 /* current code pages */
19 static unsigned int ansi_cp = 1252;  /* Windows 3.1 ISO Latin */
20 static unsigned int oem_cp = 437;    /* MS-DOS United States */
21 static unsigned int mac_cp = 10000;  /* Mac Roman */
22
23 static const union cptable *ansi_cptable;
24 static const union cptable *oem_cptable;
25 static const union cptable *mac_cptable;
26
27
28 /* find the table for a given codepage, handling CP_ACP etc. pseudo-codepages */
29 static const union cptable *get_codepage_table( unsigned int codepage )
30 {
31     const union cptable *ret = NULL;
32
33     if (!ansi_cptable)  /* initialize them */
34     {
35         /* FIXME: should load from the registry */
36         ansi_cptable = cp_get_table( ansi_cp );
37         oem_cptable = cp_get_table( oem_cp );
38         mac_cptable = cp_get_table( mac_cp );
39         assert( ansi_cptable );
40         assert( oem_cptable );
41         assert( mac_cptable );
42     }
43
44     switch(codepage)
45     {
46     case CP_SYMBOL:
47     case CP_ACP:        return ansi_cptable;
48     case CP_OEMCP:      return oem_cptable;
49     case CP_MACCP:      return mac_cptable;
50     case CP_THREAD_ACP: return ansi_cptable; /* FIXME */
51     case CP_UTF7:
52     case CP_UTF8:
53         break;
54     default:
55         if (codepage == ansi_cp) return ansi_cptable;
56         if (codepage == oem_cp) return oem_cptable;
57         if (codepage == mac_cp) return mac_cptable;
58         ret = cp_get_table( codepage );
59         break;
60     }
61     return ret;
62 }
63
64 /******************************************************************************
65  *              GetACP   (KERNEL32)
66  *
67  * RETURNS
68  *    Current ANSI code-page identifier, default if no current defined
69  */
70 UINT WINAPI GetACP(void)
71 {
72     return ansi_cp;
73 }
74
75
76 /***********************************************************************
77  *              GetOEMCP   (KERNEL32)
78  */
79 UINT WINAPI GetOEMCP(void)
80 {
81     return oem_cp;
82 }
83
84
85 /***********************************************************************
86  *           IsValidCodePage   (KERNEL32)
87  */
88 BOOL WINAPI IsValidCodePage( UINT codepage )
89 {
90     return cp_get_table( codepage ) != NULL;
91 }
92
93
94 /***********************************************************************
95  *           IsDBCSLeadByteEx   (KERNEL32)
96  */
97 BOOL WINAPI IsDBCSLeadByteEx( UINT codepage, BYTE testchar )
98 {
99     const union cptable *table = get_codepage_table( codepage );
100     return table && is_dbcs_leadbyte( table, testchar );
101 }
102
103
104 /***********************************************************************
105  *           IsDBCSLeadByte   (KERNEL32)
106  */
107 BOOL WINAPI IsDBCSLeadByte( BYTE testchar )
108 {
109     return is_dbcs_leadbyte( ansi_cptable, testchar );
110 }
111
112
113 /***********************************************************************
114  *           GetCPInfo   (KERNEL32)
115  */
116 BOOL WINAPI GetCPInfo( UINT codepage, LPCPINFO cpinfo )
117 {
118     const union cptable *table = get_codepage_table( codepage );
119
120     if (!table) 
121     {
122         SetLastError( ERROR_INVALID_PARAMETER );
123         return FALSE;
124     }
125     if (table->info.def_char & 0xff00)
126     {
127         cpinfo->DefaultChar[0] = table->info.def_char & 0xff00;
128         cpinfo->DefaultChar[1] = table->info.def_char & 0x00ff;
129     }
130     else
131     {
132         cpinfo->DefaultChar[0] = table->info.def_char & 0xff;
133         cpinfo->DefaultChar[1] = 0;
134     }
135     if ((cpinfo->MaxCharSize = table->info.char_size) == 2)
136         memcpy( cpinfo->LeadByte, table->dbcs.lead_bytes, sizeof(cpinfo->LeadByte) );
137     else
138         cpinfo->LeadByte[0] = cpinfo->LeadByte[1] = 0;
139
140     return TRUE;
141 }
142
143
144 /***********************************************************************
145  *              EnumSystemCodePagesA   (KERNEL32)
146  */
147 BOOL WINAPI EnumSystemCodePagesA( CODEPAGE_ENUMPROCA lpfnCodePageEnum, DWORD flags )
148 {
149     const union cptable *table;
150     char buffer[10];
151     int index = 0;
152
153     for (;;)
154     {
155         if (!(table = cp_enum_table( index++ ))) break;
156         sprintf( buffer, "%d", table->info.codepage );
157         if (!lpfnCodePageEnum( buffer )) break;
158     }
159     return TRUE;
160 }
161
162
163 /***********************************************************************
164  *              EnumSystemCodePagesW   (KERNEL32)
165  */
166 BOOL WINAPI EnumSystemCodePagesW( CODEPAGE_ENUMPROCW lpfnCodePageEnum, DWORD flags )
167 {
168     const union cptable *table;
169     WCHAR buffer[10], *p;
170     int page, index = 0;
171
172     for (;;)
173     {
174         if (!(table = cp_enum_table( index++ ))) break;
175         p = buffer + sizeof(buffer)/sizeof(WCHAR);
176         *--p = 0;
177         page = table->info.codepage;
178         do
179         {
180             *--p = '0' + (page % 10);
181             page /= 10;
182         } while( page );
183         if (!lpfnCodePageEnum( p )) break;
184     }
185     return TRUE;
186 }
187
188
189 /***********************************************************************
190  *              MultiByteToWideChar   (KERNEL32)
191  *
192  * PARAMS
193  *   page [in]    Codepage character set to convert from
194  *   flags [in]   Character mapping flags
195  *   src [in]     Source string buffer
196  *   srclen [in]  Length of source string buffer
197  *   dst [in]     Destination buffer
198  *   dstlen [in]  Length of destination buffer
199  *
200  * NOTES
201  *   The returned length includes the null terminator character.
202  *
203  * RETURNS
204  *   Success: If dstlen > 0, number of characters written to destination
205  *            buffer.  If dstlen == 0, number of characters needed to do
206  *            conversion.
207  *   Failure: 0. Occurs if not enough space is available.
208  *
209  * ERRORS
210  *   ERROR_INSUFFICIENT_BUFFER
211  *   ERROR_INVALID_PARAMETER
212  *   ERROR_NO_UNICODE_TRANSLATION
213  *
214  */
215 INT WINAPI MultiByteToWideChar( UINT page, DWORD flags, LPCSTR src, INT srclen,
216                                 LPWSTR dst, INT dstlen )
217 {
218     const union cptable *table;
219     int ret;
220
221     if (srclen == -1) srclen = strlen(src) + 1;
222
223     if (page >= CP_UTF7)
224     {
225         FIXME("UTF not supported\n");
226         SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
227         return 0;
228     }
229
230     if (!(table = get_codepage_table( page )))
231     {
232         SetLastError( ERROR_INVALID_PARAMETER );
233         return 0;
234     }
235
236     if (flags & MB_COMPOSITE) FIXME("MB_COMPOSITE not supported\n");
237     if (flags & MB_USEGLYPHCHARS) FIXME("MB_USEGLYPHCHARS not supported\n");
238
239     ret = cp_mbstowcs( table, flags, src, srclen, dst, dstlen );
240
241     if (ret < 0)
242     {
243         switch(ret)
244         {
245         case -1: SetLastError( ERROR_INSUFFICIENT_BUFFER ); break;
246         case -2: SetLastError( ERROR_NO_UNICODE_TRANSLATION ); break;
247         }
248         ret = 0;
249     }
250     return ret;
251 }
252
253
254 /***********************************************************************
255  *              WideCharToMultiByte   (KERNEL32)
256  *
257  * PARAMS
258  *   page [in]    Codepage character set to convert to
259  *   flags [in]   Character mapping flags
260  *   src [in]     Source string buffer
261  *   srclen [in]  Length of source string buffer
262  *   dst [in]     Destination buffer
263  *   dstlen [in]  Length of destination buffer
264  *   defchar [in] Default character to use for conversion if no exact
265  *                  conversion can be made
266  *   used [out]   Set if default character was used in the conversion
267  *
268  * NOTES
269  *   The returned length includes the null terminator character.
270  *
271  * RETURNS
272  *   Success: If dstlen > 0, number of characters written to destination
273  *            buffer.  If dstlen == 0, number of characters needed to do
274  *            conversion.
275  *   Failure: 0. Occurs if not enough space is available.
276  *
277  * ERRORS
278  *   ERROR_INSUFFICIENT_BUFFER
279  *   ERROR_INVALID_PARAMETER
280  */
281 INT WINAPI WideCharToMultiByte( UINT page, DWORD flags, LPCWSTR src, INT srclen,
282                                 LPSTR dst, INT dstlen, LPCSTR defchar, BOOL *used )
283 {
284     const union cptable *table;
285     int ret, used_tmp;
286
287     if (srclen == -1) srclen = strlenW(src) + 1;
288
289     if (page >= CP_UTF7)
290     {
291         FIXME("UTF not supported\n");
292         SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
293         return 0;
294     }
295
296     if (!(table = get_codepage_table( page )))
297     {
298         SetLastError( ERROR_INVALID_PARAMETER );
299         return 0;
300     }
301
302 /*    if (flags & WC_COMPOSITECHECK) FIXME( "WC_COMPOSITECHECK (%lx) not supported\n", flags );*/
303
304     ret = cp_wcstombs( table, flags, src, srclen, dst, dstlen, defchar, used ? &used_tmp : NULL );
305     if (used) *used = used_tmp;
306
307     if (ret == -1)
308     {
309         SetLastError( ERROR_INSUFFICIENT_BUFFER );
310         ret = 0;
311     }
312     return ret;
313 }