xref: /reactos/sdk/lib/crt/mbstring/_setmbcp.c (revision 8a978a17)
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(global_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 
223