Sync with trunk r58687.
[reactos.git] / lib / sdk / crt / mbstring / _setmbcp.c
1 /*
2 * msvcrt.dll mbcs functions
3 *
4 * Copyright 1999 Alexandre Julliard
5 * Copyright 2000 Jon Griffths
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 *
21 * FIXME
22 * Not currently binary compatible with win32. MSVCRT_mbctype must be
23 * populated correctly and the ismb* functions should reference it.
24 */
25
26 #include <precomp.h>
27
28 #include <mbctype.h>
29
30 /* It seems that the data about valid trail bytes is not available from kernel32
31 * so we have to store is here. The format is the same as for lead bytes in CPINFO */
32 struct cp_extra_info_t
33 {
34 int cp;
35 BYTE TrailBytes[MAX_LEADBYTES];
36 };
37
38 static struct cp_extra_info_t g_cpextrainfo[] =
39 {
40 {932, {0x40, 0x7e, 0x80, 0xfc, 0, 0}},
41 {936, {0x40, 0xfe, 0, 0}},
42 {949, {0x41, 0xfe, 0, 0}},
43 {950, {0x40, 0x7e, 0xa1, 0xfe, 0, 0}},
44 {1361, {0x31, 0x7e, 0x81, 0xfe, 0, 0}},
45 {20932, {1, 255, 0, 0}}, /* seems to give different results on different systems */
46 {0, {1, 255, 0, 0}} /* match all with FIXME */
47 };
48
49 /*********************************************************************
50 * INTERNAL: _setmbcp_l
51 */
52 int _setmbcp_l(int cp, LCID lcid, MSVCRT_pthreadmbcinfo mbcinfo)
53 {
54 const char format[] = ".%d";
55
56 int newcp;
57 CPINFO cpi;
58 BYTE *bytes;
59 WORD chartypes[256];
60 char bufA[256];
61 WCHAR bufW[256];
62 int charcount;
63 int ret;
64 int i;
65
66 if(!mbcinfo)
67 mbcinfo = get_mbcinfo();
68
69 switch (cp)
70 {
71 case _MB_CP_ANSI:
72 newcp = GetACP();
73 break;
74 case _MB_CP_OEM:
75 newcp = GetOEMCP();
76 break;
77 case _MB_CP_LOCALE:
78 newcp = get_locinfo()->lc_codepage;
79 if(newcp)
80 break;
81 /* fall through (C locale) */
82 case _MB_CP_SBCS:
83 newcp = 20127; /* ASCII */
84 break;
85 default:
86 newcp = cp;
87 break;
88 }
89
90 if(lcid == -1) {
91 sprintf(bufA, format, newcp);
92 mbcinfo->mblcid = MSVCRT_locale_to_LCID(bufA, NULL);
93 } else {
94 mbcinfo->mblcid = lcid;
95 }
96
97 if(mbcinfo->mblcid == -1)
98 {
99 WARN("Can't assign LCID to codepage (%d)\n", mbcinfo->mblcid);
100 mbcinfo->mblcid = 0;
101 }
102
103 if (!GetCPInfo(newcp, &cpi))
104 {
105 WARN("Codepage %d not found\n", newcp);
106 *_errno() = EINVAL;
107 return -1;
108 }
109
110 /* setup the _mbctype */
111 memset(mbcinfo->mbctype, 0, sizeof(unsigned char[257]));
112 memset(mbcinfo->mbcasemap, 0, sizeof(unsigned char[256]));
113
114 bytes = cpi.LeadByte;
115 while (bytes[0] || bytes[1])
116 {
117 for (i = bytes[0]; i <= bytes[1]; i++)
118 mbcinfo->mbctype[i + 1] |= _M1;
119 bytes += 2;
120 }
121
122 if (cpi.MaxCharSize > 1)
123 {
124 /* trail bytes not available through kernel32 but stored in a structure in msvcrt */
125 struct cp_extra_info_t *cpextra = g_cpextrainfo;
126
127 mbcinfo->ismbcodepage = 1;
128 while (TRUE)
129 {
130 if (cpextra->cp == 0 || cpextra->cp == newcp)
131 {
132 if (cpextra->cp == 0)
133 FIXME("trail bytes data not available for DBCS codepage %d - assuming all bytes\n", newcp);
134
135 bytes = cpextra->TrailBytes;
136 while (bytes[0] || bytes[1])
137 {
138 for (i = bytes[0]; i <= bytes[1]; i++)
139 mbcinfo->mbctype[i + 1] |= _M2;
140 bytes += 2;
141 }
142 break;
143 }
144 cpextra++;
145 }
146 }
147 else
148 mbcinfo->ismbcodepage = 0;
149
150 /* we can't use GetStringTypeA directly because we don't have a locale - only a code page
151 */
152 charcount = 0;
153 for (i = 0; i < 256; i++)
154 if (!(mbcinfo->mbctype[i + 1] & _M1))
155 bufA[charcount++] = i;
156
157 ret = MultiByteToWideChar(newcp, 0, bufA, charcount, bufW, charcount);
158 if (ret != charcount)
159 ERR("MultiByteToWideChar of chars failed for cp %d, ret=%d (exp %d), error=%d\n", newcp, ret, charcount, GetLastError());
160
161 GetStringTypeW(CT_CTYPE1, bufW, charcount, chartypes);
162
163 charcount = 0;
164 for (i = 0; i < 256; i++)
165 if (!(mbcinfo->mbctype[i + 1] & _M1))
166 {
167 if (chartypes[charcount] & C1_UPPER)
168 {
169 mbcinfo->mbctype[i + 1] |= _SBUP;
170 bufW[charcount] = tolowerW(bufW[charcount]);
171 }
172 else if (chartypes[charcount] & C1_LOWER)
173 {
174 mbcinfo->mbctype[i + 1] |= _SBLOW;
175 bufW[charcount] = toupperW(bufW[charcount]);
176 }
177 charcount++;
178 }
179
180 ret = WideCharToMultiByte(newcp, 0, bufW, charcount, bufA, charcount, NULL, NULL);
181 if (ret != charcount)
182 ERR("WideCharToMultiByte failed for cp %d, ret=%d (exp %d), error=%d\n", newcp, ret, charcount, GetLastError());
183
184 charcount = 0;
185 for (i = 0; i < 256; i++)
186 {
187 if(!(mbcinfo->mbctype[i + 1] & _M1))
188 {
189 if(mbcinfo->mbctype[i] & (C1_UPPER|C1_LOWER))
190 mbcinfo->mbcasemap[i] = bufA[charcount];
191 charcount++;
192 }
193 }
194
195 if (newcp == 932) /* CP932 only - set _MP and _MS */
196 {
197 /* On Windows it's possible to calculate the _MP and _MS from CT_CTYPE1
198 * and CT_CTYPE3. But as of Wine 0.9.43 we return wrong values what makes
199 * it hard. As this is set only for codepage 932 we hardcode it what gives
200 * also faster execution.
201 */
202 for (i = 161; i <= 165; i++)
203 mbcinfo->mbctype[i + 1] |= _MP;
204 for (i = 166; i <= 223; i++)
205 mbcinfo->mbctype[i + 1] |= _MS;
206 }
207
208 mbcinfo->mbcodepage = newcp;
209 if(MSVCRT_locale && mbcinfo == MSVCRT_locale->mbcinfo)
210 memcpy(_mbctype, MSVCRT_locale->mbcinfo->mbctype, sizeof(_mbctype));
211
212 return 0;
213 }
214
215 /*********************************************************************
216 * _setmbcp (MSVCRT.@)
217 */
218 int CDECL _setmbcp(int cp)
219 {
220 return _setmbcp_l(cp, -1, NULL);
221 }
222