1
0
mirror of https://gitlab.gnome.org/GNOME/libxslt synced 2025-07-31 02:43:06 +03:00

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.
This commit is contained in:
Nick Wellnhofer
2022-12-13 03:49:54 +01:00
parent ba939de9b9
commit eaa68b7738
10 changed files with 313 additions and 432 deletions

View File

@ -1,298 +1,146 @@
/** /**
* xsltICUSort.c: module provided by Richard Jinks to provide a * xsltICUSort.c: module to provide a sort function replacement using ICU,
* sort function replacement using ICU, it is not * it is not included in standard due to the size of the ICU
* included in standard due to the size of the ICU
* library * library
* *
* See http://mail.gnome.org/archives/xslt/2002-November/msg00093.html * Requires libxslt 1.1.38
* http://oss.software.ibm.com/icu/index.html
*
* Copyright Richard Jinks
*/ */
#define IN_LIBXSLT
#include "libxslt.h"
#include <libxml/parserInternals.h>
#include "xslt.h"
#include "xsltInternals.h"
#include "xsltutils.h"
#include "transform.h"
#include "templates.h"
#include <libxslt/transform.h>
#include <libxslt/xsltutils.h>
#include <unicode/ucnv.h> #include <unicode/ucnv.h>
#include <unicode/ustring.h>
#include <unicode/utypes.h>
#include <unicode/uloc.h>
#include <unicode/ucol.h> #include <unicode/ucol.h>
/** /**
* xsltICUSortFunction: * xsltICUNewLocale:
* @ctxt: a XSLT process context * @lang: lang
* @sorts: array of sort nodes
* @nbsorts: the number of sorts in the array
* *
* reorder the current node list accordingly to the set of sorting * Create a new ICU collator.
* requirement provided by the arry of nodes.
* uses the ICU library
*/ */
void void *
xsltICUSortFunction(xsltTransformContextPtr ctxt, xmlNodePtr *sorts, xsltICUNewLocale(const xmlChar *lang, int lowerFirst) {
int nbsorts) { UCollator *coll;
xmlXPathObjectPtr *resultsTab[XSLT_MAX_SORT]; UErrorCode status = U_ZERO_ERROR;
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];
/* Start ICU change */ coll = ucol_open((const char *) lang, &status);
UCollator *coll = 0; if (U_FAILURE(status)) {
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) {
status = U_ZERO_ERROR; status = U_ZERO_ERROR;
coll = ucol_open("en", &status); 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 (lowerFirst)
} ucol_setAttribute(coll, UCOL_CASE_FIRST, UCOL_LOWER_FIRST, &status);
if(comp->lower_first)
ucol_setAttribute(coll,UCOL_CASE_FIRST,UCOL_LOWER_FIRST,&status);
else else
ucol_setAttribute(coll,UCOL_CASE_FIRST,UCOL_UPPER_FIRST,&status); 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 */
/* Shell's sort of node-set */ return (void *) coll;
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]);
}
}
} }
/**
* 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
"<d>\n"
" <e>Berta</e>\n"
" <e>Ärger</e>\n"
"</d>\n",
NULL, NULL, 0
);
xmlDocPtr styleDoc = xmlReadDoc(
BAD_CAST
"<xsl:stylesheet"
" version='1.0'"
" xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>\n"
" <xsl:template match='d'>\n"
" <xsl:for-each select='*'>\n"
" <xsl:sort lang='de'/>\n"
" <xsl:copy-of select='.'/>\n"
" </xsl:for-each>\n"
" </xsl:template>\n"
"</xsl:stylesheet>\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;
}

View File

@ -28,6 +28,7 @@
#include <libxml/xmlIO.h> #include <libxml/xmlIO.h>
#include "xslt.h" #include "xslt.h"
#include "xsltInternals.h" #include "xsltInternals.h"
#include "xsltlocale.h"
#include "xsltutils.h" #include "xsltutils.h"
#include "imports.h" #include "imports.h"
#include "extensions.h" #include "extensions.h"

View File

@ -392,8 +392,6 @@ xsltFreeStylePreComp(xsltStylePreCompPtr comp) {
break; break;
case XSLT_FUNC_SORT: { case XSLT_FUNC_SORT: {
xsltStyleItemSortPtr item = (xsltStyleItemSortPtr) comp; xsltStyleItemSortPtr item = (xsltStyleItemSortPtr) comp;
if (item->locale != (xsltLocale)0)
xsltFreeLocale(item->locale);
if (item->comp != NULL) if (item->comp != NULL)
xmlXPathFreeCompExpr(item->comp); xmlXPathFreeCompExpr(item->comp);
} }
@ -496,8 +494,6 @@ xsltFreeStylePreComp(xsltStylePreCompPtr comp) {
break; break;
} }
#else #else
if (comp->locale != (xsltLocale)0)
xsltFreeLocale(comp->locale);
if (comp->comp != NULL) if (comp->comp != NULL)
xmlXPathFreeCompExpr(comp->comp); xmlXPathFreeCompExpr(comp->comp);
if (comp->numdata.countPat != NULL) if (comp->numdata.countPat != NULL)
@ -743,12 +739,6 @@ xsltSortComp(xsltStylesheetPtr style, xmlNodePtr inst) {
comp->lang = xsltEvalStaticAttrValueTemplate(style, inst, comp->lang = xsltEvalStaticAttrValueTemplate(style, inst,
(const xmlChar *)"lang", (const xmlChar *)"lang",
NULL, &comp->has_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); comp->select = xsltGetCNsProp(style, inst,(const xmlChar *)"select", XSLT_NAMESPACE);
if (comp->select == NULL) { if (comp->select == NULL) {

View File

@ -40,6 +40,7 @@
#include "xslt.h" #include "xslt.h"
#include "xsltInternals.h" #include "xsltInternals.h"
#include "xsltutils.h" #include "xsltutils.h"
#include "xsltlocale.h"
#include "pattern.h" #include "pattern.h"
#include "transform.h" #include "transform.h"
#include "variables.h" #include "variables.h"
@ -706,6 +707,10 @@ xsltNewTransformContext(xsltStylesheetPtr style, xmlDocPtr doc) {
cur->xinclude = xsltGetXIncludeDefault(); cur->xinclude = xsltGetXIncludeDefault();
cur->keyInitLevel = 0; cur->keyInitLevel = 0;
cur->newLocale = xsltNewLocale;
cur->freeLocale = xsltFreeLocale;
cur->genSortKey = xsltStrxfrm;
return(cur); return(cur);
internal_err: internal_err:
@ -716,7 +721,7 @@ internal_err:
/** /**
* xsltFreeTransformContext: * xsltFreeTransformContext:
* @ctxt: an XSLT parser context * @ctxt: an XSLT transform context
* *
* Free up the memory allocated by @ctxt * Free up the memory allocated by @ctxt
*/ */

View File

@ -21,7 +21,6 @@
#include <libxml/xmlstring.h> #include <libxml/xmlstring.h>
#include <libxslt/xslt.h> #include <libxslt/xslt.h>
#include "xsltexports.h" #include "xsltexports.h"
#include "xsltlocale.h"
#include "numbersInternals.h" #include "numbersInternals.h"
#ifdef __cplusplus #ifdef __cplusplus
@ -1047,7 +1046,6 @@ struct _xsltStyleItemSort {
int descending; /* sort */ int descending; /* sort */
const xmlChar *lang; /* sort */ const xmlChar *lang; /* sort */
int has_lang; /* sort */ int has_lang; /* sort */
xsltLocale locale; /* sort */
const xmlChar *case_order; /* sort */ const xmlChar *case_order; /* sort */
int lower_first; /* sort */ int lower_first; /* sort */
@ -1377,7 +1375,6 @@ struct _xsltStylePreComp {
int descending; /* sort */ int descending; /* sort */
const xmlChar *lang; /* sort */ const xmlChar *lang; /* sort */
int has_lang; /* sort */ int has_lang; /* sort */
xsltLocale locale; /* sort */
const xmlChar *case_order; /* sort */ const xmlChar *case_order; /* sort */
int lower_first; /* sort */ int lower_first; /* sort */
@ -1663,6 +1660,13 @@ typedef enum {
XSLT_OUTPUT_TEXT XSLT_OUTPUT_TEXT
} xsltOutputType; } xsltOutputType;
typedef void *
(*xsltNewLocaleFunc)(const xmlChar *lang, int lowerFirst);
typedef void
(*xsltFreeLocaleFunc)(void *locale);
typedef xmlChar *
(*xsltGenSortKeFunc)(void *locale, const xmlChar *lang);
typedef enum { typedef enum {
XSLT_STATE_OK = 0, XSLT_STATE_OK = 0,
XSLT_STATE_ERROR, XSLT_STATE_ERROR,
@ -1788,6 +1792,10 @@ struct _xsltTransformContext {
unsigned long opCount; unsigned long opCount;
int sourceDocDirty; int sourceDocDirty;
unsigned long currentId; /* For generate-id() */ unsigned long currentId; /* For generate-id() */
xsltNewLocaleFunc newLocale;
xsltFreeLocaleFunc freeLocale;
xsltGenSortKeFunc genSortKey;
}; };
/** /**

View File

@ -19,6 +19,30 @@
#include "xsltlocale.h" #include "xsltlocale.h"
#include "xsltutils.h" #include "xsltutils.h"
#ifdef HAVE_STRXFRM_L
#define XSLT_LOCALE_POSIX
#ifdef HAVE_LOCALE_H
#include <locale.h>
#endif
#ifdef HAVE_XLOCALE_H
#include <xlocale.h>
#endif
#elif defined(_WIN32)
#define XSLT_LOCALE_WINAPI
#include <windows.h>
#include <winnls.h>
#else
#define XSLT_LOCALE_NONE
#endif
#define TOUPPER(c) (c & ~0x20) #define TOUPPER(c) (c & ~0x20)
#define TOLOWER(c) (c | 0x20) #define TOLOWER(c) (c | 0x20)
#define ISALPHA(c) ((unsigned)(TOUPPER(c) - 'A') < 26) #define ISALPHA(c) ((unsigned)(TOUPPER(c) - 'A') < 26)
@ -37,8 +61,7 @@ xmlRMutexPtr xsltLocaleMutex = NULL;
struct xsltRFC1766Info_s { struct xsltRFC1766Info_s {
/*note typedef unsigned char xmlChar !*/ /*note typedef unsigned char xmlChar !*/
xmlChar tag[XSLTMAX_LANGTAGLEN+1]; xmlChar tag[XSLTMAX_LANGTAGLEN+1];
/*note typedef LCID xsltLocale !*/ LCID lcid;
xsltLocale lcid;
}; };
typedef struct xsltRFC1766Info_s xsltRFC1766Info; typedef struct xsltRFC1766Info_s xsltRFC1766Info;
@ -46,14 +69,15 @@ static int xsltLocaleListSize = 0;
static xsltRFC1766Info *xsltLocaleList = NULL; static xsltRFC1766Info *xsltLocaleList = NULL;
static xsltLocale static void *
xslt_locale_WINAPI(const xmlChar *languageTag) { xslt_locale_WINAPI(const xmlChar *languageTag) {
int k; int k;
xsltRFC1766Info *p = xsltLocaleList; xsltRFC1766Info *p = xsltLocaleList;
for (k=0; k<xsltLocaleListSize; k++, p++) for (k=0; k<xsltLocaleListSize; k++, p++)
if (xmlStrcmp(p->tag, languageTag) == 0) return p->lcid; if (xmlStrcmp(p->tag, languageTag) == 0)
return((xsltLocale)0); return(&p->lcid);
return(NULL);
} }
static void xsltEnumSupportedLocales(void); static void xsltEnumSupportedLocales(void);
@ -83,10 +107,10 @@ xsltFreeLocales(void) {
* *
* Returns the locale or NULL on error or if no matching locale was found * Returns the locale or NULL on error or if no matching locale was found
*/ */
xsltLocale void *
xsltNewLocale(const xmlChar *languageTag) { xsltNewLocale(const xmlChar *languageTag, int lowerFirst ATTRIBUTE_UNUSED) {
#ifdef XSLT_LOCALE_POSIX #ifdef XSLT_LOCALE_POSIX
xsltLocale locale; locale_t locale;
char localeName[XSLTMAX_LANGTAGLEN+6]; /* 6 chars for ".utf8\0" */ char localeName[XSLTMAX_LANGTAGLEN+6]; /* 6 chars for ".utf8\0" */
const xmlChar *p = languageTag; const xmlChar *p = languageTag;
const char *region = NULL; const char *region = NULL;
@ -155,7 +179,7 @@ xsltNewLocale(const xmlChar *languageTag) {
#ifdef XSLT_LOCALE_WINAPI #ifdef XSLT_LOCALE_WINAPI
{ {
xsltLocale locale = (xsltLocale)0; void *locale = NULL;
xmlChar localeName[XSLTMAX_LANGTAGLEN+1]; xmlChar localeName[XSLTMAX_LANGTAGLEN+1];
xmlChar *q = localeName; xmlChar *q = localeName;
const xmlChar *p = languageTag; const xmlChar *p = languageTag;
@ -344,7 +368,7 @@ xsltDefaultRegion(const xmlChar *localeName) {
* Frees a locale created with xsltNewLocale * Frees a locale created with xsltNewLocale
*/ */
void void
xsltFreeLocale(xsltLocale locale) { xsltFreeLocale(void *locale) {
#ifdef XSLT_LOCALE_POSIX #ifdef XSLT_LOCALE_POSIX
if (locale != NULL) if (locale != NULL)
freelocale(locale); freelocale(locale);
@ -358,58 +382,82 @@ xsltFreeLocale(xsltLocale locale) {
* @locale: locale created with xsltNewLocale * @locale: locale created with xsltNewLocale
* @string: UTF-8 string to transform * @string: UTF-8 string to transform
* *
* Transforms a string according to locale. The transformed string must then be * Transforms a string according to locale. The transformed string must be
* compared with xsltLocaleStrcmp and freed with xmlFree. * freed with xmlFree.
* *
* Returns the transformed string or NULL on error * Returns the transformed string or NULL on error
*/ */
xsltLocaleChar * xmlChar *
xsltStrxfrm(xsltLocale locale, const xmlChar *string) xsltStrxfrm(void *vlocale, const xmlChar *string)
{ {
#ifdef XSLT_LOCALE_NONE #ifdef XSLT_LOCALE_NONE
return(NULL); return(NULL);
#else #else
size_t xstrlen, r; xmlChar *xstr;
xsltLocaleChar *xstr;
#ifdef XSLT_LOCALE_POSIX #ifdef XSLT_LOCALE_POSIX
xstrlen = strxfrm_l(NULL, (const char *)string, 0, locale) + 1; size_t xstrlen, r;
xstr = (xsltLocaleChar *) xmlMalloc(xstrlen);
xstrlen = strxfrm_l(NULL, (const char *)string, 0, vlocale) + 1;
xstr = (xmlChar *) xmlMalloc(xstrlen);
if (xstr == NULL) { if (xstr == NULL) {
xsltTransformError(NULL, NULL, NULL, xsltTransformError(NULL, NULL, NULL,
"xsltStrxfrm : out of memory error\n"); "xsltStrxfrm : out of memory error\n");
return(NULL); return(NULL);
} }
r = strxfrm_l((char *)xstr, (const char *)string, xstrlen, locale); r = strxfrm_l((char *)xstr, (const char *)string, xstrlen, vlocale);
#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 */
if (r >= xstrlen) { if (r >= xstrlen) {
xsltTransformError(NULL, NULL, NULL, "xsltStrxfrm : strxfrm failed\n"); xsltTransformError(NULL, NULL, NULL, "xsltStrxfrm : strxfrm failed\n");
xmlFree(xstr); xmlFree(xstr);
return(NULL); 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); return(xstr);
#endif /* XSLT_LOCALE_NONE */ #endif /* XSLT_LOCALE_NONE */
@ -417,35 +465,22 @@ xsltStrxfrm(xsltLocale locale, const xmlChar *string)
/** /**
* xsltLocaleStrcmp: * xsltLocaleStrcmp:
* @locale: a locale identifier * @locale: unused
* @str1: a string transformed with xsltStrxfrm * @str1: a string transformed with xsltStrxfrm
* @str2: 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, * Returns a value < 0 if str1 sorts before str2,
* a value > 0 if str1 sorts after str2, * a value > 0 if str1 sorts after str2,
* 0 if str1 and str2 are equal wrt sorting * 0 if str1 and str2 are equal wrt sorting
*/ */
int int
xsltLocaleStrcmp(xsltLocale locale, const xsltLocaleChar *str1, const xsltLocaleChar *str2) { xsltLocaleStrcmp(void *locale, const xmlChar *str1, const xmlChar *str2) {
(void)locale; (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)); return(xmlStrcmp(str1, str2));
#endif
} }
#ifdef XSLT_LOCALE_WINAPI #ifdef XSLT_LOCALE_WINAPI

View File

@ -14,63 +14,23 @@
#include <libxml/xmlstring.h> #include <libxml/xmlstring.h>
#include "xsltexports.h" #include "xsltexports.h"
#ifdef HAVE_STRXFRM_L XSLTPUBFUN void * XSLTCALL
xsltNewLocale (const xmlChar *langName,
/* int lowerFirst);
* XSLT_LOCALE_POSIX:
* Macro indicating to use POSIX locale extensions
*/
#define XSLT_LOCALE_POSIX
#ifdef HAVE_LOCALE_H
#include <locale.h>
#endif
#ifdef HAVE_XLOCALE_H
#include <xlocale.h>
#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 <windows.h>
#include <winnls.h>
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 XSLTPUBFUN void XSLTCALL
xsltFreeLocale (xsltLocale locale); xsltFreeLocale (void *locale);
XSLTPUBFUN xsltLocaleChar * XSLTCALL XSLTPUBFUN xmlChar * XSLTCALL
xsltStrxfrm (xsltLocale locale, xsltStrxfrm (void *locale,
const xmlChar *string); const xmlChar *string);
XSLTPUBFUN int XSLTCALL
xsltLocaleStrcmp (xsltLocale locale,
const xsltLocaleChar *str1,
const xsltLocaleChar *str2);
XSLTPUBFUN void XSLTCALL XSLTPUBFUN void XSLTCALL
xsltFreeLocales (void); 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__ */ #endif /* __XML_XSLTLOCALE_H__ */

View File

@ -42,6 +42,7 @@
#include "transform.h" #include "transform.h"
#if defined(_WIN32) #if defined(_WIN32)
#include <windows.h>
#define XSLT_WIN32_PERFORMANCE_COUNTER #define XSLT_WIN32_PERFORMANCE_COUNTER
#endif #endif
@ -960,7 +961,7 @@ xsltDocumentSortFunction(xmlNodeSetPtr list) {
*/ */
static xmlXPathObjectPtr * static xmlXPathObjectPtr *
xsltComputeSortResultInternal(xsltTransformContextPtr ctxt, xmlNodePtr sort, xsltComputeSortResultInternal(xsltTransformContextPtr ctxt, xmlNodePtr sort,
int number, xsltLocale locale) { int number, void *locale) {
#ifdef XSLT_REFACTORED #ifdef XSLT_REFACTORED
xsltStyleItemSortPtr comp; xsltStyleItemSortPtr comp;
#else #else
@ -1047,10 +1048,17 @@ xsltComputeSortResultInternal(xsltTransformContextPtr ctxt, xmlNodePtr sort,
} }
} else { } else {
if (res->type == XPATH_STRING) { if (res->type == XPATH_STRING) {
if (locale != (xsltLocale)0) { if (locale != NULL) {
xmlChar *str = res->stringval; xmlChar *str = res->stringval;
res->stringval = (xmlChar *) xsltStrxfrm(locale, str); xmlChar *sortKey = ctxt->genSortKey(locale, str);
xmlFree(str);
if (sortKey == NULL) {
xsltTransformError(ctxt, NULL, sort,
"xsltComputeSortResult: sort key is null\n");
} else {
res->stringval = sortKey;
xmlFree(str);
}
} }
results[i] = res; results[i] = res;
@ -1094,7 +1102,8 @@ xsltComputeSortResult(xsltTransformContextPtr ctxt, xmlNodePtr sort) {
if (comp != NULL) if (comp != NULL)
number = comp->number; 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; xmlNodePtr node;
xmlXPathObjectPtr tmp; xmlXPathObjectPtr tmp;
int number[XSLT_MAX_SORT], desc[XSLT_MAX_SORT]; 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) || if ((ctxt == NULL) || (sorts == NULL) || (nbsorts <= 0) ||
(nbsorts >= XSLT_MAX_SORT)) (nbsorts >= XSLT_MAX_SORT))
@ -1140,6 +1149,8 @@ xsltDefaultSortFunction(xsltTransformContextPtr ctxt, xmlNodePtr *sorts,
return; /* nothing to do */ return; /* nothing to do */
for (j = 0; j < nbsorts; j++) { for (j = 0; j < nbsorts; j++) {
xmlChar *lang;
comp = sorts[j]->psvi; comp = sorts[j]->psvi;
if ((comp->stype == NULL) && (comp->has_stype != 0)) { if ((comp->stype == NULL) && (comp->has_stype != 0)) {
xmlChar *stype = xmlChar *stype =
@ -1181,17 +1192,18 @@ xsltDefaultSortFunction(xsltTransformContextPtr ctxt, xmlNodePtr *sorts,
desc[j] = comp->descending; desc[j] = comp->descending;
} }
if ((comp->lang == NULL) && (comp->has_lang != 0)) { if ((comp->lang == NULL) && (comp->has_lang != 0)) {
xmlChar *lang = xsltEvalAttrValueTemplate(ctxt, sorts[j], lang = xsltEvalAttrValueTemplate(ctxt, sorts[j],
(xmlChar *) "lang", (xmlChar *) "lang",
NULL); NULL);
if (lang != NULL) {
locale[j] = xsltNewLocale(lang);
xmlFree(lang);
} else {
locale[j] = 0;
}
} else { } 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) results[j + incr]->floatval)
tst = 1; tst = 1;
else 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 { } else {
tst = xmlStrcmp(results[j]->stringval, tst = xmlStrcmp(results[j]->stringval,
results[j + incr]->stringval); results[j + incr]->stringval);
@ -1298,11 +1305,6 @@ xsltDefaultSortFunction(xsltTransformContextPtr ctxt, xmlNodePtr *sorts,
res[j + incr]->floatval) res[j + incr]->floatval)
tst = 1; tst = 1;
else 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 { } else {
tst = xmlStrcmp(res[j]->stringval, tst = xmlStrcmp(res[j]->stringval,
res[j + incr]->stringval); res[j + incr]->stringval);
@ -1353,8 +1355,8 @@ cleanup:
for (j = 0; j < nbsorts; j++) { for (j = 0; j < nbsorts; j++) {
comp = sorts[j]->psvi; comp = sorts[j]->psvi;
if ((comp->lang == NULL) && (comp->has_lang != 0)) { if ((comp->lang == NULL) && (comp->has_lang != 0)) {
if (locale[j] != (xsltLocale)0) { if (locale[j] != NULL) {
xsltFreeLocale(locale[j]); ctxt->freeLocale(locale[j]);
} }
} }
if (resultsTab[j] != NULL) { if (resultsTab[j] != NULL) {
@ -1396,6 +1398,8 @@ xsltDoSortFunction(xsltTransformContextPtr ctxt, xmlNodePtr * sorts,
* xsltSetSortFunc: * xsltSetSortFunc:
* @handler: the new handler function * @handler: the new handler function
* *
* DEPRECATED: Use xsltSetCtxtLocaleHandlers.
*
* Function to reset the global handler for XSLT sorting. * Function to reset the global handler for XSLT sorting.
* If the handler is NULL, the default sort function will be used. * If the handler is NULL, the default sort function will be used.
*/ */
@ -1412,6 +1416,8 @@ xsltSetSortFunc(xsltSortFunc handler) {
* @ctxt: a XSLT process context * @ctxt: a XSLT process context
* @handler: the new handler function * @handler: the new handler function
* *
* DEPRECATED: Use xsltSetCtxtLocaleHandlers.
*
* Function to set the handler for XSLT sorting * Function to set the handler for XSLT sorting
* for the specified context. * for the specified context.
* If the handler is NULL, then the global * If the handler is NULL, then the global
@ -1422,6 +1428,28 @@ xsltSetCtxtSortFunc(xsltTransformContextPtr ctxt, xsltSortFunc handler) {
ctxt->sortfunc = 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 * * Parsing options *

View File

@ -178,6 +178,11 @@ XSLTPUBFUN void XSLTCALL
XSLTPUBFUN void XSLTCALL XSLTPUBFUN void XSLTCALL
xsltSetCtxtSortFunc (xsltTransformContextPtr ctxt, xsltSetCtxtSortFunc (xsltTransformContextPtr ctxt,
xsltSortFunc handler); xsltSortFunc handler);
XSLTPUBFUN void XSLTCALL
xsltSetCtxtLocaleHandlers (xsltTransformContextPtr ctxt,
xsltNewLocaleFunc newLocale,
xsltFreeLocaleFunc freeLocale,
xsltGenSortKeFunc genSortKey);
XSLTPUBFUN void XSLTCALL XSLTPUBFUN void XSLTCALL
xsltDefaultSortFunction (xsltTransformContextPtr ctxt, xsltDefaultSortFunction (xsltTransformContextPtr ctxt,
xmlNodePtr *sorts, xmlNodePtr *sorts,

View File

@ -1,6 +1,7 @@
#include "libxml_wrap.h" #include "libxml_wrap.h"
#include <libxslt/xslt.h> #include <libxslt/xslt.h>
#include <libxslt/xsltInternals.h> #include <libxslt/xsltInternals.h>
#include <libxslt/xsltlocale.h>
#include <libxslt/xsltutils.h> #include <libxslt/xsltutils.h>
#include <libxslt/attributes.h> #include <libxslt/attributes.h>
#include <libxslt/documents.h> #include <libxslt/documents.h>