From eaa68b77386e1c4d4d9d1eb9da299e04e8d5beca Mon Sep 17 00:00:00 2001 From: Nick Wellnhofer Date: Tue, 13 Dec 2022 03:49:54 +0100 Subject: [PATCH] xsltlocale: Make API platform-independent Make xsltlocale.h more private. This really is an internal header. Use LCMapStringW on Windows. Make the API platform-independent by passing locales as `void *`. Add support for custom locale handlers in a transform context. Update ICU example to use these handlers. --- examples/xsltICUSort.c | 406 +++++++++++++--------------------------- libxslt/extensions.c | 1 + libxslt/preproc.c | 10 - libxslt/transform.c | 7 +- libxslt/xsltInternals.h | 14 +- libxslt/xsltlocale.c | 153 +++++++++------ libxslt/xsltlocale.h | 68 ++----- libxslt/xsltutils.c | 80 +++++--- libxslt/xsltutils.h | 5 + python/libxslt_wrap.h | 1 + 10 files changed, 313 insertions(+), 432 deletions(-) diff --git a/examples/xsltICUSort.c b/examples/xsltICUSort.c index af1410ba..76db4510 100644 --- a/examples/xsltICUSort.c +++ b/examples/xsltICUSort.c @@ -1,298 +1,146 @@ /** - * xsltICUSort.c: module provided by Richard Jinks to provide a - * sort function replacement using ICU, it is not - * included in standard due to the size of the ICU + * xsltICUSort.c: module to provide a sort function replacement using ICU, + * it is not included in standard due to the size of the ICU * library * - * See http://mail.gnome.org/archives/xslt/2002-November/msg00093.html - * http://oss.software.ibm.com/icu/index.html - * - * Copyright Richard Jinks + * Requires libxslt 1.1.38 */ -#define IN_LIBXSLT -#include "libxslt.h" - -#include - -#include "xslt.h" -#include "xsltInternals.h" -#include "xsltutils.h" -#include "transform.h" -#include "templates.h" +#include +#include #include -#include -#include -#include #include /** - * xsltICUSortFunction: - * @ctxt: a XSLT process context - * @sorts: array of sort nodes - * @nbsorts: the number of sorts in the array + * xsltICUNewLocale: + * @lang: lang * - * reorder the current node list accordingly to the set of sorting - * requirement provided by the arry of nodes. - * uses the ICU library + * Create a new ICU collator. */ -void -xsltICUSortFunction(xsltTransformContextPtr ctxt, xmlNodePtr *sorts, - int nbsorts) { - xmlXPathObjectPtr *resultsTab[XSLT_MAX_SORT]; - xmlXPathObjectPtr *results = NULL, *res; - xmlNodeSetPtr list = NULL; - int len = 0; - int i, j, incr; - int tst; - int depth; - xmlNodePtr node; - xmlXPathObjectPtr tmp; - const xsltStylePreComp *comp; - int number[XSLT_MAX_SORT], desc[XSLT_MAX_SORT]; +void * +xsltICUNewLocale(const xmlChar *lang, int lowerFirst) { + UCollator *coll; + UErrorCode status = U_ZERO_ERROR; - /* Start ICU change */ - UCollator *coll = 0; - UConverter *conv; - UErrorCode status; - UChar *target,*target2; - int targetlen, target2len; - /* End ICU change */ - - if ((ctxt == NULL) || (sorts == NULL) || (nbsorts <= 0) || - (nbsorts >= XSLT_MAX_SORT)) - return; - if (sorts[0] == NULL) - return; - comp = sorts[0]->_private; - if (comp == NULL) - return; - - list = ctxt->nodeList; - if ((list == NULL) || (list->nodeNr <= 1)) - return; /* nothing to do */ - - for (j = 0; j < nbsorts; j++) { - comp = sorts[j]->_private; - if ((comp->stype == NULL) && (comp->has_stype != 0)) { - xmlChar *stype = - xsltEvalAttrValueTemplate(ctxt, sorts[j], - (const xmlChar *) "data-type", - XSLT_NAMESPACE); - number[j] = 0; - if (stype != NULL) { - if (xmlStrEqual(stype, (const xmlChar *) "text")) - ; - else if (xmlStrEqual(stype, (const xmlChar *) "number")) - number[j] = 1; - else { - xsltTransformError(ctxt, NULL, sorts[j], - "xsltDoSortFunction: no support for data-type = %s\n", - stype); - } - xmlFree(stype); - } - } else { - number[j] = comp->number; - } - if ((comp->order == NULL) && (comp->has_order != 0)) { - xmlChar *order = xsltEvalAttrValueTemplate(ctxt, sorts[j], - BAD_CAST "order", - XSLT_NAMESPACE); - desc[j] = 0; - if (order != NULL) { - if (xmlStrEqual(order, (const xmlChar *) "ascending")) - ; - else if (xmlStrEqual(order, (const xmlChar *) "descending")) - desc[j] = 1; - else { - xsltTransformError(ctxt, NULL, sorts[j], - "xsltDoSortFunction: invalid value %s for order\n", - order); - } - xmlFree(order); - } - } else { - desc[j] = comp->descending; - } - } - - len = list->nodeNr; - - resultsTab[0] = xsltComputeSortResult(ctxt, sorts[0]); - for (i = 1;i < XSLT_MAX_SORT;i++) - resultsTab[i] = NULL; - - results = resultsTab[0]; - - comp = sorts[0]->_private; - if (results == NULL) - return; - - /* Start ICU change */ - status = U_ZERO_ERROR; - conv = ucnv_open("UTF8", &status); - if(U_FAILURE(status)) { - xsltTransformError(ctxt, NULL, NULL, "xsltICUSortFunction: Error opening converter\n"); - } - if(comp->has_lang) - coll = ucol_open((const char *) comp->lang, &status); - if(U_FAILURE(status) || !comp->has_lang) { + coll = ucol_open((const char *) lang, &status); + if (U_FAILURE(status)) { status = U_ZERO_ERROR; coll = ucol_open("en", &status); + if (U_FAILURE(status)) { + return NULL; + } } - if(U_FAILURE(status)) { - xsltTransformError(ctxt, NULL, NULL, "xsltICUSortFunction: Error opening collator\n"); - } - if(comp->lower_first) - ucol_setAttribute(coll,UCOL_CASE_FIRST,UCOL_LOWER_FIRST,&status); + + if (lowerFirst) + ucol_setAttribute(coll, UCOL_CASE_FIRST, UCOL_LOWER_FIRST, &status); else - ucol_setAttribute(coll,UCOL_CASE_FIRST,UCOL_UPPER_FIRST,&status); - if(U_FAILURE(status)) { - xsltTransformError(ctxt, NULL, NULL, "xsltICUSortFunction: Error setting collator attribute\n"); - } - /* End ICU change */ + ucol_setAttribute(coll, UCOL_CASE_FIRST, UCOL_UPPER_FIRST, &status); - /* Shell's sort of node-set */ - for (incr = len / 2; incr > 0; incr /= 2) { - for (i = incr; i < len; i++) { - j = i - incr; - if (results[i] == NULL) - continue; - - while (j >= 0) { - if (results[j] == NULL) - tst = 1; - else { - if (number[0]) { - if (results[j]->floatval == results[j + incr]->floatval) - tst = 0; - else if (results[j]->floatval > - results[j + incr]->floatval) - tst = 1; - else tst = -1; - } else { -/* tst = xmlStrcmp(results[j]->stringval, - results[j + incr]->stringval); */ - /* Start ICU change */ - targetlen = xmlStrlen(results[j]->stringval) * 2; - target2len = xmlStrlen(results[j + incr]->stringval) * 2; - target = xmlMalloc(targetlen * sizeof(UChar)); - target2 = xmlMalloc(target2len * sizeof(UChar)); - targetlen = ucnv_toUChars(conv, target, targetlen, - (const char *) results[j]->stringval, - -1, &status); - target2len = ucnv_toUChars(conv, target2, target2len, - (const char *) results[j+incr]->stringval, - -1, &status); - tst = ucol_strcoll(coll, target, u_strlen(target), target2, u_strlen(target2)); - /* End ICU change */ - } - if (desc[0]) - tst = -tst; - } - if (tst == 0) { - /* - * Okay we need to use multi level sorts - */ - depth = 1; - while (depth < nbsorts) { - if (sorts[depth] == NULL) - break; - comp = sorts[depth]->_private; - if (comp == NULL) - break; - - /* - * Compute the result of the next level for the - * full set, this might be optimized ... or not - */ - if (resultsTab[depth] == NULL) - resultsTab[depth] = xsltComputeSortResult(ctxt, - sorts[depth]); - res = resultsTab[depth]; - if (res == NULL) - break; - if (res[j] == NULL) - tst = 1; - else { - if (number[depth]) { - if (res[j]->floatval == res[j + incr]->floatval) - tst = 0; - else if (res[j]->floatval > - res[j + incr]->floatval) - tst = 1; - else tst = -1; - } else { -/* tst = xmlStrcmp(res[j]->stringval, - res[j + incr]->stringval); */ - /* Start ICU change */ - targetlen = xmlStrlen(res[j]->stringval) * 2; - target2len = xmlStrlen(res[j + incr]->stringval) * 2; - target = xmlMalloc(targetlen * sizeof(UChar)); - target2 = xmlMalloc(target2len * sizeof(UChar)); - targetlen = ucnv_toUChars(conv, target, targetlen, - (const char *) res[j]->stringval, - -1, &status); - target2len = ucnv_toUChars(conv, target2, target2len, - (const char *) res[j+incr]->stringval, - -1, &status); - tst = ucol_strcoll(coll, target, u_strlen(target), target2, u_strlen(target2)); - /* End ICU change */ - } - if (desc[depth]) - tst = -tst; - } - /* - * if we still can't differenciate at this level - * try one level deeper. - */ - if (tst != 0) - break; - depth++; - } - } - if (tst == 0) { - tst = results[j]->index > results[j + incr]->index; - } - if (tst > 0) { - tmp = results[j]; - results[j] = results[j + incr]; - results[j + incr] = tmp; - node = list->nodeTab[j]; - list->nodeTab[j] = list->nodeTab[j + incr]; - list->nodeTab[j + incr] = node; - depth = 1; - while (depth < nbsorts) { - if (sorts[depth] == NULL) - break; - if (resultsTab[depth] == NULL) - break; - res = resultsTab[depth]; - tmp = res[j]; - res[j] = res[j + incr]; - res[j + incr] = tmp; - depth++; - } - j -= incr; - } else - break; - } - } - } - - /* Start ICU change */ - ucol_close(coll); - ucnv_close(conv); - /* End ICU change */ - - for (j = 0; j < nbsorts; j++) { - comp = sorts[j]->_private; - if (resultsTab[j] != NULL) { - for (i = 0;i < len;i++) - xmlXPathFreeObject(resultsTab[j][i]); - xmlFree(resultsTab[j]); - } - } + return (void *) coll; } +/** + * xsltICUNewLocale: + * @locale: ICU collator + * + * Free the ICU collator. + */ +void +xsltICUFreeLocale(void *coll) { + ucol_close((UCollator *) coll); +} + +/** + * xsltICUGenSortKey: + * @locale: ICU collator + * @str: source string + * + * Generate a localized sort key. + */ +xmlChar * +xsltICUGenSortKey(void *coll, const xmlChar *str) { + UConverter *conv; + UChar *ustr = NULL; + xmlChar *result = NULL; + UErrorCode status = U_ZERO_ERROR; + int32_t ustrLen, resultLen; + + conv = ucnv_open("UTF8", &status); + if (U_FAILURE(status)) + goto error; + + ustrLen = ucnv_toUChars(conv, NULL, 0, (const char *) str, -1, &status); + if (U_FAILURE(status) && status != U_BUFFER_OVERFLOW_ERROR) + goto error; + status = U_ZERO_ERROR; + ustr = (UChar *) xmlMalloc((ustrLen + 1) * sizeof(UChar)); + if (ustr == NULL) + goto error; + ustrLen = ucnv_toUChars(conv, ustr, ustrLen, (const char *) str, -1, + &status); + if (U_FAILURE(status)) + goto error; + + resultLen = ucol_getSortKey((UCollator *) coll, ustr, ustrLen, NULL, 0); + if (resultLen == 0) + goto error; + result = (xmlChar *) xmlMalloc(resultLen); + if (result == NULL) + goto error; + resultLen = ucol_getSortKey((UCollator *) coll, ustr, ustrLen, result, + resultLen); + if (resultLen == 0) { + xmlFree(result); + result = NULL; + goto error; + } + +error: + xmlFree(ustr); + return result; +} + +int main(void) { + xmlDocPtr sourceDoc = xmlReadDoc( + BAD_CAST + "\n" + " Berta\n" + " Ärger\n" + "\n", + NULL, NULL, 0 + ); + xmlDocPtr styleDoc = xmlReadDoc( + BAD_CAST + "\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "\n", + NULL, NULL, 0 + ); + xsltStylesheetPtr style = xsltParseStylesheetDoc(styleDoc); + if (style == NULL) + xmlFreeDoc(styleDoc); + + xsltTransformContextPtr tctxt = xsltNewTransformContext(style, sourceDoc); + xsltSetCtxtLocaleHandlers(tctxt, xsltICUNewLocale, xsltICUFreeLocale, + xsltICUGenSortKey); + + xmlDocPtr resultDoc = xsltApplyStylesheetUser(style, sourceDoc, NULL, NULL, + NULL, tctxt); + + xsltFreeTransformContext(tctxt); + + xsltSaveResultToFile(stdout, resultDoc, style); + + xmlFreeDoc(resultDoc); + xsltFreeStylesheet(style); + xmlFreeDoc(sourceDoc); + + return 0; +} diff --git a/libxslt/extensions.c b/libxslt/extensions.c index ea5e8353..8535bf53 100644 --- a/libxslt/extensions.c +++ b/libxslt/extensions.c @@ -28,6 +28,7 @@ #include #include "xslt.h" #include "xsltInternals.h" +#include "xsltlocale.h" #include "xsltutils.h" #include "imports.h" #include "extensions.h" diff --git a/libxslt/preproc.c b/libxslt/preproc.c index 7d2fa221..fae69a09 100644 --- a/libxslt/preproc.c +++ b/libxslt/preproc.c @@ -392,8 +392,6 @@ xsltFreeStylePreComp(xsltStylePreCompPtr comp) { break; case XSLT_FUNC_SORT: { xsltStyleItemSortPtr item = (xsltStyleItemSortPtr) comp; - if (item->locale != (xsltLocale)0) - xsltFreeLocale(item->locale); if (item->comp != NULL) xmlXPathFreeCompExpr(item->comp); } @@ -496,8 +494,6 @@ xsltFreeStylePreComp(xsltStylePreCompPtr comp) { break; } #else - if (comp->locale != (xsltLocale)0) - xsltFreeLocale(comp->locale); if (comp->comp != NULL) xmlXPathFreeCompExpr(comp->comp); if (comp->numdata.countPat != NULL) @@ -743,12 +739,6 @@ xsltSortComp(xsltStylesheetPtr style, xmlNodePtr inst) { comp->lang = xsltEvalStaticAttrValueTemplate(style, inst, (const xmlChar *)"lang", NULL, &comp->has_lang); - if (comp->lang != NULL) { - comp->locale = xsltNewLocale(comp->lang); - } - else { - comp->locale = (xsltLocale)0; - } comp->select = xsltGetCNsProp(style, inst,(const xmlChar *)"select", XSLT_NAMESPACE); if (comp->select == NULL) { diff --git a/libxslt/transform.c b/libxslt/transform.c index 67d041af..f565e85d 100644 --- a/libxslt/transform.c +++ b/libxslt/transform.c @@ -40,6 +40,7 @@ #include "xslt.h" #include "xsltInternals.h" #include "xsltutils.h" +#include "xsltlocale.h" #include "pattern.h" #include "transform.h" #include "variables.h" @@ -706,6 +707,10 @@ xsltNewTransformContext(xsltStylesheetPtr style, xmlDocPtr doc) { cur->xinclude = xsltGetXIncludeDefault(); cur->keyInitLevel = 0; + cur->newLocale = xsltNewLocale; + cur->freeLocale = xsltFreeLocale; + cur->genSortKey = xsltStrxfrm; + return(cur); internal_err: @@ -716,7 +721,7 @@ internal_err: /** * xsltFreeTransformContext: - * @ctxt: an XSLT parser context + * @ctxt: an XSLT transform context * * Free up the memory allocated by @ctxt */ diff --git a/libxslt/xsltInternals.h b/libxslt/xsltInternals.h index 2fd1f681..be7f43d8 100644 --- a/libxslt/xsltInternals.h +++ b/libxslt/xsltInternals.h @@ -21,7 +21,6 @@ #include #include #include "xsltexports.h" -#include "xsltlocale.h" #include "numbersInternals.h" #ifdef __cplusplus @@ -1047,7 +1046,6 @@ struct _xsltStyleItemSort { int descending; /* sort */ const xmlChar *lang; /* sort */ int has_lang; /* sort */ - xsltLocale locale; /* sort */ const xmlChar *case_order; /* sort */ int lower_first; /* sort */ @@ -1377,7 +1375,6 @@ struct _xsltStylePreComp { int descending; /* sort */ const xmlChar *lang; /* sort */ int has_lang; /* sort */ - xsltLocale locale; /* sort */ const xmlChar *case_order; /* sort */ int lower_first; /* sort */ @@ -1663,6 +1660,13 @@ typedef enum { XSLT_OUTPUT_TEXT } xsltOutputType; +typedef void * +(*xsltNewLocaleFunc)(const xmlChar *lang, int lowerFirst); +typedef void +(*xsltFreeLocaleFunc)(void *locale); +typedef xmlChar * +(*xsltGenSortKeFunc)(void *locale, const xmlChar *lang); + typedef enum { XSLT_STATE_OK = 0, XSLT_STATE_ERROR, @@ -1788,6 +1792,10 @@ struct _xsltTransformContext { unsigned long opCount; int sourceDocDirty; unsigned long currentId; /* For generate-id() */ + + xsltNewLocaleFunc newLocale; + xsltFreeLocaleFunc freeLocale; + xsltGenSortKeFunc genSortKey; }; /** diff --git a/libxslt/xsltlocale.c b/libxslt/xsltlocale.c index 76740987..2b757fd7 100644 --- a/libxslt/xsltlocale.c +++ b/libxslt/xsltlocale.c @@ -19,6 +19,30 @@ #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) @@ -37,8 +61,7 @@ xmlRMutexPtr xsltLocaleMutex = NULL; struct xsltRFC1766Info_s { /*note typedef unsigned char xmlChar !*/ xmlChar tag[XSLTMAX_LANGTAGLEN+1]; - /*note typedef LCID xsltLocale !*/ - xsltLocale lcid; + LCID lcid; }; typedef struct xsltRFC1766Info_s xsltRFC1766Info; @@ -46,14 +69,15 @@ static int xsltLocaleListSize = 0; static xsltRFC1766Info *xsltLocaleList = NULL; -static xsltLocale +static void * xslt_locale_WINAPI(const xmlChar *languageTag) { int k; xsltRFC1766Info *p = xsltLocaleList; for (k=0; ktag, languageTag) == 0) return p->lcid; - return((xsltLocale)0); + if (xmlStrcmp(p->tag, languageTag) == 0) + return(&p->lcid); + return(NULL); } static void xsltEnumSupportedLocales(void); @@ -83,10 +107,10 @@ xsltFreeLocales(void) { * * Returns the locale or NULL on error or if no matching locale was found */ -xsltLocale -xsltNewLocale(const xmlChar *languageTag) { +void * +xsltNewLocale(const xmlChar *languageTag, int lowerFirst ATTRIBUTE_UNUSED) { #ifdef XSLT_LOCALE_POSIX - xsltLocale locale; + locale_t locale; char localeName[XSLTMAX_LANGTAGLEN+6]; /* 6 chars for ".utf8\0" */ const xmlChar *p = languageTag; const char *region = NULL; @@ -155,7 +179,7 @@ xsltNewLocale(const xmlChar *languageTag) { #ifdef XSLT_LOCALE_WINAPI { - xsltLocale locale = (xsltLocale)0; + void *locale = NULL; xmlChar localeName[XSLTMAX_LANGTAGLEN+1]; xmlChar *q = localeName; const xmlChar *p = languageTag; @@ -344,7 +368,7 @@ xsltDefaultRegion(const xmlChar *localeName) { * Frees a locale created with xsltNewLocale */ void -xsltFreeLocale(xsltLocale locale) { +xsltFreeLocale(void *locale) { #ifdef XSLT_LOCALE_POSIX if (locale != NULL) freelocale(locale); @@ -358,58 +382,82 @@ xsltFreeLocale(xsltLocale locale) { * @locale: locale created with xsltNewLocale * @string: UTF-8 string to transform * - * Transforms a string according to locale. The transformed string must then be - * compared with xsltLocaleStrcmp and freed with xmlFree. + * Transforms a string according to locale. The transformed string must be + * freed with xmlFree. * * Returns the transformed string or NULL on error */ -xsltLocaleChar * -xsltStrxfrm(xsltLocale locale, const xmlChar *string) +xmlChar * +xsltStrxfrm(void *vlocale, const xmlChar *string) { #ifdef XSLT_LOCALE_NONE return(NULL); #else - size_t xstrlen, r; - xsltLocaleChar *xstr; + xmlChar *xstr; #ifdef XSLT_LOCALE_POSIX - xstrlen = strxfrm_l(NULL, (const char *)string, 0, locale) + 1; - xstr = (xsltLocaleChar *) xmlMalloc(xstrlen); + size_t xstrlen, r; + + xstrlen = strxfrm_l(NULL, (const char *)string, 0, vlocale) + 1; + xstr = (xmlChar *) xmlMalloc(xstrlen); if (xstr == NULL) { xsltTransformError(NULL, NULL, NULL, "xsltStrxfrm : out of memory error\n"); return(NULL); } - r = strxfrm_l((char *)xstr, (const char *)string, xstrlen, locale); -#endif - -#ifdef XSLT_LOCALE_WINAPI - (void) locale; - xstrlen = MultiByteToWideChar(CP_UTF8, 0, (char *) string, -1, NULL, 0); - if (xstrlen == 0) { - xsltTransformError(NULL, NULL, NULL, "xsltStrxfrm : MultiByteToWideChar check failed\n"); - return(NULL); - } - xstr = (xsltLocaleChar*) xmlMalloc(xstrlen * sizeof(xsltLocaleChar)); - if (xstr == NULL) { - xsltTransformError(NULL, NULL, NULL, "xsltStrxfrm : out of memory\n"); - return(NULL); - } - r = MultiByteToWideChar(CP_UTF8, 0, (char *) string, -1, xstr, xstrlen); - if (r == 0) { - xsltTransformError(NULL, NULL, NULL, "xsltStrxfrm : MultiByteToWideChar failed\n"); - xmlFree(xstr); - return(NULL); - } - return(xstr); -#endif /* XSLT_LOCALE_WINAPI */ + r = strxfrm_l((char *)xstr, (const char *)string, xstrlen, vlocale); if (r >= 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 */ @@ -417,35 +465,22 @@ xsltStrxfrm(xsltLocale locale, const xmlChar *string) /** * xsltLocaleStrcmp: - * @locale: a locale identifier + * @locale: unused * @str1: a string transformed with xsltStrxfrm * @str2: a string transformed with xsltStrxfrm * - * Compares two strings 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(xsltLocale locale, const xsltLocaleChar *str1, const xsltLocaleChar *str2) { +xsltLocaleStrcmp(void *locale, const xmlChar *str1, const xmlChar *str2) { (void)locale; -#ifdef XSLT_LOCALE_WINAPI -{ - int ret; - if (str1 == str2) return(0); - if (str1 == NULL) return(-1); - if (str2 == NULL) return(1); - ret = CompareStringW(locale, 0, str1, -1, str2, -1); - if (ret == 0) { - xsltTransformError(NULL, NULL, NULL, "xsltLocaleStrcmp : CompareStringW fail\n"); - return(0); - } - return(ret - 2); -} -#else return(xmlStrcmp(str1, str2)); -#endif } #ifdef XSLT_LOCALE_WINAPI diff --git a/libxslt/xsltlocale.h b/libxslt/xsltlocale.h index dc503895..10a4402f 100644 --- a/libxslt/xsltlocale.h +++ b/libxslt/xsltlocale.h @@ -14,63 +14,23 @@ #include #include "xsltexports.h" -#ifdef HAVE_STRXFRM_L - -/* - * XSLT_LOCALE_POSIX: - * Macro indicating to use POSIX locale extensions - */ -#define XSLT_LOCALE_POSIX - -#ifdef HAVE_LOCALE_H -#include -#endif -#ifdef HAVE_XLOCALE_H -#include -#endif - -typedef locale_t xsltLocale; -typedef xmlChar xsltLocaleChar; - -#elif defined(_WIN32) - -/* - * XSLT_LOCALE_WINAPI: - * Macro indicating to use WinAPI for extended locale support - */ -#define XSLT_LOCALE_WINAPI - -#include -#include - -typedef LCID xsltLocale; -typedef wchar_t xsltLocaleChar; - -#else - -/* - * XSLT_LOCALE_NONE: - * Macro indicating that there's no extended locale support - */ -#define XSLT_LOCALE_NONE - -typedef void *xsltLocale; -typedef xmlChar xsltLocaleChar; - -#endif - -XSLTPUBFUN xsltLocale XSLTCALL - xsltNewLocale (const xmlChar *langName); +XSLTPUBFUN void * XSLTCALL + xsltNewLocale (const xmlChar *langName, + int lowerFirst); XSLTPUBFUN void XSLTCALL - xsltFreeLocale (xsltLocale locale); -XSLTPUBFUN xsltLocaleChar * XSLTCALL - xsltStrxfrm (xsltLocale locale, + xsltFreeLocale (void *locale); +XSLTPUBFUN xmlChar * XSLTCALL + xsltStrxfrm (void *locale, const xmlChar *string); -XSLTPUBFUN int XSLTCALL - xsltLocaleStrcmp (xsltLocale locale, - const xsltLocaleChar *str1, - const xsltLocaleChar *str2); XSLTPUBFUN void XSLTCALL xsltFreeLocales (void); +/* Backward compatibility */ +typedef void *xsltLocale; +typedef xmlChar xsltLocaleChar; +XSLTPUBFUN int XSLTCALL + xsltLocaleStrcmp (void *locale, + const xmlChar *str1, + const xmlChar *str2); + #endif /* __XML_XSLTLOCALE_H__ */ diff --git a/libxslt/xsltutils.c b/libxslt/xsltutils.c index 390b9580..838ef4db 100644 --- a/libxslt/xsltutils.c +++ b/libxslt/xsltutils.c @@ -42,6 +42,7 @@ #include "transform.h" #if defined(_WIN32) +#include #define XSLT_WIN32_PERFORMANCE_COUNTER #endif @@ -960,7 +961,7 @@ xsltDocumentSortFunction(xmlNodeSetPtr list) { */ static xmlXPathObjectPtr * xsltComputeSortResultInternal(xsltTransformContextPtr ctxt, xmlNodePtr sort, - int number, xsltLocale locale) { + int number, void *locale) { #ifdef XSLT_REFACTORED xsltStyleItemSortPtr comp; #else @@ -1047,10 +1048,17 @@ xsltComputeSortResultInternal(xsltTransformContextPtr ctxt, xmlNodePtr sort, } } else { if (res->type == XPATH_STRING) { - if (locale != (xsltLocale)0) { + if (locale != NULL) { xmlChar *str = res->stringval; - res->stringval = (xmlChar *) xsltStrxfrm(locale, str); - xmlFree(str); + xmlChar *sortKey = ctxt->genSortKey(locale, str); + + if (sortKey == NULL) { + xsltTransformError(ctxt, NULL, sort, + "xsltComputeSortResult: sort key is null\n"); + } else { + res->stringval = sortKey; + xmlFree(str); + } } results[i] = res; @@ -1094,7 +1102,8 @@ xsltComputeSortResult(xsltTransformContextPtr ctxt, xmlNodePtr sort) { if (comp != NULL) number = comp->number; - return xsltComputeSortResultInternal(ctxt, sort, number, /* locale */ 0); + return xsltComputeSortResultInternal(ctxt, sort, number, + /* locale */ NULL); } /** @@ -1124,7 +1133,7 @@ xsltDefaultSortFunction(xsltTransformContextPtr ctxt, xmlNodePtr *sorts, xmlNodePtr node; xmlXPathObjectPtr tmp; int number[XSLT_MAX_SORT], desc[XSLT_MAX_SORT]; - xsltLocale locale[XSLT_MAX_SORT]; + void *locale[XSLT_MAX_SORT]; if ((ctxt == NULL) || (sorts == NULL) || (nbsorts <= 0) || (nbsorts >= XSLT_MAX_SORT)) @@ -1140,6 +1149,8 @@ xsltDefaultSortFunction(xsltTransformContextPtr ctxt, xmlNodePtr *sorts, return; /* nothing to do */ for (j = 0; j < nbsorts; j++) { + xmlChar *lang; + comp = sorts[j]->psvi; if ((comp->stype == NULL) && (comp->has_stype != 0)) { xmlChar *stype = @@ -1181,17 +1192,18 @@ xsltDefaultSortFunction(xsltTransformContextPtr ctxt, xmlNodePtr *sorts, desc[j] = comp->descending; } if ((comp->lang == NULL) && (comp->has_lang != 0)) { - xmlChar *lang = xsltEvalAttrValueTemplate(ctxt, sorts[j], + lang = xsltEvalAttrValueTemplate(ctxt, sorts[j], (xmlChar *) "lang", NULL); - if (lang != NULL) { - locale[j] = xsltNewLocale(lang); - xmlFree(lang); - } else { - locale[j] = 0; - } } else { - locale[j] = comp->locale; + lang = (xmlChar *) comp->lang; + } + if (lang != NULL) { + locale[j] = ctxt->newLocale(lang, comp->lower_first); + if (lang != comp->lang) + xmlFree(lang); + } else { + locale[j] = NULL; } } @@ -1236,11 +1248,6 @@ xsltDefaultSortFunction(xsltTransformContextPtr ctxt, xmlNodePtr *sorts, results[j + incr]->floatval) tst = 1; else tst = -1; - } else if(locale[0] != (xsltLocale)0) { - tst = xsltLocaleStrcmp( - locale[0], - (xsltLocaleChar *) results[j]->stringval, - (xsltLocaleChar *) results[j + incr]->stringval); } else { tst = xmlStrcmp(results[j]->stringval, results[j + incr]->stringval); @@ -1298,11 +1305,6 @@ xsltDefaultSortFunction(xsltTransformContextPtr ctxt, xmlNodePtr *sorts, res[j + incr]->floatval) tst = 1; else tst = -1; - } else if(locale[depth] != (xsltLocale)0) { - tst = xsltLocaleStrcmp( - locale[depth], - (xsltLocaleChar *) res[j]->stringval, - (xsltLocaleChar *) res[j + incr]->stringval); } else { tst = xmlStrcmp(res[j]->stringval, res[j + incr]->stringval); @@ -1353,8 +1355,8 @@ cleanup: for (j = 0; j < nbsorts; j++) { comp = sorts[j]->psvi; if ((comp->lang == NULL) && (comp->has_lang != 0)) { - if (locale[j] != (xsltLocale)0) { - xsltFreeLocale(locale[j]); + if (locale[j] != NULL) { + ctxt->freeLocale(locale[j]); } } if (resultsTab[j] != NULL) { @@ -1396,6 +1398,8 @@ xsltDoSortFunction(xsltTransformContextPtr ctxt, xmlNodePtr * sorts, * xsltSetSortFunc: * @handler: the new handler function * + * DEPRECATED: Use xsltSetCtxtLocaleHandlers. + * * Function to reset the global handler for XSLT sorting. * If the handler is NULL, the default sort function will be used. */ @@ -1412,6 +1416,8 @@ xsltSetSortFunc(xsltSortFunc handler) { * @ctxt: a XSLT process context * @handler: the new handler function * + * DEPRECATED: Use xsltSetCtxtLocaleHandlers. + * * Function to set the handler for XSLT sorting * for the specified context. * If the handler is NULL, then the global @@ -1422,6 +1428,28 @@ xsltSetCtxtSortFunc(xsltTransformContextPtr ctxt, xsltSortFunc handler) { ctxt->sortfunc = handler; } +/** + * xsltSetCtxtLocaleHandlers: + * @ctxt: an XSLT transform context + * @newLocale: locale constructor + * @freeLocale: locale destructor + * @genSortKey sort key generator + * + * Set the locale handlers. + */ +void +xsltSetCtxtLocaleHandlers(xsltTransformContextPtr ctxt, + xsltNewLocaleFunc newLocale, + xsltFreeLocaleFunc freeLocale, + xsltGenSortKeFunc genSortKey) { + if (ctxt == NULL) + return; + + ctxt->newLocale = newLocale; + ctxt->freeLocale = freeLocale; + ctxt->genSortKey = genSortKey; +} + /************************************************************************ * * * Parsing options * diff --git a/libxslt/xsltutils.h b/libxslt/xsltutils.h index 484032e7..9020f372 100644 --- a/libxslt/xsltutils.h +++ b/libxslt/xsltutils.h @@ -178,6 +178,11 @@ XSLTPUBFUN void XSLTCALL XSLTPUBFUN void XSLTCALL xsltSetCtxtSortFunc (xsltTransformContextPtr ctxt, xsltSortFunc handler); +XSLTPUBFUN void XSLTCALL + xsltSetCtxtLocaleHandlers (xsltTransformContextPtr ctxt, + xsltNewLocaleFunc newLocale, + xsltFreeLocaleFunc freeLocale, + xsltGenSortKeFunc genSortKey); XSLTPUBFUN void XSLTCALL xsltDefaultSortFunction (xsltTransformContextPtr ctxt, xmlNodePtr *sorts, diff --git a/python/libxslt_wrap.h b/python/libxslt_wrap.h index d1c79077..04b6c3c3 100644 --- a/python/libxslt_wrap.h +++ b/python/libxslt_wrap.h @@ -1,6 +1,7 @@ #include "libxml_wrap.h" #include #include +#include #include #include #include