libxslt-1.1.28/0000775000076400007640000000000012053100433010266 500000000000000libxslt-1.1.28/INSTALL0000664000076400007640000000176112021407617011255 00000000000000 How to install the XSLT library: Requirements: ============= this library requires a recent version of libxml2 which you can grab from either the GNOME FTP or the xmlsoft.org server: ftp://xmlsoft.org/ When installing from a distribution package like a tar.gz: ========================================================== expand the package run ./configure possibly indicating the desired installation prefix: ./configure --prefix=/usr then run make to build the project and make install (possibly after having gained root access) to install the library and associated include and scripts. When installing from a checkout of the GNOME CVS base: ====================================================== run ./autogen.sh possibly indicating the desired installation prefix: ./autogen.sh --prefix=/usr then run make to build the project and make install (possibly after having gained root access) to instal the library and associated include and scripts. libxslt-1.1.28/libexslt/0000775000076400007640000000000012053100426012116 500000000000000libxslt-1.1.28/libexslt/exsltexports.h0000664000076400007640000000646711202213516015010 00000000000000/* * exsltexports.h : macros for marking symbols as exportable/importable. * * See Copyright for the status of this software. * * igor@zlatkovic.com */ #ifndef __EXSLT_EXPORTS_H__ #define __EXSLT_EXPORTS_H__ /** * EXSLTPUBFUN, EXSLTPUBVAR, EXSLTCALL * * Macros which declare an exportable function, an exportable variable and * the calling convention used for functions. * * Please use an extra block for every platform/compiler combination when * modifying this, rather than overlong #ifdef lines. This helps * readability as well as the fact that different compilers on the same * platform might need different definitions. */ /** * EXSLTPUBFUN: * * Macros which declare an exportable function */ #define EXSLTPUBFUN /** * EXSLTPUBVAR: * * Macros which declare an exportable variable */ #define EXSLTPUBVAR extern /** * EXSLTCALL: * * Macros which declare the called convention for exported functions */ #define EXSLTCALL /** DOC_DISABLE */ /* Windows platform with MS compiler */ #if defined(_WIN32) && defined(_MSC_VER) #undef EXSLTPUBFUN #undef EXSLTPUBVAR #undef EXSLTCALL #if defined(IN_LIBEXSLT) && !defined(LIBEXSLT_STATIC) #define EXSLTPUBFUN __declspec(dllexport) #define EXSLTPUBVAR __declspec(dllexport) #else #define EXSLTPUBFUN #if !defined(LIBEXSLT_STATIC) #define EXSLTPUBVAR __declspec(dllimport) extern #else #define EXSLTPUBVAR extern #endif #endif #define EXSLTCALL __cdecl #if !defined _REENTRANT #define _REENTRANT #endif #endif /* Windows platform with Borland compiler */ #if defined(_WIN32) && defined(__BORLANDC__) #undef EXSLTPUBFUN #undef EXSLTPUBVAR #undef EXSLTCALL #if defined(IN_LIBEXSLT) && !defined(LIBEXSLT_STATIC) #define EXSLTPUBFUN __declspec(dllexport) #define EXSLTPUBVAR __declspec(dllexport) extern #else #define EXSLTPUBFUN #if !defined(LIBEXSLT_STATIC) #define EXSLTPUBVAR __declspec(dllimport) extern #else #define EXSLTPUBVAR extern #endif #endif #define EXSLTCALL __cdecl #if !defined _REENTRANT #define _REENTRANT #endif #endif /* Windows platform with GNU compiler (Mingw) */ #if defined(_WIN32) && defined(__MINGW32__) #undef EXSLTPUBFUN #undef EXSLTPUBVAR #undef EXSLTCALL /* #if defined(IN_LIBEXSLT) && !defined(LIBEXSLT_STATIC) */ #if !defined(LIBEXSLT_STATIC) #define EXSLTPUBFUN __declspec(dllexport) #define EXSLTPUBVAR __declspec(dllexport) extern #else #define EXSLTPUBFUN #if !defined(LIBEXSLT_STATIC) #define EXSLTPUBVAR __declspec(dllimport) extern #else #define EXSLTPUBVAR extern #endif #endif #define EXSLTCALL __cdecl #if !defined _REENTRANT #define _REENTRANT #endif #endif /* Cygwin platform, GNU compiler */ #if defined(_WIN32) && defined(__CYGWIN__) #undef EXSLTPUBFUN #undef EXSLTPUBVAR #undef EXSLTCALL #if defined(IN_LIBEXSLT) && !defined(LIBEXSLT_STATIC) #define EXSLTPUBFUN __declspec(dllexport) #define EXSLTPUBVAR __declspec(dllexport) #else #define EXSLTPUBFUN #if !defined(LIBEXSLT_STATIC) #define EXSLTPUBVAR __declspec(dllimport) extern #else #define EXSLTPUBVAR #endif #endif #define EXSLTCALL __cdecl #endif /* Compatibility */ #if !defined(LIBEXSLT_PUBLIC) #define LIBEXSLT_PUBLIC EXSLTPUBVAR #endif #endif /* __EXSLT_EXPORTS_H__ */ libxslt-1.1.28/libexslt/libexslt.h0000664000076400007640000000124212024022167014037 00000000000000/* * libexslt.h: internal header only used during the compilation of libexslt * * See COPYRIGHT for the status of this software * * Author: daniel@veillard.com */ #ifndef __XSLT_LIBEXSLT_H__ #define __XSLT_LIBEXSLT_H__ #if defined(WIN32) && !defined (__CYGWIN__) && !defined (__MINGW32__) #include #else #include "config.h" #endif #include #include #if !defined LIBEXSLT_PUBLIC #if (defined (__CYGWIN__) || defined _MSC_VER) && !defined IN_LIBEXSLT && !defined LIBEXSLT_STATIC #define LIBEXSLT_PUBLIC __declspec(dllimport) #else #define LIBEXSLT_PUBLIC #endif #endif #endif /* ! __XSLT_LIBEXSLT_H__ */ libxslt-1.1.28/libexslt/date.c0000664000076400007640000032024312024022216013121 00000000000000/* * date.c: Implementation of the EXSLT -- Dates and Times module * * References: * http://www.exslt.org/date/date.html * * See Copyright for the status of this software. * * Authors: * Charlie Bozeman * Thomas Broyer * * TODO: * elements: * date-format * functions: * format-date * parse-date * sum */ #define IN_LIBEXSLT #include "libexslt/libexslt.h" #if defined(WIN32) && !defined (__CYGWIN__) && (!__MINGW32__) #include #else #include "config.h" #endif #if defined(HAVE_LOCALTIME_R) && defined(__GLIBC__) /* _POSIX_SOURCE required by gnu libc */ #ifndef _AIX51 /* but on AIX we're not using gnu libc */ #define _POSIX_SOURCE #endif #endif #include #include #include #include #include #include #include #include "exslt.h" #include #ifdef HAVE_MATH_H #include #endif /* needed to get localtime_r on Solaris */ #ifdef __sun #ifndef __EXTENSIONS__ #define __EXTENSIONS__ #endif #endif #ifdef HAVE_TIME_H #include #endif /* * types of date and/or time (from schema datatypes) * somewhat ordered from least specific to most specific (i.e. * most truncated to least truncated). */ typedef enum { EXSLT_UNKNOWN = 0, XS_TIME = 1, /* time is left-truncated */ XS_GDAY = (XS_TIME << 1), XS_GMONTH = (XS_GDAY << 1), XS_GMONTHDAY = (XS_GMONTH | XS_GDAY), XS_GYEAR = (XS_GMONTH << 1), XS_GYEARMONTH = (XS_GYEAR | XS_GMONTH), XS_DATE = (XS_GYEAR | XS_GMONTH | XS_GDAY), XS_DATETIME = (XS_DATE | XS_TIME), XS_DURATION = (XS_GYEAR << 1) } exsltDateType; /* Date value */ typedef struct _exsltDateValDate exsltDateValDate; typedef exsltDateValDate *exsltDateValDatePtr; struct _exsltDateValDate { long year; unsigned int mon :4; /* 1 <= mon <= 12 */ unsigned int day :5; /* 1 <= day <= 31 */ unsigned int hour :5; /* 0 <= hour <= 23 */ unsigned int min :6; /* 0 <= min <= 59 */ double sec; unsigned int tz_flag :1; /* is tzo explicitely set? */ signed int tzo :12; /* -1440 <= tzo <= 1440 currently only -840 to +840 are needed */ }; /* Duration value */ typedef struct _exsltDateValDuration exsltDateValDuration; typedef exsltDateValDuration *exsltDateValDurationPtr; struct _exsltDateValDuration { long mon; /* mon stores years also */ long day; double sec; /* sec stores min and hour also */ }; typedef struct _exsltDateVal exsltDateVal; typedef exsltDateVal *exsltDateValPtr; struct _exsltDateVal { exsltDateType type; union { exsltDateValDate date; exsltDateValDuration dur; } value; }; /**************************************************************** * * * Compat./Port. macros * * * ****************************************************************/ #if defined(HAVE_TIME_H) \ && (defined(HAVE_LOCALTIME) || defined(HAVE_LOCALTIME_R)) \ && (defined(HAVE_GMTIME) || defined(HAVE_GMTIME_R)) \ && defined(HAVE_TIME) #define WITH_TIME #endif /**************************************************************** * * * Convenience macros and functions * * * ****************************************************************/ #define IS_TZO_CHAR(c) \ ((c == 0) || (c == 'Z') || (c == '+') || (c == '-')) #define VALID_ALWAYS(num) (num >= 0) #define VALID_YEAR(yr) (yr != 0) #define VALID_MONTH(mon) ((mon >= 1) && (mon <= 12)) /* VALID_DAY should only be used when month is unknown */ #define VALID_DAY(day) ((day >= 1) && (day <= 31)) #define VALID_HOUR(hr) ((hr >= 0) && (hr <= 23)) #define VALID_MIN(min) ((min >= 0) && (min <= 59)) #define VALID_SEC(sec) ((sec >= 0) && (sec < 60)) #define VALID_TZO(tzo) ((tzo > -1440) && (tzo < 1440)) #define IS_LEAP(y) \ (((y % 4 == 0) && (y % 100 != 0)) || (y % 400 == 0)) static const unsigned long daysInMonth[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; static const unsigned long daysInMonthLeap[12] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; #define MAX_DAYINMONTH(yr,mon) \ (IS_LEAP(yr) ? daysInMonthLeap[mon - 1] : daysInMonth[mon - 1]) #define VALID_MDAY(dt) \ (IS_LEAP(dt->year) ? \ (dt->day <= daysInMonthLeap[dt->mon - 1]) : \ (dt->day <= daysInMonth[dt->mon - 1])) #define VALID_DATE(dt) \ (VALID_YEAR(dt->year) && VALID_MONTH(dt->mon) && VALID_MDAY(dt)) /* hour and min structure vals are unsigned, so normal macros give warnings on some compilers. */ #define VALID_TIME(dt) \ ((dt->hour <=23 ) && (dt->min <= 59) && \ VALID_SEC(dt->sec) && VALID_TZO(dt->tzo)) #define VALID_DATETIME(dt) \ (VALID_DATE(dt) && VALID_TIME(dt)) #define SECS_PER_MIN (60) #define SECS_PER_HOUR (60 * SECS_PER_MIN) #define SECS_PER_DAY (24 * SECS_PER_HOUR) static const unsigned long dayInYearByMonth[12] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; static const unsigned long dayInLeapYearByMonth[12] = { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 }; #define DAY_IN_YEAR(day, month, year) \ ((IS_LEAP(year) ? \ dayInLeapYearByMonth[month - 1] : \ dayInYearByMonth[month - 1]) + day) /** * _exsltDateParseGYear: * @dt: pointer to a date structure * @str: pointer to the string to analyze * * Parses a xs:gYear without time zone and fills in the appropriate * field of the @dt structure. @str is updated to point just after the * xs:gYear. It is supposed that @dt->year is big enough to contain * the year. * * Returns 0 or the error code */ static int _exsltDateParseGYear (exsltDateValDatePtr dt, const xmlChar **str) { const xmlChar *cur = *str, *firstChar; int isneg = 0, digcnt = 0; if (((*cur < '0') || (*cur > '9')) && (*cur != '-') && (*cur != '+')) return -1; if (*cur == '-') { isneg = 1; cur++; } firstChar = cur; while ((*cur >= '0') && (*cur <= '9')) { dt->year = dt->year * 10 + (*cur - '0'); cur++; digcnt++; } /* year must be at least 4 digits (CCYY); over 4 * digits cannot have a leading zero. */ if ((digcnt < 4) || ((digcnt > 4) && (*firstChar == '0'))) return 1; if (isneg) dt->year = - dt->year; if (!VALID_YEAR(dt->year)) return 2; *str = cur; #ifdef DEBUG_EXSLT_DATE xsltGenericDebug(xsltGenericDebugContext, "Parsed year %04i\n", dt->year); #endif return 0; } /** * FORMAT_GYEAR: * @yr: the year to format * @cur: a pointer to an allocated buffer * * Formats @yr in xsl:gYear format. Result is appended to @cur and * @cur is updated to point after the xsl:gYear. */ #define FORMAT_GYEAR(yr, cur) \ if (yr < 0) { \ *cur = '-'; \ cur++; \ } \ { \ long year = (yr < 0) ? - yr : yr; \ xmlChar tmp_buf[100], *tmp = tmp_buf; \ /* result is in reverse-order */ \ while (year > 0) { \ *tmp = '0' + (xmlChar)(year % 10); \ year /= 10; \ tmp++; \ } \ /* virtually adds leading zeros */ \ while ((tmp - tmp_buf) < 4) \ *tmp++ = '0'; \ /* restore the correct order */ \ while (tmp > tmp_buf) { \ tmp--; \ *cur = *tmp; \ cur++; \ } \ } /** * PARSE_2_DIGITS: * @num: the integer to fill in * @cur: an #xmlChar * * @func: validation function for the number * @invalid: an integer * * Parses a 2-digits integer and updates @num with the value. @cur is * updated to point just after the integer. * In case of error, @invalid is set to %TRUE, values of @num and * @cur are undefined. */ #define PARSE_2_DIGITS(num, cur, func, invalid) \ if ((cur[0] < '0') || (cur[0] > '9') || \ (cur[1] < '0') || (cur[1] > '9')) \ invalid = 1; \ else { \ int val; \ val = (cur[0] - '0') * 10 + (cur[1] - '0'); \ if (!func(val)) \ invalid = 2; \ else \ num = val; \ } \ cur += 2; /** * FORMAT_2_DIGITS: * @num: the integer to format * @cur: a pointer to an allocated buffer * * Formats a 2-digits integer. Result is appended to @cur and * @cur is updated to point after the integer. */ #define FORMAT_2_DIGITS(num, cur) \ *cur = '0' + ((num / 10) % 10); \ cur++; \ *cur = '0' + (num % 10); \ cur++; /** * PARSE_FLOAT: * @num: the double to fill in * @cur: an #xmlChar * * @invalid: an integer * * Parses a float and updates @num with the value. @cur is * updated to point just after the float. The float must have a * 2-digits integer part and may or may not have a decimal part. * In case of error, @invalid is set to %TRUE, values of @num and * @cur are undefined. */ #define PARSE_FLOAT(num, cur, invalid) \ PARSE_2_DIGITS(num, cur, VALID_ALWAYS, invalid); \ if (!invalid && (*cur == '.')) { \ double mult = 1; \ cur++; \ if ((*cur < '0') || (*cur > '9')) \ invalid = 1; \ while ((*cur >= '0') && (*cur <= '9')) { \ mult /= 10; \ num += (*cur - '0') * mult; \ cur++; \ } \ } /** * FORMAT_FLOAT: * @num: the double to format * @cur: a pointer to an allocated buffer * @pad: a flag for padding to 2 integer digits * * Formats a float. Result is appended to @cur and @cur is updated to * point after the integer. If the @pad flag is non-zero, then the * float representation has a minimum 2-digits integer part. The * fractional part is formatted if @num has a fractional value. */ #define FORMAT_FLOAT(num, cur, pad) \ { \ xmlChar *sav, *str; \ if ((pad) && (num < 10.0)) \ *cur++ = '0'; \ str = xmlXPathCastNumberToString(num); \ sav = str; \ while (*str != 0) \ *cur++ = *str++; \ xmlFree(sav); \ } /** * _exsltDateParseGMonth: * @dt: pointer to a date structure * @str: pointer to the string to analyze * * Parses a xs:gMonth without time zone and fills in the appropriate * field of the @dt structure. @str is updated to point just after the * xs:gMonth. * * Returns 0 or the error code */ static int _exsltDateParseGMonth (exsltDateValDatePtr dt, const xmlChar **str) { const xmlChar *cur = *str; int ret = 0; PARSE_2_DIGITS(dt->mon, cur, VALID_MONTH, ret); if (ret != 0) return ret; *str = cur; #ifdef DEBUG_EXSLT_DATE xsltGenericDebug(xsltGenericDebugContext, "Parsed month %02i\n", dt->mon); #endif return 0; } /** * FORMAT_GMONTH: * @mon: the month to format * @cur: a pointer to an allocated buffer * * Formats @mon in xsl:gMonth format. Result is appended to @cur and * @cur is updated to point after the xsl:gMonth. */ #define FORMAT_GMONTH(mon, cur) \ FORMAT_2_DIGITS(mon, cur) /** * _exsltDateParseGDay: * @dt: pointer to a date structure * @str: pointer to the string to analyze * * Parses a xs:gDay without time zone and fills in the appropriate * field of the @dt structure. @str is updated to point just after the * xs:gDay. * * Returns 0 or the error code */ static int _exsltDateParseGDay (exsltDateValDatePtr dt, const xmlChar **str) { const xmlChar *cur = *str; int ret = 0; PARSE_2_DIGITS(dt->day, cur, VALID_DAY, ret); if (ret != 0) return ret; *str = cur; #ifdef DEBUG_EXSLT_DATE xsltGenericDebug(xsltGenericDebugContext, "Parsed day %02i\n", dt->day); #endif return 0; } /** * FORMAT_GDAY: * @dt: the #exsltDateValDate to format * @cur: a pointer to an allocated buffer * * Formats @dt in xsl:gDay format. Result is appended to @cur and * @cur is updated to point after the xsl:gDay. */ #define FORMAT_GDAY(dt, cur) \ FORMAT_2_DIGITS(dt->day, cur) /** * FORMAT_DATE: * @dt: the #exsltDateValDate to format * @cur: a pointer to an allocated buffer * * Formats @dt in xsl:date format. Result is appended to @cur and * @cur is updated to point after the xsl:date. */ #define FORMAT_DATE(dt, cur) \ FORMAT_GYEAR(dt->year, cur); \ *cur = '-'; \ cur++; \ FORMAT_GMONTH(dt->mon, cur); \ *cur = '-'; \ cur++; \ FORMAT_GDAY(dt, cur); /** * _exsltDateParseTime: * @dt: pointer to a date structure * @str: pointer to the string to analyze * * Parses a xs:time without time zone and fills in the appropriate * fields of the @dt structure. @str is updated to point just after the * xs:time. * In case of error, values of @dt fields are undefined. * * Returns 0 or the error code */ static int _exsltDateParseTime (exsltDateValDatePtr dt, const xmlChar **str) { const xmlChar *cur = *str; unsigned int hour = 0; /* use temp var in case str is not xs:time */ int ret = 0; PARSE_2_DIGITS(hour, cur, VALID_HOUR, ret); if (ret != 0) return ret; if (*cur != ':') return 1; cur++; /* the ':' insures this string is xs:time */ dt->hour = hour; PARSE_2_DIGITS(dt->min, cur, VALID_MIN, ret); if (ret != 0) return ret; if (*cur != ':') return 1; cur++; PARSE_FLOAT(dt->sec, cur, ret); if (ret != 0) return ret; if (!VALID_TIME(dt)) return 2; *str = cur; #ifdef DEBUG_EXSLT_DATE xsltGenericDebug(xsltGenericDebugContext, "Parsed time %02i:%02i:%02.f\n", dt->hour, dt->min, dt->sec); #endif return 0; } /** * FORMAT_TIME: * @dt: the #exsltDateValDate to format * @cur: a pointer to an allocated buffer * * Formats @dt in xsl:time format. Result is appended to @cur and * @cur is updated to point after the xsl:time. */ #define FORMAT_TIME(dt, cur) \ FORMAT_2_DIGITS(dt->hour, cur); \ *cur = ':'; \ cur++; \ FORMAT_2_DIGITS(dt->min, cur); \ *cur = ':'; \ cur++; \ FORMAT_FLOAT(dt->sec, cur, 1); /** * _exsltDateParseTimeZone: * @dt: pointer to a date structure * @str: pointer to the string to analyze * * Parses a time zone without time zone and fills in the appropriate * field of the @dt structure. @str is updated to point just after the * time zone. * * Returns 0 or the error code */ static int _exsltDateParseTimeZone (exsltDateValDatePtr dt, const xmlChar **str) { const xmlChar *cur; int ret = 0; if (str == NULL) return -1; cur = *str; switch (*cur) { case 0: dt->tz_flag = 0; dt->tzo = 0; break; case 'Z': dt->tz_flag = 1; dt->tzo = 0; cur++; break; case '+': case '-': { int isneg = 0, tmp = 0; isneg = (*cur == '-'); cur++; PARSE_2_DIGITS(tmp, cur, VALID_HOUR, ret); if (ret != 0) return ret; if (*cur != ':') return 1; cur++; dt->tzo = tmp * 60; PARSE_2_DIGITS(tmp, cur, VALID_MIN, ret); if (ret != 0) return ret; dt->tzo += tmp; if (isneg) dt->tzo = - dt->tzo; if (!VALID_TZO(dt->tzo)) return 2; break; } default: return 1; } *str = cur; #ifdef DEBUG_EXSLT_DATE xsltGenericDebug(xsltGenericDebugContext, "Parsed time zone offset (%s) %i\n", dt->tz_flag ? "explicit" : "implicit", dt->tzo); #endif return 0; } /** * FORMAT_TZ: * @tzo: the timezone offset to format * @cur: a pointer to an allocated buffer * * Formats @tzo timezone. Result is appended to @cur and * @cur is updated to point after the timezone. */ #define FORMAT_TZ(tzo, cur) \ if (tzo == 0) { \ *cur = 'Z'; \ cur++; \ } else { \ int aTzo = (tzo < 0) ? - tzo : tzo; \ int tzHh = aTzo / 60, tzMm = aTzo % 60; \ *cur = (tzo < 0) ? '-' : '+' ; \ cur++; \ FORMAT_2_DIGITS(tzHh, cur); \ *cur = ':'; \ cur++; \ FORMAT_2_DIGITS(tzMm, cur); \ } /**************************************************************** * * * XML Schema Dates/Times Datatypes Handling * * * ****************************************************************/ /** * exsltDateCreateDate: * @type: type to create * * Creates a new #exsltDateVal, uninitialized. * * Returns the #exsltDateValPtr */ static exsltDateValPtr exsltDateCreateDate (exsltDateType type) { exsltDateValPtr ret; ret = (exsltDateValPtr) xmlMalloc(sizeof(exsltDateVal)); if (ret == NULL) { xsltGenericError(xsltGenericErrorContext, "exsltDateCreateDate: out of memory\n"); return (NULL); } memset (ret, 0, sizeof(exsltDateVal)); if (type != EXSLT_UNKNOWN) ret->type = type; return ret; } /** * exsltDateFreeDate: * @date: an #exsltDateValPtr * * Frees up the @date */ static void exsltDateFreeDate (exsltDateValPtr date) { if (date == NULL) return; xmlFree(date); } /** * PARSE_DIGITS: * @num: the integer to fill in * @cur: an #xmlChar * * @num_type: an integer flag * * Parses a digits integer and updates @num with the value. @cur is * updated to point just after the integer. * In case of error, @num_type is set to -1, values of @num and * @cur are undefined. */ #define PARSE_DIGITS(num, cur, num_type) \ if ((*cur < '0') || (*cur > '9')) \ num_type = -1; \ else \ while ((*cur >= '0') && (*cur <= '9')) { \ num = num * 10 + (*cur - '0'); \ cur++; \ } /** * PARSE_NUM: * @num: the double to fill in * @cur: an #xmlChar * * @num_type: an integer flag * * Parses a float or integer and updates @num with the value. @cur is * updated to point just after the number. If the number is a float, * then it must have an integer part and a decimal part; @num_type will * be set to 1. If there is no decimal part, @num_type is set to zero. * In case of error, @num_type is set to -1, values of @num and * @cur are undefined. */ #define PARSE_NUM(num, cur, num_type) \ num = 0; \ PARSE_DIGITS(num, cur, num_type); \ if (!num_type && (*cur == '.')) { \ double mult = 1; \ cur++; \ if ((*cur < '0') || (*cur > '9')) \ num_type = -1; \ else \ num_type = 1; \ while ((*cur >= '0') && (*cur <= '9')) { \ mult /= 10; \ num += (*cur - '0') * mult; \ cur++; \ } \ } #ifdef WITH_TIME /** * exsltDateCurrent: * * Returns the current date and time. */ static exsltDateValPtr exsltDateCurrent (void) { struct tm localTm, gmTm; time_t secs; int local_s, gm_s; exsltDateValPtr ret; ret = exsltDateCreateDate(XS_DATETIME); if (ret == NULL) return NULL; /* get current time */ secs = time(NULL); #if HAVE_LOCALTIME_R localtime_r(&secs, &localTm); #else localTm = *localtime(&secs); #endif /* get real year, not years since 1900 */ ret->value.date.year = localTm.tm_year + 1900; ret->value.date.mon = localTm.tm_mon + 1; ret->value.date.day = localTm.tm_mday; ret->value.date.hour = localTm.tm_hour; ret->value.date.min = localTm.tm_min; /* floating point seconds */ ret->value.date.sec = (double) localTm.tm_sec; /* determine the time zone offset from local to gm time */ #if HAVE_GMTIME_R gmtime_r(&secs, &gmTm); #else gmTm = *gmtime(&secs); #endif ret->value.date.tz_flag = 0; #if 0 ret->value.date.tzo = (((ret->value.date.day * 1440) + (ret->value.date.hour * 60) + ret->value.date.min) - ((gmTm.tm_mday * 1440) + (gmTm.tm_hour * 60) + gmTm.tm_min)); #endif local_s = localTm.tm_hour * SECS_PER_HOUR + localTm.tm_min * SECS_PER_MIN + localTm.tm_sec; gm_s = gmTm.tm_hour * SECS_PER_HOUR + gmTm.tm_min * SECS_PER_MIN + gmTm.tm_sec; if (localTm.tm_year < gmTm.tm_year) { ret->value.date.tzo = -((SECS_PER_DAY - local_s) + gm_s)/60; } else if (localTm.tm_year > gmTm.tm_year) { ret->value.date.tzo = ((SECS_PER_DAY - gm_s) + local_s)/60; } else if (localTm.tm_mon < gmTm.tm_mon) { ret->value.date.tzo = -((SECS_PER_DAY - local_s) + gm_s)/60; } else if (localTm.tm_mon > gmTm.tm_mon) { ret->value.date.tzo = ((SECS_PER_DAY - gm_s) + local_s)/60; } else if (localTm.tm_mday < gmTm.tm_mday) { ret->value.date.tzo = -((SECS_PER_DAY - local_s) + gm_s)/60; } else if (localTm.tm_mday > gmTm.tm_mday) { ret->value.date.tzo = ((SECS_PER_DAY - gm_s) + local_s)/60; } else { ret->value.date.tzo = (local_s - gm_s)/60; } return ret; } #endif /** * exsltDateParse: * @dateTime: string to analyze * * Parses a date/time string * * Returns a newly built #exsltDateValPtr of NULL in case of error */ static exsltDateValPtr exsltDateParse (const xmlChar *dateTime) { exsltDateValPtr dt; int ret; const xmlChar *cur = dateTime; #define RETURN_TYPE_IF_VALID(t) \ if (IS_TZO_CHAR(*cur)) { \ ret = _exsltDateParseTimeZone(&(dt->value.date), &cur); \ if (ret == 0) { \ if (*cur != 0) \ goto error; \ dt->type = t; \ return dt; \ } \ } if (dateTime == NULL) return NULL; if ((*cur != '-') && (*cur < '0') && (*cur > '9')) return NULL; dt = exsltDateCreateDate(EXSLT_UNKNOWN); if (dt == NULL) return NULL; if ((cur[0] == '-') && (cur[1] == '-')) { /* * It's an incomplete date (xs:gMonthDay, xs:gMonth or * xs:gDay) */ cur += 2; /* is it an xs:gDay? */ if (*cur == '-') { ++cur; ret = _exsltDateParseGDay(&(dt->value.date), &cur); if (ret != 0) goto error; RETURN_TYPE_IF_VALID(XS_GDAY); goto error; } /* * it should be an xs:gMonthDay or xs:gMonth */ ret = _exsltDateParseGMonth(&(dt->value.date), &cur); if (ret != 0) goto error; if (*cur != '-') goto error; cur++; /* is it an xs:gMonth? */ if (*cur == '-') { cur++; RETURN_TYPE_IF_VALID(XS_GMONTH); goto error; } /* it should be an xs:gMonthDay */ ret = _exsltDateParseGDay(&(dt->value.date), &cur); if (ret != 0) goto error; RETURN_TYPE_IF_VALID(XS_GMONTHDAY); goto error; } /* * It's a right-truncated date or an xs:time. * Try to parse an xs:time then fallback on right-truncated dates. */ if ((*cur >= '0') && (*cur <= '9')) { ret = _exsltDateParseTime(&(dt->value.date), &cur); if (ret == 0) { /* it's an xs:time */ RETURN_TYPE_IF_VALID(XS_TIME); } } /* fallback on date parsing */ cur = dateTime; ret = _exsltDateParseGYear(&(dt->value.date), &cur); if (ret != 0) goto error; /* is it an xs:gYear? */ RETURN_TYPE_IF_VALID(XS_GYEAR); if (*cur != '-') goto error; cur++; ret = _exsltDateParseGMonth(&(dt->value.date), &cur); if (ret != 0) goto error; /* is it an xs:gYearMonth? */ RETURN_TYPE_IF_VALID(XS_GYEARMONTH); if (*cur != '-') goto error; cur++; ret = _exsltDateParseGDay(&(dt->value.date), &cur); if ((ret != 0) || !VALID_DATE((&(dt->value.date)))) goto error; /* is it an xs:date? */ RETURN_TYPE_IF_VALID(XS_DATE); if (*cur != 'T') goto error; cur++; /* it should be an xs:dateTime */ ret = _exsltDateParseTime(&(dt->value.date), &cur); if (ret != 0) goto error; ret = _exsltDateParseTimeZone(&(dt->value.date), &cur); if ((ret != 0) || (*cur != 0) || !VALID_DATETIME((&(dt->value.date)))) goto error; dt->type = XS_DATETIME; return dt; error: if (dt != NULL) exsltDateFreeDate(dt); return NULL; } /** * exsltDateParseDuration: * @duration: string to analyze * * Parses a duration string * * Returns a newly built #exsltDateValPtr of NULL in case of error */ static exsltDateValPtr exsltDateParseDuration (const xmlChar *duration) { const xmlChar *cur = duration; exsltDateValPtr dur; int isneg = 0; unsigned int seq = 0; if (duration == NULL) return NULL; if (*cur == '-') { isneg = 1; cur++; } /* duration must start with 'P' (after sign) */ if (*cur++ != 'P') return NULL; dur = exsltDateCreateDate(XS_DURATION); if (dur == NULL) return NULL; while (*cur != 0) { double num; int num_type = 0; /* -1 = invalid, 0 = int, 1 = floating */ const xmlChar desig[] = {'Y', 'M', 'D', 'H', 'M', 'S'}; const double multi[] = { 0.0, 0.0, 86400.0, 3600.0, 60.0, 1.0, 0.0}; /* input string should be empty or invalid date/time item */ if (seq >= sizeof(desig)) goto error; /* T designator must be present for time items */ if (*cur == 'T') { if (seq <= 3) { seq = 3; cur++; } else return NULL; } else if (seq == 3) goto error; /* parse the number portion of the item */ PARSE_NUM(num, cur, num_type); if ((num_type == -1) || (*cur == 0)) goto error; /* update duration based on item type */ while (seq < sizeof(desig)) { if (*cur == desig[seq]) { /* verify numeric type; only seconds can be float */ if ((num_type != 0) && (seq < (sizeof(desig)-1))) goto error; switch (seq) { case 0: dur->value.dur.mon = (long)num * 12; break; case 1: dur->value.dur.mon += (long)num; break; default: /* convert to seconds using multiplier */ dur->value.dur.sec += num * multi[seq]; seq++; break; } break; /* exit loop */ } /* no date designators found? */ if (++seq == 3) goto error; } cur++; } if (isneg) { dur->value.dur.mon = -dur->value.dur.mon; dur->value.dur.day = -dur->value.dur.day; dur->value.dur.sec = -dur->value.dur.sec; } #ifdef DEBUG_EXSLT_DATE xsltGenericDebug(xsltGenericDebugContext, "Parsed duration %f\n", dur->value.dur.sec); #endif return dur; error: if (dur != NULL) exsltDateFreeDate(dur); return NULL; } /** * FORMAT_ITEM: * @num: number to format * @cur: current location to convert number * @limit: max value * @item: char designator * */ #define FORMAT_ITEM(num, cur, limit, item) \ if (num != 0) { \ long comp = (long)num / limit; \ if (comp != 0) { \ FORMAT_FLOAT((double)comp, cur, 0); \ *cur++ = item; \ num -= (double)(comp * limit); \ } \ } /** * exsltDateFormatDuration: * @dt: an #exsltDateValDurationPtr * * Formats @dt in xs:duration format. * * Returns a newly allocated string, or NULL in case of error */ static xmlChar * exsltDateFormatDuration (const exsltDateValDurationPtr dt) { xmlChar buf[100], *cur = buf; double secs, days; double years, months; if (dt == NULL) return NULL; /* quick and dirty check */ if ((dt->sec == 0.0) && (dt->day == 0) && (dt->mon == 0)) return xmlStrdup((xmlChar*)"P0D"); secs = dt->sec; days = (double)dt->day; years = (double)(dt->mon / 12); months = (double)(dt->mon % 12); *cur = '\0'; if (secs < 0.0) { secs = -secs; *cur = '-'; } if (days < 0) { days = -days; *cur = '-'; } if (years < 0) { years = -years; *cur = '-'; } if (months < 0) { months = -months; *cur = '-'; } if (*cur == '-') cur++; *cur++ = 'P'; if (years != 0.0) { FORMAT_ITEM(years, cur, 1, 'Y'); } if (months != 0.0) { FORMAT_ITEM(months, cur, 1, 'M'); } if (secs >= SECS_PER_DAY) { double tmp = floor(secs / SECS_PER_DAY); days += tmp; secs -= (tmp * SECS_PER_DAY); } FORMAT_ITEM(days, cur, 1, 'D'); if (secs > 0.0) { *cur++ = 'T'; } FORMAT_ITEM(secs, cur, SECS_PER_HOUR, 'H'); FORMAT_ITEM(secs, cur, SECS_PER_MIN, 'M'); if (secs > 0.0) { FORMAT_FLOAT(secs, cur, 0); *cur++ = 'S'; } *cur = 0; return xmlStrdup(buf); } /** * exsltDateFormatDateTime: * @dt: an #exsltDateValDatePtr * * Formats @dt in xs:dateTime format. * * Returns a newly allocated string, or NULL in case of error */ static xmlChar * exsltDateFormatDateTime (const exsltDateValDatePtr dt) { xmlChar buf[100], *cur = buf; if ((dt == NULL) || !VALID_DATETIME(dt)) return NULL; FORMAT_DATE(dt, cur); *cur = 'T'; cur++; FORMAT_TIME(dt, cur); FORMAT_TZ(dt->tzo, cur); *cur = 0; return xmlStrdup(buf); } /** * exsltDateFormatDate: * @dt: an #exsltDateValDatePtr * * Formats @dt in xs:date format. * * Returns a newly allocated string, or NULL in case of error */ static xmlChar * exsltDateFormatDate (const exsltDateValDatePtr dt) { xmlChar buf[100], *cur = buf; if ((dt == NULL) || !VALID_DATETIME(dt)) return NULL; FORMAT_DATE(dt, cur); if (dt->tz_flag || (dt->tzo != 0)) { FORMAT_TZ(dt->tzo, cur); } *cur = 0; return xmlStrdup(buf); } /** * exsltDateFormatTime: * @dt: an #exsltDateValDatePtr * * Formats @dt in xs:time format. * * Returns a newly allocated string, or NULL in case of error */ static xmlChar * exsltDateFormatTime (const exsltDateValDatePtr dt) { xmlChar buf[100], *cur = buf; if ((dt == NULL) || !VALID_TIME(dt)) return NULL; FORMAT_TIME(dt, cur); if (dt->tz_flag || (dt->tzo != 0)) { FORMAT_TZ(dt->tzo, cur); } *cur = 0; return xmlStrdup(buf); } /** * exsltDateFormat: * @dt: an #exsltDateValPtr * * Formats @dt in the proper format. * Note: xs:gmonth and xs:gday are not formatted as there are no * routines that output them. * * Returns a newly allocated string, or NULL in case of error */ static xmlChar * exsltDateFormat (const exsltDateValPtr dt) { if (dt == NULL) return NULL; switch (dt->type) { case XS_DURATION: return exsltDateFormatDuration(&(dt->value.dur)); case XS_DATETIME: return exsltDateFormatDateTime(&(dt->value.date)); case XS_DATE: return exsltDateFormatDate(&(dt->value.date)); case XS_TIME: return exsltDateFormatTime(&(dt->value.date)); default: break; } if (dt->type & XS_GYEAR) { xmlChar buf[20], *cur = buf; FORMAT_GYEAR(dt->value.date.year, cur); if (dt->type == XS_GYEARMONTH) { *cur = '-'; cur++; FORMAT_GMONTH(dt->value.date.mon, cur); } if (dt->value.date.tz_flag || (dt->value.date.tzo != 0)) { FORMAT_TZ(dt->value.date.tzo, cur); } *cur = 0; return xmlStrdup(buf); } return NULL; } /** * _exsltDateCastYMToDays: * @dt: an #exsltDateValPtr * * Convert mon and year of @dt to total number of days. Take the * number of years since (or before) 1 AD and add the number of leap * years. This is a function because negative * years must be handled a little differently and there is no zero year. * * Returns number of days. */ static long _exsltDateCastYMToDays (const exsltDateValPtr dt) { long ret; if (dt->value.date.year < 0) ret = (dt->value.date.year * 365) + (((dt->value.date.year+1)/4)-((dt->value.date.year+1)/100)+ ((dt->value.date.year+1)/400)) + DAY_IN_YEAR(0, dt->value.date.mon, dt->value.date.year); else ret = ((dt->value.date.year-1) * 365) + (((dt->value.date.year-1)/4)-((dt->value.date.year-1)/100)+ ((dt->value.date.year-1)/400)) + DAY_IN_YEAR(0, dt->value.date.mon, dt->value.date.year); return ret; } /** * TIME_TO_NUMBER: * @dt: an #exsltDateValPtr * * Calculates the number of seconds in the time portion of @dt. * * Returns seconds. */ #define TIME_TO_NUMBER(dt) \ ((double)((dt->value.date.hour * SECS_PER_HOUR) + \ (dt->value.date.min * SECS_PER_MIN)) + dt->value.date.sec) /** * exsltDateCastDateToNumber: * @dt: an #exsltDateValPtr * * Calculates the number of seconds from year zero. * * Returns seconds from zero year. */ static double exsltDateCastDateToNumber (const exsltDateValPtr dt) { double ret = 0.0; if (dt == NULL) return 0.0; if ((dt->type & XS_GYEAR) == XS_GYEAR) { ret = (double)_exsltDateCastYMToDays(dt) * SECS_PER_DAY; } /* add in days */ if (dt->type == XS_DURATION) { ret += (double)dt->value.dur.day * SECS_PER_DAY; ret += dt->value.dur.sec; } else { ret += (double)dt->value.date.day * SECS_PER_DAY; /* add in time */ ret += TIME_TO_NUMBER(dt); } return ret; } /** * _exsltDateTruncateDate: * @dt: an #exsltDateValPtr * @type: dateTime type to set to * * Set @dt to truncated @type. * * Returns 0 success, non-zero otherwise. */ static int _exsltDateTruncateDate (exsltDateValPtr dt, exsltDateType type) { if (dt == NULL) return 1; if ((type & XS_TIME) != XS_TIME) { dt->value.date.hour = 0; dt->value.date.min = 0; dt->value.date.sec = 0.0; } if ((type & XS_GDAY) != XS_GDAY) dt->value.date.day = 0; if ((type & XS_GMONTH) != XS_GMONTH) dt->value.date.mon = 0; if ((type & XS_GYEAR) != XS_GYEAR) dt->value.date.year = 0; dt->type = type; return 0; } /** * _exsltDayInWeek: * @yday: year day (1-366) * @yr: year * * Determine the day-in-week from @yday and @yr. 0001-01-01 was * a Monday so all other days are calculated from there. Take the * number of years since (or before) add the number of leap years and * the day-in-year and mod by 7. This is a function because negative * years must be handled a little differently and there is no zero year. * * Returns day in week (Sunday = 0). */ static long _exsltDateDayInWeek(long yday, long yr) { long ret; if (yr < 0) { ret = ((yr + (((yr+1)/4)-((yr+1)/100)+((yr+1)/400)) + yday) % 7); if (ret < 0) ret += 7; } else ret = (((yr-1) + (((yr-1)/4)-((yr-1)/100)+((yr-1)/400)) + yday) % 7); return ret; } /* * macros for adding date/times and durations */ #define FQUOTIENT(a,b) ((floor(((double)a/(double)b)))) #define MODULO(a,b) ((a - FQUOTIENT(a,b) * b)) #define FQUOTIENT_RANGE(a,low,high) (FQUOTIENT((a-low),(high-low))) #define MODULO_RANGE(a,low,high) ((MODULO((a-low),(high-low)))+low) /** * _exsltDateAdd: * @dt: an #exsltDateValPtr * @dur: an #exsltDateValPtr of type #XS_DURATION * * Compute a new date/time from @dt and @dur. This function assumes @dt * is either #XS_DATETIME, #XS_DATE, #XS_GYEARMONTH, or #XS_GYEAR. * * Returns date/time pointer or NULL. */ static exsltDateValPtr _exsltDateAdd (exsltDateValPtr dt, exsltDateValPtr dur) { exsltDateValPtr ret; long carry, tempdays, temp; exsltDateValDatePtr r, d; exsltDateValDurationPtr u; if ((dt == NULL) || (dur == NULL)) return NULL; ret = exsltDateCreateDate(dt->type); if (ret == NULL) return NULL; r = &(ret->value.date); d = &(dt->value.date); u = &(dur->value.dur); /* normalization */ if (d->mon == 0) d->mon = 1; /* normalize for time zone offset */ u->sec -= (d->tzo * 60); /* changed from + to - (bug 153000) */ d->tzo = 0; /* normalization */ if (d->day == 0) d->day = 1; /* month */ carry = d->mon + u->mon; r->mon = (unsigned int)MODULO_RANGE(carry, 1, 13); carry = (long)FQUOTIENT_RANGE(carry, 1, 13); /* year (may be modified later) */ r->year = d->year + carry; if (r->year == 0) { if (d->year > 0) r->year--; else r->year++; } /* time zone */ r->tzo = d->tzo; r->tz_flag = d->tz_flag; /* seconds */ r->sec = d->sec + u->sec; carry = (long)FQUOTIENT((long)r->sec, 60); if (r->sec != 0.0) { r->sec = MODULO(r->sec, 60.0); } /* minute */ carry += d->min; r->min = (unsigned int)MODULO(carry, 60); carry = (long)FQUOTIENT(carry, 60); /* hours */ carry += d->hour; r->hour = (unsigned int)MODULO(carry, 24); carry = (long)FQUOTIENT(carry, 24); /* * days * Note we use tempdays because the temporary values may need more * than 5 bits */ if ((VALID_YEAR(r->year)) && (VALID_MONTH(r->mon)) && (d->day > MAX_DAYINMONTH(r->year, r->mon))) tempdays = MAX_DAYINMONTH(r->year, r->mon); else if (d->day < 1) tempdays = 1; else tempdays = d->day; tempdays += u->day + carry; while (1) { if (tempdays < 1) { long tmon = (long)MODULO_RANGE((int)r->mon-1, 1, 13); long tyr = r->year + (long)FQUOTIENT_RANGE((int)r->mon-1, 1, 13); if (tyr == 0) tyr--; /* * Coverity detected an overrun in daysInMonth * of size 12 at position 12 with index variable "((r)->mon - 1)" */ if (tmon < 0) tmon = 0; if (tmon > 12) tmon = 12; tempdays += MAX_DAYINMONTH(tyr, tmon); carry = -1; } else if (tempdays > (long)MAX_DAYINMONTH(r->year, r->mon)) { tempdays = tempdays - MAX_DAYINMONTH(r->year, r->mon); carry = 1; } else break; temp = r->mon + carry; r->mon = (unsigned int)MODULO_RANGE(temp, 1, 13); r->year = r->year + (long)FQUOTIENT_RANGE(temp, 1, 13); if (r->year == 0) { if (temp < 1) r->year--; else r->year++; } } r->day = tempdays; /* * adjust the date/time type to the date values */ if (ret->type != XS_DATETIME) { if ((r->hour) || (r->min) || (r->sec)) ret->type = XS_DATETIME; else if (ret->type != XS_DATE) { if (r->day != 1) ret->type = XS_DATE; else if ((ret->type != XS_GYEARMONTH) && (r->mon != 1)) ret->type = XS_GYEARMONTH; } } return ret; } /** * exsltDateNormalize: * @dt: an #exsltDateValPtr * * Normalize @dt to GMT time. * */ static void exsltDateNormalize (exsltDateValPtr dt) { exsltDateValPtr dur, tmp; if (dt == NULL) return; if (((dt->type & XS_TIME) != XS_TIME) && (dt->value.date.tzo == 0)) return; dur = exsltDateCreateDate(XS_DURATION); if (dur == NULL) return; tmp = _exsltDateAdd(dt, dur); if (tmp == NULL) return; memcpy(dt, tmp, sizeof(exsltDateVal)); exsltDateFreeDate(tmp); exsltDateFreeDate(dur); dt->value.date.tzo = 0; } /** * _exsltDateDifference: * @x: an #exsltDateValPtr * @y: an #exsltDateValPtr * @flag: force difference in days * * Calculate the difference between @x and @y as a duration * (i.e. y - x). If the @flag is set then even if the least specific * format of @x or @y is xs:gYear or xs:gYearMonth. * * Returns date/time pointer or NULL. */ static exsltDateValPtr _exsltDateDifference (exsltDateValPtr x, exsltDateValPtr y, int flag) { exsltDateValPtr ret; if ((x == NULL) || (y == NULL)) return NULL; if (((x->type < XS_GYEAR) || (x->type > XS_DATETIME)) || ((y->type < XS_GYEAR) || (y->type > XS_DATETIME))) return NULL; exsltDateNormalize(x); exsltDateNormalize(y); /* * the operand with the most specific format must be converted to * the same type as the operand with the least specific format. */ if (x->type != y->type) { if (x->type < y->type) { _exsltDateTruncateDate(y, x->type); } else { _exsltDateTruncateDate(x, y->type); } } ret = exsltDateCreateDate(XS_DURATION); if (ret == NULL) return NULL; if (((x->type == XS_GYEAR) || (x->type == XS_GYEARMONTH)) && (!flag)) { /* compute the difference in months */ ret->value.dur.mon = ((y->value.date.year * 12) + y->value.date.mon) - ((x->value.date.year * 12) + x->value.date.mon); /* The above will give a wrong result if x and y are on different sides of the September 1752. Resolution is welcome :-) */ } else { ret->value.dur.day = _exsltDateCastYMToDays(y) - _exsltDateCastYMToDays(x); ret->value.dur.day += y->value.date.day - x->value.date.day; ret->value.dur.sec = TIME_TO_NUMBER(y) - TIME_TO_NUMBER(x); if (ret->value.dur.day > 0.0 && ret->value.dur.sec < 0.0) { ret->value.dur.day -= 1; ret->value.dur.sec = ret->value.dur.sec + SECS_PER_DAY; } else if (ret->value.dur.day < 0.0 && ret->value.dur.sec > 0.0) { ret->value.dur.day += 1; ret->value.dur.sec = ret->value.dur.sec - SECS_PER_DAY; } } return ret; } /** * _exsltDateAddDurCalc * @ret: an exsltDateValPtr for the return value: * @x: an exsltDateValPtr for the first operand * @y: an exsltDateValPtr for the second operand * * Add two durations, catering for possible negative values. * The sum is placed in @ret. * * Returns 1 for success, 0 if error detected. */ static int _exsltDateAddDurCalc (exsltDateValPtr ret, exsltDateValPtr x, exsltDateValPtr y) { long carry; /* months */ ret->value.dur.mon = x->value.dur.mon + y->value.dur.mon; /* seconds */ ret->value.dur.sec = x->value.dur.sec + y->value.dur.sec; carry = (long)FQUOTIENT(ret->value.dur.sec, SECS_PER_DAY); if (ret->value.dur.sec != 0.0) { ret->value.dur.sec = MODULO(ret->value.dur.sec, SECS_PER_DAY); /* * Our function MODULO always gives us a positive value, so * if we end up with a "-ve" carry we need to adjust it * appropriately (bug 154021) */ if ((carry < 0) && (ret->value.dur.sec != 0)) { /* change seconds to equiv negative modulus */ ret->value.dur.sec = ret->value.dur.sec - SECS_PER_DAY; carry++; } } /* days */ ret->value.dur.day = x->value.dur.day + y->value.dur.day + carry; /* * are the results indeterminate? i.e. how do you subtract days from * months or years? */ if ((((ret->value.dur.day > 0) || (ret->value.dur.sec > 0)) && (ret->value.dur.mon < 0)) || (((ret->value.dur.day < 0) || (ret->value.dur.sec < 0)) && (ret->value.dur.mon > 0))) { return 0; } return 1; } /** * _exsltDateAddDuration: * @x: an #exsltDateValPtr of type #XS_DURATION * @y: an #exsltDateValPtr of type #XS_DURATION * * Compute a new duration from @x and @y. * * Returns date/time pointer or NULL. */ static exsltDateValPtr _exsltDateAddDuration (exsltDateValPtr x, exsltDateValPtr y) { exsltDateValPtr ret; if ((x == NULL) || (y == NULL)) return NULL; ret = exsltDateCreateDate(XS_DURATION); if (ret == NULL) return NULL; if (_exsltDateAddDurCalc(ret, x, y)) return ret; exsltDateFreeDate(ret); return NULL; } /**************************************************************** * * * EXSLT - Dates and Times functions * * * ****************************************************************/ /** * exsltDateDateTime: * * Implements the EXSLT - Dates and Times date-time() function: * string date:date-time() * * Returns the current date and time as a date/time string. */ static xmlChar * exsltDateDateTime (void) { xmlChar *ret = NULL; #ifdef WITH_TIME exsltDateValPtr cur; cur = exsltDateCurrent(); if (cur != NULL) { ret = exsltDateFormatDateTime(&(cur->value.date)); exsltDateFreeDate(cur); } #endif return ret; } /** * exsltDateDate: * @dateTime: a date/time string * * Implements the EXSLT - Dates and Times date() function: * string date:date (string?) * * Returns the date specified in the date/time string given as the * argument. If no argument is given, then the current local * date/time, as returned by date:date-time is used as a default * argument. * The date/time string specified as an argument must be a string in * the format defined as the lexical representation of either * xs:dateTime or xs:date. If the argument is not in either of these * formats, returns NULL. */ static xmlChar * exsltDateDate (const xmlChar *dateTime) { exsltDateValPtr dt = NULL; xmlChar *ret = NULL; if (dateTime == NULL) { #ifdef WITH_TIME dt = exsltDateCurrent(); if (dt == NULL) #endif return NULL; } else { dt = exsltDateParse(dateTime); if (dt == NULL) return NULL; if ((dt->type != XS_DATETIME) && (dt->type != XS_DATE)) { exsltDateFreeDate(dt); return NULL; } } ret = exsltDateFormatDate(&(dt->value.date)); exsltDateFreeDate(dt); return ret; } /** * exsltDateTime: * @dateTime: a date/time string * * Implements the EXSLT - Dates and Times time() function: * string date:time (string?) * * Returns the time specified in the date/time string given as the * argument. If no argument is given, then the current local * date/time, as returned by date:date-time is used as a default * argument. * The date/time string specified as an argument must be a string in * the format defined as the lexical representation of either * xs:dateTime or xs:time. If the argument is not in either of these * formats, returns NULL. */ static xmlChar * exsltDateTime (const xmlChar *dateTime) { exsltDateValPtr dt = NULL; xmlChar *ret = NULL; if (dateTime == NULL) { #ifdef WITH_TIME dt = exsltDateCurrent(); if (dt == NULL) #endif return NULL; } else { dt = exsltDateParse(dateTime); if (dt == NULL) return NULL; if ((dt->type != XS_DATETIME) && (dt->type != XS_TIME)) { exsltDateFreeDate(dt); return NULL; } } ret = exsltDateFormatTime(&(dt->value.date)); exsltDateFreeDate(dt); return ret; } /** * exsltDateYear: * @dateTime: a date/time string * * Implements the EXSLT - Dates and Times year() function * number date:year (string?) * Returns the year of a date as a number. If no argument is given, * then the current local date/time, as returned by date:date-time is * used as a default argument. * The date/time string specified as the first argument must be a * right-truncated string in the format defined as the lexical * representation of xs:dateTime in one of the formats defined in [XML * Schema Part 2: Datatypes]. The permitted formats are as follows: * - xs:dateTime (CCYY-MM-DDThh:mm:ss) * - xs:date (CCYY-MM-DD) * - xs:gYearMonth (CCYY-MM) * - xs:gYear (CCYY) * If the date/time string is not in one of these formats, then NaN is * returned. */ static double exsltDateYear (const xmlChar *dateTime) { exsltDateValPtr dt; double ret; if (dateTime == NULL) { #ifdef WITH_TIME dt = exsltDateCurrent(); if (dt == NULL) #endif return xmlXPathNAN; } else { dt = exsltDateParse(dateTime); if (dt == NULL) return xmlXPathNAN; if ((dt->type != XS_DATETIME) && (dt->type != XS_DATE) && (dt->type != XS_GYEARMONTH) && (dt->type != XS_GYEAR)) { exsltDateFreeDate(dt); return xmlXPathNAN; } } ret = (double) dt->value.date.year; exsltDateFreeDate(dt); return ret; } /** * exsltDateLeapYear: * @dateTime: a date/time string * * Implements the EXSLT - Dates and Times leap-year() function: * boolean date:leap-yea (string?) * Returns true if the year given in a date is a leap year. If no * argument is given, then the current local date/time, as returned by * date:date-time is used as a default argument. * The date/time string specified as the first argument must be a * right-truncated string in the format defined as the lexical * representation of xs:dateTime in one of the formats defined in [XML * Schema Part 2: Datatypes]. The permitted formats are as follows: * - xs:dateTime (CCYY-MM-DDThh:mm:ss) * - xs:date (CCYY-MM-DD) * - xs:gYearMonth (CCYY-MM) * - xs:gYear (CCYY) * If the date/time string is not in one of these formats, then NaN is * returned. */ static xmlXPathObjectPtr exsltDateLeapYear (const xmlChar *dateTime) { double year; year = exsltDateYear(dateTime); if (xmlXPathIsNaN(year)) return xmlXPathNewFloat(xmlXPathNAN); if (IS_LEAP((long)year)) return xmlXPathNewBoolean(1); return xmlXPathNewBoolean(0); } /** * exsltDateMonthInYear: * @dateTime: a date/time string * * Implements the EXSLT - Dates and Times month-in-year() function: * number date:month-in-year (string?) * Returns the month of a date as a number. If no argument is given, * then the current local date/time, as returned by date:date-time is * used the default argument. * The date/time string specified as the argument is a left or * right-truncated string in the format defined as the lexical * representation of xs:dateTime in one of the formats defined in [XML * Schema Part 2: Datatypes]. The permitted formats are as follows: * - xs:dateTime (CCYY-MM-DDThh:mm:ss) * - xs:date (CCYY-MM-DD) * - xs:gYearMonth (CCYY-MM) * - xs:gMonth (--MM--) * - xs:gMonthDay (--MM-DD) * If the date/time string is not in one of these formats, then NaN is * returned. */ static double exsltDateMonthInYear (const xmlChar *dateTime) { exsltDateValPtr dt; double ret; if (dateTime == NULL) { #ifdef WITH_TIME dt = exsltDateCurrent(); if (dt == NULL) #endif return xmlXPathNAN; } else { dt = exsltDateParse(dateTime); if (dt == NULL) return xmlXPathNAN; if ((dt->type != XS_DATETIME) && (dt->type != XS_DATE) && (dt->type != XS_GYEARMONTH) && (dt->type != XS_GMONTH) && (dt->type != XS_GMONTHDAY)) { exsltDateFreeDate(dt); return xmlXPathNAN; } } ret = (double) dt->value.date.mon; exsltDateFreeDate(dt); return ret; } /** * exsltDateMonthName: * @dateTime: a date/time string * * Implements the EXSLT - Dates and Time month-name() function * string date:month-name (string?) * Returns the full name of the month of a date. If no argument is * given, then the current local date/time, as returned by * date:date-time is used the default argument. * The date/time string specified as the argument is a left or * right-truncated string in the format defined as the lexical * representation of xs:dateTime in one of the formats defined in [XML * Schema Part 2: Datatypes]. The permitted formats are as follows: * - xs:dateTime (CCYY-MM-DDThh:mm:ss) * - xs:date (CCYY-MM-DD) * - xs:gYearMonth (CCYY-MM) * - xs:gMonth (--MM--) * If the date/time string is not in one of these formats, then an * empty string ('') is returned. * The result is an English month name: one of 'January', 'February', * 'March', 'April', 'May', 'June', 'July', 'August', 'September', * 'October', 'November' or 'December'. */ static const xmlChar * exsltDateMonthName (const xmlChar *dateTime) { static const xmlChar monthNames[13][10] = { { 0 }, { 'J', 'a', 'n', 'u', 'a', 'r', 'y', 0 }, { 'F', 'e', 'b', 'r', 'u', 'a', 'r', 'y', 0 }, { 'M', 'a', 'r', 'c', 'h', 0 }, { 'A', 'p', 'r', 'i', 'l', 0 }, { 'M', 'a', 'y', 0 }, { 'J', 'u', 'n', 'e', 0 }, { 'J', 'u', 'l', 'y', 0 }, { 'A', 'u', 'g', 'u', 's', 't', 0 }, { 'S', 'e', 'p', 't', 'e', 'm', 'b', 'e', 'r', 0 }, { 'O', 'c', 't', 'o', 'b', 'e', 'r', 0 }, { 'N', 'o', 'v', 'e', 'm', 'b', 'e', 'r', 0 }, { 'D', 'e', 'c', 'e', 'm', 'b', 'e', 'r', 0 } }; int month; month = (int) exsltDateMonthInYear(dateTime); if (!VALID_MONTH(month)) month = 0; return monthNames[month]; } /** * exsltDateMonthAbbreviation: * @dateTime: a date/time string * * Implements the EXSLT - Dates and Time month-abbreviation() function * string date:month-abbreviation (string?) * Returns the abbreviation of the month of a date. If no argument is * given, then the current local date/time, as returned by * date:date-time is used the default argument. * The date/time string specified as the argument is a left or * right-truncated string in the format defined as the lexical * representation of xs:dateTime in one of the formats defined in [XML * Schema Part 2: Datatypes]. The permitted formats are as follows: * - xs:dateTime (CCYY-MM-DDThh:mm:ss) * - xs:date (CCYY-MM-DD) * - xs:gYearMonth (CCYY-MM) * - xs:gMonth (--MM--) * If the date/time string is not in one of these formats, then an * empty string ('') is returned. * The result is an English month abbreviation: one of 'Jan', 'Feb', * 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov' or * 'Dec'. */ static const xmlChar * exsltDateMonthAbbreviation (const xmlChar *dateTime) { static const xmlChar monthAbbreviations[13][4] = { { 0 }, { 'J', 'a', 'n', 0 }, { 'F', 'e', 'b', 0 }, { 'M', 'a', 'r', 0 }, { 'A', 'p', 'r', 0 }, { 'M', 'a', 'y', 0 }, { 'J', 'u', 'n', 0 }, { 'J', 'u', 'l', 0 }, { 'A', 'u', 'g', 0 }, { 'S', 'e', 'p', 0 }, { 'O', 'c', 't', 0 }, { 'N', 'o', 'v', 0 }, { 'D', 'e', 'c', 0 } }; int month; month = (int) exsltDateMonthInYear(dateTime); if(!VALID_MONTH(month)) month = 0; return monthAbbreviations[month]; } /** * exsltDateWeekInYear: * @dateTime: a date/time string * * Implements the EXSLT - Dates and Times week-in-year() function * number date:week-in-year (string?) * Returns the week of the year as a number. If no argument is given, * then the current local date/time, as returned by date:date-time is * used as the default argument. For the purposes of numbering, * counting follows ISO 8601: week 1 in a year is the week containing * the first Thursday of the year, with new weeks beginning on a * Monday. * The date/time string specified as the argument is a right-truncated * string in the format defined as the lexical representation of * xs:dateTime in one of the formats defined in [XML Schema Part 2: * Datatypes]. The permitted formats are as follows: * - xs:dateTime (CCYY-MM-DDThh:mm:ss) * - xs:date (CCYY-MM-DD) * If the date/time string is not in one of these formats, then NaN is * returned. */ static double exsltDateWeekInYear (const xmlChar *dateTime) { exsltDateValPtr dt; long diy, diw, year, ret; if (dateTime == NULL) { #ifdef WITH_TIME dt = exsltDateCurrent(); if (dt == NULL) #endif return xmlXPathNAN; } else { dt = exsltDateParse(dateTime); if (dt == NULL) return xmlXPathNAN; if ((dt->type != XS_DATETIME) && (dt->type != XS_DATE)) { exsltDateFreeDate(dt); return xmlXPathNAN; } } diy = DAY_IN_YEAR(dt->value.date.day, dt->value.date.mon, dt->value.date.year); /* * Determine day-in-week (0=Sun, 1=Mon, etc.) then adjust so Monday * is the first day-in-week */ diw = (_exsltDateDayInWeek(diy, dt->value.date.year) + 6) % 7; /* ISO 8601 adjustment, 3 is Thu */ diy += (3 - diw); if(diy < 1) { year = dt->value.date.year - 1; if(year == 0) year--; diy = DAY_IN_YEAR(31, 12, year) + diy; } else if (diy > (long)DAY_IN_YEAR(31, 12, dt->value.date.year)) { diy -= DAY_IN_YEAR(31, 12, dt->value.date.year); } ret = ((diy - 1) / 7) + 1; exsltDateFreeDate(dt); return (double) ret; } /** * exsltDateWeekInMonth: * @dateTime: a date/time string * * Implements the EXSLT - Dates and Times week-in-month() function * number date:week-in-month (string?) * The date:week-in-month function returns the week in a month of a * date as a number. If no argument is given, then the current local * date/time, as returned by date:date-time is used the default * argument. For the purposes of numbering, the first day of the month * is in week 1 and new weeks begin on a Monday (so the first and last * weeks in a month will often have less than 7 days in them). * The date/time string specified as the argument is a right-truncated * string in the format defined as the lexical representation of * xs:dateTime in one of the formats defined in [XML Schema Part 2: * Datatypes]. The permitted formats are as follows: * - xs:dateTime (CCYY-MM-DDThh:mm:ss) * - xs:date (CCYY-MM-DD) * If the date/time string is not in one of these formats, then NaN is * returned. */ static double exsltDateWeekInMonth (const xmlChar *dateTime) { exsltDateValPtr dt; long fdiy, fdiw, ret; if (dateTime == NULL) { #ifdef WITH_TIME dt = exsltDateCurrent(); if (dt == NULL) #endif return xmlXPathNAN; } else { dt = exsltDateParse(dateTime); if (dt == NULL) return xmlXPathNAN; if ((dt->type != XS_DATETIME) && (dt->type != XS_DATE)) { exsltDateFreeDate(dt); return xmlXPathNAN; } } fdiy = DAY_IN_YEAR(1, dt->value.date.mon, dt->value.date.year); /* * Determine day-in-week (0=Sun, 1=Mon, etc.) then adjust so Monday * is the first day-in-week */ fdiw = (_exsltDateDayInWeek(fdiy, dt->value.date.year) + 6) % 7; ret = ((dt->value.date.day + fdiw - 1) / 7) + 1; exsltDateFreeDate(dt); return (double) ret; } /** * exsltDateDayInYear: * @dateTime: a date/time string * * Implements the EXSLT - Dates and Times day-in-year() function * number date:day-in-year (string?) * Returns the day of a date in a year as a number. If no argument is * given, then the current local date/time, as returned by * date:date-time is used the default argument. * The date/time string specified as the argument is a right-truncated * string in the format defined as the lexical representation of * xs:dateTime in one of the formats defined in [XML Schema Part 2: * Datatypes]. The permitted formats are as follows: * - xs:dateTime (CCYY-MM-DDThh:mm:ss) * - xs:date (CCYY-MM-DD) * If the date/time string is not in one of these formats, then NaN is * returned. */ static double exsltDateDayInYear (const xmlChar *dateTime) { exsltDateValPtr dt; long ret; if (dateTime == NULL) { #ifdef WITH_TIME dt = exsltDateCurrent(); if (dt == NULL) #endif return xmlXPathNAN; } else { dt = exsltDateParse(dateTime); if (dt == NULL) return xmlXPathNAN; if ((dt->type != XS_DATETIME) && (dt->type != XS_DATE)) { exsltDateFreeDate(dt); return xmlXPathNAN; } } ret = DAY_IN_YEAR(dt->value.date.day, dt->value.date.mon, dt->value.date.year); exsltDateFreeDate(dt); return (double) ret; } /** * exsltDateDayInMonth: * @dateTime: a date/time string * * Implements the EXSLT - Dates and Times day-in-month() function: * number date:day-in-month (string?) * Returns the day of a date as a number. If no argument is given, * then the current local date/time, as returned by date:date-time is * used the default argument. * The date/time string specified as the argument is a left or * right-truncated string in the format defined as the lexical * representation of xs:dateTime in one of the formats defined in [XML * Schema Part 2: Datatypes]. The permitted formats are as follows: * - xs:dateTime (CCYY-MM-DDThh:mm:ss) * - xs:date (CCYY-MM-DD) * - xs:gMonthDay (--MM-DD) * - xs:gDay (---DD) * If the date/time string is not in one of these formats, then NaN is * returned. */ static double exsltDateDayInMonth (const xmlChar *dateTime) { exsltDateValPtr dt; double ret; if (dateTime == NULL) { #ifdef WITH_TIME dt = exsltDateCurrent(); if (dt == NULL) #endif return xmlXPathNAN; } else { dt = exsltDateParse(dateTime); if (dt == NULL) return xmlXPathNAN; if ((dt->type != XS_DATETIME) && (dt->type != XS_DATE) && (dt->type != XS_GMONTHDAY) && (dt->type != XS_GDAY)) { exsltDateFreeDate(dt); return xmlXPathNAN; } } ret = (double) dt->value.date.day; exsltDateFreeDate(dt); return ret; } /** * exsltDateDayOfWeekInMonth: * @dateTime: a date/time string * * Implements the EXSLT - Dates and Times day-of-week-in-month() function: * number date:day-of-week-in-month (string?) * Returns the day-of-the-week in a month of a date as a number * (e.g. 3 for the 3rd Tuesday in May). If no argument is * given, then the current local date/time, as returned by * date:date-time is used the default argument. * The date/time string specified as the argument is a right-truncated * string in the format defined as the lexical representation of * xs:dateTime in one of the formats defined in [XML Schema Part 2: * Datatypes]. The permitted formats are as follows: * - xs:dateTime (CCYY-MM-DDThh:mm:ss) * - xs:date (CCYY-MM-DD) * If the date/time string is not in one of these formats, then NaN is * returned. */ static double exsltDateDayOfWeekInMonth (const xmlChar *dateTime) { exsltDateValPtr dt; long ret; if (dateTime == NULL) { #ifdef WITH_TIME dt = exsltDateCurrent(); if (dt == NULL) #endif return xmlXPathNAN; } else { dt = exsltDateParse(dateTime); if (dt == NULL) return xmlXPathNAN; if ((dt->type != XS_DATETIME) && (dt->type != XS_DATE)) { exsltDateFreeDate(dt); return xmlXPathNAN; } } ret = ((dt->value.date.day -1) / 7) + 1; exsltDateFreeDate(dt); return (double) ret; } /** * exsltDateDayInWeek: * @dateTime: a date/time string * * Implements the EXSLT - Dates and Times day-in-week() function: * number date:day-in-week (string?) * Returns the day of the week given in a date as a number. If no * argument is given, then the current local date/time, as returned by * date:date-time is used the default argument. * The date/time string specified as the argument is a left or * right-truncated string in the format defined as the lexical * representation of xs:dateTime in one of the formats defined in [XML * Schema Part 2: Datatypes]. The permitted formats are as follows: * - xs:dateTime (CCYY-MM-DDThh:mm:ss) * - xs:date (CCYY-MM-DD) * If the date/time string is not in one of these formats, then NaN is * returned. * The numbering of days of the week starts at 1 for Sunday, 2 for * Monday and so on up to 7 for Saturday. */ static double exsltDateDayInWeek (const xmlChar *dateTime) { exsltDateValPtr dt; long diy, ret; if (dateTime == NULL) { #ifdef WITH_TIME dt = exsltDateCurrent(); if (dt == NULL) #endif return xmlXPathNAN; } else { dt = exsltDateParse(dateTime); if (dt == NULL) return xmlXPathNAN; if ((dt->type != XS_DATETIME) && (dt->type != XS_DATE)) { exsltDateFreeDate(dt); return xmlXPathNAN; } } diy = DAY_IN_YEAR(dt->value.date.day, dt->value.date.mon, dt->value.date.year); ret = _exsltDateDayInWeek(diy, dt->value.date.year) + 1; exsltDateFreeDate(dt); return (double) ret; } /** * exsltDateDayName: * @dateTime: a date/time string * * Implements the EXSLT - Dates and Time day-name() function * string date:day-name (string?) * Returns the full name of the day of the week of a date. If no * argument is given, then the current local date/time, as returned by * date:date-time is used the default argument. * The date/time string specified as the argument is a left or * right-truncated string in the format defined as the lexical * representation of xs:dateTime in one of the formats defined in [XML * Schema Part 2: Datatypes]. The permitted formats are as follows: * - xs:dateTime (CCYY-MM-DDThh:mm:ss) * - xs:date (CCYY-MM-DD) * If the date/time string is not in one of these formats, then an * empty string ('') is returned. * The result is an English day name: one of 'Sunday', 'Monday', * 'Tuesday', 'Wednesday', 'Thursday' or 'Friday'. */ static const xmlChar * exsltDateDayName (const xmlChar *dateTime) { static const xmlChar dayNames[8][10] = { { 0 }, { 'S', 'u', 'n', 'd', 'a', 'y', 0 }, { 'M', 'o', 'n', 'd', 'a', 'y', 0 }, { 'T', 'u', 'e', 's', 'd', 'a', 'y', 0 }, { 'W', 'e', 'd', 'n', 'e', 's', 'd', 'a', 'y', 0 }, { 'T', 'h', 'u', 'r', 's', 'd', 'a', 'y', 0 }, { 'F', 'r', 'i', 'd', 'a', 'y', 0 }, { 'S', 'a', 't', 'u', 'r', 'd', 'a', 'y', 0 } }; int day; day = (int) exsltDateDayInWeek(dateTime); if((day < 1) || (day > 7)) day = 0; return dayNames[day]; } /** * exsltDateDayAbbreviation: * @dateTime: a date/time string * * Implements the EXSLT - Dates and Time day-abbreviation() function * string date:day-abbreviation (string?) * Returns the abbreviation of the day of the week of a date. If no * argument is given, then the current local date/time, as returned by * date:date-time is used the default argument. * The date/time string specified as the argument is a left or * right-truncated string in the format defined as the lexical * representation of xs:dateTime in one of the formats defined in [XML * Schema Part 2: Datatypes]. The permitted formats are as follows: * - xs:dateTime (CCYY-MM-DDThh:mm:ss) * - xs:date (CCYY-MM-DD) * If the date/time string is not in one of these formats, then an * empty string ('') is returned. * The result is a three-letter English day abbreviation: one of * 'Sun', 'Mon', 'Tue', 'Wed', 'Thu' or 'Fri'. */ static const xmlChar * exsltDateDayAbbreviation (const xmlChar *dateTime) { static const xmlChar dayAbbreviations[8][4] = { { 0 }, { 'S', 'u', 'n', 0 }, { 'M', 'o', 'n', 0 }, { 'T', 'u', 'e', 0 }, { 'W', 'e', 'd', 0 }, { 'T', 'h', 'u', 0 }, { 'F', 'r', 'i', 0 }, { 'S', 'a', 't', 0 } }; int day; day = (int) exsltDateDayInWeek(dateTime); if((day < 1) || (day > 7)) day = 0; return dayAbbreviations[day]; } /** * exsltDateHourInDay: * @dateTime: a date/time string * * Implements the EXSLT - Dates and Times day-in-month() function: * number date:day-in-month (string?) * Returns the hour of the day as a number. If no argument is given, * then the current local date/time, as returned by date:date-time is * used the default argument. * The date/time string specified as the argument is a left or * right-truncated string in the format defined as the lexical * representation of xs:dateTime in one of the formats defined in [XML * Schema Part 2: Datatypes]. The permitted formats are as follows: * - xs:dateTime (CCYY-MM-DDThh:mm:ss) * - xs:time (hh:mm:ss) * If the date/time string is not in one of these formats, then NaN is * returned. */ static double exsltDateHourInDay (const xmlChar *dateTime) { exsltDateValPtr dt; double ret; if (dateTime == NULL) { #ifdef WITH_TIME dt = exsltDateCurrent(); if (dt == NULL) #endif return xmlXPathNAN; } else { dt = exsltDateParse(dateTime); if (dt == NULL) return xmlXPathNAN; if ((dt->type != XS_DATETIME) && (dt->type != XS_TIME)) { exsltDateFreeDate(dt); return xmlXPathNAN; } } ret = (double) dt->value.date.hour; exsltDateFreeDate(dt); return ret; } /** * exsltDateMinuteInHour: * @dateTime: a date/time string * * Implements the EXSLT - Dates and Times day-in-month() function: * number date:day-in-month (string?) * Returns the minute of the hour as a number. If no argument is * given, then the current local date/time, as returned by * date:date-time is used the default argument. * The date/time string specified as the argument is a left or * right-truncated string in the format defined as the lexical * representation of xs:dateTime in one of the formats defined in [XML * Schema Part 2: Datatypes]. The permitted formats are as follows: * - xs:dateTime (CCYY-MM-DDThh:mm:ss) * - xs:time (hh:mm:ss) * If the date/time string is not in one of these formats, then NaN is * returned. */ static double exsltDateMinuteInHour (const xmlChar *dateTime) { exsltDateValPtr dt; double ret; if (dateTime == NULL) { #ifdef WITH_TIME dt = exsltDateCurrent(); if (dt == NULL) #endif return xmlXPathNAN; } else { dt = exsltDateParse(dateTime); if (dt == NULL) return xmlXPathNAN; if ((dt->type != XS_DATETIME) && (dt->type != XS_TIME)) { exsltDateFreeDate(dt); return xmlXPathNAN; } } ret = (double) dt->value.date.min; exsltDateFreeDate(dt); return ret; } /** * exsltDateSecondInMinute: * @dateTime: a date/time string * * Implements the EXSLT - Dates and Times second-in-minute() function: * number date:day-in-month (string?) * Returns the second of the minute as a number. If no argument is * given, then the current local date/time, as returned by * date:date-time is used the default argument. * The date/time string specified as the argument is a left or * right-truncated string in the format defined as the lexical * representation of xs:dateTime in one of the formats defined in [XML * Schema Part 2: Datatypes]. The permitted formats are as follows: * - xs:dateTime (CCYY-MM-DDThh:mm:ss) * - xs:time (hh:mm:ss) * If the date/time string is not in one of these formats, then NaN is * returned. * * Returns the second or NaN. */ static double exsltDateSecondInMinute (const xmlChar *dateTime) { exsltDateValPtr dt; double ret; if (dateTime == NULL) { #ifdef WITH_TIME dt = exsltDateCurrent(); if (dt == NULL) #endif return xmlXPathNAN; } else { dt = exsltDateParse(dateTime); if (dt == NULL) return xmlXPathNAN; if ((dt->type != XS_DATETIME) && (dt->type != XS_TIME)) { exsltDateFreeDate(dt); return xmlXPathNAN; } } ret = dt->value.date.sec; exsltDateFreeDate(dt); return ret; } /** * exsltDateAdd: * @xstr: date/time string * @ystr: date/time string * * Implements the date:add (string,string) function which returns the * date/time * resulting from adding a duration to a date/time. * The first argument (@xstr) must be right-truncated date/time * strings in one of the formats defined in [XML Schema Part 2: * Datatypes]. The permitted formats are as follows: * - xs:dateTime (CCYY-MM-DDThh:mm:ss) * - xs:date (CCYY-MM-DD) * - xs:gYearMonth (CCYY-MM) * - xs:gYear (CCYY) * The second argument (@ystr) is a string in the format defined for * xs:duration in [3.2.6 duration] of [XML Schema Part 2: Datatypes]. * The return value is a right-truncated date/time strings in one of * the formats defined in [XML Schema Part 2: Datatypes] and listed * above. This value is calculated using the algorithm described in * [Appendix E Adding durations to dateTimes] of [XML Schema Part 2: * Datatypes]. * Returns date/time string or NULL. */ static xmlChar * exsltDateAdd (const xmlChar *xstr, const xmlChar *ystr) { exsltDateValPtr dt, dur, res; xmlChar *ret; if ((xstr == NULL) || (ystr == NULL)) return NULL; dt = exsltDateParse(xstr); if (dt == NULL) return NULL; else if ((dt->type < XS_GYEAR) || (dt->type > XS_DATETIME)) { exsltDateFreeDate(dt); return NULL; } dur = exsltDateParseDuration(ystr); if (dur == NULL) { exsltDateFreeDate(dt); return NULL; } res = _exsltDateAdd(dt, dur); exsltDateFreeDate(dt); exsltDateFreeDate(dur); if (res == NULL) return NULL; ret = exsltDateFormat(res); exsltDateFreeDate(res); return ret; } /** * exsltDateAddDuration: * @xstr: first duration string * @ystr: second duration string * * Implements the date:add-duration (string,string) function which returns * the duration resulting from adding two durations together. * Both arguments are strings in the format defined for xs:duration * in [3.2.6 duration] of [XML Schema Part 2: Datatypes]. If either * argument is not in this format, the function returns an empty string * (''). * The return value is a string in the format defined for xs:duration * in [3.2.6 duration] of [XML Schema Part 2: Datatypes]. * The durations can usually be added by summing the numbers given for * each of the components in the durations. However, if the durations * are differently signed, then this sometimes results in durations * that are impossible to express in this syntax (e.g. 'P1M' + '-P1D'). * In these cases, the function returns an empty string (''). * * Returns duration string or NULL. */ static xmlChar * exsltDateAddDuration (const xmlChar *xstr, const xmlChar *ystr) { exsltDateValPtr x, y, res; xmlChar *ret; if ((xstr == NULL) || (ystr == NULL)) return NULL; x = exsltDateParseDuration(xstr); if (x == NULL) return NULL; y = exsltDateParseDuration(ystr); if (y == NULL) { exsltDateFreeDate(x); return NULL; } res = _exsltDateAddDuration(x, y); exsltDateFreeDate(x); exsltDateFreeDate(y); if (res == NULL) return NULL; ret = exsltDateFormatDuration(&(res->value.dur)); exsltDateFreeDate(res); return ret; } /** * exsltDateSumFunction: * @ns: a node set of duration strings * * The date:sum function adds a set of durations together. * The string values of the nodes in the node set passed as an argument * are interpreted as durations and added together as if using the * date:add-duration function. (from exslt.org) * * The return value is a string in the format defined for xs:duration * in [3.2.6 duration] of [XML Schema Part 2: Datatypes]. * The durations can usually be added by summing the numbers given for * each of the components in the durations. However, if the durations * are differently signed, then this sometimes results in durations * that are impossible to express in this syntax (e.g. 'P1M' + '-P1D'). * In these cases, the function returns an empty string (''). * * Returns duration string or NULL. */ static void exsltDateSumFunction (xmlXPathParserContextPtr ctxt, int nargs) { xmlNodeSetPtr ns; void *user = NULL; xmlChar *tmp; exsltDateValPtr x, total; xmlChar *ret; int i; if (nargs != 1) { xmlXPathSetArityError (ctxt); return; } /* We need to delay the freeing of value->user */ if ((ctxt->value != NULL) && ctxt->value->boolval != 0) { user = ctxt->value->user; ctxt->value->boolval = 0; ctxt->value->user = NULL; } ns = xmlXPathPopNodeSet (ctxt); if (xmlXPathCheckError (ctxt)) return; if ((ns == NULL) || (ns->nodeNr == 0)) { xmlXPathReturnEmptyString (ctxt); if (ns != NULL) xmlXPathFreeNodeSet (ns); return; } total = exsltDateCreateDate (XS_DURATION); if (total == NULL) { xmlXPathFreeNodeSet (ns); return; } for (i = 0; i < ns->nodeNr; i++) { int result; tmp = xmlXPathCastNodeToString (ns->nodeTab[i]); if (tmp == NULL) { xmlXPathFreeNodeSet (ns); exsltDateFreeDate (total); return; } x = exsltDateParseDuration (tmp); if (x == NULL) { xmlFree (tmp); exsltDateFreeDate (total); xmlXPathFreeNodeSet (ns); xmlXPathReturnEmptyString (ctxt); return; } result = _exsltDateAddDurCalc(total, total, x); exsltDateFreeDate (x); xmlFree (tmp); if (!result) { exsltDateFreeDate (total); xmlXPathFreeNodeSet (ns); xmlXPathReturnEmptyString (ctxt); return; } } ret = exsltDateFormatDuration (&(total->value.dur)); exsltDateFreeDate (total); xmlXPathFreeNodeSet (ns); if (user != NULL) xmlFreeNodeList ((xmlNodePtr) user); if (ret == NULL) xmlXPathReturnEmptyString (ctxt); else xmlXPathReturnString (ctxt, ret); } /** * exsltDateSeconds: * @dateTime: a date/time string * * Implements the EXSLT - Dates and Times seconds() function: * number date:seconds(string?) * The date:seconds function returns the number of seconds specified * by the argument string. If no argument is given, then the current * local date/time, as returned by exsltDateCurrent() is used as the * default argument. If the date/time string is a xs:duration, then the * years and months must be zero (or not present). Parsing a duration * converts the fields to seconds. If the date/time string is not a * duration (and not null), then the legal formats are: * - xs:dateTime (CCYY-MM-DDThh:mm:ss) * - xs:date (CCYY-MM-DD) * - xs:gYearMonth (CCYY-MM) * - xs:gYear (CCYY) * In these cases the difference between the @dateTime and * 1970-01-01T00:00:00Z is calculated and converted to seconds. * * Note that there was some confusion over whether "difference" meant * that a dateTime of 1970-01-01T00:00:01Z should be a positive one or * a negative one. After correspondence with exslt.org, it was determined * that the intent of the specification was to have it positive. The * coding was modified in July 2003 to reflect this. * * Returns seconds or Nan. */ static double exsltDateSeconds (const xmlChar *dateTime) { exsltDateValPtr dt; double ret = xmlXPathNAN; if (dateTime == NULL) { #ifdef WITH_TIME dt = exsltDateCurrent(); if (dt == NULL) #endif return xmlXPathNAN; } else { dt = exsltDateParseDuration(dateTime); if (dt == NULL) dt = exsltDateParse(dateTime); } if (dt == NULL) return xmlXPathNAN; if ((dt->type <= XS_DATETIME) && (dt->type >= XS_GYEAR)) { exsltDateValPtr y, dur; /* * compute the difference between the given (or current) date * and epoch date */ y = exsltDateCreateDate(XS_DATETIME); if (y != NULL) { y->value.date.year = 1970; y->value.date.mon = 1; y->value.date.day = 1; y->value.date.tz_flag = 1; dur = _exsltDateDifference(y, dt, 1); if (dur != NULL) { ret = exsltDateCastDateToNumber(dur); exsltDateFreeDate(dur); } exsltDateFreeDate(y); } } else if ((dt->type == XS_DURATION) && (dt->value.dur.mon == 0)) ret = exsltDateCastDateToNumber(dt); exsltDateFreeDate(dt); return ret; } /** * exsltDateDifference: * @xstr: date/time string * @ystr: date/time string * * Implements the date:difference (string,string) function which returns * the duration between the first date and the second date. If the first * date occurs before the second date, then the result is a positive * duration; if it occurs after the second date, the result is a * negative duration. The two dates must both be right-truncated * date/time strings in one of the formats defined in [XML Schema Part * 2: Datatypes]. The date/time with the most specific format (i.e. the * least truncation) is converted into the same format as the date with * the least specific format (i.e. the most truncation). The permitted * formats are as follows, from most specific to least specific: * - xs:dateTime (CCYY-MM-DDThh:mm:ss) * - xs:date (CCYY-MM-DD) * - xs:gYearMonth (CCYY-MM) * - xs:gYear (CCYY) * If either of the arguments is not in one of these formats, * date:difference returns the empty string (''). * The difference between the date/times is returned as a string in the * format defined for xs:duration in [3.2.6 duration] of [XML Schema * Part 2: Datatypes]. * If the date/time string with the least specific format is in either * xs:gYearMonth or xs:gYear format, then the number of days, hours, * minutes and seconds in the duration string must be equal to zero. * (The format of the string will be PnYnM.) The number of months * specified in the duration must be less than 12. * Otherwise, the number of years and months in the duration string * must be equal to zero. (The format of the string will be * PnDTnHnMnS.) The number of seconds specified in the duration string * must be less than 60; the number of minutes must be less than 60; * the number of hours must be less than 24. * * Returns duration string or NULL. */ static xmlChar * exsltDateDifference (const xmlChar *xstr, const xmlChar *ystr) { exsltDateValPtr x, y, dur; xmlChar *ret = NULL; if ((xstr == NULL) || (ystr == NULL)) return NULL; x = exsltDateParse(xstr); if (x == NULL) return NULL; y = exsltDateParse(ystr); if (y == NULL) { exsltDateFreeDate(x); return NULL; } if (((x->type < XS_GYEAR) || (x->type > XS_DATETIME)) || ((y->type < XS_GYEAR) || (y->type > XS_DATETIME))) { exsltDateFreeDate(x); exsltDateFreeDate(y); return NULL; } dur = _exsltDateDifference(x, y, 0); exsltDateFreeDate(x); exsltDateFreeDate(y); if (dur == NULL) return NULL; ret = exsltDateFormatDuration(&(dur->value.dur)); exsltDateFreeDate(dur); return ret; } /** * exsltDateDuration: * @number: a xmlChar string * * Implements the The date:duration function returns a duration string * representing the number of seconds specified by the argument string. * If no argument is given, then the result of calling date:seconds * without any arguments is used as a default argument. * The duration is returned as a string in the format defined for * xs:duration in [3.2.6 duration] of [XML Schema Part 2: Datatypes]. * The number of years and months in the duration string must be equal * to zero. (The format of the string will be PnDTnHnMnS.) The number * of seconds specified in the duration string must be less than 60; * the number of minutes must be less than 60; the number of hours must * be less than 24. * If the argument is Infinity, -Infinity or NaN, then date:duration * returns an empty string (''). * * Returns duration string or NULL. */ static xmlChar * exsltDateDuration (const xmlChar *number) { exsltDateValPtr dur; double secs; xmlChar *ret; if (number == NULL) secs = exsltDateSeconds(number); else secs = xmlXPathCastStringToNumber(number); if ((xmlXPathIsNaN(secs)) || (xmlXPathIsInf(secs))) return NULL; dur = exsltDateCreateDate(XS_DURATION); if (dur == NULL) return NULL; dur->value.dur.sec = secs; ret = exsltDateFormatDuration(&(dur->value.dur)); exsltDateFreeDate(dur); return ret; } /**************************************************************** * * * Wrappers for use by the XPath engine * * * ****************************************************************/ #ifdef WITH_TIME /** * exsltDateDateTimeFunction: * @ctxt: an XPath parser context * @nargs : the number of arguments * * Wraps exsltDateDateTime() for use by the XPath engine. */ static void exsltDateDateTimeFunction (xmlXPathParserContextPtr ctxt, int nargs) { xmlChar *ret; if (nargs != 0) { xmlXPathSetArityError(ctxt); return; } ret = exsltDateDateTime(); if (ret == NULL) xmlXPathReturnEmptyString(ctxt); else xmlXPathReturnString(ctxt, ret); } #endif /** * exsltDateDateFunction: * @ctxt: an XPath parser context * @nargs : the number of arguments * * Wraps exsltDateDate() for use by the XPath engine. */ static void exsltDateDateFunction (xmlXPathParserContextPtr ctxt, int nargs) { xmlChar *ret, *dt = NULL; if ((nargs < 0) || (nargs > 1)) { xmlXPathSetArityError(ctxt); return; } if (nargs == 1) { dt = xmlXPathPopString(ctxt); if (xmlXPathCheckError(ctxt)) { xmlXPathSetTypeError(ctxt); return; } } ret = exsltDateDate(dt); if (ret == NULL) { xsltGenericDebug(xsltGenericDebugContext, "{http://exslt.org/dates-and-times}date: " "invalid date or format %s\n", dt); xmlXPathReturnEmptyString(ctxt); } else { xmlXPathReturnString(ctxt, ret); } if (dt != NULL) xmlFree(dt); } /** * exsltDateTimeFunction: * @ctxt: an XPath parser context * @nargs : the number of arguments * * Wraps exsltDateTime() for use by the XPath engine. */ static void exsltDateTimeFunction (xmlXPathParserContextPtr ctxt, int nargs) { xmlChar *ret, *dt = NULL; if ((nargs < 0) || (nargs > 1)) { xmlXPathSetArityError(ctxt); return; } if (nargs == 1) { dt = xmlXPathPopString(ctxt); if (xmlXPathCheckError(ctxt)) { xmlXPathSetTypeError(ctxt); return; } } ret = exsltDateTime(dt); if (ret == NULL) { xsltGenericDebug(xsltGenericDebugContext, "{http://exslt.org/dates-and-times}time: " "invalid date or format %s\n", dt); xmlXPathReturnEmptyString(ctxt); } else { xmlXPathReturnString(ctxt, ret); } if (dt != NULL) xmlFree(dt); } /** * exsltDateYearFunction: * @ctxt: an XPath parser context * @nargs : the number of arguments * * Wraps exsltDateYear() for use by the XPath engine. */ static void exsltDateYearFunction (xmlXPathParserContextPtr ctxt, int nargs) { xmlChar *dt = NULL; double ret; if ((nargs < 0) || (nargs > 1)) { xmlXPathSetArityError(ctxt); return; } if (nargs == 1) { dt = xmlXPathPopString(ctxt); if (xmlXPathCheckError(ctxt)) { xmlXPathSetTypeError(ctxt); return; } } ret = exsltDateYear(dt); if (dt != NULL) xmlFree(dt); xmlXPathReturnNumber(ctxt, ret); } /** * exsltDateLeapYearFunction: * @ctxt: an XPath parser context * @nargs : the number of arguments * * Wraps exsltDateLeapYear() for use by the XPath engine. */ static void exsltDateLeapYearFunction (xmlXPathParserContextPtr ctxt, int nargs) { xmlChar *dt = NULL; xmlXPathObjectPtr ret; if ((nargs < 0) || (nargs > 1)) { xmlXPathSetArityError(ctxt); return; } if (nargs == 1) { dt = xmlXPathPopString(ctxt); if (xmlXPathCheckError(ctxt)) { xmlXPathSetTypeError(ctxt); return; } } ret = exsltDateLeapYear(dt); if (dt != NULL) xmlFree(dt); valuePush(ctxt, ret); } #define X_IN_Y(x, y) \ static void \ exsltDate##x##In##y##Function (xmlXPathParserContextPtr ctxt, \ int nargs) { \ xmlChar *dt = NULL; \ double ret; \ \ if ((nargs < 0) || (nargs > 1)) { \ xmlXPathSetArityError(ctxt); \ return; \ } \ \ if (nargs == 1) { \ dt = xmlXPathPopString(ctxt); \ if (xmlXPathCheckError(ctxt)) { \ xmlXPathSetTypeError(ctxt); \ return; \ } \ } \ \ ret = exsltDate##x##In##y(dt); \ \ if (dt != NULL) \ xmlFree(dt); \ \ xmlXPathReturnNumber(ctxt, ret); \ } /** * exsltDateMonthInYearFunction: * @ctxt: an XPath parser context * @nargs : the number of arguments * * Wraps exsltDateMonthInYear() for use by the XPath engine. */ X_IN_Y(Month,Year) /** * exsltDateMonthNameFunction: * @ctxt: an XPath parser context * @nargs : the number of arguments * * Wraps exsltDateMonthName() for use by the XPath engine. */ static void exsltDateMonthNameFunction (xmlXPathParserContextPtr ctxt, int nargs) { xmlChar *dt = NULL; const xmlChar *ret; if ((nargs < 0) || (nargs > 1)) { xmlXPathSetArityError(ctxt); return; } if (nargs == 1) { dt = xmlXPathPopString(ctxt); if (xmlXPathCheckError(ctxt)) { xmlXPathSetTypeError(ctxt); return; } } ret = exsltDateMonthName(dt); if (dt != NULL) xmlFree(dt); if (ret == NULL) xmlXPathReturnEmptyString(ctxt); else xmlXPathReturnString(ctxt, xmlStrdup(ret)); } /** * exsltDateMonthAbbreviationFunction: * @ctxt: an XPath parser context * @nargs : the number of arguments * * Wraps exsltDateMonthAbbreviation() for use by the XPath engine. */ static void exsltDateMonthAbbreviationFunction (xmlXPathParserContextPtr ctxt, int nargs) { xmlChar *dt = NULL; const xmlChar *ret; if ((nargs < 0) || (nargs > 1)) { xmlXPathSetArityError(ctxt); return; } if (nargs == 1) { dt = xmlXPathPopString(ctxt); if (xmlXPathCheckError(ctxt)) { xmlXPathSetTypeError(ctxt); return; } } ret = exsltDateMonthAbbreviation(dt); if (dt != NULL) xmlFree(dt); if (ret == NULL) xmlXPathReturnEmptyString(ctxt); else xmlXPathReturnString(ctxt, xmlStrdup(ret)); } /** * exsltDateWeekInYearFunction: * @ctxt: an XPath parser context * @nargs : the number of arguments * * Wraps exsltDateWeekInYear() for use by the XPath engine. */ X_IN_Y(Week,Year) /** * exsltDateWeekInMonthFunction: * @ctxt: an XPath parser context * @nargs : the number of arguments * * Wraps exsltDateWeekInMonthYear() for use by the XPath engine. */ X_IN_Y(Week,Month) /** * exsltDateDayInYearFunction: * @ctxt: an XPath parser context * @nargs : the number of arguments * * Wraps exsltDateDayInYear() for use by the XPath engine. */ X_IN_Y(Day,Year) /** * exsltDateDayInMonthFunction: * @ctxt: an XPath parser context * @nargs : the number of arguments * * Wraps exsltDateDayInMonth() for use by the XPath engine. */ X_IN_Y(Day,Month) /** * exsltDateDayOfWeekInMonthFunction: * @ctxt: an XPath parser context * @nargs : the number of arguments * * Wraps exsltDayOfWeekInMonth() for use by the XPath engine. */ X_IN_Y(DayOfWeek,Month) /** * exsltDateDayInWeekFunction: * @ctxt: an XPath parser context * @nargs : the number of arguments * * Wraps exsltDateDayInWeek() for use by the XPath engine. */ X_IN_Y(Day,Week) /** * exsltDateDayNameFunction: * @ctxt: an XPath parser context * @nargs : the number of arguments * * Wraps exsltDateDayName() for use by the XPath engine. */ static void exsltDateDayNameFunction (xmlXPathParserContextPtr ctxt, int nargs) { xmlChar *dt = NULL; const xmlChar *ret; if ((nargs < 0) || (nargs > 1)) { xmlXPathSetArityError(ctxt); return; } if (nargs == 1) { dt = xmlXPathPopString(ctxt); if (xmlXPathCheckError(ctxt)) { xmlXPathSetTypeError(ctxt); return; } } ret = exsltDateDayName(dt); if (dt != NULL) xmlFree(dt); if (ret == NULL) xmlXPathReturnEmptyString(ctxt); else xmlXPathReturnString(ctxt, xmlStrdup(ret)); } /** * exsltDateMonthDayFunction: * @ctxt: an XPath parser context * @nargs : the number of arguments * * Wraps exsltDateDayAbbreviation() for use by the XPath engine. */ static void exsltDateDayAbbreviationFunction (xmlXPathParserContextPtr ctxt, int nargs) { xmlChar *dt = NULL; const xmlChar *ret; if ((nargs < 0) || (nargs > 1)) { xmlXPathSetArityError(ctxt); return; } if (nargs == 1) { dt = xmlXPathPopString(ctxt); if (xmlXPathCheckError(ctxt)) { xmlXPathSetTypeError(ctxt); return; } } ret = exsltDateDayAbbreviation(dt); if (dt != NULL) xmlFree(dt); if (ret == NULL) xmlXPathReturnEmptyString(ctxt); else xmlXPathReturnString(ctxt, xmlStrdup(ret)); } /** * exsltDateHourInDayFunction: * @ctxt: an XPath parser context * @nargs : the number of arguments * * Wraps exsltDateHourInDay() for use by the XPath engine. */ X_IN_Y(Hour,Day) /** * exsltDateMinuteInHourFunction: * @ctxt: an XPath parser context * @nargs : the number of arguments * * Wraps exsltDateMinuteInHour() for use by the XPath engine. */ X_IN_Y(Minute,Hour) /** * exsltDateSecondInMinuteFunction: * @ctxt: an XPath parser context * @nargs : the number of arguments * * Wraps exsltDateSecondInMinute() for use by the XPath engine. */ X_IN_Y(Second,Minute) /** * exsltDateSecondsFunction: * @ctxt: an XPath parser context * @nargs : the number of arguments * * Wraps exsltDateSeconds() for use by the XPath engine. */ static void exsltDateSecondsFunction (xmlXPathParserContextPtr ctxt, int nargs) { xmlChar *str = NULL; double ret; if (nargs > 1) { xmlXPathSetArityError(ctxt); return; } if (nargs == 1) { str = xmlXPathPopString(ctxt); if (xmlXPathCheckError(ctxt)) { xmlXPathSetTypeError(ctxt); return; } } ret = exsltDateSeconds(str); if (str != NULL) xmlFree(str); xmlXPathReturnNumber(ctxt, ret); } /** * exsltDateAddFunction: * @ctxt: an XPath parser context * @nargs: the number of arguments * * Wraps exsltDateAdd() for use by the XPath processor. */ static void exsltDateAddFunction (xmlXPathParserContextPtr ctxt, int nargs) { xmlChar *ret, *xstr, *ystr; if (nargs != 2) { xmlXPathSetArityError(ctxt); return; } ystr = xmlXPathPopString(ctxt); if (xmlXPathCheckError(ctxt)) return; xstr = xmlXPathPopString(ctxt); if (xmlXPathCheckError(ctxt)) { xmlFree(ystr); return; } ret = exsltDateAdd(xstr, ystr); xmlFree(ystr); xmlFree(xstr); if (ret == NULL) xmlXPathReturnEmptyString(ctxt); else xmlXPathReturnString(ctxt, ret); } /** * exsltDateAddDurationFunction: * @ctxt: an XPath parser context * @nargs: the number of arguments * * Wraps exsltDateAddDuration() for use by the XPath processor. */ static void exsltDateAddDurationFunction (xmlXPathParserContextPtr ctxt, int nargs) { xmlChar *ret, *xstr, *ystr; if (nargs != 2) { xmlXPathSetArityError(ctxt); return; } ystr = xmlXPathPopString(ctxt); if (xmlXPathCheckError(ctxt)) return; xstr = xmlXPathPopString(ctxt); if (xmlXPathCheckError(ctxt)) { xmlFree(ystr); return; } ret = exsltDateAddDuration(xstr, ystr); xmlFree(ystr); xmlFree(xstr); if (ret == NULL) xmlXPathReturnEmptyString(ctxt); else xmlXPathReturnString(ctxt, ret); } /** * exsltDateDifferenceFunction: * @ctxt: an XPath parser context * @nargs: the number of arguments * * Wraps exsltDateDifference() for use by the XPath processor. */ static void exsltDateDifferenceFunction (xmlXPathParserContextPtr ctxt, int nargs) { xmlChar *ret, *xstr, *ystr; if (nargs != 2) { xmlXPathSetArityError(ctxt); return; } ystr = xmlXPathPopString(ctxt); if (xmlXPathCheckError(ctxt)) return; xstr = xmlXPathPopString(ctxt); if (xmlXPathCheckError(ctxt)) { xmlFree(ystr); return; } ret = exsltDateDifference(xstr, ystr); xmlFree(ystr); xmlFree(xstr); if (ret == NULL) xmlXPathReturnEmptyString(ctxt); else xmlXPathReturnString(ctxt, ret); } /** * exsltDateDurationFunction: * @ctxt: an XPath parser context * @nargs : the number of arguments * * Wraps exsltDateDuration() for use by the XPath engine */ static void exsltDateDurationFunction (xmlXPathParserContextPtr ctxt, int nargs) { xmlChar *ret; xmlChar *number = NULL; if ((nargs < 0) || (nargs > 1)) { xmlXPathSetArityError(ctxt); return; } if (nargs == 1) { number = xmlXPathPopString(ctxt); if (xmlXPathCheckError(ctxt)) { xmlXPathSetTypeError(ctxt); return; } } ret = exsltDateDuration(number); if (number != NULL) xmlFree(number); if (ret == NULL) xmlXPathReturnEmptyString(ctxt); else xmlXPathReturnString(ctxt, ret); } /** * exsltDateRegister: * * Registers the EXSLT - Dates and Times module */ void exsltDateRegister (void) { xsltRegisterExtModuleFunction ((const xmlChar *) "add", (const xmlChar *) EXSLT_DATE_NAMESPACE, exsltDateAddFunction); xsltRegisterExtModuleFunction ((const xmlChar *) "add-duration", (const xmlChar *) EXSLT_DATE_NAMESPACE, exsltDateAddDurationFunction); xsltRegisterExtModuleFunction ((const xmlChar *) "date", (const xmlChar *) EXSLT_DATE_NAMESPACE, exsltDateDateFunction); #ifdef WITH_TIME xsltRegisterExtModuleFunction ((const xmlChar *) "date-time", (const xmlChar *) EXSLT_DATE_NAMESPACE, exsltDateDateTimeFunction); #endif xsltRegisterExtModuleFunction ((const xmlChar *) "day-abbreviation", (const xmlChar *) EXSLT_DATE_NAMESPACE, exsltDateDayAbbreviationFunction); xsltRegisterExtModuleFunction ((const xmlChar *) "day-in-month", (const xmlChar *) EXSLT_DATE_NAMESPACE, exsltDateDayInMonthFunction); xsltRegisterExtModuleFunction ((const xmlChar *) "day-in-week", (const xmlChar *) EXSLT_DATE_NAMESPACE, exsltDateDayInWeekFunction); xsltRegisterExtModuleFunction ((const xmlChar *) "day-in-year", (const xmlChar *) EXSLT_DATE_NAMESPACE, exsltDateDayInYearFunction); xsltRegisterExtModuleFunction ((const xmlChar *) "day-name", (const xmlChar *) EXSLT_DATE_NAMESPACE, exsltDateDayNameFunction); xsltRegisterExtModuleFunction ((const xmlChar *) "day-of-week-in-month", (const xmlChar *) EXSLT_DATE_NAMESPACE, exsltDateDayOfWeekInMonthFunction); xsltRegisterExtModuleFunction ((const xmlChar *) "difference", (const xmlChar *) EXSLT_DATE_NAMESPACE, exsltDateDifferenceFunction); xsltRegisterExtModuleFunction ((const xmlChar *) "duration", (const xmlChar *) EXSLT_DATE_NAMESPACE, exsltDateDurationFunction); xsltRegisterExtModuleFunction ((const xmlChar *) "hour-in-day", (const xmlChar *) EXSLT_DATE_NAMESPACE, exsltDateHourInDayFunction); xsltRegisterExtModuleFunction ((const xmlChar *) "leap-year", (const xmlChar *) EXSLT_DATE_NAMESPACE, exsltDateLeapYearFunction); xsltRegisterExtModuleFunction ((const xmlChar *) "minute-in-hour", (const xmlChar *) EXSLT_DATE_NAMESPACE, exsltDateMinuteInHourFunction); xsltRegisterExtModuleFunction ((const xmlChar *) "month-abbreviation", (const xmlChar *) EXSLT_DATE_NAMESPACE, exsltDateMonthAbbreviationFunction); xsltRegisterExtModuleFunction ((const xmlChar *) "month-in-year", (const xmlChar *) EXSLT_DATE_NAMESPACE, exsltDateMonthInYearFunction); xsltRegisterExtModuleFunction ((const xmlChar *) "month-name", (const xmlChar *) EXSLT_DATE_NAMESPACE, exsltDateMonthNameFunction); xsltRegisterExtModuleFunction ((const xmlChar *) "second-in-minute", (const xmlChar *) EXSLT_DATE_NAMESPACE, exsltDateSecondInMinuteFunction); xsltRegisterExtModuleFunction ((const xmlChar *) "seconds", (const xmlChar *) EXSLT_DATE_NAMESPACE, exsltDateSecondsFunction); xsltRegisterExtModuleFunction ((const xmlChar *) "sum", (const xmlChar *) EXSLT_DATE_NAMESPACE, exsltDateSumFunction); xsltRegisterExtModuleFunction ((const xmlChar *) "time", (const xmlChar *) EXSLT_DATE_NAMESPACE, exsltDateTimeFunction); xsltRegisterExtModuleFunction ((const xmlChar *) "week-in-month", (const xmlChar *) EXSLT_DATE_NAMESPACE, exsltDateWeekInMonthFunction); xsltRegisterExtModuleFunction ((const xmlChar *) "week-in-year", (const xmlChar *) EXSLT_DATE_NAMESPACE, exsltDateWeekInYearFunction); xsltRegisterExtModuleFunction ((const xmlChar *) "year", (const xmlChar *) EXSLT_DATE_NAMESPACE, exsltDateYearFunction); } /** * exsltDateXpathCtxtRegister: * * Registers the EXSLT - Dates and Times module for use outside XSLT */ int exsltDateXpathCtxtRegister (xmlXPathContextPtr ctxt, const xmlChar *prefix) { if (ctxt && prefix && !xmlXPathRegisterNs(ctxt, prefix, (const xmlChar *) EXSLT_DATE_NAMESPACE) && !xmlXPathRegisterFuncNS(ctxt, (const xmlChar *) "add", (const xmlChar *) EXSLT_DATE_NAMESPACE, exsltDateAddFunction) && !xmlXPathRegisterFuncNS(ctxt, (const xmlChar *) "add-duration", (const xmlChar *) EXSLT_DATE_NAMESPACE, exsltDateAddDurationFunction) && !xmlXPathRegisterFuncNS(ctxt, (const xmlChar *) "date", (const xmlChar *) EXSLT_DATE_NAMESPACE, exsltDateDateFunction) #ifdef WITH_TIME && !xmlXPathRegisterFuncNS(ctxt, (const xmlChar *) "date-time", (const xmlChar *) EXSLT_DATE_NAMESPACE, exsltDateDateTimeFunction) #endif && !xmlXPathRegisterFuncNS(ctxt, (const xmlChar *) "day-abbreviation", (const xmlChar *) EXSLT_DATE_NAMESPACE, exsltDateDayAbbreviationFunction) && !xmlXPathRegisterFuncNS(ctxt, (const xmlChar *) "day-in-month", (const xmlChar *) EXSLT_DATE_NAMESPACE, exsltDateDayInMonthFunction) && !xmlXPathRegisterFuncNS(ctxt, (const xmlChar *) "day-in-week", (const xmlChar *) EXSLT_DATE_NAMESPACE, exsltDateDayInWeekFunction) && !xmlXPathRegisterFuncNS(ctxt, (const xmlChar *) "day-in-year", (const xmlChar *) EXSLT_DATE_NAMESPACE, exsltDateDayInYearFunction) && !xmlXPathRegisterFuncNS(ctxt, (const xmlChar *) "day-name", (const xmlChar *) EXSLT_DATE_NAMESPACE, exsltDateDayNameFunction) && !xmlXPathRegisterFuncNS(ctxt, (const xmlChar *) "day-of-week-in-month", (const xmlChar *) EXSLT_DATE_NAMESPACE, exsltDateDayOfWeekInMonthFunction) && !xmlXPathRegisterFuncNS(ctxt, (const xmlChar *) "difference", (const xmlChar *) EXSLT_DATE_NAMESPACE, exsltDateDifferenceFunction) && !xmlXPathRegisterFuncNS(ctxt, (const xmlChar *) "duration", (const xmlChar *) EXSLT_DATE_NAMESPACE, exsltDateDurationFunction) && !xmlXPathRegisterFuncNS(ctxt, (const xmlChar *) "hour-in-day", (const xmlChar *) EXSLT_DATE_NAMESPACE, exsltDateHourInDayFunction) && !xmlXPathRegisterFuncNS(ctxt, (const xmlChar *) "leap-year", (const xmlChar *) EXSLT_DATE_NAMESPACE, exsltDateLeapYearFunction) && !xmlXPathRegisterFuncNS(ctxt, (const xmlChar *) "minute-in-hour", (const xmlChar *) EXSLT_DATE_NAMESPACE, exsltDateMinuteInHourFunction) && !xmlXPathRegisterFuncNS(ctxt, (const xmlChar *) "month-abbreviation", (const xmlChar *) EXSLT_DATE_NAMESPACE, exsltDateMonthAbbreviationFunction) && !xmlXPathRegisterFuncNS(ctxt, (const xmlChar *) "month-in-year", (const xmlChar *) EXSLT_DATE_NAMESPACE, exsltDateMonthInYearFunction) && !xmlXPathRegisterFuncNS(ctxt, (const xmlChar *) "month-name", (const xmlChar *) EXSLT_DATE_NAMESPACE, exsltDateMonthNameFunction) && !xmlXPathRegisterFuncNS(ctxt, (const xmlChar *) "second-in-minute", (const xmlChar *) EXSLT_DATE_NAMESPACE, exsltDateSecondInMinuteFunction) && !xmlXPathRegisterFuncNS(ctxt, (const xmlChar *) "seconds", (const xmlChar *) EXSLT_DATE_NAMESPACE, exsltDateSecondsFunction) && !xmlXPathRegisterFuncNS(ctxt, (const xmlChar *) "sum", (const xmlChar *) EXSLT_DATE_NAMESPACE, exsltDateSumFunction) && !xmlXPathRegisterFuncNS(ctxt, (const xmlChar *) "time", (const xmlChar *) EXSLT_DATE_NAMESPACE, exsltDateTimeFunction) && !xmlXPathRegisterFuncNS(ctxt, (const xmlChar *) "week-in-month", (const xmlChar *) EXSLT_DATE_NAMESPACE, exsltDateWeekInMonthFunction) && !xmlXPathRegisterFuncNS(ctxt, (const xmlChar *) "week-in-year", (const xmlChar *) EXSLT_DATE_NAMESPACE, exsltDateWeekInYearFunction) && !xmlXPathRegisterFuncNS(ctxt, (const xmlChar *) "year", (const xmlChar *) EXSLT_DATE_NAMESPACE, exsltDateYearFunction)) { return 0; } return -1; } libxslt-1.1.28/libexslt/functions.c0000664000076400007640000005461112024022316014220 00000000000000#define IN_LIBEXSLT #include "libexslt/libexslt.h" #if defined(WIN32) && !defined (__CYGWIN__) && (!__MINGW32__) #include #else #include "config.h" #endif #include #include #include #include #include #include #include #include #include #include #include #include #include "exslt.h" typedef struct _exsltFuncFunctionData exsltFuncFunctionData; struct _exsltFuncFunctionData { int nargs; /* number of arguments to the function */ xmlNodePtr content; /* the func:fuction template content */ }; typedef struct _exsltFuncData exsltFuncData; struct _exsltFuncData { xmlHashTablePtr funcs; /* pointer to the stylesheet module data */ xmlXPathObjectPtr result; /* returned by func:result */ int error; /* did an error occur? */ xmlDocPtr RVT; /* result tree fragment */ }; typedef struct _exsltFuncResultPreComp exsltFuncResultPreComp; struct _exsltFuncResultPreComp { xsltElemPreComp comp; xmlXPathCompExprPtr select; xmlNsPtr *nsList; int nsNr; }; /* Used for callback function in exsltInitFunc */ typedef struct _exsltFuncImportRegData exsltFuncImportRegData; struct _exsltFuncImportRegData { xsltTransformContextPtr ctxt; xmlHashTablePtr hash; }; static void exsltFuncFunctionFunction (xmlXPathParserContextPtr ctxt, int nargs); static exsltFuncFunctionData *exsltFuncNewFunctionData(void); #define MAX_FUNC_RECURSION 1000 /*static const xmlChar *exsltResultDataID = (const xmlChar *) "EXSLT Result";*/ /** * exsltFuncRegisterFunc: * @func: the #exsltFuncFunctionData for the function * @ctxt: an XSLT transformation context * @URI: the function namespace URI * @name: the function name * * Registers a function declared by a func:function element */ static void exsltFuncRegisterFunc (exsltFuncFunctionData *data, xsltTransformContextPtr ctxt, const xmlChar *URI, const xmlChar *name, ATTRIBUTE_UNUSED const xmlChar *ignored) { if ((data == NULL) || (ctxt == NULL) || (URI == NULL) || (name == NULL)) return; xsltGenericDebug(xsltGenericDebugContext, "exsltFuncRegisterFunc: register {%s}%s\n", URI, name); xsltRegisterExtFunction(ctxt, name, URI, exsltFuncFunctionFunction); } /* * exsltFuncRegisterImportFunc * @data: the exsltFuncFunctionData for the function * @ch: structure containing context and hash table * @URI: the function namespace URI * @name: the function name * * Checks if imported function is already registered in top-level * stylesheet. If not, copies function data and registers function */ static void exsltFuncRegisterImportFunc (exsltFuncFunctionData *data, exsltFuncImportRegData *ch, const xmlChar *URI, const xmlChar *name, ATTRIBUTE_UNUSED const xmlChar *ignored) { exsltFuncFunctionData *func=NULL; if ((data == NULL) || (ch == NULL) || (URI == NULL) || (name == NULL)) return; if (ch->ctxt == NULL || ch->hash == NULL) return; /* Check if already present */ func = (exsltFuncFunctionData*)xmlHashLookup2(ch->hash, URI, name); if (func == NULL) { /* Not yet present - copy it in */ func = exsltFuncNewFunctionData(); memcpy(func, data, sizeof(exsltFuncFunctionData)); if (xmlHashAddEntry2(ch->hash, URI, name, func) < 0) { xsltGenericError(xsltGenericErrorContext, "Failed to register function {%s}%s\n", URI, name); } else { /* Do the registration */ xsltGenericDebug(xsltGenericDebugContext, "exsltFuncRegisterImportFunc: register {%s}%s\n", URI, name); xsltRegisterExtFunction(ch->ctxt, name, URI, exsltFuncFunctionFunction); } } } /** * exsltFuncInit: * @ctxt: an XSLT transformation context * @URI: the namespace URI for the extension * * Initializes the EXSLT - Functions module. * Called at transformation-time; merges all * functions declared in the import tree taking * import precedence into account, i.e. overriding * functions with lower import precedence. * * Returns the data for this transformation */ static exsltFuncData * exsltFuncInit (xsltTransformContextPtr ctxt, const xmlChar *URI) { exsltFuncData *ret; xsltStylesheetPtr tmp; exsltFuncImportRegData ch; xmlHashTablePtr hash; ret = (exsltFuncData *) xmlMalloc (sizeof(exsltFuncData)); if (ret == NULL) { xsltGenericError(xsltGenericErrorContext, "exsltFuncInit: not enough memory\n"); return(NULL); } memset(ret, 0, sizeof(exsltFuncData)); ret->result = NULL; ret->error = 0; ch.hash = (xmlHashTablePtr) xsltStyleGetExtData(ctxt->style, URI); ret->funcs = ch.hash; xmlHashScanFull(ch.hash, (xmlHashScannerFull) exsltFuncRegisterFunc, ctxt); tmp = ctxt->style; ch.ctxt = ctxt; while ((tmp=xsltNextImport(tmp))!=NULL) { hash = xsltGetExtInfo(tmp, URI); if (hash != NULL) { xmlHashScanFull(hash, (xmlHashScannerFull) exsltFuncRegisterImportFunc, &ch); } } return(ret); } /** * exsltFuncShutdown: * @ctxt: an XSLT transformation context * @URI: the namespace URI for the extension * @data: the module data to free up * * Shutdown the EXSLT - Functions module * Called at transformation-time. */ static void exsltFuncShutdown (xsltTransformContextPtr ctxt ATTRIBUTE_UNUSED, const xmlChar *URI ATTRIBUTE_UNUSED, exsltFuncData *data) { if (data->result != NULL) xmlXPathFreeObject(data->result); xmlFree(data); } /** * exsltFuncStyleInit: * @style: an XSLT stylesheet * @URI: the namespace URI for the extension * * Allocates the stylesheet data for EXSLT - Function * Called at compile-time. * * Returns the allocated data */ static xmlHashTablePtr exsltFuncStyleInit (xsltStylesheetPtr style ATTRIBUTE_UNUSED, const xmlChar *URI ATTRIBUTE_UNUSED) { return xmlHashCreate(1); } /** * exsltFuncStyleShutdown: * @style: an XSLT stylesheet * @URI: the namespace URI for the extension * @data: the stylesheet data to free up * * Shutdown the EXSLT - Function module * Called at compile-time. */ static void exsltFuncStyleShutdown (xsltStylesheetPtr style ATTRIBUTE_UNUSED, const xmlChar *URI ATTRIBUTE_UNUSED, xmlHashTablePtr data) { xmlHashFree(data, (xmlHashDeallocator) xmlFree); } /** * exsltFuncNewFunctionData: * * Allocates an #exslFuncFunctionData object * * Returns the new structure */ static exsltFuncFunctionData * exsltFuncNewFunctionData (void) { exsltFuncFunctionData *ret; ret = (exsltFuncFunctionData *) xmlMalloc (sizeof(exsltFuncFunctionData)); if (ret == NULL) { xsltGenericError(xsltGenericErrorContext, "exsltFuncNewFunctionData: not enough memory\n"); return (NULL); } memset(ret, 0, sizeof(exsltFuncFunctionData)); ret->nargs = 0; ret->content = NULL; return(ret); } /** * exsltFreeFuncResultPreComp: * @comp: the #exsltFuncResultPreComp to free up * * Deallocates an #exsltFuncResultPreComp */ static void exsltFreeFuncResultPreComp (exsltFuncResultPreComp *comp) { if (comp == NULL) return; if (comp->select != NULL) xmlXPathFreeCompExpr (comp->select); if (comp->nsList != NULL) xmlFree(comp->nsList); xmlFree(comp); } /** * exsltFuncFunctionFunction: * @ctxt: an XPath parser context * @nargs: the number of arguments * * Evaluates the func:function element that defines the called function. */ static void exsltFuncFunctionFunction (xmlXPathParserContextPtr ctxt, int nargs) { xmlXPathObjectPtr oldResult, ret; exsltFuncData *data; exsltFuncFunctionData *func; xmlNodePtr paramNode, oldInsert, fake; int oldBase; xsltStackElemPtr params = NULL, param; xsltTransformContextPtr tctxt = xsltXPathGetTransformContext(ctxt); int i, notSet; struct objChain { struct objChain *next; xmlXPathObjectPtr obj; }; struct objChain *savedObjChain = NULL, *savedObj; /* * retrieve func:function template */ data = (exsltFuncData *) xsltGetExtData (tctxt, EXSLT_FUNCTIONS_NAMESPACE); oldResult = data->result; data->result = NULL; func = (exsltFuncFunctionData*) xmlHashLookup2 (data->funcs, ctxt->context->functionURI, ctxt->context->function); /* * params handling */ if (nargs > func->nargs) { xsltGenericError(xsltGenericErrorContext, "{%s}%s: called with too many arguments\n", ctxt->context->functionURI, ctxt->context->function); ctxt->error = XPATH_INVALID_ARITY; return; } if (func->content != NULL) { paramNode = func->content->prev; } else paramNode = NULL; if ((paramNode == NULL) && (func->nargs != 0)) { xsltGenericError(xsltGenericErrorContext, "exsltFuncFunctionFunction: nargs != 0 and " "param == NULL\n"); return; } if (tctxt->funcLevel > MAX_FUNC_RECURSION) { xsltGenericError(xsltGenericErrorContext, "{%s}%s: detected a recursion\n", ctxt->context->functionURI, ctxt->context->function); ctxt->error = XPATH_MEMORY_ERROR; return; } tctxt->funcLevel++; /* * We have a problem with the evaluation of function parameters. * The original library code did not evaluate XPath expressions until * the last moment. After version 1.1.17 of the libxslt, the logic * of other parts of the library was changed, and the evaluation of * XPath expressions within parameters now takes place as soon as the * parameter is parsed/evaluated (xsltParseStylesheetCallerParam). * This means that the parameters need to be evaluated in lexical * order (since a variable is "in scope" as soon as it is declared). * However, on entry to this routine, the values (from the caller) are * in reverse order (held on the XPath context variable stack). To * accomplish what is required, I have added code to pop the XPath * objects off of the stack at the beginning and save them, then use * them (in the reverse order) as the params are evaluated. This * requires an xmlMalloc/xmlFree for each param set by the caller, * which is not very nice. There is probably a much better solution * (like change other code to delay the evaluation). */ /* * In order to give the function params and variables a new 'scope' * we change varsBase in the context. */ oldBase = tctxt->varsBase; tctxt->varsBase = tctxt->varsNr; /* If there are any parameters */ if (paramNode != NULL) { /* Fetch the stored argument values from the caller */ for (i = 0; i < nargs; i++) { savedObj = xmlMalloc(sizeof(struct objChain)); savedObj->next = savedObjChain; savedObj->obj = valuePop(ctxt); savedObjChain = savedObj; } /* * Prepare to process params in reverse order. First, go to * the beginning of the param chain. */ for (i = 1; i <= func->nargs; i++) { if (paramNode->prev == NULL) break; paramNode = paramNode->prev; } /* * i has total # params found, nargs is number which are present * as arguments from the caller * Calculate the number of un-set parameters */ notSet = func->nargs - nargs; for (; i > 0; i--) { param = xsltParseStylesheetCallerParam (tctxt, paramNode); if (i > notSet) { /* if parameter value set */ param->computed = 1; if (param->value != NULL) xmlXPathFreeObject(param->value); savedObj = savedObjChain; /* get next val from chain */ param->value = savedObj->obj; savedObjChain = savedObjChain->next; xmlFree(savedObj); } xsltLocalVariablePush(tctxt, param, -1); param->next = params; params = param; paramNode = paramNode->next; } } /* * actual processing */ fake = xmlNewDocNode(tctxt->output, NULL, (const xmlChar *)"fake", NULL); oldInsert = tctxt->insert; tctxt->insert = fake; xsltApplyOneTemplate (tctxt, xmlXPathGetContextNode(ctxt), func->content, NULL, NULL); xsltLocalVariablePop(tctxt, tctxt->varsBase, -2); tctxt->insert = oldInsert; tctxt->varsBase = oldBase; /* restore original scope */ if (params != NULL) xsltFreeStackElemList(params); if (data->error != 0) goto error; if (data->result != NULL) { ret = data->result; } else ret = xmlXPathNewCString(""); data->result = oldResult; /* * It is an error if the instantiation of the template results in * the generation of result nodes. */ if (fake->children != NULL) { #ifdef LIBXML_DEBUG_ENABLED xmlDebugDumpNode (stderr, fake, 1); #endif xsltGenericError(xsltGenericErrorContext, "{%s}%s: cannot write to result tree while " "executing a function\n", ctxt->context->functionURI, ctxt->context->function); xmlFreeNode(fake); goto error; } xmlFreeNode(fake); valuePush(ctxt, ret); error: /* * IMPORTANT: This enables previously tree fragments marked as * being results of a function, to be garbage-collected after * the calling process exits. */ xsltExtensionInstructionResultFinalize(tctxt); tctxt->funcLevel--; } static void exsltFuncFunctionComp (xsltStylesheetPtr style, xmlNodePtr inst) { xmlChar *name, *prefix; xmlNsPtr ns; xmlHashTablePtr data; exsltFuncFunctionData *func; if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE)) return; { xmlChar *qname; qname = xmlGetProp(inst, (const xmlChar *) "name"); name = xmlSplitQName2 (qname, &prefix); xmlFree(qname); } if ((name == NULL) || (prefix == NULL)) { xsltGenericError(xsltGenericErrorContext, "func:function: not a QName\n"); if (name != NULL) xmlFree(name); return; } /* namespace lookup */ ns = xmlSearchNs (inst->doc, inst, prefix); if (ns == NULL) { xsltGenericError(xsltGenericErrorContext, "func:function: undeclared prefix %s\n", prefix); xmlFree(name); xmlFree(prefix); return; } xmlFree(prefix); xsltParseTemplateContent(style, inst); /* * Create function data */ func = exsltFuncNewFunctionData(); func->content = inst->children; while (IS_XSLT_ELEM(func->content) && IS_XSLT_NAME(func->content, "param")) { func->content = func->content->next; func->nargs++; } /* * Register the function data such that it can be retrieved * by exslFuncFunctionFunction */ #ifdef XSLT_REFACTORED /* * Ensure that the hash table will be stored in the *current* * stylesheet level in order to correctly evaluate the * import precedence. */ data = (xmlHashTablePtr) xsltStyleStylesheetLevelGetExtData(style, EXSLT_FUNCTIONS_NAMESPACE); #else data = (xmlHashTablePtr) xsltStyleGetExtData (style, EXSLT_FUNCTIONS_NAMESPACE); #endif if (data == NULL) { xsltGenericError(xsltGenericErrorContext, "exsltFuncFunctionComp: no stylesheet data\n"); xmlFree(name); return; } if (xmlHashAddEntry2 (data, ns->href, name, func) < 0) { xsltTransformError(NULL, style, inst, "Failed to register function {%s}%s\n", ns->href, name); style->errors++; } else { xsltGenericDebug(xsltGenericDebugContext, "exsltFuncFunctionComp: register {%s}%s\n", ns->href, name); } xmlFree(name); } static xsltElemPreCompPtr exsltFuncResultComp (xsltStylesheetPtr style, xmlNodePtr inst, xsltTransformFunction function) { xmlNodePtr test; xmlChar *sel; exsltFuncResultPreComp *ret; if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE)) return (NULL); /* * "Validity" checking */ /* it is an error to have any following sibling elements aside * from the xsl:fallback element. */ for (test = inst->next; test != NULL; test = test->next) { if (test->type != XML_ELEMENT_NODE) continue; if (IS_XSLT_ELEM(test) && IS_XSLT_NAME(test, "fallback")) continue; xsltGenericError(xsltGenericErrorContext, "exsltFuncResultElem: only xsl:fallback is " "allowed to follow func:result\n"); style->errors++; return (NULL); } /* it is an error for a func:result element to not be a descendant * of func:function. * it is an error if a func:result occurs within a func:result * element. * it is an error if instanciating the content of a variable * binding element (i.e. xsl:variable, xsl:param) results in the * instanciation of a func:result element. */ for (test = inst->parent; test != NULL; test = test->parent) { if (IS_XSLT_ELEM(test) && IS_XSLT_NAME(test, "stylesheet")) { xsltGenericError(xsltGenericErrorContext, "func:result element not a descendant " "of a func:function\n"); style->errors++; return (NULL); } if ((test->ns != NULL) && (xmlStrEqual(test->ns->href, EXSLT_FUNCTIONS_NAMESPACE))) { if (xmlStrEqual(test->name, (const xmlChar *) "function")) { break; } if (xmlStrEqual(test->name, (const xmlChar *) "result")) { xsltGenericError(xsltGenericErrorContext, "func:result element not allowed within" " another func:result element\n"); style->errors++; return (NULL); } } if (IS_XSLT_ELEM(test) && (IS_XSLT_NAME(test, "variable") || IS_XSLT_NAME(test, "param"))) { xsltGenericError(xsltGenericErrorContext, "func:result element not allowed within" " a variable binding element\n"); style->errors++; return (NULL); } } /* * Precomputation */ ret = (exsltFuncResultPreComp *) xmlMalloc (sizeof(exsltFuncResultPreComp)); if (ret == NULL) { xsltPrintErrorContext(NULL, NULL, NULL); xsltGenericError(xsltGenericErrorContext, "exsltFuncResultComp : malloc failed\n"); style->errors++; return (NULL); } memset(ret, 0, sizeof(exsltFuncResultPreComp)); xsltInitElemPreComp ((xsltElemPreCompPtr) ret, style, inst, function, (xsltElemPreCompDeallocator) exsltFreeFuncResultPreComp); ret->select = NULL; /* * Precompute the select attribute */ sel = xmlGetNsProp(inst, (const xmlChar *) "select", NULL); if (sel != NULL) { ret->select = xmlXPathCompile (sel); xmlFree(sel); } /* * Precompute the namespace list */ ret->nsList = xmlGetNsList(inst->doc, inst); if (ret->nsList != NULL) { int i = 0; while (ret->nsList[i] != NULL) i++; ret->nsNr = i; } return ((xsltElemPreCompPtr) ret); } static void exsltFuncResultElem (xsltTransformContextPtr ctxt, xmlNodePtr node ATTRIBUTE_UNUSED, xmlNodePtr inst, exsltFuncResultPreComp *comp) { exsltFuncData *data; xmlXPathObjectPtr ret; /* It is an error if instantiating the content of the * func:function element results in the instantiation of more than * one func:result elements. */ data = (exsltFuncData *) xsltGetExtData (ctxt, EXSLT_FUNCTIONS_NAMESPACE); if (data == NULL) { xsltGenericError(xsltGenericErrorContext, "exsltFuncReturnElem: data == NULL\n"); return; } if (data->result != NULL) { xsltGenericError(xsltGenericErrorContext, "func:result already instanciated\n"); data->error = 1; return; } /* * Processing */ if (comp->select != NULL) { xmlNsPtr *oldXPNsList; int oldXPNsNr; xmlNodePtr oldXPContextNode; /* If the func:result element has a select attribute, then the * value of the attribute must be an expression and the * returned value is the object that results from evaluating * the expression. In this case, the content must be empty. */ if (inst->children != NULL) { xsltGenericError(xsltGenericErrorContext, "func:result content must be empty if" " the function has a select attribute\n"); data->error = 1; return; } oldXPNsList = ctxt->xpathCtxt->namespaces; oldXPNsNr = ctxt->xpathCtxt->nsNr; oldXPContextNode = ctxt->xpathCtxt->node; ctxt->xpathCtxt->namespaces = comp->nsList; ctxt->xpathCtxt->nsNr = comp->nsNr; ret = xmlXPathCompiledEval(comp->select, ctxt->xpathCtxt); ctxt->xpathCtxt->node = oldXPContextNode; ctxt->xpathCtxt->nsNr = oldXPNsNr; ctxt->xpathCtxt->namespaces = oldXPNsList; if (ret == NULL) { xsltGenericError(xsltGenericErrorContext, "exsltFuncResultElem: ret == NULL\n"); return; } /* * Mark it as a function result in order to avoid garbage * collecting of tree fragments before the function exits. */ xsltExtensionInstructionResultRegister(ctxt, ret); } else if (inst->children != NULL) { /* If the func:result element does not have a select attribute * and has non-empty content (i.e. the func:result element has * one or more child nodes), then the content of the * func:result element specifies the value. */ xmlNodePtr oldInsert; xmlDocPtr container; container = xsltCreateRVT(ctxt); if (container == NULL) { xsltGenericError(xsltGenericErrorContext, "exsltFuncResultElem: out of memory\n"); data->error = 1; return; } xsltRegisterLocalRVT(ctxt, container); oldInsert = ctxt->insert; ctxt->insert = (xmlNodePtr) container; xsltApplyOneTemplate (ctxt, ctxt->xpathCtxt->node, inst->children, NULL, NULL); ctxt->insert = oldInsert; ret = xmlXPathNewValueTree((xmlNodePtr) container); if (ret == NULL) { xsltGenericError(xsltGenericErrorContext, "exsltFuncResultElem: ret == NULL\n"); data->error = 1; } else { ret->boolval = 0; /* Freeing is not handled there anymore */ /* * Mark it as a function result in order to avoid garbage * collecting of tree fragments before the function exits. */ xsltExtensionInstructionResultRegister(ctxt, ret); } } else { /* If the func:result element has empty content and does not * have a select attribute, then the returned value is an * empty string. */ ret = xmlXPathNewCString(""); } data->result = ret; } /** * exsltFuncRegister: * * Registers the EXSLT - Functions module */ void exsltFuncRegister (void) { xsltRegisterExtModuleFull (EXSLT_FUNCTIONS_NAMESPACE, (xsltExtInitFunction) exsltFuncInit, (xsltExtShutdownFunction) exsltFuncShutdown, (xsltStyleExtInitFunction) exsltFuncStyleInit, (xsltStyleExtShutdownFunction) exsltFuncStyleShutdown); xsltRegisterExtModuleTopLevel ((const xmlChar *) "function", EXSLT_FUNCTIONS_NAMESPACE, exsltFuncFunctionComp); xsltRegisterExtModuleElement ((const xmlChar *) "result", EXSLT_FUNCTIONS_NAMESPACE, (xsltPreComputeFunction)exsltFuncResultComp, (xsltTransformFunction) exsltFuncResultElem); } libxslt-1.1.28/libexslt/common.c0000664000076400007640000000645012024022316013476 00000000000000#define IN_LIBEXSLT #include "libexslt/libexslt.h" #if defined(WIN32) && !defined (__CYGWIN__) && (!__MINGW32__) #include #else #include "config.h" #endif #include #include #include #include #include #include #include #include #include #include #include "exslt.h" static void exsltNodeSetFunction (xmlXPathParserContextPtr ctxt, int nargs) { if (nargs != 1) { xmlXPathSetArityError(ctxt); return; } if (xmlXPathStackIsNodeSet (ctxt)) { xsltFunctionNodeSet (ctxt, nargs); return; } else { xmlDocPtr fragment; xsltTransformContextPtr tctxt = xsltXPathGetTransformContext(ctxt); xmlNodePtr txt; xmlChar *strval; xmlXPathObjectPtr obj; /* * SPEC EXSLT: * "You can also use this function to turn a string into a text * node, which is helpful if you want to pass a string to a * function that only accepts a node-set." */ fragment = xsltCreateRVT(tctxt); if (fragment == NULL) { xsltTransformError(tctxt, NULL, tctxt->inst, "exsltNodeSetFunction: Failed to create a tree fragment.\n"); tctxt->state = XSLT_STATE_STOPPED; return; } xsltRegisterLocalRVT(tctxt, fragment); strval = xmlXPathPopString (ctxt); txt = xmlNewDocText (fragment, strval); xmlAddChild((xmlNodePtr) fragment, txt); obj = xmlXPathNewNodeSet(txt); if (obj == NULL) { xsltTransformError(tctxt, NULL, tctxt->inst, "exsltNodeSetFunction: Failed to create a node set object.\n"); tctxt->state = XSLT_STATE_STOPPED; } else { /* * Mark it as a function result in order to avoid garbage * collecting of tree fragments */ xsltExtensionInstructionResultRegister(tctxt, obj); } if (strval != NULL) xmlFree (strval); valuePush (ctxt, obj); } } static void exsltObjectTypeFunction (xmlXPathParserContextPtr ctxt, int nargs) { xmlXPathObjectPtr obj, ret; if (nargs != 1) { xmlXPathSetArityError(ctxt); return; } obj = valuePop(ctxt); switch (obj->type) { case XPATH_STRING: ret = xmlXPathNewCString("string"); break; case XPATH_NUMBER: ret = xmlXPathNewCString("number"); break; case XPATH_BOOLEAN: ret = xmlXPathNewCString("boolean"); break; case XPATH_NODESET: ret = xmlXPathNewCString("node-set"); break; case XPATH_XSLT_TREE: ret = xmlXPathNewCString("RTF"); break; case XPATH_USERS: ret = xmlXPathNewCString("external"); break; default: xsltGenericError(xsltGenericErrorContext, "object-type() invalid arg\n"); ctxt->error = XPATH_INVALID_TYPE; xmlXPathFreeObject(obj); return; } xmlXPathFreeObject(obj); valuePush(ctxt, ret); } /** * exsltCommonRegister: * * Registers the EXSLT - Common module */ void exsltCommonRegister (void) { xsltRegisterExtModuleFunction((const xmlChar *) "node-set", EXSLT_COMMON_NAMESPACE, exsltNodeSetFunction); xsltRegisterExtModuleFunction((const xmlChar *) "object-type", EXSLT_COMMON_NAMESPACE, exsltObjectTypeFunction); xsltRegisterExtModuleElement((const xmlChar *) "document", EXSLT_COMMON_NAMESPACE, (xsltPreComputeFunction) xsltDocumentComp, (xsltTransformFunction) xsltDocumentElem); } libxslt-1.1.28/libexslt/dynamic.c0000664000076400007640000002206612024022316013633 00000000000000/* * dynamic.c: Implementation of the EXSLT -- Dynamic module * * References: * http://www.exslt.org/dyn/dyn.html * * See Copyright for the status of this software. * * Authors: * Mark Vakoc * Thomas Broyer * * TODO: * elements: * functions: * min * max * sum * map * closure */ #define IN_LIBEXSLT #include "libexslt/libexslt.h" #if defined(WIN32) && !defined (__CYGWIN__) && (!__MINGW32__) #include #else #include "config.h" #endif #include #include #include #include #include #include #include #include "exslt.h" /** * exsltDynEvaluateFunction: * @ctxt: an XPath parser context * @nargs: the number of arguments * * Evaluates the string as an XPath expression and returns the result * value, which may be a boolean, number, string, node set, result tree * fragment or external object. */ static void exsltDynEvaluateFunction(xmlXPathParserContextPtr ctxt, int nargs) { xmlChar *str = NULL; xmlXPathObjectPtr ret = NULL; if (ctxt == NULL) return; if (nargs != 1) { xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt), NULL, NULL); xsltGenericError(xsltGenericErrorContext, "dyn:evalute() : invalid number of args %d\n", nargs); ctxt->error = XPATH_INVALID_ARITY; return; } str = xmlXPathPopString(ctxt); /* return an empty node-set if an empty string is passed in */ if (!str||!xmlStrlen(str)) { if (str) xmlFree(str); valuePush(ctxt,xmlXPathNewNodeSet(NULL)); return; } ret = xmlXPathEval(str,ctxt->context); if (ret) valuePush(ctxt,ret); else { xsltGenericError(xsltGenericErrorContext, "dyn:evaluate() : unable to evaluate expression '%s'\n",str); valuePush(ctxt,xmlXPathNewNodeSet(NULL)); } xmlFree(str); return; } /** * exsltDynMapFunction: * @ctxt: an XPath parser context * @nargs: the number of arguments * * Evaluates the string as an XPath expression and returns the result * value, which may be a boolean, number, string, node set, result tree * fragment or external object. */ static void exsltDynMapFunction(xmlXPathParserContextPtr ctxt, int nargs) { xmlChar *str = NULL; xmlNodeSetPtr nodeset = NULL; xsltTransformContextPtr tctxt; xmlXPathCompExprPtr comp = NULL; xmlXPathObjectPtr ret = NULL; xmlDocPtr oldDoc, container = NULL; xmlNodePtr oldNode; int oldContextSize; int oldProximityPosition; int i, j; if (nargs != 2) { xmlXPathSetArityError(ctxt); return; } str = xmlXPathPopString(ctxt); if (xmlXPathCheckError(ctxt)) { xmlXPathSetTypeError(ctxt); return; } nodeset = xmlXPathPopNodeSet(ctxt); if (xmlXPathCheckError(ctxt)) { xmlXPathSetTypeError(ctxt); return; } if (str == NULL || !xmlStrlen(str) || !(comp = xmlXPathCompile(str))) { if (nodeset != NULL) xmlXPathFreeNodeSet(nodeset); if (str != NULL) xmlFree(str); valuePush(ctxt, xmlXPathNewNodeSet(NULL)); return; } ret = xmlXPathNewNodeSet(NULL); if (ret == NULL) { xsltGenericError(xsltGenericErrorContext, "exsltDynMapFunction: ret == NULL\n"); goto cleanup; } oldDoc = ctxt->context->doc; oldNode = ctxt->context->node; oldContextSize = ctxt->context->contextSize; oldProximityPosition = ctxt->context->proximityPosition; /** * since we really don't know we're going to be adding node(s) * down the road we create the RVT regardless */ tctxt = xsltXPathGetTransformContext(ctxt); if (tctxt == NULL) { xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, "dyn:map : internal error tctxt == NULL\n"); goto cleanup; } container = xsltCreateRVT(tctxt); if (container == NULL) { xsltTransformError(tctxt, NULL, NULL, "dyn:map : internal error container == NULL\n"); goto cleanup; } xsltRegisterLocalRVT(tctxt, container); if (nodeset && nodeset->nodeNr > 0) { xmlXPathNodeSetSort(nodeset); ctxt->context->contextSize = nodeset->nodeNr; ctxt->context->proximityPosition = 0; for (i = 0; i < nodeset->nodeNr; i++) { xmlXPathObjectPtr subResult = NULL; ctxt->context->proximityPosition++; ctxt->context->node = nodeset->nodeTab[i]; ctxt->context->doc = nodeset->nodeTab[i]->doc; subResult = xmlXPathCompiledEval(comp, ctxt->context); if (subResult != NULL) { switch (subResult->type) { case XPATH_NODESET: if (subResult->nodesetval != NULL) for (j = 0; j < subResult->nodesetval->nodeNr; j++) xmlXPathNodeSetAdd(ret->nodesetval, subResult->nodesetval-> nodeTab[j]); break; case XPATH_BOOLEAN: if (container != NULL) { xmlNodePtr cur = xmlNewChild((xmlNodePtr) container, NULL, BAD_CAST "boolean", BAD_CAST (subResult-> boolval ? "true" : "")); if (cur != NULL) { cur->ns = xmlNewNs(cur, BAD_CAST "http://exslt.org/common", BAD_CAST "exsl"); xmlXPathNodeSetAddUnique(ret->nodesetval, cur); } xsltExtensionInstructionResultRegister(tctxt, ret); } break; case XPATH_NUMBER: if (container != NULL) { xmlChar *val = xmlXPathCastNumberToString(subResult-> floatval); xmlNodePtr cur = xmlNewChild((xmlNodePtr) container, NULL, BAD_CAST "number", val); if (val != NULL) xmlFree(val); if (cur != NULL) { cur->ns = xmlNewNs(cur, BAD_CAST "http://exslt.org/common", BAD_CAST "exsl"); xmlXPathNodeSetAddUnique(ret->nodesetval, cur); } xsltExtensionInstructionResultRegister(tctxt, ret); } break; case XPATH_STRING: if (container != NULL) { xmlNodePtr cur = xmlNewChild((xmlNodePtr) container, NULL, BAD_CAST "string", subResult->stringval); if (cur != NULL) { cur->ns = xmlNewNs(cur, BAD_CAST "http://exslt.org/common", BAD_CAST "exsl"); xmlXPathNodeSetAddUnique(ret->nodesetval, cur); } xsltExtensionInstructionResultRegister(tctxt, ret); } break; default: break; } xmlXPathFreeObject(subResult); } } } ctxt->context->doc = oldDoc; ctxt->context->node = oldNode; ctxt->context->contextSize = oldContextSize; ctxt->context->proximityPosition = oldProximityPosition; cleanup: /* restore the xpath context */ if (comp != NULL) xmlXPathFreeCompExpr(comp); if (nodeset != NULL) xmlXPathFreeNodeSet(nodeset); if (str != NULL) xmlFree(str); valuePush(ctxt, ret); return; } /** * exsltDynRegister: * * Registers the EXSLT - Dynamic module */ void exsltDynRegister (void) { xsltRegisterExtModuleFunction ((const xmlChar *) "evaluate", EXSLT_DYNAMIC_NAMESPACE, exsltDynEvaluateFunction); xsltRegisterExtModuleFunction ((const xmlChar *) "map", EXSLT_DYNAMIC_NAMESPACE, exsltDynMapFunction); } libxslt-1.1.28/libexslt/crypto.c0000664000076400007640000005116112024022166013530 00000000000000#define IN_LIBEXSLT #include "libexslt/libexslt.h" #if defined(WIN32) && !defined (__CYGWIN__) && (!__MINGW32__) #include #else #include "config.h" #endif #include #include #include #include #include #include #include #include #include #include #include "exslt.h" #ifdef EXSLT_CRYPTO_ENABLED #define HASH_DIGEST_LENGTH 32 #define MD5_DIGEST_LENGTH 16 #define SHA1_DIGEST_LENGTH 20 /* gcrypt rc4 can do 256 bit keys, but cryptoapi limit seems to be 128 for the default provider */ #define RC4_KEY_LENGTH 128 /* The following routines have been declared static - this should be reviewed to consider whether we want to expose them to the API exsltCryptoBin2Hex exsltCryptoHex2Bin exsltCryptoGcryptInit exsltCryptoGcryptHash exsltCryptoGcryptRc4Encrypt exsltCryptoGcryptRC4Decrypt */ /** * exsltCryptoBin2Hex: * @bin: binary blob to convert * @binlen: length of binary blob * @hex: buffer to store hex version of blob * @hexlen: length of buffer to store hex version of blob * * Helper function which encodes a binary blob as hex. */ static void exsltCryptoBin2Hex (const unsigned char *bin, int binlen, unsigned char *hex, int hexlen) { static const char bin2hex[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; unsigned char lo, hi; int i, pos; for (i = 0, pos = 0; (i < binlen && pos < hexlen); i++) { lo = bin[i] & 0xf; hi = bin[i] >> 4; hex[pos++] = bin2hex[hi]; hex[pos++] = bin2hex[lo]; } hex[pos] = '\0'; } /** * exsltCryptoHex2Bin: * @hex: hex version of blob to convert * @hexlen: length of hex buffer * @bin: destination binary buffer * @binlen: length of binary buffer * * Helper function which decodes a hex blob to binary */ static int exsltCryptoHex2Bin (const unsigned char *hex, int hexlen, unsigned char *bin, int binlen) { int i = 0, j = 0; unsigned char lo, hi, result, tmp; while (i < hexlen && j < binlen) { hi = lo = 0; tmp = hex[i++]; if (tmp >= '0' && tmp <= '9') hi = tmp - '0'; else if (tmp >= 'a' && tmp <= 'f') hi = 10 + (tmp - 'a'); tmp = hex[i++]; if (tmp >= '0' && tmp <= '9') lo = tmp - '0'; else if (tmp >= 'a' && tmp <= 'f') lo = 10 + (tmp - 'a'); result = hi << 4; result += lo; bin[j++] = result; } return j; } #if defined(WIN32) #define HAVE_CRYPTO #define PLATFORM_HASH exsltCryptoCryptoApiHash #define PLATFORM_RC4_ENCRYPT exsltCryptoCryptoApiRc4Encrypt #define PLATFORM_RC4_DECRYPT exsltCryptoCryptoApiRc4Decrypt #define PLATFORM_MD4 CALG_MD4 #define PLATFORM_MD5 CALG_MD5 #define PLATFORM_SHA1 CALG_SHA1 #include #include #pragma comment(lib, "advapi32.lib") static void exsltCryptoCryptoApiReportError (xmlXPathParserContextPtr ctxt, int line) { LPVOID lpMsgBuf; DWORD dw = GetLastError (); FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, dw, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) & lpMsgBuf, 0, NULL); xsltTransformError (xsltXPathGetTransformContext (ctxt), NULL, NULL, "exslt:crypto error (line %d). %s", line, lpMsgBuf); LocalFree (lpMsgBuf); } static HCRYPTHASH exsltCryptoCryptoApiCreateHash (xmlXPathParserContextPtr ctxt, HCRYPTPROV hCryptProv, ALG_ID algorithm, const char *msg, unsigned int msglen, char *dest, unsigned int destlen) { HCRYPTHASH hHash = 0; DWORD dwHashLen = destlen; if (!CryptCreateHash (hCryptProv, algorithm, 0, 0, &hHash)) { exsltCryptoCryptoApiReportError (ctxt, __LINE__); return 0; } if (!CryptHashData (hHash, (const BYTE *) msg, msglen, 0)) { exsltCryptoCryptoApiReportError (ctxt, __LINE__); goto fail; } if (!CryptGetHashParam (hHash, HP_HASHVAL, dest, &dwHashLen, 0)) { exsltCryptoCryptoApiReportError (ctxt, __LINE__); goto fail; } fail: return hHash; } /** * exsltCryptoCryptoApiHash: * @ctxt: an XPath parser context * @algorithm: hashing algorithm to use * @msg: text to be hashed * @msglen: length of text to be hashed * @dest: buffer to place hash result * * Helper function which hashes a message using MD4, MD5, or SHA1. * Uses Win32 CryptoAPI. */ static void exsltCryptoCryptoApiHash (xmlXPathParserContextPtr ctxt, ALG_ID algorithm, const char *msg, unsigned long msglen, char dest[HASH_DIGEST_LENGTH]) { HCRYPTPROV hCryptProv; HCRYPTHASH hHash; if (!CryptAcquireContext (&hCryptProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) { exsltCryptoCryptoApiReportError (ctxt, __LINE__); return; } hHash = exsltCryptoCryptoApiCreateHash (ctxt, hCryptProv, algorithm, msg, msglen, dest, HASH_DIGEST_LENGTH); if (0 != hHash) { CryptDestroyHash (hHash); } CryptReleaseContext (hCryptProv, 0); } static void exsltCryptoCryptoApiRc4Encrypt (xmlXPathParserContextPtr ctxt, const unsigned char *key, const unsigned char *msg, int msglen, unsigned char *dest, int destlen) { HCRYPTPROV hCryptProv; HCRYPTKEY hKey; HCRYPTHASH hHash; DWORD dwDataLen; unsigned char hash[HASH_DIGEST_LENGTH]; if (msglen > destlen) { xsltTransformError (xsltXPathGetTransformContext (ctxt), NULL, NULL, "exslt:crypto : internal error exsltCryptoCryptoApiRc4Encrypt dest buffer too small.\n"); return; } if (!CryptAcquireContext (&hCryptProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) { exsltCryptoCryptoApiReportError (ctxt, __LINE__); return; } hHash = exsltCryptoCryptoApiCreateHash (ctxt, hCryptProv, CALG_SHA1, key, RC4_KEY_LENGTH, hash, HASH_DIGEST_LENGTH); if (!CryptDeriveKey (hCryptProv, CALG_RC4, hHash, 0x00800000, &hKey)) { exsltCryptoCryptoApiReportError (ctxt, __LINE__); goto fail; } /* Now encrypt data. */ dwDataLen = msglen; memcpy (dest, msg, msglen); if (!CryptEncrypt (hKey, 0, TRUE, 0, dest, &dwDataLen, msglen)) { exsltCryptoCryptoApiReportError (ctxt, __LINE__); goto fail; } fail: if (0 != hHash) { CryptDestroyHash (hHash); } CryptDestroyKey (hKey); CryptReleaseContext (hCryptProv, 0); } static void exsltCryptoCryptoApiRc4Decrypt (xmlXPathParserContextPtr ctxt, const unsigned char *key, const unsigned char *msg, int msglen, unsigned char *dest, int destlen) { HCRYPTPROV hCryptProv; HCRYPTKEY hKey; HCRYPTHASH hHash; DWORD dwDataLen; unsigned char hash[HASH_DIGEST_LENGTH]; if (msglen > destlen) { xsltTransformError (xsltXPathGetTransformContext (ctxt), NULL, NULL, "exslt:crypto : internal error exsltCryptoCryptoApiRc4Encrypt dest buffer too small.\n"); return; } if (!CryptAcquireContext (&hCryptProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) { exsltCryptoCryptoApiReportError (ctxt, __LINE__); return; } hHash = exsltCryptoCryptoApiCreateHash (ctxt, hCryptProv, CALG_SHA1, key, RC4_KEY_LENGTH, hash, HASH_DIGEST_LENGTH); if (!CryptDeriveKey (hCryptProv, CALG_RC4, hHash, 0x00800000, &hKey)) { exsltCryptoCryptoApiReportError (ctxt, __LINE__); goto fail; } /* Now encrypt data. */ dwDataLen = msglen; memcpy (dest, msg, msglen); if (!CryptDecrypt (hKey, 0, TRUE, 0, dest, &dwDataLen)) { exsltCryptoCryptoApiReportError (ctxt, __LINE__); goto fail; } fail: if (0 != hHash) { CryptDestroyHash (hHash); } CryptDestroyKey (hKey); CryptReleaseContext (hCryptProv, 0); } #endif /* defined(WIN32) */ #if defined(HAVE_GCRYPT) #define HAVE_CRYPTO #define PLATFORM_HASH exsltCryptoGcryptHash #define PLATFORM_RC4_ENCRYPT exsltCryptoGcryptRc4Encrypt #define PLATFORM_RC4_DECRYPT exsltCryptoGcryptRc4Decrypt #define PLATFORM_MD4 GCRY_MD_MD4 #define PLATFORM_MD5 GCRY_MD_MD5 #define PLATFORM_SHA1 GCRY_MD_SHA1 #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_STDINT_H # include #endif #ifdef HAVE_SYS_SELECT_H #include /* needed by gcrypt.h 4 Jul 04 */ #endif #include static void exsltCryptoGcryptInit (void) { static int gcrypt_init; xmlLockLibrary (); if (!gcrypt_init) { /* The function `gcry_check_version' must be called before any other function in the library, because it initializes the thread support subsystem in Libgcrypt. To achieve this in all generality, it is necessary to synchronize the call to this function with all other calls to functions in the library, using the synchronization mechanisms available in your thread library. (from gcrypt.info) */ gcry_check_version (GCRYPT_VERSION); gcrypt_init = 1; } xmlUnlockLibrary (); } /** * exsltCryptoGcryptHash: * @ctxt: an XPath parser context * @algorithm: hashing algorithm to use * @msg: text to be hashed * @msglen: length of text to be hashed * @dest: buffer to place hash result * * Helper function which hashes a message using MD4, MD5, or SHA1. * using gcrypt */ static void exsltCryptoGcryptHash (xmlXPathParserContextPtr ctxt ATTRIBUTE_UNUSED, /* changed the enum to int */ int algorithm, const char *msg, unsigned long msglen, char dest[HASH_DIGEST_LENGTH]) { exsltCryptoGcryptInit (); gcry_md_hash_buffer (algorithm, dest, msg, msglen); } static void exsltCryptoGcryptRc4Encrypt (xmlXPathParserContextPtr ctxt, const unsigned char *key, const unsigned char *msg, int msglen, unsigned char *dest, int destlen) { gcry_cipher_hd_t cipher; gcry_error_t rc = 0; exsltCryptoGcryptInit (); rc = gcry_cipher_open (&cipher, GCRY_CIPHER_ARCFOUR, GCRY_CIPHER_MODE_STREAM, 0); if (rc) { xsltTransformError (xsltXPathGetTransformContext (ctxt), NULL, NULL, "exslt:crypto internal error %s (gcry_cipher_open)\n", gcry_strerror (rc)); } rc = gcry_cipher_setkey (cipher, key, RC4_KEY_LENGTH); if (rc) { xsltTransformError (xsltXPathGetTransformContext (ctxt), NULL, NULL, "exslt:crypto internal error %s (gcry_cipher_setkey)\n", gcry_strerror (rc)); } rc = gcry_cipher_encrypt (cipher, (unsigned char *) dest, destlen, (const unsigned char *) msg, msglen); if (rc) { xsltTransformError (xsltXPathGetTransformContext (ctxt), NULL, NULL, "exslt:crypto internal error %s (gcry_cipher_encrypt)\n", gcry_strerror (rc)); } gcry_cipher_close (cipher); } static void exsltCryptoGcryptRc4Decrypt (xmlXPathParserContextPtr ctxt, const unsigned char *key, const unsigned char *msg, int msglen, unsigned char *dest, int destlen) { gcry_cipher_hd_t cipher; gcry_error_t rc = 0; exsltCryptoGcryptInit (); rc = gcry_cipher_open (&cipher, GCRY_CIPHER_ARCFOUR, GCRY_CIPHER_MODE_STREAM, 0); if (rc) { xsltTransformError (xsltXPathGetTransformContext (ctxt), NULL, NULL, "exslt:crypto internal error %s (gcry_cipher_open)\n", gcry_strerror (rc)); } rc = gcry_cipher_setkey (cipher, key, RC4_KEY_LENGTH); if (rc) { xsltTransformError (xsltXPathGetTransformContext (ctxt), NULL, NULL, "exslt:crypto internal error %s (gcry_cipher_setkey)\n", gcry_strerror (rc)); } rc = gcry_cipher_decrypt (cipher, (unsigned char *) dest, destlen, (const unsigned char *) msg, msglen); if (rc) { xsltTransformError (xsltXPathGetTransformContext (ctxt), NULL, NULL, "exslt:crypto internal error %s (gcry_cipher_decrypt)\n", gcry_strerror (rc)); } gcry_cipher_close (cipher); } #endif /* defined(HAVE_GCRYPT) */ #if defined(HAVE_CRYPTO) /** * exsltCryptoPopString: * @ctxt: an XPath parser context * @nargs: the number of arguments * * Helper function which checks for and returns first string argument and its length */ static int exsltCryptoPopString (xmlXPathParserContextPtr ctxt, int nargs, xmlChar ** str) { int str_len = 0; if ((nargs < 1) || (nargs > 2)) { xmlXPathSetArityError (ctxt); return 0; } *str = xmlXPathPopString (ctxt); str_len = xmlUTF8Strlen (*str); if (str_len == 0) { xmlXPathReturnEmptyString (ctxt); xmlFree (*str); return 0; } return str_len; } /** * exsltCryptoMd4Function: * @ctxt: an XPath parser context * @nargs: the number of arguments * * computes the md4 hash of a string and returns as hex */ static void exsltCryptoMd4Function (xmlXPathParserContextPtr ctxt, int nargs) { int str_len = 0; xmlChar *str = NULL, *ret = NULL; unsigned char hash[HASH_DIGEST_LENGTH]; unsigned char hex[MD5_DIGEST_LENGTH * 2 + 1]; str_len = exsltCryptoPopString (ctxt, nargs, &str); if (str_len == 0) { xmlXPathReturnEmptyString (ctxt); xmlFree (str); return; } PLATFORM_HASH (ctxt, PLATFORM_MD4, (const char *) str, str_len, (char *) hash); exsltCryptoBin2Hex (hash, sizeof (hash) - 1, hex, sizeof (hex) - 1); ret = xmlStrdup ((xmlChar *) hex); xmlXPathReturnString (ctxt, ret); if (str != NULL) xmlFree (str); } /** * exsltCryptoMd5Function: * @ctxt: an XPath parser context * @nargs: the number of arguments * * computes the md5 hash of a string and returns as hex */ static void exsltCryptoMd5Function (xmlXPathParserContextPtr ctxt, int nargs) { int str_len = 0; xmlChar *str = NULL, *ret = NULL; unsigned char hash[HASH_DIGEST_LENGTH]; unsigned char hex[MD5_DIGEST_LENGTH * 2 + 1]; str_len = exsltCryptoPopString (ctxt, nargs, &str); if (str_len == 0) { xmlXPathReturnEmptyString (ctxt); xmlFree (str); return; } PLATFORM_HASH (ctxt, PLATFORM_MD5, (const char *) str, str_len, (char *) hash); exsltCryptoBin2Hex (hash, sizeof (hash) - 1, hex, sizeof (hex) - 1); ret = xmlStrdup ((xmlChar *) hex); xmlXPathReturnString (ctxt, ret); if (str != NULL) xmlFree (str); } /** * exsltCryptoSha1Function: * @ctxt: an XPath parser context * @nargs: the number of arguments * * computes the sha1 hash of a string and returns as hex */ static void exsltCryptoSha1Function (xmlXPathParserContextPtr ctxt, int nargs) { int str_len = 0; xmlChar *str = NULL, *ret = NULL; unsigned char hash[HASH_DIGEST_LENGTH]; unsigned char hex[SHA1_DIGEST_LENGTH * 2 + 1]; str_len = exsltCryptoPopString (ctxt, nargs, &str); if (str_len == 0) { xmlXPathReturnEmptyString (ctxt); xmlFree (str); return; } PLATFORM_HASH (ctxt, PLATFORM_SHA1, (const char *) str, str_len, (char *) hash); exsltCryptoBin2Hex (hash, sizeof (hash) - 1, hex, sizeof (hex) - 1); ret = xmlStrdup ((xmlChar *) hex); xmlXPathReturnString (ctxt, ret); if (str != NULL) xmlFree (str); } /** * exsltCryptoRc4EncryptFunction: * @ctxt: an XPath parser context * @nargs: the number of arguments * * computes the sha1 hash of a string and returns as hex */ static void exsltCryptoRc4EncryptFunction (xmlXPathParserContextPtr ctxt, int nargs) { int key_len = 0, key_size = 0; int str_len = 0, bin_len = 0, hex_len = 0; xmlChar *key = NULL, *str = NULL, *padkey = NULL; xmlChar *bin = NULL, *hex = NULL; xsltTransformContextPtr tctxt = NULL; if (nargs != 2) { xmlXPathSetArityError (ctxt); return; } tctxt = xsltXPathGetTransformContext(ctxt); str = xmlXPathPopString (ctxt); str_len = xmlUTF8Strlen (str); if (str_len == 0) { xmlXPathReturnEmptyString (ctxt); xmlFree (str); return; } key = xmlXPathPopString (ctxt); key_len = xmlUTF8Strlen (key); if (key_len == 0) { xmlXPathReturnEmptyString (ctxt); xmlFree (key); xmlFree (str); return; } padkey = xmlMallocAtomic (RC4_KEY_LENGTH + 1); if (padkey == NULL) { xsltTransformError(tctxt, NULL, tctxt->inst, "exsltCryptoRc4EncryptFunction: Failed to allocate padkey\n"); tctxt->state = XSLT_STATE_STOPPED; xmlXPathReturnEmptyString (ctxt); goto done; } memset(padkey, 0, RC4_KEY_LENGTH + 1); key_size = xmlUTF8Strsize (key, key_len); if ((key_size > RC4_KEY_LENGTH) || (key_size < 0)) { xsltTransformError(tctxt, NULL, tctxt->inst, "exsltCryptoRc4EncryptFunction: key size too long or key broken\n"); tctxt->state = XSLT_STATE_STOPPED; xmlXPathReturnEmptyString (ctxt); goto done; } memcpy (padkey, key, key_size); /* encrypt it */ bin_len = str_len; bin = xmlStrdup (str); if (bin == NULL) { xsltTransformError(tctxt, NULL, tctxt->inst, "exsltCryptoRc4EncryptFunction: Failed to allocate string\n"); tctxt->state = XSLT_STATE_STOPPED; xmlXPathReturnEmptyString (ctxt); goto done; } PLATFORM_RC4_ENCRYPT (ctxt, padkey, str, str_len, bin, bin_len); /* encode it */ hex_len = str_len * 2 + 1; hex = xmlMallocAtomic (hex_len); if (hex == NULL) { xsltTransformError(tctxt, NULL, tctxt->inst, "exsltCryptoRc4EncryptFunction: Failed to allocate result\n"); tctxt->state = XSLT_STATE_STOPPED; xmlXPathReturnEmptyString (ctxt); goto done; } exsltCryptoBin2Hex (bin, str_len, hex, hex_len); xmlXPathReturnString (ctxt, hex); done: if (key != NULL) xmlFree (key); if (str != NULL) xmlFree (str); if (padkey != NULL) xmlFree (padkey); if (bin != NULL) xmlFree (bin); } /** * exsltCryptoRc4DecryptFunction: * @ctxt: an XPath parser context * @nargs: the number of arguments * * computes the sha1 hash of a string and returns as hex */ static void exsltCryptoRc4DecryptFunction (xmlXPathParserContextPtr ctxt, int nargs) { int key_len = 0, key_size = 0; int str_len = 0, bin_len = 0, ret_len = 0; xmlChar *key = NULL, *str = NULL, *padkey = NULL, *bin = NULL, *ret = NULL; xsltTransformContextPtr tctxt = NULL; if (nargs != 2) { xmlXPathSetArityError (ctxt); return; } tctxt = xsltXPathGetTransformContext(ctxt); str = xmlXPathPopString (ctxt); str_len = xmlUTF8Strlen (str); if (str_len == 0) { xmlXPathReturnEmptyString (ctxt); xmlFree (str); return; } key = xmlXPathPopString (ctxt); key_len = xmlUTF8Strlen (key); if (key_len == 0) { xmlXPathReturnEmptyString (ctxt); xmlFree (key); xmlFree (str); return; } padkey = xmlMallocAtomic (RC4_KEY_LENGTH + 1); if (padkey == NULL) { xsltTransformError(tctxt, NULL, tctxt->inst, "exsltCryptoRc4EncryptFunction: Failed to allocate padkey\n"); tctxt->state = XSLT_STATE_STOPPED; xmlXPathReturnEmptyString (ctxt); goto done; } memset(padkey, 0, RC4_KEY_LENGTH + 1); key_size = xmlUTF8Strsize (key, key_len); if ((key_size > RC4_KEY_LENGTH) || (key_size < 0)) { xsltTransformError(tctxt, NULL, tctxt->inst, "exsltCryptoRc4EncryptFunction: key size too long or key broken\n"); tctxt->state = XSLT_STATE_STOPPED; xmlXPathReturnEmptyString (ctxt); goto done; } memcpy (padkey, key, key_size); /* decode hex to binary */ bin_len = str_len; bin = xmlMallocAtomic (bin_len); if (bin == NULL) { xsltTransformError(tctxt, NULL, tctxt->inst, "exsltCryptoRc4EncryptFunction: Failed to allocate string\n"); tctxt->state = XSLT_STATE_STOPPED; xmlXPathReturnEmptyString (ctxt); goto done; } ret_len = exsltCryptoHex2Bin (str, str_len, bin, bin_len); /* decrypt the binary blob */ ret = xmlMallocAtomic (ret_len + 1); if (ret == NULL) { xsltTransformError(tctxt, NULL, tctxt->inst, "exsltCryptoRc4EncryptFunction: Failed to allocate result\n"); tctxt->state = XSLT_STATE_STOPPED; xmlXPathReturnEmptyString (ctxt); goto done; } PLATFORM_RC4_DECRYPT (ctxt, padkey, bin, ret_len, ret, ret_len); ret[ret_len] = 0; xmlXPathReturnString (ctxt, ret); done: if (key != NULL) xmlFree (key); if (str != NULL) xmlFree (str); if (padkey != NULL) xmlFree (padkey); if (bin != NULL) xmlFree (bin); } /** * exsltCryptoRegister: * * Registers the EXSLT - Crypto module */ void exsltCryptoRegister (void) { xsltRegisterExtModuleFunction ((const xmlChar *) "md4", EXSLT_CRYPTO_NAMESPACE, exsltCryptoMd4Function); xsltRegisterExtModuleFunction ((const xmlChar *) "md5", EXSLT_CRYPTO_NAMESPACE, exsltCryptoMd5Function); xsltRegisterExtModuleFunction ((const xmlChar *) "sha1", EXSLT_CRYPTO_NAMESPACE, exsltCryptoSha1Function); xsltRegisterExtModuleFunction ((const xmlChar *) "rc4_encrypt", EXSLT_CRYPTO_NAMESPACE, exsltCryptoRc4EncryptFunction); xsltRegisterExtModuleFunction ((const xmlChar *) "rc4_decrypt", EXSLT_CRYPTO_NAMESPACE, exsltCryptoRc4DecryptFunction); } #else /** * exsltCryptoRegister: * * Registers the EXSLT - Crypto module */ void exsltCryptoRegister (void) { } #endif /* defined(HAVE_CRYPTO) */ #endif /* EXSLT_CRYPTO_ENABLED */ libxslt-1.1.28/libexslt/saxon.c0000664000076400007640000002130512024022166013335 00000000000000#define IN_LIBEXSLT #include "libexslt/libexslt.h" #if defined(WIN32) && !defined (__CYGWIN__) && (!__MINGW32__) #include #else #include "config.h" #endif #include #include #include #include #include #include #include #include #include #include "exslt.h" /** * exsltSaxonInit: * @ctxt: an XSLT transformation context * @URI: the namespace URI for the extension * * Initializes the SAXON module. * * Returns the data for this transformation */ static xmlHashTablePtr exsltSaxonInit (xsltTransformContextPtr ctxt ATTRIBUTE_UNUSED, const xmlChar *URI ATTRIBUTE_UNUSED) { return xmlHashCreate(1); } /** * exsltSaxonShutdown: * @ctxt: an XSLT transformation context * @URI: the namespace URI for the extension * @data: the module data to free up * * Shutdown the SAXON extension module */ static void exsltSaxonShutdown (xsltTransformContextPtr ctxt ATTRIBUTE_UNUSED, const xmlChar *URI ATTRIBUTE_UNUSED, xmlHashTablePtr data) { xmlHashFree(data, (xmlHashDeallocator) xmlXPathFreeCompExpr); } /** * exsltSaxonExpressionFunction: * @ctxt: an XPath parser context * @nargs: the number of arguments * * The supplied string must contain an XPath expression. The result of * the function is a stored expression, which may be supplied as an * argument to other extension functions such as saxon:eval(), * saxon:sum() and saxon:distinct(). The result of the expression will * usually depend on the current node. The expression may contain * references to variables that are in scope at the point where * saxon:expression() is called: these variables will be replaced in * the stored expression with the values they take at the time * saxon:expression() is called, not the values of the variables at * the time the stored expression is evaluated. Similarly, if the * expression contains namespace prefixes, these are interpreted in * terms of the namespace declarations in scope at the point where the * saxon:expression() function is called, not those in scope where the * stored expression is evaluated. * * TODO: current implementation doesn't conform to SAXON behaviour * regarding context and namespaces. */ static void exsltSaxonExpressionFunction (xmlXPathParserContextPtr ctxt, int nargs) { xmlChar *arg; xmlXPathCompExprPtr ret; xmlHashTablePtr hash; xsltTransformContextPtr tctxt = xsltXPathGetTransformContext(ctxt); if (nargs != 1) { xmlXPathSetArityError(ctxt); return; } arg = xmlXPathPopString(ctxt); if (xmlXPathCheckError(ctxt) || (arg == NULL)) { xmlXPathSetTypeError(ctxt); return; } hash = (xmlHashTablePtr) xsltGetExtData(tctxt, ctxt->context->functionURI); ret = xmlHashLookup(hash, arg); if (ret == NULL) { ret = xmlXPathCompile(arg); if (ret == NULL) { xmlFree(arg); xsltGenericError(xsltGenericErrorContext, "{%s}:%s: argument is not an XPath expression\n", ctxt->context->functionURI, ctxt->context->function); return; } xmlHashAddEntry(hash, arg, (void *) ret); } xmlFree(arg); xmlXPathReturnExternal(ctxt, ret); } /** * exsltSaxonEvalFunction: * @ctxt: an XPath parser context * @nargs: number of arguments * * Implements de SAXON eval() function: * object saxon:eval (saxon:stored-expression) * Returns the result of evaluating the supplied stored expression. * A stored expression may be obtained as the result of calling * the saxon:expression() function. * The stored expression is evaluated in the current context, that * is, the context node is the current node, and the context position * and context size are the same as the result of calling position() * or last() respectively. */ static void exsltSaxonEvalFunction (xmlXPathParserContextPtr ctxt, int nargs) { xmlXPathCompExprPtr expr; xmlXPathObjectPtr ret; if (nargs != 1) { xmlXPathSetArityError(ctxt); return; } if (!xmlXPathStackIsExternal(ctxt)) { xmlXPathSetTypeError(ctxt); return; } expr = (xmlXPathCompExprPtr) xmlXPathPopExternal(ctxt); ret = xmlXPathCompiledEval(expr, ctxt->context); valuePush(ctxt, ret); } /** * exsltSaxonEvaluateFunction: * @ctxt: an XPath parser context * @nargs: number of arguments * * Implements the SAXON evaluate() function * object saxon:evaluate (string) * The supplied string must contain an XPath expression. The result of * the function is the result of evaluating the XPath expression. This * is useful where an expression needs to be constructed at run-time or * passed to the stylesheet as a parameter, for example where the sort * key is determined dynamically. The context for the expression (e.g. * which variables and namespaces are available) is exactly the same as * if the expression were written explicitly at this point in the * stylesheet. The function saxon:evaluate(string) is shorthand for * saxon:eval(saxon:expression(string)). */ static void exsltSaxonEvaluateFunction (xmlXPathParserContextPtr ctxt, int nargs) { if (nargs != 1) { xmlXPathSetArityError(ctxt); return; } exsltSaxonExpressionFunction(ctxt, 1); exsltSaxonEvalFunction(ctxt, 1); } /** * exsltSaxonSystemIdFunction: * @ctxt: an XPath parser context * @nargs: number of arguments * * Implements the SAXON systemId() function * string saxon:systemId () * This function returns the system ID of the document being styled. */ static void exsltSaxonSystemIdFunction(xmlXPathParserContextPtr ctxt, int nargs) { if (ctxt == NULL) return; if (nargs != 0) { xmlXPathSetArityError(ctxt); return; } if ((ctxt->context) && (ctxt->context->doc) && (ctxt->context->doc->URL)) valuePush(ctxt, xmlXPathNewString(ctxt->context->doc->URL)); else valuePush(ctxt, xmlXPathNewString(BAD_CAST "")); } /** * exsltSaxonLineNumberFunction: * @ctxt: an XPath parser context * @nargs: number of arguments * * Implements the SAXON line-number() function * integer saxon:line-number() * * This returns the line number of the context node in the source document * within the entity that contains it. There are no arguments. If line numbers * are not maintained for the current document, the function returns -1. (To * ensure that line numbers are maintained, use the -l option on the command * line) * * The extension has been extended to have the following form: * integer saxon:line-number([node-set-1]) * If a node-set is given, this extension will return the line number of the * node in the argument node-set that is first in document order. */ static void exsltSaxonLineNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) { xmlNodePtr cur = NULL; if (nargs == 0) { cur = ctxt->context->node; } else if (nargs == 1) { xmlXPathObjectPtr obj; xmlNodeSetPtr nodelist; int i; if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_NODESET)) { xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, "saxon:line-number() : invalid arg expecting a node-set\n"); ctxt->error = XPATH_INVALID_TYPE; return; } obj = valuePop(ctxt); nodelist = obj->nodesetval; if ((nodelist == NULL) || (nodelist->nodeNr <= 0)) { xmlXPathFreeObject(obj); valuePush(ctxt, xmlXPathNewFloat(-1)); return; } cur = nodelist->nodeTab[0]; for (i = 1;i < nodelist->nodeNr;i++) { int ret = xmlXPathCmpNodes(cur, nodelist->nodeTab[i]); if (ret == -1) cur = nodelist->nodeTab[i]; } xmlXPathFreeObject(obj); } else { xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, "saxon:line-number() : invalid number of args %d\n", nargs); ctxt->error = XPATH_INVALID_ARITY; return; } valuePush(ctxt, xmlXPathNewFloat(xmlGetLineNo(cur))); return; } /** * exsltSaxonRegister: * * Registers the SAXON extension module */ void exsltSaxonRegister (void) { xsltRegisterExtModule (SAXON_NAMESPACE, (xsltExtInitFunction) exsltSaxonInit, (xsltExtShutdownFunction) exsltSaxonShutdown); xsltRegisterExtModuleFunction((const xmlChar *) "expression", SAXON_NAMESPACE, exsltSaxonExpressionFunction); xsltRegisterExtModuleFunction((const xmlChar *) "eval", SAXON_NAMESPACE, exsltSaxonEvalFunction); xsltRegisterExtModuleFunction((const xmlChar *) "evaluate", SAXON_NAMESPACE, exsltSaxonEvaluateFunction); xsltRegisterExtModuleFunction ((const xmlChar *) "line-number", SAXON_NAMESPACE, exsltSaxonLineNumberFunction); xsltRegisterExtModuleFunction ((const xmlChar *) "systemId", SAXON_NAMESPACE, exsltSaxonSystemIdFunction); } libxslt-1.1.28/libexslt/Makefile.am0000664000076400007640000000143612053043724014105 00000000000000AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/libxslt -I$(top_srcdir)/libexslt \ -I$(top_builddir) -I$(top_builddir)/libxslt \ -I$(top_builddir)/libexslt AM_CFLAGS = $(LIBGCRYPT_CFLAGS) $(LIBXML_CFLAGS) lib_LTLIBRARIES = libexslt.la exsltincdir = $(includedir)/libexslt exsltinc_HEADERS = \ exslt.h \ exsltconfig.h \ exsltexports.h libexslt_la_SOURCES = \ exslt.c \ common.c \ crypto.c \ math.c \ sets.c \ functions.c \ strings.c \ date.c \ saxon.c \ libexslt.h \ dynamic.c libexslt_la_LIBADD = $(top_builddir)/libxslt/libxslt.la $(EXTRA_LIBS) $(LIBGCRYPT_LIBS) libexslt_la_LDFLAGS = $(WIN32_EXTRA_LDFLAGS) -version-info $(LIBEXSLT_VERSION_INFO) man_MANS = libexslt.3 EXTRA_DIST = $(man_MANS) libxslt-1.1.28/libexslt/exslt.c0000664000076400007640000000152612024022166013347 00000000000000#define IN_LIBEXSLT #include "libexslt/libexslt.h" #include #include "config.h" #include #include #include #include "exslt.h" const char *exsltLibraryVersion = LIBEXSLT_VERSION_STRING LIBEXSLT_VERSION_EXTRA; const int exsltLibexsltVersion = LIBEXSLT_VERSION; const int exsltLibxsltVersion = LIBXSLT_VERSION; const int exsltLibxmlVersion = LIBXML_VERSION; /** * exsltRegisterAll: * * Registers all available EXSLT extensions */ void exsltRegisterAll (void) { xsltInitGlobals(); exsltCommonRegister(); #ifdef EXSLT_CRYPTO_ENABLED exsltCryptoRegister(); #endif exsltMathRegister(); exsltSetsRegister(); exsltFuncRegister(); exsltStrRegister(); exsltDateRegister(); exsltSaxonRegister(); exsltDynRegister(); } libxslt-1.1.28/libexslt/sets.c0000664000076400007640000002025412021407617013172 00000000000000#define IN_LIBEXSLT #include "libexslt/libexslt.h" #if defined(WIN32) && !defined (__CYGWIN__) && (!__MINGW32__) #include #else #include "config.h" #endif #include #include #include #include #include #include #include "exslt.h" /** * exsltSetsDifferenceFunction: * @ctxt: an XPath parser context * @nargs: the number of arguments * * Wraps #xmlXPathDifference for use by the XPath processor */ static void exsltSetsDifferenceFunction (xmlXPathParserContextPtr ctxt, int nargs) { xmlNodeSetPtr arg1, arg2, ret; if (nargs != 2) { xmlXPathSetArityError(ctxt); return; } arg2 = xmlXPathPopNodeSet(ctxt); if (xmlXPathCheckError(ctxt)) { xmlXPathSetTypeError(ctxt); return; } arg1 = xmlXPathPopNodeSet(ctxt); if (xmlXPathCheckError(ctxt)) { xmlXPathSetTypeError(ctxt); return; } ret = xmlXPathDifference(arg1, arg2); if (ret != arg1) xmlXPathFreeNodeSet(arg1); xmlXPathFreeNodeSet(arg2); xmlXPathReturnNodeSet(ctxt, ret); } /** * exsltSetsIntersectionFunction: * @ctxt: an XPath parser context * @nargs: the number of arguments * * Wraps #xmlXPathIntersection for use by the XPath processor */ static void exsltSetsIntersectionFunction (xmlXPathParserContextPtr ctxt, int nargs) { xmlNodeSetPtr arg1, arg2, ret; if (nargs != 2) { xmlXPathSetArityError(ctxt); return; } arg2 = xmlXPathPopNodeSet(ctxt); if (xmlXPathCheckError(ctxt)) { xmlXPathSetTypeError(ctxt); return; } arg1 = xmlXPathPopNodeSet(ctxt); if (xmlXPathCheckError(ctxt)) { xmlXPathSetTypeError(ctxt); return; } ret = xmlXPathIntersection(arg1, arg2); xmlXPathFreeNodeSet(arg1); xmlXPathFreeNodeSet(arg2); xmlXPathReturnNodeSet(ctxt, ret); } /** * exsltSetsDistinctFunction: * @ctxt: an XPath parser context * @nargs: the number of arguments * * Wraps #xmlXPathDistinct for use by the XPath processor */ static void exsltSetsDistinctFunction (xmlXPathParserContextPtr ctxt, int nargs) { xmlXPathObjectPtr obj; xmlNodeSetPtr ns, ret; int boolval = 0; void *user = NULL; if (nargs != 1) { xmlXPathSetArityError(ctxt); return; } if (ctxt->value != NULL) { boolval = ctxt->value->boolval; user = ctxt->value->user; ctxt->value->boolval = 0; ctxt->value->user = NULL; } ns = xmlXPathPopNodeSet(ctxt); if (xmlXPathCheckError(ctxt)) return; /* !!! must be sorted !!! */ ret = xmlXPathDistinctSorted(ns); if (ret != ns) xmlXPathFreeNodeSet(ns); obj = xmlXPathWrapNodeSet(ret); obj->user = user; obj->boolval = boolval; valuePush((ctxt), obj); } /** * exsltSetsHasSameNodesFunction: * @ctxt: an XPath parser context * @nargs: the number of arguments * * Wraps #xmlXPathHasSameNodes for use by the XPath processor */ static void exsltSetsHasSameNodesFunction (xmlXPathParserContextPtr ctxt, int nargs) { xmlNodeSetPtr arg1, arg2; int ret; if (nargs != 2) { xmlXPathSetArityError(ctxt); return; } arg2 = xmlXPathPopNodeSet(ctxt); if (xmlXPathCheckError(ctxt)) { xmlXPathSetTypeError(ctxt); return; } arg1 = xmlXPathPopNodeSet(ctxt); if (xmlXPathCheckError(ctxt)) { xmlXPathSetTypeError(ctxt); return; } ret = xmlXPathHasSameNodes(arg1, arg2); xmlXPathFreeNodeSet(arg1); xmlXPathFreeNodeSet(arg2); xmlXPathReturnBoolean(ctxt, ret); } /** * exsltSetsLeadingFunction: * @ctxt: an XPath parser context * @nargs: the number of arguments * * Wraps #xmlXPathLeading for use by the XPath processor */ static void exsltSetsLeadingFunction (xmlXPathParserContextPtr ctxt, int nargs) { xmlNodeSetPtr arg1, arg2, ret; if (nargs != 2) { xmlXPathSetArityError(ctxt); return; } arg2 = xmlXPathPopNodeSet(ctxt); if (xmlXPathCheckError(ctxt)) { xmlXPathSetTypeError(ctxt); return; } arg1 = xmlXPathPopNodeSet(ctxt); if (xmlXPathCheckError(ctxt)) { xmlXPathSetTypeError(ctxt); return; } /* If the second node set is empty, then the first node set is * returned. */ if (xmlXPathNodeSetIsEmpty(arg2)) { xmlXPathReturnNodeSet(ctxt, arg1); xmlXPathFreeNodeSet(arg2); return; } /* !!! must be sorted */ ret = xmlXPathNodeLeadingSorted(arg1, xmlXPathNodeSetItem(arg2, 0)); xmlXPathFreeNodeSet(arg1); xmlXPathFreeNodeSet(arg2); xmlXPathReturnNodeSet(ctxt, ret); } /** * exsltSetsTrailingFunction: * @ctxt: an XPath parser context * @nargs: the number of arguments * * Wraps #xmlXPathTrailing for use by the XPath processor */ static void exsltSetsTrailingFunction (xmlXPathParserContextPtr ctxt, int nargs) { xmlNodeSetPtr arg1, arg2, ret; if (nargs != 2) { xmlXPathSetArityError(ctxt); return; } arg2 = xmlXPathPopNodeSet(ctxt); if (xmlXPathCheckError(ctxt)) { xmlXPathSetTypeError(ctxt); return; } arg1 = xmlXPathPopNodeSet(ctxt); if (xmlXPathCheckError(ctxt)) { xmlXPathSetTypeError(ctxt); return; } /* If the second node set is empty, then the first node set is * returned. */ if (xmlXPathNodeSetIsEmpty(arg2)) { xmlXPathReturnNodeSet(ctxt, arg1); xmlXPathFreeNodeSet(arg2); return; } /* !!! mist be sorted */ ret = xmlXPathNodeTrailingSorted(arg1, xmlXPathNodeSetItem(arg2, 0)); xmlXPathFreeNodeSet(arg1); xmlXPathFreeNodeSet(arg2); xmlXPathReturnNodeSet(ctxt, ret); } /** * exsltSetsRegister: * * Registers the EXSLT - Sets module */ void exsltSetsRegister (void) { xsltRegisterExtModuleFunction ((const xmlChar *) "difference", EXSLT_SETS_NAMESPACE, exsltSetsDifferenceFunction); xsltRegisterExtModuleFunction ((const xmlChar *) "intersection", EXSLT_SETS_NAMESPACE, exsltSetsIntersectionFunction); xsltRegisterExtModuleFunction ((const xmlChar *) "distinct", EXSLT_SETS_NAMESPACE, exsltSetsDistinctFunction); xsltRegisterExtModuleFunction ((const xmlChar *) "has-same-node", EXSLT_SETS_NAMESPACE, exsltSetsHasSameNodesFunction); xsltRegisterExtModuleFunction ((const xmlChar *) "leading", EXSLT_SETS_NAMESPACE, exsltSetsLeadingFunction); xsltRegisterExtModuleFunction ((const xmlChar *) "trailing", EXSLT_SETS_NAMESPACE, exsltSetsTrailingFunction); } /** * exsltSetsXpathCtxtRegister: * * Registers the EXSLT - Sets module for use outside XSLT */ int exsltSetsXpathCtxtRegister (xmlXPathContextPtr ctxt, const xmlChar *prefix) { if (ctxt && prefix && !xmlXPathRegisterNs(ctxt, prefix, (const xmlChar *) EXSLT_SETS_NAMESPACE) && !xmlXPathRegisterFuncNS(ctxt, (const xmlChar *) "difference", (const xmlChar *) EXSLT_SETS_NAMESPACE, exsltSetsDifferenceFunction) && !xmlXPathRegisterFuncNS(ctxt, (const xmlChar *) "intersection", (const xmlChar *) EXSLT_SETS_NAMESPACE, exsltSetsIntersectionFunction) && !xmlXPathRegisterFuncNS(ctxt, (const xmlChar *) "distinct", (const xmlChar *) EXSLT_SETS_NAMESPACE, exsltSetsDistinctFunction) && !xmlXPathRegisterFuncNS(ctxt, (const xmlChar *) "has-same-node", (const xmlChar *) EXSLT_SETS_NAMESPACE, exsltSetsHasSameNodesFunction) && !xmlXPathRegisterFuncNS(ctxt, (const xmlChar *) "leading", (const xmlChar *) EXSLT_SETS_NAMESPACE, exsltSetsLeadingFunction) && !xmlXPathRegisterFuncNS(ctxt, (const xmlChar *) "trailing", (const xmlChar *) EXSLT_SETS_NAMESPACE, exsltSetsTrailingFunction)) { return 0; } return -1; } libxslt-1.1.28/libexslt/exsltconfig.h0000664000076400007640000000230212053100424014527 00000000000000/* * exsltconfig.h: compile-time version informations for the EXSLT library * * See Copyright for the status of this software. * * daniel@veillard.com */ #ifndef __XML_EXSLTCONFIG_H__ #define __XML_EXSLTCONFIG_H__ #ifdef __cplusplus extern "C" { #endif /** * LIBEXSLT_DOTTED_VERSION: * * the version string like "1.2.3" */ #define LIBEXSLT_DOTTED_VERSION "1.1.28" /** * LIBEXSLT_VERSION: * * the version number: 1.2.3 value is 10203 */ #define LIBEXSLT_VERSION 817 /** * LIBEXSLT_VERSION_STRING: * * the version number string, 1.2.3 value is "10203" */ #define LIBEXSLT_VERSION_STRING "817" /** * LIBEXSLT_VERSION_EXTRA: * * extra version information, used to show a CVS compilation */ #define LIBEXSLT_VERSION_EXTRA "" /** * WITH_CRYPTO: * * Whether crypto support is configured into exslt */ #if 1 #define EXSLT_CRYPTO_ENABLED #endif /** * ATTRIBUTE_UNUSED: * * This macro is used to flag unused function parameters to GCC */ #ifdef __GNUC__ #ifdef HAVE_ANSIDECL_H #include #endif #ifndef ATTRIBUTE_UNUSED #define ATTRIBUTE_UNUSED __attribute__((unused)) #endif #else #define ATTRIBUTE_UNUSED #endif #ifdef __cplusplus } #endif #endif /* __XML_EXSLTCONFIG_H__ */ libxslt-1.1.28/libexslt/strings.c0000664000076400007640000005435212024022216013702 00000000000000#define IN_LIBEXSLT #include "libexslt/libexslt.h" #if defined(WIN32) && !defined (__CYGWIN__) && (!__MINGW32__) #include #else #include "config.h" #endif #include #include #include #include #include #include #include #include #include #include #include "exslt.h" /** * exsltStrTokenizeFunction: * @ctxt: an XPath parser context * @nargs: the number of arguments * * Splits up a string on the characters of the delimiter string and returns a * node set of token elements, each containing one token from the string. */ static void exsltStrTokenizeFunction(xmlXPathParserContextPtr ctxt, int nargs) { xsltTransformContextPtr tctxt; xmlChar *str, *delimiters, *cur; const xmlChar *token, *delimiter; xmlNodePtr node; xmlDocPtr container; xmlXPathObjectPtr ret = NULL; int clen; if ((nargs < 1) || (nargs > 2)) { xmlXPathSetArityError(ctxt); return; } if (nargs == 2) { delimiters = xmlXPathPopString(ctxt); if (xmlXPathCheckError(ctxt)) return; } else { delimiters = xmlStrdup((const xmlChar *) "\t\r\n "); } if (delimiters == NULL) return; str = xmlXPathPopString(ctxt); if (xmlXPathCheckError(ctxt) || (str == NULL)) { xmlFree(delimiters); return; } /* Return a result tree fragment */ tctxt = xsltXPathGetTransformContext(ctxt); if (tctxt == NULL) { xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, "exslt:tokenize : internal error tctxt == NULL\n"); goto fail; } container = xsltCreateRVT(tctxt); if (container != NULL) { xsltRegisterLocalRVT(tctxt, container); ret = xmlXPathNewNodeSet(NULL); if (ret != NULL) { for (cur = str, token = str; *cur != 0; cur += clen) { clen = xmlUTF8Size(cur); if (*delimiters == 0) { /* empty string case */ xmlChar ctmp; ctmp = *(cur+clen); *(cur+clen) = 0; node = xmlNewDocRawNode(container, NULL, (const xmlChar *) "token", cur); xmlAddChild((xmlNodePtr) container, node); xmlXPathNodeSetAddUnique(ret->nodesetval, node); *(cur+clen) = ctmp; /* restore the changed byte */ token = cur + clen; } else for (delimiter = delimiters; *delimiter != 0; delimiter += xmlUTF8Size(delimiter)) { if (!xmlUTF8Charcmp(cur, delimiter)) { if (cur == token) { /* discard empty tokens */ token = cur + clen; break; } *cur = 0; /* terminate the token */ node = xmlNewDocRawNode(container, NULL, (const xmlChar *) "token", token); xmlAddChild((xmlNodePtr) container, node); xmlXPathNodeSetAddUnique(ret->nodesetval, node); *cur = *delimiter; /* restore the changed byte */ token = cur + clen; break; } } } if (token != cur) { node = xmlNewDocRawNode(container, NULL, (const xmlChar *) "token", token); xmlAddChild((xmlNodePtr) container, node); xmlXPathNodeSetAddUnique(ret->nodesetval, node); } /* * Mark it as a function result in order to avoid garbage * collecting of tree fragments */ xsltExtensionInstructionResultRegister(tctxt, ret); } } fail: if (str != NULL) xmlFree(str); if (delimiters != NULL) xmlFree(delimiters); if (ret != NULL) valuePush(ctxt, ret); else valuePush(ctxt, xmlXPathNewNodeSet(NULL)); } /** * exsltStrSplitFunction: * @ctxt: an XPath parser context * @nargs: the number of arguments * * Splits up a string on a delimiting string and returns a node set of token * elements, each containing one token from the string. */ static void exsltStrSplitFunction(xmlXPathParserContextPtr ctxt, int nargs) { xsltTransformContextPtr tctxt; xmlChar *str, *delimiter, *cur; const xmlChar *token; xmlNodePtr node; xmlDocPtr container; xmlXPathObjectPtr ret = NULL; int delimiterLength; if ((nargs < 1) || (nargs > 2)) { xmlXPathSetArityError(ctxt); return; } if (nargs == 2) { delimiter = xmlXPathPopString(ctxt); if (xmlXPathCheckError(ctxt)) return; } else { delimiter = xmlStrdup((const xmlChar *) " "); } if (delimiter == NULL) return; delimiterLength = xmlStrlen (delimiter); str = xmlXPathPopString(ctxt); if (xmlXPathCheckError(ctxt) || (str == NULL)) { xmlFree(delimiter); return; } /* Return a result tree fragment */ tctxt = xsltXPathGetTransformContext(ctxt); if (tctxt == NULL) { xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, "exslt:tokenize : internal error tctxt == NULL\n"); goto fail; } /* * OPTIMIZE TODO: We are creating an xmlDoc for every split! */ container = xsltCreateRVT(tctxt); if (container != NULL) { xsltRegisterLocalRVT(tctxt, container); ret = xmlXPathNewNodeSet(NULL); if (ret != NULL) { for (cur = str, token = str; *cur != 0; cur++) { if (delimiterLength == 0) { if (cur != token) { xmlChar tmp = *cur; *cur = 0; node = xmlNewDocRawNode(container, NULL, (const xmlChar *) "token", token); xmlAddChild((xmlNodePtr) container, node); xmlXPathNodeSetAddUnique(ret->nodesetval, node); *cur = tmp; token++; } } else if (!xmlStrncasecmp(cur, delimiter, delimiterLength)) { if (cur == token) { /* discard empty tokens */ cur = cur + delimiterLength - 1; token = cur + 1; continue; } *cur = 0; node = xmlNewDocRawNode(container, NULL, (const xmlChar *) "token", token); xmlAddChild((xmlNodePtr) container, node); xmlXPathNodeSetAddUnique(ret->nodesetval, node); *cur = *delimiter; cur = cur + delimiterLength - 1; token = cur + 1; } } if (token != cur) { node = xmlNewDocRawNode(container, NULL, (const xmlChar *) "token", token); xmlAddChild((xmlNodePtr) container, node); xmlXPathNodeSetAddUnique(ret->nodesetval, node); } /* * Mark it as a function result in order to avoid garbage * collecting of tree fragments */ xsltExtensionInstructionResultRegister(tctxt, ret); } } fail: if (str != NULL) xmlFree(str); if (delimiter != NULL) xmlFree(delimiter); if (ret != NULL) valuePush(ctxt, ret); else valuePush(ctxt, xmlXPathNewNodeSet(NULL)); } /** * exsltStrEncodeUriFunction: * @ctxt: an XPath parser context * @nargs: the number of arguments * * URI-Escapes a string */ static void exsltStrEncodeUriFunction (xmlXPathParserContextPtr ctxt, int nargs) { int escape_all = 1, str_len = 0; xmlChar *str = NULL, *ret = NULL, *tmp; if ((nargs < 2) || (nargs > 3)) { xmlXPathSetArityError(ctxt); return; } if (nargs >= 3) { /* check for UTF-8 if encoding was explicitly given; we don't support anything else yet */ tmp = xmlXPathPopString(ctxt); if (xmlUTF8Strlen(tmp) != 5 || xmlStrcmp((const xmlChar *)"UTF-8",tmp)) { xmlXPathReturnEmptyString(ctxt); xmlFree(tmp); return; } xmlFree(tmp); } escape_all = xmlXPathPopBoolean(ctxt); str = xmlXPathPopString(ctxt); str_len = xmlUTF8Strlen(str); if (str_len == 0) { xmlXPathReturnEmptyString(ctxt); xmlFree(str); return; } ret = xmlURIEscapeStr(str,(const xmlChar *)(escape_all?"-_.!~*'()":"-_.!~*'();/?:@&=+$,[]")); xmlXPathReturnString(ctxt, ret); if (str != NULL) xmlFree(str); } /** * exsltStrDecodeUriFunction: * @ctxt: an XPath parser context * @nargs: the number of arguments * * reverses URI-Escaping of a string */ static void exsltStrDecodeUriFunction (xmlXPathParserContextPtr ctxt, int nargs) { int str_len = 0; xmlChar *str = NULL, *ret = NULL, *tmp; if ((nargs < 1) || (nargs > 2)) { xmlXPathSetArityError(ctxt); return; } if (nargs >= 2) { /* check for UTF-8 if encoding was explicitly given; we don't support anything else yet */ tmp = xmlXPathPopString(ctxt); if (xmlUTF8Strlen(tmp) != 5 || xmlStrcmp((const xmlChar *)"UTF-8",tmp)) { xmlXPathReturnEmptyString(ctxt); xmlFree(tmp); return; } xmlFree(tmp); } str = xmlXPathPopString(ctxt); str_len = xmlUTF8Strlen(str); if (str_len == 0) { xmlXPathReturnEmptyString(ctxt); xmlFree(str); return; } ret = (xmlChar *) xmlURIUnescapeString((const char *)str,0,NULL); if (!xmlCheckUTF8(ret)) { /* FIXME: instead of throwing away the whole URI, we should only discard the invalid sequence(s). How to do that? */ xmlXPathReturnEmptyString(ctxt); xmlFree(str); xmlFree(ret); return; } xmlXPathReturnString(ctxt, ret); if (str != NULL) xmlFree(str); } /** * exsltStrPaddingFunction: * @ctxt: an XPath parser context * @nargs: the number of arguments * * Creates a padding string of a certain length. */ static void exsltStrPaddingFunction (xmlXPathParserContextPtr ctxt, int nargs) { int number, str_len = 0; xmlChar *str = NULL, *ret = NULL, *tmp; if ((nargs < 1) || (nargs > 2)) { xmlXPathSetArityError(ctxt); return; } if (nargs == 2) { str = xmlXPathPopString(ctxt); str_len = xmlUTF8Strlen(str); } if (str_len == 0) { if (str != NULL) xmlFree(str); str = xmlStrdup((const xmlChar *) " "); str_len = 1; } number = (int) xmlXPathPopNumber(ctxt); if (number <= 0) { xmlXPathReturnEmptyString(ctxt); xmlFree(str); return; } while (number >= str_len) { ret = xmlStrncat(ret, str, str_len); number -= str_len; } tmp = xmlUTF8Strndup (str, number); ret = xmlStrcat(ret, tmp); if (tmp != NULL) xmlFree (tmp); xmlXPathReturnString(ctxt, ret); if (str != NULL) xmlFree(str); } /** * exsltStrAlignFunction: * @ctxt: an XPath parser context * @nargs: the number of arguments * * Aligns a string within another string. */ static void exsltStrAlignFunction (xmlXPathParserContextPtr ctxt, int nargs) { xmlChar *str, *padding, *alignment, *ret; int str_l, padding_l; if ((nargs < 2) || (nargs > 3)) { xmlXPathSetArityError(ctxt); return; } if (nargs == 3) alignment = xmlXPathPopString(ctxt); else alignment = NULL; padding = xmlXPathPopString(ctxt); str = xmlXPathPopString(ctxt); str_l = xmlUTF8Strlen (str); padding_l = xmlUTF8Strlen (padding); if (str_l == padding_l) { xmlXPathReturnString (ctxt, str); xmlFree(padding); xmlFree(alignment); return; } if (str_l > padding_l) { ret = xmlUTF8Strndup (str, padding_l); } else { if (xmlStrEqual(alignment, (const xmlChar *) "right")) { ret = xmlUTF8Strndup (padding, padding_l - str_l); ret = xmlStrcat (ret, str); } else if (xmlStrEqual(alignment, (const xmlChar *) "center")) { int left = (padding_l - str_l) / 2; int right_start; ret = xmlUTF8Strndup (padding, left); ret = xmlStrcat (ret, str); right_start = xmlUTF8Strsize (padding, left + str_l); ret = xmlStrcat (ret, padding + right_start); } else { int str_s; str_s = xmlStrlen (str); ret = xmlStrdup (str); ret = xmlStrcat (ret, padding + str_s); } } xmlXPathReturnString (ctxt, ret); xmlFree(str); xmlFree(padding); xmlFree(alignment); } /** * exsltStrConcatFunction: * @ctxt: an XPath parser context * @nargs: the number of arguments * * Takes a node set and returns the concatenation of the string values * of the nodes in that node set. If the node set is empty, it * returns an empty string. */ static void exsltStrConcatFunction (xmlXPathParserContextPtr ctxt, int nargs) { xmlXPathObjectPtr obj; xmlChar *ret = NULL; int i; if (nargs != 1) { xmlXPathSetArityError(ctxt); return; } if (!xmlXPathStackIsNodeSet(ctxt)) { xmlXPathSetTypeError(ctxt); return; } obj = valuePop (ctxt); if (xmlXPathNodeSetIsEmpty(obj->nodesetval)) { xmlXPathReturnEmptyString(ctxt); return; } for (i = 0; i < obj->nodesetval->nodeNr; i++) { xmlChar *tmp; tmp = xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]); ret = xmlStrcat (ret, tmp); xmlFree(tmp); } xmlXPathFreeObject (obj); xmlXPathReturnString(ctxt, ret); } /** * exsltStrReturnString: * @ctxt: an XPath parser context * @str: a string * @len: length of string * * Returns a string as a node set. */ static int exsltStrReturnString(xmlXPathParserContextPtr ctxt, const xmlChar *str, int len) { xsltTransformContextPtr tctxt = xsltXPathGetTransformContext(ctxt); xmlDocPtr container; xmlNodePtr text_node; xmlXPathObjectPtr ret; container = xsltCreateRVT(tctxt); if (container == NULL) { xmlXPathSetError(ctxt, XPATH_MEMORY_ERROR); return(-1); } xsltRegisterLocalRVT(tctxt, container); text_node = xmlNewTextLen(str, len); if (text_node == NULL) { xmlXPathSetError(ctxt, XPATH_MEMORY_ERROR); return(-1); } xmlAddChild((xmlNodePtr) container, text_node); ret = xmlXPathNewNodeSet(text_node); if (ret == NULL) { xmlXPathSetError(ctxt, XPATH_MEMORY_ERROR); return(-1); } xsltExtensionInstructionResultRegister(tctxt, ret); valuePush(ctxt, ret); return(0); } /** * exsltStrReplaceFunction: * @ctxt: an XPath parser context * @nargs: the number of arguments * * Takes a string, and two node sets and returns the string with all strings in * the first node set replaced by all strings in the second node set. */ static void exsltStrReplaceFunction (xmlXPathParserContextPtr ctxt, int nargs) { int i, i_empty, n, slen0, rlen0, *slen, *rlen; void *mem = NULL; const xmlChar *src, *start; xmlChar *string, *search_str = NULL, *replace_str = NULL; xmlChar **search, **replace; xmlNodeSetPtr search_set = NULL, replace_set = NULL; xmlBufferPtr buf; if (nargs != 3) { xmlXPathSetArityError(ctxt); return; } /* get replace argument */ if (!xmlXPathStackIsNodeSet(ctxt)) replace_str = xmlXPathPopString(ctxt); else replace_set = xmlXPathPopNodeSet(ctxt); if (xmlXPathCheckError(ctxt)) goto fail_replace; /* get search argument */ if (!xmlXPathStackIsNodeSet(ctxt)) { search_str = xmlXPathPopString(ctxt); n = 1; } else { search_set = xmlXPathPopNodeSet(ctxt); n = search_set != NULL ? search_set->nodeNr : 0; } if (xmlXPathCheckError(ctxt)) goto fail_search; /* get string argument */ string = xmlXPathPopString(ctxt); if (xmlXPathCheckError(ctxt)) goto fail_string; /* check for empty search node list */ if (n <= 0) { exsltStrReturnString(ctxt, string, xmlStrlen(string)); goto done_empty_search; } /* allocate memory for string pointer and length arrays */ if (n == 1) { search = &search_str; replace = &replace_str; slen = &slen0; rlen = &rlen0; } else { mem = xmlMalloc(2 * n * (sizeof(const xmlChar *) + sizeof(int))); if (mem == NULL) { xmlXPathSetError(ctxt, XPATH_MEMORY_ERROR); goto fail_malloc; } search = (xmlChar **) mem; replace = search + n; slen = (int *) (replace + n); rlen = slen + n; } /* process arguments */ i_empty = -1; for (i=0; inodeTab[i]); if (search[i] == NULL) { n = i; goto fail_process_args; } } slen[i] = xmlStrlen(search[i]); if (i_empty < 0 && slen[i] == 0) i_empty = i; if (replace_set != NULL) { if (i < replace_set->nodeNr) { replace[i] = xmlXPathCastNodeToString(replace_set->nodeTab[i]); if (replace[i] == NULL) { n = i + 1; goto fail_process_args; } } else replace[i] = NULL; } else { if (i == 0) replace[i] = replace_str; else replace[i] = NULL; } if (replace[i] == NULL) rlen[i] = 0; else rlen[i] = xmlStrlen(replace[i]); } if (i_empty >= 0 && rlen[i_empty] == 0) i_empty = -1; /* replace operation */ buf = xmlBufferCreate(); if (buf == NULL) { xmlXPathSetError(ctxt, XPATH_MEMORY_ERROR); goto fail_buffer; } src = string; start = string; while (*src != 0) { int max_len = 0, i_match = 0; for (i=0; i max_len && xmlStrncmp(src, search[i], slen[i]) == 0) { i_match = i; max_len = slen[i]; } } if (max_len == 0) { if (i_empty >= 0 && start < src) { if (xmlBufferAdd(buf, start, src - start) || xmlBufferAdd(buf, replace[i_empty], rlen[i_empty])) { xmlXPathSetError(ctxt, XPATH_MEMORY_ERROR); goto fail_buffer_add; } start = src; } src += xmlUTF8Size(src); } else { if ((start < src && xmlBufferAdd(buf, start, src - start)) || (rlen[i_match] && xmlBufferAdd(buf, replace[i_match], rlen[i_match]))) { xmlXPathSetError(ctxt, XPATH_MEMORY_ERROR); goto fail_buffer_add; } src += slen[i_match]; start = src; } } if (start < src && xmlBufferAdd(buf, start, src - start)) { xmlXPathSetError(ctxt, XPATH_MEMORY_ERROR); goto fail_buffer_add; } /* create result node set */ exsltStrReturnString(ctxt, xmlBufferContent(buf), xmlBufferLength(buf)); /* clean up */ fail_buffer_add: xmlBufferFree(buf); fail_buffer: fail_process_args: if (search_set != NULL) { for (i=0; i #else #include "config.h" #endif #include #include #include #include #include #include #include #ifdef HAVE_MATH_H #include #endif #ifdef HAVE_STDLIB_H #include #endif #include "exslt.h" /** * exsltMathMin: * @ns: a node-set * * Implements the EXSLT - Math min() function: * number math:min (node-set) * * Returns the minimum value of the nodes passed as the argument, or * xmlXPathNAN if @ns is NULL or empty or if one of the nodes * turns into NaN. */ static double exsltMathMin (xmlNodeSetPtr ns) { double ret, cur; int i; if ((ns == NULL) || (ns->nodeNr == 0)) return(xmlXPathNAN); ret = xmlXPathCastNodeToNumber(ns->nodeTab[0]); if (xmlXPathIsNaN(ret)) return(xmlXPathNAN); for (i = 1; i < ns->nodeNr; i++) { cur = xmlXPathCastNodeToNumber(ns->nodeTab[i]); if (xmlXPathIsNaN(cur)) return(xmlXPathNAN); if (cur < ret) ret = cur; } return(ret); } /** * exsltMathMinFunction: * @ctxt: an XPath parser context * @nargs: the number of arguments * * Wraps #exsltMathMin for use by the XPath processor. */ static void exsltMathMinFunction (xmlXPathParserContextPtr ctxt, int nargs) { xmlNodeSetPtr ns; double ret; void *user = NULL; if (nargs != 1) { xsltGenericError(xsltGenericErrorContext, "math:min: invalid number of arguments\n"); ctxt->error = XPATH_INVALID_ARITY; return; } /* We need to delay the freeing of value->user */ if ((ctxt->value != NULL) && (ctxt->value->boolval != 0)) { user = ctxt->value->user; ctxt->value->boolval = 0; ctxt->value->user = NULL; } ns = xmlXPathPopNodeSet(ctxt); if (xmlXPathCheckError(ctxt)) return; ret = exsltMathMin(ns); xmlXPathFreeNodeSet(ns); if (user != NULL) xmlFreeNodeList((xmlNodePtr)user); xmlXPathReturnNumber(ctxt, ret); } /** * exsltMathMax: * @ns: a node-set * * Implements the EXSLT - Math max() function: * number math:max (node-set) * * Returns the maximum value of the nodes passed as arguments, or * xmlXPathNAN if @ns is NULL or empty or if one of the nodes * turns into NaN. */ static double exsltMathMax (xmlNodeSetPtr ns) { double ret, cur; int i; if ((ns == NULL) || (ns->nodeNr == 0)) return(xmlXPathNAN); ret = xmlXPathCastNodeToNumber(ns->nodeTab[0]); if (xmlXPathIsNaN(ret)) return(xmlXPathNAN); for (i = 1; i < ns->nodeNr; i++) { cur = xmlXPathCastNodeToNumber(ns->nodeTab[i]); if (xmlXPathIsNaN(cur)) return(xmlXPathNAN); if (cur > ret) ret = cur; } return(ret); } /** * exsltMathMaxFunction: * @ctxt: an XPath parser context * @nargs: the number of arguments * * Wraps #exsltMathMax for use by the XPath processor. */ static void exsltMathMaxFunction (xmlXPathParserContextPtr ctxt, int nargs) { xmlNodeSetPtr ns; double ret; void *user = NULL; if (nargs != 1) { xmlXPathSetArityError(ctxt); return; } /* We need to delay the freeing of value->user */ if ((ctxt->value != NULL) && (ctxt->value->boolval != 0)) { user = ctxt->value->user; ctxt->value->boolval = 0; ctxt->value->user = 0; } ns = xmlXPathPopNodeSet(ctxt); if (xmlXPathCheckError(ctxt)) return; ret = exsltMathMax(ns); xmlXPathFreeNodeSet(ns); if (user != NULL) xmlFreeNodeList((xmlNodePtr)user); xmlXPathReturnNumber(ctxt, ret); } /** * exsltMathHighest: * @ns: a node-set * * Implements the EXSLT - Math highest() function: * node-set math:highest (node-set) * * Returns the nodes in the node-set whose value is the maximum value * for the node-set. */ static xmlNodeSetPtr exsltMathHighest (xmlNodeSetPtr ns) { xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL); double max, cur; int i; if ((ns == NULL) || (ns->nodeNr == 0)) return(ret); max = xmlXPathCastNodeToNumber(ns->nodeTab[0]); if (xmlXPathIsNaN(max)) return(ret); else xmlXPathNodeSetAddUnique(ret, ns->nodeTab[0]); for (i = 1; i < ns->nodeNr; i++) { cur = xmlXPathCastNodeToNumber(ns->nodeTab[i]); if (xmlXPathIsNaN(cur)) { xmlXPathEmptyNodeSet(ret); return(ret); } if (cur < max) continue; if (cur > max) { max = cur; xmlXPathEmptyNodeSet(ret); xmlXPathNodeSetAddUnique(ret, ns->nodeTab[i]); continue; } xmlXPathNodeSetAddUnique(ret, ns->nodeTab[i]); } return(ret); } /** * exsltMathHighestFunction: * @ctxt: an XPath parser context * @nargs: the number of arguments * * Wraps #exsltMathHighest for use by the XPath processor */ static void exsltMathHighestFunction (xmlXPathParserContextPtr ctxt, int nargs) { xmlNodeSetPtr ns, ret; void *user = NULL; if (nargs != 1) { xmlXPathSetArityError(ctxt); return; } /* We need to delay the freeing of value->user */ if ((ctxt->value != NULL) && ctxt->value->boolval != 0) { user = ctxt->value->user; ctxt->value->boolval = 0; ctxt->value->user = NULL; } ns = xmlXPathPopNodeSet(ctxt); if (xmlXPathCheckError(ctxt)) return; ret = exsltMathHighest(ns); xmlXPathFreeNodeSet(ns); if (user != NULL) xmlFreeNodeList((xmlNodePtr)user); xmlXPathReturnNodeSet(ctxt, ret); } /** * exsltMathLowest: * @ns: a node-set * * Implements the EXSLT - Math lowest() function * node-set math:lowest (node-set) * * Returns the nodes in the node-set whose value is the minimum value * for the node-set. */ static xmlNodeSetPtr exsltMathLowest (xmlNodeSetPtr ns) { xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL); double min, cur; int i; if ((ns == NULL) || (ns->nodeNr == 0)) return(ret); min = xmlXPathCastNodeToNumber(ns->nodeTab[0]); if (xmlXPathIsNaN(min)) return(ret); else xmlXPathNodeSetAddUnique(ret, ns->nodeTab[0]); for (i = 1; i < ns->nodeNr; i++) { cur = xmlXPathCastNodeToNumber(ns->nodeTab[i]); if (xmlXPathIsNaN(cur)) { xmlXPathEmptyNodeSet(ret); return(ret); } if (cur > min) continue; if (cur < min) { min = cur; xmlXPathEmptyNodeSet(ret); xmlXPathNodeSetAddUnique(ret, ns->nodeTab[i]); continue; } xmlXPathNodeSetAddUnique(ret, ns->nodeTab[i]); } return(ret); } /** * exsltMathLowestFunction: * @ctxt: an XPath parser context * @nargs: the number of arguments * * Wraps #exsltMathLowest for use by the XPath processor */ static void exsltMathLowestFunction (xmlXPathParserContextPtr ctxt, int nargs) { xmlNodeSetPtr ns, ret; void *user = NULL; if (nargs != 1) { xmlXPathSetArityError(ctxt); return; } /* We need to delay the freeing of value->user */ if ((ctxt->value != NULL) && (ctxt->value->boolval != 0)) { user = ctxt->value->user; ctxt->value->boolval = 0; ctxt->value->user = NULL; } ns = xmlXPathPopNodeSet(ctxt); if (xmlXPathCheckError(ctxt)) return; ret = exsltMathLowest(ns); xmlXPathFreeNodeSet(ns); if (user != NULL) xmlFreeNodeList((xmlNodePtr)user); xmlXPathReturnNodeSet(ctxt, ret); } /* math other functions */ /* constant values */ #define EXSLT_PI (const xmlChar *) \ "3.1415926535897932384626433832795028841971693993751" #define EXSLT_E (const xmlChar *) \ "2.71828182845904523536028747135266249775724709369996" #define EXSLT_SQRRT2 (const xmlChar *) \ "1.41421356237309504880168872420969807856967187537694" #define EXSLT_LN2 (const xmlChar *) \ "0.69314718055994530941723212145817656807550013436025" #define EXSLT_LN10 (const xmlChar *) \ "2.30258509299404568402" #define EXSLT_LOG2E (const xmlChar *) \ "1.4426950408889634074" #define EXSLT_SQRT1_2 (const xmlChar *) \ "0.70710678118654752440" /** * exsltMathConstant * @name: string * @precision: number * * Implements the EXSLT - Math constant function: * number math:constant(string, number) * * Returns a number value of the given constant with the given precision or * xmlXPathNAN if name is unknown. * The constants are PI, E, SQRRT2, LN2, LN10, LOG2E, and SQRT1_2 */ static double exsltMathConstant (xmlChar *name, double precision) { xmlChar *str; double ret; if ((name == NULL) || (xmlXPathIsNaN(precision)) || (precision < 1.0)) { return xmlXPathNAN; } if (xmlStrEqual(name, BAD_CAST "PI")) { int len = xmlStrlen(EXSLT_PI); if (precision <= len) len = (int)precision; str = xmlStrsub(EXSLT_PI, 0, len); } else if (xmlStrEqual(name, BAD_CAST "E")) { int len = xmlStrlen(EXSLT_E); if (precision <= len) len = (int)precision; str = xmlStrsub(EXSLT_E, 0, len); } else if (xmlStrEqual(name, BAD_CAST "SQRRT2")) { int len = xmlStrlen(EXSLT_SQRRT2); if (precision <= len) len = (int)precision; str = xmlStrsub(EXSLT_SQRRT2, 0, len); } else if (xmlStrEqual(name, BAD_CAST "LN2")) { int len = xmlStrlen(EXSLT_LN2); if (precision <= len) len = (int)precision; str = xmlStrsub(EXSLT_LN2, 0, len); } else if (xmlStrEqual(name, BAD_CAST "LN10")) { int len = xmlStrlen(EXSLT_LN10); if (precision <= len) len = (int)precision; str = xmlStrsub(EXSLT_LN10, 0, len); } else if (xmlStrEqual(name, BAD_CAST "LOG2E")) { int len = xmlStrlen(EXSLT_LOG2E); if (precision <= len) len = (int)precision; str = xmlStrsub(EXSLT_LOG2E, 0, len); } else if (xmlStrEqual(name, BAD_CAST "SQRT1_2")) { int len = xmlStrlen(EXSLT_SQRT1_2); if (precision <= len) len = (int)precision; str = xmlStrsub(EXSLT_SQRT1_2, 0, len); } else { str = NULL; } if (str == NULL) return xmlXPathNAN; ret = xmlXPathCastStringToNumber(str); xmlFree(str); return ret; } /** * exsltMathConstantFunction: * @ctxt: an XPath parser context * @nargs: the number of arguments * * Wraps #exsltMathConstant for use by the XPath processor. */ static void exsltMathConstantFunction (xmlXPathParserContextPtr ctxt, int nargs) { double ret; xmlChar *name; if (nargs != 2) { xmlXPathSetArityError(ctxt); return; } ret = xmlXPathPopNumber(ctxt); if (xmlXPathCheckError(ctxt)) return; name = xmlXPathPopString(ctxt); if (xmlXPathCheckError(ctxt)) return; ret = exsltMathConstant(name, ret); if (name != NULL) xmlFree(name); xmlXPathReturnNumber(ctxt, ret); } #if defined(HAVE_STDLIB_H) && defined(RAND_MAX) /** * exsltMathRandom: * * Implements the EXSLT - Math random() function: * number math:random () * * Returns a random number between 0 and 1 inclusive. */ static double exsltMathRandom (void) { double ret; int num; num = rand(); ret = (double)num / (double)RAND_MAX; return(ret); } /** * exsltMathRandomFunction: * @ctxt: an XPath parser context * @nargs: the number of arguments * * Wraps #exsltMathRandom for use by the XPath processor. */ static void exsltMathRandomFunction (xmlXPathParserContextPtr ctxt, int nargs) { double ret; if (nargs != 0) { xmlXPathSetArityError(ctxt); return; } ret = exsltMathRandom(); xmlXPathReturnNumber(ctxt, ret); } #endif /* defined(HAVE_STDLIB_H) && defined(RAND_MAX) */ #if HAVE_MATH_H /** * exsltMathAbs: * @num: a double * * Implements the EXSLT - Math abs() function: * number math:abs (number) * * Returns the absolute value of the argument, or xmlXPathNAN if @num is Nan. */ static double exsltMathAbs (double num) { double ret; if (xmlXPathIsNaN(num)) return(xmlXPathNAN); ret = fabs(num); return(ret); } /** * exsltMathAbsFunction: * @ctxt: an XPath parser context * @nargs: the number of arguments * * Wraps #exsltMathAbs for use by the XPath processor. */ static void exsltMathAbsFunction (xmlXPathParserContextPtr ctxt, int nargs) { double ret; if (nargs != 1) { xmlXPathSetArityError(ctxt); return; } ret = xmlXPathPopNumber(ctxt); if (xmlXPathCheckError(ctxt)) return; ret = exsltMathAbs(ret); xmlXPathReturnNumber(ctxt, ret); } /** * exsltMathSqrt: * @num: a double * * Implements the EXSLT - Math sqrt() function: * number math:sqrt (number) * * Returns the square root of the argument, or xmlXPathNAN if @num is Nan. */ static double exsltMathSqrt (double num) { double ret; if (xmlXPathIsNaN(num)) return(xmlXPathNAN); ret = sqrt(num); return(ret); } /** * exsltMathSqrtFunction: * @ctxt: an XPath parser context * @nargs: the number of arguments * * Wraps #exsltMathSqrt for use by the XPath processor. */ static void exsltMathSqrtFunction (xmlXPathParserContextPtr ctxt, int nargs) { double ret; if (nargs != 1) { xmlXPathSetArityError(ctxt); return; } ret = xmlXPathPopNumber(ctxt); if (xmlXPathCheckError(ctxt)) return; ret = exsltMathSqrt(ret); xmlXPathReturnNumber(ctxt, ret); } /** * exsltMathPower: * @base: a double * @power: a double * * Implements the EXSLT - Math power() function: * number math:power (number, number) * * Returns the power base and power arguments, or xmlXPathNAN * if either @base or @power is Nan. */ static double exsltMathPower (double base, double power) { double ret; if ((xmlXPathIsNaN(base) || xmlXPathIsNaN(power))) return(xmlXPathNAN); ret = pow(base, power); return(ret); } /** * exsltMathPower: * @ctxt: an XPath parser context * @nargs: the number of arguments * * Wraps #exsltMathPower for use by the XPath processor. */ static void exsltMathPowerFunction (xmlXPathParserContextPtr ctxt, int nargs) { double ret, base; if (nargs != 2) { xmlXPathSetArityError(ctxt); return; } ret = xmlXPathPopNumber(ctxt); if (xmlXPathCheckError(ctxt)) return; /* power */ base = xmlXPathPopNumber(ctxt); if (xmlXPathCheckError(ctxt)) return; ret = exsltMathPower(base, ret); xmlXPathReturnNumber(ctxt, ret); } /** * exsltMathLog: * @num: a double * * Implements the EXSLT - Math log() function: * number math:log (number) * * Returns the natural log of the argument, or xmlXPathNAN if @num is Nan. */ static double exsltMathLog (double num) { double ret; if (xmlXPathIsNaN(num)) return(xmlXPathNAN); ret = log(num); return(ret); } /** * exsltMathLogFunction: * @ctxt: an XPath parser context * @nargs: the number of arguments * * Wraps #exsltMathLog for use by the XPath processor. */ static void exsltMathLogFunction (xmlXPathParserContextPtr ctxt, int nargs) { double ret; if (nargs != 1) { xmlXPathSetArityError(ctxt); return; } ret = xmlXPathPopNumber(ctxt); if (xmlXPathCheckError(ctxt)) return; ret = exsltMathLog(ret); xmlXPathReturnNumber(ctxt, ret); } /** * exsltMathSin: * @num: a double * * Implements the EXSLT - Math sin() function: * number math:sin (number) * * Returns the sine of the argument, or xmlXPathNAN if @num is Nan. */ static double exsltMathSin (double num) { double ret; if (xmlXPathIsNaN(num)) return(xmlXPathNAN); ret = sin(num); return(ret); } /** * exsltMathSinFunction: * @ctxt: an XPath parser context * @nargs: the number of arguments * * Wraps #exsltMathSin for use by the XPath processor. */ static void exsltMathSinFunction (xmlXPathParserContextPtr ctxt, int nargs) { double ret; if (nargs != 1) { xmlXPathSetArityError(ctxt); return; } ret = xmlXPathPopNumber(ctxt); if (xmlXPathCheckError(ctxt)) return; ret = exsltMathSin(ret); xmlXPathReturnNumber(ctxt, ret); } /** * exsltMathCos: * @num: a double * * Implements the EXSLT - Math cos() function: * number math:cos (number) * * Returns the cosine of the argument, or xmlXPathNAN if @num is Nan. */ static double exsltMathCos (double num) { double ret; if (xmlXPathIsNaN(num)) return(xmlXPathNAN); ret = cos(num); return(ret); } /** * exsltMathCosFunction: * @ctxt: an XPath parser context * @nargs: the number of arguments * * Wraps #exsltMathCos for use by the XPath processor. */ static void exsltMathCosFunction (xmlXPathParserContextPtr ctxt, int nargs) { double ret; if (nargs != 1) { xmlXPathSetArityError(ctxt); return; } ret = xmlXPathPopNumber(ctxt); if (xmlXPathCheckError(ctxt)) return; ret = exsltMathCos(ret); xmlXPathReturnNumber(ctxt, ret); } /** * exsltMathTan: * @num: a double * * Implements the EXSLT - Math tan() function: * number math:tan (number) * * Returns the tangent of the argument, or xmlXPathNAN if @num is Nan. */ static double exsltMathTan (double num) { double ret; if (xmlXPathIsNaN(num)) return(xmlXPathNAN); ret = tan(num); return(ret); } /** * exsltMathTanFunction: * @ctxt: an XPath parser context * @nargs: the number of arguments * * Wraps #exsltMathTan for use by the XPath processor. */ static void exsltMathTanFunction (xmlXPathParserContextPtr ctxt, int nargs) { double ret; if (nargs != 1) { xmlXPathSetArityError(ctxt); return; } ret = xmlXPathPopNumber(ctxt); if (xmlXPathCheckError(ctxt)) return; ret = exsltMathTan(ret); xmlXPathReturnNumber(ctxt, ret); } /** * exsltMathAsin: * @num: a double * * Implements the EXSLT - Math asin() function: * number math:asin (number) * * Returns the arc sine of the argument, or xmlXPathNAN if @num is Nan. */ static double exsltMathAsin (double num) { double ret; if (xmlXPathIsNaN(num)) return(xmlXPathNAN); ret = asin(num); return(ret); } /** * exsltMathAsinFunction: * @ctxt: an XPath parser context * @nargs: the number of arguments * * Wraps #exsltMathAsin for use by the XPath processor. */ static void exsltMathAsinFunction (xmlXPathParserContextPtr ctxt, int nargs) { double ret; if (nargs != 1) { xmlXPathSetArityError(ctxt); return; } ret = xmlXPathPopNumber(ctxt); if (xmlXPathCheckError(ctxt)) return; ret = exsltMathAsin(ret); xmlXPathReturnNumber(ctxt, ret); } /** * exsltMathAcos: * @num: a double * * Implements the EXSLT - Math acos() function: * number math:acos (number) * * Returns the arc cosine of the argument, or xmlXPathNAN if @num is Nan. */ static double exsltMathAcos (double num) { double ret; if (xmlXPathIsNaN(num)) return(xmlXPathNAN); ret = acos(num); return(ret); } /** * exsltMathAcosFunction: * @ctxt: an XPath parser context * @nargs: the number of arguments * * Wraps #exsltMathAcos for use by the XPath processor. */ static void exsltMathAcosFunction (xmlXPathParserContextPtr ctxt, int nargs) { double ret; if (nargs != 1) { xmlXPathSetArityError(ctxt); return; } ret = xmlXPathPopNumber(ctxt); if (xmlXPathCheckError(ctxt)) return; ret = exsltMathAcos(ret); xmlXPathReturnNumber(ctxt, ret); } /** * exsltMathAtan: * @num: a double * * Implements the EXSLT - Math atan() function: * number math:atan (number) * * Returns the arc tangent of the argument, or xmlXPathNAN if @num is Nan. */ static double exsltMathAtan (double num) { double ret; if (xmlXPathIsNaN(num)) return(xmlXPathNAN); ret = atan(num); return(ret); } /** * exsltMathAtanFunction: * @ctxt: an XPath parser context * @nargs: the number of arguments * * Wraps #exsltMathAtan for use by the XPath processor. */ static void exsltMathAtanFunction (xmlXPathParserContextPtr ctxt, int nargs) { double ret; if (nargs != 1) { xmlXPathSetArityError(ctxt); return; } ret = xmlXPathPopNumber(ctxt); if (xmlXPathCheckError(ctxt)) return; ret = exsltMathAtan(ret); xmlXPathReturnNumber(ctxt, ret); } /** * exsltMathAtan2: * @y: a double * @x: a double * * Implements the EXSLT - Math atan2() function: * number math:atan2 (number, number) * * Returns the arc tangent function of the y/x arguments, or xmlXPathNAN * if either @y or @x is Nan. */ static double exsltMathAtan2 (double y, double x) { double ret; if ((xmlXPathIsNaN(y) || xmlXPathIsNaN(x))) return(xmlXPathNAN); ret = atan2(y, x); return(ret); } /** * exsltMathAtan2Function: * @ctxt: an XPath parser context * @nargs: the number of arguments * * Wraps #exsltMathAtan2 for use by the XPath processor. */ static void exsltMathAtan2Function (xmlXPathParserContextPtr ctxt, int nargs) { double ret, x; if (nargs != 2) { xmlXPathSetArityError(ctxt); return; } x = xmlXPathPopNumber(ctxt); if (xmlXPathCheckError(ctxt)) return; /* y */ ret = xmlXPathPopNumber(ctxt); if (xmlXPathCheckError(ctxt)) return; ret = exsltMathAtan2(ret, x); xmlXPathReturnNumber(ctxt, ret); } /** * exsltMathExp: * @num: a double * * Implements the EXSLT - Math exp() function: * number math:exp (number) * * Returns the exponential function of the argument, or xmlXPathNAN if * @num is Nan. */ static double exsltMathExp (double num) { double ret; if (xmlXPathIsNaN(num)) return(xmlXPathNAN); ret = exp(num); return(ret); } /** * exsltMathExpFunction: * @ctxt: an XPath parser context * @nargs: the number of arguments * * Wraps #exsltMathExp for use by the XPath processor. */ static void exsltMathExpFunction (xmlXPathParserContextPtr ctxt, int nargs) { double ret; if (nargs != 1) { xmlXPathSetArityError(ctxt); return; } ret = xmlXPathPopNumber(ctxt); if (xmlXPathCheckError(ctxt)) return; ret = exsltMathExp(ret); xmlXPathReturnNumber(ctxt, ret); } #endif /* HAVE_MATH_H */ /** * exsltMathRegister: * * Registers the EXSLT - Math module */ void exsltMathRegister (void) { xsltRegisterExtModuleFunction ((const xmlChar *) "min", EXSLT_MATH_NAMESPACE, exsltMathMinFunction); xsltRegisterExtModuleFunction ((const xmlChar *) "max", EXSLT_MATH_NAMESPACE, exsltMathMaxFunction); xsltRegisterExtModuleFunction ((const xmlChar *) "highest", EXSLT_MATH_NAMESPACE, exsltMathHighestFunction); xsltRegisterExtModuleFunction ((const xmlChar *) "lowest", EXSLT_MATH_NAMESPACE, exsltMathLowestFunction); /* register other math functions */ xsltRegisterExtModuleFunction ((const xmlChar *) "constant", EXSLT_MATH_NAMESPACE, exsltMathConstantFunction); #ifdef HAVE_STDLIB_H xsltRegisterExtModuleFunction ((const xmlChar *) "random", EXSLT_MATH_NAMESPACE, exsltMathRandomFunction); #endif #if HAVE_MATH_H xsltRegisterExtModuleFunction ((const xmlChar *) "abs", EXSLT_MATH_NAMESPACE, exsltMathAbsFunction); xsltRegisterExtModuleFunction ((const xmlChar *) "sqrt", EXSLT_MATH_NAMESPACE, exsltMathSqrtFunction); xsltRegisterExtModuleFunction ((const xmlChar *) "power", EXSLT_MATH_NAMESPACE, exsltMathPowerFunction); xsltRegisterExtModuleFunction ((const xmlChar *) "log", EXSLT_MATH_NAMESPACE, exsltMathLogFunction); xsltRegisterExtModuleFunction ((const xmlChar *) "sin", EXSLT_MATH_NAMESPACE, exsltMathSinFunction); xsltRegisterExtModuleFunction ((const xmlChar *) "cos", EXSLT_MATH_NAMESPACE, exsltMathCosFunction); xsltRegisterExtModuleFunction ((const xmlChar *) "tan", EXSLT_MATH_NAMESPACE, exsltMathTanFunction); xsltRegisterExtModuleFunction ((const xmlChar *) "asin", EXSLT_MATH_NAMESPACE, exsltMathAsinFunction); xsltRegisterExtModuleFunction ((const xmlChar *) "acos", EXSLT_MATH_NAMESPACE, exsltMathAcosFunction); xsltRegisterExtModuleFunction ((const xmlChar *) "atan", EXSLT_MATH_NAMESPACE, exsltMathAtanFunction); xsltRegisterExtModuleFunction ((const xmlChar *) "atan2", EXSLT_MATH_NAMESPACE, exsltMathAtan2Function); xsltRegisterExtModuleFunction ((const xmlChar *) "exp", EXSLT_MATH_NAMESPACE, exsltMathExpFunction); #endif } /** * exsltMathXpathCtxtRegister: * * Registers the EXSLT - Math module for use outside XSLT */ int exsltMathXpathCtxtRegister (xmlXPathContextPtr ctxt, const xmlChar *prefix) { if (ctxt && prefix && !xmlXPathRegisterNs(ctxt, prefix, (const xmlChar *) EXSLT_MATH_NAMESPACE) && !xmlXPathRegisterFuncNS(ctxt, (const xmlChar *) "min", (const xmlChar *) EXSLT_MATH_NAMESPACE, exsltMathMinFunction) && !xmlXPathRegisterFuncNS(ctxt, (const xmlChar *) "max", (const xmlChar *) EXSLT_MATH_NAMESPACE, exsltMathMaxFunction) && !xmlXPathRegisterFuncNS(ctxt, (const xmlChar *) "highest", (const xmlChar *) EXSLT_MATH_NAMESPACE, exsltMathHighestFunction) && !xmlXPathRegisterFuncNS(ctxt, (const xmlChar *) "lowest", (const xmlChar *) EXSLT_MATH_NAMESPACE, exsltMathLowestFunction) #ifdef HAVE_STDLIB_H && !xmlXPathRegisterFuncNS(ctxt, (const xmlChar *) "random", (const xmlChar *) EXSLT_MATH_NAMESPACE, exsltMathRandomFunction) #endif #if HAVE_MATH_H && !xmlXPathRegisterFuncNS(ctxt, (const xmlChar *) "abs", (const xmlChar *) EXSLT_MATH_NAMESPACE, exsltMathAbsFunction) && !xmlXPathRegisterFuncNS(ctxt, (const xmlChar *) "sqrt", (const xmlChar *) EXSLT_MATH_NAMESPACE, exsltMathSqrtFunction) && !xmlXPathRegisterFuncNS(ctxt, (const xmlChar *) "power", (const xmlChar *) EXSLT_MATH_NAMESPACE, exsltMathPowerFunction) && !xmlXPathRegisterFuncNS(ctxt, (const xmlChar *) "log", (const xmlChar *) EXSLT_MATH_NAMESPACE, exsltMathLogFunction) && !xmlXPathRegisterFuncNS(ctxt, (const xmlChar *) "sin", (const xmlChar *) EXSLT_MATH_NAMESPACE, exsltMathSinFunction) && !xmlXPathRegisterFuncNS(ctxt, (const xmlChar *) "cos", (const xmlChar *) EXSLT_MATH_NAMESPACE, exsltMathCosFunction) && !xmlXPathRegisterFuncNS(ctxt, (const xmlChar *) "tan", (const xmlChar *) EXSLT_MATH_NAMESPACE, exsltMathTanFunction) && !xmlXPathRegisterFuncNS(ctxt, (const xmlChar *) "asin", (const xmlChar *) EXSLT_MATH_NAMESPACE, exsltMathAsinFunction) && !xmlXPathRegisterFuncNS(ctxt, (const xmlChar *) "acos", (const xmlChar *) EXSLT_MATH_NAMESPACE, exsltMathAcosFunction) && !xmlXPathRegisterFuncNS(ctxt, (const xmlChar *) "atan", (const xmlChar *) EXSLT_MATH_NAMESPACE, exsltMathAtanFunction) && !xmlXPathRegisterFuncNS(ctxt, (const xmlChar *) "atan2", (const xmlChar *) EXSLT_MATH_NAMESPACE, exsltMathAtan2Function) && !xmlXPathRegisterFuncNS(ctxt, (const xmlChar *) "exp", (const xmlChar *) EXSLT_MATH_NAMESPACE, exsltMathExpFunction) #endif && !xmlXPathRegisterFuncNS(ctxt, (const xmlChar *) "constant", (const xmlChar *) EXSLT_MATH_NAMESPACE, exsltMathConstantFunction)) { return 0; } return -1; } libxslt-1.1.28/libexslt/Makefile.in0000664000076400007640000006161012053100416014106 00000000000000# Makefile.in generated by automake 1.11.6 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software # Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__make_dryrun = \ { \ am__dry=no; \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ echo 'am--echo: ; @echo "AM" OK' | $(MAKE) -f - 2>/dev/null \ | grep '^AM OK$$' >/dev/null || am__dry=yes;; \ *) \ for am__flg in $$MAKEFLAGS; do \ case $$am__flg in \ *=*|--*) ;; \ *n*) am__dry=yes; break;; \ esac; \ done;; \ esac; \ test $$am__dry = yes; \ } pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = libexslt DIST_COMMON = $(exsltinc_HEADERS) $(srcdir)/Makefile.am \ $(srcdir)/Makefile.in $(srcdir)/exsltconfig.h.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.in am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = exsltconfig.h CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(man3dir)" \ "$(DESTDIR)$(exsltincdir)" LTLIBRARIES = $(lib_LTLIBRARIES) am__DEPENDENCIES_1 = libexslt_la_DEPENDENCIES = $(top_builddir)/libxslt/libxslt.la \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) am_libexslt_la_OBJECTS = exslt.lo common.lo crypto.lo math.lo sets.lo \ functions.lo strings.lo date.lo saxon.lo dynamic.lo libexslt_la_OBJECTS = $(am_libexslt_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent libexslt_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(libexslt_la_LDFLAGS) $(LDFLAGS) -o $@ DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; SOURCES = $(libexslt_la_SOURCES) DIST_SOURCES = $(libexslt_la_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac man3dir = $(mandir)/man3 NROFF = nroff MANS = $(man_MANS) HEADERS = $(exsltinc_HEADERS) ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ EXSLT_INCLUDEDIR = @EXSLT_INCLUDEDIR@ EXSLT_LIBDIR = @EXSLT_LIBDIR@ EXSLT_LIBS = @EXSLT_LIBS@ EXTRA_LIBS = @EXTRA_LIBS@ FGREP = @FGREP@ GREP = @GREP@ HTML_DIR = @HTML_DIR@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBEXSLT_MAJOR_VERSION = @LIBEXSLT_MAJOR_VERSION@ LIBEXSLT_MICRO_VERSION = @LIBEXSLT_MICRO_VERSION@ LIBEXSLT_MINOR_VERSION = @LIBEXSLT_MINOR_VERSION@ LIBEXSLT_VERSION = @LIBEXSLT_VERSION@ LIBEXSLT_VERSION_EXTRA = @LIBEXSLT_VERSION_EXTRA@ LIBEXSLT_VERSION_INFO = @LIBEXSLT_VERSION_INFO@ LIBEXSLT_VERSION_NUMBER = @LIBEXSLT_VERSION_NUMBER@ LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIBXML_CFLAGS = @LIBXML_CFLAGS@ LIBXML_LIBS = @LIBXML_LIBS@ LIBXML_REQUIRED_VERSION = @LIBXML_REQUIRED_VERSION@ LIBXML_SRC = @LIBXML_SRC@ LIBXSLT_DEFAULT_PLUGINS_PATH = @LIBXSLT_DEFAULT_PLUGINS_PATH@ LIBXSLT_MAJOR_MINOR_VERSION = @LIBXSLT_MAJOR_MINOR_VERSION@ LIBXSLT_MAJOR_VERSION = @LIBXSLT_MAJOR_VERSION@ LIBXSLT_MICRO_VERSION = @LIBXSLT_MICRO_VERSION@ LIBXSLT_MINOR_VERSION = @LIBXSLT_MINOR_VERSION@ LIBXSLT_VERSION = @LIBXSLT_VERSION@ LIBXSLT_VERSION_EXTRA = @LIBXSLT_VERSION_EXTRA@ LIBXSLT_VERSION_INFO = @LIBXSLT_VERSION_INFO@ LIBXSLT_VERSION_NUMBER = @LIBXSLT_VERSION_NUMBER@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MV = @MV@ M_LIBS = @M_LIBS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PERL = @PERL@ PYTHON = @PYTHON@ PYTHONSODV = @PYTHONSODV@ PYTHON_INCLUDES = @PYTHON_INCLUDES@ PYTHON_LIBS = @PYTHON_LIBS@ PYTHON_SITE_PACKAGES = @PYTHON_SITE_PACKAGES@ PYTHON_SUBDIR = @PYTHON_SUBDIR@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ RELDATE = @RELDATE@ RM = @RM@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ TAR = @TAR@ THREAD_LIBS = @THREAD_LIBS@ VERSION = @VERSION@ VERSION_SCRIPT_FLAGS = @VERSION_SCRIPT_FLAGS@ WIN32_EXTRA_LDFLAGS = @WIN32_EXTRA_LDFLAGS@ WIN32_EXTRA_LIBADD = @WIN32_EXTRA_LIBADD@ WITH_CRYPTO = @WITH_CRYPTO@ WITH_DEBUGGER = @WITH_DEBUGGER@ WITH_MEM_DEBUG = @WITH_MEM_DEBUG@ WITH_MODULES = @WITH_MODULES@ WITH_TRIO = @WITH_TRIO@ WITH_XSLT_DEBUG = @WITH_XSLT_DEBUG@ XMLLINT = @XMLLINT@ XML_CONFIG = @XML_CONFIG@ XSLTPROC = @XSLTPROC@ XSLTPROCDV = @XSLTPROCDV@ XSLT_INCLUDEDIR = @XSLT_INCLUDEDIR@ XSLT_LIBDIR = @XSLT_LIBDIR@ XSLT_LIBS = @XSLT_LIBS@ XSLT_LOCALE_WINAPI = @XSLT_LOCALE_WINAPI@ XSLT_LOCALE_XLOCALE = @XSLT_LOCALE_XLOCALE@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/libxslt -I$(top_srcdir)/libexslt \ -I$(top_builddir) -I$(top_builddir)/libxslt \ -I$(top_builddir)/libexslt AM_CFLAGS = $(LIBGCRYPT_CFLAGS) $(LIBXML_CFLAGS) lib_LTLIBRARIES = libexslt.la exsltincdir = $(includedir)/libexslt exsltinc_HEADERS = \ exslt.h \ exsltconfig.h \ exsltexports.h libexslt_la_SOURCES = \ exslt.c \ common.c \ crypto.c \ math.c \ sets.c \ functions.c \ strings.c \ date.c \ saxon.c \ libexslt.h \ dynamic.c libexslt_la_LIBADD = $(top_builddir)/libxslt/libxslt.la $(EXTRA_LIBS) $(LIBGCRYPT_LIBS) libexslt_la_LDFLAGS = $(WIN32_EXTRA_LDFLAGS) -version-info $(LIBEXSLT_VERSION_INFO) man_MANS = libexslt.3 EXTRA_DIST = $(man_MANS) all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu libexslt/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu libexslt/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): exsltconfig.h: $(top_builddir)/config.status $(srcdir)/exsltconfig.h.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ install-libLTLIBRARIES: $(lib_LTLIBRARIES) @$(NORMAL_INSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ } uninstall-libLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ done clean-libLTLIBRARIES: -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ test "$$dir" != "$$p" || dir=.; \ echo "rm -f \"$${dir}/so_locations\""; \ rm -f "$${dir}/so_locations"; \ done libexslt.la: $(libexslt_la_OBJECTS) $(libexslt_la_DEPENDENCIES) $(EXTRA_libexslt_la_DEPENDENCIES) $(AM_V_CCLD)$(libexslt_la_LINK) -rpath $(libdir) $(libexslt_la_OBJECTS) $(libexslt_la_LIBADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/common.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/crypto.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/date.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dynamic.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/exslt.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/functions.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/math.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/saxon.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sets.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/strings.Plo@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-man3: $(man_MANS) @$(NORMAL_INSTALL) @list1=''; \ list2='$(man_MANS)'; \ test -n "$(man3dir)" \ && test -n "`echo $$list1$$list2`" \ || exit 0; \ echo " $(MKDIR_P) '$(DESTDIR)$(man3dir)'"; \ $(MKDIR_P) "$(DESTDIR)$(man3dir)" || exit 1; \ { for i in $$list1; do echo "$$i"; done; \ if test -n "$$list2"; then \ for i in $$list2; do echo "$$i"; done \ | sed -n '/\.3[a-z]*$$/p'; \ fi; \ } | while read p; do \ if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; echo "$$p"; \ done | \ sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^3][0-9a-z]*$$,3,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \ sed 'N;N;s,\n, ,g' | { \ list=; while read file base inst; do \ if test "$$base" = "$$inst"; then list="$$list $$file"; else \ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man3dir)/$$inst'"; \ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man3dir)/$$inst" || exit $$?; \ fi; \ done; \ for i in $$list; do echo "$$i"; done | $(am__base_list) | \ while read files; do \ test -z "$$files" || { \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man3dir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(man3dir)" || exit $$?; }; \ done; } uninstall-man3: @$(NORMAL_UNINSTALL) @list=''; test -n "$(man3dir)" || exit 0; \ files=`{ for i in $$list; do echo "$$i"; done; \ l2='$(man_MANS)'; for i in $$l2; do echo "$$i"; done | \ sed -n '/\.3[a-z]*$$/p'; \ } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^3][0-9a-z]*$$,3,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \ dir='$(DESTDIR)$(man3dir)'; $(am__uninstall_files_from_dir) install-exsltincHEADERS: $(exsltinc_HEADERS) @$(NORMAL_INSTALL) @list='$(exsltinc_HEADERS)'; test -n "$(exsltincdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(exsltincdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(exsltincdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(exsltincdir)'"; \ $(INSTALL_HEADER) $$files "$(DESTDIR)$(exsltincdir)" || exit $$?; \ done uninstall-exsltincHEADERS: @$(NORMAL_UNINSTALL) @list='$(exsltinc_HEADERS)'; test -n "$(exsltincdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(exsltincdir)'; $(am__uninstall_files_from_dir) ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) set x; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: CTAGS CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @list='$(MANS)'; if test -n "$$list"; then \ list=`for p in $$list; do \ if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ if test -f "$$d$$p"; then echo "$$d$$p"; else :; fi; done`; \ if test -n "$$list" && \ grep 'ab help2man is required to generate this page' $$list >/dev/null; then \ echo "error: found man pages containing the \`missing help2man' replacement text:" >&2; \ grep -l 'ab help2man is required to generate this page' $$list | sed 's/^/ /' >&2; \ echo " to fix them, install help2man, remove and regenerate the man pages;" >&2; \ echo " typically \`make maintainer-clean' will remove them" >&2; \ exit 1; \ else :; fi; \ else :; fi @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(LTLIBRARIES) $(MANS) $(HEADERS) installdirs: for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(man3dir)" "$(DESTDIR)$(exsltincdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \ mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-exsltincHEADERS install-man install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-libLTLIBRARIES install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-man3 install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-exsltincHEADERS uninstall-libLTLIBRARIES \ uninstall-man uninstall-man: uninstall-man3 .MAKE: install-am install-strip .PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ clean-libLTLIBRARIES clean-libtool ctags distclean \ distclean-compile distclean-generic distclean-libtool \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am \ install-exsltincHEADERS install-html install-html-am \ install-info install-info-am install-libLTLIBRARIES \ install-man install-man3 install-pdf install-pdf-am install-ps \ install-ps-am install-strip installcheck installcheck-am \ installdirs maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf pdf-am ps ps-am tags uninstall \ uninstall-am uninstall-exsltincHEADERS \ uninstall-libLTLIBRARIES uninstall-man uninstall-man3 # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: libxslt-1.1.28/libexslt/libexslt.30000664000076400007640000001457111202213516013760 00000000000000.TH LIBEXSLT 3 "04 November 2003" libxslt .SH NAME libexslt \- extension library for XSLT .SH SYNOPSIS .B #include .sp .B void exsltCommonRegister(void); .br .B void exsltDateRegister(void); .br .B void exsltDynRegister(void); .br .B void exsltFuncRegister(void); .br .B void exsltMathRegister(void); .br .B void exsltSetsRegister(void); .br .B void exsltStrRegister(void); .br .B void exsltRegisterAll(void); .br .B void exsltSaxonRegister(void); .SH DESCRIPTION The .B libexslt library is used to provide extensions to .SM XSLT functions. These extensions come from the .SM EXSLT project .LP .SH USAGE To make use of these functions in .SM XSLT the appropriate namespace must be defined on the .B xsl:stylesheet element. To enable support for them in .BR libxslt (3) you must call the appropriate functions (listed in the .B SYNOPSIS section) to register the extensions. The .I xslt-config shell script can be used to obtain the necessary flags for the pre-processor and linker. The supported extensions are: .SS COMMON .TP 2.2i Namespace: http://exslt.org/common .TP 2.2i See http://www.exslt.org/exsl/index.html for a description. .TP 2.2i .B node-set() convert the given RTF into a node-set. .TP .B object-type() returns the type of the given argument. .TP .B document Create multiple output documents. See http://www.exslt.org/exsl/elements/document/index.html .SS MATH .TP 2.2i Namespace: http://exslt.org/math .TP 2.2i See http://www.exslt.org/math/index.html for a description. .TP 2.2i .B min() returns the minimum value of the given node-set .TP .B max() returns the maximum value of the given node-set .TP .B highest() returns the nodes in the node-set whose value is the maximum value for the node-set. .TP .B lowest() returns the nodes in the node-set whose value is the minimum value for the node-set. .TP .B constant() returns a number value of the given constant with the given precision. The constants are PI, E, SQRRT2, LN2, LN10, LOG2E, and SQRT1_2. .TP .B random() returns a random number between 0 and 1 inclusive. .TP .B abs() returns the absolute value of the argument. .TP .B sqrt() returns the square root of the argument. .TP .B power() returns the power base and power arguments. .TP .B log() returns the natural log of the argument. .TP .B sin() returns the sine of the argument. .TP .B cos() returns the cosine of the argument. .TP .B tan() returns the tangent of the argument. .TP .B asin() returns the arc sine of the argument. .TP .B acos() returns the arc cosine of the argument. .TP .B atan() returns the arc tangent of the argument. .TP .B atan2() returns the arc tangent function of the y/x arguments. .TP .B exp() returns the exponential function of the argument. .SS SETS .TP 2.2i Namespace: http://exslt.org/sets .TP 2.2i See http://www.exslt.org/set/index.html for a description. .TP 2.2i .B difference() returns the difference between the two given node-sets. .TP .B intersection() returns a node-set of the nodes within both given node-sets. .TP .B distinct() returns a node-set of all nodes in the first argument that are not in the seconds argument. .TP .B has-same-node() returns TRUE if there is an intersection between the two given node-sets. .TP .B leading() returns a node-set of all nodes in the first argument that precede the first node in the second argument. .TP .B trailing() returns a node-set of all nodes in the first argument that follow the first node in the second argument. .SS "DATES and TIMES" .TP 2.2i Namespace: http://exslt.org/dates-and-times .TP 2.2i See http://www.exslt.org/date/date.html for a description. .TP 2.2i .B date-time() returns the current date and time as a date/time string. .TP .B date() returns the date specified in the given date/time string. .TP .B time() returns the time specified in the date/time string given as the argument. .TP .B year() returns the year of a date as a number. .TP .B leap-year() returns true if the year given in a date is a leap year. .TP .B month-in-year() returns the month of a date as a number. .TP .B month-name() returns the full name of the month of a date. .TP .B month-abbreviation() returns the abbreviation of the month of a date. .TP .B week-in-year() returns the week of the year as a number. .TP .B week-in-month() returns the week in a month of a date as a number. .TP .B day-in-year() returns the month of a date as a number. .TP .B day-in-month() returns the day of a date as a number. .TP .B day-of-week-in-month() returns the day-of-the-week in a month of a date as a number. .TP .B day-in-week() returns the day of the week given in a date as a number. .TP .B day-name() returns the full name of the day of the week of a date. .TP .B day-abbreviation() returns the abbreviation of the day of the week of a date. .TP .B hour-in-day() returns the hour of the day as a number. .TP .B minute-in-hour() returns the minute of the hour as a number. .TP .B second-in-minute() returns the second of the minute as a number. .TP .B seconds() returns the number of seconds specified by the argument string. .TP .B add() returns the date/time resulting from adding a duration to a date/time. .TP .B add-duration() returns the duration resulting from adding two given durations together. .TP .B difference() returns the duration between the first date and the second date. .TP .B duration() returns a duration string that represents the given number of seconds since 1970-01-01T00:00:00. .SS STRINGS .TP 2.2i Namespace: http://exslt.org/strings .TP 2.2i See http://www.exslt.org/str/index.html for a description. .TP 2.2i .B tokenize() returns a node set of token elements, each containing one token from the string. .TP .B padding() returns a string padded to a certain length. .TP .B align() returns a string aligned within another string. .TP .B concat() returns the concatenation of the string values of the nodes in that node set. .SS FUNCTIONS .TP 2.2i Namespace: http://exslt.org/functions .TP 2.2i See http://www.exslt.org/func/index.html for a description. .TP 2.2i .B function declares an extension function. .TP .B result returns the result of an extension function declared in function(). .SH FILES .TP .I /usr/bin/xslt-config shell script giving pre-processor and linker flags. .TP .I /usr/lib/libexslt.a static library .TP .I /usr/lib/libexslt.so sharable library .SH AUTHORS Manual page by Heiko W. Rupp (hwr@pilhuhn.de) .SH "SEE ALSO" .BR libxml (3), .BR libxslt (3), .BR xmllint (1) .BR xsltproc (1), .\" end of manual page libxslt-1.1.28/libexslt/exslt.h0000664000076400007640000000571212021407617013362 00000000000000 #ifndef __EXSLT_H__ #define __EXSLT_H__ #include #include #include "exsltexports.h" #include #ifdef __cplusplus extern "C" { #endif EXSLTPUBVAR const char *exsltLibraryVersion; EXSLTPUBVAR const int exsltLibexsltVersion; EXSLTPUBVAR const int exsltLibxsltVersion; EXSLTPUBVAR const int exsltLibxmlVersion; /** * EXSLT_COMMON_NAMESPACE: * * Namespace for EXSLT common functions */ #define EXSLT_COMMON_NAMESPACE ((const xmlChar *) "http://exslt.org/common") /** * EXSLT_CRYPTO_NAMESPACE: * * Namespace for EXSLT crypto functions */ #define EXSLT_CRYPTO_NAMESPACE ((const xmlChar *) "http://exslt.org/crypto") /** * EXSLT_MATH_NAMESPACE: * * Namespace for EXSLT math functions */ #define EXSLT_MATH_NAMESPACE ((const xmlChar *) "http://exslt.org/math") /** * EXSLT_SETS_NAMESPACE: * * Namespace for EXSLT set functions */ #define EXSLT_SETS_NAMESPACE ((const xmlChar *) "http://exslt.org/sets") /** * EXSLT_FUNCTIONS_NAMESPACE: * * Namespace for EXSLT functions extension functions */ #define EXSLT_FUNCTIONS_NAMESPACE ((const xmlChar *) "http://exslt.org/functions") /** * EXSLT_STRINGS_NAMESPACE: * * Namespace for EXSLT strings functions */ #define EXSLT_STRINGS_NAMESPACE ((const xmlChar *) "http://exslt.org/strings") /** * EXSLT_DATE_NAMESPACE: * * Namespace for EXSLT date functions */ #define EXSLT_DATE_NAMESPACE ((const xmlChar *) "http://exslt.org/dates-and-times") /** * EXSLT_DYNAMIC_NAMESPACE: * * Namespace for EXSLT dynamic functions */ #define EXSLT_DYNAMIC_NAMESPACE ((const xmlChar *) "http://exslt.org/dynamic") /** * SAXON_NAMESPACE: * * Namespace for SAXON extensions functions */ #define SAXON_NAMESPACE ((const xmlChar *) "http://icl.com/saxon") EXSLTPUBFUN void EXSLTCALL exsltCommonRegister (void); #ifdef EXSLT_CRYPTO_ENABLED EXSLTPUBFUN void EXSLTCALL exsltCryptoRegister (void); #endif EXSLTPUBFUN void EXSLTCALL exsltMathRegister (void); EXSLTPUBFUN void EXSLTCALL exsltSetsRegister (void); EXSLTPUBFUN void EXSLTCALL exsltFuncRegister (void); EXSLTPUBFUN void EXSLTCALL exsltStrRegister (void); EXSLTPUBFUN void EXSLTCALL exsltDateRegister (void); EXSLTPUBFUN void EXSLTCALL exsltSaxonRegister (void); EXSLTPUBFUN void EXSLTCALL exsltDynRegister(void); EXSLTPUBFUN void EXSLTCALL exsltRegisterAll (void); EXSLTPUBFUN int EXSLTCALL exsltDateXpathCtxtRegister (xmlXPathContextPtr ctxt, const xmlChar *prefix); EXSLTPUBFUN int EXSLTCALL exsltMathXpathCtxtRegister (xmlXPathContextPtr ctxt, const xmlChar *prefix); EXSLTPUBFUN int EXSLTCALL exsltSetsXpathCtxtRegister (xmlXPathContextPtr ctxt, const xmlChar *prefix); EXSLTPUBFUN int EXSLTCALL exsltStrXpathCtxtRegister (xmlXPathContextPtr ctxt, const xmlChar *prefix); #ifdef __cplusplus } #endif #endif /* __EXSLT_H__ */ libxslt-1.1.28/libexslt/exsltconfig.h.in0000664000076400007640000000242512021407617015153 00000000000000/* * exsltconfig.h: compile-time version informations for the EXSLT library * * See Copyright for the status of this software. * * daniel@veillard.com */ #ifndef __XML_EXSLTCONFIG_H__ #define __XML_EXSLTCONFIG_H__ #ifdef __cplusplus extern "C" { #endif /** * LIBEXSLT_DOTTED_VERSION: * * the version string like "1.2.3" */ #define LIBEXSLT_DOTTED_VERSION "@VERSION@" /** * LIBEXSLT_VERSION: * * the version number: 1.2.3 value is 10203 */ #define LIBEXSLT_VERSION @LIBEXSLT_VERSION_NUMBER@ /** * LIBEXSLT_VERSION_STRING: * * the version number string, 1.2.3 value is "10203" */ #define LIBEXSLT_VERSION_STRING "@LIBEXSLT_VERSION_NUMBER@" /** * LIBEXSLT_VERSION_EXTRA: * * extra version information, used to show a CVS compilation */ #define LIBEXSLT_VERSION_EXTRA "@LIBEXSLT_VERSION_EXTRA@" /** * WITH_CRYPTO: * * Whether crypto support is configured into exslt */ #if @WITH_CRYPTO@ #define EXSLT_CRYPTO_ENABLED #endif /** * ATTRIBUTE_UNUSED: * * This macro is used to flag unused function parameters to GCC */ #ifdef __GNUC__ #ifdef HAVE_ANSIDECL_H #include #endif #ifndef ATTRIBUTE_UNUSED #define ATTRIBUTE_UNUSED __attribute__((unused)) #endif #else #define ATTRIBUTE_UNUSED #endif #ifdef __cplusplus } #endif #endif /* __XML_EXSLTCONFIG_H__ */ libxslt-1.1.28/libxslt.m40000664000076400007640000001766711202213516012154 00000000000000# Based on: # Configure paths for LIBXML2 # Toshio Kuratomi 2001-04-21 # Adapted from: # Configure paths for GLIB # Owen Taylor 97-11-3 # # Modified to work with libxslt by Thomas Schraitle 2002/10/25 # Fixed by Edward Rudd 2004/05/12 dnl AM_PATH_XSLT([MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]]) dnl Test for XML, and define XML_CFLAGS and XML_LIBS dnl AC_DEFUN([AM_PATH_XSLT],[ AC_ARG_WITH(xslt-prefix, [ --with-xslt-prefix=PFX Prefix where libxslt is installed (optional)], xslt_config_prefix="$withval", xslt_config_prefix="") AC_ARG_WITH(xslt-exec-prefix, [ --with-xslt-exec-prefix=PFX Exec prefix where libxslt is installed (optional)], xslt_config_exec_prefix="$withval", xslt_config_exec_prefix="") AC_ARG_ENABLE(xslttest, [ --disable-xslttest Do not try to compile and run a test LIBXSLT program],, enable_xslttest=yes) if test x$xslt_config_exec_prefix != x ; then xslt_config_args="$xslt_config_args --exec-prefix=$xslt_config_exec_prefix" if test x${XSLT_CONFIG+set} != xset ; then XSLT_CONFIG=$xslt_config_exec_prefix/bin/xslt-config fi fi if test x$xslt_config_prefix != x ; then xslt_config_args="$xslt_config_args --prefix=$xslt_config_prefix" if test x${XSLT_CONFIG+set} != xset ; then XSLT_CONFIG=$xslt_config_prefix/bin/xslt-config fi fi AC_PATH_PROG(XSLT_CONFIG, xslt-config, no) min_xslt_version=ifelse([$1], ,1.0.0,[$1]) AC_MSG_CHECKING(for libxslt - version >= $min_xslt_version) no_xslt="" if test "$XSLT_CONFIG" = "no" ; then no_xslt=yes else XSLT_CFLAGS=`$XSLT_CONFIG $xslt_config_args --cflags` XSLT_LIBS=`$XSLT_CONFIG $xslt_config_args --libs` xslt_config_major_version=`$XSLT_CONFIG $xslt_config_args --version | \ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'` xslt_config_minor_version=`$XSLT_CONFIG $xslt_config_args --version | \ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'` xslt_config_micro_version=`$XSLT_CONFIG $xslt_config_args --version | \ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'` if test "x$enable_xslttest" = "xyes" ; then ac_save_CFLAGS="$CFLAGS" ac_save_LIBS="$LIBS" CFLAGS="$CFLAGS $XSLT_CFLAGS" LIBS="$XSLT_LIBS $LIBS" dnl dnl Now check if the installed libxslt is sufficiently new. dnl (Also sanity checks the results of xslt-config to some extent) dnl rm -f conf.xslttest AC_TRY_RUN([ #include #include #include #include #include int main() { int xslt_major_version, xslt_minor_version, xslt_micro_version; int major, minor, micro; char *tmp_version; system("touch conf.xslttest"); /* Capture xslt-config output via autoconf/configure variables */ /* HP/UX 9 (%@#!) writes to sscanf strings */ tmp_version = (char *)strdup("$min_xslt_version"); if (sscanf(tmp_version, "%d.%d.%d", &major, &minor, µ) != 3) { printf("%s, bad version string from xslt-config\n", "$min_xslt_version"); exit(1); } free(tmp_version); /* Capture the version information from the header files */ tmp_version = (char *)strdup(LIBXSLT_DOTTED_VERSION); if (sscanf(tmp_version, "%d.%d.%d", &xslt_major_version, &xslt_minor_version, &xslt_micro_version) != 3) { printf("%s, bad version string from libxslt includes\n", "LIBXSLT_DOTTED_VERSION"); exit(1); } free(tmp_version); /* Compare xslt-config output to the libxslt headers */ if ((xslt_major_version != $xslt_config_major_version) || (xslt_minor_version != $xslt_config_minor_version) || (xslt_micro_version != $xslt_config_micro_version)) { printf("*** libxslt header files (version %d.%d.%d) do not match\n", xslt_major_version, xslt_minor_version, xslt_micro_version); printf("*** xslt-config (version %d.%d.%d)\n", $xslt_config_major_version, $xslt_config_minor_version, $xslt_config_micro_version); return 1; } /* Compare the headers to the library to make sure we match */ /* Less than ideal -- doesn't provide us with return value feedback, * only exits if there's a serious mismatch between header and library. */ /* copied from LIBXML_TEST_VERSION; */ xmlCheckVersion(LIBXML_VERSION); /* Test that the library is greater than our minimum version */ if ((xslt_major_version > major) || ((xslt_major_version == major) && (xslt_minor_version > minor)) || ((xslt_major_version == major) && (xslt_minor_version == minor) && (xslt_micro_version >= micro))) { return 0; } else { printf("\n*** An old version of libxslt (%d.%d.%d) was found.\n", xslt_major_version, xslt_minor_version, xslt_micro_version); printf("*** You need a version of libxslt newer than %d.%d.%d. The latest version of\n", major, minor, micro); printf("*** libxslt is always available from ftp://ftp.xmlsoft.org.\n"); printf("***\n"); printf("*** If you have already installed a sufficiently new version, this error\n"); printf("*** probably means that the wrong copy of the xslt-config shell script is\n"); printf("*** being found. The easiest way to fix this is to remove the old version\n"); printf("*** of LIBXSLT, but you can also set the XSLT_CONFIG environment to point to the\n"); printf("*** correct copy of xslt-config. (In this case, you will have to\n"); printf("*** modify your LD_LIBRARY_PATH enviroment variable, or edit /etc/ld.so.conf\n"); printf("*** so that the correct libraries are found at run-time))\n"); } return 1; } ],, no_xslt=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"]) CFLAGS="$ac_save_CFLAGS" LIBS="$ac_save_LIBS" fi fi if test "x$no_xslt" = x ; then AC_MSG_RESULT(yes (version $xslt_config_major_version.$xslt_config_minor_version.$xslt_config_micro_version)) ifelse([$2], , :, [$2]) else AC_MSG_RESULT(no) if test "$XSLT_CONFIG" = "no" ; then echo "*** The xslt-config script installed by LIBXSLT could not be found" echo "*** If libxslt was installed in PREFIX, make sure PREFIX/bin is in" echo "*** your path, or set the XSLT_CONFIG environment variable to the" echo "*** full path to xslt-config." else if test -f conf.xslttest ; then : else echo "*** Could not run libxslt test program, checking why..." CFLAGS="$CFLAGS $XSLT_CFLAGS" LIBS="$LIBS $XSLT_LIBS" AC_TRY_LINK([ #include #include ], [ LIBXSLT_TEST_VERSION; return 0;], [ echo "*** The test program compiled, but did not run. This usually means" echo "*** that the run-time linker is not finding LIBXSLT or finding the wrong" echo "*** version of LIBXSLT. If it is not finding LIBXSLT, you'll need to set your" echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point" echo "*** to the installed location Also, make sure you have run ldconfig if that" echo "*** is required on your system" echo "***" echo "*** If you have an old version installed, it is best to remove it, although" echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH" ], [ echo "*** The test program failed to compile or link. See the file config.log for the" echo "*** exact error that occured. This usually means LIBXSLT was incorrectly installed" echo "*** or that you have moved LIBXSLT since it was installed. In the latter case, you" echo "*** may want to edit the xslt-config script: $XSLT_CONFIG" ]) CFLAGS="$ac_save_CFLAGS" LIBS="$ac_save_LIBS" fi fi XSLT_CFLAGS="" XSLT_LIBS="" ifelse([$3], , :, [$3]) fi AC_SUBST(XSLT_CFLAGS) AC_SUBST(XSLT_LIBS) rm -f conf.xslttest ]) libxslt-1.1.28/libxslt.spec.in0000664000076400007640000000706512022113314013156 00000000000000Summary: Library providing the GNOME XSLT engine Name: libxslt Version: @VERSION@ Release: 1 License: MIT Group: Development/Libraries Source: ftp://xmlsoft.org/XSLT/libxslt-%{version}.tar.gz BuildRoot: %{_tmppath}/%{name}-%{version}-root URL: http://xmlsoft.org/XSLT/ Requires: libxml2 >= @LIBXML_REQUIRED_VERSION@ BuildRequires: libxml2-devel >= @LIBXML_REQUIRED_VERSION@ BuildRequires: python python-devel BuildRequires: libxml2-python BuildRequires: libgcrypt-devel Prefix: %{_prefix} Docdir: %{_docdir} %description This C library allows to transform XML files into other XML files (or HTML, text, ...) using the standard XSLT stylesheet transformation mechanism. To use it you need to have a version of libxml2 >= @LIBXML_REQUIRED_VERSION@ installed. The xsltproc command is a command line interface to the XSLT engine %package devel Summary: Libraries, includes, etc. to embed the GNOME XSLT engine Group: Development/Libraries Requires: libxslt = %{version}-%{release} Requires: libxml2-devel >= @LIBXML_REQUIRED_VERSION@ Requires: libgcrypt-devel Requires: pkgconfig %description devel This C library allows to transform XML files into other XML files (or HTML, text, ...) using the standard XSLT stylesheet transformation mechanism. To use it you need to have a version of libxml2 >= @LIBXML_REQUIRED_VERSION@ installed. %package python Summary: Python bindings for the libxslt library Group: Development/Libraries Requires: libxslt = %{version}-%{release} Requires: libxml2 >= @LIBXML_REQUIRED_VERSION@ Requires: libxml2-python >= @LIBXML_REQUIRED_VERSION@ Requires: python %description python The libxslt-python package contains a module that permits applications written in the Python programming language to use the interface supplied by the libxslt library to apply XSLT transformations. This library allows to parse sytlesheets, uses the libxml2-python to load and save XML and HTML files. Direct access to XPath and the XSLT transformation context are possible to extend the XSLT language with XPath functions written in Python. %prep %setup -q %build %configure make gzip -9 ChangeLog %install rm -fr %{buildroot} %makeinstall rm -fr $RPM_BUILD_ROOT%{_libdir}/*.la \ $RPM_BUILD_ROOT%{_libdir}/python*/site-packages/libxsltmod*a %clean rm -fr %{buildroot} %post /sbin/ldconfig %postun /sbin/ldconfig %files %defattr(-, root, root) %doc AUTHORS ChangeLog.gz NEWS README Copyright TODO FEATURES %doc doc/*.html doc/html doc/tutorial doc/tutorial2 doc/*.gif %doc doc/EXSLT %doc %{_mandir}/man1/xsltproc.1* %{_libdir}/lib*.so.* %{_libdir}/libxslt-plugins %{prefix}/bin/xsltproc %files devel %defattr(-, root, root) %doc AUTHORS ChangeLog.gz NEWS README Copyright TODO FEATURES %doc doc/libxslt-api.xml %doc doc/libxslt-refs.xml %doc doc/EXSLT/libexslt-api.xml %doc doc/EXSLT/libexslt-refs.xml %doc %{_mandir}/man3/libxslt.3* %doc %{_mandir}/man3/libexslt.3* %doc doc/*.html doc/html doc/*.gif doc/*.png %doc doc/tutorial %doc doc/tutorial2 %doc doc/images %doc doc/EXSLT %{_libdir}/lib*.so %{_libdir}/*a %{_libdir}/*.sh %{prefix}/share/aclocal/libxslt.m4 %{prefix}/include/* %{prefix}/bin/xslt-config %{_libdir}/pkgconfig/libxslt.pc %{_libdir}/pkgconfig/libexslt.pc %files python %defattr(-, root, root) %doc AUTHORS ChangeLog.gz NEWS README Copyright FEATURES %{_libdir}/python*/site-packages/libxslt.py* %{_libdir}/python*/site-packages/libxsltmod* %doc python/TODO %doc python/libxsltclass.txt %doc python/tests/*.py %doc python/tests/*.xml %doc python/tests/*.xsl %changelog * @RELDATE@ Daniel Veillard - upstream release @VERSION@ see http://xmlsoft.org/XSLT/news.html libxslt-1.1.28/xsltConf.sh.in0000664000076400007640000000025411202213532012750 00000000000000# # Configuration file for using the xslt library # XSLT_LIBDIR="@XSLT_LIBDIR@" XSLT_LIBS="@XSLT_LIBS@" XSLT_INCLUDEDIR="@XSLT_INCLUDEDIR@" MODULE_VERSION="xslt-@VERSION@" libxslt-1.1.28/libxslt/0000775000076400007640000000000012053100426011751 500000000000000libxslt-1.1.28/libxslt/xsltexports.h0000664000076400007640000000654211202213516014470 00000000000000/* * Summary: macros for marking symbols as exportable/importable. * Description: macros for marking symbols as exportable/importable. * * Copy: See Copyright for the status of this software. * * Author: Igor Zlatkovic */ #ifndef __XSLT_EXPORTS_H__ #define __XSLT_EXPORTS_H__ /** * XSLTPUBFUN: * XSLTPUBFUN, XSLTPUBVAR, XSLTCALL * * Macros which declare an exportable function, an exportable variable and * the calling convention used for functions. * * Please use an extra block for every platform/compiler combination when * modifying this, rather than overlong #ifdef lines. This helps * readability as well as the fact that different compilers on the same * platform might need different definitions. */ /** * XSLTPUBFUN: * * Macros which declare an exportable function */ #define XSLTPUBFUN /** * XSLTPUBVAR: * * Macros which declare an exportable variable */ #define XSLTPUBVAR extern /** * XSLTCALL: * * Macros which declare the called convention for exported functions */ #define XSLTCALL /** DOC_DISABLE */ /* Windows platform with MS compiler */ #if defined(_WIN32) && defined(_MSC_VER) #undef XSLTPUBFUN #undef XSLTPUBVAR #undef XSLTCALL #if defined(IN_LIBXSLT) && !defined(LIBXSLT_STATIC) #define XSLTPUBFUN __declspec(dllexport) #define XSLTPUBVAR __declspec(dllexport) #else #define XSLTPUBFUN #if !defined(LIBXSLT_STATIC) #define XSLTPUBVAR __declspec(dllimport) extern #else #define XSLTPUBVAR extern #endif #endif #define XSLTCALL __cdecl #if !defined _REENTRANT #define _REENTRANT #endif #endif /* Windows platform with Borland compiler */ #if defined(_WIN32) && defined(__BORLANDC__) #undef XSLTPUBFUN #undef XSLTPUBVAR #undef XSLTCALL #if defined(IN_LIBXSLT) && !defined(LIBXSLT_STATIC) #define XSLTPUBFUN __declspec(dllexport) #define XSLTPUBVAR __declspec(dllexport) extern #else #define XSLTPUBFUN #if !defined(LIBXSLT_STATIC) #define XSLTPUBVAR __declspec(dllimport) extern #else #define XSLTPUBVAR extern #endif #endif #define XSLTCALL __cdecl #if !defined _REENTRANT #define _REENTRANT #endif #endif /* Windows platform with GNU compiler (Mingw) */ #if defined(_WIN32) && defined(__MINGW32__) #undef XSLTPUBFUN #undef XSLTPUBVAR #undef XSLTCALL /* #if defined(IN_LIBXSLT) && !defined(LIBXSLT_STATIC) */ #if !defined(LIBXSLT_STATIC) #define XSLTPUBFUN __declspec(dllexport) #define XSLTPUBVAR __declspec(dllexport) extern #else #define XSLTPUBFUN #if !defined(LIBXSLT_STATIC) #define XSLTPUBVAR __declspec(dllimport) extern #else #define XSLTPUBVAR extern #endif #endif #define XSLTCALL __cdecl #if !defined _REENTRANT #define _REENTRANT #endif #endif /* Cygwin platform, GNU compiler */ #if defined(_WIN32) && defined(__CYGWIN__) #undef XSLTPUBFUN #undef XSLTPUBVAR #undef XSLTCALL #if defined(IN_LIBXSLT) && !defined(LIBXSLT_STATIC) #define XSLTPUBFUN __declspec(dllexport) #define XSLTPUBVAR __declspec(dllexport) #else #define XSLTPUBFUN #if !defined(LIBXSLT_STATIC) #define XSLTPUBVAR __declspec(dllimport) extern #else #define XSLTPUBVAR #endif #endif #define XSLTCALL __cdecl #endif /* Compatibility */ #if !defined(LIBXSLT_PUBLIC) #define LIBXSLT_PUBLIC XSLTPUBVAR #endif #endif /* __XSLT_EXPORTS_H__ */ libxslt-1.1.28/libxslt/imports.h0000664000076400007640000000346012024022316013541 00000000000000/* * Summary: interface for the XSLT import support * Description: macros and fuctions needed to implement and * access the import tree * * Copy: See Copyright for the status of this software. * * Author: Daniel Veillard */ #ifndef __XML_XSLT_IMPORTS_H__ #define __XML_XSLT_IMPORTS_H__ #include #include "xsltexports.h" #include "xsltInternals.h" #ifdef __cplusplus extern "C" { #endif /** * XSLT_GET_IMPORT_PTR: * * A macro to import pointers from the stylesheet cascading order. */ #define XSLT_GET_IMPORT_PTR(res, style, name) { \ xsltStylesheetPtr st = style; \ res = NULL; \ while (st != NULL) { \ if (st->name != NULL) { res = st->name; break; } \ st = xsltNextImport(st); \ }} /** * XSLT_GET_IMPORT_INT: * * A macro to import intergers from the stylesheet cascading order. */ #define XSLT_GET_IMPORT_INT(res, style, name) { \ xsltStylesheetPtr st = style; \ res = -1; \ while (st != NULL) { \ if (st->name != -1) { res = st->name; break; } \ st = xsltNextImport(st); \ }} /* * Module interfaces */ XSLTPUBFUN int XSLTCALL xsltParseStylesheetImport(xsltStylesheetPtr style, xmlNodePtr cur); XSLTPUBFUN int XSLTCALL xsltParseStylesheetInclude (xsltStylesheetPtr style, xmlNodePtr cur); XSLTPUBFUN xsltStylesheetPtr XSLTCALL xsltNextImport (xsltStylesheetPtr style); XSLTPUBFUN int XSLTCALL xsltNeedElemSpaceHandling(xsltTransformContextPtr ctxt); XSLTPUBFUN int XSLTCALL xsltFindElemSpaceHandling(xsltTransformContextPtr ctxt, xmlNodePtr node); XSLTPUBFUN xsltTemplatePtr XSLTCALL xsltFindTemplate (xsltTransformContextPtr ctxt, const xmlChar *name, const xmlChar *nameURI); #ifdef __cplusplus } #endif #endif /* __XML_XSLT_IMPORTS_H__ */ libxslt-1.1.28/libxslt/templates.h0000664000076400007640000000433412024022317014044 00000000000000/* * Summary: interface for the template processing * Description: This set of routine encapsulates XPath calls * and Attribute Value Templates evaluation. * * Copy: See Copyright for the status of this software. * * Author: Daniel Veillard */ #ifndef __XML_XSLT_TEMPLATES_H__ #define __XML_XSLT_TEMPLATES_H__ #include #include #include "xsltexports.h" #include "xsltInternals.h" #ifdef __cplusplus extern "C" { #endif XSLTPUBFUN int XSLTCALL xsltEvalXPathPredicate (xsltTransformContextPtr ctxt, xmlXPathCompExprPtr comp, xmlNsPtr *nsList, int nsNr); XSLTPUBFUN xmlChar * XSLTCALL xsltEvalTemplateString (xsltTransformContextPtr ctxt, xmlNodePtr contextNode, xmlNodePtr inst); XSLTPUBFUN xmlChar * XSLTCALL xsltEvalAttrValueTemplate (xsltTransformContextPtr ctxt, xmlNodePtr node, const xmlChar *name, const xmlChar *ns); XSLTPUBFUN const xmlChar * XSLTCALL xsltEvalStaticAttrValueTemplate (xsltStylesheetPtr style, xmlNodePtr node, const xmlChar *name, const xmlChar *ns, int *found); /* TODO: this is obviously broken ... the namespaces should be passed too ! */ XSLTPUBFUN xmlChar * XSLTCALL xsltEvalXPathString (xsltTransformContextPtr ctxt, xmlXPathCompExprPtr comp); XSLTPUBFUN xmlChar * XSLTCALL xsltEvalXPathStringNs (xsltTransformContextPtr ctxt, xmlXPathCompExprPtr comp, int nsNr, xmlNsPtr *nsList); XSLTPUBFUN xmlNodePtr * XSLTCALL xsltTemplateProcess (xsltTransformContextPtr ctxt, xmlNodePtr node); XSLTPUBFUN xmlAttrPtr XSLTCALL xsltAttrListTemplateProcess (xsltTransformContextPtr ctxt, xmlNodePtr target, xmlAttrPtr cur); XSLTPUBFUN xmlAttrPtr XSLTCALL xsltAttrTemplateProcess (xsltTransformContextPtr ctxt, xmlNodePtr target, xmlAttrPtr attr); XSLTPUBFUN xmlChar * XSLTCALL xsltAttrTemplateValueProcess (xsltTransformContextPtr ctxt, const xmlChar* attr); XSLTPUBFUN xmlChar * XSLTCALL xsltAttrTemplateValueProcessNode(xsltTransformContextPtr ctxt, const xmlChar* str, xmlNodePtr node); #ifdef __cplusplus } #endif #endif /* __XML_XSLT_TEMPLATES_H__ */ libxslt-1.1.28/libxslt/security.c0000664000076400007640000002574312024022166013721 00000000000000/* * security.c: Implementation of the XSLT security framework * * See Copyright for the status of this software. * * daniel@veillard.com */ #define IN_LIBXSLT #include "libxslt.h" #include #ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_SYS_STAT_H #include #endif #ifdef HAVE_MATH_H #include #endif #ifdef HAVE_FLOAT_H #include #endif #ifdef HAVE_IEEEFP_H #include #endif #ifdef HAVE_NAN_H #include #endif #ifdef HAVE_CTYPE_H #include #endif #if defined(WIN32) && !defined(__CYGWIN__) #include #ifndef INVALID_FILE_ATTRIBUTES #define INVALID_FILE_ATTRIBUTES ((DWORD)-1) #endif #endif #ifndef HAVE_STAT # ifdef HAVE__STAT /* MS C library seems to define stat and _stat. The definition * is identical. Still, mapping them to each other causes a warning. */ # ifndef _MSC_VER # define stat(x,y) _stat(x,y) # endif # define HAVE_STAT # endif #endif #include #include #include #include "xslt.h" #include "xsltInternals.h" #include "xsltutils.h" #include "extensions.h" #include "security.h" struct _xsltSecurityPrefs { xsltSecurityCheck readFile; xsltSecurityCheck createFile; xsltSecurityCheck createDir; xsltSecurityCheck readNet; xsltSecurityCheck writeNet; }; static xsltSecurityPrefsPtr xsltDefaultSecurityPrefs = NULL; /************************************************************************ * * * Module interfaces * * * ************************************************************************/ /** * xsltNewSecurityPrefs: * * Create a new security preference block * * Returns a pointer to the new block or NULL in case of error */ xsltSecurityPrefsPtr xsltNewSecurityPrefs(void) { xsltSecurityPrefsPtr ret; xsltInitGlobals(); ret = (xsltSecurityPrefsPtr) xmlMalloc(sizeof(xsltSecurityPrefs)); if (ret == NULL) { xsltTransformError(NULL, NULL, NULL, "xsltNewSecurityPrefs : malloc failed\n"); return(NULL); } memset(ret, 0, sizeof(xsltSecurityPrefs)); return(ret); } /** * xsltFreeSecurityPrefs: * @sec: the security block to free * * Free up a security preference block */ void xsltFreeSecurityPrefs(xsltSecurityPrefsPtr sec) { if (sec == NULL) return; xmlFree(sec); } /** * xsltSetSecurityPrefs: * @sec: the security block to update * @option: the option to update * @func: the user callback to use for this option * * Update the security option to use the new callback checking function * * Returns -1 in case of error, 0 otherwise */ int xsltSetSecurityPrefs(xsltSecurityPrefsPtr sec, xsltSecurityOption option, xsltSecurityCheck func) { xsltInitGlobals(); if (sec == NULL) return(-1); switch (option) { case XSLT_SECPREF_READ_FILE: sec->readFile = func; return(0); case XSLT_SECPREF_WRITE_FILE: sec->createFile = func; return(0); case XSLT_SECPREF_CREATE_DIRECTORY: sec->createDir = func; return(0); case XSLT_SECPREF_READ_NETWORK: sec->readNet = func; return(0); case XSLT_SECPREF_WRITE_NETWORK: sec->writeNet = func; return(0); } return(-1); } /** * xsltGetSecurityPrefs: * @sec: the security block to update * @option: the option to lookup * * Lookup the security option to get the callback checking function * * Returns NULL if not found, the function otherwise */ xsltSecurityCheck xsltGetSecurityPrefs(xsltSecurityPrefsPtr sec, xsltSecurityOption option) { if (sec == NULL) return(NULL); switch (option) { case XSLT_SECPREF_READ_FILE: return(sec->readFile); case XSLT_SECPREF_WRITE_FILE: return(sec->createFile); case XSLT_SECPREF_CREATE_DIRECTORY: return(sec->createDir); case XSLT_SECPREF_READ_NETWORK: return(sec->readNet); case XSLT_SECPREF_WRITE_NETWORK: return(sec->writeNet); } return(NULL); } /** * xsltSetDefaultSecurityPrefs: * @sec: the security block to use * * Set the default security preference application-wide */ void xsltSetDefaultSecurityPrefs(xsltSecurityPrefsPtr sec) { xsltDefaultSecurityPrefs = sec; } /** * xsltGetDefaultSecurityPrefs: * * Get the default security preference application-wide * * Returns the current xsltSecurityPrefsPtr in use or NULL if none */ xsltSecurityPrefsPtr xsltGetDefaultSecurityPrefs(void) { return(xsltDefaultSecurityPrefs); } /** * xsltSetCtxtSecurityPrefs: * @sec: the security block to use * @ctxt: an XSLT transformation context * * Set the security preference for a specific transformation * * Returns -1 in case of error, 0 otherwise */ int xsltSetCtxtSecurityPrefs(xsltSecurityPrefsPtr sec, xsltTransformContextPtr ctxt) { if (ctxt == NULL) return(-1); ctxt->sec = (void *) sec; return(0); } /** * xsltSecurityAllow: * @sec: the security block to use * @ctxt: an XSLT transformation context * @value: unused * * Function used to always allow an operation * * Returns 1 always */ int xsltSecurityAllow(xsltSecurityPrefsPtr sec ATTRIBUTE_UNUSED, xsltTransformContextPtr ctxt ATTRIBUTE_UNUSED, const char *value ATTRIBUTE_UNUSED) { return(1); } /** * xsltSecurityForbid: * @sec: the security block to use * @ctxt: an XSLT transformation context * @value: unused * * Function used to always forbid an operation * * Returns 0 always */ int xsltSecurityForbid(xsltSecurityPrefsPtr sec ATTRIBUTE_UNUSED, xsltTransformContextPtr ctxt ATTRIBUTE_UNUSED, const char *value ATTRIBUTE_UNUSED) { return(0); } /************************************************************************ * * * Internal interfaces * * * ************************************************************************/ /** * xsltCheckFilename * @path: the path to check * * function checks to see if @path is a valid source * (file, socket...) for XML. * * TODO: remove at some point !!! * Local copy of xmlCheckFilename to avoid a hard dependency on * a new version of libxml2 * * if stat is not available on the target machine, * returns 1. if stat fails, returns 0 (if calling * stat on the filename fails, it can't be right). * if stat succeeds and the file is a directory, * returns 2. otherwise returns 1. */ static int xsltCheckFilename (const char *path) { #ifdef HAVE_STAT struct stat stat_buffer; #if defined(WIN32) && !defined(__CYGWIN__) DWORD dwAttrs; dwAttrs = GetFileAttributes(path); if (dwAttrs != INVALID_FILE_ATTRIBUTES) { if (dwAttrs & FILE_ATTRIBUTE_DIRECTORY) { return 2; } } #endif if (stat(path, &stat_buffer) == -1) return 0; #ifdef S_ISDIR if (S_ISDIR(stat_buffer.st_mode)) { return 2; } #endif #endif return 1; } static int xsltCheckWritePath(xsltSecurityPrefsPtr sec, xsltTransformContextPtr ctxt, const char *path) { int ret; xsltSecurityCheck check; char *directory; check = xsltGetSecurityPrefs(sec, XSLT_SECPREF_WRITE_FILE); if (check != NULL) { ret = check(sec, ctxt, path); if (ret == 0) { xsltTransformError(ctxt, NULL, NULL, "File write for %s refused\n", path); return(0); } } directory = xmlParserGetDirectory (path); if (directory != NULL) { ret = xsltCheckFilename(directory); if (ret == 0) { /* * The directory doesn't exist check for creation */ check = xsltGetSecurityPrefs(sec, XSLT_SECPREF_CREATE_DIRECTORY); if (check != NULL) { ret = check(sec, ctxt, directory); if (ret == 0) { xsltTransformError(ctxt, NULL, NULL, "Directory creation for %s refused\n", path); xmlFree(directory); return(0); } } ret = xsltCheckWritePath(sec, ctxt, directory); if (ret == 1) ret = mkdir(directory, 0755); } xmlFree(directory); if (ret < 0) return(ret); } return(1); } /** * xsltCheckWrite: * @sec: the security options * @ctxt: an XSLT transformation context * @URL: the resource to be written * * Check if the resource is allowed to be written, if necessary makes * some preliminary work like creating directories * * Return 1 if write is allowed, 0 if not and -1 in case or error. */ int xsltCheckWrite(xsltSecurityPrefsPtr sec, xsltTransformContextPtr ctxt, const xmlChar *URL) { int ret; xmlURIPtr uri; xsltSecurityCheck check; uri = xmlParseURI((const char *)URL); if (uri == NULL) { uri = xmlCreateURI(); if (uri == NULL) { xsltTransformError(ctxt, NULL, NULL, "xsltCheckWrite: out of memory for %s\n", URL); return(-1); } uri->path = (char *)xmlStrdup(URL); } if ((uri->scheme == NULL) || (xmlStrEqual(BAD_CAST uri->scheme, BAD_CAST "file"))) { #if defined(WIN32) && !defined(__CYGWIN__) if ((uri->path)&&(uri->path[0]=='/')&& (uri->path[1]!='\0')&&(uri->path[2]==':')) ret = xsltCheckWritePath(sec, ctxt, uri->path+1); else #endif /* * Check if we are allowed to write this file */ ret = xsltCheckWritePath(sec, ctxt, uri->path); if (ret <= 0) { xmlFreeURI(uri); return(ret); } } else { /* * Check if we are allowed to write this network resource */ check = xsltGetSecurityPrefs(sec, XSLT_SECPREF_WRITE_NETWORK); if (check != NULL) { ret = check(sec, ctxt, (const char *)URL); if (ret == 0) { xsltTransformError(ctxt, NULL, NULL, "File write for %s refused\n", URL); xmlFreeURI(uri); return(0); } } } xmlFreeURI(uri); return(1); } /** * xsltCheckRead: * @sec: the security options * @ctxt: an XSLT transformation context * @URL: the resource to be read * * Check if the resource is allowed to be read * * Return 1 if read is allowed, 0 if not and -1 in case or error. */ int xsltCheckRead(xsltSecurityPrefsPtr sec, xsltTransformContextPtr ctxt, const xmlChar *URL) { int ret; xmlURIPtr uri; xsltSecurityCheck check; uri = xmlParseURI((const char *)URL); if (uri == NULL) { xsltTransformError(ctxt, NULL, NULL, "xsltCheckRead: URL parsing failed for %s\n", URL); return(-1); } if ((uri->scheme == NULL) || (xmlStrEqual(BAD_CAST uri->scheme, BAD_CAST "file"))) { /* * Check if we are allowed to read this file */ check = xsltGetSecurityPrefs(sec, XSLT_SECPREF_READ_FILE); if (check != NULL) { ret = check(sec, ctxt, uri->path); if (ret == 0) { xsltTransformError(ctxt, NULL, NULL, "Local file read for %s refused\n", URL); xmlFreeURI(uri); return(0); } } } else { /* * Check if we are allowed to write this network resource */ check = xsltGetSecurityPrefs(sec, XSLT_SECPREF_READ_NETWORK); if (check != NULL) { ret = check(sec, ctxt, (const char *)URL); if (ret == 0) { xsltTransformError(ctxt, NULL, NULL, "Network file read for %s refused\n", URL); xmlFreeURI(uri); return(0); } } } xmlFreeURI(uri); return(1); } libxslt-1.1.28/libxslt/win32config.h0000664000076400007640000000443212024022167014200 00000000000000/* * Summary: Windows configuration header * Description: Windows configuration header * * Copy: See Copyright for the status of this software. * * Author: Igor Zlatkovic */ #ifndef __LIBXSLT_WIN32_CONFIG__ #define __LIBXSLT_WIN32_CONFIG__ #define HAVE_CTYPE_H 1 #define HAVE_STDLIB_H 1 #define HAVE_STDARG_H 1 #define HAVE_MALLOC_H 1 #define HAVE_TIME_H 1 #define HAVE_LOCALTIME 1 #define HAVE_GMTIME 1 #define HAVE_TIME 1 #define HAVE_MATH_H 1 #define HAVE_FCNTL_H 1 #include #define HAVE_ISINF #define HAVE_ISNAN #include #if defined _MSC_VER || defined __MINGW32__ /* MS C-runtime has functions which can be used in order to determine if a given floating-point variable contains NaN, (+-)INF. These are preferred, because floating-point technology is considered propriatary by MS and we can assume that their functions know more about their oddities than we do. */ #include /* Bjorn Reese figured a quite nice construct for isinf() using the _fpclass() function. */ #ifndef isinf #define isinf(d) ((_fpclass(d) == _FPCLASS_PINF) ? 1 \ : ((_fpclass(d) == _FPCLASS_NINF) ? -1 : 0)) #endif /* _isnan(x) returns nonzero if (x == NaN) and zero otherwise. */ #ifndef isnan #define isnan(d) (_isnan(d)) #endif #else /* _MSC_VER */ static int isinf (double d) { int expon = 0; double val = frexp (d, &expon); if (expon == 1025) { if (val == 0.5) { return 1; } else if (val == -0.5) { return -1; } else { return 0; } } else { return 0; } } static int isnan (double d) { int expon = 0; double val = frexp (d, &expon); if (expon == 1025) { if (val == 0.5) { return 0; } else if (val == -0.5) { return 0; } else { return 1; } } else { return 0; } } #endif /* _MSC_VER */ #include #if defined(_MSC_VER) || defined(__MINGW32__) #define mkdir(p,m) _mkdir(p) #define snprintf _snprintf #if _MSC_VER < 1500 #define vsnprintf(b,c,f,a) _vsnprintf(b,c,f,a) #endif #endif #define HAVE_SYS_STAT_H #define HAVE__STAT #define HAVE_STRING_H #include #ifndef ATTRIBUTE_UNUSED #define ATTRIBUTE_UNUSED #endif #define _WINSOCKAPI_ #endif /* __LIBXSLT_WIN32_CONFIG__ */ libxslt-1.1.28/libxslt/trio.h0000664000076400007640000001603711202213516013026 00000000000000/************************************************************************* * * $Id$ * * Copyright (C) 1998 Bjorn Reese and Daniel Stenberg. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND * CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER. * ************************************************************************* * * http://ctrio.sourceforge.net/ * ************************************************************************/ #ifndef TRIO_TRIO_H #define TRIO_TRIO_H #if !defined(WITHOUT_TRIO) /* * Use autoconf defines if present. Packages using trio must define * HAVE_CONFIG_H as a compiler option themselves. */ #if defined(HAVE_CONFIG_H) # include #endif #include "triodef.h" #include #include #if defined(TRIO_COMPILER_ANCIENT) # include #else # include #endif #ifdef __cplusplus extern "C" { #endif /* * Error codes. * * Remember to add a textual description to trio_strerror. */ enum { TRIO_EOF = 1, TRIO_EINVAL = 2, TRIO_ETOOMANY = 3, TRIO_EDBLREF = 4, TRIO_EGAP = 5, TRIO_ENOMEM = 6, TRIO_ERANGE = 7, TRIO_ERRNO = 8, TRIO_ECUSTOM = 9 }; /* Error macros */ #define TRIO_ERROR_CODE(x) ((-(x)) & 0x00FF) #define TRIO_ERROR_POSITION(x) ((-(x)) >> 8) #define TRIO_ERROR_NAME(x) trio_strerror(x) typedef int (*trio_outstream_t) TRIO_PROTO((trio_pointer_t, int)); typedef int (*trio_instream_t) TRIO_PROTO((trio_pointer_t)); TRIO_CONST char *trio_strerror TRIO_PROTO((int)); /************************************************************************* * Print Functions */ int trio_printf TRIO_PROTO((TRIO_CONST char *format, ...)); int trio_vprintf TRIO_PROTO((TRIO_CONST char *format, va_list args)); int trio_printfv TRIO_PROTO((TRIO_CONST char *format, void **args)); int trio_fprintf TRIO_PROTO((FILE *file, TRIO_CONST char *format, ...)); int trio_vfprintf TRIO_PROTO((FILE *file, TRIO_CONST char *format, va_list args)); int trio_fprintfv TRIO_PROTO((FILE *file, TRIO_CONST char *format, void **args)); int trio_dprintf TRIO_PROTO((int fd, TRIO_CONST char *format, ...)); int trio_vdprintf TRIO_PROTO((int fd, TRIO_CONST char *format, va_list args)); int trio_dprintfv TRIO_PROTO((int fd, TRIO_CONST char *format, void **args)); int trio_cprintf TRIO_PROTO((trio_outstream_t stream, trio_pointer_t closure, TRIO_CONST char *format, ...)); int trio_vcprintf TRIO_PROTO((trio_outstream_t stream, trio_pointer_t closure, TRIO_CONST char *format, va_list args)); int trio_cprintfv TRIO_PROTO((trio_outstream_t stream, trio_pointer_t closure, TRIO_CONST char *format, void **args)); int trio_sprintf TRIO_PROTO((char *buffer, TRIO_CONST char *format, ...)); int trio_vsprintf TRIO_PROTO((char *buffer, TRIO_CONST char *format, va_list args)); int trio_sprintfv TRIO_PROTO((char *buffer, TRIO_CONST char *format, void **args)); int trio_snprintf TRIO_PROTO((char *buffer, size_t max, TRIO_CONST char *format, ...)); int trio_vsnprintf TRIO_PROTO((char *buffer, size_t bufferSize, TRIO_CONST char *format, va_list args)); int trio_snprintfv TRIO_PROTO((char *buffer, size_t bufferSize, TRIO_CONST char *format, void **args)); int trio_snprintfcat TRIO_PROTO((char *buffer, size_t max, TRIO_CONST char *format, ...)); int trio_vsnprintfcat TRIO_PROTO((char *buffer, size_t bufferSize, TRIO_CONST char *format, va_list args)); char *trio_aprintf TRIO_PROTO((TRIO_CONST char *format, ...)); char *trio_vaprintf TRIO_PROTO((TRIO_CONST char *format, va_list args)); int trio_asprintf TRIO_PROTO((char **ret, TRIO_CONST char *format, ...)); int trio_vasprintf TRIO_PROTO((char **ret, TRIO_CONST char *format, va_list args)); /************************************************************************* * Scan Functions */ int trio_scanf TRIO_PROTO((TRIO_CONST char *format, ...)); int trio_vscanf TRIO_PROTO((TRIO_CONST char *format, va_list args)); int trio_scanfv TRIO_PROTO((TRIO_CONST char *format, void **args)); int trio_fscanf TRIO_PROTO((FILE *file, TRIO_CONST char *format, ...)); int trio_vfscanf TRIO_PROTO((FILE *file, TRIO_CONST char *format, va_list args)); int trio_fscanfv TRIO_PROTO((FILE *file, TRIO_CONST char *format, void **args)); int trio_dscanf TRIO_PROTO((int fd, TRIO_CONST char *format, ...)); int trio_vdscanf TRIO_PROTO((int fd, TRIO_CONST char *format, va_list args)); int trio_dscanfv TRIO_PROTO((int fd, TRIO_CONST char *format, void **args)); int trio_cscanf TRIO_PROTO((trio_instream_t stream, trio_pointer_t closure, TRIO_CONST char *format, ...)); int trio_vcscanf TRIO_PROTO((trio_instream_t stream, trio_pointer_t closure, TRIO_CONST char *format, va_list args)); int trio_cscanfv TRIO_PROTO((trio_instream_t stream, trio_pointer_t closure, TRIO_CONST char *format, void **args)); int trio_sscanf TRIO_PROTO((TRIO_CONST char *buffer, TRIO_CONST char *format, ...)); int trio_vsscanf TRIO_PROTO((TRIO_CONST char *buffer, TRIO_CONST char *format, va_list args)); int trio_sscanfv TRIO_PROTO((TRIO_CONST char *buffer, TRIO_CONST char *format, void **args)); /************************************************************************* * Locale Functions */ void trio_locale_set_decimal_point TRIO_PROTO((char *decimalPoint)); void trio_locale_set_thousand_separator TRIO_PROTO((char *thousandSeparator)); void trio_locale_set_grouping TRIO_PROTO((char *grouping)); /************************************************************************* * Renaming */ #ifdef TRIO_REPLACE_STDIO /* Replace the functions */ #ifndef HAVE_PRINTF # define printf trio_printf #endif #ifndef HAVE_VPRINTF # define vprintf trio_vprintf #endif #ifndef HAVE_FPRINTF # define fprintf trio_fprintf #endif #ifndef HAVE_VFPRINTF # define vfprintf trio_vfprintf #endif #ifndef HAVE_SPRINTF # define sprintf trio_sprintf #endif #ifndef HAVE_VSPRINTF # define vsprintf trio_vsprintf #endif #ifndef HAVE_SNPRINTF # define snprintf trio_snprintf #endif #ifndef HAVE_VSNPRINTF # define vsnprintf trio_vsnprintf #endif #ifndef HAVE_SCANF # define scanf trio_scanf #endif #ifndef HAVE_VSCANF # define vscanf trio_vscanf #endif #ifndef HAVE_FSCANF # define fscanf trio_fscanf #endif #ifndef HAVE_VFSCANF # define vfscanf trio_vfscanf #endif #ifndef HAVE_SSCANF # define sscanf trio_sscanf #endif #ifndef HAVE_VSSCANF # define vsscanf trio_vsscanf #endif /* These aren't stdio functions, but we make them look similar */ #define dprintf trio_dprintf #define vdprintf trio_vdprintf #define aprintf trio_aprintf #define vaprintf trio_vaprintf #define asprintf trio_asprintf #define vasprintf trio_vasprintf #define dscanf trio_dscanf #define vdscanf trio_vdscanf #endif #ifdef __cplusplus } /* extern "C" */ #endif #endif /* WITHOUT_TRIO */ #endif /* TRIO_TRIO_H */ libxslt-1.1.28/libxslt/xsltInternals.h0000664000076400007640000015715112053100136014724 00000000000000/* * Summary: internal data structures, constants and functions * Description: Internal data structures, constants and functions used * by the XSLT engine. * They are not part of the API or ABI, i.e. they can change * without prior notice, use carefully. * * Copy: See Copyright for the status of this software. * * Author: Daniel Veillard */ #ifndef __XML_XSLT_INTERNALS_H__ #define __XML_XSLT_INTERNALS_H__ #include #include #include #include #include #include #include #include "xsltexports.h" #include "xsltlocale.h" #include "numbersInternals.h" #ifdef __cplusplus extern "C" { #endif /* #define XSLT_DEBUG_PROFILE_CACHE */ /** * XSLT_IS_TEXT_NODE: * * check if the argument is a text node */ #define XSLT_IS_TEXT_NODE(n) ((n != NULL) && \ (((n)->type == XML_TEXT_NODE) || \ ((n)->type == XML_CDATA_SECTION_NODE))) /** * XSLT_MARK_RES_TREE_FRAG: * * internal macro to set up tree fragments */ #define XSLT_MARK_RES_TREE_FRAG(n) \ (n)->name = (char *) xmlStrdup(BAD_CAST " fake node libxslt"); /** * XSLT_IS_RES_TREE_FRAG: * * internal macro to test tree fragments */ #define XSLT_IS_RES_TREE_FRAG(n) \ ((n != NULL) && ((n)->type == XML_DOCUMENT_NODE) && \ ((n)->name != NULL) && ((n)->name[0] == ' ')) /** * XSLT_REFACTORED_KEYCOMP: * * Internal define to enable on-demand xsl:key computation. * That's the only mode now but the define is kept for compatibility */ #define XSLT_REFACTORED_KEYCOMP /** * XSLT_FAST_IF: * * Internal define to enable usage of xmlXPathCompiledEvalToBoolean() * for XSLT "tests"; e.g. in */ #define XSLT_FAST_IF /** * XSLT_REFACTORED: * * Internal define to enable the refactored parts of Libxslt. */ /* #define XSLT_REFACTORED */ /* ==================================================================== */ /** * XSLT_REFACTORED_VARS: * * Internal define to enable the refactored variable part of libxslt */ #define XSLT_REFACTORED_VARS #ifdef XSLT_REFACTORED extern const xmlChar *xsltXSLTAttrMarker; /* TODO: REMOVE: #define XSLT_REFACTORED_EXCLRESNS */ /* TODO: REMOVE: #define XSLT_REFACTORED_NSALIAS */ /** * XSLT_REFACTORED_XSLT_NSCOMP * * Internal define to enable the pointer-comparison of * namespaces of XSLT elements. */ /* #define XSLT_REFACTORED_XSLT_NSCOMP */ /** * XSLT_REFACTORED_XPATHCOMP: * * Internal define to enable the optimization of the * compilation of XPath expressions. */ #define XSLT_REFACTORED_XPATHCOMP #ifdef XSLT_REFACTORED_XSLT_NSCOMP extern const xmlChar *xsltConstNamespaceNameXSLT; /** * IS_XSLT_ELEM_FAST: * * quick test to detect XSLT elements */ #define IS_XSLT_ELEM_FAST(n) \ (((n) != NULL) && ((n)->ns != NULL) && \ ((n)->ns->href == xsltConstNamespaceNameXSLT)) /** * IS_XSLT_ATTR_FAST: * * quick test to detect XSLT attributes */ #define IS_XSLT_ATTR_FAST(a) \ (((a) != NULL) && ((a)->ns != NULL) && \ ((a)->ns->href == xsltConstNamespaceNameXSLT)) /** * XSLT_HAS_INTERNAL_NSMAP: * * check for namespace mapping */ #define XSLT_HAS_INTERNAL_NSMAP(s) \ (((s) != NULL) && ((s)->principal) && \ ((s)->principal->principalData) && \ ((s)->principal->principalData->nsMap)) /** * XSLT_GET_INTERNAL_NSMAP: * * get pointer to namespace map */ #define XSLT_GET_INTERNAL_NSMAP(s) ((s)->principal->principalData->nsMap) #else /* XSLT_REFACTORED_XSLT_NSCOMP */ /** * IS_XSLT_ELEM_FAST: * * quick check whether this is an xslt element */ #define IS_XSLT_ELEM_FAST(n) \ (((n) != NULL) && ((n)->ns != NULL) && \ (xmlStrEqual((n)->ns->href, XSLT_NAMESPACE))) /** * IS_XSLT_ATTR_FAST: * * quick check for xslt namespace attribute */ #define IS_XSLT_ATTR_FAST(a) \ (((a) != NULL) && ((a)->ns != NULL) && \ (xmlStrEqual((a)->ns->href, XSLT_NAMESPACE))) #endif /* XSLT_REFACTORED_XSLT_NSCOMP */ /** * XSLT_REFACTORED_MANDATORY_VERSION: * * TODO: Currently disabled to surpress regression test failures, since * the old behaviour was that a missing version attribute * produced a only a warning and not an error, which was incerrect. * So the regression tests need to be fixed if this is enabled. */ /* #define XSLT_REFACTORED_MANDATORY_VERSION */ /** * xsltPointerList: * * Pointer-list for various purposes. */ typedef struct _xsltPointerList xsltPointerList; typedef xsltPointerList *xsltPointerListPtr; struct _xsltPointerList { void **items; int number; int size; }; #endif /** * XSLT_REFACTORED_PARSING: * * Internal define to enable the refactored parts of Libxslt * related to parsing. */ /* #define XSLT_REFACTORED_PARSING */ /** * XSLT_MAX_SORT: * * Max number of specified xsl:sort on an element. */ #define XSLT_MAX_SORT 15 /** * XSLT_PAT_NO_PRIORITY: * * Specific value for pattern without priority expressed. */ #define XSLT_PAT_NO_PRIORITY -12345789 /** * xsltRuntimeExtra: * * Extra information added to the transformation context. */ typedef struct _xsltRuntimeExtra xsltRuntimeExtra; typedef xsltRuntimeExtra *xsltRuntimeExtraPtr; struct _xsltRuntimeExtra { void *info; /* pointer to the extra data */ xmlFreeFunc deallocate; /* pointer to the deallocation routine */ union { /* dual-purpose field */ void *ptr; /* data not needing deallocation */ int ival; /* integer value storage */ } val; }; /** * XSLT_RUNTIME_EXTRA_LST: * @ctxt: the transformation context * @nr: the index * * Macro used to access extra information stored in the context */ #define XSLT_RUNTIME_EXTRA_LST(ctxt, nr) (ctxt)->extras[(nr)].info /** * XSLT_RUNTIME_EXTRA_FREE: * @ctxt: the transformation context * @nr: the index * * Macro used to free extra information stored in the context */ #define XSLT_RUNTIME_EXTRA_FREE(ctxt, nr) (ctxt)->extras[(nr)].deallocate /** * XSLT_RUNTIME_EXTRA: * @ctxt: the transformation context * @nr: the index * * Macro used to define extra information stored in the context */ #define XSLT_RUNTIME_EXTRA(ctxt, nr, typ) (ctxt)->extras[(nr)].val.typ /** * xsltTemplate: * * The in-memory structure corresponding to an XSLT Template. */ typedef struct _xsltTemplate xsltTemplate; typedef xsltTemplate *xsltTemplatePtr; struct _xsltTemplate { struct _xsltTemplate *next;/* chained list sorted by priority */ struct _xsltStylesheet *style;/* the containing stylesheet */ xmlChar *match; /* the matching string */ float priority; /* as given from the stylesheet, not computed */ const xmlChar *name; /* the local part of the name QName */ const xmlChar *nameURI; /* the URI part of the name QName */ const xmlChar *mode;/* the local part of the mode QName */ const xmlChar *modeURI;/* the URI part of the mode QName */ xmlNodePtr content; /* the template replacement value */ xmlNodePtr elem; /* the source element */ /* * TODO: @inheritedNsNr and @inheritedNs won't be used in the * refactored code. */ int inheritedNsNr; /* number of inherited namespaces */ xmlNsPtr *inheritedNs;/* inherited non-excluded namespaces */ /* Profiling informations */ int nbCalls; /* the number of time the template was called */ unsigned long time; /* the time spent in this template */ void *params; /* xsl:param instructions */ int templNr; /* Nb of templates in the stack */ int templMax; /* Size of the templtes stack */ xsltTemplatePtr *templCalledTab; /* templates called */ int *templCountTab; /* .. and how often */ }; /** * xsltDecimalFormat: * * Data structure of decimal-format. */ typedef struct _xsltDecimalFormat xsltDecimalFormat; typedef xsltDecimalFormat *xsltDecimalFormatPtr; struct _xsltDecimalFormat { struct _xsltDecimalFormat *next; /* chained list */ xmlChar *name; /* Used for interpretation of pattern */ xmlChar *digit; xmlChar *patternSeparator; /* May appear in result */ xmlChar *minusSign; xmlChar *infinity; xmlChar *noNumber; /* Not-a-number */ /* Used for interpretation of pattern and may appear in result */ xmlChar *decimalPoint; xmlChar *grouping; xmlChar *percent; xmlChar *permille; xmlChar *zeroDigit; }; /** * xsltDocument: * * Data structure associated to a parsed document. */ typedef struct _xsltDocument xsltDocument; typedef xsltDocument *xsltDocumentPtr; struct _xsltDocument { struct _xsltDocument *next; /* documents are kept in a chained list */ int main; /* is this the main document */ xmlDocPtr doc; /* the parsed document */ void *keys; /* key tables storage */ struct _xsltDocument *includes; /* subsidiary includes */ int preproc; /* pre-processing already done */ int nbKeysComputed; }; /** * xsltKeyDef: * * Representation of an xsl:key. */ typedef struct _xsltKeyDef xsltKeyDef; typedef xsltKeyDef *xsltKeyDefPtr; struct _xsltKeyDef { struct _xsltKeyDef *next; xmlNodePtr inst; xmlChar *name; xmlChar *nameURI; xmlChar *match; xmlChar *use; xmlXPathCompExprPtr comp; xmlXPathCompExprPtr usecomp; xmlNsPtr *nsList; /* the namespaces in scope */ int nsNr; /* the number of namespaces in scope */ }; /** * xsltKeyTable: * * Holds the computed keys for key definitions of the same QName. * Is owned by an xsltDocument. */ typedef struct _xsltKeyTable xsltKeyTable; typedef xsltKeyTable *xsltKeyTablePtr; struct _xsltKeyTable { struct _xsltKeyTable *next; xmlChar *name; xmlChar *nameURI; xmlHashTablePtr keys; }; /* * The in-memory structure corresponding to an XSLT Stylesheet. * NOTE: most of the content is simply linked from the doc tree * structure, no specific allocation is made. */ typedef struct _xsltStylesheet xsltStylesheet; typedef xsltStylesheet *xsltStylesheetPtr; typedef struct _xsltTransformContext xsltTransformContext; typedef xsltTransformContext *xsltTransformContextPtr; /** * xsltElemPreComp: * * The in-memory structure corresponding to element precomputed data, * designed to be extended by extension implementors. */ typedef struct _xsltElemPreComp xsltElemPreComp; typedef xsltElemPreComp *xsltElemPreCompPtr; /** * xsltTransformFunction: * @ctxt: the XSLT transformation context * @node: the input node * @inst: the stylesheet node * @comp: the compiled information from the stylesheet * * Signature of the function associated to elements part of the * stylesheet language like xsl:if or xsl:apply-templates. */ typedef void (*xsltTransformFunction) (xsltTransformContextPtr ctxt, xmlNodePtr node, xmlNodePtr inst, xsltElemPreCompPtr comp); /** * xsltSortFunc: * @ctxt: a transformation context * @sorts: the node-set to sort * @nbsorts: the number of sorts * * Signature of the function to use during sorting */ typedef void (*xsltSortFunc) (xsltTransformContextPtr ctxt, xmlNodePtr *sorts, int nbsorts); typedef enum { XSLT_FUNC_COPY=1, XSLT_FUNC_SORT, XSLT_FUNC_TEXT, XSLT_FUNC_ELEMENT, XSLT_FUNC_ATTRIBUTE, XSLT_FUNC_COMMENT, XSLT_FUNC_PI, XSLT_FUNC_COPYOF, XSLT_FUNC_VALUEOF, XSLT_FUNC_NUMBER, XSLT_FUNC_APPLYIMPORTS, XSLT_FUNC_CALLTEMPLATE, XSLT_FUNC_APPLYTEMPLATES, XSLT_FUNC_CHOOSE, XSLT_FUNC_IF, XSLT_FUNC_FOREACH, XSLT_FUNC_DOCUMENT, XSLT_FUNC_WITHPARAM, XSLT_FUNC_PARAM, XSLT_FUNC_VARIABLE, XSLT_FUNC_WHEN, XSLT_FUNC_EXTENSION #ifdef XSLT_REFACTORED , XSLT_FUNC_OTHERWISE, XSLT_FUNC_FALLBACK, XSLT_FUNC_MESSAGE, XSLT_FUNC_INCLUDE, XSLT_FUNC_ATTRSET, XSLT_FUNC_LITERAL_RESULT_ELEMENT, XSLT_FUNC_UNKOWN_FORWARDS_COMPAT #endif } xsltStyleType; /** * xsltElemPreCompDeallocator: * @comp: the #xsltElemPreComp to free up * * Deallocates an #xsltElemPreComp structure. */ typedef void (*xsltElemPreCompDeallocator) (xsltElemPreCompPtr comp); /** * xsltElemPreComp: * * The basic structure for compiled items of the AST of the XSLT processor. * This structure is also intended to be extended by extension implementors. * TODO: This is somehow not nice, since it has a "free" field, which * derived stylesheet-structs do not have. */ struct _xsltElemPreComp { xsltElemPreCompPtr next; /* next item in the global chained list hold by xsltStylesheet. */ xsltStyleType type; /* type of the element */ xsltTransformFunction func; /* handling function */ xmlNodePtr inst; /* the node in the stylesheet's tree corresponding to this item */ /* end of common part */ xsltElemPreCompDeallocator free; /* the deallocator */ }; /** * xsltStylePreComp: * * The abstract basic structure for items of the XSLT processor. * This includes: * 1) compiled forms of XSLT instructions (xsl:if, xsl:attribute, etc.) * 2) compiled forms of literal result elements * 3) compiled forms of extension elements */ typedef struct _xsltStylePreComp xsltStylePreComp; typedef xsltStylePreComp *xsltStylePreCompPtr; #ifdef XSLT_REFACTORED /* * Some pointer-list utility functions. */ XSLTPUBFUN xsltPointerListPtr XSLTCALL xsltPointerListCreate (int initialSize); XSLTPUBFUN void XSLTCALL xsltPointerListFree (xsltPointerListPtr list); XSLTPUBFUN void XSLTCALL xsltPointerListClear (xsltPointerListPtr list); XSLTPUBFUN int XSLTCALL xsltPointerListAddSize (xsltPointerListPtr list, void *item, int initialSize); /************************************************************************ * * * Refactored structures * * * ************************************************************************/ typedef struct _xsltNsListContainer xsltNsListContainer; typedef xsltNsListContainer *xsltNsListContainerPtr; struct _xsltNsListContainer { xmlNsPtr *list; int totalNumber; int xpathNumber; }; /** * XSLT_ITEM_COMPATIBILITY_FIELDS: * * Fields for API compatibility to the structure * _xsltElemPreComp which is used for extension functions. * Note that @next is used for storage; it does not reflect a next * sibling in the tree. * TODO: Evaluate if we really need such a compatibility. */ #define XSLT_ITEM_COMPATIBILITY_FIELDS \ xsltElemPreCompPtr next;\ xsltStyleType type;\ xsltTransformFunction func;\ xmlNodePtr inst; /** * XSLT_ITEM_NAVIGATION_FIELDS: * * Currently empty. * TODO: It is intended to hold navigational fields in the future. */ #define XSLT_ITEM_NAVIGATION_FIELDS /* xsltStylePreCompPtr parent;\ xsltStylePreCompPtr children;\ xsltStylePreCompPtr nextItem; */ /** * XSLT_ITEM_NSINSCOPE_FIELDS: * * The in-scope namespaces. */ #define XSLT_ITEM_NSINSCOPE_FIELDS xsltNsListContainerPtr inScopeNs; /** * XSLT_ITEM_COMMON_FIELDS: * * Common fields used for all items. */ #define XSLT_ITEM_COMMON_FIELDS \ XSLT_ITEM_COMPATIBILITY_FIELDS \ XSLT_ITEM_NAVIGATION_FIELDS \ XSLT_ITEM_NSINSCOPE_FIELDS /** * _xsltStylePreComp: * * The abstract basic structure for items of the XSLT processor. * This includes: * 1) compiled forms of XSLT instructions (e.g. xsl:if, xsl:attribute, etc.) * 2) compiled forms of literal result elements * 3) various properties for XSLT instructions (e.g. xsl:when, * xsl:with-param) * * REVISIT TODO: Keep this structure equal to the fields * defined by XSLT_ITEM_COMMON_FIELDS */ struct _xsltStylePreComp { xsltElemPreCompPtr next; /* next item in the global chained list hold by xsltStylesheet */ xsltStyleType type; /* type of the item */ xsltTransformFunction func; /* handling function */ xmlNodePtr inst; /* the node in the stylesheet's tree corresponding to this item. */ /* Currently no navigational fields. */ xsltNsListContainerPtr inScopeNs; }; /** * xsltStyleBasicEmptyItem: * * Abstract structure only used as a short-cut for * XSLT items with no extra fields. * NOTE that it is intended that this structure looks the same as * _xsltStylePreComp. */ typedef struct _xsltStyleBasicEmptyItem xsltStyleBasicEmptyItem; typedef xsltStyleBasicEmptyItem *xsltStyleBasicEmptyItemPtr; struct _xsltStyleBasicEmptyItem { XSLT_ITEM_COMMON_FIELDS }; /** * xsltStyleBasicExpressionItem: * * Abstract structure only used as a short-cut for * XSLT items with just an expression. */ typedef struct _xsltStyleBasicExpressionItem xsltStyleBasicExpressionItem; typedef xsltStyleBasicExpressionItem *xsltStyleBasicExpressionItemPtr; struct _xsltStyleBasicExpressionItem { XSLT_ITEM_COMMON_FIELDS const xmlChar *select; /* TODO: Change this to "expression". */ xmlXPathCompExprPtr comp; /* TODO: Change this to compExpr. */ }; /************************************************************************ * * * XSLT-instructions/declarations * * * ************************************************************************/ /** * xsltStyleItemElement: * * * * * */ typedef struct _xsltStyleItemElement xsltStyleItemElement; typedef xsltStyleItemElement *xsltStyleItemElementPtr; struct _xsltStyleItemElement { XSLT_ITEM_COMMON_FIELDS const xmlChar *use; int has_use; const xmlChar *name; int has_name; const xmlChar *ns; const xmlChar *nsPrefix; int has_ns; }; /** * xsltStyleItemAttribute: * * * * * */ typedef struct _xsltStyleItemAttribute xsltStyleItemAttribute; typedef xsltStyleItemAttribute *xsltStyleItemAttributePtr; struct _xsltStyleItemAttribute { XSLT_ITEM_COMMON_FIELDS const xmlChar *name; int has_name; const xmlChar *ns; const xmlChar *nsPrefix; int has_ns; }; /** * xsltStyleItemText: * * * * * */ typedef struct _xsltStyleItemText xsltStyleItemText; typedef xsltStyleItemText *xsltStyleItemTextPtr; struct _xsltStyleItemText { XSLT_ITEM_COMMON_FIELDS int noescape; /* text */ }; /** * xsltStyleItemComment: * * * * * */ typedef xsltStyleBasicEmptyItem xsltStyleItemComment; typedef xsltStyleItemComment *xsltStyleItemCommentPtr; /** * xsltStyleItemPI: * * * * * */ typedef struct _xsltStyleItemPI xsltStyleItemPI; typedef xsltStyleItemPI *xsltStyleItemPIPtr; struct _xsltStyleItemPI { XSLT_ITEM_COMMON_FIELDS const xmlChar *name; int has_name; }; /** * xsltStyleItemApplyImports: * * * */ typedef xsltStyleBasicEmptyItem xsltStyleItemApplyImports; typedef xsltStyleItemApplyImports *xsltStyleItemApplyImportsPtr; /** * xsltStyleItemApplyTemplates: * * * * * */ typedef struct _xsltStyleItemApplyTemplates xsltStyleItemApplyTemplates; typedef xsltStyleItemApplyTemplates *xsltStyleItemApplyTemplatesPtr; struct _xsltStyleItemApplyTemplates { XSLT_ITEM_COMMON_FIELDS const xmlChar *mode; /* apply-templates */ const xmlChar *modeURI; /* apply-templates */ const xmlChar *select; /* sort, copy-of, value-of, apply-templates */ xmlXPathCompExprPtr comp; /* a precompiled XPath expression */ /* TODO: with-params */ }; /** * xsltStyleItemCallTemplate: * * * * * */ typedef struct _xsltStyleItemCallTemplate xsltStyleItemCallTemplate; typedef xsltStyleItemCallTemplate *xsltStyleItemCallTemplatePtr; struct _xsltStyleItemCallTemplate { XSLT_ITEM_COMMON_FIELDS xsltTemplatePtr templ; /* call-template */ const xmlChar *name; /* element, attribute, pi */ int has_name; /* element, attribute, pi */ const xmlChar *ns; /* element */ int has_ns; /* element */ /* TODO: with-params */ }; /** * xsltStyleItemCopy: * * * * * */ typedef struct _xsltStyleItemCopy xsltStyleItemCopy; typedef xsltStyleItemCopy *xsltStyleItemCopyPtr; struct _xsltStyleItemCopy { XSLT_ITEM_COMMON_FIELDS const xmlChar *use; /* copy, element */ int has_use; /* copy, element */ }; /** * xsltStyleItemIf: * * * * * */ typedef struct _xsltStyleItemIf xsltStyleItemIf; typedef xsltStyleItemIf *xsltStyleItemIfPtr; struct _xsltStyleItemIf { XSLT_ITEM_COMMON_FIELDS const xmlChar *test; /* if */ xmlXPathCompExprPtr comp; /* a precompiled XPath expression */ }; /** * xsltStyleItemCopyOf: * * * */ typedef xsltStyleBasicExpressionItem xsltStyleItemCopyOf; typedef xsltStyleItemCopyOf *xsltStyleItemCopyOfPtr; /** * xsltStyleItemValueOf: * * * */ typedef struct _xsltStyleItemValueOf xsltStyleItemValueOf; typedef xsltStyleItemValueOf *xsltStyleItemValueOfPtr; struct _xsltStyleItemValueOf { XSLT_ITEM_COMMON_FIELDS const xmlChar *select; xmlXPathCompExprPtr comp; /* a precompiled XPath expression */ int noescape; }; /** * xsltStyleItemNumber: * * * */ typedef struct _xsltStyleItemNumber xsltStyleItemNumber; typedef xsltStyleItemNumber *xsltStyleItemNumberPtr; struct _xsltStyleItemNumber { XSLT_ITEM_COMMON_FIELDS xsltNumberData numdata; /* number */ }; /** * xsltStyleItemChoose: * * * * * */ typedef xsltStyleBasicEmptyItem xsltStyleItemChoose; typedef xsltStyleItemChoose *xsltStyleItemChoosePtr; /** * xsltStyleItemFallback: * * * * * */ typedef xsltStyleBasicEmptyItem xsltStyleItemFallback; typedef xsltStyleItemFallback *xsltStyleItemFallbackPtr; /** * xsltStyleItemForEach: * * * * * */ typedef xsltStyleBasicExpressionItem xsltStyleItemForEach; typedef xsltStyleItemForEach *xsltStyleItemForEachPtr; /** * xsltStyleItemMessage: * * * * * */ typedef struct _xsltStyleItemMessage xsltStyleItemMessage; typedef xsltStyleItemMessage *xsltStyleItemMessagePtr; struct _xsltStyleItemMessage { XSLT_ITEM_COMMON_FIELDS int terminate; }; /** * xsltStyleItemDocument: * * NOTE: This is not an instruction of XSLT 1.0. */ typedef struct _xsltStyleItemDocument xsltStyleItemDocument; typedef xsltStyleItemDocument *xsltStyleItemDocumentPtr; struct _xsltStyleItemDocument { XSLT_ITEM_COMMON_FIELDS int ver11; /* assigned: in xsltDocumentComp; read: nowhere; TODO: Check if we need. */ const xmlChar *filename; /* document URL */ int has_filename; }; /************************************************************************ * * * Non-instructions (actually properties of instructions/declarations) * * * ************************************************************************/ /** * xsltStyleBasicItemVariable: * * Basic struct for xsl:variable, xsl:param and xsl:with-param. * It's currently important to have equal fields, since * xsltParseStylesheetCallerParam() is used with xsl:with-param from * the xslt side and with xsl:param from the exslt side (in * exsltFuncFunctionFunction()). * * FUTURE NOTE: In XSLT 2.0 xsl:param, xsl:variable and xsl:with-param * have additional different fields. */ typedef struct _xsltStyleBasicItemVariable xsltStyleBasicItemVariable; typedef xsltStyleBasicItemVariable *xsltStyleBasicItemVariablePtr; struct _xsltStyleBasicItemVariable { XSLT_ITEM_COMMON_FIELDS const xmlChar *select; xmlXPathCompExprPtr comp; const xmlChar *name; int has_name; const xmlChar *ns; int has_ns; }; /** * xsltStyleItemVariable: * * * * * */ typedef xsltStyleBasicItemVariable xsltStyleItemVariable; typedef xsltStyleItemVariable *xsltStyleItemVariablePtr; /** * xsltStyleItemParam: * * * * * */ typedef struct _xsltStyleItemParam xsltStyleItemParam; typedef xsltStyleItemParam *xsltStyleItemParamPtr; struct _xsltStyleItemParam { XSLT_ITEM_COMMON_FIELDS const xmlChar *select; xmlXPathCompExprPtr comp; const xmlChar *name; int has_name; const xmlChar *ns; int has_ns; }; /** * xsltStyleItemWithParam: * * * * */ typedef xsltStyleBasicItemVariable xsltStyleItemWithParam; typedef xsltStyleItemWithParam *xsltStyleItemWithParamPtr; /** * xsltStyleItemSort: * * Reflects the XSLT xsl:sort item. * Allowed parents: xsl:apply-templates, xsl:for-each * */ typedef struct _xsltStyleItemSort xsltStyleItemSort; typedef xsltStyleItemSort *xsltStyleItemSortPtr; struct _xsltStyleItemSort { XSLT_ITEM_COMMON_FIELDS const xmlChar *stype; /* sort */ int has_stype; /* sort */ int number; /* sort */ const xmlChar *order; /* sort */ int has_order; /* sort */ int descending; /* sort */ const xmlChar *lang; /* sort */ int has_lang; /* sort */ xsltLocale locale; /* sort */ const xmlChar *case_order; /* sort */ int lower_first; /* sort */ const xmlChar *use; int has_use; const xmlChar *select; /* sort, copy-of, value-of, apply-templates */ xmlXPathCompExprPtr comp; /* a precompiled XPath expression */ }; /** * xsltStyleItemWhen: * * * * * Allowed parent: xsl:choose */ typedef struct _xsltStyleItemWhen xsltStyleItemWhen; typedef xsltStyleItemWhen *xsltStyleItemWhenPtr; struct _xsltStyleItemWhen { XSLT_ITEM_COMMON_FIELDS const xmlChar *test; xmlXPathCompExprPtr comp; }; /** * xsltStyleItemOtherwise: * * Allowed parent: xsl:choose * * * */ typedef struct _xsltStyleItemOtherwise xsltStyleItemOtherwise; typedef xsltStyleItemOtherwise *xsltStyleItemOtherwisePtr; struct _xsltStyleItemOtherwise { XSLT_ITEM_COMMON_FIELDS }; typedef struct _xsltStyleItemInclude xsltStyleItemInclude; typedef xsltStyleItemInclude *xsltStyleItemIncludePtr; struct _xsltStyleItemInclude { XSLT_ITEM_COMMON_FIELDS xsltDocumentPtr include; }; /************************************************************************ * * * XSLT elements in forwards-compatible mode * * * ************************************************************************/ typedef struct _xsltStyleItemUknown xsltStyleItemUknown; typedef xsltStyleItemUknown *xsltStyleItemUknownPtr; struct _xsltStyleItemUknown { XSLT_ITEM_COMMON_FIELDS }; /************************************************************************ * * * Extension elements * * * ************************************************************************/ /* * xsltStyleItemExtElement: * * Reflects extension elements. * * NOTE: Due to the fact that the structure xsltElemPreComp is most * probably already heavily in use out there by users, so we cannot * easily change it, we'll create an intermediate structure which will * hold an xsltElemPreCompPtr. * BIG NOTE: The only problem I see here is that the user processes the * content of the stylesheet tree, possibly he'll lookup the node->psvi * fields in order to find subsequent extension functions. * In this case, the user's code will break, since the node->psvi * field will hold now the xsltStyleItemExtElementPtr and not * the xsltElemPreCompPtr. * However the place where the structure is anchored in the node-tree, * namely node->psvi, has beed already once been moved from node->_private * to node->psvi, so we have a precedent here, which, I think, should allow * us to change such semantics without headaches. */ typedef struct _xsltStyleItemExtElement xsltStyleItemExtElement; typedef xsltStyleItemExtElement *xsltStyleItemExtElementPtr; struct _xsltStyleItemExtElement { XSLT_ITEM_COMMON_FIELDS xsltElemPreCompPtr item; }; /************************************************************************ * * * Literal result elements * * * ************************************************************************/ typedef struct _xsltEffectiveNs xsltEffectiveNs; typedef xsltEffectiveNs *xsltEffectiveNsPtr; struct _xsltEffectiveNs { xsltEffectiveNsPtr nextInStore; /* storage next */ xsltEffectiveNsPtr next; /* next item in the list */ const xmlChar *prefix; const xmlChar *nsName; /* * Indicates if eclared on the literal result element; dunno if really * needed. */ int holdByElem; }; /* * Info for literal result elements. * This will be set on the elem->psvi field and will be * shared by literal result elements, which have the same * excluded result namespaces; i.e., this *won't* be created uniquely * for every literal result element. */ typedef struct _xsltStyleItemLRElementInfo xsltStyleItemLRElementInfo; typedef xsltStyleItemLRElementInfo *xsltStyleItemLRElementInfoPtr; struct _xsltStyleItemLRElementInfo { XSLT_ITEM_COMMON_FIELDS /* * @effectiveNs is the set of effective ns-nodes * on the literal result element, which will be added to the result * element if not already existing in the result tree. * This means that excluded namespaces (via exclude-result-prefixes, * extension-element-prefixes and the XSLT namespace) not added * to the set. * Namespace-aliasing was applied on the @effectiveNs. */ xsltEffectiveNsPtr effectiveNs; }; #ifdef XSLT_REFACTORED typedef struct _xsltNsAlias xsltNsAlias; typedef xsltNsAlias *xsltNsAliasPtr; struct _xsltNsAlias { xsltNsAliasPtr next; /* next in the list */ xmlNsPtr literalNs; xmlNsPtr targetNs; xmlDocPtr docOfTargetNs; }; #endif #ifdef XSLT_REFACTORED_XSLT_NSCOMP typedef struct _xsltNsMap xsltNsMap; typedef xsltNsMap *xsltNsMapPtr; struct _xsltNsMap { xsltNsMapPtr next; /* next in the list */ xmlDocPtr doc; xmlNodePtr elem; /* the element holding the ns-decl */ xmlNsPtr ns; /* the xmlNs structure holding the XML namespace name */ const xmlChar *origNsName; /* the original XML namespace name */ const xmlChar *newNsName; /* the mapped XML namespace name */ }; #endif /************************************************************************ * * * Compile-time structures for *internal* use only * * * ************************************************************************/ typedef struct _xsltPrincipalStylesheetData xsltPrincipalStylesheetData; typedef xsltPrincipalStylesheetData *xsltPrincipalStylesheetDataPtr; typedef struct _xsltNsList xsltNsList; typedef xsltNsList *xsltNsListPtr; struct _xsltNsList { xsltNsListPtr next; /* next in the list */ xmlNsPtr ns; }; /* * xsltVarInfo: * * Used at compilation time for parameters and variables. */ typedef struct _xsltVarInfo xsltVarInfo; typedef xsltVarInfo *xsltVarInfoPtr; struct _xsltVarInfo { xsltVarInfoPtr next; /* next in the list */ xsltVarInfoPtr prev; int depth; /* the depth in the tree */ const xmlChar *name; const xmlChar *nsName; }; /** * xsltCompilerNodeInfo: * * Per-node information during compile-time. */ typedef struct _xsltCompilerNodeInfo xsltCompilerNodeInfo; typedef xsltCompilerNodeInfo *xsltCompilerNodeInfoPtr; struct _xsltCompilerNodeInfo { xsltCompilerNodeInfoPtr next; xsltCompilerNodeInfoPtr prev; xmlNodePtr node; int depth; xsltTemplatePtr templ; /* The owning template */ int category; /* XSLT element, LR-element or extension element */ xsltStyleType type; xsltElemPreCompPtr item; /* The compiled information */ /* The current in-scope namespaces */ xsltNsListContainerPtr inScopeNs; /* The current excluded result namespaces */ xsltPointerListPtr exclResultNs; /* The current extension instruction namespaces */ xsltPointerListPtr extElemNs; /* The current info for literal result elements. */ xsltStyleItemLRElementInfoPtr litResElemInfo; /* * Set to 1 if in-scope namespaces changed, * or excluded result namespaces changed, * or extension element namespaces changed. * This will trigger creation of new infos * for literal result elements. */ int nsChanged; int preserveWhitespace; int stripWhitespace; int isRoot; /* whether this is the stylesheet's root node */ int forwardsCompat; /* whether forwards-compatible mode is enabled */ /* whether the content of an extension element was processed */ int extContentHandled; /* the type of the current child */ xsltStyleType curChildType; }; /** * XSLT_CCTXT: * * get pointer to compiler context */ #define XSLT_CCTXT(style) ((xsltCompilerCtxtPtr) style->compCtxt) typedef enum { XSLT_ERROR_SEVERITY_ERROR = 0, XSLT_ERROR_SEVERITY_WARNING } xsltErrorSeverityType; typedef struct _xsltCompilerCtxt xsltCompilerCtxt; typedef xsltCompilerCtxt *xsltCompilerCtxtPtr; struct _xsltCompilerCtxt { void *errorCtxt; /* user specific error context */ /* * used for error/warning reports; e.g. XSLT_ERROR_SEVERITY_WARNING */ xsltErrorSeverityType errSeverity; int warnings; /* TODO: number of warnings found at compilation */ int errors; /* TODO: number of errors found at compilation */ xmlDictPtr dict; xsltStylesheetPtr style; int simplified; /* whether this is a simplified stylesheet */ /* TODO: structured/unstructured error contexts. */ int depth; /* Current depth of processing */ xsltCompilerNodeInfoPtr inode; xsltCompilerNodeInfoPtr inodeList; xsltCompilerNodeInfoPtr inodeLast; xsltPointerListPtr tmpList; /* Used for various purposes */ /* * The XSLT version as specified by the stylesheet's root element. */ int isInclude; int hasForwardsCompat; /* whether forwards-compatible mode was used in a parsing episode */ int maxNodeInfos; /* TEMP TODO: just for the interest */ int maxLREs; /* TEMP TODO: just for the interest */ /* * In order to keep the old behaviour, applying strict rules of * the spec can be turned off. This has effect only on special * mechanisms like whitespace-stripping in the stylesheet. */ int strict; xsltPrincipalStylesheetDataPtr psData; #ifdef XSLT_REFACTORED_XPATHCOMP xmlXPathContextPtr xpathCtxt; #endif xsltStyleItemUknownPtr unknownItem; int hasNsAliases; /* Indicator if there was an xsl:namespace-alias. */ xsltNsAliasPtr nsAliases; xsltVarInfoPtr ivars; /* Storage of local in-scope variables/params. */ xsltVarInfoPtr ivar; /* topmost local variable/param. */ }; #else /* XSLT_REFACTORED */ /* * The old structures before refactoring. */ /** * _xsltStylePreComp: * * The in-memory structure corresponding to XSLT stylesheet constructs * precomputed data. */ struct _xsltStylePreComp { xsltElemPreCompPtr next; /* chained list */ xsltStyleType type; /* type of the element */ xsltTransformFunction func; /* handling function */ xmlNodePtr inst; /* the instruction */ /* * Pre computed values. */ const xmlChar *stype; /* sort */ int has_stype; /* sort */ int number; /* sort */ const xmlChar *order; /* sort */ int has_order; /* sort */ int descending; /* sort */ const xmlChar *lang; /* sort */ int has_lang; /* sort */ xsltLocale locale; /* sort */ const xmlChar *case_order; /* sort */ int lower_first; /* sort */ const xmlChar *use; /* copy, element */ int has_use; /* copy, element */ int noescape; /* text */ const xmlChar *name; /* element, attribute, pi */ int has_name; /* element, attribute, pi */ const xmlChar *ns; /* element */ int has_ns; /* element */ const xmlChar *mode; /* apply-templates */ const xmlChar *modeURI; /* apply-templates */ const xmlChar *test; /* if */ xsltTemplatePtr templ; /* call-template */ const xmlChar *select; /* sort, copy-of, value-of, apply-templates */ int ver11; /* document */ const xmlChar *filename; /* document URL */ int has_filename; /* document */ xsltNumberData numdata; /* number */ xmlXPathCompExprPtr comp; /* a precompiled XPath expression */ xmlNsPtr *nsList; /* the namespaces in scope */ int nsNr; /* the number of namespaces in scope */ }; #endif /* XSLT_REFACTORED */ /* * The in-memory structure corresponding to an XSLT Variable * or Param. */ typedef struct _xsltStackElem xsltStackElem; typedef xsltStackElem *xsltStackElemPtr; struct _xsltStackElem { struct _xsltStackElem *next;/* chained list */ xsltStylePreCompPtr comp; /* the compiled form */ int computed; /* was the evaluation done */ const xmlChar *name; /* the local part of the name QName */ const xmlChar *nameURI; /* the URI part of the name QName */ const xmlChar *select; /* the eval string */ xmlNodePtr tree; /* the sequence constructor if no eval string or the location */ xmlXPathObjectPtr value; /* The value if computed */ xmlDocPtr fragment; /* The Result Tree Fragments (needed for XSLT 1.0) which are bound to the variable's lifetime. */ int level; /* the depth in the tree; -1 if persistent (e.g. a given xsl:with-param) */ xsltTransformContextPtr context; /* The transformation context; needed to cache the variables */ int flags; }; #ifdef XSLT_REFACTORED struct _xsltPrincipalStylesheetData { /* * Namespace dictionary for ns-prefixes and ns-names: * TODO: Shared between stylesheets, and XPath mechanisms. * Not used yet. */ xmlDictPtr namespaceDict; /* * Global list of in-scope namespaces. */ xsltPointerListPtr inScopeNamespaces; /* * Global list of information for [xsl:]excluded-result-prefixes. */ xsltPointerListPtr exclResultNamespaces; /* * Global list of information for [xsl:]extension-element-prefixes. */ xsltPointerListPtr extElemNamespaces; xsltEffectiveNsPtr effectiveNs; #ifdef XSLT_REFACTORED_XSLT_NSCOMP /* * Namespace name map to get rid of string comparison of namespace names. */ xsltNsMapPtr nsMap; #endif }; #endif /* * Note that we added a @compCtxt field to anchor an stylesheet compilation * context, since, due to historical reasons, various compile-time function * take only the stylesheet as argument and not a compilation context. */ struct _xsltStylesheet { /* * The stylesheet import relation is kept as a tree. */ struct _xsltStylesheet *parent; struct _xsltStylesheet *next; struct _xsltStylesheet *imports; xsltDocumentPtr docList; /* the include document list */ /* * General data on the style sheet document. */ xmlDocPtr doc; /* the parsed XML stylesheet */ xmlHashTablePtr stripSpaces;/* the hash table of the strip-space and preserve space elements */ int stripAll; /* strip-space * (1) preserve-space * (-1) */ xmlHashTablePtr cdataSection;/* the hash table of the cdata-section */ /* * Global variable or parameters. */ xsltStackElemPtr variables; /* linked list of param and variables */ /* * Template descriptions. */ xsltTemplatePtr templates; /* the ordered list of templates */ void *templatesHash; /* hash table or wherever compiled templates informations are stored */ void *rootMatch; /* template based on / */ void *keyMatch; /* template based on key() */ void *elemMatch; /* template based on * */ void *attrMatch; /* template based on @* */ void *parentMatch; /* template based on .. */ void *textMatch; /* template based on text() */ void *piMatch; /* template based on processing-instruction() */ void *commentMatch; /* template based on comment() */ /* * Namespace aliases. * NOTE: Not used in the refactored code. */ xmlHashTablePtr nsAliases; /* the namespace alias hash tables */ /* * Attribute sets. */ xmlHashTablePtr attributeSets;/* the attribute sets hash tables */ /* * Namespaces. * TODO: Eliminate this. */ xmlHashTablePtr nsHash; /* the set of namespaces in use: ATTENTION: This is used for execution of XPath expressions; unfortunately it restricts the stylesheet to have distinct prefixes. TODO: We need to get rid of this. */ void *nsDefs; /* ATTENTION TODO: This is currently used to store xsltExtDefPtr (in extensions.c) and *not* xmlNsPtr. */ /* * Key definitions. */ void *keys; /* key definitions */ /* * Output related stuff. */ xmlChar *method; /* the output method */ xmlChar *methodURI; /* associated namespace if any */ xmlChar *version; /* version string */ xmlChar *encoding; /* encoding string */ int omitXmlDeclaration; /* omit-xml-declaration = "yes" | "no" */ /* * Number formatting. */ xsltDecimalFormatPtr decimalFormat; int standalone; /* standalone = "yes" | "no" */ xmlChar *doctypePublic; /* doctype-public string */ xmlChar *doctypeSystem; /* doctype-system string */ int indent; /* should output being indented */ xmlChar *mediaType; /* media-type string */ /* * Precomputed blocks. */ xsltElemPreCompPtr preComps;/* list of precomputed blocks */ int warnings; /* number of warnings found at compilation */ int errors; /* number of errors found at compilation */ xmlChar *exclPrefix; /* last excluded prefixes */ xmlChar **exclPrefixTab; /* array of excluded prefixes */ int exclPrefixNr; /* number of excluded prefixes in scope */ int exclPrefixMax; /* size of the array */ void *_private; /* user defined data */ /* * Extensions. */ xmlHashTablePtr extInfos; /* the extension data */ int extrasNr; /* the number of extras required */ /* * For keeping track of nested includes */ xsltDocumentPtr includes; /* points to last nested include */ /* * dictionary: shared between stylesheet, context and documents. */ xmlDictPtr dict; /* * precompiled attribute value templates. */ void *attVTs; /* * if namespace-alias has an alias for the default stylesheet prefix * NOTE: Not used in the refactored code. */ const xmlChar *defaultAlias; /* * bypass pre-processing (already done) (used in imports) */ int nopreproc; /* * all document text strings were internalized */ int internalized; /* * Literal Result Element as Stylesheet c.f. section 2.3 */ int literal_result; /* * The principal stylesheet */ xsltStylesheetPtr principal; #ifdef XSLT_REFACTORED /* * Compilation context used during compile-time. */ xsltCompilerCtxtPtr compCtxt; /* TODO: Change this to (void *). */ xsltPrincipalStylesheetDataPtr principalData; #endif /* * Forwards-compatible processing */ int forwards_compatible; }; typedef struct _xsltTransformCache xsltTransformCache; typedef xsltTransformCache *xsltTransformCachePtr; struct _xsltTransformCache { xmlDocPtr RVT; int nbRVT; xsltStackElemPtr stackItems; int nbStackItems; #ifdef XSLT_DEBUG_PROFILE_CACHE int dbgCachedRVTs; int dbgReusedRVTs; int dbgCachedVars; int dbgReusedVars; #endif }; /* * The in-memory structure corresponding to an XSLT Transformation. */ typedef enum { XSLT_OUTPUT_XML = 0, XSLT_OUTPUT_HTML, XSLT_OUTPUT_TEXT } xsltOutputType; typedef enum { XSLT_STATE_OK = 0, XSLT_STATE_ERROR, XSLT_STATE_STOPPED } xsltTransformState; struct _xsltTransformContext { xsltStylesheetPtr style; /* the stylesheet used */ xsltOutputType type; /* the type of output */ xsltTemplatePtr templ; /* the current template */ int templNr; /* Nb of templates in the stack */ int templMax; /* Size of the templtes stack */ xsltTemplatePtr *templTab; /* the template stack */ xsltStackElemPtr vars; /* the current variable list */ int varsNr; /* Nb of variable list in the stack */ int varsMax; /* Size of the variable list stack */ xsltStackElemPtr *varsTab; /* the variable list stack */ int varsBase; /* the var base for current templ */ /* * Extensions */ xmlHashTablePtr extFunctions; /* the extension functions */ xmlHashTablePtr extElements; /* the extension elements */ xmlHashTablePtr extInfos; /* the extension data */ const xmlChar *mode; /* the current mode */ const xmlChar *modeURI; /* the current mode URI */ xsltDocumentPtr docList; /* the document list */ xsltDocumentPtr document; /* the current source document; can be NULL if an RTF */ xmlNodePtr node; /* the current node being processed */ xmlNodeSetPtr nodeList; /* the current node list */ /* xmlNodePtr current; the node */ xmlDocPtr output; /* the resulting document */ xmlNodePtr insert; /* the insertion node */ xmlXPathContextPtr xpathCtxt; /* the XPath context */ xsltTransformState state; /* the current state */ /* * Global variables */ xmlHashTablePtr globalVars; /* the global variables and params */ xmlNodePtr inst; /* the instruction in the stylesheet */ int xinclude; /* should XInclude be processed */ const char * outputFile; /* the output URI if known */ int profile; /* is this run profiled */ long prof; /* the current profiled value */ int profNr; /* Nb of templates in the stack */ int profMax; /* Size of the templtaes stack */ long *profTab; /* the profile template stack */ void *_private; /* user defined data */ int extrasNr; /* the number of extras used */ int extrasMax; /* the number of extras allocated */ xsltRuntimeExtraPtr extras; /* extra per runtime informations */ xsltDocumentPtr styleList; /* the stylesheet docs list */ void * sec; /* the security preferences if any */ xmlGenericErrorFunc error; /* a specific error handler */ void * errctx; /* context for the error handler */ xsltSortFunc sortfunc; /* a ctxt specific sort routine */ /* * handling of temporary Result Value Tree * (XSLT 1.0 term: "Result Tree Fragment") */ xmlDocPtr tmpRVT; /* list of RVT without persistance */ xmlDocPtr persistRVT; /* list of persistant RVTs */ int ctxtflags; /* context processing flags */ /* * Speed optimization when coalescing text nodes */ const xmlChar *lasttext; /* last text node content */ unsigned int lasttsize; /* last text node size */ unsigned int lasttuse; /* last text node use */ /* * Per Context Debugging */ int debugStatus; /* the context level debug status */ unsigned long* traceCode; /* pointer to the variable holding the mask */ int parserOptions; /* parser options xmlParserOption */ /* * dictionary: shared between stylesheet, context and documents. */ xmlDictPtr dict; xmlDocPtr tmpDoc; /* Obsolete; not used in the library. */ /* * all document text strings are internalized */ int internalized; int nbKeys; int hasTemplKeyPatterns; xsltTemplatePtr currentTemplateRule; /* the Current Template Rule */ xmlNodePtr initialContextNode; xmlDocPtr initialContextDoc; xsltTransformCachePtr cache; void *contextVariable; /* the current variable item */ xmlDocPtr localRVT; /* list of local tree fragments; will be freed when the instruction which created the fragment exits */ xmlDocPtr localRVTBase; int keyInitLevel; /* Needed to catch recursive keys issues */ int funcLevel; /* Needed to catch recursive functions issues */ int maxTemplateDepth; int maxTemplateVars; }; /** * CHECK_STOPPED: * * Macro to check if the XSLT processing should be stopped. * Will return from the function. */ #define CHECK_STOPPED if (ctxt->state == XSLT_STATE_STOPPED) return; /** * CHECK_STOPPEDE: * * Macro to check if the XSLT processing should be stopped. * Will goto the error: label. */ #define CHECK_STOPPEDE if (ctxt->state == XSLT_STATE_STOPPED) goto error; /** * CHECK_STOPPED0: * * Macro to check if the XSLT processing should be stopped. * Will return from the function with a 0 value. */ #define CHECK_STOPPED0 if (ctxt->state == XSLT_STATE_STOPPED) return(0); /* * The macro XML_CAST_FPTR is a hack to avoid a gcc warning about * possible incompatibilities between function pointers and object * pointers. It is defined in libxml/hash.h within recent versions * of libxml2, but is put here for compatibility. */ #ifndef XML_CAST_FPTR /** * XML_CAST_FPTR: * @fptr: pointer to a function * * Macro to do a casting from an object pointer to a * function pointer without encountering a warning from * gcc * * #define XML_CAST_FPTR(fptr) (*(void **)(&fptr)) * This macro violated ISO C aliasing rules (gcc4 on s390 broke) * so it is disabled now */ #define XML_CAST_FPTR(fptr) fptr #endif /* * Functions associated to the internal types xsltDecimalFormatPtr xsltDecimalFormatGetByName(xsltStylesheetPtr sheet, xmlChar *name); */ XSLTPUBFUN xsltStylesheetPtr XSLTCALL xsltNewStylesheet (void); XSLTPUBFUN xsltStylesheetPtr XSLTCALL xsltParseStylesheetFile (const xmlChar* filename); XSLTPUBFUN void XSLTCALL xsltFreeStylesheet (xsltStylesheetPtr style); XSLTPUBFUN int XSLTCALL xsltIsBlank (xmlChar *str); XSLTPUBFUN void XSLTCALL xsltFreeStackElemList (xsltStackElemPtr elem); XSLTPUBFUN xsltDecimalFormatPtr XSLTCALL xsltDecimalFormatGetByName(xsltStylesheetPtr style, xmlChar *name); XSLTPUBFUN xsltStylesheetPtr XSLTCALL xsltParseStylesheetProcess(xsltStylesheetPtr ret, xmlDocPtr doc); XSLTPUBFUN void XSLTCALL xsltParseStylesheetOutput(xsltStylesheetPtr style, xmlNodePtr cur); XSLTPUBFUN xsltStylesheetPtr XSLTCALL xsltParseStylesheetDoc (xmlDocPtr doc); XSLTPUBFUN xsltStylesheetPtr XSLTCALL xsltParseStylesheetImportedDoc(xmlDocPtr doc, xsltStylesheetPtr style); XSLTPUBFUN xsltStylesheetPtr XSLTCALL xsltLoadStylesheetPI (xmlDocPtr doc); XSLTPUBFUN void XSLTCALL xsltNumberFormat (xsltTransformContextPtr ctxt, xsltNumberDataPtr data, xmlNodePtr node); XSLTPUBFUN xmlXPathError XSLTCALL xsltFormatNumberConversion(xsltDecimalFormatPtr self, xmlChar *format, double number, xmlChar **result); XSLTPUBFUN void XSLTCALL xsltParseTemplateContent(xsltStylesheetPtr style, xmlNodePtr templ); XSLTPUBFUN int XSLTCALL xsltAllocateExtra (xsltStylesheetPtr style); XSLTPUBFUN int XSLTCALL xsltAllocateExtraCtxt (xsltTransformContextPtr ctxt); /* * Extra functions for Result Value Trees */ XSLTPUBFUN xmlDocPtr XSLTCALL xsltCreateRVT (xsltTransformContextPtr ctxt); XSLTPUBFUN int XSLTCALL xsltRegisterTmpRVT (xsltTransformContextPtr ctxt, xmlDocPtr RVT); XSLTPUBFUN int XSLTCALL xsltRegisterLocalRVT (xsltTransformContextPtr ctxt, xmlDocPtr RVT); XSLTPUBFUN int XSLTCALL xsltRegisterPersistRVT (xsltTransformContextPtr ctxt, xmlDocPtr RVT); XSLTPUBFUN int XSLTCALL xsltExtensionInstructionResultRegister( xsltTransformContextPtr ctxt, xmlXPathObjectPtr obj); XSLTPUBFUN int XSLTCALL xsltExtensionInstructionResultFinalize( xsltTransformContextPtr ctxt); XSLTPUBFUN void XSLTCALL xsltFreeRVTs (xsltTransformContextPtr ctxt); XSLTPUBFUN void XSLTCALL xsltReleaseRVT (xsltTransformContextPtr ctxt, xmlDocPtr RVT); /* * Extra functions for Attribute Value Templates */ XSLTPUBFUN void XSLTCALL xsltCompileAttr (xsltStylesheetPtr style, xmlAttrPtr attr); XSLTPUBFUN xmlChar * XSLTCALL xsltEvalAVT (xsltTransformContextPtr ctxt, void *avt, xmlNodePtr node); XSLTPUBFUN void XSLTCALL xsltFreeAVTList (void *avt); /* * Extra function for successful xsltCleanupGlobals / xsltInit sequence. */ XSLTPUBFUN void XSLTCALL xsltUninit (void); /************************************************************************ * * * Compile-time functions for *internal* use only * * * ************************************************************************/ #ifdef XSLT_REFACTORED XSLTPUBFUN void XSLTCALL xsltParseSequenceConstructor( xsltCompilerCtxtPtr cctxt, xmlNodePtr start); XSLTPUBFUN int XSLTCALL xsltParseAnyXSLTElem (xsltCompilerCtxtPtr cctxt, xmlNodePtr elem); #ifdef XSLT_REFACTORED_XSLT_NSCOMP XSLTPUBFUN int XSLTCALL xsltRestoreDocumentNamespaces( xsltNsMapPtr ns, xmlDocPtr doc); #endif #endif /* XSLT_REFACTORED */ /************************************************************************ * * * Transformation-time functions for *internal* use only * * * ************************************************************************/ XSLTPUBFUN int XSLTCALL xsltInitCtxtKey (xsltTransformContextPtr ctxt, xsltDocumentPtr doc, xsltKeyDefPtr keyd); XSLTPUBFUN int XSLTCALL xsltInitAllDocKeys (xsltTransformContextPtr ctxt); #ifdef __cplusplus } #endif #endif /* __XML_XSLT_H__ */ libxslt-1.1.28/libxslt/extensions.c0000664000076400007640000017335612024022316014252 00000000000000/* * extensions.c: Implemetation of the extensions support * * Reference: * http://www.w3.org/TR/1999/REC-xslt-19991116 * * See Copyright for the status of this software. * * daniel@veillard.com */ #define IN_LIBXSLT #include "libxslt.h" #include #include #include #include #include #include #include #include #ifdef WITH_MODULES #include #endif #include #include #include "xslt.h" #include "xsltInternals.h" #include "xsltutils.h" #include "imports.h" #include "extensions.h" #ifdef _WIN32 #include /* for _MAX_PATH */ #ifndef PATH_MAX #define PATH_MAX _MAX_PATH #endif #endif #ifdef WITH_XSLT_DEBUG #define WITH_XSLT_DEBUG_EXTENSIONS #endif /************************************************************************ * * * Private Types and Globals * * * ************************************************************************/ typedef struct _xsltExtDef xsltExtDef; typedef xsltExtDef *xsltExtDefPtr; struct _xsltExtDef { struct _xsltExtDef *next; xmlChar *prefix; xmlChar *URI; void *data; }; typedef struct _xsltExtModule xsltExtModule; typedef xsltExtModule *xsltExtModulePtr; struct _xsltExtModule { xsltExtInitFunction initFunc; xsltExtShutdownFunction shutdownFunc; xsltStyleExtInitFunction styleInitFunc; xsltStyleExtShutdownFunction styleShutdownFunc; }; typedef struct _xsltExtData xsltExtData; typedef xsltExtData *xsltExtDataPtr; struct _xsltExtData { xsltExtModulePtr extModule; void *extData; }; typedef struct _xsltExtElement xsltExtElement; typedef xsltExtElement *xsltExtElementPtr; struct _xsltExtElement { xsltPreComputeFunction precomp; xsltTransformFunction transform; }; static xmlHashTablePtr xsltExtensionsHash = NULL; static xmlHashTablePtr xsltFunctionsHash = NULL; static xmlHashTablePtr xsltElementsHash = NULL; static xmlHashTablePtr xsltTopLevelsHash = NULL; static xmlHashTablePtr xsltModuleHash = NULL; static xmlMutexPtr xsltExtMutex = NULL; /************************************************************************ * * * Type functions * * * ************************************************************************/ /** * xsltNewExtDef: * @prefix: the extension prefix * @URI: the namespace URI * * Create a new XSLT ExtDef * * Returns the newly allocated xsltExtDefPtr or NULL in case of error */ static xsltExtDefPtr xsltNewExtDef(const xmlChar * prefix, const xmlChar * URI) { xsltExtDefPtr cur; cur = (xsltExtDefPtr) xmlMalloc(sizeof(xsltExtDef)); if (cur == NULL) { xsltTransformError(NULL, NULL, NULL, "xsltNewExtDef : malloc failed\n"); return (NULL); } memset(cur, 0, sizeof(xsltExtDef)); if (prefix != NULL) cur->prefix = xmlStrdup(prefix); if (URI != NULL) cur->URI = xmlStrdup(URI); return (cur); } /** * xsltFreeExtDef: * @extensiond: an XSLT extension definition * * Free up the memory allocated by @extensiond */ static void xsltFreeExtDef(xsltExtDefPtr extensiond) { if (extensiond == NULL) return; if (extensiond->prefix != NULL) xmlFree(extensiond->prefix); if (extensiond->URI != NULL) xmlFree(extensiond->URI); xmlFree(extensiond); } /** * xsltFreeExtDefList: * @extensiond: an XSLT extension definition list * * Free up the memory allocated by all the elements of @extensiond */ static void xsltFreeExtDefList(xsltExtDefPtr extensiond) { xsltExtDefPtr cur; while (extensiond != NULL) { cur = extensiond; extensiond = extensiond->next; xsltFreeExtDef(cur); } } /** * xsltNewExtModule: * @initFunc: the module initialization function * @shutdownFunc: the module shutdown function * @styleInitFunc: the stylesheet module data allocator function * @styleShutdownFunc: the stylesheet module data free function * * Create a new XSLT extension module * * Returns the newly allocated xsltExtModulePtr or NULL in case of error */ static xsltExtModulePtr xsltNewExtModule(xsltExtInitFunction initFunc, xsltExtShutdownFunction shutdownFunc, xsltStyleExtInitFunction styleInitFunc, xsltStyleExtShutdownFunction styleShutdownFunc) { xsltExtModulePtr cur; cur = (xsltExtModulePtr) xmlMalloc(sizeof(xsltExtModule)); if (cur == NULL) { xsltTransformError(NULL, NULL, NULL, "xsltNewExtModule : malloc failed\n"); return (NULL); } cur->initFunc = initFunc; cur->shutdownFunc = shutdownFunc; cur->styleInitFunc = styleInitFunc; cur->styleShutdownFunc = styleShutdownFunc; return (cur); } /** * xsltFreeExtModule: * @ext: an XSLT extension module * * Free up the memory allocated by @ext */ static void xsltFreeExtModule(xsltExtModulePtr ext) { if (ext == NULL) return; xmlFree(ext); } /** * xsltNewExtData: * @extModule: the module * @extData: the associated data * * Create a new XSLT extension module data wrapper * * Returns the newly allocated xsltExtDataPtr or NULL in case of error */ static xsltExtDataPtr xsltNewExtData(xsltExtModulePtr extModule, void *extData) { xsltExtDataPtr cur; if (extModule == NULL) return (NULL); cur = (xsltExtDataPtr) xmlMalloc(sizeof(xsltExtData)); if (cur == NULL) { xsltTransformError(NULL, NULL, NULL, "xsltNewExtData : malloc failed\n"); return (NULL); } cur->extModule = extModule; cur->extData = extData; return (cur); } /** * xsltFreeExtData: * @ext: an XSLT extension module data wrapper * * Free up the memory allocated by @ext */ static void xsltFreeExtData(xsltExtDataPtr ext) { if (ext == NULL) return; xmlFree(ext); } /** * xsltNewExtElement: * @precomp: the pre-computation function * @transform: the transformation function * * Create a new XSLT extension element * * Returns the newly allocated xsltExtElementPtr or NULL in case of * error */ static xsltExtElementPtr xsltNewExtElement(xsltPreComputeFunction precomp, xsltTransformFunction transform) { xsltExtElementPtr cur; if (transform == NULL) return (NULL); cur = (xsltExtElementPtr) xmlMalloc(sizeof(xsltExtElement)); if (cur == NULL) { xsltTransformError(NULL, NULL, NULL, "xsltNewExtElement : malloc failed\n"); return (NULL); } cur->precomp = precomp; cur->transform = transform; return (cur); } /** * xsltFreeExtElement: * @ext: an XSLT extension element * * Frees up the memory allocated by @ext */ static void xsltFreeExtElement(xsltExtElementPtr ext) { if (ext == NULL) return; xmlFree(ext); } #ifdef WITH_MODULES typedef void (*exsltRegisterFunction) (void); #ifndef PATH_MAX #define PATH_MAX 4096 #endif /** * xsltExtModuleRegisterDynamic: * @URI: the function or element namespace URI * * Dynamically loads an extension plugin when available. * * The plugin name is derived from the URI by removing the * initial protocol designation, e.g. "http://", then converting * the characters ".", "-", "/", and "\" into "_", the removing * any trailing "/", then concatenating LIBXML_MODULE_EXTENSION. * * Plugins are loaded from the directory specified by the * environment variable LIBXSLT_PLUGINS_PATH, or if NULL, * by LIBXSLT_DEFAULT_PLUGINS_PATH() which is determined at * compile time. * * Returns 0 if successful, -1 in case of error. */ static int xsltExtModuleRegisterDynamic(const xmlChar * URI) { xmlModulePtr m; exsltRegisterFunction regfunc; xmlChar *ext_name; char module_filename[PATH_MAX]; const xmlChar *ext_directory = NULL; const xmlChar *protocol = NULL; xmlChar *i, *regfunc_name; void *vregfunc; int rc; /* check for bad inputs */ if (URI == NULL) return (-1); if (NULL == xsltModuleHash) { xsltModuleHash = xmlHashCreate(5); if (xsltModuleHash == NULL) return (-1); } xmlMutexLock(xsltExtMutex); /* have we attempted to register this module already? */ if (xmlHashLookup(xsltModuleHash, URI) != NULL) { xmlMutexUnlock(xsltExtMutex); return (-1); } xmlMutexUnlock(xsltExtMutex); /* transform extension namespace into a module name */ protocol = xmlStrstr(URI, BAD_CAST "://"); if (protocol == NULL) { ext_name = xmlStrdup(URI); } else { ext_name = xmlStrdup(protocol + 3); } if (ext_name == NULL) { return (-1); } i = ext_name; while ('\0' != *i) { if (('/' == *i) || ('\\' == *i) || ('.' == *i) || ('-' == *i)) *i = '_'; i++; } if (*(i - 1) == '_') *i = '\0'; /* determine module directory */ ext_directory = (xmlChar *) getenv("LIBXSLT_PLUGINS_PATH"); if (NULL == ext_directory) { ext_directory = BAD_CAST LIBXSLT_DEFAULT_PLUGINS_PATH(); if (NULL == ext_directory) return (-1); } #ifdef WITH_XSLT_DEBUG_EXTENSIONS else xsltGenericDebug(xsltGenericDebugContext, "LIBXSLT_PLUGINS_PATH is %s\n", ext_directory); #endif /* build the module filename, and confirm the module exists */ xmlStrPrintf((xmlChar *) module_filename, sizeof(module_filename), BAD_CAST "%s/%s%s", ext_directory, ext_name, LIBXML_MODULE_EXTENSION); #ifdef WITH_XSLT_DEBUG_EXTENSIONS xsltGenericDebug(xsltGenericDebugContext, "Attempting to load plugin: %s for URI: %s\n", module_filename, URI); #endif if (1 != xmlCheckFilename(module_filename)) { #ifdef WITH_XSLT_DEBUG_EXTENSIONS xsltGenericDebug(xsltGenericDebugContext, "xmlCheckFilename failed for plugin: %s\n", module_filename); #endif xmlFree(ext_name); return (-1); } /* attempt to open the module */ m = xmlModuleOpen(module_filename, 0); if (NULL == m) { #ifdef WITH_XSLT_DEBUG_EXTENSIONS xsltGenericDebug(xsltGenericDebugContext, "xmlModuleOpen failed for plugin: %s\n", module_filename); #endif xmlFree(ext_name); return (-1); } /* construct initialization func name */ regfunc_name = xmlStrdup(ext_name); regfunc_name = xmlStrcat(regfunc_name, BAD_CAST "_init"); vregfunc = NULL; rc = xmlModuleSymbol(m, (const char *) regfunc_name, &vregfunc); regfunc = vregfunc; if (0 == rc) { /* * Call the module's init function. Note that this function * calls xsltRegisterExtModuleFull which will add the module * to xsltExtensionsHash (together with it's entry points). */ (*regfunc) (); /* register this module in our hash */ xmlMutexLock(xsltExtMutex); xmlHashAddEntry(xsltModuleHash, URI, (void *) m); xmlMutexUnlock(xsltExtMutex); } else { #ifdef WITH_XSLT_DEBUG_EXTENSIONS xsltGenericDebug(xsltGenericDebugContext, "xmlModuleSymbol failed for plugin: %s, regfunc: %s\n", module_filename, regfunc_name); #endif /* if regfunc not found unload the module immediately */ xmlModuleClose(m); } xmlFree(ext_name); xmlFree(regfunc_name); return (NULL == regfunc) ? -1 : 0; } #else static int xsltExtModuleRegisterDynamic(const xmlChar * URI ATTRIBUTE_UNUSED) { return -1; } #endif /************************************************************************ * * * The stylesheet extension prefixes handling * * * ************************************************************************/ /** * xsltFreeExts: * @style: an XSLT stylesheet * * Free up the memory used by XSLT extensions in a stylesheet */ void xsltFreeExts(xsltStylesheetPtr style) { if (style->nsDefs != NULL) xsltFreeExtDefList((xsltExtDefPtr) style->nsDefs); } /** * xsltRegisterExtPrefix: * @style: an XSLT stylesheet * @prefix: the prefix used (optional) * @URI: the URI associated to the extension * * Registers an extension namespace * This is called from xslt.c during compile-time. * The given prefix is not needed. * Called by: * xsltParseExtElemPrefixes() (new function) * xsltRegisterExtPrefix() (old function) * * Returns 0 in case of success, 1 if the @URI was already * registered as an extension namespace and * -1 in case of failure */ int xsltRegisterExtPrefix(xsltStylesheetPtr style, const xmlChar * prefix, const xmlChar * URI) { xsltExtDefPtr def, ret; if ((style == NULL) || (URI == NULL)) return (-1); #ifdef WITH_XSLT_DEBUG_EXTENSIONS xsltGenericDebug(xsltGenericDebugContext, "Registering extension namespace '%s'.\n", URI); #endif def = (xsltExtDefPtr) style->nsDefs; #ifdef XSLT_REFACTORED /* * The extension is associated with a namespace name. */ while (def != NULL) { if (xmlStrEqual(URI, def->URI)) return (1); def = def->next; } #else while (def != NULL) { if (xmlStrEqual(prefix, def->prefix)) return (-1); def = def->next; } #endif ret = xsltNewExtDef(prefix, URI); if (ret == NULL) return (-1); ret->next = (xsltExtDefPtr) style->nsDefs; style->nsDefs = ret; /* * check whether there is an extension module with a stylesheet * initialization function. */ #ifdef XSLT_REFACTORED /* * Don't initialize modules based on specified namespaces via * the attribute "[xsl:]extension-element-prefixes". */ #else if (xsltExtensionsHash != NULL) { xsltExtModulePtr module; xmlMutexLock(xsltExtMutex); module = xmlHashLookup(xsltExtensionsHash, URI); xmlMutexUnlock(xsltExtMutex); if (NULL == module) { if (!xsltExtModuleRegisterDynamic(URI)) { xmlMutexLock(xsltExtMutex); module = xmlHashLookup(xsltExtensionsHash, URI); xmlMutexUnlock(xsltExtMutex); } } if (module != NULL) { xsltStyleGetExtData(style, URI); } } #endif return (0); } /************************************************************************ * * * The extensions modules interfaces * * * ************************************************************************/ /** * xsltRegisterExtFunction: * @ctxt: an XSLT transformation context * @name: the name of the element * @URI: the URI associated to the element * @function: the actual implementation which should be called * * Registers an extension function * * Returns 0 in case of success, -1 in case of failure */ int xsltRegisterExtFunction(xsltTransformContextPtr ctxt, const xmlChar * name, const xmlChar * URI, xmlXPathFunction function) { int ret; if ((ctxt == NULL) || (name == NULL) || (URI == NULL) || (function == NULL)) return (-1); if (ctxt->xpathCtxt != NULL) { xmlXPathRegisterFuncNS(ctxt->xpathCtxt, name, URI, function); } if (ctxt->extFunctions == NULL) ctxt->extFunctions = xmlHashCreate(10); if (ctxt->extFunctions == NULL) return (-1); ret = xmlHashAddEntry2(ctxt->extFunctions, name, URI, XML_CAST_FPTR(function)); return(ret); } /** * xsltRegisterExtElement: * @ctxt: an XSLT transformation context * @name: the name of the element * @URI: the URI associated to the element * @function: the actual implementation which should be called * * Registers an extension element * * Returns 0 in case of success, -1 in case of failure */ int xsltRegisterExtElement(xsltTransformContextPtr ctxt, const xmlChar * name, const xmlChar * URI, xsltTransformFunction function) { if ((ctxt == NULL) || (name == NULL) || (URI == NULL) || (function == NULL)) return (-1); if (ctxt->extElements == NULL) ctxt->extElements = xmlHashCreate(10); if (ctxt->extElements == NULL) return (-1); return (xmlHashAddEntry2 (ctxt->extElements, name, URI, XML_CAST_FPTR(function))); } /** * xsltFreeCtxtExts: * @ctxt: an XSLT transformation context * * Free the XSLT extension data */ void xsltFreeCtxtExts(xsltTransformContextPtr ctxt) { if (ctxt->extElements != NULL) xmlHashFree(ctxt->extElements, NULL); if (ctxt->extFunctions != NULL) xmlHashFree(ctxt->extFunctions, NULL); } /** * xsltStyleGetStylesheetExtData: * @style: an XSLT stylesheet * @URI: the URI associated to the exension module * * Fires the compile-time initialization callback * of an extension module and returns a container * holding the user-data (retrieved via the callback). * * Returns the create module-data container * or NULL if such a module was not registered. */ static xsltExtDataPtr xsltStyleInitializeStylesheetModule(xsltStylesheetPtr style, const xmlChar * URI) { xsltExtDataPtr dataContainer; void *userData = NULL; xsltExtModulePtr module; if ((style == NULL) || (URI == NULL)) return(NULL); if (xsltExtensionsHash == NULL) { #ifdef WITH_XSLT_DEBUG_EXTENSIONS xsltGenericDebug(xsltGenericDebugContext, "Not registered extension module: %s\n", URI); #endif return(NULL); } xmlMutexLock(xsltExtMutex); module = xmlHashLookup(xsltExtensionsHash, URI); xmlMutexUnlock(xsltExtMutex); if (module == NULL) { #ifdef WITH_XSLT_DEBUG_EXTENSIONS xsltGenericDebug(xsltGenericDebugContext, "Not registered extension module: %s\n", URI); #endif return (NULL); } /* * The specified module was registered so initialize it. */ if (style->extInfos == NULL) { style->extInfos = xmlHashCreate(10); if (style->extInfos == NULL) return (NULL); } /* * Fire the initialization callback if available. */ if (module->styleInitFunc == NULL) { #ifdef WITH_XSLT_DEBUG_EXTENSIONS xsltGenericDebug(xsltGenericDebugContext, "Initializing module with *no* callback: %s\n", URI); #endif } else { #ifdef WITH_XSLT_DEBUG_EXTENSIONS xsltGenericDebug(xsltGenericDebugContext, "Initializing module with callback: %s\n", URI); #endif /* * Fire the initialization callback. */ userData = module->styleInitFunc(style, URI); } /* * Store the user-data in the context of the given stylesheet. */ dataContainer = xsltNewExtData(module, userData); if (dataContainer == NULL) return (NULL); if (xmlHashAddEntry(style->extInfos, URI, (void *) dataContainer) < 0) { xsltTransformError(NULL, style, NULL, "Failed to register module '%s'.\n", URI); style->errors++; if (module->styleShutdownFunc) module->styleShutdownFunc(style, URI, userData); xsltFreeExtData(dataContainer); return (NULL); } return(dataContainer); } /** * xsltStyleGetExtData: * @style: an XSLT stylesheet * @URI: the URI associated to the exension module * * Retrieve the data associated to the extension module * in this given stylesheet. * Called by: * xsltRegisterExtPrefix(), * ( xsltExtElementPreCompTest(), xsltExtInitTest ) * * Returns the pointer or NULL if not present */ void * xsltStyleGetExtData(xsltStylesheetPtr style, const xmlChar * URI) { xsltExtDataPtr dataContainer = NULL; xsltStylesheetPtr tmpStyle; if ((style == NULL) || (URI == NULL) || (xsltExtensionsHash == NULL)) return (NULL); #ifdef XSLT_REFACTORED /* * This is intended for global storage, so only the main * stylesheet will hold the data. */ tmpStyle = style; while (tmpStyle->parent != NULL) tmpStyle = tmpStyle->parent; if (tmpStyle->extInfos != NULL) { dataContainer = (xsltExtDataPtr) xmlHashLookup(tmpStyle->extInfos, URI); if (dataContainer != NULL) { /* * The module was already initialized in the context * of this stylesheet; just return the user-data that * comes with it. */ return(dataContainer->extData); } } #else /* * Old behaviour. */ tmpStyle = style; while (tmpStyle != NULL) { if (tmpStyle->extInfos != NULL) { dataContainer = (xsltExtDataPtr) xmlHashLookup(tmpStyle->extInfos, URI); if (dataContainer != NULL) { return(dataContainer->extData); } } tmpStyle = xsltNextImport(tmpStyle); } tmpStyle = style; #endif dataContainer = xsltStyleInitializeStylesheetModule(tmpStyle, URI); if (dataContainer != NULL) return (dataContainer->extData); return(NULL); } #ifdef XSLT_REFACTORED /** * xsltStyleStylesheetLevelGetExtData: * @style: an XSLT stylesheet * @URI: the URI associated to the exension module * * Retrieve the data associated to the extension module in this given * stylesheet. * * Returns the pointer or NULL if not present */ void * xsltStyleStylesheetLevelGetExtData(xsltStylesheetPtr style, const xmlChar * URI) { xsltExtDataPtr dataContainer = NULL; if ((style == NULL) || (URI == NULL) || (xsltExtensionsHash == NULL)) return (NULL); if (style->extInfos != NULL) { dataContainer = (xsltExtDataPtr) xmlHashLookup(style->extInfos, URI); /* * The module was already initialized in the context * of this stylesheet; just return the user-data that * comes with it. */ if (dataContainer) return(dataContainer->extData); } dataContainer = xsltStyleInitializeStylesheetModule(style, URI); if (dataContainer != NULL) return (dataContainer->extData); return(NULL); } #endif /** * xsltGetExtData: * @ctxt: an XSLT transformation context * @URI: the URI associated to the exension module * * Retrieve the data associated to the extension module in this given * transformation. * * Returns the pointer or NULL if not present */ void * xsltGetExtData(xsltTransformContextPtr ctxt, const xmlChar * URI) { xsltExtDataPtr data; if ((ctxt == NULL) || (URI == NULL)) return (NULL); if (ctxt->extInfos == NULL) { ctxt->extInfos = xmlHashCreate(10); if (ctxt->extInfos == NULL) return (NULL); data = NULL; } else { data = (xsltExtDataPtr) xmlHashLookup(ctxt->extInfos, URI); } if (data == NULL) { void *extData; xsltExtModulePtr module; xmlMutexLock(xsltExtMutex); module = xmlHashLookup(xsltExtensionsHash, URI); xmlMutexUnlock(xsltExtMutex); if (module == NULL) { #ifdef WITH_XSLT_DEBUG_EXTENSIONS xsltGenericDebug(xsltGenericDebugContext, "Not registered extension module: %s\n", URI); #endif return (NULL); } else { if (module->initFunc == NULL) return (NULL); #ifdef WITH_XSLT_DEBUG_EXTENSIONS xsltGenericDebug(xsltGenericDebugContext, "Initializing module: %s\n", URI); #endif extData = module->initFunc(ctxt, URI); if (extData == NULL) return (NULL); data = xsltNewExtData(module, extData); if (data == NULL) return (NULL); if (xmlHashAddEntry(ctxt->extInfos, URI, (void *) data) < 0) { xsltTransformError(ctxt, NULL, NULL, "Failed to register module data: %s\n", URI); if (module->shutdownFunc) module->shutdownFunc(ctxt, URI, extData); xsltFreeExtData(data); return (NULL); } } } return (data->extData); } typedef struct _xsltInitExtCtxt xsltInitExtCtxt; struct _xsltInitExtCtxt { xsltTransformContextPtr ctxt; int ret; }; /** * xsltInitCtxtExt: * @styleData: the registered stylesheet data for the module * @ctxt: the XSLT transformation context + the return value * @URI: the extension URI * * Initializes an extension module */ static void xsltInitCtxtExt(xsltExtDataPtr styleData, xsltInitExtCtxt * ctxt, const xmlChar * URI) { xsltExtModulePtr module; xsltExtDataPtr ctxtData; void *extData; if ((styleData == NULL) || (ctxt == NULL) || (URI == NULL) || (ctxt->ret == -1)) { #ifdef WITH_XSLT_DEBUG_EXTENSIONS xsltGenericDebug(xsltGenericDebugContext, "xsltInitCtxtExt: NULL param or error\n"); #endif return; } module = styleData->extModule; if ((module == NULL) || (module->initFunc == NULL)) { #ifdef WITH_XSLT_DEBUG_EXTENSIONS xsltGenericDebug(xsltGenericDebugContext, "xsltInitCtxtExt: no module or no initFunc\n"); #endif return; } ctxtData = (xsltExtDataPtr) xmlHashLookup(ctxt->ctxt->extInfos, URI); if (ctxtData != NULL) { #ifdef WITH_XSLT_DEBUG_EXTENSIONS xsltGenericDebug(xsltGenericDebugContext, "xsltInitCtxtExt: already initialized\n"); #endif return; } extData = module->initFunc(ctxt->ctxt, URI); if (extData == NULL) { #ifdef WITH_XSLT_DEBUG_EXTENSIONS xsltGenericDebug(xsltGenericDebugContext, "xsltInitCtxtExt: no extData\n"); #endif } ctxtData = xsltNewExtData(module, extData); if (ctxtData == NULL) { ctxt->ret = -1; return; } if (ctxt->ctxt->extInfos == NULL) ctxt->ctxt->extInfos = xmlHashCreate(10); if (ctxt->ctxt->extInfos == NULL) { ctxt->ret = -1; return; } if (xmlHashAddEntry(ctxt->ctxt->extInfos, URI, ctxtData) < 0) { xsltGenericError(xsltGenericErrorContext, "Failed to register module data: %s\n", URI); if (module->shutdownFunc) module->shutdownFunc(ctxt->ctxt, URI, extData); xsltFreeExtData(ctxtData); ctxt->ret = -1; return; } #ifdef WITH_XSLT_DEBUG_EXTENSIONS xsltGenericDebug(xsltGenericDebugContext, "Registered module %s\n", URI); #endif ctxt->ret++; } /** * xsltInitCtxtExts: * @ctxt: an XSLT transformation context * * Initialize the set of modules with registered stylesheet data * * Returns the number of modules initialized or -1 in case of error */ int xsltInitCtxtExts(xsltTransformContextPtr ctxt) { xsltStylesheetPtr style; xsltInitExtCtxt ctx; if (ctxt == NULL) return (-1); style = ctxt->style; if (style == NULL) return (-1); ctx.ctxt = ctxt; ctx.ret = 0; while (style != NULL) { if (style->extInfos != NULL) { xmlHashScan(style->extInfos, (xmlHashScanner) xsltInitCtxtExt, &ctx); if (ctx.ret == -1) return (-1); } style = xsltNextImport(style); } #ifdef WITH_XSLT_DEBUG_EXTENSIONS xsltGenericDebug(xsltGenericDebugContext, "Registered %d modules\n", ctx.ret); #endif return (ctx.ret); } /** * xsltShutdownCtxtExt: * @data: the registered data for the module * @ctxt: the XSLT transformation context * @URI: the extension URI * * Shutdown an extension module loaded */ static void xsltShutdownCtxtExt(xsltExtDataPtr data, xsltTransformContextPtr ctxt, const xmlChar * URI) { xsltExtModulePtr module; if ((data == NULL) || (ctxt == NULL) || (URI == NULL)) return; module = data->extModule; if ((module == NULL) || (module->shutdownFunc == NULL)) return; #ifdef WITH_XSLT_DEBUG_EXTENSIONS xsltGenericDebug(xsltGenericDebugContext, "Shutting down module : %s\n", URI); #endif module->shutdownFunc(ctxt, URI, data->extData); } /** * xsltShutdownCtxtExts: * @ctxt: an XSLT transformation context * * Shutdown the set of modules loaded */ void xsltShutdownCtxtExts(xsltTransformContextPtr ctxt) { if (ctxt == NULL) return; if (ctxt->extInfos == NULL) return; xmlHashScan(ctxt->extInfos, (xmlHashScanner) xsltShutdownCtxtExt, ctxt); xmlHashFree(ctxt->extInfos, (xmlHashDeallocator) xsltFreeExtData); ctxt->extInfos = NULL; } /** * xsltShutdownExt: * @data: the registered data for the module * @ctxt: the XSLT stylesheet * @URI: the extension URI * * Shutdown an extension module loaded */ static void xsltShutdownExt(xsltExtDataPtr data, xsltStylesheetPtr style, const xmlChar * URI) { xsltExtModulePtr module; if ((data == NULL) || (style == NULL) || (URI == NULL)) return; module = data->extModule; if ((module == NULL) || (module->styleShutdownFunc == NULL)) return; #ifdef WITH_XSLT_DEBUG_EXTENSIONS xsltGenericDebug(xsltGenericDebugContext, "Shutting down module : %s\n", URI); #endif module->styleShutdownFunc(style, URI, data->extData); /* * Don't remove the entry from the hash table here, since * this will produce segfaults - this fixes bug #340624. * * xmlHashRemoveEntry(style->extInfos, URI, * (xmlHashDeallocator) xsltFreeExtData); */ } /** * xsltShutdownExts: * @style: an XSLT stylesheet * * Shutdown the set of modules loaded */ void xsltShutdownExts(xsltStylesheetPtr style) { if (style == NULL) return; if (style->extInfos == NULL) return; xmlHashScan(style->extInfos, (xmlHashScanner) xsltShutdownExt, style); xmlHashFree(style->extInfos, (xmlHashDeallocator) xsltFreeExtData); style->extInfos = NULL; } /** * xsltCheckExtPrefix: * @style: the stylesheet * @URI: the namespace prefix (possibly NULL) * * Check if the given prefix is one of the declared extensions. * This is intended to be called only at compile-time. * Called by: * xsltGetInheritedNsList() (xslt.c) * xsltParseTemplateContent (xslt.c) * * Returns 1 if this is an extension, 0 otherwise */ int xsltCheckExtPrefix(xsltStylesheetPtr style, const xmlChar * URI) { #ifdef XSLT_REFACTORED if ((style == NULL) || (style->compCtxt == NULL) || (XSLT_CCTXT(style)->inode == NULL) || (XSLT_CCTXT(style)->inode->extElemNs == NULL)) return (0); /* * Lookup the extension namespaces registered * at the current node in the stylesheet's tree. */ if (XSLT_CCTXT(style)->inode->extElemNs != NULL) { int i; xsltPointerListPtr list = XSLT_CCTXT(style)->inode->extElemNs; for (i = 0; i < list->number; i++) { if (xmlStrEqual((const xmlChar *) list->items[i], URI)) { return(1); } } } #else xsltExtDefPtr cur; if ((style == NULL) || (style->nsDefs == NULL)) return (0); if (URI == NULL) URI = BAD_CAST "#default"; cur = (xsltExtDefPtr) style->nsDefs; while (cur != NULL) { /* * NOTE: This was change to work on namespace names rather * than namespace prefixes. This fixes bug #339583. * TODO: Consider renaming the field "prefix" of xsltExtDef * to "href". */ if (xmlStrEqual(URI, cur->prefix)) return (1); cur = cur->next; } #endif return (0); } /** * xsltCheckExtURI: * @style: the stylesheet * @URI: the namespace URI (possibly NULL) * * Check if the given prefix is one of the declared extensions. * This is intended to be called only at compile-time. * Called by: * xsltPrecomputeStylesheet() (xslt.c) * xsltParseTemplateContent (xslt.c) * * Returns 1 if this is an extension, 0 otherwise */ int xsltCheckExtURI(xsltStylesheetPtr style, const xmlChar * URI) { xsltExtDefPtr cur; if ((style == NULL) || (style->nsDefs == NULL)) return (0); if (URI == NULL) return (0); cur = (xsltExtDefPtr) style->nsDefs; while (cur != NULL) { if (xmlStrEqual(URI, cur->URI)) return (1); cur = cur->next; } return (0); } /** * xsltRegisterExtModuleFull: * @URI: URI associated to this module * @initFunc: the module initialization function * @shutdownFunc: the module shutdown function * @styleInitFunc: the module initialization function * @styleShutdownFunc: the module shutdown function * * Register an XSLT extension module to the library. * * Returns 0 if sucessful, -1 in case of error */ int xsltRegisterExtModuleFull(const xmlChar * URI, xsltExtInitFunction initFunc, xsltExtShutdownFunction shutdownFunc, xsltStyleExtInitFunction styleInitFunc, xsltStyleExtShutdownFunction styleShutdownFunc) { int ret; xsltExtModulePtr module; if ((URI == NULL) || (initFunc == NULL)) return (-1); if (xsltExtensionsHash == NULL) xsltExtensionsHash = xmlHashCreate(10); if (xsltExtensionsHash == NULL) return (-1); xmlMutexLock(xsltExtMutex); module = xmlHashLookup(xsltExtensionsHash, URI); if (module != NULL) { if ((module->initFunc == initFunc) && (module->shutdownFunc == shutdownFunc)) ret = 0; else ret = -1; goto done; } module = xsltNewExtModule(initFunc, shutdownFunc, styleInitFunc, styleShutdownFunc); if (module == NULL) { ret = -1; goto done; } ret = xmlHashAddEntry(xsltExtensionsHash, URI, (void *) module); done: xmlMutexUnlock(xsltExtMutex); return (ret); } /** * xsltRegisterExtModule: * @URI: URI associated to this module * @initFunc: the module initialization function * @shutdownFunc: the module shutdown function * * Register an XSLT extension module to the library. * * Returns 0 if sucessful, -1 in case of error */ int xsltRegisterExtModule(const xmlChar * URI, xsltExtInitFunction initFunc, xsltExtShutdownFunction shutdownFunc) { return xsltRegisterExtModuleFull(URI, initFunc, shutdownFunc, NULL, NULL); } /** * xsltUnregisterExtModule: * @URI: URI associated to this module * * Unregister an XSLT extension module from the library. * * Returns 0 if sucessful, -1 in case of error */ int xsltUnregisterExtModule(const xmlChar * URI) { int ret; if (URI == NULL) return (-1); if (xsltExtensionsHash == NULL) return (-1); xmlMutexLock(xsltExtMutex); ret = xmlHashRemoveEntry(xsltExtensionsHash, URI, (xmlHashDeallocator) xsltFreeExtModule); xmlMutexUnlock(xsltExtMutex); return (ret); } /** * xsltUnregisterAllExtModules: * * Unregister all the XSLT extension module from the library. */ static void xsltUnregisterAllExtModules(void) { if (xsltExtensionsHash == NULL) return; xmlMutexLock(xsltExtMutex); xmlHashFree(xsltExtensionsHash, (xmlHashDeallocator) xsltFreeExtModule); xsltExtensionsHash = NULL; xmlMutexUnlock(xsltExtMutex); } /** * xsltXPathGetTransformContext: * @ctxt: an XPath transformation context * * Provides the XSLT transformation context from the XPath transformation * context. This is useful when an XPath function in the extension module * is called by the XPath interpreter and that the XSLT context is needed * for example to retrieve the associated data pertaining to this XSLT * transformation. * * Returns the XSLT transformation context or NULL in case of error. */ xsltTransformContextPtr xsltXPathGetTransformContext(xmlXPathParserContextPtr ctxt) { if ((ctxt == NULL) || (ctxt->context == NULL)) return (NULL); return (ctxt->context->extra); } /** * xsltRegisterExtModuleFunction: * @name: the function name * @URI: the function namespace URI * @function: the function callback * * Registers an extension module function. * * Returns 0 if successful, -1 in case of error. */ int xsltRegisterExtModuleFunction(const xmlChar * name, const xmlChar * URI, xmlXPathFunction function) { if ((name == NULL) || (URI == NULL) || (function == NULL)) return (-1); if (xsltFunctionsHash == NULL) xsltFunctionsHash = xmlHashCreate(10); if (xsltFunctionsHash == NULL) return (-1); xmlMutexLock(xsltExtMutex); xmlHashUpdateEntry2(xsltFunctionsHash, name, URI, XML_CAST_FPTR(function), NULL); xmlMutexUnlock(xsltExtMutex); return (0); } /** * xsltExtModuleFunctionLookup: * @name: the function name * @URI: the function namespace URI * * Looks up an extension module function * * Returns the function if found, NULL otherwise. */ xmlXPathFunction xsltExtModuleFunctionLookup(const xmlChar * name, const xmlChar * URI) { xmlXPathFunction ret; if ((xsltFunctionsHash == NULL) || (name == NULL) || (URI == NULL)) return (NULL); xmlMutexLock(xsltExtMutex); XML_CAST_FPTR(ret) = xmlHashLookup2(xsltFunctionsHash, name, URI); xmlMutexUnlock(xsltExtMutex); /* if lookup fails, attempt a dynamic load on supported platforms */ if (NULL == ret) { if (!xsltExtModuleRegisterDynamic(URI)) { xmlMutexLock(xsltExtMutex); XML_CAST_FPTR(ret) = xmlHashLookup2(xsltFunctionsHash, name, URI); xmlMutexUnlock(xsltExtMutex); } } return ret; } /** * xsltUnregisterExtModuleFunction: * @name: the function name * @URI: the function namespace URI * * Unregisters an extension module function * * Returns 0 if successful, -1 in case of error. */ int xsltUnregisterExtModuleFunction(const xmlChar * name, const xmlChar * URI) { int ret; if ((xsltFunctionsHash == NULL) || (name == NULL) || (URI == NULL)) return (-1); xmlMutexLock(xsltExtMutex); ret = xmlHashRemoveEntry2(xsltFunctionsHash, name, URI, NULL); xmlMutexUnlock(xsltExtMutex); return(ret); } /** * xsltUnregisterAllExtModuleFunction: * * Unregisters all extension module function */ static void xsltUnregisterAllExtModuleFunction(void) { xmlMutexLock(xsltExtMutex); xmlHashFree(xsltFunctionsHash, NULL); xsltFunctionsHash = NULL; xmlMutexUnlock(xsltExtMutex); } /** * xsltNewElemPreComp: * @style: the XSLT stylesheet * @inst: the element node * @function: the transform function * * Creates and initializes an #xsltElemPreComp * * Returns the new and initialized #xsltElemPreComp */ xsltElemPreCompPtr xsltNewElemPreComp(xsltStylesheetPtr style, xmlNodePtr inst, xsltTransformFunction function) { xsltElemPreCompPtr cur; cur = (xsltElemPreCompPtr) xmlMalloc(sizeof(xsltElemPreComp)); if (cur == NULL) { xsltTransformError(NULL, style, NULL, "xsltNewExtElement : malloc failed\n"); return (NULL); } memset(cur, 0, sizeof(xsltElemPreComp)); xsltInitElemPreComp(cur, style, inst, function, (xsltElemPreCompDeallocator) xmlFree); return (cur); } /** * xsltInitElemPreComp: * @comp: an #xsltElemPreComp (or generally a derived structure) * @style: the XSLT stylesheet * @inst: the element node * @function: the transform function * @freeFunc: the @comp deallocator * * Initializes an existing #xsltElemPreComp structure. This is usefull * when extending an #xsltElemPreComp to store precomputed data. * This function MUST be called on any extension element precomputed * data struct. */ void xsltInitElemPreComp(xsltElemPreCompPtr comp, xsltStylesheetPtr style, xmlNodePtr inst, xsltTransformFunction function, xsltElemPreCompDeallocator freeFunc) { comp->type = XSLT_FUNC_EXTENSION; comp->func = function; comp->inst = inst; comp->free = freeFunc; comp->next = style->preComps; style->preComps = comp; } /** * xsltPreComputeExtModuleElement: * @style: the stylesheet * @inst: the element node * * Precomputes an extension module element * * Returns the precomputed data */ xsltElemPreCompPtr xsltPreComputeExtModuleElement(xsltStylesheetPtr style, xmlNodePtr inst) { xsltExtElementPtr ext; xsltElemPreCompPtr comp = NULL; if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE) || (inst->ns == NULL)) return (NULL); xmlMutexLock(xsltExtMutex); ext = (xsltExtElementPtr) xmlHashLookup2(xsltElementsHash, inst->name, inst->ns->href); xmlMutexUnlock(xsltExtMutex); /* * EXT TODO: Now what? */ if (ext == NULL) return (NULL); if (ext->precomp != NULL) { /* * REVISIT TODO: Check if the text below is correct. * This will return a xsltElemPreComp structure or NULL. * 1) If the the author of the extension needs a * custom structure to hold the specific values of * this extension, he will derive a structure based on * xsltElemPreComp; thus we obviously *cannot* refactor * the xsltElemPreComp structure, since all already derived * user-defined strucures will break. * Example: For the extension xsl:document, * in xsltDocumentComp() (preproc.c), the structure * xsltStyleItemDocument is allocated, filled with * specific values and returned. * 2) If the author needs no values to be stored in * this structure, then he'll return NULL; */ comp = ext->precomp(style, inst, ext->transform); } if (comp == NULL) { /* * Default creation of a xsltElemPreComp structure, if * the author of this extension did not create a custom * structure. */ comp = xsltNewElemPreComp(style, inst, ext->transform); } return (comp); } /** * xsltRegisterExtModuleElement: * @name: the element name * @URI: the element namespace URI * @precomp: the pre-computation callback * @transform: the transformation callback * * Registers an extension module element. * * Returns 0 if successful, -1 in case of error. */ int xsltRegisterExtModuleElement(const xmlChar * name, const xmlChar * URI, xsltPreComputeFunction precomp, xsltTransformFunction transform) { int ret; xsltExtElementPtr ext; if ((name == NULL) || (URI == NULL) || (transform == NULL)) return (-1); if (xsltElementsHash == NULL) xsltElementsHash = xmlHashCreate(10); if (xsltElementsHash == NULL) return (-1); xmlMutexLock(xsltExtMutex); ext = xsltNewExtElement(precomp, transform); if (ext == NULL) { ret = -1; goto done; } xmlHashUpdateEntry2(xsltElementsHash, name, URI, (void *) ext, (xmlHashDeallocator) xsltFreeExtElement); done: xmlMutexUnlock(xsltExtMutex); return (0); } /** * xsltExtElementLookup: * @ctxt: an XSLT process context * @name: the element name * @URI: the element namespace URI * * Looks up an extension element. @ctxt can be NULL to search only in * module elements. * * Returns the element callback or NULL if not found */ xsltTransformFunction xsltExtElementLookup(xsltTransformContextPtr ctxt, const xmlChar * name, const xmlChar * URI) { xsltTransformFunction ret; if ((name == NULL) || (URI == NULL)) return (NULL); if ((ctxt != NULL) && (ctxt->extElements != NULL)) { XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->extElements, name, URI); if (ret != NULL) { return(ret); } } ret = xsltExtModuleElementLookup(name, URI); return (ret); } /** * xsltExtModuleElementLookup: * @name: the element name * @URI: the element namespace URI * * Looks up an extension module element * * Returns the callback function if found, NULL otherwise. */ xsltTransformFunction xsltExtModuleElementLookup(const xmlChar * name, const xmlChar * URI) { xsltExtElementPtr ext; if ((xsltElementsHash == NULL) || (name == NULL) || (URI == NULL)) return (NULL); xmlMutexLock(xsltExtMutex); ext = (xsltExtElementPtr) xmlHashLookup2(xsltElementsHash, name, URI); xmlMutexUnlock(xsltExtMutex); /* * if function lookup fails, attempt a dynamic load on * supported platforms */ if (NULL == ext) { if (!xsltExtModuleRegisterDynamic(URI)) { xmlMutexLock(xsltExtMutex); ext = (xsltExtElementPtr) xmlHashLookup2(xsltElementsHash, name, URI); xmlMutexUnlock(xsltExtMutex); } } if (ext == NULL) return (NULL); return (ext->transform); } /** * xsltExtModuleElementPreComputeLookup: * @name: the element name * @URI: the element namespace URI * * Looks up an extension module element pre-computation function * * Returns the callback function if found, NULL otherwise. */ xsltPreComputeFunction xsltExtModuleElementPreComputeLookup(const xmlChar * name, const xmlChar * URI) { xsltExtElementPtr ext; if ((xsltElementsHash == NULL) || (name == NULL) || (URI == NULL)) return (NULL); xmlMutexLock(xsltExtMutex); ext = (xsltExtElementPtr) xmlHashLookup2(xsltElementsHash, name, URI); xmlMutexUnlock(xsltExtMutex); if (ext == NULL) { if (!xsltExtModuleRegisterDynamic(URI)) { xmlMutexLock(xsltExtMutex); ext = (xsltExtElementPtr) xmlHashLookup2(xsltElementsHash, name, URI); xmlMutexUnlock(xsltExtMutex); } } if (ext == NULL) return (NULL); return (ext->precomp); } /** * xsltUnregisterExtModuleElement: * @name: the element name * @URI: the element namespace URI * * Unregisters an extension module element * * Returns 0 if successful, -1 in case of error. */ int xsltUnregisterExtModuleElement(const xmlChar * name, const xmlChar * URI) { int ret; if ((xsltElementsHash == NULL) || (name == NULL) || (URI == NULL)) return (-1); xmlMutexLock(xsltExtMutex); ret = xmlHashRemoveEntry2(xsltElementsHash, name, URI, (xmlHashDeallocator) xsltFreeExtElement); xmlMutexUnlock(xsltExtMutex); return(ret); } /** * xsltUnregisterAllExtModuleElement: * * Unregisters all extension module element */ static void xsltUnregisterAllExtModuleElement(void) { xmlMutexLock(xsltExtMutex); xmlHashFree(xsltElementsHash, (xmlHashDeallocator) xsltFreeExtElement); xsltElementsHash = NULL; xmlMutexUnlock(xsltExtMutex); } /** * xsltRegisterExtModuleTopLevel: * @name: the top-level element name * @URI: the top-level element namespace URI * @function: the top-level element callback * * Registers an extension module top-level element. * * Returns 0 if successful, -1 in case of error. */ int xsltRegisterExtModuleTopLevel(const xmlChar * name, const xmlChar * URI, xsltTopLevelFunction function) { if ((name == NULL) || (URI == NULL) || (function == NULL)) return (-1); if (xsltTopLevelsHash == NULL) xsltTopLevelsHash = xmlHashCreate(10); if (xsltTopLevelsHash == NULL) return (-1); xmlMutexLock(xsltExtMutex); xmlHashUpdateEntry2(xsltTopLevelsHash, name, URI, XML_CAST_FPTR(function), NULL); xmlMutexUnlock(xsltExtMutex); return (0); } /** * xsltExtModuleTopLevelLookup: * @name: the top-level element name * @URI: the top-level element namespace URI * * Looks up an extension module top-level element * * Returns the callback function if found, NULL otherwise. */ xsltTopLevelFunction xsltExtModuleTopLevelLookup(const xmlChar * name, const xmlChar * URI) { xsltTopLevelFunction ret; if ((xsltTopLevelsHash == NULL) || (name == NULL) || (URI == NULL)) return (NULL); xmlMutexLock(xsltExtMutex); XML_CAST_FPTR(ret) = xmlHashLookup2(xsltTopLevelsHash, name, URI); xmlMutexUnlock(xsltExtMutex); /* if lookup fails, attempt a dynamic load on supported platforms */ if (NULL == ret) { if (!xsltExtModuleRegisterDynamic(URI)) { xmlMutexLock(xsltExtMutex); XML_CAST_FPTR(ret) = xmlHashLookup2(xsltTopLevelsHash, name, URI); xmlMutexUnlock(xsltExtMutex); } } return (ret); } /** * xsltUnregisterExtModuleTopLevel: * @name: the top-level element name * @URI: the top-level element namespace URI * * Unregisters an extension module top-level element * * Returns 0 if successful, -1 in case of error. */ int xsltUnregisterExtModuleTopLevel(const xmlChar * name, const xmlChar * URI) { int ret; if ((xsltTopLevelsHash == NULL) || (name == NULL) || (URI == NULL)) return (-1); xmlMutexLock(xsltExtMutex); ret = xmlHashRemoveEntry2(xsltTopLevelsHash, name, URI, NULL); xmlMutexUnlock(xsltExtMutex); return(ret); } /** * xsltUnregisterAllExtModuleTopLevel: * * Unregisters all extension module function */ static void xsltUnregisterAllExtModuleTopLevel(void) { xmlMutexLock(xsltExtMutex); xmlHashFree(xsltTopLevelsHash, NULL); xsltTopLevelsHash = NULL; xmlMutexUnlock(xsltExtMutex); } /** * xsltGetExtInfo: * @style: pointer to a stylesheet * @URI: the namespace URI desired * * looks up URI in extInfos of the stylesheet * * returns a pointer to the hash table if found, else NULL */ xmlHashTablePtr xsltGetExtInfo(xsltStylesheetPtr style, const xmlChar * URI) { xsltExtDataPtr data; /* * TODO: Why do we have a return type of xmlHashTablePtr? * Is the user-allocated data for extension modules expected * to be a xmlHashTablePtr only? Or is this intended for * the EXSLT module only? */ if (style != NULL && style->extInfos != NULL) { data = xmlHashLookup(style->extInfos, URI); if (data != NULL && data->extData != NULL) return data->extData; } return NULL; } /************************************************************************ * * * Test module http://xmlsoft.org/XSLT/ * * * ************************************************************************/ /************************************************************************ * * * Test of the extension module API * * * ************************************************************************/ static xmlChar *testData = NULL; static xmlChar *testStyleData = NULL; /** * xsltExtFunctionTest: * @ctxt: the XPath Parser context * @nargs: the number of arguments * * function libxslt:test() for testing the extensions support. */ static void xsltExtFunctionTest(xmlXPathParserContextPtr ctxt, int nargs ATTRIBUTE_UNUSED) { xsltTransformContextPtr tctxt; void *data = NULL; tctxt = xsltXPathGetTransformContext(ctxt); if (testData == NULL) { xsltGenericDebug(xsltGenericDebugContext, "xsltExtFunctionTest: not initialized," " calling xsltGetExtData\n"); data = xsltGetExtData(tctxt, (const xmlChar *) XSLT_DEFAULT_URL); if (data == NULL) { xsltTransformError(tctxt, NULL, NULL, "xsltExtElementTest: not initialized\n"); return; } } if (tctxt == NULL) { xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, "xsltExtFunctionTest: failed to get the transformation context\n"); return; } if (data == NULL) data = xsltGetExtData(tctxt, (const xmlChar *) XSLT_DEFAULT_URL); if (data == NULL) { xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, "xsltExtFunctionTest: failed to get module data\n"); return; } if (data != testData) { xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, "xsltExtFunctionTest: got wrong module data\n"); return; } #ifdef WITH_XSLT_DEBUG_FUNCTION xsltGenericDebug(xsltGenericDebugContext, "libxslt:test() called with %d args\n", nargs); #endif } /** * xsltExtElementPreCompTest: * @style: the stylesheet * @inst: the instruction in the stylesheet * * Process a libxslt:test node */ static xsltElemPreCompPtr xsltExtElementPreCompTest(xsltStylesheetPtr style, xmlNodePtr inst, xsltTransformFunction function) { xsltElemPreCompPtr ret; if (style == NULL) { xsltTransformError(NULL, NULL, inst, "xsltExtElementTest: no transformation context\n"); return (NULL); } if (testStyleData == NULL) { xsltGenericDebug(xsltGenericDebugContext, "xsltExtElementPreCompTest: not initialized," " calling xsltStyleGetExtData\n"); xsltStyleGetExtData(style, (const xmlChar *) XSLT_DEFAULT_URL); if (testStyleData == NULL) { xsltTransformError(NULL, style, inst, "xsltExtElementPreCompTest: not initialized\n"); if (style != NULL) style->errors++; return (NULL); } } if (inst == NULL) { xsltTransformError(NULL, style, inst, "xsltExtElementPreCompTest: no instruction\n"); if (style != NULL) style->errors++; return (NULL); } ret = xsltNewElemPreComp(style, inst, function); return (ret); } /** * xsltExtElementTest: * @ctxt: an XSLT processing context * @node: The current node * @inst: the instruction in the stylesheet * @comp: precomputed informations * * Process a libxslt:test node */ static void xsltExtElementTest(xsltTransformContextPtr ctxt, xmlNodePtr node, xmlNodePtr inst, xsltElemPreCompPtr comp ATTRIBUTE_UNUSED) { xmlNodePtr commentNode; if (testData == NULL) { xsltGenericDebug(xsltGenericDebugContext, "xsltExtElementTest: not initialized," " calling xsltGetExtData\n"); xsltGetExtData(ctxt, (const xmlChar *) XSLT_DEFAULT_URL); if (testData == NULL) { xsltTransformError(ctxt, NULL, inst, "xsltExtElementTest: not initialized\n"); return; } } if (ctxt == NULL) { xsltTransformError(ctxt, NULL, inst, "xsltExtElementTest: no transformation context\n"); return; } if (node == NULL) { xsltTransformError(ctxt, NULL, inst, "xsltExtElementTest: no current node\n"); return; } if (inst == NULL) { xsltTransformError(ctxt, NULL, inst, "xsltExtElementTest: no instruction\n"); return; } if (ctxt->insert == NULL) { xsltTransformError(ctxt, NULL, inst, "xsltExtElementTest: no insertion point\n"); return; } commentNode = xmlNewComment((const xmlChar *) "libxslt:test element test worked"); xmlAddChild(ctxt->insert, commentNode); } /** * xsltExtInitTest: * @ctxt: an XSLT transformation context * @URI: the namespace URI for the extension * * A function called at initialization time of an XSLT extension module * * Returns a pointer to the module specific data for this transformation */ static void * xsltExtInitTest(xsltTransformContextPtr ctxt, const xmlChar * URI) { if (testStyleData == NULL) { xsltGenericDebug(xsltGenericErrorContext, "xsltExtInitTest: not initialized," " calling xsltStyleGetExtData\n"); testStyleData = xsltStyleGetExtData(ctxt->style, URI); if (testStyleData == NULL) { xsltTransformError(ctxt, NULL, NULL, "xsltExtInitTest: not initialized\n"); return (NULL); } } if (testData != NULL) { xsltTransformError(ctxt, NULL, NULL, "xsltExtInitTest: already initialized\n"); return (NULL); } testData = (void *) "test data"; xsltGenericDebug(xsltGenericDebugContext, "Registered test module : %s\n", URI); return (testData); } /** * xsltExtShutdownTest: * @ctxt: an XSLT transformation context * @URI: the namespace URI for the extension * @data: the data associated to this module * * A function called at shutdown time of an XSLT extension module */ static void xsltExtShutdownTest(xsltTransformContextPtr ctxt, const xmlChar * URI, void *data) { if (testData == NULL) { xsltTransformError(ctxt, NULL, NULL, "xsltExtShutdownTest: not initialized\n"); return; } if (data != testData) { xsltTransformError(ctxt, NULL, NULL, "xsltExtShutdownTest: wrong data\n"); } testData = NULL; xsltGenericDebug(xsltGenericDebugContext, "Unregistered test module : %s\n", URI); } /** * xsltExtStyleInitTest: * @style: an XSLT stylesheet * @URI: the namespace URI for the extension * * A function called at initialization time of an XSLT extension module * * Returns a pointer to the module specific data for this transformation */ static void * xsltExtStyleInitTest(xsltStylesheetPtr style ATTRIBUTE_UNUSED, const xmlChar * URI) { if (testStyleData != NULL) { xsltTransformError(NULL, NULL, NULL, "xsltExtInitTest: already initialized\n"); return (NULL); } testStyleData = (void *) "test data"; xsltGenericDebug(xsltGenericDebugContext, "Registered test module : %s\n", URI); return (testStyleData); } /** * xsltExtStyleShutdownTest: * @style: an XSLT stylesheet * @URI: the namespace URI for the extension * @data: the data associated to this module * * A function called at shutdown time of an XSLT extension module */ static void xsltExtStyleShutdownTest(xsltStylesheetPtr style ATTRIBUTE_UNUSED, const xmlChar * URI, void *data) { if (testStyleData == NULL) { xsltGenericError(xsltGenericErrorContext, "xsltExtShutdownTest: not initialized\n"); return; } if (data != testStyleData) { xsltTransformError(NULL, NULL, NULL, "xsltExtShutdownTest: wrong data\n"); } testStyleData = NULL; xsltGenericDebug(xsltGenericDebugContext, "Unregistered test module : %s\n", URI); } /** * xsltRegisterTestModule: * * Registers the test module */ void xsltRegisterTestModule(void) { xsltInitGlobals(); xsltRegisterExtModuleFull((const xmlChar *) XSLT_DEFAULT_URL, xsltExtInitTest, xsltExtShutdownTest, xsltExtStyleInitTest, xsltExtStyleShutdownTest); xsltRegisterExtModuleFunction((const xmlChar *) "test", (const xmlChar *) XSLT_DEFAULT_URL, xsltExtFunctionTest); xsltRegisterExtModuleElement((const xmlChar *) "test", (const xmlChar *) XSLT_DEFAULT_URL, xsltExtElementPreCompTest, xsltExtElementTest); } static void xsltHashScannerModuleFree(void *payload ATTRIBUTE_UNUSED, void *data ATTRIBUTE_UNUSED, xmlChar * name ATTRIBUTE_UNUSED) { #ifdef WITH_MODULES xmlModuleClose(payload); #endif } /** * xsltInitGlobals: * * Initialize the global variables for extensions */ void xsltInitGlobals(void) { if (xsltExtMutex == NULL) { xsltExtMutex = xmlNewMutex(); } } /** * xsltCleanupGlobals: * * Unregister all global variables set up by the XSLT library */ void xsltCleanupGlobals(void) { xsltUnregisterAllExtModules(); xsltUnregisterAllExtModuleFunction(); xsltUnregisterAllExtModuleElement(); xsltUnregisterAllExtModuleTopLevel(); xmlMutexLock(xsltExtMutex); /* cleanup dynamic module hash */ if (NULL != xsltModuleHash) { xmlHashScan(xsltModuleHash, xsltHashScannerModuleFree, 0); xmlHashFree(xsltModuleHash, NULL); xsltModuleHash = NULL; } xmlMutexUnlock(xsltExtMutex); xmlFreeMutex(xsltExtMutex); xsltExtMutex = NULL; xsltFreeLocales(); xsltUninit(); } static void xsltDebugDumpExtensionsCallback(void *function ATTRIBUTE_UNUSED, FILE * output, const xmlChar * name, const xmlChar * URI, const xmlChar * not_used ATTRIBUTE_UNUSED) { if (!name || !URI) return; fprintf(output, "{%s}%s\n", URI, name); } static void xsltDebugDumpExtModulesCallback(void *function ATTRIBUTE_UNUSED, FILE * output, const xmlChar * URI, const xmlChar * not_used ATTRIBUTE_UNUSED, const xmlChar * not_used2 ATTRIBUTE_UNUSED) { if (!URI) return; fprintf(output, "%s\n", URI); } /** * xsltDebugDumpExtensions: * @output: the FILE * for the output, if NULL stdout is used * * Dumps a list of the registered XSLT extension functions and elements */ void xsltDebugDumpExtensions(FILE * output) { if (output == NULL) output = stdout; fprintf(output, "Registered XSLT Extensions\n--------------------------\n"); if (!xsltFunctionsHash) fprintf(output, "No registered extension functions\n"); else { fprintf(output, "Registered Extension Functions:\n"); xmlMutexLock(xsltExtMutex); xmlHashScanFull(xsltFunctionsHash, (xmlHashScannerFull) xsltDebugDumpExtensionsCallback, output); xmlMutexUnlock(xsltExtMutex); } if (!xsltElementsHash) fprintf(output, "\nNo registered extension elements\n"); else { fprintf(output, "\nRegistered Extension Elements:\n"); xmlMutexLock(xsltExtMutex); xmlHashScanFull(xsltElementsHash, (xmlHashScannerFull) xsltDebugDumpExtensionsCallback, output); xmlMutexUnlock(xsltExtMutex); } if (!xsltExtensionsHash) fprintf(output, "\nNo registered extension modules\n"); else { fprintf(output, "\nRegistered Extension Modules:\n"); xmlMutexLock(xsltExtMutex); xmlHashScanFull(xsltExtensionsHash, (xmlHashScannerFull) xsltDebugDumpExtModulesCallback, output); xmlMutexUnlock(xsltExtMutex); } } libxslt-1.1.28/libxslt/templates.c0000664000076400007640000005414512024022316014043 00000000000000/* * templates.c: Implementation of the template processing * * Reference: * http://www.w3.org/TR/1999/REC-xslt-19991116 * * See Copyright for the status of this software. * * daniel@veillard.com */ #define IN_LIBXSLT #include "libxslt.h" #include #include #include #include #include #include #include #include #include "xslt.h" #include "xsltInternals.h" #include "xsltutils.h" #include "variables.h" #include "functions.h" #include "templates.h" #include "transform.h" #include "namespaces.h" #include "attributes.h" #ifdef WITH_XSLT_DEBUG #define WITH_XSLT_DEBUG_TEMPLATES #endif /************************************************************************ * * * Module interfaces * * * ************************************************************************/ /** * xsltEvalXPathPredicate: * @ctxt: the XSLT transformation context * @comp: the XPath compiled expression * @nsList: the namespaces in scope * @nsNr: the number of namespaces in scope * * Process the expression using XPath and evaluate the result as * an XPath predicate * * Returns 1 is the predicate was true, 0 otherwise */ int xsltEvalXPathPredicate(xsltTransformContextPtr ctxt, xmlXPathCompExprPtr comp, xmlNsPtr *nsList, int nsNr) { int ret; xmlXPathObjectPtr res; int oldNsNr; xmlNsPtr *oldNamespaces; xmlNodePtr oldInst; int oldProximityPosition, oldContextSize; oldContextSize = ctxt->xpathCtxt->contextSize; oldProximityPosition = ctxt->xpathCtxt->proximityPosition; oldNsNr = ctxt->xpathCtxt->nsNr; oldNamespaces = ctxt->xpathCtxt->namespaces; oldInst = ctxt->inst; ctxt->xpathCtxt->node = ctxt->node; ctxt->xpathCtxt->namespaces = nsList; ctxt->xpathCtxt->nsNr = nsNr; res = xmlXPathCompiledEval(comp, ctxt->xpathCtxt); if (res != NULL) { ret = xmlXPathEvalPredicate(ctxt->xpathCtxt, res); xmlXPathFreeObject(res); #ifdef WITH_XSLT_DEBUG_TEMPLATES XSLT_TRACE(ctxt,XSLT_TRACE_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext, "xsltEvalXPathPredicate: returns %d\n", ret)); #endif } else { #ifdef WITH_XSLT_DEBUG_TEMPLATES XSLT_TRACE(ctxt,XSLT_TRACE_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext, "xsltEvalXPathPredicate: failed\n")); #endif ctxt->state = XSLT_STATE_STOPPED; ret = 0; } ctxt->xpathCtxt->nsNr = oldNsNr; ctxt->xpathCtxt->namespaces = oldNamespaces; ctxt->inst = oldInst; ctxt->xpathCtxt->contextSize = oldContextSize; ctxt->xpathCtxt->proximityPosition = oldProximityPosition; return(ret); } /** * xsltEvalXPathStringNs: * @ctxt: the XSLT transformation context * @comp: the compiled XPath expression * @nsNr: the number of namespaces in the list * @nsList: the list of in-scope namespaces to use * * Process the expression using XPath, allowing to pass a namespace mapping * context and get a string * * Returns the computed string value or NULL, must be deallocated by the * caller. */ xmlChar * xsltEvalXPathStringNs(xsltTransformContextPtr ctxt, xmlXPathCompExprPtr comp, int nsNr, xmlNsPtr *nsList) { xmlChar *ret = NULL; xmlXPathObjectPtr res; xmlNodePtr oldInst; xmlNodePtr oldNode; int oldPos, oldSize; int oldNsNr; xmlNsPtr *oldNamespaces; oldInst = ctxt->inst; oldNode = ctxt->node; oldPos = ctxt->xpathCtxt->proximityPosition; oldSize = ctxt->xpathCtxt->contextSize; oldNsNr = ctxt->xpathCtxt->nsNr; oldNamespaces = ctxt->xpathCtxt->namespaces; ctxt->xpathCtxt->node = ctxt->node; /* TODO: do we need to propagate the namespaces here ? */ ctxt->xpathCtxt->namespaces = nsList; ctxt->xpathCtxt->nsNr = nsNr; res = xmlXPathCompiledEval(comp, ctxt->xpathCtxt); if (res != NULL) { if (res->type != XPATH_STRING) res = xmlXPathConvertString(res); if (res->type == XPATH_STRING) { ret = res->stringval; res->stringval = NULL; } else { xsltTransformError(ctxt, NULL, NULL, "xpath : string() function didn't return a String\n"); } xmlXPathFreeObject(res); } else { ctxt->state = XSLT_STATE_STOPPED; } #ifdef WITH_XSLT_DEBUG_TEMPLATES XSLT_TRACE(ctxt,XSLT_TRACE_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext, "xsltEvalXPathString: returns %s\n", ret)); #endif ctxt->inst = oldInst; ctxt->node = oldNode; ctxt->xpathCtxt->contextSize = oldSize; ctxt->xpathCtxt->proximityPosition = oldPos; ctxt->xpathCtxt->nsNr = oldNsNr; ctxt->xpathCtxt->namespaces = oldNamespaces; return(ret); } /** * xsltEvalXPathString: * @ctxt: the XSLT transformation context * @comp: the compiled XPath expression * * Process the expression using XPath and get a string * * Returns the computed string value or NULL, must be deallocated by the * caller. */ xmlChar * xsltEvalXPathString(xsltTransformContextPtr ctxt, xmlXPathCompExprPtr comp) { return(xsltEvalXPathStringNs(ctxt, comp, 0, NULL)); } /** * xsltEvalTemplateString: * @ctxt: the XSLT transformation context * @contextNode: the current node in the source tree * @inst: the XSLT instruction (xsl:comment, xsl:processing-instruction) * * Processes the sequence constructor of the given instruction on * @contextNode and converts the resulting tree to a string. * This is needed by e.g. xsl:comment and xsl:processing-instruction. * * Returns the computed string value or NULL; it's up to the caller to * free the result. */ xmlChar * xsltEvalTemplateString(xsltTransformContextPtr ctxt, xmlNodePtr contextNode, xmlNodePtr inst) { xmlNodePtr oldInsert, insert = NULL; xmlChar *ret; if ((ctxt == NULL) || (contextNode == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE)) return(NULL); if (inst->children == NULL) return(NULL); /* * This creates a temporary element-node to add the resulting * text content to. * OPTIMIZE TODO: Keep such an element-node in the transformation * context to avoid creating it every time. */ insert = xmlNewDocNode(ctxt->output, NULL, (const xmlChar *)"fake", NULL); if (insert == NULL) { xsltTransformError(ctxt, NULL, contextNode, "Failed to create temporary node\n"); return(NULL); } oldInsert = ctxt->insert; ctxt->insert = insert; /* * OPTIMIZE TODO: if inst->children consists only of text-nodes. */ xsltApplyOneTemplate(ctxt, contextNode, inst->children, NULL, NULL); ctxt->insert = oldInsert; ret = xmlNodeGetContent(insert); if (insert != NULL) xmlFreeNode(insert); return(ret); } /** * xsltAttrTemplateValueProcessNode: * @ctxt: the XSLT transformation context * @str: the attribute template node value * @inst: the instruction (or LRE) in the stylesheet holding the * attribute with an AVT * * Process the given string, allowing to pass a namespace mapping * context and return the new string value. * * Called by: * - xsltAttrTemplateValueProcess() (templates.c) * - xsltEvalAttrValueTemplate() (templates.c) * * QUESTION: Why is this function public? It is not used outside * of templates.c. * * Returns the computed string value or NULL, must be deallocated by the * caller. */ xmlChar * xsltAttrTemplateValueProcessNode(xsltTransformContextPtr ctxt, const xmlChar *str, xmlNodePtr inst) { xmlChar *ret = NULL; const xmlChar *cur; xmlChar *expr, *val; xmlNsPtr *nsList = NULL; int nsNr = 0; if (str == NULL) return(NULL); if (*str == 0) return(xmlStrndup((xmlChar *)"", 0)); cur = str; while (*cur != 0) { if (*cur == '{') { if (*(cur+1) == '{') { /* escaped '{' */ cur++; ret = xmlStrncat(ret, str, cur - str); cur++; str = cur; continue; } ret = xmlStrncat(ret, str, cur - str); str = cur; cur++; while ((*cur != 0) && (*cur != '}')) { /* Need to check for literal (bug539741) */ if ((*cur == '\'') || (*cur == '"')) { char delim = *(cur++); while ((*cur != 0) && (*cur != delim)) cur++; if (*cur != 0) cur++; /* skip the ending delimiter */ } else cur++; } if (*cur == 0) { xsltTransformError(ctxt, NULL, inst, "xsltAttrTemplateValueProcessNode: unmatched '{'\n"); ret = xmlStrncat(ret, str, cur - str); return(ret); } str++; expr = xmlStrndup(str, cur - str); if (expr == NULL) return(ret); else if (*expr == '{') { ret = xmlStrcat(ret, expr); xmlFree(expr); } else { xmlXPathCompExprPtr comp; /* * TODO: keep precompiled form around */ if ((nsList == NULL) && (inst != NULL)) { int i = 0; nsList = xmlGetNsList(inst->doc, inst); if (nsList != NULL) { while (nsList[i] != NULL) i++; nsNr = i; } } comp = xmlXPathCompile(expr); val = xsltEvalXPathStringNs(ctxt, comp, nsNr, nsList); xmlXPathFreeCompExpr(comp); xmlFree(expr); if (val != NULL) { ret = xmlStrcat(ret, val); xmlFree(val); } } cur++; str = cur; } else if (*cur == '}') { cur++; if (*cur == '}') { /* escaped '}' */ ret = xmlStrncat(ret, str, cur - str); cur++; str = cur; continue; } else { xsltTransformError(ctxt, NULL, inst, "xsltAttrTemplateValueProcessNode: unmatched '}'\n"); } } else cur++; } if (cur != str) { ret = xmlStrncat(ret, str, cur - str); } if (nsList != NULL) xmlFree(nsList); return(ret); } /** * xsltAttrTemplateValueProcess: * @ctxt: the XSLT transformation context * @str: the attribute template node value * * Process the given node and return the new string value. * * Returns the computed string value or NULL, must be deallocated by the * caller. */ xmlChar * xsltAttrTemplateValueProcess(xsltTransformContextPtr ctxt, const xmlChar *str) { return(xsltAttrTemplateValueProcessNode(ctxt, str, NULL)); } /** * xsltEvalAttrValueTemplate: * @ctxt: the XSLT transformation context * @inst: the instruction (or LRE) in the stylesheet holding the * attribute with an AVT * @name: the attribute QName * @ns: the attribute namespace URI * * Evaluate a attribute value template, i.e. the attribute value can * contain expressions contained in curly braces ({}) and those are * substituted by they computed value. * * Returns the computed string value or NULL, must be deallocated by the * caller. */ xmlChar * xsltEvalAttrValueTemplate(xsltTransformContextPtr ctxt, xmlNodePtr inst, const xmlChar *name, const xmlChar *ns) { xmlChar *ret; xmlChar *expr; if ((ctxt == NULL) || (inst == NULL) || (name == NULL) || (inst->type != XML_ELEMENT_NODE)) return(NULL); expr = xsltGetNsProp(inst, name, ns); if (expr == NULL) return(NULL); /* * TODO: though now {} is detected ahead, it would still be good to * optimize both functions to keep the splitted value if the * attribute content and the XPath precompiled expressions around */ ret = xsltAttrTemplateValueProcessNode(ctxt, expr, inst); #ifdef WITH_XSLT_DEBUG_TEMPLATES XSLT_TRACE(ctxt,XSLT_TRACE_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext, "xsltEvalAttrValueTemplate: %s returns %s\n", expr, ret)); #endif if (expr != NULL) xmlFree(expr); return(ret); } /** * xsltEvalStaticAttrValueTemplate: * @style: the XSLT stylesheet * @inst: the instruction (or LRE) in the stylesheet holding the * attribute with an AVT * @name: the attribute Name * @ns: the attribute namespace URI * @found: indicator whether the attribute is present * * Check if an attribute value template has a static value, i.e. the * attribute value does not contain expressions contained in curly braces ({}) * * Returns the static string value or NULL, must be deallocated by the * caller. */ const xmlChar * xsltEvalStaticAttrValueTemplate(xsltStylesheetPtr style, xmlNodePtr inst, const xmlChar *name, const xmlChar *ns, int *found) { const xmlChar *ret; xmlChar *expr; if ((style == NULL) || (inst == NULL) || (name == NULL) || (inst->type != XML_ELEMENT_NODE)) return(NULL); expr = xsltGetNsProp(inst, name, ns); if (expr == NULL) { *found = 0; return(NULL); } *found = 1; ret = xmlStrchr(expr, '{'); if (ret != NULL) { xmlFree(expr); return(NULL); } ret = xmlDictLookup(style->dict, expr, -1); xmlFree(expr); return(ret); } /** * xsltAttrTemplateProcess: * @ctxt: the XSLT transformation context * @target: the element where the attribute will be grafted * @attr: the attribute node of a literal result element * * Process one attribute of a Literal Result Element (in the stylesheet). * Evaluates Attribute Value Templates and copies the attribute over to * the result element. * This does *not* process attribute sets (xsl:use-attribute-set). * * * Returns the generated attribute node. */ xmlAttrPtr xsltAttrTemplateProcess(xsltTransformContextPtr ctxt, xmlNodePtr target, xmlAttrPtr attr) { const xmlChar *value; xmlAttrPtr ret; if ((ctxt == NULL) || (attr == NULL) || (target == NULL) || (target->type != XML_ELEMENT_NODE)) return(NULL); if (attr->type != XML_ATTRIBUTE_NODE) return(NULL); /* * Skip all XSLT attributes. */ #ifdef XSLT_REFACTORED if (attr->psvi == xsltXSLTAttrMarker) return(NULL); #else if ((attr->ns != NULL) && xmlStrEqual(attr->ns->href, XSLT_NAMESPACE)) return(NULL); #endif /* * Get the value. */ if (attr->children != NULL) { if ((attr->children->type != XML_TEXT_NODE) || (attr->children->next != NULL)) { xsltTransformError(ctxt, NULL, attr->parent, "Internal error: The children of an attribute node of a " "literal result element are not in the expected form.\n"); return(NULL); } value = attr->children->content; if (value == NULL) value = xmlDictLookup(ctxt->dict, BAD_CAST "", 0); } else value = xmlDictLookup(ctxt->dict, BAD_CAST "", 0); /* * Overwrite duplicates. */ ret = target->properties; while (ret != NULL) { if (((attr->ns != NULL) == (ret->ns != NULL)) && xmlStrEqual(ret->name, attr->name) && ((attr->ns == NULL) || xmlStrEqual(ret->ns->href, attr->ns->href))) { break; } ret = ret->next; } if (ret != NULL) { /* free the existing value */ xmlFreeNodeList(ret->children); ret->children = ret->last = NULL; /* * Adjust ns-prefix if needed. */ if ((ret->ns != NULL) && (! xmlStrEqual(ret->ns->prefix, attr->ns->prefix))) { ret->ns = xsltGetNamespace(ctxt, attr->parent, attr->ns, target); } } else { /* create a new attribute */ if (attr->ns != NULL) ret = xmlNewNsProp(target, xsltGetNamespace(ctxt, attr->parent, attr->ns, target), attr->name, NULL); else ret = xmlNewNsProp(target, NULL, attr->name, NULL); } /* * Set the value. */ if (ret != NULL) { xmlNodePtr text; text = xmlNewText(NULL); if (text != NULL) { ret->last = ret->children = text; text->parent = (xmlNodePtr) ret; text->doc = ret->doc; if (attr->psvi != NULL) { /* * Evaluate the Attribute Value Template. */ xmlChar *val; val = xsltEvalAVT(ctxt, attr->psvi, attr->parent); if (val == NULL) { /* * TODO: Damn, we need an easy mechanism to report * qualified names! */ if (attr->ns) { xsltTransformError(ctxt, NULL, attr->parent, "Internal error: Failed to evaluate the AVT " "of attribute '{%s}%s'.\n", attr->ns->href, attr->name); } else { xsltTransformError(ctxt, NULL, attr->parent, "Internal error: Failed to evaluate the AVT " "of attribute '%s'.\n", attr->name); } text->content = xmlStrdup(BAD_CAST ""); } else { text->content = val; } } else if ((ctxt->internalized) && (target != NULL) && (target->doc != NULL) && (target->doc->dict == ctxt->dict) && xmlDictOwns(ctxt->dict, value)) { text->content = (xmlChar *) value; } else { text->content = xmlStrdup(value); } } } else { if (attr->ns) { xsltTransformError(ctxt, NULL, attr->parent, "Internal error: Failed to create attribute '{%s}%s'.\n", attr->ns->href, attr->name); } else { xsltTransformError(ctxt, NULL, attr->parent, "Internal error: Failed to create attribute '%s'.\n", attr->name); } } return(ret); } /** * xsltAttrListTemplateProcess: * @ctxt: the XSLT transformation context * @target: the element where the attributes will be grafted * @attrs: the first attribute * * Processes all attributes of a Literal Result Element. * Attribute references are applied via xsl:use-attribute-set * attributes. * Copies all non XSLT-attributes over to the @target element * and evaluates Attribute Value Templates. * * Called by xsltApplySequenceConstructor() (transform.c). * * Returns a new list of attribute nodes, or NULL in case of error. * (Don't assign the result to @target->properties; if * the result is NULL, you'll get memory leaks, since the * attributes will be disattached.) */ xmlAttrPtr xsltAttrListTemplateProcess(xsltTransformContextPtr ctxt, xmlNodePtr target, xmlAttrPtr attrs) { xmlAttrPtr attr, copy, last; xmlNodePtr oldInsert, text; xmlNsPtr origNs = NULL, copyNs = NULL; const xmlChar *value; xmlChar *valueAVT; if ((ctxt == NULL) || (target == NULL) || (attrs == NULL) || (target->type != XML_ELEMENT_NODE)) return(NULL); oldInsert = ctxt->insert; ctxt->insert = target; /* * Instantiate LRE-attributes. */ if (target->properties) { last = target->properties; while (last->next != NULL) last = last->next; } else { last = NULL; } attr = attrs; do { /* * Skip XSLT attributes. */ #ifdef XSLT_REFACTORED if (attr->psvi == xsltXSLTAttrMarker) { goto next_attribute; } #else if ((attr->ns != NULL) && xmlStrEqual(attr->ns->href, XSLT_NAMESPACE)) { goto next_attribute; } #endif /* * Get the value. */ if (attr->children != NULL) { if ((attr->children->type != XML_TEXT_NODE) || (attr->children->next != NULL)) { xsltTransformError(ctxt, NULL, attr->parent, "Internal error: The children of an attribute node of a " "literal result element are not in the expected form.\n"); goto error; } value = attr->children->content; if (value == NULL) value = xmlDictLookup(ctxt->dict, BAD_CAST "", 0); } else value = xmlDictLookup(ctxt->dict, BAD_CAST "", 0); /* * Create a new attribute. */ copy = xmlNewDocProp(target->doc, attr->name, NULL); if (copy == NULL) { if (attr->ns) { xsltTransformError(ctxt, NULL, attr->parent, "Internal error: Failed to create attribute '{%s}%s'.\n", attr->ns->href, attr->name); } else { xsltTransformError(ctxt, NULL, attr->parent, "Internal error: Failed to create attribute '%s'.\n", attr->name); } goto error; } /* * Attach it to the target element. */ copy->parent = target; if (last == NULL) { target->properties = copy; last = copy; } else { last->next = copy; copy->prev = last; last = copy; } /* * Set the namespace. Avoid lookups of same namespaces. */ if (attr->ns != origNs) { origNs = attr->ns; if (attr->ns != NULL) { #ifdef XSLT_REFACTORED copyNs = xsltGetSpecialNamespace(ctxt, attr->parent, attr->ns->href, attr->ns->prefix, target); #else copyNs = xsltGetNamespace(ctxt, attr->parent, attr->ns, target); #endif if (copyNs == NULL) goto error; } else copyNs = NULL; } copy->ns = copyNs; /* * Set the value. */ text = xmlNewText(NULL); if (text != NULL) { copy->last = copy->children = text; text->parent = (xmlNodePtr) copy; text->doc = copy->doc; if (attr->psvi != NULL) { /* * Evaluate the Attribute Value Template. */ valueAVT = xsltEvalAVT(ctxt, attr->psvi, attr->parent); if (valueAVT == NULL) { /* * TODO: Damn, we need an easy mechanism to report * qualified names! */ if (attr->ns) { xsltTransformError(ctxt, NULL, attr->parent, "Internal error: Failed to evaluate the AVT " "of attribute '{%s}%s'.\n", attr->ns->href, attr->name); } else { xsltTransformError(ctxt, NULL, attr->parent, "Internal error: Failed to evaluate the AVT " "of attribute '%s'.\n", attr->name); } text->content = xmlStrdup(BAD_CAST ""); goto error; } else { text->content = valueAVT; } } else if ((ctxt->internalized) && (target->doc != NULL) && (target->doc->dict == ctxt->dict) && xmlDictOwns(ctxt->dict, value)) { text->content = (xmlChar *) value; } else { text->content = xmlStrdup(value); } if ((copy != NULL) && (text != NULL) && (xmlIsID(copy->doc, copy->parent, copy))) xmlAddID(NULL, copy->doc, text->content, copy); } next_attribute: attr = attr->next; } while (attr != NULL); /* * Apply attribute-sets. * The creation of such attributes will not overwrite any existing * attribute. */ attr = attrs; do { #ifdef XSLT_REFACTORED if ((attr->psvi == xsltXSLTAttrMarker) && xmlStrEqual(attr->name, (const xmlChar *)"use-attribute-sets")) { xsltApplyAttributeSet(ctxt, ctxt->node, (xmlNodePtr) attr, NULL); } #else if ((attr->ns != NULL) && xmlStrEqual(attr->name, (const xmlChar *)"use-attribute-sets") && xmlStrEqual(attr->ns->href, XSLT_NAMESPACE)) { xsltApplyAttributeSet(ctxt, ctxt->node, (xmlNodePtr) attr, NULL); } #endif attr = attr->next; } while (attr != NULL); ctxt->insert = oldInsert; return(target->properties); error: ctxt->insert = oldInsert; return(NULL); } /** * xsltTemplateProcess: * @ctxt: the XSLT transformation context * @node: the attribute template node * * Obsolete. Don't use it. * * Returns NULL. */ xmlNodePtr * xsltTemplateProcess(xsltTransformContextPtr ctxt ATTRIBUTE_UNUSED, xmlNodePtr node) { if (node == NULL) return(NULL); return(0); } libxslt-1.1.28/libxslt/libxslt.30000664000076400007640000000146011202213516013437 00000000000000.TH libxslt 3 "30 August 2001" .SH NAME libxslt \- library used to do XSL transformations on XML documents .SH DESCRIPTION The .I libxslt library is used to do XSL transformations on XML documents that have been loaded into memory with functions from .I libxml. .LP .SH FILES .TP 2.2i .B /usr/lib/libxslt_1.0.0/libxslt.a static library .TP .B /usr/lib/libxslt_1.0.0/libxslt.so sharable library .TP .B /usr/package/libxslt_1.0.0/bin/xsltproc binary application to do XSL transformations on the command line .SH AUTHORS Daniel Veillard (daniel@veillard.com). If you download and install this package look at instructions on the Web site http://xmlsoft.org/XSLT/ . Manual page by Heiko W. Rupp (hwr@pilhuhn.de) .SH SEE ALSO .IR libexslt (3), .IR libxml (3), .IR xsltproc (1), .IR xmllint (1) .\" end of manual page libxslt-1.1.28/libxslt/functions.c0000664000076400007640000006741412053042674014073 00000000000000/* * functions.c: Implementation of the XSLT extra functions * * Reference: * http://www.w3.org/TR/1999/REC-xslt-19991116 * * See Copyright for the status of this software. * * daniel@veillard.com * Bjorn Reese for number formatting */ #define IN_LIBXSLT #include "libxslt.h" #include #ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_CTYPE_H #include #endif #include #include #include #include #include #include #include #include #include #include #include #include "xslt.h" #include "xsltInternals.h" #include "xsltutils.h" #include "functions.h" #include "extensions.h" #include "numbersInternals.h" #include "keys.h" #include "documents.h" #ifdef WITH_XSLT_DEBUG #define WITH_XSLT_DEBUG_FUNCTION #endif /* * Some versions of DocBook XSL use the vendor string to detect * supporting chunking, this is a workaround to be considered * in the list of decent XSLT processors */ #define DOCBOOK_XSL_HACK /** * xsltXPathFunctionLookup: * @ctxt: a void * but the XSLT transformation context actually * @name: the function name * @ns_uri: the function namespace URI * * This is the entry point when a function is needed by the XPath * interpretor. * * Returns the callback function or NULL if not found */ xmlXPathFunction xsltXPathFunctionLookup (xmlXPathContextPtr ctxt, const xmlChar *name, const xmlChar *ns_uri) { xmlXPathFunction ret; if ((ctxt == NULL) || (name == NULL) || (ns_uri == NULL)) return (NULL); #ifdef WITH_XSLT_DEBUG_FUNCTION xsltGenericDebug(xsltGenericDebugContext, "Lookup function {%s}%s\n", ns_uri, name); #endif /* give priority to context-level functions */ /* ret = (xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri); */ XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri); if (ret == NULL) ret = xsltExtModuleFunctionLookup(name, ns_uri); #ifdef WITH_XSLT_DEBUG_FUNCTION if (ret != NULL) xsltGenericDebug(xsltGenericDebugContext, "found function %s\n", name); #endif return(ret); } /************************************************************************ * * * Module interfaces * * * ************************************************************************/ static void xsltDocumentFunctionLoadDocument(xmlXPathParserContextPtr ctxt, xmlChar* URI) { xsltTransformContextPtr tctxt; xmlURIPtr uri; xmlChar *fragment; xsltDocumentPtr idoc; /* document info */ xmlDocPtr doc; xmlXPathContextPtr xptrctxt = NULL; xmlXPathObjectPtr resObj = NULL; tctxt = xsltXPathGetTransformContext(ctxt); if (tctxt == NULL) { xsltTransformError(NULL, NULL, NULL, "document() : internal error tctxt == NULL\n"); valuePush(ctxt, xmlXPathNewNodeSet(NULL)); return; } uri = xmlParseURI((const char *) URI); if (uri == NULL) { xsltTransformError(tctxt, NULL, NULL, "document() : failed to parse URI\n"); valuePush(ctxt, xmlXPathNewNodeSet(NULL)); return; } /* * check for and remove fragment identifier */ fragment = (xmlChar *)uri->fragment; if (fragment != NULL) { xmlChar *newURI; uri->fragment = NULL; newURI = xmlSaveUri(uri); idoc = xsltLoadDocument(tctxt, newURI); xmlFree(newURI); } else idoc = xsltLoadDocument(tctxt, URI); xmlFreeURI(uri); if (idoc == NULL) { if ((URI == NULL) || (URI[0] == '#') || ((tctxt->style->doc != NULL) && (xmlStrEqual(tctxt->style->doc->URL, URI)))) { /* * This selects the stylesheet's doc itself. */ doc = tctxt->style->doc; } else { valuePush(ctxt, xmlXPathNewNodeSet(NULL)); if (fragment != NULL) xmlFree(fragment); return; } } else doc = idoc->doc; if (fragment == NULL) { valuePush(ctxt, xmlXPathNewNodeSet((xmlNodePtr) doc)); return; } /* use XPointer of HTML location for fragment ID */ #ifdef LIBXML_XPTR_ENABLED xptrctxt = xmlXPtrNewContext(doc, NULL, NULL); if (xptrctxt == NULL) { xsltTransformError(tctxt, NULL, NULL, "document() : internal error xptrctxt == NULL\n"); goto out_fragment; } resObj = xmlXPtrEval(fragment, xptrctxt); xmlXPathFreeContext(xptrctxt); #endif xmlFree(fragment); if (resObj == NULL) goto out_fragment; switch (resObj->type) { case XPATH_NODESET: break; case XPATH_UNDEFINED: case XPATH_BOOLEAN: case XPATH_NUMBER: case XPATH_STRING: case XPATH_POINT: case XPATH_USERS: case XPATH_XSLT_TREE: case XPATH_RANGE: case XPATH_LOCATIONSET: xsltTransformError(tctxt, NULL, NULL, "document() : XPointer does not select a node set: #%s\n", fragment); goto out_object; } valuePush(ctxt, resObj); return; out_object: xmlXPathFreeObject(resObj); out_fragment: valuePush(ctxt, xmlXPathNewNodeSet(NULL)); } /** * xsltDocumentFunction: * @ctxt: the XPath Parser context * @nargs: the number of arguments * * Implement the document() XSLT function * node-set document(object, node-set?) */ void xsltDocumentFunction(xmlXPathParserContextPtr ctxt, int nargs) { xmlXPathObjectPtr obj, obj2 = NULL; xmlChar *base = NULL, *URI; if ((nargs < 1) || (nargs > 2)) { xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, "document() : invalid number of args %d\n", nargs); ctxt->error = XPATH_INVALID_ARITY; return; } if (ctxt->value == NULL) { xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, "document() : invalid arg value\n"); ctxt->error = XPATH_INVALID_TYPE; return; } if (nargs == 2) { if (ctxt->value->type != XPATH_NODESET) { xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, "document() : invalid arg expecting a nodeset\n"); ctxt->error = XPATH_INVALID_TYPE; return; } obj2 = valuePop(ctxt); } if (ctxt->value->type == XPATH_NODESET) { int i; xmlXPathObjectPtr newobj, ret; obj = valuePop(ctxt); ret = xmlXPathNewNodeSet(NULL); if ((obj != NULL) && obj->nodesetval) { for (i = 0; i < obj->nodesetval->nodeNr; i++) { valuePush(ctxt, xmlXPathNewNodeSet(obj->nodesetval->nodeTab[i])); xmlXPathStringFunction(ctxt, 1); if (nargs == 2) { valuePush(ctxt, xmlXPathObjectCopy(obj2)); } else { valuePush(ctxt, xmlXPathNewNodeSet(obj->nodesetval-> nodeTab[i])); } xsltDocumentFunction(ctxt, 2); newobj = valuePop(ctxt); ret->nodesetval = xmlXPathNodeSetMerge(ret->nodesetval, newobj->nodesetval); xmlXPathFreeObject(newobj); } } if (obj != NULL) xmlXPathFreeObject(obj); if (obj2 != NULL) xmlXPathFreeObject(obj2); valuePush(ctxt, ret); return; } /* * Make sure it's converted to a string */ xmlXPathStringFunction(ctxt, 1); if (ctxt->value->type != XPATH_STRING) { xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, "document() : invalid arg expecting a string\n"); ctxt->error = XPATH_INVALID_TYPE; if (obj2 != NULL) xmlXPathFreeObject(obj2); return; } obj = valuePop(ctxt); if (obj->stringval == NULL) { valuePush(ctxt, xmlXPathNewNodeSet(NULL)); } else { xsltTransformContextPtr tctxt; tctxt = xsltXPathGetTransformContext(ctxt); if ((obj2 != NULL) && (obj2->nodesetval != NULL) && (obj2->nodesetval->nodeNr > 0) && IS_XSLT_REAL_NODE(obj2->nodesetval->nodeTab[0])) { xmlNodePtr target; target = obj2->nodesetval->nodeTab[0]; if ((target->type == XML_ATTRIBUTE_NODE) || (target->type == XML_PI_NODE)) { target = ((xmlAttrPtr) target)->parent; } base = xmlNodeGetBase(target->doc, target); } else { if ((tctxt != NULL) && (tctxt->inst != NULL)) { base = xmlNodeGetBase(tctxt->inst->doc, tctxt->inst); } else if ((tctxt != NULL) && (tctxt->style != NULL) && (tctxt->style->doc != NULL)) { base = xmlNodeGetBase(tctxt->style->doc, (xmlNodePtr) tctxt->style->doc); } } URI = xmlBuildURI(obj->stringval, base); if (base != NULL) xmlFree(base); if (URI == NULL) { if ((tctxt != NULL) && (tctxt->style != NULL) && (tctxt->style->doc != NULL) && (xmlStrEqual(URI, tctxt->style->doc->URL))) { /* This selects the stylesheet's doc itself. */ valuePush(ctxt, xmlXPathNewNodeSet((xmlNodePtr) tctxt->style->doc)); } else { valuePush(ctxt, xmlXPathNewNodeSet(NULL)); } } else { xsltDocumentFunctionLoadDocument( ctxt, URI ); xmlFree(URI); } } xmlXPathFreeObject(obj); if (obj2 != NULL) xmlXPathFreeObject(obj2); } /** * xsltKeyFunction: * @ctxt: the XPath Parser context * @nargs: the number of arguments * * Implement the key() XSLT function * node-set key(string, object) */ void xsltKeyFunction(xmlXPathParserContextPtr ctxt, int nargs){ xmlXPathObjectPtr obj1, obj2; if (nargs != 2) { xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, "key() : expects two arguments\n"); ctxt->error = XPATH_INVALID_ARITY; return; } /* * Get the key's value. */ obj2 = valuePop(ctxt); xmlXPathStringFunction(ctxt, 1); if ((obj2 == NULL) || (ctxt->value == NULL) || (ctxt->value->type != XPATH_STRING)) { xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, "key() : invalid arg expecting a string\n"); ctxt->error = XPATH_INVALID_TYPE; xmlXPathFreeObject(obj2); return; } /* * Get the key's name. */ obj1 = valuePop(ctxt); if ((obj2->type == XPATH_NODESET) || (obj2->type == XPATH_XSLT_TREE)) { int i; xmlXPathObjectPtr newobj, ret; ret = xmlXPathNewNodeSet(NULL); if (obj2->nodesetval != NULL) { for (i = 0; i < obj2->nodesetval->nodeNr; i++) { valuePush(ctxt, xmlXPathObjectCopy(obj1)); valuePush(ctxt, xmlXPathNewNodeSet(obj2->nodesetval->nodeTab[i])); xmlXPathStringFunction(ctxt, 1); xsltKeyFunction(ctxt, 2); newobj = valuePop(ctxt); ret->nodesetval = xmlXPathNodeSetMerge(ret->nodesetval, newobj->nodesetval); xmlXPathFreeObject(newobj); } } valuePush(ctxt, ret); } else { xmlNodeSetPtr nodelist = NULL; xmlChar *key = NULL, *value; const xmlChar *keyURI; xsltTransformContextPtr tctxt; xmlChar *qname, *prefix; xmlXPathContextPtr xpctxt = ctxt->context; xmlNodePtr tmpNode = NULL; xsltDocumentPtr oldDocInfo; tctxt = xsltXPathGetTransformContext(ctxt); oldDocInfo = tctxt->document; if (xpctxt->node == NULL) { xsltTransformError(tctxt, NULL, tctxt->inst, "Internal error in xsltKeyFunction(): " "The context node is not set on the XPath context.\n"); tctxt->state = XSLT_STATE_STOPPED; goto error; } /* * Get the associated namespace URI if qualified name */ qname = obj1->stringval; key = xmlSplitQName2(qname, &prefix); if (key == NULL) { key = xmlStrdup(obj1->stringval); keyURI = NULL; if (prefix != NULL) xmlFree(prefix); } else { if (prefix != NULL) { keyURI = xmlXPathNsLookup(xpctxt, prefix); if (keyURI == NULL) { xsltTransformError(tctxt, NULL, tctxt->inst, "key() : prefix %s is not bound\n", prefix); /* * TODO: Shouldn't we stop here? */ } xmlFree(prefix); } else { keyURI = NULL; } } /* * Force conversion of first arg to string */ valuePush(ctxt, obj2); xmlXPathStringFunction(ctxt, 1); if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_STRING)) { xsltTransformError(tctxt, NULL, tctxt->inst, "key() : invalid arg expecting a string\n"); ctxt->error = XPATH_INVALID_TYPE; goto error; } obj2 = valuePop(ctxt); value = obj2->stringval; /* * We need to ensure that ctxt->document is available for * xsltGetKey(). * First find the relevant doc, which is the context node's * owner doc; using context->doc is not safe, since * the doc could have been acquired via the document() function, * or the doc might be a Result Tree Fragment. * FUTURE INFO: In XSLT 2.0 the key() function takes an additional * argument indicating the doc to use. */ if (xpctxt->node->type == XML_NAMESPACE_DECL) { /* * REVISIT: This is a libxml hack! Check xpath.c for details. * The XPath module sets the owner element of a ns-node on * the ns->next field. */ if ((((xmlNsPtr) xpctxt->node)->next != NULL) && (((xmlNsPtr) xpctxt->node)->next->type == XML_ELEMENT_NODE)) { tmpNode = (xmlNodePtr) ((xmlNsPtr) xpctxt->node)->next; } } else tmpNode = xpctxt->node; if ((tmpNode == NULL) || (tmpNode->doc == NULL)) { xsltTransformError(tctxt, NULL, tctxt->inst, "Internal error in xsltKeyFunction(): " "Couldn't get the doc of the XPath context node.\n"); goto error; } if ((tctxt->document == NULL) || (tctxt->document->doc != tmpNode->doc)) { if (tmpNode->doc->name && (tmpNode->doc->name[0] == ' ')) { /* * This is a Result Tree Fragment. */ if (tmpNode->doc->_private == NULL) { tmpNode->doc->_private = xsltNewDocument(tctxt, tmpNode->doc); if (tmpNode->doc->_private == NULL) goto error; } tctxt->document = (xsltDocumentPtr) tmpNode->doc->_private; } else { /* * May be the initial source doc or a doc acquired via the * document() function. */ tctxt->document = xsltFindDocument(tctxt, tmpNode->doc); } if (tctxt->document == NULL) { xsltTransformError(tctxt, NULL, tctxt->inst, "Internal error in xsltKeyFunction(): " "Could not get the document info of a context doc.\n"); tctxt->state = XSLT_STATE_STOPPED; goto error; } } /* * Get/compute the key value. */ nodelist = xsltGetKey(tctxt, key, keyURI, value); error: tctxt->document = oldDocInfo; valuePush(ctxt, xmlXPathWrapNodeSet( xmlXPathNodeSetMerge(NULL, nodelist))); if (key != NULL) xmlFree(key); } if (obj1 != NULL) xmlXPathFreeObject(obj1); if (obj2 != NULL) xmlXPathFreeObject(obj2); } /** * xsltUnparsedEntityURIFunction: * @ctxt: the XPath Parser context * @nargs: the number of arguments * * Implement the unparsed-entity-uri() XSLT function * string unparsed-entity-uri(string) */ void xsltUnparsedEntityURIFunction(xmlXPathParserContextPtr ctxt, int nargs){ xmlXPathObjectPtr obj; xmlChar *str; if ((nargs != 1) || (ctxt->value == NULL)) { xsltGenericError(xsltGenericErrorContext, "unparsed-entity-uri() : expects one string arg\n"); ctxt->error = XPATH_INVALID_ARITY; return; } obj = valuePop(ctxt); if (obj->type != XPATH_STRING) { obj = xmlXPathConvertString(obj); } str = obj->stringval; if (str == NULL) { valuePush(ctxt, xmlXPathNewString((const xmlChar *)"")); } else { xmlEntityPtr entity; entity = xmlGetDocEntity(ctxt->context->doc, str); if (entity == NULL) { valuePush(ctxt, xmlXPathNewString((const xmlChar *)"")); } else { if (entity->URI != NULL) valuePush(ctxt, xmlXPathNewString(entity->URI)); else valuePush(ctxt, xmlXPathNewString((const xmlChar *)"")); } } xmlXPathFreeObject(obj); } /** * xsltFormatNumberFunction: * @ctxt: the XPath Parser context * @nargs: the number of arguments * * Implement the format-number() XSLT function * string format-number(number, string, string?) */ void xsltFormatNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) { xmlXPathObjectPtr numberObj = NULL; xmlXPathObjectPtr formatObj = NULL; xmlXPathObjectPtr decimalObj = NULL; xsltStylesheetPtr sheet; xsltDecimalFormatPtr formatValues; xmlChar *result; xsltTransformContextPtr tctxt; tctxt = xsltXPathGetTransformContext(ctxt); if (tctxt == NULL) return; sheet = tctxt->style; if (sheet == NULL) return; formatValues = sheet->decimalFormat; switch (nargs) { case 3: CAST_TO_STRING; decimalObj = valuePop(ctxt); formatValues = xsltDecimalFormatGetByName(sheet, decimalObj->stringval); if (formatValues == NULL) { xsltTransformError(tctxt, NULL, NULL, "format-number() : undeclared decimal format '%s'\n", decimalObj->stringval); } /* Intentional fall-through */ case 2: CAST_TO_STRING; formatObj = valuePop(ctxt); CAST_TO_NUMBER; numberObj = valuePop(ctxt); break; default: XP_ERROR(XPATH_INVALID_ARITY); } if (formatValues != NULL) { if (xsltFormatNumberConversion(formatValues, formatObj->stringval, numberObj->floatval, &result) == XPATH_EXPRESSION_OK) { valuePush(ctxt, xmlXPathNewString(result)); xmlFree(result); } } xmlXPathFreeObject(numberObj); xmlXPathFreeObject(formatObj); xmlXPathFreeObject(decimalObj); } /** * xsltGenerateIdFunction: * @ctxt: the XPath Parser context * @nargs: the number of arguments * * Implement the generate-id() XSLT function * string generate-id(node-set?) */ void xsltGenerateIdFunction(xmlXPathParserContextPtr ctxt, int nargs){ static char base_address; xmlNodePtr cur = NULL; xmlXPathObjectPtr obj = NULL; long val; xmlChar str[30]; xmlDocPtr doc; if (nargs == 0) { cur = ctxt->context->node; } else if (nargs == 1) { xmlNodeSetPtr nodelist; int i, ret; if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_NODESET)) { ctxt->error = XPATH_INVALID_TYPE; xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, "generate-id() : invalid arg expecting a node-set\n"); return; } obj = valuePop(ctxt); nodelist = obj->nodesetval; if ((nodelist == NULL) || (nodelist->nodeNr <= 0)) { xmlXPathFreeObject(obj); valuePush(ctxt, xmlXPathNewCString("")); return; } cur = nodelist->nodeTab[0]; for (i = 1;i < nodelist->nodeNr;i++) { ret = xmlXPathCmpNodes(cur, nodelist->nodeTab[i]); if (ret == -1) cur = nodelist->nodeTab[i]; } } else { xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, "generate-id() : invalid number of args %d\n", nargs); ctxt->error = XPATH_INVALID_ARITY; return; } /* * Okay this is ugly but should work, use the NodePtr address * to forge the ID */ if (cur->type != XML_NAMESPACE_DECL) doc = cur->doc; else { xmlNsPtr ns = (xmlNsPtr) cur; if (ns->context != NULL) doc = ns->context; else doc = ctxt->context->doc; } if (obj) xmlXPathFreeObject(obj); val = (long)((char *)cur - (char *)&base_address); if (val >= 0) { sprintf((char *)str, "idp%ld", val); } else { sprintf((char *)str, "idm%ld", -val); } valuePush(ctxt, xmlXPathNewString(str)); } /** * xsltSystemPropertyFunction: * @ctxt: the XPath Parser context * @nargs: the number of arguments * * Implement the system-property() XSLT function * object system-property(string) */ void xsltSystemPropertyFunction(xmlXPathParserContextPtr ctxt, int nargs){ xmlXPathObjectPtr obj; xmlChar *prefix, *name; const xmlChar *nsURI = NULL; if (nargs != 1) { xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, "system-property() : expects one string arg\n"); ctxt->error = XPATH_INVALID_ARITY; return; } if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_STRING)) { xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, "system-property() : invalid arg expecting a string\n"); ctxt->error = XPATH_INVALID_TYPE; return; } obj = valuePop(ctxt); if (obj->stringval == NULL) { valuePush(ctxt, xmlXPathNewString((const xmlChar *)"")); } else { name = xmlSplitQName2(obj->stringval, &prefix); if (name == NULL) { name = xmlStrdup(obj->stringval); } else { nsURI = xmlXPathNsLookup(ctxt->context, prefix); if (nsURI == NULL) { xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, "system-property() : prefix %s is not bound\n", prefix); } } if (xmlStrEqual(nsURI, XSLT_NAMESPACE)) { #ifdef DOCBOOK_XSL_HACK if (xmlStrEqual(name, (const xmlChar *)"vendor")) { xsltStylesheetPtr sheet; xsltTransformContextPtr tctxt; tctxt = xsltXPathGetTransformContext(ctxt); if ((tctxt != NULL) && (tctxt->inst != NULL) && (xmlStrEqual(tctxt->inst->name, BAD_CAST "variable")) && (tctxt->inst->parent != NULL) && (xmlStrEqual(tctxt->inst->parent->name, BAD_CAST "template"))) sheet = tctxt->style; else sheet = NULL; if ((sheet != NULL) && (sheet->doc != NULL) && (sheet->doc->URL != NULL) && (xmlStrstr(sheet->doc->URL, (const xmlChar *)"chunk") != NULL)) { valuePush(ctxt, xmlXPathNewString( (const xmlChar *)"libxslt (SAXON 6.2 compatible)")); } else { valuePush(ctxt, xmlXPathNewString( (const xmlChar *)XSLT_DEFAULT_VENDOR)); } } else #else if (xmlStrEqual(name, (const xmlChar *)"vendor")) { valuePush(ctxt, xmlXPathNewString( (const xmlChar *)XSLT_DEFAULT_VENDOR)); } else #endif if (xmlStrEqual(name, (const xmlChar *)"version")) { valuePush(ctxt, xmlXPathNewString( (const xmlChar *)XSLT_DEFAULT_VERSION)); } else if (xmlStrEqual(name, (const xmlChar *)"vendor-url")) { valuePush(ctxt, xmlXPathNewString( (const xmlChar *)XSLT_DEFAULT_URL)); } else { valuePush(ctxt, xmlXPathNewString((const xmlChar *)"")); } } else { valuePush(ctxt, xmlXPathNewString((const xmlChar *)"")); } if (name != NULL) xmlFree(name); if (prefix != NULL) xmlFree(prefix); } xmlXPathFreeObject(obj); } /** * xsltElementAvailableFunction: * @ctxt: the XPath Parser context * @nargs: the number of arguments * * Implement the element-available() XSLT function * boolean element-available(string) */ void xsltElementAvailableFunction(xmlXPathParserContextPtr ctxt, int nargs){ xmlXPathObjectPtr obj; xmlChar *prefix, *name; const xmlChar *nsURI = NULL; xsltTransformContextPtr tctxt; if (nargs != 1) { xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, "element-available() : expects one string arg\n"); ctxt->error = XPATH_INVALID_ARITY; return; } xmlXPathStringFunction(ctxt, 1); if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_STRING)) { xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, "element-available() : invalid arg expecting a string\n"); ctxt->error = XPATH_INVALID_TYPE; return; } obj = valuePop(ctxt); tctxt = xsltXPathGetTransformContext(ctxt); if (tctxt == NULL) { xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, "element-available() : internal error tctxt == NULL\n"); xmlXPathFreeObject(obj); valuePush(ctxt, xmlXPathNewBoolean(0)); return; } name = xmlSplitQName2(obj->stringval, &prefix); if (name == NULL) { xmlNsPtr ns; name = xmlStrdup(obj->stringval); ns = xmlSearchNs(tctxt->inst->doc, tctxt->inst, NULL); if (ns != NULL) nsURI = xmlStrdup(ns->href); } else { nsURI = xmlXPathNsLookup(ctxt->context, prefix); if (nsURI == NULL) { xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, "element-available() : prefix %s is not bound\n", prefix); } } if (xsltExtElementLookup(tctxt, name, nsURI) != NULL) { valuePush(ctxt, xmlXPathNewBoolean(1)); } else { valuePush(ctxt, xmlXPathNewBoolean(0)); } xmlXPathFreeObject(obj); if (name != NULL) xmlFree(name); if (prefix != NULL) xmlFree(prefix); } /** * xsltFunctionAvailableFunction: * @ctxt: the XPath Parser context * @nargs: the number of arguments * * Implement the function-available() XSLT function * boolean function-available(string) */ void xsltFunctionAvailableFunction(xmlXPathParserContextPtr ctxt, int nargs){ xmlXPathObjectPtr obj; xmlChar *prefix, *name; const xmlChar *nsURI = NULL; if (nargs != 1) { xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, "function-available() : expects one string arg\n"); ctxt->error = XPATH_INVALID_ARITY; return; } xmlXPathStringFunction(ctxt, 1); if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_STRING)) { xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, "function-available() : invalid arg expecting a string\n"); ctxt->error = XPATH_INVALID_TYPE; return; } obj = valuePop(ctxt); name = xmlSplitQName2(obj->stringval, &prefix); if (name == NULL) { name = xmlStrdup(obj->stringval); } else { nsURI = xmlXPathNsLookup(ctxt->context, prefix); if (nsURI == NULL) { xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, "function-available() : prefix %s is not bound\n", prefix); } } if (xmlXPathFunctionLookupNS(ctxt->context, name, nsURI) != NULL) { valuePush(ctxt, xmlXPathNewBoolean(1)); } else { valuePush(ctxt, xmlXPathNewBoolean(0)); } xmlXPathFreeObject(obj); if (name != NULL) xmlFree(name); if (prefix != NULL) xmlFree(prefix); } /** * xsltCurrentFunction: * @ctxt: the XPath Parser context * @nargs: the number of arguments * * Implement the current() XSLT function * node-set current() */ static void xsltCurrentFunction(xmlXPathParserContextPtr ctxt, int nargs){ xsltTransformContextPtr tctxt; if (nargs != 0) { xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, "current() : function uses no argument\n"); ctxt->error = XPATH_INVALID_ARITY; return; } tctxt = xsltXPathGetTransformContext(ctxt); if (tctxt == NULL) { xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, "current() : internal error tctxt == NULL\n"); valuePush(ctxt, xmlXPathNewNodeSet(NULL)); } else { valuePush(ctxt, xmlXPathNewNodeSet(tctxt->node)); /* current */ } } /************************************************************************ * * * Registration of XSLT and libxslt functions * * * ************************************************************************/ /** * xsltRegisterAllFunctions: * @ctxt: the XPath context * * Registers all default XSLT functions in this context */ void xsltRegisterAllFunctions(xmlXPathContextPtr ctxt) { xmlXPathRegisterFunc(ctxt, (const xmlChar *) "current", xsltCurrentFunction); xmlXPathRegisterFunc(ctxt, (const xmlChar *) "document", xsltDocumentFunction); xmlXPathRegisterFunc(ctxt, (const xmlChar *) "key", xsltKeyFunction); xmlXPathRegisterFunc(ctxt, (const xmlChar *) "unparsed-entity-uri", xsltUnparsedEntityURIFunction); xmlXPathRegisterFunc(ctxt, (const xmlChar *) "format-number", xsltFormatNumberFunction); xmlXPathRegisterFunc(ctxt, (const xmlChar *) "generate-id", xsltGenerateIdFunction); xmlXPathRegisterFunc(ctxt, (const xmlChar *) "system-property", xsltSystemPropertyFunction); xmlXPathRegisterFunc(ctxt, (const xmlChar *) "element-available", xsltElementAvailableFunction); xmlXPathRegisterFunc(ctxt, (const xmlChar *) "function-available", xsltFunctionAvailableFunction); } libxslt-1.1.28/libxslt/pattern.h0000664000076400007640000000371612021407617013535 00000000000000/* * Summary: interface for the pattern matching used in template matches. * Description: the implementation of the lookup of the right template * for a given node must be really fast in order to keep * decent performances. * * Copy: See Copyright for the status of this software. * * Author: Daniel Veillard */ #ifndef __XML_XSLT_PATTERN_H__ #define __XML_XSLT_PATTERN_H__ #include "xsltInternals.h" #include "xsltexports.h" #ifdef __cplusplus extern "C" { #endif /** * xsltCompMatch: * * Data structure used for the implementation of patterns. * It is kept private (in pattern.c). */ typedef struct _xsltCompMatch xsltCompMatch; typedef xsltCompMatch *xsltCompMatchPtr; /* * Pattern related interfaces. */ XSLTPUBFUN xsltCompMatchPtr XSLTCALL xsltCompilePattern (const xmlChar *pattern, xmlDocPtr doc, xmlNodePtr node, xsltStylesheetPtr style, xsltTransformContextPtr runtime); XSLTPUBFUN void XSLTCALL xsltFreeCompMatchList (xsltCompMatchPtr comp); XSLTPUBFUN int XSLTCALL xsltTestCompMatchList (xsltTransformContextPtr ctxt, xmlNodePtr node, xsltCompMatchPtr comp); XSLTPUBFUN void XSLTCALL xsltNormalizeCompSteps (void *payload, void *data, const xmlChar *name); /* * Template related interfaces. */ XSLTPUBFUN int XSLTCALL xsltAddTemplate (xsltStylesheetPtr style, xsltTemplatePtr cur, const xmlChar *mode, const xmlChar *modeURI); XSLTPUBFUN xsltTemplatePtr XSLTCALL xsltGetTemplate (xsltTransformContextPtr ctxt, xmlNodePtr node, xsltStylesheetPtr style); XSLTPUBFUN void XSLTCALL xsltFreeTemplateHashes (xsltStylesheetPtr style); XSLTPUBFUN void XSLTCALL xsltCleanupTemplates (xsltStylesheetPtr style); #if 0 int xsltMatchPattern (xsltTransformContextPtr ctxt, xmlNodePtr node, const xmlChar *pattern, xmlDocPtr ctxtdoc, xmlNodePtr ctxtnode); #endif #ifdef __cplusplus } #endif #endif /* __XML_XSLT_PATTERN_H__ */ libxslt-1.1.28/libxslt/xsltlocale.h0000664000076400007640000000232112021407617014221 00000000000000/* * Summary: Locale handling * Description: Interfaces for locale handling. Needed for language dependent * sorting. * * Copy: See Copyright for the status of this software. * * Author: Nick Wellnhofer */ #ifndef __XML_XSLTLOCALE_H__ #define __XML_XSLTLOCALE_H__ #include #ifdef XSLT_LOCALE_XLOCALE #include #include #ifdef __GLIBC__ /*locale_t is defined only if _GNU_SOURCE is defined*/ typedef __locale_t xsltLocale; #else typedef locale_t xsltLocale; #endif typedef xmlChar xsltLocaleChar; #elif defined(XSLT_LOCALE_WINAPI) #include #include typedef LCID xsltLocale; typedef wchar_t xsltLocaleChar; #else /* * XSLT_LOCALE_NONE: * Macro indicating that locale are not supported */ #ifndef XSLT_LOCALE_NONE #define XSLT_LOCALE_NONE #endif typedef void *xsltLocale; typedef xmlChar xsltLocaleChar; #endif xsltLocale xsltNewLocale(const xmlChar *langName); void xsltFreeLocale(xsltLocale locale); xsltLocaleChar *xsltStrxfrm(xsltLocale locale, const xmlChar *string); int xsltLocaleStrcmp(xsltLocale locale, const xsltLocaleChar *str1, const xsltLocaleChar *str2); void xsltFreeLocales(void); #endif /* __XML_XSLTLOCALE_H__ */ libxslt-1.1.28/libxslt/documents.h0000664000076400007640000000522012024022316014041 00000000000000/* * Summary: interface for the document handling * Description: implements document loading and cache (multiple * document() reference for the same resources must * be equal. * * Copy: See Copyright for the status of this software. * * Author: Daniel Veillard */ #ifndef __XML_XSLT_DOCUMENTS_H__ #define __XML_XSLT_DOCUMENTS_H__ #include #include "xsltexports.h" #include "xsltInternals.h" #ifdef __cplusplus extern "C" { #endif XSLTPUBFUN xsltDocumentPtr XSLTCALL xsltNewDocument (xsltTransformContextPtr ctxt, xmlDocPtr doc); XSLTPUBFUN xsltDocumentPtr XSLTCALL xsltLoadDocument (xsltTransformContextPtr ctxt, const xmlChar *URI); XSLTPUBFUN xsltDocumentPtr XSLTCALL xsltFindDocument (xsltTransformContextPtr ctxt, xmlDocPtr doc); XSLTPUBFUN void XSLTCALL xsltFreeDocuments (xsltTransformContextPtr ctxt); XSLTPUBFUN xsltDocumentPtr XSLTCALL xsltLoadStyleDocument (xsltStylesheetPtr style, const xmlChar *URI); XSLTPUBFUN xsltDocumentPtr XSLTCALL xsltNewStyleDocument (xsltStylesheetPtr style, xmlDocPtr doc); XSLTPUBFUN void XSLTCALL xsltFreeStyleDocuments (xsltStylesheetPtr style); /* * Hooks for document loading */ /** * xsltLoadType: * * Enum defining the kind of loader requirement. */ typedef enum { XSLT_LOAD_START = 0, /* loading for a top stylesheet */ XSLT_LOAD_STYLESHEET = 1, /* loading for a stylesheet include/import */ XSLT_LOAD_DOCUMENT = 2 /* loading document at transformation time */ } xsltLoadType; /** * xsltDocLoaderFunc: * @URI: the URI of the document to load * @dict: the dictionary to use when parsing that document * @options: parsing options, a set of xmlParserOption * @ctxt: the context, either a stylesheet or a transformation context * @type: the xsltLoadType indicating the kind of loading required * * An xsltDocLoaderFunc is a signature for a function which can be * registered to load document not provided by the compilation or * transformation API themselve, for example when an xsl:import, * xsl:include is found at compilation time or when a document() * call is made at runtime. * * Returns the pointer to the document (which will be modified and * freed by the engine later), or NULL in case of error. */ typedef xmlDocPtr (*xsltDocLoaderFunc) (const xmlChar *URI, xmlDictPtr dict, int options, void *ctxt, xsltLoadType type); XSLTPUBFUN void XSLTCALL xsltSetLoaderFunc (xsltDocLoaderFunc f); /* the loader may be needed by extension libraries so it is exported */ XSLTPUBVAR xsltDocLoaderFunc xsltDocDefaultLoader; #ifdef __cplusplus } #endif #endif /* __XML_XSLT_DOCUMENTS_H__ */ libxslt-1.1.28/libxslt/xslt.h0000664000076400007640000000365412024022317013044 00000000000000/* * Summary: Interfaces, constants and types related to the XSLT engine * Description: Interfaces, constants and types related to the XSLT engine * * Copy: See Copyright for the status of this software. * * Author: Daniel Veillard */ #ifndef __XML_XSLT_H__ #define __XML_XSLT_H__ #include #include "xsltexports.h" #ifdef __cplusplus extern "C" { #endif /** * XSLT_DEFAULT_VERSION: * * The default version of XSLT supported. */ #define XSLT_DEFAULT_VERSION "1.0" /** * XSLT_DEFAULT_VENDOR: * * The XSLT "vendor" string for this processor. */ #define XSLT_DEFAULT_VENDOR "libxslt" /** * XSLT_DEFAULT_URL: * * The XSLT "vendor" URL for this processor. */ #define XSLT_DEFAULT_URL "http://xmlsoft.org/XSLT/" /** * XSLT_NAMESPACE: * * The XSLT specification namespace. */ #define XSLT_NAMESPACE ((const xmlChar *)"http://www.w3.org/1999/XSL/Transform") /** * XSLT_PARSE_OPTIONS: * * The set of options to pass to an xmlReadxxx when loading files for * XSLT consumption. */ #define XSLT_PARSE_OPTIONS \ XML_PARSE_NOENT | XML_PARSE_DTDLOAD | XML_PARSE_DTDATTR | XML_PARSE_NOCDATA /** * xsltMaxDepth: * * This value is used to detect templates loops. */ XSLTPUBVAR int xsltMaxDepth; /** * * xsltMaxVars: * * * * This value is used to detect templates loops. * */ XSLTPUBVAR int xsltMaxVars; /** * xsltEngineVersion: * * The version string for libxslt. */ XSLTPUBVAR const char *xsltEngineVersion; /** * xsltLibxsltVersion: * * The version of libxslt compiled. */ XSLTPUBVAR const int xsltLibxsltVersion; /** * xsltLibxmlVersion: * * The version of libxml libxslt was compiled against. */ XSLTPUBVAR const int xsltLibxmlVersion; /* * Global initialization function. */ XSLTPUBFUN void XSLTCALL xsltInit (void); /* * Global cleanup function. */ XSLTPUBFUN void XSLTCALL xsltCleanupGlobals (void); #ifdef __cplusplus } #endif #endif /* __XML_XSLT_H__ */ libxslt-1.1.28/libxslt/functions.h0000664000076400007640000000372612024022316014061 00000000000000/* * Summary: interface for the XSLT functions not from XPath * Description: a set of extra functions coming from XSLT but not in XPath * * Copy: See Copyright for the status of this software. * * Author: Daniel Veillard and Bjorn Reese */ #ifndef __XML_XSLT_FUNCTIONS_H__ #define __XML_XSLT_FUNCTIONS_H__ #include #include #include "xsltexports.h" #include "xsltInternals.h" #ifdef __cplusplus extern "C" { #endif /** * XSLT_REGISTER_FUNCTION_LOOKUP: * * Registering macro, not general purpose at all but used in different modules. */ #define XSLT_REGISTER_FUNCTION_LOOKUP(ctxt) \ xmlXPathRegisterFuncLookup((ctxt)->xpathCtxt, \ (xmlXPathFuncLookupFunc) xsltXPathFunctionLookup, \ (void *)(ctxt->xpathCtxt)); XSLTPUBFUN xmlXPathFunction XSLTCALL xsltXPathFunctionLookup (xmlXPathContextPtr ctxt, const xmlChar *name, const xmlChar *ns_uri); /* * Interfaces for the functions implementations. */ XSLTPUBFUN void XSLTCALL xsltDocumentFunction (xmlXPathParserContextPtr ctxt, int nargs); XSLTPUBFUN void XSLTCALL xsltKeyFunction (xmlXPathParserContextPtr ctxt, int nargs); XSLTPUBFUN void XSLTCALL xsltUnparsedEntityURIFunction (xmlXPathParserContextPtr ctxt, int nargs); XSLTPUBFUN void XSLTCALL xsltFormatNumberFunction (xmlXPathParserContextPtr ctxt, int nargs); XSLTPUBFUN void XSLTCALL xsltGenerateIdFunction (xmlXPathParserContextPtr ctxt, int nargs); XSLTPUBFUN void XSLTCALL xsltSystemPropertyFunction (xmlXPathParserContextPtr ctxt, int nargs); XSLTPUBFUN void XSLTCALL xsltElementAvailableFunction (xmlXPathParserContextPtr ctxt, int nargs); XSLTPUBFUN void XSLTCALL xsltFunctionAvailableFunction (xmlXPathParserContextPtr ctxt, int nargs); /* * And the registration */ XSLTPUBFUN void XSLTCALL xsltRegisterAllFunctions (xmlXPathContextPtr ctxt); #ifdef __cplusplus } #endif #endif /* __XML_XSLT_FUNCTIONS_H__ */ libxslt-1.1.28/libxslt/Makefile.am0000664000076400007640000000263112021653677013747 00000000000000AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/libxslt AM_CFLAGS = $(LIBXML_CFLAGS) lib_LTLIBRARIES = libxslt.la xsltincdir = $(includedir)/libxslt xsltinc_HEADERS = \ xslt.h \ xsltutils.h \ pattern.h \ templates.h \ variables.h \ keys.h \ numbersInternals.h \ extensions.h \ extra.h \ functions.h \ namespaces.h \ imports.h \ attributes.h \ documents.h \ preproc.h \ transform.h \ security.h \ xsltInternals.h \ xsltconfig.h \ xsltexports.h \ xsltlocale.h libxslt_la_SOURCES = \ attrvt.c \ xslt.c \ xsltlocale.c \ xsltutils.c \ pattern.c \ templates.c \ variables.c \ keys.c \ numbers.c \ extensions.c \ extra.c \ functions.c \ namespaces.c \ imports.c \ attributes.c \ documents.c \ preproc.c \ transform.c \ security.c \ win32config.h \ xsltwin32config.h \ xsltwin32config.h.in \ libxslt.h if USE_VERSION_SCRIPT LIBXSLT_VERSION_SCRIPT = $(VERSION_SCRIPT_FLAGS)$(srcdir)/libxslt.syms else LIBXSLT_VERSION_SCRIPT = endif libxslt_la_LIBADD = $(LIBXML_LIBS) $(EXTRA_LIBS) libxslt_la_LDFLAGS = \ $(WIN32_EXTRA_LDFLAGS) \ $(LIBXSLT_VERSION_SCRIPT) \ -version-info $(LIBXSLT_VERSION_INFO) man_MANS = libxslt.3 EXTRA_DIST = $(man_MANS) trio.h triodef.h libxslt.syms xsltproc: all @(cd ../xsltproc ; $(MAKE)) install-exec-hook: $(MKDIR_P) "$(DESTDIR)$(libdir)/libxslt-plugins" libxslt-1.1.28/libxslt/numbers.c0000664000076400007640000010457212024022316013520 00000000000000/* * numbers.c: Implementation of the XSLT number functions * * Reference: * http://www.w3.org/TR/1999/REC-xslt-19991116 * * See Copyright for the status of this software. * * daniel@veillard.com * Bjorn Reese */ #define IN_LIBXSLT #include "libxslt.h" #include #include #include #include #include #include #include #include #include #include "xsltutils.h" #include "pattern.h" #include "templates.h" #include "transform.h" #include "numbersInternals.h" #ifndef FALSE # define FALSE (0 == 1) # define TRUE (1 == 1) #endif #define SYMBOL_QUOTE ((xmlChar)'\'') #define DEFAULT_TOKEN (xmlChar)'0' #define DEFAULT_SEPARATOR "." #define MAX_TOKENS 1024 typedef struct _xsltFormatToken xsltFormatToken; typedef xsltFormatToken *xsltFormatTokenPtr; struct _xsltFormatToken { xmlChar *separator; xmlChar token; int width; }; typedef struct _xsltFormat xsltFormat; typedef xsltFormat *xsltFormatPtr; struct _xsltFormat { xmlChar *start; xsltFormatToken tokens[MAX_TOKENS]; int nTokens; xmlChar *end; }; static char alpha_upper_list[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; static char alpha_lower_list[] = "abcdefghijklmnopqrstuvwxyz"; static xsltFormatToken default_token; /* * **** Start temp insert **** * * The following two routines (xsltUTF8Size and xsltUTF8Charcmp) * will be replaced with calls to the corresponding libxml routines * at a later date (when other inter-library dependencies require it) */ /** * xsltUTF8Size: * @utf: pointer to the UTF8 character * * returns the numbers of bytes in the character, -1 on format error */ static int xsltUTF8Size(xmlChar *utf) { xmlChar mask; int len; if (utf == NULL) return -1; if (*utf < 0x80) return 1; /* check valid UTF8 character */ if (!(*utf & 0x40)) return -1; /* determine number of bytes in char */ len = 2; for (mask=0x20; mask != 0; mask>>=1) { if (!(*utf & mask)) return len; len++; } return -1; } /** * xsltUTF8Charcmp * @utf1: pointer to first UTF8 char * @utf2: pointer to second UTF8 char * * returns result of comparing the two UCS4 values * as with xmlStrncmp */ static int xsltUTF8Charcmp(xmlChar *utf1, xmlChar *utf2) { if (utf1 == NULL ) { if (utf2 == NULL) return 0; return -1; } return xmlStrncmp(utf1, utf2, xsltUTF8Size(utf1)); } /***** Stop temp insert *****/ /************************************************************************ * * * Utility functions * * * ************************************************************************/ #define IS_SPECIAL(self,letter) \ ((xsltUTF8Charcmp((letter), (self)->zeroDigit) == 0) || \ (xsltUTF8Charcmp((letter), (self)->digit) == 0) || \ (xsltUTF8Charcmp((letter), (self)->decimalPoint) == 0) || \ (xsltUTF8Charcmp((letter), (self)->grouping) == 0) || \ (xsltUTF8Charcmp((letter), (self)->patternSeparator) == 0)) #define IS_DIGIT_ZERO(x) xsltIsDigitZero(x) #define IS_DIGIT_ONE(x) xsltIsDigitZero((xmlChar)(x)-1) static int xsltIsDigitZero(unsigned int ch) { /* * Reference: ftp://ftp.unicode.org/Public/UNIDATA/UnicodeData.txt */ switch (ch) { case 0x0030: case 0x0660: case 0x06F0: case 0x0966: case 0x09E6: case 0x0A66: case 0x0AE6: case 0x0B66: case 0x0C66: case 0x0CE6: case 0x0D66: case 0x0E50: case 0x0E60: case 0x0F20: case 0x1040: case 0x17E0: case 0x1810: case 0xFF10: return TRUE; default: return FALSE; } } static void xsltNumberFormatDecimal(xmlBufferPtr buffer, double number, int digit_zero, int width, int digitsPerGroup, int groupingCharacter, int groupingCharacterLen) { /* * This used to be * xmlChar temp_string[sizeof(double) * CHAR_BIT * sizeof(xmlChar) + 4]; * which would be length 68 on x86 arch. It was changed to be a longer, * fixed length in order to try to cater for (reasonable) UTF8 * separators and numeric characters. The max UTF8 char size will be * 6 or less, so the value used [500] should be *much* larger than needed */ xmlChar temp_string[500]; xmlChar *pointer; xmlChar temp_char[6]; int i; int val; int len; /* Build buffer from back */ pointer = &temp_string[sizeof(temp_string)] - 1; /* last char */ *pointer = 0; i = 0; while (pointer > temp_string) { if ((i >= width) && (fabs(number) < 1.0)) break; /* for */ if ((i > 0) && (groupingCharacter != 0) && (digitsPerGroup > 0) && ((i % digitsPerGroup) == 0)) { if (pointer - groupingCharacterLen < temp_string) { i = -1; /* flag error */ break; } pointer -= groupingCharacterLen; xmlCopyCharMultiByte(pointer, groupingCharacter); } val = digit_zero + (int)fmod(number, 10.0); if (val < 0x80) { /* shortcut if ASCII */ if (pointer <= temp_string) { /* Check enough room */ i = -1; break; } *(--pointer) = val; } else { /* * Here we have a multibyte character. It's a little messy, * because until we generate the char we don't know how long * it is. So, we generate it into the buffer temp_char, then * copy from there into temp_string. */ len = xmlCopyCharMultiByte(temp_char, val); if ( (pointer - len) < temp_string ) { i = -1; break; } pointer -= len; memcpy(pointer, temp_char, len); } number /= 10.0; ++i; } if (i < 0) xsltGenericError(xsltGenericErrorContext, "xsltNumberFormatDecimal: Internal buffer size exceeded"); xmlBufferCat(buffer, pointer); } static void xsltNumberFormatAlpha(xmlBufferPtr buffer, double number, int is_upper) { char temp_string[sizeof(double) * CHAR_BIT * sizeof(xmlChar) + 1]; char *pointer; int i; char *alpha_list; double alpha_size = (double)(sizeof(alpha_upper_list) - 1); /* Build buffer from back */ pointer = &temp_string[sizeof(temp_string)]; *(--pointer) = 0; alpha_list = (is_upper) ? alpha_upper_list : alpha_lower_list; for (i = 1; i < (int)sizeof(temp_string); i++) { number--; *(--pointer) = alpha_list[((int)fmod(number, alpha_size))]; number /= alpha_size; if (fabs(number) < 1.0) break; /* for */ } xmlBufferCCat(buffer, pointer); } static void xsltNumberFormatRoman(xmlBufferPtr buffer, double number, int is_upper) { /* * Based on an example by Jim Walsh */ while (number >= 1000.0) { xmlBufferCCat(buffer, (is_upper) ? "M" : "m"); number -= 1000.0; } if (number >= 900.0) { xmlBufferCCat(buffer, (is_upper) ? "CM" : "cm"); number -= 900.0; } while (number >= 500.0) { xmlBufferCCat(buffer, (is_upper) ? "D" : "d"); number -= 500.0; } if (number >= 400.0) { xmlBufferCCat(buffer, (is_upper) ? "CD" : "cd"); number -= 400.0; } while (number >= 100.0) { xmlBufferCCat(buffer, (is_upper) ? "C" : "c"); number -= 100.0; } if (number >= 90.0) { xmlBufferCCat(buffer, (is_upper) ? "XC" : "xc"); number -= 90.0; } while (number >= 50.0) { xmlBufferCCat(buffer, (is_upper) ? "L" : "l"); number -= 50.0; } if (number >= 40.0) { xmlBufferCCat(buffer, (is_upper) ? "XL" : "xl"); number -= 40.0; } while (number >= 10.0) { xmlBufferCCat(buffer, (is_upper) ? "X" : "x"); number -= 10.0; } if (number >= 9.0) { xmlBufferCCat(buffer, (is_upper) ? "IX" : "ix"); number -= 9.0; } while (number >= 5.0) { xmlBufferCCat(buffer, (is_upper) ? "V" : "v"); number -= 5.0; } if (number >= 4.0) { xmlBufferCCat(buffer, (is_upper) ? "IV" : "iv"); number -= 4.0; } while (number >= 1.0) { xmlBufferCCat(buffer, (is_upper) ? "I" : "i"); number--; } } static void xsltNumberFormatTokenize(const xmlChar *format, xsltFormatPtr tokens) { int ix = 0; int j; int val; int len; default_token.token = DEFAULT_TOKEN; default_token.width = 1; default_token.separator = BAD_CAST(DEFAULT_SEPARATOR); tokens->start = NULL; tokens->tokens[0].separator = NULL; tokens->end = NULL; /* * Insert initial non-alphanumeric token. * There is always such a token in the list, even if NULL */ while (! (IS_LETTER(val=xmlStringCurrentChar(NULL, format+ix, &len)) || IS_DIGIT(val)) ) { if (format[ix] == 0) /* if end of format string */ break; /* while */ ix += len; } if (ix > 0) tokens->start = xmlStrndup(format, ix); for (tokens->nTokens = 0; tokens->nTokens < MAX_TOKENS; tokens->nTokens++) { if (format[ix] == 0) break; /* for */ /* * separator has already been parsed (except for the first * number) in tokens->end, recover it. */ if (tokens->nTokens > 0) { tokens->tokens[tokens->nTokens].separator = tokens->end; tokens->end = NULL; } val = xmlStringCurrentChar(NULL, format+ix, &len); if (IS_DIGIT_ONE(val) || IS_DIGIT_ZERO(val)) { tokens->tokens[tokens->nTokens].width = 1; while (IS_DIGIT_ZERO(val)) { tokens->tokens[tokens->nTokens].width++; ix += len; val = xmlStringCurrentChar(NULL, format+ix, &len); } if (IS_DIGIT_ONE(val)) { tokens->tokens[tokens->nTokens].token = val - 1; ix += len; val = xmlStringCurrentChar(NULL, format+ix, &len); } } else if ( (val == (xmlChar)'A') || (val == (xmlChar)'a') || (val == (xmlChar)'I') || (val == (xmlChar)'i') ) { tokens->tokens[tokens->nTokens].token = val; ix += len; val = xmlStringCurrentChar(NULL, format+ix, &len); } else { /* XSLT section 7.7 * "Any other format token indicates a numbering sequence * that starts with that token. If an implementation does * not support a numbering sequence that starts with that * token, it must use a format token of 1." */ tokens->tokens[tokens->nTokens].token = (xmlChar)'0'; tokens->tokens[tokens->nTokens].width = 1; } /* * Skip over remaining alphanumeric characters from the Nd * (Number, decimal digit), Nl (Number, letter), No (Number, * other), Lu (Letter, uppercase), Ll (Letter, lowercase), Lt * (Letters, titlecase), Lm (Letters, modifiers), and Lo * (Letters, other (uncased)) Unicode categories. This happens * to correspond to the Letter and Digit classes from XML (and * one wonders why XSLT doesn't refer to these instead). */ while (IS_LETTER(val) || IS_DIGIT(val)) { ix += len; val = xmlStringCurrentChar(NULL, format+ix, &len); } /* * Insert temporary non-alphanumeric final tooken. */ j = ix; while (! (IS_LETTER(val) || IS_DIGIT(val))) { if (val == 0) break; /* while */ ix += len; val = xmlStringCurrentChar(NULL, format+ix, &len); } if (ix > j) tokens->end = xmlStrndup(&format[j], ix - j); } } static void xsltNumberFormatInsertNumbers(xsltNumberDataPtr data, double *numbers, int numbers_max, xsltFormatPtr tokens, xmlBufferPtr buffer) { int i = 0; double number; xsltFormatTokenPtr token; /* * Handle initial non-alphanumeric token */ if (tokens->start != NULL) xmlBufferCat(buffer, tokens->start); for (i = 0; i < numbers_max; i++) { /* Insert number */ number = numbers[(numbers_max - 1) - i]; if (i < tokens->nTokens) { /* * The "n"th format token will be used to format the "n"th * number in the list */ token = &(tokens->tokens[i]); } else if (tokens->nTokens > 0) { /* * If there are more numbers than format tokens, then the * last format token will be used to format the remaining * numbers. */ token = &(tokens->tokens[tokens->nTokens - 1]); } else { /* * If there are no format tokens, then a format token of * 1 is used to format all numbers. */ token = &default_token; } /* Print separator, except for the first number */ if (i > 0) { if (token->separator != NULL) xmlBufferCat(buffer, token->separator); else xmlBufferCCat(buffer, DEFAULT_SEPARATOR); } switch (xmlXPathIsInf(number)) { case -1: xmlBufferCCat(buffer, "-Infinity"); break; case 1: xmlBufferCCat(buffer, "Infinity"); break; default: if (xmlXPathIsNaN(number)) { xmlBufferCCat(buffer, "NaN"); } else { switch (token->token) { case 'A': xsltNumberFormatAlpha(buffer, number, TRUE); break; case 'a': xsltNumberFormatAlpha(buffer, number, FALSE); break; case 'I': xsltNumberFormatRoman(buffer, number, TRUE); break; case 'i': xsltNumberFormatRoman(buffer, number, FALSE); break; default: if (IS_DIGIT_ZERO(token->token)) { xsltNumberFormatDecimal(buffer, number, token->token, token->width, data->digitsPerGroup, data->groupingCharacter, data->groupingCharacterLen); } break; } } } } /* * Handle final non-alphanumeric token */ if (tokens->end != NULL) xmlBufferCat(buffer, tokens->end); } static int xsltNumberFormatGetAnyLevel(xsltTransformContextPtr context, xmlNodePtr node, xsltCompMatchPtr countPat, xsltCompMatchPtr fromPat, double *array, xmlDocPtr doc, xmlNodePtr elem) { int amount = 0; int cnt = 0; xmlNodePtr cur; /* select the starting node */ switch (node->type) { case XML_ELEMENT_NODE: cur = node; break; case XML_ATTRIBUTE_NODE: cur = ((xmlAttrPtr) node)->parent; break; case XML_TEXT_NODE: case XML_PI_NODE: case XML_COMMENT_NODE: cur = node->parent; break; default: cur = NULL; break; } while (cur != NULL) { /* process current node */ if (countPat == NULL) { if ((node->type == cur->type) && /* FIXME: must use expanded-name instead of local name */ xmlStrEqual(node->name, cur->name)) { if ((node->ns == cur->ns) || ((node->ns != NULL) && (cur->ns != NULL) && (xmlStrEqual(node->ns->href, cur->ns->href) ))) cnt++; } } else { if (xsltTestCompMatchList(context, cur, countPat)) cnt++; } if ((fromPat != NULL) && xsltTestCompMatchList(context, cur, fromPat)) { break; /* while */ } /* Skip to next preceding or ancestor */ if ((cur->type == XML_DOCUMENT_NODE) || #ifdef LIBXML_DOCB_ENABLED (cur->type == XML_DOCB_DOCUMENT_NODE) || #endif (cur->type == XML_HTML_DOCUMENT_NODE)) break; /* while */ while ((cur->prev != NULL) && ((cur->prev->type == XML_DTD_NODE) || (cur->prev->type == XML_XINCLUDE_START) || (cur->prev->type == XML_XINCLUDE_END))) cur = cur->prev; if (cur->prev != NULL) { for (cur = cur->prev; cur->last != NULL; cur = cur->last); } else { cur = cur->parent; } } array[amount++] = (double) cnt; return(amount); } static int xsltNumberFormatGetMultipleLevel(xsltTransformContextPtr context, xmlNodePtr node, xsltCompMatchPtr countPat, xsltCompMatchPtr fromPat, double *array, int max, xmlDocPtr doc, xmlNodePtr elem) { int amount = 0; int cnt; xmlNodePtr ancestor; xmlNodePtr preceding; xmlXPathParserContextPtr parser; context->xpathCtxt->node = node; parser = xmlXPathNewParserContext(NULL, context->xpathCtxt); if (parser) { /* ancestor-or-self::*[count] */ for (ancestor = node; (ancestor != NULL) && (ancestor->type != XML_DOCUMENT_NODE); ancestor = xmlXPathNextAncestor(parser, ancestor)) { if ((fromPat != NULL) && xsltTestCompMatchList(context, ancestor, fromPat)) break; /* for */ if ((countPat == NULL && node->type == ancestor->type && xmlStrEqual(node->name, ancestor->name)) || xsltTestCompMatchList(context, ancestor, countPat)) { /* count(preceding-sibling::*) */ cnt = 0; for (preceding = ancestor; preceding != NULL; preceding = xmlXPathNextPrecedingSibling(parser, preceding)) { if (countPat == NULL) { if ((preceding->type == ancestor->type) && xmlStrEqual(preceding->name, ancestor->name)){ if ((preceding->ns == ancestor->ns) || ((preceding->ns != NULL) && (ancestor->ns != NULL) && (xmlStrEqual(preceding->ns->href, ancestor->ns->href) ))) cnt++; } } else { if (xsltTestCompMatchList(context, preceding, countPat)) cnt++; } } array[amount++] = (double)cnt; if (amount >= max) break; /* for */ } } xmlXPathFreeParserContext(parser); } return amount; } static int xsltNumberFormatGetValue(xmlXPathContextPtr context, xmlNodePtr node, const xmlChar *value, double *number) { int amount = 0; xmlBufferPtr pattern; xmlXPathObjectPtr obj; pattern = xmlBufferCreate(); if (pattern != NULL) { xmlBufferCCat(pattern, "number("); xmlBufferCat(pattern, value); xmlBufferCCat(pattern, ")"); context->node = node; obj = xmlXPathEvalExpression(xmlBufferContent(pattern), context); if (obj != NULL) { *number = obj->floatval; amount++; xmlXPathFreeObject(obj); } xmlBufferFree(pattern); } return amount; } /** * xsltNumberFormat: * @ctxt: the XSLT transformation context * @data: the formatting informations * @node: the data to format * * Convert one number. */ void xsltNumberFormat(xsltTransformContextPtr ctxt, xsltNumberDataPtr data, xmlNodePtr node) { xmlBufferPtr output = NULL; int amount, i; double number; xsltFormat tokens; int tempformat = 0; if ((data->format == NULL) && (data->has_format != 0)) { data->format = xsltEvalAttrValueTemplate(ctxt, data->node, (const xmlChar *) "format", XSLT_NAMESPACE); tempformat = 1; } if (data->format == NULL) { return; } output = xmlBufferCreate(); if (output == NULL) goto XSLT_NUMBER_FORMAT_END; xsltNumberFormatTokenize(data->format, &tokens); /* * Evaluate the XPath expression to find the value(s) */ if (data->value) { amount = xsltNumberFormatGetValue(ctxt->xpathCtxt, node, data->value, &number); if (amount == 1) { xsltNumberFormatInsertNumbers(data, &number, 1, &tokens, output); } } else if (data->level) { if (xmlStrEqual(data->level, (const xmlChar *) "single")) { amount = xsltNumberFormatGetMultipleLevel(ctxt, node, data->countPat, data->fromPat, &number, 1, data->doc, data->node); if (amount == 1) { xsltNumberFormatInsertNumbers(data, &number, 1, &tokens, output); } } else if (xmlStrEqual(data->level, (const xmlChar *) "multiple")) { double numarray[1024]; int max = sizeof(numarray)/sizeof(numarray[0]); amount = xsltNumberFormatGetMultipleLevel(ctxt, node, data->countPat, data->fromPat, numarray, max, data->doc, data->node); if (amount > 0) { xsltNumberFormatInsertNumbers(data, numarray, amount, &tokens, output); } } else if (xmlStrEqual(data->level, (const xmlChar *) "any")) { amount = xsltNumberFormatGetAnyLevel(ctxt, node, data->countPat, data->fromPat, &number, data->doc, data->node); if (amount > 0) { xsltNumberFormatInsertNumbers(data, &number, 1, &tokens, output); } } } /* Insert number as text node */ xsltCopyTextString(ctxt, ctxt->insert, xmlBufferContent(output), 0); if (tokens.start != NULL) xmlFree(tokens.start); if (tokens.end != NULL) xmlFree(tokens.end); for (i = 0;i < tokens.nTokens;i++) { if (tokens.tokens[i].separator != NULL) xmlFree(tokens.tokens[i].separator); } XSLT_NUMBER_FORMAT_END: if (tempformat == 1) { /* The format need to be recomputed each time */ data->format = NULL; } if (output != NULL) xmlBufferFree(output); } static int xsltFormatNumberPreSuffix(xsltDecimalFormatPtr self, xmlChar **format, xsltFormatNumberInfoPtr info) { int count=0; /* will hold total length of prefix/suffix */ int len; while (1) { /* * prefix / suffix ends at end of string or at * first 'special' character */ if (**format == 0) return count; /* if next character 'escaped' just count it */ if (**format == SYMBOL_QUOTE) { if (*++(*format) == 0) return -1; } else if (IS_SPECIAL(self, *format)) return count; /* * else treat percent/per-mille as special cases, * depending on whether +ve or -ve */ else { /* * for +ve prefix/suffix, allow only a * single occurence of either */ if (xsltUTF8Charcmp(*format, self->percent) == 0) { if (info->is_multiplier_set) return -1; info->multiplier = 100; info->is_multiplier_set = TRUE; } else if (xsltUTF8Charcmp(*format, self->permille) == 0) { if (info->is_multiplier_set) return -1; info->multiplier = 1000; info->is_multiplier_set = TRUE; } } if ((len=xsltUTF8Size(*format)) < 1) return -1; count += len; *format += len; } } /** * xsltFormatNumberConversion: * @self: the decimal format * @format: the format requested * @number: the value to format * @result: the place to ouput the result * * format-number() uses the JDK 1.1 DecimalFormat class: * * http://java.sun.com/products/jdk/1.1/docs/api/java.text.DecimalFormat.html * * Structure: * * pattern := subpattern{;subpattern} * subpattern := {prefix}integer{.fraction}{suffix} * prefix := '\\u0000'..'\\uFFFD' - specialCharacters * suffix := '\\u0000'..'\\uFFFD' - specialCharacters * integer := '#'* '0'* '0' * fraction := '0'* '#'* * * Notation: * X* 0 or more instances of X * (X | Y) either X or Y. * X..Y any character from X up to Y, inclusive. * S - T characters in S, except those in T * * Special Characters: * * Symbol Meaning * 0 a digit * # a digit, zero shows as absent * . placeholder for decimal separator * , placeholder for grouping separator. * ; separates formats. * - default negative prefix. * % multiply by 100 and show as percentage * ? multiply by 1000 and show as per mille * X any other characters can be used in the prefix or suffix * ' used to quote special characters in a prefix or suffix. * * Returns a possible XPath error */ xmlXPathError xsltFormatNumberConversion(xsltDecimalFormatPtr self, xmlChar *format, double number, xmlChar **result) { xmlXPathError status = XPATH_EXPRESSION_OK; xmlBufferPtr buffer; xmlChar *the_format, *prefix = NULL, *suffix = NULL; xmlChar *nprefix, *nsuffix = NULL; xmlChar pchar; int prefix_length, suffix_length = 0, nprefix_length, nsuffix_length; double scale; int j, len; int self_grouping_len; xsltFormatNumberInfo format_info; /* * delayed_multiplier allows a 'trailing' percent or * permille to be treated as suffix */ int delayed_multiplier = 0; /* flag to show no -ve format present for -ve number */ char default_sign = 0; /* flag to show error found, should use default format */ char found_error = 0; if (xmlStrlen(format) <= 0) { xsltTransformError(NULL, NULL, NULL, "xsltFormatNumberConversion : " "Invalid format (0-length)\n"); } *result = NULL; switch (xmlXPathIsInf(number)) { case -1: if (self->minusSign == NULL) *result = xmlStrdup(BAD_CAST "-"); else *result = xmlStrdup(self->minusSign); /* no-break on purpose */ case 1: if ((self == NULL) || (self->infinity == NULL)) *result = xmlStrcat(*result, BAD_CAST "Infinity"); else *result = xmlStrcat(*result, self->infinity); return(status); default: if (xmlXPathIsNaN(number)) { if ((self == NULL) || (self->noNumber == NULL)) *result = xmlStrdup(BAD_CAST "NaN"); else *result = xmlStrdup(self->noNumber); return(status); } } buffer = xmlBufferCreate(); if (buffer == NULL) { return XPATH_MEMORY_ERROR; } format_info.integer_hash = 0; format_info.integer_digits = 0; format_info.frac_digits = 0; format_info.frac_hash = 0; format_info.group = -1; format_info.multiplier = 1; format_info.add_decimal = FALSE; format_info.is_multiplier_set = FALSE; format_info.is_negative_pattern = FALSE; the_format = format; /* * First we process the +ve pattern to get percent / permille, * as well as main format */ prefix = the_format; prefix_length = xsltFormatNumberPreSuffix(self, &the_format, &format_info); if (prefix_length < 0) { found_error = 1; goto OUTPUT_NUMBER; } /* * Here we process the "number" part of the format. It gets * a little messy because of the percent/per-mille - if that * appears at the end, it may be part of the suffix instead * of part of the number, so the variable delayed_multiplier * is used to handle it */ self_grouping_len = xmlStrlen(self->grouping); while ((*the_format != 0) && (xsltUTF8Charcmp(the_format, self->decimalPoint) != 0) && (xsltUTF8Charcmp(the_format, self->patternSeparator) != 0)) { if (delayed_multiplier != 0) { format_info.multiplier = delayed_multiplier; format_info.is_multiplier_set = TRUE; delayed_multiplier = 0; } if (xsltUTF8Charcmp(the_format, self->digit) == 0) { if (format_info.integer_digits > 0) { found_error = 1; goto OUTPUT_NUMBER; } format_info.integer_hash++; if (format_info.group >= 0) format_info.group++; } else if (xsltUTF8Charcmp(the_format, self->zeroDigit) == 0) { format_info.integer_digits++; if (format_info.group >= 0) format_info.group++; } else if ((self_grouping_len > 0) && (!xmlStrncmp(the_format, self->grouping, self_grouping_len))) { /* Reset group count */ format_info.group = 0; the_format += self_grouping_len; continue; } else if (xsltUTF8Charcmp(the_format, self->percent) == 0) { if (format_info.is_multiplier_set) { found_error = 1; goto OUTPUT_NUMBER; } delayed_multiplier = 100; } else if (xsltUTF8Charcmp(the_format, self->permille) == 0) { if (format_info.is_multiplier_set) { found_error = 1; goto OUTPUT_NUMBER; } delayed_multiplier = 1000; } else break; /* while */ if ((len=xsltUTF8Size(the_format)) < 1) { found_error = 1; goto OUTPUT_NUMBER; } the_format += len; } /* We have finished the integer part, now work on fraction */ if (xsltUTF8Charcmp(the_format, self->decimalPoint) == 0) { format_info.add_decimal = TRUE; the_format += xsltUTF8Size(the_format); /* Skip over the decimal */ } while (*the_format != 0) { if (xsltUTF8Charcmp(the_format, self->zeroDigit) == 0) { if (format_info.frac_hash != 0) { found_error = 1; goto OUTPUT_NUMBER; } format_info.frac_digits++; } else if (xsltUTF8Charcmp(the_format, self->digit) == 0) { format_info.frac_hash++; } else if (xsltUTF8Charcmp(the_format, self->percent) == 0) { if (format_info.is_multiplier_set) { found_error = 1; goto OUTPUT_NUMBER; } delayed_multiplier = 100; if ((len = xsltUTF8Size(the_format)) < 1) { found_error = 1; goto OUTPUT_NUMBER; } the_format += len; continue; /* while */ } else if (xsltUTF8Charcmp(the_format, self->permille) == 0) { if (format_info.is_multiplier_set) { found_error = 1; goto OUTPUT_NUMBER; } delayed_multiplier = 1000; if ((len = xsltUTF8Size(the_format)) < 1) { found_error = 1; goto OUTPUT_NUMBER; } the_format += len; continue; /* while */ } else if (xsltUTF8Charcmp(the_format, self->grouping) != 0) { break; /* while */ } if ((len = xsltUTF8Size(the_format)) < 1) { found_error = 1; goto OUTPUT_NUMBER; } the_format += len; if (delayed_multiplier != 0) { format_info.multiplier = delayed_multiplier; delayed_multiplier = 0; format_info.is_multiplier_set = TRUE; } } /* * If delayed_multiplier is set after processing the * "number" part, should be in suffix */ if (delayed_multiplier != 0) { the_format -= len; delayed_multiplier = 0; } suffix = the_format; suffix_length = xsltFormatNumberPreSuffix(self, &the_format, &format_info); if ( (suffix_length < 0) || ((*the_format != 0) && (xsltUTF8Charcmp(the_format, self->patternSeparator) != 0)) ) { found_error = 1; goto OUTPUT_NUMBER; } /* * We have processed the +ve prefix, number part and +ve suffix. * If the number is -ve, we must substitute the -ve prefix / suffix */ if (number < 0) { /* * Note that j is the number of UTF8 chars before the separator, * not the number of bytes! (bug 151975) */ j = xmlUTF8Strloc(format, self->patternSeparator); if (j < 0) { /* No -ve pattern present, so use default signing */ default_sign = 1; } else { /* Skip over pattern separator (accounting for UTF8) */ the_format = (xmlChar *)xmlUTF8Strpos(format, j + 1); /* * Flag changes interpretation of percent/permille * in -ve pattern */ format_info.is_negative_pattern = TRUE; format_info.is_multiplier_set = FALSE; /* First do the -ve prefix */ nprefix = the_format; nprefix_length = xsltFormatNumberPreSuffix(self, &the_format, &format_info); if (nprefix_length<0) { found_error = 1; goto OUTPUT_NUMBER; } while (*the_format != 0) { if ( (xsltUTF8Charcmp(the_format, (self)->percent) == 0) || (xsltUTF8Charcmp(the_format, (self)->permille)== 0) ) { if (format_info.is_multiplier_set) { found_error = 1; goto OUTPUT_NUMBER; } format_info.is_multiplier_set = TRUE; delayed_multiplier = 1; } else if (IS_SPECIAL(self, the_format)) delayed_multiplier = 0; else break; /* while */ if ((len = xsltUTF8Size(the_format)) < 1) { found_error = 1; goto OUTPUT_NUMBER; } the_format += len; } if (delayed_multiplier != 0) { format_info.is_multiplier_set = FALSE; the_format -= len; } /* Finally do the -ve suffix */ if (*the_format != 0) { nsuffix = the_format; nsuffix_length = xsltFormatNumberPreSuffix(self, &the_format, &format_info); if (nsuffix_length < 0) { found_error = 1; goto OUTPUT_NUMBER; } } else nsuffix_length = 0; if (*the_format != 0) { found_error = 1; goto OUTPUT_NUMBER; } /* * Here's another Java peculiarity: * if -ve prefix/suffix == +ve ones, discard & use default */ if ((nprefix_length != prefix_length) || (nsuffix_length != suffix_length) || ((nprefix_length > 0) && (xmlStrncmp(nprefix, prefix, prefix_length) !=0 )) || ((nsuffix_length > 0) && (xmlStrncmp(nsuffix, suffix, suffix_length) !=0 ))) { prefix = nprefix; prefix_length = nprefix_length; suffix = nsuffix; suffix_length = nsuffix_length; } /* else { default_sign = 1; } */ } } OUTPUT_NUMBER: if (found_error != 0) { xsltTransformError(NULL, NULL, NULL, "xsltFormatNumberConversion : " "error in format string '%s', using default\n", format); default_sign = (number < 0.0) ? 1 : 0; prefix_length = suffix_length = 0; format_info.integer_hash = 0; format_info.integer_digits = 1; format_info.frac_digits = 1; format_info.frac_hash = 4; format_info.group = -1; format_info.multiplier = 1; format_info.add_decimal = TRUE; } /* Ready to output our number. First see if "default sign" is required */ if (default_sign != 0) xmlBufferAdd(buffer, self->minusSign, xsltUTF8Size(self->minusSign)); /* Put the prefix into the buffer */ for (j = 0; j < prefix_length; j++) { if ((pchar = *prefix++) == SYMBOL_QUOTE) { len = xsltUTF8Size(prefix); xmlBufferAdd(buffer, prefix, len); prefix += len; j += len - 1; /* length of symbol less length of quote */ } else xmlBufferAdd(buffer, &pchar, 1); } /* Next do the integer part of the number */ number = fabs(number) * (double)format_info.multiplier; scale = pow(10.0, (double)(format_info.frac_digits + format_info.frac_hash)); number = floor((scale * number + 0.5)) / scale; if ((self->grouping != NULL) && (self->grouping[0] != 0)) { len = xmlStrlen(self->grouping); pchar = xsltGetUTF8Char(self->grouping, &len); xsltNumberFormatDecimal(buffer, floor(number), self->zeroDigit[0], format_info.integer_digits, format_info.group, pchar, len); } else xsltNumberFormatDecimal(buffer, floor(number), self->zeroDigit[0], format_info.integer_digits, format_info.group, ',', 1); /* Special case: java treats '.#' like '.0', '.##' like '.0#', etc. */ if ((format_info.integer_digits + format_info.integer_hash + format_info.frac_digits == 0) && (format_info.frac_hash > 0)) { ++format_info.frac_digits; --format_info.frac_hash; } /* Add leading zero, if required */ if ((floor(number) == 0) && (format_info.integer_digits + format_info.frac_digits == 0)) { xmlBufferAdd(buffer, self->zeroDigit, xsltUTF8Size(self->zeroDigit)); } /* Next the fractional part, if required */ if (format_info.frac_digits + format_info.frac_hash == 0) { if (format_info.add_decimal) xmlBufferAdd(buffer, self->decimalPoint, xsltUTF8Size(self->decimalPoint)); } else { number -= floor(number); if ((number != 0) || (format_info.frac_digits != 0)) { xmlBufferAdd(buffer, self->decimalPoint, xsltUTF8Size(self->decimalPoint)); number = floor(scale * number + 0.5); for (j = format_info.frac_hash; j > 0; j--) { if (fmod(number, 10.0) >= 1.0) break; /* for */ number /= 10.0; } xsltNumberFormatDecimal(buffer, floor(number), self->zeroDigit[0], format_info.frac_digits + j, 0, 0, 0); } } /* Put the suffix into the buffer */ for (j = 0; j < suffix_length; j++) { if ((pchar = *suffix++) == SYMBOL_QUOTE) { len = xsltUTF8Size(suffix); xmlBufferAdd(buffer, suffix, len); suffix += len; j += len - 1; /* length of symbol less length of escape */ } else xmlBufferAdd(buffer, &pchar, 1); } *result = xmlStrdup(xmlBufferContent(buffer)); xmlBufferFree(buffer); return status; } libxslt-1.1.28/libxslt/libxslt.syms0000664000076400007640000002110312053100433014262 00000000000000# # Officially exported symbols, for which header # file definitions are installed in /usr/include/libxslt # # Automatically generated from symbols.xml and syms.xsl # # Versions here are *fixed* to match the libxslt version # at which the symbol was introduced. This ensures that # a new client app requiring symbol foo() can't accidentally # run with old libxslt.so not providing foo() - the global # soname version info can't enforce this since we never # change the soname # LIBXML2_1.0.11 { global: # attributes xsltApplyAttributeSet; xsltFreeAttributeSetsHashes; xsltParseStylesheetAttributeSet; # documents xsltFindDocument; xsltFreeDocuments; xsltFreeStyleDocuments; xsltLoadDocument; xsltLoadStyleDocument; xsltNewDocument; xsltNewStyleDocument; # extensions xsltCheckExtPrefix; xsltExtElementLookup; xsltExtModuleElementLookup; xsltExtModuleFunctionLookup; xsltExtModuleTopLevelLookup; xsltFreeCtxtExts; xsltFreeExts; xsltGetExtData; xsltInitCtxtExts; xsltInitElemPreComp; xsltNewElemPreComp; xsltPreComputeExtModuleElement; xsltRegisterExtElement; xsltRegisterExtFunction; xsltRegisterExtModuleElement; xsltRegisterExtModuleFull; xsltRegisterExtModuleFunction; xsltRegisterExtModule; xsltRegisterExtModuleTopLevel; xsltRegisterExtPrefix; xsltRegisterTestModule; xsltShutdownCtxtExts; xsltShutdownExts; xsltStyleGetExtData; xsltUnregisterExtModuleElement; xsltUnregisterExtModuleFunction; xsltUnregisterExtModule; xsltUnregisterExtModuleTopLevel; # extra xsltDebug; xsltFunctionNodeSet; xsltRegisterAllExtras; xsltRegisterExtras; # functions xsltDocumentFunction; xsltElementAvailableFunction; xsltFormatNumberFunction; xsltFunctionAvailableFunction; xsltGenerateIdFunction; xsltKeyFunction; xsltRegisterAllFunctions; xsltSystemPropertyFunction; xsltUnparsedEntityURIFunction; xsltXPathFunctionLookup; # imports xsltFindElemSpaceHandling; xsltFindTemplate; xsltNeedElemSpaceHandling; xsltNextImport; xsltParseStylesheetImport; xsltParseStylesheetInclude; # keys xsltAddKey; xsltFreeDocumentKeys; xsltFreeKeys; xsltGetKey; xsltInitCtxtKeys; # namespaces xsltCopyNamespaceList; xsltCopyNamespace; xsltFreeNamespaceAliasHashes; xsltGetNamespace; xsltGetSpecialNamespace; xsltNamespaceAlias; # pattern xsltAddTemplate; xsltCleanupTemplates; xsltCompilePattern; xsltFreeCompMatchList; xsltFreeTemplateHashes; xsltGetTemplate; xsltMatchPattern; xsltTestCompMatchList; # preproc xsltDocumentComp; xsltFreeStylePreComps; xsltStylePreCompute; # templates xsltAttrListTemplateProcess; xsltAttrTemplateProcess; xsltAttrTemplateValueProcess; xsltEvalAttrValueTemplate; xsltEvalStaticAttrValueTemplate; xsltEvalTemplateString; xsltEvalXPathPredicate; xsltEvalXPathString; xsltTemplateProcess; # transform xslHandleDebugger; xsltApplyImports; xsltApplyOneTemplate; xsltApplyStripSpaces; xsltApplyStylesheet; xsltApplyStylesheetUser; xsltApplyTemplates; xsltAttribute; xsltCallTemplate; xsltChoose; xsltComment; xsltCopyOf; xsltCopy; xsltDocumentElem; xsltElement; xsltForEach; xsltFreeTransformContext; xsltGetXIncludeDefault; xsltIf; xsltNewTransformContext; xsltNumber; xsltProcessingInstruction; xsltProfileStylesheet; xsltRegisterAllElement; xsltRunStylesheet; xsltSetXIncludeDefault; xsltSort; xsltText; xsltValueOf; # variables xsltAddStackElemList; xsltEvalGlobalVariables; xsltEvalOneUserParam; xsltEvalUserParams; xsltFreeGlobalVariables; xsltParseGlobalParam; xsltParseGlobalVariable; xsltParseStylesheetCallerParam; xsltParseStylesheetParam; xsltParseStylesheetVariable; xsltQuoteOneUserParam; xsltQuoteUserParams; xsltVariableLookup; xsltXPathVariableLookup; # xsltInternals xsltDecimalFormatGetByName; xsltFormatNumberConversion; xsltFreeStackElemList; xsltFreeStylesheet; xsltIsBlank; xsltLoadStylesheetPI; xsltNewStylesheet; xsltNumberFormat; xsltParseStylesheetDoc; xsltParseStylesheetFile; xsltParseStylesheetOutput; xsltParseStylesheetProcess; xsltParseTemplateContent; # xsltutils xslAddCall; xslDropCall; xsltCalibrateAdjust; xsltDocumentSortFunction; xsltDoSortFunction; xsltGetNsProp; xsltGetQNameURI; xsltMessage; xsltPrintErrorContext; xsltSaveProfiling; xsltSaveResultToFd; xsltSaveResultToFilename; xsltSaveResultToFile; xsltSaveResultTo; xsltSetDebuggerCallbacks; xsltSetGenericDebugFunc; xsltSetGenericErrorFunc; xsltTimestamp; # xslt xsltCleanupGlobals; } ; LIBXML2_1.0.12 { global: # xsltInternals xsltAllocateExtraCtxt; xsltAllocateExtra; } LIBXML2_1.0.11; LIBXML2_1.0.13 { global: # extensions xsltExtModuleElementPreComputeLookup; xsltXPathGetTransformContext; } LIBXML2_1.0.12; LIBXML2_1.0.16 { global: # attributes xsltResolveStylesheetAttributeSet; } LIBXML2_1.0.13; LIBXML2_1.0.17 { global: # transform xsltRunStylesheetUser; } LIBXML2_1.0.16; LIBXML2_1.0.18 { global: # extensions xsltDebugDumpExtensions; # xsltutils xsltSaveResultToString; } LIBXML2_1.0.17; LIBXML2_1.0.22 { global: # templates xsltAttrTemplateValueProcessNode; # security xsltCheckRead; xsltCheckWrite; # templates xsltEvalXPathStringNs; # security xsltFreeSecurityPrefs; xsltGetDefaultSecurityPrefs; xsltGetSecurityPrefs; xsltNewSecurityPrefs; xsltSecurityAllow; xsltSecurityForbid; xsltSetCtxtSecurityPrefs; xsltSetDefaultSecurityPrefs; xsltSetSecurityPrefs; # xsltutils xsltSetTransformErrorFunc; xsltTransformError; } LIBXML2_1.0.18; LIBXML2_1.0.24 { global: # xsltutils xslDebugStatus; # variable xsltComputeSortResult; xsltDefaultSortFunction; # xslt xsltEngineVersion; # variable # preproc xsltExtMarker; # variable # xsltutils xsltGenericDebugContext; # variable xsltGenericDebug; # variable xsltGenericErrorContext; # variable xsltGenericError; # variable xsltGetProfileInformation; xsltGetUTF8Char; # xslt xsltLibxmlVersion; # variable xsltLibxsltVersion; # variable xsltMaxDepth; # variable xsltMaxVars; # variable # xsltInternals xsltParseStylesheetImportedDoc; # xsltutils xsltSetCtxtSortFunc; xsltSetSortFunc; } LIBXML2_1.0.22; LIBXML2_1.0.30 { global: # xsltInternals xsltCreateRVT; xsltFreeRVTs; xsltRegisterPersistRVT; xsltRegisterTmpRVT; } LIBXML2_1.0.24; LIBXML2_1.0.32 { global: # transform xsltCopyTextString; # extensions xsltGetExtInfo; } LIBXML2_1.0.30; LIBXML2_1.0.33 { global: # pattern xsltNormalizeCompSteps; } LIBXML2_1.0.32; LIBXML2_1.1.0 { global: # xsltutils xsltGetDebuggerStatus; xsltSetDebuggerStatus; } LIBXML2_1.0.33; LIBXML2_1.1.1 { global: # xsltutils xsltDebugGetDefaultTrace; xsltDebugSetDefaultTrace; } LIBXML2_1.1.0; LIBXML2_1.1.2 { global: # xsltutils xsltSetCtxtParseOptions; } LIBXML2_1.1.1; LIBXML2_1.1.3 { global: # xsltInternals xsltCompileAttr; xsltEvalAVT; xsltFreeAVTList; # xsltutils xsltGetCNsProp; xsltSplitQName; xsltXPathCompile; } LIBXML2_1.1.2; LIBXML2_1.1.5 { global: # xsltutils xsltGetQNameURI2; } LIBXML2_1.1.3; LIBXML2_1.1.7 { global: # namespaces xsltGetPlainNamespace; } LIBXML2_1.1.5; LIBXML2_1.1.9 { global: # documents xsltDocDefaultLoader; # variable xsltSetLoaderFunc; } LIBXML2_1.1.7; LIBXML2_1.1.18 { global: # xsltInternals xsltConstNamespaceNameXSLT; # variable xsltExtensionInstructionResultFinalize; xsltExtensionInstructionResultRegister; xsltInitCtxtKey; # xslt xsltInit; # xsltInternals xsltParseAnyXSLTElem; xsltParseSequenceConstructor; xsltPointerListAddSize; xsltPointerListClear; xsltPointerListCreate; xsltPointerListFree; xsltRegisterLocalRVT; xsltReleaseRVT; xsltRestoreDocumentNamespaces; # extensions xsltStyleStylesheetLevelGetExtData; # xsltInternals # xsltTransStorageAdd; removed in 1.1.28 # xsltTransStorageRemove; removed in 1.1.28 xsltUninit; xsltXSLTAttrMarker; # variable } LIBXML2_1.1.9; LIBXML2_1.1.20 { global: # transform xsltLocalVariablePop; xsltLocalVariablePush; } LIBXML2_1.1.18; LIBXML2_1.1.23 { global: # xsltInternals xsltInitAllDocKeys; } LIBXML2_1.1.20; LIBXML2_1.1.24 { global: # extensions xsltCheckExtURI; } LIBXML2_1.1.23; LIBXML2_1.1.25 { global: # xsltlocale xsltFreeLocale; xsltLocaleStrcmp; xsltNewLocale; xsltStrxfrm; # extensions xsltInitGlobals; } LIBXML2_1.1.24; LIBXML2_1.1.26 { global: # transform xsltProcessOneNode; } LIBXML2_1.1.25; LIBXML2_1.1.27 { global: # xsltlocale xsltFreeLocales; # xsltutils xsltXPathCompileFlags; } LIBXML2_1.1.26; libxslt-1.1.28/libxslt/numbersInternals.h0000664000076400007640000000374312024022167015407 00000000000000/* * Summary: Implementation of the XSLT number functions * Description: Implementation of the XSLT number functions * * Copy: See Copyright for the status of this software. * * Author: Bjorn Reese and Daniel Veillard */ #ifndef __XML_XSLT_NUMBERSINTERNALS_H__ #define __XML_XSLT_NUMBERSINTERNALS_H__ #include #include "xsltexports.h" #ifdef __cplusplus extern "C" { #endif struct _xsltCompMatch; /** * xsltNumberData: * * This data structure is just a wrapper to pass xsl:number data in. */ typedef struct _xsltNumberData xsltNumberData; typedef xsltNumberData *xsltNumberDataPtr; struct _xsltNumberData { const xmlChar *level; const xmlChar *count; const xmlChar *from; const xmlChar *value; const xmlChar *format; int has_format; int digitsPerGroup; int groupingCharacter; int groupingCharacterLen; xmlDocPtr doc; xmlNodePtr node; struct _xsltCompMatch *countPat; struct _xsltCompMatch *fromPat; /* * accelerators */ }; /** * xsltFormatNumberInfo,: * * This data structure lists the various parameters needed to format numbers. */ typedef struct _xsltFormatNumberInfo xsltFormatNumberInfo; typedef xsltFormatNumberInfo *xsltFormatNumberInfoPtr; struct _xsltFormatNumberInfo { int integer_hash; /* Number of '#' in integer part */ int integer_digits; /* Number of '0' in integer part */ int frac_digits; /* Number of '0' in fractional part */ int frac_hash; /* Number of '#' in fractional part */ int group; /* Number of chars per display 'group' */ int multiplier; /* Scaling for percent or permille */ char add_decimal; /* Flag for whether decimal point appears in pattern */ char is_multiplier_set; /* Flag to catch multiple occurences of percent/permille */ char is_negative_pattern;/* Flag for processing -ve prefix/suffix */ }; #ifdef __cplusplus } #endif #endif /* __XML_XSLT_NUMBERSINTERNALS_H__ */ libxslt-1.1.28/libxslt/attributes.c0000664000076400007640000007273712024022316014242 00000000000000/* * attributes.c: Implementation of the XSLT attributes handling * * Reference: * http://www.w3.org/TR/1999/REC-xslt-19991116 * * See Copyright for the status of this software. * * daniel@veillard.com */ #define IN_LIBXSLT #include "libxslt.h" #include #ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_MATH_H #include #endif #ifdef HAVE_FLOAT_H #include #endif #ifdef HAVE_IEEEFP_H #include #endif #ifdef HAVE_NAN_H #include #endif #ifdef HAVE_CTYPE_H #include #endif #include #include #include #include #include #include #include "xslt.h" #include "xsltInternals.h" #include "xsltutils.h" #include "attributes.h" #include "namespaces.h" #include "templates.h" #include "imports.h" #include "transform.h" #include "preproc.h" #define WITH_XSLT_DEBUG_ATTRIBUTES #ifdef WITH_XSLT_DEBUG #define WITH_XSLT_DEBUG_ATTRIBUTES #endif /* * TODO: merge attribute sets from different import precedence. * all this should be precomputed just before the transformation * starts or at first hit with a cache in the context. * The simple way for now would be to not allow redefinition of * attributes once generated in the output tree, possibly costlier. */ /* * Useful macros */ #ifdef IS_BLANK #undef IS_BLANK #endif #define IS_BLANK(c) (((c) == 0x20) || ((c) == 0x09) || ((c) == 0xA) || \ ((c) == 0x0D)) #define IS_BLANK_NODE(n) \ (((n)->type == XML_TEXT_NODE) && (xsltIsBlank((n)->content))) /* * The in-memory structure corresponding to an XSLT Attribute in * an attribute set */ typedef struct _xsltAttrElem xsltAttrElem; typedef xsltAttrElem *xsltAttrElemPtr; struct _xsltAttrElem { struct _xsltAttrElem *next;/* chained list */ xmlNodePtr attr; /* the xsl:attribute definition */ const xmlChar *set; /* or the attribute set */ const xmlChar *ns; /* and its namespace */ }; /************************************************************************ * * * XSLT Attribute handling * * * ************************************************************************/ /** * xsltNewAttrElem: * @attr: the new xsl:attribute node * * Create a new XSLT AttrElem * * Returns the newly allocated xsltAttrElemPtr or NULL in case of error */ static xsltAttrElemPtr xsltNewAttrElem(xmlNodePtr attr) { xsltAttrElemPtr cur; cur = (xsltAttrElemPtr) xmlMalloc(sizeof(xsltAttrElem)); if (cur == NULL) { xsltGenericError(xsltGenericErrorContext, "xsltNewAttrElem : malloc failed\n"); return(NULL); } memset(cur, 0, sizeof(xsltAttrElem)); cur->attr = attr; return(cur); } /** * xsltFreeAttrElem: * @attr: an XSLT AttrElem * * Free up the memory allocated by @attr */ static void xsltFreeAttrElem(xsltAttrElemPtr attr) { xmlFree(attr); } /** * xsltFreeAttrElemList: * @list: an XSLT AttrElem list * * Free up the memory allocated by @list */ static void xsltFreeAttrElemList(xsltAttrElemPtr list) { xsltAttrElemPtr next; while (list != NULL) { next = list->next; xsltFreeAttrElem(list); list = next; } } #ifdef XSLT_REFACTORED /* * This was moved to xsltParseStylesheetAttributeSet(). */ #else /** * xsltAddAttrElemList: * @list: an XSLT AttrElem list * @attr: the new xsl:attribute node * * Add the new attribute to the list. * * Returns the new list pointer */ static xsltAttrElemPtr xsltAddAttrElemList(xsltAttrElemPtr list, xmlNodePtr attr) { xsltAttrElemPtr next, cur; if (attr == NULL) return(list); if (list == NULL) return(xsltNewAttrElem(attr)); cur = list; while (cur != NULL) { next = cur->next; if (cur->attr == attr) return(cur); if (cur->next == NULL) { cur->next = xsltNewAttrElem(attr); return(list); } cur = next; } return(list); } #endif /* XSLT_REFACTORED */ /** * xsltMergeAttrElemList: * @list: an XSLT AttrElem list * @old: another XSLT AttrElem list * * Add all the attributes from list @old to list @list, * but drop redefinition of existing values. * * Returns the new list pointer */ static xsltAttrElemPtr xsltMergeAttrElemList(xsltStylesheetPtr style, xsltAttrElemPtr list, xsltAttrElemPtr old) { xsltAttrElemPtr cur; int add; while (old != NULL) { if ((old->attr == NULL) && (old->set == NULL)) { old = old->next; continue; } /* * Check that the attribute is not yet in the list */ cur = list; add = 1; while (cur != NULL) { if ((cur->attr == NULL) && (cur->set == NULL)) { if (cur->next == NULL) break; cur = cur->next; continue; } if ((cur->set != NULL) && (cur->set == old->set)) { add = 0; break; } if (cur->set != NULL) { if (cur->next == NULL) break; cur = cur->next; continue; } if (old->set != NULL) { if (cur->next == NULL) break; cur = cur->next; continue; } if (cur->attr == old->attr) { xsltGenericError(xsltGenericErrorContext, "xsl:attribute-set : use-attribute-sets recursion detected\n"); return(list); } if (cur->next == NULL) break; cur = cur->next; } if (add == 1) { /* * Changed to use the string-dict, rather than duplicating * @set and @ns; this fixes bug #340400. */ if (cur == NULL) { list = xsltNewAttrElem(old->attr); if (old->set != NULL) { list->set = xmlDictLookup(style->dict, old->set, -1); if (old->ns != NULL) list->ns = xmlDictLookup(style->dict, old->ns, -1); } } else if (add) { cur->next = xsltNewAttrElem(old->attr); if (old->set != NULL) { cur->next->set = xmlDictLookup(style->dict, old->set, -1); if (old->ns != NULL) cur->next->ns = xmlDictLookup(style->dict, old->ns, -1); } } } old = old->next; } return(list); } /************************************************************************ * * * Module interfaces * * * ************************************************************************/ /** * xsltParseStylesheetAttributeSet: * @style: the XSLT stylesheet * @cur: the "attribute-set" element * * parse an XSLT stylesheet attribute-set element */ void xsltParseStylesheetAttributeSet(xsltStylesheetPtr style, xmlNodePtr cur) { const xmlChar *ncname; const xmlChar *prefix; xmlChar *value; xmlNodePtr child; xsltAttrElemPtr attrItems; if ((cur == NULL) || (style == NULL) || (cur->type != XML_ELEMENT_NODE)) return; value = xmlGetNsProp(cur, (const xmlChar *)"name", NULL); if (value == NULL) { xsltGenericError(xsltGenericErrorContext, "xsl:attribute-set : name is missing\n"); return; } ncname = xsltSplitQName(style->dict, value, &prefix); xmlFree(value); value = NULL; if (style->attributeSets == NULL) { #ifdef WITH_XSLT_DEBUG_ATTRIBUTES xsltGenericDebug(xsltGenericDebugContext, "creating attribute set table\n"); #endif style->attributeSets = xmlHashCreate(10); } if (style->attributeSets == NULL) return; attrItems = xmlHashLookup2(style->attributeSets, ncname, prefix); /* * Parse the content. Only xsl:attribute elements are allowed. */ child = cur->children; while (child != NULL) { /* * Report invalid nodes. */ if ((child->type != XML_ELEMENT_NODE) || (child->ns == NULL) || (! IS_XSLT_ELEM(child))) { if (child->type == XML_ELEMENT_NODE) xsltTransformError(NULL, style, child, "xsl:attribute-set : unexpected child %s\n", child->name); else xsltTransformError(NULL, style, child, "xsl:attribute-set : child of unexpected type\n"); } else if (!IS_XSLT_NAME(child, "attribute")) { xsltTransformError(NULL, style, child, "xsl:attribute-set : unexpected child xsl:%s\n", child->name); } else { #ifdef XSLT_REFACTORED xsltAttrElemPtr nextAttr, curAttr; /* * Process xsl:attribute * --------------------- */ #ifdef WITH_XSLT_DEBUG_ATTRIBUTES xsltGenericDebug(xsltGenericDebugContext, "add attribute to list %s\n", ncname); #endif /* * The following was taken over from * xsltAddAttrElemList(). */ if (attrItems == NULL) { attrItems = xsltNewAttrElem(child); } else { curAttr = attrItems; while (curAttr != NULL) { nextAttr = curAttr->next; if (curAttr->attr == child) { /* * URGENT TODO: Can somebody explain * why attrItems is set to curAttr * here? Is this somehow related to * avoidance of recursions? */ attrItems = curAttr; goto next_child; } if (curAttr->next == NULL) curAttr->next = xsltNewAttrElem(child); curAttr = nextAttr; } } /* * Parse the xsl:attribute and its content. */ xsltParseAnyXSLTElem(XSLT_CCTXT(style), child); #else #ifdef WITH_XSLT_DEBUG_ATTRIBUTES xsltGenericDebug(xsltGenericDebugContext, "add attribute to list %s\n", ncname); #endif /* * OLD behaviour: */ attrItems = xsltAddAttrElemList(attrItems, child); #endif } #ifdef XSLT_REFACTORED next_child: #endif child = child->next; } /* * Process attribue "use-attribute-sets". */ /* TODO check recursion */ value = xmlGetNsProp(cur, (const xmlChar *)"use-attribute-sets", NULL); if (value != NULL) { const xmlChar *curval, *endval; curval = value; while (*curval != 0) { while (IS_BLANK(*curval)) curval++; if (*curval == 0) break; endval = curval; while ((*endval != 0) && (!IS_BLANK(*endval))) endval++; curval = xmlDictLookup(style->dict, curval, endval - curval); if (curval) { const xmlChar *ncname2 = NULL; const xmlChar *prefix2 = NULL; xsltAttrElemPtr refAttrItems; #ifdef WITH_XSLT_DEBUG_ATTRIBUTES xsltGenericDebug(xsltGenericDebugContext, "xsl:attribute-set : %s adds use %s\n", ncname, curval); #endif ncname2 = xsltSplitQName(style->dict, curval, &prefix2); refAttrItems = xsltNewAttrElem(NULL); if (refAttrItems != NULL) { refAttrItems->set = ncname2; refAttrItems->ns = prefix2; attrItems = xsltMergeAttrElemList(style, attrItems, refAttrItems); xsltFreeAttrElem(refAttrItems); } } curval = endval; } xmlFree(value); value = NULL; } /* * Update the value */ /* * TODO: Why is this dummy entry needed.? */ if (attrItems == NULL) attrItems = xsltNewAttrElem(NULL); xmlHashUpdateEntry2(style->attributeSets, ncname, prefix, attrItems, NULL); #ifdef WITH_XSLT_DEBUG_ATTRIBUTES xsltGenericDebug(xsltGenericDebugContext, "updated attribute list %s\n", ncname); #endif } /** * xsltGetSAS: * @style: the XSLT stylesheet * @name: the attribute list name * @ns: the attribute list namespace * * lookup an attribute set based on the style cascade * * Returns the attribute set or NULL */ static xsltAttrElemPtr xsltGetSAS(xsltStylesheetPtr style, const xmlChar *name, const xmlChar *ns) { xsltAttrElemPtr values; while (style != NULL) { values = xmlHashLookup2(style->attributeSets, name, ns); if (values != NULL) return(values); style = xsltNextImport(style); } return(NULL); } /** * xsltResolveSASCallback,: * @style: the XSLT stylesheet * * resolve the references in an attribute set. */ static void xsltResolveSASCallback(xsltAttrElemPtr values, xsltStylesheetPtr style, const xmlChar *name, const xmlChar *ns, ATTRIBUTE_UNUSED const xmlChar *ignored) { xsltAttrElemPtr tmp; xsltAttrElemPtr refs; tmp = values; while (tmp != NULL) { if (tmp->set != NULL) { /* * Check against cycles ! */ if ((xmlStrEqual(name, tmp->set)) && (xmlStrEqual(ns, tmp->ns))) { xsltGenericError(xsltGenericErrorContext, "xsl:attribute-set : use-attribute-sets recursion detected on %s\n", name); } else { #ifdef WITH_XSLT_DEBUG_ATTRIBUTES xsltGenericDebug(xsltGenericDebugContext, "Importing attribute list %s\n", tmp->set); #endif refs = xsltGetSAS(style, tmp->set, tmp->ns); if (refs == NULL) { xsltGenericError(xsltGenericErrorContext, "xsl:attribute-set : use-attribute-sets %s reference missing %s\n", name, tmp->set); } else { /* * recurse first for cleanup */ xsltResolveSASCallback(refs, style, name, ns, NULL); /* * Then merge */ xsltMergeAttrElemList(style, values, refs); /* * Then suppress the reference */ tmp->set = NULL; tmp->ns = NULL; } } } tmp = tmp->next; } } /** * xsltMergeSASCallback,: * @style: the XSLT stylesheet * * Merge an attribute set from an imported stylesheet. */ static void xsltMergeSASCallback(xsltAttrElemPtr values, xsltStylesheetPtr style, const xmlChar *name, const xmlChar *ns, ATTRIBUTE_UNUSED const xmlChar *ignored) { int ret; xsltAttrElemPtr topSet; ret = xmlHashAddEntry2(style->attributeSets, name, ns, values); if (ret < 0) { /* * Add failed, this attribute set can be removed. */ #ifdef WITH_XSLT_DEBUG_ATTRIBUTES xsltGenericDebug(xsltGenericDebugContext, "attribute set %s present already in top stylesheet" " - merging\n", name); #endif topSet = xmlHashLookup2(style->attributeSets, name, ns); if (topSet==NULL) { xsltGenericError(xsltGenericErrorContext, "xsl:attribute-set : logic error merging from imports for" " attribute-set %s\n", name); } else { topSet = xsltMergeAttrElemList(style, topSet, values); xmlHashUpdateEntry2(style->attributeSets, name, ns, topSet, NULL); } xsltFreeAttrElemList(values); #ifdef WITH_XSLT_DEBUG_ATTRIBUTES } else { xsltGenericDebug(xsltGenericDebugContext, "attribute set %s moved to top stylesheet\n", name); #endif } } /** * xsltResolveStylesheetAttributeSet: * @style: the XSLT stylesheet * * resolve the references between attribute sets. */ void xsltResolveStylesheetAttributeSet(xsltStylesheetPtr style) { xsltStylesheetPtr cur; #ifdef WITH_XSLT_DEBUG_ATTRIBUTES xsltGenericDebug(xsltGenericDebugContext, "Resolving attribute sets references\n"); #endif /* * First aggregate all the attribute sets definitions from the imports */ cur = xsltNextImport(style); while (cur != NULL) { if (cur->attributeSets != NULL) { if (style->attributeSets == NULL) { #ifdef WITH_XSLT_DEBUG_ATTRIBUTES xsltGenericDebug(xsltGenericDebugContext, "creating attribute set table\n"); #endif style->attributeSets = xmlHashCreate(10); } xmlHashScanFull(cur->attributeSets, (xmlHashScannerFull) xsltMergeSASCallback, style); /* * the attribute lists have either been migrated to style * or freed directly in xsltMergeSASCallback() */ xmlHashFree(cur->attributeSets, NULL); cur->attributeSets = NULL; } cur = xsltNextImport(cur); } /* * Then resolve all the references and computes the resulting sets */ if (style->attributeSets != NULL) { xmlHashScanFull(style->attributeSets, (xmlHashScannerFull) xsltResolveSASCallback, style); } } /** * xsltAttributeInternal: * @ctxt: a XSLT process context * @node: the current node in the source tree * @inst: the xsl:attribute element * @comp: precomputed information * @fromAttributeSet: the attribute comes from an attribute-set * * Process the xslt attribute node on the source node */ static void xsltAttributeInternal(xsltTransformContextPtr ctxt, xmlNodePtr contextNode, xmlNodePtr inst, xsltStylePreCompPtr castedComp, int fromAttributeSet) { #ifdef XSLT_REFACTORED xsltStyleItemAttributePtr comp = (xsltStyleItemAttributePtr) castedComp; #else xsltStylePreCompPtr comp = castedComp; #endif xmlNodePtr targetElem; xmlChar *prop = NULL; const xmlChar *name = NULL, *prefix = NULL, *nsName = NULL; xmlChar *value = NULL; xmlNsPtr ns = NULL; xmlAttrPtr attr; if ((ctxt == NULL) || (contextNode == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE) ) return; /* * A comp->has_name == 0 indicates that we need to skip this instruction, * since it was evaluated to be invalid already during compilation. */ if (!comp->has_name) return; /* * BIG NOTE: This previously used xsltGetSpecialNamespace() and * xsltGetNamespace(), but since both are not appropriate, we * will process namespace lookup here to avoid adding yet another * ns-lookup function to namespaces.c. */ /* * SPEC XSLT 1.0: Error cases: * - Creating nodes other than text nodes during the instantiation of * the content of the xsl:attribute element; implementations may * either signal the error or ignore the offending nodes." */ if (comp == NULL) { xsltTransformError(ctxt, NULL, inst, "Internal error in xsltAttributeInternal(): " "The XSLT 'attribute' instruction was not compiled.\n"); return; } /* * TODO: Shouldn't ctxt->insert == NULL be treated as an internal error? * So report an internal error? */ if (ctxt->insert == NULL) return; /* * SPEC XSLT 1.0: * "Adding an attribute to a node that is not an element; * implementations may either signal the error or ignore the attribute." * * TODO: I think we should signal such errors in the future, and maybe * provide an option to ignore such errors. */ targetElem = ctxt->insert; if (targetElem->type != XML_ELEMENT_NODE) return; /* * SPEC XSLT 1.0: * "Adding an attribute to an element after children have been added * to it; implementations may either signal the error or ignore the * attribute." * * TODO: We should decide whether not to report such errors or * to ignore them; note that we *ignore* if the parent is not an * element, but here we report an error. */ if (targetElem->children != NULL) { /* * NOTE: Ah! This seems to be intended to support streamed * result generation!. */ xsltTransformError(ctxt, NULL, inst, "xsl:attribute: Cannot add attributes to an " "element if children have been already added " "to the element.\n"); return; } /* * Process the name * ---------------- */ #ifdef WITH_DEBUGGER if (ctxt->debugStatus != XSLT_DEBUG_NONE) xslHandleDebugger(inst, contextNode, NULL, ctxt); #endif if (comp->name == NULL) { /* TODO: fix attr acquisition wrt to the XSLT namespace */ prop = xsltEvalAttrValueTemplate(ctxt, inst, (const xmlChar *) "name", XSLT_NAMESPACE); if (prop == NULL) { xsltTransformError(ctxt, NULL, inst, "xsl:attribute: The attribute 'name' is missing.\n"); goto error; } if (xmlValidateQName(prop, 0)) { xsltTransformError(ctxt, NULL, inst, "xsl:attribute: The effective name '%s' is not a " "valid QName.\n", prop); /* we fall through to catch any further errors, if possible */ } /* * Reject a name of "xmlns". */ if (xmlStrEqual(prop, BAD_CAST "xmlns")) { xsltTransformError(ctxt, NULL, inst, "xsl:attribute: The effective name 'xmlns' is not allowed.\n"); xmlFree(prop); goto error; } name = xsltSplitQName(ctxt->dict, prop, &prefix); xmlFree(prop); } else { /* * The "name" value was static. */ #ifdef XSLT_REFACTORED prefix = comp->nsPrefix; name = comp->name; #else name = xsltSplitQName(ctxt->dict, comp->name, &prefix); #endif } /* * Process namespace semantics * --------------------------- * * Evaluate the namespace name. */ if (comp->has_ns) { /* * The "namespace" attribute was existent. */ if (comp->ns != NULL) { /* * No AVT; just plain text for the namespace name. */ if (comp->ns[0] != 0) nsName = comp->ns; } else { xmlChar *tmpNsName; /* * Eval the AVT. */ /* TODO: check attr acquisition wrt to the XSLT namespace */ tmpNsName = xsltEvalAttrValueTemplate(ctxt, inst, (const xmlChar *) "namespace", XSLT_NAMESPACE); /* * This fixes bug #302020: The AVT might also evaluate to the * empty string; this means that the empty string also indicates * "no namespace". * SPEC XSLT 1.0: * "If the string is empty, then the expanded-name of the * attribute has a null namespace URI." */ if ((tmpNsName != NULL) && (tmpNsName[0] != 0)) nsName = xmlDictLookup(ctxt->dict, BAD_CAST tmpNsName, -1); xmlFree(tmpNsName); } if (xmlStrEqual(nsName, BAD_CAST "http://www.w3.org/2000/xmlns/")) { xsltTransformError(ctxt, NULL, inst, "xsl:attribute: Namespace http://www.w3.org/2000/xmlns/ " "forbidden.\n"); goto error; } if (xmlStrEqual(nsName, XML_XML_NAMESPACE)) { prefix = BAD_CAST "xml"; } else if (xmlStrEqual(prefix, BAD_CAST "xml")) { prefix = NULL; } } else if (prefix != NULL) { /* * SPEC XSLT 1.0: * "If the namespace attribute is not present, then the QName is * expanded into an expanded-name using the namespace declarations * in effect for the xsl:attribute element, *not* including any * default namespace declaration." */ ns = xmlSearchNs(inst->doc, inst, prefix); if (ns == NULL) { /* * Note that this is treated as an error now (checked with * Saxon, Xalan-J and MSXML). */ xsltTransformError(ctxt, NULL, inst, "xsl:attribute: The QName '%s:%s' has no " "namespace binding in scope in the stylesheet; " "this is an error, since the namespace was not " "specified by the instruction itself.\n", prefix, name); } else nsName = ns->href; } if (fromAttributeSet) { /* * This tries to ensure that xsl:attribute(s) coming * from an xsl:attribute-set won't override attribute of * literal result elements or of explicit xsl:attribute(s). * URGENT TODO: This might be buggy, since it will miss to * overwrite two equal attributes both from attribute sets. */ attr = xmlHasNsProp(targetElem, name, nsName); if (attr != NULL) return; } /* * Find/create a matching ns-decl in the result tree. */ ns = NULL; #if 0 if (0) { /* * OPTIMIZE TODO: How do we know if we are adding to a * fragment or to the result tree? * * If we are adding to a result tree fragment (i.e., not to the * actual result tree), we'll don't bother searching for the * ns-decl, but just store it in the dummy-doc of the result * tree fragment. */ if (nsName != NULL) { /* * TODO: Get the doc of @targetElem. */ ns = xsltTreeAcquireStoredNs(some doc, nsName, prefix); } } #endif if (nsName != NULL) { /* * Something about ns-prefixes: * SPEC XSLT 1.0: * "XSLT processors may make use of the prefix of the QName specified * in the name attribute when selecting the prefix used for outputting * the created attribute as XML; however, they are not required to do * so and, if the prefix is xmlns, they must not do so" */ /* * xsl:attribute can produce a scenario where the prefix is NULL, * so generate a prefix. */ if ((prefix == NULL) || xmlStrEqual(prefix, BAD_CAST "xmlns")) { xmlChar *pref = xmlStrdup(BAD_CAST "ns_1"); ns = xsltGetSpecialNamespace(ctxt, inst, nsName, pref, targetElem); xmlFree(pref); } else { ns = xsltGetSpecialNamespace(ctxt, inst, nsName, prefix, targetElem); } if (ns == NULL) { xsltTransformError(ctxt, NULL, inst, "Namespace fixup error: Failed to acquire an in-scope " "namespace binding for the generated attribute '{%s}%s'.\n", nsName, name); goto error; } } /* * Construction of the value * ------------------------- */ if (inst->children == NULL) { /* * No content. * TODO: Do we need to put the empty string in ? */ attr = xmlSetNsProp(ctxt->insert, ns, name, (const xmlChar *) ""); } else if ((inst->children->next == NULL) && ((inst->children->type == XML_TEXT_NODE) || (inst->children->type == XML_CDATA_SECTION_NODE))) { xmlNodePtr copyTxt; /* * xmlSetNsProp() will take care of duplicates. */ attr = xmlSetNsProp(ctxt->insert, ns, name, NULL); if (attr == NULL) /* TODO: report error ? */ goto error; /* * This was taken over from xsltCopyText() (transform.c). */ if (ctxt->internalized && (ctxt->insert->doc != NULL) && (ctxt->insert->doc->dict == ctxt->dict)) { copyTxt = xmlNewText(NULL); if (copyTxt == NULL) /* TODO: report error */ goto error; /* * This is a safe scenario where we don't need to lookup * the dict. */ copyTxt->content = inst->children->content; /* * Copy "disable-output-escaping" information. * TODO: Does this have any effect for attribute values * anyway? */ if (inst->children->name == xmlStringTextNoenc) copyTxt->name = xmlStringTextNoenc; } else { /* * Copy the value. */ copyTxt = xmlNewText(inst->children->content); if (copyTxt == NULL) /* TODO: report error */ goto error; } attr->children = attr->last = copyTxt; copyTxt->parent = (xmlNodePtr) attr; copyTxt->doc = attr->doc; /* * Copy "disable-output-escaping" information. * TODO: Does this have any effect for attribute values * anyway? */ if (inst->children->name == xmlStringTextNoenc) copyTxt->name = xmlStringTextNoenc; /* * since we create the attribute without content IDness must be * asserted as a second step */ if ((copyTxt->content != NULL) && (xmlIsID(attr->doc, attr->parent, attr))) xmlAddID(NULL, attr->doc, copyTxt->content, attr); } else { /* * The sequence constructor might be complex, so instantiate it. */ value = xsltEvalTemplateString(ctxt, contextNode, inst); if (value != NULL) { attr = xmlSetNsProp(ctxt->insert, ns, name, value); xmlFree(value); } else { /* * TODO: Do we have to add the empty string to the attr? * TODO: Does a value of NULL indicate an * error in xsltEvalTemplateString() ? */ attr = xmlSetNsProp(ctxt->insert, ns, name, (const xmlChar *) ""); } } error: return; } /** * xsltAttribute: * @ctxt: a XSLT process context * @node: the node in the source tree. * @inst: the xslt attribute node * @comp: precomputed information * * Process the xslt attribute node on the source node */ void xsltAttribute(xsltTransformContextPtr ctxt, xmlNodePtr node, xmlNodePtr inst, xsltStylePreCompPtr comp) { xsltAttributeInternal(ctxt, node, inst, comp, 0); } /** * xsltApplyAttributeSet: * @ctxt: the XSLT stylesheet * @node: the node in the source tree. * @inst: the attribute node "xsl:use-attribute-sets" * @attrSets: the list of QNames of the attribute-sets to be applied * * Apply the xsl:use-attribute-sets. * If @attrSets is NULL, then @inst will be used to exctract this * value. * If both, @attrSets and @inst, are NULL, then this will do nothing. */ void xsltApplyAttributeSet(xsltTransformContextPtr ctxt, xmlNodePtr node, xmlNodePtr inst, const xmlChar *attrSets) { const xmlChar *ncname = NULL; const xmlChar *prefix = NULL; const xmlChar *curstr, *endstr; xsltAttrElemPtr attrs; xsltStylesheetPtr style; if (attrSets == NULL) { if (inst == NULL) return; else { /* * Extract the value from @inst. */ if (inst->type == XML_ATTRIBUTE_NODE) { if ( ((xmlAttrPtr) inst)->children != NULL) attrSets = ((xmlAttrPtr) inst)->children->content; } if (attrSets == NULL) { /* * TODO: Return an error? */ return; } } } /* * Parse/apply the list of QNames. */ curstr = attrSets; while (*curstr != 0) { while (IS_BLANK(*curstr)) curstr++; if (*curstr == 0) break; endstr = curstr; while ((*endstr != 0) && (!IS_BLANK(*endstr))) endstr++; curstr = xmlDictLookup(ctxt->dict, curstr, endstr - curstr); if (curstr) { /* * TODO: Validate the QName. */ #ifdef WITH_XSLT_DEBUG_curstrUTES xsltGenericDebug(xsltGenericDebugContext, "apply curstrute set %s\n", curstr); #endif ncname = xsltSplitQName(ctxt->dict, curstr, &prefix); style = ctxt->style; #ifdef WITH_DEBUGGER if ((style != NULL) && (style->attributeSets != NULL) && (ctxt->debugStatus != XSLT_DEBUG_NONE)) { attrs = xmlHashLookup2(style->attributeSets, ncname, prefix); if ((attrs != NULL) && (attrs->attr != NULL)) xslHandleDebugger(attrs->attr->parent, node, NULL, ctxt); } #endif /* * Lookup the referenced curstrute-set. */ while (style != NULL) { attrs = xmlHashLookup2(style->attributeSets, ncname, prefix); while (attrs != NULL) { if (attrs->attr != NULL) { xsltAttributeInternal(ctxt, node, attrs->attr, attrs->attr->psvi, 1); } attrs = attrs->next; } style = xsltNextImport(style); } } curstr = endstr; } } /** * xsltFreeAttributeSetsHashes: * @style: an XSLT stylesheet * * Free up the memory used by attribute sets */ void xsltFreeAttributeSetsHashes(xsltStylesheetPtr style) { if (style->attributeSets != NULL) xmlHashFree((xmlHashTablePtr) style->attributeSets, (xmlHashDeallocator) xsltFreeAttrElemList); style->attributeSets = NULL; } libxslt-1.1.28/libxslt/xsltlocale.c0000664000076400007640000003333012024022316014210 00000000000000/* * xsltlocale.c: locale handling * * Reference: * RFC 3066: Tags for the Identification of Languages * http://www.ietf.org/rfc/rfc3066.txt * ISO 639-1, ISO 3166-1 * * Author: Nick Wellnhofer * winapi port: Roumen Petrov */ #define IN_LIBXSLT #include "libxslt.h" #include #include #include "xsltlocale.h" #include "xsltutils.h" #if defined(__GLIBC__) && __GLIBC__ == 2 && __GLIBC_MINOR__ <= 2 #define newlocale __newlocale #define freelocale __freelocale #define strxfrm_l __strxfrm_l #define LC_COLLATE_MASK (1 << LC_COLLATE) #endif #define TOUPPER(c) (c & ~0x20) #define TOLOWER(c) (c | 0x20) #define ISALPHA(c) ((unsigned)(TOUPPER(c) - 'A') < 26) /*without terminating null character*/ #define XSLTMAX_ISO639LANGLEN 8 #define XSLTMAX_ISO3166CNTRYLEN 8 /* - */ #define XSLTMAX_LANGTAGLEN (XSLTMAX_ISO639LANGLEN+1+XSLTMAX_ISO3166CNTRYLEN) static const xmlChar* xsltDefaultRegion(const xmlChar *localeName); #ifdef XSLT_LOCALE_WINAPI xmlRMutexPtr xsltLocaleMutex = NULL; struct xsltRFC1766Info_s { /*note typedef unsigned char xmlChar !*/ xmlChar tag[XSLTMAX_LANGTAGLEN+1]; /*note typedef LCID xsltLocale !*/ xsltLocale lcid; }; typedef struct xsltRFC1766Info_s xsltRFC1766Info; static int xsltLocaleListSize = 0; static xsltRFC1766Info *xsltLocaleList = NULL; static xsltLocale xslt_locale_WINAPI(const xmlChar *languageTag) { int k; xsltRFC1766Info *p = xsltLocaleList; for (k=0; ktag, languageTag) == 0) return p->lcid; return((xsltLocale)0); } static void xsltEnumSupportedLocales(void); #endif /** * xsltFreeLocales: * * Cleanup function for the locale support on shutdown */ void xsltFreeLocales(void) { #ifdef XSLT_LOCALE_WINAPI xmlRMutexLock(xsltLocaleMutex); xmlFree(xsltLocaleList); xsltLocaleList = NULL; xmlRMutexUnlock(xsltLocaleMutex); #endif } /** * xsltNewLocale: * @languageTag: RFC 3066 language tag * * Creates a new locale of an opaque system dependent type based on the * language tag. * * Returns the locale or NULL on error or if no matching locale was found */ xsltLocale xsltNewLocale(const xmlChar *languageTag) { #ifdef XSLT_LOCALE_XLOCALE xsltLocale locale; char localeName[XSLTMAX_LANGTAGLEN+6]; /* 6 chars for ".utf8\0" */ const xmlChar *p = languageTag; const char *region = NULL; char *q = localeName; int i, llen; /* Convert something like "pt-br" to "pt_BR.utf8" */ if (languageTag == NULL) return(NULL); for (i=0; i= xstrlen) { xsltTransformError(NULL, NULL, NULL, "xsltStrxfrm : strxfrm failed\n"); xmlFree(xstr); return(NULL); } return(xstr); #endif /* XSLT_LOCALE_NONE */ } /** * xsltLocaleStrcmp: * @locale: a locale identifier * @str1: a string transformed with xsltStrxfrm * @str2: a string transformed with xsltStrxfrm * * 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) { (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 /** * xsltCountSupportedLocales: * @lcid: not used * * callback used to count locales * * Returns TRUE */ BOOL CALLBACK xsltCountSupportedLocales(LPSTR lcid) { (void) lcid; ++xsltLocaleListSize; return(TRUE); } /** * xsltIterateSupportedLocales: * @lcid: not used * * callback used to track locales * * Returns TRUE if not at the end of the array */ BOOL CALLBACK xsltIterateSupportedLocales(LPSTR lcid) { static int count = 0; xmlChar iso639lang [XSLTMAX_ISO639LANGLEN +1]; xmlChar iso3136ctry[XSLTMAX_ISO3166CNTRYLEN+1]; int k, l; xsltRFC1766Info *p = xsltLocaleList + count; k = sscanf(lcid, "%lx", (long*)&p->lcid); if (k < 1) goto end; /*don't count terminating null character*/ k = GetLocaleInfoA(p->lcid, LOCALE_SISO639LANGNAME , iso639lang , sizeof(iso639lang )); if (--k < 1) goto end; l = GetLocaleInfoA(p->lcid, LOCALE_SISO3166CTRYNAME, iso3136ctry, sizeof(iso3136ctry)); if (--l < 1) goto end; { /*fill results*/ xmlChar *q = p->tag; memcpy(q, iso639lang, k); q += k; *q++ = '-'; memcpy(q, iso3136ctry, l); q += l; *q = '\0'; } ++count; end: return((count < xsltLocaleListSize) ? TRUE : FALSE); } static void xsltEnumSupportedLocales(void) { xmlRMutexLock(xsltLocaleMutex); if (xsltLocaleListSize <= 0) { size_t len; EnumSystemLocalesA(xsltCountSupportedLocales, LCID_SUPPORTED); len = xsltLocaleListSize * sizeof(xsltRFC1766Info); xsltLocaleList = xmlMalloc(len); memset(xsltLocaleList, 0, len); EnumSystemLocalesA(xsltIterateSupportedLocales, LCID_SUPPORTED); } xmlRMutexUnlock(xsltLocaleMutex); } #endif /*def XSLT_LOCALE_WINAPI*/ libxslt-1.1.28/libxslt/attrvt.c0000664000076400007640000002320512024022216013361 00000000000000/* * attrvt.c: Implementation of the XSL Transformation 1.0 engine * attribute value template handling part. * * References: * http://www.w3.org/TR/1999/REC-xslt-19991116 * * Michael Kay "XSLT Programmer's Reference" pp 637-643 * Writing Multiple Output Files * * See Copyright for the status of this software. * * daniel@veillard.com */ #define IN_LIBXSLT #include "libxslt.h" #include #include #include #include #include #include "xslt.h" #include "xsltutils.h" #include "xsltInternals.h" #include "templates.h" #ifdef WITH_XSLT_DEBUG #define WITH_XSLT_DEBUG_AVT #endif #define MAX_AVT_SEG 10 typedef struct _xsltAttrVT xsltAttrVT; typedef xsltAttrVT *xsltAttrVTPtr; struct _xsltAttrVT { struct _xsltAttrVT *next; /* next xsltAttrVT */ int nb_seg; /* Number of segments */ int max_seg; /* max capacity before re-alloc needed */ int strstart; /* is the start a string */ /* * the namespaces in scope */ xmlNsPtr *nsList; int nsNr; /* * the content is an alternate of string and xmlXPathCompExprPtr */ void *segments[MAX_AVT_SEG]; }; /** * xsltNewAttrVT: * @style: a XSLT process context * * Build a new xsltAttrVT structure * * Returns the structure or NULL in case of error */ static xsltAttrVTPtr xsltNewAttrVT(xsltStylesheetPtr style) { xsltAttrVTPtr cur; cur = (xsltAttrVTPtr) xmlMalloc(sizeof(xsltAttrVT)); if (cur == NULL) { xsltTransformError(NULL, style, NULL, "xsltNewAttrVTPtr : malloc failed\n"); if (style != NULL) style->errors++; return(NULL); } memset(cur, 0, sizeof(xsltAttrVT)); cur->nb_seg = 0; cur->max_seg = MAX_AVT_SEG; cur->strstart = 0; cur->next = style->attVTs; /* * Note: this pointer may be changed by a re-alloc within xsltCompileAttr, * so that code may change the stylesheet pointer also! */ style->attVTs = (xsltAttrVTPtr) cur; return(cur); } /** * xsltFreeAttrVT: * @avt: pointer to an xsltAttrVT structure * * Free up the memory associated to the attribute value template */ static void xsltFreeAttrVT(xsltAttrVTPtr avt) { int i; if (avt == NULL) return; if (avt->strstart == 1) { for (i = 0;i < avt->nb_seg; i += 2) if (avt->segments[i] != NULL) xmlFree((xmlChar *) avt->segments[i]); for (i = 1;i < avt->nb_seg; i += 2) xmlXPathFreeCompExpr((xmlXPathCompExprPtr) avt->segments[i]); } else { for (i = 0;i < avt->nb_seg; i += 2) xmlXPathFreeCompExpr((xmlXPathCompExprPtr) avt->segments[i]); for (i = 1;i < avt->nb_seg; i += 2) if (avt->segments[i] != NULL) xmlFree((xmlChar *) avt->segments[i]); } if (avt->nsList != NULL) xmlFree(avt->nsList); xmlFree(avt); } /** * xsltFreeAVTList: * @avt: pointer to an list of AVT structures * * Free up the memory associated to the attribute value templates */ void xsltFreeAVTList(void *avt) { xsltAttrVTPtr cur = (xsltAttrVTPtr) avt, next; while (cur != NULL) { next = cur->next; xsltFreeAttrVT(cur); cur = next; } } /** * xsltSetAttrVTsegment: * @ avt: pointer to an xsltAttrVT structure * @ val: the value to be set to the next available segment * * Within xsltCompileAttr there are several places where a value * needs to be added to the 'segments' array within the xsltAttrVT * structure, and at each place the allocated size may have to be * re-allocated. This routine takes care of that situation. * * Returns the avt pointer, which may have been changed by a re-alloc */ static xsltAttrVTPtr xsltSetAttrVTsegment(xsltAttrVTPtr avt, void *val) { if (avt->nb_seg >= avt->max_seg) { avt = (xsltAttrVTPtr) xmlRealloc(avt, sizeof(xsltAttrVT) + avt->max_seg * sizeof(void *)); if (avt == NULL) { return NULL; } memset(&avt->segments[avt->nb_seg], 0, MAX_AVT_SEG*sizeof(void *)); avt->max_seg += MAX_AVT_SEG; } avt->segments[avt->nb_seg++] = val; return avt; } /** * xsltCompileAttr: * @style: a XSLT process context * @attr: the attribute coming from the stylesheet. * * Precompile an attribute in a stylesheet, basically it checks if it is * an attrubute value template, and if yes establish some structures needed * to process it at transformation time. */ void xsltCompileAttr(xsltStylesheetPtr style, xmlAttrPtr attr) { const xmlChar *str; const xmlChar *cur; xmlChar *ret = NULL; xmlChar *expr = NULL; xsltAttrVTPtr avt; int i = 0, lastavt = 0; if ((style == NULL) || (attr == NULL) || (attr->children == NULL)) return; if ((attr->children->type != XML_TEXT_NODE) || (attr->children->next != NULL)) { xsltTransformError(NULL, style, attr->parent, "Attribute '%s': The content is expected to be a single text " "node when compiling an AVT.\n", attr->name); style->errors++; return; } str = attr->children->content; if ((xmlStrchr(str, '{') == NULL) && (xmlStrchr(str, '}') == NULL)) return; #ifdef WITH_XSLT_DEBUG_AVT xsltGenericDebug(xsltGenericDebugContext, "Found AVT %s: %s\n", attr->name, str); #endif if (attr->psvi != NULL) { #ifdef WITH_XSLT_DEBUG_AVT xsltGenericDebug(xsltGenericDebugContext, "AVT %s: already compiled\n", attr->name); #endif return; } /* * Create a new AVT object. */ avt = xsltNewAttrVT(style); if (avt == NULL) return; attr->psvi = avt; avt->nsList = xmlGetNsList(attr->doc, attr->parent); if (avt->nsList != NULL) { while (avt->nsList[i] != NULL) i++; } avt->nsNr = i; cur = str; while (*cur != 0) { if (*cur == '{') { if (*(cur+1) == '{') { /* escaped '{' */ cur++; ret = xmlStrncat(ret, str, cur - str); cur++; str = cur; continue; } if (*(cur+1) == '}') { /* skip empty AVT */ ret = xmlStrncat(ret, str, cur - str); cur += 2; str = cur; continue; } if ((ret != NULL) || (cur - str > 0)) { ret = xmlStrncat(ret, str, cur - str); str = cur; if (avt->nb_seg == 0) avt->strstart = 1; if ((avt = xsltSetAttrVTsegment(avt, (void *) ret)) == NULL) goto error; ret = NULL; lastavt = 0; } cur++; while ((*cur != 0) && (*cur != '}')) { /* Need to check for literal (bug539741) */ if ((*cur == '\'') || (*cur == '"')) { char delim = *(cur++); while ((*cur != 0) && (*cur != delim)) cur++; if (*cur != 0) cur++; /* skip the ending delimiter */ } else cur++; } if (*cur == 0) { xsltTransformError(NULL, style, attr->parent, "Attribute '%s': The AVT has an unmatched '{'.\n", attr->name); style->errors++; goto error; } str++; expr = xmlStrndup(str, cur - str); if (expr == NULL) { /* * TODO: What needs to be done here? */ XSLT_TODO goto error; } else { xmlXPathCompExprPtr comp; comp = xsltXPathCompile(style, expr); if (comp == NULL) { xsltTransformError(NULL, style, attr->parent, "Attribute '%s': Failed to compile the expression " "'%s' in the AVT.\n", attr->name, expr); style->errors++; goto error; } if (avt->nb_seg == 0) avt->strstart = 0; if (lastavt == 1) { if ((avt = xsltSetAttrVTsegment(avt, NULL)) == NULL) goto error; } if ((avt = xsltSetAttrVTsegment(avt, (void *) comp)) == NULL) goto error; lastavt = 1; xmlFree(expr); expr = NULL; } cur++; str = cur; } else if (*cur == '}') { cur++; if (*cur == '}') { /* escaped '}' */ ret = xmlStrncat(ret, str, cur - str); cur++; str = cur; continue; } else { xsltTransformError(NULL, style, attr->parent, "Attribute '%s': The AVT has an unmatched '}'.\n", attr->name); goto error; } } else cur++; } if ((ret != NULL) || (cur - str > 0)) { ret = xmlStrncat(ret, str, cur - str); str = cur; if (avt->nb_seg == 0) avt->strstart = 1; if ((avt = xsltSetAttrVTsegment(avt, (void *) ret)) == NULL) goto error; ret = NULL; } error: if (avt == NULL) { xsltTransformError(NULL, style, attr->parent, "xsltCompileAttr: malloc problem\n"); } else { if (attr->psvi != avt) { /* may have changed from realloc */ attr->psvi = avt; /* * This is a "hack", but I can't see any clean method of * doing it. If a re-alloc has taken place, then the pointer * for this AVT may have changed. style->attVTs was set by * xsltNewAttrVT, so it needs to be re-set to the new value! */ style->attVTs = avt; } } if (ret != NULL) xmlFree(ret); if (expr != NULL) xmlFree(expr); } /** * xsltEvalAVT: * @ctxt: the XSLT transformation context * @avt: the prevompiled attribute value template info * @node: the node hosting the attribute * * Process the given AVT, and return the new string value. * * Returns the computed string value or NULL, must be deallocated by the * caller. */ xmlChar * xsltEvalAVT(xsltTransformContextPtr ctxt, void *avt, xmlNodePtr node) { xmlChar *ret = NULL, *tmp; xmlXPathCompExprPtr comp; xsltAttrVTPtr cur = (xsltAttrVTPtr) avt; int i; int str; if ((ctxt == NULL) || (avt == NULL) || (node == NULL)) return(NULL); str = cur->strstart; for (i = 0;i < cur->nb_seg;i++) { if (str) { ret = xmlStrcat(ret, (const xmlChar *) cur->segments[i]); } else { comp = (xmlXPathCompExprPtr) cur->segments[i]; tmp = xsltEvalXPathStringNs(ctxt, comp, cur->nsNr, cur->nsList); if (tmp != NULL) { if (ret != NULL) { ret = xmlStrcat(ret, tmp); xmlFree(tmp); } else { ret = tmp; } } } str = !str; } return(ret); } libxslt-1.1.28/libxslt/transform.c0000664000076400007640000056234112034711124014065 00000000000000/* * transform.c: Implementation of the XSL Transformation 1.0 engine * transform part, i.e. applying a Stylesheet to a document * * References: * http://www.w3.org/TR/1999/REC-xslt-19991116 * * Michael Kay "XSLT Programmer's Reference" pp 637-643 * Writing Multiple Output Files * * XSLT-1.1 Working Draft * http://www.w3.org/TR/xslt11#multiple-output * * See Copyright for the status of this software. * * daniel@veillard.com */ #define IN_LIBXSLT #include "libxslt.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "xslt.h" #include "xsltInternals.h" #include "xsltutils.h" #include "pattern.h" #include "transform.h" #include "variables.h" #include "numbersInternals.h" #include "namespaces.h" #include "attributes.h" #include "templates.h" #include "imports.h" #include "keys.h" #include "documents.h" #include "extensions.h" #include "extra.h" #include "preproc.h" #include "security.h" #ifdef WITH_XSLT_DEBUG #define WITH_XSLT_DEBUG_EXTRA #define WITH_XSLT_DEBUG_PROCESS #endif #define XSLT_GENERATE_HTML_DOCTYPE #ifdef XSLT_GENERATE_HTML_DOCTYPE static int xsltGetHTMLIDs(const xmlChar *version, const xmlChar **publicID, const xmlChar **systemID); #endif int xsltMaxDepth = 3000; int xsltMaxVars = 15000; /* * Useful macros */ #ifndef FALSE # define FALSE (0 == 1) # define TRUE (!FALSE) #endif #define IS_BLANK_NODE(n) \ (((n)->type == XML_TEXT_NODE) && (xsltIsBlank((n)->content))) /* * Forward declarations */ static xmlNsPtr xsltCopyNamespaceListInternal(xmlNodePtr node, xmlNsPtr cur); static xmlNodePtr xsltCopyTreeInternal(xsltTransformContextPtr ctxt, xmlNodePtr invocNode, xmlNodePtr node, xmlNodePtr insert, int isLRE, int topElemVisited); static void xsltApplySequenceConstructor(xsltTransformContextPtr ctxt, xmlNodePtr contextNode, xmlNodePtr list, xsltTemplatePtr templ); static void xsltApplyXSLTTemplate(xsltTransformContextPtr ctxt, xmlNodePtr contextNode, xmlNodePtr list, xsltTemplatePtr templ, xsltStackElemPtr withParams); /** * templPush: * @ctxt: the transformation context * @value: the template to push on the stack * * Push a template on the stack * * Returns the new index in the stack or 0 in case of error */ static int templPush(xsltTransformContextPtr ctxt, xsltTemplatePtr value) { if (ctxt->templMax == 0) { ctxt->templMax = 4; ctxt->templTab = (xsltTemplatePtr *) xmlMalloc(ctxt->templMax * sizeof(ctxt->templTab[0])); if (ctxt->templTab == NULL) { xmlGenericError(xmlGenericErrorContext, "malloc failed !\n"); return (0); } } else if (ctxt->templNr >= ctxt->templMax) { ctxt->templMax *= 2; ctxt->templTab = (xsltTemplatePtr *) xmlRealloc(ctxt->templTab, ctxt->templMax * sizeof(ctxt->templTab[0])); if (ctxt->templTab == NULL) { xmlGenericError(xmlGenericErrorContext, "realloc failed !\n"); return (0); } } ctxt->templTab[ctxt->templNr] = value; ctxt->templ = value; return (ctxt->templNr++); } /** * templPop: * @ctxt: the transformation context * * Pop a template value from the stack * * Returns the stored template value */ static xsltTemplatePtr templPop(xsltTransformContextPtr ctxt) { xsltTemplatePtr ret; if (ctxt->templNr <= 0) return (0); ctxt->templNr--; if (ctxt->templNr > 0) ctxt->templ = ctxt->templTab[ctxt->templNr - 1]; else ctxt->templ = (xsltTemplatePtr) 0; ret = ctxt->templTab[ctxt->templNr]; ctxt->templTab[ctxt->templNr] = 0; return (ret); } /** * xsltLocalVariablePop: * @ctxt: the transformation context * @limitNr: number of variables which should remain * @level: the depth in the xsl:template's tree * * Pops all variable values at the given @depth from the stack. * * Returns the stored variable value * **NOTE:** * This is an internal routine and should not be called by users! */ void xsltLocalVariablePop(xsltTransformContextPtr ctxt, int limitNr, int level) { xsltStackElemPtr variable; if (ctxt->varsNr <= 0) return; do { if (ctxt->varsNr <= limitNr) break; variable = ctxt->varsTab[ctxt->varsNr - 1]; if (variable->level <= level) break; if (variable->level >= 0) xsltFreeStackElemList(variable); ctxt->varsNr--; } while (ctxt->varsNr != 0); if (ctxt->varsNr > 0) ctxt->vars = ctxt->varsTab[ctxt->varsNr - 1]; else ctxt->vars = NULL; } /** * xsltTemplateParamsCleanup: * * Removes xsl:param and xsl:with-param items from the * variable-stack. Only xsl:with-param items are not freed. */ static void xsltTemplateParamsCleanup(xsltTransformContextPtr ctxt) { xsltStackElemPtr param; for (; ctxt->varsNr > ctxt->varsBase; ctxt->varsNr--) { param = ctxt->varsTab[ctxt->varsNr -1]; /* * Free xsl:param items. * xsl:with-param items will have a level of -1 or -2. */ if (param->level >= 0) { xsltFreeStackElemList(param); } } if (ctxt->varsNr > 0) ctxt->vars = ctxt->varsTab[ctxt->varsNr - 1]; else ctxt->vars = NULL; } /** * profPush: * @ctxt: the transformation context * @value: the profiling value to push on the stack * * Push a profiling value on the stack * * Returns the new index in the stack or 0 in case of error */ static int profPush(xsltTransformContextPtr ctxt, long value) { if (ctxt->profMax == 0) { ctxt->profMax = 4; ctxt->profTab = (long *) xmlMalloc(ctxt->profMax * sizeof(ctxt->profTab[0])); if (ctxt->profTab == NULL) { xmlGenericError(xmlGenericErrorContext, "malloc failed !\n"); return (0); } } else if (ctxt->profNr >= ctxt->profMax) { ctxt->profMax *= 2; ctxt->profTab = (long *) xmlRealloc(ctxt->profTab, ctxt->profMax * sizeof(ctxt->profTab[0])); if (ctxt->profTab == NULL) { xmlGenericError(xmlGenericErrorContext, "realloc failed !\n"); return (0); } } ctxt->profTab[ctxt->profNr] = value; ctxt->prof = value; return (ctxt->profNr++); } /** * profPop: * @ctxt: the transformation context * * Pop a profiling value from the stack * * Returns the stored profiling value */ static long profPop(xsltTransformContextPtr ctxt) { long ret; if (ctxt->profNr <= 0) return (0); ctxt->profNr--; if (ctxt->profNr > 0) ctxt->prof = ctxt->profTab[ctxt->profNr - 1]; else ctxt->prof = (long) 0; ret = ctxt->profTab[ctxt->profNr]; ctxt->profTab[ctxt->profNr] = 0; return (ret); } static void profCallgraphAdd(xsltTemplatePtr templ, xsltTemplatePtr parent) { int i; if (templ->templMax == 0) { templ->templMax = 4; templ->templCalledTab = (xsltTemplatePtr *) xmlMalloc(templ->templMax * sizeof(templ->templCalledTab[0])); templ->templCountTab = (int *) xmlMalloc(templ->templMax * sizeof(templ->templCountTab[0])); if (templ->templCalledTab == NULL || templ->templCountTab == NULL) { xmlGenericError(xmlGenericErrorContext, "malloc failed !\n"); return; } } else if (templ->templNr >= templ->templMax) { templ->templMax *= 2; templ->templCalledTab = (xsltTemplatePtr *) xmlRealloc(templ->templCalledTab, templ->templMax * sizeof(templ->templCalledTab[0])); templ->templCountTab = (int *) xmlRealloc(templ->templCountTab, templ->templMax * sizeof(templ->templCountTab[0])); if (templ->templCalledTab == NULL || templ->templCountTab == NULL) { xmlGenericError(xmlGenericErrorContext, "realloc failed !\n"); return; } } for (i = 0; i < templ->templNr; i++) { if (templ->templCalledTab[i] == parent) { templ->templCountTab[i]++; break; } } if (i == templ->templNr) { /* not found, add new one */ templ->templCalledTab[templ->templNr] = parent; templ->templCountTab[templ->templNr] = 1; templ->templNr++; } } /************************************************************************ * * * XInclude default settings * * * ************************************************************************/ static int xsltDoXIncludeDefault = 0; /** * xsltSetXIncludeDefault: * @xinclude: whether to do XInclude processing * * Set whether XInclude should be processed on document being loaded by default */ void xsltSetXIncludeDefault(int xinclude) { xsltDoXIncludeDefault = (xinclude != 0); } /** * xsltGetXIncludeDefault: * * Provides the default state for XInclude processing * * Returns 0 if there is no processing 1 otherwise */ int xsltGetXIncludeDefault(void) { return(xsltDoXIncludeDefault); } unsigned long xsltDefaultTrace = (unsigned long) XSLT_TRACE_ALL; /** * xsltDebugSetDefaultTrace: * @val: tracing level mask * * Set the default debug tracing level mask */ void xsltDebugSetDefaultTrace(xsltDebugTraceCodes val) { xsltDefaultTrace = val; } /** * xsltDebugGetDefaultTrace: * * Get the current default debug tracing level mask * * Returns the current default debug tracing level mask */ xsltDebugTraceCodes xsltDebugGetDefaultTrace() { return xsltDefaultTrace; } /************************************************************************ * * * Handling of Transformation Contexts * * * ************************************************************************/ static xsltTransformCachePtr xsltTransformCacheCreate(void) { xsltTransformCachePtr ret; ret = (xsltTransformCachePtr) xmlMalloc(sizeof(xsltTransformCache)); if (ret == NULL) { xsltTransformError(NULL, NULL, NULL, "xsltTransformCacheCreate : malloc failed\n"); return(NULL); } memset(ret, 0, sizeof(xsltTransformCache)); return(ret); } static void xsltTransformCacheFree(xsltTransformCachePtr cache) { if (cache == NULL) return; /* * Free tree fragments. */ if (cache->RVT) { xmlDocPtr tmp, cur = cache->RVT; while (cur) { tmp = cur; cur = (xmlDocPtr) cur->next; if (tmp->_private != NULL) { /* * Tree the document info. */ xsltFreeDocumentKeys((xsltDocumentPtr) tmp->_private); xmlFree(tmp->_private); } xmlFreeDoc(tmp); } } /* * Free vars/params. */ if (cache->stackItems) { xsltStackElemPtr tmp, cur = cache->stackItems; while (cur) { tmp = cur; cur = cur->next; /* * REVISIT TODO: Should be call a destruction-function * instead? */ xmlFree(tmp); } } xmlFree(cache); } /** * xsltNewTransformContext: * @style: a parsed XSLT stylesheet * @doc: the input document * * Create a new XSLT TransformContext * * Returns the newly allocated xsltTransformContextPtr or NULL in case of error */ xsltTransformContextPtr xsltNewTransformContext(xsltStylesheetPtr style, xmlDocPtr doc) { xsltTransformContextPtr cur; xsltDocumentPtr docu; int i; xsltInitGlobals(); cur = (xsltTransformContextPtr) xmlMalloc(sizeof(xsltTransformContext)); if (cur == NULL) { xsltTransformError(NULL, NULL, (xmlNodePtr)doc, "xsltNewTransformContext : malloc failed\n"); return(NULL); } memset(cur, 0, sizeof(xsltTransformContext)); cur->cache = xsltTransformCacheCreate(); if (cur->cache == NULL) goto internal_err; /* * setup of the dictionary must be done early as some of the * processing later like key handling may need it. */ cur->dict = xmlDictCreateSub(style->dict); cur->internalized = ((style->internalized) && (cur->dict != NULL)); #ifdef WITH_XSLT_DEBUG xsltGenericDebug(xsltGenericDebugContext, "Creating sub-dictionary from stylesheet for transformation\n"); #endif /* * initialize the template stack */ cur->templTab = (xsltTemplatePtr *) xmlMalloc(10 * sizeof(xsltTemplatePtr)); if (cur->templTab == NULL) { xsltTransformError(NULL, NULL, (xmlNodePtr) doc, "xsltNewTransformContext: out of memory\n"); goto internal_err; } cur->templNr = 0; cur->templMax = 5; cur->templ = NULL; cur->maxTemplateDepth = xsltMaxDepth; /* * initialize the variables stack */ cur->varsTab = (xsltStackElemPtr *) xmlMalloc(10 * sizeof(xsltStackElemPtr)); if (cur->varsTab == NULL) { xmlGenericError(xmlGenericErrorContext, "xsltNewTransformContext: out of memory\n"); goto internal_err; } cur->varsNr = 0; cur->varsMax = 10; cur->vars = NULL; cur->varsBase = 0; cur->maxTemplateVars = xsltMaxVars; /* * the profiling stack is not initialized by default */ cur->profTab = NULL; cur->profNr = 0; cur->profMax = 0; cur->prof = 0; cur->style = style; xmlXPathInit(); cur->xpathCtxt = xmlXPathNewContext(doc); if (cur->xpathCtxt == NULL) { xsltTransformError(NULL, NULL, (xmlNodePtr) doc, "xsltNewTransformContext : xmlXPathNewContext failed\n"); goto internal_err; } /* * Create an XPath cache. */ if (xmlXPathContextSetCache(cur->xpathCtxt, 1, -1, 0) == -1) goto internal_err; /* * Initialize the extras array */ if (style->extrasNr != 0) { cur->extrasMax = style->extrasNr + 20; cur->extras = (xsltRuntimeExtraPtr) xmlMalloc(cur->extrasMax * sizeof(xsltRuntimeExtra)); if (cur->extras == NULL) { xmlGenericError(xmlGenericErrorContext, "xsltNewTransformContext: out of memory\n"); goto internal_err; } cur->extrasNr = style->extrasNr; for (i = 0;i < cur->extrasMax;i++) { cur->extras[i].info = NULL; cur->extras[i].deallocate = NULL; cur->extras[i].val.ptr = NULL; } } else { cur->extras = NULL; cur->extrasNr = 0; cur->extrasMax = 0; } XSLT_REGISTER_VARIABLE_LOOKUP(cur); XSLT_REGISTER_FUNCTION_LOOKUP(cur); cur->xpathCtxt->nsHash = style->nsHash; /* * Initialize the registered external modules */ xsltInitCtxtExts(cur); /* * Setup document element ordering for later efficiencies * (bug 133289) */ if (xslDebugStatus == XSLT_DEBUG_NONE) xmlXPathOrderDocElems(doc); /* * Must set parserOptions before calling xsltNewDocument * (bug 164530) */ cur->parserOptions = XSLT_PARSE_OPTIONS; docu = xsltNewDocument(cur, doc); if (docu == NULL) { xsltTransformError(cur, NULL, (xmlNodePtr)doc, "xsltNewTransformContext : xsltNewDocument failed\n"); goto internal_err; } docu->main = 1; cur->document = docu; cur->inst = NULL; cur->outputFile = NULL; cur->sec = xsltGetDefaultSecurityPrefs(); cur->debugStatus = xslDebugStatus; cur->traceCode = (unsigned long*) &xsltDefaultTrace; cur->xinclude = xsltGetXIncludeDefault(); cur->keyInitLevel = 0; return(cur); internal_err: if (cur != NULL) xsltFreeTransformContext(cur); return(NULL); } /** * xsltFreeTransformContext: * @ctxt: an XSLT parser context * * Free up the memory allocated by @ctxt */ void xsltFreeTransformContext(xsltTransformContextPtr ctxt) { if (ctxt == NULL) return; /* * Shutdown the extension modules associated to the stylesheet * used if needed. */ xsltShutdownCtxtExts(ctxt); if (ctxt->xpathCtxt != NULL) { ctxt->xpathCtxt->nsHash = NULL; xmlXPathFreeContext(ctxt->xpathCtxt); } if (ctxt->templTab != NULL) xmlFree(ctxt->templTab); if (ctxt->varsTab != NULL) xmlFree(ctxt->varsTab); if (ctxt->profTab != NULL) xmlFree(ctxt->profTab); if ((ctxt->extrasNr > 0) && (ctxt->extras != NULL)) { int i; for (i = 0;i < ctxt->extrasNr;i++) { if ((ctxt->extras[i].deallocate != NULL) && (ctxt->extras[i].info != NULL)) ctxt->extras[i].deallocate(ctxt->extras[i].info); } xmlFree(ctxt->extras); } xsltFreeGlobalVariables(ctxt); xsltFreeDocuments(ctxt); xsltFreeCtxtExts(ctxt); xsltFreeRVTs(ctxt); xsltTransformCacheFree(ctxt->cache); xmlDictFree(ctxt->dict); #ifdef WITH_XSLT_DEBUG xsltGenericDebug(xsltGenericDebugContext, "freeing transformation dictionary\n"); #endif memset(ctxt, -1, sizeof(xsltTransformContext)); xmlFree(ctxt); } /************************************************************************ * * * Copy of Nodes in an XSLT fashion * * * ************************************************************************/ xmlNodePtr xsltCopyTree(xsltTransformContextPtr ctxt, xmlNodePtr node, xmlNodePtr insert, int literal); /** * xsltAddChild: * @parent: the parent node * @cur: the child node * * Wrapper version of xmlAddChild with a more consistent behaviour on * error. One expect the use to be child = xsltAddChild(parent, child); * and the routine will take care of not leaking on errors or node merge * * Returns the child is successfully attached or NULL if merged or freed */ static xmlNodePtr xsltAddChild(xmlNodePtr parent, xmlNodePtr cur) { xmlNodePtr ret; if ((cur == NULL) || (parent == NULL)) return(NULL); if (parent == NULL) { xmlFreeNode(cur); return(NULL); } ret = xmlAddChild(parent, cur); return(ret); } /** * xsltAddTextString: * @ctxt: a XSLT process context * @target: the text node where the text will be attached * @string: the text string * @len: the string length in byte * * Extend the current text node with the new string, it handles coalescing * * Returns: the text node */ static xmlNodePtr xsltAddTextString(xsltTransformContextPtr ctxt, xmlNodePtr target, const xmlChar *string, int len) { /* * optimization */ if ((len <= 0) || (string == NULL) || (target == NULL)) return(target); if (ctxt->lasttext == target->content) { if (ctxt->lasttuse + len >= ctxt->lasttsize) { xmlChar *newbuf; int size; size = ctxt->lasttsize + len + 100; size *= 2; newbuf = (xmlChar *) xmlRealloc(target->content,size); if (newbuf == NULL) { xsltTransformError(ctxt, NULL, target, "xsltCopyText: text allocation failed\n"); return(NULL); } ctxt->lasttsize = size; ctxt->lasttext = newbuf; target->content = newbuf; } memcpy(&(target->content[ctxt->lasttuse]), string, len); ctxt->lasttuse += len; target->content[ctxt->lasttuse] = 0; } else { xmlNodeAddContent(target, string); ctxt->lasttext = target->content; len = xmlStrlen(target->content); ctxt->lasttsize = len; ctxt->lasttuse = len; } return(target); } /** * xsltCopyTextString: * @ctxt: a XSLT process context * @target: the element where the text will be attached * @string: the text string * @noescape: should disable-escaping be activated for this text node. * * Adds @string to a newly created or an existent text node child of * @target. * * Returns: the text node, where the text content of @cur is copied to. * NULL in case of API or internal errors. */ xmlNodePtr xsltCopyTextString(xsltTransformContextPtr ctxt, xmlNodePtr target, const xmlChar *string, int noescape) { xmlNodePtr copy; int len; if (string == NULL) return(NULL); #ifdef WITH_XSLT_DEBUG_PROCESS XSLT_TRACE(ctxt,XSLT_TRACE_COPY_TEXT,xsltGenericDebug(xsltGenericDebugContext, "xsltCopyTextString: copy text %s\n", string)); #endif /* * Play safe and reset the merging mechanism for every new * target node. */ if ((target == NULL) || (target->children == NULL)) { ctxt->lasttext = NULL; } /* handle coalescing of text nodes here */ len = xmlStrlen(string); if ((ctxt->type == XSLT_OUTPUT_XML) && (ctxt->style->cdataSection != NULL) && (target != NULL) && (target->type == XML_ELEMENT_NODE) && (((target->ns == NULL) && (xmlHashLookup2(ctxt->style->cdataSection, target->name, NULL) != NULL)) || ((target->ns != NULL) && (xmlHashLookup2(ctxt->style->cdataSection, target->name, target->ns->href) != NULL)))) { /* * Process "cdata-section-elements". */ if ((target->last != NULL) && (target->last->type == XML_CDATA_SECTION_NODE)) { return(xsltAddTextString(ctxt, target->last, string, len)); } copy = xmlNewCDataBlock(ctxt->output, string, len); } else if (noescape) { /* * Process "disable-output-escaping". */ if ((target != NULL) && (target->last != NULL) && (target->last->type == XML_TEXT_NODE) && (target->last->name == xmlStringTextNoenc)) { return(xsltAddTextString(ctxt, target->last, string, len)); } copy = xmlNewTextLen(string, len); if (copy != NULL) copy->name = xmlStringTextNoenc; } else { /* * Default processing. */ if ((target != NULL) && (target->last != NULL) && (target->last->type == XML_TEXT_NODE) && (target->last->name == xmlStringText)) { return(xsltAddTextString(ctxt, target->last, string, len)); } copy = xmlNewTextLen(string, len); } if (copy != NULL) { if (target != NULL) copy = xsltAddChild(target, copy); ctxt->lasttext = copy->content; ctxt->lasttsize = len; ctxt->lasttuse = len; } else { xsltTransformError(ctxt, NULL, target, "xsltCopyTextString: text copy failed\n"); ctxt->lasttext = NULL; } return(copy); } /** * xsltCopyText: * @ctxt: a XSLT process context * @target: the element where the text will be attached * @cur: the text or CDATA node * @interned: the string is in the target doc dictionary * * Copy the text content of @cur and append it to @target's children. * * Returns: the text node, where the text content of @cur is copied to. * NULL in case of API or internal errors. */ static xmlNodePtr xsltCopyText(xsltTransformContextPtr ctxt, xmlNodePtr target, xmlNodePtr cur, int interned) { xmlNodePtr copy; if ((cur->type != XML_TEXT_NODE) && (cur->type != XML_CDATA_SECTION_NODE)) return(NULL); if (cur->content == NULL) return(NULL); #ifdef WITH_XSLT_DEBUG_PROCESS if (cur->type == XML_CDATA_SECTION_NODE) { XSLT_TRACE(ctxt,XSLT_TRACE_COPY_TEXT,xsltGenericDebug(xsltGenericDebugContext, "xsltCopyText: copy CDATA text %s\n", cur->content)); } else if (cur->name == xmlStringTextNoenc) { XSLT_TRACE(ctxt,XSLT_TRACE_COPY_TEXT,xsltGenericDebug(xsltGenericDebugContext, "xsltCopyText: copy unescaped text %s\n", cur->content)); } else { XSLT_TRACE(ctxt,XSLT_TRACE_COPY_TEXT,xsltGenericDebug(xsltGenericDebugContext, "xsltCopyText: copy text %s\n", cur->content)); } #endif /* * Play save and reset the merging mechanism for every new * target node. */ if ((target == NULL) || (target->children == NULL)) { ctxt->lasttext = NULL; } if ((ctxt->style->cdataSection != NULL) && (ctxt->type == XSLT_OUTPUT_XML) && (target != NULL) && (target->type == XML_ELEMENT_NODE) && (((target->ns == NULL) && (xmlHashLookup2(ctxt->style->cdataSection, target->name, NULL) != NULL)) || ((target->ns != NULL) && (xmlHashLookup2(ctxt->style->cdataSection, target->name, target->ns->href) != NULL)))) { /* * Process "cdata-section-elements". */ /* * OPTIMIZE TODO: xsltCopyText() is also used for attribute content. */ /* * TODO: Since this doesn't merge adjacent CDATA-section nodes, * we'll get: . * TODO: Reported in #321505. */ if ((target->last != NULL) && (target->last->type == XML_CDATA_SECTION_NODE)) { /* * Append to existing CDATA-section node. */ copy = xsltAddTextString(ctxt, target->last, cur->content, xmlStrlen(cur->content)); goto exit; } else { unsigned int len; len = xmlStrlen(cur->content); copy = xmlNewCDataBlock(ctxt->output, cur->content, len); if (copy == NULL) goto exit; ctxt->lasttext = copy->content; ctxt->lasttsize = len; ctxt->lasttuse = len; } } else if ((target != NULL) && (target->last != NULL) && /* both escaped or both non-escaped text-nodes */ (((target->last->type == XML_TEXT_NODE) && (target->last->name == cur->name)) || /* non-escaped text nodes and CDATA-section nodes */ (((target->last->type == XML_CDATA_SECTION_NODE) && (cur->name == xmlStringTextNoenc))))) { /* * we are appending to an existing text node */ copy = xsltAddTextString(ctxt, target->last, cur->content, xmlStrlen(cur->content)); goto exit; } else if ((interned) && (target != NULL) && (target->doc != NULL) && (target->doc->dict == ctxt->dict)) { /* * TODO: DO we want to use this also for "text" output? */ copy = xmlNewTextLen(NULL, 0); if (copy == NULL) goto exit; if (cur->name == xmlStringTextNoenc) copy->name = xmlStringTextNoenc; /* * Must confirm that content is in dict (bug 302821) * TODO: This check should be not needed for text coming * from the stylesheets */ if (xmlDictOwns(ctxt->dict, cur->content)) copy->content = cur->content; else { if ((copy->content = xmlStrdup(cur->content)) == NULL) return NULL; } } else { /* * normal processing. keep counters to extend the text node * in xsltAddTextString if needed. */ unsigned int len; len = xmlStrlen(cur->content); copy = xmlNewTextLen(cur->content, len); if (copy == NULL) goto exit; if (cur->name == xmlStringTextNoenc) copy->name = xmlStringTextNoenc; ctxt->lasttext = copy->content; ctxt->lasttsize = len; ctxt->lasttuse = len; } if (copy != NULL) { if (target != NULL) { copy->doc = target->doc; /* * MAYBE TODO: Maybe we should reset the ctxt->lasttext here * to ensure that the optimized text-merging mechanism * won't interfere with normal node-merging in any case. */ copy = xsltAddChild(target, copy); } } else { xsltTransformError(ctxt, NULL, target, "xsltCopyText: text copy failed\n"); } exit: if ((copy == NULL) || (copy->content == NULL)) { xsltTransformError(ctxt, NULL, target, "Internal error in xsltCopyText(): " "Failed to copy the string.\n"); ctxt->state = XSLT_STATE_STOPPED; } return(copy); } /** * xsltShallowCopyAttr: * @ctxt: a XSLT process context * @invocNode: responsible node in the stylesheet; used for error reports * @target: the element where the attribute will be grafted * @attr: the attribute to be copied * * Do a copy of an attribute. * Called by: * - xsltCopyTreeInternal() * - xsltCopyOf() * - xsltCopy() * * Returns: a new xmlAttrPtr, or NULL in case of error. */ static xmlAttrPtr xsltShallowCopyAttr(xsltTransformContextPtr ctxt, xmlNodePtr invocNode, xmlNodePtr target, xmlAttrPtr attr) { xmlAttrPtr copy; xmlChar *value; if (attr == NULL) return(NULL); if (target->type != XML_ELEMENT_NODE) { xsltTransformError(ctxt, NULL, invocNode, "Cannot add an attribute node to a non-element node.\n"); return(NULL); } if (target->children != NULL) { xsltTransformError(ctxt, NULL, invocNode, "Attribute nodes must be added before " "any child nodes to an element.\n"); return(NULL); } value = xmlNodeListGetString(attr->doc, attr->children, 1); if (attr->ns != NULL) { xmlNsPtr ns; ns = xsltGetSpecialNamespace(ctxt, invocNode, attr->ns->href, attr->ns->prefix, target); if (ns == NULL) { xsltTransformError(ctxt, NULL, invocNode, "Namespace fixup error: Failed to acquire an in-scope " "namespace binding of the copied attribute '{%s}%s'.\n", attr->ns->href, attr->name); /* * TODO: Should we just stop here? */ } /* * Note that xmlSetNsProp() will take care of duplicates * and assigns the new namespace even to a duplicate. */ copy = xmlSetNsProp(target, ns, attr->name, value); } else { copy = xmlSetNsProp(target, NULL, attr->name, value); } if (value != NULL) xmlFree(value); if (copy == NULL) return(NULL); #if 0 /* * NOTE: This was optimized according to bug #342695. * TODO: Can this further be optimized, if source and target * share the same dict and attr->children is just 1 text node * which is in the dict? How probable is such a case? */ /* * TODO: Do we need to create an empty text node if the value * is the empty string? */ value = xmlNodeListGetString(attr->doc, attr->children, 1); if (value != NULL) { txtNode = xmlNewDocText(target->doc, NULL); if (txtNode == NULL) return(NULL); if ((target->doc != NULL) && (target->doc->dict != NULL)) { txtNode->content = (xmlChar *) xmlDictLookup(target->doc->dict, BAD_CAST value, -1); xmlFree(value); } else txtNode->content = value; copy->children = txtNode; } #endif return(copy); } /** * xsltCopyAttrListNoOverwrite: * @ctxt: a XSLT process context * @invocNode: responsible node in the stylesheet; used for error reports * @target: the element where the new attributes will be grafted * @attr: the first attribute in the list to be copied * * Copies a list of attribute nodes, starting with @attr, over to the * @target element node. * * Called by: * - xsltCopyTreeInternal() * * Returns 0 on success and -1 on errors and internal errors. */ static int xsltCopyAttrListNoOverwrite(xsltTransformContextPtr ctxt, xmlNodePtr invocNode, xmlNodePtr target, xmlAttrPtr attr) { xmlAttrPtr copy; xmlNsPtr origNs = NULL, copyNs = NULL; xmlChar *value; /* * Don't use xmlCopyProp() here, since it will try to * reconciliate namespaces. */ while (attr != NULL) { /* * Find a namespace node in the tree of @target. * Avoid searching for the same ns. */ if (attr->ns != origNs) { origNs = attr->ns; if (attr->ns != NULL) { copyNs = xsltGetSpecialNamespace(ctxt, invocNode, attr->ns->href, attr->ns->prefix, target); if (copyNs == NULL) return(-1); } else copyNs = NULL; } /* * If attribute has a value, we need to copy it (watching out * for possible entities) */ if ((attr->children) && (attr->children->type == XML_TEXT_NODE) && (attr->children->next == NULL)) { copy = xmlNewNsProp(target, copyNs, attr->name, attr->children->content); } else if (attr->children != NULL) { value = xmlNodeListGetString(attr->doc, attr->children, 1); copy = xmlNewNsProp(target, copyNs, attr->name, BAD_CAST value); xmlFree(value); } else { copy = xmlNewNsProp(target, copyNs, attr->name, NULL); } if (copy == NULL) return(-1); attr = attr->next; } return(0); } /** * xsltShallowCopyElem: * @ctxt: the XSLT process context * @node: the element node in the source tree * or the Literal Result Element * @insert: the parent in the result tree * @isLRE: if @node is a Literal Result Element * * Make a copy of the element node @node * and insert it as last child of @insert. * * URGENT TODO: The problem with this one (for the non-refactored code) * is that it is used for both, Literal Result Elements *and* * copying input nodes. * * BIG NOTE: This is only called for XML_ELEMENT_NODEs. * * Called from: * xsltApplySequenceConstructor() * (for Literal Result Elements - which is a problem) * xsltCopy() (for shallow-copying elements via xsl:copy) * * Returns a pointer to the new node, or NULL in case of error */ static xmlNodePtr xsltShallowCopyElem(xsltTransformContextPtr ctxt, xmlNodePtr node, xmlNodePtr insert, int isLRE) { xmlNodePtr copy; if ((node->type == XML_DTD_NODE) || (insert == NULL)) return(NULL); if ((node->type == XML_TEXT_NODE) || (node->type == XML_CDATA_SECTION_NODE)) return(xsltCopyText(ctxt, insert, node, 0)); copy = xmlDocCopyNode(node, insert->doc, 0); if (copy != NULL) { copy->doc = ctxt->output; copy = xsltAddChild(insert, copy); if (node->type == XML_ELEMENT_NODE) { /* * Add namespaces as they are needed */ if (node->nsDef != NULL) { /* * TODO: Remove the LRE case in the refactored code * gets enabled. */ if (isLRE) xsltCopyNamespaceList(ctxt, copy, node->nsDef); else xsltCopyNamespaceListInternal(copy, node->nsDef); } /* * URGENT TODO: The problem with this is that it does not * copy over all namespace nodes in scope. * The damn thing about this is, that we would need to * use the xmlGetNsList(), for every single node; this is * also done in xsltCopyTreeInternal(), but only for the top node. */ if (node->ns != NULL) { if (isLRE) { /* * REVISIT TODO: Since the non-refactored code still does * ns-aliasing, we need to call xsltGetNamespace() here. * Remove this when ready. */ copy->ns = xsltGetNamespace(ctxt, node, node->ns, copy); } else { copy->ns = xsltGetSpecialNamespace(ctxt, node, node->ns->href, node->ns->prefix, copy); } } else if ((insert->type == XML_ELEMENT_NODE) && (insert->ns != NULL)) { /* * "Undeclare" the default namespace. */ xsltGetSpecialNamespace(ctxt, node, NULL, NULL, copy); } } } else { xsltTransformError(ctxt, NULL, node, "xsltShallowCopyElem: copy %s failed\n", node->name); } return(copy); } /** * xsltCopyTreeList: * @ctxt: a XSLT process context * @invocNode: responsible node in the stylesheet; used for error reports * @list: the list of element nodes in the source tree. * @insert: the parent in the result tree. * @isLRE: is this a literal result element list * @topElemVisited: indicates if a top-most element was already processed * * Make a copy of the full list of tree @list * and insert it as last children of @insert * * NOTE: Not to be used for Literal Result Elements. * * Used by: * - xsltCopyOf() * * Returns a pointer to the new list, or NULL in case of error */ static xmlNodePtr xsltCopyTreeList(xsltTransformContextPtr ctxt, xmlNodePtr invocNode, xmlNodePtr list, xmlNodePtr insert, int isLRE, int topElemVisited) { xmlNodePtr copy, ret = NULL; while (list != NULL) { copy = xsltCopyTreeInternal(ctxt, invocNode, list, insert, isLRE, topElemVisited); if (copy != NULL) { if (ret == NULL) { ret = copy; } } list = list->next; } return(ret); } /** * xsltCopyNamespaceListInternal: * @node: the target node * @cur: the first namespace * * Do a copy of a namespace list. If @node is non-NULL the * new namespaces are added automatically. * Called by: * xsltCopyTreeInternal() * * QUESTION: What is the exact difference between this function * and xsltCopyNamespaceList() in "namespaces.c"? * ANSWER: xsltCopyNamespaceList() tries to apply ns-aliases. * * Returns: a new xmlNsPtr, or NULL in case of error. */ static xmlNsPtr xsltCopyNamespaceListInternal(xmlNodePtr elem, xmlNsPtr ns) { xmlNsPtr ret = NULL; xmlNsPtr p = NULL, q, luNs; if (ns == NULL) return(NULL); /* * One can add namespaces only on element nodes */ if ((elem != NULL) && (elem->type != XML_ELEMENT_NODE)) elem = NULL; do { if (ns->type != XML_NAMESPACE_DECL) break; /* * Avoid duplicating namespace declarations on the tree. */ if (elem != NULL) { if ((elem->ns != NULL) && xmlStrEqual(elem->ns->prefix, ns->prefix) && xmlStrEqual(elem->ns->href, ns->href)) { ns = ns->next; continue; } luNs = xmlSearchNs(elem->doc, elem, ns->prefix); if ((luNs != NULL) && (xmlStrEqual(luNs->href, ns->href))) { ns = ns->next; continue; } } q = xmlNewNs(elem, ns->href, ns->prefix); if (p == NULL) { ret = p = q; } else if (q != NULL) { p->next = q; p = q; } ns = ns->next; } while (ns != NULL); return(ret); } /** * xsltShallowCopyNsNode: * @ctxt: the XSLT transformation context * @invocNode: responsible node in the stylesheet; used for error reports * @insert: the target element node in the result tree * @ns: the namespace node * * This is used for copying ns-nodes with xsl:copy-of and xsl:copy. * * Returns a new/existing ns-node, or NULL. */ static xmlNsPtr xsltShallowCopyNsNode(xsltTransformContextPtr ctxt, xmlNodePtr invocNode, xmlNodePtr insert, xmlNsPtr ns) { /* * TODO: Contrary to header comments, this is declared as int. * be modified to return a node pointer, or NULL if any error */ xmlNsPtr tmpns; if ((insert == NULL) || (insert->type != XML_ELEMENT_NODE)) return(NULL); if (insert->children != NULL) { xsltTransformError(ctxt, NULL, invocNode, "Namespace nodes must be added before " "any child nodes are added to an element.\n"); return(NULL); } /* * BIG NOTE: Xalan-J simply overwrites any ns-decls with * an equal prefix. We definitively won't do that. * * MSXML 4.0 and the .NET ignores ns-decls for which an * equal prefix is already in use. * * Saxon raises an error like: * "net.sf.saxon.xpath.DynamicError: Cannot create two namespace * nodes with the same name". * * NOTE: We'll currently follow MSXML here. * REVISIT TODO: Check if it's better to follow Saxon here. */ if (ns->prefix == NULL) { /* * If we are adding ns-nodes to an element using e.g. * , then we need * to ensure that we don't incorrectly declare a default * namespace on an element in no namespace, which otherwise * would move the element incorrectly into a namespace, if * the node tree is serialized. */ if (insert->ns == NULL) goto occupied; } else if ((ns->prefix[0] == 'x') && xmlStrEqual(ns->prefix, BAD_CAST "xml")) { /* * The XML namespace is built in. */ return(NULL); } if (insert->nsDef != NULL) { tmpns = insert->nsDef; do { if ((tmpns->prefix == NULL) == (ns->prefix == NULL)) { if ((tmpns->prefix == ns->prefix) || xmlStrEqual(tmpns->prefix, ns->prefix)) { /* * Same prefix. */ if (xmlStrEqual(tmpns->href, ns->href)) return(NULL); goto occupied; } } tmpns = tmpns->next; } while (tmpns != NULL); } tmpns = xmlSearchNs(insert->doc, insert, ns->prefix); if ((tmpns != NULL) && xmlStrEqual(tmpns->href, ns->href)) return(NULL); /* * Declare a new namespace. * TODO: The problem (wrt efficiency) with this xmlNewNs() is * that it will again search the already declared namespaces * for a duplicate :-/ */ return(xmlNewNs(insert, ns->href, ns->prefix)); occupied: /* * TODO: We could as well raise an error here (like Saxon does), * or at least generate a warning. */ return(NULL); } /** * xsltCopyTreeInternal: * @ctxt: the XSLT transformation context * @invocNode: responsible node in the stylesheet; used for error reports * @node: the element node in the source tree * @insert: the parent in the result tree * @isLRE: indicates if @node is a Literal Result Element * @topElemVisited: indicates if a top-most element was already processed * * Make a copy of the full tree under the element node @node * and insert it as last child of @insert * * NOTE: Not to be used for Literal Result Elements. * * Used by: * - xsltCopyOf() * * Returns a pointer to the new tree, or NULL in case of error */ static xmlNodePtr xsltCopyTreeInternal(xsltTransformContextPtr ctxt, xmlNodePtr invocNode, xmlNodePtr node, xmlNodePtr insert, int isLRE, int topElemVisited) { xmlNodePtr copy; if (node == NULL) return(NULL); switch (node->type) { case XML_ELEMENT_NODE: case XML_ENTITY_REF_NODE: case XML_ENTITY_NODE: case XML_PI_NODE: case XML_COMMENT_NODE: case XML_DOCUMENT_NODE: case XML_HTML_DOCUMENT_NODE: #ifdef LIBXML_DOCB_ENABLED case XML_DOCB_DOCUMENT_NODE: #endif break; case XML_TEXT_NODE: { int noenc = (node->name == xmlStringTextNoenc); return(xsltCopyTextString(ctxt, insert, node->content, noenc)); } case XML_CDATA_SECTION_NODE: return(xsltCopyTextString(ctxt, insert, node->content, 0)); case XML_ATTRIBUTE_NODE: return((xmlNodePtr) xsltShallowCopyAttr(ctxt, invocNode, insert, (xmlAttrPtr) node)); case XML_NAMESPACE_DECL: return((xmlNodePtr) xsltShallowCopyNsNode(ctxt, invocNode, insert, (xmlNsPtr) node)); case XML_DOCUMENT_TYPE_NODE: case XML_DOCUMENT_FRAG_NODE: case XML_NOTATION_NODE: case XML_DTD_NODE: case XML_ELEMENT_DECL: case XML_ATTRIBUTE_DECL: case XML_ENTITY_DECL: case XML_XINCLUDE_START: case XML_XINCLUDE_END: return(NULL); } if (XSLT_IS_RES_TREE_FRAG(node)) { if (node->children != NULL) copy = xsltCopyTreeList(ctxt, invocNode, node->children, insert, 0, 0); else copy = NULL; return(copy); } copy = xmlDocCopyNode(node, insert->doc, 0); if (copy != NULL) { copy->doc = ctxt->output; copy = xsltAddChild(insert, copy); /* * The node may have been coalesced into another text node. */ if (insert->last != copy) return(insert->last); copy->next = NULL; if (node->type == XML_ELEMENT_NODE) { /* * Copy in-scope namespace nodes. * * REVISIT: Since we try to reuse existing in-scope ns-decls by * using xmlSearchNsByHref(), this will eventually change * the prefix of an original ns-binding; thus it might * break QNames in element/attribute content. * OPTIMIZE TODO: If we had a xmlNsPtr * on the transformation * context, plus a ns-lookup function, which writes directly * to a given list, then we wouldn't need to create/free the * nsList every time. */ if ((topElemVisited == 0) && (node->parent != NULL) && (node->parent->type != XML_DOCUMENT_NODE) && (node->parent->type != XML_HTML_DOCUMENT_NODE)) { xmlNsPtr *nsList, *curns, ns; /* * If this is a top-most element in a tree to be * copied, then we need to ensure that all in-scope * namespaces are copied over. For nodes deeper in the * tree, it is sufficient to reconcile only the ns-decls * (node->nsDef entries). */ nsList = xmlGetNsList(node->doc, node); if (nsList != NULL) { curns = nsList; do { /* * Search by prefix first in order to break as less * QNames in element/attribute content as possible. */ ns = xmlSearchNs(insert->doc, insert, (*curns)->prefix); if ((ns == NULL) || (! xmlStrEqual(ns->href, (*curns)->href))) { ns = NULL; /* * Search by namespace name. * REVISIT TODO: Currently disabled. */ #if 0 ns = xmlSearchNsByHref(insert->doc, insert, (*curns)->href); #endif } if (ns == NULL) { /* * Declare a new namespace on the copied element. */ ns = xmlNewNs(copy, (*curns)->href, (*curns)->prefix); /* TODO: Handle errors */ } if (node->ns == *curns) { /* * If this was the original's namespace then set * the generated counterpart on the copy. */ copy->ns = ns; } curns++; } while (*curns != NULL); xmlFree(nsList); } } else if (node->nsDef != NULL) { /* * Copy over all namespace declaration attributes. */ if (node->nsDef != NULL) { if (isLRE) xsltCopyNamespaceList(ctxt, copy, node->nsDef); else xsltCopyNamespaceListInternal(copy, node->nsDef); } } /* * Set the namespace. */ if (node->ns != NULL) { if (copy->ns == NULL) { /* * This will map copy->ns to one of the newly created * in-scope ns-decls, OR create a new ns-decl on @copy. */ copy->ns = xsltGetSpecialNamespace(ctxt, invocNode, node->ns->href, node->ns->prefix, copy); } } else if ((insert->type == XML_ELEMENT_NODE) && (insert->ns != NULL)) { /* * "Undeclare" the default namespace on @copy with xmlns="". */ xsltGetSpecialNamespace(ctxt, invocNode, NULL, NULL, copy); } /* * Copy attribute nodes. */ if (node->properties != NULL) { xsltCopyAttrListNoOverwrite(ctxt, invocNode, copy, node->properties); } if (topElemVisited == 0) topElemVisited = 1; } /* * Copy the subtree. */ if (node->children != NULL) { xsltCopyTreeList(ctxt, invocNode, node->children, copy, isLRE, topElemVisited); } } else { xsltTransformError(ctxt, NULL, invocNode, "xsltCopyTreeInternal: Copying of '%s' failed.\n", node->name); } return(copy); } /** * xsltCopyTree: * @ctxt: the XSLT transformation context * @node: the element node in the source tree * @insert: the parent in the result tree * @literal: indicates if @node is a Literal Result Element * * Make a copy of the full tree under the element node @node * and insert it as last child of @insert * For literal result element, some of the namespaces may not be copied * over according to section 7.1. * TODO: Why is this a public function? * * Returns a pointer to the new tree, or NULL in case of error */ xmlNodePtr xsltCopyTree(xsltTransformContextPtr ctxt, xmlNodePtr node, xmlNodePtr insert, int literal) { return(xsltCopyTreeInternal(ctxt, node, node, insert, literal, 0)); } /************************************************************************ * * * Error/fallback processing * * * ************************************************************************/ /** * xsltApplyFallbacks: * @ctxt: a XSLT process context * @node: the node in the source tree. * @inst: the node generating the error * * Process possible xsl:fallback nodes present under @inst * * Returns the number of xsl:fallback element found and processed */ static int xsltApplyFallbacks(xsltTransformContextPtr ctxt, xmlNodePtr node, xmlNodePtr inst) { xmlNodePtr child; int ret = 0; if ((ctxt == NULL) || (node == NULL) || (inst == NULL) || (inst->children == NULL)) return(0); child = inst->children; while (child != NULL) { if ((IS_XSLT_ELEM(child)) && (xmlStrEqual(child->name, BAD_CAST "fallback"))) { #ifdef WITH_XSLT_DEBUG_PARSING xsltGenericDebug(xsltGenericDebugContext, "applying xsl:fallback\n"); #endif ret++; xsltApplySequenceConstructor(ctxt, node, child->children, NULL); } child = child->next; } return(ret); } /************************************************************************ * * * Default processing * * * ************************************************************************/ /** * xsltDefaultProcessOneNode: * @ctxt: a XSLT process context * @node: the node in the source tree. * @params: extra parameters passed to the template if any * * Process the source node with the default built-in template rule: * * * * * and * * * * * * Note also that namespace declarations are copied directly: * * the built-in template rule is the only template rule that is applied * for namespace nodes. */ static void xsltDefaultProcessOneNode(xsltTransformContextPtr ctxt, xmlNodePtr node, xsltStackElemPtr params) { xmlNodePtr copy; xmlNodePtr delete = NULL, cur; int nbchild = 0, oldSize; int childno = 0, oldPos; xsltTemplatePtr template; CHECK_STOPPED; /* * Handling of leaves */ switch (node->type) { case XML_DOCUMENT_NODE: case XML_HTML_DOCUMENT_NODE: case XML_ELEMENT_NODE: break; case XML_CDATA_SECTION_NODE: #ifdef WITH_XSLT_DEBUG_PROCESS XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, "xsltDefaultProcessOneNode: copy CDATA %s\n", node->content)); #endif copy = xsltCopyText(ctxt, ctxt->insert, node, 0); if (copy == NULL) { xsltTransformError(ctxt, NULL, node, "xsltDefaultProcessOneNode: cdata copy failed\n"); } return; case XML_TEXT_NODE: #ifdef WITH_XSLT_DEBUG_PROCESS if (node->content == NULL) { XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, "xsltDefaultProcessOneNode: copy empty text\n")); return; } else { XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, "xsltDefaultProcessOneNode: copy text %s\n", node->content)); } #endif copy = xsltCopyText(ctxt, ctxt->insert, node, 0); if (copy == NULL) { xsltTransformError(ctxt, NULL, node, "xsltDefaultProcessOneNode: text copy failed\n"); } return; case XML_ATTRIBUTE_NODE: cur = node->children; while ((cur != NULL) && (cur->type != XML_TEXT_NODE)) cur = cur->next; if (cur == NULL) { xsltTransformError(ctxt, NULL, node, "xsltDefaultProcessOneNode: no text for attribute\n"); } else { #ifdef WITH_XSLT_DEBUG_PROCESS if (cur->content == NULL) { XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, "xsltDefaultProcessOneNode: copy empty text\n")); } else { XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, "xsltDefaultProcessOneNode: copy text %s\n", cur->content)); } #endif copy = xsltCopyText(ctxt, ctxt->insert, cur, 0); if (copy == NULL) { xsltTransformError(ctxt, NULL, node, "xsltDefaultProcessOneNode: text copy failed\n"); } } return; default: return; } /* * Handling of Elements: first pass, cleanup and counting */ cur = node->children; while (cur != NULL) { switch (cur->type) { case XML_TEXT_NODE: case XML_CDATA_SECTION_NODE: case XML_DOCUMENT_NODE: case XML_HTML_DOCUMENT_NODE: case XML_ELEMENT_NODE: case XML_PI_NODE: case XML_COMMENT_NODE: nbchild++; break; case XML_DTD_NODE: /* Unlink the DTD, it's still reachable using doc->intSubset */ if (cur->next != NULL) cur->next->prev = cur->prev; if (cur->prev != NULL) cur->prev->next = cur->next; break; default: #ifdef WITH_XSLT_DEBUG_PROCESS XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, "xsltDefaultProcessOneNode: skipping node type %d\n", cur->type)); #endif delete = cur; } cur = cur->next; if (delete != NULL) { #ifdef WITH_XSLT_DEBUG_PROCESS XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, "xsltDefaultProcessOneNode: removing ignorable blank node\n")); #endif xmlUnlinkNode(delete); xmlFreeNode(delete); delete = NULL; } } if (delete != NULL) { #ifdef WITH_XSLT_DEBUG_PROCESS XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, "xsltDefaultProcessOneNode: removing ignorable blank node\n")); #endif xmlUnlinkNode(delete); xmlFreeNode(delete); delete = NULL; } /* * Handling of Elements: second pass, actual processing */ oldSize = ctxt->xpathCtxt->contextSize; oldPos = ctxt->xpathCtxt->proximityPosition; cur = node->children; while (cur != NULL) { childno++; switch (cur->type) { case XML_DOCUMENT_NODE: case XML_HTML_DOCUMENT_NODE: case XML_ELEMENT_NODE: ctxt->xpathCtxt->contextSize = nbchild; ctxt->xpathCtxt->proximityPosition = childno; xsltProcessOneNode(ctxt, cur, params); break; case XML_CDATA_SECTION_NODE: template = xsltGetTemplate(ctxt, cur, NULL); if (template) { #ifdef WITH_XSLT_DEBUG_PROCESS XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, "xsltDefaultProcessOneNode: applying template for CDATA %s\n", cur->content)); #endif /* * Instantiate the xsl:template. */ xsltApplyXSLTTemplate(ctxt, cur, template->content, template, params); } else /* if (ctxt->mode == NULL) */ { #ifdef WITH_XSLT_DEBUG_PROCESS XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, "xsltDefaultProcessOneNode: copy CDATA %s\n", cur->content)); #endif copy = xsltCopyText(ctxt, ctxt->insert, cur, 0); if (copy == NULL) { xsltTransformError(ctxt, NULL, cur, "xsltDefaultProcessOneNode: cdata copy failed\n"); } } break; case XML_TEXT_NODE: template = xsltGetTemplate(ctxt, cur, NULL); if (template) { #ifdef WITH_XSLT_DEBUG_PROCESS XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, "xsltDefaultProcessOneNode: applying template for text %s\n", cur->content)); #endif ctxt->xpathCtxt->contextSize = nbchild; ctxt->xpathCtxt->proximityPosition = childno; /* * Instantiate the xsl:template. */ xsltApplyXSLTTemplate(ctxt, cur, template->content, template, params); } else /* if (ctxt->mode == NULL) */ { #ifdef WITH_XSLT_DEBUG_PROCESS if (cur->content == NULL) { XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, "xsltDefaultProcessOneNode: copy empty text\n")); } else { XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, "xsltDefaultProcessOneNode: copy text %s\n", cur->content)); } #endif copy = xsltCopyText(ctxt, ctxt->insert, cur, 0); if (copy == NULL) { xsltTransformError(ctxt, NULL, cur, "xsltDefaultProcessOneNode: text copy failed\n"); } } break; case XML_PI_NODE: case XML_COMMENT_NODE: template = xsltGetTemplate(ctxt, cur, NULL); if (template) { #ifdef WITH_XSLT_DEBUG_PROCESS if (cur->type == XML_PI_NODE) { XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, "xsltDefaultProcessOneNode: template found for PI %s\n", cur->name)); } else if (cur->type == XML_COMMENT_NODE) { XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, "xsltDefaultProcessOneNode: template found for comment\n")); } #endif ctxt->xpathCtxt->contextSize = nbchild; ctxt->xpathCtxt->proximityPosition = childno; /* * Instantiate the xsl:template. */ xsltApplyXSLTTemplate(ctxt, cur, template->content, template, params); } break; default: break; } cur = cur->next; } ctxt->xpathCtxt->contextSize = oldSize; ctxt->xpathCtxt->proximityPosition = oldPos; } /** * xsltProcessOneNode: * @ctxt: a XSLT process context * @contextNode: the "current node" in the source tree * @withParams: extra parameters (e.g. xsl:with-param) passed to the * template if any * * Process the source node. */ void xsltProcessOneNode(xsltTransformContextPtr ctxt, xmlNodePtr contextNode, xsltStackElemPtr withParams) { xsltTemplatePtr templ; xmlNodePtr oldNode; templ = xsltGetTemplate(ctxt, contextNode, NULL); /* * If no template is found, apply the default rule. */ if (templ == NULL) { #ifdef WITH_XSLT_DEBUG_PROCESS if (contextNode->type == XML_DOCUMENT_NODE) { XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, "xsltProcessOneNode: no template found for /\n")); } else if (contextNode->type == XML_CDATA_SECTION_NODE) { XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, "xsltProcessOneNode: no template found for CDATA\n")); } else if (contextNode->type == XML_ATTRIBUTE_NODE) { XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, "xsltProcessOneNode: no template found for attribute %s\n", ((xmlAttrPtr) contextNode)->name)); } else { XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, "xsltProcessOneNode: no template found for %s\n", contextNode->name)); } #endif oldNode = ctxt->node; ctxt->node = contextNode; xsltDefaultProcessOneNode(ctxt, contextNode, withParams); ctxt->node = oldNode; return; } if (contextNode->type == XML_ATTRIBUTE_NODE) { xsltTemplatePtr oldCurTempRule = ctxt->currentTemplateRule; /* * Set the "current template rule". */ ctxt->currentTemplateRule = templ; #ifdef WITH_XSLT_DEBUG_PROCESS XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, "xsltProcessOneNode: applying template '%s' for attribute %s\n", templ->match, contextNode->name)); #endif xsltApplyXSLTTemplate(ctxt, contextNode, templ->content, templ, withParams); ctxt->currentTemplateRule = oldCurTempRule; } else { xsltTemplatePtr oldCurTempRule = ctxt->currentTemplateRule; /* * Set the "current template rule". */ ctxt->currentTemplateRule = templ; #ifdef WITH_XSLT_DEBUG_PROCESS if (contextNode->type == XML_DOCUMENT_NODE) { XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, "xsltProcessOneNode: applying template '%s' for /\n", templ->match)); } else { XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, "xsltProcessOneNode: applying template '%s' for %s\n", templ->match, contextNode->name)); } #endif xsltApplyXSLTTemplate(ctxt, contextNode, templ->content, templ, withParams); ctxt->currentTemplateRule = oldCurTempRule; } } static xmlNodePtr xsltDebuggerStartSequenceConstructor(xsltTransformContextPtr ctxt, xmlNodePtr contextNode, xmlNodePtr list, xsltTemplatePtr templ, int *addCallResult) { xmlNodePtr debugedNode = NULL; if (ctxt->debugStatus != XSLT_DEBUG_NONE) { if (templ) { *addCallResult = xslAddCall(templ, templ->elem); } else { *addCallResult = xslAddCall(NULL, list); } switch (ctxt->debugStatus) { case XSLT_DEBUG_RUN_RESTART: case XSLT_DEBUG_QUIT: if (*addCallResult) xslDropCall(); return(NULL); } if (templ) { xslHandleDebugger(templ->elem, contextNode, templ, ctxt); debugedNode = templ->elem; } else if (list) { xslHandleDebugger(list, contextNode, templ, ctxt); debugedNode = list; } else if (ctxt->inst) { xslHandleDebugger(ctxt->inst, contextNode, templ, ctxt); debugedNode = ctxt->inst; } } return(debugedNode); } /** * xsltLocalVariablePush: * @ctxt: the transformation context * @variable: variable to be pushed to the variable stack * @level: new value for variable's level * * Places the variable onto the local variable stack * * Returns: 0 for success, -1 for any error * **NOTE:** * This is an internal routine and should not be called by users! */ int xsltLocalVariablePush(xsltTransformContextPtr ctxt, xsltStackElemPtr variable, int level) { if (ctxt->varsMax == 0) { ctxt->varsMax = 10; ctxt->varsTab = (xsltStackElemPtr *) xmlMalloc(ctxt->varsMax * sizeof(ctxt->varsTab[0])); if (ctxt->varsTab == NULL) { xmlGenericError(xmlGenericErrorContext, "malloc failed !\n"); return (-1); } } if (ctxt->varsNr >= ctxt->varsMax) { ctxt->varsMax *= 2; ctxt->varsTab = (xsltStackElemPtr *) xmlRealloc(ctxt->varsTab, ctxt->varsMax * sizeof(ctxt->varsTab[0])); if (ctxt->varsTab == NULL) { xmlGenericError(xmlGenericErrorContext, "realloc failed !\n"); return (-1); } } ctxt->varsTab[ctxt->varsNr++] = variable; ctxt->vars = variable; variable->level = level; return(0); } /** * xsltReleaseLocalRVTs: * * Fragments which are results of extension instructions * are preserved; all other fragments are freed/cached. */ static void xsltReleaseLocalRVTs(xsltTransformContextPtr ctxt, xmlDocPtr base) { xmlDocPtr cur = ctxt->localRVT, tmp; while ((cur != NULL) && (cur != base)) { if (cur->psvi == (void *) ((long) 1)) { cur = (xmlDocPtr) cur->next; } else { tmp = cur; cur = (xmlDocPtr) cur->next; if (tmp == ctxt->localRVT) ctxt->localRVT = cur; /* * We need ctxt->localRVTBase for extension instructions * which return values (like EXSLT's function). */ if (tmp == ctxt->localRVTBase) ctxt->localRVTBase = cur; if (tmp->prev) tmp->prev->next = (xmlNodePtr) cur; if (cur) cur->prev = tmp->prev; xsltReleaseRVT(ctxt, tmp); } } } /** * xsltApplySequenceConstructor: * @ctxt: a XSLT process context * @contextNode: the "current node" in the source tree * @list: the nodes of a sequence constructor; * (plus leading xsl:param elements) * @templ: the compiled xsl:template (optional) * * Processes a sequence constructor. * * NOTE: ctxt->currentTemplateRule was introduced to reflect the * semantics of "current template rule". I.e. the field ctxt->templ * is not intended to reflect this, thus always pushed onto the * template stack. */ static void xsltApplySequenceConstructor(xsltTransformContextPtr ctxt, xmlNodePtr contextNode, xmlNodePtr list, xsltTemplatePtr templ) { xmlNodePtr oldInsert, oldInst, oldCurInst, oldContextNode; xmlNodePtr cur, insert, copy = NULL; int level = 0, oldVarsNr; xmlDocPtr oldLocalFragmentTop, oldLocalFragmentBase; #ifdef XSLT_REFACTORED xsltStylePreCompPtr info; #endif #ifdef WITH_DEBUGGER int addCallResult = 0; xmlNodePtr debuggedNode = NULL; #endif if (ctxt == NULL) return; #ifdef WITH_DEBUGGER if (ctxt->debugStatus != XSLT_DEBUG_NONE) { debuggedNode = xsltDebuggerStartSequenceConstructor(ctxt, contextNode, list, templ, &addCallResult); if (debuggedNode == NULL) return; } #endif if (list == NULL) return; CHECK_STOPPED; oldLocalFragmentTop = ctxt->localRVT; oldInsert = insert = ctxt->insert; oldInst = oldCurInst = ctxt->inst; oldContextNode = ctxt->node; /* * Save current number of variables on the stack; new vars are popped when * exiting. */ oldVarsNr = ctxt->varsNr; /* * Process the sequence constructor. */ cur = list; while (cur != NULL) { ctxt->inst = cur; #ifdef WITH_DEBUGGER switch (ctxt->debugStatus) { case XSLT_DEBUG_RUN_RESTART: case XSLT_DEBUG_QUIT: break; } #endif /* * Test; we must have a valid insertion point. */ if (insert == NULL) { #ifdef WITH_XSLT_DEBUG_PROCESS XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext, "xsltApplySequenceConstructor: insert == NULL !\n")); #endif goto error; } #ifdef WITH_DEBUGGER if ((ctxt->debugStatus != XSLT_DEBUG_NONE) && (debuggedNode != cur)) xslHandleDebugger(cur, contextNode, templ, ctxt); #endif #ifdef XSLT_REFACTORED if (cur->type == XML_ELEMENT_NODE) { info = (xsltStylePreCompPtr) cur->psvi; /* * We expect a compiled representation on: * 1) XSLT instructions of this XSLT version (1.0) * (with a few exceptions) * 2) Literal result elements * 3) Extension instructions * 4) XSLT instructions of future XSLT versions * (forwards-compatible mode). */ if (info == NULL) { /* * Handle the rare cases where we don't expect a compiled * representation on an XSLT element. */ if (IS_XSLT_ELEM_FAST(cur) && IS_XSLT_NAME(cur, "message")) { xsltMessage(ctxt, contextNode, cur); goto skip_children; } /* * Something really went wrong: */ xsltTransformError(ctxt, NULL, cur, "Internal error in xsltApplySequenceConstructor(): " "The element '%s' in the stylesheet has no compiled " "representation.\n", cur->name); goto skip_children; } if (info->type == XSLT_FUNC_LITERAL_RESULT_ELEMENT) { xsltStyleItemLRElementInfoPtr lrInfo = (xsltStyleItemLRElementInfoPtr) info; /* * Literal result elements * -------------------------------------------------------- */ #ifdef WITH_XSLT_DEBUG_PROCESS XSLT_TRACE(ctxt, XSLT_TRACE_APPLY_TEMPLATE, xsltGenericDebug(xsltGenericDebugContext, "xsltApplySequenceConstructor: copy literal result " "element '%s'\n", cur->name)); #endif /* * Copy the raw element-node. * OLD: if ((copy = xsltShallowCopyElem(ctxt, cur, insert)) * == NULL) * goto error; */ copy = xmlDocCopyNode(cur, insert->doc, 0); if (copy == NULL) { xsltTransformError(ctxt, NULL, cur, "Internal error in xsltApplySequenceConstructor(): " "Failed to copy literal result element '%s'.\n", cur->name); goto error; } else { /* * Add the element-node to the result tree. */ copy->doc = ctxt->output; copy = xsltAddChild(insert, copy); /* * Create effective namespaces declarations. * OLD: xsltCopyNamespaceList(ctxt, copy, cur->nsDef); */ if (lrInfo->effectiveNs != NULL) { xsltEffectiveNsPtr effNs = lrInfo->effectiveNs; xmlNsPtr ns, lastns = NULL; while (effNs != NULL) { /* * Avoid generating redundant namespace * declarations; thus lookup if there is already * such a ns-decl in the result. */ ns = xmlSearchNs(copy->doc, copy, effNs->prefix); if ((ns != NULL) && (xmlStrEqual(ns->href, effNs->nsName))) { effNs = effNs->next; continue; } ns = xmlNewNs(copy, effNs->nsName, effNs->prefix); if (ns == NULL) { xsltTransformError(ctxt, NULL, cur, "Internal error in " "xsltApplySequenceConstructor(): " "Failed to copy a namespace " "declaration.\n"); goto error; } if (lastns == NULL) copy->nsDef = ns; else lastns->next =ns; lastns = ns; effNs = effNs->next; } } /* * NOTE that we don't need to apply ns-alising: this was * already done at compile-time. */ if (cur->ns != NULL) { /* * If there's no such ns-decl in the result tree, * then xsltGetSpecialNamespace() will * create a ns-decl on the copied node. */ copy->ns = xsltGetSpecialNamespace(ctxt, cur, cur->ns->href, cur->ns->prefix, copy); } else { /* * Undeclare the default namespace if needed. * This can be skipped, if the result element has * no ns-decls, in which case the result element * obviously does not declare a default namespace; * AND there's either no parent, or the parent * element is in no namespace; this means there's no * default namespace is scope to care about. * * REVISIT: This might result in massive * generation of ns-decls if nodes in a default * namespaces are mixed with nodes in no namespace. * */ if (copy->nsDef || ((insert != NULL) && (insert->type == XML_ELEMENT_NODE) && (insert->ns != NULL))) { xsltGetSpecialNamespace(ctxt, cur, NULL, NULL, copy); } } } /* * SPEC XSLT 2.0 "Each attribute of the literal result * element, other than an attribute in the XSLT namespace, * is processed to produce an attribute for the element in * the result tree." * NOTE: See bug #341325. */ if (cur->properties != NULL) { xsltAttrListTemplateProcess(ctxt, copy, cur->properties); } } else if (IS_XSLT_ELEM_FAST(cur)) { /* * XSLT instructions * -------------------------------------------------------- */ if (info->type == XSLT_FUNC_UNKOWN_FORWARDS_COMPAT) { /* * We hit an unknown XSLT element. * Try to apply one of the fallback cases. */ ctxt->insert = insert; if (!xsltApplyFallbacks(ctxt, contextNode, cur)) { xsltTransformError(ctxt, NULL, cur, "The is no fallback behaviour defined for " "the unknown XSLT element '%s'.\n", cur->name); } ctxt->insert = oldInsert; } else if (info->func != NULL) { /* * Execute the XSLT instruction. */ ctxt->insert = insert; info->func(ctxt, contextNode, cur, (xsltElemPreCompPtr) info); /* * Cleanup temporary tree fragments. */ if (oldLocalFragmentTop != ctxt->localRVT) xsltReleaseLocalRVTs(ctxt, oldLocalFragmentTop); ctxt->insert = oldInsert; } else if (info->type == XSLT_FUNC_VARIABLE) { xsltStackElemPtr tmpvar = ctxt->vars; xsltParseStylesheetVariable(ctxt, cur); if (tmpvar != ctxt->vars) { /* * TODO: Using a @tmpvar is an annoying workaround, but * the current mechanisms do not provide any other way * of knowing if the var was really pushed onto the * stack. */ ctxt->vars->level = level; } } else if (info->type == XSLT_FUNC_MESSAGE) { /* * TODO: Won't be hit, since we don't compile xsl:message. */ xsltMessage(ctxt, contextNode, cur); } else { xsltTransformError(ctxt, NULL, cur, "Unexpected XSLT element '%s'.\n", cur->name); } goto skip_children; } else { xsltTransformFunction func; /* * Extension intructions (elements) * -------------------------------------------------------- */ if (cur->psvi == xsltExtMarker) { /* * The xsltExtMarker was set during the compilation * of extension instructions if there was no registered * handler for this specific extension function at * compile-time. * Libxslt will now lookup if a handler is * registered in the context of this transformation. */ func = (xsltTransformFunction) xsltExtElementLookup(ctxt, cur->name, cur->ns->href); } else func = ((xsltElemPreCompPtr) cur->psvi)->func; if (func == NULL) { /* * No handler available. * Try to execute fallback behaviour via xsl:fallback. */ #ifdef WITH_XSLT_DEBUG_PROCESS XSLT_TRACE(ctxt, XSLT_TRACE_APPLY_TEMPLATE, xsltGenericDebug(xsltGenericDebugContext, "xsltApplySequenceConstructor: unknown extension %s\n", cur->name)); #endif ctxt->insert = insert; if (!xsltApplyFallbacks(ctxt, contextNode, cur)) { xsltTransformError(ctxt, NULL, cur, "Unknown extension instruction '{%s}%s'.\n", cur->ns->href, cur->name); } ctxt->insert = oldInsert; } else { /* * Execute the handler-callback. */ #ifdef WITH_XSLT_DEBUG_PROCESS XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext, "xsltApplySequenceConstructor: extension construct %s\n", cur->name)); #endif ctxt->insert = insert; /* * We need the fragment base for extension instructions * which return values (like EXSLT's function). */ oldLocalFragmentBase = ctxt->localRVTBase; ctxt->localRVTBase = NULL; func(ctxt, contextNode, cur, cur->psvi); ctxt->localRVTBase = oldLocalFragmentBase; /* * Cleanup temporary tree fragments. */ if (oldLocalFragmentTop != ctxt->localRVT) xsltReleaseLocalRVTs(ctxt, oldLocalFragmentTop); ctxt->insert = oldInsert; } goto skip_children; } } else if (XSLT_IS_TEXT_NODE(cur)) { /* * Text * ------------------------------------------------------------ */ #ifdef WITH_XSLT_DEBUG_PROCESS if (cur->name == xmlStringTextNoenc) { XSLT_TRACE(ctxt, XSLT_TRACE_APPLY_TEMPLATE, xsltGenericDebug(xsltGenericDebugContext, "xsltApplySequenceConstructor: copy unescaped text '%s'\n", cur->content)); } else { XSLT_TRACE(ctxt, XSLT_TRACE_APPLY_TEMPLATE, xsltGenericDebug(xsltGenericDebugContext, "xsltApplySequenceConstructor: copy text '%s'\n", cur->content)); } #endif if (xsltCopyText(ctxt, insert, cur, ctxt->internalized) == NULL) goto error; } #else /* XSLT_REFACTORED */ if (IS_XSLT_ELEM(cur)) { /* * This is an XSLT node */ xsltStylePreCompPtr info = (xsltStylePreCompPtr) cur->psvi; if (info == NULL) { if (IS_XSLT_NAME(cur, "message")) { xsltMessage(ctxt, contextNode, cur); } else { /* * That's an error try to apply one of the fallback cases */ ctxt->insert = insert; if (!xsltApplyFallbacks(ctxt, contextNode, cur)) { xsltGenericError(xsltGenericErrorContext, "xsltApplySequenceConstructor: %s was not compiled\n", cur->name); } ctxt->insert = oldInsert; } goto skip_children; } if (info->func != NULL) { oldCurInst = ctxt->inst; ctxt->inst = cur; ctxt->insert = insert; oldLocalFragmentBase = ctxt->localRVTBase; ctxt->localRVTBase = NULL; info->func(ctxt, contextNode, cur, (xsltElemPreCompPtr) info); ctxt->localRVTBase = oldLocalFragmentBase; /* * Cleanup temporary tree fragments. */ if (oldLocalFragmentTop != ctxt->localRVT) xsltReleaseLocalRVTs(ctxt, oldLocalFragmentTop); ctxt->insert = oldInsert; ctxt->inst = oldCurInst; goto skip_children; } if (IS_XSLT_NAME(cur, "variable")) { xsltStackElemPtr tmpvar = ctxt->vars; oldCurInst = ctxt->inst; ctxt->inst = cur; xsltParseStylesheetVariable(ctxt, cur); ctxt->inst = oldCurInst; if (tmpvar != ctxt->vars) { /* * TODO: Using a @tmpvar is an annoying workaround, but * the current mechanisms do not provide any other way * of knowing if the var was really pushed onto the * stack. */ ctxt->vars->level = level; } } else if (IS_XSLT_NAME(cur, "message")) { xsltMessage(ctxt, contextNode, cur); } else { xsltTransformError(ctxt, NULL, cur, "Unexpected XSLT element '%s'.\n", cur->name); } goto skip_children; } else if ((cur->type == XML_TEXT_NODE) || (cur->type == XML_CDATA_SECTION_NODE)) { /* * This text comes from the stylesheet * For stylesheets, the set of whitespace-preserving * element names consists of just xsl:text. */ #ifdef WITH_XSLT_DEBUG_PROCESS if (cur->type == XML_CDATA_SECTION_NODE) { XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext, "xsltApplySequenceConstructor: copy CDATA text %s\n", cur->content)); } else if (cur->name == xmlStringTextNoenc) { XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext, "xsltApplySequenceConstructor: copy unescaped text %s\n", cur->content)); } else { XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext, "xsltApplySequenceConstructor: copy text %s\n", cur->content)); } #endif if (xsltCopyText(ctxt, insert, cur, ctxt->internalized) == NULL) goto error; } else if ((cur->type == XML_ELEMENT_NODE) && (cur->ns != NULL) && (cur->psvi != NULL)) { xsltTransformFunction function; oldCurInst = ctxt->inst; ctxt->inst = cur; /* * Flagged as an extension element */ if (cur->psvi == xsltExtMarker) function = (xsltTransformFunction) xsltExtElementLookup(ctxt, cur->name, cur->ns->href); else function = ((xsltElemPreCompPtr) cur->psvi)->func; if (function == NULL) { xmlNodePtr child; int found = 0; #ifdef WITH_XSLT_DEBUG_PROCESS XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext, "xsltApplySequenceConstructor: unknown extension %s\n", cur->name)); #endif /* * Search if there are fallbacks */ child = cur->children; while (child != NULL) { if ((IS_XSLT_ELEM(child)) && (IS_XSLT_NAME(child, "fallback"))) { found = 1; xsltApplySequenceConstructor(ctxt, contextNode, child->children, NULL); } child = child->next; } if (!found) { xsltTransformError(ctxt, NULL, cur, "xsltApplySequenceConstructor: failed to find extension %s\n", cur->name); } } else { #ifdef WITH_XSLT_DEBUG_PROCESS XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext, "xsltApplySequenceConstructor: extension construct %s\n", cur->name)); #endif ctxt->insert = insert; /* * We need the fragment base for extension instructions * which return values (like EXSLT's function). */ oldLocalFragmentBase = ctxt->localRVTBase; ctxt->localRVTBase = NULL; function(ctxt, contextNode, cur, cur->psvi); /* * Cleanup temporary tree fragments. */ if (oldLocalFragmentTop != ctxt->localRVT) xsltReleaseLocalRVTs(ctxt, oldLocalFragmentTop); ctxt->localRVTBase = oldLocalFragmentBase; ctxt->insert = oldInsert; } ctxt->inst = oldCurInst; goto skip_children; } else if (cur->type == XML_ELEMENT_NODE) { #ifdef WITH_XSLT_DEBUG_PROCESS XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext, "xsltApplySequenceConstructor: copy node %s\n", cur->name)); #endif oldCurInst = ctxt->inst; ctxt->inst = cur; if ((copy = xsltShallowCopyElem(ctxt, cur, insert, 1)) == NULL) goto error; /* * Add extra namespaces inherited from the current template * if we are in the first level children and this is a * "real" template. */ if ((templ != NULL) && (oldInsert == insert) && (ctxt->templ != NULL) && (ctxt->templ->inheritedNs != NULL)) { int i; xmlNsPtr ns, ret; for (i = 0; i < ctxt->templ->inheritedNsNr; i++) { const xmlChar *URI = NULL; xsltStylesheetPtr style; ns = ctxt->templ->inheritedNs[i]; /* Note that the XSLT namespace was already excluded * in xsltGetInheritedNsList(). */ #if 0 if (xmlStrEqual(ns->href, XSLT_NAMESPACE)) continue; #endif style = ctxt->style; while (style != NULL) { if (style->nsAliases != NULL) URI = (const xmlChar *) xmlHashLookup(style->nsAliases, ns->href); if (URI != NULL) break; style = xsltNextImport(style); } if (URI == UNDEFINED_DEFAULT_NS) continue; if (URI == NULL) URI = ns->href; /* * TODO: The following will still be buggy for the * non-refactored code. */ ret = xmlSearchNs(copy->doc, copy, ns->prefix); if ((ret == NULL) || (!xmlStrEqual(ret->href, URI))) { xmlNewNs(copy, URI, ns->prefix); } } if (copy->ns != NULL) { /* * Fix the node namespace if needed */ copy->ns = xsltGetNamespace(ctxt, cur, copy->ns, copy); } } /* * all the attributes are directly inherited */ if (cur->properties != NULL) { xsltAttrListTemplateProcess(ctxt, copy, cur->properties); } ctxt->inst = oldCurInst; } #endif /* else of XSLT_REFACTORED */ /* * Descend into content in document order. */ if (cur->children != NULL) { if (cur->children->type != XML_ENTITY_DECL) { cur = cur->children; level++; if (copy != NULL) insert = copy; continue; } } skip_children: /* * If xslt:message was just processed, we might have hit a * terminate='yes'; if so, then break the loop and clean up. * TODO: Do we need to check this also before trying to descend * into the content? */ if (ctxt->state == XSLT_STATE_STOPPED) break; if (cur->next != NULL) { cur = cur->next; continue; } do { cur = cur->parent; level--; /* * Pop variables/params (xsl:variable and xsl:param). */ if ((ctxt->varsNr > oldVarsNr) && (ctxt->vars->level > level)) { xsltLocalVariablePop(ctxt, oldVarsNr, level); } insert = insert->parent; if (cur == NULL) break; if (cur == list->parent) { cur = NULL; break; } if (cur->next != NULL) { cur = cur->next; break; } } while (cur != NULL); } error: /* * In case of errors: pop remaining variables. */ if (ctxt->varsNr > oldVarsNr) xsltLocalVariablePop(ctxt, oldVarsNr, -1); ctxt->node = oldContextNode; ctxt->inst = oldInst; ctxt->insert = oldInsert; #ifdef WITH_DEBUGGER if ((ctxt->debugStatus != XSLT_DEBUG_NONE) && (addCallResult)) { xslDropCall(); } #endif } /* * xsltApplyXSLTTemplate: * @ctxt: a XSLT transformation context * @contextNode: the node in the source tree. * @list: the nodes of a sequence constructor; * (plus leading xsl:param elements) * @templ: the compiled xsl:template declaration; * NULL if a sequence constructor * @withParams: a set of caller-parameters (xsl:with-param) or NULL * * Called by: * - xsltApplyImports() * - xsltCallTemplate() * - xsltDefaultProcessOneNode() * - xsltProcessOneNode() */ static void xsltApplyXSLTTemplate(xsltTransformContextPtr ctxt, xmlNodePtr contextNode, xmlNodePtr list, xsltTemplatePtr templ, xsltStackElemPtr withParams) { int oldVarsBase = 0; long start = 0; xmlNodePtr cur; xsltStackElemPtr tmpParam = NULL; xmlDocPtr oldUserFragmentTop, oldLocalFragmentTop; #ifdef XSLT_REFACTORED xsltStyleItemParamPtr iparam; #else xsltStylePreCompPtr iparam; #endif #ifdef WITH_DEBUGGER int addCallResult = 0; #endif if (ctxt == NULL) return; if (templ == NULL) { xsltTransformError(ctxt, NULL, list, "xsltApplyXSLTTemplate: Bad arguments; @templ is mandatory.\n"); return; } #ifdef WITH_DEBUGGER if (ctxt->debugStatus != XSLT_DEBUG_NONE) { if (xsltDebuggerStartSequenceConstructor(ctxt, contextNode, list, templ, &addCallResult) == NULL) return; } #endif if (list == NULL) return; CHECK_STOPPED; /* * Check for infinite recursion: stop if the maximum of nested templates * is excceeded. Adjust xsltMaxDepth if you need more. */ if (ctxt->templNr >= ctxt->maxTemplateDepth) { xsltTransformError(ctxt, NULL, list, "xsltApplyXSLTTemplate: A potential infinite template recursion " "was detected.\n" "You can adjust xsltMaxDepth (--maxdepth) in order to " "raise the maximum number of nested template calls and " "variables/params (currently set to %d).\n", ctxt->maxTemplateDepth); xsltDebug(ctxt, contextNode, list, NULL); return; } if (ctxt->varsNr >= ctxt->maxTemplateVars) { xsltTransformError(ctxt, NULL, list, "xsltApplyXSLTTemplate: A potential infinite template recursion " "was detected.\n" "You can adjust maxTemplateVars (--maxvars) in order to " "raise the maximum number of variables/params (currently set to %d).\n", ctxt->maxTemplateVars); xsltDebug(ctxt, contextNode, list, NULL); return; } oldUserFragmentTop = ctxt->tmpRVT; ctxt->tmpRVT = NULL; oldLocalFragmentTop = ctxt->localRVT; /* * Initiate a distinct scope of local params/variables. */ oldVarsBase = ctxt->varsBase; ctxt->varsBase = ctxt->varsNr; ctxt->node = contextNode; if (ctxt->profile) { templ->nbCalls++; start = xsltTimestamp(); profPush(ctxt, 0); profCallgraphAdd(templ, ctxt->templ); } /* * Push the xsl:template declaration onto the stack. */ templPush(ctxt, templ); #ifdef WITH_XSLT_DEBUG_PROCESS if (templ->name != NULL) XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext, "applying xsl:template '%s'\n", templ->name)); #endif /* * Process xsl:param instructions and skip those elements for * further processing. */ cur = list; do { if (cur->type == XML_TEXT_NODE) { cur = cur->next; continue; } if ((cur->type != XML_ELEMENT_NODE) || (cur->name[0] != 'p') || (cur->psvi == NULL) || (! xmlStrEqual(cur->name, BAD_CAST "param")) || (! IS_XSLT_ELEM(cur))) { break; } list = cur->next; #ifdef XSLT_REFACTORED iparam = (xsltStyleItemParamPtr) cur->psvi; #else iparam = (xsltStylePreCompPtr) cur->psvi; #endif /* * Substitute xsl:param for a given xsl:with-param. * Since the XPath expression will reference the params/vars * by index, we need to slot the xsl:with-params in the * order of encountered xsl:params to keep the sequence of * params/variables in the stack exactly as it was at * compile time, */ tmpParam = NULL; if (withParams) { tmpParam = withParams; do { if ((tmpParam->name == (iparam->name)) && (tmpParam->nameURI == (iparam->ns))) { /* * Push the caller-parameter. */ xsltLocalVariablePush(ctxt, tmpParam, -1); break; } tmpParam = tmpParam->next; } while (tmpParam != NULL); } /* * Push the xsl:param. */ if (tmpParam == NULL) { /* * Note that we must assume that the added parameter * has a @depth of 0. */ xsltParseStylesheetParam(ctxt, cur); } cur = cur->next; } while (cur != NULL); /* * Process the sequence constructor. */ xsltApplySequenceConstructor(ctxt, contextNode, list, templ); /* * Remove remaining xsl:param and xsl:with-param items from * the stack. Don't free xsl:with-param items. */ if (ctxt->varsNr > ctxt->varsBase) xsltTemplateParamsCleanup(ctxt); ctxt->varsBase = oldVarsBase; /* * Clean up remaining local tree fragments. * This also frees fragments which are the result of * extension instructions. Should normally not be hit; but * just for the case xsltExtensionInstructionResultFinalize() * was not called by the extension author. */ if (oldLocalFragmentTop != ctxt->localRVT) { xmlDocPtr curdoc = ctxt->localRVT, tmp; do { tmp = curdoc; curdoc = (xmlDocPtr) curdoc->next; /* Need to housekeep localRVTBase */ if (tmp == ctxt->localRVTBase) ctxt->localRVTBase = curdoc; if (tmp->prev) tmp->prev->next = (xmlNodePtr) curdoc; if (curdoc) curdoc->prev = tmp->prev; xsltReleaseRVT(ctxt, tmp); } while (curdoc != oldLocalFragmentTop); } ctxt->localRVT = oldLocalFragmentTop; /* * Release user-created fragments stored in the scope * of xsl:template. Note that this mechanism is deprecated: * user code should now use xsltRegisterLocalRVT() instead * of the obsolete xsltRegisterTmpRVT(). */ if (ctxt->tmpRVT) { xmlDocPtr curdoc = ctxt->tmpRVT, tmp; while (curdoc != NULL) { tmp = curdoc; curdoc = (xmlDocPtr) curdoc->next; xsltReleaseRVT(ctxt, tmp); } } ctxt->tmpRVT = oldUserFragmentTop; /* * Pop the xsl:template declaration from the stack. */ templPop(ctxt); if (ctxt->profile) { long spent, child, total, end; end = xsltTimestamp(); child = profPop(ctxt); total = end - start; spent = total - child; if (spent <= 0) { /* * Not possible unless the original calibration failed * we can try to correct it on the fly. */ xsltCalibrateAdjust(spent); spent = 0; } templ->time += spent; if (ctxt->profNr > 0) ctxt->profTab[ctxt->profNr - 1] += total; } #ifdef WITH_DEBUGGER if ((ctxt->debugStatus != XSLT_DEBUG_NONE) && (addCallResult)) { xslDropCall(); } #endif } /** * xsltApplyOneTemplate: * @ctxt: a XSLT process context * @contextNode: the node in the source tree. * @list: the nodes of a sequence constructor * @templ: not used * @params: a set of parameters (xsl:param) or NULL * * Processes a sequence constructor on the current node in the source tree. * * @params are the already computed variable stack items; this function * pushes them on the variable stack, and pops them before exiting; it's * left to the caller to free or reuse @params afterwards. The initial * states of the variable stack will always be restored before this * function exits. * NOTE that this does *not* initiate a new distinct variable scope; i.e. * variables already on the stack are visible to the process. The caller's * side needs to start a new variable scope if needed (e.g. in exsl:function). * * @templ is obsolete and not used anymore (e.g. does not * provide a @templ); a non-NULL @templ might raise an error in the future. * * BIG NOTE: This function is not intended to process the content of an * xsl:template; it does not expect xsl:param instructions in @list and * will report errors if found. * * Called by: * - xsltEvalVariable() (variables.c) * - exsltFuncFunctionFunction() (libexsl/functions.c) */ void xsltApplyOneTemplate(xsltTransformContextPtr ctxt, xmlNodePtr contextNode, xmlNodePtr list, xsltTemplatePtr templ ATTRIBUTE_UNUSED, xsltStackElemPtr params) { if ((ctxt == NULL) || (list == NULL)) return; CHECK_STOPPED; if (params) { /* * This code should be obsolete - was previously used * by libexslt/functions.c, but due to bug 381319 the * logic there was changed. */ int oldVarsNr = ctxt->varsNr; /* * Push the given xsl:param(s) onto the variable stack. */ while (params != NULL) { xsltLocalVariablePush(ctxt, params, -1); params = params->next; } xsltApplySequenceConstructor(ctxt, contextNode, list, templ); /* * Pop the given xsl:param(s) from the stack but don't free them. */ xsltLocalVariablePop(ctxt, oldVarsNr, -2); } else xsltApplySequenceConstructor(ctxt, contextNode, list, templ); } /************************************************************************ * * * XSLT-1.1 extensions * * * ************************************************************************/ /** * xsltDocumentElem: * @ctxt: an XSLT processing context * @node: The current node * @inst: the instruction in the stylesheet * @castedComp: precomputed information * * Process an EXSLT/XSLT-1.1 document element */ void xsltDocumentElem(xsltTransformContextPtr ctxt, xmlNodePtr node, xmlNodePtr inst, xsltStylePreCompPtr castedComp) { #ifdef XSLT_REFACTORED xsltStyleItemDocumentPtr comp = (xsltStyleItemDocumentPtr) castedComp; #else xsltStylePreCompPtr comp = castedComp; #endif xsltStylesheetPtr style = NULL; int ret; xmlChar *filename = NULL, *prop, *elements; xmlChar *element, *end; xmlDocPtr res = NULL; xmlDocPtr oldOutput; xmlNodePtr oldInsert, root; const char *oldOutputFile; xsltOutputType oldType; xmlChar *URL = NULL; const xmlChar *method; const xmlChar *doctypePublic; const xmlChar *doctypeSystem; const xmlChar *version; const xmlChar *encoding; int redirect_write_append = 0; if ((ctxt == NULL) || (node == NULL) || (inst == NULL) || (comp == NULL)) return; if (comp->filename == NULL) { if (xmlStrEqual(inst->name, (const xmlChar *) "output")) { /* * The element "output" is in the namespace XSLT_SAXON_NAMESPACE * (http://icl.com/saxon) * The @file is in no namespace. */ #ifdef WITH_XSLT_DEBUG_EXTRA xsltGenericDebug(xsltGenericDebugContext, "Found saxon:output extension\n"); #endif URL = xsltEvalAttrValueTemplate(ctxt, inst, (const xmlChar *) "file", XSLT_SAXON_NAMESPACE); if (URL == NULL) URL = xsltEvalAttrValueTemplate(ctxt, inst, (const xmlChar *) "href", XSLT_SAXON_NAMESPACE); } else if (xmlStrEqual(inst->name, (const xmlChar *) "write")) { #ifdef WITH_XSLT_DEBUG_EXTRA xsltGenericDebug(xsltGenericDebugContext, "Found xalan:write extension\n"); #endif URL = xsltEvalAttrValueTemplate(ctxt, inst, (const xmlChar *) "select", XSLT_XALAN_NAMESPACE); if (URL != NULL) { xmlXPathCompExprPtr cmp; xmlChar *val; /* * Trying to handle bug #59212 * The value of the "select" attribute is an * XPath expression. * (see http://xml.apache.org/xalan-j/extensionslib.html#redirect) */ cmp = xmlXPathCompile(URL); val = xsltEvalXPathString(ctxt, cmp); xmlXPathFreeCompExpr(cmp); xmlFree(URL); URL = val; } if (URL == NULL) URL = xsltEvalAttrValueTemplate(ctxt, inst, (const xmlChar *) "file", XSLT_XALAN_NAMESPACE); if (URL == NULL) URL = xsltEvalAttrValueTemplate(ctxt, inst, (const xmlChar *) "href", XSLT_XALAN_NAMESPACE); } else if (xmlStrEqual(inst->name, (const xmlChar *) "document")) { URL = xsltEvalAttrValueTemplate(ctxt, inst, (const xmlChar *) "href", NULL); } } else { URL = xmlStrdup(comp->filename); } if (URL == NULL) { xsltTransformError(ctxt, NULL, inst, "xsltDocumentElem: href/URI-Reference not found\n"); return; } /* * If the computation failed, it's likely that the URL wasn't escaped */ filename = xmlBuildURI(URL, (const xmlChar *) ctxt->outputFile); if (filename == NULL) { xmlChar *escURL; escURL=xmlURIEscapeStr(URL, BAD_CAST ":/.?,"); if (escURL != NULL) { filename = xmlBuildURI(escURL, (const xmlChar *) ctxt->outputFile); xmlFree(escURL); } } if (filename == NULL) { xsltTransformError(ctxt, NULL, inst, "xsltDocumentElem: URL computation failed for %s\n", URL); xmlFree(URL); return; } /* * Security checking: can we write to this resource */ if (ctxt->sec != NULL) { ret = xsltCheckWrite(ctxt->sec, ctxt, filename); if (ret == 0) { xsltTransformError(ctxt, NULL, inst, "xsltDocumentElem: write rights for %s denied\n", filename); xmlFree(URL); xmlFree(filename); return; } } oldOutputFile = ctxt->outputFile; oldOutput = ctxt->output; oldInsert = ctxt->insert; oldType = ctxt->type; ctxt->outputFile = (const char *) filename; style = xsltNewStylesheet(); if (style == NULL) { xsltTransformError(ctxt, NULL, inst, "xsltDocumentElem: out of memory\n"); goto error; } /* * Version described in 1.1 draft allows full parameterization * of the output. */ prop = xsltEvalAttrValueTemplate(ctxt, inst, (const xmlChar *) "version", NULL); if (prop != NULL) { if (style->version != NULL) xmlFree(style->version); style->version = prop; } prop = xsltEvalAttrValueTemplate(ctxt, inst, (const xmlChar *) "encoding", NULL); if (prop != NULL) { if (style->encoding != NULL) xmlFree(style->encoding); style->encoding = prop; } prop = xsltEvalAttrValueTemplate(ctxt, inst, (const xmlChar *) "method", NULL); if (prop != NULL) { const xmlChar *URI; if (style->method != NULL) xmlFree(style->method); style->method = NULL; if (style->methodURI != NULL) xmlFree(style->methodURI); style->methodURI = NULL; URI = xsltGetQNameURI(inst, &prop); if (prop == NULL) { if (style != NULL) style->errors++; } else if (URI == NULL) { if ((xmlStrEqual(prop, (const xmlChar *) "xml")) || (xmlStrEqual(prop, (const xmlChar *) "html")) || (xmlStrEqual(prop, (const xmlChar *) "text"))) { style->method = prop; } else { xsltTransformError(ctxt, NULL, inst, "invalid value for method: %s\n", prop); if (style != NULL) style->warnings++; } } else { style->method = prop; style->methodURI = xmlStrdup(URI); } } prop = xsltEvalAttrValueTemplate(ctxt, inst, (const xmlChar *) "doctype-system", NULL); if (prop != NULL) { if (style->doctypeSystem != NULL) xmlFree(style->doctypeSystem); style->doctypeSystem = prop; } prop = xsltEvalAttrValueTemplate(ctxt, inst, (const xmlChar *) "doctype-public", NULL); if (prop != NULL) { if (style->doctypePublic != NULL) xmlFree(style->doctypePublic); style->doctypePublic = prop; } prop = xsltEvalAttrValueTemplate(ctxt, inst, (const xmlChar *) "standalone", NULL); if (prop != NULL) { if (xmlStrEqual(prop, (const xmlChar *) "yes")) { style->standalone = 1; } else if (xmlStrEqual(prop, (const xmlChar *) "no")) { style->standalone = 0; } else { xsltTransformError(ctxt, NULL, inst, "invalid value for standalone: %s\n", prop); if (style != NULL) style->warnings++; } xmlFree(prop); } prop = xsltEvalAttrValueTemplate(ctxt, inst, (const xmlChar *) "indent", NULL); if (prop != NULL) { if (xmlStrEqual(prop, (const xmlChar *) "yes")) { style->indent = 1; } else if (xmlStrEqual(prop, (const xmlChar *) "no")) { style->indent = 0; } else { xsltTransformError(ctxt, NULL, inst, "invalid value for indent: %s\n", prop); if (style != NULL) style->warnings++; } xmlFree(prop); } prop = xsltEvalAttrValueTemplate(ctxt, inst, (const xmlChar *) "omit-xml-declaration", NULL); if (prop != NULL) { if (xmlStrEqual(prop, (const xmlChar *) "yes")) { style->omitXmlDeclaration = 1; } else if (xmlStrEqual(prop, (const xmlChar *) "no")) { style->omitXmlDeclaration = 0; } else { xsltTransformError(ctxt, NULL, inst, "invalid value for omit-xml-declaration: %s\n", prop); if (style != NULL) style->warnings++; } xmlFree(prop); } elements = xsltEvalAttrValueTemplate(ctxt, inst, (const xmlChar *) "cdata-section-elements", NULL); if (elements != NULL) { if (style->stripSpaces == NULL) style->stripSpaces = xmlHashCreate(10); if (style->stripSpaces == NULL) return; element = elements; while (*element != 0) { while (IS_BLANK_CH(*element)) element++; if (*element == 0) break; end = element; while ((*end != 0) && (!IS_BLANK_CH(*end))) end++; element = xmlStrndup(element, end - element); if (element) { const xmlChar *URI; #ifdef WITH_XSLT_DEBUG_PARSING xsltGenericDebug(xsltGenericDebugContext, "add cdata section output element %s\n", element); #endif URI = xsltGetQNameURI(inst, &element); xmlHashAddEntry2(style->stripSpaces, element, URI, (xmlChar *) "cdata"); xmlFree(element); } element = end; } xmlFree(elements); } /* * Create a new document tree and process the element template */ XSLT_GET_IMPORT_PTR(method, style, method) XSLT_GET_IMPORT_PTR(doctypePublic, style, doctypePublic) XSLT_GET_IMPORT_PTR(doctypeSystem, style, doctypeSystem) XSLT_GET_IMPORT_PTR(version, style, version) XSLT_GET_IMPORT_PTR(encoding, style, encoding) if ((method != NULL) && (!xmlStrEqual(method, (const xmlChar *) "xml"))) { if (xmlStrEqual(method, (const xmlChar *) "html")) { ctxt->type = XSLT_OUTPUT_HTML; if (((doctypePublic != NULL) || (doctypeSystem != NULL))) res = htmlNewDoc(doctypeSystem, doctypePublic); else { if (version != NULL) { #ifdef XSLT_GENERATE_HTML_DOCTYPE xsltGetHTMLIDs(version, &doctypePublic, &doctypeSystem); #endif } res = htmlNewDocNoDtD(doctypeSystem, doctypePublic); } if (res == NULL) goto error; res->dict = ctxt->dict; xmlDictReference(res->dict); } else if (xmlStrEqual(method, (const xmlChar *) "xhtml")) { xsltTransformError(ctxt, NULL, inst, "xsltDocumentElem: unsupported method xhtml\n", style->method); ctxt->type = XSLT_OUTPUT_HTML; res = htmlNewDocNoDtD(doctypeSystem, doctypePublic); if (res == NULL) goto error; res->dict = ctxt->dict; xmlDictReference(res->dict); } else if (xmlStrEqual(method, (const xmlChar *) "text")) { ctxt->type = XSLT_OUTPUT_TEXT; res = xmlNewDoc(style->version); if (res == NULL) goto error; res->dict = ctxt->dict; xmlDictReference(res->dict); #ifdef WITH_XSLT_DEBUG xsltGenericDebug(xsltGenericDebugContext, "reusing transformation dict for output\n"); #endif } else { xsltTransformError(ctxt, NULL, inst, "xsltDocumentElem: unsupported method %s\n", style->method); goto error; } } else { ctxt->type = XSLT_OUTPUT_XML; res = xmlNewDoc(style->version); if (res == NULL) goto error; res->dict = ctxt->dict; xmlDictReference(res->dict); #ifdef WITH_XSLT_DEBUG xsltGenericDebug(xsltGenericDebugContext, "reusing transformation dict for output\n"); #endif } res->charset = XML_CHAR_ENCODING_UTF8; if (encoding != NULL) res->encoding = xmlStrdup(encoding); ctxt->output = res; ctxt->insert = (xmlNodePtr) res; xsltApplySequenceConstructor(ctxt, node, inst->children, NULL); /* * Do some post processing work depending on the generated output */ root = xmlDocGetRootElement(res); if (root != NULL) { const xmlChar *doctype = NULL; if ((root->ns != NULL) && (root->ns->prefix != NULL)) doctype = xmlDictQLookup(ctxt->dict, root->ns->prefix, root->name); if (doctype == NULL) doctype = root->name; /* * Apply the default selection of the method */ if ((method == NULL) && (root->ns == NULL) && (!xmlStrcasecmp(root->name, (const xmlChar *) "html"))) { xmlNodePtr tmp; tmp = res->children; while ((tmp != NULL) && (tmp != root)) { if (tmp->type == XML_ELEMENT_NODE) break; if ((tmp->type == XML_TEXT_NODE) && (!xmlIsBlankNode(tmp))) break; tmp = tmp->next; } if (tmp == root) { ctxt->type = XSLT_OUTPUT_HTML; res->type = XML_HTML_DOCUMENT_NODE; if (((doctypePublic != NULL) || (doctypeSystem != NULL))) { res->intSubset = xmlCreateIntSubset(res, doctype, doctypePublic, doctypeSystem); #ifdef XSLT_GENERATE_HTML_DOCTYPE } else if (version != NULL) { xsltGetHTMLIDs(version, &doctypePublic, &doctypeSystem); if (((doctypePublic != NULL) || (doctypeSystem != NULL))) res->intSubset = xmlCreateIntSubset(res, doctype, doctypePublic, doctypeSystem); #endif } } } if (ctxt->type == XSLT_OUTPUT_XML) { XSLT_GET_IMPORT_PTR(doctypePublic, style, doctypePublic) XSLT_GET_IMPORT_PTR(doctypeSystem, style, doctypeSystem) if (((doctypePublic != NULL) || (doctypeSystem != NULL))) res->intSubset = xmlCreateIntSubset(res, doctype, doctypePublic, doctypeSystem); } } /* * Calls to redirect:write also take an optional attribute append. * Attribute append="true|yes" which will attempt to simply append * to an existing file instead of always opening a new file. The * default behavior of always overwriting the file still happens * if we do not specify append. * Note that append use will forbid use of remote URI target. */ prop = xsltEvalAttrValueTemplate(ctxt, inst, (const xmlChar *)"append", NULL); if (prop != NULL) { if (xmlStrEqual(prop, (const xmlChar *) "true") || xmlStrEqual(prop, (const xmlChar *) "yes")) { style->omitXmlDeclaration = 1; redirect_write_append = 1; } else style->omitXmlDeclaration = 0; xmlFree(prop); } if (redirect_write_append) { FILE *f; f = fopen((const char *) filename, "ab"); if (f == NULL) { ret = -1; } else { ret = xsltSaveResultToFile(f, res, style); fclose(f); } } else { ret = xsltSaveResultToFilename((const char *) filename, res, style, 0); } if (ret < 0) { xsltTransformError(ctxt, NULL, inst, "xsltDocumentElem: unable to save to %s\n", filename); ctxt->state = XSLT_STATE_ERROR; #ifdef WITH_XSLT_DEBUG_EXTRA } else { xsltGenericDebug(xsltGenericDebugContext, "Wrote %d bytes to %s\n", ret, filename); #endif } error: ctxt->output = oldOutput; ctxt->insert = oldInsert; ctxt->type = oldType; ctxt->outputFile = oldOutputFile; if (URL != NULL) xmlFree(URL); if (filename != NULL) xmlFree(filename); if (style != NULL) xsltFreeStylesheet(style); if (res != NULL) xmlFreeDoc(res); } /************************************************************************ * * * Most of the XSLT-1.0 transformations * * * ************************************************************************/ /** * xsltSort: * @ctxt: a XSLT process context * @node: the node in the source tree. * @inst: the xslt sort node * @comp: precomputed information * * function attached to xsl:sort nodes, but this should not be * called directly */ void xsltSort(xsltTransformContextPtr ctxt, xmlNodePtr node ATTRIBUTE_UNUSED, xmlNodePtr inst, xsltStylePreCompPtr comp) { if (comp == NULL) { xsltTransformError(ctxt, NULL, inst, "xsl:sort : compilation failed\n"); return; } xsltTransformError(ctxt, NULL, inst, "xsl:sort : improper use this should not be reached\n"); } /** * xsltCopy: * @ctxt: an XSLT process context * @node: the node in the source tree * @inst: the element node of the XSLT-copy instruction * @castedComp: computed information of the XSLT-copy instruction * * Execute the XSLT-copy instruction on the source node. */ void xsltCopy(xsltTransformContextPtr ctxt, xmlNodePtr node, xmlNodePtr inst, xsltStylePreCompPtr castedComp) { #ifdef XSLT_REFACTORED xsltStyleItemCopyPtr comp = (xsltStyleItemCopyPtr) castedComp; #else xsltStylePreCompPtr comp = castedComp; #endif xmlNodePtr copy, oldInsert; oldInsert = ctxt->insert; if (ctxt->insert != NULL) { switch (node->type) { case XML_TEXT_NODE: case XML_CDATA_SECTION_NODE: /* * This text comes from the stylesheet * For stylesheets, the set of whitespace-preserving * element names consists of just xsl:text. */ #ifdef WITH_XSLT_DEBUG_PROCESS if (node->type == XML_CDATA_SECTION_NODE) { XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext, "xsltCopy: CDATA text %s\n", node->content)); } else { XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext, "xsltCopy: text %s\n", node->content)); } #endif xsltCopyText(ctxt, ctxt->insert, node, 0); break; case XML_DOCUMENT_NODE: case XML_HTML_DOCUMENT_NODE: break; case XML_ELEMENT_NODE: /* * REVISIT NOTE: The "fake" is a doc-node, not an element node. * REMOVED: * if (xmlStrEqual(node->name, BAD_CAST " fake node libxslt")) * return; */ #ifdef WITH_XSLT_DEBUG_PROCESS XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext, "xsltCopy: node %s\n", node->name)); #endif copy = xsltShallowCopyElem(ctxt, node, ctxt->insert, 0); ctxt->insert = copy; if (comp->use != NULL) { xsltApplyAttributeSet(ctxt, node, inst, comp->use); } break; case XML_ATTRIBUTE_NODE: { #ifdef WITH_XSLT_DEBUG_PROCESS XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext, "xsltCopy: attribute %s\n", node->name)); #endif /* * REVISIT: We could also raise an error if the parent is not * an element node. * OPTIMIZE TODO: Can we set the value/children of the * attribute without an intermediate copy of the string value? */ xsltShallowCopyAttr(ctxt, inst, ctxt->insert, (xmlAttrPtr) node); break; } case XML_PI_NODE: #ifdef WITH_XSLT_DEBUG_PROCESS XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext, "xsltCopy: PI %s\n", node->name)); #endif copy = xmlNewDocPI(ctxt->insert->doc, node->name, node->content); copy = xsltAddChild(ctxt->insert, copy); break; case XML_COMMENT_NODE: #ifdef WITH_XSLT_DEBUG_PROCESS XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext, "xsltCopy: comment\n")); #endif copy = xmlNewComment(node->content); copy = xsltAddChild(ctxt->insert, copy); break; case XML_NAMESPACE_DECL: #ifdef WITH_XSLT_DEBUG_PROCESS XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext, "xsltCopy: namespace declaration\n")); #endif xsltShallowCopyNsNode(ctxt, inst, ctxt->insert, (xmlNsPtr)node); break; default: break; } } switch (node->type) { case XML_DOCUMENT_NODE: case XML_HTML_DOCUMENT_NODE: case XML_ELEMENT_NODE: xsltApplySequenceConstructor(ctxt, ctxt->node, inst->children, NULL); break; default: break; } ctxt->insert = oldInsert; } /** * xsltText: * @ctxt: a XSLT process context * @node: the node in the source tree. * @inst: the xslt text node * @comp: precomputed information * * Process the xslt text node on the source node */ void xsltText(xsltTransformContextPtr ctxt, xmlNodePtr node ATTRIBUTE_UNUSED, xmlNodePtr inst, xsltStylePreCompPtr comp ATTRIBUTE_UNUSED) { if ((inst->children != NULL) && (comp != NULL)) { xmlNodePtr text = inst->children; xmlNodePtr copy; while (text != NULL) { if ((text->type != XML_TEXT_NODE) && (text->type != XML_CDATA_SECTION_NODE)) { xsltTransformError(ctxt, NULL, inst, "xsl:text content problem\n"); break; } copy = xmlNewDocText(ctxt->output, text->content); if (text->type != XML_CDATA_SECTION_NODE) { #ifdef WITH_XSLT_DEBUG_PARSING xsltGenericDebug(xsltGenericDebugContext, "Disable escaping: %s\n", text->content); #endif copy->name = xmlStringTextNoenc; } copy = xsltAddChild(ctxt->insert, copy); text = text->next; } } } /** * xsltElement: * @ctxt: a XSLT process context * @node: the node in the source tree. * @inst: the xslt element node * @castedComp: precomputed information * * Process the xslt element node on the source node */ void xsltElement(xsltTransformContextPtr ctxt, xmlNodePtr node, xmlNodePtr inst, xsltStylePreCompPtr castedComp) { #ifdef XSLT_REFACTORED xsltStyleItemElementPtr comp = (xsltStyleItemElementPtr) castedComp; #else xsltStylePreCompPtr comp = castedComp; #endif xmlChar *prop = NULL; const xmlChar *name, *prefix = NULL, *nsName = NULL; xmlNodePtr copy; xmlNodePtr oldInsert; if (ctxt->insert == NULL) return; /* * A comp->has_name == 0 indicates that we need to skip this instruction, * since it was evaluated to be invalid already during compilation. */ if (!comp->has_name) return; /* * stack and saves */ oldInsert = ctxt->insert; if (comp->name == NULL) { /* TODO: fix attr acquisition wrt to the XSLT namespace */ prop = xsltEvalAttrValueTemplate(ctxt, inst, (const xmlChar *) "name", XSLT_NAMESPACE); if (prop == NULL) { xsltTransformError(ctxt, NULL, inst, "xsl:element: The attribute 'name' is missing.\n"); goto error; } if (xmlValidateQName(prop, 0)) { xsltTransformError(ctxt, NULL, inst, "xsl:element: The effective name '%s' is not a " "valid QName.\n", prop); /* we fall through to catch any further errors, if possible */ } name = xsltSplitQName(ctxt->dict, prop, &prefix); xmlFree(prop); } else { /* * The "name" value was static. */ #ifdef XSLT_REFACTORED prefix = comp->nsPrefix; name = comp->name; #else name = xsltSplitQName(ctxt->dict, comp->name, &prefix); #endif } /* * Create the new element */ if (ctxt->output->dict == ctxt->dict) { copy = xmlNewDocNodeEatName(ctxt->output, NULL, (xmlChar *)name, NULL); } else { copy = xmlNewDocNode(ctxt->output, NULL, (xmlChar *)name, NULL); } if (copy == NULL) { xsltTransformError(ctxt, NULL, inst, "xsl:element : creation of %s failed\n", name); return; } copy = xsltAddChild(ctxt->insert, copy); /* * Namespace * --------- */ if (comp->has_ns) { if (comp->ns != NULL) { /* * No AVT; just plain text for the namespace name. */ if (comp->ns[0] != 0) nsName = comp->ns; } else { xmlChar *tmpNsName; /* * Eval the AVT. */ /* TODO: check attr acquisition wrt to the XSLT namespace */ tmpNsName = xsltEvalAttrValueTemplate(ctxt, inst, (const xmlChar *) "namespace", XSLT_NAMESPACE); /* * SPEC XSLT 1.0: * "If the string is empty, then the expanded-name of the * attribute has a null namespace URI." */ if ((tmpNsName != NULL) && (tmpNsName[0] != 0)) nsName = xmlDictLookup(ctxt->dict, BAD_CAST tmpNsName, -1); xmlFree(tmpNsName); } if (xmlStrEqual(nsName, BAD_CAST "http://www.w3.org/2000/xmlns/")) { xsltTransformError(ctxt, NULL, inst, "xsl:attribute: Namespace http://www.w3.org/2000/xmlns/ " "forbidden.\n"); goto error; } if (xmlStrEqual(nsName, XML_XML_NAMESPACE)) { prefix = BAD_CAST "xml"; } else if (xmlStrEqual(prefix, BAD_CAST "xml")) { prefix = NULL; } } else { xmlNsPtr ns; /* * SPEC XSLT 1.0: * "If the namespace attribute is not present, then the QName is * expanded into an expanded-name using the namespace declarations * in effect for the xsl:element element, including any default * namespace declaration. */ ns = xmlSearchNs(inst->doc, inst, prefix); if (ns == NULL) { /* * TODO: Check this in the compilation layer in case it's a * static value. */ if (prefix != NULL) { xsltTransformError(ctxt, NULL, inst, "xsl:element: The QName '%s:%s' has no " "namespace binding in scope in the stylesheet; " "this is an error, since the namespace was not " "specified by the instruction itself.\n", prefix, name); } } else nsName = ns->href; } /* * Find/create a matching ns-decl in the result tree. */ if (nsName != NULL) { if (xmlStrEqual(prefix, BAD_CAST "xmlns")) { /* Don't use a prefix of "xmlns" */ xmlChar *pref = xmlStrdup(BAD_CAST "ns_1"); copy->ns = xsltGetSpecialNamespace(ctxt, inst, nsName, pref, copy); xmlFree(pref); } else { copy->ns = xsltGetSpecialNamespace(ctxt, inst, nsName, prefix, copy); } } else if ((copy->parent != NULL) && (copy->parent->type == XML_ELEMENT_NODE) && (copy->parent->ns != NULL)) { /* * "Undeclare" the default namespace. */ xsltGetSpecialNamespace(ctxt, inst, NULL, NULL, copy); } ctxt->insert = copy; if (comp->has_use) { if (comp->use != NULL) { xsltApplyAttributeSet(ctxt, node, inst, comp->use); } else { xmlChar *attrSets = NULL; /* * BUG TODO: use-attribute-sets is not a value template. * use-attribute-sets = qnames */ attrSets = xsltEvalAttrValueTemplate(ctxt, inst, (const xmlChar *)"use-attribute-sets", NULL); if (attrSets != NULL) { xsltApplyAttributeSet(ctxt, node, inst, attrSets); xmlFree(attrSets); } } } /* * Instantiate the sequence constructor. */ if (inst->children != NULL) xsltApplySequenceConstructor(ctxt, ctxt->node, inst->children, NULL); error: ctxt->insert = oldInsert; return; } /** * xsltComment: * @ctxt: a XSLT process context * @node: the node in the source tree. * @inst: the xslt comment node * @comp: precomputed information * * Process the xslt comment node on the source node */ void xsltComment(xsltTransformContextPtr ctxt, xmlNodePtr node, xmlNodePtr inst, xsltStylePreCompPtr comp ATTRIBUTE_UNUSED) { xmlChar *value = NULL; xmlNodePtr commentNode; int len; value = xsltEvalTemplateString(ctxt, node, inst); /* TODO: use or generate the compiled form */ len = xmlStrlen(value); if (len > 0) { if ((value[len-1] == '-') || (xmlStrstr(value, BAD_CAST "--"))) { xsltTransformError(ctxt, NULL, inst, "xsl:comment : '--' or ending '-' not allowed in comment\n"); /* fall through to try to catch further errors */ } } #ifdef WITH_XSLT_DEBUG_PROCESS if (value == NULL) { XSLT_TRACE(ctxt,XSLT_TRACE_COMMENT,xsltGenericDebug(xsltGenericDebugContext, "xsltComment: empty\n")); } else { XSLT_TRACE(ctxt,XSLT_TRACE_COMMENT,xsltGenericDebug(xsltGenericDebugContext, "xsltComment: content %s\n", value)); } #endif commentNode = xmlNewComment(value); commentNode = xsltAddChild(ctxt->insert, commentNode); if (value != NULL) xmlFree(value); } /** * xsltProcessingInstruction: * @ctxt: a XSLT process context * @node: the node in the source tree. * @inst: the xslt processing-instruction node * @castedComp: precomputed information * * Process the xslt processing-instruction node on the source node */ void xsltProcessingInstruction(xsltTransformContextPtr ctxt, xmlNodePtr node, xmlNodePtr inst, xsltStylePreCompPtr castedComp) { #ifdef XSLT_REFACTORED xsltStyleItemPIPtr comp = (xsltStyleItemPIPtr) castedComp; #else xsltStylePreCompPtr comp = castedComp; #endif const xmlChar *name; xmlChar *value = NULL; xmlNodePtr pi; if (ctxt->insert == NULL) return; if (comp->has_name == 0) return; if (comp->name == NULL) { name = xsltEvalAttrValueTemplate(ctxt, inst, (const xmlChar *)"name", NULL); if (name == NULL) { xsltTransformError(ctxt, NULL, inst, "xsl:processing-instruction : name is missing\n"); goto error; } } else { name = comp->name; } /* TODO: check that it's both an an NCName and a PITarget. */ value = xsltEvalTemplateString(ctxt, node, inst); if (xmlStrstr(value, BAD_CAST "?>") != NULL) { xsltTransformError(ctxt, NULL, inst, "xsl:processing-instruction: '?>' not allowed within PI content\n"); goto error; } #ifdef WITH_XSLT_DEBUG_PROCESS if (value == NULL) { XSLT_TRACE(ctxt,XSLT_TRACE_PI,xsltGenericDebug(xsltGenericDebugContext, "xsltProcessingInstruction: %s empty\n", name)); } else { XSLT_TRACE(ctxt,XSLT_TRACE_PI,xsltGenericDebug(xsltGenericDebugContext, "xsltProcessingInstruction: %s content %s\n", name, value)); } #endif pi = xmlNewDocPI(ctxt->insert->doc, name, value); pi = xsltAddChild(ctxt->insert, pi); error: if ((name != NULL) && (name != comp->name)) xmlFree((xmlChar *) name); if (value != NULL) xmlFree(value); } /** * xsltCopyOf: * @ctxt: an XSLT transformation context * @node: the current node in the source tree * @inst: the element node of the XSLT copy-of instruction * @castedComp: precomputed information of the XSLT copy-of instruction * * Process the XSLT copy-of instruction. */ void xsltCopyOf(xsltTransformContextPtr ctxt, xmlNodePtr node, xmlNodePtr inst, xsltStylePreCompPtr castedComp) { #ifdef XSLT_REFACTORED xsltStyleItemCopyOfPtr comp = (xsltStyleItemCopyOfPtr) castedComp; #else xsltStylePreCompPtr comp = castedComp; #endif xmlXPathObjectPtr res = NULL; xmlNodeSetPtr list = NULL; int i; xmlDocPtr oldXPContextDoc; xmlNsPtr *oldXPNamespaces; xmlNodePtr oldXPContextNode; int oldXPProximityPosition, oldXPContextSize, oldXPNsNr; xmlXPathContextPtr xpctxt; if ((ctxt == NULL) || (node == NULL) || (inst == NULL)) return; if ((comp == NULL) || (comp->select == NULL) || (comp->comp == NULL)) { xsltTransformError(ctxt, NULL, inst, "xsl:copy-of : compilation failed\n"); return; } /* * SPEC XSLT 1.0: * "The xsl:copy-of element can be used to insert a result tree * fragment into the result tree, without first converting it to * a string as xsl:value-of does (see [7.6.1 Generating Text with * xsl:value-of]). The required select attribute contains an * expression. When the result of evaluating the expression is a * result tree fragment, the complete fragment is copied into the * result tree. When the result is a node-set, all the nodes in the * set are copied in document order into the result tree; copying * an element node copies the attribute nodes, namespace nodes and * children of the element node as well as the element node itself; * a root node is copied by copying its children. When the result * is neither a node-set nor a result tree fragment, the result is * converted to a string and then inserted into the result tree, * as with xsl:value-of. */ #ifdef WITH_XSLT_DEBUG_PROCESS XSLT_TRACE(ctxt,XSLT_TRACE_COPY_OF,xsltGenericDebug(xsltGenericDebugContext, "xsltCopyOf: select %s\n", comp->select)); #endif /* * Evaluate the "select" expression. */ xpctxt = ctxt->xpathCtxt; oldXPContextDoc = xpctxt->doc; oldXPContextNode = xpctxt->node; oldXPProximityPosition = xpctxt->proximityPosition; oldXPContextSize = xpctxt->contextSize; oldXPNsNr = xpctxt->nsNr; oldXPNamespaces = xpctxt->namespaces; xpctxt->node = node; if (comp != NULL) { #ifdef XSLT_REFACTORED if (comp->inScopeNs != NULL) { xpctxt->namespaces = comp->inScopeNs->list; xpctxt->nsNr = comp->inScopeNs->xpathNumber; } else { xpctxt->namespaces = NULL; xpctxt->nsNr = 0; } #else xpctxt->namespaces = comp->nsList; xpctxt->nsNr = comp->nsNr; #endif } else { xpctxt->namespaces = NULL; xpctxt->nsNr = 0; } res = xmlXPathCompiledEval(comp->comp, xpctxt); xpctxt->doc = oldXPContextDoc; xpctxt->node = oldXPContextNode; xpctxt->contextSize = oldXPContextSize; xpctxt->proximityPosition = oldXPProximityPosition; xpctxt->nsNr = oldXPNsNr; xpctxt->namespaces = oldXPNamespaces; if (res != NULL) { if (res->type == XPATH_NODESET) { /* * Node-set * -------- */ #ifdef WITH_XSLT_DEBUG_PROCESS XSLT_TRACE(ctxt,XSLT_TRACE_COPY_OF,xsltGenericDebug(xsltGenericDebugContext, "xsltCopyOf: result is a node set\n")); #endif list = res->nodesetval; if (list != NULL) { xmlNodePtr cur; /* * The list is already sorted in document order by XPath. * Append everything in this order under ctxt->insert. */ for (i = 0;i < list->nodeNr;i++) { cur = list->nodeTab[i]; if (cur == NULL) continue; if ((cur->type == XML_DOCUMENT_NODE) || (cur->type == XML_HTML_DOCUMENT_NODE)) { xsltCopyTreeList(ctxt, inst, cur->children, ctxt->insert, 0, 0); } else if (cur->type == XML_ATTRIBUTE_NODE) { xsltShallowCopyAttr(ctxt, inst, ctxt->insert, (xmlAttrPtr) cur); } else { xsltCopyTreeInternal(ctxt, inst, cur, ctxt->insert, 0, 0); } } } } else if (res->type == XPATH_XSLT_TREE) { /* * Result tree fragment * -------------------- * E.g. via * Note that the root node of such trees is an xmlDocPtr in Libxslt. */ #ifdef WITH_XSLT_DEBUG_PROCESS XSLT_TRACE(ctxt,XSLT_TRACE_COPY_OF,xsltGenericDebug(xsltGenericDebugContext, "xsltCopyOf: result is a result tree fragment\n")); #endif list = res->nodesetval; if ((list != NULL) && (list->nodeTab != NULL) && (list->nodeTab[0] != NULL) && (IS_XSLT_REAL_NODE(list->nodeTab[0]))) { xsltCopyTreeList(ctxt, inst, list->nodeTab[0]->children, ctxt->insert, 0, 0); } } else { xmlChar *value = NULL; /* * Convert to a string. */ value = xmlXPathCastToString(res); if (value == NULL) { xsltTransformError(ctxt, NULL, inst, "Internal error in xsltCopyOf(): " "failed to cast an XPath object to string.\n"); ctxt->state = XSLT_STATE_STOPPED; } else { if (value[0] != 0) { /* * Append content as text node. */ xsltCopyTextString(ctxt, ctxt->insert, value, 0); } xmlFree(value); #ifdef WITH_XSLT_DEBUG_PROCESS XSLT_TRACE(ctxt,XSLT_TRACE_COPY_OF,xsltGenericDebug(xsltGenericDebugContext, "xsltCopyOf: result %s\n", res->stringval)); #endif } } } else { ctxt->state = XSLT_STATE_STOPPED; } if (res != NULL) xmlXPathFreeObject(res); } /** * xsltValueOf: * @ctxt: a XSLT process context * @node: the node in the source tree. * @inst: the xslt value-of node * @castedComp: precomputed information * * Process the xslt value-of node on the source node */ void xsltValueOf(xsltTransformContextPtr ctxt, xmlNodePtr node, xmlNodePtr inst, xsltStylePreCompPtr castedComp) { #ifdef XSLT_REFACTORED xsltStyleItemValueOfPtr comp = (xsltStyleItemValueOfPtr) castedComp; #else xsltStylePreCompPtr comp = castedComp; #endif xmlXPathObjectPtr res = NULL; xmlChar *value = NULL; xmlDocPtr oldXPContextDoc; xmlNsPtr *oldXPNamespaces; xmlNodePtr oldXPContextNode; int oldXPProximityPosition, oldXPContextSize, oldXPNsNr; xmlXPathContextPtr xpctxt; if ((ctxt == NULL) || (node == NULL) || (inst == NULL)) return; if ((comp == NULL) || (comp->select == NULL) || (comp->comp == NULL)) { xsltTransformError(ctxt, NULL, inst, "Internal error in xsltValueOf(): " "The XSLT 'value-of' instruction was not compiled.\n"); return; } #ifdef WITH_XSLT_DEBUG_PROCESS XSLT_TRACE(ctxt,XSLT_TRACE_VALUE_OF,xsltGenericDebug(xsltGenericDebugContext, "xsltValueOf: select %s\n", comp->select)); #endif xpctxt = ctxt->xpathCtxt; oldXPContextDoc = xpctxt->doc; oldXPContextNode = xpctxt->node; oldXPProximityPosition = xpctxt->proximityPosition; oldXPContextSize = xpctxt->contextSize; oldXPNsNr = xpctxt->nsNr; oldXPNamespaces = xpctxt->namespaces; xpctxt->node = node; if (comp != NULL) { #ifdef XSLT_REFACTORED if (comp->inScopeNs != NULL) { xpctxt->namespaces = comp->inScopeNs->list; xpctxt->nsNr = comp->inScopeNs->xpathNumber; } else { xpctxt->namespaces = NULL; xpctxt->nsNr = 0; } #else xpctxt->namespaces = comp->nsList; xpctxt->nsNr = comp->nsNr; #endif } else { xpctxt->namespaces = NULL; xpctxt->nsNr = 0; } res = xmlXPathCompiledEval(comp->comp, xpctxt); xpctxt->doc = oldXPContextDoc; xpctxt->node = oldXPContextNode; xpctxt->contextSize = oldXPContextSize; xpctxt->proximityPosition = oldXPProximityPosition; xpctxt->nsNr = oldXPNsNr; xpctxt->namespaces = oldXPNamespaces; /* * Cast the XPath object to string. */ if (res != NULL) { value = xmlXPathCastToString(res); if (value == NULL) { xsltTransformError(ctxt, NULL, inst, "Internal error in xsltValueOf(): " "failed to cast an XPath object to string.\n"); ctxt->state = XSLT_STATE_STOPPED; goto error; } if (value[0] != 0) { xsltCopyTextString(ctxt, ctxt->insert, value, comp->noescape); } } else { xsltTransformError(ctxt, NULL, inst, "XPath evaluation returned no result.\n"); ctxt->state = XSLT_STATE_STOPPED; goto error; } #ifdef WITH_XSLT_DEBUG_PROCESS if (value) { XSLT_TRACE(ctxt,XSLT_TRACE_VALUE_OF,xsltGenericDebug(xsltGenericDebugContext, "xsltValueOf: result '%s'\n", value)); } #endif error: if (value != NULL) xmlFree(value); if (res != NULL) xmlXPathFreeObject(res); } /** * xsltNumber: * @ctxt: a XSLT process context * @node: the node in the source tree. * @inst: the xslt number node * @castedComp: precomputed information * * Process the xslt number node on the source node */ void xsltNumber(xsltTransformContextPtr ctxt, xmlNodePtr node, xmlNodePtr inst, xsltStylePreCompPtr castedComp) { #ifdef XSLT_REFACTORED xsltStyleItemNumberPtr comp = (xsltStyleItemNumberPtr) castedComp; #else xsltStylePreCompPtr comp = castedComp; #endif if (comp == NULL) { xsltTransformError(ctxt, NULL, inst, "xsl:number : compilation failed\n"); return; } if ((ctxt == NULL) || (node == NULL) || (inst == NULL) || (comp == NULL)) return; comp->numdata.doc = inst->doc; comp->numdata.node = inst; xsltNumberFormat(ctxt, &comp->numdata, node); } /** * xsltApplyImports: * @ctxt: an XSLT transformation context * @contextNode: the current node in the source tree. * @inst: the element node of the XSLT 'apply-imports' instruction * @comp: the compiled instruction * * Process the XSLT apply-imports element. */ void xsltApplyImports(xsltTransformContextPtr ctxt, xmlNodePtr contextNode, xmlNodePtr inst, xsltStylePreCompPtr comp ATTRIBUTE_UNUSED) { xsltTemplatePtr templ; if ((ctxt == NULL) || (inst == NULL)) return; if (comp == NULL) { xsltTransformError(ctxt, NULL, inst, "Internal error in xsltApplyImports(): " "The XSLT 'apply-imports' instruction was not compiled.\n"); return; } /* * NOTE that ctxt->currentTemplateRule and ctxt->templ is not the * same; the former is the "Current Template Rule" as defined by the * XSLT spec, the latter is simply the template struct being * currently processed. */ if (ctxt->currentTemplateRule == NULL) { /* * SPEC XSLT 2.0: * "[ERR XTDE0560] It is a non-recoverable dynamic error if * xsl:apply-imports or xsl:next-match is evaluated when the * current template rule is null." */ xsltTransformError(ctxt, NULL, inst, "It is an error to call 'apply-imports' " "when there's no current template rule.\n"); return; } /* * TODO: Check if this is correct. */ templ = xsltGetTemplate(ctxt, contextNode, ctxt->currentTemplateRule->style); if (templ != NULL) { xsltTemplatePtr oldCurTemplRule = ctxt->currentTemplateRule; /* * Set the current template rule. */ ctxt->currentTemplateRule = templ; /* * URGENT TODO: Need xsl:with-param be handled somehow here? */ xsltApplyXSLTTemplate(ctxt, contextNode, templ->content, templ, NULL); ctxt->currentTemplateRule = oldCurTemplRule; } } /** * xsltCallTemplate: * @ctxt: a XSLT transformation context * @node: the "current node" in the source tree * @inst: the XSLT 'call-template' instruction * @castedComp: the compiled information of the instruction * * Processes the XSLT call-template instruction on the source node. */ void xsltCallTemplate(xsltTransformContextPtr ctxt, xmlNodePtr node, xmlNodePtr inst, xsltStylePreCompPtr castedComp) { #ifdef XSLT_REFACTORED xsltStyleItemCallTemplatePtr comp = (xsltStyleItemCallTemplatePtr) castedComp; #else xsltStylePreCompPtr comp = castedComp; #endif xsltStackElemPtr withParams = NULL; if (ctxt->insert == NULL) return; if (comp == NULL) { xsltTransformError(ctxt, NULL, inst, "The XSLT 'call-template' instruction was not compiled.\n"); return; } /* * The template must have been precomputed */ if (comp->templ == NULL) { comp->templ = xsltFindTemplate(ctxt, comp->name, comp->ns); if (comp->templ == NULL) { if (comp->ns != NULL) { xsltTransformError(ctxt, NULL, inst, "The called template '{%s}%s' was not found.\n", comp->ns, comp->name); } else { xsltTransformError(ctxt, NULL, inst, "The called template '%s' was not found.\n", comp->name); } return; } } #ifdef WITH_XSLT_DEBUG_PROCESS if ((comp != NULL) && (comp->name != NULL)) XSLT_TRACE(ctxt,XSLT_TRACE_CALL_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext, "call-template: name %s\n", comp->name)); #endif if (inst->children) { xmlNodePtr cur; xsltStackElemPtr param; cur = inst->children; while (cur != NULL) { #ifdef WITH_DEBUGGER if (ctxt->debugStatus != XSLT_DEBUG_NONE) xslHandleDebugger(cur, node, comp->templ, ctxt); #endif if (ctxt->state == XSLT_STATE_STOPPED) break; /* * TODO: The "with-param"s could be part of the "call-template" * structure. Avoid to "search" for params dynamically * in the XML tree every time. */ if (IS_XSLT_ELEM(cur)) { if (IS_XSLT_NAME(cur, "with-param")) { param = xsltParseStylesheetCallerParam(ctxt, cur); if (param != NULL) { param->next = withParams; withParams = param; } } else { xsltGenericError(xsltGenericErrorContext, "xsl:call-template: misplaced xsl:%s\n", cur->name); } } else { xsltGenericError(xsltGenericErrorContext, "xsl:call-template: misplaced %s element\n", cur->name); } cur = cur->next; } } /* * Create a new frame using the params first */ xsltApplyXSLTTemplate(ctxt, node, comp->templ->content, comp->templ, withParams); if (withParams != NULL) xsltFreeStackElemList(withParams); #ifdef WITH_XSLT_DEBUG_PROCESS if ((comp != NULL) && (comp->name != NULL)) XSLT_TRACE(ctxt,XSLT_TRACE_CALL_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext, "call-template returned: name %s\n", comp->name)); #endif } /** * xsltApplyTemplates: * @ctxt: a XSLT transformation context * @node: the 'current node' in the source tree * @inst: the element node of an XSLT 'apply-templates' instruction * @castedComp: the compiled instruction * * Processes the XSLT 'apply-templates' instruction on the current node. */ void xsltApplyTemplates(xsltTransformContextPtr ctxt, xmlNodePtr node, xmlNodePtr inst, xsltStylePreCompPtr castedComp) { #ifdef XSLT_REFACTORED xsltStyleItemApplyTemplatesPtr comp = (xsltStyleItemApplyTemplatesPtr) castedComp; #else xsltStylePreCompPtr comp = castedComp; #endif int i; xmlNodePtr cur, delNode = NULL, oldContextNode; xmlNodeSetPtr list = NULL, oldList; xsltStackElemPtr withParams = NULL; int oldXPProximityPosition, oldXPContextSize, oldXPNsNr; const xmlChar *oldMode, *oldModeURI; xmlDocPtr oldXPDoc; xsltDocumentPtr oldDocInfo; xmlXPathContextPtr xpctxt; xmlNsPtr *oldXPNamespaces; if (comp == NULL) { xsltTransformError(ctxt, NULL, inst, "xsl:apply-templates : compilation failed\n"); return; } if ((ctxt == NULL) || (node == NULL) || (inst == NULL) || (comp == NULL)) return; #ifdef WITH_XSLT_DEBUG_PROCESS if ((node != NULL) && (node->name != NULL)) XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext, "xsltApplyTemplates: node: '%s'\n", node->name)); #endif xpctxt = ctxt->xpathCtxt; /* * Save context states. */ oldContextNode = ctxt->node; oldMode = ctxt->mode; oldModeURI = ctxt->modeURI; oldDocInfo = ctxt->document; oldList = ctxt->nodeList; /* * The xpath context size and proximity position, as * well as the xpath and context documents, may be changed * so we save their initial state and will restore on exit */ oldXPContextSize = xpctxt->contextSize; oldXPProximityPosition = xpctxt->proximityPosition; oldXPDoc = xpctxt->doc; oldXPNsNr = xpctxt->nsNr; oldXPNamespaces = xpctxt->namespaces; /* * Set up contexts. */ ctxt->mode = comp->mode; ctxt->modeURI = comp->modeURI; if (comp->select != NULL) { xmlXPathObjectPtr res = NULL; if (comp->comp == NULL) { xsltTransformError(ctxt, NULL, inst, "xsl:apply-templates : compilation failed\n"); goto error; } #ifdef WITH_XSLT_DEBUG_PROCESS XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext, "xsltApplyTemplates: select %s\n", comp->select)); #endif /* * Set up XPath. */ xpctxt->node = node; /* Set the "context node" */ #ifdef XSLT_REFACTORED if (comp->inScopeNs != NULL) { xpctxt->namespaces = comp->inScopeNs->list; xpctxt->nsNr = comp->inScopeNs->xpathNumber; } else { xpctxt->namespaces = NULL; xpctxt->nsNr = 0; } #else xpctxt->namespaces = comp->nsList; xpctxt->nsNr = comp->nsNr; #endif res = xmlXPathCompiledEval(comp->comp, xpctxt); xpctxt->contextSize = oldXPContextSize; xpctxt->proximityPosition = oldXPProximityPosition; if (res != NULL) { if (res->type == XPATH_NODESET) { list = res->nodesetval; /* consume the node set */ res->nodesetval = NULL; } else { xsltTransformError(ctxt, NULL, inst, "The 'select' expression did not evaluate to a " "node set.\n"); ctxt->state = XSLT_STATE_STOPPED; xmlXPathFreeObject(res); goto error; } xmlXPathFreeObject(res); /* * Note: An xsl:apply-templates with a 'select' attribute, * can change the current source doc. */ } else { xsltTransformError(ctxt, NULL, inst, "Failed to evaluate the 'select' expression.\n"); ctxt->state = XSLT_STATE_STOPPED; goto error; } if (list == NULL) { #ifdef WITH_XSLT_DEBUG_PROCESS XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext, "xsltApplyTemplates: select didn't evaluate to a node list\n")); #endif goto exit; } /* * * NOTE: Previously a document info (xsltDocument) was * created and attached to the Result Tree Fragment. * But such a document info is created on demand in * xsltKeyFunction() (functions.c), so we need to create * it here beforehand. * In order to take care of potential keys we need to * do some extra work for the case when a Result Tree Fragment * is converted into a nodeset (e.g. exslt:node-set()) : * We attach a "pseudo-doc" (xsltDocument) to _private. * This xsltDocument, together with the keyset, will be freed * when the Result Tree Fragment is freed. * */ #if 0 if ((ctxt->nbKeys > 0) && (list->nodeNr != 0) && (list->nodeTab[0]->doc != NULL) && XSLT_IS_RES_TREE_FRAG(list->nodeTab[0]->doc)) { /* * NOTE that it's also OK if @effectiveDocInfo will be * set to NULL. */ isRTF = 1; effectiveDocInfo = list->nodeTab[0]->doc->_private; } #endif } else { /* * Build an XPath node set with the children */ list = xmlXPathNodeSetCreate(NULL); if (list == NULL) goto error; if (node->type != XML_NAMESPACE_DECL) cur = node->children; else cur = NULL; while (cur != NULL) { switch (cur->type) { case XML_TEXT_NODE: if ((IS_BLANK_NODE(cur)) && (cur->parent != NULL) && (cur->parent->type == XML_ELEMENT_NODE) && (ctxt->style->stripSpaces != NULL)) { const xmlChar *val; if (cur->parent->ns != NULL) { val = (const xmlChar *) xmlHashLookup2(ctxt->style->stripSpaces, cur->parent->name, cur->parent->ns->href); if (val == NULL) { val = (const xmlChar *) xmlHashLookup2(ctxt->style->stripSpaces, BAD_CAST "*", cur->parent->ns->href); } } else { val = (const xmlChar *) xmlHashLookup2(ctxt->style->stripSpaces, cur->parent->name, NULL); } if ((val != NULL) && (xmlStrEqual(val, (xmlChar *) "strip"))) { delNode = cur; break; } } /* no break on purpose */ case XML_ELEMENT_NODE: case XML_DOCUMENT_NODE: case XML_HTML_DOCUMENT_NODE: case XML_CDATA_SECTION_NODE: case XML_PI_NODE: case XML_COMMENT_NODE: xmlXPathNodeSetAddUnique(list, cur); break; case XML_DTD_NODE: /* Unlink the DTD, it's still reachable * using doc->intSubset */ if (cur->next != NULL) cur->next->prev = cur->prev; if (cur->prev != NULL) cur->prev->next = cur->next; break; case XML_NAMESPACE_DECL: break; default: #ifdef WITH_XSLT_DEBUG_PROCESS XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext, "xsltApplyTemplates: skipping cur type %d\n", cur->type)); #endif delNode = cur; } cur = cur->next; if (delNode != NULL) { #ifdef WITH_XSLT_DEBUG_PROCESS XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext, "xsltApplyTemplates: removing ignorable blank cur\n")); #endif xmlUnlinkNode(delNode); xmlFreeNode(delNode); delNode = NULL; } } } #ifdef WITH_XSLT_DEBUG_PROCESS if (list != NULL) XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext, "xsltApplyTemplates: list of %d nodes\n", list->nodeNr)); #endif if ((list == NULL) || (list->nodeNr == 0)) goto exit; /* * Set the context's node set and size; this is also needed for * for xsltDoSortFunction(). */ ctxt->nodeList = list; /* * Process xsl:with-param and xsl:sort instructions. * (The code became so verbose just to avoid the * xmlNodePtr sorts[XSLT_MAX_SORT] if there's no xsl:sort) * BUG TODO: We are not using namespaced potentially defined on the * xsl:sort or xsl:with-param elements; XPath expression might fail. */ if (inst->children) { xsltStackElemPtr param; cur = inst->children; while (cur) { #ifdef WITH_DEBUGGER if (ctxt->debugStatus != XSLT_DEBUG_NONE) xslHandleDebugger(cur, node, NULL, ctxt); #endif if (ctxt->state == XSLT_STATE_STOPPED) break; if (cur->type == XML_TEXT_NODE) { cur = cur->next; continue; } if (! IS_XSLT_ELEM(cur)) break; if (IS_XSLT_NAME(cur, "with-param")) { param = xsltParseStylesheetCallerParam(ctxt, cur); if (param != NULL) { param->next = withParams; withParams = param; } } if (IS_XSLT_NAME(cur, "sort")) { xsltTemplatePtr oldCurTempRule = ctxt->currentTemplateRule; int nbsorts = 0; xmlNodePtr sorts[XSLT_MAX_SORT]; sorts[nbsorts++] = cur; while (cur) { #ifdef WITH_DEBUGGER if (ctxt->debugStatus != XSLT_DEBUG_NONE) xslHandleDebugger(cur, node, NULL, ctxt); #endif if (ctxt->state == XSLT_STATE_STOPPED) break; if (cur->type == XML_TEXT_NODE) { cur = cur->next; continue; } if (! IS_XSLT_ELEM(cur)) break; if (IS_XSLT_NAME(cur, "with-param")) { param = xsltParseStylesheetCallerParam(ctxt, cur); if (param != NULL) { param->next = withParams; withParams = param; } } if (IS_XSLT_NAME(cur, "sort")) { if (nbsorts >= XSLT_MAX_SORT) { xsltTransformError(ctxt, NULL, cur, "The number (%d) of xsl:sort instructions exceeds the " "maximum allowed by this processor's settings.\n", nbsorts); ctxt->state = XSLT_STATE_STOPPED; break; } else { sorts[nbsorts++] = cur; } } cur = cur->next; } /* * The "current template rule" is cleared for xsl:sort. */ ctxt->currentTemplateRule = NULL; /* * Sort. */ xsltDoSortFunction(ctxt, sorts, nbsorts); ctxt->currentTemplateRule = oldCurTempRule; break; } cur = cur->next; } } xpctxt->contextSize = list->nodeNr; /* * Apply templates for all selected source nodes. */ for (i = 0; i < list->nodeNr; i++) { cur = list->nodeTab[i]; /* * The node becomes the "current node". */ ctxt->node = cur; /* * An xsl:apply-templates can change the current context doc. * OPTIMIZE TODO: Get rid of the need to set the context doc. */ if ((cur->type != XML_NAMESPACE_DECL) && (cur->doc != NULL)) xpctxt->doc = cur->doc; xpctxt->proximityPosition = i + 1; /* * Find and apply a template for this node. */ xsltProcessOneNode(ctxt, cur, withParams); } exit: error: /* * Free the parameter list. */ if (withParams != NULL) xsltFreeStackElemList(withParams); if (list != NULL) xmlXPathFreeNodeSet(list); /* * Restore context states. */ xpctxt->nsNr = oldXPNsNr; xpctxt->namespaces = oldXPNamespaces; xpctxt->doc = oldXPDoc; xpctxt->contextSize = oldXPContextSize; xpctxt->proximityPosition = oldXPProximityPosition; ctxt->document = oldDocInfo; ctxt->nodeList = oldList; ctxt->node = oldContextNode; ctxt->mode = oldMode; ctxt->modeURI = oldModeURI; } /** * xsltChoose: * @ctxt: a XSLT process context * @contextNode: the current node in the source tree * @inst: the xsl:choose instruction * @comp: compiled information of the instruction * * Processes the xsl:choose instruction on the source node. */ void xsltChoose(xsltTransformContextPtr ctxt, xmlNodePtr contextNode, xmlNodePtr inst, xsltStylePreCompPtr comp ATTRIBUTE_UNUSED) { xmlNodePtr cur; if ((ctxt == NULL) || (contextNode == NULL) || (inst == NULL)) return; /* * TODO: Content model checks should be done only at compilation * time. */ cur = inst->children; if (cur == NULL) { xsltTransformError(ctxt, NULL, inst, "xsl:choose: The instruction has no content.\n"); return; } #ifdef XSLT_REFACTORED /* * We don't check the content model during transformation. */ #else if ((! IS_XSLT_ELEM(cur)) || (! IS_XSLT_NAME(cur, "when"))) { xsltTransformError(ctxt, NULL, inst, "xsl:choose: xsl:when expected first\n"); return; } #endif { int testRes = 0, res = 0; xmlXPathContextPtr xpctxt = ctxt->xpathCtxt; xmlDocPtr oldXPContextDoc = xpctxt->doc; int oldXPProximityPosition = xpctxt->proximityPosition; int oldXPContextSize = xpctxt->contextSize; xmlNsPtr *oldXPNamespaces = xpctxt->namespaces; int oldXPNsNr = xpctxt->nsNr; #ifdef XSLT_REFACTORED xsltStyleItemWhenPtr wcomp = NULL; #else xsltStylePreCompPtr wcomp = NULL; #endif /* * Process xsl:when --------------------------------------------------- */ while (IS_XSLT_ELEM(cur) && IS_XSLT_NAME(cur, "when")) { wcomp = cur->psvi; if ((wcomp == NULL) || (wcomp->test == NULL) || (wcomp->comp == NULL)) { xsltTransformError(ctxt, NULL, cur, "Internal error in xsltChoose(): " "The XSLT 'when' instruction was not compiled.\n"); goto error; } #ifdef WITH_DEBUGGER if (xslDebugStatus != XSLT_DEBUG_NONE) { /* * TODO: Isn't comp->templ always NULL for xsl:choose? */ xslHandleDebugger(cur, contextNode, NULL, ctxt); } #endif #ifdef WITH_XSLT_DEBUG_PROCESS XSLT_TRACE(ctxt,XSLT_TRACE_CHOOSE,xsltGenericDebug(xsltGenericDebugContext, "xsltChoose: test %s\n", wcomp->test)); #endif xpctxt->node = contextNode; xpctxt->doc = oldXPContextDoc; xpctxt->proximityPosition = oldXPProximityPosition; xpctxt->contextSize = oldXPContextSize; #ifdef XSLT_REFACTORED if (wcomp->inScopeNs != NULL) { xpctxt->namespaces = wcomp->inScopeNs->list; xpctxt->nsNr = wcomp->inScopeNs->xpathNumber; } else { xpctxt->namespaces = NULL; xpctxt->nsNr = 0; } #else xpctxt->namespaces = wcomp->nsList; xpctxt->nsNr = wcomp->nsNr; #endif #ifdef XSLT_FAST_IF res = xmlXPathCompiledEvalToBoolean(wcomp->comp, xpctxt); if (res == -1) { ctxt->state = XSLT_STATE_STOPPED; goto error; } testRes = (res == 1) ? 1 : 0; #else /* XSLT_FAST_IF */ res = xmlXPathCompiledEval(wcomp->comp, xpctxt); if (res != NULL) { if (res->type != XPATH_BOOLEAN) res = xmlXPathConvertBoolean(res); if (res->type == XPATH_BOOLEAN) testRes = res->boolval; else { #ifdef WITH_XSLT_DEBUG_PROCESS XSLT_TRACE(ctxt,XSLT_TRACE_CHOOSE,xsltGenericDebug(xsltGenericDebugContext, "xsltChoose: test didn't evaluate to a boolean\n")); #endif goto error; } xmlXPathFreeObject(res); res = NULL; } else { ctxt->state = XSLT_STATE_STOPPED; goto error; } #endif /* else of XSLT_FAST_IF */ #ifdef WITH_XSLT_DEBUG_PROCESS XSLT_TRACE(ctxt,XSLT_TRACE_CHOOSE,xsltGenericDebug(xsltGenericDebugContext, "xsltChoose: test evaluate to %d\n", testRes)); #endif if (testRes) goto test_is_true; cur = cur->next; } /* * Process xsl:otherwise ---------------------------------------------- */ if (IS_XSLT_ELEM(cur) && IS_XSLT_NAME(cur, "otherwise")) { #ifdef WITH_DEBUGGER if (xslDebugStatus != XSLT_DEBUG_NONE) xslHandleDebugger(cur, contextNode, NULL, ctxt); #endif #ifdef WITH_XSLT_DEBUG_PROCESS XSLT_TRACE(ctxt,XSLT_TRACE_CHOOSE,xsltGenericDebug(xsltGenericDebugContext, "evaluating xsl:otherwise\n")); #endif goto test_is_true; } xpctxt->node = contextNode; xpctxt->doc = oldXPContextDoc; xpctxt->proximityPosition = oldXPProximityPosition; xpctxt->contextSize = oldXPContextSize; xpctxt->namespaces = oldXPNamespaces; xpctxt->nsNr = oldXPNsNr; goto exit; test_is_true: xpctxt->node = contextNode; xpctxt->doc = oldXPContextDoc; xpctxt->proximityPosition = oldXPProximityPosition; xpctxt->contextSize = oldXPContextSize; xpctxt->namespaces = oldXPNamespaces; xpctxt->nsNr = oldXPNsNr; goto process_sequence; } process_sequence: /* * Instantiate the sequence constructor. */ xsltApplySequenceConstructor(ctxt, ctxt->node, cur->children, NULL); exit: error: return; } /** * xsltIf: * @ctxt: a XSLT process context * @contextNode: the current node in the source tree * @inst: the xsl:if instruction * @castedComp: compiled information of the instruction * * Processes the xsl:if instruction on the source node. */ void xsltIf(xsltTransformContextPtr ctxt, xmlNodePtr contextNode, xmlNodePtr inst, xsltStylePreCompPtr castedComp) { int res = 0; #ifdef XSLT_REFACTORED xsltStyleItemIfPtr comp = (xsltStyleItemIfPtr) castedComp; #else xsltStylePreCompPtr comp = castedComp; #endif if ((ctxt == NULL) || (contextNode == NULL) || (inst == NULL)) return; if ((comp == NULL) || (comp->test == NULL) || (comp->comp == NULL)) { xsltTransformError(ctxt, NULL, inst, "Internal error in xsltIf(): " "The XSLT 'if' instruction was not compiled.\n"); return; } #ifdef WITH_XSLT_DEBUG_PROCESS XSLT_TRACE(ctxt,XSLT_TRACE_IF,xsltGenericDebug(xsltGenericDebugContext, "xsltIf: test %s\n", comp->test)); #endif #ifdef XSLT_FAST_IF { xmlXPathContextPtr xpctxt = ctxt->xpathCtxt; xmlDocPtr oldXPContextDoc = xpctxt->doc; xmlNsPtr *oldXPNamespaces = xpctxt->namespaces; xmlNodePtr oldXPContextNode = xpctxt->node; int oldXPProximityPosition = xpctxt->proximityPosition; int oldXPContextSize = xpctxt->contextSize; int oldXPNsNr = xpctxt->nsNr; xmlDocPtr oldLocalFragmentTop = ctxt->localRVT; xpctxt->node = contextNode; if (comp != NULL) { #ifdef XSLT_REFACTORED if (comp->inScopeNs != NULL) { xpctxt->namespaces = comp->inScopeNs->list; xpctxt->nsNr = comp->inScopeNs->xpathNumber; } else { xpctxt->namespaces = NULL; xpctxt->nsNr = 0; } #else xpctxt->namespaces = comp->nsList; xpctxt->nsNr = comp->nsNr; #endif } else { xpctxt->namespaces = NULL; xpctxt->nsNr = 0; } /* * This XPath function is optimized for boolean results. */ res = xmlXPathCompiledEvalToBoolean(comp->comp, xpctxt); /* * Cleanup fragments created during evaluation of the * "select" expression. */ if (oldLocalFragmentTop != ctxt->localRVT) xsltReleaseLocalRVTs(ctxt, oldLocalFragmentTop); xpctxt->doc = oldXPContextDoc; xpctxt->node = oldXPContextNode; xpctxt->contextSize = oldXPContextSize; xpctxt->proximityPosition = oldXPProximityPosition; xpctxt->nsNr = oldXPNsNr; xpctxt->namespaces = oldXPNamespaces; } #ifdef WITH_XSLT_DEBUG_PROCESS XSLT_TRACE(ctxt,XSLT_TRACE_IF,xsltGenericDebug(xsltGenericDebugContext, "xsltIf: test evaluate to %d\n", res)); #endif if (res == -1) { ctxt->state = XSLT_STATE_STOPPED; goto error; } if (res == 1) { /* * Instantiate the sequence constructor of xsl:if. */ xsltApplySequenceConstructor(ctxt, contextNode, inst->children, NULL); } #else /* XSLT_FAST_IF */ { xmlXPathObjectPtr xpobj = NULL; /* * OLD CODE: */ { xmlXPathContextPtr xpctxt = ctxt->xpathCtxt; xmlDocPtr oldXPContextDoc = xpctxt->doc; xmlNsPtr *oldXPNamespaces = xpctxt->namespaces; xmlNodePtr oldXPContextNode = xpctxt->node; int oldXPProximityPosition = xpctxt->proximityPosition; int oldXPContextSize = xpctxt->contextSize; int oldXPNsNr = xpctxt->nsNr; xpctxt->node = contextNode; if (comp != NULL) { #ifdef XSLT_REFACTORED if (comp->inScopeNs != NULL) { xpctxt->namespaces = comp->inScopeNs->list; xpctxt->nsNr = comp->inScopeNs->xpathNumber; } else { xpctxt->namespaces = NULL; xpctxt->nsNr = 0; } #else xpctxt->namespaces = comp->nsList; xpctxt->nsNr = comp->nsNr; #endif } else { xpctxt->namespaces = NULL; xpctxt->nsNr = 0; } /* * This XPath function is optimized for boolean results. */ xpobj = xmlXPathCompiledEval(comp->comp, xpctxt); xpctxt->doc = oldXPContextDoc; xpctxt->node = oldXPContextNode; xpctxt->contextSize = oldXPContextSize; xpctxt->proximityPosition = oldXPProximityPosition; xpctxt->nsNr = oldXPNsNr; xpctxt->namespaces = oldXPNamespaces; } if (xpobj != NULL) { if (xpobj->type != XPATH_BOOLEAN) xpobj = xmlXPathConvertBoolean(xpobj); if (xpobj->type == XPATH_BOOLEAN) { res = xpobj->boolval; #ifdef WITH_XSLT_DEBUG_PROCESS XSLT_TRACE(ctxt,XSLT_TRACE_IF,xsltGenericDebug(xsltGenericDebugContext, "xsltIf: test evaluate to %d\n", res)); #endif if (res) { xsltApplySequenceConstructor(ctxt, contextNode, inst->children, NULL); } } else { #ifdef WITH_XSLT_DEBUG_PROCESS XSLT_TRACE(ctxt, XSLT_TRACE_IF, xsltGenericDebug(xsltGenericDebugContext, "xsltIf: test didn't evaluate to a boolean\n")); #endif ctxt->state = XSLT_STATE_STOPPED; } xmlXPathFreeObject(xpobj); } else { ctxt->state = XSLT_STATE_STOPPED; } } #endif /* else of XSLT_FAST_IF */ error: return; } /** * xsltForEach: * @ctxt: an XSLT transformation context * @contextNode: the "current node" in the source tree * @inst: the element node of the xsl:for-each instruction * @castedComp: the compiled information of the instruction * * Process the xslt for-each node on the source node */ void xsltForEach(xsltTransformContextPtr ctxt, xmlNodePtr contextNode, xmlNodePtr inst, xsltStylePreCompPtr castedComp) { #ifdef XSLT_REFACTORED xsltStyleItemForEachPtr comp = (xsltStyleItemForEachPtr) castedComp; #else xsltStylePreCompPtr comp = castedComp; #endif int i; xmlXPathObjectPtr res = NULL; xmlNodePtr cur, curInst; xmlNodeSetPtr list = NULL; xmlNodeSetPtr oldList; int oldXPProximityPosition, oldXPContextSize; xmlNodePtr oldContextNode; xsltTemplatePtr oldCurTemplRule; xmlDocPtr oldXPDoc; xsltDocumentPtr oldDocInfo; xmlXPathContextPtr xpctxt; if ((ctxt == NULL) || (contextNode == NULL) || (inst == NULL)) { xsltGenericError(xsltGenericErrorContext, "xsltForEach(): Bad arguments.\n"); return; } if (comp == NULL) { xsltTransformError(ctxt, NULL, inst, "Internal error in xsltForEach(): " "The XSLT 'for-each' instruction was not compiled.\n"); return; } if ((comp->select == NULL) || (comp->comp == NULL)) { xsltTransformError(ctxt, NULL, inst, "Internal error in xsltForEach(): " "The selecting expression of the XSLT 'for-each' " "instruction was not compiled correctly.\n"); return; } xpctxt = ctxt->xpathCtxt; #ifdef WITH_XSLT_DEBUG_PROCESS XSLT_TRACE(ctxt,XSLT_TRACE_FOR_EACH,xsltGenericDebug(xsltGenericDebugContext, "xsltForEach: select %s\n", comp->select)); #endif /* * Save context states. */ oldDocInfo = ctxt->document; oldList = ctxt->nodeList; oldContextNode = ctxt->node; /* * The "current template rule" is cleared for the instantiation of * xsl:for-each. */ oldCurTemplRule = ctxt->currentTemplateRule; ctxt->currentTemplateRule = NULL; oldXPDoc = xpctxt->doc; oldXPProximityPosition = xpctxt->proximityPosition; oldXPContextSize = xpctxt->contextSize; /* * Set up XPath. */ xpctxt->node = contextNode; #ifdef XSLT_REFACTORED if (comp->inScopeNs != NULL) { xpctxt->namespaces = comp->inScopeNs->list; xpctxt->nsNr = comp->inScopeNs->xpathNumber; } else { xpctxt->namespaces = NULL; xpctxt->nsNr = 0; } #else xpctxt->namespaces = comp->nsList; xpctxt->nsNr = comp->nsNr; #endif /* * Evaluate the 'select' expression. */ res = xmlXPathCompiledEval(comp->comp, ctxt->xpathCtxt); if (res != NULL) { if (res->type == XPATH_NODESET) list = res->nodesetval; else { xsltTransformError(ctxt, NULL, inst, "The 'select' expression does not evaluate to a node set.\n"); #ifdef WITH_XSLT_DEBUG_PROCESS XSLT_TRACE(ctxt,XSLT_TRACE_FOR_EACH,xsltGenericDebug(xsltGenericDebugContext, "xsltForEach: select didn't evaluate to a node list\n")); #endif goto error; } } else { xsltTransformError(ctxt, NULL, inst, "Failed to evaluate the 'select' expression.\n"); ctxt->state = XSLT_STATE_STOPPED; goto error; } if ((list == NULL) || (list->nodeNr <= 0)) goto exit; #ifdef WITH_XSLT_DEBUG_PROCESS XSLT_TRACE(ctxt,XSLT_TRACE_FOR_EACH,xsltGenericDebug(xsltGenericDebugContext, "xsltForEach: select evaluates to %d nodes\n", list->nodeNr)); #endif /* * Restore XPath states for the "current node". */ xpctxt->contextSize = oldXPContextSize; xpctxt->proximityPosition = oldXPProximityPosition; xpctxt->node = contextNode; /* * Set the list; this has to be done already here for xsltDoSortFunction(). */ ctxt->nodeList = list; /* * Handle xsl:sort instructions and skip them for further processing. * BUG TODO: We are not using namespaced potentially defined on the * xsl:sort element; XPath expression might fail. */ curInst = inst->children; if (IS_XSLT_ELEM(curInst) && IS_XSLT_NAME(curInst, "sort")) { int nbsorts = 0; xmlNodePtr sorts[XSLT_MAX_SORT]; sorts[nbsorts++] = curInst; #ifdef WITH_DEBUGGER if (xslDebugStatus != XSLT_DEBUG_NONE) xslHandleDebugger(curInst, contextNode, NULL, ctxt); #endif curInst = curInst->next; while (IS_XSLT_ELEM(curInst) && IS_XSLT_NAME(curInst, "sort")) { if (nbsorts >= XSLT_MAX_SORT) { xsltTransformError(ctxt, NULL, curInst, "The number of xsl:sort instructions exceeds the " "maximum (%d) allowed by this processor.\n", XSLT_MAX_SORT); goto error; } else { sorts[nbsorts++] = curInst; } #ifdef WITH_DEBUGGER if (xslDebugStatus != XSLT_DEBUG_NONE) xslHandleDebugger(curInst, contextNode, NULL, ctxt); #endif curInst = curInst->next; } xsltDoSortFunction(ctxt, sorts, nbsorts); } xpctxt->contextSize = list->nodeNr; /* * Instantiate the sequence constructor for each selected node. */ for (i = 0; i < list->nodeNr; i++) { cur = list->nodeTab[i]; /* * The selected node becomes the "current node". */ ctxt->node = cur; /* * An xsl:for-each can change the current context doc. * OPTIMIZE TODO: Get rid of the need to set the context doc. */ if ((cur->type != XML_NAMESPACE_DECL) && (cur->doc != NULL)) xpctxt->doc = cur->doc; xpctxt->proximityPosition = i + 1; xsltApplySequenceConstructor(ctxt, cur, curInst, NULL); } exit: error: if (res != NULL) xmlXPathFreeObject(res); /* * Restore old states. */ ctxt->document = oldDocInfo; ctxt->nodeList = oldList; ctxt->node = oldContextNode; ctxt->currentTemplateRule = oldCurTemplRule; xpctxt->doc = oldXPDoc; xpctxt->contextSize = oldXPContextSize; xpctxt->proximityPosition = oldXPProximityPosition; } /************************************************************************ * * * Generic interface * * * ************************************************************************/ #ifdef XSLT_GENERATE_HTML_DOCTYPE typedef struct xsltHTMLVersion { const char *version; const char *public; const char *system; } xsltHTMLVersion; static xsltHTMLVersion xsltHTMLVersions[] = { { "4.01frame", "-//W3C//DTD HTML 4.01 Frameset//EN", "http://www.w3.org/TR/1999/REC-html401-19991224/frameset.dtd"}, { "4.01strict", "-//W3C//DTD HTML 4.01//EN", "http://www.w3.org/TR/1999/REC-html401-19991224/strict.dtd"}, { "4.01trans", "-//W3C//DTD HTML 4.01 Transitional//EN", "http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd"}, { "4.01", "-//W3C//DTD HTML 4.01 Transitional//EN", "http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd"}, { "4.0strict", "-//W3C//DTD HTML 4.01//EN", "http://www.w3.org/TR/html4/strict.dtd"}, { "4.0trans", "-//W3C//DTD HTML 4.01 Transitional//EN", "http://www.w3.org/TR/html4/loose.dtd"}, { "4.0frame", "-//W3C//DTD HTML 4.01 Frameset//EN", "http://www.w3.org/TR/html4/frameset.dtd"}, { "4.0", "-//W3C//DTD HTML 4.01 Transitional//EN", "http://www.w3.org/TR/html4/loose.dtd"}, { "3.2", "-//W3C//DTD HTML 3.2//EN", NULL } }; /** * xsltGetHTMLIDs: * @version: the version string * @publicID: used to return the public ID * @systemID: used to return the system ID * * Returns -1 if not found, 0 otherwise and the system and public * Identifier for this given verion of HTML */ static int xsltGetHTMLIDs(const xmlChar *version, const xmlChar **publicID, const xmlChar **systemID) { unsigned int i; if (version == NULL) return(-1); for (i = 0;i < (sizeof(xsltHTMLVersions)/sizeof(xsltHTMLVersions[1])); i++) { if (!xmlStrcasecmp(version, (const xmlChar *) xsltHTMLVersions[i].version)) { if (publicID != NULL) *publicID = (const xmlChar *) xsltHTMLVersions[i].public; if (systemID != NULL) *systemID = (const xmlChar *) xsltHTMLVersions[i].system; return(0); } } return(-1); } #endif /** * xsltApplyStripSpaces: * @ctxt: a XSLT process context * @node: the root of the XML tree * * Strip the unwanted ignorable spaces from the input tree */ void xsltApplyStripSpaces(xsltTransformContextPtr ctxt, xmlNodePtr node) { xmlNodePtr current; #ifdef WITH_XSLT_DEBUG_PROCESS int nb = 0; #endif current = node; while (current != NULL) { /* * Cleanup children empty nodes if asked for */ if ((IS_XSLT_REAL_NODE(current)) && (current->children != NULL) && (xsltFindElemSpaceHandling(ctxt, current))) { xmlNodePtr delete = NULL, cur = current->children; while (cur != NULL) { if (IS_BLANK_NODE(cur)) delete = cur; cur = cur->next; if (delete != NULL) { xmlUnlinkNode(delete); xmlFreeNode(delete); delete = NULL; #ifdef WITH_XSLT_DEBUG_PROCESS nb++; #endif } } } /* * Skip to next node in document order. */ if (node->type == XML_ENTITY_REF_NODE) { /* process deep in entities */ xsltApplyStripSpaces(ctxt, node->children); } if ((current->children != NULL) && (current->type != XML_ENTITY_REF_NODE)) { current = current->children; } else if (current->next != NULL) { current = current->next; } else { do { current = current->parent; if (current == NULL) break; if (current == node) goto done; if (current->next != NULL) { current = current->next; break; } } while (current != NULL); } } done: #ifdef WITH_XSLT_DEBUG_PROCESS XSLT_TRACE(ctxt,XSLT_TRACE_STRIP_SPACES,xsltGenericDebug(xsltGenericDebugContext, "xsltApplyStripSpaces: removed %d ignorable blank node\n", nb)); #endif return; } static int xsltCountKeys(xsltTransformContextPtr ctxt) { xsltStylesheetPtr style; xsltKeyDefPtr keyd; if (ctxt == NULL) return(-1); /* * Do we have those nastly templates with a key() in the match pattern? */ ctxt->hasTemplKeyPatterns = 0; style = ctxt->style; while (style != NULL) { if (style->keyMatch != NULL) { ctxt->hasTemplKeyPatterns = 1; break; } style = xsltNextImport(style); } /* * Count number of key declarations. */ ctxt->nbKeys = 0; style = ctxt->style; while (style != NULL) { keyd = style->keys; while (keyd) { ctxt->nbKeys++; keyd = keyd->next; } style = xsltNextImport(style); } return(ctxt->nbKeys); } /** * xsltApplyStylesheetInternal: * @style: a parsed XSLT stylesheet * @doc: a parsed XML document * @params: a NULL terminated array of parameters names/values tuples * @output: the targetted output * @profile: profile FILE * output or NULL * @user: user provided parameter * * Apply the stylesheet to the document * NOTE: This may lead to a non-wellformed output XML wise ! * * Returns the result document or NULL in case of error */ static xmlDocPtr xsltApplyStylesheetInternal(xsltStylesheetPtr style, xmlDocPtr doc, const char **params, const char *output, FILE * profile, xsltTransformContextPtr userCtxt) { xmlDocPtr res = NULL; xsltTransformContextPtr ctxt = NULL; xmlNodePtr root, node; const xmlChar *method; const xmlChar *doctypePublic; const xmlChar *doctypeSystem; const xmlChar *version; const xmlChar *encoding; xsltStackElemPtr variables; xsltStackElemPtr vptr; xsltInitGlobals(); if ((style == NULL) || (doc == NULL)) return (NULL); if (style->internalized == 0) { #ifdef WITH_XSLT_DEBUG xsltGenericDebug(xsltGenericDebugContext, "Stylesheet was not fully internalized !\n"); #endif } if (doc->intSubset != NULL) { /* * Avoid hitting the DTD when scanning nodes * but keep it linked as doc->intSubset */ xmlNodePtr cur = (xmlNodePtr) doc->intSubset; if (cur->next != NULL) cur->next->prev = cur->prev; if (cur->prev != NULL) cur->prev->next = cur->next; if (doc->children == cur) doc->children = cur->next; if (doc->last == cur) doc->last = cur->prev; cur->prev = cur->next = NULL; } /* * Check for XPath document order availability */ root = xmlDocGetRootElement(doc); if (root != NULL) { if (((long) root->content) >= 0 && (xslDebugStatus == XSLT_DEBUG_NONE)) xmlXPathOrderDocElems(doc); } if (userCtxt != NULL) ctxt = userCtxt; else ctxt = xsltNewTransformContext(style, doc); if (ctxt == NULL) return (NULL); ctxt->initialContextDoc = doc; ctxt->initialContextNode = (xmlNodePtr) doc; if (profile != NULL) ctxt->profile = 1; if (output != NULL) ctxt->outputFile = output; else ctxt->outputFile = NULL; /* * internalize the modes if needed */ if (ctxt->dict != NULL) { if (ctxt->mode != NULL) ctxt->mode = xmlDictLookup(ctxt->dict, ctxt->mode, -1); if (ctxt->modeURI != NULL) ctxt->modeURI = xmlDictLookup(ctxt->dict, ctxt->modeURI, -1); } XSLT_GET_IMPORT_PTR(method, style, method) XSLT_GET_IMPORT_PTR(doctypePublic, style, doctypePublic) XSLT_GET_IMPORT_PTR(doctypeSystem, style, doctypeSystem) XSLT_GET_IMPORT_PTR(version, style, version) XSLT_GET_IMPORT_PTR(encoding, style, encoding) if ((method != NULL) && (!xmlStrEqual(method, (const xmlChar *) "xml"))) { if (xmlStrEqual(method, (const xmlChar *) "html")) { ctxt->type = XSLT_OUTPUT_HTML; if (((doctypePublic != NULL) || (doctypeSystem != NULL))) { res = htmlNewDoc(doctypeSystem, doctypePublic); } else { if (version == NULL) { xmlDtdPtr dtd; res = htmlNewDoc(NULL, NULL); /* * Make sure no DTD node is generated in this case */ if (res != NULL) { dtd = xmlGetIntSubset(res); if (dtd != NULL) { xmlUnlinkNode((xmlNodePtr) dtd); xmlFreeDtd(dtd); } res->intSubset = NULL; res->extSubset = NULL; } } else { #ifdef XSLT_GENERATE_HTML_DOCTYPE xsltGetHTMLIDs(version, &doctypePublic, &doctypeSystem); #endif res = htmlNewDoc(doctypeSystem, doctypePublic); } } if (res == NULL) goto error; res->dict = ctxt->dict; xmlDictReference(res->dict); #ifdef WITH_XSLT_DEBUG xsltGenericDebug(xsltGenericDebugContext, "reusing transformation dict for output\n"); #endif } else if (xmlStrEqual(method, (const xmlChar *) "xhtml")) { xsltTransformError(ctxt, NULL, (xmlNodePtr) doc, "xsltApplyStylesheetInternal: unsupported method xhtml, using html\n", style->method); ctxt->type = XSLT_OUTPUT_HTML; res = htmlNewDoc(doctypeSystem, doctypePublic); if (res == NULL) goto error; res->dict = ctxt->dict; xmlDictReference(res->dict); #ifdef WITH_XSLT_DEBUG xsltGenericDebug(xsltGenericDebugContext, "reusing transformation dict for output\n"); #endif } else if (xmlStrEqual(method, (const xmlChar *) "text")) { ctxt->type = XSLT_OUTPUT_TEXT; res = xmlNewDoc(style->version); if (res == NULL) goto error; res->dict = ctxt->dict; xmlDictReference(res->dict); #ifdef WITH_XSLT_DEBUG xsltGenericDebug(xsltGenericDebugContext, "reusing transformation dict for output\n"); #endif } else { xsltTransformError(ctxt, NULL, (xmlNodePtr) doc, "xsltApplyStylesheetInternal: unsupported method %s\n", style->method); goto error; } } else { ctxt->type = XSLT_OUTPUT_XML; res = xmlNewDoc(style->version); if (res == NULL) goto error; res->dict = ctxt->dict; xmlDictReference(ctxt->dict); #ifdef WITH_XSLT_DEBUG xsltGenericDebug(xsltGenericDebugContext, "reusing transformation dict for output\n"); #endif } res->charset = XML_CHAR_ENCODING_UTF8; if (encoding != NULL) res->encoding = xmlStrdup(encoding); variables = style->variables; /* * Start the evaluation, evaluate the params, the stylesheets globals * and start by processing the top node. */ if (xsltNeedElemSpaceHandling(ctxt)) xsltApplyStripSpaces(ctxt, xmlDocGetRootElement(doc)); /* * Evaluate global params and user-provided params. */ ctxt->node = (xmlNodePtr) doc; if (ctxt->globalVars == NULL) ctxt->globalVars = xmlHashCreate(20); if (params != NULL) { xsltEvalUserParams(ctxt, params); } /* need to be called before evaluating global variables */ xsltCountKeys(ctxt); xsltEvalGlobalVariables(ctxt); ctxt->node = (xmlNodePtr) doc; ctxt->output = res; ctxt->insert = (xmlNodePtr) res; ctxt->varsBase = ctxt->varsNr - 1; ctxt->xpathCtxt->contextSize = 1; ctxt->xpathCtxt->proximityPosition = 1; ctxt->xpathCtxt->node = NULL; /* TODO: Set the context node here? */ /* * Start processing the source tree ----------------------------------- */ xsltProcessOneNode(ctxt, ctxt->node, NULL); /* * Remove all remaining vars from the stack. */ xsltLocalVariablePop(ctxt, 0, -2); xsltShutdownCtxtExts(ctxt); xsltCleanupTemplates(style); /* TODO: <- style should be read only */ /* * Now cleanup our variables so stylesheet can be re-used * * TODO: this is not needed anymore global variables are copied * and not evaluated directly anymore, keep this as a check */ if (style->variables != variables) { vptr = style->variables; while (vptr->next != variables) vptr = vptr->next; vptr->next = NULL; xsltFreeStackElemList(style->variables); style->variables = variables; } vptr = style->variables; while (vptr != NULL) { if (vptr->computed) { if (vptr->value != NULL) { xmlXPathFreeObject(vptr->value); vptr->value = NULL; vptr->computed = 0; } } vptr = vptr->next; } #if 0 /* * code disabled by wmb; awaiting kb's review * problem is that global variable(s) may contain xpath objects * from doc associated with RVT, so can't be freed at this point. * xsltFreeTransformContext includes a call to xsltFreeRVTs, so * I assume this shouldn't be required at this point. */ /* * Free all remaining tree fragments. */ xsltFreeRVTs(ctxt); #endif /* * Do some post processing work depending on the generated output */ root = xmlDocGetRootElement(res); if (root != NULL) { const xmlChar *doctype = NULL; if ((root->ns != NULL) && (root->ns->prefix != NULL)) doctype = xmlDictQLookup(ctxt->dict, root->ns->prefix, root->name); if (doctype == NULL) doctype = root->name; /* * Apply the default selection of the method */ if ((method == NULL) && (root->ns == NULL) && (!xmlStrcasecmp(root->name, (const xmlChar *) "html"))) { xmlNodePtr tmp; tmp = res->children; while ((tmp != NULL) && (tmp != root)) { if (tmp->type == XML_ELEMENT_NODE) break; if ((tmp->type == XML_TEXT_NODE) && (!xmlIsBlankNode(tmp))) break; tmp = tmp->next; } if (tmp == root) { ctxt->type = XSLT_OUTPUT_HTML; /* * REVISIT TODO: XML_HTML_DOCUMENT_NODE is set after the * transformation on the doc, but functions like */ res->type = XML_HTML_DOCUMENT_NODE; if (((doctypePublic != NULL) || (doctypeSystem != NULL))) { res->intSubset = xmlCreateIntSubset(res, doctype, doctypePublic, doctypeSystem); #ifdef XSLT_GENERATE_HTML_DOCTYPE } else if (version != NULL) { xsltGetHTMLIDs(version, &doctypePublic, &doctypeSystem); if (((doctypePublic != NULL) || (doctypeSystem != NULL))) res->intSubset = xmlCreateIntSubset(res, doctype, doctypePublic, doctypeSystem); #endif } } } if (ctxt->type == XSLT_OUTPUT_XML) { XSLT_GET_IMPORT_PTR(doctypePublic, style, doctypePublic) XSLT_GET_IMPORT_PTR(doctypeSystem, style, doctypeSystem) if (((doctypePublic != NULL) || (doctypeSystem != NULL))) { xmlNodePtr last; /* Need a small "hack" here to assure DTD comes before possible comment nodes */ node = res->children; last = res->last; res->children = NULL; res->last = NULL; res->intSubset = xmlCreateIntSubset(res, doctype, doctypePublic, doctypeSystem); if (res->children != NULL) { res->children->next = node; node->prev = res->children; res->last = last; } else { res->children = node; res->last = last; } } } } xmlXPathFreeNodeSet(ctxt->nodeList); if (profile != NULL) { xsltSaveProfiling(ctxt, profile); } /* * Be pedantic. */ if ((ctxt != NULL) && (ctxt->state == XSLT_STATE_ERROR)) { xmlFreeDoc(res); res = NULL; } if ((res != NULL) && (ctxt != NULL) && (output != NULL)) { int ret; ret = xsltCheckWrite(ctxt->sec, ctxt, (const xmlChar *) output); if (ret == 0) { xsltTransformError(ctxt, NULL, NULL, "xsltApplyStylesheet: forbidden to save to %s\n", output); } else if (ret < 0) { xsltTransformError(ctxt, NULL, NULL, "xsltApplyStylesheet: saving to %s may not be possible\n", output); } } #ifdef XSLT_DEBUG_PROFILE_CACHE printf("# Cache:\n"); printf("# Reused tree fragments: %d\n", ctxt->cache->dbgReusedRVTs); printf("# Reused variables : %d\n", ctxt->cache->dbgReusedVars); #endif if ((ctxt != NULL) && (userCtxt == NULL)) xsltFreeTransformContext(ctxt); return (res); error: if (res != NULL) xmlFreeDoc(res); #ifdef XSLT_DEBUG_PROFILE_CACHE printf("# Cache:\n"); printf("# Reused tree fragments: %d\n", ctxt->cache->dbgReusedRVTs); printf("# Reused variables : %d\n", ctxt->cache->dbgReusedVars); #endif if ((ctxt != NULL) && (userCtxt == NULL)) xsltFreeTransformContext(ctxt); return (NULL); } /** * xsltApplyStylesheet: * @style: a parsed XSLT stylesheet * @doc: a parsed XML document * @params: a NULL terminated arry of parameters names/values tuples * * Apply the stylesheet to the document * NOTE: This may lead to a non-wellformed output XML wise ! * * Returns the result document or NULL in case of error */ xmlDocPtr xsltApplyStylesheet(xsltStylesheetPtr style, xmlDocPtr doc, const char **params) { return (xsltApplyStylesheetInternal(style, doc, params, NULL, NULL, NULL)); } /** * xsltProfileStylesheet: * @style: a parsed XSLT stylesheet * @doc: a parsed XML document * @params: a NULL terminated arry of parameters names/values tuples * @output: a FILE * for the profiling output * * Apply the stylesheet to the document and dump the profiling to * the given output. * * Returns the result document or NULL in case of error */ xmlDocPtr xsltProfileStylesheet(xsltStylesheetPtr style, xmlDocPtr doc, const char **params, FILE * output) { xmlDocPtr res; res = xsltApplyStylesheetInternal(style, doc, params, NULL, output, NULL); return (res); } /** * xsltApplyStylesheetUser: * @style: a parsed XSLT stylesheet * @doc: a parsed XML document * @params: a NULL terminated array of parameters names/values tuples * @output: the targetted output * @profile: profile FILE * output or NULL * @userCtxt: user provided transform context * * Apply the stylesheet to the document and allow the user to provide * its own transformation context. * * Returns the result document or NULL in case of error */ xmlDocPtr xsltApplyStylesheetUser(xsltStylesheetPtr style, xmlDocPtr doc, const char **params, const char *output, FILE * profile, xsltTransformContextPtr userCtxt) { xmlDocPtr res; res = xsltApplyStylesheetInternal(style, doc, params, output, profile, userCtxt); return (res); } /** * xsltRunStylesheetUser: * @style: a parsed XSLT stylesheet * @doc: a parsed XML document * @params: a NULL terminated array of parameters names/values tuples * @output: the URL/filename ot the generated resource if available * @SAX: a SAX handler for progressive callback output (not implemented yet) * @IObuf: an output buffer for progressive output (not implemented yet) * @profile: profile FILE * output or NULL * @userCtxt: user provided transform context * * Apply the stylesheet to the document and generate the output according * to @output @SAX and @IObuf. It's an error to specify both @SAX and @IObuf. * * NOTE: This may lead to a non-wellformed output XML wise ! * NOTE: This may also result in multiple files being generated * NOTE: using IObuf, the result encoding used will be the one used for * creating the output buffer, use the following macro to read it * from the stylesheet * XSLT_GET_IMPORT_PTR(encoding, style, encoding) * NOTE: using SAX, any encoding specified in the stylesheet will be lost * since the interface uses only UTF8 * * Returns the number of by written to the main resource or -1 in case of * error. */ int xsltRunStylesheetUser(xsltStylesheetPtr style, xmlDocPtr doc, const char **params, const char *output, xmlSAXHandlerPtr SAX, xmlOutputBufferPtr IObuf, FILE * profile, xsltTransformContextPtr userCtxt) { xmlDocPtr tmp; int ret; if ((output == NULL) && (SAX == NULL) && (IObuf == NULL)) return (-1); if ((SAX != NULL) && (IObuf != NULL)) return (-1); /* unsupported yet */ if (SAX != NULL) { XSLT_TODO /* xsltRunStylesheet xmlSAXHandlerPtr SAX */ return (-1); } tmp = xsltApplyStylesheetInternal(style, doc, params, output, profile, userCtxt); if (tmp == NULL) { xsltTransformError(NULL, NULL, (xmlNodePtr) doc, "xsltRunStylesheet : run failed\n"); return (-1); } if (IObuf != NULL) { /* TODO: incomplete, IObuf output not progressive */ ret = xsltSaveResultTo(IObuf, tmp, style); } else { ret = xsltSaveResultToFilename(output, tmp, style, 0); } xmlFreeDoc(tmp); return (ret); } /** * xsltRunStylesheet: * @style: a parsed XSLT stylesheet * @doc: a parsed XML document * @params: a NULL terminated array of parameters names/values tuples * @output: the URL/filename ot the generated resource if available * @SAX: a SAX handler for progressive callback output (not implemented yet) * @IObuf: an output buffer for progressive output (not implemented yet) * * Apply the stylesheet to the document and generate the output according * to @output @SAX and @IObuf. It's an error to specify both @SAX and @IObuf. * * NOTE: This may lead to a non-wellformed output XML wise ! * NOTE: This may also result in multiple files being generated * NOTE: using IObuf, the result encoding used will be the one used for * creating the output buffer, use the following macro to read it * from the stylesheet * XSLT_GET_IMPORT_PTR(encoding, style, encoding) * NOTE: using SAX, any encoding specified in the stylesheet will be lost * since the interface uses only UTF8 * * Returns the number of bytes written to the main resource or -1 in case of * error. */ int xsltRunStylesheet(xsltStylesheetPtr style, xmlDocPtr doc, const char **params, const char *output, xmlSAXHandlerPtr SAX, xmlOutputBufferPtr IObuf) { return(xsltRunStylesheetUser(style, doc, params, output, SAX, IObuf, NULL, NULL)); } /** * xsltRegisterAllElement: * @ctxt: the XPath context * * Registers all default XSLT elements in this context */ void xsltRegisterAllElement(xsltTransformContextPtr ctxt) { xsltRegisterExtElement(ctxt, (const xmlChar *) "apply-templates", XSLT_NAMESPACE, (xsltTransformFunction) xsltApplyTemplates); xsltRegisterExtElement(ctxt, (const xmlChar *) "apply-imports", XSLT_NAMESPACE, (xsltTransformFunction) xsltApplyImports); xsltRegisterExtElement(ctxt, (const xmlChar *) "call-template", XSLT_NAMESPACE, (xsltTransformFunction) xsltCallTemplate); xsltRegisterExtElement(ctxt, (const xmlChar *) "element", XSLT_NAMESPACE, (xsltTransformFunction) xsltElement); xsltRegisterExtElement(ctxt, (const xmlChar *) "attribute", XSLT_NAMESPACE, (xsltTransformFunction) xsltAttribute); xsltRegisterExtElement(ctxt, (const xmlChar *) "text", XSLT_NAMESPACE, (xsltTransformFunction) xsltText); xsltRegisterExtElement(ctxt, (const xmlChar *) "processing-instruction", XSLT_NAMESPACE, (xsltTransformFunction) xsltProcessingInstruction); xsltRegisterExtElement(ctxt, (const xmlChar *) "comment", XSLT_NAMESPACE, (xsltTransformFunction) xsltComment); xsltRegisterExtElement(ctxt, (const xmlChar *) "copy", XSLT_NAMESPACE, (xsltTransformFunction) xsltCopy); xsltRegisterExtElement(ctxt, (const xmlChar *) "value-of", XSLT_NAMESPACE, (xsltTransformFunction) xsltValueOf); xsltRegisterExtElement(ctxt, (const xmlChar *) "number", XSLT_NAMESPACE, (xsltTransformFunction) xsltNumber); xsltRegisterExtElement(ctxt, (const xmlChar *) "for-each", XSLT_NAMESPACE, (xsltTransformFunction) xsltForEach); xsltRegisterExtElement(ctxt, (const xmlChar *) "if", XSLT_NAMESPACE, (xsltTransformFunction) xsltIf); xsltRegisterExtElement(ctxt, (const xmlChar *) "choose", XSLT_NAMESPACE, (xsltTransformFunction) xsltChoose); xsltRegisterExtElement(ctxt, (const xmlChar *) "sort", XSLT_NAMESPACE, (xsltTransformFunction) xsltSort); xsltRegisterExtElement(ctxt, (const xmlChar *) "copy-of", XSLT_NAMESPACE, (xsltTransformFunction) xsltCopyOf); xsltRegisterExtElement(ctxt, (const xmlChar *) "message", XSLT_NAMESPACE, (xsltTransformFunction) xsltMessage); /* * Those don't have callable entry points but are registered anyway */ xsltRegisterExtElement(ctxt, (const xmlChar *) "variable", XSLT_NAMESPACE, (xsltTransformFunction) xsltDebug); xsltRegisterExtElement(ctxt, (const xmlChar *) "param", XSLT_NAMESPACE, (xsltTransformFunction) xsltDebug); xsltRegisterExtElement(ctxt, (const xmlChar *) "with-param", XSLT_NAMESPACE, (xsltTransformFunction) xsltDebug); xsltRegisterExtElement(ctxt, (const xmlChar *) "decimal-format", XSLT_NAMESPACE, (xsltTransformFunction) xsltDebug); xsltRegisterExtElement(ctxt, (const xmlChar *) "when", XSLT_NAMESPACE, (xsltTransformFunction) xsltDebug); xsltRegisterExtElement(ctxt, (const xmlChar *) "otherwise", XSLT_NAMESPACE, (xsltTransformFunction) xsltDebug); xsltRegisterExtElement(ctxt, (const xmlChar *) "fallback", XSLT_NAMESPACE, (xsltTransformFunction) xsltDebug); } libxslt-1.1.28/libxslt/keys.h0000664000076400007640000000220312024022316013011 00000000000000/* * Summary: interface for the key matching used in key() and template matches. * Description: implementation of the key mechanims. * * Copy: See Copyright for the status of this software. * * Author: Daniel Veillard */ #ifndef __XML_XSLT_KEY_H__ #define __XML_XSLT_KEY_H__ #include #include "xsltexports.h" #include "xsltInternals.h" #ifdef __cplusplus extern "C" { #endif /** * NODE_IS_KEYED: * * check for bit 15 set */ #define NODE_IS_KEYED (1 >> 15) XSLTPUBFUN int XSLTCALL xsltAddKey (xsltStylesheetPtr style, const xmlChar *name, const xmlChar *nameURI, const xmlChar *match, const xmlChar *use, xmlNodePtr inst); XSLTPUBFUN xmlNodeSetPtr XSLTCALL xsltGetKey (xsltTransformContextPtr ctxt, const xmlChar *name, const xmlChar *nameURI, const xmlChar *value); XSLTPUBFUN void XSLTCALL xsltInitCtxtKeys (xsltTransformContextPtr ctxt, xsltDocumentPtr doc); XSLTPUBFUN void XSLTCALL xsltFreeKeys (xsltStylesheetPtr style); XSLTPUBFUN void XSLTCALL xsltFreeDocumentKeys (xsltDocumentPtr doc); #ifdef __cplusplus } #endif #endif /* __XML_XSLT_H__ */ libxslt-1.1.28/libxslt/extensions.h0000664000076400007640000001536712021407617014264 00000000000000/* * Summary: interface for the extension support * Description: This provide the API needed for simple and module * extension support. * * Copy: See Copyright for the status of this software. * * Author: Daniel Veillard */ #ifndef __XML_XSLT_EXTENSION_H__ #define __XML_XSLT_EXTENSION_H__ #include #include "xsltexports.h" #include "xsltInternals.h" #ifdef __cplusplus extern "C" { #endif /** * Extension Modules API. */ /** * xsltInitGlobals: * * Initialize the global variables for extensions * */ XSLTPUBFUN void XSLTCALL xsltInitGlobals (void); /** * xsltStyleExtInitFunction: * @ctxt: an XSLT stylesheet * @URI: the namespace URI for the extension * * A function called at initialization time of an XSLT extension module. * * Returns a pointer to the module specific data for this transformation. */ typedef void * (*xsltStyleExtInitFunction) (xsltStylesheetPtr style, const xmlChar *URI); /** * xsltStyleExtShutdownFunction: * @ctxt: an XSLT stylesheet * @URI: the namespace URI for the extension * @data: the data associated to this module * * A function called at shutdown time of an XSLT extension module. */ typedef void (*xsltStyleExtShutdownFunction) (xsltStylesheetPtr style, const xmlChar *URI, void *data); /** * xsltExtInitFunction: * @ctxt: an XSLT transformation context * @URI: the namespace URI for the extension * * A function called at initialization time of an XSLT extension module. * * Returns a pointer to the module specific data for this transformation. */ typedef void * (*xsltExtInitFunction) (xsltTransformContextPtr ctxt, const xmlChar *URI); /** * xsltExtShutdownFunction: * @ctxt: an XSLT transformation context * @URI: the namespace URI for the extension * @data: the data associated to this module * * A function called at shutdown time of an XSLT extension module. */ typedef void (*xsltExtShutdownFunction) (xsltTransformContextPtr ctxt, const xmlChar *URI, void *data); XSLTPUBFUN int XSLTCALL xsltRegisterExtModule (const xmlChar *URI, xsltExtInitFunction initFunc, xsltExtShutdownFunction shutdownFunc); XSLTPUBFUN int XSLTCALL xsltRegisterExtModuleFull (const xmlChar * URI, xsltExtInitFunction initFunc, xsltExtShutdownFunction shutdownFunc, xsltStyleExtInitFunction styleInitFunc, xsltStyleExtShutdownFunction styleShutdownFunc); XSLTPUBFUN int XSLTCALL xsltUnregisterExtModule (const xmlChar * URI); XSLTPUBFUN void * XSLTCALL xsltGetExtData (xsltTransformContextPtr ctxt, const xmlChar *URI); XSLTPUBFUN void * XSLTCALL xsltStyleGetExtData (xsltStylesheetPtr style, const xmlChar *URI); #ifdef XSLT_REFACTORED XSLTPUBFUN void * XSLTCALL xsltStyleStylesheetLevelGetExtData( xsltStylesheetPtr style, const xmlChar * URI); #endif XSLTPUBFUN void XSLTCALL xsltShutdownCtxtExts (xsltTransformContextPtr ctxt); XSLTPUBFUN void XSLTCALL xsltShutdownExts (xsltStylesheetPtr style); XSLTPUBFUN xsltTransformContextPtr XSLTCALL xsltXPathGetTransformContext (xmlXPathParserContextPtr ctxt); /* * extension functions */ XSLTPUBFUN int XSLTCALL xsltRegisterExtModuleFunction (const xmlChar *name, const xmlChar *URI, xmlXPathFunction function); XSLTPUBFUN xmlXPathFunction XSLTCALL xsltExtModuleFunctionLookup (const xmlChar *name, const xmlChar *URI); XSLTPUBFUN int XSLTCALL xsltUnregisterExtModuleFunction (const xmlChar *name, const xmlChar *URI); /* * extension elements */ typedef xsltElemPreCompPtr (*xsltPreComputeFunction) (xsltStylesheetPtr style, xmlNodePtr inst, xsltTransformFunction function); XSLTPUBFUN xsltElemPreCompPtr XSLTCALL xsltNewElemPreComp (xsltStylesheetPtr style, xmlNodePtr inst, xsltTransformFunction function); XSLTPUBFUN void XSLTCALL xsltInitElemPreComp (xsltElemPreCompPtr comp, xsltStylesheetPtr style, xmlNodePtr inst, xsltTransformFunction function, xsltElemPreCompDeallocator freeFunc); XSLTPUBFUN int XSLTCALL xsltRegisterExtModuleElement (const xmlChar *name, const xmlChar *URI, xsltPreComputeFunction precomp, xsltTransformFunction transform); XSLTPUBFUN xsltTransformFunction XSLTCALL xsltExtElementLookup (xsltTransformContextPtr ctxt, const xmlChar *name, const xmlChar *URI); XSLTPUBFUN xsltTransformFunction XSLTCALL xsltExtModuleElementLookup (const xmlChar *name, const xmlChar *URI); XSLTPUBFUN xsltPreComputeFunction XSLTCALL xsltExtModuleElementPreComputeLookup (const xmlChar *name, const xmlChar *URI); XSLTPUBFUN int XSLTCALL xsltUnregisterExtModuleElement (const xmlChar *name, const xmlChar *URI); /* * top-level elements */ typedef void (*xsltTopLevelFunction) (xsltStylesheetPtr style, xmlNodePtr inst); XSLTPUBFUN int XSLTCALL xsltRegisterExtModuleTopLevel (const xmlChar *name, const xmlChar *URI, xsltTopLevelFunction function); XSLTPUBFUN xsltTopLevelFunction XSLTCALL xsltExtModuleTopLevelLookup (const xmlChar *name, const xmlChar *URI); XSLTPUBFUN int XSLTCALL xsltUnregisterExtModuleTopLevel (const xmlChar *name, const xmlChar *URI); /* These 2 functions are deprecated for use within modules. */ XSLTPUBFUN int XSLTCALL xsltRegisterExtFunction (xsltTransformContextPtr ctxt, const xmlChar *name, const xmlChar *URI, xmlXPathFunction function); XSLTPUBFUN int XSLTCALL xsltRegisterExtElement (xsltTransformContextPtr ctxt, const xmlChar *name, const xmlChar *URI, xsltTransformFunction function); /* * Extension Prefix handling API. * Those are used by the XSLT (pre)processor. */ XSLTPUBFUN int XSLTCALL xsltRegisterExtPrefix (xsltStylesheetPtr style, const xmlChar *prefix, const xmlChar *URI); XSLTPUBFUN int XSLTCALL xsltCheckExtPrefix (xsltStylesheetPtr style, const xmlChar *URI); XSLTPUBFUN int XSLTCALL xsltCheckExtURI (xsltStylesheetPtr style, const xmlChar *URI); XSLTPUBFUN int XSLTCALL xsltInitCtxtExts (xsltTransformContextPtr ctxt); XSLTPUBFUN void XSLTCALL xsltFreeCtxtExts (xsltTransformContextPtr ctxt); XSLTPUBFUN void XSLTCALL xsltFreeExts (xsltStylesheetPtr style); XSLTPUBFUN xsltElemPreCompPtr XSLTCALL xsltPreComputeExtModuleElement (xsltStylesheetPtr style, xmlNodePtr inst); /* * Extension Infos access. * Used by exslt initialisation */ XSLTPUBFUN xmlHashTablePtr XSLTCALL xsltGetExtInfo (xsltStylesheetPtr style, const xmlChar *URI); /** * Test module http://xmlsoft.org/XSLT/ */ XSLTPUBFUN void XSLTCALL xsltRegisterTestModule (void); XSLTPUBFUN void XSLTCALL xsltDebugDumpExtensions (FILE * output); #ifdef __cplusplus } #endif #endif /* __XML_XSLT_EXTENSION_H__ */ libxslt-1.1.28/libxslt/triodef.h0000664000076400007640000001504411202213516013502 00000000000000/************************************************************************* * * $Id$ * * Copyright (C) 2001 Bjorn Reese * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND * CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER. * ************************************************************************/ #ifndef TRIO_TRIODEF_H #define TRIO_TRIODEF_H /************************************************************************* * Platform and compiler support detection */ #if defined(__GNUC__) # define TRIO_COMPILER_GCC #elif defined(__SUNPRO_C) # define TRIO_COMPILER_SUNPRO #elif defined(__SUNPRO_CC) # define TRIO_COMPILER_SUNPRO # define __SUNPRO_C __SUNPRO_CC #elif defined(__xlC__) || defined(__IBMC__) || defined(__IBMCPP__) # define TRIO_COMPILER_XLC #elif defined(_AIX) && !defined(__GNUC__) # define TRIO_COMPILER_XLC /* Workaround for old xlc */ #elif defined(__DECC) || defined(__DECCXX) # define TRIO_COMPILER_DECC #elif defined(__osf__) && defined(__LANGUAGE_C__) # define TRIO_COMPILER_DECC /* Workaround for old DEC C compilers */ #elif defined(_MSC_VER) # define TRIO_COMPILER_MSVC #elif defined(__BORLANDC__) # define TRIO_COMPILER_BCB #endif #if defined(VMS) || defined(__VMS) /* * VMS is placed first to avoid identifying the platform as Unix * based on the DECC compiler later on. */ # define TRIO_PLATFORM_VMS #elif defined(unix) || defined(__unix) || defined(__unix__) # define TRIO_PLATFORM_UNIX #elif defined(TRIO_COMPILER_XLC) || defined(_AIX) # define TRIO_PLATFORM_UNIX #elif defined(TRIO_COMPILER_DECC) || defined(__osf___) # define TRIO_PLATFORM_UNIX #elif defined(__NetBSD__) # define TRIO_PLATFORM_UNIX #elif defined(__QNX__) # define TRIO_PLATFORM_UNIX # define TRIO_PLATFORM_QNX #elif defined(__CYGWIN__) # define TRIO_PLATFORM_UNIX #elif defined(AMIGA) && defined(TRIO_COMPILER_GCC) # define TRIO_PLATFORM_UNIX #elif defined(TRIO_COMPILER_MSVC) || defined(WIN32) || defined(_WIN32) # define TRIO_PLATFORM_WIN32 #elif defined(mpeix) || defined(__mpexl) # define TRIO_PLATFORM_MPEIX #endif #if defined(_AIX) # define TRIO_PLATFORM_AIX #elif defined(__hpux) # define TRIO_PLATFORM_HPUX #elif defined(sun) || defined(__sun__) # if defined(__SVR4) || defined(__svr4__) # define TRIO_PLATFORM_SOLARIS # else # define TRIO_PLATFORM_SUNOS # endif #endif #if defined(__STDC__) || defined(TRIO_COMPILER_MSVC) || defined(TRIO_COMPILER_BCB) # define TRIO_COMPILER_SUPPORTS_C89 # if defined(__STDC_VERSION__) # define TRIO_COMPILER_SUPPORTS_C90 # if (__STDC_VERSION__ >= 199409L) # define TRIO_COMPILER_SUPPORTS_C94 # endif # if (__STDC_VERSION__ >= 199901L) # define TRIO_COMPILER_SUPPORTS_C99 # endif # elif defined(TRIO_COMPILER_SUNPRO) # if (__SUNPRO_C >= 0x420) # define TRIO_COMPILER_SUPPORTS_C94 # endif # endif #endif #if defined(_XOPEN_SOURCE) # if defined(_XOPEN_SOURCE_EXTENDED) # define TRIO_COMPILER_SUPPORTS_UNIX95 # endif # if (_XOPEN_VERSION >= 500) # define TRIO_COMPILER_SUPPORTS_UNIX98 # endif # if (_XOPEN_VERSION >= 600) # define TRIO_COMPILER_SUPPORTS_UNIX01 # endif #endif /************************************************************************* * Generic defines */ #if !defined(TRIO_PUBLIC) # define TRIO_PUBLIC #endif #if !defined(TRIO_PRIVATE) # define TRIO_PRIVATE static #endif #if !(defined(TRIO_COMPILER_SUPPORTS_C89) || defined(__cplusplus)) # define TRIO_COMPILER_ANCIENT #endif #if defined(TRIO_COMPILER_ANCIENT) # define TRIO_CONST # define TRIO_VOLATILE # define TRIO_SIGNED typedef double trio_long_double_t; typedef char * trio_pointer_t; # define TRIO_SUFFIX_LONG(x) x # define TRIO_PROTO(x) () # define TRIO_NOARGS # define TRIO_ARGS1(list,a1) list a1; # define TRIO_ARGS2(list,a1,a2) list a1; a2; # define TRIO_ARGS3(list,a1,a2,a3) list a1; a2; a3; # define TRIO_ARGS4(list,a1,a2,a3,a4) list a1; a2; a3; a4; # define TRIO_ARGS5(list,a1,a2,a3,a4,a5) list a1; a2; a3; a4; a5; # define TRIO_ARGS6(list,a1,a2,a3,a4,a5,a6) list a1; a2; a3; a4; a5; a6; # define TRIO_VARGS2(list,a1,a2) list a1; a2 # define TRIO_VARGS3(list,a1,a2,a3) list a1; a2; a3 # define TRIO_VARGS4(list,a1,a2,a3,a4) list a1; a2; a3; a4 # define TRIO_VARGS5(list,a1,a2,a3,a4,a5) list a1; a2; a3; a4; a5 # define TRIO_VA_DECL va_dcl # define TRIO_VA_START(x,y) va_start(x) # define TRIO_VA_END(x) va_end(x) #else /* ANSI C */ # define TRIO_CONST const # define TRIO_VOLATILE volatile # define TRIO_SIGNED signed typedef long double trio_long_double_t; typedef void * trio_pointer_t; # define TRIO_SUFFIX_LONG(x) x ## L # define TRIO_PROTO(x) x # define TRIO_NOARGS void # define TRIO_ARGS1(list,a1) (a1) # define TRIO_ARGS2(list,a1,a2) (a1,a2) # define TRIO_ARGS3(list,a1,a2,a3) (a1,a2,a3) # define TRIO_ARGS4(list,a1,a2,a3,a4) (a1,a2,a3,a4) # define TRIO_ARGS5(list,a1,a2,a3,a4,a5) (a1,a2,a3,a4,a5) # define TRIO_ARGS6(list,a1,a2,a3,a4,a5,a6) (a1,a2,a3,a4,a5,a6) # define TRIO_VARGS2 TRIO_ARGS2 # define TRIO_VARGS3 TRIO_ARGS3 # define TRIO_VARGS4 TRIO_ARGS4 # define TRIO_VARGS5 TRIO_ARGS5 # define TRIO_VA_DECL ... # define TRIO_VA_START(x,y) va_start(x,y) # define TRIO_VA_END(x) va_end(x) #endif #if defined(TRIO_COMPILER_SUPPORTS_C99) || defined(__cplusplus) # define TRIO_INLINE inline #elif defined(TRIO_COMPILER_GCC) # define TRIO_INLINE __inline__ #elif defined(TRIO_COMPILER_MSVC) # define TRIO_INLINE _inline #elif defined(TRIO_COMPILER_BCB) # define TRIO_INLINE __inline #else # define TRIO_INLINE #endif /************************************************************************* * Workarounds */ #if defined(TRIO_PLATFORM_VMS) /* * Computations done with constants at compile time can trigger these * even when compiling with IEEE enabled. */ # pragma message disable (UNDERFLOW, FLOATOVERFL) # if (__CRTL_VER < 80000000) /* * Although the compiler supports C99 language constructs, the C * run-time library does not contain all C99 functions. * * This was the case for 70300022. Update the 80000000 value when * it has been accurately determined what version of the library * supports C99. */ # if defined(TRIO_COMPILER_SUPPORTS_C99) # undef TRIO_COMPILER_SUPPORTS_C99 # endif # endif #endif /* * Not all preprocessors supports the LL token. */ #if defined(TRIO_COMPILER_BCB) #else # define TRIO_COMPILER_SUPPORTS_LL #endif #endif /* TRIO_TRIODEF_H */ libxslt-1.1.28/libxslt/security.h0000664000076400007640000000513412024022317013714 00000000000000/* * Summary: interface for the libxslt security framework * Description: the libxslt security framework allow to restrict * the access to new resources (file or URL) from * the stylesheet at runtime. * * Copy: See Copyright for the status of this software. * * Author: Daniel Veillard */ #ifndef __XML_XSLT_SECURITY_H__ #define __XML_XSLT_SECURITY_H__ #include #include "xsltexports.h" #include "xsltInternals.h" #ifdef __cplusplus extern "C" { #endif /** * xsltSecurityPref: * * structure to indicate the preferences for security in the XSLT * transformation. */ typedef struct _xsltSecurityPrefs xsltSecurityPrefs; typedef xsltSecurityPrefs *xsltSecurityPrefsPtr; /** * xsltSecurityOption: * * the set of option that can be configured */ typedef enum { XSLT_SECPREF_READ_FILE = 1, XSLT_SECPREF_WRITE_FILE, XSLT_SECPREF_CREATE_DIRECTORY, XSLT_SECPREF_READ_NETWORK, XSLT_SECPREF_WRITE_NETWORK } xsltSecurityOption; /** * xsltSecurityCheck: * * User provided function to check the value of a string like a file * path or an URL ... */ typedef int (*xsltSecurityCheck) (xsltSecurityPrefsPtr sec, xsltTransformContextPtr ctxt, const char *value); /* * Module interfaces */ XSLTPUBFUN xsltSecurityPrefsPtr XSLTCALL xsltNewSecurityPrefs (void); XSLTPUBFUN void XSLTCALL xsltFreeSecurityPrefs (xsltSecurityPrefsPtr sec); XSLTPUBFUN int XSLTCALL xsltSetSecurityPrefs (xsltSecurityPrefsPtr sec, xsltSecurityOption option, xsltSecurityCheck func); XSLTPUBFUN xsltSecurityCheck XSLTCALL xsltGetSecurityPrefs (xsltSecurityPrefsPtr sec, xsltSecurityOption option); XSLTPUBFUN void XSLTCALL xsltSetDefaultSecurityPrefs (xsltSecurityPrefsPtr sec); XSLTPUBFUN xsltSecurityPrefsPtr XSLTCALL xsltGetDefaultSecurityPrefs (void); XSLTPUBFUN int XSLTCALL xsltSetCtxtSecurityPrefs (xsltSecurityPrefsPtr sec, xsltTransformContextPtr ctxt); XSLTPUBFUN int XSLTCALL xsltSecurityAllow (xsltSecurityPrefsPtr sec, xsltTransformContextPtr ctxt, const char *value); XSLTPUBFUN int XSLTCALL xsltSecurityForbid (xsltSecurityPrefsPtr sec, xsltTransformContextPtr ctxt, const char *value); /* * internal interfaces */ XSLTPUBFUN int XSLTCALL xsltCheckWrite (xsltSecurityPrefsPtr sec, xsltTransformContextPtr ctxt, const xmlChar *URL); XSLTPUBFUN int XSLTCALL xsltCheckRead (xsltSecurityPrefsPtr sec, xsltTransformContextPtr ctxt, const xmlChar *URL); #ifdef __cplusplus } #endif #endif /* __XML_XSLT_SECURITY_H__ */ libxslt-1.1.28/libxslt/imports.c0000664000076400007640000002375412024022166013547 00000000000000/* * imports.c: Implementation of the XSLT imports * * Reference: * http://www.w3.org/TR/1999/REC-xslt-19991116 * * See Copyright for the status of this software. * * daniel@veillard.com */ #define IN_LIBXSLT #include "libxslt.h" #include #ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_MATH_H #include #endif #ifdef HAVE_FLOAT_H #include #endif #ifdef HAVE_IEEEFP_H #include #endif #ifdef HAVE_NAN_H #include #endif #ifdef HAVE_CTYPE_H #include #endif #include #include #include #include #include #include "xslt.h" #include "xsltInternals.h" #include "xsltutils.h" #include "preproc.h" #include "imports.h" #include "documents.h" #include "security.h" #include "pattern.h" /************************************************************************ * * * Module interfaces * * * ************************************************************************/ /** * xsltFixImportedCompSteps: * @master: the "master" stylesheet * @style: the stylesheet being imported by the master * * normalize the comp steps for the stylesheet being imported * by the master, together with any imports within that. * */ static void xsltFixImportedCompSteps(xsltStylesheetPtr master, xsltStylesheetPtr style) { xsltStylesheetPtr res; xmlHashScan(style->templatesHash, (xmlHashScanner) xsltNormalizeCompSteps, master); master->extrasNr += style->extrasNr; for (res = style->imports; res != NULL; res = res->next) { xsltFixImportedCompSteps(master, res); } } /** * xsltParseStylesheetImport: * @style: the XSLT stylesheet * @cur: the import element * * parse an XSLT stylesheet import element * * Returns 0 in case of success -1 in case of failure. */ int xsltParseStylesheetImport(xsltStylesheetPtr style, xmlNodePtr cur) { int ret = -1; xmlDocPtr import = NULL; xmlChar *base = NULL; xmlChar *uriRef = NULL; xmlChar *URI = NULL; xsltStylesheetPtr res; xsltSecurityPrefsPtr sec; if ((cur == NULL) || (style == NULL)) return (ret); uriRef = xmlGetNsProp(cur, (const xmlChar *)"href", NULL); if (uriRef == NULL) { xsltTransformError(NULL, style, cur, "xsl:import : missing href attribute\n"); goto error; } base = xmlNodeGetBase(style->doc, cur); URI = xmlBuildURI(uriRef, base); if (URI == NULL) { xsltTransformError(NULL, style, cur, "xsl:import : invalid URI reference %s\n", uriRef); goto error; } res = style; while (res != NULL) { if (res->doc == NULL) break; if (xmlStrEqual(res->doc->URL, URI)) { xsltTransformError(NULL, style, cur, "xsl:import : recursion detected on imported URL %s\n", URI); goto error; } res = res->parent; } /* * Security framework check */ sec = xsltGetDefaultSecurityPrefs(); if (sec != NULL) { int secres; secres = xsltCheckRead(sec, NULL, URI); if (secres == 0) { xsltTransformError(NULL, NULL, NULL, "xsl:import: read rights for %s denied\n", URI); goto error; } } import = xsltDocDefaultLoader(URI, style->dict, XSLT_PARSE_OPTIONS, (void *) style, XSLT_LOAD_STYLESHEET); if (import == NULL) { xsltTransformError(NULL, style, cur, "xsl:import : unable to load %s\n", URI); goto error; } res = xsltParseStylesheetImportedDoc(import, style); if (res != NULL) { res->next = style->imports; style->imports = res; if (style->parent == NULL) { xsltFixImportedCompSteps(style, res); } ret = 0; } else { xmlFreeDoc(import); } error: if (uriRef != NULL) xmlFree(uriRef); if (base != NULL) xmlFree(base); if (URI != NULL) xmlFree(URI); return (ret); } /** * xsltParseStylesheetInclude: * @style: the XSLT stylesheet * @cur: the include node * * parse an XSLT stylesheet include element * * Returns 0 in case of success -1 in case of failure */ int xsltParseStylesheetInclude(xsltStylesheetPtr style, xmlNodePtr cur) { int ret = -1; xmlDocPtr oldDoc; xmlChar *base = NULL; xmlChar *uriRef = NULL; xmlChar *URI = NULL; xsltStylesheetPtr result; xsltDocumentPtr include; xsltDocumentPtr docptr; int oldNopreproc; if ((cur == NULL) || (style == NULL)) return (ret); uriRef = xmlGetNsProp(cur, (const xmlChar *)"href", NULL); if (uriRef == NULL) { xsltTransformError(NULL, style, cur, "xsl:include : missing href attribute\n"); goto error; } base = xmlNodeGetBase(style->doc, cur); URI = xmlBuildURI(uriRef, base); if (URI == NULL) { xsltTransformError(NULL, style, cur, "xsl:include : invalid URI reference %s\n", uriRef); goto error; } /* * in order to detect recursion, we check all previously included * stylesheets. */ docptr = style->includes; while (docptr != NULL) { if (xmlStrEqual(docptr->doc->URL, URI)) { xsltTransformError(NULL, style, cur, "xsl:include : recursion detected on included URL %s\n", URI); goto error; } docptr = docptr->includes; } include = xsltLoadStyleDocument(style, URI); if (include == NULL) { xsltTransformError(NULL, style, cur, "xsl:include : unable to load %s\n", URI); goto error; } #ifdef XSLT_REFACTORED if (IS_XSLT_ELEM_FAST(cur) && (cur->psvi != NULL)) { ((xsltStyleItemIncludePtr) cur->psvi)->include = include; } else { xsltTransformError(NULL, style, cur, "Internal error: (xsltParseStylesheetInclude) " "The xsl:include element was not compiled.\n", URI); style->errors++; } #endif oldDoc = style->doc; style->doc = include->doc; /* chain to stylesheet for recursion checking */ include->includes = style->includes; style->includes = include; oldNopreproc = style->nopreproc; style->nopreproc = include->preproc; /* * TODO: This will change some values of the * including stylesheet with every included module * (e.g. excluded-result-prefixes) * We need to strictly seperate such stylesheet-owned values. */ result = xsltParseStylesheetProcess(style, include->doc); style->nopreproc = oldNopreproc; include->preproc = 1; style->includes = include->includes; style->doc = oldDoc; if (result == NULL) { ret = -1; goto error; } ret = 0; error: if (uriRef != NULL) xmlFree(uriRef); if (base != NULL) xmlFree(base); if (URI != NULL) xmlFree(URI); return (ret); } /** * xsltNextImport: * @cur: the current XSLT stylesheet * * Find the next stylesheet in import precedence. * * Returns the next stylesheet or NULL if it was the last one */ xsltStylesheetPtr xsltNextImport(xsltStylesheetPtr cur) { if (cur == NULL) return(NULL); if (cur->imports != NULL) return(cur->imports); if (cur->next != NULL) return(cur->next) ; do { cur = cur->parent; if (cur == NULL) break; if (cur->next != NULL) return(cur->next); } while (cur != NULL); return(cur); } /** * xsltNeedElemSpaceHandling: * @ctxt: an XSLT transformation context * * Checks whether that stylesheet requires white-space stripping * * Returns 1 if space should be stripped, 0 if not */ int xsltNeedElemSpaceHandling(xsltTransformContextPtr ctxt) { xsltStylesheetPtr style; if (ctxt == NULL) return(0); style = ctxt->style; while (style != NULL) { if (style->stripSpaces != NULL) return(1); style = xsltNextImport(style); } return(0); } /** * xsltFindElemSpaceHandling: * @ctxt: an XSLT transformation context * @node: an XML node * * Find strip-space or preserve-space informations for an element * respect the import precedence or the wildcards * * Returns 1 if space should be stripped, 0 if not, and 2 if everything * should be CDTATA wrapped. */ int xsltFindElemSpaceHandling(xsltTransformContextPtr ctxt, xmlNodePtr node) { xsltStylesheetPtr style; const xmlChar *val; if ((ctxt == NULL) || (node == NULL)) return(0); style = ctxt->style; while (style != NULL) { if (node->ns != NULL) { val = (const xmlChar *) xmlHashLookup2(style->stripSpaces, node->name, node->ns->href); if (val == NULL) { val = (const xmlChar *) xmlHashLookup2(style->stripSpaces, BAD_CAST "*", node->ns->href); } } else { val = (const xmlChar *) xmlHashLookup2(style->stripSpaces, node->name, NULL); } if (val != NULL) { if (xmlStrEqual(val, (xmlChar *) "strip")) return(1); if (xmlStrEqual(val, (xmlChar *) "preserve")) return(0); } if (style->stripAll == 1) return(1); if (style->stripAll == -1) return(0); style = xsltNextImport(style); } return(0); } /** * xsltFindTemplate: * @ctxt: an XSLT transformation context * @name: the template name * @nameURI: the template name URI * * Finds the named template, apply import precedence rule. * REVISIT TODO: We'll change the nameURI fields of * templates to be in the string dict, so if the * specified @nameURI is in the same dict, then use pointer * comparison. Check if this can be done in a sane way. * Maybe this function is not needed internally at * transformation-time if we hard-wire the called templates * to the caller. * * Returns the xsltTemplatePtr or NULL if not found */ xsltTemplatePtr xsltFindTemplate(xsltTransformContextPtr ctxt, const xmlChar *name, const xmlChar *nameURI) { xsltTemplatePtr cur; xsltStylesheetPtr style; if ((ctxt == NULL) || (name == NULL)) return(NULL); style = ctxt->style; while (style != NULL) { cur = style->templates; while (cur != NULL) { if (xmlStrEqual(name, cur->name)) { if (((nameURI == NULL) && (cur->nameURI == NULL)) || ((nameURI != NULL) && (cur->nameURI != NULL) && (xmlStrEqual(nameURI, cur->nameURI)))) { return(cur); } } cur = cur->next; } style = xsltNextImport(style); } return(NULL); } libxslt-1.1.28/libxslt/xslt.c0000664000076400007640000055044312024022316013041 00000000000000/* * xslt.c: Implemetation of an XSL Transformation 1.0 engine * * Reference: * XSLT specification * http://www.w3.org/TR/1999/REC-xslt-19991116 * * Associating Style Sheets with XML documents * http://www.w3.org/1999/06/REC-xml-stylesheet-19990629 * * See Copyright for the status of this software. * * daniel@veillard.com */ #define IN_LIBXSLT #include "libxslt.h" #include #include #include #include #include #include #include #include #include #include #include #include "xslt.h" #include "xsltInternals.h" #include "pattern.h" #include "variables.h" #include "namespaces.h" #include "attributes.h" #include "xsltutils.h" #include "imports.h" #include "keys.h" #include "documents.h" #include "extensions.h" #include "preproc.h" #include "extra.h" #include "security.h" #ifdef WITH_XSLT_DEBUG #define WITH_XSLT_DEBUG_PARSING /* #define WITH_XSLT_DEBUG_BLANKS */ #endif const char *xsltEngineVersion = LIBXSLT_VERSION_STRING LIBXSLT_VERSION_EXTRA; const int xsltLibxsltVersion = LIBXSLT_VERSION; const int xsltLibxmlVersion = LIBXML_VERSION; #ifdef XSLT_REFACTORED const xmlChar *xsltConstNamespaceNameXSLT = (const xmlChar *) XSLT_NAMESPACE; #define XSLT_ELEMENT_CATEGORY_XSLT 0 #define XSLT_ELEMENT_CATEGORY_EXTENSION 1 #define XSLT_ELEMENT_CATEGORY_LRE 2 /* * xsltLiteralResultMarker: * Marker for Literal result elements, in order to avoid multiple attempts * to recognize such elements in the stylesheet's tree. * This marker is set on node->psvi during the initial traversal * of a stylesheet's node tree. * const xmlChar *xsltLiteralResultMarker = (const xmlChar *) "Literal Result Element"; */ /* * xsltXSLTTextMarker: * Marker for xsl:text elements. Used to recognize xsl:text elements * for post-processing of the stylesheet's tree, where those * elements are removed from the tree. */ const xmlChar *xsltXSLTTextMarker = (const xmlChar *) "XSLT Text Element"; /* * xsltXSLTAttrMarker: * Marker for XSLT attribute on Literal Result Elements. */ const xmlChar *xsltXSLTAttrMarker = (const xmlChar *) "LRE XSLT Attr"; #endif #ifdef XSLT_LOCALE_WINAPI extern xmlRMutexPtr xsltLocaleMutex; #endif /* * Harmless but avoiding a problem when compiling against a * libxml <= 2.3.11 without LIBXML_DEBUG_ENABLED */ #ifndef LIBXML_DEBUG_ENABLED double xmlXPathStringEvalNumber(const xmlChar *str); #endif /* * Useful macros */ #ifdef IS_BLANK #undef IS_BLANK #endif #define IS_BLANK(c) (((c) == 0x20) || ((c) == 0x09) || ((c) == 0xA) || \ ((c) == 0x0D)) #ifdef IS_BLANK_NODE #undef IS_BLANK_NODE #endif #define IS_BLANK_NODE(n) \ (((n)->type == XML_TEXT_NODE) && (xsltIsBlank((n)->content))) /** * xsltParseContentError: * * @style: the stylesheet * @node: the node where the error occured * * Compile-time error function. */ static void xsltParseContentError(xsltStylesheetPtr style, xmlNodePtr node) { if ((style == NULL) || (node == NULL)) return; if (IS_XSLT_ELEM(node)) xsltTransformError(NULL, style, node, "The XSLT-element '%s' is not allowed at this position.\n", node->name); else xsltTransformError(NULL, style, node, "The element '%s' is not allowed at this position.\n", node->name); style->errors++; } #ifdef XSLT_REFACTORED #else /** * exclPrefixPush: * @style: the transformation stylesheet * @value: the excluded namespace name to push on the stack * * Push an excluded namespace name on the stack * * Returns the new index in the stack or -1 if already present or * in case of error */ static int exclPrefixPush(xsltStylesheetPtr style, xmlChar * value) { int i; if (style->exclPrefixMax == 0) { style->exclPrefixMax = 4; style->exclPrefixTab = (xmlChar * *)xmlMalloc(style->exclPrefixMax * sizeof(style->exclPrefixTab[0])); if (style->exclPrefixTab == NULL) { xmlGenericError(xmlGenericErrorContext, "malloc failed !\n"); return (-1); } } /* do not push duplicates */ for (i = 0;i < style->exclPrefixNr;i++) { if (xmlStrEqual(style->exclPrefixTab[i], value)) return(-1); } if (style->exclPrefixNr >= style->exclPrefixMax) { style->exclPrefixMax *= 2; style->exclPrefixTab = (xmlChar * *)xmlRealloc(style->exclPrefixTab, style->exclPrefixMax * sizeof(style->exclPrefixTab[0])); if (style->exclPrefixTab == NULL) { xmlGenericError(xmlGenericErrorContext, "realloc failed !\n"); return (-1); } } style->exclPrefixTab[style->exclPrefixNr] = value; style->exclPrefix = value; return (style->exclPrefixNr++); } /** * exclPrefixPop: * @style: the transformation stylesheet * * Pop an excluded prefix value from the stack * * Returns the stored excluded prefix value */ static xmlChar * exclPrefixPop(xsltStylesheetPtr style) { xmlChar *ret; if (style->exclPrefixNr <= 0) return (0); style->exclPrefixNr--; if (style->exclPrefixNr > 0) style->exclPrefix = style->exclPrefixTab[style->exclPrefixNr - 1]; else style->exclPrefix = NULL; ret = style->exclPrefixTab[style->exclPrefixNr]; style->exclPrefixTab[style->exclPrefixNr] = 0; return (ret); } #endif /************************************************************************ * * * Helper functions * * * ************************************************************************/ static int initialized = 0; /** * xsltInit: * * Initializes the processor (e.g. registers built-in extensions, * etc.) */ void xsltInit (void) { if (initialized == 0) { initialized = 1; #ifdef XSLT_LOCALE_WINAPI xsltLocaleMutex = xmlNewRMutex(); #endif xsltRegisterAllExtras(); } } /** * xsltUninit: * * Uninitializes the processor. */ void xsltUninit (void) { #ifdef XSLT_LOCALE_WINAPI xmlFreeRMutex(xsltLocaleMutex); xsltLocaleMutex = NULL; #endif initialized = 0; } /** * xsltIsBlank: * @str: a string * * Check if a string is ignorable * * Returns 1 if the string is NULL or made of blanks chars, 0 otherwise */ int xsltIsBlank(xmlChar *str) { if (str == NULL) return(1); while (*str != 0) { if (!(IS_BLANK(*str))) return(0); str++; } return(1); } /************************************************************************ * * * Routines to handle XSLT data structures * * * ************************************************************************/ static xsltDecimalFormatPtr xsltNewDecimalFormat(xmlChar *name) { xsltDecimalFormatPtr self; /* UTF-8 for 0x2030 */ static const xmlChar permille[4] = {0xe2, 0x80, 0xb0, 0}; self = xmlMalloc(sizeof(xsltDecimalFormat)); if (self != NULL) { self->next = NULL; self->name = name; /* Default values */ self->digit = xmlStrdup(BAD_CAST("#")); self->patternSeparator = xmlStrdup(BAD_CAST(";")); self->decimalPoint = xmlStrdup(BAD_CAST(".")); self->grouping = xmlStrdup(BAD_CAST(",")); self->percent = xmlStrdup(BAD_CAST("%")); self->permille = xmlStrdup(BAD_CAST(permille)); self->zeroDigit = xmlStrdup(BAD_CAST("0")); self->minusSign = xmlStrdup(BAD_CAST("-")); self->infinity = xmlStrdup(BAD_CAST("Infinity")); self->noNumber = xmlStrdup(BAD_CAST("NaN")); } return self; } static void xsltFreeDecimalFormat(xsltDecimalFormatPtr self) { if (self != NULL) { if (self->digit) xmlFree(self->digit); if (self->patternSeparator) xmlFree(self->patternSeparator); if (self->decimalPoint) xmlFree(self->decimalPoint); if (self->grouping) xmlFree(self->grouping); if (self->percent) xmlFree(self->percent); if (self->permille) xmlFree(self->permille); if (self->zeroDigit) xmlFree(self->zeroDigit); if (self->minusSign) xmlFree(self->minusSign); if (self->infinity) xmlFree(self->infinity); if (self->noNumber) xmlFree(self->noNumber); if (self->name) xmlFree(self->name); xmlFree(self); } } static void xsltFreeDecimalFormatList(xsltStylesheetPtr self) { xsltDecimalFormatPtr iter; xsltDecimalFormatPtr tmp; if (self == NULL) return; iter = self->decimalFormat; while (iter != NULL) { tmp = iter->next; xsltFreeDecimalFormat(iter); iter = tmp; } } /** * xsltDecimalFormatGetByName: * @style: the XSLT stylesheet * @name: the decimal-format name to find * * Find decimal-format by name * * Returns the xsltDecimalFormatPtr */ xsltDecimalFormatPtr xsltDecimalFormatGetByName(xsltStylesheetPtr style, xmlChar *name) { xsltDecimalFormatPtr result = NULL; if (name == NULL) return style->decimalFormat; while (style != NULL) { for (result = style->decimalFormat->next; result != NULL; result = result->next) { if (xmlStrEqual(name, result->name)) return result; } style = xsltNextImport(style); } return result; } /** * xsltNewTemplate: * * Create a new XSLT Template * * Returns the newly allocated xsltTemplatePtr or NULL in case of error */ static xsltTemplatePtr xsltNewTemplate(void) { xsltTemplatePtr cur; cur = (xsltTemplatePtr) xmlMalloc(sizeof(xsltTemplate)); if (cur == NULL) { xsltTransformError(NULL, NULL, NULL, "xsltNewTemplate : malloc failed\n"); return(NULL); } memset(cur, 0, sizeof(xsltTemplate)); cur->priority = XSLT_PAT_NO_PRIORITY; return(cur); } /** * xsltFreeTemplate: * @template: an XSLT template * * Free up the memory allocated by @template */ static void xsltFreeTemplate(xsltTemplatePtr template) { if (template == NULL) return; if (template->match) xmlFree(template->match); /* * NOTE: @name and @nameURI are put into the string dict now. * if (template->name) xmlFree(template->name); * if (template->nameURI) xmlFree(template->nameURI); */ /* if (template->mode) xmlFree(template->mode); if (template->modeURI) xmlFree(template->modeURI); */ if (template->inheritedNs) xmlFree(template->inheritedNs); /* free profiling data */ if (template->templCalledTab) xmlFree(template->templCalledTab); if (template->templCountTab) xmlFree(template->templCountTab); memset(template, -1, sizeof(xsltTemplate)); xmlFree(template); } /** * xsltFreeTemplateList: * @template: an XSLT template list * * Free up the memory allocated by all the elements of @template */ static void xsltFreeTemplateList(xsltTemplatePtr template) { xsltTemplatePtr cur; while (template != NULL) { cur = template; template = template->next; xsltFreeTemplate(cur); } } #ifdef XSLT_REFACTORED static void xsltFreeNsAliasList(xsltNsAliasPtr item) { xsltNsAliasPtr tmp; while (item) { tmp = item; item = item->next; xmlFree(tmp); } return; } #ifdef XSLT_REFACTORED_XSLT_NSCOMP static void xsltFreeNamespaceMap(xsltNsMapPtr item) { xsltNsMapPtr tmp; while (item) { tmp = item; item = item->next; xmlFree(tmp); } return; } static xsltNsMapPtr xsltNewNamespaceMapItem(xsltCompilerCtxtPtr cctxt, xmlDocPtr doc, xmlNsPtr ns, xmlNodePtr elem) { xsltNsMapPtr ret; if ((cctxt == NULL) || (doc == NULL) || (ns == NULL)) return(NULL); ret = (xsltNsMapPtr) xmlMalloc(sizeof(xsltNsMap)); if (ret == NULL) { xsltTransformError(NULL, cctxt->style, elem, "Internal error: (xsltNewNamespaceMapItem) " "memory allocation failed.\n"); return(NULL); } memset(ret, 0, sizeof(xsltNsMap)); ret->doc = doc; ret->ns = ns; ret->origNsName = ns->href; /* * Store the item at current stylesheet-level. */ if (cctxt->psData->nsMap != NULL) ret->next = cctxt->psData->nsMap; cctxt->psData->nsMap = ret; return(ret); } #endif /* XSLT_REFACTORED_XSLT_NSCOMP */ /** * xsltCompilerVarInfoFree: * @cctxt: the compilation context * * Frees the list of information for vars/params. */ static void xsltCompilerVarInfoFree(xsltCompilerCtxtPtr cctxt) { xsltVarInfoPtr ivar = cctxt->ivars, ivartmp; while (ivar) { ivartmp = ivar; ivar = ivar->next; xmlFree(ivartmp); } } /** * xsltCompilerCtxtFree: * * Free an XSLT compiler context. */ static void xsltCompilationCtxtFree(xsltCompilerCtxtPtr cctxt) { if (cctxt == NULL) return; #ifdef WITH_XSLT_DEBUG_PARSING xsltGenericDebug(xsltGenericDebugContext, "Freeing compilation context\n"); xsltGenericDebug(xsltGenericDebugContext, "### Max inodes: %d\n", cctxt->maxNodeInfos); xsltGenericDebug(xsltGenericDebugContext, "### Max LREs : %d\n", cctxt->maxLREs); #endif /* * Free node-infos. */ if (cctxt->inodeList != NULL) { xsltCompilerNodeInfoPtr tmp, cur = cctxt->inodeList; while (cur != NULL) { tmp = cur; cur = cur->next; xmlFree(tmp); } } if (cctxt->tmpList != NULL) xsltPointerListFree(cctxt->tmpList); #ifdef XSLT_REFACTORED_XPATHCOMP if (cctxt->xpathCtxt != NULL) xmlXPathFreeContext(cctxt->xpathCtxt); #endif if (cctxt->nsAliases != NULL) xsltFreeNsAliasList(cctxt->nsAliases); if (cctxt->ivars) xsltCompilerVarInfoFree(cctxt); xmlFree(cctxt); } /** * xsltCompilerCreate: * * Creates an XSLT compiler context. * * Returns the pointer to the created xsltCompilerCtxt or * NULL in case of an internal error. */ static xsltCompilerCtxtPtr xsltCompilationCtxtCreate(xsltStylesheetPtr style) { xsltCompilerCtxtPtr ret; ret = (xsltCompilerCtxtPtr) xmlMalloc(sizeof(xsltCompilerCtxt)); if (ret == NULL) { xsltTransformError(NULL, style, NULL, "xsltCompilerCreate: allocation of compiler " "context failed.\n"); return(NULL); } memset(ret, 0, sizeof(xsltCompilerCtxt)); ret->errSeverity = XSLT_ERROR_SEVERITY_ERROR; ret->tmpList = xsltPointerListCreate(20); if (ret->tmpList == NULL) { goto internal_err; } #ifdef XSLT_REFACTORED_XPATHCOMP /* * Create the XPath compilation context in order * to speed up precompilation of XPath expressions. */ ret->xpathCtxt = xmlXPathNewContext(NULL); if (ret->xpathCtxt == NULL) goto internal_err; #endif return(ret); internal_err: xsltCompilationCtxtFree(ret); return(NULL); } static void xsltLREEffectiveNsNodesFree(xsltEffectiveNsPtr first) { xsltEffectiveNsPtr tmp; while (first != NULL) { tmp = first; first = first->nextInStore; xmlFree(tmp); } } static void xsltFreePrincipalStylesheetData(xsltPrincipalStylesheetDataPtr data) { if (data == NULL) return; if (data->inScopeNamespaces != NULL) { int i; xsltNsListContainerPtr nsi; xsltPointerListPtr list = (xsltPointerListPtr) data->inScopeNamespaces; for (i = 0; i < list->number; i++) { /* * REVISIT TODO: Free info of in-scope namespaces. */ nsi = (xsltNsListContainerPtr) list->items[i]; if (nsi->list != NULL) xmlFree(nsi->list); xmlFree(nsi); } xsltPointerListFree(list); data->inScopeNamespaces = NULL; } if (data->exclResultNamespaces != NULL) { int i; xsltPointerListPtr list = (xsltPointerListPtr) data->exclResultNamespaces; for (i = 0; i < list->number; i++) xsltPointerListFree((xsltPointerListPtr) list->items[i]); xsltPointerListFree(list); data->exclResultNamespaces = NULL; } if (data->extElemNamespaces != NULL) { xsltPointerListPtr list = (xsltPointerListPtr) data->extElemNamespaces; int i; for (i = 0; i < list->number; i++) xsltPointerListFree((xsltPointerListPtr) list->items[i]); xsltPointerListFree(list); data->extElemNamespaces = NULL; } if (data->effectiveNs) { xsltLREEffectiveNsNodesFree(data->effectiveNs); data->effectiveNs = NULL; } #ifdef XSLT_REFACTORED_XSLT_NSCOMP xsltFreeNamespaceMap(data->nsMap); #endif xmlFree(data); } static xsltPrincipalStylesheetDataPtr xsltNewPrincipalStylesheetData(void) { xsltPrincipalStylesheetDataPtr ret; ret = (xsltPrincipalStylesheetDataPtr) xmlMalloc(sizeof(xsltPrincipalStylesheetData)); if (ret == NULL) { xsltTransformError(NULL, NULL, NULL, "xsltNewPrincipalStylesheetData: memory allocation failed.\n"); return(NULL); } memset(ret, 0, sizeof(xsltPrincipalStylesheetData)); /* * Global list of in-scope namespaces. */ ret->inScopeNamespaces = xsltPointerListCreate(-1); if (ret->inScopeNamespaces == NULL) goto internal_err; /* * Global list of excluded result ns-decls. */ ret->exclResultNamespaces = xsltPointerListCreate(-1); if (ret->exclResultNamespaces == NULL) goto internal_err; /* * Global list of extension instruction namespace names. */ ret->extElemNamespaces = xsltPointerListCreate(-1); if (ret->extElemNamespaces == NULL) goto internal_err; return(ret); internal_err: return(NULL); } #endif /** * xsltNewStylesheet: * * Create a new XSLT Stylesheet * * Returns the newly allocated xsltStylesheetPtr or NULL in case of error */ xsltStylesheetPtr xsltNewStylesheet(void) { xsltStylesheetPtr ret = NULL; ret = (xsltStylesheetPtr) xmlMalloc(sizeof(xsltStylesheet)); if (ret == NULL) { xsltTransformError(NULL, NULL, NULL, "xsltNewStylesheet : malloc failed\n"); goto internal_err; } memset(ret, 0, sizeof(xsltStylesheet)); ret->omitXmlDeclaration = -1; ret->standalone = -1; ret->decimalFormat = xsltNewDecimalFormat(NULL); ret->indent = -1; ret->errors = 0; ret->warnings = 0; ret->exclPrefixNr = 0; ret->exclPrefixMax = 0; ret->exclPrefixTab = NULL; ret->extInfos = NULL; ret->extrasNr = 0; ret->internalized = 1; ret->literal_result = 0; ret->forwards_compatible = 0; ret->dict = xmlDictCreate(); #ifdef WITH_XSLT_DEBUG xsltGenericDebug(xsltGenericDebugContext, "creating dictionary for stylesheet\n"); #endif xsltInit(); return(ret); internal_err: if (ret != NULL) xsltFreeStylesheet(ret); return(NULL); } /** * xsltAllocateExtra: * @style: an XSLT stylesheet * * Allocate an extra runtime information slot statically while compiling * the stylesheet and return its number * * Returns the number of the slot */ int xsltAllocateExtra(xsltStylesheetPtr style) { return(style->extrasNr++); } /** * xsltAllocateExtraCtxt: * @ctxt: an XSLT transformation context * * Allocate an extra runtime information slot at run-time * and return its number * This make sure there is a slot ready in the transformation context * * Returns the number of the slot */ int xsltAllocateExtraCtxt(xsltTransformContextPtr ctxt) { if (ctxt->extrasNr >= ctxt->extrasMax) { int i; if (ctxt->extrasNr == 0) { ctxt->extrasMax = 20; ctxt->extras = (xsltRuntimeExtraPtr) xmlMalloc(ctxt->extrasMax * sizeof(xsltRuntimeExtra)); if (ctxt->extras == NULL) { xmlGenericError(xmlGenericErrorContext, "xsltAllocateExtraCtxt: out of memory\n"); ctxt->state = XSLT_STATE_ERROR; return(0); } for (i = 0;i < ctxt->extrasMax;i++) { ctxt->extras[i].info = NULL; ctxt->extras[i].deallocate = NULL; ctxt->extras[i].val.ptr = NULL; } } else { xsltRuntimeExtraPtr tmp; ctxt->extrasMax += 100; tmp = (xsltRuntimeExtraPtr) xmlRealloc(ctxt->extras, ctxt->extrasMax * sizeof(xsltRuntimeExtra)); if (tmp == NULL) { xmlGenericError(xmlGenericErrorContext, "xsltAllocateExtraCtxt: out of memory\n"); ctxt->state = XSLT_STATE_ERROR; return(0); } ctxt->extras = tmp; for (i = ctxt->extrasNr;i < ctxt->extrasMax;i++) { ctxt->extras[i].info = NULL; ctxt->extras[i].deallocate = NULL; ctxt->extras[i].val.ptr = NULL; } } } return(ctxt->extrasNr++); } /** * xsltFreeStylesheetList: * @style: an XSLT stylesheet list * * Free up the memory allocated by the list @style */ static void xsltFreeStylesheetList(xsltStylesheetPtr style) { xsltStylesheetPtr next; while (style != NULL) { next = style->next; xsltFreeStylesheet(style); style = next; } } /** * xsltCleanupStylesheetTree: * * @doc: the document-node * @node: the element where the stylesheet is rooted at * * Actually @node need not be the document-element, but * currently Libxslt does not support embedded stylesheets. * * Returns 0 if OK, -1 on API or internal errors. */ static int xsltCleanupStylesheetTree(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr rootElem ATTRIBUTE_UNUSED) { #if 0 /* TODO: Currently disabled, since probably not needed. */ xmlNodePtr cur; if ((doc == NULL) || (rootElem == NULL) || (rootElem->type != XML_ELEMENT_NODE) || (doc != rootElem->doc)) return(-1); /* * Cleanup was suggested by Aleksey Sanin: * Clear the PSVI field to avoid problems if the * node-tree of the stylesheet is intended to be used for * further processing by the user (e.g. for compiling it * once again - although not recommended). */ cur = rootElem; while (cur != NULL) { if (cur->type == XML_ELEMENT_NODE) { /* * Clear the PSVI field. */ cur->psvi = NULL; if (cur->children) { cur = cur->children; continue; } } leave_node: if (cur == rootElem) break; if (cur->next != NULL) cur = cur->next; else { cur = cur->parent; if (cur == NULL) break; goto leave_node; } } #endif /* #if 0 */ return(0); } /** * xsltFreeStylesheet: * @style: an XSLT stylesheet * * Free up the memory allocated by @style */ void xsltFreeStylesheet(xsltStylesheetPtr style) { if (style == NULL) return; #ifdef XSLT_REFACTORED /* * Start with a cleanup of the main stylesheet's doc. */ if ((style->principal == style) && (style->doc)) xsltCleanupStylesheetTree(style->doc, xmlDocGetRootElement(style->doc)); #ifdef XSLT_REFACTORED_XSLT_NSCOMP /* * Restore changed ns-decls before freeing the document. */ if ((style->doc != NULL) && XSLT_HAS_INTERNAL_NSMAP(style)) { xsltRestoreDocumentNamespaces(XSLT_GET_INTERNAL_NSMAP(style), style->doc); } #endif /* XSLT_REFACTORED_XSLT_NSCOMP */ #else /* * Start with a cleanup of the main stylesheet's doc. */ if ((style->parent == NULL) && (style->doc)) xsltCleanupStylesheetTree(style->doc, xmlDocGetRootElement(style->doc)); #endif /* XSLT_REFACTORED */ xsltFreeKeys(style); xsltFreeExts(style); xsltFreeTemplateHashes(style); xsltFreeDecimalFormatList(style); xsltFreeTemplateList(style->templates); xsltFreeAttributeSetsHashes(style); xsltFreeNamespaceAliasHashes(style); xsltFreeStylePreComps(style); /* * Free documents of all included stylsheet modules of this * stylesheet level. */ xsltFreeStyleDocuments(style); /* * TODO: Best time to shutdown extension stuff? */ xsltShutdownExts(style); if (style->variables != NULL) xsltFreeStackElemList(style->variables); if (style->cdataSection != NULL) xmlHashFree(style->cdataSection, NULL); if (style->stripSpaces != NULL) xmlHashFree(style->stripSpaces, NULL); if (style->nsHash != NULL) xmlHashFree(style->nsHash, NULL); if (style->exclPrefixTab != NULL) xmlFree(style->exclPrefixTab); if (style->method != NULL) xmlFree(style->method); if (style->methodURI != NULL) xmlFree(style->methodURI); if (style->version != NULL) xmlFree(style->version); if (style->encoding != NULL) xmlFree(style->encoding); if (style->doctypePublic != NULL) xmlFree(style->doctypePublic); if (style->doctypeSystem != NULL) xmlFree(style->doctypeSystem); if (style->mediaType != NULL) xmlFree(style->mediaType); if (style->attVTs) xsltFreeAVTList(style->attVTs); if (style->imports != NULL) xsltFreeStylesheetList(style->imports); #ifdef XSLT_REFACTORED /* * If this is the principal stylesheet, then * free its internal data. */ if (style->principal == style) { if (style->principalData) { xsltFreePrincipalStylesheetData(style->principalData); style->principalData = NULL; } } #endif /* * Better to free the main document of this stylesheet level * at the end - so here. */ if (style->doc != NULL) { xmlFreeDoc(style->doc); } #ifdef WITH_XSLT_DEBUG xsltGenericDebug(xsltGenericDebugContext, "freeing dictionary from stylesheet\n"); #endif xmlDictFree(style->dict); memset(style, -1, sizeof(xsltStylesheet)); xmlFree(style); } /************************************************************************ * * * Parsing of an XSLT Stylesheet * * * ************************************************************************/ #ifdef XSLT_REFACTORED /* * This is now performed in an optimized way in xsltParseXSLTTemplate. */ #else /** * xsltGetInheritedNsList: * @style: the stylesheet * @template: the template * @node: the current node * * Search all the namespace applying to a given element except the ones * from excluded output prefixes currently in scope. Initialize the * template inheritedNs list with it. * * Returns the number of entries found */ static int xsltGetInheritedNsList(xsltStylesheetPtr style, xsltTemplatePtr template, xmlNodePtr node) { xmlNsPtr cur; xmlNsPtr *ret = NULL; int nbns = 0; int maxns = 10; int i; if ((style == NULL) || (template == NULL) || (node == NULL) || (template->inheritedNsNr != 0) || (template->inheritedNs != NULL)) return(0); while (node != NULL) { if (node->type == XML_ELEMENT_NODE) { cur = node->nsDef; while (cur != NULL) { if (xmlStrEqual(cur->href, XSLT_NAMESPACE)) goto skip_ns; if ((cur->prefix != NULL) && (xsltCheckExtPrefix(style, cur->prefix))) goto skip_ns; /* * Check if this namespace was excluded. * Note that at this point only the exclusions defined * on the topmost stylesheet element are in the exclusion-list. */ for (i = 0;i < style->exclPrefixNr;i++) { if (xmlStrEqual(cur->href, style->exclPrefixTab[i])) goto skip_ns; } if (ret == NULL) { ret = (xmlNsPtr *) xmlMalloc((maxns + 1) * sizeof(xmlNsPtr)); if (ret == NULL) { xmlGenericError(xmlGenericErrorContext, "xsltGetInheritedNsList : out of memory!\n"); return(0); } ret[nbns] = NULL; } /* * Skip shadowed namespace bindings. */ for (i = 0; i < nbns; i++) { if ((cur->prefix == ret[i]->prefix) || (xmlStrEqual(cur->prefix, ret[i]->prefix))) break; } if (i >= nbns) { if (nbns >= maxns) { maxns *= 2; ret = (xmlNsPtr *) xmlRealloc(ret, (maxns + 1) * sizeof(xmlNsPtr)); if (ret == NULL) { xmlGenericError(xmlGenericErrorContext, "xsltGetInheritedNsList : realloc failed!\n"); return(0); } } ret[nbns++] = cur; ret[nbns] = NULL; } skip_ns: cur = cur->next; } } node = node->parent; } if (nbns != 0) { #ifdef WITH_XSLT_DEBUG_PARSING xsltGenericDebug(xsltGenericDebugContext, "template has %d inherited namespaces\n", nbns); #endif template->inheritedNsNr = nbns; template->inheritedNs = ret; } return (nbns); } #endif /* else of XSLT_REFACTORED */ /** * xsltParseStylesheetOutput: * @style: the XSLT stylesheet * @cur: the "output" element * * parse an XSLT stylesheet output element and record * information related to the stylesheet output */ void xsltParseStylesheetOutput(xsltStylesheetPtr style, xmlNodePtr cur) { xmlChar *elements, *prop; xmlChar *element, *end; if ((cur == NULL) || (style == NULL) || (cur->type != XML_ELEMENT_NODE)) return; prop = xmlGetNsProp(cur, (const xmlChar *) "version", NULL); if (prop != NULL) { if (style->version != NULL) xmlFree(style->version); style->version = prop; } prop = xmlGetNsProp(cur, (const xmlChar *) "encoding", NULL); if (prop != NULL) { if (style->encoding != NULL) xmlFree(style->encoding); style->encoding = prop; } /* relaxed to support xt:document * TODO KB: What does "relaxed to support xt:document" mean? */ prop = xmlGetNsProp(cur, (const xmlChar *) "method", NULL); if (prop != NULL) { const xmlChar *URI; if (style->method != NULL) xmlFree(style->method); style->method = NULL; if (style->methodURI != NULL) xmlFree(style->methodURI); style->methodURI = NULL; /* * TODO: Don't use xsltGetQNameURI(). */ URI = xsltGetQNameURI(cur, &prop); if (prop == NULL) { if (style != NULL) style->errors++; } else if (URI == NULL) { if ((xmlStrEqual(prop, (const xmlChar *) "xml")) || (xmlStrEqual(prop, (const xmlChar *) "html")) || (xmlStrEqual(prop, (const xmlChar *) "text"))) { style->method = prop; } else { xsltTransformError(NULL, style, cur, "invalid value for method: %s\n", prop); if (style != NULL) style->warnings++; } } else { style->method = prop; style->methodURI = xmlStrdup(URI); } } prop = xmlGetNsProp(cur, (const xmlChar *) "doctype-system", NULL); if (prop != NULL) { if (style->doctypeSystem != NULL) xmlFree(style->doctypeSystem); style->doctypeSystem = prop; } prop = xmlGetNsProp(cur, (const xmlChar *) "doctype-public", NULL); if (prop != NULL) { if (style->doctypePublic != NULL) xmlFree(style->doctypePublic); style->doctypePublic = prop; } prop = xmlGetNsProp(cur, (const xmlChar *) "standalone", NULL); if (prop != NULL) { if (xmlStrEqual(prop, (const xmlChar *) "yes")) { style->standalone = 1; } else if (xmlStrEqual(prop, (const xmlChar *) "no")) { style->standalone = 0; } else { xsltTransformError(NULL, style, cur, "invalid value for standalone: %s\n", prop); style->errors++; } xmlFree(prop); } prop = xmlGetNsProp(cur, (const xmlChar *) "indent", NULL); if (prop != NULL) { if (xmlStrEqual(prop, (const xmlChar *) "yes")) { style->indent = 1; } else if (xmlStrEqual(prop, (const xmlChar *) "no")) { style->indent = 0; } else { xsltTransformError(NULL, style, cur, "invalid value for indent: %s\n", prop); style->errors++; } xmlFree(prop); } prop = xmlGetNsProp(cur, (const xmlChar *) "omit-xml-declaration", NULL); if (prop != NULL) { if (xmlStrEqual(prop, (const xmlChar *) "yes")) { style->omitXmlDeclaration = 1; } else if (xmlStrEqual(prop, (const xmlChar *) "no")) { style->omitXmlDeclaration = 0; } else { xsltTransformError(NULL, style, cur, "invalid value for omit-xml-declaration: %s\n", prop); style->errors++; } xmlFree(prop); } elements = xmlGetNsProp(cur, (const xmlChar *) "cdata-section-elements", NULL); if (elements != NULL) { if (style->cdataSection == NULL) style->cdataSection = xmlHashCreate(10); if (style->cdataSection == NULL) return; element = elements; while (*element != 0) { while (IS_BLANK(*element)) element++; if (*element == 0) break; end = element; while ((*end != 0) && (!IS_BLANK(*end))) end++; element = xmlStrndup(element, end - element); if (element) { #ifdef WITH_XSLT_DEBUG_PARSING xsltGenericDebug(xsltGenericDebugContext, "add cdata section output element %s\n", element); #endif if (xmlValidateQName(BAD_CAST element, 0) != 0) { xsltTransformError(NULL, style, cur, "Attribute 'cdata-section-elements': The value " "'%s' is not a valid QName.\n", element); xmlFree(element); style->errors++; } else { const xmlChar *URI; /* * TODO: Don't use xsltGetQNameURI(). */ URI = xsltGetQNameURI(cur, &element); if (element == NULL) { /* * TODO: We'll report additionally an error * via the stylesheet's error handling. */ xsltTransformError(NULL, style, cur, "Attribute 'cdata-section-elements': The value " "'%s' is not a valid QName.\n", element); style->errors++; } else { xmlNsPtr ns; /* * XSLT-1.0 "Each QName is expanded into an * expanded-name using the namespace declarations in * effect on the xsl:output element in which the QName * occurs; if there is a default namespace, it is used * for QNames that do not have a prefix" * NOTE: Fix of bug #339570. */ if (URI == NULL) { ns = xmlSearchNs(style->doc, cur, NULL); if (ns != NULL) URI = ns->href; } xmlHashAddEntry2(style->cdataSection, element, URI, (void *) "cdata"); xmlFree(element); } } } element = end; } xmlFree(elements); } prop = xmlGetNsProp(cur, (const xmlChar *) "media-type", NULL); if (prop != NULL) { if (style->mediaType) xmlFree(style->mediaType); style->mediaType = prop; } if (cur->children != NULL) { xsltParseContentError(style, cur->children); } } /** * xsltParseStylesheetDecimalFormat: * @style: the XSLT stylesheet * @cur: the "decimal-format" element * * * * * parse an XSLT stylesheet decimal-format element and * and record the formatting characteristics */ static void xsltParseStylesheetDecimalFormat(xsltStylesheetPtr style, xmlNodePtr cur) { xmlChar *prop; xsltDecimalFormatPtr format; xsltDecimalFormatPtr iter; if ((cur == NULL) || (style == NULL) || (cur->type != XML_ELEMENT_NODE)) return; format = style->decimalFormat; prop = xmlGetNsProp(cur, BAD_CAST("name"), NULL); if (prop != NULL) { format = xsltDecimalFormatGetByName(style, prop); if (format != NULL) { xsltTransformError(NULL, style, cur, "xsltParseStylestyleDecimalFormat: %s already exists\n", prop); if (style != NULL) style->warnings++; return; } format = xsltNewDecimalFormat(prop); if (format == NULL) { xsltTransformError(NULL, style, cur, "xsltParseStylestyleDecimalFormat: failed creating new decimal-format\n"); if (style != NULL) style->errors++; return; } /* Append new decimal-format structure */ for (iter = style->decimalFormat; iter->next; iter = iter->next) ; if (iter) iter->next = format; } prop = xmlGetNsProp(cur, (const xmlChar *)"decimal-separator", NULL); if (prop != NULL) { if (format->decimalPoint != NULL) xmlFree(format->decimalPoint); format->decimalPoint = prop; } prop = xmlGetNsProp(cur, (const xmlChar *)"grouping-separator", NULL); if (prop != NULL) { if (format->grouping != NULL) xmlFree(format->grouping); format->grouping = prop; } prop = xmlGetNsProp(cur, (const xmlChar *)"infinity", NULL); if (prop != NULL) { if (format->infinity != NULL) xmlFree(format->infinity); format->infinity = prop; } prop = xmlGetNsProp(cur, (const xmlChar *)"minus-sign", NULL); if (prop != NULL) { if (format->minusSign != NULL) xmlFree(format->minusSign); format->minusSign = prop; } prop = xmlGetNsProp(cur, (const xmlChar *)"NaN", NULL); if (prop != NULL) { if (format->noNumber != NULL) xmlFree(format->noNumber); format->noNumber = prop; } prop = xmlGetNsProp(cur, (const xmlChar *)"percent", NULL); if (prop != NULL) { if (format->percent != NULL) xmlFree(format->percent); format->percent = prop; } prop = xmlGetNsProp(cur, (const xmlChar *)"per-mille", NULL); if (prop != NULL) { if (format->permille != NULL) xmlFree(format->permille); format->permille = prop; } prop = xmlGetNsProp(cur, (const xmlChar *)"zero-digit", NULL); if (prop != NULL) { if (format->zeroDigit != NULL) xmlFree(format->zeroDigit); format->zeroDigit = prop; } prop = xmlGetNsProp(cur, (const xmlChar *)"digit", NULL); if (prop != NULL) { if (format->digit != NULL) xmlFree(format->digit); format->digit = prop; } prop = xmlGetNsProp(cur, (const xmlChar *)"pattern-separator", NULL); if (prop != NULL) { if (format->patternSeparator != NULL) xmlFree(format->patternSeparator); format->patternSeparator = prop; } if (cur->children != NULL) { xsltParseContentError(style, cur->children); } } /** * xsltParseStylesheetPreserveSpace: * @style: the XSLT stylesheet * @cur: the "preserve-space" element * * parse an XSLT stylesheet preserve-space element and record * elements needing preserving */ static void xsltParseStylesheetPreserveSpace(xsltStylesheetPtr style, xmlNodePtr cur) { xmlChar *elements; xmlChar *element, *end; if ((cur == NULL) || (style == NULL) || (cur->type != XML_ELEMENT_NODE)) return; elements = xmlGetNsProp(cur, (const xmlChar *)"elements", NULL); if (elements == NULL) { xsltTransformError(NULL, style, cur, "xsltParseStylesheetPreserveSpace: missing elements attribute\n"); if (style != NULL) style->warnings++; return; } if (style->stripSpaces == NULL) style->stripSpaces = xmlHashCreate(10); if (style->stripSpaces == NULL) return; element = elements; while (*element != 0) { while (IS_BLANK(*element)) element++; if (*element == 0) break; end = element; while ((*end != 0) && (!IS_BLANK(*end))) end++; element = xmlStrndup(element, end - element); if (element) { #ifdef WITH_XSLT_DEBUG_PARSING xsltGenericDebug(xsltGenericDebugContext, "add preserved space element %s\n", element); #endif if (xmlStrEqual(element, (const xmlChar *)"*")) { style->stripAll = -1; } else { const xmlChar *URI; /* * TODO: Don't use xsltGetQNameURI(). */ URI = xsltGetQNameURI(cur, &element); xmlHashAddEntry2(style->stripSpaces, element, URI, (xmlChar *) "preserve"); } xmlFree(element); } element = end; } xmlFree(elements); if (cur->children != NULL) { xsltParseContentError(style, cur->children); } } #ifdef XSLT_REFACTORED #else /** * xsltParseStylesheetExtPrefix: * @style: the XSLT stylesheet * @template: the "extension-element-prefixes" prefix * * parse an XSLT stylesheet's "extension-element-prefix" attribute value * and register the namespaces of extension instruction. * SPEC "A namespace is designated as an extension namespace by using * an extension-element-prefixes attribute on: * 1) an xsl:stylesheet element * 2) an xsl:extension-element-prefixes attribute on a * literal result element * 3) an extension instruction." */ static void xsltParseStylesheetExtPrefix(xsltStylesheetPtr style, xmlNodePtr cur, int isXsltElem) { xmlChar *prefixes; xmlChar *prefix, *end; if ((cur == NULL) || (style == NULL) || (cur->type != XML_ELEMENT_NODE)) return; if (isXsltElem) { /* For xsl:stylesheet/xsl:transform. */ prefixes = xmlGetNsProp(cur, (const xmlChar *)"extension-element-prefixes", NULL); } else { /* For literal result elements and extension instructions. */ prefixes = xmlGetNsProp(cur, (const xmlChar *)"extension-element-prefixes", XSLT_NAMESPACE); } if (prefixes == NULL) { return; } prefix = prefixes; while (*prefix != 0) { while (IS_BLANK(*prefix)) prefix++; if (*prefix == 0) break; end = prefix; while ((*end != 0) && (!IS_BLANK(*end))) end++; prefix = xmlStrndup(prefix, end - prefix); if (prefix) { xmlNsPtr ns; if (xmlStrEqual(prefix, (const xmlChar *)"#default")) ns = xmlSearchNs(style->doc, cur, NULL); else ns = xmlSearchNs(style->doc, cur, prefix); if (ns == NULL) { xsltTransformError(NULL, style, cur, "xsl:extension-element-prefix : undefined namespace %s\n", prefix); if (style != NULL) style->warnings++; } else { #ifdef WITH_XSLT_DEBUG_PARSING xsltGenericDebug(xsltGenericDebugContext, "add extension prefix %s\n", prefix); #endif xsltRegisterExtPrefix(style, prefix, ns->href); } xmlFree(prefix); } prefix = end; } xmlFree(prefixes); } #endif /* else of XSLT_REFACTORED */ /** * xsltParseStylesheetStripSpace: * @style: the XSLT stylesheet * @cur: the "strip-space" element * * parse an XSLT stylesheet's strip-space element and record * the elements needing stripping */ static void xsltParseStylesheetStripSpace(xsltStylesheetPtr style, xmlNodePtr cur) { xmlChar *elements; xmlChar *element, *end; if ((cur == NULL) || (style == NULL) || (cur->type != XML_ELEMENT_NODE)) return; elements = xmlGetNsProp(cur, (const xmlChar *)"elements", NULL); if (elements == NULL) { xsltTransformError(NULL, style, cur, "xsltParseStylesheetStripSpace: missing elements attribute\n"); if (style != NULL) style->warnings++; return; } if (style->stripSpaces == NULL) style->stripSpaces = xmlHashCreate(10); if (style->stripSpaces == NULL) return; element = elements; while (*element != 0) { while (IS_BLANK(*element)) element++; if (*element == 0) break; end = element; while ((*end != 0) && (!IS_BLANK(*end))) end++; element = xmlStrndup(element, end - element); if (element) { #ifdef WITH_XSLT_DEBUG_PARSING xsltGenericDebug(xsltGenericDebugContext, "add stripped space element %s\n", element); #endif if (xmlStrEqual(element, (const xmlChar *)"*")) { style->stripAll = 1; } else { const xmlChar *URI; /* * TODO: Don't use xsltGetQNameURI(). */ URI = xsltGetQNameURI(cur, &element); xmlHashAddEntry2(style->stripSpaces, element, URI, (xmlChar *) "strip"); } xmlFree(element); } element = end; } xmlFree(elements); if (cur->children != NULL) { xsltParseContentError(style, cur->children); } } #ifdef XSLT_REFACTORED #else /** * xsltParseStylesheetExcludePrefix: * @style: the XSLT stylesheet * @cur: the current point in the stylesheet * * parse an XSLT stylesheet exclude prefix and record * namespaces needing stripping * * Returns the number of Excluded prefixes added at that level */ static int xsltParseStylesheetExcludePrefix(xsltStylesheetPtr style, xmlNodePtr cur, int isXsltElem) { int nb = 0; xmlChar *prefixes; xmlChar *prefix, *end; if ((cur == NULL) || (style == NULL) || (cur->type != XML_ELEMENT_NODE)) return(0); if (isXsltElem) prefixes = xmlGetNsProp(cur, (const xmlChar *)"exclude-result-prefixes", NULL); else prefixes = xmlGetNsProp(cur, (const xmlChar *)"exclude-result-prefixes", XSLT_NAMESPACE); if (prefixes == NULL) { return(0); } prefix = prefixes; while (*prefix != 0) { while (IS_BLANK(*prefix)) prefix++; if (*prefix == 0) break; end = prefix; while ((*end != 0) && (!IS_BLANK(*end))) end++; prefix = xmlStrndup(prefix, end - prefix); if (prefix) { xmlNsPtr ns; if (xmlStrEqual(prefix, (const xmlChar *)"#default")) ns = xmlSearchNs(style->doc, cur, NULL); else ns = xmlSearchNs(style->doc, cur, prefix); if (ns == NULL) { xsltTransformError(NULL, style, cur, "xsl:exclude-result-prefixes : undefined namespace %s\n", prefix); if (style != NULL) style->warnings++; } else { if (exclPrefixPush(style, (xmlChar *) ns->href) >= 0) { #ifdef WITH_XSLT_DEBUG_PARSING xsltGenericDebug(xsltGenericDebugContext, "exclude result prefix %s\n", prefix); #endif nb++; } } xmlFree(prefix); } prefix = end; } xmlFree(prefixes); return(nb); } #endif /* else of XSLT_REFACTORED */ #ifdef XSLT_REFACTORED /* * xsltTreeEnsureXMLDecl: * @doc: the doc * * BIG NOTE: * This was copy&pasted from Libxml2's xmlTreeEnsureXMLDecl() in "tree.c". * Ensures that there is an XML namespace declaration on the doc. * * Returns the XML ns-struct or NULL on API and internal errors. */ static xmlNsPtr xsltTreeEnsureXMLDecl(xmlDocPtr doc) { if (doc == NULL) return (NULL); if (doc->oldNs != NULL) return (doc->oldNs); { xmlNsPtr ns; ns = (xmlNsPtr) xmlMalloc(sizeof(xmlNs)); if (ns == NULL) { xmlGenericError(xmlGenericErrorContext, "xsltTreeEnsureXMLDecl: Failed to allocate " "the XML namespace.\n"); return (NULL); } memset(ns, 0, sizeof(xmlNs)); ns->type = XML_LOCAL_NAMESPACE; /* * URGENT TODO: revisit this. */ #ifdef LIBXML_NAMESPACE_DICT if (doc->dict) ns->href = xmlDictLookup(doc->dict, XML_XML_NAMESPACE, -1); else ns->href = xmlStrdup(XML_XML_NAMESPACE); #else ns->href = xmlStrdup(XML_XML_NAMESPACE); #endif ns->prefix = xmlStrdup((const xmlChar *)"xml"); doc->oldNs = ns; return (ns); } } /* * xsltTreeAcquireStoredNs: * @doc: the doc * @nsName: the namespace name * @prefix: the prefix * * BIG NOTE: * This was copy&pasted from Libxml2's xmlDOMWrapStoreNs() in "tree.c". * Creates or reuses an xmlNs struct on doc->oldNs with * the given prefix and namespace name. * * Returns the aquired ns struct or NULL in case of an API * or internal error. */ static xmlNsPtr xsltTreeAcquireStoredNs(xmlDocPtr doc, const xmlChar *nsName, const xmlChar *prefix) { xmlNsPtr ns; if (doc == NULL) return (NULL); if (doc->oldNs != NULL) ns = doc->oldNs; else ns = xsltTreeEnsureXMLDecl(doc); if (ns == NULL) return (NULL); if (ns->next != NULL) { /* Reuse. */ ns = ns->next; while (ns != NULL) { if ((ns->prefix == NULL) != (prefix == NULL)) { /* NOP */ } else if (prefix == NULL) { if (xmlStrEqual(ns->href, nsName)) return (ns); } else { if ((ns->prefix[0] == prefix[0]) && xmlStrEqual(ns->prefix, prefix) && xmlStrEqual(ns->href, nsName)) return (ns); } if (ns->next == NULL) break; ns = ns->next; } } /* Create. */ ns->next = xmlNewNs(NULL, nsName, prefix); return (ns->next); } /** * xsltLREBuildEffectiveNs: * * Apply ns-aliasing on the namespace of the given @elem and * its attributes. */ static int xsltLREBuildEffectiveNs(xsltCompilerCtxtPtr cctxt, xmlNodePtr elem) { xmlNsPtr ns; xsltNsAliasPtr alias; if ((cctxt == NULL) || (elem == NULL)) return(-1); if ((cctxt->nsAliases == NULL) || (! cctxt->hasNsAliases)) return(0); alias = cctxt->nsAliases; while (alias != NULL) { if ( /* If both namespaces are NULL... */ ( (elem->ns == NULL) && ((alias->literalNs == NULL) || (alias->literalNs->href == NULL)) ) || /* ... or both namespace are equal */ ( (elem->ns != NULL) && (alias->literalNs != NULL) && xmlStrEqual(elem->ns->href, alias->literalNs->href) ) ) { if ((alias->targetNs != NULL) && (alias->targetNs->href != NULL)) { /* * Convert namespace. */ if (elem->doc == alias->docOfTargetNs) { /* * This is the nice case: same docs. * This will eventually assign a ns-decl which * is shadowed, but this has no negative effect on * the generation of the result tree. */ elem->ns = alias->targetNs; } else { /* * This target xmlNs originates from a different * stylesheet tree. Try to locate it in the * in-scope namespaces. * OPTIMIZE TODO: Use the compiler-node-info inScopeNs. */ ns = xmlSearchNs(elem->doc, elem, alias->targetNs->prefix); /* * If no matching ns-decl found, then assign a * ns-decl stored in xmlDoc. */ if ((ns == NULL) || (! xmlStrEqual(ns->href, alias->targetNs->href))) { /* * BIG NOTE: The use of xsltTreeAcquireStoredNs() * is not very efficient, but currently I don't * see an other way of *safely* changing a node's * namespace, since the xmlNs struct in * alias->targetNs might come from an other * stylesheet tree. So we need to anchor it in the * current document, without adding it to the tree, * which would otherwise change the in-scope-ns * semantic of the tree. */ ns = xsltTreeAcquireStoredNs(elem->doc, alias->targetNs->href, alias->targetNs->prefix); if (ns == NULL) { xsltTransformError(NULL, cctxt->style, elem, "Internal error in " "xsltLREBuildEffectiveNs(): " "failed to acquire a stored " "ns-declaration.\n"); cctxt->style->errors++; return(-1); } } elem->ns = ns; } } else { /* * Move into or leave in the NULL namespace. */ elem->ns = NULL; } break; } alias = alias->next; } /* * Same with attributes of literal result elements. */ if (elem->properties != NULL) { xmlAttrPtr attr = elem->properties; while (attr != NULL) { if (attr->ns == NULL) { attr = attr->next; continue; } alias = cctxt->nsAliases; while (alias != NULL) { if ( /* If both namespaces are NULL... */ ( (elem->ns == NULL) && ((alias->literalNs == NULL) || (alias->literalNs->href == NULL)) ) || /* ... or both namespace are equal */ ( (elem->ns != NULL) && (alias->literalNs != NULL) && xmlStrEqual(elem->ns->href, alias->literalNs->href) ) ) { if ((alias->targetNs != NULL) && (alias->targetNs->href != NULL)) { if (elem->doc == alias->docOfTargetNs) { elem->ns = alias->targetNs; } else { ns = xmlSearchNs(elem->doc, elem, alias->targetNs->prefix); if ((ns == NULL) || (! xmlStrEqual(ns->href, alias->targetNs->href))) { ns = xsltTreeAcquireStoredNs(elem->doc, alias->targetNs->href, alias->targetNs->prefix); if (ns == NULL) { xsltTransformError(NULL, cctxt->style, elem, "Internal error in " "xsltLREBuildEffectiveNs(): " "failed to acquire a stored " "ns-declaration.\n"); cctxt->style->errors++; return(-1); } } elem->ns = ns; } } else { /* * Move into or leave in the NULL namespace. */ elem->ns = NULL; } break; } alias = alias->next; } attr = attr->next; } } return(0); } /** * xsltLREBuildEffectiveNsNodes: * * Computes the effective namespaces nodes for a literal result * element. * @effectiveNs is the set of effective ns-nodes * on the literal result element, which will be added to the result * element if not already existing in the result tree. * This means that excluded namespaces (via exclude-result-prefixes, * extension-element-prefixes and the XSLT namespace) not added * to the set. * Namespace-aliasing was applied on the @effectiveNs. */ static int xsltLREBuildEffectiveNsNodes(xsltCompilerCtxtPtr cctxt, xsltStyleItemLRElementInfoPtr item, xmlNodePtr elem, int isLRE) { xmlNsPtr ns, tmpns; xsltEffectiveNsPtr effNs, lastEffNs = NULL; int i, j, holdByElem; xsltPointerListPtr extElemNs = cctxt->inode->extElemNs; xsltPointerListPtr exclResultNs = cctxt->inode->exclResultNs; if ((cctxt == NULL) || (cctxt->inode == NULL) || (elem == NULL) || (item == NULL) || (item->effectiveNs != NULL)) return(-1); if (item->inScopeNs == NULL) return(0); extElemNs = cctxt->inode->extElemNs; exclResultNs = cctxt->inode->exclResultNs; for (i = 0; i < item->inScopeNs->totalNumber; i++) { ns = item->inScopeNs->list[i]; /* * Skip namespaces designated as excluded namespaces * ------------------------------------------------- * * XSLT-20 TODO: In XSLT 2.0 we need to keep namespaces * which are target namespaces of namespace-aliases * regardless if designated as excluded. * * Exclude the XSLT namespace. */ if (xmlStrEqual(ns->href, XSLT_NAMESPACE)) goto skip_ns; /* * Apply namespace aliasing * ------------------------ * * SPEC XSLT 2.0 * "- A namespace node whose string value is a literal namespace * URI is not copied to the result tree. * - A namespace node whose string value is a target namespace URI * is copied to the result tree, whether or not the URI * identifies an excluded namespace." * * NOTE: The ns-aliasing machanism is non-cascading. * (checked with Saxon, Xalan and MSXML .NET). * URGENT TODO: is style->nsAliases the effective list of * ns-aliases, or do we need to lookup the whole * import-tree? * TODO: Get rid of import-tree lookup. */ if (cctxt->hasNsAliases) { xsltNsAliasPtr alias; /* * First check for being a target namespace. */ alias = cctxt->nsAliases; do { /* * TODO: Is xmlns="" handled already? */ if ((alias->targetNs != NULL) && (xmlStrEqual(alias->targetNs->href, ns->href))) { /* * Recognized as a target namespace; use it regardless * if excluded otherwise. */ goto add_effective_ns; } alias = alias->next; } while (alias != NULL); alias = cctxt->nsAliases; do { /* * TODO: Is xmlns="" handled already? */ if ((alias->literalNs != NULL) && (xmlStrEqual(alias->literalNs->href, ns->href))) { /* * Recognized as an namespace alias; do not use it. */ goto skip_ns; } alias = alias->next; } while (alias != NULL); } /* * Exclude excluded result namespaces. */ if (exclResultNs) { for (j = 0; j < exclResultNs->number; j++) if (xmlStrEqual(ns->href, BAD_CAST exclResultNs->items[j])) goto skip_ns; } /* * Exclude extension-element namespaces. */ if (extElemNs) { for (j = 0; j < extElemNs->number; j++) if (xmlStrEqual(ns->href, BAD_CAST extElemNs->items[j])) goto skip_ns; } add_effective_ns: /* * OPTIMIZE TODO: This information may not be needed. */ if (isLRE && (elem->nsDef != NULL)) { holdByElem = 0; tmpns = elem->nsDef; do { if (tmpns == ns) { holdByElem = 1; break; } tmpns = tmpns->next; } while (tmpns != NULL); } else holdByElem = 0; /* * Add the effective namespace declaration. */ effNs = (xsltEffectiveNsPtr) xmlMalloc(sizeof(xsltEffectiveNs)); if (effNs == NULL) { xsltTransformError(NULL, cctxt->style, elem, "Internal error in xsltLREBuildEffectiveNs(): " "failed to allocate memory.\n"); cctxt->style->errors++; return(-1); } if (cctxt->psData->effectiveNs == NULL) { cctxt->psData->effectiveNs = effNs; effNs->nextInStore = NULL; } else { effNs->nextInStore = cctxt->psData->effectiveNs; cctxt->psData->effectiveNs = effNs; } effNs->next = NULL; effNs->prefix = ns->prefix; effNs->nsName = ns->href; effNs->holdByElem = holdByElem; if (lastEffNs == NULL) item->effectiveNs = effNs; else lastEffNs->next = effNs; lastEffNs = effNs; skip_ns: {} } return(0); } /** * xsltLREInfoCreate: * * @isLRE: indicates if the given @elem is a literal result element * * Creates a new info for a literal result element. */ static int xsltLREInfoCreate(xsltCompilerCtxtPtr cctxt, xmlNodePtr elem, int isLRE) { xsltStyleItemLRElementInfoPtr item; if ((cctxt == NULL) || (cctxt->inode == NULL)) return(-1); item = (xsltStyleItemLRElementInfoPtr) xmlMalloc(sizeof(xsltStyleItemLRElementInfo)); if (item == NULL) { xsltTransformError(NULL, cctxt->style, NULL, "Internal error in xsltLREInfoCreate(): " "memory allocation failed.\n"); cctxt->style->errors++; return(-1); } memset(item, 0, sizeof(xsltStyleItemLRElementInfo)); item->type = XSLT_FUNC_LITERAL_RESULT_ELEMENT; /* * Store it in the stylesheet. */ item->next = cctxt->style->preComps; cctxt->style->preComps = (xsltElemPreCompPtr) item; /* * @inScopeNs are used for execution of XPath expressions * in AVTs. */ item->inScopeNs = cctxt->inode->inScopeNs; if (elem) xsltLREBuildEffectiveNsNodes(cctxt, item, elem, isLRE); cctxt->inode->litResElemInfo = item; cctxt->inode->nsChanged = 0; cctxt->maxLREs++; return(0); } /** * xsltCompilerVarInfoPush: * @cctxt: the compilation context * * Pushes a new var/param info onto the stack. * * Returns the acquired variable info. */ static xsltVarInfoPtr xsltCompilerVarInfoPush(xsltCompilerCtxtPtr cctxt, xmlNodePtr inst, const xmlChar *name, const xmlChar *nsName) { xsltVarInfoPtr ivar; if ((cctxt->ivar != NULL) && (cctxt->ivar->next != NULL)) { ivar = cctxt->ivar->next; } else if ((cctxt->ivar == NULL) && (cctxt->ivars != NULL)) { ivar = cctxt->ivars; } else { ivar = (xsltVarInfoPtr) xmlMalloc(sizeof(xsltVarInfo)); if (ivar == NULL) { xsltTransformError(NULL, cctxt->style, inst, "xsltParseInScopeVarPush: xmlMalloc() failed!\n"); cctxt->style->errors++; return(NULL); } /* memset(retVar, 0, sizeof(xsltInScopeVar)); */ if (cctxt->ivars == NULL) { cctxt->ivars = ivar; ivar->prev = NULL; } else { cctxt->ivar->next = ivar; ivar->prev = cctxt->ivar; } cctxt->ivar = ivar; ivar->next = NULL; } ivar->depth = cctxt->depth; ivar->name = name; ivar->nsName = nsName; return(ivar); } /** * xsltCompilerVarInfoPop: * @cctxt: the compilation context * * Pops all var/param infos from the stack, which * have the current depth. */ static void xsltCompilerVarInfoPop(xsltCompilerCtxtPtr cctxt) { while ((cctxt->ivar != NULL) && (cctxt->ivar->depth > cctxt->depth)) { cctxt->ivar = cctxt->ivar->prev; } } /* * xsltCompilerNodePush: * * @cctxt: the compilation context * @node: the node to be pushed (this can also be the doc-node) * * * * Returns the current node info structure or * NULL in case of an internal error. */ static xsltCompilerNodeInfoPtr xsltCompilerNodePush(xsltCompilerCtxtPtr cctxt, xmlNodePtr node) { xsltCompilerNodeInfoPtr inode, iprev; if ((cctxt->inode != NULL) && (cctxt->inode->next != NULL)) { inode = cctxt->inode->next; } else if ((cctxt->inode == NULL) && (cctxt->inodeList != NULL)) { inode = cctxt->inodeList; } else { /* * Create a new node-info. */ inode = (xsltCompilerNodeInfoPtr) xmlMalloc(sizeof(xsltCompilerNodeInfo)); if (inode == NULL) { xsltTransformError(NULL, cctxt->style, NULL, "xsltCompilerNodePush: malloc failed.\n"); return(NULL); } memset(inode, 0, sizeof(xsltCompilerNodeInfo)); if (cctxt->inodeList == NULL) cctxt->inodeList = inode; else { cctxt->inodeLast->next = inode; inode->prev = cctxt->inodeLast; } cctxt->inodeLast = inode; cctxt->maxNodeInfos++; if (cctxt->inode == NULL) { cctxt->inode = inode; /* * Create an initial literal result element info for * the root of the stylesheet. */ xsltLREInfoCreate(cctxt, NULL, 0); } } cctxt->depth++; cctxt->inode = inode; /* * REVISIT TODO: Keep the reset always complete. * NOTE: Be carefull with the @node, since it might be * a doc-node. */ inode->node = node; inode->depth = cctxt->depth; inode->templ = NULL; inode->category = XSLT_ELEMENT_CATEGORY_XSLT; inode->type = 0; inode->item = NULL; inode->curChildType = 0; inode->extContentHandled = 0; inode->isRoot = 0; if (inode->prev != NULL) { iprev = inode->prev; /* * Inherit the following information: * --------------------------------- * * In-scope namespaces */ inode->inScopeNs = iprev->inScopeNs; /* * Info for literal result elements */ inode->litResElemInfo = iprev->litResElemInfo; inode->nsChanged = iprev->nsChanged; /* * Excluded result namespaces */ inode->exclResultNs = iprev->exclResultNs; /* * Extension instruction namespaces */ inode->extElemNs = iprev->extElemNs; /* * Whitespace preservation */ inode->preserveWhitespace = iprev->preserveWhitespace; /* * Forwards-compatible mode */ inode->forwardsCompat = iprev->forwardsCompat; } else { inode->inScopeNs = NULL; inode->exclResultNs = NULL; inode->extElemNs = NULL; inode->preserveWhitespace = 0; inode->forwardsCompat = 0; } return(inode); } /* * xsltCompilerNodePop: * * @cctxt: the compilation context * @node: the node to be pushed (this can also be the doc-node) * * Pops the current node info. */ static void xsltCompilerNodePop(xsltCompilerCtxtPtr cctxt, xmlNodePtr node) { if (cctxt->inode == NULL) { xmlGenericError(xmlGenericErrorContext, "xsltCompilerNodePop: Top-node mismatch.\n"); return; } /* * NOTE: Be carefull with the @node, since it might be * a doc-node. */ if (cctxt->inode->node != node) { xmlGenericError(xmlGenericErrorContext, "xsltCompilerNodePop: Node mismatch.\n"); goto mismatch; } if (cctxt->inode->depth != cctxt->depth) { xmlGenericError(xmlGenericErrorContext, "xsltCompilerNodePop: Depth mismatch.\n"); goto mismatch; } cctxt->depth--; /* * Pop information of variables. */ if ((cctxt->ivar) && (cctxt->ivar->depth > cctxt->depth)) xsltCompilerVarInfoPop(cctxt); cctxt->inode = cctxt->inode->prev; if (cctxt->inode != NULL) cctxt->inode->curChildType = 0; return; mismatch: { const xmlChar *nsName = NULL, *name = NULL; const xmlChar *infnsName = NULL, *infname = NULL; if (node) { if (node->type == XML_ELEMENT_NODE) { name = node->name; if (node->ns != NULL) nsName = node->ns->href; else nsName = BAD_CAST ""; } else { name = BAD_CAST "#document"; nsName = BAD_CAST ""; } } else name = BAD_CAST "Not given"; if (cctxt->inode->node) { if (node->type == XML_ELEMENT_NODE) { infname = cctxt->inode->node->name; if (cctxt->inode->node->ns != NULL) infnsName = cctxt->inode->node->ns->href; else infnsName = BAD_CAST ""; } else { infname = BAD_CAST "#document"; infnsName = BAD_CAST ""; } } else infname = BAD_CAST "Not given"; xmlGenericError(xmlGenericErrorContext, "xsltCompilerNodePop: Given : '%s' URI '%s'\n", name, nsName); xmlGenericError(xmlGenericErrorContext, "xsltCompilerNodePop: Expected: '%s' URI '%s'\n", infname, infnsName); } } /* * xsltCompilerBuildInScopeNsList: * * Create and store the list of in-scope namespaces for the given * node in the stylesheet. If there are no changes in the in-scope * namespaces then the last ns-info of the ancestor axis will be returned. * Compilation-time only. * * Returns the ns-info or NULL if there are no namespaces in scope. */ static xsltNsListContainerPtr xsltCompilerBuildInScopeNsList(xsltCompilerCtxtPtr cctxt, xmlNodePtr node) { xsltNsListContainerPtr nsi = NULL; xmlNsPtr *list = NULL, ns; int i, maxns = 5; /* * Create a new ns-list for this position in the node-tree. * xmlGetNsList() will return NULL, if there are no ns-decls in the * tree. Note that the ns-decl for the XML namespace is not added * to the resulting list; the XPath module handles the XML namespace * internally. */ while (node != NULL) { if (node->type == XML_ELEMENT_NODE) { ns = node->nsDef; while (ns != NULL) { if (nsi == NULL) { nsi = (xsltNsListContainerPtr) xmlMalloc(sizeof(xsltNsListContainer)); if (nsi == NULL) { xsltTransformError(NULL, cctxt->style, NULL, "xsltCompilerBuildInScopeNsList: " "malloc failed!\n"); goto internal_err; } memset(nsi, 0, sizeof(xsltNsListContainer)); nsi->list = (xmlNsPtr *) xmlMalloc(maxns * sizeof(xmlNsPtr)); if (nsi->list == NULL) { xsltTransformError(NULL, cctxt->style, NULL, "xsltCompilerBuildInScopeNsList: " "malloc failed!\n"); goto internal_err; } nsi->list[0] = NULL; } /* * Skip shadowed namespace bindings. */ for (i = 0; i < nsi->totalNumber; i++) { if ((ns->prefix == nsi->list[i]->prefix) || (xmlStrEqual(ns->prefix, nsi->list[i]->prefix))) break; } if (i >= nsi->totalNumber) { if (nsi->totalNumber +1 >= maxns) { maxns *= 2; nsi->list = (xmlNsPtr *) xmlRealloc(nsi->list, maxns * sizeof(xmlNsPtr)); if (nsi->list == NULL) { xsltTransformError(NULL, cctxt->style, NULL, "xsltCompilerBuildInScopeNsList: " "realloc failed!\n"); goto internal_err; } } nsi->list[nsi->totalNumber++] = ns; nsi->list[nsi->totalNumber] = NULL; } ns = ns->next; } } node = node->parent; } if (nsi == NULL) return(NULL); /* * Move the default namespace to last position. */ nsi->xpathNumber = nsi->totalNumber; for (i = 0; i < nsi->totalNumber; i++) { if (nsi->list[i]->prefix == NULL) { ns = nsi->list[i]; nsi->list[i] = nsi->list[nsi->totalNumber-1]; nsi->list[nsi->totalNumber-1] = ns; nsi->xpathNumber--; break; } } /* * Store the ns-list in the stylesheet. */ if (xsltPointerListAddSize( (xsltPointerListPtr)cctxt->psData->inScopeNamespaces, (void *) nsi, 5) == -1) { xmlFree(nsi); nsi = NULL; xsltTransformError(NULL, cctxt->style, NULL, "xsltCompilerBuildInScopeNsList: failed to add ns-info.\n"); goto internal_err; } /* * Notify of change in status wrt namespaces. */ if (cctxt->inode != NULL) cctxt->inode->nsChanged = 1; return(nsi); internal_err: if (list != NULL) xmlFree(list); cctxt->style->errors++; return(NULL); } static int xsltParseNsPrefixList(xsltCompilerCtxtPtr cctxt, xsltPointerListPtr list, xmlNodePtr node, const xmlChar *value) { xmlChar *cur, *end; xmlNsPtr ns; if ((cctxt == NULL) || (value == NULL) || (list == NULL)) return(-1); list->number = 0; cur = (xmlChar *) value; while (*cur != 0) { while (IS_BLANK(*cur)) cur++; if (*cur == 0) break; end = cur; while ((*end != 0) && (!IS_BLANK(*end))) end++; cur = xmlStrndup(cur, end - cur); if (cur == NULL) { cur = end; continue; } /* * TODO: Export and use xmlSearchNsByPrefixStrict() * in Libxml2, tree.c, since xmlSearchNs() is in most * cases not efficient and in some cases not correct. * * XSLT-2 TODO: XSLT 2.0 allows an additional "#all" value. */ if ((cur[0] == '#') && xmlStrEqual(cur, (const xmlChar *)"#default")) ns = xmlSearchNs(cctxt->style->doc, node, NULL); else ns = xmlSearchNs(cctxt->style->doc, node, cur); if (ns == NULL) { /* * TODO: Better to report the attr-node, otherwise * the user won't know which attribute was invalid. */ xsltTransformError(NULL, cctxt->style, node, "No namespace binding in scope for prefix '%s'.\n", cur); /* * XSLT-1.0: "It is an error if there is no namespace * bound to the prefix on the element bearing the * exclude-result-prefixes or xsl:exclude-result-prefixes * attribute." */ cctxt->style->errors++; } else { #ifdef WITH_XSLT_DEBUG_PARSING xsltGenericDebug(xsltGenericDebugContext, "resolved prefix '%s'\n", cur); #endif /* * Note that we put the namespace name into the dict. */ if (xsltPointerListAddSize(list, (void *) xmlDictLookup(cctxt->style->dict, ns->href, -1), 5) == -1) { xmlFree(cur); goto internal_err; } } xmlFree(cur); cur = end; } return(0); internal_err: cctxt->style->errors++; return(-1); } /** * xsltCompilerUtilsCreateMergedList: * @dest: the destination list (optional) * @first: the first list * @second: the second list (optional) * * Appends the content of @second to @first into @destination. * If @destination is NULL a new list will be created. * * Returns the merged list of items or NULL if there's nothing to merge. */ static xsltPointerListPtr xsltCompilerUtilsCreateMergedList(xsltPointerListPtr first, xsltPointerListPtr second) { xsltPointerListPtr ret; size_t num; if (first) num = first->number; else num = 0; if (second) num += second->number; if (num == 0) return(NULL); ret = xsltPointerListCreate(num); if (ret == NULL) return(NULL); /* * Copy contents. */ if ((first != NULL) && (first->number != 0)) { memcpy(ret->items, first->items, first->number * sizeof(void *)); if ((second != NULL) && (second->number != 0)) memcpy(ret->items + first->number, second->items, second->number * sizeof(void *)); } else if ((second != NULL) && (second->number != 0)) memcpy(ret->items, (void *) second->items, second->number * sizeof(void *)); ret->number = num; return(ret); } /* * xsltParseExclResultPrefixes: * * Create and store the list of in-scope namespaces for the given * node in the stylesheet. If there are no changes in the in-scope * namespaces then the last ns-info of the ancestor axis will be returned. * Compilation-time only. * * Returns the ns-info or NULL if there are no namespaces in scope. */ static xsltPointerListPtr xsltParseExclResultPrefixes(xsltCompilerCtxtPtr cctxt, xmlNodePtr node, xsltPointerListPtr def, int instrCategory) { xsltPointerListPtr list = NULL; xmlChar *value; xmlAttrPtr attr; if ((cctxt == NULL) || (node == NULL)) return(NULL); if (instrCategory == XSLT_ELEMENT_CATEGORY_XSLT) attr = xmlHasNsProp(node, BAD_CAST "exclude-result-prefixes", NULL); else attr = xmlHasNsProp(node, BAD_CAST "exclude-result-prefixes", XSLT_NAMESPACE); if (attr == NULL) return(def); if (attr && (instrCategory == XSLT_ELEMENT_CATEGORY_LRE)) { /* * Mark the XSLT attr. */ attr->psvi = (void *) xsltXSLTAttrMarker; } if ((attr->children != NULL) && (attr->children->content != NULL)) value = attr->children->content; else { xsltTransformError(NULL, cctxt->style, node, "Attribute 'exclude-result-prefixes': Invalid value.\n"); cctxt->style->errors++; return(def); } if (xsltParseNsPrefixList(cctxt, cctxt->tmpList, node, BAD_CAST value) != 0) goto exit; if (cctxt->tmpList->number == 0) goto exit; /* * Merge the list with the inherited list. */ list = xsltCompilerUtilsCreateMergedList(def, cctxt->tmpList); if (list == NULL) goto exit; /* * Store the list in the stylesheet/compiler context. */ if (xsltPointerListAddSize( cctxt->psData->exclResultNamespaces, list, 5) == -1) { xsltPointerListFree(list); list = NULL; goto exit; } /* * Notify of change in status wrt namespaces. */ if (cctxt->inode != NULL) cctxt->inode->nsChanged = 1; exit: if (list != NULL) return(list); else return(def); } /* * xsltParseExtElemPrefixes: * * Create and store the list of in-scope namespaces for the given * node in the stylesheet. If there are no changes in the in-scope * namespaces then the last ns-info of the ancestor axis will be returned. * Compilation-time only. * * Returns the ns-info or NULL if there are no namespaces in scope. */ static xsltPointerListPtr xsltParseExtElemPrefixes(xsltCompilerCtxtPtr cctxt, xmlNodePtr node, xsltPointerListPtr def, int instrCategory) { xsltPointerListPtr list = NULL; xmlAttrPtr attr; xmlChar *value; int i; if ((cctxt == NULL) || (node == NULL)) return(NULL); if (instrCategory == XSLT_ELEMENT_CATEGORY_XSLT) attr = xmlHasNsProp(node, BAD_CAST "extension-element-prefixes", NULL); else attr = xmlHasNsProp(node, BAD_CAST "extension-element-prefixes", XSLT_NAMESPACE); if (attr == NULL) return(def); if (attr && (instrCategory == XSLT_ELEMENT_CATEGORY_LRE)) { /* * Mark the XSLT attr. */ attr->psvi = (void *) xsltXSLTAttrMarker; } if ((attr->children != NULL) && (attr->children->content != NULL)) value = attr->children->content; else { xsltTransformError(NULL, cctxt->style, node, "Attribute 'extension-element-prefixes': Invalid value.\n"); cctxt->style->errors++; return(def); } if (xsltParseNsPrefixList(cctxt, cctxt->tmpList, node, BAD_CAST value) != 0) goto exit; if (cctxt->tmpList->number == 0) goto exit; /* * REVISIT: Register the extension namespaces. */ for (i = 0; i < cctxt->tmpList->number; i++) xsltRegisterExtPrefix(cctxt->style, NULL, BAD_CAST cctxt->tmpList->items[i]); /* * Merge the list with the inherited list. */ list = xsltCompilerUtilsCreateMergedList(def, cctxt->tmpList); if (list == NULL) goto exit; /* * Store the list in the stylesheet. */ if (xsltPointerListAddSize( cctxt->psData->extElemNamespaces, list, 5) == -1) { xsltPointerListFree(list); list = NULL; goto exit; } /* * Notify of change in status wrt namespaces. */ if (cctxt->inode != NULL) cctxt->inode->nsChanged = 1; exit: if (list != NULL) return(list); else return(def); } /* * xsltParseAttrXSLTVersion: * * @cctxt: the compilation context * @node: the element-node * @isXsltElem: whether this is an XSLT element * * Parses the attribute xsl:version. * * Returns 1 if there was such an attribute, 0 if not and * -1 if an internal or API error occured. */ static int xsltParseAttrXSLTVersion(xsltCompilerCtxtPtr cctxt, xmlNodePtr node, int instrCategory) { xmlChar *value; xmlAttrPtr attr; if ((cctxt == NULL) || (node == NULL)) return(-1); if (instrCategory == XSLT_ELEMENT_CATEGORY_XSLT) attr = xmlHasNsProp(node, BAD_CAST "version", NULL); else attr = xmlHasNsProp(node, BAD_CAST "version", XSLT_NAMESPACE); if (attr == NULL) return(0); attr->psvi = (void *) xsltXSLTAttrMarker; if ((attr->children != NULL) && (attr->children->content != NULL)) value = attr->children->content; else { xsltTransformError(NULL, cctxt->style, node, "Attribute 'version': Invalid value.\n"); cctxt->style->errors++; return(1); } if (! xmlStrEqual(value, (const xmlChar *)"1.0")) { cctxt->inode->forwardsCompat = 1; /* * TODO: To what extent do we support the * forwards-compatible mode? */ /* * Report this only once per compilation episode. */ if (! cctxt->hasForwardsCompat) { cctxt->hasForwardsCompat = 1; cctxt->errSeverity = XSLT_ERROR_SEVERITY_WARNING; xsltTransformError(NULL, cctxt->style, node, "Warning: the attribute xsl:version specifies a value " "different from '1.0'. Switching to forwards-compatible " "mode. Only features of XSLT 1.0 are supported by this " "processor.\n"); cctxt->style->warnings++; cctxt->errSeverity = XSLT_ERROR_SEVERITY_ERROR; } } else { cctxt->inode->forwardsCompat = 0; } if (attr && (instrCategory == XSLT_ELEMENT_CATEGORY_LRE)) { /* * Set a marker on XSLT attributes. */ attr->psvi = (void *) xsltXSLTAttrMarker; } return(1); } static int xsltParsePreprocessStylesheetTree(xsltCompilerCtxtPtr cctxt, xmlNodePtr node) { xmlNodePtr deleteNode, cur, txt, textNode = NULL; xmlDocPtr doc; xsltStylesheetPtr style; int internalize = 0, findSpaceAttr; int xsltStylesheetElemDepth; xmlAttrPtr attr; xmlChar *value; const xmlChar *name, *nsNameXSLT = NULL; int strictWhitespace, inXSLText = 0; #ifdef XSLT_REFACTORED_XSLT_NSCOMP xsltNsMapPtr nsMapItem; #endif if ((cctxt == NULL) || (cctxt->style == NULL) || (node == NULL) || (node->type != XML_ELEMENT_NODE)) return(-1); doc = node->doc; if (doc == NULL) goto internal_err; style = cctxt->style; if ((style->dict != NULL) && (doc->dict == style->dict)) internalize = 1; else style->internalized = 0; /* * Init value of xml:space. Since this might be an embedded * stylesheet, this is needed to be performed on the element * where the stylesheet is rooted at, taking xml:space of * ancestors into account. */ if (! cctxt->simplified) xsltStylesheetElemDepth = cctxt->depth +1; else xsltStylesheetElemDepth = 0; if (xmlNodeGetSpacePreserve(node) != 1) cctxt->inode->preserveWhitespace = 0; else cctxt->inode->preserveWhitespace = 1; /* * Eval if we should keep the old incorrect behaviour. */ strictWhitespace = (cctxt->strict != 0) ? 1 : 0; nsNameXSLT = xsltConstNamespaceNameXSLT; deleteNode = NULL; cur = node; while (cur != NULL) { if (deleteNode != NULL) { #ifdef WITH_XSLT_DEBUG_BLANKS xsltGenericDebug(xsltGenericDebugContext, "xsltParsePreprocessStylesheetTree: removing node\n"); #endif xmlUnlinkNode(deleteNode); xmlFreeNode(deleteNode); deleteNode = NULL; } if (cur->type == XML_ELEMENT_NODE) { /* * Clear the PSVI field. */ cur->psvi = NULL; xsltCompilerNodePush(cctxt, cur); inXSLText = 0; textNode = NULL; findSpaceAttr = 1; cctxt->inode->stripWhitespace = 0; /* * TODO: I'd love to use a string pointer comparison here :-/ */ if (IS_XSLT_ELEM(cur)) { #ifdef XSLT_REFACTORED_XSLT_NSCOMP if (cur->ns->href != nsNameXSLT) { nsMapItem = xsltNewNamespaceMapItem(cctxt, doc, cur->ns, cur); if (nsMapItem == NULL) goto internal_err; cur->ns->href = nsNameXSLT; } #endif if (cur->name == NULL) goto process_attributes; /* * Mark the XSLT element for later recognition. * TODO: Using the marker is still too dangerous, since if * the parsing mechanism leaves out an XSLT element, then * this might hit the transformation-mechanism, which * will break if it doesn't expect such a marker. */ /* cur->psvi = (void *) xsltXSLTElemMarker; */ /* * XSLT 2.0: "Any whitespace text node whose parent is * one of the following elements is removed from the " * tree, regardless of any xml:space attributes:..." * xsl:apply-imports, * xsl:apply-templates, * xsl:attribute-set, * xsl:call-template, * xsl:choose, * xsl:stylesheet, xsl:transform. * XSLT 2.0: xsl:analyze-string, * xsl:character-map, * xsl:next-match * * TODO: I'd love to use a string pointer comparison here :-/ */ name = cur->name; switch (*name) { case 't': if ((name[0] == 't') && (name[1] == 'e') && (name[2] == 'x') && (name[3] == 't') && (name[4] == 0)) { /* * Process the xsl:text element. * ---------------------------- * Mark it for later recognition. */ cur->psvi = (void *) xsltXSLTTextMarker; /* * For stylesheets, the set of * whitespace-preserving element names * consists of just xsl:text. */ findSpaceAttr = 0; cctxt->inode->preserveWhitespace = 1; inXSLText = 1; } break; case 'c': if (xmlStrEqual(name, BAD_CAST "choose") || xmlStrEqual(name, BAD_CAST "call-template")) cctxt->inode->stripWhitespace = 1; break; case 'a': if (xmlStrEqual(name, BAD_CAST "apply-templates") || xmlStrEqual(name, BAD_CAST "apply-imports") || xmlStrEqual(name, BAD_CAST "attribute-set")) cctxt->inode->stripWhitespace = 1; break; default: if (xsltStylesheetElemDepth == cctxt->depth) { /* * This is a xsl:stylesheet/xsl:transform. */ cctxt->inode->stripWhitespace = 1; break; } if ((cur->prev != NULL) && (cur->prev->type == XML_TEXT_NODE)) { /* * XSLT 2.0 : "Any whitespace text node whose * following-sibling node is an xsl:param or * xsl:sort element is removed from the tree, * regardless of any xml:space attributes." */ if (((*name == 'p') || (*name == 's')) && (xmlStrEqual(name, BAD_CAST "param") || xmlStrEqual(name, BAD_CAST "sort"))) { do { if (IS_BLANK_NODE(cur->prev)) { txt = cur->prev; xmlUnlinkNode(txt); xmlFreeNode(txt); } else { /* * This will result in a content * error, when hitting the parsing * functions. */ break; } } while (cur->prev); } } break; } } process_attributes: /* * Process attributes. * ------------------ */ if (cur->properties != NULL) { if (cur->children == NULL) findSpaceAttr = 0; attr = cur->properties; do { #ifdef XSLT_REFACTORED_XSLT_NSCOMP if ((attr->ns) && (attr->ns->href != nsNameXSLT) && xmlStrEqual(attr->ns->href, nsNameXSLT)) { nsMapItem = xsltNewNamespaceMapItem(cctxt, doc, attr->ns, cur); if (nsMapItem == NULL) goto internal_err; attr->ns->href = nsNameXSLT; } #endif if (internalize) { /* * Internalize the attribute's value; the goal is to * speed up operations and minimize used space by * compiled stylesheets. */ txt = attr->children; /* * NOTE that this assumes only one * text-node in the attribute's content. */ if ((txt != NULL) && (txt->content != NULL) && (!xmlDictOwns(style->dict, txt->content))) { value = (xmlChar *) xmlDictLookup(style->dict, txt->content, -1); xmlNodeSetContent(txt, NULL); txt->content = value; } } /* * Process xml:space attributes. * ---------------------------- */ if ((findSpaceAttr != 0) && (attr->ns != NULL) && (attr->name != NULL) && (attr->name[0] == 's') && (attr->ns->prefix != NULL) && (attr->ns->prefix[0] == 'x') && (attr->ns->prefix[1] == 'm') && (attr->ns->prefix[2] == 'l') && (attr->ns->prefix[3] == 0)) { value = xmlGetNsProp(cur, BAD_CAST "space", XML_XML_NAMESPACE); if (value != NULL) { if (xmlStrEqual(value, BAD_CAST "preserve")) { cctxt->inode->preserveWhitespace = 1; } else if (xmlStrEqual(value, BAD_CAST "default")) { cctxt->inode->preserveWhitespace = 0; } else { /* Invalid value for xml:space. */ xsltTransformError(NULL, style, cur, "Attribute xml:space: Invalid value.\n"); cctxt->style->warnings++; } findSpaceAttr = 0; xmlFree(value); } } attr = attr->next; } while (attr != NULL); } /* * We'll descend into the children of element nodes only. */ if (cur->children != NULL) { cur = cur->children; continue; } } else if ((cur->type == XML_TEXT_NODE) || (cur->type == XML_CDATA_SECTION_NODE)) { /* * Merge adjacent text/CDATA-section-nodes * --------------------------------------- * In order to avoid breaking of existing stylesheets, * if the old behaviour is wanted (strictWhitespace == 0), * then we *won't* merge adjacent text-nodes * (except in xsl:text); this will ensure that whitespace-only * text nodes are (incorrectly) not stripped in some cases. * * Example: : zoo * Corrent (strict) result: zoo * Incorrect (old) result : zoo * * NOTE that we *will* merge adjacent text-nodes if * they are in xsl:text. * Example, the following: * zoo * will result in both cases in: * zoo */ cur->type = XML_TEXT_NODE; if ((strictWhitespace != 0) || (inXSLText != 0)) { /* * New behaviour; merge nodes. */ if (textNode == NULL) textNode = cur; else { if (cur->content != NULL) xmlNodeAddContent(textNode, cur->content); deleteNode = cur; } if ((cur->next == NULL) || (cur->next->type == XML_ELEMENT_NODE)) goto end_of_text; else goto next_sibling; } else { /* * Old behaviour. */ if (textNode == NULL) textNode = cur; goto end_of_text; } } else if ((cur->type == XML_COMMENT_NODE) || (cur->type == XML_PI_NODE)) { /* * Remove processing instructions and comments. */ deleteNode = cur; if ((cur->next == NULL) || (cur->next->type == XML_ELEMENT_NODE)) goto end_of_text; else goto next_sibling; } else { textNode = NULL; /* * Invalid node-type for this data-model. */ xsltTransformError(NULL, style, cur, "Invalid type of node for the XSLT data model.\n"); cctxt->style->errors++; goto next_sibling; } end_of_text: if (textNode) { value = textNode->content; /* * At this point all adjacent text/CDATA-section nodes * have been merged. * * Strip whitespace-only text-nodes. * (cctxt->inode->stripWhitespace) */ if ((value == NULL) || (*value == 0) || (((cctxt->inode->stripWhitespace) || (! cctxt->inode->preserveWhitespace)) && IS_BLANK(*value) && xsltIsBlank(value))) { if (textNode != cur) { xmlUnlinkNode(textNode); xmlFreeNode(textNode); } else deleteNode = textNode; textNode = NULL; goto next_sibling; } /* * Convert CDATA-section nodes to text-nodes. * TODO: Can this produce problems? */ if (textNode->type != XML_TEXT_NODE) { textNode->type = XML_TEXT_NODE; textNode->name = xmlStringText; } if (internalize && (textNode->content != NULL) && (!xmlDictOwns(style->dict, textNode->content))) { /* * Internalize the string. */ value = (xmlChar *) xmlDictLookup(style->dict, textNode->content, -1); xmlNodeSetContent(textNode, NULL); textNode->content = value; } textNode = NULL; /* * Note that "disable-output-escaping" of the xsl:text * element will be applied at a later level, when * XSLT elements are processed. */ } next_sibling: if (cur->type == XML_ELEMENT_NODE) { xsltCompilerNodePop(cctxt, cur); } if (cur == node) break; if (cur->next != NULL) { cur = cur->next; } else { cur = cur->parent; inXSLText = 0; goto next_sibling; }; } if (deleteNode != NULL) { #ifdef WITH_XSLT_DEBUG_PARSING xsltGenericDebug(xsltGenericDebugContext, "xsltParsePreprocessStylesheetTree: removing node\n"); #endif xmlUnlinkNode(deleteNode); xmlFreeNode(deleteNode); } return(0); internal_err: return(-1); } #endif /* XSLT_REFACTORED */ #ifdef XSLT_REFACTORED #else static void xsltPrecomputeStylesheet(xsltStylesheetPtr style, xmlNodePtr cur) { xmlNodePtr deleteNode, styleelem; int internalize = 0; if ((style == NULL) || (cur == NULL)) return; if ((cur->doc != NULL) && (style->dict != NULL) && (cur->doc->dict == style->dict)) internalize = 1; else style->internalized = 0; if ((cur != NULL) && (IS_XSLT_ELEM(cur)) && (IS_XSLT_NAME(cur, "stylesheet"))) { styleelem = cur; } else { styleelem = NULL; } /* * This content comes from the stylesheet * For stylesheets, the set of whitespace-preserving * element names consists of just xsl:text. */ deleteNode = NULL; while (cur != NULL) { if (deleteNode != NULL) { #ifdef WITH_XSLT_DEBUG_BLANKS xsltGenericDebug(xsltGenericDebugContext, "xsltPrecomputeStylesheet: removing ignorable blank node\n"); #endif xmlUnlinkNode(deleteNode); xmlFreeNode(deleteNode); deleteNode = NULL; } if (cur->type == XML_ELEMENT_NODE) { int exclPrefixes; /* * Internalize attributes values. */ if ((internalize) && (cur->properties != NULL)) { xmlAttrPtr attr = cur->properties; xmlNodePtr txt; while (attr != NULL) { txt = attr->children; if ((txt != NULL) && (txt->type == XML_TEXT_NODE) && (txt->content != NULL) && (!xmlDictOwns(style->dict, txt->content))) { xmlChar *tmp; /* * internalize the text string, goal is to speed * up operations and minimize used space by compiled * stylesheets. */ tmp = (xmlChar *) xmlDictLookup(style->dict, txt->content, -1); if (tmp != txt->content) { xmlNodeSetContent(txt, NULL); txt->content = tmp; } } attr = attr->next; } } if (IS_XSLT_ELEM(cur)) { exclPrefixes = 0; xsltStylePreCompute(style, cur); if (IS_XSLT_NAME(cur, "text")) { for (;exclPrefixes > 0;exclPrefixes--) exclPrefixPop(style); goto skip_children; } } else { exclPrefixes = xsltParseStylesheetExcludePrefix(style, cur, 0); } if ((cur->nsDef != NULL) && (style->exclPrefixNr > 0)) { xmlNsPtr ns = cur->nsDef, prev = NULL, next; xmlNodePtr root = NULL; int i, moved; root = xmlDocGetRootElement(cur->doc); if ((root != NULL) && (root != cur)) { while (ns != NULL) { moved = 0; next = ns->next; for (i = 0;i < style->exclPrefixNr;i++) { if ((ns->prefix != NULL) && (xmlStrEqual(ns->href, style->exclPrefixTab[i]))) { /* * Move the namespace definition on the root * element to avoid duplicating it without * loosing it. */ if (prev == NULL) { cur->nsDef = ns->next; } else { prev->next = ns->next; } ns->next = root->nsDef; root->nsDef = ns; moved = 1; break; } } if (moved == 0) prev = ns; ns = next; } } } /* * If we have prefixes locally, recurse and pop them up when * going back */ if (exclPrefixes > 0) { xsltPrecomputeStylesheet(style, cur->children); for (;exclPrefixes > 0;exclPrefixes--) exclPrefixPop(style); goto skip_children; } } else if (cur->type == XML_TEXT_NODE) { if (IS_BLANK_NODE(cur)) { if (xmlNodeGetSpacePreserve(cur) != 1) { deleteNode = cur; } } else if ((cur->content != NULL) && (internalize) && (!xmlDictOwns(style->dict, cur->content))) { xmlChar *tmp; /* * internalize the text string, goal is to speed * up operations and minimize used space by compiled * stylesheets. */ tmp = (xmlChar *) xmlDictLookup(style->dict, cur->content, -1); xmlNodeSetContent(cur, NULL); cur->content = tmp; } } else if ((cur->type != XML_ELEMENT_NODE) && (cur->type != XML_CDATA_SECTION_NODE)) { deleteNode = cur; goto skip_children; } /* * Skip to next node. In case of a namespaced element children of * the stylesheet and not in the XSLT namespace and not an extension * element, ignore its content. */ if ((cur->type == XML_ELEMENT_NODE) && (cur->ns != NULL) && (styleelem != NULL) && (cur->parent == styleelem) && (!xmlStrEqual(cur->ns->href, XSLT_NAMESPACE)) && (!xsltCheckExtURI(style, cur->ns->href))) { goto skip_children; } else if (cur->children != NULL) { if ((cur->children->type != XML_ENTITY_DECL) && (cur->children->type != XML_ENTITY_REF_NODE) && (cur->children->type != XML_ENTITY_NODE)) { cur = cur->children; continue; } } skip_children: if (cur->next != NULL) { cur = cur->next; continue; } do { cur = cur->parent; if (cur == NULL) break; if (cur == (xmlNodePtr) style->doc) { cur = NULL; break; } if (cur->next != NULL) { cur = cur->next; break; } } while (cur != NULL); } if (deleteNode != NULL) { #ifdef WITH_XSLT_DEBUG_PARSING xsltGenericDebug(xsltGenericDebugContext, "xsltPrecomputeStylesheet: removing ignorable blank node\n"); #endif xmlUnlinkNode(deleteNode); xmlFreeNode(deleteNode); } } #endif /* end of else XSLT_REFACTORED */ /** * xsltGatherNamespaces: * @style: the XSLT stylesheet * * Browse the stylesheet and build the namspace hash table which * will be used for XPath interpretation. If needed do a bit of normalization */ static void xsltGatherNamespaces(xsltStylesheetPtr style) { xmlNodePtr cur; const xmlChar *URI; if (style == NULL) return; /* * TODO: basically if the stylesheet uses the same prefix for different * patterns, well they may be in problem, hopefully they will get * a warning first. */ /* * TODO: Eliminate the use of the hash for XPath expressions. * An expression should be evaluated in the context of the in-scope * namespaces; eliminate the restriction of an XML document to contain * no duplicate prefixes for different namespace names. * */ cur = xmlDocGetRootElement(style->doc); while (cur != NULL) { if (cur->type == XML_ELEMENT_NODE) { xmlNsPtr ns = cur->nsDef; while (ns != NULL) { if (ns->prefix != NULL) { if (style->nsHash == NULL) { style->nsHash = xmlHashCreate(10); if (style->nsHash == NULL) { xsltTransformError(NULL, style, cur, "xsltGatherNamespaces: failed to create hash table\n"); style->errors++; return; } } URI = xmlHashLookup(style->nsHash, ns->prefix); if ((URI != NULL) && (!xmlStrEqual(URI, ns->href))) { xsltTransformError(NULL, style, cur, "Namespaces prefix %s used for multiple namespaces\n",ns->prefix); style->warnings++; } else if (URI == NULL) { xmlHashUpdateEntry(style->nsHash, ns->prefix, (void *) ns->href, (xmlHashDeallocator)xmlFree); #ifdef WITH_XSLT_DEBUG_PARSING xsltGenericDebug(xsltGenericDebugContext, "Added namespace: %s mapped to %s\n", ns->prefix, ns->href); #endif } } ns = ns->next; } } /* * Skip to next node */ if (cur->children != NULL) { if (cur->children->type != XML_ENTITY_DECL) { cur = cur->children; continue; } } if (cur->next != NULL) { cur = cur->next; continue; } do { cur = cur->parent; if (cur == NULL) break; if (cur == (xmlNodePtr) style->doc) { cur = NULL; break; } if (cur->next != NULL) { cur = cur->next; break; } } while (cur != NULL); } } #ifdef XSLT_REFACTORED static xsltStyleType xsltGetXSLTElementTypeByNode(xsltCompilerCtxtPtr cctxt, xmlNodePtr node) { if ((node == NULL) || (node->type != XML_ELEMENT_NODE) || (node->name == NULL)) return(0); if (node->name[0] == 'a') { if (IS_XSLT_NAME(node, "apply-templates")) return(XSLT_FUNC_APPLYTEMPLATES); else if (IS_XSLT_NAME(node, "attribute")) return(XSLT_FUNC_ATTRIBUTE); else if (IS_XSLT_NAME(node, "apply-imports")) return(XSLT_FUNC_APPLYIMPORTS); else if (IS_XSLT_NAME(node, "attribute-set")) return(0); } else if (node->name[0] == 'c') { if (IS_XSLT_NAME(node, "choose")) return(XSLT_FUNC_CHOOSE); else if (IS_XSLT_NAME(node, "copy")) return(XSLT_FUNC_COPY); else if (IS_XSLT_NAME(node, "copy-of")) return(XSLT_FUNC_COPYOF); else if (IS_XSLT_NAME(node, "call-template")) return(XSLT_FUNC_CALLTEMPLATE); else if (IS_XSLT_NAME(node, "comment")) return(XSLT_FUNC_COMMENT); } else if (node->name[0] == 'd') { if (IS_XSLT_NAME(node, "document")) return(XSLT_FUNC_DOCUMENT); else if (IS_XSLT_NAME(node, "decimal-format")) return(0); } else if (node->name[0] == 'e') { if (IS_XSLT_NAME(node, "element")) return(XSLT_FUNC_ELEMENT); } else if (node->name[0] == 'f') { if (IS_XSLT_NAME(node, "for-each")) return(XSLT_FUNC_FOREACH); else if (IS_XSLT_NAME(node, "fallback")) return(XSLT_FUNC_FALLBACK); } else if (*(node->name) == 'i') { if (IS_XSLT_NAME(node, "if")) return(XSLT_FUNC_IF); else if (IS_XSLT_NAME(node, "include")) return(0); else if (IS_XSLT_NAME(node, "import")) return(0); } else if (*(node->name) == 'k') { if (IS_XSLT_NAME(node, "key")) return(0); } else if (*(node->name) == 'm') { if (IS_XSLT_NAME(node, "message")) return(XSLT_FUNC_MESSAGE); } else if (*(node->name) == 'n') { if (IS_XSLT_NAME(node, "number")) return(XSLT_FUNC_NUMBER); else if (IS_XSLT_NAME(node, "namespace-alias")) return(0); } else if (*(node->name) == 'o') { if (IS_XSLT_NAME(node, "otherwise")) return(XSLT_FUNC_OTHERWISE); else if (IS_XSLT_NAME(node, "output")) return(0); } else if (*(node->name) == 'p') { if (IS_XSLT_NAME(node, "param")) return(XSLT_FUNC_PARAM); else if (IS_XSLT_NAME(node, "processing-instruction")) return(XSLT_FUNC_PI); else if (IS_XSLT_NAME(node, "preserve-space")) return(0); } else if (*(node->name) == 's') { if (IS_XSLT_NAME(node, "sort")) return(XSLT_FUNC_SORT); else if (IS_XSLT_NAME(node, "strip-space")) return(0); else if (IS_XSLT_NAME(node, "stylesheet")) return(0); } else if (node->name[0] == 't') { if (IS_XSLT_NAME(node, "text")) return(XSLT_FUNC_TEXT); else if (IS_XSLT_NAME(node, "template")) return(0); else if (IS_XSLT_NAME(node, "transform")) return(0); } else if (*(node->name) == 'v') { if (IS_XSLT_NAME(node, "value-of")) return(XSLT_FUNC_VALUEOF); else if (IS_XSLT_NAME(node, "variable")) return(XSLT_FUNC_VARIABLE); } else if (*(node->name) == 'w') { if (IS_XSLT_NAME(node, "when")) return(XSLT_FUNC_WHEN); if (IS_XSLT_NAME(node, "with-param")) return(XSLT_FUNC_WITHPARAM); } return(0); } /** * xsltParseAnyXSLTElem: * * @cctxt: the compilation context * @elem: the element node of the XSLT instruction * * Parses, validates the content models and compiles XSLT instructions. * * Returns 0 if everything's fine; * -1 on API or internal errors. */ int xsltParseAnyXSLTElem(xsltCompilerCtxtPtr cctxt, xmlNodePtr elem) { if ((cctxt == NULL) || (elem == NULL) || (elem->type != XML_ELEMENT_NODE)) return(-1); elem->psvi = NULL; if (! (IS_XSLT_ELEM_FAST(elem))) return(-1); /* * Detection of handled content of extension instructions. */ if (cctxt->inode->category == XSLT_ELEMENT_CATEGORY_EXTENSION) { cctxt->inode->extContentHandled = 1; } xsltCompilerNodePush(cctxt, elem); /* * URGENT TODO: Find a way to speed up this annoying redundant * textual node-name and namespace comparison. */ if (cctxt->inode->prev->curChildType != 0) cctxt->inode->type = cctxt->inode->prev->curChildType; else cctxt->inode->type = xsltGetXSLTElementTypeByNode(cctxt, elem); /* * Update the in-scope namespaces if needed. */ if (elem->nsDef != NULL) cctxt->inode->inScopeNs = xsltCompilerBuildInScopeNsList(cctxt, elem); /* * xsltStylePreCompute(): * This will compile the information found on the current * element's attributes. NOTE that this won't process the * children of the instruction. */ xsltStylePreCompute(cctxt->style, elem); /* * TODO: How to react on errors in xsltStylePreCompute() ? */ /* * Validate the content model of the XSLT-element. */ switch (cctxt->inode->type) { case XSLT_FUNC_APPLYIMPORTS: /* EMPTY */ goto empty_content; case XSLT_FUNC_APPLYTEMPLATES: /* */ goto apply_templates; case XSLT_FUNC_ATTRIBUTE: /* */ goto sequence_constructor; case XSLT_FUNC_CALLTEMPLATE: /* */ goto call_template; case XSLT_FUNC_CHOOSE: /* */ goto choose; case XSLT_FUNC_COMMENT: /* */ goto sequence_constructor; case XSLT_FUNC_COPY: /* */ goto sequence_constructor; case XSLT_FUNC_COPYOF: /* EMPTY */ goto empty_content; case XSLT_FUNC_DOCUMENT: /* Extra one */ /* ?? template ?? */ goto sequence_constructor; case XSLT_FUNC_ELEMENT: /* */ goto sequence_constructor; case XSLT_FUNC_FALLBACK: /* */ goto sequence_constructor; case XSLT_FUNC_FOREACH: /* */ goto for_each; case XSLT_FUNC_IF: /* */ goto sequence_constructor; case XSLT_FUNC_OTHERWISE: /* */ goto sequence_constructor; case XSLT_FUNC_MESSAGE: /* */ goto sequence_constructor; case XSLT_FUNC_NUMBER: /* EMPTY */ goto empty_content; case XSLT_FUNC_PARAM: /* * Check for redefinition. */ if ((elem->psvi != NULL) && (cctxt->ivar != NULL)) { xsltVarInfoPtr ivar = cctxt->ivar; do { if ((ivar->name == ((xsltStyleItemParamPtr) elem->psvi)->name) && (ivar->nsName == ((xsltStyleItemParamPtr) elem->psvi)->ns)) { elem->psvi = NULL; xsltTransformError(NULL, cctxt->style, elem, "Redefinition of variable or parameter '%s'.\n", ivar->name); cctxt->style->errors++; goto error; } ivar = ivar->prev; } while (ivar != NULL); } /* */ goto sequence_constructor; case XSLT_FUNC_PI: /* */ goto sequence_constructor; case XSLT_FUNC_SORT: /* EMPTY */ goto empty_content; case XSLT_FUNC_TEXT: /* */ goto text; case XSLT_FUNC_VALUEOF: /* EMPTY */ goto empty_content; case XSLT_FUNC_VARIABLE: /* * Check for redefinition. */ if ((elem->psvi != NULL) && (cctxt->ivar != NULL)) { xsltVarInfoPtr ivar = cctxt->ivar; do { if ((ivar->name == ((xsltStyleItemVariablePtr) elem->psvi)->name) && (ivar->nsName == ((xsltStyleItemVariablePtr) elem->psvi)->ns)) { elem->psvi = NULL; xsltTransformError(NULL, cctxt->style, elem, "Redefinition of variable or parameter '%s'.\n", ivar->name); cctxt->style->errors++; goto error; } ivar = ivar->prev; } while (ivar != NULL); } /* */ goto sequence_constructor; case XSLT_FUNC_WHEN: /* */ goto sequence_constructor; case XSLT_FUNC_WITHPARAM: /* */ goto sequence_constructor; default: #ifdef WITH_XSLT_DEBUG_PARSING xsltGenericDebug(xsltGenericDebugContext, "xsltParseXSLTNode: Unhandled XSLT element '%s'.\n", elem->name); #endif xsltTransformError(NULL, cctxt->style, elem, "xsltParseXSLTNode: Internal error; " "unhandled XSLT element '%s'.\n", elem->name); cctxt->style->errors++; goto internal_err; } apply_templates: /* */ if (elem->children != NULL) { xmlNodePtr child = elem->children; do { if (child->type == XML_ELEMENT_NODE) { if (IS_XSLT_ELEM_FAST(child)) { if (xmlStrEqual(child->name, BAD_CAST "with-param")) { cctxt->inode->curChildType = XSLT_FUNC_WITHPARAM; xsltParseAnyXSLTElem(cctxt, child); } else if (xmlStrEqual(child->name, BAD_CAST "sort")) { cctxt->inode->curChildType = XSLT_FUNC_SORT; xsltParseAnyXSLTElem(cctxt, child); } else xsltParseContentError(cctxt->style, child); } else xsltParseContentError(cctxt->style, child); } child = child->next; } while (child != NULL); } goto exit; call_template: /* */ if (elem->children != NULL) { xmlNodePtr child = elem->children; do { if (child->type == XML_ELEMENT_NODE) { if (IS_XSLT_ELEM_FAST(child)) { xsltStyleType type; type = xsltGetXSLTElementTypeByNode(cctxt, child); if (type == XSLT_FUNC_WITHPARAM) { cctxt->inode->curChildType = XSLT_FUNC_WITHPARAM; xsltParseAnyXSLTElem(cctxt, child); } else { xsltParseContentError(cctxt->style, child); } } else xsltParseContentError(cctxt->style, child); } child = child->next; } while (child != NULL); } goto exit; text: if (elem->children != NULL) { xmlNodePtr child = elem->children; do { if ((child->type != XML_TEXT_NODE) && (child->type != XML_CDATA_SECTION_NODE)) { xsltTransformError(NULL, cctxt->style, elem, "The XSLT 'text' element must have only character " "data as content.\n"); } child = child->next; } while (child != NULL); } goto exit; empty_content: if (elem->children != NULL) { xmlNodePtr child = elem->children; /* * Relaxed behaviour: we will allow whitespace-only text-nodes. */ do { if (((child->type != XML_TEXT_NODE) && (child->type != XML_CDATA_SECTION_NODE)) || (! IS_BLANK_NODE(child))) { xsltTransformError(NULL, cctxt->style, elem, "This XSLT element must have no content.\n"); cctxt->style->errors++; break; } child = child->next; } while (child != NULL); } goto exit; choose: /* */ /* * TODO: text-nodes in between are *not* allowed in XSLT 1.0. * The old behaviour did not check this. * NOTE: In XSLT 2.0 they are stripped beforehand * if whitespace-only (regardless of xml:space). */ if (elem->children != NULL) { xmlNodePtr child = elem->children; int nbWhen = 0, nbOtherwise = 0, err = 0; do { if (child->type == XML_ELEMENT_NODE) { if (IS_XSLT_ELEM_FAST(child)) { xsltStyleType type; type = xsltGetXSLTElementTypeByNode(cctxt, child); if (type == XSLT_FUNC_WHEN) { nbWhen++; if (nbOtherwise) { xsltParseContentError(cctxt->style, child); err = 1; break; } cctxt->inode->curChildType = XSLT_FUNC_WHEN; xsltParseAnyXSLTElem(cctxt, child); } else if (type == XSLT_FUNC_OTHERWISE) { if (! nbWhen) { xsltParseContentError(cctxt->style, child); err = 1; break; } if (nbOtherwise) { xsltTransformError(NULL, cctxt->style, elem, "The XSLT 'choose' element must not contain " "more than one XSLT 'otherwise' element.\n"); cctxt->style->errors++; err = 1; break; } nbOtherwise++; cctxt->inode->curChildType = XSLT_FUNC_OTHERWISE; xsltParseAnyXSLTElem(cctxt, child); } else xsltParseContentError(cctxt->style, child); } else xsltParseContentError(cctxt->style, child); } /* else xsltParseContentError(cctxt, child); */ child = child->next; } while (child != NULL); if ((! err) && (! nbWhen)) { xsltTransformError(NULL, cctxt->style, elem, "The XSLT element 'choose' must contain at least one " "XSLT element 'when'.\n"); cctxt->style->errors++; } } goto exit; for_each: /* */ /* * NOTE: Text-nodes before xsl:sort are *not* allowed in XSLT 1.0. * The old behaviour did not allow this, but it catched this * only at transformation-time. * In XSLT 2.0 they are stripped beforehand if whitespace-only * (regardless of xml:space). */ if (elem->children != NULL) { xmlNodePtr child = elem->children; /* * Parse xsl:sort first. */ do { if ((child->type == XML_ELEMENT_NODE) && IS_XSLT_ELEM_FAST(child)) { if (xsltGetXSLTElementTypeByNode(cctxt, child) == XSLT_FUNC_SORT) { cctxt->inode->curChildType = XSLT_FUNC_SORT; xsltParseAnyXSLTElem(cctxt, child); } else break; } else break; child = child->next; } while (child != NULL); /* * Parse the sequece constructor. */ if (child != NULL) xsltParseSequenceConstructor(cctxt, child); } goto exit; sequence_constructor: /* * Parse the sequence constructor. */ if (elem->children != NULL) xsltParseSequenceConstructor(cctxt, elem->children); /* * Register information for vars/params. Only needed if there * are any following siblings. */ if ((elem->next != NULL) && ((cctxt->inode->type == XSLT_FUNC_VARIABLE) || (cctxt->inode->type == XSLT_FUNC_PARAM))) { if ((elem->psvi != NULL) && (((xsltStyleBasicItemVariablePtr) elem->psvi)->name)) { xsltCompilerVarInfoPush(cctxt, elem, ((xsltStyleBasicItemVariablePtr) elem->psvi)->name, ((xsltStyleBasicItemVariablePtr) elem->psvi)->ns); } } error: exit: xsltCompilerNodePop(cctxt, elem); return(0); internal_err: xsltCompilerNodePop(cctxt, elem); return(-1); } /** * xsltForwardsCompatUnkownItemCreate: * * @cctxt: the compilation context * * Creates a compiled representation of the unknown * XSLT instruction. * * Returns the compiled representation. */ static xsltStyleItemUknownPtr xsltForwardsCompatUnkownItemCreate(xsltCompilerCtxtPtr cctxt) { xsltStyleItemUknownPtr item; item = (xsltStyleItemUknownPtr) xmlMalloc(sizeof(xsltStyleItemUknown)); if (item == NULL) { xsltTransformError(NULL, cctxt->style, NULL, "Internal error in xsltForwardsCompatUnkownItemCreate(): " "Failed to allocate memory.\n"); cctxt->style->errors++; return(NULL); } memset(item, 0, sizeof(xsltStyleItemUknown)); item->type = XSLT_FUNC_UNKOWN_FORWARDS_COMPAT; /* * Store it in the stylesheet. */ item->next = cctxt->style->preComps; cctxt->style->preComps = (xsltElemPreCompPtr) item; return(item); } /** * xsltParseUnknownXSLTElem: * * @cctxt: the compilation context * @node: the element of the unknown XSLT instruction * * Parses an unknown XSLT element. * If forwards compatible mode is enabled this will allow * such an unknown XSLT and; otherwise it is rejected. * * Returns 1 in the unknown XSLT instruction is rejected, * 0 if everything's fine and * -1 on API or internal errors. */ static int xsltParseUnknownXSLTElem(xsltCompilerCtxtPtr cctxt, xmlNodePtr node) { if ((cctxt == NULL) || (node == NULL) || (node->type != XML_ELEMENT_NODE)) return(-1); /* * Detection of handled content of extension instructions. */ if (cctxt->inode->category == XSLT_ELEMENT_CATEGORY_EXTENSION) { cctxt->inode->extContentHandled = 1; } if (cctxt->inode->forwardsCompat == 0) { /* * We are not in forwards-compatible mode, so raise an error. */ xsltTransformError(NULL, cctxt->style, node, "Unknown XSLT element '%s'.\n", node->name); cctxt->style->errors++; return(1); } /* * Forwards-compatible mode. * ------------------------ * * Parse/compile xsl:fallback elements. * * QUESTION: Do we have to raise an error if there's no xsl:fallback? * ANSWER: No, since in the stylesheet the fallback behaviour might * also be provided by using the XSLT function "element-available". */ if (cctxt->unknownItem == NULL) { /* * Create a singleton for all unknown XSLT instructions. */ cctxt->unknownItem = xsltForwardsCompatUnkownItemCreate(cctxt); if (cctxt->unknownItem == NULL) { node->psvi = NULL; return(-1); } } node->psvi = cctxt->unknownItem; if (node->children == NULL) return(0); else { xmlNodePtr child = node->children; xsltCompilerNodePush(cctxt, node); /* * Update the in-scope namespaces if needed. */ if (node->nsDef != NULL) cctxt->inode->inScopeNs = xsltCompilerBuildInScopeNsList(cctxt, node); /* * Parse all xsl:fallback children. */ do { if ((child->type == XML_ELEMENT_NODE) && IS_XSLT_ELEM_FAST(child) && IS_XSLT_NAME(child, "fallback")) { cctxt->inode->curChildType = XSLT_FUNC_FALLBACK; xsltParseAnyXSLTElem(cctxt, child); } child = child->next; } while (child != NULL); xsltCompilerNodePop(cctxt, node); } return(0); } /** * xsltParseSequenceConstructor: * * @cctxt: the compilation context * @cur: the start-node of the content to be parsed * * Parses a "template" content (or "sequence constructor" in XSLT 2.0 terms). * This will additionally remove xsl:text elements from the tree. */ void xsltParseSequenceConstructor(xsltCompilerCtxtPtr cctxt, xmlNodePtr cur) { xsltStyleType type; xmlNodePtr deleteNode = NULL; if (cctxt == NULL) { xmlGenericError(xmlGenericErrorContext, "xsltParseSequenceConstructor: Bad arguments\n"); cctxt->style->errors++; return; } /* * Detection of handled content of extension instructions. */ if (cctxt->inode->category == XSLT_ELEMENT_CATEGORY_EXTENSION) { cctxt->inode->extContentHandled = 1; } if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL)) return; /* * This is the content reffered to as a "template". * E.g. an xsl:element has such content model: * * * * NOTE that in XSLT-2 the term "template" was abandoned due to * confusion with xsl:template and the term "sequence constructor" * was introduced instead. * * The following XSLT-instructions are allowed to appear: * xsl:apply-templates, xsl:call-template, xsl:apply-imports, * xsl:for-each, xsl:value-of, xsl:copy-of, xsl:number, * xsl:choose, xsl:if, xsl:text, xsl:copy, xsl:variable, * xsl:message, xsl:fallback, * xsl:processing-instruction, xsl:comment, xsl:element * xsl:attribute. * Additional allowed content: * 1) extension instructions * 2) literal result elements * 3) PCDATA * * NOTE that this content model does *not* allow xsl:param. */ while (cur != NULL) { if (deleteNode != NULL) { #ifdef WITH_XSLT_DEBUG_BLANKS xsltGenericDebug(xsltGenericDebugContext, "xsltParseSequenceConstructor: removing xsl:text element\n"); #endif xmlUnlinkNode(deleteNode); xmlFreeNode(deleteNode); deleteNode = NULL; } if (cur->type == XML_ELEMENT_NODE) { if (cur->psvi == xsltXSLTTextMarker) { /* * xsl:text elements * -------------------------------------------------------- */ xmlNodePtr tmp; cur->psvi = NULL; /* * Mark the xsl:text element for later deletion. */ deleteNode = cur; /* * Validate content. */ tmp = cur->children; if (tmp) { /* * We don't expect more than one text-node in the * content, since we already merged adjacent * text/CDATA-nodes and eliminated PI/comment-nodes. */ if ((tmp->type == XML_TEXT_NODE) || (tmp->next == NULL)) { /* * Leave the contained text-node in the tree. */ xmlUnlinkNode(tmp); xmlAddPrevSibling(cur, tmp); } else { tmp = NULL; xsltTransformError(NULL, cctxt->style, cur, "Element 'xsl:text': Invalid type " "of node found in content.\n"); cctxt->style->errors++; } } if (cur->properties) { xmlAttrPtr attr; /* * TODO: We need to report errors for * invalid attrs. */ attr = cur->properties; do { if ((attr->ns == NULL) && (attr->name != NULL) && (attr->name[0] == 'd') && xmlStrEqual(attr->name, BAD_CAST "disable-output-escaping")) { /* * Attr "disable-output-escaping". * XSLT-2: This attribute is deprecated. */ if ((attr->children != NULL) && xmlStrEqual(attr->children->content, BAD_CAST "yes")) { /* * Disable output escaping for this * text node. */ if (tmp) tmp->name = xmlStringTextNoenc; } else if ((attr->children == NULL) || (attr->children->content == NULL) || (!xmlStrEqual(attr->children->content, BAD_CAST "no"))) { xsltTransformError(NULL, cctxt->style, cur, "Attribute 'disable-output-escaping': " "Invalid value. Expected is " "'yes' or 'no'.\n"); cctxt->style->errors++; } break; } attr = attr->next; } while (attr != NULL); } } else if (IS_XSLT_ELEM_FAST(cur)) { /* * TODO: Using the XSLT-marker is still not stable yet. */ /* if (cur->psvi == xsltXSLTElemMarker) { */ /* * XSLT instructions * -------------------------------------------------------- */ cur->psvi = NULL; type = xsltGetXSLTElementTypeByNode(cctxt, cur); switch (type) { case XSLT_FUNC_APPLYIMPORTS: case XSLT_FUNC_APPLYTEMPLATES: case XSLT_FUNC_ATTRIBUTE: case XSLT_FUNC_CALLTEMPLATE: case XSLT_FUNC_CHOOSE: case XSLT_FUNC_COMMENT: case XSLT_FUNC_COPY: case XSLT_FUNC_COPYOF: case XSLT_FUNC_DOCUMENT: /* Extra one */ case XSLT_FUNC_ELEMENT: case XSLT_FUNC_FALLBACK: case XSLT_FUNC_FOREACH: case XSLT_FUNC_IF: case XSLT_FUNC_MESSAGE: case XSLT_FUNC_NUMBER: case XSLT_FUNC_PI: case XSLT_FUNC_TEXT: case XSLT_FUNC_VALUEOF: case XSLT_FUNC_VARIABLE: /* * Parse the XSLT element. */ cctxt->inode->curChildType = type; xsltParseAnyXSLTElem(cctxt, cur); break; default: xsltParseUnknownXSLTElem(cctxt, cur); cur = cur->next; continue; } } else { /* * Non-XSLT elements * ----------------- */ xsltCompilerNodePush(cctxt, cur); /* * Update the in-scope namespaces if needed. */ if (cur->nsDef != NULL) cctxt->inode->inScopeNs = xsltCompilerBuildInScopeNsList(cctxt, cur); /* * The current element is either a literal result element * or an extension instruction. * * Process attr "xsl:extension-element-prefixes". * FUTURE TODO: IIRC in XSLT 2.0 this attribute must be * processed by the implementor of the extension function; * i.e., it won't be handled by the XSLT processor. */ /* SPEC 1.0: * "exclude-result-prefixes" is only allowed on literal * result elements and "xsl:exclude-result-prefixes" * on xsl:stylesheet/xsl:transform. * SPEC 2.0: * "There are a number of standard attributes * that may appear on any XSLT element: specifically * version, exclude-result-prefixes, * extension-element-prefixes, xpath-default-namespace, * default-collation, and use-when." * * SPEC 2.0: * For literal result elements: * "xsl:version, xsl:exclude-result-prefixes, * xsl:extension-element-prefixes, * xsl:xpath-default-namespace, * xsl:default-collation, or xsl:use-when." */ if (cur->properties) cctxt->inode->extElemNs = xsltParseExtElemPrefixes(cctxt, cur, cctxt->inode->extElemNs, XSLT_ELEMENT_CATEGORY_LRE); /* * Eval if we have an extension instruction here. */ if ((cur->ns != NULL) && (cctxt->inode->extElemNs != NULL) && (xsltCheckExtPrefix(cctxt->style, cur->ns->href) == 1)) { /* * Extension instructions * ---------------------------------------------------- * Mark the node information. */ cctxt->inode->category = XSLT_ELEMENT_CATEGORY_EXTENSION; cctxt->inode->extContentHandled = 0; if (cur->psvi != NULL) { cur->psvi = NULL; /* * TODO: Temporary sanity check. */ xsltTransformError(NULL, cctxt->style, cur, "Internal error in xsltParseSequenceConstructor(): " "Occupied PSVI field.\n"); cctxt->style->errors++; cur = cur->next; continue; } cur->psvi = (void *) xsltPreComputeExtModuleElement(cctxt->style, cur); if (cur->psvi == NULL) { /* * OLD COMMENT: "Unknown element, maybe registered * at the context level. Mark it for later * recognition." * QUESTION: What does the xsltExtMarker mean? * ANSWER: It is used in * xsltApplySequenceConstructor() at * transformation-time to look out for extension * registered in the transformation context. */ cur->psvi = (void *) xsltExtMarker; } /* * BIG NOTE: Now the ugly part. In previous versions * of Libxslt (until 1.1.16), all the content of an * extension instruction was processed and compiled without * the need of the extension-author to explicitely call * such a processing;.We now need to mimic this old * behaviour in order to avoid breaking old code * on the extension-author's side. * The mechanism: * 1) If the author does *not* set the * compile-time-flag @extContentHandled, then we'll * parse the content assuming that it's a "template" * (or "sequence constructor in XSLT 2.0 terms). * NOTE: If the extension is registered at * transformation-time only, then there's no way of * knowing that content shall be valid, and we'll * process the content the same way. * 2) If the author *does* set the flag, then we'll assume * that the author has handled the parsing him/herself * (e.g. called xsltParseSequenceConstructor(), etc. * explicitely in his/her code). */ if ((cur->children != NULL) && (cctxt->inode->extContentHandled == 0)) { /* * Default parsing of the content using the * sequence-constructor model. */ xsltParseSequenceConstructor(cctxt, cur->children); } } else { /* * Literal result element * ---------------------------------------------------- * Allowed XSLT attributes: * xsl:extension-element-prefixes CDATA #IMPLIED * xsl:exclude-result-prefixes CDATA #IMPLIED * TODO: xsl:use-attribute-sets %qnames; #IMPLIED * xsl:version NMTOKEN #IMPLIED */ cur->psvi = NULL; cctxt->inode->category = XSLT_ELEMENT_CATEGORY_LRE; if (cur->properties != NULL) { xmlAttrPtr attr = cur->properties; /* * Attribute "xsl:exclude-result-prefixes". */ cctxt->inode->exclResultNs = xsltParseExclResultPrefixes(cctxt, cur, cctxt->inode->exclResultNs, XSLT_ELEMENT_CATEGORY_LRE); /* * Attribute "xsl:version". */ xsltParseAttrXSLTVersion(cctxt, cur, XSLT_ELEMENT_CATEGORY_LRE); /* * Report invalid XSLT attributes. * For XSLT 1.0 only xsl:use-attribute-sets is allowed * next to xsl:version, xsl:exclude-result-prefixes and * xsl:extension-element-prefixes. * * Mark all XSLT attributes, in order to skip such * attributes when instantiating the LRE. */ do { if ((attr->psvi != xsltXSLTAttrMarker) && IS_XSLT_ATTR_FAST(attr)) { if (! xmlStrEqual(attr->name, BAD_CAST "use-attribute-sets")) { xsltTransformError(NULL, cctxt->style, cur, "Unknown XSLT attribute '%s'.\n", attr->name); cctxt->style->errors++; } else { /* * XSLT attr marker. */ attr->psvi = (void *) xsltXSLTAttrMarker; } } attr = attr->next; } while (attr != NULL); } /* * Create/reuse info for the literal result element. */ if (cctxt->inode->nsChanged) xsltLREInfoCreate(cctxt, cur, 1); cur->psvi = cctxt->inode->litResElemInfo; /* * Apply ns-aliasing on the element and on its attributes. */ if (cctxt->hasNsAliases) xsltLREBuildEffectiveNs(cctxt, cur); /* * Compile attribute value templates (AVT). */ if (cur->properties) { xmlAttrPtr attr = cur->properties; while (attr != NULL) { xsltCompileAttr(cctxt->style, attr); attr = attr->next; } } /* * Parse the content, which is defined to be a "template" * (or "sequence constructor" in XSLT 2.0 terms). */ if (cur->children != NULL) { xsltParseSequenceConstructor(cctxt, cur->children); } } /* * Leave the non-XSLT element. */ xsltCompilerNodePop(cctxt, cur); } } cur = cur->next; } if (deleteNode != NULL) { #ifdef WITH_XSLT_DEBUG_BLANKS xsltGenericDebug(xsltGenericDebugContext, "xsltParseSequenceConstructor: removing xsl:text element\n"); #endif xmlUnlinkNode(deleteNode); xmlFreeNode(deleteNode); deleteNode = NULL; } } /** * xsltParseTemplateContent: * @style: the XSLT stylesheet * @templ: the node containing the content to be parsed * * Parses and compiles the content-model of an xsl:template element. * Note that this is *not* the "template" content model (or "sequence * constructor" in XSLT 2.0); it it allows addional xsl:param * elements as immediate children of @templ. * * Called by: * exsltFuncFunctionComp() (EXSLT, functions.c) * So this is intended to be called from extension functions. */ void xsltParseTemplateContent(xsltStylesheetPtr style, xmlNodePtr templ) { if ((style == NULL) || (templ == NULL) || (templ->type == XML_NAMESPACE_DECL)) return; /* * Detection of handled content of extension instructions. */ if (XSLT_CCTXT(style)->inode->category == XSLT_ELEMENT_CATEGORY_EXTENSION) { XSLT_CCTXT(style)->inode->extContentHandled = 1; } if (templ->children != NULL) { xmlNodePtr child = templ->children; /* * Process xsl:param elements, which can only occur as the * immediate children of xsl:template (well, and of any * user-defined extension instruction if needed). */ do { if ((child->type == XML_ELEMENT_NODE) && IS_XSLT_ELEM_FAST(child) && IS_XSLT_NAME(child, "param")) { XSLT_CCTXT(style)->inode->curChildType = XSLT_FUNC_PARAM; xsltParseAnyXSLTElem(XSLT_CCTXT(style), child); } else break; child = child->next; } while (child != NULL); /* * Parse the content and register the pattern. */ xsltParseSequenceConstructor(XSLT_CCTXT(style), child); } } #else /* XSLT_REFACTORED */ /** * xsltParseTemplateContent: * @style: the XSLT stylesheet * @templ: the container node (can be a document for literal results) * * parse a template content-model * Clean-up the template content from unwanted ignorable blank nodes * and process xslt:text */ void xsltParseTemplateContent(xsltStylesheetPtr style, xmlNodePtr templ) { xmlNodePtr cur, delete; if ((style == NULL) || (templ == NULL) || (templ->type == XML_NAMESPACE_DECL)) return; /* * This content comes from the stylesheet * For stylesheets, the set of whitespace-preserving * element names consists of just xsl:text. */ cur = templ->children; delete = NULL; while (cur != NULL) { if (delete != NULL) { #ifdef WITH_XSLT_DEBUG_BLANKS xsltGenericDebug(xsltGenericDebugContext, "xsltParseTemplateContent: removing text\n"); #endif xmlUnlinkNode(delete); xmlFreeNode(delete); delete = NULL; } if (IS_XSLT_ELEM(cur)) { if (IS_XSLT_NAME(cur, "text")) { /* * TODO: Processing of xsl:text should be moved to * xsltPrecomputeStylesheet(), since otherwise this * will be performed for every multiply included * stylesheet; i.e. this here is not skipped with * the use of the style->nopreproc flag. */ if (cur->children != NULL) { xmlChar *prop; xmlNodePtr text = cur->children, next; int noesc = 0; prop = xmlGetNsProp(cur, (const xmlChar *)"disable-output-escaping", NULL); if (prop != NULL) { #ifdef WITH_XSLT_DEBUG_PARSING xsltGenericDebug(xsltGenericDebugContext, "Disable escaping: %s\n", text->content); #endif if (xmlStrEqual(prop, (const xmlChar *)"yes")) { noesc = 1; } else if (!xmlStrEqual(prop, (const xmlChar *)"no")){ xsltTransformError(NULL, style, cur, "xsl:text: disable-output-escaping allows only yes or no\n"); style->warnings++; } xmlFree(prop); } while (text != NULL) { if (text->type == XML_COMMENT_NODE) { text = text->next; continue; } if ((text->type != XML_TEXT_NODE) && (text->type != XML_CDATA_SECTION_NODE)) { xsltTransformError(NULL, style, cur, "xsltParseTemplateContent: xslt:text content problem\n"); style->errors++; break; } if ((noesc) && (text->type != XML_CDATA_SECTION_NODE)) text->name = xmlStringTextNoenc; text = text->next; } /* * replace xsl:text by the list of childs */ if (text == NULL) { text = cur->children; while (text != NULL) { if ((style->internalized) && (text->content != NULL) && (!xmlDictOwns(style->dict, text->content))) { /* * internalize the text string */ if (text->doc->dict != NULL) { const xmlChar *tmp; tmp = xmlDictLookup(text->doc->dict, text->content, -1); if (tmp != text->content) { xmlNodeSetContent(text, NULL); text->content = (xmlChar *) tmp; } } } next = text->next; xmlUnlinkNode(text); xmlAddPrevSibling(cur, text); text = next; } } } delete = cur; goto skip_children; } } else if ((cur->ns != NULL) && (style->nsDefs != NULL) && (xsltCheckExtPrefix(style, cur->ns->prefix))) { /* * okay this is an extension element compile it too */ xsltStylePreCompute(style, cur); } else if (cur->type == XML_ELEMENT_NODE) { /* * This is an element which will be output as part of the * template exectution, precompile AVT if found. */ if ((cur->ns == NULL) && (style->defaultAlias != NULL)) { cur->ns = xmlSearchNsByHref(cur->doc, cur, style->defaultAlias); } if (cur->properties != NULL) { xmlAttrPtr attr = cur->properties; while (attr != NULL) { xsltCompileAttr(style, attr); attr = attr->next; } } } /* * Skip to next node */ if (cur->children != NULL) { if (cur->children->type != XML_ENTITY_DECL) { cur = cur->children; continue; } } skip_children: if (cur->next != NULL) { cur = cur->next; continue; } do { cur = cur->parent; if (cur == NULL) break; if (cur == templ) { cur = NULL; break; } if (cur->next != NULL) { cur = cur->next; break; } } while (cur != NULL); } if (delete != NULL) { #ifdef WITH_XSLT_DEBUG_PARSING xsltGenericDebug(xsltGenericDebugContext, "xsltParseTemplateContent: removing text\n"); #endif xmlUnlinkNode(delete); xmlFreeNode(delete); delete = NULL; } /* * Skip the first params */ cur = templ->children; while (cur != NULL) { if ((IS_XSLT_ELEM(cur)) && (!(IS_XSLT_NAME(cur, "param")))) break; cur = cur->next; } /* * Browse the remainder of the template */ while (cur != NULL) { if ((IS_XSLT_ELEM(cur)) && (IS_XSLT_NAME(cur, "param"))) { xmlNodePtr param = cur; xsltTransformError(NULL, style, cur, "xsltParseTemplateContent: ignoring misplaced param element\n"); if (style != NULL) style->warnings++; cur = cur->next; xmlUnlinkNode(param); xmlFreeNode(param); } else break; } } #endif /* else XSLT_REFACTORED */ /** * xsltParseStylesheetKey: * @style: the XSLT stylesheet * @key: the "key" element * * * * * parse an XSLT stylesheet key definition and register it */ static void xsltParseStylesheetKey(xsltStylesheetPtr style, xmlNodePtr key) { xmlChar *prop = NULL; xmlChar *use = NULL; xmlChar *match = NULL; xmlChar *name = NULL; xmlChar *nameURI = NULL; if ((style == NULL) || (key == NULL) || (key->type != XML_ELEMENT_NODE)) return; /* * Get arguments */ prop = xmlGetNsProp(key, (const xmlChar *)"name", NULL); if (prop != NULL) { const xmlChar *URI; /* * TODO: Don't use xsltGetQNameURI(). */ URI = xsltGetQNameURI(key, &prop); if (prop == NULL) { if (style != NULL) style->errors++; goto error; } else { name = prop; if (URI != NULL) nameURI = xmlStrdup(URI); } #ifdef WITH_XSLT_DEBUG_PARSING xsltGenericDebug(xsltGenericDebugContext, "xsltParseStylesheetKey: name %s\n", name); #endif } else { xsltTransformError(NULL, style, key, "xsl:key : error missing name\n"); if (style != NULL) style->errors++; goto error; } match = xmlGetNsProp(key, (const xmlChar *)"match", NULL); if (match == NULL) { xsltTransformError(NULL, style, key, "xsl:key : error missing match\n"); if (style != NULL) style->errors++; goto error; } use = xmlGetNsProp(key, (const xmlChar *)"use", NULL); if (use == NULL) { xsltTransformError(NULL, style, key, "xsl:key : error missing use\n"); if (style != NULL) style->errors++; goto error; } /* * register the keys */ xsltAddKey(style, name, nameURI, match, use, key); error: if (use != NULL) xmlFree(use); if (match != NULL) xmlFree(match); if (name != NULL) xmlFree(name); if (nameURI != NULL) xmlFree(nameURI); if (key->children != NULL) { xsltParseContentError(style, key->children); } } #ifdef XSLT_REFACTORED /** * xsltParseXSLTTemplate: * @style: the XSLT stylesheet * @template: the "template" element * * parse an XSLT stylesheet template building the associated structures * TODO: Is @style ever expected to be NULL? * * Called from: * xsltParseXSLTStylesheet() * xsltParseStylesheetTop() */ static void xsltParseXSLTTemplate(xsltCompilerCtxtPtr cctxt, xmlNodePtr templNode) { xsltTemplatePtr templ; xmlChar *prop; double priority; if ((cctxt == NULL) || (templNode == NULL) || (templNode->type != XML_ELEMENT_NODE)) return; /* * Create and link the structure */ templ = xsltNewTemplate(); if (templ == NULL) return; xsltCompilerNodePush(cctxt, templNode); if (templNode->nsDef != NULL) cctxt->inode->inScopeNs = xsltCompilerBuildInScopeNsList(cctxt, templNode); templ->next = cctxt->style->templates; cctxt->style->templates = templ; templ->style = cctxt->style; /* * Attribute "mode". */ prop = xmlGetNsProp(templNode, (const xmlChar *)"mode", NULL); if (prop != NULL) { const xmlChar *modeURI; /* * TODO: We need a standardized function for extraction * of namespace names and local names from QNames. * Don't use xsltGetQNameURI() as it cannot channe� * reports through the context. */ modeURI = xsltGetQNameURI(templNode, &prop); if (prop == NULL) { cctxt->style->errors++; goto error; } templ->mode = xmlDictLookup(cctxt->style->dict, prop, -1); xmlFree(prop); prop = NULL; if (xmlValidateNCName(templ->mode, 0)) { xsltTransformError(NULL, cctxt->style, templNode, "xsl:template: Attribute 'mode': The local part '%s' " "of the value is not a valid NCName.\n", templ->name); cctxt->style->errors++; goto error; } if (modeURI != NULL) templ->modeURI = xmlDictLookup(cctxt->style->dict, modeURI, -1); #ifdef WITH_XSLT_DEBUG_PARSING xsltGenericDebug(xsltGenericDebugContext, "xsltParseXSLTTemplate: mode %s\n", templ->mode); #endif } /* * Attribute "match". */ prop = xmlGetNsProp(templNode, (const xmlChar *)"match", NULL); if (prop != NULL) { templ->match = prop; prop = NULL; } /* * Attribute "priority". */ prop = xmlGetNsProp(templNode, (const xmlChar *)"priority", NULL); if (prop != NULL) { priority = xmlXPathStringEvalNumber(prop); templ->priority = (float) priority; xmlFree(prop); prop = NULL; } /* * Attribute "name". */ prop = xmlGetNsProp(templNode, (const xmlChar *)"name", NULL); if (prop != NULL) { const xmlChar *nameURI; xsltTemplatePtr curTempl; /* * TODO: Don't use xsltGetQNameURI(). */ nameURI = xsltGetQNameURI(templNode, &prop); if (prop == NULL) { cctxt->style->errors++; goto error; } templ->name = xmlDictLookup(cctxt->style->dict, prop, -1); xmlFree(prop); prop = NULL; if (xmlValidateNCName(templ->name, 0)) { xsltTransformError(NULL, cctxt->style, templNode, "xsl:template: Attribute 'name': The local part '%s' of " "the value is not a valid NCName.\n", templ->name); cctxt->style->errors++; goto error; } if (nameURI != NULL) templ->nameURI = xmlDictLookup(cctxt->style->dict, nameURI, -1); curTempl = templ->next; while (curTempl != NULL) { if ((nameURI != NULL && xmlStrEqual(curTempl->name, templ->name) && xmlStrEqual(curTempl->nameURI, nameURI) ) || (nameURI == NULL && curTempl->nameURI == NULL && xmlStrEqual(curTempl->name, templ->name))) { xsltTransformError(NULL, cctxt->style, templNode, "xsl:template: error duplicate name '%s'\n", templ->name); cctxt->style->errors++; goto error; } curTempl = curTempl->next; } } if (templNode->children != NULL) { xsltParseTemplateContent(cctxt->style, templNode); /* * MAYBE TODO: Custom behaviour: In order to stay compatible with * Xalan and MSXML(.NET), we could allow whitespace * to appear before an xml:param element; this whitespace * will additionally become part of the "template". * NOTE that this is totally deviates from the spec, but * is the de facto behaviour of Xalan and MSXML(.NET). * Personally I wouldn't allow this, since if we have: * * * * * ... the whitespace between every xsl:param would be * added to the result tree. */ } templ->elem = templNode; templ->content = templNode->children; xsltAddTemplate(cctxt->style, templ, templ->mode, templ->modeURI); error: xsltCompilerNodePop(cctxt, templNode); return; } #else /* XSLT_REFACTORED */ /** * xsltParseStylesheetTemplate: * @style: the XSLT stylesheet * @template: the "template" element * * parse an XSLT stylesheet template building the associated structures */ static void xsltParseStylesheetTemplate(xsltStylesheetPtr style, xmlNodePtr template) { xsltTemplatePtr ret; xmlChar *prop; xmlChar *mode = NULL; xmlChar *modeURI = NULL; double priority; if ((style == NULL) || (template == NULL) || (template->type != XML_ELEMENT_NODE)) return; /* * Create and link the structure */ ret = xsltNewTemplate(); if (ret == NULL) return; ret->next = style->templates; style->templates = ret; ret->style = style; /* * Get inherited namespaces */ /* * TODO: Apply the optimized in-scope-namespace mechanism * as for the other XSLT instructions. */ xsltGetInheritedNsList(style, ret, template); /* * Get arguments */ prop = xmlGetNsProp(template, (const xmlChar *)"mode", NULL); if (prop != NULL) { const xmlChar *URI; /* * TODO: Don't use xsltGetQNameURI(). */ URI = xsltGetQNameURI(template, &prop); if (prop == NULL) { if (style != NULL) style->errors++; goto error; } else { mode = prop; if (URI != NULL) modeURI = xmlStrdup(URI); } ret->mode = xmlDictLookup(style->dict, mode, -1); ret->modeURI = xmlDictLookup(style->dict, modeURI, -1); #ifdef WITH_XSLT_DEBUG_PARSING xsltGenericDebug(xsltGenericDebugContext, "xsltParseStylesheetTemplate: mode %s\n", mode); #endif if (mode != NULL) xmlFree(mode); if (modeURI != NULL) xmlFree(modeURI); } prop = xmlGetNsProp(template, (const xmlChar *)"match", NULL); if (prop != NULL) { if (ret->match != NULL) xmlFree(ret->match); ret->match = prop; } prop = xmlGetNsProp(template, (const xmlChar *)"priority", NULL); if (prop != NULL) { priority = xmlXPathStringEvalNumber(prop); ret->priority = (float) priority; xmlFree(prop); } prop = xmlGetNsProp(template, (const xmlChar *)"name", NULL); if (prop != NULL) { const xmlChar *URI; xsltTemplatePtr cur; /* * TODO: Don't use xsltGetQNameURI(). */ URI = xsltGetQNameURI(template, &prop); if (prop == NULL) { if (style != NULL) style->errors++; goto error; } else { if (xmlValidateNCName(prop,0)) { xsltTransformError(NULL, style, template, "xsl:template : error invalid name '%s'\n", prop); if (style != NULL) style->errors++; goto error; } ret->name = xmlDictLookup(style->dict, BAD_CAST prop, -1); xmlFree(prop); prop = NULL; if (URI != NULL) ret->nameURI = xmlDictLookup(style->dict, BAD_CAST URI, -1); else ret->nameURI = NULL; cur = ret->next; while (cur != NULL) { if ((URI != NULL && xmlStrEqual(cur->name, ret->name) && xmlStrEqual(cur->nameURI, URI) ) || (URI == NULL && cur->nameURI == NULL && xmlStrEqual(cur->name, ret->name))) { xsltTransformError(NULL, style, template, "xsl:template: error duplicate name '%s'\n", ret->name); style->errors++; goto error; } cur = cur->next; } } } /* * parse the content and register the pattern */ xsltParseTemplateContent(style, template); ret->elem = template; ret->content = template->children; xsltAddTemplate(style, ret, ret->mode, ret->modeURI); error: return; } #endif /* else XSLT_REFACTORED */ #ifdef XSLT_REFACTORED /** * xsltIncludeComp: * @cctxt: the compilation contenxt * @node: the xsl:include node * * Process the xslt include node on the source node */ static xsltStyleItemIncludePtr xsltCompileXSLTIncludeElem(xsltCompilerCtxtPtr cctxt, xmlNodePtr node) { xsltStyleItemIncludePtr item; if ((cctxt == NULL) || (node == NULL) || (node->type != XML_ELEMENT_NODE)) return(NULL); node->psvi = NULL; item = (xsltStyleItemIncludePtr) xmlMalloc(sizeof(xsltStyleItemInclude)); if (item == NULL) { xsltTransformError(NULL, cctxt->style, node, "xsltIncludeComp : malloc failed\n"); cctxt->style->errors++; return(NULL); } memset(item, 0, sizeof(xsltStyleItemInclude)); node->psvi = item; item->inst = node; item->type = XSLT_FUNC_INCLUDE; item->next = cctxt->style->preComps; cctxt->style->preComps = (xsltElemPreCompPtr) item; return(item); } /** * xsltParseFindTopLevelElem: */ static int xsltParseFindTopLevelElem(xsltCompilerCtxtPtr cctxt, xmlNodePtr cur, const xmlChar *name, const xmlChar *namespaceURI, int breakOnOtherElem, xmlNodePtr *resultNode) { if (name == NULL) return(-1); *resultNode = NULL; while (cur != NULL) { if (cur->type == XML_ELEMENT_NODE) { if ((cur->ns != NULL) && (cur->name != NULL)) { if ((*(cur->name) == *name) && xmlStrEqual(cur->name, name) && xmlStrEqual(cur->ns->href, namespaceURI)) { *resultNode = cur; return(1); } } if (breakOnOtherElem) break; } cur = cur->next; } *resultNode = cur; return(0); } static int xsltParseTopLevelXSLTElem(xsltCompilerCtxtPtr cctxt, xmlNodePtr node, xsltStyleType type) { int ret = 0; /* * TODO: The reason why this function exists: * due to historical reasons some of the * top-level declarations are processed by functions * in other files. Since we need still to set * up the node-info and generate information like * in-scope namespaces, this is a wrapper around * those old parsing functions. */ xsltCompilerNodePush(cctxt, node); if (node->nsDef != NULL) cctxt->inode->inScopeNs = xsltCompilerBuildInScopeNsList(cctxt, node); cctxt->inode->type = type; switch (type) { case XSLT_FUNC_INCLUDE: { int oldIsInclude; if (xsltCompileXSLTIncludeElem(cctxt, node) == NULL) goto exit; /* * Mark this stylesheet tree as being currently included. */ oldIsInclude = cctxt->isInclude; cctxt->isInclude = 1; if (xsltParseStylesheetInclude(cctxt->style, node) != 0) { cctxt->style->errors++; } cctxt->isInclude = oldIsInclude; } break; case XSLT_FUNC_PARAM: xsltStylePreCompute(cctxt->style, node); xsltParseGlobalParam(cctxt->style, node); break; case XSLT_FUNC_VARIABLE: xsltStylePreCompute(cctxt->style, node); xsltParseGlobalVariable(cctxt->style, node); break; case XSLT_FUNC_ATTRSET: xsltParseStylesheetAttributeSet(cctxt->style, node); break; default: xsltTransformError(NULL, cctxt->style, node, "Internal error: (xsltParseTopLevelXSLTElem) " "Cannot handle this top-level declaration.\n"); cctxt->style->errors++; ret = -1; } exit: xsltCompilerNodePop(cctxt, node); return(ret); } #if 0 static int xsltParseRemoveWhitespace(xmlNodePtr node) { if ((node == NULL) || (node->children == NULL)) return(0); else { xmlNodePtr delNode = NULL, child = node->children; do { if (delNode) { xmlUnlinkNode(delNode); xmlFreeNode(delNode); delNode = NULL; } if (((child->type == XML_TEXT_NODE) || (child->type == XML_CDATA_SECTION_NODE)) && (IS_BLANK_NODE(child))) delNode = child; child = child->next; } while (child != NULL); if (delNode) { xmlUnlinkNode(delNode); xmlFreeNode(delNode); delNode = NULL; } } return(0); } #endif static int xsltParseXSLTStylesheetElemCore(xsltCompilerCtxtPtr cctxt, xmlNodePtr node) { #ifdef WITH_XSLT_DEBUG_PARSING int templates = 0; #endif xmlNodePtr cur, start = NULL; xsltStylesheetPtr style; if ((cctxt == NULL) || (node == NULL) || (node->type != XML_ELEMENT_NODE)) return(-1); style = cctxt->style; /* * At this stage all import declarations of all stylesheet modules * with the same stylesheet level have been processed. * Now we can safely parse the rest of the declarations. */ if (IS_XSLT_ELEM_FAST(node) && IS_XSLT_NAME(node, "include")) { xsltDocumentPtr include; /* * URGENT TODO: Make this work with simplified stylesheets! * I.e., when we won't find an xsl:stylesheet element. */ /* * This is as include declaration. */ include = ((xsltStyleItemIncludePtr) node->psvi)->include; if (include == NULL) { /* TODO: raise error? */ return(-1); } /* * TODO: Actually an xsl:include should locate an embedded * stylesheet as well; so the document-element won't always * be the element where the actual stylesheet is rooted at. * But such embedded stylesheets are not supported by Libxslt yet. */ node = xmlDocGetRootElement(include->doc); if (node == NULL) { return(-1); } } if (node->children == NULL) return(0); /* * Push the xsl:stylesheet/xsl:transform element. */ xsltCompilerNodePush(cctxt, node); cctxt->inode->isRoot = 1; cctxt->inode->nsChanged = 0; /* * Start with the naked dummy info for literal result elements. */ cctxt->inode->litResElemInfo = cctxt->inodeList->litResElemInfo; /* * In every case, we need to have * the in-scope namespaces of the element, where the * stylesheet is rooted at, regardless if it's an XSLT * instruction or a literal result instruction (or if * this is an embedded stylesheet). */ cctxt->inode->inScopeNs = xsltCompilerBuildInScopeNsList(cctxt, node); /* * Process attributes of xsl:stylesheet/xsl:transform. * -------------------------------------------------- * Allowed are: * id = id * extension-element-prefixes = tokens * exclude-result-prefixes = tokens * version = number (mandatory) */ if (xsltParseAttrXSLTVersion(cctxt, node, XSLT_ELEMENT_CATEGORY_XSLT) == 0) { /* * Attribute "version". * XSLT 1.0: "An xsl:stylesheet element *must* have a version * attribute, indicating the version of XSLT that the * stylesheet requires". * The root element of a simplified stylesheet must also have * this attribute. */ #ifdef XSLT_REFACTORED_MANDATORY_VERSION if (isXsltElem) xsltTransformError(NULL, cctxt->style, node, "The attribute 'version' is missing.\n"); cctxt->style->errors++; #else /* OLD behaviour. */ xsltTransformError(NULL, cctxt->style, node, "xsl:version is missing: document may not be a stylesheet\n"); cctxt->style->warnings++; #endif } /* * The namespaces declared by the attributes * "extension-element-prefixes" and * "exclude-result-prefixes" are local to *this* * stylesheet tree; i.e., they are *not* visible to * other stylesheet-modules, whether imported or included. * * Attribute "extension-element-prefixes". */ cctxt->inode->extElemNs = xsltParseExtElemPrefixes(cctxt, node, NULL, XSLT_ELEMENT_CATEGORY_XSLT); /* * Attribute "exclude-result-prefixes". */ cctxt->inode->exclResultNs = xsltParseExclResultPrefixes(cctxt, node, NULL, XSLT_ELEMENT_CATEGORY_XSLT); /* * Create/reuse info for the literal result element. */ if (cctxt->inode->nsChanged) xsltLREInfoCreate(cctxt, node, 0); /* * Processed top-level elements: * ---------------------------- * xsl:variable, xsl:param (QName, in-scope ns, * expression (vars allowed)) * xsl:attribute-set (QName, in-scope ns) * xsl:strip-space, xsl:preserve-space (XPath NameTests, * in-scope ns) * I *think* global scope, merge with includes * xsl:output (QName, in-scope ns) * xsl:key (QName, in-scope ns, pattern, * expression (vars *not* allowed)) * xsl:decimal-format (QName, needs in-scope ns) * xsl:namespace-alias (in-scope ns) * global scope, merge with includes * xsl:template (last, QName, pattern) * * (whitespace-only text-nodes have *not* been removed * yet; this will be done in xsltParseSequenceConstructor) * * Report misplaced child-nodes first. */ cur = node->children; while (cur != NULL) { if (cur->type == XML_TEXT_NODE) { xsltTransformError(NULL, style, cur, "Misplaced text node (content: '%s').\n", (cur->content != NULL) ? cur->content : BAD_CAST ""); style->errors++; } else if (cur->type != XML_ELEMENT_NODE) { xsltTransformError(NULL, style, cur, "Misplaced node.\n"); style->errors++; } cur = cur->next; } /* * Skip xsl:import elements; they have been processed * already. */ cur = node->children; while ((cur != NULL) && xsltParseFindTopLevelElem(cctxt, cur, BAD_CAST "import", XSLT_NAMESPACE, 1, &cur) == 1) cur = cur->next; if (cur == NULL) goto exit; start = cur; /* * Process all top-level xsl:param elements. */ while ((cur != NULL) && xsltParseFindTopLevelElem(cctxt, cur, BAD_CAST "param", XSLT_NAMESPACE, 0, &cur) == 1) { xsltParseTopLevelXSLTElem(cctxt, cur, XSLT_FUNC_PARAM); cur = cur->next; } /* * Process all top-level xsl:variable elements. */ cur = start; while ((cur != NULL) && xsltParseFindTopLevelElem(cctxt, cur, BAD_CAST "variable", XSLT_NAMESPACE, 0, &cur) == 1) { xsltParseTopLevelXSLTElem(cctxt, cur, XSLT_FUNC_VARIABLE); cur = cur->next; } /* * Process all the rest of top-level elements. */ cur = start; while (cur != NULL) { /* * Process element nodes. */ if (cur->type == XML_ELEMENT_NODE) { if (cur->ns == NULL) { xsltTransformError(NULL, style, cur, "Unexpected top-level element in no namespace.\n"); style->errors++; cur = cur->next; continue; } /* * Process all XSLT elements. */ if (IS_XSLT_ELEM_FAST(cur)) { /* * xsl:import is only allowed at the beginning. */ if (IS_XSLT_NAME(cur, "import")) { xsltTransformError(NULL, style, cur, "Misplaced xsl:import element.\n"); style->errors++; cur = cur->next; continue; } /* * TODO: Change the return type of the parsing functions * to int. */ if (IS_XSLT_NAME(cur, "template")) { #ifdef WITH_XSLT_DEBUG_PARSING templates++; #endif /* * TODO: Is the position of xsl:template in the * tree significant? If not it would be easier to * parse them at a later stage. */ xsltParseXSLTTemplate(cctxt, cur); } else if (IS_XSLT_NAME(cur, "variable")) { /* NOP; done already */ } else if (IS_XSLT_NAME(cur, "param")) { /* NOP; done already */ } else if (IS_XSLT_NAME(cur, "include")) { if (cur->psvi != NULL) xsltParseXSLTStylesheetElemCore(cctxt, cur); else { xsltTransformError(NULL, style, cur, "Internal error: " "(xsltParseXSLTStylesheetElemCore) " "The xsl:include element was not compiled.\n"); style->errors++; } } else if (IS_XSLT_NAME(cur, "strip-space")) { /* No node info needed. */ xsltParseStylesheetStripSpace(style, cur); } else if (IS_XSLT_NAME(cur, "preserve-space")) { /* No node info needed. */ xsltParseStylesheetPreserveSpace(style, cur); } else if (IS_XSLT_NAME(cur, "output")) { /* No node-info needed. */ xsltParseStylesheetOutput(style, cur); } else if (IS_XSLT_NAME(cur, "key")) { /* TODO: node-info needed for expressions ? */ xsltParseStylesheetKey(style, cur); } else if (IS_XSLT_NAME(cur, "decimal-format")) { /* No node-info needed. */ xsltParseStylesheetDecimalFormat(style, cur); } else if (IS_XSLT_NAME(cur, "attribute-set")) { xsltParseTopLevelXSLTElem(cctxt, cur, XSLT_FUNC_ATTRSET); } else if (IS_XSLT_NAME(cur, "namespace-alias")) { /* NOP; done already */ } else { if (cctxt->inode->forwardsCompat) { /* * Forwards-compatible mode: * * XSLT-1: "if it is a top-level element and * XSLT 1.0 does not allow such elements as top-level * elements, then the element must be ignored along * with its content;" */ /* * TODO: I don't think we should generate a warning. */ xsltTransformError(NULL, style, cur, "Forwards-compatible mode: Ignoring unknown XSLT " "element '%s'.\n", cur->name); style->warnings++; } else { xsltTransformError(NULL, style, cur, "Unknown XSLT element '%s'.\n", cur->name); style->errors++; } } } else { xsltTopLevelFunction function; /* * Process non-XSLT elements, which are in a * non-NULL namespace. */ /* * QUESTION: What does xsltExtModuleTopLevelLookup() * do exactly? */ function = xsltExtModuleTopLevelLookup(cur->name, cur->ns->href); if (function != NULL) function(style, cur); #ifdef WITH_XSLT_DEBUG_PARSING xsltGenericDebug(xsltGenericDebugContext, "xsltParseXSLTStylesheetElemCore : User-defined " "data element '%s'.\n", cur->name); #endif } } cur = cur->next; } exit: #ifdef WITH_XSLT_DEBUG_PARSING xsltGenericDebug(xsltGenericDebugContext, "### END of parsing top-level elements of doc '%s'.\n", node->doc->URL); xsltGenericDebug(xsltGenericDebugContext, "### Templates: %d\n", templates); #ifdef XSLT_REFACTORED xsltGenericDebug(xsltGenericDebugContext, "### Max inodes: %d\n", cctxt->maxNodeInfos); xsltGenericDebug(xsltGenericDebugContext, "### Max LREs : %d\n", cctxt->maxLREs); #endif /* XSLT_REFACTORED */ #endif /* WITH_XSLT_DEBUG_PARSING */ xsltCompilerNodePop(cctxt, node); return(0); } /** * xsltParseXSLTStylesheet: * @cctxt: the compiler context * @node: the xsl:stylesheet/xsl:transform element-node * * Parses the xsl:stylesheet and xsl:transform element. * * * * * * BIG TODO: The xsl:include stuff. * * Called by xsltParseStylesheetTree() * * Returns 0 on success, a positive result on errors and * -1 on API or internal errors. */ static int xsltParseXSLTStylesheetElem(xsltCompilerCtxtPtr cctxt, xmlNodePtr node) { xmlNodePtr cur, start; if ((cctxt == NULL) || (node == NULL) || (node->type != XML_ELEMENT_NODE)) return(-1); if (node->children == NULL) goto exit; /* * Process top-level elements: * xsl:import (must be first) * xsl:include (this is just a pre-processing) */ cur = node->children; /* * Process xsl:import elements. * XSLT 1.0: "The xsl:import element children must precede all * other element children of an xsl:stylesheet element, * including any xsl:include element children." */ while ((cur != NULL) && xsltParseFindTopLevelElem(cctxt, cur, BAD_CAST "import", XSLT_NAMESPACE, 1, &cur) == 1) { if (xsltParseStylesheetImport(cctxt->style, cur) != 0) { cctxt->style->errors++; } cur = cur->next; } if (cur == NULL) goto exit; start = cur; /* * Pre-process all xsl:include elements. */ cur = start; while ((cur != NULL) && xsltParseFindTopLevelElem(cctxt, cur, BAD_CAST "include", XSLT_NAMESPACE, 0, &cur) == 1) { xsltParseTopLevelXSLTElem(cctxt, cur, XSLT_FUNC_INCLUDE); cur = cur->next; } /* * Pre-process all xsl:namespace-alias elements. * URGENT TODO: This won't work correctly: the order of included * aliases and aliases defined here is significant. */ cur = start; while ((cur != NULL) && xsltParseFindTopLevelElem(cctxt, cur, BAD_CAST "namespace-alias", XSLT_NAMESPACE, 0, &cur) == 1) { xsltNamespaceAlias(cctxt->style, cur); cur = cur->next; } if (cctxt->isInclude) { /* * If this stylesheet is intended for inclusion, then * we will process only imports and includes. */ goto exit; } /* * Now parse the rest of the top-level elements. */ xsltParseXSLTStylesheetElemCore(cctxt, node); exit: return(0); } #else /* XSLT_REFACTORED */ /** * xsltParseStylesheetTop: * @style: the XSLT stylesheet * @top: the top level "stylesheet" or "transform" element * * scan the top level elements of an XSL stylesheet */ static void xsltParseStylesheetTop(xsltStylesheetPtr style, xmlNodePtr top) { xmlNodePtr cur; xmlChar *prop; #ifdef WITH_XSLT_DEBUG_PARSING int templates = 0; #endif if ((top == NULL) || (top->type != XML_ELEMENT_NODE)) return; prop = xmlGetNsProp(top, (const xmlChar *)"version", NULL); if (prop == NULL) { xsltTransformError(NULL, style, top, "xsl:version is missing: document may not be a stylesheet\n"); if (style != NULL) style->warnings++; } else { if ((!xmlStrEqual(prop, (const xmlChar *)"1.0")) && (!xmlStrEqual(prop, (const xmlChar *)"1.1"))) { xsltTransformError(NULL, style, top, "xsl:version: only 1.0 features are supported\n"); if (style != NULL) { style->forwards_compatible = 1; style->warnings++; } } xmlFree(prop); } /* * process xsl:import elements */ cur = top->children; while (cur != NULL) { if (IS_BLANK_NODE(cur)) { cur = cur->next; continue; } if (IS_XSLT_ELEM(cur) && IS_XSLT_NAME(cur, "import")) { if (xsltParseStylesheetImport(style, cur) != 0) if (style != NULL) style->errors++; } else break; cur = cur->next; } /* * process other top-level elements */ while (cur != NULL) { if (IS_BLANK_NODE(cur)) { cur = cur->next; continue; } if (cur->type == XML_TEXT_NODE) { if (cur->content != NULL) { xsltTransformError(NULL, style, cur, "misplaced text node: '%s'\n", cur->content); } if (style != NULL) style->errors++; cur = cur->next; continue; } if ((cur->type == XML_ELEMENT_NODE) && (cur->ns == NULL)) { xsltGenericError(xsltGenericErrorContext, "Found a top-level element %s with null namespace URI\n", cur->name); if (style != NULL) style->errors++; cur = cur->next; continue; } if ((cur->type == XML_ELEMENT_NODE) && (!(IS_XSLT_ELEM(cur)))) { xsltTopLevelFunction function; function = xsltExtModuleTopLevelLookup(cur->name, cur->ns->href); if (function != NULL) function(style, cur); #ifdef WITH_XSLT_DEBUG_PARSING xsltGenericDebug(xsltGenericDebugContext, "xsltParseStylesheetTop : found foreign element %s\n", cur->name); #endif cur = cur->next; continue; } if (IS_XSLT_NAME(cur, "import")) { xsltTransformError(NULL, style, cur, "xsltParseStylesheetTop: ignoring misplaced import element\n"); if (style != NULL) style->errors++; } else if (IS_XSLT_NAME(cur, "include")) { if (xsltParseStylesheetInclude(style, cur) != 0) if (style != NULL) style->errors++; } else if (IS_XSLT_NAME(cur, "strip-space")) { xsltParseStylesheetStripSpace(style, cur); } else if (IS_XSLT_NAME(cur, "preserve-space")) { xsltParseStylesheetPreserveSpace(style, cur); } else if (IS_XSLT_NAME(cur, "output")) { xsltParseStylesheetOutput(style, cur); } else if (IS_XSLT_NAME(cur, "key")) { xsltParseStylesheetKey(style, cur); } else if (IS_XSLT_NAME(cur, "decimal-format")) { xsltParseStylesheetDecimalFormat(style, cur); } else if (IS_XSLT_NAME(cur, "attribute-set")) { xsltParseStylesheetAttributeSet(style, cur); } else if (IS_XSLT_NAME(cur, "variable")) { xsltParseGlobalVariable(style, cur); } else if (IS_XSLT_NAME(cur, "param")) { xsltParseGlobalParam(style, cur); } else if (IS_XSLT_NAME(cur, "template")) { #ifdef WITH_XSLT_DEBUG_PARSING templates++; #endif xsltParseStylesheetTemplate(style, cur); } else if (IS_XSLT_NAME(cur, "namespace-alias")) { xsltNamespaceAlias(style, cur); } else { if ((style != NULL) && (style->forwards_compatible == 0)) { xsltTransformError(NULL, style, cur, "xsltParseStylesheetTop: unknown %s element\n", cur->name); if (style != NULL) style->errors++; } else { /* do Forwards-Compatible Processing */ xsltTransformError(NULL, style, cur, "xsltParseStylesheetTop: ignoring unknown %s element\n", cur->name); if (style != NULL) style->warnings++; } } cur = cur->next; } #ifdef WITH_XSLT_DEBUG_PARSING xsltGenericDebug(xsltGenericDebugContext, "parsed %d templates\n", templates); #endif } #endif /* else of XSLT_REFACTORED */ #ifdef XSLT_REFACTORED /** * xsltParseSimplifiedStylesheetTree: * * @style: the stylesheet (TODO: Change this to the compiler context) * @doc: the document containing the stylesheet. * @node: the node where the stylesheet is rooted at * * Returns 0 in case of success, a positive result if an error occurred * and -1 on API and internal errors. */ static int xsltParseSimplifiedStylesheetTree(xsltCompilerCtxtPtr cctxt, xmlDocPtr doc, xmlNodePtr node) { xsltTemplatePtr templ; if ((cctxt == NULL) || (node == NULL)) return(-1); if (xsltParseAttrXSLTVersion(cctxt, node, 0) == XSLT_ELEMENT_CATEGORY_LRE) { /* * TODO: Adjust report, since this might be an * embedded stylesheet. */ xsltTransformError(NULL, cctxt->style, node, "The attribute 'xsl:version' is missing; cannot identify " "this document as an XSLT stylesheet document.\n"); cctxt->style->errors++; return(1); } #ifdef WITH_XSLT_DEBUG_PARSING xsltGenericDebug(xsltGenericDebugContext, "xsltParseSimplifiedStylesheetTree: document is stylesheet\n"); #endif /* * Create and link the template */ templ = xsltNewTemplate(); if (templ == NULL) { return(-1); } templ->next = cctxt->style->templates; cctxt->style->templates = templ; templ->match = xmlStrdup(BAD_CAST "/"); /* * Note that we push the document-node in this special case. */ xsltCompilerNodePush(cctxt, (xmlNodePtr) doc); /* * In every case, we need to have * the in-scope namespaces of the element, where the * stylesheet is rooted at, regardless if it's an XSLT * instruction or a literal result instruction (or if * this is an embedded stylesheet). */ cctxt->inode->inScopeNs = xsltCompilerBuildInScopeNsList(cctxt, node); /* * Parse the content and register the match-pattern. */ xsltParseSequenceConstructor(cctxt, node); xsltCompilerNodePop(cctxt, (xmlNodePtr) doc); templ->elem = (xmlNodePtr) doc; templ->content = node; xsltAddTemplate(cctxt->style, templ, NULL, NULL); cctxt->style->literal_result = 1; return(0); } #ifdef XSLT_REFACTORED_XSLT_NSCOMP /** * xsltRestoreDocumentNamespaces: * @ns: map of namespaces * @doc: the document * * Restore the namespaces for the document * * Returns 0 in case of success, -1 in case of failure */ int xsltRestoreDocumentNamespaces(xsltNsMapPtr ns, xmlDocPtr doc) { if (doc == NULL) return(-1); /* * Revert the changes we have applied to the namespace-URIs of * ns-decls. */ while (ns != NULL) { if ((ns->doc == doc) && (ns->ns != NULL)) { ns->ns->href = ns->origNsName; ns->origNsName = NULL; ns->ns = NULL; } ns = ns->next; } return(0); } #endif /* XSLT_REFACTORED_XSLT_NSCOMP */ /** * xsltParseStylesheetProcess: * @style: the XSLT stylesheet (the current stylesheet-level) * @doc: and xmlDoc parsed XML * * Parses an XSLT stylesheet, adding the associated structures. * Called by: * xsltParseStylesheetImportedDoc() (xslt.c) * xsltParseStylesheetInclude() (imports.c) * * Returns the value of the @style parameter if everything * went right, NULL if something went amiss. */ xsltStylesheetPtr xsltParseStylesheetProcess(xsltStylesheetPtr style, xmlDocPtr doc) { xsltCompilerCtxtPtr cctxt; xmlNodePtr cur; int oldIsSimplifiedStylesheet; xsltInitGlobals(); if ((style == NULL) || (doc == NULL)) return(NULL); cctxt = XSLT_CCTXT(style); cur = xmlDocGetRootElement(doc); if (cur == NULL) { xsltTransformError(NULL, style, (xmlNodePtr) doc, "xsltParseStylesheetProcess : empty stylesheet\n"); return(NULL); } oldIsSimplifiedStylesheet = cctxt->simplified; if ((IS_XSLT_ELEM(cur)) && ((IS_XSLT_NAME(cur, "stylesheet")) || (IS_XSLT_NAME(cur, "transform")))) { #ifdef WITH_XSLT_DEBUG_PARSING xsltGenericDebug(xsltGenericDebugContext, "xsltParseStylesheetProcess : found stylesheet\n"); #endif cctxt->simplified = 0; style->literal_result = 0; } else { cctxt->simplified = 1; style->literal_result = 1; } /* * Pre-process the stylesheet if not already done before. * This will remove PIs and comments, merge adjacent * text nodes, internalize strings, etc. */ if (! style->nopreproc) xsltParsePreprocessStylesheetTree(cctxt, cur); /* * Parse and compile the stylesheet. */ if (style->literal_result == 0) { if (xsltParseXSLTStylesheetElem(cctxt, cur) != 0) return(NULL); } else { if (xsltParseSimplifiedStylesheetTree(cctxt, doc, cur) != 0) return(NULL); } cctxt->simplified = oldIsSimplifiedStylesheet; return(style); } #else /* XSLT_REFACTORED */ /** * xsltParseStylesheetProcess: * @ret: the XSLT stylesheet (the current stylesheet-level) * @doc: and xmlDoc parsed XML * * Parses an XSLT stylesheet, adding the associated structures. * Called by: * xsltParseStylesheetImportedDoc() (xslt.c) * xsltParseStylesheetInclude() (imports.c) * * Returns the value of the @style parameter if everything * went right, NULL if something went amiss. */ xsltStylesheetPtr xsltParseStylesheetProcess(xsltStylesheetPtr ret, xmlDocPtr doc) { xmlNodePtr cur; xsltInitGlobals(); if (doc == NULL) return(NULL); if (ret == NULL) return(ret); /* * First steps, remove blank nodes, * locate the xsl:stylesheet element and the * namespace declaration. */ cur = xmlDocGetRootElement(doc); if (cur == NULL) { xsltTransformError(NULL, ret, (xmlNodePtr) doc, "xsltParseStylesheetProcess : empty stylesheet\n"); return(NULL); } if ((IS_XSLT_ELEM(cur)) && ((IS_XSLT_NAME(cur, "stylesheet")) || (IS_XSLT_NAME(cur, "transform")))) { #ifdef WITH_XSLT_DEBUG_PARSING xsltGenericDebug(xsltGenericDebugContext, "xsltParseStylesheetProcess : found stylesheet\n"); #endif ret->literal_result = 0; xsltParseStylesheetExcludePrefix(ret, cur, 1); xsltParseStylesheetExtPrefix(ret, cur, 1); } else { xsltParseStylesheetExcludePrefix(ret, cur, 0); xsltParseStylesheetExtPrefix(ret, cur, 0); ret->literal_result = 1; } if (!ret->nopreproc) { xsltPrecomputeStylesheet(ret, cur); } if (ret->literal_result == 0) { xsltParseStylesheetTop(ret, cur); } else { xmlChar *prop; xsltTemplatePtr template; /* * the document itself might be the template, check xsl:version */ prop = xmlGetNsProp(cur, (const xmlChar *)"version", XSLT_NAMESPACE); if (prop == NULL) { xsltTransformError(NULL, ret, cur, "xsltParseStylesheetProcess : document is not a stylesheet\n"); return(NULL); } #ifdef WITH_XSLT_DEBUG_PARSING xsltGenericDebug(xsltGenericDebugContext, "xsltParseStylesheetProcess : document is stylesheet\n"); #endif if (!xmlStrEqual(prop, (const xmlChar *)"1.0")) { xsltTransformError(NULL, ret, cur, "xsl:version: only 1.0 features are supported\n"); /* TODO set up compatibility when not XSLT 1.0 */ ret->warnings++; } xmlFree(prop); /* * Create and link the template */ template = xsltNewTemplate(); if (template == NULL) { return(NULL); } template->next = ret->templates; ret->templates = template; template->match = xmlStrdup((const xmlChar *)"/"); /* * parse the content and register the pattern */ xsltParseTemplateContent(ret, (xmlNodePtr) doc); template->elem = (xmlNodePtr) doc; template->content = doc->children; xsltAddTemplate(ret, template, NULL, NULL); ret->literal_result = 1; } return(ret); } #endif /* else of XSLT_REFACTORED */ /** * xsltParseStylesheetImportedDoc: * @doc: an xmlDoc parsed XML * @parentStyle: pointer to the parent stylesheet (if it exists) * * parse an XSLT stylesheet building the associated structures * except the processing not needed for imported documents. * * Returns a new XSLT stylesheet structure. */ xsltStylesheetPtr xsltParseStylesheetImportedDoc(xmlDocPtr doc, xsltStylesheetPtr parentStyle) { xsltStylesheetPtr retStyle; if (doc == NULL) return(NULL); retStyle = xsltNewStylesheet(); if (retStyle == NULL) return(NULL); /* * Set the importing stylesheet module; also used to detect recursion. */ retStyle->parent = parentStyle; /* * Adjust the string dict. */ if (doc->dict != NULL) { xmlDictFree(retStyle->dict); retStyle->dict = doc->dict; #ifdef WITH_XSLT_DEBUG xsltGenericDebug(xsltGenericDebugContext, "reusing dictionary from %s for stylesheet\n", doc->URL); #endif xmlDictReference(retStyle->dict); } /* * TODO: Eliminate xsltGatherNamespaces(); we must not restrict * the stylesheet to containt distinct namespace prefixes. */ xsltGatherNamespaces(retStyle); #ifdef XSLT_REFACTORED { xsltCompilerCtxtPtr cctxt; xsltStylesheetPtr oldCurSheet; if (parentStyle == NULL) { xsltPrincipalStylesheetDataPtr principalData; /* * Principal stylesheet * -------------------- */ retStyle->principal = retStyle; /* * Create extra data for the principal stylesheet. */ principalData = xsltNewPrincipalStylesheetData(); if (principalData == NULL) { xsltFreeStylesheet(retStyle); return(NULL); } retStyle->principalData = principalData; /* * Create the compilation context * ------------------------------ * (only once; for the principal stylesheet). * This is currently the only function where the * compilation context is created. */ cctxt = xsltCompilationCtxtCreate(retStyle); if (cctxt == NULL) { xsltFreeStylesheet(retStyle); return(NULL); } retStyle->compCtxt = (void *) cctxt; cctxt->style = retStyle; cctxt->dict = retStyle->dict; cctxt->psData = principalData; /* * Push initial dummy node info. */ cctxt->depth = -1; xsltCompilerNodePush(cctxt, (xmlNodePtr) doc); } else { /* * Imported stylesheet. */ retStyle->principal = parentStyle->principal; cctxt = parentStyle->compCtxt; retStyle->compCtxt = cctxt; } /* * Save the old and set the current stylesheet structure in the * compilation context. */ oldCurSheet = cctxt->style; cctxt->style = retStyle; retStyle->doc = doc; xsltParseStylesheetProcess(retStyle, doc); cctxt->style = oldCurSheet; if (parentStyle == NULL) { /* * Pop the initial dummy node info. */ xsltCompilerNodePop(cctxt, (xmlNodePtr) doc); } else { /* * Clear the compilation context of imported * stylesheets. * TODO: really? */ /* retStyle->compCtxt = NULL; */ } /* * Free the stylesheet if there were errors. */ if (retStyle != NULL) { if (retStyle->errors != 0) { #ifdef XSLT_REFACTORED_XSLT_NSCOMP /* * Restore all changes made to namespace URIs of ns-decls. */ if (cctxt->psData->nsMap) xsltRestoreDocumentNamespaces(cctxt->psData->nsMap, doc); #endif /* * Detach the doc from the stylesheet; otherwise the doc * will be freed in xsltFreeStylesheet(). */ retStyle->doc = NULL; /* * Cleanup the doc if its the main stylesheet. */ if (parentStyle == NULL) { xsltCleanupStylesheetTree(doc, xmlDocGetRootElement(doc)); if (retStyle->compCtxt != NULL) { xsltCompilationCtxtFree(retStyle->compCtxt); retStyle->compCtxt = NULL; } } xsltFreeStylesheet(retStyle); retStyle = NULL; } } } #else /* XSLT_REFACTORED */ /* * Old behaviour. */ retStyle->doc = doc; if (xsltParseStylesheetProcess(retStyle, doc) == NULL) { retStyle->doc = NULL; xsltFreeStylesheet(retStyle); retStyle = NULL; } if (retStyle != NULL) { if (retStyle->errors != 0) { retStyle->doc = NULL; if (parentStyle == NULL) xsltCleanupStylesheetTree(doc, xmlDocGetRootElement(doc)); xsltFreeStylesheet(retStyle); retStyle = NULL; } } #endif /* else of XSLT_REFACTORED */ return(retStyle); } /** * xsltParseStylesheetDoc: * @doc: and xmlDoc parsed XML * * parse an XSLT stylesheet, building the associated structures. doc * is kept as a reference within the returned stylesheet, so changes * to doc after the parsing will be reflected when the stylesheet * is applied, and the doc is automatically freed when the * stylesheet is closed. * * Returns a new XSLT stylesheet structure. */ xsltStylesheetPtr xsltParseStylesheetDoc(xmlDocPtr doc) { xsltStylesheetPtr ret; xsltInitGlobals(); ret = xsltParseStylesheetImportedDoc(doc, NULL); if (ret == NULL) return(NULL); xsltResolveStylesheetAttributeSet(ret); #ifdef XSLT_REFACTORED /* * Free the compilation context. * TODO: Check if it's better to move this cleanup to * xsltParseStylesheetImportedDoc(). */ if (ret->compCtxt != NULL) { xsltCompilationCtxtFree(XSLT_CCTXT(ret)); ret->compCtxt = NULL; } #endif return(ret); } /** * xsltParseStylesheetFile: * @filename: the filename/URL to the stylesheet * * Load and parse an XSLT stylesheet * * Returns a new XSLT stylesheet structure. */ xsltStylesheetPtr xsltParseStylesheetFile(const xmlChar* filename) { xsltSecurityPrefsPtr sec; xsltStylesheetPtr ret; xmlDocPtr doc; xsltInitGlobals(); if (filename == NULL) return(NULL); #ifdef WITH_XSLT_DEBUG_PARSING xsltGenericDebug(xsltGenericDebugContext, "xsltParseStylesheetFile : parse %s\n", filename); #endif /* * Security framework check */ sec = xsltGetDefaultSecurityPrefs(); if (sec != NULL) { int res; res = xsltCheckRead(sec, NULL, filename); if (res == 0) { xsltTransformError(NULL, NULL, NULL, "xsltParseStylesheetFile: read rights for %s denied\n", filename); return(NULL); } } doc = xsltDocDefaultLoader(filename, NULL, XSLT_PARSE_OPTIONS, NULL, XSLT_LOAD_START); if (doc == NULL) { xsltTransformError(NULL, NULL, NULL, "xsltParseStylesheetFile : cannot parse %s\n", filename); return(NULL); } ret = xsltParseStylesheetDoc(doc); if (ret == NULL) { xmlFreeDoc(doc); return(NULL); } return(ret); } /************************************************************************ * * * Handling of Stylesheet PI * * * ************************************************************************/ #define CUR (*cur) #define SKIP(val) cur += (val) #define NXT(val) cur[(val)] #define SKIP_BLANKS \ while (IS_BLANK(CUR)) NEXT #define NEXT ((*cur) ? cur++ : cur) /** * xsltParseStylesheetPI: * @value: the value of the PI * * This function checks that the type is text/xml and extracts * the URI-Reference for the stylesheet * * Returns the URI-Reference for the stylesheet or NULL (it need to * be freed by the caller) */ static xmlChar * xsltParseStylesheetPI(const xmlChar *value) { const xmlChar *cur; const xmlChar *start; xmlChar *val; xmlChar tmp; xmlChar *href = NULL; int isXml = 0; if (value == NULL) return(NULL); cur = value; while (CUR != 0) { SKIP_BLANKS; if ((CUR == 't') && (NXT(1) == 'y') && (NXT(2) == 'p') && (NXT(3) == 'e')) { SKIP(4); SKIP_BLANKS; if (CUR != '=') continue; NEXT; if ((CUR != '\'') && (CUR != '"')) continue; tmp = CUR; NEXT; start = cur; while ((CUR != 0) && (CUR != tmp)) NEXT; if (CUR != tmp) continue; val = xmlStrndup(start, cur - start); NEXT; if (val == NULL) return(NULL); if ((xmlStrcasecmp(val, BAD_CAST "text/xml")) && (xmlStrcasecmp(val, BAD_CAST "text/xsl"))) { xmlFree(val); break; } isXml = 1; xmlFree(val); } else if ((CUR == 'h') && (NXT(1) == 'r') && (NXT(2) == 'e') && (NXT(3) == 'f')) { SKIP(4); SKIP_BLANKS; if (CUR != '=') continue; NEXT; if ((CUR != '\'') && (CUR != '"')) continue; tmp = CUR; NEXT; start = cur; while ((CUR != 0) && (CUR != tmp)) NEXT; if (CUR != tmp) continue; if (href == NULL) href = xmlStrndup(start, cur - start); NEXT; } else { while ((CUR != 0) && (!IS_BLANK(CUR))) NEXT; } } if (!isXml) { if (href != NULL) xmlFree(href); href = NULL; } return(href); } /** * xsltLoadStylesheetPI: * @doc: a document to process * * This function tries to locate the stylesheet PI in the given document * If found, and if contained within the document, it will extract * that subtree to build the stylesheet to process @doc (doc itself will * be modified). If found but referencing an external document it will * attempt to load it and generate a stylesheet from it. In both cases, * the resulting stylesheet and the document need to be freed once the * transformation is done. * * Returns a new XSLT stylesheet structure or NULL if not found. */ xsltStylesheetPtr xsltLoadStylesheetPI(xmlDocPtr doc) { xmlNodePtr child; xsltStylesheetPtr ret = NULL; xmlChar *href = NULL; xmlURIPtr URI; xsltInitGlobals(); if (doc == NULL) return(NULL); /* * Find the text/xml stylesheet PI id any before the root */ child = doc->children; while ((child != NULL) && (child->type != XML_ELEMENT_NODE)) { if ((child->type == XML_PI_NODE) && (xmlStrEqual(child->name, BAD_CAST "xml-stylesheet"))) { href = xsltParseStylesheetPI(child->content); if (href != NULL) break; } child = child->next; } /* * If found check the href to select processing */ if (href != NULL) { #ifdef WITH_XSLT_DEBUG_PARSING xsltGenericDebug(xsltGenericDebugContext, "xsltLoadStylesheetPI : found PI href=%s\n", href); #endif URI = xmlParseURI((const char *) href); if (URI == NULL) { xsltTransformError(NULL, NULL, child, "xml-stylesheet : href %s is not valid\n", href); xmlFree(href); return(NULL); } if ((URI->fragment != NULL) && (URI->scheme == NULL) && (URI->opaque == NULL) && (URI->authority == NULL) && (URI->server == NULL) && (URI->user == NULL) && (URI->path == NULL) && (URI->query == NULL)) { xmlAttrPtr ID; #ifdef WITH_XSLT_DEBUG_PARSING xsltGenericDebug(xsltGenericDebugContext, "xsltLoadStylesheetPI : Reference to ID %s\n", href); #endif if (URI->fragment[0] == '#') ID = xmlGetID(doc, (const xmlChar *) &(URI->fragment[1])); else ID = xmlGetID(doc, (const xmlChar *) URI->fragment); if (ID == NULL) { xsltTransformError(NULL, NULL, child, "xml-stylesheet : no ID %s found\n", URI->fragment); } else { xmlDocPtr fake; xmlNodePtr subtree, newtree; xmlNsPtr ns; #ifdef WITH_XSLT_DEBUG xsltGenericDebug(xsltGenericDebugContext, "creating new document from %s for embedded stylesheet\n", doc->URL); #endif /* * move the subtree in a new document passed to * the stylesheet analyzer */ subtree = ID->parent; fake = xmlNewDoc(NULL); if (fake != NULL) { /* * Should the dictionary still be shared even though * the nodes are being copied rather than moved? */ fake->dict = doc->dict; xmlDictReference(doc->dict); #ifdef WITH_XSLT_DEBUG xsltGenericDebug(xsltGenericDebugContext, "reusing dictionary from %s for embedded stylesheet\n", doc->URL); #endif newtree = xmlDocCopyNode(subtree, fake, 1); fake->URL = xmlNodeGetBase(doc, subtree->parent); #ifdef WITH_XSLT_DEBUG xsltGenericDebug(xsltGenericDebugContext, "set base URI for embedded stylesheet as %s\n", fake->URL); #endif /* * Add all namespaces in scope of embedded stylesheet to * root element of newly created stylesheet document */ while ((subtree = subtree->parent) != (xmlNodePtr)doc) { for (ns = subtree->ns; ns; ns = ns->next) { xmlNewNs(newtree, ns->href, ns->prefix); } } xmlAddChild((xmlNodePtr)fake, newtree); ret = xsltParseStylesheetDoc(fake); if (ret == NULL) xmlFreeDoc(fake); } } } else { xmlChar *URL, *base; /* * Reference to an external stylesheet */ base = xmlNodeGetBase(doc, (xmlNodePtr) doc); URL = xmlBuildURI(href, base); if (URL != NULL) { #ifdef WITH_XSLT_DEBUG_PARSING xsltGenericDebug(xsltGenericDebugContext, "xsltLoadStylesheetPI : fetching %s\n", URL); #endif ret = xsltParseStylesheetFile(URL); xmlFree(URL); } else { #ifdef WITH_XSLT_DEBUG_PARSING xsltGenericDebug(xsltGenericDebugContext, "xsltLoadStylesheetPI : fetching %s\n", href); #endif ret = xsltParseStylesheetFile(href); } if (base != NULL) xmlFree(base); } xmlFreeURI(URI); xmlFree(href); } return(ret); } libxslt-1.1.28/libxslt/xsltutils.h0000664000076400007640000002012012024025431014110 00000000000000/* * Summary: set of utilities for the XSLT engine * Description: interfaces for the utilities module of the XSLT engine. * things like message handling, profiling, and other * generally useful routines. * * Copy: See Copyright for the status of this software. * * Author: Daniel Veillard */ #ifndef __XML_XSLTUTILS_H__ #define __XML_XSLTUTILS_H__ #include #ifdef HAVE_STDARG_H #include #endif #include #include #include #include "xsltexports.h" #include "xsltInternals.h" #ifdef __cplusplus extern "C" { #endif /** * XSLT_TODO: * * Macro to flag unimplemented blocks. */ #define XSLT_TODO \ xsltGenericError(xsltGenericErrorContext, \ "Unimplemented block at %s:%d\n", \ __FILE__, __LINE__); /** * XSLT_STRANGE: * * Macro to flag that a problem was detected internally. */ #define XSLT_STRANGE \ xsltGenericError(xsltGenericErrorContext, \ "Internal error at %s:%d\n", \ __FILE__, __LINE__); /** * IS_XSLT_ELEM: * * Checks that the element pertains to XSLT namespace. */ #define IS_XSLT_ELEM(n) \ (((n) != NULL) && ((n)->type == XML_ELEMENT_NODE) && \ ((n)->ns != NULL) && (xmlStrEqual((n)->ns->href, XSLT_NAMESPACE))) /** * IS_XSLT_NAME: * * Checks the value of an element in XSLT namespace. */ #define IS_XSLT_NAME(n, val) \ (xmlStrEqual((n)->name, (const xmlChar *) (val))) /** * IS_XSLT_REAL_NODE: * * Check that a node is a 'real' one: document, element, text or attribute. */ #define IS_XSLT_REAL_NODE(n) \ (((n) != NULL) && \ (((n)->type == XML_ELEMENT_NODE) || \ ((n)->type == XML_TEXT_NODE) || \ ((n)->type == XML_CDATA_SECTION_NODE) || \ ((n)->type == XML_ATTRIBUTE_NODE) || \ ((n)->type == XML_DOCUMENT_NODE) || \ ((n)->type == XML_HTML_DOCUMENT_NODE) || \ ((n)->type == XML_COMMENT_NODE) || \ ((n)->type == XML_PI_NODE))) /* * Our own version of namespaced atributes lookup. */ XSLTPUBFUN xmlChar * XSLTCALL xsltGetNsProp (xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace); XSLTPUBFUN const xmlChar * XSLTCALL xsltGetCNsProp (xsltStylesheetPtr style, xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace); XSLTPUBFUN int XSLTCALL xsltGetUTF8Char (const unsigned char *utf, int *len); /* * XSLT Debug Tracing Tracing Types */ typedef enum { XSLT_TRACE_ALL = -1, XSLT_TRACE_NONE = 0, XSLT_TRACE_COPY_TEXT = 1<<0, XSLT_TRACE_PROCESS_NODE = 1<<1, XSLT_TRACE_APPLY_TEMPLATE = 1<<2, XSLT_TRACE_COPY = 1<<3, XSLT_TRACE_COMMENT = 1<<4, XSLT_TRACE_PI = 1<<5, XSLT_TRACE_COPY_OF = 1<<6, XSLT_TRACE_VALUE_OF = 1<<7, XSLT_TRACE_CALL_TEMPLATE = 1<<8, XSLT_TRACE_APPLY_TEMPLATES = 1<<9, XSLT_TRACE_CHOOSE = 1<<10, XSLT_TRACE_IF = 1<<11, XSLT_TRACE_FOR_EACH = 1<<12, XSLT_TRACE_STRIP_SPACES = 1<<13, XSLT_TRACE_TEMPLATES = 1<<14, XSLT_TRACE_KEYS = 1<<15, XSLT_TRACE_VARIABLES = 1<<16 } xsltDebugTraceCodes; /** * XSLT_TRACE: * * Control the type of xsl debugtrace messages emitted. */ #define XSLT_TRACE(ctxt,code,call) \ if (ctxt->traceCode && (*(ctxt->traceCode) & code)) \ call XSLTPUBFUN void XSLTCALL xsltDebugSetDefaultTrace(xsltDebugTraceCodes val); XSLTPUBFUN xsltDebugTraceCodes XSLTCALL xsltDebugGetDefaultTrace(void); /* * XSLT specific error and debug reporting functions. */ XSLTPUBVAR xmlGenericErrorFunc xsltGenericError; XSLTPUBVAR void *xsltGenericErrorContext; XSLTPUBVAR xmlGenericErrorFunc xsltGenericDebug; XSLTPUBVAR void *xsltGenericDebugContext; XSLTPUBFUN void XSLTCALL xsltPrintErrorContext (xsltTransformContextPtr ctxt, xsltStylesheetPtr style, xmlNodePtr node); XSLTPUBFUN void XSLTCALL xsltMessage (xsltTransformContextPtr ctxt, xmlNodePtr node, xmlNodePtr inst); XSLTPUBFUN void XSLTCALL xsltSetGenericErrorFunc (void *ctx, xmlGenericErrorFunc handler); XSLTPUBFUN void XSLTCALL xsltSetGenericDebugFunc (void *ctx, xmlGenericErrorFunc handler); XSLTPUBFUN void XSLTCALL xsltSetTransformErrorFunc (xsltTransformContextPtr ctxt, void *ctx, xmlGenericErrorFunc handler); XSLTPUBFUN void XSLTCALL xsltTransformError (xsltTransformContextPtr ctxt, xsltStylesheetPtr style, xmlNodePtr node, const char *msg, ...); XSLTPUBFUN int XSLTCALL xsltSetCtxtParseOptions (xsltTransformContextPtr ctxt, int options); /* * Sorting. */ XSLTPUBFUN void XSLTCALL xsltDocumentSortFunction (xmlNodeSetPtr list); XSLTPUBFUN void XSLTCALL xsltSetSortFunc (xsltSortFunc handler); XSLTPUBFUN void XSLTCALL xsltSetCtxtSortFunc (xsltTransformContextPtr ctxt, xsltSortFunc handler); XSLTPUBFUN void XSLTCALL xsltDefaultSortFunction (xsltTransformContextPtr ctxt, xmlNodePtr *sorts, int nbsorts); XSLTPUBFUN void XSLTCALL xsltDoSortFunction (xsltTransformContextPtr ctxt, xmlNodePtr * sorts, int nbsorts); XSLTPUBFUN xmlXPathObjectPtr * XSLTCALL xsltComputeSortResult (xsltTransformContextPtr ctxt, xmlNodePtr sort); /* * QNames handling. */ XSLTPUBFUN const xmlChar * XSLTCALL xsltSplitQName (xmlDictPtr dict, const xmlChar *name, const xmlChar **prefix); XSLTPUBFUN const xmlChar * XSLTCALL xsltGetQNameURI (xmlNodePtr node, xmlChar **name); XSLTPUBFUN const xmlChar * XSLTCALL xsltGetQNameURI2 (xsltStylesheetPtr style, xmlNodePtr node, const xmlChar **name); /* * Output, reuse libxml I/O buffers. */ XSLTPUBFUN int XSLTCALL xsltSaveResultTo (xmlOutputBufferPtr buf, xmlDocPtr result, xsltStylesheetPtr style); XSLTPUBFUN int XSLTCALL xsltSaveResultToFilename (const char *URI, xmlDocPtr result, xsltStylesheetPtr style, int compression); XSLTPUBFUN int XSLTCALL xsltSaveResultToFile (FILE *file, xmlDocPtr result, xsltStylesheetPtr style); XSLTPUBFUN int XSLTCALL xsltSaveResultToFd (int fd, xmlDocPtr result, xsltStylesheetPtr style); XSLTPUBFUN int XSLTCALL xsltSaveResultToString (xmlChar **doc_txt_ptr, int * doc_txt_len, xmlDocPtr result, xsltStylesheetPtr style); /* * XPath interface */ XSLTPUBFUN xmlXPathCompExprPtr XSLTCALL xsltXPathCompile (xsltStylesheetPtr style, const xmlChar *str); XSLTPUBFUN xmlXPathCompExprPtr XSLTCALL xsltXPathCompileFlags (xsltStylesheetPtr style, const xmlChar *str, int flags); /* * Profiling. */ XSLTPUBFUN void XSLTCALL xsltSaveProfiling (xsltTransformContextPtr ctxt, FILE *output); XSLTPUBFUN xmlDocPtr XSLTCALL xsltGetProfileInformation (xsltTransformContextPtr ctxt); XSLTPUBFUN long XSLTCALL xsltTimestamp (void); XSLTPUBFUN void XSLTCALL xsltCalibrateAdjust (long delta); /** * XSLT_TIMESTAMP_TICS_PER_SEC: * * Sampling precision for profiling */ #define XSLT_TIMESTAMP_TICS_PER_SEC 100000l /* * Hooks for the debugger. */ typedef enum { XSLT_DEBUG_NONE = 0, /* no debugging allowed */ XSLT_DEBUG_INIT, XSLT_DEBUG_STEP, XSLT_DEBUG_STEPOUT, XSLT_DEBUG_NEXT, XSLT_DEBUG_STOP, XSLT_DEBUG_CONT, XSLT_DEBUG_RUN, XSLT_DEBUG_RUN_RESTART, XSLT_DEBUG_QUIT } xsltDebugStatusCodes; XSLTPUBVAR int xslDebugStatus; typedef void (*xsltHandleDebuggerCallback) (xmlNodePtr cur, xmlNodePtr node, xsltTemplatePtr templ, xsltTransformContextPtr ctxt); typedef int (*xsltAddCallCallback) (xsltTemplatePtr templ, xmlNodePtr source); typedef void (*xsltDropCallCallback) (void); XSLTPUBFUN void XSLTCALL xsltSetDebuggerStatus (int value); XSLTPUBFUN int XSLTCALL xsltGetDebuggerStatus (void); XSLTPUBFUN int XSLTCALL xsltSetDebuggerCallbacks (int no, void *block); XSLTPUBFUN int XSLTCALL xslAddCall (xsltTemplatePtr templ, xmlNodePtr source); XSLTPUBFUN void XSLTCALL xslDropCall (void); #ifdef __cplusplus } #endif #endif /* __XML_XSLTUTILS_H__ */ libxslt-1.1.28/libxslt/Makefile.in0000664000076400007640000006505612053100416013751 00000000000000# Makefile.in generated by automake 1.11.6 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software # Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__make_dryrun = \ { \ am__dry=no; \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ echo 'am--echo: ; @echo "AM" OK' | $(MAKE) -f - 2>/dev/null \ | grep '^AM OK$$' >/dev/null || am__dry=yes;; \ *) \ for am__flg in $$MAKEFLAGS; do \ case $$am__flg in \ *=*|--*) ;; \ *n*) am__dry=yes; break;; \ esac; \ done;; \ esac; \ test $$am__dry = yes; \ } pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = libxslt DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ $(srcdir)/xsltconfig.h.in $(srcdir)/xsltwin32config.h.in \ $(xsltinc_HEADERS) ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.in am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = xsltconfig.h xsltwin32config.h CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(man3dir)" \ "$(DESTDIR)$(xsltincdir)" LTLIBRARIES = $(lib_LTLIBRARIES) am__DEPENDENCIES_1 = libxslt_la_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) am_libxslt_la_OBJECTS = attrvt.lo xslt.lo xsltlocale.lo xsltutils.lo \ pattern.lo templates.lo variables.lo keys.lo numbers.lo \ extensions.lo extra.lo functions.lo namespaces.lo imports.lo \ attributes.lo documents.lo preproc.lo transform.lo security.lo libxslt_la_OBJECTS = $(am_libxslt_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent libxslt_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(libxslt_la_LDFLAGS) $(LDFLAGS) -o $@ DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; SOURCES = $(libxslt_la_SOURCES) DIST_SOURCES = $(libxslt_la_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac man3dir = $(mandir)/man3 NROFF = nroff MANS = $(man_MANS) HEADERS = $(xsltinc_HEADERS) ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ EXSLT_INCLUDEDIR = @EXSLT_INCLUDEDIR@ EXSLT_LIBDIR = @EXSLT_LIBDIR@ EXSLT_LIBS = @EXSLT_LIBS@ EXTRA_LIBS = @EXTRA_LIBS@ FGREP = @FGREP@ GREP = @GREP@ HTML_DIR = @HTML_DIR@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBEXSLT_MAJOR_VERSION = @LIBEXSLT_MAJOR_VERSION@ LIBEXSLT_MICRO_VERSION = @LIBEXSLT_MICRO_VERSION@ LIBEXSLT_MINOR_VERSION = @LIBEXSLT_MINOR_VERSION@ LIBEXSLT_VERSION = @LIBEXSLT_VERSION@ LIBEXSLT_VERSION_EXTRA = @LIBEXSLT_VERSION_EXTRA@ LIBEXSLT_VERSION_INFO = @LIBEXSLT_VERSION_INFO@ LIBEXSLT_VERSION_NUMBER = @LIBEXSLT_VERSION_NUMBER@ LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIBXML_CFLAGS = @LIBXML_CFLAGS@ LIBXML_LIBS = @LIBXML_LIBS@ LIBXML_REQUIRED_VERSION = @LIBXML_REQUIRED_VERSION@ LIBXML_SRC = @LIBXML_SRC@ LIBXSLT_DEFAULT_PLUGINS_PATH = @LIBXSLT_DEFAULT_PLUGINS_PATH@ LIBXSLT_MAJOR_MINOR_VERSION = @LIBXSLT_MAJOR_MINOR_VERSION@ LIBXSLT_MAJOR_VERSION = @LIBXSLT_MAJOR_VERSION@ LIBXSLT_MICRO_VERSION = @LIBXSLT_MICRO_VERSION@ LIBXSLT_MINOR_VERSION = @LIBXSLT_MINOR_VERSION@ LIBXSLT_VERSION = @LIBXSLT_VERSION@ LIBXSLT_VERSION_EXTRA = @LIBXSLT_VERSION_EXTRA@ LIBXSLT_VERSION_INFO = @LIBXSLT_VERSION_INFO@ LIBXSLT_VERSION_NUMBER = @LIBXSLT_VERSION_NUMBER@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MV = @MV@ M_LIBS = @M_LIBS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PERL = @PERL@ PYTHON = @PYTHON@ PYTHONSODV = @PYTHONSODV@ PYTHON_INCLUDES = @PYTHON_INCLUDES@ PYTHON_LIBS = @PYTHON_LIBS@ PYTHON_SITE_PACKAGES = @PYTHON_SITE_PACKAGES@ PYTHON_SUBDIR = @PYTHON_SUBDIR@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ RELDATE = @RELDATE@ RM = @RM@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ TAR = @TAR@ THREAD_LIBS = @THREAD_LIBS@ VERSION = @VERSION@ VERSION_SCRIPT_FLAGS = @VERSION_SCRIPT_FLAGS@ WIN32_EXTRA_LDFLAGS = @WIN32_EXTRA_LDFLAGS@ WIN32_EXTRA_LIBADD = @WIN32_EXTRA_LIBADD@ WITH_CRYPTO = @WITH_CRYPTO@ WITH_DEBUGGER = @WITH_DEBUGGER@ WITH_MEM_DEBUG = @WITH_MEM_DEBUG@ WITH_MODULES = @WITH_MODULES@ WITH_TRIO = @WITH_TRIO@ WITH_XSLT_DEBUG = @WITH_XSLT_DEBUG@ XMLLINT = @XMLLINT@ XML_CONFIG = @XML_CONFIG@ XSLTPROC = @XSLTPROC@ XSLTPROCDV = @XSLTPROCDV@ XSLT_INCLUDEDIR = @XSLT_INCLUDEDIR@ XSLT_LIBDIR = @XSLT_LIBDIR@ XSLT_LIBS = @XSLT_LIBS@ XSLT_LOCALE_WINAPI = @XSLT_LOCALE_WINAPI@ XSLT_LOCALE_XLOCALE = @XSLT_LOCALE_XLOCALE@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/libxslt AM_CFLAGS = $(LIBXML_CFLAGS) lib_LTLIBRARIES = libxslt.la xsltincdir = $(includedir)/libxslt xsltinc_HEADERS = \ xslt.h \ xsltutils.h \ pattern.h \ templates.h \ variables.h \ keys.h \ numbersInternals.h \ extensions.h \ extra.h \ functions.h \ namespaces.h \ imports.h \ attributes.h \ documents.h \ preproc.h \ transform.h \ security.h \ xsltInternals.h \ xsltconfig.h \ xsltexports.h \ xsltlocale.h libxslt_la_SOURCES = \ attrvt.c \ xslt.c \ xsltlocale.c \ xsltutils.c \ pattern.c \ templates.c \ variables.c \ keys.c \ numbers.c \ extensions.c \ extra.c \ functions.c \ namespaces.c \ imports.c \ attributes.c \ documents.c \ preproc.c \ transform.c \ security.c \ win32config.h \ xsltwin32config.h \ xsltwin32config.h.in \ libxslt.h @USE_VERSION_SCRIPT_FALSE@LIBXSLT_VERSION_SCRIPT = @USE_VERSION_SCRIPT_TRUE@LIBXSLT_VERSION_SCRIPT = $(VERSION_SCRIPT_FLAGS)$(srcdir)/libxslt.syms libxslt_la_LIBADD = $(LIBXML_LIBS) $(EXTRA_LIBS) libxslt_la_LDFLAGS = \ $(WIN32_EXTRA_LDFLAGS) \ $(LIBXSLT_VERSION_SCRIPT) \ -version-info $(LIBXSLT_VERSION_INFO) man_MANS = libxslt.3 EXTRA_DIST = $(man_MANS) trio.h triodef.h libxslt.syms all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu libxslt/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu libxslt/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): xsltconfig.h: $(top_builddir)/config.status $(srcdir)/xsltconfig.h.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ xsltwin32config.h: $(top_builddir)/config.status $(srcdir)/xsltwin32config.h.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ install-libLTLIBRARIES: $(lib_LTLIBRARIES) @$(NORMAL_INSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ } uninstall-libLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ done clean-libLTLIBRARIES: -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ test "$$dir" != "$$p" || dir=.; \ echo "rm -f \"$${dir}/so_locations\""; \ rm -f "$${dir}/so_locations"; \ done libxslt.la: $(libxslt_la_OBJECTS) $(libxslt_la_DEPENDENCIES) $(EXTRA_libxslt_la_DEPENDENCIES) $(AM_V_CCLD)$(libxslt_la_LINK) -rpath $(libdir) $(libxslt_la_OBJECTS) $(libxslt_la_LIBADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/attributes.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/attrvt.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/documents.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/extensions.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/extra.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/functions.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imports.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/keys.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/namespaces.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/numbers.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pattern.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/preproc.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/security.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/templates.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/transform.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/variables.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xslt.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xsltlocale.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xsltutils.Plo@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-man3: $(man_MANS) @$(NORMAL_INSTALL) @list1=''; \ list2='$(man_MANS)'; \ test -n "$(man3dir)" \ && test -n "`echo $$list1$$list2`" \ || exit 0; \ echo " $(MKDIR_P) '$(DESTDIR)$(man3dir)'"; \ $(MKDIR_P) "$(DESTDIR)$(man3dir)" || exit 1; \ { for i in $$list1; do echo "$$i"; done; \ if test -n "$$list2"; then \ for i in $$list2; do echo "$$i"; done \ | sed -n '/\.3[a-z]*$$/p'; \ fi; \ } | while read p; do \ if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; echo "$$p"; \ done | \ sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^3][0-9a-z]*$$,3,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \ sed 'N;N;s,\n, ,g' | { \ list=; while read file base inst; do \ if test "$$base" = "$$inst"; then list="$$list $$file"; else \ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man3dir)/$$inst'"; \ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man3dir)/$$inst" || exit $$?; \ fi; \ done; \ for i in $$list; do echo "$$i"; done | $(am__base_list) | \ while read files; do \ test -z "$$files" || { \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man3dir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(man3dir)" || exit $$?; }; \ done; } uninstall-man3: @$(NORMAL_UNINSTALL) @list=''; test -n "$(man3dir)" || exit 0; \ files=`{ for i in $$list; do echo "$$i"; done; \ l2='$(man_MANS)'; for i in $$l2; do echo "$$i"; done | \ sed -n '/\.3[a-z]*$$/p'; \ } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^3][0-9a-z]*$$,3,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \ dir='$(DESTDIR)$(man3dir)'; $(am__uninstall_files_from_dir) install-xsltincHEADERS: $(xsltinc_HEADERS) @$(NORMAL_INSTALL) @list='$(xsltinc_HEADERS)'; test -n "$(xsltincdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(xsltincdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(xsltincdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(xsltincdir)'"; \ $(INSTALL_HEADER) $$files "$(DESTDIR)$(xsltincdir)" || exit $$?; \ done uninstall-xsltincHEADERS: @$(NORMAL_UNINSTALL) @list='$(xsltinc_HEADERS)'; test -n "$(xsltincdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(xsltincdir)'; $(am__uninstall_files_from_dir) ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) set x; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: CTAGS CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @list='$(MANS)'; if test -n "$$list"; then \ list=`for p in $$list; do \ if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ if test -f "$$d$$p"; then echo "$$d$$p"; else :; fi; done`; \ if test -n "$$list" && \ grep 'ab help2man is required to generate this page' $$list >/dev/null; then \ echo "error: found man pages containing the \`missing help2man' replacement text:" >&2; \ grep -l 'ab help2man is required to generate this page' $$list | sed 's/^/ /' >&2; \ echo " to fix them, install help2man, remove and regenerate the man pages;" >&2; \ echo " typically \`make maintainer-clean' will remove them" >&2; \ exit 1; \ else :; fi; \ else :; fi @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(LTLIBRARIES) $(MANS) $(HEADERS) installdirs: for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(man3dir)" "$(DESTDIR)$(xsltincdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \ mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-man install-xsltincHEADERS install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-libLTLIBRARIES @$(NORMAL_INSTALL) $(MAKE) $(AM_MAKEFLAGS) install-exec-hook install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-man3 install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-libLTLIBRARIES uninstall-man \ uninstall-xsltincHEADERS uninstall-man: uninstall-man3 .MAKE: install-am install-exec-am install-strip .PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ clean-libLTLIBRARIES clean-libtool ctags distclean \ distclean-compile distclean-generic distclean-libtool \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-exec-hook \ install-html install-html-am install-info install-info-am \ install-libLTLIBRARIES install-man install-man3 install-pdf \ install-pdf-am install-ps install-ps-am install-strip \ install-xsltincHEADERS installcheck installcheck-am \ installdirs maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf pdf-am ps ps-am tags uninstall \ uninstall-am uninstall-libLTLIBRARIES uninstall-man \ uninstall-man3 uninstall-xsltincHEADERS xsltproc: all @(cd ../xsltproc ; $(MAKE)) install-exec-hook: $(MKDIR_P) "$(DESTDIR)$(libdir)/libxslt-plugins" # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: libxslt-1.1.28/libxslt/xsltwin32config.h0000664000076400007640000000410412053100424015102 00000000000000/* * Summary: compile-time version informations for the XSLT engine * when compiled on windows * Description: compile-time version informations for the XSLT engine * when compiled on windows. This file is generated. * * Copy: See Copyright for the status of this software. * * Author: Daniel Veillard */ #ifndef __XML_XSLTWIN32CONFIG_H__ #define __XML_XSLTWIN32CONFIG_H__ #include "win32config.h" #ifdef __cplusplus extern "C" { #endif /** * LIBXSLT_DOTTED_VERSION: * * the version string like "1.2.3" */ #define LIBXSLT_DOTTED_VERSION "1.1.28" /** * LIBXSLT_VERSION: * * the version number: 1.2.3 value is 1002003 */ #define LIBXSLT_VERSION 10128 /** * LIBXSLT_VERSION_STRING: * * the version number string, 1.2.3 value is "1002003" */ #define LIBXSLT_VERSION_STRING "10128" /** * LIBXSLT_VERSION_EXTRA: * * extra version information, used to show a CVS compilation */ #define LIBXSLT_VERSION_EXTRA "-win32" /** * WITH_XSLT_DEBUG: * * Activate the compilation of the debug reporting. Speed penalty * is insignifiant and being able to run xsltpoc -v is useful. On * by default */ #if 1 #define WITH_XSLT_DEBUG #endif /** * WITH_MODULES: * * Whether module support is configured into libxslt */ #if 1 #ifndef WITH_MODULES #define WITH_MODULES #endif #define LIBXSLT_PLUGINS_PATH() getenv("LIBXSLT_PLUGINS_PATH") #endif #if 0 /** * DEBUG_MEMORY: * * should be activated only when debugging libxslt. It replaces the * allocator with a collect and debug shell to the libc allocator. * Use configure --with-mem-debug to activate it on both library */ #define DEBUG_MEMORY /** * DEBUG_MEMORY_LOCATION: * * should be activated only when debugging libxslt. * DEBUG_MEMORY_LOCATION should be activated only when libxml has * been configured with --with-debug-mem too */ #define DEBUG_MEMORY_LOCATION #endif /** * ATTRIBUTE_UNUSED: * * This macro is used to flag unused function parameters to GCC, useless here */ #ifndef ATTRIBUTE_UNUSED #define ATTRIBUTE_UNUSED #endif #ifdef __cplusplus } #endif #endif /* __XML_XSLTWIN32CONFIG_H__ */ libxslt-1.1.28/libxslt/namespaces.c0000664000076400007640000005665612024022316014175 00000000000000/* * namespaces.c: Implementation of the XSLT namespaces handling * * Reference: * http://www.w3.org/TR/1999/REC-xslt-19991116 * * See Copyright for the status of this software. * * daniel@veillard.com */ #define IN_LIBXSLT #include "libxslt.h" #include #ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_MATH_H #include #endif #ifdef HAVE_FLOAT_H #include #endif #ifdef HAVE_IEEEFP_H #include #endif #ifdef HAVE_NAN_H #include #endif #ifdef HAVE_CTYPE_H #include #endif #ifndef XSLT_NEED_TRIO #include #else #include #endif #include #include #include #include #include #include "xslt.h" #include "xsltInternals.h" #include "xsltutils.h" #include "namespaces.h" #include "imports.h" /************************************************************************ * * * Module interfaces * * * ************************************************************************/ #ifdef XSLT_REFACTORED static xsltNsAliasPtr xsltNewNsAlias(xsltCompilerCtxtPtr cctxt) { xsltNsAliasPtr ret; if (cctxt == NULL) return(NULL); ret = (xsltNsAliasPtr) xmlMalloc(sizeof(xsltNsAlias)); if (ret == NULL) { xsltTransformError(NULL, cctxt->style, NULL, "Internal error in xsltNewNsAlias(): Memory allocation failed.\n"); cctxt->style->errors++; return(NULL); } memset(ret, 0, sizeof(xsltNsAlias)); /* * TODO: Store the item at current stylesheet-level. */ ret->next = cctxt->nsAliases; cctxt->nsAliases = ret; return(ret); } #endif /* XSLT_REFACTORED */ /** * xsltNamespaceAlias: * @style: the XSLT stylesheet * @node: the xsl:namespace-alias node * * Read the stylesheet-prefix and result-prefix attributes, register * them as well as the corresponding namespace. */ void xsltNamespaceAlias(xsltStylesheetPtr style, xmlNodePtr node) { xmlChar *resultPrefix = NULL; xmlChar *stylePrefix = NULL; xmlNsPtr literalNs = NULL; xmlNsPtr targetNs = NULL; #ifdef XSLT_REFACTORED xsltNsAliasPtr alias; if ((style == NULL) || (node == NULL)) return; /* * SPEC XSLT 1.0: * "If a namespace URI is declared to be an alias for multiple * different namespace URIs, then the declaration with the highest * import precedence is used. It is an error if there is more than * one such declaration. An XSLT processor may signal the error; * if it does not signal the error, it must recover by choosing, * from amongst the declarations with the highest import precedence, * the one that occurs last in the stylesheet." * * SPEC TODO: Check for the errors mentioned above. */ /* * NOTE that the XSLT 2.0 also *does* use the NULL namespace if * "#default" is used and there's no default namespace is scope. * I.e., this is *not* an error. * Most XSLT 1.0 implementations work this way. * The XSLT 1.0 spec has nothing to say on the subject. */ /* * Attribute "stylesheet-prefix". */ stylePrefix = xmlGetNsProp(node, (const xmlChar *)"stylesheet-prefix", NULL); if (stylePrefix == NULL) { xsltTransformError(NULL, style, node, "The attribute 'stylesheet-prefix' is missing.\n"); return; } if (xmlStrEqual(stylePrefix, (const xmlChar *)"#default")) literalNs = xmlSearchNs(node->doc, node, NULL); else { literalNs = xmlSearchNs(node->doc, node, stylePrefix); if (literalNs == NULL) { xsltTransformError(NULL, style, node, "Attribute 'stylesheet-prefix': There's no namespace " "declaration in scope for the prefix '%s'.\n", stylePrefix); goto error; } } /* * Attribute "result-prefix". */ resultPrefix = xmlGetNsProp(node, (const xmlChar *)"result-prefix", NULL); if (resultPrefix == NULL) { xsltTransformError(NULL, style, node, "The attribute 'result-prefix' is missing.\n"); goto error; } if (xmlStrEqual(resultPrefix, (const xmlChar *)"#default")) targetNs = xmlSearchNs(node->doc, node, NULL); else { targetNs = xmlSearchNs(node->doc, node, resultPrefix); if (targetNs == NULL) { xsltTransformError(NULL, style, node, "Attribute 'result-prefix': There's no namespace " "declaration in scope for the prefix '%s'.\n", stylePrefix); goto error; } } /* * * Same alias for multiple different target namespace URIs: * TODO: The one with the highest import precedence is used. * Example: * * * * * Same target namespace URI for multiple different aliases: * All alias-definitions will be used. * Example: * * * * Cases using #default: * * TODO: Has this an effect at all? * * * From namespace to no namespace. * * * From no namespace to namespace. */ /* * Store the ns-node in the alias-object. */ alias = xsltNewNsAlias(XSLT_CCTXT(style)); if (alias == NULL) return; alias->literalNs = literalNs; alias->targetNs = targetNs; XSLT_CCTXT(style)->hasNsAliases = 1; #else /* XSLT_REFACTORED */ const xmlChar *literalNsName; const xmlChar *targetNsName; if ((style == NULL) || (node == NULL)) return; stylePrefix = xmlGetNsProp(node, (const xmlChar *)"stylesheet-prefix", NULL); if (stylePrefix == NULL) { xsltTransformError(NULL, style, node, "namespace-alias: stylesheet-prefix attribute missing\n"); return; } resultPrefix = xmlGetNsProp(node, (const xmlChar *)"result-prefix", NULL); if (resultPrefix == NULL) { xsltTransformError(NULL, style, node, "namespace-alias: result-prefix attribute missing\n"); goto error; } if (xmlStrEqual(stylePrefix, (const xmlChar *)"#default")) { literalNs = xmlSearchNs(node->doc, node, NULL); if (literalNs == NULL) { literalNsName = NULL; } else literalNsName = literalNs->href; /* Yes - set for nsAlias table */ } else { literalNs = xmlSearchNs(node->doc, node, stylePrefix); if ((literalNs == NULL) || (literalNs->href == NULL)) { xsltTransformError(NULL, style, node, "namespace-alias: prefix %s not bound to any namespace\n", stylePrefix); goto error; } else literalNsName = literalNs->href; } /* * When "#default" is used for result, if a default namespace has not * been explicitly declared the special value UNDEFINED_DEFAULT_NS is * put into the nsAliases table */ if (xmlStrEqual(resultPrefix, (const xmlChar *)"#default")) { targetNs = xmlSearchNs(node->doc, node, NULL); if (targetNs == NULL) { targetNsName = UNDEFINED_DEFAULT_NS; } else targetNsName = targetNs->href; } else { targetNs = xmlSearchNs(node->doc, node, resultPrefix); if ((targetNs == NULL) || (targetNs->href == NULL)) { xsltTransformError(NULL, style, node, "namespace-alias: prefix %s not bound to any namespace\n", resultPrefix); goto error; } else targetNsName = targetNs->href; } /* * Special case: if #default is used for * the stylesheet-prefix (literal namespace) and there's no default * namespace in scope, we'll use style->defaultAlias for this. */ if (literalNsName == NULL) { if (targetNs != NULL) { /* * BUG TODO: Is it not sufficient to have only 1 field for * this, since subsequently alias declarations will * overwrite this. * Example: * * * The mapping for "foo" won't be visible anymore. */ style->defaultAlias = targetNs->href; } } else { if (style->nsAliases == NULL) style->nsAliases = xmlHashCreate(10); if (style->nsAliases == NULL) { xsltTransformError(NULL, style, node, "namespace-alias: cannot create hash table\n"); goto error; } xmlHashAddEntry((xmlHashTablePtr) style->nsAliases, literalNsName, (void *) targetNsName); } #endif /* else of XSLT_REFACTORED */ error: if (stylePrefix != NULL) xmlFree(stylePrefix); if (resultPrefix != NULL) xmlFree(resultPrefix); } /** * xsltGetSpecialNamespace: * @ctxt: the transformation context * @invocNode: the invoking node; e.g. a literal result element/attr; * only used for error reports * @nsName: the namespace name (or NULL) * @nsPrefix: the suggested namespace prefix (or NULL) * @target: the result element on which to anchor a namespace * * Find a matching (prefix and ns-name) ns-declaration * for the requested @nsName and @nsPrefix in the result tree. * If none is found then a new ns-declaration will be * added to @resultElem. If, in this case, the given prefix is * already in use, then a ns-declaration with a modified ns-prefix * be we created. Note that this function's priority is to * preserve ns-prefixes; it will only change a prefix if there's * a namespace clash. * If both @nsName and @nsPrefix are NULL, then this will try to * "undeclare" a default namespace by declaring an xmlns="". * * Returns a namespace declaration or NULL. */ xmlNsPtr xsltGetSpecialNamespace(xsltTransformContextPtr ctxt, xmlNodePtr invocNode, const xmlChar *nsName, const xmlChar *nsPrefix, xmlNodePtr target) { xmlNsPtr ns; int prefixOccupied = 0; if ((ctxt == NULL) || (target == NULL) || (target->type != XML_ELEMENT_NODE)) return(NULL); /* * NOTE: Namespace exclusion and ns-aliasing is performed at * compilation-time in the refactored code; so this need not be done * here (it was in the old code). * NOTE: @invocNode was named @cur in the old code and was documented to * be an input node; since it was only used to anchor an error report * somewhere, we can safely change this to @invocNode, which now * will be the XSLT instruction (also a literal result element/attribute), * which was responsible for this call. */ /* * OPTIMIZE TODO: This all could be optimized by keeping track of * the ns-decls currently in-scope via a specialized context. */ if ((nsPrefix == NULL) && ((nsName == NULL) || (nsName[0] == 0))) { /* * NOTE: the "undeclaration" of the default namespace was * part of the logic of the old xsltGetSpecialNamespace() code, * so we'll keep that mechanism. * Related to the old code: bug #302020: */ /* * OPTIMIZE TODO: This all could be optimized by keeping track of * the ns-decls currently in-scope via a specialized context. */ /* * Search on the result element itself. */ if (target->nsDef != NULL) { ns = target->nsDef; do { if (ns->prefix == NULL) { if ((ns->href != NULL) && (ns->href[0] != 0)) { /* * Raise a namespace normalization error. */ xsltTransformError(ctxt, NULL, invocNode, "Namespace normalization error: Cannot undeclare " "the default namespace, since the default namespace " "'%s' is already declared on the result element " "'%s'.\n", ns->href, target->name); return(NULL); } else { /* * The default namespace was undeclared on the * result element. */ return(NULL); } break; } ns = ns->next; } while (ns != NULL); } if ((target->parent != NULL) && (target->parent->type == XML_ELEMENT_NODE)) { /* * The parent element is in no namespace, so assume * that there is no default namespace in scope. */ if (target->parent->ns == NULL) return(NULL); ns = xmlSearchNs(target->doc, target->parent, NULL); /* * Fine if there's no default ns is scope, or if the * default ns was undeclared. */ if ((ns == NULL) || (ns->href == NULL) || (ns->href[0] == 0)) return(NULL); /* * Undeclare the default namespace. */ xmlNewNs(target, BAD_CAST "", NULL); /* TODO: Check result */ return(NULL); } return(NULL); } /* * Handle the XML namespace. * QUESTION: Is this faster than using xmlStrEqual() anyway? */ if ((nsPrefix != NULL) && (nsPrefix[0] == 'x') && (nsPrefix[1] == 'm') && (nsPrefix[2] == 'l') && (nsPrefix[3] == 0)) { return(xmlSearchNs(target->doc, target, nsPrefix)); } /* * First: search on the result element itself. */ if (target->nsDef != NULL) { ns = target->nsDef; do { if ((ns->prefix == NULL) == (nsPrefix == NULL)) { if (ns->prefix == nsPrefix) { if (xmlStrEqual(ns->href, nsName)) return(ns); prefixOccupied = 1; break; } else if (xmlStrEqual(ns->prefix, nsPrefix)) { if (xmlStrEqual(ns->href, nsName)) return(ns); prefixOccupied = 1; break; } } ns = ns->next; } while (ns != NULL); } if (prefixOccupied) { /* * If the ns-prefix is occupied by an other ns-decl on the * result element, then this means: * 1) The desired prefix is shadowed * 2) There's no way around changing the prefix * * Try a desperate search for an in-scope ns-decl * with a matching ns-name before we use the last option, * which is to recreate the ns-decl with a modified prefix. */ ns = xmlSearchNsByHref(target->doc, target, nsName); if (ns != NULL) return(ns); /* * Fallback to changing the prefix. */ } else if ((target->parent != NULL) && (target->parent->type == XML_ELEMENT_NODE)) { /* * Try to find a matching ns-decl in the ancestor-axis. * * Check the common case: The parent element of the current * result element is in the same namespace (with an equal ns-prefix). */ if ((target->parent->ns != NULL) && ((target->parent->ns->prefix != NULL) == (nsPrefix != NULL))) { ns = target->parent->ns; if (nsPrefix == NULL) { if (xmlStrEqual(ns->href, nsName)) return(ns); } else if (xmlStrEqual(ns->prefix, nsPrefix) && xmlStrEqual(ns->href, nsName)) { return(ns); } } /* * Lookup the remaining in-scope namespaces. */ ns = xmlSearchNs(target->doc, target->parent, nsPrefix); if (ns != NULL) { if (xmlStrEqual(ns->href, nsName)) return(ns); /* * Now check for a nasty case: We need to ensure that the new * ns-decl won't shadow a prefix in-use by an existing attribute. * * * * val-b * * */ if (target->properties) { xmlAttrPtr attr = target->properties; do { if ((attr->ns) && xmlStrEqual(attr->ns->prefix, nsPrefix)) { /* * Bad, this prefix is already in use. * Since we'll change the prefix anyway, try * a search for a matching ns-decl based on the * namespace name. */ ns = xmlSearchNsByHref(target->doc, target, nsName); if (ns != NULL) return(ns); goto declare_new_prefix; } attr = attr->next; } while (attr != NULL); } } else { /* * Either no matching ns-prefix was found or the namespace is * shadowed. * Create a new ns-decl on the current result element. * * Hmm, we could also try to reuse an in-scope * namespace with a matching ns-name but a different * ns-prefix. * What has higher priority? * 1) If keeping the prefix: create a new ns-decl. * 2) If reusal: first lookup ns-names; then fallback * to creation of a new ns-decl. * REVISIT: this currently uses case 1) although * the old way was use xmlSearchNsByHref() and to let change * the prefix. */ #if 0 ns = xmlSearchNsByHref(target->doc, target, nsName); if (ns != NULL) return(ns); #endif } /* * Create the ns-decl on the current result element. */ ns = xmlNewNs(target, nsName, nsPrefix); /* TODO: check errors */ return(ns); } else { /* * This is either the root of the tree or something weird is going on. */ ns = xmlNewNs(target, nsName, nsPrefix); /* TODO: Check result */ return(ns); } declare_new_prefix: /* * Fallback: we need to generate a new prefix and declare the namespace * on the result element. */ { xmlChar pref[30]; int counter = 1; if (nsPrefix == NULL) { nsPrefix = BAD_CAST "ns"; } do { snprintf((char *) pref, 30, "%s_%d", nsPrefix, counter++); ns = xmlSearchNs(target->doc, target, BAD_CAST pref); if (counter > 1000) { xsltTransformError(ctxt, NULL, invocNode, "Internal error in xsltAcquireResultInScopeNs(): " "Failed to compute a unique ns-prefix for the " "generated element"); return(NULL); } } while (ns != NULL); ns = xmlNewNs(target, nsName, BAD_CAST pref); /* TODO: Check result */ return(ns); } return(NULL); } /** * xsltGetNamespace: * @ctxt: a transformation context * @cur: the input node * @ns: the namespace * @out: the output node (or its parent) * * Find a matching (prefix and ns-name) ns-declaration * for the requested @ns->prefix and @ns->href in the result tree. * If none is found then a new ns-declaration will be * added to @resultElem. If, in this case, the given prefix is * already in use, then a ns-declaration with a modified ns-prefix * be we created. * * Called by: * - xsltCopyPropList() (*not* anymore) * - xsltShallowCopyElement() * - xsltCopyTreeInternal() (*not* anymore) * - xsltApplySequenceConstructor() (*not* in the refactored code), * - xsltElement() (*not* anymore) * * Returns a namespace declaration or NULL in case of * namespace fixup failures or API or internal errors. */ xmlNsPtr xsltGetNamespace(xsltTransformContextPtr ctxt, xmlNodePtr cur, xmlNsPtr ns, xmlNodePtr out) { if (ns == NULL) return(NULL); #ifdef XSLT_REFACTORED /* * Namespace exclusion and ns-aliasing is performed at * compilation-time in the refactored code. * Additionally, aliasing is not intended for non Literal * Result Elements. */ return(xsltGetSpecialNamespace(ctxt, cur, ns->href, ns->prefix, out)); #else { xsltStylesheetPtr style; const xmlChar *URI = NULL; /* the replacement URI */ if ((ctxt == NULL) || (cur == NULL) || (out == NULL)) return(NULL); style = ctxt->style; while (style != NULL) { if (style->nsAliases != NULL) URI = (const xmlChar *) xmlHashLookup(style->nsAliases, ns->href); if (URI != NULL) break; style = xsltNextImport(style); } if (URI == UNDEFINED_DEFAULT_NS) { return(xsltGetSpecialNamespace(ctxt, cur, NULL, NULL, out)); #if 0 /* * TODO: Removed, since wrong. If there was no default * namespace in the stylesheet then this must resolve to * the NULL namespace. */ xmlNsPtr dflt; dflt = xmlSearchNs(cur->doc, cur, NULL); if (dflt != NULL) URI = dflt->href; else return NULL; #endif } else if (URI == NULL) URI = ns->href; return(xsltGetSpecialNamespace(ctxt, cur, URI, ns->prefix, out)); } #endif } /** * xsltGetPlainNamespace: * @ctxt: a transformation context * @cur: the input node * @ns: the namespace * @out: the result element * * Obsolete. * *Not* called by any Libxslt/Libexslt function. * Exaclty the same as xsltGetNamespace(). * * Returns a namespace declaration or NULL in case of * namespace fixup failures or API or internal errors. */ xmlNsPtr xsltGetPlainNamespace(xsltTransformContextPtr ctxt, xmlNodePtr cur, xmlNsPtr ns, xmlNodePtr out) { return(xsltGetNamespace(ctxt, cur, ns, out)); } /** * xsltCopyNamespaceList: * @ctxt: a transformation context * @node: the target node * @cur: the first namespace * * Do a copy of an namespace list. If @node is non-NULL the * new namespaces are added automatically. This handles namespaces * aliases. * This function is intended only for *internal* use at * transformation-time for copying ns-declarations of Literal * Result Elements. * * Called by: * xsltCopyTreeInternal() (transform.c) * xsltShallowCopyElem() (transform.c) * * REVISIT: This function won't be used in the refactored code. * * Returns: a new xmlNsPtr, or NULL in case of error. */ xmlNsPtr xsltCopyNamespaceList(xsltTransformContextPtr ctxt, xmlNodePtr node, xmlNsPtr cur) { xmlNsPtr ret = NULL, tmp; xmlNsPtr p = NULL,q; if (cur == NULL) return(NULL); if (cur->type != XML_NAMESPACE_DECL) return(NULL); /* * One can add namespaces only on element nodes */ if ((node != NULL) && (node->type != XML_ELEMENT_NODE)) node = NULL; while (cur != NULL) { if (cur->type != XML_NAMESPACE_DECL) break; /* * Avoid duplicating namespace declarations in the tree if * a matching declaration is in scope. */ if (node != NULL) { if ((node->ns != NULL) && (xmlStrEqual(node->ns->prefix, cur->prefix)) && (xmlStrEqual(node->ns->href, cur->href))) { cur = cur->next; continue; } tmp = xmlSearchNs(node->doc, node, cur->prefix); if ((tmp != NULL) && (xmlStrEqual(tmp->href, cur->href))) { cur = cur->next; continue; } } #ifdef XSLT_REFACTORED /* * Namespace exclusion and ns-aliasing is performed at * compilation-time in the refactored code. */ q = xmlNewNs(node, cur->href, cur->prefix); if (p == NULL) { ret = p = q; } else { p->next = q; p = q; } #else /* * TODO: Remove this if the refactored code gets enabled. */ if (!xmlStrEqual(cur->href, XSLT_NAMESPACE)) { const xmlChar *URI; /* TODO apply cascading */ URI = (const xmlChar *) xmlHashLookup(ctxt->style->nsAliases, cur->href); if (URI == UNDEFINED_DEFAULT_NS) continue; if (URI != NULL) { q = xmlNewNs(node, URI, cur->prefix); } else { q = xmlNewNs(node, cur->href, cur->prefix); } if (p == NULL) { ret = p = q; } else { p->next = q; p = q; } } #endif cur = cur->next; } return(ret); } /** * xsltCopyNamespace: * @ctxt: a transformation context * @elem: the target element node * @ns: the namespace node * * Copies a namespace node (declaration). If @elem is not NULL, * then the new namespace will be declared on @elem. * * Returns: a new xmlNsPtr, or NULL in case of an error. */ xmlNsPtr xsltCopyNamespace(xsltTransformContextPtr ctxt ATTRIBUTE_UNUSED, xmlNodePtr elem, xmlNsPtr ns) { if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL)) return(NULL); /* * One can add namespaces only on element nodes */ if ((elem != NULL) && (elem->type != XML_ELEMENT_NODE)) return(xmlNewNs(NULL, ns->href, ns->prefix)); else return(xmlNewNs(elem, ns->href, ns->prefix)); } /** * xsltFreeNamespaceAliasHashes: * @style: an XSLT stylesheet * * Free up the memory used by namespaces aliases */ void xsltFreeNamespaceAliasHashes(xsltStylesheetPtr style) { if (style->nsAliases != NULL) xmlHashFree((xmlHashTablePtr) style->nsAliases, NULL); style->nsAliases = NULL; } libxslt-1.1.28/libxslt/attributes.h0000664000076400007640000000164212024022316014232 00000000000000/* * Summary: interface for the XSLT attribute handling * Description: this module handles the specificities of attribute * and attribute groups processing. * * Copy: See Copyright for the status of this software. * * Author: Daniel Veillard */ #ifndef __XML_XSLT_ATTRIBUTES_H__ #define __XML_XSLT_ATTRIBUTES_H__ #include #include "xsltexports.h" #ifdef __cplusplus extern "C" { #endif XSLTPUBFUN void XSLTCALL xsltParseStylesheetAttributeSet (xsltStylesheetPtr style, xmlNodePtr cur); XSLTPUBFUN void XSLTCALL xsltFreeAttributeSetsHashes (xsltStylesheetPtr style); XSLTPUBFUN void XSLTCALL xsltApplyAttributeSet (xsltTransformContextPtr ctxt, xmlNodePtr node, xmlNodePtr inst, const xmlChar *attributes); XSLTPUBFUN void XSLTCALL xsltResolveStylesheetAttributeSet(xsltStylesheetPtr style); #ifdef __cplusplus } #endif #endif /* __XML_XSLT_ATTRIBUTES_H__ */ libxslt-1.1.28/libxslt/preproc.c0000664000076400007640000020335312024022316013514 00000000000000/* * preproc.c: Preprocessing of style operations * * References: * http://www.w3.org/TR/1999/REC-xslt-19991116 * * Michael Kay "XSLT Programmer's Reference" pp 637-643 * Writing Multiple Output Files * * XSLT-1.1 Working Draft * http://www.w3.org/TR/xslt11#multiple-output * * See Copyright for the status of this software. * * daniel@veillard.com */ #define IN_LIBXSLT #include "libxslt.h" #include #include #include #include #include #include #include #include #include #include "xslt.h" #include "xsltutils.h" #include "xsltInternals.h" #include "transform.h" #include "templates.h" #include "variables.h" #include "numbersInternals.h" #include "preproc.h" #include "extra.h" #include "imports.h" #include "extensions.h" #include "pattern.h" #ifdef WITH_XSLT_DEBUG #define WITH_XSLT_DEBUG_PREPROC #endif const xmlChar *xsltExtMarker = (const xmlChar *) "Extension Element"; /************************************************************************ * * * Grammar checks * * * ************************************************************************/ #ifdef XSLT_REFACTORED /* * Grammar checks are now performed in xslt.c. */ #else /** * xsltCheckTopLevelElement: * @style: the XSLT stylesheet * @inst: the XSLT instruction * @err: raise an error or not * * Check that the instruction is instanciated as a top level element. * * Returns -1 in case of error, 0 if failed and 1 in case of success */ static int xsltCheckTopLevelElement(xsltStylesheetPtr style, xmlNodePtr inst, int err) { xmlNodePtr parent; if ((style == NULL) || (inst == NULL) || (inst->ns == NULL)) return(-1); parent = inst->parent; if (parent == NULL) { if (err) { xsltTransformError(NULL, style, inst, "internal problem: element has no parent\n"); style->errors++; } return(0); } if ((parent->ns == NULL) || (parent->type != XML_ELEMENT_NODE) || ((parent->ns != inst->ns) && (!xmlStrEqual(parent->ns->href, inst->ns->href))) || ((!xmlStrEqual(parent->name, BAD_CAST "stylesheet")) && (!xmlStrEqual(parent->name, BAD_CAST "transform")))) { if (err) { xsltTransformError(NULL, style, inst, "element %s only allowed as child of stylesheet\n", inst->name); style->errors++; } return(0); } return(1); } /** * xsltCheckInstructionElement: * @style: the XSLT stylesheet * @inst: the XSLT instruction * * Check that the instruction is instanciated as an instruction element. */ static void xsltCheckInstructionElement(xsltStylesheetPtr style, xmlNodePtr inst) { xmlNodePtr parent; int has_ext; if ((style == NULL) || (inst == NULL) || (inst->ns == NULL) || (style->literal_result)) return; has_ext = (style->extInfos != NULL); parent = inst->parent; if (parent == NULL) { xsltTransformError(NULL, style, inst, "internal problem: element has no parent\n"); style->errors++; return; } while ((parent != NULL) && (parent->type != XML_DOCUMENT_NODE)) { if (((parent->ns == inst->ns) || ((parent->ns != NULL) && (xmlStrEqual(parent->ns->href, inst->ns->href)))) && ((xmlStrEqual(parent->name, BAD_CAST "template")) || (xmlStrEqual(parent->name, BAD_CAST "param")) || (xmlStrEqual(parent->name, BAD_CAST "attribute")) || (xmlStrEqual(parent->name, BAD_CAST "variable")))) { return; } /* * if we are within an extension element all bets are off * about the semantic there e.g. xsl:param within func:function */ if ((has_ext) && (parent->ns != NULL) && (xmlHashLookup(style->extInfos, parent->ns->href) != NULL)) return; parent = parent->parent; } xsltTransformError(NULL, style, inst, "element %s only allowed within a template, variable or param\n", inst->name); style->errors++; } /** * xsltCheckParentElement: * @style: the XSLT stylesheet * @inst: the XSLT instruction * @allow1: allowed parent1 * @allow2: allowed parent2 * * Check that the instruction is instanciated as the childre of one of the * possible parents. */ static void xsltCheckParentElement(xsltStylesheetPtr style, xmlNodePtr inst, const xmlChar *allow1, const xmlChar *allow2) { xmlNodePtr parent; if ((style == NULL) || (inst == NULL) || (inst->ns == NULL) || (style->literal_result)) return; parent = inst->parent; if (parent == NULL) { xsltTransformError(NULL, style, inst, "internal problem: element has no parent\n"); style->errors++; return; } if (((parent->ns == inst->ns) || ((parent->ns != NULL) && (xmlStrEqual(parent->ns->href, inst->ns->href)))) && ((xmlStrEqual(parent->name, allow1)) || (xmlStrEqual(parent->name, allow2)))) { return; } if (style->extInfos != NULL) { while ((parent != NULL) && (parent->type != XML_DOCUMENT_NODE)) { /* * if we are within an extension element all bets are off * about the semantic there e.g. xsl:param within func:function */ if ((parent->ns != NULL) && (xmlHashLookup(style->extInfos, parent->ns->href) != NULL)) return; parent = parent->parent; } } xsltTransformError(NULL, style, inst, "element %s is not allowed within that context\n", inst->name); style->errors++; } #endif /************************************************************************ * * * handling of precomputed data * * * ************************************************************************/ /** * xsltNewStylePreComp: * @style: the XSLT stylesheet * @type: the construct type * * Create a new XSLT Style precomputed block * * Returns the newly allocated specialized structure * or NULL in case of error */ static xsltStylePreCompPtr xsltNewStylePreComp(xsltStylesheetPtr style, xsltStyleType type) { xsltStylePreCompPtr cur; #ifdef XSLT_REFACTORED size_t size; #endif if (style == NULL) return(NULL); #ifdef XSLT_REFACTORED /* * URGENT TODO: Use specialized factory functions in order * to avoid this ugliness. */ switch (type) { case XSLT_FUNC_COPY: size = sizeof(xsltStyleItemCopy); break; case XSLT_FUNC_SORT: size = sizeof(xsltStyleItemSort); break; case XSLT_FUNC_TEXT: size = sizeof(xsltStyleItemText); break; case XSLT_FUNC_ELEMENT: size = sizeof(xsltStyleItemElement); break; case XSLT_FUNC_ATTRIBUTE: size = sizeof(xsltStyleItemAttribute); break; case XSLT_FUNC_COMMENT: size = sizeof(xsltStyleItemComment); break; case XSLT_FUNC_PI: size = sizeof(xsltStyleItemPI); break; case XSLT_FUNC_COPYOF: size = sizeof(xsltStyleItemCopyOf); break; case XSLT_FUNC_VALUEOF: size = sizeof(xsltStyleItemValueOf); break;; case XSLT_FUNC_NUMBER: size = sizeof(xsltStyleItemNumber); break; case XSLT_FUNC_APPLYIMPORTS: size = sizeof(xsltStyleItemApplyImports); break; case XSLT_FUNC_CALLTEMPLATE: size = sizeof(xsltStyleItemCallTemplate); break; case XSLT_FUNC_APPLYTEMPLATES: size = sizeof(xsltStyleItemApplyTemplates); break; case XSLT_FUNC_CHOOSE: size = sizeof(xsltStyleItemChoose); break; case XSLT_FUNC_IF: size = sizeof(xsltStyleItemIf); break; case XSLT_FUNC_FOREACH: size = sizeof(xsltStyleItemForEach); break; case XSLT_FUNC_DOCUMENT: size = sizeof(xsltStyleItemDocument); break; case XSLT_FUNC_WITHPARAM: size = sizeof(xsltStyleItemWithParam); break; case XSLT_FUNC_PARAM: size = sizeof(xsltStyleItemParam); break; case XSLT_FUNC_VARIABLE: size = sizeof(xsltStyleItemVariable); break; case XSLT_FUNC_WHEN: size = sizeof(xsltStyleItemWhen); break; case XSLT_FUNC_OTHERWISE: size = sizeof(xsltStyleItemOtherwise); break; default: xsltTransformError(NULL, style, NULL, "xsltNewStylePreComp : invalid type %d\n", type); style->errors++; return(NULL); } /* * Create the structure. */ cur = (xsltStylePreCompPtr) xmlMalloc(size); if (cur == NULL) { xsltTransformError(NULL, style, NULL, "xsltNewStylePreComp : malloc failed\n"); style->errors++; return(NULL); } memset(cur, 0, size); #else /* XSLT_REFACTORED */ /* * Old behaviour. */ cur = (xsltStylePreCompPtr) xmlMalloc(sizeof(xsltStylePreComp)); if (cur == NULL) { xsltTransformError(NULL, style, NULL, "xsltNewStylePreComp : malloc failed\n"); style->errors++; return(NULL); } memset(cur, 0, sizeof(xsltStylePreComp)); #endif /* XSLT_REFACTORED */ /* * URGENT TODO: Better to move this to spezialized factory functions. */ cur->type = type; switch (cur->type) { case XSLT_FUNC_COPY: cur->func = (xsltTransformFunction) xsltCopy;break; case XSLT_FUNC_SORT: cur->func = (xsltTransformFunction) xsltSort;break; case XSLT_FUNC_TEXT: cur->func = (xsltTransformFunction) xsltText;break; case XSLT_FUNC_ELEMENT: cur->func = (xsltTransformFunction) xsltElement;break; case XSLT_FUNC_ATTRIBUTE: cur->func = (xsltTransformFunction) xsltAttribute;break; case XSLT_FUNC_COMMENT: cur->func = (xsltTransformFunction) xsltComment;break; case XSLT_FUNC_PI: cur->func = (xsltTransformFunction) xsltProcessingInstruction; break; case XSLT_FUNC_COPYOF: cur->func = (xsltTransformFunction) xsltCopyOf;break; case XSLT_FUNC_VALUEOF: cur->func = (xsltTransformFunction) xsltValueOf;break; case XSLT_FUNC_NUMBER: cur->func = (xsltTransformFunction) xsltNumber;break; case XSLT_FUNC_APPLYIMPORTS: cur->func = (xsltTransformFunction) xsltApplyImports;break; case XSLT_FUNC_CALLTEMPLATE: cur->func = (xsltTransformFunction) xsltCallTemplate;break; case XSLT_FUNC_APPLYTEMPLATES: cur->func = (xsltTransformFunction) xsltApplyTemplates;break; case XSLT_FUNC_CHOOSE: cur->func = (xsltTransformFunction) xsltChoose;break; case XSLT_FUNC_IF: cur->func = (xsltTransformFunction) xsltIf;break; case XSLT_FUNC_FOREACH: cur->func = (xsltTransformFunction) xsltForEach;break; case XSLT_FUNC_DOCUMENT: cur->func = (xsltTransformFunction) xsltDocumentElem;break; case XSLT_FUNC_WITHPARAM: case XSLT_FUNC_PARAM: case XSLT_FUNC_VARIABLE: case XSLT_FUNC_WHEN: break; default: if (cur->func == NULL) { xsltTransformError(NULL, style, NULL, "xsltNewStylePreComp : no function for type %d\n", type); style->errors++; } } cur->next = style->preComps; style->preComps = (xsltElemPreCompPtr) cur; return(cur); } /** * xsltFreeStylePreComp: * @comp: an XSLT Style precomputed block * * Free up the memory allocated by @comp */ static void xsltFreeStylePreComp(xsltStylePreCompPtr comp) { if (comp == NULL) return; #ifdef XSLT_REFACTORED /* * URGENT TODO: Implement destructors. */ switch (comp->type) { case XSLT_FUNC_LITERAL_RESULT_ELEMENT: break; case XSLT_FUNC_COPY: break; case XSLT_FUNC_SORT: { xsltStyleItemSortPtr item = (xsltStyleItemSortPtr) comp; if (item->locale != (xsltLocale)0) xsltFreeLocale(item->locale); if (item->comp != NULL) xmlXPathFreeCompExpr(item->comp); } break; case XSLT_FUNC_TEXT: break; case XSLT_FUNC_ELEMENT: break; case XSLT_FUNC_ATTRIBUTE: break; case XSLT_FUNC_COMMENT: break; case XSLT_FUNC_PI: break; case XSLT_FUNC_COPYOF: { xsltStyleItemCopyOfPtr item = (xsltStyleItemCopyOfPtr) comp; if (item->comp != NULL) xmlXPathFreeCompExpr(item->comp); } break; case XSLT_FUNC_VALUEOF: { xsltStyleItemValueOfPtr item = (xsltStyleItemValueOfPtr) comp; if (item->comp != NULL) xmlXPathFreeCompExpr(item->comp); } break; case XSLT_FUNC_NUMBER: { xsltStyleItemNumberPtr item = (xsltStyleItemNumberPtr) comp; if (item->numdata.countPat != NULL) xsltFreeCompMatchList(item->numdata.countPat); if (item->numdata.fromPat != NULL) xsltFreeCompMatchList(item->numdata.fromPat); } break; case XSLT_FUNC_APPLYIMPORTS: break; case XSLT_FUNC_CALLTEMPLATE: break; case XSLT_FUNC_APPLYTEMPLATES: { xsltStyleItemApplyTemplatesPtr item = (xsltStyleItemApplyTemplatesPtr) comp; if (item->comp != NULL) xmlXPathFreeCompExpr(item->comp); } break; case XSLT_FUNC_CHOOSE: break; case XSLT_FUNC_IF: { xsltStyleItemIfPtr item = (xsltStyleItemIfPtr) comp; if (item->comp != NULL) xmlXPathFreeCompExpr(item->comp); } break; case XSLT_FUNC_FOREACH: { xsltStyleItemForEachPtr item = (xsltStyleItemForEachPtr) comp; if (item->comp != NULL) xmlXPathFreeCompExpr(item->comp); } break; case XSLT_FUNC_DOCUMENT: break; case XSLT_FUNC_WITHPARAM: { xsltStyleItemWithParamPtr item = (xsltStyleItemWithParamPtr) comp; if (item->comp != NULL) xmlXPathFreeCompExpr(item->comp); } break; case XSLT_FUNC_PARAM: { xsltStyleItemParamPtr item = (xsltStyleItemParamPtr) comp; if (item->comp != NULL) xmlXPathFreeCompExpr(item->comp); } break; case XSLT_FUNC_VARIABLE: { xsltStyleItemVariablePtr item = (xsltStyleItemVariablePtr) comp; if (item->comp != NULL) xmlXPathFreeCompExpr(item->comp); } break; case XSLT_FUNC_WHEN: { xsltStyleItemWhenPtr item = (xsltStyleItemWhenPtr) comp; if (item->comp != NULL) xmlXPathFreeCompExpr(item->comp); } break; case XSLT_FUNC_OTHERWISE: case XSLT_FUNC_FALLBACK: case XSLT_FUNC_MESSAGE: case XSLT_FUNC_INCLUDE: case XSLT_FUNC_ATTRSET: break; default: /* TODO: Raise error. */ break; } #else if (comp->locale != (xsltLocale)0) xsltFreeLocale(comp->locale); if (comp->comp != NULL) xmlXPathFreeCompExpr(comp->comp); if (comp->numdata.countPat != NULL) xsltFreeCompMatchList(comp->numdata.countPat); if (comp->numdata.fromPat != NULL) xsltFreeCompMatchList(comp->numdata.fromPat); if (comp->nsList != NULL) xmlFree(comp->nsList); #endif xmlFree(comp); } /************************************************************************ * * * XSLT-1.1 extensions * * * ************************************************************************/ /** * xsltDocumentComp: * @style: the XSLT stylesheet * @inst: the instruction in the stylesheet * @function: unused * * Pre process an XSLT-1.1 document element * * Returns a precompiled data structure for the element */ xsltElemPreCompPtr xsltDocumentComp(xsltStylesheetPtr style, xmlNodePtr inst, xsltTransformFunction function ATTRIBUTE_UNUSED) { #ifdef XSLT_REFACTORED xsltStyleItemDocumentPtr comp; #else xsltStylePreCompPtr comp; #endif const xmlChar *filename = NULL; /* * As of 2006-03-30, this function is currently defined in Libxslt * to be used for: * (in libxslt/extra.c) * "output" in XSLT_SAXON_NAMESPACE * "write" XSLT_XALAN_NAMESPACE * "document" XSLT_XT_NAMESPACE * "document" XSLT_NAMESPACE (from the abandoned old working * draft of XSLT 1.1) * (in libexslt/common.c) * "document" in EXSLT_COMMON_NAMESPACE */ #ifdef XSLT_REFACTORED comp = (xsltStyleItemDocumentPtr) xsltNewStylePreComp(style, XSLT_FUNC_DOCUMENT); #else comp = xsltNewStylePreComp(style, XSLT_FUNC_DOCUMENT); #endif if (comp == NULL) return (NULL); comp->inst = inst; comp->ver11 = 0; if (xmlStrEqual(inst->name, (const xmlChar *) "output")) { #ifdef WITH_XSLT_DEBUG_EXTRA xsltGenericDebug(xsltGenericDebugContext, "Found saxon:output extension\n"); #endif /* * The element "output" is in the namespace XSLT_SAXON_NAMESPACE * (http://icl.com/saxon) * The @file is in no namespace; it is an AVT. * (http://www.computerwizards.com/saxon/doc/extensions.html#saxon:output) * * TODO: Do we need not to check the namespace here? */ filename = xsltEvalStaticAttrValueTemplate(style, inst, (const xmlChar *)"file", NULL, &comp->has_filename); } else if (xmlStrEqual(inst->name, (const xmlChar *) "write")) { #ifdef WITH_XSLT_DEBUG_EXTRA xsltGenericDebug(xsltGenericDebugContext, "Found xalan:write extension\n"); #endif /* the filename need to be interpreted */ /* * TODO: Is "filename need to be interpreted" meant to be a todo? * Where will be the filename of xalan:write be processed? * * TODO: Do we need not to check the namespace here? * The extension ns is "http://xml.apache.org/xalan/redirect". * See http://xml.apache.org/xalan-j/extensionslib.html. */ } else if (xmlStrEqual(inst->name, (const xmlChar *) "document")) { if (inst->ns != NULL) { if (xmlStrEqual(inst->ns->href, XSLT_NAMESPACE)) { /* * Mark the instruction as being of * XSLT version 1.1 (abandoned). */ comp->ver11 = 1; #ifdef WITH_XSLT_DEBUG_EXTRA xsltGenericDebug(xsltGenericDebugContext, "Found xslt11:document construct\n"); #endif } else { if (xmlStrEqual(inst->ns->href, (const xmlChar *)"http://exslt.org/common")) { /* EXSLT. */ #ifdef WITH_XSLT_DEBUG_EXTRA xsltGenericDebug(xsltGenericDebugContext, "Found exslt:document extension\n"); #endif } else if (xmlStrEqual(inst->ns->href, XSLT_XT_NAMESPACE)) { /* James Clark's XT. */ #ifdef WITH_XSLT_DEBUG_EXTRA xsltGenericDebug(xsltGenericDebugContext, "Found xt:document extension\n"); #endif } } } /* * The element "document" is used in conjunction with the * following namespaces: * * 1) XSLT_NAMESPACE (http://www.w3.org/1999/XSL/Transform version 1.1) * * * TODO: is @href is an AVT? * * In all cases @href is in no namespace. */ filename = xsltEvalStaticAttrValueTemplate(style, inst, (const xmlChar *)"href", NULL, &comp->has_filename); } if (!comp->has_filename) { goto error; } comp->filename = filename; error: return ((xsltElemPreCompPtr) comp); } /************************************************************************ * * * Most of the XSLT-1.0 transformations * * * ************************************************************************/ /** * xsltSortComp: * @style: the XSLT stylesheet * @inst: the xslt sort node * * Process the xslt sort node on the source node */ static void xsltSortComp(xsltStylesheetPtr style, xmlNodePtr inst) { #ifdef XSLT_REFACTORED xsltStyleItemSortPtr comp; #else xsltStylePreCompPtr comp; #endif if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE)) return; #ifdef XSLT_REFACTORED comp = (xsltStyleItemSortPtr) xsltNewStylePreComp(style, XSLT_FUNC_SORT); #else comp = xsltNewStylePreComp(style, XSLT_FUNC_SORT); #endif if (comp == NULL) return; inst->psvi = comp; comp->inst = inst; comp->stype = xsltEvalStaticAttrValueTemplate(style, inst, (const xmlChar *)"data-type", NULL, &comp->has_stype); if (comp->stype != NULL) { if (xmlStrEqual(comp->stype, (const xmlChar *) "text")) comp->number = 0; else if (xmlStrEqual(comp->stype, (const xmlChar *) "number")) comp->number = 1; else { xsltTransformError(NULL, style, inst, "xsltSortComp: no support for data-type = %s\n", comp->stype); comp->number = 0; /* use default */ if (style != NULL) style->warnings++; } } comp->order = xsltEvalStaticAttrValueTemplate(style, inst, (const xmlChar *)"order", NULL, &comp->has_order); if (comp->order != NULL) { if (xmlStrEqual(comp->order, (const xmlChar *) "ascending")) comp->descending = 0; else if (xmlStrEqual(comp->order, (const xmlChar *) "descending")) comp->descending = 1; else { xsltTransformError(NULL, style, inst, "xsltSortComp: invalid value %s for order\n", comp->order); comp->descending = 0; /* use default */ if (style != NULL) style->warnings++; } } comp->case_order = xsltEvalStaticAttrValueTemplate(style, inst, (const xmlChar *)"case-order", NULL, &comp->has_use); if (comp->case_order != NULL) { if (xmlStrEqual(comp->case_order, (const xmlChar *) "upper-first")) comp->lower_first = 0; else if (xmlStrEqual(comp->case_order, (const xmlChar *) "lower-first")) comp->lower_first = 1; else { xsltTransformError(NULL, style, inst, "xsltSortComp: invalid value %s for order\n", comp->order); comp->lower_first = 0; /* use default */ if (style != NULL) style->warnings++; } } 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) { /* * The default value of the select attribute is ., which will * cause the string-value of the current node to be used as * the sort key. */ comp->select = xmlDictLookup(style->dict, BAD_CAST ".", 1); } comp->comp = xsltXPathCompile(style, comp->select); if (comp->comp == NULL) { xsltTransformError(NULL, style, inst, "xsltSortComp: could not compile select expression '%s'\n", comp->select); if (style != NULL) style->errors++; } if (inst->children != NULL) { xsltTransformError(NULL, style, inst, "xsl:sort : is not empty\n"); if (style != NULL) style->errors++; } } /** * xsltCopyComp: * @style: the XSLT stylesheet * @inst: the xslt copy node * * Process the xslt copy node on the source node */ static void xsltCopyComp(xsltStylesheetPtr style, xmlNodePtr inst) { #ifdef XSLT_REFACTORED xsltStyleItemCopyPtr comp; #else xsltStylePreCompPtr comp; #endif if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE)) return; #ifdef XSLT_REFACTORED comp = (xsltStyleItemCopyPtr) xsltNewStylePreComp(style, XSLT_FUNC_COPY); #else comp = xsltNewStylePreComp(style, XSLT_FUNC_COPY); #endif if (comp == NULL) return; inst->psvi = comp; comp->inst = inst; comp->use = xsltGetCNsProp(style, inst, (const xmlChar *)"use-attribute-sets", XSLT_NAMESPACE); if (comp->use == NULL) comp->has_use = 0; else comp->has_use = 1; } #ifdef XSLT_REFACTORED /* Enable if ever needed for xsl:text. */ #else /** * xsltTextComp: * @style: an XSLT compiled stylesheet * @inst: the xslt text node * * TODO: This function is obsolete, since xsl:text won't * be compiled, but removed from the tree. * * Process the xslt text node on the source node */ static void xsltTextComp(xsltStylesheetPtr style, xmlNodePtr inst) { #ifdef XSLT_REFACTORED xsltStyleItemTextPtr comp; #else xsltStylePreCompPtr comp; #endif const xmlChar *prop; if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE)) return; #ifdef XSLT_REFACTORED comp = (xsltStyleItemTextPtr) xsltNewStylePreComp(style, XSLT_FUNC_TEXT); #else comp = xsltNewStylePreComp(style, XSLT_FUNC_TEXT); #endif if (comp == NULL) return; inst->psvi = comp; comp->inst = inst; comp->noescape = 0; prop = xsltGetCNsProp(style, inst, (const xmlChar *)"disable-output-escaping", XSLT_NAMESPACE); if (prop != NULL) { if (xmlStrEqual(prop, (const xmlChar *)"yes")) { comp->noescape = 1; } else if (!xmlStrEqual(prop, (const xmlChar *)"no")){ xsltTransformError(NULL, style, inst, "xsl:text: disable-output-escaping allows only yes or no\n"); if (style != NULL) style->warnings++; } } } #endif /* else of XSLT_REFACTORED */ /** * xsltElementComp: * @style: an XSLT compiled stylesheet * @inst: the xslt element node * * Process the xslt element node on the source node */ static void xsltElementComp(xsltStylesheetPtr style, xmlNodePtr inst) { #ifdef XSLT_REFACTORED xsltStyleItemElementPtr comp; #else xsltStylePreCompPtr comp; #endif /* * * * */ if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE)) return; #ifdef XSLT_REFACTORED comp = (xsltStyleItemElementPtr) xsltNewStylePreComp(style, XSLT_FUNC_ELEMENT); #else comp = xsltNewStylePreComp(style, XSLT_FUNC_ELEMENT); #endif if (comp == NULL) return; inst->psvi = comp; comp->inst = inst; /* * Attribute "name". */ /* * TODO: Precompile the AVT. See bug #344894. */ comp->name = xsltEvalStaticAttrValueTemplate(style, inst, (const xmlChar *)"name", NULL, &comp->has_name); if (! comp->has_name) { xsltTransformError(NULL, style, inst, "xsl:element: The attribute 'name' is missing.\n"); style->errors++; goto error; } /* * Attribute "namespace". */ /* * TODO: Precompile the AVT. See bug #344894. */ comp->ns = xsltEvalStaticAttrValueTemplate(style, inst, (const xmlChar *)"namespace", NULL, &comp->has_ns); if (comp->name != NULL) { if (xmlValidateQName(comp->name, 0)) { xsltTransformError(NULL, style, inst, "xsl:element: The value '%s' of the attribute 'name' is " "not a valid QName.\n", comp->name); style->errors++; } else { const xmlChar *prefix = NULL, *name; name = xsltSplitQName(style->dict, comp->name, &prefix); if (comp->has_ns == 0) { xmlNsPtr ns; /* * SPEC XSLT 1.0: * "If the namespace attribute is not present, then the QName is * expanded into an expanded-name using the namespace declarations * in effect for the xsl:element element, including any default * namespace declaration. */ ns = xmlSearchNs(inst->doc, inst, prefix); if (ns != NULL) { comp->ns = xmlDictLookup(style->dict, ns->href, -1); comp->has_ns = 1; #ifdef XSLT_REFACTORED comp->nsPrefix = prefix; comp->name = name; #endif } else if (prefix != NULL) { xsltTransformError(NULL, style, inst, "xsl:element: The prefixed QName '%s' " "has no namespace binding in scope in the " "stylesheet; this is an error, since the namespace was " "not specified by the instruction itself.\n", comp->name); style->errors++; } } if ((prefix != NULL) && (!xmlStrncasecmp(prefix, (xmlChar *)"xml", 3))) { /* * Mark is to be skipped. */ comp->has_name = 0; } } } /* * Attribute "use-attribute-sets", */ comp->use = xsltEvalStaticAttrValueTemplate(style, inst, (const xmlChar *)"use-attribute-sets", NULL, &comp->has_use); error: return; } /** * xsltAttributeComp: * @style: an XSLT compiled stylesheet * @inst: the xslt attribute node * * Process the xslt attribute node on the source node */ static void xsltAttributeComp(xsltStylesheetPtr style, xmlNodePtr inst) { #ifdef XSLT_REFACTORED xsltStyleItemAttributePtr comp; #else xsltStylePreCompPtr comp; #endif /* * * * */ if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE)) return; #ifdef XSLT_REFACTORED comp = (xsltStyleItemAttributePtr) xsltNewStylePreComp(style, XSLT_FUNC_ATTRIBUTE); #else comp = xsltNewStylePreComp(style, XSLT_FUNC_ATTRIBUTE); #endif if (comp == NULL) return; inst->psvi = comp; comp->inst = inst; /* * Attribute "name". */ /* * TODO: Precompile the AVT. See bug #344894. */ comp->name = xsltEvalStaticAttrValueTemplate(style, inst, (const xmlChar *)"name", NULL, &comp->has_name); if (! comp->has_name) { xsltTransformError(NULL, style, inst, "XSLT-attribute: The attribute 'name' is missing.\n"); style->errors++; return; } /* * Attribute "namespace". */ /* * TODO: Precompile the AVT. See bug #344894. */ comp->ns = xsltEvalStaticAttrValueTemplate(style, inst, (const xmlChar *)"namespace", NULL, &comp->has_ns); if (comp->name != NULL) { if (xmlValidateQName(comp->name, 0)) { xsltTransformError(NULL, style, inst, "xsl:attribute: The value '%s' of the attribute 'name' is " "not a valid QName.\n", comp->name); style->errors++; } else if (xmlStrEqual(comp->name, BAD_CAST "xmlns")) { xsltTransformError(NULL, style, inst, "xsl:attribute: The attribute name 'xmlns' is not allowed.\n"); style->errors++; } else { const xmlChar *prefix = NULL, *name; name = xsltSplitQName(style->dict, comp->name, &prefix); if (prefix != NULL) { if (comp->has_ns == 0) { xmlNsPtr ns; /* * SPEC XSLT 1.0: * "If the namespace attribute is not present, then the * QName is expanded into an expanded-name using the * namespace declarations in effect for the xsl:element * element, including any default namespace declaration. */ ns = xmlSearchNs(inst->doc, inst, prefix); if (ns != NULL) { comp->ns = xmlDictLookup(style->dict, ns->href, -1); comp->has_ns = 1; #ifdef XSLT_REFACTORED comp->nsPrefix = prefix; comp->name = name; #endif } else { xsltTransformError(NULL, style, inst, "xsl:attribute: The prefixed QName '%s' " "has no namespace binding in scope in the " "stylesheet; this is an error, since the " "namespace was not specified by the instruction " "itself.\n", comp->name); style->errors++; } } } } } } /** * xsltCommentComp: * @style: an XSLT compiled stylesheet * @inst: the xslt comment node * * Process the xslt comment node on the source node */ static void xsltCommentComp(xsltStylesheetPtr style, xmlNodePtr inst) { #ifdef XSLT_REFACTORED xsltStyleItemCommentPtr comp; #else xsltStylePreCompPtr comp; #endif if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE)) return; #ifdef XSLT_REFACTORED comp = (xsltStyleItemCommentPtr) xsltNewStylePreComp(style, XSLT_FUNC_COMMENT); #else comp = xsltNewStylePreComp(style, XSLT_FUNC_COMMENT); #endif if (comp == NULL) return; inst->psvi = comp; comp->inst = inst; } /** * xsltProcessingInstructionComp: * @style: an XSLT compiled stylesheet * @inst: the xslt processing-instruction node * * Process the xslt processing-instruction node on the source node */ static void xsltProcessingInstructionComp(xsltStylesheetPtr style, xmlNodePtr inst) { #ifdef XSLT_REFACTORED xsltStyleItemPIPtr comp; #else xsltStylePreCompPtr comp; #endif if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE)) return; #ifdef XSLT_REFACTORED comp = (xsltStyleItemPIPtr) xsltNewStylePreComp(style, XSLT_FUNC_PI); #else comp = xsltNewStylePreComp(style, XSLT_FUNC_PI); #endif if (comp == NULL) return; inst->psvi = comp; comp->inst = inst; comp->name = xsltEvalStaticAttrValueTemplate(style, inst, (const xmlChar *)"name", XSLT_NAMESPACE, &comp->has_name); } /** * xsltCopyOfComp: * @style: an XSLT compiled stylesheet * @inst: the xslt copy-of node * * Process the xslt copy-of node on the source node */ static void xsltCopyOfComp(xsltStylesheetPtr style, xmlNodePtr inst) { #ifdef XSLT_REFACTORED xsltStyleItemCopyOfPtr comp; #else xsltStylePreCompPtr comp; #endif if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE)) return; #ifdef XSLT_REFACTORED comp = (xsltStyleItemCopyOfPtr) xsltNewStylePreComp(style, XSLT_FUNC_COPYOF); #else comp = xsltNewStylePreComp(style, XSLT_FUNC_COPYOF); #endif if (comp == NULL) return; inst->psvi = comp; comp->inst = inst; comp->select = xsltGetCNsProp(style, inst, (const xmlChar *)"select", XSLT_NAMESPACE); if (comp->select == NULL) { xsltTransformError(NULL, style, inst, "xsl:copy-of : select is missing\n"); if (style != NULL) style->errors++; return; } comp->comp = xsltXPathCompile(style, comp->select); if (comp->comp == NULL) { xsltTransformError(NULL, style, inst, "xsl:copy-of : could not compile select expression '%s'\n", comp->select); if (style != NULL) style->errors++; } } /** * xsltValueOfComp: * @style: an XSLT compiled stylesheet * @inst: the xslt value-of node * * Process the xslt value-of node on the source node */ static void xsltValueOfComp(xsltStylesheetPtr style, xmlNodePtr inst) { #ifdef XSLT_REFACTORED xsltStyleItemValueOfPtr comp; #else xsltStylePreCompPtr comp; #endif const xmlChar *prop; if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE)) return; #ifdef XSLT_REFACTORED comp = (xsltStyleItemValueOfPtr) xsltNewStylePreComp(style, XSLT_FUNC_VALUEOF); #else comp = xsltNewStylePreComp(style, XSLT_FUNC_VALUEOF); #endif if (comp == NULL) return; inst->psvi = comp; comp->inst = inst; prop = xsltGetCNsProp(style, inst, (const xmlChar *)"disable-output-escaping", XSLT_NAMESPACE); if (prop != NULL) { if (xmlStrEqual(prop, (const xmlChar *)"yes")) { comp->noescape = 1; } else if (!xmlStrEqual(prop, (const xmlChar *)"no")){ xsltTransformError(NULL, style, inst, "xsl:value-of : disable-output-escaping allows only yes or no\n"); if (style != NULL) style->warnings++; } } comp->select = xsltGetCNsProp(style, inst, (const xmlChar *)"select", XSLT_NAMESPACE); if (comp->select == NULL) { xsltTransformError(NULL, style, inst, "xsl:value-of : select is missing\n"); if (style != NULL) style->errors++; return; } comp->comp = xsltXPathCompile(style, comp->select); if (comp->comp == NULL) { xsltTransformError(NULL, style, inst, "xsl:value-of : could not compile select expression '%s'\n", comp->select); if (style != NULL) style->errors++; } } static void xsltGetQNameProperty(xsltStylesheetPtr style, xmlNodePtr inst, const xmlChar *propName, int mandatory, int *hasProp, const xmlChar **nsName, const xmlChar** localName) { const xmlChar *prop; if (nsName) *nsName = NULL; if (localName) *localName = NULL; if (hasProp) *hasProp = 0; prop = xsltGetCNsProp(style, inst, propName, XSLT_NAMESPACE); if (prop == NULL) { if (mandatory) { xsltTransformError(NULL, style, inst, "The attribute '%s' is missing.\n", propName); style->errors++; return; } } else { const xmlChar *URI; if (xmlValidateQName(prop, 0)) { xsltTransformError(NULL, style, inst, "The value '%s' of the attribute " "'%s' is not a valid QName.\n", prop, propName); style->errors++; return; } else { /* * @prop will be in the string dict afterwards, @URI not. */ URI = xsltGetQNameURI2(style, inst, &prop); if (prop == NULL) { style->errors++; } else { *localName = prop; if (hasProp) *hasProp = 1; if (URI != NULL) { /* * Fixes bug #308441: Put the ns-name in the dict * in order to pointer compare names during XPath's * variable lookup. */ if (nsName) *nsName = xmlDictLookup(style->dict, URI, -1); /* comp->has_ns = 1; */ } } } } return; } /** * xsltWithParamComp: * @style: an XSLT compiled stylesheet * @inst: the xslt with-param node * * Process the xslt with-param node on the source node * Allowed parents: xsl:call-template, xsl:apply-templates. * * * */ static void xsltWithParamComp(xsltStylesheetPtr style, xmlNodePtr inst) { #ifdef XSLT_REFACTORED xsltStyleItemWithParamPtr comp; #else xsltStylePreCompPtr comp; #endif if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE)) return; #ifdef XSLT_REFACTORED comp = (xsltStyleItemWithParamPtr) xsltNewStylePreComp(style, XSLT_FUNC_WITHPARAM); #else comp = xsltNewStylePreComp(style, XSLT_FUNC_WITHPARAM); #endif if (comp == NULL) return; inst->psvi = comp; comp->inst = inst; /* * Attribute "name". */ xsltGetQNameProperty(style, inst, BAD_CAST "name", 1, &(comp->has_name), &(comp->ns), &(comp->name)); if (comp->ns) comp->has_ns = 1; /* * Attribute "select". */ comp->select = xsltGetCNsProp(style, inst, (const xmlChar *)"select", XSLT_NAMESPACE); if (comp->select != NULL) { comp->comp = xsltXPathCompile(style, comp->select); if (comp->comp == NULL) { xsltTransformError(NULL, style, inst, "XSLT-with-param: Failed to compile select " "expression '%s'\n", comp->select); style->errors++; } if (inst->children != NULL) { xsltTransformError(NULL, style, inst, "XSLT-with-param: The content should be empty since " "the attribute select is present.\n"); style->warnings++; } } } /** * xsltNumberComp: * @style: an XSLT compiled stylesheet * @cur: the xslt number node * * Process the xslt number node on the source node */ static void xsltNumberComp(xsltStylesheetPtr style, xmlNodePtr cur) { #ifdef XSLT_REFACTORED xsltStyleItemNumberPtr comp; #else xsltStylePreCompPtr comp; #endif const xmlChar *prop; if ((style == NULL) || (cur == NULL) || (cur->type != XML_ELEMENT_NODE)) return; #ifdef XSLT_REFACTORED comp = (xsltStyleItemNumberPtr) xsltNewStylePreComp(style, XSLT_FUNC_NUMBER); #else comp = xsltNewStylePreComp(style, XSLT_FUNC_NUMBER); #endif if (comp == NULL) return; cur->psvi = comp; if ((style == NULL) || (cur == NULL)) return; comp->numdata.doc = cur->doc; comp->numdata.node = cur; comp->numdata.value = xsltGetCNsProp(style, cur, (const xmlChar *)"value", XSLT_NAMESPACE); prop = xsltEvalStaticAttrValueTemplate(style, cur, (const xmlChar *)"format", XSLT_NAMESPACE, &comp->numdata.has_format); if (comp->numdata.has_format == 0) { comp->numdata.format = xmlDictLookup(style->dict, BAD_CAST "" , 0); } else { comp->numdata.format = prop; } comp->numdata.count = xsltGetCNsProp(style, cur, (const xmlChar *)"count", XSLT_NAMESPACE); comp->numdata.from = xsltGetCNsProp(style, cur, (const xmlChar *)"from", XSLT_NAMESPACE); prop = xsltGetCNsProp(style, cur, (const xmlChar *)"count", XSLT_NAMESPACE); if (prop != NULL) { comp->numdata.countPat = xsltCompilePattern(prop, cur->doc, cur, style, NULL); } prop = xsltGetCNsProp(style, cur, (const xmlChar *)"from", XSLT_NAMESPACE); if (prop != NULL) { comp->numdata.fromPat = xsltCompilePattern(prop, cur->doc, cur, style, NULL); } prop = xsltGetCNsProp(style, cur, (const xmlChar *)"level", XSLT_NAMESPACE); if (prop != NULL) { if (xmlStrEqual(prop, BAD_CAST("single")) || xmlStrEqual(prop, BAD_CAST("multiple")) || xmlStrEqual(prop, BAD_CAST("any"))) { comp->numdata.level = prop; } else { xsltTransformError(NULL, style, cur, "xsl:number : invalid value %s for level\n", prop); if (style != NULL) style->warnings++; } } prop = xsltGetCNsProp(style, cur, (const xmlChar *)"lang", XSLT_NAMESPACE); if (prop != NULL) { xsltTransformError(NULL, style, cur, "xsl:number : lang attribute not implemented\n"); XSLT_TODO; /* xsl:number lang attribute */ } prop = xsltGetCNsProp(style, cur, (const xmlChar *)"letter-value", XSLT_NAMESPACE); if (prop != NULL) { if (xmlStrEqual(prop, BAD_CAST("alphabetic"))) { xsltTransformError(NULL, style, cur, "xsl:number : letter-value 'alphabetic' not implemented\n"); if (style != NULL) style->warnings++; XSLT_TODO; /* xsl:number letter-value attribute alphabetic */ } else if (xmlStrEqual(prop, BAD_CAST("traditional"))) { xsltTransformError(NULL, style, cur, "xsl:number : letter-value 'traditional' not implemented\n"); if (style != NULL) style->warnings++; XSLT_TODO; /* xsl:number letter-value attribute traditional */ } else { xsltTransformError(NULL, style, cur, "xsl:number : invalid value %s for letter-value\n", prop); if (style != NULL) style->warnings++; } } prop = xsltGetCNsProp(style, cur, (const xmlChar *)"grouping-separator", XSLT_NAMESPACE); if (prop != NULL) { comp->numdata.groupingCharacterLen = xmlStrlen(prop); comp->numdata.groupingCharacter = xsltGetUTF8Char(prop, &(comp->numdata.groupingCharacterLen)); } prop = xsltGetCNsProp(style, cur, (const xmlChar *)"grouping-size", XSLT_NAMESPACE); if (prop != NULL) { sscanf((char *)prop, "%d", &comp->numdata.digitsPerGroup); } else { comp->numdata.groupingCharacter = 0; } /* Set default values */ if (comp->numdata.value == NULL) { if (comp->numdata.level == NULL) { comp->numdata.level = xmlDictLookup(style->dict, BAD_CAST"single", 6); } } } /** * xsltApplyImportsComp: * @style: an XSLT compiled stylesheet * @inst: the xslt apply-imports node * * Process the xslt apply-imports node on the source node */ static void xsltApplyImportsComp(xsltStylesheetPtr style, xmlNodePtr inst) { #ifdef XSLT_REFACTORED xsltStyleItemApplyImportsPtr comp; #else xsltStylePreCompPtr comp; #endif if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE)) return; #ifdef XSLT_REFACTORED comp = (xsltStyleItemApplyImportsPtr) xsltNewStylePreComp(style, XSLT_FUNC_APPLYIMPORTS); #else comp = xsltNewStylePreComp(style, XSLT_FUNC_APPLYIMPORTS); #endif if (comp == NULL) return; inst->psvi = comp; comp->inst = inst; } /** * xsltCallTemplateComp: * @style: an XSLT compiled stylesheet * @inst: the xslt call-template node * * Process the xslt call-template node on the source node */ static void xsltCallTemplateComp(xsltStylesheetPtr style, xmlNodePtr inst) { #ifdef XSLT_REFACTORED xsltStyleItemCallTemplatePtr comp; #else xsltStylePreCompPtr comp; #endif if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE)) return; #ifdef XSLT_REFACTORED comp = (xsltStyleItemCallTemplatePtr) xsltNewStylePreComp(style, XSLT_FUNC_CALLTEMPLATE); #else comp = xsltNewStylePreComp(style, XSLT_FUNC_CALLTEMPLATE); #endif if (comp == NULL) return; inst->psvi = comp; comp->inst = inst; /* * Attribute "name". */ xsltGetQNameProperty(style, inst, BAD_CAST "name", 1, &(comp->has_name), &(comp->ns), &(comp->name)); if (comp->ns) comp->has_ns = 1; } /** * xsltApplyTemplatesComp: * @style: an XSLT compiled stylesheet * @inst: the apply-templates node * * Process the apply-templates node on the source node */ static void xsltApplyTemplatesComp(xsltStylesheetPtr style, xmlNodePtr inst) { #ifdef XSLT_REFACTORED xsltStyleItemApplyTemplatesPtr comp; #else xsltStylePreCompPtr comp; #endif if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE)) return; #ifdef XSLT_REFACTORED comp = (xsltStyleItemApplyTemplatesPtr) xsltNewStylePreComp(style, XSLT_FUNC_APPLYTEMPLATES); #else comp = xsltNewStylePreComp(style, XSLT_FUNC_APPLYTEMPLATES); #endif if (comp == NULL) return; inst->psvi = comp; comp->inst = inst; /* * Attribute "mode". */ xsltGetQNameProperty(style, inst, BAD_CAST "mode", 0, NULL, &(comp->modeURI), &(comp->mode)); /* * Attribute "select". */ comp->select = xsltGetCNsProp(style, inst, BAD_CAST "select", XSLT_NAMESPACE); if (comp->select != NULL) { comp->comp = xsltXPathCompile(style, comp->select); if (comp->comp == NULL) { xsltTransformError(NULL, style, inst, "XSLT-apply-templates: could not compile select " "expression '%s'\n", comp->select); style->errors++; } } /* TODO: handle (or skip) the xsl:sort and xsl:with-param */ } /** * xsltChooseComp: * @style: an XSLT compiled stylesheet * @inst: the xslt choose node * * Process the xslt choose node on the source node */ static void xsltChooseComp(xsltStylesheetPtr style, xmlNodePtr inst) { #ifdef XSLT_REFACTORED xsltStyleItemChoosePtr comp; #else xsltStylePreCompPtr comp; #endif if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE)) return; #ifdef XSLT_REFACTORED comp = (xsltStyleItemChoosePtr) xsltNewStylePreComp(style, XSLT_FUNC_CHOOSE); #else comp = xsltNewStylePreComp(style, XSLT_FUNC_CHOOSE); #endif if (comp == NULL) return; inst->psvi = comp; comp->inst = inst; } /** * xsltIfComp: * @style: an XSLT compiled stylesheet * @inst: the xslt if node * * Process the xslt if node on the source node */ static void xsltIfComp(xsltStylesheetPtr style, xmlNodePtr inst) { #ifdef XSLT_REFACTORED xsltStyleItemIfPtr comp; #else xsltStylePreCompPtr comp; #endif if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE)) return; #ifdef XSLT_REFACTORED comp = (xsltStyleItemIfPtr) xsltNewStylePreComp(style, XSLT_FUNC_IF); #else comp = xsltNewStylePreComp(style, XSLT_FUNC_IF); #endif if (comp == NULL) return; inst->psvi = comp; comp->inst = inst; comp->test = xsltGetCNsProp(style, inst, (const xmlChar *)"test", XSLT_NAMESPACE); if (comp->test == NULL) { xsltTransformError(NULL, style, inst, "xsl:if : test is not defined\n"); if (style != NULL) style->errors++; return; } comp->comp = xsltXPathCompile(style, comp->test); if (comp->comp == NULL) { xsltTransformError(NULL, style, inst, "xsl:if : could not compile test expression '%s'\n", comp->test); if (style != NULL) style->errors++; } } /** * xsltWhenComp: * @style: an XSLT compiled stylesheet * @inst: the xslt if node * * Process the xslt if node on the source node */ static void xsltWhenComp(xsltStylesheetPtr style, xmlNodePtr inst) { #ifdef XSLT_REFACTORED xsltStyleItemWhenPtr comp; #else xsltStylePreCompPtr comp; #endif if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE)) return; #ifdef XSLT_REFACTORED comp = (xsltStyleItemWhenPtr) xsltNewStylePreComp(style, XSLT_FUNC_WHEN); #else comp = xsltNewStylePreComp(style, XSLT_FUNC_WHEN); #endif if (comp == NULL) return; inst->psvi = comp; comp->inst = inst; comp->test = xsltGetCNsProp(style, inst, (const xmlChar *)"test", XSLT_NAMESPACE); if (comp->test == NULL) { xsltTransformError(NULL, style, inst, "xsl:when : test is not defined\n"); if (style != NULL) style->errors++; return; } comp->comp = xsltXPathCompile(style, comp->test); if (comp->comp == NULL) { xsltTransformError(NULL, style, inst, "xsl:when : could not compile test expression '%s'\n", comp->test); if (style != NULL) style->errors++; } } /** * xsltForEachComp: * @style: an XSLT compiled stylesheet * @inst: the xslt for-each node * * Process the xslt for-each node on the source node */ static void xsltForEachComp(xsltStylesheetPtr style, xmlNodePtr inst) { #ifdef XSLT_REFACTORED xsltStyleItemForEachPtr comp; #else xsltStylePreCompPtr comp; #endif if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE)) return; #ifdef XSLT_REFACTORED comp = (xsltStyleItemForEachPtr) xsltNewStylePreComp(style, XSLT_FUNC_FOREACH); #else comp = xsltNewStylePreComp(style, XSLT_FUNC_FOREACH); #endif if (comp == NULL) return; inst->psvi = comp; comp->inst = inst; comp->select = xsltGetCNsProp(style, inst, (const xmlChar *)"select", XSLT_NAMESPACE); if (comp->select == NULL) { xsltTransformError(NULL, style, inst, "xsl:for-each : select is missing\n"); if (style != NULL) style->errors++; } else { comp->comp = xsltXPathCompile(style, comp->select); if (comp->comp == NULL) { xsltTransformError(NULL, style, inst, "xsl:for-each : could not compile select expression '%s'\n", comp->select); if (style != NULL) style->errors++; } } /* TODO: handle and skip the xsl:sort */ } /** * xsltVariableComp: * @style: an XSLT compiled stylesheet * @inst: the xslt variable node * * Process the xslt variable node on the source node */ static void xsltVariableComp(xsltStylesheetPtr style, xmlNodePtr inst) { #ifdef XSLT_REFACTORED xsltStyleItemVariablePtr comp; #else xsltStylePreCompPtr comp; #endif if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE)) return; #ifdef XSLT_REFACTORED comp = (xsltStyleItemVariablePtr) xsltNewStylePreComp(style, XSLT_FUNC_VARIABLE); #else comp = xsltNewStylePreComp(style, XSLT_FUNC_VARIABLE); #endif if (comp == NULL) return; inst->psvi = comp; comp->inst = inst; /* * The full template resolution can be done statically */ /* * Attribute "name". */ xsltGetQNameProperty(style, inst, BAD_CAST "name", 1, &(comp->has_name), &(comp->ns), &(comp->name)); if (comp->ns) comp->has_ns = 1; /* * Attribute "select". */ comp->select = xsltGetCNsProp(style, inst, (const xmlChar *)"select", XSLT_NAMESPACE); if (comp->select != NULL) { #ifndef XSLT_REFACTORED xmlNodePtr cur; #endif comp->comp = xsltXPathCompile(style, comp->select); if (comp->comp == NULL) { xsltTransformError(NULL, style, inst, "XSLT-variable: Failed to compile the XPath expression '%s'.\n", comp->select); style->errors++; } #ifdef XSLT_REFACTORED if (inst->children != NULL) { xsltTransformError(NULL, style, inst, "XSLT-variable: There must be no child nodes, since the " "attribute 'select' was specified.\n"); style->errors++; } #else for (cur = inst->children; cur != NULL; cur = cur->next) { if (cur->type != XML_COMMENT_NODE && (cur->type != XML_TEXT_NODE || !xsltIsBlank(cur->content))) { xsltTransformError(NULL, style, inst, "XSLT-variable: There must be no child nodes, since the " "attribute 'select' was specified.\n"); style->errors++; } } #endif } } /** * xsltParamComp: * @style: an XSLT compiled stylesheet * @inst: the xslt param node * * Process the xslt param node on the source node */ static void xsltParamComp(xsltStylesheetPtr style, xmlNodePtr inst) { #ifdef XSLT_REFACTORED xsltStyleItemParamPtr comp; #else xsltStylePreCompPtr comp; #endif if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE)) return; #ifdef XSLT_REFACTORED comp = (xsltStyleItemParamPtr) xsltNewStylePreComp(style, XSLT_FUNC_PARAM); #else comp = xsltNewStylePreComp(style, XSLT_FUNC_PARAM); #endif if (comp == NULL) return; inst->psvi = comp; comp->inst = inst; /* * Attribute "name". */ xsltGetQNameProperty(style, inst, BAD_CAST "name", 1, &(comp->has_name), &(comp->ns), &(comp->name)); if (comp->ns) comp->has_ns = 1; /* * Attribute "select". */ comp->select = xsltGetCNsProp(style, inst, (const xmlChar *)"select", XSLT_NAMESPACE); if (comp->select != NULL) { comp->comp = xsltXPathCompile(style, comp->select); if (comp->comp == NULL) { xsltTransformError(NULL, style, inst, "XSLT-param: could not compile select expression '%s'.\n", comp->select); style->errors++; } if (inst->children != NULL) { xsltTransformError(NULL, style, inst, "XSLT-param: The content should be empty since the " "attribute 'select' is present.\n"); style->warnings++; } } } /************************************************************************ * * * Generic interface * * * ************************************************************************/ /** * xsltFreeStylePreComps: * @style: an XSLT transformation context * * Free up the memory allocated by all precomputed blocks */ void xsltFreeStylePreComps(xsltStylesheetPtr style) { xsltElemPreCompPtr cur, next; if (style == NULL) return; cur = style->preComps; while (cur != NULL) { next = cur->next; if (cur->type == XSLT_FUNC_EXTENSION) cur->free(cur); else xsltFreeStylePreComp((xsltStylePreCompPtr) cur); cur = next; } } #ifdef XSLT_REFACTORED /** * xsltStylePreCompute: * @style: the XSLT stylesheet * @node: the element in the XSLT namespace * * Precompute an XSLT element. * This expects the type of the element to be already * set in style->compCtxt->inode->type; */ void xsltStylePreCompute(xsltStylesheetPtr style, xmlNodePtr node) { /* * The xsltXSLTElemMarker marker was set beforehand by * the parsing mechanism for all elements in the XSLT namespace. */ if (style == NULL) { if ((node != NULL) && (node->type == XML_ELEMENT_NODE)) node->psvi = NULL; return; } if (node == NULL) return; if (! IS_XSLT_ELEM_FAST(node)) return; node->psvi = NULL; if (XSLT_CCTXT(style)->inode->type != 0) { switch (XSLT_CCTXT(style)->inode->type) { case XSLT_FUNC_APPLYTEMPLATES: xsltApplyTemplatesComp(style, node); break; case XSLT_FUNC_WITHPARAM: xsltWithParamComp(style, node); break; case XSLT_FUNC_VALUEOF: xsltValueOfComp(style, node); break; case XSLT_FUNC_COPY: xsltCopyComp(style, node); break; case XSLT_FUNC_COPYOF: xsltCopyOfComp(style, node); break; case XSLT_FUNC_IF: xsltIfComp(style, node); break; case XSLT_FUNC_CHOOSE: xsltChooseComp(style, node); break; case XSLT_FUNC_WHEN: xsltWhenComp(style, node); break; case XSLT_FUNC_OTHERWISE: /* NOP yet */ return; case XSLT_FUNC_FOREACH: xsltForEachComp(style, node); break; case XSLT_FUNC_APPLYIMPORTS: xsltApplyImportsComp(style, node); break; case XSLT_FUNC_ATTRIBUTE: xsltAttributeComp(style, node); break; case XSLT_FUNC_ELEMENT: xsltElementComp(style, node); break; case XSLT_FUNC_SORT: xsltSortComp(style, node); break; case XSLT_FUNC_COMMENT: xsltCommentComp(style, node); break; case XSLT_FUNC_NUMBER: xsltNumberComp(style, node); break; case XSLT_FUNC_PI: xsltProcessingInstructionComp(style, node); break; case XSLT_FUNC_CALLTEMPLATE: xsltCallTemplateComp(style, node); break; case XSLT_FUNC_PARAM: xsltParamComp(style, node); break; case XSLT_FUNC_VARIABLE: xsltVariableComp(style, node); break; case XSLT_FUNC_FALLBACK: /* NOP yet */ return; case XSLT_FUNC_DOCUMENT: /* The extra one */ node->psvi = (void *) xsltDocumentComp(style, node, (xsltTransformFunction) xsltDocumentElem); break; case XSLT_FUNC_MESSAGE: /* NOP yet */ return; default: /* * NOTE that xsl:text, xsl:template, xsl:stylesheet, * xsl:transform, xsl:import, xsl:include are not expected * to be handed over to this function. */ xsltTransformError(NULL, style, node, "Internal error: (xsltStylePreCompute) cannot handle " "the XSLT element '%s'.\n", node->name); style->errors++; return; } } else { /* * Fallback to string comparison. */ if (IS_XSLT_NAME(node, "apply-templates")) { xsltApplyTemplatesComp(style, node); } else if (IS_XSLT_NAME(node, "with-param")) { xsltWithParamComp(style, node); } else if (IS_XSLT_NAME(node, "value-of")) { xsltValueOfComp(style, node); } else if (IS_XSLT_NAME(node, "copy")) { xsltCopyComp(style, node); } else if (IS_XSLT_NAME(node, "copy-of")) { xsltCopyOfComp(style, node); } else if (IS_XSLT_NAME(node, "if")) { xsltIfComp(style, node); } else if (IS_XSLT_NAME(node, "choose")) { xsltChooseComp(style, node); } else if (IS_XSLT_NAME(node, "when")) { xsltWhenComp(style, node); } else if (IS_XSLT_NAME(node, "otherwise")) { /* NOP yet */ return; } else if (IS_XSLT_NAME(node, "for-each")) { xsltForEachComp(style, node); } else if (IS_XSLT_NAME(node, "apply-imports")) { xsltApplyImportsComp(style, node); } else if (IS_XSLT_NAME(node, "attribute")) { xsltAttributeComp(style, node); } else if (IS_XSLT_NAME(node, "element")) { xsltElementComp(style, node); } else if (IS_XSLT_NAME(node, "sort")) { xsltSortComp(style, node); } else if (IS_XSLT_NAME(node, "comment")) { xsltCommentComp(style, node); } else if (IS_XSLT_NAME(node, "number")) { xsltNumberComp(style, node); } else if (IS_XSLT_NAME(node, "processing-instruction")) { xsltProcessingInstructionComp(style, node); } else if (IS_XSLT_NAME(node, "call-template")) { xsltCallTemplateComp(style, node); } else if (IS_XSLT_NAME(node, "param")) { xsltParamComp(style, node); } else if (IS_XSLT_NAME(node, "variable")) { xsltVariableComp(style, node); } else if (IS_XSLT_NAME(node, "fallback")) { /* NOP yet */ return; } else if (IS_XSLT_NAME(node, "document")) { /* The extra one */ node->psvi = (void *) xsltDocumentComp(style, node, (xsltTransformFunction) xsltDocumentElem); } else if (IS_XSLT_NAME(node, "output")) { /* Top-level */ return; } else if (IS_XSLT_NAME(node, "preserve-space")) { /* Top-level */ return; } else if (IS_XSLT_NAME(node, "strip-space")) { /* Top-level */ return; } else if (IS_XSLT_NAME(node, "key")) { /* Top-level */ return; } else if (IS_XSLT_NAME(node, "message")) { return; } else if (IS_XSLT_NAME(node, "attribute-set")) { /* Top-level */ return; } else if (IS_XSLT_NAME(node, "namespace-alias")) { /* Top-level */ return; } else if (IS_XSLT_NAME(node, "decimal-format")) { /* Top-level */ return; } else if (IS_XSLT_NAME(node, "include")) { /* Top-level */ } else { /* * NOTE that xsl:text, xsl:template, xsl:stylesheet, * xsl:transform, xsl:import, xsl:include are not expected * to be handed over to this function. */ xsltTransformError(NULL, style, node, "Internal error: (xsltStylePreCompute) cannot handle " "the XSLT element '%s'.\n", node->name); style->errors++; return; } } /* * Assign the current list of in-scope namespaces to the * item. This is needed for XPath expressions. */ if (node->psvi != NULL) { ((xsltStylePreCompPtr) node->psvi)->inScopeNs = XSLT_CCTXT(style)->inode->inScopeNs; } } #else /** * xsltStylePreCompute: * @style: the XSLT stylesheet * @inst: the instruction in the stylesheet * * Precompute an XSLT stylesheet element */ void xsltStylePreCompute(xsltStylesheetPtr style, xmlNodePtr inst) { /* * URGENT TODO: Normally inst->psvi Should never be reserved here, * BUT: since if we include the same stylesheet from * multiple imports, then the stylesheet will be parsed * again. We simply must not try to compute the stylesheet again. * TODO: Get to the point where we don't need to query the * namespace- and local-name of the node, but can evaluate this * using cctxt->style->inode->category; */ if ((inst == NULL) || (inst->type != XML_ELEMENT_NODE) || (inst->psvi != NULL)) return; if (IS_XSLT_ELEM(inst)) { xsltStylePreCompPtr cur; if (IS_XSLT_NAME(inst, "apply-templates")) { xsltCheckInstructionElement(style, inst); xsltApplyTemplatesComp(style, inst); } else if (IS_XSLT_NAME(inst, "with-param")) { xsltCheckParentElement(style, inst, BAD_CAST "apply-templates", BAD_CAST "call-template"); xsltWithParamComp(style, inst); } else if (IS_XSLT_NAME(inst, "value-of")) { xsltCheckInstructionElement(style, inst); xsltValueOfComp(style, inst); } else if (IS_XSLT_NAME(inst, "copy")) { xsltCheckInstructionElement(style, inst); xsltCopyComp(style, inst); } else if (IS_XSLT_NAME(inst, "copy-of")) { xsltCheckInstructionElement(style, inst); xsltCopyOfComp(style, inst); } else if (IS_XSLT_NAME(inst, "if")) { xsltCheckInstructionElement(style, inst); xsltIfComp(style, inst); } else if (IS_XSLT_NAME(inst, "when")) { xsltCheckParentElement(style, inst, BAD_CAST "choose", NULL); xsltWhenComp(style, inst); } else if (IS_XSLT_NAME(inst, "choose")) { xsltCheckInstructionElement(style, inst); xsltChooseComp(style, inst); } else if (IS_XSLT_NAME(inst, "for-each")) { xsltCheckInstructionElement(style, inst); xsltForEachComp(style, inst); } else if (IS_XSLT_NAME(inst, "apply-imports")) { xsltCheckInstructionElement(style, inst); xsltApplyImportsComp(style, inst); } else if (IS_XSLT_NAME(inst, "attribute")) { xmlNodePtr parent = inst->parent; if ((parent == NULL) || (parent->ns == NULL) || ((parent->ns != inst->ns) && (!xmlStrEqual(parent->ns->href, inst->ns->href))) || (!xmlStrEqual(parent->name, BAD_CAST "attribute-set"))) { xsltCheckInstructionElement(style, inst); } xsltAttributeComp(style, inst); } else if (IS_XSLT_NAME(inst, "element")) { xsltCheckInstructionElement(style, inst); xsltElementComp(style, inst); } else if (IS_XSLT_NAME(inst, "text")) { xsltCheckInstructionElement(style, inst); xsltTextComp(style, inst); } else if (IS_XSLT_NAME(inst, "sort")) { xsltCheckParentElement(style, inst, BAD_CAST "apply-templates", BAD_CAST "for-each"); xsltSortComp(style, inst); } else if (IS_XSLT_NAME(inst, "comment")) { xsltCheckInstructionElement(style, inst); xsltCommentComp(style, inst); } else if (IS_XSLT_NAME(inst, "number")) { xsltCheckInstructionElement(style, inst); xsltNumberComp(style, inst); } else if (IS_XSLT_NAME(inst, "processing-instruction")) { xsltCheckInstructionElement(style, inst); xsltProcessingInstructionComp(style, inst); } else if (IS_XSLT_NAME(inst, "call-template")) { xsltCheckInstructionElement(style, inst); xsltCallTemplateComp(style, inst); } else if (IS_XSLT_NAME(inst, "param")) { if (xsltCheckTopLevelElement(style, inst, 0) == 0) xsltCheckInstructionElement(style, inst); xsltParamComp(style, inst); } else if (IS_XSLT_NAME(inst, "variable")) { if (xsltCheckTopLevelElement(style, inst, 0) == 0) xsltCheckInstructionElement(style, inst); xsltVariableComp(style, inst); } else if (IS_XSLT_NAME(inst, "otherwise")) { xsltCheckParentElement(style, inst, BAD_CAST "choose", NULL); xsltCheckInstructionElement(style, inst); return; } else if (IS_XSLT_NAME(inst, "template")) { xsltCheckTopLevelElement(style, inst, 1); return; } else if (IS_XSLT_NAME(inst, "output")) { xsltCheckTopLevelElement(style, inst, 1); return; } else if (IS_XSLT_NAME(inst, "preserve-space")) { xsltCheckTopLevelElement(style, inst, 1); return; } else if (IS_XSLT_NAME(inst, "strip-space")) { xsltCheckTopLevelElement(style, inst, 1); return; } else if ((IS_XSLT_NAME(inst, "stylesheet")) || (IS_XSLT_NAME(inst, "transform"))) { xmlNodePtr parent = inst->parent; if ((parent == NULL) || (parent->type != XML_DOCUMENT_NODE)) { xsltTransformError(NULL, style, inst, "element %s only allowed only as root element\n", inst->name); style->errors++; } return; } else if (IS_XSLT_NAME(inst, "key")) { xsltCheckTopLevelElement(style, inst, 1); return; } else if (IS_XSLT_NAME(inst, "message")) { xsltCheckInstructionElement(style, inst); return; } else if (IS_XSLT_NAME(inst, "attribute-set")) { xsltCheckTopLevelElement(style, inst, 1); return; } else if (IS_XSLT_NAME(inst, "namespace-alias")) { xsltCheckTopLevelElement(style, inst, 1); return; } else if (IS_XSLT_NAME(inst, "include")) { xsltCheckTopLevelElement(style, inst, 1); return; } else if (IS_XSLT_NAME(inst, "import")) { xsltCheckTopLevelElement(style, inst, 1); return; } else if (IS_XSLT_NAME(inst, "decimal-format")) { xsltCheckTopLevelElement(style, inst, 1); return; } else if (IS_XSLT_NAME(inst, "fallback")) { xsltCheckInstructionElement(style, inst); return; } else if (IS_XSLT_NAME(inst, "document")) { xsltCheckInstructionElement(style, inst); inst->psvi = (void *) xsltDocumentComp(style, inst, (xsltTransformFunction) xsltDocumentElem); } else { xsltTransformError(NULL, style, inst, "xsltStylePreCompute: unknown xsl:%s\n", inst->name); if (style != NULL) style->warnings++; } cur = (xsltStylePreCompPtr) inst->psvi; /* * A ns-list is build for every XSLT item in the * node-tree. This is needed for XPath expressions. */ if (cur != NULL) { int i = 0; cur->nsList = xmlGetNsList(inst->doc, inst); if (cur->nsList != NULL) { while (cur->nsList[i] != NULL) i++; } cur->nsNr = i; } } else { inst->psvi = (void *) xsltPreComputeExtModuleElement(style, inst); /* * Unknown element, maybe registered at the context * level. Mark it for later recognition. */ if (inst->psvi == NULL) inst->psvi = (void *) xsltExtMarker; } } #endif /* XSLT_REFACTORED */ libxslt-1.1.28/libxslt/xsltutils.c0000664000076400007640000020262512024022316014116 00000000000000/* * xsltutils.c: Utilities for the XSL Transformation 1.0 engine * * Reference: * http://www.w3.org/TR/1999/REC-xslt-19991116 * * See Copyright for the status of this software. * * daniel@veillard.com */ #define IN_LIBXSLT #include "libxslt.h" #ifndef XSLT_NEED_TRIO #include #else #include #endif #include #include #ifdef HAVE_SYS_TIME_H #include #endif #ifdef HAVE_UNISTD_H #include #endif #ifdef HAVE_STDLIB_H #include #endif #include #include #include #include #include #include #include "xsltutils.h" #include "templates.h" #include "xsltInternals.h" #include "imports.h" #include "transform.h" /* gettimeofday on Windows ??? */ #if defined(WIN32) && !defined(__CYGWIN__) #ifdef _MSC_VER #include #pragma comment(lib, "ws2_32.lib") #define gettimeofday(p1,p2) #define HAVE_GETTIMEOFDAY #define XSLT_WIN32_PERFORMANCE_COUNTER #endif /* _MS_VER */ #endif /* WIN32 */ /************************************************************************ * * * Convenience function * * * ************************************************************************/ /** * xsltGetCNsProp: * @style: the stylesheet * @node: the node * @name: the attribute name * @nameSpace: the URI of the namespace * * Similar to xmlGetNsProp() but with a slightly different semantic * * Search and get the value of an attribute associated to a node * This attribute has to be anchored in the namespace specified, * or has no namespace and the element is in that namespace. * * This does the entity substitution. * This function looks in DTD attribute declaration for #FIXED or * default declaration values unless DTD use has been turned off. * * Returns the attribute value or NULL if not found. The string is allocated * in the stylesheet dictionary. */ const xmlChar * xsltGetCNsProp(xsltStylesheetPtr style, xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) { xmlAttrPtr prop; xmlDocPtr doc; xmlNsPtr ns; xmlChar *tmp; const xmlChar *ret; if ((node == NULL) || (style == NULL) || (style->dict == NULL)) return(NULL); if (nameSpace == NULL) return xmlGetProp(node, name); if (node->type == XML_NAMESPACE_DECL) return(NULL); if (node->type == XML_ELEMENT_NODE) prop = node->properties; else prop = NULL; while (prop != NULL) { /* * One need to have * - same attribute names * - and the attribute carrying that namespace */ if ((xmlStrEqual(prop->name, name)) && (((prop->ns == NULL) && (node->ns != NULL) && (xmlStrEqual(node->ns->href, nameSpace))) || ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, nameSpace))))) { tmp = xmlNodeListGetString(node->doc, prop->children, 1); if (tmp == NULL) ret = xmlDictLookup(style->dict, BAD_CAST "", 0); else { ret = xmlDictLookup(style->dict, tmp, -1); xmlFree(tmp); } return ret; } prop = prop->next; } tmp = NULL; /* * Check if there is a default declaration in the internal * or external subsets */ doc = node->doc; if (doc != NULL) { if (doc->intSubset != NULL) { xmlAttributePtr attrDecl; attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name); if ((attrDecl == NULL) && (doc->extSubset != NULL)) attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name); if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) { /* * The DTD declaration only allows a prefix search */ ns = xmlSearchNs(doc, node, attrDecl->prefix); if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace))) return(xmlDictLookup(style->dict, attrDecl->defaultValue, -1)); } } } return(NULL); } /** * xsltGetNsProp: * @node: the node * @name: the attribute name * @nameSpace: the URI of the namespace * * Similar to xmlGetNsProp() but with a slightly different semantic * * Search and get the value of an attribute associated to a node * This attribute has to be anchored in the namespace specified, * or has no namespace and the element is in that namespace. * * This does the entity substitution. * This function looks in DTD attribute declaration for #FIXED or * default declaration values unless DTD use has been turned off. * * Returns the attribute value or NULL if not found. * It's up to the caller to free the memory. */ xmlChar * xsltGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) { xmlAttrPtr prop; xmlDocPtr doc; xmlNsPtr ns; if (node == NULL) return(NULL); if (nameSpace == NULL) return xmlGetProp(node, name); if (node->type == XML_NAMESPACE_DECL) return(NULL); if (node->type == XML_ELEMENT_NODE) prop = node->properties; else prop = NULL; /* * TODO: Substitute xmlGetProp() for xmlGetNsProp(), since the former * is not namespace-aware and will return an attribute with equal * name regardless of its namespace. * Example: * * So this would return "myName" even if an attribute @name * in the XSLT was requested. */ while (prop != NULL) { /* * One need to have * - same attribute names * - and the attribute carrying that namespace */ if ((xmlStrEqual(prop->name, name)) && (((prop->ns == NULL) && (node->ns != NULL) && (xmlStrEqual(node->ns->href, nameSpace))) || ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, nameSpace))))) { xmlChar *ret; ret = xmlNodeListGetString(node->doc, prop->children, 1); if (ret == NULL) return(xmlStrdup((xmlChar *)"")); return(ret); } prop = prop->next; } /* * Check if there is a default declaration in the internal * or external subsets */ doc = node->doc; if (doc != NULL) { if (doc->intSubset != NULL) { xmlAttributePtr attrDecl; attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name); if ((attrDecl == NULL) && (doc->extSubset != NULL)) attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name); if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) { /* * The DTD declaration only allows a prefix search */ ns = xmlSearchNs(doc, node, attrDecl->prefix); if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace))) return(xmlStrdup(attrDecl->defaultValue)); } } } return(NULL); } /** * xsltGetUTF8Char: * @utf: a sequence of UTF-8 encoded bytes * @len: a pointer to @bytes len * * Read one UTF8 Char from @utf * Function copied from libxml2 xmlGetUTF8Char() ... to discard ultimately * and use the original API * * Returns the char value or -1 in case of error and update @len with the * number of bytes used */ int xsltGetUTF8Char(const unsigned char *utf, int *len) { unsigned int c; if (utf == NULL) goto error; if (len == NULL) goto error; if (*len < 1) goto error; c = utf[0]; if (c & 0x80) { if (*len < 2) goto error; if ((utf[1] & 0xc0) != 0x80) goto error; if ((c & 0xe0) == 0xe0) { if (*len < 3) goto error; if ((utf[2] & 0xc0) != 0x80) goto error; if ((c & 0xf0) == 0xf0) { if (*len < 4) goto error; if ((c & 0xf8) != 0xf0 || (utf[3] & 0xc0) != 0x80) goto error; *len = 4; /* 4-byte code */ c = (utf[0] & 0x7) << 18; c |= (utf[1] & 0x3f) << 12; c |= (utf[2] & 0x3f) << 6; c |= utf[3] & 0x3f; } else { /* 3-byte code */ *len = 3; c = (utf[0] & 0xf) << 12; c |= (utf[1] & 0x3f) << 6; c |= utf[2] & 0x3f; } } else { /* 2-byte code */ *len = 2; c = (utf[0] & 0x1f) << 6; c |= utf[1] & 0x3f; } } else { /* 1-byte code */ *len = 1; } return(c); error: if (len != NULL) *len = 0; return(-1); } #ifdef XSLT_REFACTORED /** * xsltPointerListAddSize: * @list: the pointer list structure * @item: the item to be stored * @initialSize: the initial size of the list * * Adds an item to the list. * * Returns the position of the added item in the list or * -1 in case of an error. */ int xsltPointerListAddSize(xsltPointerListPtr list, void *item, int initialSize) { if (list->items == NULL) { if (initialSize <= 0) initialSize = 1; list->items = (void **) xmlMalloc( initialSize * sizeof(void *)); if (list->items == NULL) { xsltGenericError(xsltGenericErrorContext, "xsltPointerListAddSize: memory allocation failure.\n"); return(-1); } list->number = 0; list->size = initialSize; } else if (list->size <= list->number) { list->size *= 2; list->items = (void **) xmlRealloc(list->items, list->size * sizeof(void *)); if (list->items == NULL) { xsltGenericError(xsltGenericErrorContext, "xsltPointerListAddSize: memory re-allocation failure.\n"); list->size = 0; return(-1); } } list->items[list->number++] = item; return(0); } /** * xsltPointerListCreate: * @initialSize: the initial size for the list * * Creates an xsltPointerList structure. * * Returns a xsltPointerList structure or NULL in case of an error. */ xsltPointerListPtr xsltPointerListCreate(int initialSize) { xsltPointerListPtr ret; ret = xmlMalloc(sizeof(xsltPointerList)); if (ret == NULL) { xsltGenericError(xsltGenericErrorContext, "xsltPointerListCreate: memory allocation failure.\n"); return (NULL); } memset(ret, 0, sizeof(xsltPointerList)); if (initialSize > 0) { xsltPointerListAddSize(ret, NULL, initialSize); ret->number = 0; } return (ret); } /** * xsltPointerListFree: * @list: pointer to the list to be freed * * Frees the xsltPointerList structure. This does not free * the content of the list. */ void xsltPointerListFree(xsltPointerListPtr list) { if (list == NULL) return; if (list->items != NULL) xmlFree(list->items); xmlFree(list); } /** * xsltPointerListClear: * @list: pointer to the list to be cleared * * Resets the list, but does not free the allocated array * and does not free the content of the list. */ void xsltPointerListClear(xsltPointerListPtr list) { if (list->items != NULL) { xmlFree(list->items); list->items = NULL; } list->number = 0; list->size = 0; } #endif /* XSLT_REFACTORED */ /************************************************************************ * * * Handling of XSLT stylesheets messages * * * ************************************************************************/ /** * xsltMessage: * @ctxt: an XSLT processing context * @node: The current node * @inst: The node containing the message instruction * * Process and xsl:message construct */ void xsltMessage(xsltTransformContextPtr ctxt, xmlNodePtr node, xmlNodePtr inst) { xmlGenericErrorFunc error = xsltGenericError; void *errctx = xsltGenericErrorContext; xmlChar *prop, *message; int terminate = 0; if ((ctxt == NULL) || (inst == NULL)) return; if (ctxt->error != NULL) { error = ctxt->error; errctx = ctxt->errctx; } prop = xmlGetNsProp(inst, (const xmlChar *)"terminate", NULL); if (prop != NULL) { if (xmlStrEqual(prop, (const xmlChar *)"yes")) { terminate = 1; } else if (xmlStrEqual(prop, (const xmlChar *)"no")) { terminate = 0; } else { error(errctx, "xsl:message : terminate expecting 'yes' or 'no'\n"); ctxt->state = XSLT_STATE_ERROR; } xmlFree(prop); } message = xsltEvalTemplateString(ctxt, node, inst); if (message != NULL) { int len = xmlStrlen(message); error(errctx, "%s", (const char *)message); if ((len > 0) && (message[len - 1] != '\n')) error(errctx, "\n"); xmlFree(message); } if (terminate) ctxt->state = XSLT_STATE_STOPPED; } /************************************************************************ * * * Handling of out of context errors * * * ************************************************************************/ #define XSLT_GET_VAR_STR(msg, str) { \ int size; \ int chars; \ char *larger; \ va_list ap; \ \ str = (char *) xmlMalloc(150); \ if (str == NULL) \ return; \ \ size = 150; \ \ while (size < 64000) { \ va_start(ap, msg); \ chars = vsnprintf(str, size, msg, ap); \ va_end(ap); \ if ((chars > -1) && (chars < size)) \ break; \ if (chars > -1) \ size += chars + 1; \ else \ size += 100; \ if ((larger = (char *) xmlRealloc(str, size)) == NULL) {\ xmlFree(str); \ return; \ } \ str = larger; \ } \ } /** * xsltGenericErrorDefaultFunc: * @ctx: an error context * @msg: the message to display/transmit * @...: extra parameters for the message display * * Default handler for out of context error messages. */ static void xsltGenericErrorDefaultFunc(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...) { va_list args; if (xsltGenericErrorContext == NULL) xsltGenericErrorContext = (void *) stderr; va_start(args, msg); vfprintf((FILE *)xsltGenericErrorContext, msg, args); va_end(args); } xmlGenericErrorFunc xsltGenericError = xsltGenericErrorDefaultFunc; void *xsltGenericErrorContext = NULL; /** * xsltSetGenericErrorFunc: * @ctx: the new error handling context * @handler: the new handler function * * Function to reset the handler and the error context for out of * context error messages. * This simply means that @handler will be called for subsequent * error messages while not parsing nor validating. And @ctx will * be passed as first argument to @handler * One can simply force messages to be emitted to another FILE * than * stderr by setting @ctx to this file handle and @handler to NULL. */ void xsltSetGenericErrorFunc(void *ctx, xmlGenericErrorFunc handler) { xsltGenericErrorContext = ctx; if (handler != NULL) xsltGenericError = handler; else xsltGenericError = xsltGenericErrorDefaultFunc; } /** * xsltGenericDebugDefaultFunc: * @ctx: an error context * @msg: the message to display/transmit * @...: extra parameters for the message display * * Default handler for out of context error messages. */ static void xsltGenericDebugDefaultFunc(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...) { va_list args; if (xsltGenericDebugContext == NULL) return; va_start(args, msg); vfprintf((FILE *)xsltGenericDebugContext, msg, args); va_end(args); } xmlGenericErrorFunc xsltGenericDebug = xsltGenericDebugDefaultFunc; void *xsltGenericDebugContext = NULL; /** * xsltSetGenericDebugFunc: * @ctx: the new error handling context * @handler: the new handler function * * Function to reset the handler and the error context for out of * context error messages. * This simply means that @handler will be called for subsequent * error messages while not parsing or validating. And @ctx will * be passed as first argument to @handler * One can simply force messages to be emitted to another FILE * than * stderr by setting @ctx to this file handle and @handler to NULL. */ void xsltSetGenericDebugFunc(void *ctx, xmlGenericErrorFunc handler) { xsltGenericDebugContext = ctx; if (handler != NULL) xsltGenericDebug = handler; else xsltGenericDebug = xsltGenericDebugDefaultFunc; } /** * xsltPrintErrorContext: * @ctxt: the transformation context * @style: the stylesheet * @node: the current node being processed * * Display the context of an error. */ void xsltPrintErrorContext(xsltTransformContextPtr ctxt, xsltStylesheetPtr style, xmlNodePtr node) { int line = 0; const xmlChar *file = NULL; const xmlChar *name = NULL; const char *type = "error"; xmlGenericErrorFunc error = xsltGenericError; void *errctx = xsltGenericErrorContext; if (ctxt != NULL) { ctxt->state = XSLT_STATE_ERROR; if (ctxt->error != NULL) { error = ctxt->error; errctx = ctxt->errctx; } } if ((node == NULL) && (ctxt != NULL)) node = ctxt->inst; if (node != NULL) { if ((node->type == XML_DOCUMENT_NODE) || (node->type == XML_HTML_DOCUMENT_NODE)) { xmlDocPtr doc = (xmlDocPtr) node; file = doc->URL; } else { line = xmlGetLineNo(node); if ((node->doc != NULL) && (node->doc->URL != NULL)) file = node->doc->URL; if (node->name != NULL) name = node->name; } } if (ctxt != NULL) type = "runtime error"; else if (style != NULL) { #ifdef XSLT_REFACTORED if (XSLT_CCTXT(style)->errSeverity == XSLT_ERROR_SEVERITY_WARNING) type = "compilation warning"; else type = "compilation error"; #else type = "compilation error"; #endif } if ((file != NULL) && (line != 0) && (name != NULL)) error(errctx, "%s: file %s line %d element %s\n", type, file, line, name); else if ((file != NULL) && (name != NULL)) error(errctx, "%s: file %s element %s\n", type, file, name); else if ((file != NULL) && (line != 0)) error(errctx, "%s: file %s line %d\n", type, file, line); else if (file != NULL) error(errctx, "%s: file %s\n", type, file); else if (name != NULL) error(errctx, "%s: element %s\n", type, name); else error(errctx, "%s\n", type); } /** * xsltSetTransformErrorFunc: * @ctxt: the XSLT transformation context * @ctx: the new error handling context * @handler: the new handler function * * Function to reset the handler and the error context for out of * context error messages specific to a given XSLT transromation. * * This simply means that @handler will be called for subsequent * error messages while running the transformation. */ void xsltSetTransformErrorFunc(xsltTransformContextPtr ctxt, void *ctx, xmlGenericErrorFunc handler) { ctxt->error = handler; ctxt->errctx = ctx; } /** * xsltTransformError: * @ctxt: an XSLT transformation context * @style: the XSLT stylesheet used * @node: the current node in the stylesheet * @msg: the message to display/transmit * @...: extra parameters for the message display * * Display and format an error messages, gives file, line, position and * extra parameters, will use the specific transformation context if available */ void xsltTransformError(xsltTransformContextPtr ctxt, xsltStylesheetPtr style, xmlNodePtr node, const char *msg, ...) { xmlGenericErrorFunc error = xsltGenericError; void *errctx = xsltGenericErrorContext; char * str; if (ctxt != NULL) { ctxt->state = XSLT_STATE_ERROR; if (ctxt->error != NULL) { error = ctxt->error; errctx = ctxt->errctx; } } if ((node == NULL) && (ctxt != NULL)) node = ctxt->inst; xsltPrintErrorContext(ctxt, style, node); XSLT_GET_VAR_STR(msg, str); error(errctx, "%s", str); if (str != NULL) xmlFree(str); } /************************************************************************ * * * QNames * * * ************************************************************************/ /** * xsltSplitQName: * @dict: a dictionary * @name: the full QName * @prefix: the return value * * Split QNames into prefix and local names, both allocated from a dictionary. * * Returns: the localname or NULL in case of error. */ const xmlChar * xsltSplitQName(xmlDictPtr dict, const xmlChar *name, const xmlChar **prefix) { int len = 0; const xmlChar *ret = NULL; *prefix = NULL; if ((name == NULL) || (dict == NULL)) return(NULL); if (name[0] == ':') return(xmlDictLookup(dict, name, -1)); while ((name[len] != 0) && (name[len] != ':')) len++; if (name[len] == 0) return(xmlDictLookup(dict, name, -1)); *prefix = xmlDictLookup(dict, name, len); ret = xmlDictLookup(dict, &name[len + 1], -1); return(ret); } /** * xsltGetQNameURI: * @node: the node holding the QName * @name: pointer to the initial QName value * * This function analyzes @name, if the name contains a prefix, * the function seaches the associated namespace in scope for it. * It will also replace @name value with the NCName, the old value being * freed. * Errors in the prefix lookup are signalled by setting @name to NULL. * * NOTE: the namespace returned is a pointer to the place where it is * defined and hence has the same lifespan as the document holding it. * * Returns the namespace URI if there is a prefix, or NULL if @name is * not prefixed. */ const xmlChar * xsltGetQNameURI(xmlNodePtr node, xmlChar ** name) { int len = 0; xmlChar *qname; xmlNsPtr ns; if (name == NULL) return(NULL); qname = *name; if ((qname == NULL) || (*qname == 0)) return(NULL); if (node == NULL) { xsltGenericError(xsltGenericErrorContext, "QName: no element for namespace lookup %s\n", qname); xmlFree(qname); *name = NULL; return(NULL); } /* nasty but valid */ if (qname[0] == ':') return(NULL); /* * we are not trying to validate but just to cut, and yes it will * work even if this is a set of UTF-8 encoded chars */ while ((qname[len] != 0) && (qname[len] != ':')) len++; if (qname[len] == 0) return(NULL); /* * handle xml: separately, this one is magical */ if ((qname[0] == 'x') && (qname[1] == 'm') && (qname[2] == 'l') && (qname[3] == ':')) { if (qname[4] == 0) return(NULL); *name = xmlStrdup(&qname[4]); xmlFree(qname); return(XML_XML_NAMESPACE); } qname[len] = 0; ns = xmlSearchNs(node->doc, node, qname); if (ns == NULL) { xsltGenericError(xsltGenericErrorContext, "%s:%s : no namespace bound to prefix %s\n", qname, &qname[len + 1], qname); *name = NULL; xmlFree(qname); return(NULL); } *name = xmlStrdup(&qname[len + 1]); xmlFree(qname); return(ns->href); } /** * xsltGetQNameURI2: * @style: stylesheet pointer * @node: the node holding the QName * @name: pointer to the initial QName value * * This function is similar to xsltGetQNameURI, but is used when * @name is a dictionary entry. * * Returns the namespace URI if there is a prefix, or NULL if @name is * not prefixed. */ const xmlChar * xsltGetQNameURI2(xsltStylesheetPtr style, xmlNodePtr node, const xmlChar **name) { int len = 0; xmlChar *qname; xmlNsPtr ns; if (name == NULL) return(NULL); qname = (xmlChar *)*name; if ((qname == NULL) || (*qname == 0)) return(NULL); if (node == NULL) { xsltGenericError(xsltGenericErrorContext, "QName: no element for namespace lookup %s\n", qname); *name = NULL; return(NULL); } /* * we are not trying to validate but just to cut, and yes it will * work even if this is a set of UTF-8 encoded chars */ while ((qname[len] != 0) && (qname[len] != ':')) len++; if (qname[len] == 0) return(NULL); /* * handle xml: separately, this one is magical */ if ((qname[0] == 'x') && (qname[1] == 'm') && (qname[2] == 'l') && (qname[3] == ':')) { if (qname[4] == 0) return(NULL); *name = xmlDictLookup(style->dict, &qname[4], -1); return(XML_XML_NAMESPACE); } qname = xmlStrndup(*name, len); ns = xmlSearchNs(node->doc, node, qname); if (ns == NULL) { if (style) { xsltTransformError(NULL, style, node, "No namespace bound to prefix '%s'.\n", qname); style->errors++; } else { xsltGenericError(xsltGenericErrorContext, "%s : no namespace bound to prefix %s\n", *name, qname); } *name = NULL; xmlFree(qname); return(NULL); } *name = xmlDictLookup(style->dict, (*name)+len+1, -1); xmlFree(qname); return(ns->href); } /************************************************************************ * * * Sorting * * * ************************************************************************/ /** * xsltDocumentSortFunction: * @list: the node set * * reorder the current node list @list accordingly to the document order * This function is slow, obsolete and should not be used anymore. */ void xsltDocumentSortFunction(xmlNodeSetPtr list) { int i, j; int len, tst; xmlNodePtr node; if (list == NULL) return; len = list->nodeNr; if (len <= 1) return; /* TODO: sort is really not optimized, does it needs to ? */ for (i = 0;i < len -1;i++) { for (j = i + 1; j < len; j++) { tst = xmlXPathCmpNodes(list->nodeTab[i], list->nodeTab[j]); if (tst == -1) { node = list->nodeTab[i]; list->nodeTab[i] = list->nodeTab[j]; list->nodeTab[j] = node; } } } } /** * xsltComputeSortResult: * @ctxt: a XSLT process context * @sort: node list * * reorder the current node list accordingly to the set of sorting * requirement provided by the array of nodes. * * Returns a ordered XPath nodeset or NULL in case of error. */ xmlXPathObjectPtr * xsltComputeSortResult(xsltTransformContextPtr ctxt, xmlNodePtr sort) { #ifdef XSLT_REFACTORED xsltStyleItemSortPtr comp; #else xsltStylePreCompPtr comp; #endif xmlXPathObjectPtr *results = NULL; xmlNodeSetPtr list = NULL; xmlXPathObjectPtr res; int len = 0; int i; xmlNodePtr oldNode; xmlNodePtr oldInst; int oldPos, oldSize ; int oldNsNr; xmlNsPtr *oldNamespaces; comp = sort->psvi; if (comp == NULL) { xsltGenericError(xsltGenericErrorContext, "xsl:sort : compilation failed\n"); return(NULL); } if ((comp->select == NULL) || (comp->comp == NULL)) return(NULL); list = ctxt->nodeList; if ((list == NULL) || (list->nodeNr <= 1)) return(NULL); len = list->nodeNr; /* TODO: xsl:sort lang attribute */ /* TODO: xsl:sort case-order attribute */ results = xmlMalloc(len * sizeof(xmlXPathObjectPtr)); if (results == NULL) { xsltGenericError(xsltGenericErrorContext, "xsltComputeSortResult: memory allocation failure\n"); return(NULL); } oldNode = ctxt->node; oldInst = ctxt->inst; oldPos = ctxt->xpathCtxt->proximityPosition; oldSize = ctxt->xpathCtxt->contextSize; oldNsNr = ctxt->xpathCtxt->nsNr; oldNamespaces = ctxt->xpathCtxt->namespaces; for (i = 0;i < len;i++) { ctxt->inst = sort; ctxt->xpathCtxt->contextSize = len; ctxt->xpathCtxt->proximityPosition = i + 1; ctxt->node = list->nodeTab[i]; ctxt->xpathCtxt->node = ctxt->node; #ifdef XSLT_REFACTORED if (comp->inScopeNs != NULL) { ctxt->xpathCtxt->namespaces = comp->inScopeNs->list; ctxt->xpathCtxt->nsNr = comp->inScopeNs->xpathNumber; } else { ctxt->xpathCtxt->namespaces = NULL; ctxt->xpathCtxt->nsNr = 0; } #else ctxt->xpathCtxt->namespaces = comp->nsList; ctxt->xpathCtxt->nsNr = comp->nsNr; #endif res = xmlXPathCompiledEval(comp->comp, ctxt->xpathCtxt); if (res != NULL) { if (res->type != XPATH_STRING) res = xmlXPathConvertString(res); if (comp->number) res = xmlXPathConvertNumber(res); res->index = i; /* Save original pos for dupl resolv */ if (comp->number) { if (res->type == XPATH_NUMBER) { results[i] = res; } else { #ifdef WITH_XSLT_DEBUG_PROCESS xsltGenericDebug(xsltGenericDebugContext, "xsltComputeSortResult: select didn't evaluate to a number\n"); #endif results[i] = NULL; } } else { if (res->type == XPATH_STRING) { if (comp->locale != (xsltLocale)0) { xmlChar *str = res->stringval; res->stringval = (xmlChar *) xsltStrxfrm(comp->locale, str); xmlFree(str); } results[i] = res; } else { #ifdef WITH_XSLT_DEBUG_PROCESS xsltGenericDebug(xsltGenericDebugContext, "xsltComputeSortResult: select didn't evaluate to a string\n"); #endif results[i] = NULL; } } } else { ctxt->state = XSLT_STATE_STOPPED; results[i] = NULL; } } ctxt->node = oldNode; ctxt->inst = oldInst; ctxt->xpathCtxt->contextSize = oldSize; ctxt->xpathCtxt->proximityPosition = oldPos; ctxt->xpathCtxt->nsNr = oldNsNr; ctxt->xpathCtxt->namespaces = oldNamespaces; return(results); } /** * xsltDefaultSortFunction: * @ctxt: a XSLT process context * @sorts: array of sort nodes * @nbsorts: the number of sorts in the array * * reorder the current node list accordingly to the set of sorting * requirement provided by the arry of nodes. */ void xsltDefaultSortFunction(xsltTransformContextPtr ctxt, xmlNodePtr *sorts, int nbsorts) { #ifdef XSLT_REFACTORED xsltStyleItemSortPtr comp; #else xsltStylePreCompPtr comp; #endif xmlXPathObjectPtr *resultsTab[XSLT_MAX_SORT]; xmlXPathObjectPtr *results = NULL, *res; xmlNodeSetPtr list = NULL; int descending, number, desc, numb; int len = 0; int i, j, incr; int tst; int depth; xmlNodePtr node; xmlXPathObjectPtr tmp; int tempstype[XSLT_MAX_SORT], temporder[XSLT_MAX_SORT]; if ((ctxt == NULL) || (sorts == NULL) || (nbsorts <= 0) || (nbsorts >= XSLT_MAX_SORT)) return; if (sorts[0] == NULL) return; comp = sorts[0]->psvi; 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]->psvi; tempstype[j] = 0; if ((comp->stype == NULL) && (comp->has_stype != 0)) { comp->stype = xsltEvalAttrValueTemplate(ctxt, sorts[j], (const xmlChar *) "data-type", XSLT_NAMESPACE); if (comp->stype != NULL) { tempstype[j] = 1; if (xmlStrEqual(comp->stype, (const xmlChar *) "text")) comp->number = 0; else if (xmlStrEqual(comp->stype, (const xmlChar *) "number")) comp->number = 1; else { xsltTransformError(ctxt, NULL, sorts[j], "xsltDoSortFunction: no support for data-type = %s\n", comp->stype); comp->number = 0; /* use default */ } } } temporder[j] = 0; if ((comp->order == NULL) && (comp->has_order != 0)) { comp->order = xsltEvalAttrValueTemplate(ctxt, sorts[j], (const xmlChar *) "order", XSLT_NAMESPACE); if (comp->order != NULL) { temporder[j] = 1; if (xmlStrEqual(comp->order, (const xmlChar *) "ascending")) comp->descending = 0; else if (xmlStrEqual(comp->order, (const xmlChar *) "descending")) comp->descending = 1; else { xsltTransformError(ctxt, NULL, sorts[j], "xsltDoSortFunction: invalid value %s for order\n", comp->order); comp->descending = 0; /* use default */ } } } } 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]->psvi; descending = comp->descending; number = comp->number; if (results == NULL) return; /* 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) { /* We make NaN smaller than number in accordance with XSLT spec */ if (xmlXPathIsNaN(results[j]->floatval)) { if (xmlXPathIsNaN(results[j + incr]->floatval)) tst = 0; else tst = -1; } else if (xmlXPathIsNaN(results[j + incr]->floatval)) tst = 1; else 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 if(comp->locale != (xsltLocale)0) { tst = xsltLocaleStrcmp( comp->locale, (xsltLocaleChar *) results[j]->stringval, (xsltLocaleChar *) results[j + incr]->stringval); } else { tst = xmlStrcmp(results[j]->stringval, results[j + incr]->stringval); } if (descending) 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]->psvi; if (comp == NULL) break; desc = comp->descending; numb = comp->number; /* * 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) { if (res[j+incr] != NULL) tst = 1; } else { if (numb) { /* We make NaN smaller than number in accordance with XSLT spec */ if (xmlXPathIsNaN(res[j]->floatval)) { if (xmlXPathIsNaN(res[j + incr]->floatval)) tst = 0; else tst = -1; } else if (xmlXPathIsNaN(res[j + incr]-> floatval)) tst = 1; else 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 if(comp->locale != (xsltLocale)0) { tst = xsltLocaleStrcmp( comp->locale, (xsltLocaleChar *) res[j]->stringval, (xsltLocaleChar *) res[j + incr]->stringval); } else { tst = xmlStrcmp(res[j]->stringval, res[j + incr]->stringval); } if (desc) 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; } } } for (j = 0; j < nbsorts; j++) { comp = sorts[j]->psvi; if (tempstype[j] == 1) { /* The data-type needs to be recomputed each time */ xmlFree((void *)(comp->stype)); comp->stype = NULL; } if (temporder[j] == 1) { /* The order needs to be recomputed each time */ xmlFree((void *)(comp->order)); comp->order = NULL; } if (resultsTab[j] != NULL) { for (i = 0;i < len;i++) xmlXPathFreeObject(resultsTab[j][i]); xmlFree(resultsTab[j]); } } } static xsltSortFunc xsltSortFunction = xsltDefaultSortFunction; /** * xsltDoSortFunction: * @ctxt: a XSLT process context * @sorts: array of sort nodes * @nbsorts: the number of sorts in the array * * reorder the current node list accordingly to the set of sorting * requirement provided by the arry of nodes. * This is a wrapper function, the actual function used is specified * using xsltSetCtxtSortFunc() to set the context specific sort function, * or xsltSetSortFunc() to set the global sort function. * If a sort function is set on the context, this will get called. * Otherwise the global sort function is called. */ void xsltDoSortFunction(xsltTransformContextPtr ctxt, xmlNodePtr * sorts, int nbsorts) { if (ctxt->sortfunc != NULL) (ctxt->sortfunc)(ctxt, sorts, nbsorts); else if (xsltSortFunction != NULL) xsltSortFunction(ctxt, sorts, nbsorts); } /** * xsltSetSortFunc: * @handler: the new handler function * * Function to reset the global handler for XSLT sorting. * If the handler is NULL, the default sort function will be used. */ void xsltSetSortFunc(xsltSortFunc handler) { if (handler != NULL) xsltSortFunction = handler; else xsltSortFunction = xsltDefaultSortFunction; } /** * xsltSetCtxtSortFunc: * @ctxt: a XSLT process context * @handler: the new handler function * * Function to set the handler for XSLT sorting * for the specified context. * If the handler is NULL, then the global * sort function will be called */ void xsltSetCtxtSortFunc(xsltTransformContextPtr ctxt, xsltSortFunc handler) { ctxt->sortfunc = handler; } /************************************************************************ * * * Parsing options * * * ************************************************************************/ /** * xsltSetCtxtParseOptions: * @ctxt: a XSLT process context * @options: a combination of libxml2 xmlParserOption * * Change the default parser option passed by the XSLT engine to the * parser when using document() loading. * * Returns the previous options or -1 in case of error */ int xsltSetCtxtParseOptions(xsltTransformContextPtr ctxt, int options) { int oldopts; if (ctxt == NULL) return(-1); oldopts = ctxt->parserOptions; if (ctxt->xinclude) oldopts |= XML_PARSE_XINCLUDE; ctxt->parserOptions = options; if (options & XML_PARSE_XINCLUDE) ctxt->xinclude = 1; else ctxt->xinclude = 0; return(oldopts); } /************************************************************************ * * * Output * * * ************************************************************************/ /** * xsltSaveResultTo: * @buf: an output buffer * @result: the result xmlDocPtr * @style: the stylesheet * * Save the result @result obtained by applying the @style stylesheet * to an I/O output channel @buf * * Returns the number of byte written or -1 in case of failure. */ int xsltSaveResultTo(xmlOutputBufferPtr buf, xmlDocPtr result, xsltStylesheetPtr style) { const xmlChar *encoding; int base; const xmlChar *method; int indent; if ((buf == NULL) || (result == NULL) || (style == NULL)) return(-1); if ((result->children == NULL) || ((result->children->type == XML_DTD_NODE) && (result->children->next == NULL))) return(0); if ((style->methodURI != NULL) && ((style->method == NULL) || (!xmlStrEqual(style->method, (const xmlChar *) "xhtml")))) { xsltGenericError(xsltGenericErrorContext, "xsltSaveResultTo : unknown ouput method\n"); return(-1); } base = buf->written; XSLT_GET_IMPORT_PTR(method, style, method) XSLT_GET_IMPORT_PTR(encoding, style, encoding) XSLT_GET_IMPORT_INT(indent, style, indent); if ((method == NULL) && (result->type == XML_HTML_DOCUMENT_NODE)) method = (const xmlChar *) "html"; if ((method != NULL) && (xmlStrEqual(method, (const xmlChar *) "html"))) { if (encoding != NULL) { htmlSetMetaEncoding(result, (const xmlChar *) encoding); } else { htmlSetMetaEncoding(result, (const xmlChar *) "UTF-8"); } if (indent == -1) indent = 1; htmlDocContentDumpFormatOutput(buf, result, (const char *) encoding, indent); xmlOutputBufferFlush(buf); } else if ((method != NULL) && (xmlStrEqual(method, (const xmlChar *) "xhtml"))) { if (encoding != NULL) { htmlSetMetaEncoding(result, (const xmlChar *) encoding); } else { htmlSetMetaEncoding(result, (const xmlChar *) "UTF-8"); } htmlDocContentDumpOutput(buf, result, (const char *) encoding); xmlOutputBufferFlush(buf); } else if ((method != NULL) && (xmlStrEqual(method, (const xmlChar *) "text"))) { xmlNodePtr cur; cur = result->children; while (cur != NULL) { if (cur->type == XML_TEXT_NODE) xmlOutputBufferWriteString(buf, (const char *) cur->content); /* * Skip to next node */ if (cur->children != NULL) { if ((cur->children->type != XML_ENTITY_DECL) && (cur->children->type != XML_ENTITY_REF_NODE) && (cur->children->type != XML_ENTITY_NODE)) { cur = cur->children; continue; } } if (cur->next != NULL) { cur = cur->next; continue; } do { cur = cur->parent; if (cur == NULL) break; if (cur == (xmlNodePtr) style->doc) { cur = NULL; break; } if (cur->next != NULL) { cur = cur->next; break; } } while (cur != NULL); } xmlOutputBufferFlush(buf); } else { int omitXmlDecl; int standalone; XSLT_GET_IMPORT_INT(omitXmlDecl, style, omitXmlDeclaration); XSLT_GET_IMPORT_INT(standalone, style, standalone); if (omitXmlDecl != 1) { xmlOutputBufferWriteString(buf, "version != NULL) { xmlOutputBufferWriteString(buf, "\""); xmlOutputBufferWriteString(buf, (const char *)result->version); xmlOutputBufferWriteString(buf, "\""); } else xmlOutputBufferWriteString(buf, "\"1.0\""); if (encoding == NULL) { if (result->encoding != NULL) encoding = result->encoding; else if (result->charset != XML_CHAR_ENCODING_UTF8) encoding = (const xmlChar *) xmlGetCharEncodingName((xmlCharEncoding) result->charset); } if (encoding != NULL) { xmlOutputBufferWriteString(buf, " encoding="); xmlOutputBufferWriteString(buf, "\""); xmlOutputBufferWriteString(buf, (const char *) encoding); xmlOutputBufferWriteString(buf, "\""); } switch (standalone) { case 0: xmlOutputBufferWriteString(buf, " standalone=\"no\""); break; case 1: xmlOutputBufferWriteString(buf, " standalone=\"yes\""); break; default: break; } xmlOutputBufferWriteString(buf, "?>\n"); } if (result->children != NULL) { xmlNodePtr child = result->children; while (child != NULL) { xmlNodeDumpOutput(buf, result, child, 0, (indent == 1), (const char *) encoding); if (indent && ((child->type == XML_DTD_NODE) || ((child->type == XML_COMMENT_NODE) && (child->next != NULL)))) xmlOutputBufferWriteString(buf, "\n"); child = child->next; } if (indent) xmlOutputBufferWriteString(buf, "\n"); } xmlOutputBufferFlush(buf); } return(buf->written - base); } /** * xsltSaveResultToFilename: * @URL: a filename or URL * @result: the result xmlDocPtr * @style: the stylesheet * @compression: the compression factor (0 - 9 included) * * Save the result @result obtained by applying the @style stylesheet * to a file or @URL * * Returns the number of byte written or -1 in case of failure. */ int xsltSaveResultToFilename(const char *URL, xmlDocPtr result, xsltStylesheetPtr style, int compression) { xmlOutputBufferPtr buf; const xmlChar *encoding; int ret; if ((URL == NULL) || (result == NULL) || (style == NULL)) return(-1); if (result->children == NULL) return(0); XSLT_GET_IMPORT_PTR(encoding, style, encoding) if (encoding != NULL) { xmlCharEncodingHandlerPtr encoder; encoder = xmlFindCharEncodingHandler((char *)encoding); if ((encoder != NULL) && (xmlStrEqual((const xmlChar *)encoder->name, (const xmlChar *) "UTF-8"))) encoder = NULL; buf = xmlOutputBufferCreateFilename(URL, encoder, compression); } else { buf = xmlOutputBufferCreateFilename(URL, NULL, compression); } if (buf == NULL) return(-1); xsltSaveResultTo(buf, result, style); ret = xmlOutputBufferClose(buf); return(ret); } /** * xsltSaveResultToFile: * @file: a FILE * I/O * @result: the result xmlDocPtr * @style: the stylesheet * * Save the result @result obtained by applying the @style stylesheet * to an open FILE * I/O. * This does not close the FILE @file * * Returns the number of bytes written or -1 in case of failure. */ int xsltSaveResultToFile(FILE *file, xmlDocPtr result, xsltStylesheetPtr style) { xmlOutputBufferPtr buf; const xmlChar *encoding; int ret; if ((file == NULL) || (result == NULL) || (style == NULL)) return(-1); if (result->children == NULL) return(0); XSLT_GET_IMPORT_PTR(encoding, style, encoding) if (encoding != NULL) { xmlCharEncodingHandlerPtr encoder; encoder = xmlFindCharEncodingHandler((char *)encoding); if ((encoder != NULL) && (xmlStrEqual((const xmlChar *)encoder->name, (const xmlChar *) "UTF-8"))) encoder = NULL; buf = xmlOutputBufferCreateFile(file, encoder); } else { buf = xmlOutputBufferCreateFile(file, NULL); } if (buf == NULL) return(-1); xsltSaveResultTo(buf, result, style); ret = xmlOutputBufferClose(buf); return(ret); } /** * xsltSaveResultToFd: * @fd: a file descriptor * @result: the result xmlDocPtr * @style: the stylesheet * * Save the result @result obtained by applying the @style stylesheet * to an open file descriptor * This does not close the descriptor. * * Returns the number of bytes written or -1 in case of failure. */ int xsltSaveResultToFd(int fd, xmlDocPtr result, xsltStylesheetPtr style) { xmlOutputBufferPtr buf; const xmlChar *encoding; int ret; if ((fd < 0) || (result == NULL) || (style == NULL)) return(-1); if (result->children == NULL) return(0); XSLT_GET_IMPORT_PTR(encoding, style, encoding) if (encoding != NULL) { xmlCharEncodingHandlerPtr encoder; encoder = xmlFindCharEncodingHandler((char *)encoding); if ((encoder != NULL) && (xmlStrEqual((const xmlChar *)encoder->name, (const xmlChar *) "UTF-8"))) encoder = NULL; buf = xmlOutputBufferCreateFd(fd, encoder); } else { buf = xmlOutputBufferCreateFd(fd, NULL); } if (buf == NULL) return(-1); xsltSaveResultTo(buf, result, style); ret = xmlOutputBufferClose(buf); return(ret); } /** * xsltSaveResultToString: * @doc_txt_ptr: Memory pointer for allocated XML text * @doc_txt_len: Length of the generated XML text * @result: the result xmlDocPtr * @style: the stylesheet * * Save the result @result obtained by applying the @style stylesheet * to a new allocated string. * * Returns 0 in case of success and -1 in case of error */ int xsltSaveResultToString(xmlChar **doc_txt_ptr, int * doc_txt_len, xmlDocPtr result, xsltStylesheetPtr style) { xmlOutputBufferPtr buf; const xmlChar *encoding; *doc_txt_ptr = NULL; *doc_txt_len = 0; if (result->children == NULL) return(0); XSLT_GET_IMPORT_PTR(encoding, style, encoding) if (encoding != NULL) { xmlCharEncodingHandlerPtr encoder; encoder = xmlFindCharEncodingHandler((char *)encoding); if ((encoder != NULL) && (xmlStrEqual((const xmlChar *)encoder->name, (const xmlChar *) "UTF-8"))) encoder = NULL; buf = xmlAllocOutputBuffer(encoder); } else { buf = xmlAllocOutputBuffer(NULL); } if (buf == NULL) return(-1); xsltSaveResultTo(buf, result, style); #ifdef LIBXML2_NEW_BUFFER if (buf->conv != NULL) { *doc_txt_len = xmlBufUse(buf->conv); *doc_txt_ptr = xmlStrndup(xmlBufContent(buf->conv), *doc_txt_len); } else { *doc_txt_len = xmlBufUse(buf->buffer); *doc_txt_ptr = xmlStrndup(xmlBufContent(buf->buffer), *doc_txt_len); } #else if (buf->conv != NULL) { *doc_txt_len = buf->conv->use; *doc_txt_ptr = xmlStrndup(buf->conv->content, *doc_txt_len); } else { *doc_txt_len = buf->buffer->use; *doc_txt_ptr = xmlStrndup(buf->buffer->content, *doc_txt_len); } #endif (void)xmlOutputBufferClose(buf); return 0; } /************************************************************************ * * * Generating profiling informations * * * ************************************************************************/ static long calibration = -1; /** * xsltCalibrateTimestamps: * * Used for to calibrate the xsltTimestamp() function * Should work if launched at startup and we don't loose our quantum :-) * * Returns the number of milliseconds used by xsltTimestamp() */ static long xsltCalibrateTimestamps(void) { register int i; for (i = 0;i < 999;i++) xsltTimestamp(); return(xsltTimestamp() / 1000); } /** * xsltCalibrateAdjust: * @delta: a negative dealy value found * * Used for to correct the calibration for xsltTimestamp() */ void xsltCalibrateAdjust(long delta) { calibration += delta; } /** * xsltTimestamp: * * Used for gathering profiling data * * Returns the number of tenth of milliseconds since the beginning of the * profiling */ long xsltTimestamp(void) { #ifdef XSLT_WIN32_PERFORMANCE_COUNTER BOOL ok; LARGE_INTEGER performanceCount; LARGE_INTEGER performanceFrequency; LONGLONG quadCount; double seconds; static LONGLONG startupQuadCount = 0; static LONGLONG startupQuadFreq = 0; ok = QueryPerformanceCounter(&performanceCount); if (!ok) return 0; quadCount = performanceCount.QuadPart; if (calibration < 0) { calibration = 0; ok = QueryPerformanceFrequency(&performanceFrequency); if (!ok) return 0; startupQuadFreq = performanceFrequency.QuadPart; startupQuadCount = quadCount; return (0); } if (startupQuadFreq == 0) return 0; seconds = (quadCount - startupQuadCount) / (double) startupQuadFreq; return (long) (seconds * XSLT_TIMESTAMP_TICS_PER_SEC); #else /* XSLT_WIN32_PERFORMANCE_COUNTER */ #ifdef HAVE_CLOCK_GETTIME # if defined(CLOCK_MONOTONIC) # define XSLT_CLOCK CLOCK_MONOTONIC # elif defined(CLOCK_HIGHRES) # define XSLT_CLOCK CLOCK_HIGHRES # else # define XSLT_CLOCK CLOCK_REALTIME # endif static struct timespec startup; struct timespec cur; long tics; if (calibration < 0) { clock_gettime(XSLT_CLOCK, &startup); calibration = 0; calibration = xsltCalibrateTimestamps(); clock_gettime(XSLT_CLOCK, &startup); return (0); } clock_gettime(XSLT_CLOCK, &cur); tics = (cur.tv_sec - startup.tv_sec) * XSLT_TIMESTAMP_TICS_PER_SEC; tics += (cur.tv_nsec - startup.tv_nsec) / (1000000000l / XSLT_TIMESTAMP_TICS_PER_SEC); tics -= calibration; return(tics); #elif HAVE_GETTIMEOFDAY static struct timeval startup; struct timeval cur; long tics; if (calibration < 0) { gettimeofday(&startup, NULL); calibration = 0; calibration = xsltCalibrateTimestamps(); gettimeofday(&startup, NULL); return (0); } gettimeofday(&cur, NULL); tics = (cur.tv_sec - startup.tv_sec) * XSLT_TIMESTAMP_TICS_PER_SEC; tics += (cur.tv_usec - startup.tv_usec) / (1000000l / XSLT_TIMESTAMP_TICS_PER_SEC); tics -= calibration; return(tics); #else /* Neither gettimeofday() nor Win32 performance counter available */ return (0); #endif /* HAVE_GETTIMEOFDAY */ #endif /* XSLT_WIN32_PERFORMANCE_COUNTER */ } static char * pretty_templ_match(xsltTemplatePtr templ) { static char dst[1001]; char *src = (char *)templ->match; int i=0,j; /* strip white spaces */ for (j=0; i<1000 && src[j]; i++,j++) { for(;src[j]==' ';j++); dst[i]=src[j]; } if(i<998 && templ->mode) { /* append [mode] */ dst[i++]='['; src=(char *)templ->mode; for (j=0; i<999 && src[j]; i++,j++) { dst[i]=src[j]; } dst[i++]=']'; } dst[i]='\0'; return dst; } #define MAX_TEMPLATES 10000 /** * xsltSaveProfiling: * @ctxt: an XSLT context * @output: a FILE * for saving the informations * * Save the profiling informations on @output */ void xsltSaveProfiling(xsltTransformContextPtr ctxt, FILE *output) { int nb, i,j,k,l; int max; int total; long totalt; xsltTemplatePtr *templates; xsltStylesheetPtr style; xsltTemplatePtr templ1,templ2; int *childt; if ((output == NULL) || (ctxt == NULL)) return; if (ctxt->profile == 0) return; nb = 0; max = MAX_TEMPLATES; templates = xmlMalloc(max * sizeof(xsltTemplatePtr)); if (templates == NULL) return; style = ctxt->style; while (style != NULL) { templ1 = style->templates; while (templ1 != NULL) { if (nb >= max) break; if (templ1->nbCalls > 0) templates[nb++] = templ1; templ1 = templ1->next; } style = xsltNextImport(style); } for (i = 0;i < nb -1;i++) { for (j = i + 1; j < nb; j++) { if ((templates[i]->time <= templates[j]->time) || ((templates[i]->time == templates[j]->time) && (templates[i]->nbCalls <= templates[j]->nbCalls))) { templ1 = templates[j]; templates[j] = templates[i]; templates[i] = templ1; } } } /* print flat profile */ fprintf(output, "%6s%20s%20s%10s Calls Tot 100us Avg\n\n", "number", "match", "name", "mode"); total = 0; totalt = 0; for (i = 0;i < nb;i++) { templ1 = templates[i]; fprintf(output, "%5d ", i); if (templ1->match != NULL) { if (xmlStrlen(templ1->match) > 20) fprintf(output, "%s\n%26s", templ1->match, ""); else fprintf(output, "%20s", templ1->match); } else { fprintf(output, "%20s", ""); } if (templ1->name != NULL) { if (xmlStrlen(templ1->name) > 20) fprintf(output, "%s\n%46s", templ1->name, ""); else fprintf(output, "%20s", templ1->name); } else { fprintf(output, "%20s", ""); } if (templ1->mode != NULL) { if (xmlStrlen(templ1->mode) > 10) fprintf(output, "%s\n%56s", templ1->mode, ""); else fprintf(output, "%10s", templ1->mode); } else { fprintf(output, "%10s", ""); } fprintf(output, " %6d", templ1->nbCalls); fprintf(output, " %6ld %6ld\n", templ1->time, templ1->time / templ1->nbCalls); total += templ1->nbCalls; totalt += templ1->time; } fprintf(output, "\n%30s%26s %6d %6ld\n", "Total", "", total, totalt); /* print call graph */ childt = xmlMalloc((nb + 1) * sizeof(int)); if (childt == NULL) return; /* precalculate children times */ for (i = 0; i < nb; i++) { templ1 = templates[i]; childt[i] = 0; for (k = 0; k < nb; k++) { templ2 = templates[k]; for (l = 0; l < templ2->templNr; l++) { if (templ2->templCalledTab[l] == templ1) { childt[i] +=templ2->time; } } } } childt[i] = 0; fprintf(output, "\nindex %% time self children called name\n"); for (i = 0; i < nb; i++) { char ix_str[20], timep_str[20], times_str[20], timec_str[20], called_str[20]; int t; templ1 = templates[i]; /* callers */ for (j = 0; j < templ1->templNr; j++) { templ2 = templ1->templCalledTab[j]; for (k = 0; k < nb; k++) { if (templates[k] == templ2) break; } t=templ2?templ2->time:totalt; sprintf(times_str,"%8.3f",(float)t/XSLT_TIMESTAMP_TICS_PER_SEC); sprintf(timec_str,"%8.3f",(float)childt[k]/XSLT_TIMESTAMP_TICS_PER_SEC); sprintf(called_str,"%6d/%d", templ1->templCountTab[j], /* number of times caller calls 'this' */ templ1->nbCalls); /* total number of calls to 'this' */ fprintf(output, " %-8s %-8s %-12s %s [%d]\n", times_str,timec_str,called_str, (templ2?(templ2->name?(char *)templ2->name:pretty_templ_match(templ2)):"-"),k); } /* this */ sprintf(ix_str,"[%d]",i); sprintf(timep_str,"%6.2f",(float)templ1->time*100.0/totalt); sprintf(times_str,"%8.3f",(float)templ1->time/XSLT_TIMESTAMP_TICS_PER_SEC); sprintf(timec_str,"%8.3f",(float)childt[i]/XSLT_TIMESTAMP_TICS_PER_SEC); fprintf(output, "%-5s %-6s %-8s %-8s %6d %s [%d]\n", ix_str, timep_str,times_str,timec_str, templ1->nbCalls, templ1->name?(char *)templ1->name:pretty_templ_match(templ1),i); /* callees * - go over templates[0..nb] and their templCalledTab[] * - print those where we in the the call-stack */ total = 0; for (k = 0; k < nb; k++) { templ2 = templates[k]; for (l = 0; l < templ2->templNr; l++) { if (templ2->templCalledTab[l] == templ1) { total+=templ2->templCountTab[l]; } } } for (k = 0; k < nb; k++) { templ2 = templates[k]; for (l = 0; l < templ2->templNr; l++) { if (templ2->templCalledTab[l] == templ1) { sprintf(times_str,"%8.3f",(float)templ2->time/XSLT_TIMESTAMP_TICS_PER_SEC); sprintf(timec_str,"%8.3f",(float)childt[k]/XSLT_TIMESTAMP_TICS_PER_SEC); sprintf(called_str,"%6d/%d", templ2->templCountTab[l], /* number of times 'this' calls callee */ total); /* total number of calls from 'this' */ fprintf(output, " %-8s %-8s %-12s %s [%d]\n", times_str,timec_str,called_str, templ2->name?(char *)templ2->name:pretty_templ_match(templ2),k); } } } fprintf(output, "-----------------------------------------------\n"); } fprintf(output, "\f\nIndex by function name\n"); for (i = 0; i < nb; i++) { templ1 = templates[i]; fprintf(output, "[%d] %s (%s:%d)\n", i, templ1->name?(char *)templ1->name:pretty_templ_match(templ1), templ1->style->doc->URL,templ1->elem->line); } fprintf(output, "\f\n"); xmlFree(childt); xmlFree(templates); } /************************************************************************ * * * Fetching profiling informations * * * ************************************************************************/ /** * xsltGetProfileInformation: * @ctxt: a transformation context * * This function should be called after the transformation completed * to extract template processing profiling informations if availble. * The informations are returned as an XML document tree like * * *