/* * xsltlocale.c: locale handling * * Reference: * RFC 3066: Tags for the Identification of Languages * http://www.ietf.org/rfc/rfc3066.txt * ISO 639-1, ISO 3166-1 * * Author: Nick Wellnhofer * winapi port: Roumen Petrov */ #define IN_LIBXSLT #include "libxslt.h" #include #include #include "xsltlocale.h" #include "xsltutils.h" #ifdef HAVE_STRXFRM_L #define XSLT_LOCALE_POSIX #ifdef HAVE_LOCALE_H #include #endif #ifdef HAVE_XLOCALE_H #include #endif #elif defined(_WIN32) #define XSLT_LOCALE_WINAPI #include #include #else #define XSLT_LOCALE_NONE #endif #define TOUPPER(c) (c & ~0x20) #define TOLOWER(c) (c | 0x20) #define ISALPHA(c) ((unsigned)(TOUPPER(c) - 'A') < 26) /*without terminating null character*/ #define XSLTMAX_ISO639LANGLEN 8 #define XSLTMAX_ISO3166CNTRYLEN 8 /* - */ #define XSLTMAX_LANGTAGLEN (XSLTMAX_ISO639LANGLEN+1+XSLTMAX_ISO3166CNTRYLEN) static const xmlChar* xsltDefaultRegion(const xmlChar *localeName); #ifdef XSLT_LOCALE_WINAPI xmlRMutexPtr xsltLocaleMutex = NULL; struct xsltRFC1766Info_s { /*note typedef unsigned char xmlChar !*/ xmlChar tag[XSLTMAX_LANGTAGLEN+1]; LCID lcid; }; typedef struct xsltRFC1766Info_s xsltRFC1766Info; static int xsltLocaleListSize = 0; static xsltRFC1766Info *xsltLocaleList = NULL; static void * xslt_locale_WINAPI(const xmlChar *languageTag) { int k; xsltRFC1766Info *p = xsltLocaleList; for (k=0; ktag, languageTag) == 0) return(&p->lcid); return(NULL); } static void xsltEnumSupportedLocales(void); #endif /** * xsltFreeLocales: * * Cleanup function for the locale support on shutdown */ void xsltFreeLocales(void) { #ifdef XSLT_LOCALE_WINAPI xmlRMutexLock(xsltLocaleMutex); xmlFree(xsltLocaleList); xsltLocaleList = NULL; xmlRMutexUnlock(xsltLocaleMutex); #endif } /** * xsltNewLocale: * @languageTag: RFC 3066 language tag * * Creates a new locale of an opaque system dependent type based on the * language tag. * * Returns the locale or NULL on error or if no matching locale was found */ void * xsltNewLocale(const xmlChar *languageTag, int lowerFirst ATTRIBUTE_UNUSED) { #ifdef XSLT_LOCALE_POSIX locale_t locale; char localeName[XSLTMAX_LANGTAGLEN+7]; /* 7 chars for ".UTF-8\0" */ const xmlChar *p = languageTag; const char *region = NULL; char *q = localeName; int i, llen; /* Convert something like "pt-br" to "pt_BR.UTF-8" */ if (languageTag == NULL) return(NULL); for (i=0; i= xstrlen) { xsltTransformError(NULL, NULL, NULL, "xsltStrxfrm : strxfrm failed\n"); xmlFree(xstr); return(NULL); } #endif #ifdef XSLT_LOCALE_WINAPI int wstrlen, xstrlen, r; wchar_t *wstr; LCID *lcid = vlocale; wstrlen = MultiByteToWideChar(CP_UTF8, 0, (char *) string, -1, NULL, 0); if (wstrlen == 0) { xsltTransformError(NULL, NULL, NULL, "xsltStrxfrm : MultiByteToWideChar check failed\n"); return(NULL); } wstr = (wchar_t *) xmlMalloc(wstrlen * sizeof(wchar_t)); if (wstr == NULL) { xsltTransformError(NULL, NULL, NULL, "xsltStrxfrm : out of memory\n"); return(NULL); } r = MultiByteToWideChar(CP_UTF8, 0, (char *) string, -1, wstr, wstrlen); if (r == 0) { xsltTransformError(NULL, NULL, NULL, "xsltStrxfrm : MultiByteToWideChar failed\n"); xmlFree(wstr); return(NULL); } /* This returns the size in bytes. */ xstrlen = LCMapStringW(*lcid, LCMAP_SORTKEY, wstr, wstrlen, NULL, 0); if (xstrlen == 0) { xsltTransformError(NULL, NULL, NULL, "xsltStrxfrm : LCMapStringW failed\n"); xmlFree(wstr); return(NULL); } xstr = (xmlChar*) xmlMalloc(xstrlen); if (xstr == NULL) { xsltTransformError(NULL, NULL, NULL, "xsltStrxfrm : out of memory\n"); xmlFree(wstr); return(NULL); } r = LCMapStringW(*lcid, LCMAP_SORTKEY, wstr, wstrlen, (wchar_t *) xstr, xstrlen); xmlFree(wstr); if (r == 0) { xsltTransformError(NULL, NULL, NULL, "xsltStrxfrm : LCMapStringW failed\n"); xmlFree(xstr); return(NULL); } #endif /* XSLT_LOCALE_WINAPI */ return(xstr); #endif /* XSLT_LOCALE_NONE */ } /** * xsltLocaleStrcmp: * @locale: unused * @str1: a string transformed with xsltStrxfrm * @str2: a string transformed with xsltStrxfrm * * DEPRECATED: Same as xmlStrcmp. * * Compares two strings transformed with xsltStrxfrm. * * Returns a value < 0 if str1 sorts before str2, * a value > 0 if str1 sorts after str2, * 0 if str1 and str2 are equal wrt sorting */ int xsltLocaleStrcmp(void *locale, const xmlChar *str1, const xmlChar *str2) { (void)locale; return(xmlStrcmp(str1, str2)); } #ifdef XSLT_LOCALE_WINAPI /** * xsltCountSupportedLocales: * @lcid: not used * * callback used to count locales * * Returns TRUE */ static BOOL CALLBACK xsltCountSupportedLocales(LPSTR lcid) { (void) lcid; ++xsltLocaleListSize; return(TRUE); } /** * xsltIterateSupportedLocales: * @lcid: not used * * callback used to track locales * * Returns TRUE if not at the end of the array */ static BOOL CALLBACK xsltIterateSupportedLocales(LPSTR lcid) { static int count = 0; xmlChar iso639lang [XSLTMAX_ISO639LANGLEN +1]; xmlChar iso3136ctry[XSLTMAX_ISO3166CNTRYLEN+1]; int k, l; xsltRFC1766Info *p = xsltLocaleList + count; k = sscanf(lcid, "%lx", (unsigned long*)&p->lcid); if (k < 1) goto end; /*don't count terminating null character*/ k = GetLocaleInfoA(p->lcid, LOCALE_SISO639LANGNAME, (char *) iso639lang, sizeof(iso639lang)); if (--k < 1) goto end; l = GetLocaleInfoA(p->lcid, LOCALE_SISO3166CTRYNAME, (char *) iso3136ctry, sizeof(iso3136ctry)); if (--l < 1) goto end; { /*fill results*/ xmlChar *q = p->tag; memcpy(q, iso639lang, k); q += k; *q++ = '-'; memcpy(q, iso3136ctry, l); q += l; *q = '\0'; } ++count; end: return((count < xsltLocaleListSize) ? TRUE : FALSE); } static void xsltEnumSupportedLocales(void) { xmlRMutexLock(xsltLocaleMutex); if (xsltLocaleListSize <= 0) { size_t len; EnumSystemLocalesA(xsltCountSupportedLocales, LCID_SUPPORTED); len = xsltLocaleListSize * sizeof(xsltRFC1766Info); xsltLocaleList = xmlMalloc(len); memset(xsltLocaleList, 0, len); EnumSystemLocalesA(xsltIterateSupportedLocales, LCID_SUPPORTED); } xmlRMutexUnlock(xsltLocaleMutex); } #endif /*def XSLT_LOCALE_WINAPI*/