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 22static const wchar_t* __wtrue_name = L"true"; 23static const wchar_t* __wfalse_name = L"false"; 24 25typedef 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 */ 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 45wint_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 53wint_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 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 92char 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 98void _Locale_codecvt_destroy(_Locale_codecvt_t* lcodecvt) { 99 if (!lcodecvt) return; 100 101 free(lcodecvt); 102} 103 104int _WLocale_mb_cur_max (_Locale_codecvt_t * lcodecvt) 105{ return lcodecvt->max_char_size; } 106 107int _WLocale_mb_cur_min (_Locale_codecvt_t *lcodecvt) { 108 _STLP_MARK_PARAMETER_AS_UNUSED(lcodecvt) 109 return 1; 110} 111 112int _WLocale_is_stateless (_Locale_codecvt_t * lcodecvt) 113{ return (lcodecvt->max_char_size == 1) ? 1 : 0; } 114 115static 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 120static 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 143size_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 168size_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 185size_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. */ 197static 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 213int _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 221size_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 */ 246wchar_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 252wchar_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 258const 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 265const 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 */ 273const 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 276const 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 279wchar_t _WLocale_mon_decimal_point(_Locale_monetary_t * lmon) 280{ return lmon->decimal_point[0]; } 281 282wchar_t _WLocale_mon_thousands_sep(_Locale_monetary_t * lmon) 283{ return lmon->thousands_sep[0]; } 284 285const 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 288const 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 */ 292const 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 296const 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 300const 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 304const 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 308const 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 312const 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