1
0
mirror of https://gitlab.gnome.org/GNOME/libxslt synced 2025-08-05 23:35:48 +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;
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)) { 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)) { if (U_FAILURE(status)) {
xsltTransformError(ctxt, NULL, NULL, "xsltICUSortFunction: Error opening collator\n"); return NULL;
} }
if(comp->lower_first) }
if (lowerFirst)
ucol_setAttribute(coll, UCOL_CASE_FIRST, UCOL_LOWER_FIRST, &status); 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) * xsltICUNewLocale:
tst = 1; * @locale: ICU collator
else { *
if (number[0]) { * Free the ICU collator.
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; void
while (depth < nbsorts) { xsltICUFreeLocale(void *coll) {
if (sorts[depth] == NULL) ucol_close((UCollator *) coll);
break; }
comp = sorts[depth]->_private;
if (comp == NULL)
break;
/* /**
* Compute the result of the next level for the * xsltICUGenSortKey:
* full set, this might be optimized ... or not * @locale: ICU collator
* @str: source string
*
* Generate a localized sort key.
*/ */
if (resultsTab[depth] == NULL) xmlChar *
resultsTab[depth] = xsltComputeSortResult(ctxt, xsltICUGenSortKey(void *coll, const xmlChar *str) {
sorts[depth]); UConverter *conv;
res = resultsTab[depth]; UChar *ustr = NULL;
if (res == NULL) xmlChar *result = NULL;
break; UErrorCode status = U_ZERO_ERROR;
if (res[j] == NULL) int32_t ustrLen, resultLen;
tst = 1;
else { conv = ucnv_open("UTF8", &status);
if (number[depth]) { if (U_FAILURE(status))
if (res[j]->floatval == res[j + incr]->floatval) goto error;
tst = 0;
else if (res[j]->floatval > ustrLen = ucnv_toUChars(conv, NULL, 0, (const char *) str, -1, &status);
res[j + incr]->floatval) if (U_FAILURE(status) && status != U_BUFFER_OVERFLOW_ERROR)
tst = 1; goto error;
else tst = -1; status = U_ZERO_ERROR;
} else { ustr = (UChar *) xmlMalloc((ustrLen + 1) * sizeof(UChar));
/* tst = xmlStrcmp(res[j]->stringval, if (ustr == NULL)
res[j + incr]->stringval); */ goto error;
/* Start ICU change */ ustrLen = ucnv_toUChars(conv, ustr, ustrLen, (const char *) str, -1,
targetlen = xmlStrlen(res[j]->stringval) * 2; &status);
target2len = xmlStrlen(res[j + incr]->stringval) * 2; if (U_FAILURE(status))
target = xmlMalloc(targetlen * sizeof(UChar)); goto error;
target2 = xmlMalloc(target2len * sizeof(UChar));
targetlen = ucnv_toUChars(conv, target, targetlen, resultLen = ucol_getSortKey((UCollator *) coll, ustr, ustrLen, NULL, 0);
(const char *) res[j]->stringval, if (resultLen == 0)
-1, &status); goto error;
target2len = ucnv_toUChars(conv, target2, target2len, result = (xmlChar *) xmlMalloc(resultLen);
(const char *) res[j+incr]->stringval, if (result == NULL)
-1, &status); goto error;
tst = ucol_strcoll(coll, target, u_strlen(target), target2, u_strlen(target2)); resultLen = ucol_getSortKey((UCollator *) coll, ustr, ustrLen, result,
/* End ICU change */ resultLen);
} if (resultLen == 0) {
if (desc[depth]) xmlFree(result);
tst = -tst; result = NULL;
} goto error;
/*
* 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 */ error:
ucol_close(coll); xmlFree(ustr);
ucnv_close(conv); return result;
/* 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]);
}
}
} }
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,11 +1048,18 @@ 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);
if (sortKey == NULL) {
xsltTransformError(ctxt, NULL, sort,
"xsltComputeSortResult: sort key is null\n");
} else {
res->stringval = sortKey;
xmlFree(str); xmlFree(str);
} }
}
results[i] = res; results[i] = res;
} else { } else {
@@ -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);
} else {
lang = (xmlChar *) comp->lang;
}
if (lang != NULL) { if (lang != NULL) {
locale[j] = xsltNewLocale(lang); locale[j] = ctxt->newLocale(lang, comp->lower_first);
if (lang != comp->lang)
xmlFree(lang); xmlFree(lang);
} else { } else {
locale[j] = 0; locale[j] = NULL;
}
} else {
locale[j] = comp->locale;
} }
} }
@@ -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>