From cd40951e8e8a00e3ea022c2956d352bc131a54ba Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
Date: Sun, 4 Aug 2013 22:59:26 +0200
Subject: [PATCH 09/14] Fix certain patterns with predicates

The optimization for predicates in patterns only supports XSLT_OP_ELEM
and XSLT_OP_ALL. This commit makes predicates on other ops fall back to
the slow direct matching code path.

Fixes bugs #531685 and #538580.
---
 libxslt/pattern.c         | 18 ++++++++++++------
 tests/docs/Makefile.am    |  2 ++
 tests/docs/bug-181.xml    |  4 ++++
 tests/docs/bug-182.xml    |  4 ++++
 tests/general/Makefile.am |  2 ++
 tests/general/bug-181.out |  5 +++++
 tests/general/bug-181.xsl | 13 +++++++++++++
 tests/general/bug-182.out |  2 ++
 tests/general/bug-182.xsl | 19 +++++++++++++++++++
 9 files changed, 63 insertions(+), 6 deletions(-)
 create mode 100644 tests/docs/bug-181.xml
 create mode 100644 tests/docs/bug-182.xml
 create mode 100644 tests/general/bug-181.out
 create mode 100644 tests/general/bug-181.xsl
 create mode 100644 tests/general/bug-182.out
 create mode 100644 tests/general/bug-182.xsl

diff --git a/libxslt/pattern.c b/libxslt/pattern.c
index 058917a..a97726c 100644
--- a/libxslt/pattern.c
+++ b/libxslt/pattern.c
@@ -451,11 +451,14 @@ xsltReverseCompMatch(xsltParserContextPtr ctxt, xsltCompMatchPtr comp) {
     xsltCompMatchAdd(ctxt, comp, XSLT_OP_END, NULL, NULL, 0);
 
     /*
-     * detect consecutive XSLT_OP_PREDICATE indicating a direct
-     * matching should be done.
+     * Detect consecutive XSLT_OP_PREDICATE and predicates on ops which
+     * haven't been optimized yet indicating a direct matching should be done.
      */
     for (i = 0;i < comp->nbStep - 1;i++) {
-        if ((comp->steps[i].op == XSLT_OP_PREDICATE) &&
+        xsltOp op = comp->steps[i].op;
+
+        if ((op != XSLT_OP_ELEM) &&
+            (op != XSLT_OP_ALL) &&
 	    (comp->steps[i + 1].op == XSLT_OP_PREDICATE)) {
 
 	    comp->direct = 1;
@@ -655,8 +658,10 @@ xsltTestPredicateMatch(xsltTransformContextPtr ctxt, xsltCompMatchPtr comp,
         isRVT = 0;
 
     /*
-     * Depending on the last selection, one may need to
-     * recompute contextSize and proximityPosition.
+     * Recompute contextSize and proximityPosition.
+     *
+     * TODO: Make this work for additional ops. Currently, only XSLT_OP_ELEM
+     * and XSLT_OP_ALL are supported.
      */
     oldCS = ctxt->xpathCtxt->contextSize;
     oldCP = ctxt->xpathCtxt->proximityPosition;
@@ -1128,7 +1133,8 @@ restart:
 		break;
 	    case XSLT_OP_PREDICATE: {
 		/*
-		 * when there is cascading XSLT_OP_PREDICATE, then use a
+		 * When there is cascading XSLT_OP_PREDICATE or a predicate
+		 * after an op which hasn't been optimized yet, then use a
 		 * direct computation approach. It's not done directly
 		 * at the beginning of the routine to filter out as much
 		 * as possible this costly computation.
diff --git a/tests/docs/Makefile.am b/tests/docs/Makefile.am
index c5dad4c..e3a4aef 100644
--- a/tests/docs/Makefile.am
+++ b/tests/docs/Makefile.am
@@ -179,6 +179,8 @@ EXTRA_DIST =	\
 	bug-178.xml \
 	bug-179.xml \
 	bug-180.xml \
+	bug-181.xml \
+	bug-182.xml \
 	character.xml \
 	array.xml \
 	items.xml
diff --git a/tests/docs/bug-181.xml b/tests/docs/bug-181.xml
new file mode 100644
index 0000000..285b69a
--- /dev/null
+++ b/tests/docs/bug-181.xml
@@ -0,0 +1,4 @@
+<Urmel>
+  <E>1. zwei <F>drei</F> zwei eins</E>
+  <E a="b">2. zwei <F>drei</F> zwei eins</E>
+</Urmel>
diff --git a/tests/docs/bug-182.xml b/tests/docs/bug-182.xml
new file mode 100644
index 0000000..02b378d
--- /dev/null
+++ b/tests/docs/bug-182.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<root>
+<body><b> b 1 </b> text 1 <b> b 2 </b> text 2 </body>
+</root>
diff --git a/tests/general/Makefile.am b/tests/general/Makefile.am
index 0c2ef30..4802a6b 100644
--- a/tests/general/Makefile.am
+++ b/tests/general/Makefile.am
@@ -188,6 +188,8 @@ EXTRA_DIST = \
     bug-178.out bug-178.xsl \
     bug-179.out bug-179.xsl \
     bug-180.out bug-180.xsl bug-180.err \
+    bug-181.out bug-181.xsl \
+    bug-182.out bug-182.xsl \
     character.out character.xsl \
     character2.out character2.xsl \
     itemschoose.out itemschoose.xsl \
diff --git a/tests/general/bug-181.out b/tests/general/bug-181.out
new file mode 100644
index 0000000..730387a
--- /dev/null
+++ b/tests/general/bug-181.out
@@ -0,0 +1,5 @@
+<?xml version="1.0"?>
+<Urmel>
+  <E>1. * zwei <F>drei</F> zwei eins</E>
+  <E a="b">2. * zwei <F>drei</F> zwei eins</E>
+</Urmel>
diff --git a/tests/general/bug-181.xsl b/tests/general/bug-181.xsl
new file mode 100644
index 0000000..0c4de71
--- /dev/null
+++ b/tests/general/bug-181.xsl
@@ -0,0 +1,13 @@
+<xsl:transform version="1.0"
+  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+  <xsl:template match="E/text()[ 1 ]">
+    <xsl:value-of select="substring-before( . , ' ')"/>
+    <xsl:text> * </xsl:text>
+    <xsl:value-of select="substring-after( . , ' ')"/>
+  </xsl:template>
+  <xsl:template match="@*|node()">
+    <xsl:copy>
+      <xsl:apply-templates select="@*|node()"/>
+    </xsl:copy>
+  </xsl:template>
+</xsl:transform>
diff --git a/tests/general/bug-182.out b/tests/general/bug-182.out
new file mode 100644
index 0000000..93ab15e
--- /dev/null
+++ b/tests/general/bug-182.out
@@ -0,0 +1,2 @@
+<?xml version="1.0"?>
+<body><p>b[2]:  b 2 </p><p>text()[2]:  text 2 </p></body>
diff --git a/tests/general/bug-182.xsl b/tests/general/bug-182.xsl
new file mode 100644
index 0000000..ecce187
--- /dev/null
+++ b/tests/general/bug-182.xsl
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+
+<xsl:template match="node()"/>
+
+<xsl:template match="text()[2]">
+  <p>text()[2]: <xsl:value-of select="."/></p>
+</xsl:template>
+<xsl:template match="b[2]">
+  <p>b[2]: <xsl:value-of select="."/></p>
+</xsl:template>
+
+<xsl:template match="/">
+  <body>
+    <xsl:apply-templates select="/root/body/node()"/>
+  </body>
+</xsl:template>
+
+</xsl:stylesheet>
-- 
1.8.4.1

