Index: third_party/libxslt/libxslt/variables.c |
diff --git a/third_party/libxslt/libxslt/variables.c b/third_party/libxslt/libxslt/variables.c |
index 345123d6ac144b1e15e0cfb60a21373e0a29aa95..e1a80eeee56b037961237fee0e1fc8caf011cd8e 100644 |
--- a/third_party/libxslt/libxslt/variables.c |
+++ b/third_party/libxslt/libxslt/variables.c |
@@ -43,8 +43,8 @@ const xmlChar *xsltDocFragFake = (const xmlChar *) " fake node libxslt"; |
const xmlChar *xsltComputingGlobalVarMarker = |
(const xmlChar *) " var/param being computed"; |
-#define XSLT_VAR_GLOBAL 1<<0 |
-#define XSLT_VAR_IN_SELECT 1<<1 |
+#define XSLT_VAR_GLOBAL (1<<0) |
+#define XSLT_VAR_IN_SELECT (1<<1) |
#define XSLT_TCTXT_VARIABLE(c) ((xsltStackElemPtr) (c)->contextVariable) |
/************************************************************************ |
@@ -122,6 +122,9 @@ xsltRegisterTmpRVT(xsltTransformContextPtr ctxt, xmlDocPtr RVT) |
if ((ctxt == NULL) || (RVT == NULL)) |
return(-1); |
+ RVT->prev = NULL; |
+ RVT->psvi = XSLT_RVT_VARIABLE; |
+ |
/* |
* We'll restrict the lifetime of user-created fragments |
* insinde an xsl:variable and xsl:param to the lifetime of the |
@@ -159,15 +162,18 @@ xsltRegisterLocalRVT(xsltTransformContextPtr ctxt, |
if ((ctxt == NULL) || (RVT == NULL)) |
return(-1); |
+ RVT->prev = NULL; |
+ |
/* |
* When evaluating "select" expressions of xsl:variable |
* 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. |
*/ |
if ((ctxt->contextVariable != NULL) && |
(XSLT_TCTXT_VARIABLE(ctxt)->flags & XSLT_VAR_IN_SELECT)) |
{ |
+ RVT->psvi = XSLT_RVT_VARIABLE; |
RVT->next = (xmlNodePtr) XSLT_TCTXT_VARIABLE(ctxt)->fragment; |
XSLT_TCTXT_VARIABLE(ctxt)->fragment = RVT; |
return(0); |
@@ -177,19 +183,11 @@ xsltRegisterLocalRVT(xsltTransformContextPtr ctxt, |
* If not reference by a returning instruction (like EXSLT's function), |
* then this fragment will be freed, when the instruction exits. |
*/ |
+ RVT->psvi = XSLT_RVT_LOCAL; |
RVT->next = (xmlNodePtr) ctxt->localRVT; |
if (ctxt->localRVT != NULL) |
ctxt->localRVT->prev = (xmlNodePtr) 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); |
} |
@@ -204,26 +202,16 @@ xsltRegisterLocalRVT(xsltTransformContextPtr ctxt, |
* 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. |
+ * |
+ * This function is unsupported in newer releases of libxslt. |
*/ |
int |
xsltExtensionInstructionResultFinalize(xsltTransformContextPtr ctxt) |
{ |
- xmlDocPtr cur; |
- |
- if (ctxt == NULL) |
- 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); |
+ xmlGenericError(xmlGenericErrorContext, |
+ "xsltExtensionInstructionResultFinalize is unsupported " |
+ "in this release of libxslt.\n"); |
+ return(-1); |
} |
/** |
@@ -238,11 +226,35 @@ xsltExtensionInstructionResultFinalize(xsltTransformContextPtr ctxt) |
* tree fragments (via xsltCreateRVT()) with xsltRegisterLocalRVT(). |
* |
* 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 |
xsltExtensionInstructionResultRegister(xsltTransformContextPtr ctxt, |
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; |
xmlNodePtr cur; |
xmlDocPtr doc; |
@@ -275,36 +287,59 @@ xsltExtensionInstructionResultRegister(xsltTransformContextPtr ctxt, |
doc = cur->doc; |
} else { |
xsltTransformError(ctxt, NULL, ctxt->inst, |
- "Internal error in " |
- "xsltExtensionInstructionResultRegister(): " |
+ "Internal error in xsltFlagRVTs(): " |
"Cannot retrieve the doc of a namespace node.\n"); |
- goto error; |
+ return(-1); |
} |
} else { |
doc = cur->doc; |
} |
if (doc == NULL) { |
xsltTransformError(ctxt, NULL, ctxt->inst, |
- "Internal error in " |
- "xsltExtensionInstructionResultRegister(): " |
+ "Internal error in xsltFlagRVTs(): " |
"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. |
- * We'll use the @psvi field for reference counting. |
- * TODO: How do we know if this is a value of a |
- * global variable or a doc acquired via the |
+ * We store ownership information in the @psvi field. |
+ * TODO: How do we know if this is a doc acquired via the |
* 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); |
-error: |
- return(-1); |
} |
/** |
@@ -350,9 +385,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; |
ctxt->cache->RVT = RVT; |
@@ -391,6 +426,8 @@ xsltRegisterPersistRVT(xsltTransformContextPtr ctxt, xmlDocPtr RVT) |
{ |
if ((ctxt == NULL) || (RVT == NULL)) return(-1); |
+ RVT->psvi = XSLT_RVT_GLOBAL; |
+ RVT->prev = NULL; |
RVT->next = (xmlNodePtr) ctxt->persistRVT; |
if (ctxt->persistRVT != NULL) |
ctxt->persistRVT->prev = (xmlNodePtr) RVT; |
@@ -541,35 +578,21 @@ xsltFreeStackElem(xsltStackElemPtr elem) { |
/* |
* Release the list of temporary Result Tree Fragments. |
*/ |
- if (elem->fragment) { |
+ if (elem->context) { |
xmlDocPtr cur; |
while (elem->fragment != NULL) { |
cur = elem->fragment; |
elem->fragment = (xmlDocPtr) cur->next; |
- if (elem->context && |
- (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 { |
+ if (cur->psvi == XSLT_RVT_VARIABLE) { |
xsltReleaseRVT((xsltTransformContextPtr) elem->context, |
cur); |
- } |
+ } else if (cur->psvi != XSLT_RVT_FUNC_RESULT) { |
+ xmlGenericError(xmlGenericErrorContext, |
+ "xsltFreeStackElem: Unexpected RVT flag %p\n", |
+ cur->psvi); |
+ } |
} |
} |
/* |
@@ -963,6 +986,7 @@ xsltEvalVariable(xsltTransformContextPtr ctxt, xsltStackElemPtr variable, |
* the Result Tree Fragment. |
*/ |
variable->fragment = container; |
+ container->psvi = XSLT_RVT_VARIABLE; |
oldOutput = ctxt->output; |
oldInsert = ctxt->insert; |
@@ -1149,16 +1173,23 @@ xsltEvalGlobalVariable(xsltStackElemPtr elem, xsltTransformContextPtr ctxt) |
xsltTransformError(ctxt, NULL, comp->inst, |
"Evaluating global variable %s failed\n", elem->name); |
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 LIBXML_DEBUG_ENABLED |
- } else { |
- if ((xsltGenericDebugContext == stdout) || |
- (xsltGenericDebugContext == stderr)) |
- xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext, |
- result, 0); |
+ if ((xsltGenericDebugContext == stdout) || |
+ (xsltGenericDebugContext == stderr)) |
+ xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext, |
+ result, 0); |
#endif |
#endif |
- } |
} else { |
if (elem->tree == NULL) { |
result = xmlXPathNewCString(""); |
@@ -1772,8 +1803,7 @@ xsltBuildVariable(xsltTransformContextPtr ctxt, |
elem->tree = tree; |
elem->value = xsltEvalVariable(ctxt, elem, |
(xsltStylePreCompPtr) comp); |
- if (elem->value != NULL) |
- elem->computed = 1; |
+ elem->computed = 1; |
return(elem); |
} |