Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenxsltlocale.c
Go to the documentation of this file.
00001 /* 00002 * xsltlocale.c: locale handling 00003 * 00004 * Reference: 00005 * RFC 3066: Tags for the Identification of Languages 00006 * http://www.ietf.org/rfc/rfc3066.txt 00007 * ISO 639-1, ISO 3166-1 00008 * 00009 * Author: Nick Wellnhofer 00010 * winapi port: Roumen Petrov 00011 */ 00012 00013 #define IN_LIBXSLT 00014 #include "libxslt.h" 00015 00016 #include <string.h> 00017 #include <libxml/xmlmemory.h> 00018 00019 #include "xsltlocale.h" 00020 #include "xsltutils.h" 00021 00022 #if defined(__GLIBC__) && __GLIBC__ == 2 && __GLIBC_MINOR__ <= 2 00023 #define newlocale __newlocale 00024 #define freelocale __freelocale 00025 #define strxfrm_l __strxfrm_l 00026 #define LC_COLLATE_MASK (1 << LC_COLLATE) 00027 #endif 00028 00029 #define ISALPHA(c) ((c & 0xc0) == 0x40 && (unsigned)((c & 0x1f) - 1) < 26) 00030 #define TOUPPER(c) (c & ~0x20) 00031 #define TOLOWER(c) (c | 0x20) 00032 00033 /*without terminating null character*/ 00034 #define XSLTMAX_ISO639LANGLEN 8 00035 #define XSLTMAX_ISO3166CNTRYLEN 8 00036 /* <lang>-<cntry> */ 00037 #define XSLTMAX_LANGTAGLEN (XSLTMAX_ISO639LANGLEN+1+XSLTMAX_ISO3166CNTRYLEN) 00038 00039 static const xmlChar* xsltDefaultRegion(const xmlChar *localeName); 00040 00041 #ifdef XSLT_LOCALE_WINAPI 00042 xmlRMutexPtr xsltLocaleMutex = NULL; 00043 00044 struct xsltRFC1766Info_s { 00045 /*note typedef unsigned char xmlChar !*/ 00046 xmlChar tag[XSLTMAX_LANGTAGLEN+1]; 00047 /*note typedef LCID xsltLocale !*/ 00048 xsltLocale lcid; 00049 }; 00050 typedef struct xsltRFC1766Info_s xsltRFC1766Info; 00051 00052 static int xsltLocaleListSize = 0; 00053 static xsltRFC1766Info *xsltLocaleList = NULL; 00054 00055 00056 static xsltLocale 00057 xslt_locale_WINAPI(const xmlChar *languageTag) { 00058 int k; 00059 xsltRFC1766Info *p = xsltLocaleList; 00060 00061 for (k=0; k<xsltLocaleListSize; k++, p++) 00062 if (xmlStrcmp(p->tag, languageTag) == 0) return p->lcid; 00063 return((xsltLocale)0); 00064 } 00065 00066 static void xsltEnumSupportedLocales(void); 00067 #endif 00068 00078 xsltLocale 00079 xsltNewLocale(const xmlChar *languageTag) { 00080 #ifdef XSLT_LOCALE_XLOCALE 00081 xsltLocale locale; 00082 char localeName[XSLTMAX_LANGTAGLEN+6]; /* 6 chars for ".utf8\0" */ 00083 const xmlChar *p = languageTag; 00084 const char *region = NULL; 00085 char *q = localeName; 00086 int i, llen; 00087 00088 /* Convert something like "pt-br" to "pt_BR.utf8" */ 00089 00090 if (languageTag == NULL) 00091 return(NULL); 00092 00093 for (i=0; i<XSLTMAX_ISO639LANGLEN && ISALPHA(*p); ++i) 00094 *q++ = TOLOWER(*p++); 00095 00096 if (i == 0) 00097 return(NULL); 00098 00099 llen = i; 00100 *q++ = '_'; 00101 00102 if (*p) { 00103 if (*p++ != '-') 00104 return(NULL); 00105 00106 for (i=0; i<XSLTMAX_ISO3166CNTRYLEN && ISALPHA(*p); ++i) 00107 *q++ = TOUPPER(*p++); 00108 00109 if (i == 0 || *p) 00110 return(NULL); 00111 00112 memcpy(q, ".utf8", 6); 00113 locale = newlocale(LC_COLLATE_MASK, localeName, NULL); 00114 if (locale != NULL) 00115 return(locale); 00116 00117 /* Continue without using country code */ 00118 00119 q = localeName + llen + 1; 00120 } 00121 00122 /* Try locale without territory, e.g. for Esperanto (eo) */ 00123 00124 memcpy(q, ".utf8", 6); 00125 locale = newlocale(LC_COLLATE_MASK, localeName, NULL); 00126 if (locale != NULL) 00127 return(locale); 00128 00129 /* Try to find most common country for language */ 00130 00131 if (llen != 2) 00132 return(NULL); 00133 00134 region = (char *)xsltDefaultRegion((xmlChar *)localeName); 00135 if (region == NULL) 00136 return(NULL); 00137 00138 q = localeName + llen + 1; 00139 *q++ = region[0]; 00140 *q++ = region[1]; 00141 memcpy(q, ".utf8", 6); 00142 locale = newlocale(LC_COLLATE_MASK, localeName, NULL); 00143 00144 return(locale); 00145 #endif 00146 00147 #ifdef XSLT_LOCALE_WINAPI 00148 { 00149 xsltLocale locale = (xsltLocale)0; 00150 xmlChar localeName[XSLTMAX_LANGTAGLEN+1]; 00151 xmlChar *q = localeName; 00152 const xmlChar *p = languageTag; 00153 int i, llen; 00154 const xmlChar *region = NULL; 00155 00156 if (languageTag == NULL) goto end; 00157 00158 xsltEnumSupportedLocales(); 00159 00160 for (i=0; i<XSLTMAX_ISO639LANGLEN && ISALPHA(*p); ++i) 00161 *q++ = TOLOWER(*p++); 00162 if (i == 0) goto end; 00163 00164 llen = i; 00165 *q++ = '-'; 00166 if (*p) { /*if country tag is given*/ 00167 if (*p++ != '-') goto end; 00168 00169 for (i=0; i<XSLTMAX_ISO3166CNTRYLEN && ISALPHA(*p); ++i) 00170 *q++ = TOUPPER(*p++); 00171 if (i == 0 || *p) goto end; 00172 00173 *q = '\0'; 00174 locale = xslt_locale_WINAPI(localeName); 00175 if (locale != (xsltLocale)0) goto end; 00176 } 00177 /* Try to find most common country for language */ 00178 region = xsltDefaultRegion(localeName); 00179 if (region == NULL) goto end; 00180 00181 strcpy(localeName + llen + 1, region); 00182 locale = xslt_locale_WINAPI(localeName); 00183 end: 00184 return(locale); 00185 } 00186 #endif 00187 00188 #ifdef XSLT_LOCALE_NONE 00189 return(NULL); 00190 #endif 00191 } 00192 00193 static const xmlChar* 00194 xsltDefaultRegion(const xmlChar *localeName) { 00195 xmlChar c; 00196 /* region should be xmlChar, but gcc warns on all string assignments */ 00197 const char *region = NULL; 00198 00199 c = localeName[1]; 00200 /* This is based on the locales from glibc 2.3.3 */ 00201 00202 switch (localeName[0]) { 00203 case 'a': 00204 if (c == 'a' || c == 'm') region = "ET"; 00205 else if (c == 'f') region = "ZA"; 00206 else if (c == 'n') region = "ES"; 00207 else if (c == 'r') region = "AE"; 00208 else if (c == 'z') region = "AZ"; 00209 break; 00210 case 'b': 00211 if (c == 'e') region = "BY"; 00212 else if (c == 'g') region = "BG"; 00213 else if (c == 'n') region = "BD"; 00214 else if (c == 'r') region = "FR"; 00215 else if (c == 's') region = "BA"; 00216 break; 00217 case 'c': 00218 if (c == 'a') region = "ES"; 00219 else if (c == 's') region = "CZ"; 00220 else if (c == 'y') region = "GB"; 00221 break; 00222 case 'd': 00223 if (c == 'a') region = "DK"; 00224 else if (c == 'e') region = "DE"; 00225 break; 00226 case 'e': 00227 if (c == 'l') region = "GR"; 00228 else if (c == 'n' || c == 'o') region = "US"; 00229 else if (c == 's' || c == 'u') region = "ES"; 00230 else if (c == 't') region = "EE"; 00231 break; 00232 case 'f': 00233 if (c == 'a') region = "IR"; 00234 else if (c == 'i') region = "FI"; 00235 else if (c == 'o') region = "FO"; 00236 else if (c == 'r') region = "FR"; 00237 break; 00238 case 'g': 00239 if (c == 'a') region = "IE"; 00240 else if (c == 'l') region = "ES"; 00241 else if (c == 'v') region = "GB"; 00242 break; 00243 case 'h': 00244 if (c == 'e') region = "IL"; 00245 else if (c == 'i') region = "IN"; 00246 else if (c == 'r') region = "HT"; 00247 else if (c == 'u') region = "HU"; 00248 break; 00249 case 'i': 00250 if (c == 'd') region = "ID"; 00251 else if (c == 's') region = "IS"; 00252 else if (c == 't') region = "IT"; 00253 else if (c == 'w') region = "IL"; 00254 break; 00255 case 'j': 00256 if (c == 'a') region = "JP"; 00257 break; 00258 case 'k': 00259 if (c == 'l') region = "GL"; 00260 else if (c == 'o') region = "KR"; 00261 else if (c == 'w') region = "GB"; 00262 break; 00263 case 'l': 00264 if (c == 't') region = "LT"; 00265 else if (c == 'v') region = "LV"; 00266 break; 00267 case 'm': 00268 if (c == 'k') region = "MK"; 00269 else if (c == 'l' || c == 'r') region = "IN"; 00270 else if (c == 'n') region = "MN"; 00271 else if (c == 's') region = "MY"; 00272 else if (c == 't') region = "MT"; 00273 break; 00274 case 'n': 00275 if (c == 'b' || c == 'n' || c == 'o') region = "NO"; 00276 else if (c == 'e') region = "NP"; 00277 else if (c == 'l') region = "NL"; 00278 break; 00279 case 'o': 00280 if (c == 'm') region = "ET"; 00281 break; 00282 case 'p': 00283 if (c == 'a') region = "IN"; 00284 else if (c == 'l') region = "PL"; 00285 else if (c == 't') region = "PT"; 00286 break; 00287 case 'r': 00288 if (c == 'o') region = "RO"; 00289 else if (c == 'u') region = "RU"; 00290 break; 00291 case 's': 00292 switch (c) { 00293 case 'e': region = "NO"; break; 00294 case 'h': region = "YU"; break; 00295 case 'k': region = "SK"; break; 00296 case 'l': region = "SI"; break; 00297 case 'o': region = "ET"; break; 00298 case 'q': region = "AL"; break; 00299 case 't': region = "ZA"; break; 00300 case 'v': region = "SE"; break; 00301 } 00302 break; 00303 case 't': 00304 if (c == 'a' || c == 'e') region = "IN"; 00305 else if (c == 'h') region = "TH"; 00306 else if (c == 'i') region = "ER"; 00307 else if (c == 'r') region = "TR"; 00308 else if (c == 't') region = "RU"; 00309 break; 00310 case 'u': 00311 if (c == 'k') region = "UA"; 00312 else if (c == 'r') region = "PK"; 00313 break; 00314 case 'v': 00315 if (c == 'i') region = "VN"; 00316 break; 00317 case 'w': 00318 if (c == 'a') region = "BE"; 00319 break; 00320 case 'x': 00321 if (c == 'h') region = "ZA"; 00322 break; 00323 case 'z': 00324 if (c == 'h') region = "CN"; 00325 else if (c == 'u') region = "ZA"; 00326 break; 00327 } 00328 return((xmlChar *)region); 00329 } 00330 00337 void 00338 xsltFreeLocale(xsltLocale locale) { 00339 #ifdef XSLT_LOCALE_XLOCALE 00340 freelocale(locale); 00341 #endif 00342 } 00343 00354 xsltLocaleChar * 00355 xsltStrxfrm(xsltLocale locale, const xmlChar *string) 00356 { 00357 #ifdef XSLT_LOCALE_NONE 00358 return(NULL); 00359 #else 00360 size_t xstrlen, r; 00361 xsltLocaleChar *xstr; 00362 00363 #ifdef XSLT_LOCALE_XLOCALE 00364 xstrlen = strxfrm_l(NULL, (const char *)string, 0, locale) + 1; 00365 xstr = (xsltLocaleChar *) xmlMalloc(xstrlen); 00366 if (xstr == NULL) { 00367 xsltTransformError(NULL, NULL, NULL, 00368 "xsltStrxfrm : out of memory error\n"); 00369 return(NULL); 00370 } 00371 00372 r = strxfrm_l((char *)xstr, (const char *)string, xstrlen, locale); 00373 #endif 00374 00375 #ifdef XSLT_LOCALE_WINAPI 00376 xstrlen = MultiByteToWideChar(CP_UTF8, 0, string, -1, NULL, 0); 00377 if (xstrlen == 0) { 00378 xsltTransformError(NULL, NULL, NULL, "xsltStrxfrm : MultiByteToWideChar check failed\n"); 00379 return(NULL); 00380 } 00381 xstr = (xsltLocaleChar*) xmlMalloc(xstrlen * sizeof(xsltLocaleChar)); 00382 if (xstr == NULL) { 00383 xsltTransformError(NULL, NULL, NULL, "xsltStrxfrm : out of memory\n"); 00384 return(NULL); 00385 } 00386 r = MultiByteToWideChar(CP_UTF8, 0, string, -1, xstr, xstrlen); 00387 if (r == 0) { 00388 xsltTransformError(NULL, NULL, NULL, "xsltStrxfrm : MultiByteToWideChar failed\n"); 00389 xmlFree(xstr); 00390 return(NULL); 00391 } 00392 return(xstr); 00393 #endif /* XSLT_LOCALE_WINAPI */ 00394 00395 if (r >= xstrlen) { 00396 xsltTransformError(NULL, NULL, NULL, "xsltStrxfrm : strxfrm failed\n"); 00397 xmlFree(xstr); 00398 return(NULL); 00399 } 00400 00401 return(xstr); 00402 #endif /* XSLT_LOCALE_NONE */ 00403 } 00404 00417 int 00418 xsltLocaleStrcmp(xsltLocale locale, const xsltLocaleChar *str1, const xsltLocaleChar *str2) { 00419 (void)locale; 00420 #ifdef XSLT_LOCALE_WINAPI 00421 { 00422 int ret; 00423 if (str1 == str2) return(0); 00424 if (str1 == NULL) return(-1); 00425 if (str2 == NULL) return(1); 00426 ret = CompareStringW(locale, 0, str1, -1, str2, -1); 00427 if (ret == 0) { 00428 xsltTransformError(NULL, NULL, NULL, "xsltLocaleStrcmp : CompareStringW fail\n"); 00429 return(0); 00430 } 00431 return(ret - 2); 00432 } 00433 #else 00434 return(xmlStrcmp(str1, str2)); 00435 #endif 00436 } 00437 00438 #ifdef XSLT_LOCALE_WINAPI 00439 00447 BOOL CALLBACK 00448 xsltCountSupportedLocales(LPSTR lcid) { 00449 (void) lcid; 00450 ++xsltLocaleListSize; 00451 return(TRUE); 00452 } 00453 00462 BOOL CALLBACK 00463 xsltIterateSupportedLocales(LPSTR lcid) { 00464 static int count = 0; 00465 xmlChar iso639lang [XSLTMAX_ISO639LANGLEN +1]; 00466 xmlChar iso3136ctry[XSLTMAX_ISO3166CNTRYLEN+1]; 00467 int k, l; 00468 xsltRFC1766Info *p = xsltLocaleList + count; 00469 00470 k = sscanf(lcid, "%lx", (long*)&p->lcid); 00471 if (k < 1) goto end; 00472 /*don't count terminating null character*/ 00473 k = GetLocaleInfoA(p->lcid, LOCALE_SISO639LANGNAME , iso639lang , sizeof(iso639lang )); 00474 if (--k < 1) goto end; 00475 l = GetLocaleInfoA(p->lcid, LOCALE_SISO3166CTRYNAME, iso3136ctry, sizeof(iso3136ctry)); 00476 if (--l < 1) goto end; 00477 00478 { /*fill results*/ 00479 xmlChar *q = p->tag; 00480 memcpy(q, iso639lang, k); 00481 q += k; 00482 *q++ = '-'; 00483 memcpy(q, iso3136ctry, l); 00484 q += l; 00485 *q = '\0'; 00486 } 00487 ++count; 00488 end: 00489 return((count < xsltLocaleListSize) ? TRUE : FALSE); 00490 } 00491 00492 00493 static void 00494 xsltEnumSupportedLocales(void) { 00495 xmlRMutexLock(xsltLocaleMutex); 00496 if (xsltLocaleListSize <= 0) { 00497 size_t len; 00498 00499 EnumSystemLocalesA(xsltCountSupportedLocales, LCID_SUPPORTED); 00500 00501 len = xsltLocaleListSize * sizeof(xsltRFC1766Info); 00502 xsltLocaleList = xmlMalloc(len); 00503 memset(xsltLocaleList, 0, len); 00504 EnumSystemLocalesA(xsltIterateSupportedLocales, LCID_SUPPORTED); 00505 } 00506 xmlRMutexUnlock(xsltLocaleMutex); 00507 } 00508 00509 #endif /*def XSLT_LOCALE_WINAPI*/ Generated on Fri May 25 2012 04:17:49 for ReactOS by
1.7.6.1
|