[LIBXSLT] Update to version 1.1.32. CORE-14291

This commit is contained in:
Thomas Faber 2018-02-04 15:52:31 +01:00
parent 5c72e50fd0
commit 5c0faa58cf
No known key found for this signature in database
GPG key ID: 076E7C3D44720826
24 changed files with 945 additions and 911 deletions

View file

@ -62,7 +62,7 @@ else
LIBXSLT_VERSION_SCRIPT = LIBXSLT_VERSION_SCRIPT =
endif endif
libxslt_la_LIBADD = $(LIBXML_LIBS) $(EXTRA_LIBS) libxslt_la_LIBADD = $(LIBXML_LIBS) $(EXTRA_LIBS) $(M_LIBS)
libxslt_la_LDFLAGS = \ libxslt_la_LDFLAGS = \
$(WIN32_EXTRA_LDFLAGS) \ $(WIN32_EXTRA_LDFLAGS) \
$(LIBXSLT_VERSION_SCRIPT) \ $(LIBXSLT_VERSION_SCRIPT) \

View file

@ -16,14 +16,6 @@
#define WITH_XSLT_DEBUG_ATTRIBUTES #define WITH_XSLT_DEBUG_ATTRIBUTES
#endif #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 * Useful macros
*/ */
@ -37,6 +29,10 @@
#define IS_BLANK_NODE(n) \ #define IS_BLANK_NODE(n) \
(((n)->type == XML_TEXT_NODE) && (xsltIsBlank((n)->content))) (((n)->type == XML_TEXT_NODE) && (xsltIsBlank((n)->content)))
#define ATTRSET_UNRESOLVED 0
#define ATTRSET_RESOLVING 1
#define ATTRSET_RESOLVED 2
/* /*
* The in-memory structure corresponding to an XSLT Attribute in * The in-memory structure corresponding to an XSLT Attribute in
@ -49,10 +45,36 @@ typedef xsltAttrElem *xsltAttrElemPtr;
struct _xsltAttrElem { struct _xsltAttrElem {
struct _xsltAttrElem *next;/* chained list */ struct _xsltAttrElem *next;/* chained list */
xmlNodePtr attr; /* the xsl:attribute definition */ xmlNodePtr attr; /* the xsl:attribute definition */
const xmlChar *set; /* or the attribute set */
const xmlChar *ns; /* and its namespace */
}; };
typedef struct _xsltUseAttrSet xsltUseAttrSet;
typedef xsltUseAttrSet *xsltUseAttrSetPtr;
struct _xsltUseAttrSet {
struct _xsltUseAttrSet *next; /* chained list */
const xmlChar *ncname;
const xmlChar *ns;
};
typedef struct _xsltAttrSet xsltAttrSet;
typedef xsltAttrSet *xsltAttrSetPtr;
struct _xsltAttrSet {
int state;
xsltAttrElemPtr attrs; /* list head */
xsltUseAttrSetPtr useAttrSets; /* list head */
};
typedef struct _xsltAttrSetContext xsltAttrSetContext;
typedef xsltAttrSetContext *xsltAttrSetContextPtr;
struct _xsltAttrSetContext {
xsltStylesheetPtr topStyle;
xsltStylesheetPtr style;
};
static void
xsltResolveAttrSet(xsltAttrSetPtr set, xsltStylesheetPtr topStyle,
xsltStylesheetPtr style, const xmlChar *name,
const xmlChar *ns, int depth);
/************************************************************************ /************************************************************************
* * * *
* XSLT Attribute handling * * XSLT Attribute handling *
@ -110,11 +132,6 @@ xsltFreeAttrElemList(xsltAttrElemPtr list) {
} }
} }
#ifdef XSLT_REFACTORED
/*
* This was moved to xsltParseStylesheetAttributeSet().
*/
#else
/** /**
* xsltAddAttrElemList: * xsltAddAttrElemList:
* @list: an XSLT AttrElem list * @list: an XSLT AttrElem list
@ -135,9 +152,7 @@ xsltAddAttrElemList(xsltAttrElemPtr list, xmlNodePtr attr) {
cur = list; cur = list;
while (cur != NULL) { while (cur != NULL) {
next = cur->next; next = cur->next;
if (cur->attr == attr) if (next == NULL) {
return(cur);
if (cur->next == NULL) {
cur->next = xsltNewAttrElem(attr); cur->next = xsltNewAttrElem(attr);
return(list); return(list);
} }
@ -145,92 +160,174 @@ xsltAddAttrElemList(xsltAttrElemPtr list, xmlNodePtr attr) {
} }
return(list); return(list);
} }
#endif /* XSLT_REFACTORED */
/** /**
* xsltMergeAttrElemList: * xsltNewUseAttrSet:
* @list: an XSLT AttrElem list * @ncname: local name
* @old: another XSLT AttrElem list * @ns: namespace URI
* *
* Add all the attributes from list @old to list @list, * Create a new XSLT UseAttrSet
* but drop redefinition of existing values.
* *
* Returns the new list pointer * Returns the newly allocated xsltUseAttrSetPtr or NULL in case of error.
*/ */
static xsltAttrElemPtr static xsltUseAttrSetPtr
xsltMergeAttrElemList(xsltStylesheetPtr style, xsltNewUseAttrSet(const xmlChar *ncname, const xmlChar *ns) {
xsltAttrElemPtr list, xsltAttrElemPtr old) { xsltUseAttrSetPtr cur;
cur = (xsltUseAttrSetPtr) xmlMalloc(sizeof(xsltUseAttrSet));
if (cur == NULL) {
xsltGenericError(xsltGenericErrorContext,
"xsltNewUseAttrSet : malloc failed\n");
return(NULL);
}
memset(cur, 0, sizeof(xsltUseAttrSet));
cur->ncname = ncname;
cur->ns = ns;
return(cur);
}
/**
* xsltFreeUseAttrSet:
* @use: an XSLT UseAttrSet
*
* Free up the memory allocated by @use
*/
static void
xsltFreeUseAttrSet(xsltUseAttrSetPtr use) {
xmlFree(use);
}
/**
* xsltFreeUseAttrSetList:
* @list: an XSLT UseAttrSet list
*
* Free up the memory allocated by @list
*/
static void
xsltFreeUseAttrSetList(xsltUseAttrSetPtr list) {
xsltUseAttrSetPtr next;
while (list != NULL) {
next = list->next;
xsltFreeUseAttrSet(list);
list = next;
}
}
/**
* xsltAddUseAttrSetList:
* @list: a xsltUseAttrSet list
* @ncname: local name
* @ns: namespace URI
*
* Add the use-attribute-set name to the list.
*
* Returns the new list pointer.
*/
static xsltUseAttrSetPtr
xsltAddUseAttrSetList(xsltUseAttrSetPtr list, const xmlChar *ncname,
const xmlChar *ns) {
xsltUseAttrSetPtr next, cur;
if (ncname == NULL)
return(list);
if (list == NULL)
return(xsltNewUseAttrSet(ncname, ns));
cur = list;
while (cur != NULL) {
if ((cur->ncname == ncname) && (cur->ns == ns))
return(list);
next = cur->next;
if (next == NULL) {
cur->next = xsltNewUseAttrSet(ncname, ns);
return(list);
}
cur = next;
}
return(list);
}
/**
* xsltNewAttrSet:
*
* Create a new attribute set.
*
* Returns the newly allocated xsltAttrSetPtr or NULL in case of error.
*/
static xsltAttrSetPtr
xsltNewAttrSet() {
xsltAttrSetPtr cur;
cur = (xsltAttrSetPtr) xmlMalloc(sizeof(xsltAttrSet));
if (cur == NULL) {
xsltGenericError(xsltGenericErrorContext,
"xsltNewAttrSet : malloc failed\n");
return(NULL);
}
memset(cur, 0, sizeof(xsltAttrSet));
return(cur);
}
/**
* xsltFreeAttrSet:
* @set: an attribute set
*
* Free memory allocated by @set
*/
static void
xsltFreeAttrSet(xsltAttrSetPtr set) {
if (set == NULL)
return;
xsltFreeAttrElemList(set->attrs);
xsltFreeUseAttrSetList(set->useAttrSets);
xmlFree(set);
}
/**
* xsltMergeAttrSets:
* @set: an attribute set
* @other: another attribute set
*
* Add all the attributes from @other to @set,
* but drop redefinition of existing values.
*/
static void
xsltMergeAttrSets(xsltAttrSetPtr set, xsltAttrSetPtr other) {
xsltAttrElemPtr cur; xsltAttrElemPtr cur;
xsltAttrElemPtr old = other->attrs;
int add; int add;
while (old != NULL) { while (old != NULL) {
if ((old->attr == NULL) && (old->set == NULL)) {
old = old->next;
continue;
}
/* /*
* Check that the attribute is not yet in the list * Check that the attribute is not yet in the list
*/ */
cur = list; cur = set->attrs;
add = 1; add = 1;
while (cur != NULL) { while (cur != NULL) {
if ((cur->attr == NULL) && (cur->set == NULL)) { xsltStylePreCompPtr curComp = cur->attr->psvi;
if (cur->next == NULL) xsltStylePreCompPtr oldComp = old->attr->psvi;
break;
cur = cur->next; if ((curComp->name == oldComp->name) &&
continue; (curComp->ns == oldComp->ns)) {
} add = 0;
if ((cur->set != NULL) && (cur->set == old->set)) { break;
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) if (cur->next == NULL)
break; break;
cur = cur->next; cur = cur->next;
} }
if (add == 1) { if (add == 1) {
/*
* Changed to use the string-dict, rather than duplicating
* @set and @ns; this fixes bug #340400.
*/
if (cur == NULL) { if (cur == NULL) {
list = xsltNewAttrElem(old->attr); set->attrs = 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) { } else if (add) {
cur->next = xsltNewAttrElem(old->attr); 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; old = old->next;
} }
return(list);
} }
/************************************************************************ /************************************************************************
@ -251,9 +348,10 @@ void
xsltParseStylesheetAttributeSet(xsltStylesheetPtr style, xmlNodePtr cur) { xsltParseStylesheetAttributeSet(xsltStylesheetPtr style, xmlNodePtr cur) {
const xmlChar *ncname; const xmlChar *ncname;
const xmlChar *prefix; const xmlChar *prefix;
const xmlChar *nsUri = NULL;
xmlChar *value; xmlChar *value;
xmlNodePtr child; xmlNodePtr child;
xsltAttrElemPtr attrItems; xsltAttrSetPtr set;
if ((cur == NULL) || (style == NULL) || (cur->type != XML_ELEMENT_NODE)) if ((cur == NULL) || (style == NULL) || (cur->type != XML_ELEMENT_NODE))
return; return;
@ -267,9 +365,29 @@ xsltParseStylesheetAttributeSet(xsltStylesheetPtr style, xmlNodePtr cur) {
return; return;
} }
if (xmlValidateQName(value, 0)) {
xsltTransformError(NULL, style, cur,
"xsl:attribute-set : The name '%s' is not a valid QName.\n",
value);
style->errors++;
xmlFree(value);
return;
}
ncname = xsltSplitQName(style->dict, value, &prefix); ncname = xsltSplitQName(style->dict, value, &prefix);
xmlFree(value); xmlFree(value);
value = NULL; value = NULL;
if (prefix != NULL) {
xmlNsPtr ns = xmlSearchNs(style->doc, cur, prefix);
if (ns == NULL) {
xsltTransformError(NULL, style, cur,
"xsl:attribute-set : No namespace found for QName '%s:%s'\n",
prefix, ncname);
style->errors++;
return;
}
nsUri = ns->href;
}
if (style->attributeSets == NULL) { if (style->attributeSets == NULL) {
#ifdef WITH_XSLT_DEBUG_ATTRIBUTES #ifdef WITH_XSLT_DEBUG_ATTRIBUTES
@ -281,7 +399,13 @@ xsltParseStylesheetAttributeSet(xsltStylesheetPtr style, xmlNodePtr cur) {
if (style->attributeSets == NULL) if (style->attributeSets == NULL)
return; return;
attrItems = xmlHashLookup2(style->attributeSets, ncname, prefix); set = xmlHashLookup2(style->attributeSets, ncname, nsUri);
if (set == NULL) {
set = xsltNewAttrSet();
if (set == NULL)
return;
xmlHashAddEntry2(style->attributeSets, ncname, nsUri, set);
}
/* /*
* Parse the content. Only xsl:attribute elements are allowed. * Parse the content. Only xsl:attribute elements are allowed.
@ -307,71 +431,36 @@ xsltParseStylesheetAttributeSet(xsltStylesheetPtr style, xmlNodePtr cur) {
"xsl:attribute-set : unexpected child xsl:%s\n", "xsl:attribute-set : unexpected child xsl:%s\n",
child->name); child->name);
} else { } else {
#ifdef WITH_XSLT_DEBUG_ATTRIBUTES
xsltGenericDebug(xsltGenericDebugContext,
"add attribute to list %s\n", ncname);
#endif
xsltStylePreCompute(style, child);
if (child->children != NULL) {
#ifdef XSLT_REFACTORED #ifdef XSLT_REFACTORED
xsltAttrElemPtr nextAttr, curAttr; xsltParseSequenceConstructor(XSLT_CCTXT(style),
child->children);
/*
* 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 #else
#ifdef WITH_XSLT_DEBUG_ATTRIBUTES xsltParseTemplateContent(style, child);
xsltGenericDebug(xsltGenericDebugContext,
"add attribute to list %s\n", ncname);
#endif
/*
* OLD behaviour:
*/
attrItems = xsltAddAttrElemList(attrItems, child);
#endif #endif
}
if (child->psvi == NULL) {
xsltTransformError(NULL, style, child,
"xsl:attribute-set : internal error, attribute %s not "
"compiled\n", child->name);
}
else {
set->attrs = xsltAddAttrElemList(set->attrs, child);
}
} }
#ifdef XSLT_REFACTORED
next_child:
#endif
child = child->next; child = child->next;
} }
/* /*
* Process attribue "use-attribute-sets". * Process attribute "use-attribute-sets".
*/ */
/* TODO check recursion */ value = xmlGetNsProp(cur, BAD_CAST "use-attribute-sets", NULL);
value = xmlGetNsProp(cur, (const xmlChar *)"use-attribute-sets",
NULL);
if (value != NULL) { if (value != NULL) {
const xmlChar *curval, *endval; const xmlChar *curval, *endval;
curval = value; curval = value;
@ -385,21 +474,38 @@ next_child:
if (curval) { if (curval) {
const xmlChar *ncname2 = NULL; const xmlChar *ncname2 = NULL;
const xmlChar *prefix2 = NULL; const xmlChar *prefix2 = NULL;
xsltAttrElemPtr refAttrItems; const xmlChar *nsUri2 = NULL;
#ifdef WITH_XSLT_DEBUG_ATTRIBUTES #ifdef WITH_XSLT_DEBUG_ATTRIBUTES
xsltGenericDebug(xsltGenericDebugContext, xsltGenericDebug(xsltGenericDebugContext,
"xsl:attribute-set : %s adds use %s\n", ncname, curval); "xsl:attribute-set : %s adds use %s\n", ncname, curval);
#endif #endif
if (xmlValidateQName(curval, 0)) {
xsltTransformError(NULL, style, cur,
"xsl:attribute-set : The name '%s' in "
"use-attribute-sets is not a valid QName.\n", curval);
style->errors++;
xmlFree(value);
return;
}
ncname2 = xsltSplitQName(style->dict, curval, &prefix2); ncname2 = xsltSplitQName(style->dict, curval, &prefix2);
refAttrItems = xsltNewAttrElem(NULL); if (prefix2 != NULL) {
if (refAttrItems != NULL) { xmlNsPtr ns2 = xmlSearchNs(style->doc, cur, prefix2);
refAttrItems->set = ncname2; if (ns2 == NULL) {
refAttrItems->ns = prefix2; xsltTransformError(NULL, style, cur,
attrItems = xsltMergeAttrElemList(style, "xsl:attribute-set : No namespace found for QName "
attrItems, refAttrItems); "'%s:%s' in use-attribute-sets\n",
xsltFreeAttrElem(refAttrItems); prefix2, ncname2);
} style->errors++;
xmlFree(value);
return;
}
nsUri2 = ns2->href;
}
set->useAttrSets = xsltAddUseAttrSetList(set->useAttrSets,
ncname2, nsUri2);
} }
curval = endval; curval = endval;
} }
@ -407,15 +513,6 @@ next_child:
value = NULL; 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 #ifdef WITH_XSLT_DEBUG_ATTRIBUTES
xsltGenericDebug(xsltGenericDebugContext, xsltGenericDebug(xsltGenericDebugContext,
"updated attribute list %s\n", ncname); "updated attribute list %s\n", ncname);
@ -423,143 +520,141 @@ next_child:
} }
/** /**
* xsltGetSAS: * xsltResolveUseAttrSets:
* @style: the XSLT stylesheet * @set: the attribute set
* @name: the attribute list name * @asctx: the context for attribute set resolution
* @ns: the attribute list namespace * @depth: recursion depth
* *
* lookup an attribute set based on the style cascade * Process "use-attribute-sets".
*
* Returns the attribute set or NULL
*/ */
static xsltAttrElemPtr static void
xsltGetSAS(xsltStylesheetPtr style, const xmlChar *name, const xmlChar *ns) { xsltResolveUseAttrSets(xsltAttrSetPtr set, xsltStylesheetPtr topStyle,
xsltAttrElemPtr values; int depth) {
xsltStylesheetPtr cur;
xsltAttrSetPtr other;
xsltUseAttrSetPtr use = set->useAttrSets;
xsltUseAttrSetPtr next;
while (style != NULL) { while (use != NULL) {
values = xmlHashLookup2(style->attributeSets, name, ns); /*
if (values != NULL) * Iterate top stylesheet and all imports.
return(values); */
style = xsltNextImport(style); cur = topStyle;
while (cur != NULL) {
if (cur->attributeSets) {
other = xmlHashLookup2(cur->attributeSets, use->ncname,
use->ns);
if (other != NULL) {
xsltResolveAttrSet(other, topStyle, cur, use->ncname,
use->ns, depth + 1);
xsltMergeAttrSets(set, other);
break;
}
}
cur = xsltNextImport(cur);
}
next = use->next;
/* Free useAttrSets early. */
xsltFreeUseAttrSet(use);
use = next;
} }
return(NULL);
set->useAttrSets = NULL;
} }
/** /**
* xsltResolveSASCallbackInt: * xsltResolveAttrSet:
* @style: the XSLT stylesheet * @set: the attribute set
* @asctx: the context for attribute set resolution
* @name: the local name of the attirbute set
* @ns: the namespace of the attribute set
* @depth: recursion depth
* *
* resolve the references in an attribute set. * resolve the references in an attribute set.
*/ */
static void static void
xsltResolveSASCallbackInt(xsltAttrElemPtr values, xsltStylesheetPtr style, xsltResolveAttrSet(xsltAttrSetPtr set, xsltStylesheetPtr topStyle,
const xmlChar *name, const xmlChar *ns, xsltStylesheetPtr style, const xmlChar *name,
int depth) { const xmlChar *ns, int depth) {
xsltAttrElemPtr tmp; xsltStylesheetPtr cur;
xsltAttrElemPtr refs; xsltAttrSetPtr other;
tmp = values; if (set->state == ATTRSET_RESOLVED)
if ((name == NULL) || (name[0] == 0))
return; return;
if (set->state == ATTRSET_RESOLVING) {
xsltTransformError(NULL, topStyle, NULL,
"xsl:attribute-set : use-attribute-sets recursion detected"
" on %s\n", name);
topStyle->errors++;
set->state = ATTRSET_RESOLVED;
return;
}
if (depth > 100) { if (depth > 100) {
xsltGenericError(xsltGenericErrorContext, xsltTransformError(NULL, topStyle, NULL,
"xsl:attribute-set : use-attribute-sets recursion detected on %s\n", "xsl:attribute-set : use-attribute-sets maximum recursion "
name); "depth exceeded on %s\n", name);
topStyle->errors++;
return; return;
} }
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); set->state = ATTRSET_RESOLVING;
if (refs == NULL) {
xsltGenericError(xsltGenericErrorContext, xsltResolveUseAttrSets(set, topStyle, depth);
"xsl:attribute-set : use-attribute-sets %s reference missing %s\n",
name, tmp->set); /* Merge imported sets. */
} else { cur = xsltNextImport(style);
/* while (cur != NULL) {
* recurse first for cleanup if (cur->attributeSets != NULL) {
*/ other = xmlHashLookup2(cur->attributeSets, name, ns);
xsltResolveSASCallbackInt(refs, style, name, ns, depth + 1);
/* if (other != NULL) {
* Then merge #ifdef WITH_XSLT_DEBUG_ATTRIBUTES
*/ xsltGenericDebug(xsltGenericDebugContext,
xsltMergeAttrElemList(style, values, refs); "xsl:attribute-set : merging import for %s\n", name);
/* #endif
* Then suppress the reference xsltResolveUseAttrSets(other, topStyle, depth);
*/ xsltMergeAttrSets(set, other);
tmp->set = NULL; xmlHashRemoveEntry2(cur->attributeSets, name, ns, NULL);
tmp->ns = NULL; xsltFreeAttrSet(other);
} }
} }
}
tmp = tmp->next; cur = xsltNextImport(cur);
} }
set->state = ATTRSET_RESOLVED;
} }
/** /**
* xsltResolveSASCallback,: * xsltResolveSASCallback:
* @style: the XSLT stylesheet * @set: the attribute set
* @asctx: the context for attribute set resolution
* @name: the local name of the attirbute set
* @ns: the namespace of the attribute set
* *
* resolve the references in an attribute set. * resolve the references in an attribute set.
*/ */
static void static void
xsltResolveSASCallback(xsltAttrElemPtr values, xsltStylesheetPtr style, xsltResolveSASCallback(xsltAttrSetPtr set, xsltAttrSetContextPtr asctx,
const xmlChar *name, const xmlChar *ns, const xmlChar *name, const xmlChar *ns,
ATTRIBUTE_UNUSED const xmlChar *ignored) { ATTRIBUTE_UNUSED const xmlChar *ignored) {
xsltResolveSASCallbackInt(values, style, name, ns, 1); xsltStylesheetPtr topStyle = asctx->topStyle;
} xsltStylesheetPtr style = asctx->style;
/** xsltResolveAttrSet(set, topStyle, style, name, ns, 1);
* 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); /* Move attribute sets to top stylesheet. */
if (ret < 0) { if (style != topStyle) {
/* /*
* Add failed, this attribute set can be removed. * This imported stylesheet won't be visited anymore. Don't bother
*/ * removing the hash entry.
#ifdef WITH_XSLT_DEBUG_ATTRIBUTES */
xsltGenericDebug(xsltGenericDebugContext, if (xmlHashAddEntry2(topStyle->attributeSets, name, ns, set) < 0) {
"attribute set %s present already in top stylesheet"
" - merging\n", name);
#endif
topSet = xmlHashLookup2(style->attributeSets, name, ns);
if (topSet==NULL) {
xsltGenericError(xsltGenericErrorContext, xsltGenericError(xsltGenericErrorContext,
"xsl:attribute-set : logic error merging from imports for" "xsl:attribute-set : internal error, can't move imported "
" attribute-set %s\n", name); " 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
} }
} }
@ -572,15 +667,14 @@ xsltMergeSASCallback(xsltAttrElemPtr values, xsltStylesheetPtr style,
void void
xsltResolveStylesheetAttributeSet(xsltStylesheetPtr style) { xsltResolveStylesheetAttributeSet(xsltStylesheetPtr style) {
xsltStylesheetPtr cur; xsltStylesheetPtr cur;
xsltAttrSetContext asctx;
#ifdef WITH_XSLT_DEBUG_ATTRIBUTES #ifdef WITH_XSLT_DEBUG_ATTRIBUTES
xsltGenericDebug(xsltGenericDebugContext, xsltGenericDebug(xsltGenericDebugContext,
"Resolving attribute sets references\n"); "Resolving attribute sets references\n");
#endif #endif
/* asctx.topStyle = style;
* First aggregate all the attribute sets definitions from the imports cur = style;
*/
cur = xsltNextImport(style);
while (cur != NULL) { while (cur != NULL) {
if (cur->attributeSets != NULL) { if (cur->attributeSets != NULL) {
if (style->attributeSets == NULL) { if (style->attributeSets == NULL) {
@ -590,43 +684,37 @@ xsltResolveStylesheetAttributeSet(xsltStylesheetPtr style) {
#endif #endif
style->attributeSets = xmlHashCreate(10); style->attributeSets = xmlHashCreate(10);
} }
asctx.style = cur;
xmlHashScanFull(cur->attributeSets, xmlHashScanFull(cur->attributeSets,
(xmlHashScannerFull) xsltMergeSASCallback, style); (xmlHashScannerFull) xsltResolveSASCallback, &asctx);
/*
* the attribute lists have either been migrated to style if (cur != style) {
* or freed directly in xsltMergeSASCallback() /*
*/ * the attribute lists have either been migrated to style
xmlHashFree(cur->attributeSets, NULL); * or freed directly in xsltResolveSASCallback()
cur->attributeSets = NULL; */
xmlHashFree(cur->attributeSets, NULL);
cur->attributeSets = NULL;
}
} }
cur = xsltNextImport(cur); cur = xsltNextImport(cur);
} }
/*
* Then resolve all the references and computes the resulting sets
*/
if (style->attributeSets != NULL) {
xmlHashScanFull(style->attributeSets,
(xmlHashScannerFull) xsltResolveSASCallback, style);
}
} }
/** /**
* xsltAttributeInternal: * xsltAttribute:
* @ctxt: a XSLT process context * @ctxt: a XSLT process context
* @node: the current node in the source tree * @contextNode: the current node in the source tree
* @inst: the xsl:attribute element * @inst: the xsl:attribute element
* @comp: precomputed information * @castedComp: precomputed information
* @fromAttributeSet: the attribute comes from an attribute-set
* *
* Process the xslt attribute node on the source node * Process the xslt attribute node on the source node
*/ */
static void void
xsltAttributeInternal(xsltTransformContextPtr ctxt, xsltAttribute(xsltTransformContextPtr ctxt,
xmlNodePtr contextNode, xmlNodePtr contextNode,
xmlNodePtr inst, xmlNodePtr inst,
xsltStylePreCompPtr castedComp, xsltStylePreCompPtr castedComp)
int fromAttributeSet)
{ {
#ifdef XSLT_REFACTORED #ifdef XSLT_REFACTORED
xsltStyleItemAttributePtr comp = xsltStyleItemAttributePtr comp =
@ -666,7 +754,7 @@ xsltAttributeInternal(xsltTransformContextPtr ctxt,
if (comp == NULL) { if (comp == NULL) {
xsltTransformError(ctxt, NULL, inst, xsltTransformError(ctxt, NULL, inst,
"Internal error in xsltAttributeInternal(): " "Internal error in xsltAttribute(): "
"The XSLT 'attribute' instruction was not compiled.\n"); "The XSLT 'attribute' instruction was not compiled.\n");
return; return;
} }
@ -831,19 +919,6 @@ xsltAttributeInternal(xsltTransformContextPtr ctxt,
nsName = ns->href; 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. * Find/create a matching ns-decl in the result tree.
*/ */
@ -993,21 +1068,6 @@ error:
return; 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: * xsltApplyAttributeSet:
* @ctxt: the XSLT stylesheet * @ctxt: the XSLT stylesheet
@ -1028,7 +1088,7 @@ xsltApplyAttributeSet(xsltTransformContextPtr ctxt, xmlNodePtr node,
const xmlChar *ncname = NULL; const xmlChar *ncname = NULL;
const xmlChar *prefix = NULL; const xmlChar *prefix = NULL;
const xmlChar *curstr, *endstr; const xmlChar *curstr, *endstr;
xsltAttrElemPtr attrs; xsltAttrSetPtr set;
xsltStylesheetPtr style; xsltStylesheetPtr style;
if (attrSets == NULL) { if (attrSets == NULL) {
@ -1065,15 +1125,32 @@ xsltApplyAttributeSet(xsltTransformContextPtr ctxt, xmlNodePtr node,
endstr++; endstr++;
curstr = xmlDictLookup(ctxt->dict, curstr, endstr - curstr); curstr = xmlDictLookup(ctxt->dict, curstr, endstr - curstr);
if (curstr) { if (curstr) {
/* xmlNsPtr ns;
* TODO: Validate the QName. const xmlChar *nsUri = NULL;
*/
#ifdef WITH_XSLT_DEBUG_curstrUTES #ifdef WITH_XSLT_DEBUG_ATTRIBUTES
xsltGenericDebug(xsltGenericDebugContext, xsltGenericDebug(xsltGenericDebugContext,
"apply curstrute set %s\n", curstr); "apply attribute set %s\n", curstr);
#endif #endif
if (xmlValidateQName(curstr, 0)) {
xsltTransformError(ctxt, NULL, inst,
"The name '%s' in use-attribute-sets is not a valid "
"QName.\n", curstr);
return;
}
ncname = xsltSplitQName(ctxt->dict, curstr, &prefix); ncname = xsltSplitQName(ctxt->dict, curstr, &prefix);
if (prefix != NULL) {
ns = xmlSearchNs(inst->doc, inst, prefix);
if (ns == NULL) {
xsltTransformError(ctxt, NULL, inst,
"use-attribute-set : No namespace found for QName "
"'%s:%s'\n", prefix, ncname);
return;
}
nsUri = ns->href;
}
style = ctxt->style; style = ctxt->style;
@ -1082,27 +1159,28 @@ xsltApplyAttributeSet(xsltTransformContextPtr ctxt, xmlNodePtr node,
(style->attributeSets != NULL) && (style->attributeSets != NULL) &&
(ctxt->debugStatus != XSLT_DEBUG_NONE)) (ctxt->debugStatus != XSLT_DEBUG_NONE))
{ {
attrs = set = xmlHashLookup2(style->attributeSets, ncname, nsUri);
xmlHashLookup2(style->attributeSets, ncname, prefix); if ((set != NULL) && (set->attrs != NULL) &&
if ((attrs != NULL) && (attrs->attr != NULL)) (set->attrs->attr != NULL))
xslHandleDebugger(attrs->attr->parent, node, NULL, xslHandleDebugger(set->attrs->attr->parent, node, NULL,
ctxt); ctxt);
} }
#endif #endif
/* /*
* Lookup the referenced curstrute-set. * Lookup the referenced attribute-set. All attribute sets were
* moved to the top stylesheet so there's no need to iterate
* imported stylesheets
*/ */
while (style != NULL) { set = xmlHashLookup2(style->attributeSets, ncname, nsUri);
attrs = if (set != NULL) {
xmlHashLookup2(style->attributeSets, ncname, prefix); xsltAttrElemPtr cur = set->attrs;
while (attrs != NULL) { while (cur != NULL) {
if (attrs->attr != NULL) { if (cur->attr != NULL) {
xsltAttributeInternal(ctxt, node, attrs->attr, xsltAttribute(ctxt, node, cur->attr,
attrs->attr->psvi, 1); cur->attr->psvi);
} }
attrs = attrs->next; cur = cur->next;
} }
style = xsltNextImport(style);
} }
} }
curstr = endstr; curstr = endstr;
@ -1119,6 +1197,6 @@ void
xsltFreeAttributeSetsHashes(xsltStylesheetPtr style) { xsltFreeAttributeSetsHashes(xsltStylesheetPtr style) {
if (style->attributeSets != NULL) if (style->attributeSets != NULL)
xmlHashFree((xmlHashTablePtr) style->attributeSets, xmlHashFree((xmlHashTablePtr) style->attributeSets,
(xmlHashDeallocator) xsltFreeAttrElemList); (xmlHashDeallocator) xsltFreeAttrSet);
style->attributeSets = NULL; style->attributeSets = NULL;
} }

View file

@ -372,8 +372,7 @@ xsltExtModuleRegisterDynamic(const xmlChar * URI)
/* build the module filename, and confirm the module exists */ /* build the module filename, and confirm the module exists */
xmlStrPrintf((xmlChar *) module_filename, sizeof(module_filename), xmlStrPrintf((xmlChar *) module_filename, sizeof(module_filename),
BAD_CAST "%s/%s%s", "%s/%s%s", ext_directory, ext_name, LIBXML_MODULE_EXTENSION);
ext_directory, ext_name, LIBXML_MODULE_EXTENSION);
#ifdef WITH_XSLT_DEBUG_EXTENSIONS #ifdef WITH_XSLT_DEBUG_EXTENSIONS
xsltGenericDebug(xsltGenericDebugContext, xsltGenericDebug(xsltGenericDebugContext,

View file

@ -76,7 +76,10 @@ xsltDebug(xsltTransformContextPtr ctxt, xmlNodePtr node ATTRIBUTE_UNUSED,
xsltGenericError(xsltGenericErrorContext, "noname !!!!"); xsltGenericError(xsltGenericErrorContext, "noname !!!!");
#ifdef LIBXML_DEBUG_ENABLED #ifdef LIBXML_DEBUG_ENABLED
if (cur->value != NULL) { if (cur->value != NULL) {
xmlXPathDebugDumpObject(stdout, cur->value, 1); if ((xsltGenericDebugContext == stdout) ||
(xsltGenericDebugContext == stderr))
xmlXPathDebugDumpObject((FILE*)xsltGenericDebugContext,
cur->value, 1);
} else { } else {
xsltGenericError(xsltGenericErrorContext, "NULL !!!!"); xsltGenericError(xsltGenericErrorContext, "NULL !!!!");
} }
@ -125,134 +128,6 @@ xsltFunctionNodeSet(xmlXPathParserContextPtr ctxt, int nargs){
} }
} }
/*
* Okay the following really seems unportable and since it's not
* part of any standard I'm not too ashamed to do this
*/
#if defined(linux) || defined(__sun)
#if defined(HAVE_MKTIME) && defined(HAVE_LOCALTIME) && defined(HAVE_ASCTIME)
#define WITH_LOCALTIME
/**
* xsltFunctionLocalTime:
* @ctxt: the XPath Parser context
* @nargs: the number of arguments
*
* Implement the localTime XSLT function used by NORM
* string localTime(???)
*
* This function is available in Norm's extension namespace
* Code (and comments) contributed by Norm
*/
static void
xsltFunctionLocalTime(xmlXPathParserContextPtr ctxt, int nargs) {
xmlXPathObjectPtr obj;
char *str;
char digits[5];
char result[29];
long int field;
time_t gmt, lmt;
struct tm gmt_tm;
struct tm *local_tm;
if (nargs != 1) {
xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
"localTime() : invalid number of args %d\n", nargs);
ctxt->error = XPATH_INVALID_ARITY;
return;
}
obj = valuePop(ctxt);
if (obj->type != XPATH_STRING) {
obj = xmlXPathConvertString(obj);
}
if (obj == NULL) {
valuePush(ctxt, xmlXPathNewString((const xmlChar *)""));
return;
}
str = (char *) obj->stringval;
/* str = "$Date$" */
memset(digits, 0, sizeof(digits));
strncpy(digits, str+7, 4);
field = strtol(digits, NULL, 10);
gmt_tm.tm_year = field - 1900;
memset(digits, 0, sizeof(digits));
strncpy(digits, str+12, 2);
field = strtol(digits, NULL, 10);
gmt_tm.tm_mon = field - 1;
memset(digits, 0, sizeof(digits));
strncpy(digits, str+15, 2);
field = strtol(digits, NULL, 10);
gmt_tm.tm_mday = field;
memset(digits, 0, sizeof(digits));
strncpy(digits, str+18, 2);
field = strtol(digits, NULL, 10);
gmt_tm.tm_hour = field;
memset(digits, 0, sizeof(digits));
strncpy(digits, str+21, 2);
field = strtol(digits, NULL, 10);
gmt_tm.tm_min = field;
memset(digits, 0, sizeof(digits));
strncpy(digits, str+24, 2);
field = strtol(digits, NULL, 10);
gmt_tm.tm_sec = field;
/* Now turn gmt_tm into a time. */
gmt = mktime(&gmt_tm);
/*
* FIXME: it's been too long since I did manual memory management.
* (I swore never to do it again.) Does this introduce a memory leak?
*/
local_tm = localtime(&gmt);
/*
* Calling localtime() has the side-effect of setting timezone.
* After we know the timezone, we can adjust for it
*/
#if !defined(__FreeBSD__)
lmt = gmt - timezone;
#else /* FreeBSD DOESN'T have such side-ffect */
lmt = gmt - local_tm->tm_gmtoff;
#endif
/*
* FIXME: it's been too long since I did manual memory management.
* (I swore never to do it again.) Does this introduce a memory leak?
*/
local_tm = localtime(&lmt);
/*
* Now convert local_tm back into a string. This doesn't introduce
* a memory leak, so says asctime(3).
*/
str = asctime(local_tm); /* "Tue Jun 26 05:02:16 2001" */
/* 0123456789 123456789 123 */
memset(result, 0, sizeof(result)); /* "Thu, 26 Jun 2001" */
/* 0123456789 12345 */
strncpy(result, str, 20);
strcpy(result+20, "???"); /* tzname doesn't work, fake it */
strncpy(result+23, str+19, 5);
/* Ok, now result contains the string I want to send back. */
valuePush(ctxt, xmlXPathNewString((xmlChar *)result));
}
#endif
#endif /* linux or sun */
/** /**
* xsltRegisterExtras: * xsltRegisterExtras:
* @ctxt: a XSLT process context * @ctxt: a XSLT process context
@ -281,11 +156,6 @@ xsltRegisterAllExtras (void) {
xsltRegisterExtModuleFunction((const xmlChar *) "node-set", xsltRegisterExtModuleFunction((const xmlChar *) "node-set",
XSLT_XT_NAMESPACE, XSLT_XT_NAMESPACE,
xsltFunctionNodeSet); xsltFunctionNodeSet);
#ifdef WITH_LOCALTIME
xsltRegisterExtModuleFunction((const xmlChar *) "localTime",
XSLT_NORM_SAXON_NAMESPACE,
xsltFunctionLocalTime);
#endif
xsltRegisterExtModuleElement((const xmlChar *) "debug", xsltRegisterExtModuleElement((const xmlChar *) "debug",
XSLT_LIBXSLT_NAMESPACE, XSLT_LIBXSLT_NAMESPACE,
NULL, NULL,

View file

@ -48,14 +48,6 @@ extern "C" {
#define XSLT_XALAN_NAMESPACE ((xmlChar *) \ #define XSLT_XALAN_NAMESPACE ((xmlChar *) \
"org.apache.xalan.xslt.extensions.Redirect") "org.apache.xalan.xslt.extensions.Redirect")
/**
* XSLT_NORM_SAXON_NAMESPACE:
*
* This is Norm's namespace for SAXON extensions.
*/
#define XSLT_NORM_SAXON_NAMESPACE ((xmlChar *) \
"http://nwalsh.com/xslt/ext/com.nwalsh.saxon.CVS")
XSLTPUBFUN void XSLTCALL XSLTPUBFUN void XSLTCALL
xsltFunctionNodeSet (xmlXPathParserContextPtr ctxt, xsltFunctionNodeSet (xmlXPathParserContextPtr ctxt,

View file

@ -575,12 +575,15 @@ xsltFormatNumberFunction(xmlXPathParserContextPtr ctxt, int nargs)
xmlXPathObjectPtr formatObj = NULL; xmlXPathObjectPtr formatObj = NULL;
xmlXPathObjectPtr decimalObj = NULL; xmlXPathObjectPtr decimalObj = NULL;
xsltStylesheetPtr sheet; xsltStylesheetPtr sheet;
xsltDecimalFormatPtr formatValues; xsltDecimalFormatPtr formatValues = NULL;
xmlChar *result; xmlChar *result;
const xmlChar *ncname;
const xmlChar *prefix = NULL;
const xmlChar *nsUri = NULL;
xsltTransformContextPtr tctxt; xsltTransformContextPtr tctxt;
tctxt = xsltXPathGetTransformContext(ctxt); tctxt = xsltXPathGetTransformContext(ctxt);
if (tctxt == NULL) if ((tctxt == NULL) || (tctxt->inst == NULL))
return; return;
sheet = tctxt->style; sheet = tctxt->style;
if (sheet == NULL) if (sheet == NULL)
@ -591,7 +594,23 @@ xsltFormatNumberFunction(xmlXPathParserContextPtr ctxt, int nargs)
case 3: case 3:
CAST_TO_STRING; CAST_TO_STRING;
decimalObj = valuePop(ctxt); decimalObj = valuePop(ctxt);
formatValues = xsltDecimalFormatGetByName(sheet, decimalObj->stringval); ncname = xsltSplitQName(sheet->dict, decimalObj->stringval, &prefix);
if (prefix != NULL) {
xmlNsPtr ns = xmlSearchNs(tctxt->inst->doc, tctxt->inst, prefix);
if (ns == NULL) {
xsltTransformError(tctxt, NULL, NULL,
"format-number : No namespace found for QName '%s:%s'\n",
prefix, ncname);
sheet->errors++;
ncname = NULL;
}
else {
nsUri = ns->href;
}
}
if (ncname != NULL) {
formatValues = xsltDecimalFormatGetByQName(sheet, nsUri, ncname);
}
if (formatValues == NULL) { if (formatValues == NULL) {
xsltTransformError(tctxt, NULL, NULL, xsltTransformError(tctxt, NULL, NULL,
"format-number() : undeclared decimal format '%s'\n", "format-number() : undeclared decimal format '%s'\n",
@ -807,7 +826,7 @@ xsltElementAvailableFunction(xmlXPathParserContextPtr ctxt, int nargs){
} }
obj = valuePop(ctxt); obj = valuePop(ctxt);
tctxt = xsltXPathGetTransformContext(ctxt); tctxt = xsltXPathGetTransformContext(ctxt);
if (tctxt == NULL) { if ((tctxt == NULL) || (tctxt->inst == NULL)) {
xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
"element-available() : internal error tctxt == NULL\n"); "element-available() : internal error tctxt == NULL\n");
xmlXPathFreeObject(obj); xmlXPathFreeObject(obj);
@ -822,7 +841,7 @@ xsltElementAvailableFunction(xmlXPathParserContextPtr ctxt, int nargs){
name = xmlStrdup(obj->stringval); name = xmlStrdup(obj->stringval);
ns = xmlSearchNs(tctxt->inst->doc, tctxt->inst, NULL); ns = xmlSearchNs(tctxt->inst->doc, tctxt->inst, NULL);
if (ns != NULL) nsURI = xmlStrdup(ns->href); if (ns != NULL) nsURI = ns->href;
} else { } else {
nsURI = xmlXPathNsLookup(ctxt->context, prefix); nsURI = xmlXPathNsLookup(ctxt->context, prefix);
if (nsURI == NULL) { if (nsURI == NULL) {

View file

@ -384,10 +384,13 @@ xsltAddKey(xsltStylesheetPtr style, const xmlChar *name,
prev->next = key; prev->next = key;
} }
key->next = NULL; key->next = NULL;
key = NULL;
error: error:
if (pattern != NULL) if (pattern != NULL)
xmlFree(pattern); xmlFree(pattern);
if (key != NULL)
xsltFreeKeyDef(key);
return(0); return(0);
} }

View file

@ -48,39 +48,11 @@ static xsltFormatToken default_token;
/* /*
* **** Start temp insert **** * **** Start temp insert ****
* *
* The following two routines (xsltUTF8Size and xsltUTF8Charcmp) * The following routine xsltUTF8Charcmp will be replaced with calls to
* will be replaced with calls to the corresponding libxml routines * the corresponding libxml routine at a later date (when other
* at a later date (when other inter-library dependencies require it) * 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 * xsltUTF8Charcmp
* @utf1: pointer to first UTF8 char * @utf1: pointer to first UTF8 char
@ -91,13 +63,16 @@ xsltUTF8Size(xmlChar *utf) {
*/ */
static int static int
xsltUTF8Charcmp(xmlChar *utf1, xmlChar *utf2) { xsltUTF8Charcmp(xmlChar *utf1, xmlChar *utf2) {
int len = xmlUTF8Strsize(utf1, 1);
if (len < 1)
return -1;
if (utf1 == NULL ) { if (utf1 == NULL ) {
if (utf2 == NULL) if (utf2 == NULL)
return 0; return 0;
return -1; return -1;
} }
return xmlStrncmp(utf1, utf2, xsltUTF8Size(utf1)); return xmlStrncmp(utf1, utf2, len);
} }
/***** Stop temp insert *****/ /***** Stop temp insert *****/
@ -205,7 +180,7 @@ xsltNumberFormatDecimal(xmlBufferPtr buffer,
} }
if (i < 0) if (i < 0)
xsltGenericError(xsltGenericErrorContext, xsltGenericError(xsltGenericErrorContext,
"xsltNumberFormatDecimal: Internal buffer size exceeded"); "xsltNumberFormatDecimal: Internal buffer size exceeded\n");
xmlBufferCat(buffer, pointer); xmlBufferCat(buffer, pointer);
} }
@ -599,25 +574,7 @@ xsltNumberFormatGetAnyLevel(xsltTransformContextPtr context,
{ {
int amount = 0; int amount = 0;
int cnt = 0; int cnt = 0;
xmlNodePtr cur; xmlNodePtr cur = node;
/* 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) { while (cur != NULL) {
/* process current node */ /* process current node */
@ -636,16 +593,25 @@ xsltNumberFormatGetAnyLevel(xsltTransformContextPtr context,
(cur->type == XML_HTML_DOCUMENT_NODE)) (cur->type == XML_HTML_DOCUMENT_NODE))
break; /* while */ break; /* while */
while ((cur->prev != NULL) && ((cur->prev->type == XML_DTD_NODE) || if (cur->type == XML_NAMESPACE_DECL) {
(cur->prev->type == XML_XINCLUDE_START) || /*
(cur->prev->type == XML_XINCLUDE_END))) * The XPath module stores the parent of a namespace node in
cur = cur->prev; * the ns->next field.
if (cur->prev != NULL) { */
for (cur = cur->prev; cur->last != NULL; cur = cur->last); cur = (xmlNodePtr) ((xmlNsPtr) cur)->next;
} else { } else if (cur->type == XML_ATTRIBUTE_NODE) {
cur = cur->parent; cur = cur->parent;
} } else {
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; array[amount++] = (double) cnt;
@ -891,7 +857,7 @@ xsltFormatNumberPreSuffix(xsltDecimalFormatPtr self, xmlChar **format, xsltForma
} }
} }
if ((len=xsltUTF8Size(*format)) < 1) if ((len=xmlUTF8Strsize(*format, 1)) < 1)
return -1; return -1;
count += len; count += len;
*format += len; *format += len;
@ -1073,7 +1039,7 @@ xsltFormatNumberConversion(xsltDecimalFormatPtr self,
} else } else
break; /* while */ break; /* while */
if ((len=xsltUTF8Size(the_format)) < 1) { if ((len=xmlUTF8Strsize(the_format, 1)) < 1) {
found_error = 1; found_error = 1;
goto OUTPUT_NUMBER; goto OUTPUT_NUMBER;
} }
@ -1082,9 +1048,14 @@ xsltFormatNumberConversion(xsltDecimalFormatPtr self,
} }
/* We have finished the integer part, now work on fraction */ /* We have finished the integer part, now work on fraction */
if (xsltUTF8Charcmp(the_format, self->decimalPoint) == 0) { if ( (*the_format != 0) &&
(xsltUTF8Charcmp(the_format, self->decimalPoint) == 0) ) {
format_info.add_decimal = TRUE; format_info.add_decimal = TRUE;
the_format += xsltUTF8Size(the_format); /* Skip over the decimal */ if ((len = xmlUTF8Strsize(the_format, 1)) < 1) {
found_error = 1;
goto OUTPUT_NUMBER;
}
the_format += len; /* Skip over the decimal */
} }
while (*the_format != 0) { while (*the_format != 0) {
@ -1103,7 +1074,7 @@ xsltFormatNumberConversion(xsltDecimalFormatPtr self,
goto OUTPUT_NUMBER; goto OUTPUT_NUMBER;
} }
delayed_multiplier = 100; delayed_multiplier = 100;
if ((len = xsltUTF8Size(the_format)) < 1) { if ((len = xmlUTF8Strsize(the_format, 1)) < 1) {
found_error = 1; found_error = 1;
goto OUTPUT_NUMBER; goto OUTPUT_NUMBER;
} }
@ -1115,7 +1086,7 @@ xsltFormatNumberConversion(xsltDecimalFormatPtr self,
goto OUTPUT_NUMBER; goto OUTPUT_NUMBER;
} }
delayed_multiplier = 1000; delayed_multiplier = 1000;
if ((len = xsltUTF8Size(the_format)) < 1) { if ((len = xmlUTF8Strsize(the_format, 1)) < 1) {
found_error = 1; found_error = 1;
goto OUTPUT_NUMBER; goto OUTPUT_NUMBER;
} }
@ -1124,7 +1095,7 @@ xsltFormatNumberConversion(xsltDecimalFormatPtr self,
} else if (xsltUTF8Charcmp(the_format, self->grouping) != 0) { } else if (xsltUTF8Charcmp(the_format, self->grouping) != 0) {
break; /* while */ break; /* while */
} }
if ((len = xsltUTF8Size(the_format)) < 1) { if ((len = xmlUTF8Strsize(the_format, 1)) < 1) {
found_error = 1; found_error = 1;
goto OUTPUT_NUMBER; goto OUTPUT_NUMBER;
} }
@ -1201,7 +1172,7 @@ xsltFormatNumberConversion(xsltDecimalFormatPtr self,
delayed_multiplier = 0; delayed_multiplier = 0;
else else
break; /* while */ break; /* while */
if ((len = xsltUTF8Size(the_format)) < 1) { if ((len = xmlUTF8Strsize(the_format, 1)) < 1) {
found_error = 1; found_error = 1;
goto OUTPUT_NUMBER; goto OUTPUT_NUMBER;
} }
@ -1267,12 +1238,12 @@ OUTPUT_NUMBER:
/* Ready to output our number. First see if "default sign" is required */ /* Ready to output our number. First see if "default sign" is required */
if (default_sign != 0) if (default_sign != 0)
xmlBufferAdd(buffer, self->minusSign, xsltUTF8Size(self->minusSign)); xmlBufferAdd(buffer, self->minusSign, xmlUTF8Strsize(self->minusSign, 1));
/* Put the prefix into the buffer */ /* Put the prefix into the buffer */
for (j = 0; j < prefix_length; j++) { for (j = 0; j < prefix_length; j++) {
if ((pchar = *prefix++) == SYMBOL_QUOTE) { if ((pchar = *prefix++) == SYMBOL_QUOTE) {
len = xsltUTF8Size(prefix); len = xmlUTF8Strsize(prefix, 1);
xmlBufferAdd(buffer, prefix, len); xmlBufferAdd(buffer, prefix, len);
prefix += len; prefix += len;
j += len - 1; /* length of symbol less length of quote */ j += len - 1; /* length of symbol less length of quote */
@ -1309,20 +1280,20 @@ OUTPUT_NUMBER:
/* Add leading zero, if required */ /* Add leading zero, if required */
if ((floor(number) == 0) && if ((floor(number) == 0) &&
(format_info.integer_digits + format_info.frac_digits == 0)) { (format_info.integer_digits + format_info.frac_digits == 0)) {
xmlBufferAdd(buffer, self->zeroDigit, xsltUTF8Size(self->zeroDigit)); xmlBufferAdd(buffer, self->zeroDigit, xmlUTF8Strsize(self->zeroDigit, 1));
} }
/* Next the fractional part, if required */ /* Next the fractional part, if required */
if (format_info.frac_digits + format_info.frac_hash == 0) { if (format_info.frac_digits + format_info.frac_hash == 0) {
if (format_info.add_decimal) if (format_info.add_decimal)
xmlBufferAdd(buffer, self->decimalPoint, xmlBufferAdd(buffer, self->decimalPoint,
xsltUTF8Size(self->decimalPoint)); xmlUTF8Strsize(self->decimalPoint, 1));
} }
else { else {
number -= floor(number); number -= floor(number);
if ((number != 0) || (format_info.frac_digits != 0)) { if ((number != 0) || (format_info.frac_digits != 0)) {
xmlBufferAdd(buffer, self->decimalPoint, xmlBufferAdd(buffer, self->decimalPoint,
xsltUTF8Size(self->decimalPoint)); xmlUTF8Strsize(self->decimalPoint, 1));
number = floor(scale * number + 0.5); number = floor(scale * number + 0.5);
for (j = format_info.frac_hash; j > 0; j--) { for (j = format_info.frac_hash; j > 0; j--) {
if (fmod(number, 10.0) >= 1.0) if (fmod(number, 10.0) >= 1.0)
@ -1337,7 +1308,7 @@ OUTPUT_NUMBER:
/* Put the suffix into the buffer */ /* Put the suffix into the buffer */
for (j = 0; j < suffix_length; j++) { for (j = 0; j < suffix_length; j++) {
if ((pchar = *suffix++) == SYMBOL_QUOTE) { if ((pchar = *suffix++) == SYMBOL_QUOTE) {
len = xsltUTF8Size(suffix); len = xmlUTF8Strsize(suffix, 1);
xmlBufferAdd(buffer, suffix, len); xmlBufferAdd(buffer, suffix, len);
suffix += len; suffix += len;
j += len - 1; /* length of symbol less length of escape */ j += len - 1; /* length of symbol less length of escape */

View file

@ -85,6 +85,7 @@ struct _xsltCompMatch {
const xmlChar *mode; /* the mode */ const xmlChar *mode; /* the mode */
const xmlChar *modeURI; /* the mode URI */ const xmlChar *modeURI; /* the mode URI */
xsltTemplatePtr template; /* the associated template */ xsltTemplatePtr template; /* the associated template */
xmlNodePtr node; /* the containing element */
int direct; int direct;
/* TODO fix the statically allocated size steps[] */ /* TODO fix the statically allocated size steps[] */
@ -895,7 +896,9 @@ xsltTestCompMatch(xsltTransformContextPtr ctxt, xsltCompMatchPtr comp,
xmlNodePtr matchNode, const xmlChar *mode, xmlNodePtr matchNode, const xmlChar *mode,
const xmlChar *modeURI) { const xmlChar *modeURI) {
int i; int i;
int found = 0;
xmlNodePtr node = matchNode; xmlNodePtr node = matchNode;
xmlNodePtr oldInst;
xsltStepOpPtr step, sel = NULL; xsltStepOpPtr step, sel = NULL;
xsltStepStates states = {0, 0, NULL}; /* // may require backtrack */ xsltStepStates states = {0, 0, NULL}; /* // may require backtrack */
@ -929,6 +932,10 @@ xsltTestCompMatch(xsltTransformContextPtr ctxt, xsltCompMatchPtr comp,
return(0); return(0);
} }
/* Some XPath functions rely on inst being set correctly. */
oldInst = ctxt->inst;
ctxt->inst = comp->node;
i = 0; i = 0;
restart: restart:
for (;i < comp->nbStep;i++) { for (;i < comp->nbStep;i++) {
@ -1121,12 +1128,9 @@ restart:
* as possible this costly computation. * as possible this costly computation.
*/ */
if (comp->direct) { if (comp->direct) {
if (states.states != NULL) { found = xsltTestCompMatchDirect(ctxt, comp, matchNode,
/* Free the rollback states */ comp->nsList, comp->nsNr);
xmlFree(states.states); goto exit;
}
return(xsltTestCompMatchDirect(ctxt, comp, matchNode,
comp->nsList, comp->nsNr));
} }
if (!xsltTestPredicateMatch(ctxt, comp, node, step, sel)) if (!xsltTestPredicateMatch(ctxt, comp, node, step, sel))
@ -1166,18 +1170,19 @@ restart:
} }
} }
found: found:
found = 1;
exit:
ctxt->inst = oldInst;
if (states.states != NULL) { if (states.states != NULL) {
/* Free the rollback states */ /* Free the rollback states */
xmlFree(states.states); xmlFree(states.states);
} }
return(1); return found;
rollback: rollback:
/* got an error try to rollback */ /* got an error try to rollback */
if (states.states == NULL) if (states.states == NULL || states.nbstates <= 0) {
return(0); found = 0;
if (states.nbstates <= 0) { goto exit;
xmlFree(states.states);
return(0);
} }
states.nbstates--; states.nbstates--;
i = states.states[states.nbstates].step; i = states.states[states.nbstates].step;
@ -1456,6 +1461,7 @@ xsltCompileIdKeyPattern(xsltParserContextPtr ctxt, xmlChar *name,
xsltTransformError(NULL, NULL, NULL, xsltTransformError(NULL, NULL, NULL,
"xsltCompileIdKeyPattern : ) expected\n"); "xsltCompileIdKeyPattern : ) expected\n");
ctxt->error = 1; ctxt->error = 1;
xmlFree(lit);
return; return;
} }
} }
@ -1618,6 +1624,7 @@ parse_node_test:
xsltTransformError(NULL, NULL, NULL, xsltTransformError(NULL, NULL, NULL,
"xsltCompileStepPattern : Name expected\n"); "xsltCompileStepPattern : Name expected\n");
ctxt->error = 1; ctxt->error = 1;
xmlFree(URL);
goto error; goto error;
} }
} else { } else {
@ -1925,6 +1932,7 @@ xsltCompilePatternInternal(const xmlChar *pattern, xmlDocPtr doc,
goto error; goto error;
ctxt->cur = &(ctxt->base)[current - start]; ctxt->cur = &(ctxt->base)[current - start];
element->pattern = ctxt->base; element->pattern = ctxt->base;
element->node = node;
element->nsList = xmlGetNsList(doc, node); element->nsList = xmlGetNsList(doc, node);
j = 0; j = 0;
if (element->nsList != NULL) { if (element->nsList != NULL) {

View file

@ -1394,9 +1394,6 @@ xsltNumberComp(xsltStylesheetPtr style, xmlNodePtr cur) {
return; return;
cur->psvi = comp; cur->psvi = comp;
if ((style == NULL) || (cur == NULL))
return;
comp->numdata.doc = cur->doc; comp->numdata.doc = cur->doc;
comp->numdata.node = cur; comp->numdata.node = cur;
comp->numdata.value = xsltGetCNsProp(style, cur, (const xmlChar *)"value", comp->numdata.value = xsltGetCNsProp(style, cur, (const xmlChar *)"value",
@ -2319,7 +2316,7 @@ xsltStylePreCompute(xsltStylesheetPtr style, xmlNodePtr inst) {
xsltCheckInstructionElement(style, inst); xsltCheckInstructionElement(style, inst);
inst->psvi = (void *) xsltDocumentComp(style, inst, inst->psvi = (void *) xsltDocumentComp(style, inst,
(xsltTransformFunction) xsltDocumentElem); (xsltTransformFunction) xsltDocumentElem);
} else { } else if ((style == NULL) || (style->forwards_compatible == 0)) {
xsltTransformError(NULL, style, inst, xsltTransformError(NULL, style, inst,
"xsltStylePreCompute: unknown xsl:%s\n", inst->name); "xsltStylePreCompute: unknown xsl:%s\n", inst->name);
if (style != NULL) style->warnings++; if (style != NULL) style->warnings++;

View file

@ -246,7 +246,7 @@ xsltCheckFilename (const char *path)
{ {
#ifdef HAVE_STAT #ifdef HAVE_STAT
struct stat stat_buffer; struct stat stat_buffer;
#if defined(WIN32) && !defined(__CYGWIN__) #if defined(_WIN32) && !defined(__CYGWIN__)
DWORD dwAttrs; DWORD dwAttrs;
dwAttrs = GetFileAttributes(path); dwAttrs = GetFileAttributes(path);
@ -351,7 +351,7 @@ xsltCheckWrite(xsltSecurityPrefsPtr sec,
if ((uri->scheme == NULL) || if ((uri->scheme == NULL) ||
(xmlStrEqual(BAD_CAST uri->scheme, BAD_CAST "file"))) { (xmlStrEqual(BAD_CAST uri->scheme, BAD_CAST "file"))) {
#if defined(WIN32) && !defined(__CYGWIN__) #if defined(_WIN32) && !defined(__CYGWIN__)
if ((uri->path)&&(uri->path[0]=='/')&& if ((uri->path)&&(uri->path[0]=='/')&&
(uri->path[1]!='\0')&&(uri->path[2]==':')) (uri->path[1]!='\0')&&(uri->path[2]==':'))
ret = xsltCheckWritePath(sec, ctxt, uri->path+1); ret = xsltCheckWritePath(sec, ctxt, uri->path+1);

View file

@ -45,6 +45,12 @@ xsltEvalXPathPredicate(xsltTransformContextPtr ctxt, xmlXPathCompExprPtr comp,
xmlNodePtr oldInst; xmlNodePtr oldInst;
int oldProximityPosition, oldContextSize; int oldProximityPosition, oldContextSize;
if ((ctxt == NULL) || (ctxt->inst == NULL)) {
xsltTransformError(ctxt, NULL, NULL,
"xsltEvalXPathPredicate: No context or instruction\n");
return(0);
}
oldContextSize = ctxt->xpathCtxt->contextSize; oldContextSize = ctxt->xpathCtxt->contextSize;
oldProximityPosition = ctxt->xpathCtxt->proximityPosition; oldProximityPosition = ctxt->xpathCtxt->proximityPosition;
oldNsNr = ctxt->xpathCtxt->nsNr; oldNsNr = ctxt->xpathCtxt->nsNr;
@ -106,6 +112,12 @@ xsltEvalXPathStringNs(xsltTransformContextPtr ctxt, xmlXPathCompExprPtr comp,
int oldNsNr; int oldNsNr;
xmlNsPtr *oldNamespaces; xmlNsPtr *oldNamespaces;
if ((ctxt == NULL) || (ctxt->inst == NULL)) {
xsltTransformError(ctxt, NULL, NULL,
"xsltEvalXPathStringNs: No context or instruction\n");
return(0);
}
oldInst = ctxt->inst; oldInst = ctxt->inst;
oldNode = ctxt->node; oldNode = ctxt->node;
oldPos = ctxt->xpathCtxt->proximityPosition; oldPos = ctxt->xpathCtxt->proximityPosition;
@ -278,12 +290,12 @@ xsltAttrTemplateValueProcessNode(xsltTransformContextPtr ctxt,
xsltTransformError(ctxt, NULL, inst, xsltTransformError(ctxt, NULL, inst,
"xsltAttrTemplateValueProcessNode: unmatched '{'\n"); "xsltAttrTemplateValueProcessNode: unmatched '{'\n");
ret = xmlStrncat(ret, str, cur - str); ret = xmlStrncat(ret, str, cur - str);
return(ret); goto exit;
} }
str++; str++;
expr = xmlStrndup(str, cur - str); expr = xmlStrndup(str, cur - str);
if (expr == NULL) if (expr == NULL)
return(ret); goto exit;
else if (*expr == '{') { else if (*expr == '{') {
ret = xmlStrcat(ret, expr); ret = xmlStrcat(ret, expr);
xmlFree(expr); xmlFree(expr);
@ -331,6 +343,7 @@ xsltAttrTemplateValueProcessNode(xsltTransformContextPtr ctxt,
ret = xmlStrncat(ret, str, cur - str); ret = xmlStrncat(ret, str, cur - str);
} }
exit:
if (nsList != NULL) if (nsList != NULL)
xmlFree(nsList); xmlFree(nsList);

View file

@ -23,6 +23,7 @@
#ifdef WITH_XSLT_DEBUG #ifdef WITH_XSLT_DEBUG
#define WITH_XSLT_DEBUG_EXTRA #define WITH_XSLT_DEBUG_EXTRA
#define WITH_XSLT_DEBUG_PROCESS #define WITH_XSLT_DEBUG_PROCESS
#define WITH_XSLT_DEBUG_VARIABLE
#endif #endif
#define XSLT_GENERATE_HTML_DOCTYPE #define XSLT_GENERATE_HTML_DOCTYPE
@ -55,10 +56,9 @@ static xmlNsPtr
xsltCopyNamespaceListInternal(xmlNodePtr node, xmlNsPtr cur); xsltCopyNamespaceListInternal(xmlNodePtr node, xmlNsPtr cur);
static xmlNodePtr static xmlNodePtr
xsltCopyTreeInternal(xsltTransformContextPtr ctxt, xsltCopyTree(xsltTransformContextPtr ctxt, xmlNodePtr invocNode,
xmlNodePtr invocNode, xmlNodePtr node, xmlNodePtr insert, int isLRE,
xmlNodePtr node, int topElemVisited);
xmlNodePtr insert, int isLRE, int topElemVisited);
static void static void
xsltApplySequenceConstructor(xsltTransformContextPtr ctxt, xsltApplySequenceConstructor(xsltTransformContextPtr ctxt,
@ -434,7 +434,7 @@ xsltGetXIncludeDefault(void) {
return(xsltDoXIncludeDefault); return(xsltDoXIncludeDefault);
} }
unsigned long xsltDefaultTrace = (unsigned long) XSLT_TRACE_ALL; static unsigned long xsltDefaultTrace = (unsigned long) XSLT_TRACE_ALL;
/** /**
* xsltDebugSetDefaultTrace: * xsltDebugSetDefaultTrace:
@ -733,9 +733,6 @@ xsltFreeTransformContext(xsltTransformContextPtr ctxt) {
* * * *
************************************************************************/ ************************************************************************/
xmlNodePtr xsltCopyTree(xsltTransformContextPtr ctxt,
xmlNodePtr node, xmlNodePtr insert, int literal);
/** /**
* xsltAddChild: * xsltAddChild:
* @parent: the parent node * @parent: the parent node
@ -751,7 +748,7 @@ static xmlNodePtr
xsltAddChild(xmlNodePtr parent, xmlNodePtr cur) { xsltAddChild(xmlNodePtr parent, xmlNodePtr cur) {
xmlNodePtr ret; xmlNodePtr ret;
if ((cur == NULL) || (parent == NULL)) if (cur == NULL)
return(NULL); return(NULL);
if (parent == NULL) { if (parent == NULL) {
xmlFreeNode(cur); xmlFreeNode(cur);
@ -783,13 +780,32 @@ xsltAddTextString(xsltTransformContextPtr ctxt, xmlNodePtr target,
return(target); return(target);
if (ctxt->lasttext == target->content) { if (ctxt->lasttext == target->content) {
int minSize;
if (ctxt->lasttuse + len >= ctxt->lasttsize) { /* Check for integer overflow accounting for NUL terminator. */
if (len >= INT_MAX - ctxt->lasttuse) {
xsltTransformError(ctxt, NULL, target,
"xsltCopyText: text allocation failed\n");
return(NULL);
}
minSize = ctxt->lasttuse + len + 1;
if (ctxt->lasttsize < minSize) {
xmlChar *newbuf; xmlChar *newbuf;
int size; int size;
int extra;
/* Double buffer size but increase by at least 100 bytes. */
extra = minSize < 100 ? 100 : minSize;
/* Check for integer overflow. */
if (extra > INT_MAX - ctxt->lasttsize) {
size = INT_MAX;
}
else {
size = ctxt->lasttsize + extra;
}
size = ctxt->lasttsize + len + 100;
size *= 2;
newbuf = (xmlChar *) xmlRealloc(target->content,size); newbuf = (xmlChar *) xmlRealloc(target->content,size);
if (newbuf == NULL) { if (newbuf == NULL) {
xsltTransformError(ctxt, NULL, target, xsltTransformError(ctxt, NULL, target,
@ -1090,7 +1106,7 @@ exit:
* *
* Do a copy of an attribute. * Do a copy of an attribute.
* Called by: * Called by:
* - xsltCopyTreeInternal() * - xsltCopyTree()
* - xsltCopyOf() * - xsltCopyOf()
* - xsltCopy() * - xsltCopy()
* *
@ -1191,7 +1207,7 @@ xsltShallowCopyAttr(xsltTransformContextPtr ctxt, xmlNodePtr invocNode,
* @target element node. * @target element node.
* *
* Called by: * Called by:
* - xsltCopyTreeInternal() * - xsltCopyTree()
* *
* Returns 0 on success and -1 on errors and internal errors. * Returns 0 on success and -1 on errors and internal errors.
*/ */
@ -1313,7 +1329,7 @@ xsltShallowCopyElem(xsltTransformContextPtr ctxt, xmlNodePtr node,
* copy over all namespace nodes in scope. * copy over all namespace nodes in scope.
* The damn thing about this is, that we would need to * The damn thing about this is, that we would need to
* use the xmlGetNsList(), for every single node; this is * use the xmlGetNsList(), for every single node; this is
* also done in xsltCopyTreeInternal(), but only for the top node. * also done in xsltCopyTree(), but only for the top node.
*/ */
if (node->ns != NULL) { if (node->ns != NULL) {
if (isLRE) { if (isLRE) {
@ -1371,7 +1387,7 @@ xsltCopyTreeList(xsltTransformContextPtr ctxt, xmlNodePtr invocNode,
xmlNodePtr copy, ret = NULL; xmlNodePtr copy, ret = NULL;
while (list != NULL) { while (list != NULL) {
copy = xsltCopyTreeInternal(ctxt, invocNode, copy = xsltCopyTree(ctxt, invocNode,
list, insert, isLRE, topElemVisited); list, insert, isLRE, topElemVisited);
if (copy != NULL) { if (copy != NULL) {
if (ret == NULL) { if (ret == NULL) {
@ -1391,7 +1407,7 @@ xsltCopyTreeList(xsltTransformContextPtr ctxt, xmlNodePtr invocNode,
* Do a copy of a namespace list. If @node is non-NULL the * Do a copy of a namespace list. If @node is non-NULL the
* new namespaces are added automatically. * new namespaces are added automatically.
* Called by: * Called by:
* xsltCopyTreeInternal() * xsltCopyTree()
* *
* QUESTION: What is the exact difference between this function * QUESTION: What is the exact difference between this function
* and xsltCopyNamespaceList() in "namespaces.c"? * and xsltCopyNamespaceList() in "namespaces.c"?
@ -1549,7 +1565,7 @@ occupied:
} }
/** /**
* xsltCopyTreeInternal: * xsltCopyTree:
* @ctxt: the XSLT transformation context * @ctxt: the XSLT transformation context
* @invocNode: responsible node in the stylesheet; used for error reports * @invocNode: responsible node in the stylesheet; used for error reports
* @node: the element node in the source tree * @node: the element node in the source tree
@ -1568,10 +1584,9 @@ occupied:
* Returns a pointer to the new tree, or NULL in case of error * Returns a pointer to the new tree, or NULL in case of error
*/ */
static xmlNodePtr static xmlNodePtr
xsltCopyTreeInternal(xsltTransformContextPtr ctxt, xsltCopyTree(xsltTransformContextPtr ctxt, xmlNodePtr invocNode,
xmlNodePtr invocNode, xmlNodePtr node, xmlNodePtr insert, int isLRE,
xmlNodePtr node, int topElemVisited)
xmlNodePtr insert, int isLRE, int topElemVisited)
{ {
xmlNodePtr copy; xmlNodePtr copy;
@ -1627,7 +1642,7 @@ xsltCopyTreeInternal(xsltTransformContextPtr ctxt,
copy = xsltAddChild(insert, copy); copy = xsltAddChild(insert, copy);
if (copy == NULL) { if (copy == NULL) {
xsltTransformError(ctxt, NULL, invocNode, xsltTransformError(ctxt, NULL, invocNode,
"xsltCopyTreeInternal: Copying of '%s' failed.\n", node->name); "xsltCopyTree: Copying of '%s' failed.\n", node->name);
return (copy); return (copy);
} }
/* /*
@ -1758,34 +1773,11 @@ xsltCopyTreeInternal(xsltTransformContextPtr ctxt,
} }
} else { } else {
xsltTransformError(ctxt, NULL, invocNode, xsltTransformError(ctxt, NULL, invocNode,
"xsltCopyTreeInternal: Copying of '%s' failed.\n", node->name); "xsltCopyTree: Copying of '%s' failed.\n", node->name);
} }
return(copy); 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 * * Error/fallback processing *
@ -1987,6 +1979,9 @@ xsltDefaultProcessOneNode(xsltTransformContextPtr ctxt, xmlNodePtr node,
/* /*
* Handling of Elements: second pass, actual processing * Handling of Elements: second pass, actual processing
*
* Note that params are passed to the next template. This matches
* XSLT 2.0 behavior but doesn't conform to XSLT 1.0.
*/ */
oldSize = ctxt->xpathCtxt->contextSize; oldSize = ctxt->xpathCtxt->contextSize;
oldPos = ctxt->xpathCtxt->proximityPosition; oldPos = ctxt->xpathCtxt->proximityPosition;
@ -2266,30 +2261,28 @@ xsltReleaseLocalRVTs(xsltTransformContextPtr ctxt, xmlDocPtr base)
{ {
xmlDocPtr cur = ctxt->localRVT, tmp; xmlDocPtr cur = ctxt->localRVT, tmp;
while ((cur != NULL) && (cur != base)) { if (cur == base)
if (cur->psvi == (void *) ((long) 1)) { return;
cur = (xmlDocPtr) cur->next; if (cur->prev != NULL)
} else { xsltTransformError(ctxt, NULL, NULL, "localRVT not head of list\n");
tmp = cur;
cur = (xmlDocPtr) cur->next;
if (tmp == ctxt->localRVT) do {
ctxt->localRVT = cur; tmp = cur;
cur = (xmlDocPtr) cur->next;
if (tmp->psvi == XSLT_RVT_LOCAL) {
xsltReleaseRVT(ctxt, tmp);
} else if (tmp->psvi == XSLT_RVT_GLOBAL) {
xsltRegisterPersistRVT(ctxt, tmp);
} else if (tmp->psvi != XSLT_RVT_FUNC_RESULT) {
xmlGenericError(xmlGenericErrorContext,
"xsltReleaseLocalRVTs: Unexpected RVT flag %p\n",
tmp->psvi);
}
} while (cur != base);
/* if (base != NULL)
* We need ctxt->localRVTBase for extension instructions base->prev = NULL;
* which return values (like EXSLT's function). ctxt->localRVT = base;
*/
if (tmp == ctxt->localRVTBase)
ctxt->localRVTBase = cur;
if (tmp->prev)
tmp->prev->next = (xmlNodePtr) cur;
if (cur)
cur->prev = tmp->prev;
xsltReleaseRVT(ctxt, tmp);
}
}
} }
/** /**
@ -2315,7 +2308,7 @@ xsltApplySequenceConstructor(xsltTransformContextPtr ctxt,
xmlNodePtr oldInsert, oldInst, oldCurInst, oldContextNode; xmlNodePtr oldInsert, oldInst, oldCurInst, oldContextNode;
xmlNodePtr cur, insert, copy = NULL; xmlNodePtr cur, insert, copy = NULL;
int level = 0, oldVarsNr; int level = 0, oldVarsNr;
xmlDocPtr oldLocalFragmentTop, oldLocalFragmentBase; xmlDocPtr oldLocalFragmentTop;
#ifdef XSLT_REFACTORED #ifdef XSLT_REFACTORED
xsltStylePreCompPtr info; xsltStylePreCompPtr info;
@ -2343,6 +2336,24 @@ xsltApplySequenceConstructor(xsltTransformContextPtr ctxt,
return; return;
CHECK_STOPPED; CHECK_STOPPED;
/*
* Check for infinite recursion: stop if the maximum of nested templates
* is excceeded. Adjust xsltMaxDepth if you need more.
*/
if (ctxt->depth >= ctxt->maxTemplateDepth) {
xsltTransformError(ctxt, NULL, list,
"xsltApplySequenceConstructor: 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);
ctxt->state = XSLT_STATE_STOPPED;
return;
}
ctxt->depth++;
oldLocalFragmentTop = ctxt->localRVT; oldLocalFragmentTop = ctxt->localRVT;
oldInsert = insert = ctxt->insert; oldInsert = insert = ctxt->insert;
oldInst = oldCurInst = ctxt->inst; oldInst = oldCurInst = ctxt->inst;
@ -2642,17 +2653,22 @@ xsltApplySequenceConstructor(xsltTransformContextPtr ctxt,
"xsltApplySequenceConstructor: extension construct %s\n", "xsltApplySequenceConstructor: extension construct %s\n",
cur->name)); cur->name));
#endif #endif
/*
* Disable the xsltCopyTextString optimization for
* extension elements. Extensions could append text using
* xmlAddChild which will free the buffer pointed to by
* 'lasttext'. This buffer could later be reallocated with
* a different size than recorded in 'lasttsize'. See bug
* #777432.
*/
if (cur->psvi == xsltExtMarker) {
ctxt->lasttext = NULL;
}
ctxt->insert = insert; 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); func(ctxt, contextNode, cur, cur->psvi);
ctxt->localRVTBase = oldLocalFragmentBase;
/* /*
* Cleanup temporary tree fragments. * Cleanup temporary tree fragments.
*/ */
@ -2716,12 +2732,9 @@ xsltApplySequenceConstructor(xsltTransformContextPtr ctxt,
oldCurInst = ctxt->inst; oldCurInst = ctxt->inst;
ctxt->inst = cur; ctxt->inst = cur;
ctxt->insert = insert; ctxt->insert = insert;
oldLocalFragmentBase = ctxt->localRVTBase;
ctxt->localRVTBase = NULL;
info->func(ctxt, contextNode, cur, (xsltElemPreCompPtr) info); info->func(ctxt, contextNode, cur, (xsltElemPreCompPtr) info);
ctxt->localRVTBase = oldLocalFragmentBase;
/* /*
* Cleanup temporary tree fragments. * Cleanup temporary tree fragments.
*/ */
@ -2835,13 +2848,19 @@ xsltApplySequenceConstructor(xsltTransformContextPtr ctxt,
cur->name)); cur->name));
#endif #endif
/*
* Disable the xsltCopyTextString optimization for
* extension elements. Extensions could append text using
* xmlAddChild which will free the buffer pointed to by
* 'lasttext'. This buffer could later be reallocated with
* a different size than recorded in 'lasttsize'. See bug
* #777432.
*/
if (cur->psvi == xsltExtMarker) {
ctxt->lasttext = NULL;
}
ctxt->insert = insert; 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); function(ctxt, contextNode, cur, cur->psvi);
/* /*
@ -2850,7 +2869,6 @@ xsltApplySequenceConstructor(xsltTransformContextPtr ctxt,
if (oldLocalFragmentTop != ctxt->localRVT) if (oldLocalFragmentTop != ctxt->localRVT)
xsltReleaseLocalRVTs(ctxt, oldLocalFragmentTop); xsltReleaseLocalRVTs(ctxt, oldLocalFragmentTop);
ctxt->localRVTBase = oldLocalFragmentBase;
ctxt->insert = oldInsert; ctxt->insert = oldInsert;
} }
@ -2992,6 +3010,8 @@ error:
ctxt->inst = oldInst; ctxt->inst = oldInst;
ctxt->insert = oldInsert; ctxt->insert = oldInsert;
ctxt->depth--;
#ifdef WITH_DEBUGGER #ifdef WITH_DEBUGGER
if ((ctxt->debugStatus != XSLT_DEBUG_NONE) && (addCallResult)) { if ((ctxt->debugStatus != XSLT_DEBUG_NONE) && (addCallResult)) {
xslDropCall(); xslDropCall();
@ -3026,7 +3046,7 @@ xsltApplyXSLTTemplate(xsltTransformContextPtr ctxt,
long start = 0; long start = 0;
xmlNodePtr cur; xmlNodePtr cur;
xsltStackElemPtr tmpParam = NULL; xsltStackElemPtr tmpParam = NULL;
xmlDocPtr oldUserFragmentTop, oldLocalFragmentTop; xmlDocPtr oldUserFragmentTop;
#ifdef XSLT_REFACTORED #ifdef XSLT_REFACTORED
xsltStyleItemParamPtr iparam; xsltStyleItemParamPtr iparam;
@ -3058,23 +3078,6 @@ xsltApplyXSLTTemplate(xsltTransformContextPtr ctxt,
return; return;
CHECK_STOPPED; 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) if (ctxt->varsNr >= ctxt->maxTemplateVars)
{ {
xsltTransformError(ctxt, NULL, list, xsltTransformError(ctxt, NULL, list,
@ -3084,12 +3087,12 @@ xsltApplyXSLTTemplate(xsltTransformContextPtr ctxt,
"raise the maximum number of variables/params (currently set to %d).\n", "raise the maximum number of variables/params (currently set to %d).\n",
ctxt->maxTemplateVars); ctxt->maxTemplateVars);
xsltDebug(ctxt, contextNode, list, NULL); xsltDebug(ctxt, contextNode, list, NULL);
ctxt->state = XSLT_STATE_STOPPED;
return; return;
} }
oldUserFragmentTop = ctxt->tmpRVT; oldUserFragmentTop = ctxt->tmpRVT;
ctxt->tmpRVT = NULL; ctxt->tmpRVT = NULL;
oldLocalFragmentTop = ctxt->localRVT;
/* /*
* Initiate a distinct scope of local params/variables. * Initiate a distinct scope of local params/variables.
@ -3190,31 +3193,6 @@ xsltApplyXSLTTemplate(xsltTransformContextPtr ctxt,
xsltTemplateParamsCleanup(ctxt); xsltTemplateParamsCleanup(ctxt);
ctxt->varsBase = oldVarsBase; 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 * Release user-created fragments stored in the scope
* of xsl:template. Note that this mechanism is deprecated: * of xsl:template. Note that this mechanism is deprecated:
@ -3820,7 +3798,6 @@ xsltDocumentElem(xsltTransformContextPtr ctxt, xmlNodePtr node,
xsltTransformError(ctxt, NULL, inst, xsltTransformError(ctxt, NULL, inst,
"xsltDocumentElem: unable to save to %s\n", "xsltDocumentElem: unable to save to %s\n",
filename); filename);
ctxt->state = XSLT_STATE_ERROR;
#ifdef WITH_XSLT_DEBUG_EXTRA #ifdef WITH_XSLT_DEBUG_EXTRA
} else { } else {
xsltGenericDebug(xsltGenericDebugContext, xsltGenericDebug(xsltGenericDebugContext,
@ -4433,8 +4410,7 @@ xsltCopyOf(xsltTransformContextPtr ctxt, xmlNodePtr node,
xsltShallowCopyAttr(ctxt, inst, xsltShallowCopyAttr(ctxt, inst,
ctxt->insert, (xmlAttrPtr) cur); ctxt->insert, (xmlAttrPtr) cur);
} else { } else {
xsltCopyTreeInternal(ctxt, inst, xsltCopyTree(ctxt, inst, cur, ctxt->insert, 0, 0);
cur, ctxt->insert, 0, 0);
} }
} }
} }
@ -4685,6 +4661,10 @@ xsltApplyImports(xsltTransformContextPtr ctxt, xmlNodePtr contextNode,
ctxt->currentTemplateRule = oldCurTemplRule; ctxt->currentTemplateRule = oldCurTemplRule;
} }
else {
/* Use built-in templates. */
xsltDefaultProcessOneNode(ctxt, contextNode, NULL);
}
} }
/** /**
@ -5632,6 +5612,7 @@ typedef struct xsltHTMLVersion {
} xsltHTMLVersion; } xsltHTMLVersion;
static xsltHTMLVersion xsltHTMLVersions[] = { static xsltHTMLVersion xsltHTMLVersions[] = {
{ "5", NULL, "about:legacy-compat" },
{ "4.01frame", "-//W3C//DTD HTML 4.01 Frameset//EN", { "4.01frame", "-//W3C//DTD HTML 4.01 Frameset//EN",
"http://www.w3.org/TR/1999/REC-html401-19991224/frameset.dtd"}, "http://www.w3.org/TR/1999/REC-html401-19991224/frameset.dtd"},
{ "4.01strict", "-//W3C//DTD HTML 4.01//EN", { "4.01strict", "-//W3C//DTD HTML 4.01//EN",
@ -5857,7 +5838,8 @@ xsltApplyStylesheetInternal(xsltStylesheetPtr style, xmlDocPtr doc,
*/ */
root = xmlDocGetRootElement(doc); root = xmlDocGetRootElement(doc);
if (root != NULL) { if (root != NULL) {
if (((long) root->content) >= 0 && (xslDebugStatus == XSLT_DEBUG_NONE)) if (((ptrdiff_t) root->content >= 0) &&
(xslDebugStatus == XSLT_DEBUG_NONE))
xmlXPathOrderDocElems(doc); xmlXPathOrderDocElems(doc);
} }
@ -6007,6 +5989,9 @@ xsltApplyStylesheetInternal(xsltStylesheetPtr style, xmlDocPtr doc,
xsltEvalGlobalVariables(ctxt); xsltEvalGlobalVariables(ctxt);
/* Clean up any unused RVTs. */
xsltReleaseLocalRVTs(ctxt, NULL);
ctxt->node = (xmlNodePtr) doc; ctxt->node = (xmlNodePtr) doc;
ctxt->output = res; ctxt->output = res;
ctxt->insert = (xmlNodePtr) res; ctxt->insert = (xmlNodePtr) res;
@ -6151,7 +6136,7 @@ xsltApplyStylesheetInternal(xsltStylesheetPtr style, xmlDocPtr doc,
/* /*
* Be pedantic. * Be pedantic.
*/ */
if ((ctxt != NULL) && (ctxt->state == XSLT_STATE_ERROR)) { if ((ctxt != NULL) && (ctxt->state != XSLT_STATE_OK)) {
xmlFreeDoc(res); xmlFreeDoc(res);
res = NULL; res = NULL;
} }

View file

@ -19,11 +19,11 @@
const xmlChar *xsltDocFragFake = (const xmlChar *) " fake node libxslt"; const xmlChar *xsltDocFragFake = (const xmlChar *) " fake node libxslt";
#endif #endif
const xmlChar *xsltComputingGlobalVarMarker = static const xmlChar *xsltComputingGlobalVarMarker =
(const xmlChar *) " var/param being computed"; (const xmlChar *) " var/param being computed";
#define XSLT_VAR_GLOBAL 1<<0 #define XSLT_VAR_GLOBAL (1<<0)
#define XSLT_VAR_IN_SELECT 1<<1 #define XSLT_VAR_IN_SELECT (1<<1)
#define XSLT_TCTXT_VARIABLE(c) ((xsltStackElemPtr) (c)->contextVariable) #define XSLT_TCTXT_VARIABLE(c) ((xsltStackElemPtr) (c)->contextVariable)
/************************************************************************ /************************************************************************
@ -101,6 +101,9 @@ xsltRegisterTmpRVT(xsltTransformContextPtr ctxt, xmlDocPtr RVT)
if ((ctxt == NULL) || (RVT == NULL)) if ((ctxt == NULL) || (RVT == NULL))
return(-1); return(-1);
RVT->prev = NULL;
RVT->psvi = XSLT_RVT_VARIABLE;
/* /*
* We'll restrict the lifetime of user-created fragments * We'll restrict the lifetime of user-created fragments
* insinde an xsl:variable and xsl:param to the lifetime of the * insinde an xsl:variable and xsl:param to the lifetime of the
@ -138,15 +141,18 @@ xsltRegisterLocalRVT(xsltTransformContextPtr ctxt,
if ((ctxt == NULL) || (RVT == NULL)) if ((ctxt == NULL) || (RVT == NULL))
return(-1); return(-1);
RVT->prev = NULL;
/* /*
* When evaluating "select" expressions of xsl:variable * When evaluating "select" expressions of xsl:variable
* and xsl:param, we need to bind newly created tree fragments * and xsl:param, we need to bind newly created tree fragments
* to the variable itself; otherwise the tragment will be * to the variable itself; otherwise the fragment will be
* freed before we leave the scope of a var. * freed before we leave the scope of a var.
*/ */
if ((ctxt->contextVariable != NULL) && if ((ctxt->contextVariable != NULL) &&
(XSLT_TCTXT_VARIABLE(ctxt)->flags & XSLT_VAR_IN_SELECT)) (XSLT_TCTXT_VARIABLE(ctxt)->flags & XSLT_VAR_IN_SELECT))
{ {
RVT->psvi = XSLT_RVT_VARIABLE;
RVT->next = (xmlNodePtr) XSLT_TCTXT_VARIABLE(ctxt)->fragment; RVT->next = (xmlNodePtr) XSLT_TCTXT_VARIABLE(ctxt)->fragment;
XSLT_TCTXT_VARIABLE(ctxt)->fragment = RVT; XSLT_TCTXT_VARIABLE(ctxt)->fragment = RVT;
return(0); return(0);
@ -156,19 +162,11 @@ xsltRegisterLocalRVT(xsltTransformContextPtr ctxt,
* If not reference by a returning instruction (like EXSLT's function), * If not reference by a returning instruction (like EXSLT's function),
* then this fragment will be freed, when the instruction exits. * then this fragment will be freed, when the instruction exits.
*/ */
RVT->psvi = XSLT_RVT_LOCAL;
RVT->next = (xmlNodePtr) ctxt->localRVT; RVT->next = (xmlNodePtr) ctxt->localRVT;
if (ctxt->localRVT != NULL) if (ctxt->localRVT != NULL)
ctxt->localRVT->prev = (xmlNodePtr) RVT; ctxt->localRVT->prev = (xmlNodePtr) RVT;
ctxt->localRVT = RVT; ctxt->localRVT = RVT;
/*
* We need to keep track of the first registered fragment
* for extension instructions which return fragments
* (e.g. EXSLT'S function), in order to let
* xsltExtensionInstructionResultFinalize() clear the
* preserving flag on the fragments.
*/
if (ctxt->localRVTBase == NULL)
ctxt->localRVTBase = RVT;
return(0); return(0);
} }
@ -183,26 +181,16 @@ xsltRegisterLocalRVT(xsltTransformContextPtr ctxt,
* collector will free them after the function-calling process exits. * collector will free them after the function-calling process exits.
* *
* Returns 0 in case of success and -1 in case of API or internal errors. * Returns 0 in case of success and -1 in case of API or internal errors.
*
* This function is unsupported in newer releases of libxslt.
*/ */
int int
xsltExtensionInstructionResultFinalize(xsltTransformContextPtr ctxt) xsltExtensionInstructionResultFinalize(xsltTransformContextPtr ctxt)
{ {
xmlDocPtr cur; xmlGenericError(xmlGenericErrorContext,
"xsltExtensionInstructionResultFinalize is unsupported "
if (ctxt == NULL) "in this release of libxslt.\n");
return(-1); return(-1);
if (ctxt->localRVTBase == NULL)
return(0);
/*
* Enable remaining local tree fragments to be freed
* by the fragment garbage collector.
*/
cur = ctxt->localRVTBase;
do {
cur->psvi = NULL;
cur = (xmlDocPtr) cur->next;
} while (cur != NULL);
return(0);
} }
/** /**
@ -217,11 +205,35 @@ xsltExtensionInstructionResultFinalize(xsltTransformContextPtr ctxt)
* tree fragments (via xsltCreateRVT()) with xsltRegisterLocalRVT(). * tree fragments (via xsltCreateRVT()) with xsltRegisterLocalRVT().
* *
* Returns 0 in case of success and -1 in case of error. * Returns 0 in case of success and -1 in case of error.
*
* It isn't necessary to call this function in newer releases of
* libxslt.
*/ */
int int
xsltExtensionInstructionResultRegister(xsltTransformContextPtr ctxt, xsltExtensionInstructionResultRegister(xsltTransformContextPtr ctxt,
xmlXPathObjectPtr obj) xmlXPathObjectPtr obj)
{ {
return(0);
}
/**
* xsltFlagRVTs:
* @ctxt: an XSLT transformation context
* @obj: an XPath object to be inspected for result tree fragments
* @val: the flag value
*
* Updates ownership information of RVTs in @obj according to @val.
*
* @val = XSLT_RVT_FUNC_RESULT for the result of an extension function, so its
* RVTs won't be destroyed after leaving the returning scope.
* @val = XSLT_RVT_LOCAL for the result of an extension function to reset
* the state of its RVTs after it was returned to a new scope.
* @val = XSLT_RVT_GLOBAL for parts of global variables.
*
* Returns 0 in case of success and -1 in case of error.
*/
int
xsltFlagRVTs(xsltTransformContextPtr ctxt, xmlXPathObjectPtr obj, void *val) {
int i; int i;
xmlNodePtr cur; xmlNodePtr cur;
xmlDocPtr doc; xmlDocPtr doc;
@ -254,36 +266,59 @@ xsltExtensionInstructionResultRegister(xsltTransformContextPtr ctxt,
doc = cur->doc; doc = cur->doc;
} else { } else {
xsltTransformError(ctxt, NULL, ctxt->inst, xsltTransformError(ctxt, NULL, ctxt->inst,
"Internal error in " "Internal error in xsltFlagRVTs(): "
"xsltExtensionInstructionResultRegister(): "
"Cannot retrieve the doc of a namespace node.\n"); "Cannot retrieve the doc of a namespace node.\n");
goto error; return(-1);
} }
} else { } else {
doc = cur->doc; doc = cur->doc;
} }
if (doc == NULL) { if (doc == NULL) {
xsltTransformError(ctxt, NULL, ctxt->inst, xsltTransformError(ctxt, NULL, ctxt->inst,
"Internal error in " "Internal error in xsltFlagRVTs(): "
"xsltExtensionInstructionResultRegister(): "
"Cannot retrieve the doc of a node.\n"); "Cannot retrieve the doc of a node.\n");
goto error; return(-1);
} }
if (doc->name && (doc->name[0] == ' ')) { if (doc->name && (doc->name[0] == ' ') &&
doc->psvi != XSLT_RVT_GLOBAL) {
/* /*
* This is a result tree fragment. * This is a result tree fragment.
* We'll use the @psvi field for reference counting. * We store ownership information in the @psvi field.
* TODO: How do we know if this is a value of a * TODO: How do we know if this is a doc acquired via the
* global variable or a doc acquired via the
* document() function? * document() function?
*/ */
doc->psvi = (void *) ((long) 1); #ifdef WITH_XSLT_DEBUG_VARIABLE
XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
"Flagging RVT %p: %p -> %p\n", doc, doc->psvi, val));
#endif
if (val == XSLT_RVT_LOCAL) {
if (doc->psvi != XSLT_RVT_FUNC_RESULT) {
xmlGenericError(xmlGenericErrorContext,
"xsltFlagRVTs: Invalid transition %p => LOCAL\n",
doc->psvi);
return(-1);
}
xsltRegisterLocalRVT(ctxt, doc);
} else if (val == XSLT_RVT_GLOBAL) {
if (doc->psvi != XSLT_RVT_LOCAL) {
xmlGenericError(xmlGenericErrorContext,
"xsltFlagRVTs: Invalid transition %p => GLOBAL\n",
doc->psvi);
doc->psvi = XSLT_RVT_GLOBAL;
return(-1);
}
/* Will be registered as persistant in xsltReleaseLocalRVTs. */
doc->psvi = XSLT_RVT_GLOBAL;
} else if (val == XSLT_RVT_FUNC_RESULT) {
doc->psvi = val;
}
} }
} }
return(0); return(0);
error:
return(-1);
} }
/** /**
@ -329,9 +364,9 @@ xsltReleaseRVT(xsltTransformContextPtr ctxt, xmlDocPtr RVT)
} }
/* /*
* Reset the reference counter. * Reset the ownership information.
*/ */
RVT->psvi = 0; RVT->psvi = NULL;
RVT->next = (xmlNodePtr) ctxt->cache->RVT; RVT->next = (xmlNodePtr) ctxt->cache->RVT;
ctxt->cache->RVT = RVT; ctxt->cache->RVT = RVT;
@ -370,6 +405,8 @@ xsltRegisterPersistRVT(xsltTransformContextPtr ctxt, xmlDocPtr RVT)
{ {
if ((ctxt == NULL) || (RVT == NULL)) return(-1); if ((ctxt == NULL) || (RVT == NULL)) return(-1);
RVT->psvi = XSLT_RVT_GLOBAL;
RVT->prev = NULL;
RVT->next = (xmlNodePtr) ctxt->persistRVT; RVT->next = (xmlNodePtr) ctxt->persistRVT;
if (ctxt->persistRVT != NULL) if (ctxt->persistRVT != NULL)
ctxt->persistRVT->prev = (xmlNodePtr) RVT; ctxt->persistRVT->prev = (xmlNodePtr) RVT;
@ -520,35 +557,21 @@ xsltFreeStackElem(xsltStackElemPtr elem) {
/* /*
* Release the list of temporary Result Tree Fragments. * Release the list of temporary Result Tree Fragments.
*/ */
if (elem->fragment) { if (elem->context) {
xmlDocPtr cur; xmlDocPtr cur;
while (elem->fragment != NULL) { while (elem->fragment != NULL) {
cur = elem->fragment; cur = elem->fragment;
elem->fragment = (xmlDocPtr) cur->next; elem->fragment = (xmlDocPtr) cur->next;
if (elem->context && if (cur->psvi == XSLT_RVT_VARIABLE) {
(cur->psvi == (void *) ((long) 1)))
{
/*
* This fragment is a result of an extension instruction
* (e.g. XSLT's function) and needs to be preserved until
* the instruction exits.
* Example: The fragment of the variable must not be freed
* since it is returned by the EXSLT function:
* <f:function name="foo">
* <xsl:variable name="bar">
* <bar/>
* </xsl:variable>
* <f:result select="$bar"/>
* </f:function>
*
*/
xsltRegisterLocalRVT(elem->context, cur);
} else {
xsltReleaseRVT((xsltTransformContextPtr) elem->context, xsltReleaseRVT((xsltTransformContextPtr) elem->context,
cur); cur);
} } else if (cur->psvi != XSLT_RVT_FUNC_RESULT) {
xmlGenericError(xmlGenericErrorContext,
"xsltFreeStackElem: Unexpected RVT flag %p\n",
cur->psvi);
}
} }
} }
/* /*
@ -942,6 +965,7 @@ xsltEvalVariable(xsltTransformContextPtr ctxt, xsltStackElemPtr variable,
* the Result Tree Fragment. * the Result Tree Fragment.
*/ */
variable->fragment = container; variable->fragment = container;
container->psvi = XSLT_RVT_VARIABLE;
oldOutput = ctxt->output; oldOutput = ctxt->output;
oldInsert = ctxt->insert; oldInsert = ctxt->insert;
@ -1128,16 +1152,23 @@ xsltEvalGlobalVariable(xsltStackElemPtr elem, xsltTransformContextPtr ctxt)
xsltTransformError(ctxt, NULL, comp->inst, xsltTransformError(ctxt, NULL, comp->inst,
"Evaluating global variable %s failed\n", elem->name); "Evaluating global variable %s failed\n", elem->name);
ctxt->state = XSLT_STATE_STOPPED; ctxt->state = XSLT_STATE_STOPPED;
goto error;
}
/*
* Mark all RVTs that are referenced from result as part
* of this variable so they won't be freed too early.
*/
xsltFlagRVTs(ctxt, result, XSLT_RVT_GLOBAL);
#ifdef WITH_XSLT_DEBUG_VARIABLE #ifdef WITH_XSLT_DEBUG_VARIABLE
#ifdef LIBXML_DEBUG_ENABLED #ifdef LIBXML_DEBUG_ENABLED
} else { if ((xsltGenericDebugContext == stdout) ||
if ((xsltGenericDebugContext == stdout) || (xsltGenericDebugContext == stderr))
(xsltGenericDebugContext == stderr)) xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext, result, 0);
result, 0);
#endif #endif
#endif #endif
}
} else { } else {
if (elem->tree == NULL) { if (elem->tree == NULL) {
result = xmlXPathNewCString(""); result = xmlXPathNewCString("");
@ -1751,8 +1782,7 @@ xsltBuildVariable(xsltTransformContextPtr ctxt,
elem->tree = tree; elem->tree = tree;
elem->value = xsltEvalVariable(ctxt, elem, elem->value = xsltEvalVariable(ctxt, elem,
(xsltStylePreCompPtr) comp); (xsltStylePreCompPtr) comp);
if (elem->value != NULL) elem->computed = 1;
elem->computed = 1;
return(elem); return(elem);
} }

View file

@ -247,7 +247,7 @@ xsltIsBlank(xmlChar *str) {
* * * *
************************************************************************/ ************************************************************************/
static xsltDecimalFormatPtr static xsltDecimalFormatPtr
xsltNewDecimalFormat(xmlChar *name) xsltNewDecimalFormat(const xmlChar *nsUri, xmlChar *name)
{ {
xsltDecimalFormatPtr self; xsltDecimalFormatPtr self;
/* UTF-8 for 0x2030 */ /* UTF-8 for 0x2030 */
@ -256,6 +256,7 @@ xsltNewDecimalFormat(xmlChar *name)
self = xmlMalloc(sizeof(xsltDecimalFormat)); self = xmlMalloc(sizeof(xsltDecimalFormat));
if (self != NULL) { if (self != NULL) {
self->next = NULL; self->next = NULL;
self->nsUri = nsUri;
self->name = name; self->name = name;
/* Default values */ /* Default values */
@ -341,7 +342,39 @@ xsltDecimalFormatGetByName(xsltStylesheetPtr style, xmlChar *name)
for (result = style->decimalFormat->next; for (result = style->decimalFormat->next;
result != NULL; result != NULL;
result = result->next) { result = result->next) {
if (xmlStrEqual(name, result->name)) if ((result->nsUri == NULL) && xmlStrEqual(name, result->name))
return result;
}
style = xsltNextImport(style);
}
return result;
}
/**
* xsltDecimalFormatGetByQName:
* @style: the XSLT stylesheet
* @nsUri: the namespace URI of the QName
* @name: the local part of the QName
*
* Find decimal-format by QName
*
* Returns the xsltDecimalFormatPtr
*/
xsltDecimalFormatPtr
xsltDecimalFormatGetByQName(xsltStylesheetPtr style, const xmlChar *nsUri,
const 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(nsUri, result->nsUri) &&
xmlStrEqual(name, result->name))
return result; return result;
} }
style = xsltNextImport(style); style = xsltNextImport(style);
@ -719,7 +752,7 @@ xsltNewStylesheet(void) {
ret->omitXmlDeclaration = -1; ret->omitXmlDeclaration = -1;
ret->standalone = -1; ret->standalone = -1;
ret->decimalFormat = xsltNewDecimalFormat(NULL); ret->decimalFormat = xsltNewDecimalFormat(NULL, NULL);
ret->indent = -1; ret->indent = -1;
ret->errors = 0; ret->errors = 0;
ret->warnings = 0; ret->warnings = 0;
@ -782,9 +815,8 @@ xsltAllocateExtraCtxt(xsltTransformContextPtr ctxt)
ctxt->extras = (xsltRuntimeExtraPtr) ctxt->extras = (xsltRuntimeExtraPtr)
xmlMalloc(ctxt->extrasMax * sizeof(xsltRuntimeExtra)); xmlMalloc(ctxt->extrasMax * sizeof(xsltRuntimeExtra));
if (ctxt->extras == NULL) { if (ctxt->extras == NULL) {
xmlGenericError(xmlGenericErrorContext, xsltTransformError(ctxt, NULL, NULL,
"xsltAllocateExtraCtxt: out of memory\n"); "xsltAllocateExtraCtxt: out of memory\n");
ctxt->state = XSLT_STATE_ERROR;
return(0); return(0);
} }
for (i = 0;i < ctxt->extrasMax;i++) { for (i = 0;i < ctxt->extrasMax;i++) {
@ -800,9 +832,8 @@ xsltAllocateExtraCtxt(xsltTransformContextPtr ctxt)
tmp = (xsltRuntimeExtraPtr) xmlRealloc(ctxt->extras, tmp = (xsltRuntimeExtraPtr) xmlRealloc(ctxt->extras,
ctxt->extrasMax * sizeof(xsltRuntimeExtra)); ctxt->extrasMax * sizeof(xsltRuntimeExtra));
if (tmp == NULL) { if (tmp == NULL) {
xmlGenericError(xmlGenericErrorContext, xsltTransformError(ctxt, NULL, NULL,
"xsltAllocateExtraCtxt: out of memory\n"); "xsltAllocateExtraCtxt: out of memory\n");
ctxt->state = XSLT_STATE_ERROR;
return(0); return(0);
} }
ctxt->extras = tmp; ctxt->extras = tmp;
@ -1181,6 +1212,7 @@ xsltParseStylesheetOutput(xsltStylesheetPtr style, xmlNodePtr cur)
xsltTransformError(NULL, style, cur, xsltTransformError(NULL, style, cur,
"invalid value for method: %s\n", prop); "invalid value for method: %s\n", prop);
if (style != NULL) style->warnings++; if (style != NULL) style->warnings++;
xmlFree(prop);
} }
} else { } else {
style->method = prop; style->method = prop;
@ -1358,18 +1390,37 @@ xsltParseStylesheetDecimalFormat(xsltStylesheetPtr style, xmlNodePtr cur)
prop = xmlGetNsProp(cur, BAD_CAST("name"), NULL); prop = xmlGetNsProp(cur, BAD_CAST("name"), NULL);
if (prop != NULL) { if (prop != NULL) {
format = xsltDecimalFormatGetByName(style, prop); const xmlChar *nsUri;
if (xmlValidateQName(prop, 0) != 0) {
xsltTransformError(NULL, style, cur,
"xsl:decimal-format: Invalid QName '%s'.\n", prop);
style->warnings++;
xmlFree(prop);
return;
}
/*
* TODO: Don't use xsltGetQNameURI().
*/
nsUri = xsltGetQNameURI(cur, &prop);
if (prop == NULL) {
style->warnings++;
return;
}
format = xsltDecimalFormatGetByQName(style, nsUri, prop);
if (format != NULL) { if (format != NULL) {
xsltTransformError(NULL, style, cur, xsltTransformError(NULL, style, cur,
"xsltParseStylestyleDecimalFormat: %s already exists\n", prop); "xsltParseStylestyleDecimalFormat: %s already exists\n", prop);
if (style != NULL) style->warnings++; style->warnings++;
xmlFree(prop);
return; return;
} }
format = xsltNewDecimalFormat(prop); format = xsltNewDecimalFormat(nsUri, prop);
if (format == NULL) { if (format == NULL) {
xsltTransformError(NULL, style, cur, xsltTransformError(NULL, style, cur,
"xsltParseStylestyleDecimalFormat: failed creating new decimal-format\n"); "xsltParseStylestyleDecimalFormat: failed creating new decimal-format\n");
if (style != NULL) style->errors++; style->errors++;
xmlFree(prop);
return; return;
} }
/* Append new decimal-format structure */ /* Append new decimal-format structure */
@ -3396,7 +3447,7 @@ internal_err:
#ifdef XSLT_REFACTORED #ifdef XSLT_REFACTORED
#else #else
static void static void
xsltPrecomputeStylesheet(xsltStylesheetPtr style, xmlNodePtr cur) xsltPreprocessStylesheet(xsltStylesheetPtr style, xmlNodePtr cur)
{ {
xmlNodePtr deleteNode, styleelem; xmlNodePtr deleteNode, styleelem;
int internalize = 0; int internalize = 0;
@ -3427,7 +3478,7 @@ xsltPrecomputeStylesheet(xsltStylesheetPtr style, xmlNodePtr cur)
if (deleteNode != NULL) { if (deleteNode != NULL) {
#ifdef WITH_XSLT_DEBUG_BLANKS #ifdef WITH_XSLT_DEBUG_BLANKS
xsltGenericDebug(xsltGenericDebugContext, xsltGenericDebug(xsltGenericDebugContext,
"xsltPrecomputeStylesheet: removing ignorable blank node\n"); "xsltPreprocessStylesheet: removing ignorable blank node\n");
#endif #endif
xmlUnlinkNode(deleteNode); xmlUnlinkNode(deleteNode);
xmlFreeNode(deleteNode); xmlFreeNode(deleteNode);
@ -3467,7 +3518,6 @@ xsltPrecomputeStylesheet(xsltStylesheetPtr style, xmlNodePtr cur)
} }
if (IS_XSLT_ELEM(cur)) { if (IS_XSLT_ELEM(cur)) {
exclPrefixes = 0; exclPrefixes = 0;
xsltStylePreCompute(style, cur);
if (IS_XSLT_NAME(cur, "text")) { if (IS_XSLT_NAME(cur, "text")) {
for (;exclPrefixes > 0;exclPrefixes--) for (;exclPrefixes > 0;exclPrefixes--)
exclPrefixPop(style); exclPrefixPop(style);
@ -3518,7 +3568,7 @@ xsltPrecomputeStylesheet(xsltStylesheetPtr style, xmlNodePtr cur)
* going back * going back
*/ */
if (exclPrefixes > 0) { if (exclPrefixes > 0) {
xsltPrecomputeStylesheet(style, cur->children); xsltPreprocessStylesheet(style, cur->children);
for (;exclPrefixes > 0;exclPrefixes--) for (;exclPrefixes > 0;exclPrefixes--)
exclPrefixPop(style); exclPrefixPop(style);
goto skip_children; goto skip_children;
@ -3589,7 +3639,7 @@ skip_children:
if (deleteNode != NULL) { if (deleteNode != NULL) {
#ifdef WITH_XSLT_DEBUG_PARSING #ifdef WITH_XSLT_DEBUG_PARSING
xsltGenericDebug(xsltGenericDebugContext, xsltGenericDebug(xsltGenericDebugContext,
"xsltPrecomputeStylesheet: removing ignorable blank node\n"); "xsltPreprocessStylesheet: removing ignorable blank node\n");
#endif #endif
xmlUnlinkNode(deleteNode); xmlUnlinkNode(deleteNode);
xmlFreeNode(deleteNode); xmlFreeNode(deleteNode);
@ -4834,10 +4884,12 @@ xsltParseTemplateContent(xsltStylesheetPtr style, xmlNodePtr templ) {
delete = NULL; delete = NULL;
} }
if (IS_XSLT_ELEM(cur)) { if (IS_XSLT_ELEM(cur)) {
xsltStylePreCompute(style, cur);
if (IS_XSLT_NAME(cur, "text")) { if (IS_XSLT_NAME(cur, "text")) {
/* /*
* TODO: Processing of xsl:text should be moved to * TODO: Processing of xsl:text should be moved to
* xsltPrecomputeStylesheet(), since otherwise this * xsltPreprocessStylesheet(), since otherwise this
* will be performed for every multiply included * will be performed for every multiply included
* stylesheet; i.e. this here is not skipped with * stylesheet; i.e. this here is not skipped with
* the use of the style->nopreproc flag. * the use of the style->nopreproc flag.
@ -5367,6 +5419,7 @@ xsltParseStylesheetTemplate(xsltStylesheetPtr style, xmlNodePtr template) {
xsltTransformError(NULL, style, template, xsltTransformError(NULL, style, template,
"xsl:template : error invalid name '%s'\n", prop); "xsl:template : error invalid name '%s'\n", prop);
if (style != NULL) style->errors++; if (style != NULL) style->errors++;
xmlFree(prop);
goto error; goto error;
} }
ret->name = xmlDictLookup(style->dict, BAD_CAST prop, -1); ret->name = xmlDictLookup(style->dict, BAD_CAST prop, -1);
@ -6026,7 +6079,7 @@ xsltParseStylesheetTop(xsltStylesheetPtr style, xmlNodePtr top) {
if ((!xmlStrEqual(prop, (const xmlChar *)"1.0")) && if ((!xmlStrEqual(prop, (const xmlChar *)"1.0")) &&
(!xmlStrEqual(prop, (const xmlChar *)"1.1"))) { (!xmlStrEqual(prop, (const xmlChar *)"1.1"))) {
xsltTransformError(NULL, style, top, xsltTransformError(NULL, style, top,
"xsl:version: only 1.0 features are supported\n"); "xsl:version: only 1.1 features are supported\n");
if (style != NULL) { if (style != NULL) {
style->forwards_compatible = 1; style->forwards_compatible = 1;
style->warnings++; style->warnings++;
@ -6097,31 +6150,31 @@ xsltParseStylesheetTop(xsltStylesheetPtr style, xmlNodePtr top) {
xsltTransformError(NULL, style, cur, xsltTransformError(NULL, style, cur,
"xsltParseStylesheetTop: ignoring misplaced import element\n"); "xsltParseStylesheetTop: ignoring misplaced import element\n");
if (style != NULL) style->errors++; if (style != NULL) style->errors++;
} else if (IS_XSLT_NAME(cur, "include")) { } else if (IS_XSLT_NAME(cur, "include")) {
if (xsltParseStylesheetInclude(style, cur) != 0) if (xsltParseStylesheetInclude(style, cur) != 0)
if (style != NULL) style->errors++; if (style != NULL) style->errors++;
} else if (IS_XSLT_NAME(cur, "strip-space")) { } else if (IS_XSLT_NAME(cur, "strip-space")) {
xsltParseStylesheetStripSpace(style, cur); xsltParseStylesheetStripSpace(style, cur);
} else if (IS_XSLT_NAME(cur, "preserve-space")) { } else if (IS_XSLT_NAME(cur, "preserve-space")) {
xsltParseStylesheetPreserveSpace(style, cur); xsltParseStylesheetPreserveSpace(style, cur);
} else if (IS_XSLT_NAME(cur, "output")) { } else if (IS_XSLT_NAME(cur, "output")) {
xsltParseStylesheetOutput(style, cur); xsltParseStylesheetOutput(style, cur);
} else if (IS_XSLT_NAME(cur, "key")) { } else if (IS_XSLT_NAME(cur, "key")) {
xsltParseStylesheetKey(style, cur); xsltParseStylesheetKey(style, cur);
} else if (IS_XSLT_NAME(cur, "decimal-format")) { } else if (IS_XSLT_NAME(cur, "decimal-format")) {
xsltParseStylesheetDecimalFormat(style, cur); xsltParseStylesheetDecimalFormat(style, cur);
} else if (IS_XSLT_NAME(cur, "attribute-set")) { } else if (IS_XSLT_NAME(cur, "attribute-set")) {
xsltParseStylesheetAttributeSet(style, cur); xsltParseStylesheetAttributeSet(style, cur);
} else if (IS_XSLT_NAME(cur, "variable")) { } else if (IS_XSLT_NAME(cur, "variable")) {
xsltParseGlobalVariable(style, cur); xsltParseGlobalVariable(style, cur);
} else if (IS_XSLT_NAME(cur, "param")) { } else if (IS_XSLT_NAME(cur, "param")) {
xsltParseGlobalParam(style, cur); xsltParseGlobalParam(style, cur);
} else if (IS_XSLT_NAME(cur, "template")) { } else if (IS_XSLT_NAME(cur, "template")) {
#ifdef WITH_XSLT_DEBUG_PARSING #ifdef WITH_XSLT_DEBUG_PARSING
templates++; templates++;
#endif #endif
xsltParseStylesheetTemplate(style, cur); xsltParseStylesheetTemplate(style, cur);
} else if (IS_XSLT_NAME(cur, "namespace-alias")) { } else if (IS_XSLT_NAME(cur, "namespace-alias")) {
xsltNamespaceAlias(style, cur); xsltNamespaceAlias(style, cur);
} else { } else {
if ((style != NULL) && (style->forwards_compatible == 0)) { if ((style != NULL) && (style->forwards_compatible == 0)) {
@ -6130,13 +6183,6 @@ xsltParseStylesheetTop(xsltStylesheetPtr style, xmlNodePtr top) {
cur->name); cur->name);
if (style != NULL) style->errors++; 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; cur = cur->next;
} }
@ -6380,7 +6426,7 @@ xsltParseStylesheetProcess(xsltStylesheetPtr ret, xmlDocPtr doc) {
ret->literal_result = 1; ret->literal_result = 1;
} }
if (!ret->nopreproc) { if (!ret->nopreproc) {
xsltPrecomputeStylesheet(ret, cur); xsltPreprocessStylesheet(ret, cur);
} }
if (ret->literal_result == 0) { if (ret->literal_result == 0) {
xsltParseStylesheetTop(ret, cur); xsltParseStylesheetTop(ret, cur);
@ -6403,10 +6449,11 @@ xsltParseStylesheetProcess(xsltStylesheetPtr ret, xmlDocPtr doc) {
"xsltParseStylesheetProcess : document is stylesheet\n"); "xsltParseStylesheetProcess : document is stylesheet\n");
#endif #endif
if (!xmlStrEqual(prop, (const xmlChar *)"1.0")) { if ((!xmlStrEqual(prop, (const xmlChar *)"1.0")) &&
(!xmlStrEqual(prop, (const xmlChar *)"1.1"))) {
xsltTransformError(NULL, ret, cur, xsltTransformError(NULL, ret, cur,
"xsl:version: only 1.0 features are supported\n"); "xsl:version: only 1.1 features are supported\n");
/* TODO set up compatibility when not XSLT 1.0 */ ret->forwards_compatible = 1;
ret->warnings++; ret->warnings++;
} }
xmlFree(prop); xmlFree(prop);

View file

@ -123,19 +123,6 @@ extern "C" {
#define LIBXSLT_DEFAULT_PLUGINS_PATH() "@LIBXSLT_DEFAULT_PLUGINS_PATH@" #define LIBXSLT_DEFAULT_PLUGINS_PATH() "@LIBXSLT_DEFAULT_PLUGINS_PATH@"
#endif #endif
/**
* Locale support
*/
#if @XSLT_LOCALE_XLOCALE@
#ifndef XSLT_LOCALE_XLOCALE
#define XSLT_LOCALE_XLOCALE
#endif
#elif @XSLT_LOCALE_WINAPI@
#ifndef XSLT_LOCALE_WINAPI
#define XSLT_LOCALE_WINAPI
#endif
#endif
/** /**
* ATTRIBUTE_UNUSED: * ATTRIBUTE_UNUSED:
* *

View file

@ -14,13 +14,6 @@
#include "xsltlocale.h" #include "xsltlocale.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 TOUPPER(c) (c & ~0x20)
#define TOLOWER(c) (c | 0x20) #define TOLOWER(c) (c | 0x20)
#define ISALPHA(c) ((unsigned)(TOUPPER(c) - 'A') < 26) #define ISALPHA(c) ((unsigned)(TOUPPER(c) - 'A') < 26)
@ -87,7 +80,7 @@ xsltFreeLocales(void) {
*/ */
xsltLocale xsltLocale
xsltNewLocale(const xmlChar *languageTag) { xsltNewLocale(const xmlChar *languageTag) {
#ifdef XSLT_LOCALE_XLOCALE #ifdef XSLT_LOCALE_POSIX
xsltLocale locale; xsltLocale locale;
char localeName[XSLTMAX_LANGTAGLEN+6]; /* 6 chars for ".utf8\0" */ char localeName[XSLTMAX_LANGTAGLEN+6]; /* 6 chars for ".utf8\0" */
const xmlChar *p = languageTag; const xmlChar *p = languageTag;
@ -189,7 +182,7 @@ xsltNewLocale(const xmlChar *languageTag) {
region = xsltDefaultRegion(localeName); region = xsltDefaultRegion(localeName);
if (region == NULL) goto end; if (region == NULL) goto end;
strcpy(localeName + llen + 1, region); strcpy((char *) localeName + llen + 1, (char *) region);
locale = xslt_locale_WINAPI(localeName); locale = xslt_locale_WINAPI(localeName);
end: end:
return(locale); return(locale);
@ -347,7 +340,7 @@ xsltDefaultRegion(const xmlChar *localeName) {
*/ */
void void
xsltFreeLocale(xsltLocale locale) { xsltFreeLocale(xsltLocale locale) {
#ifdef XSLT_LOCALE_XLOCALE #ifdef XSLT_LOCALE_POSIX
freelocale(locale); freelocale(locale);
#endif #endif
} }
@ -371,7 +364,7 @@ xsltStrxfrm(xsltLocale locale, const xmlChar *string)
size_t xstrlen, r; size_t xstrlen, r;
xsltLocaleChar *xstr; xsltLocaleChar *xstr;
#ifdef XSLT_LOCALE_XLOCALE #ifdef XSLT_LOCALE_POSIX
xstrlen = strxfrm_l(NULL, (const char *)string, 0, locale) + 1; xstrlen = strxfrm_l(NULL, (const char *)string, 0, locale) + 1;
xstr = (xsltLocaleChar *) xmlMalloc(xstrlen); xstr = (xsltLocaleChar *) xmlMalloc(xstrlen);
if (xstr == NULL) { if (xstr == NULL) {
@ -384,7 +377,7 @@ xsltStrxfrm(xsltLocale locale, const xmlChar *string)
#endif #endif
#ifdef XSLT_LOCALE_WINAPI #ifdef XSLT_LOCALE_WINAPI
xstrlen = MultiByteToWideChar(CP_UTF8, 0, string, -1, NULL, 0); xstrlen = MultiByteToWideChar(CP_UTF8, 0, (char *) string, -1, NULL, 0);
if (xstrlen == 0) { if (xstrlen == 0) {
xsltTransformError(NULL, NULL, NULL, "xsltStrxfrm : MultiByteToWideChar check failed\n"); xsltTransformError(NULL, NULL, NULL, "xsltStrxfrm : MultiByteToWideChar check failed\n");
return(NULL); return(NULL);
@ -394,7 +387,7 @@ xsltStrxfrm(xsltLocale locale, const xmlChar *string)
xsltTransformError(NULL, NULL, NULL, "xsltStrxfrm : out of memory\n"); xsltTransformError(NULL, NULL, NULL, "xsltStrxfrm : out of memory\n");
return(NULL); return(NULL);
} }
r = MultiByteToWideChar(CP_UTF8, 0, string, -1, xstr, xstrlen); r = MultiByteToWideChar(CP_UTF8, 0, (char *) string, -1, xstr, xstrlen);
if (r == 0) { if (r == 0) {
xsltTransformError(NULL, NULL, NULL, "xsltStrxfrm : MultiByteToWideChar failed\n"); xsltTransformError(NULL, NULL, NULL, "xsltStrxfrm : MultiByteToWideChar failed\n");
xmlFree(xstr); xmlFree(xstr);
@ -481,9 +474,11 @@ xsltIterateSupportedLocales(LPSTR lcid) {
k = sscanf(lcid, "%lx", (long*)&p->lcid); k = sscanf(lcid, "%lx", (long*)&p->lcid);
if (k < 1) goto end; if (k < 1) goto end;
/*don't count terminating null character*/ /*don't count terminating null character*/
k = GetLocaleInfoA(p->lcid, LOCALE_SISO639LANGNAME , iso639lang , sizeof(iso639lang )); k = GetLocaleInfoA(p->lcid, LOCALE_SISO639LANGNAME,
(char *) iso639lang, sizeof(iso639lang));
if (--k < 1) goto end; if (--k < 1) goto end;
l = GetLocaleInfoA(p->lcid, LOCALE_SISO3166CTRYNAME, iso3136ctry, sizeof(iso3136ctry)); l = GetLocaleInfoA(p->lcid, LOCALE_SISO3166CTRYNAME,
(char *) iso3136ctry, sizeof(iso3136ctry));
if (--l < 1) goto end; if (--l < 1) goto end;
{ /*fill results*/ { /*fill results*/

View file

@ -18,16 +18,9 @@
#include <unistd.h> #include <unistd.h>
#endif #endif
/* gettimeofday on Windows ??? */ #if defined(_WIN32) && !defined(__CYGWIN__)
#if defined(WIN32) && !defined(__CYGWIN__)
#ifdef _MSC_VER
#include <winsock2.h>
#pragma comment(lib, "ws2_32.lib")
#define gettimeofday(p1,p2)
#define HAVE_GETTIMEOFDAY
#define XSLT_WIN32_PERFORMANCE_COUNTER #define XSLT_WIN32_PERFORMANCE_COUNTER
#endif /* _MS_VER */ #endif
#endif /* WIN32 */
/************************************************************************ /************************************************************************
* * * *
@ -433,9 +426,8 @@ xsltMessage(xsltTransformContextPtr ctxt, xmlNodePtr node, xmlNodePtr inst) {
} else if (xmlStrEqual(prop, (const xmlChar *)"no")) { } else if (xmlStrEqual(prop, (const xmlChar *)"no")) {
terminate = 0; terminate = 0;
} else { } else {
error(errctx, xsltTransformError(ctxt, NULL, inst,
"xsl:message : terminate expecting 'yes' or 'no'\n"); "xsl:message : terminate expecting 'yes' or 'no'\n");
ctxt->state = XSLT_STATE_ERROR;
} }
xmlFree(prop); xmlFree(prop);
} }
@ -598,7 +590,8 @@ xsltPrintErrorContext(xsltTransformContextPtr ctxt,
void *errctx = xsltGenericErrorContext; void *errctx = xsltGenericErrorContext;
if (ctxt != NULL) { if (ctxt != NULL) {
ctxt->state = XSLT_STATE_ERROR; if (ctxt->state == XSLT_STATE_OK)
ctxt->state = XSLT_STATE_ERROR;
if (ctxt->error != NULL) { if (ctxt->error != NULL) {
error = ctxt->error; error = ctxt->error;
errctx = ctxt->errctx; errctx = ctxt->errctx;
@ -691,7 +684,8 @@ xsltTransformError(xsltTransformContextPtr ctxt,
char * str; char * str;
if (ctxt != NULL) { if (ctxt != NULL) {
ctxt->state = XSLT_STATE_ERROR; if (ctxt->state == XSLT_STATE_OK)
ctxt->state = XSLT_STATE_ERROR;
if (ctxt->error != NULL) { if (ctxt->error != NULL) {
error = ctxt->error; error = ctxt->error;
errctx = ctxt->errctx; errctx = ctxt->errctx;
@ -1224,6 +1218,8 @@ xsltDefaultSortFunction(xsltTransformContextPtr ctxt, xmlNodePtr *sorts,
if (res[j] == NULL) { if (res[j] == NULL) {
if (res[j+incr] != NULL) if (res[j+incr] != NULL)
tst = 1; tst = 1;
} else if (res[j+incr] == NULL) {
tst = -1;
} else { } else {
if (numb) { if (numb) {
/* We make NaN smaller than number in /* We make NaN smaller than number in
@ -1784,6 +1780,8 @@ static long calibration = -1;
* *
* Returns the number of milliseconds used by xsltTimestamp() * Returns the number of milliseconds used by xsltTimestamp()
*/ */
#if !defined(XSLT_WIN32_PERFORMANCE_COUNTER) && \
(defined(HAVE_CLOCK_GETTIME) || defined(HAVE_GETTIMEOFDAY))
static long static long
xsltCalibrateTimestamps(void) { xsltCalibrateTimestamps(void) {
register int i; register int i;
@ -1792,6 +1790,7 @@ xsltCalibrateTimestamps(void) {
xsltTimestamp(); xsltTimestamp();
return(xsltTimestamp() / 1000); return(xsltTimestamp() / 1000);
} }
#endif
/** /**
* xsltCalibrateAdjust: * xsltCalibrateAdjust:

View file

@ -23,21 +23,21 @@ extern "C" {
* *
* the version string like "1.2.3" * the version string like "1.2.3"
*/ */
#define LIBXSLT_DOTTED_VERSION "1.1.28" #define LIBXSLT_DOTTED_VERSION "1.1.32"
/** /**
* LIBXSLT_VERSION: * LIBXSLT_VERSION:
* *
* the version number: 1.2.3 value is 1002003 * the version number: 1.2.3 value is 1002003
*/ */
#define LIBXSLT_VERSION 10128 #define LIBXSLT_VERSION 10132
/** /**
* LIBXSLT_VERSION_STRING: * LIBXSLT_VERSION_STRING:
* *
* the version number string, 1.2.3 value is "1002003" * the version number string, 1.2.3 value is "1002003"
*/ */
#define LIBXSLT_VERSION_STRING "10128" #define LIBXSLT_VERSION_STRING "10132"
/** /**
* LIBXSLT_VERSION_EXTRA: * LIBXSLT_VERSION_EXTRA:
@ -53,7 +53,7 @@ extern "C" {
* is insignifiant and being able to run xsltpoc -v is useful. On * is insignifiant and being able to run xsltpoc -v is useful. On
* by default * by default
*/ */
#if 0 #if 1
#define WITH_XSLT_DEBUG #define WITH_XSLT_DEBUG
#endif #endif
@ -62,7 +62,7 @@ extern "C" {
* *
* Whether module support is configured into libxslt * Whether module support is configured into libxslt
*/ */
#if 0 #if 1
#ifndef WITH_MODULES #ifndef WITH_MODULES
#define WITH_MODULES #define WITH_MODULES
#endif #endif

View file

@ -10,7 +10,7 @@
#ifndef __XSLT_LIBXSLT_H__ #ifndef __XSLT_LIBXSLT_H__
#define __XSLT_LIBXSLT_H__ #define __XSLT_LIBXSLT_H__
#if defined(WIN32) && !defined (__CYGWIN__) && !defined (__MINGW32__) #if defined(_WIN32) && !defined (__CYGWIN__) && !defined (__MINGW32__)
#include <win32config.h> #include <win32config.h>
#else #else
#include "config.h" #include "config.h"

View file

@ -34,6 +34,41 @@ extern "C" {
xsltRegisterAllElement(ctxt); \ xsltRegisterAllElement(ctxt); \
(ctxt)->xpathCtxt->extra = ctxt (ctxt)->xpathCtxt->extra = ctxt
/*
* Flags for memory management of RVTs
*/
/**
* XSLT_RVT_LOCAL:
*
* RVT is destroyed after the current instructions ends.
*/
#define XSLT_RVT_LOCAL ((void *)1)
/**
* XSLT_RVT_VARIABLE:
*
* RVT is part of a local variable and destroyed after the variable goes out
* of scope.
*/
#define XSLT_RVT_VARIABLE ((void *)2)
/**
* XSLT_RVT_FUNC_RESULT:
*
* RVT is part of results returned with func:result. The RVT won't be
* destroyed after exiting a template and will be reset to XSLT_RVT_LOCAL or
* XSLT_RVT_VARIABLE in the template that receives the return value.
*/
#define XSLT_RVT_FUNC_RESULT ((void *)3)
/**
* XSLT_RVT_GLOBAL:
*
* RVT is part of a global variable.
*/
#define XSLT_RVT_GLOBAL ((void *)4)
/* /*
* Interfaces for the variable module. * Interfaces for the variable module.
*/ */

View file

@ -324,6 +324,7 @@ struct _xsltDecimalFormat {
xmlChar *percent; xmlChar *percent;
xmlChar *permille; xmlChar *permille;
xmlChar *zeroDigit; xmlChar *zeroDigit;
const xmlChar *nsUri;
}; };
/** /**
@ -1754,8 +1755,8 @@ struct _xsltTransformContext {
* Speed optimization when coalescing text nodes * Speed optimization when coalescing text nodes
*/ */
const xmlChar *lasttext; /* last text node content */ const xmlChar *lasttext; /* last text node content */
unsigned int lasttsize; /* last text node size */ int lasttsize; /* last text node size */
unsigned int lasttuse; /* last text node use */ int lasttuse; /* last text node use */
/* /*
* Per Context Debugging * Per Context Debugging
*/ */
@ -1783,9 +1784,9 @@ struct _xsltTransformContext {
xmlDocPtr localRVT; /* list of local tree fragments; will be freed when xmlDocPtr localRVT; /* list of local tree fragments; will be freed when
the instruction which created the fragment the instruction which created the fragment
exits */ exits */
xmlDocPtr localRVTBase; xmlDocPtr localRVTBase; /* Obsolete */
int keyInitLevel; /* Needed to catch recursive keys issues */ int keyInitLevel; /* Needed to catch recursive keys issues */
int funcLevel; /* Needed to catch recursive functions issues */ int depth; /* Needed to catch recursions */
int maxTemplateDepth; int maxTemplateDepth;
int maxTemplateVars; int maxTemplateVars;
}; };
@ -1854,6 +1855,10 @@ XSLTPUBFUN void XSLTCALL
XSLTPUBFUN xsltDecimalFormatPtr XSLTCALL XSLTPUBFUN xsltDecimalFormatPtr XSLTCALL
xsltDecimalFormatGetByName(xsltStylesheetPtr style, xsltDecimalFormatGetByName(xsltStylesheetPtr style,
xmlChar *name); xmlChar *name);
XSLTPUBFUN xsltDecimalFormatPtr XSLTCALL
xsltDecimalFormatGetByQName(xsltStylesheetPtr style,
const xmlChar *nsUri,
const xmlChar *name);
XSLTPUBFUN xsltStylesheetPtr XSLTCALL XSLTPUBFUN xsltStylesheetPtr XSLTCALL
xsltParseStylesheetProcess(xsltStylesheetPtr ret, xsltParseStylesheetProcess(xsltStylesheetPtr ret,
@ -1906,6 +1911,11 @@ XSLTPUBFUN int XSLTCALL
XSLTPUBFUN int XSLTCALL XSLTPUBFUN int XSLTCALL
xsltExtensionInstructionResultFinalize( xsltExtensionInstructionResultFinalize(
xsltTransformContextPtr ctxt); xsltTransformContextPtr ctxt);
XSLTPUBFUN int XSLTCALL
xsltFlagRVTs(
xsltTransformContextPtr ctxt,
xmlXPathObjectPtr obj,
void *val);
XSLTPUBFUN void XSLTCALL XSLTPUBFUN void XSLTCALL
xsltFreeRVTs (xsltTransformContextPtr ctxt); xsltFreeRVTs (xsltTransformContextPtr ctxt);
XSLTPUBFUN void XSLTCALL XSLTPUBFUN void XSLTCALL

View file

@ -20,21 +20,21 @@ extern "C" {
* *
* the version string like "1.2.3" * the version string like "1.2.3"
*/ */
#define LIBXSLT_DOTTED_VERSION "1.1.29" #define LIBXSLT_DOTTED_VERSION "1.1.32"
/** /**
* LIBXSLT_VERSION: * LIBXSLT_VERSION:
* *
* the version number: 1.2.3 value is 10203 * the version number: 1.2.3 value is 10203
*/ */
#define LIBXSLT_VERSION 10129 #define LIBXSLT_VERSION 10132
/** /**
* LIBXSLT_VERSION_STRING: * LIBXSLT_VERSION_STRING:
* *
* the version number string, 1.2.3 value is "10203" * the version number string, 1.2.3 value is "10203"
*/ */
#define LIBXSLT_VERSION_STRING "10129" #define LIBXSLT_VERSION_STRING "10132"
/** /**
* LIBXSLT_VERSION_EXTRA: * LIBXSLT_VERSION_EXTRA:
@ -123,19 +123,6 @@ extern "C" {
#define LIBXSLT_DEFAULT_PLUGINS_PATH() "/usr/lib/libxslt-plugins" #define LIBXSLT_DEFAULT_PLUGINS_PATH() "/usr/lib/libxslt-plugins"
#endif #endif
/**
* Locale support
*/
#if 0
#ifndef XSLT_LOCALE_XLOCALE
#define XSLT_LOCALE_XLOCALE
#endif
#elif 1
#ifndef XSLT_LOCALE_WINAPI
#define XSLT_LOCALE_WINAPI
#endif
#endif
/** /**
* ATTRIBUTE_UNUSED: * ATTRIBUTE_UNUSED:
* *

View file

@ -14,20 +14,31 @@
#include <libxml/xmlstring.h> #include <libxml/xmlstring.h>
#include "xsltexports.h" #include "xsltexports.h"
#ifdef XSLT_LOCALE_XLOCALE #ifdef HAVE_STRXFRM_L
/*
* XSLT_LOCALE_POSIX:
* Macro indicating to use POSIX locale extensions
*/
#define XSLT_LOCALE_POSIX
#ifdef HAVE_LOCALE_H
#include <locale.h> #include <locale.h>
#include <xlocale.h>
#ifdef __GLIBC__
/*locale_t is defined only if _GNU_SOURCE is defined*/
typedef __locale_t xsltLocale;
#else
typedef locale_t xsltLocale;
#endif #endif
#ifdef HAVE_XLOCALE_H
#include <xlocale.h>
#endif
typedef locale_t xsltLocale;
typedef xmlChar xsltLocaleChar; typedef xmlChar xsltLocaleChar;
#elif defined(XSLT_LOCALE_WINAPI) #elif defined(_WIN32) && !defined(__CYGWIN__)
/*
* XSLT_LOCALE_WINAPI:
* Macro indicating to use WinAPI for extended locale support
*/
#define XSLT_LOCALE_WINAPI
#ifdef __REACTOS__ #ifdef __REACTOS__
#define WIN32_NO_STATUS #define WIN32_NO_STATUS
@ -45,11 +56,9 @@ typedef wchar_t xsltLocaleChar;
/* /*
* XSLT_LOCALE_NONE: * XSLT_LOCALE_NONE:
* Macro indicating that locale are not supported * Macro indicating that there's no extended locale support
*/ */
#ifndef XSLT_LOCALE_NONE
#define XSLT_LOCALE_NONE #define XSLT_LOCALE_NONE
#endif
typedef void *xsltLocale; typedef void *xsltLocale;
typedef xmlChar xsltLocaleChar; typedef xmlChar xsltLocaleChar;