1 /*
2 * Copyright (c) 2007 2008
3 * Francois Dumont
4 *
5 * This material is provided "as is", with absolutely no warranty expressed
6 * or implied. Any use is at your own risk.
7 *
8 * Permission to use or copy this software for any purpose is hereby granted
9 * without fee, provided the above notices are retained on all copies.
10 * Permission to modify the code and to distribute modified code is granted,
11 * provided the above notices are retained, and a notice that the code was
12 * modified is included with the above copyright notice.
13 *
14 */
15
16 #if defined (_STLP_USE_SAFE_STRING_FUNCTIONS)
17 # define _STLP_WCSNCPY(D, DS, S, C) wcsncpy_s(D, DS, S, C)
18 #else
19 # define _STLP_WCSNCPY(D, DS, S, C) wcsncpy(D, S, C)
20 #endif
21
22 static const wchar_t* __wtrue_name = L"true";
23 static const wchar_t* __wfalse_name = L"false";
24
25 typedef struct _Locale_codecvt {
26 _Locale_lcid_t lc;
27 UINT cp;
28 unsigned char cleads[256 / CHAR_BIT];
29 unsigned char max_char_size;
30 DWORD mbtowc_flags;
31 DWORD wctomb_flags;
32 } _Locale_codecvt_t;
33
34 /* Ctype */
_WLocale_ctype(_Locale_ctype_t * ltype,wint_t c,_Locale_mask_t which_bits)35 _Locale_mask_t _WLocale_ctype(_Locale_ctype_t* ltype, wint_t c,
36 _Locale_mask_t which_bits) {
37 wchar_t buf[2];
38 WORD out[2];
39 buf[0] = c; buf[1] = 0;
40 GetStringTypeW(CT_CTYPE1, buf, -1, out);
41 _STLP_MARK_PARAMETER_AS_UNUSED(ltype)
42 return (_Locale_mask_t)(MapCtypeMask(out[0]) & which_bits);
43 }
44
_WLocale_tolower(_Locale_ctype_t * ltype,wint_t c)45 wint_t _WLocale_tolower(_Locale_ctype_t* ltype, wint_t c) {
46 wchar_t in_c = c;
47 wchar_t res;
48
49 LCMapStringW(ltype->lc.id, LCMAP_LOWERCASE, &in_c, 1, &res, 1);
50 return res;
51 }
52
_WLocale_toupper(_Locale_ctype_t * ltype,wint_t c)53 wint_t _WLocale_toupper(_Locale_ctype_t* ltype, wint_t c) {
54 wchar_t in_c = c;
55 wchar_t res;
56
57 LCMapStringW(ltype->lc.id, LCMAP_UPPERCASE, &in_c, 1, &res, 1);
58 return res;
59 }
60
_Locale_codecvt_create(const char * name,_Locale_lcid_t * lc_hint,int * __err_code)61 _Locale_codecvt_t* _Locale_codecvt_create(const char * name, _Locale_lcid_t* lc_hint, int *__err_code) {
62 char cp_name[MAX_CP_LEN + 1];
63 unsigned char *ptr;
64 CPINFO CPInfo;
65 int i;
66
67 _Locale_codecvt_t *lcodecvt = (_Locale_codecvt_t*)malloc(sizeof(_Locale_codecvt_t));
68
69 if (!lcodecvt) { *__err_code = _STLP_LOC_NO_MEMORY; return lcodecvt; }
70 memset(lcodecvt, 0, sizeof(_Locale_codecvt_t));
71
72 if (__GetLCIDFromName(name, &lcodecvt->lc.id, cp_name, lc_hint) == -1)
73 { free(lcodecvt); *__err_code = _STLP_LOC_UNKNOWN_NAME; return NULL; }
74
75 lcodecvt->cp = atoi(cp_name);
76 if (!GetCPInfo(lcodecvt->cp, &CPInfo)) { free(lcodecvt); return NULL; }
77
78 if (lcodecvt->cp != CP_UTF7 && lcodecvt->cp != CP_UTF8) {
79 lcodecvt->mbtowc_flags = MB_PRECOMPOSED;
80 lcodecvt->wctomb_flags = WC_COMPOSITECHECK | WC_SEPCHARS;
81 }
82 lcodecvt->max_char_size = CPInfo.MaxCharSize;
83
84 if (CPInfo.MaxCharSize > 1) {
85 for (ptr = (unsigned char*)CPInfo.LeadByte; *ptr && *(ptr + 1); ptr += 2)
86 for (i = *ptr; i <= *(ptr + 1); ++i) lcodecvt->cleads[i / CHAR_BIT] |= (0x01 << i % CHAR_BIT);
87 }
88
89 return lcodecvt;
90 }
91
_Locale_codecvt_name(const _Locale_codecvt_t * lcodecvt,char * buf)92 char const* _Locale_codecvt_name(const _Locale_codecvt_t* lcodecvt, char* buf) {
93 char cp_buf[MAX_CP_LEN + 1];
94 my_ltoa(lcodecvt->cp, cp_buf);
95 return __GetLocaleName(lcodecvt->lc.id, cp_buf, buf);
96 }
97
_Locale_codecvt_destroy(_Locale_codecvt_t * lcodecvt)98 void _Locale_codecvt_destroy(_Locale_codecvt_t* lcodecvt) {
99 if (!lcodecvt) return;
100
101 free(lcodecvt);
102 }
103
_WLocale_mb_cur_max(_Locale_codecvt_t * lcodecvt)104 int _WLocale_mb_cur_max (_Locale_codecvt_t * lcodecvt)
105 { return lcodecvt->max_char_size; }
106
_WLocale_mb_cur_min(_Locale_codecvt_t * lcodecvt)107 int _WLocale_mb_cur_min (_Locale_codecvt_t *lcodecvt) {
108 _STLP_MARK_PARAMETER_AS_UNUSED(lcodecvt)
109 return 1;
110 }
111
_WLocale_is_stateless(_Locale_codecvt_t * lcodecvt)112 int _WLocale_is_stateless (_Locale_codecvt_t * lcodecvt)
113 { return (lcodecvt->max_char_size == 1) ? 1 : 0; }
114
__isleadbyte(int i,unsigned char * ctable)115 static int __isleadbyte(int i, unsigned char *ctable) {
116 unsigned char c = (unsigned char)i;
117 return (ctable[c / CHAR_BIT] & (0x01 << c % CHAR_BIT));
118 }
119
__mbtowc(_Locale_codecvt_t * l,wchar_t * dst,const char * from,unsigned int count)120 static int __mbtowc(_Locale_codecvt_t *l, wchar_t *dst, const char *from, unsigned int count) {
121 int result;
122
123 if (l->cp == CP_UTF7 || l->cp == CP_UTF8) {
124 result = MultiByteToWideChar(l->cp, l->mbtowc_flags, from, count, dst, 1);
125 if (result == 0) {
126 switch (GetLastError()) {
127 case ERROR_NO_UNICODE_TRANSLATION:
128 return -2;
129 default:
130 return -1;
131 }
132 }
133 }
134 else {
135 if (count == 1 && __isleadbyte(*from, l->cleads)) return (size_t)-2;
136 result = MultiByteToWideChar(l->cp, l->mbtowc_flags, from, count, dst, 1);
137 if (result == 0) return -1;
138 }
139
140 return result;
141 }
142
_WLocale_mbtowc(_Locale_codecvt_t * lcodecvt,wchar_t * to,const char * from,size_t n,mbstate_t * shift_state)143 size_t _WLocale_mbtowc(_Locale_codecvt_t *lcodecvt, wchar_t *to,
144 const char *from, size_t n, mbstate_t *shift_state) {
145 int result;
146 _STLP_MARK_PARAMETER_AS_UNUSED(shift_state)
147 if (lcodecvt->max_char_size == 1) { /* Single byte encoding. */
148 result = MultiByteToWideChar(lcodecvt->cp, lcodecvt->mbtowc_flags, from, 1, to, 1);
149 if (result == 0) return (size_t)-1;
150 return result;
151 }
152 else { /* Multi byte encoding. */
153 int retval;
154 unsigned int count = 1;
155 while (n--) {
156 retval = __mbtowc(lcodecvt, to, from, count);
157 if (retval == -2)
158 { if (++count > ((unsigned int)lcodecvt->max_char_size)) return (size_t)-1; }
159 else if (retval == -1)
160 { return (size_t)-1; }
161 else
162 { return count; }
163 }
164 return (size_t)-2;
165 }
166 }
167
_WLocale_wctomb(_Locale_codecvt_t * lcodecvt,char * to,size_t n,const wchar_t c,mbstate_t * shift_state)168 size_t _WLocale_wctomb(_Locale_codecvt_t *lcodecvt, char *to, size_t n,
169 const wchar_t c, mbstate_t *shift_state) {
170 int size = WideCharToMultiByte(lcodecvt->cp, lcodecvt->wctomb_flags, &c, 1, NULL, 0, NULL, NULL);
171
172 if (!size) return (size_t)-1;
173 if ((size_t)size > n) return (size_t)-2;
174
175 if (n > INT_MAX)
176 /* Limiting the output buf size to INT_MAX seems like reasonable to transform a single wchar_t. */
177 n = INT_MAX;
178
179 WideCharToMultiByte(lcodecvt->cp, lcodecvt->wctomb_flags, &c, 1, to, (int)n, NULL, NULL);
180
181 _STLP_MARK_PARAMETER_AS_UNUSED(shift_state)
182 return (size_t)size;
183 }
184
_WLocale_unshift(_Locale_codecvt_t * lcodecvt,mbstate_t * st,char * buf,size_t n,char ** next)185 size_t _WLocale_unshift(_Locale_codecvt_t *lcodecvt, mbstate_t *st,
186 char *buf, size_t n, char **next) {
187 /* _WLocale_wctomb do not even touch to st, there is nothing to unshift in this localization implementation. */
188 _STLP_MARK_PARAMETER_AS_UNUSED(lcodecvt)
189 _STLP_MARK_PARAMETER_AS_UNUSED(st)
190 _STLP_MARK_PARAMETER_AS_UNUSED(&n)
191 *next = buf;
192 return 0;
193 }
194
195 /* Collate */
196 /* This function takes care of the potential size_t DWORD different size. */
_WLocale_strcmp_aux(_Locale_collate_t * lcol,const wchar_t * s1,size_t n1,const wchar_t * s2,size_t n2)197 static int _WLocale_strcmp_aux(_Locale_collate_t* lcol,
198 const wchar_t* s1, size_t n1,
199 const wchar_t* s2, size_t n2) {
200 int result = CSTR_EQUAL;
201 while (n1 > 0 || n2 > 0) {
202 DWORD size1 = trim_size_t_to_DWORD(n1);
203 DWORD size2 = trim_size_t_to_DWORD(n2);
204 result = CompareStringW(lcol->lc.id, 0, s1, size1, s2, size2);
205 if (result != CSTR_EQUAL)
206 break;
207 n1 -= size1;
208 n2 -= size2;
209 }
210 return result;
211 }
212
_WLocale_strcmp(_Locale_collate_t * lcol,const wchar_t * s1,size_t n1,const wchar_t * s2,size_t n2)213 int _WLocale_strcmp(_Locale_collate_t* lcol,
214 const wchar_t* s1, size_t n1,
215 const wchar_t* s2, size_t n2) {
216 int result;
217 result = _WLocale_strcmp_aux(lcol, s1, n1, s2, n2);
218 return (result == CSTR_EQUAL) ? 0 : (result == CSTR_LESS_THAN) ? -1 : 1;
219 }
220
_WLocale_strxfrm(_Locale_collate_t * lcol,wchar_t * dst,size_t dst_size,const wchar_t * src,size_t src_size)221 size_t _WLocale_strxfrm(_Locale_collate_t* lcol,
222 wchar_t* dst, size_t dst_size,
223 const wchar_t* src, size_t src_size) {
224 int result, i;
225
226 /* see _Locale_strxfrm: */
227 if (src_size > INT_MAX) {
228 if (dst != 0) {
229 _STLP_WCSNCPY(dst, dst_size, src, src_size);
230 }
231 return src_size;
232 }
233 if (dst_size > INT_MAX) {
234 dst_size = INT_MAX;
235 }
236 result = LCMapStringW(lcol->lc.id, LCMAP_SORTKEY, src, (int)src_size, dst, (int)dst_size);
237 if (result != 0 && dst != 0) {
238 for (i = result - 1; i >= 0; --i) {
239 dst[i] = ((unsigned char*)dst)[i];
240 }
241 }
242 return result != 0 ? result - 1 : 0;
243 }
244
245 /* Numeric */
_WLocale_decimal_point(_Locale_numeric_t * lnum)246 wchar_t _WLocale_decimal_point(_Locale_numeric_t* lnum) {
247 wchar_t buf[4];
248 GetLocaleInfoW(lnum->lc.id, LOCALE_SDECIMAL, buf, 4);
249 return buf[0];
250 }
251
_WLocale_thousands_sep(_Locale_numeric_t * lnum)252 wchar_t _WLocale_thousands_sep(_Locale_numeric_t* lnum) {
253 wchar_t buf[4];
254 GetLocaleInfoW(lnum->lc.id, LOCALE_STHOUSAND, buf, 4);
255 return buf[0];
256 }
257
_WLocale_true(_Locale_numeric_t * lnum,wchar_t * buf,size_t bufSize)258 const wchar_t * _WLocale_true(_Locale_numeric_t* lnum, wchar_t* buf, size_t bufSize) {
259 _STLP_MARK_PARAMETER_AS_UNUSED(lnum)
260 _STLP_MARK_PARAMETER_AS_UNUSED(buf)
261 _STLP_MARK_PARAMETER_AS_UNUSED(&bufSize)
262 return __wtrue_name;
263 }
264
_WLocale_false(_Locale_numeric_t * lnum,wchar_t * buf,size_t bufSize)265 const wchar_t * _WLocale_false(_Locale_numeric_t* lnum, wchar_t* buf, size_t bufSize) {
266 _STLP_MARK_PARAMETER_AS_UNUSED(lnum)
267 _STLP_MARK_PARAMETER_AS_UNUSED(buf)
268 _STLP_MARK_PARAMETER_AS_UNUSED(&bufSize)
269 return __wfalse_name;
270 }
271
272 /* Monetary */
_WLocale_int_curr_symbol(_Locale_monetary_t * lmon,wchar_t * buf,size_t bufSize)273 const wchar_t* _WLocale_int_curr_symbol(_Locale_monetary_t * lmon, wchar_t* buf, size_t bufSize)
274 { GetLocaleInfoW(lmon->lc.id, LOCALE_SINTLSYMBOL, buf, (int)bufSize); return buf; }
275
_WLocale_currency_symbol(_Locale_monetary_t * lmon,wchar_t * buf,size_t bufSize)276 const wchar_t* _WLocale_currency_symbol(_Locale_monetary_t * lmon, wchar_t* buf, size_t bufSize)
277 { GetLocaleInfoW(lmon->lc.id, LOCALE_SCURRENCY, buf, (int)bufSize); return buf; }
278
_WLocale_mon_decimal_point(_Locale_monetary_t * lmon)279 wchar_t _WLocale_mon_decimal_point(_Locale_monetary_t * lmon)
280 { return lmon->decimal_point[0]; }
281
_WLocale_mon_thousands_sep(_Locale_monetary_t * lmon)282 wchar_t _WLocale_mon_thousands_sep(_Locale_monetary_t * lmon)
283 { return lmon->thousands_sep[0]; }
284
_WLocale_positive_sign(_Locale_monetary_t * lmon,wchar_t * buf,size_t bufSize)285 const wchar_t* _WLocale_positive_sign(_Locale_monetary_t * lmon, wchar_t* buf, size_t bufSize)
286 { GetLocaleInfoW(lmon->lc.id, LOCALE_SPOSITIVESIGN, buf, (int)bufSize); return buf; }
287
_WLocale_negative_sign(_Locale_monetary_t * lmon,wchar_t * buf,size_t bufSize)288 const wchar_t* _WLocale_negative_sign(_Locale_monetary_t * lmon, wchar_t* buf, size_t bufSize)
289 { GetLocaleInfoW(lmon->lc.id, LOCALE_SNEGATIVESIGN, buf, (int)bufSize); return buf; }
290
291 /* Time */
_WLocale_full_monthname(_Locale_time_t * ltime,int month,wchar_t * buf,size_t bufSize)292 const wchar_t * _WLocale_full_monthname(_Locale_time_t * ltime, int month,
293 wchar_t* buf, size_t bufSize)
294 { GetLocaleInfoW(ltime->lc.id, LOCALE_SMONTHNAME1 + month, buf, (int)bufSize); return buf; }
295
_WLocale_abbrev_monthname(_Locale_time_t * ltime,int month,wchar_t * buf,size_t bufSize)296 const wchar_t * _WLocale_abbrev_monthname(_Locale_time_t * ltime, int month,
297 wchar_t* buf, size_t bufSize)
298 { GetLocaleInfoW(ltime->lc.id, LOCALE_SABBREVMONTHNAME1 + month, buf, (int)bufSize); return buf; }
299
_WLocale_full_dayofweek(_Locale_time_t * ltime,int day,wchar_t * buf,size_t bufSize)300 const wchar_t * _WLocale_full_dayofweek(_Locale_time_t * ltime, int day,
301 wchar_t* buf, size_t bufSize)
302 { GetLocaleInfoW(ltime->lc.id, LOCALE_SDAYNAME1 + day, buf, (int)bufSize); return buf; }
303
_WLocale_abbrev_dayofweek(_Locale_time_t * ltime,int day,wchar_t * buf,size_t bufSize)304 const wchar_t * _WLocale_abbrev_dayofweek(_Locale_time_t * ltime, int day,
305 wchar_t* buf, size_t bufSize)
306 { GetLocaleInfoW(ltime->lc.id, LOCALE_SABBREVDAYNAME1 + day, buf, (int)bufSize); return buf; }
307
_WLocale_am_str(_Locale_time_t * ltime,wchar_t * buf,size_t bufSize)308 const wchar_t* _WLocale_am_str(_Locale_time_t* ltime,
309 wchar_t* buf, size_t bufSize)
310 { GetLocaleInfoW(ltime->lc.id, LOCALE_S1159, buf, (int)bufSize); return buf; }
311
_WLocale_pm_str(_Locale_time_t * ltime,wchar_t * buf,size_t bufSize)312 const wchar_t* _WLocale_pm_str(_Locale_time_t* ltime,
313 wchar_t* buf, size_t bufSize)
314 { GetLocaleInfoW(ltime->lc.id, LOCALE_S2359, buf, (int)bufSize); return buf; }
315