From 515283959aae470a6ee5033deb9f977a489e7578 Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
Date: Sun, 4 Aug 2013 16:42:51 +0200
Subject: [PATCH 06/14] Fix str:padding to work with UTF-8 strings

Thanks to Tobias Hoffmann for the report.

Also add some tests.
---
 libexslt/strings.c                | 16 +++++++++-------
 tests/exslt/strings/padding.1.out | 27 ++++++++++++++++++++++++++
 tests/exslt/strings/padding.1.xml | 10 ++++++++++
 tests/exslt/strings/padding.1.xsl | 40 +++++++++++++++++++++++++++++++++++++++
 4 files changed, 86 insertions(+), 7 deletions(-)
 create mode 100644 tests/exslt/strings/padding.1.out
 create mode 100644 tests/exslt/strings/padding.1.xml
 create mode 100644 tests/exslt/strings/padding.1.xsl

diff --git a/libexslt/strings.c b/libexslt/strings.c
index c0c7a18..3c702ad 100644
--- a/libexslt/strings.c
+++ b/libexslt/strings.c
@@ -351,8 +351,8 @@ exsltStrDecodeUriFunction (xmlXPathParserContextPtr ctxt, int nargs) {
  */
 static void
 exsltStrPaddingFunction (xmlXPathParserContextPtr ctxt, int nargs) {
-    int number, str_len = 0;
-    xmlChar *str = NULL, *ret = NULL, *tmp;
+    int number, str_len = 0, str_size = 0;
+    xmlChar *str = NULL, *ret = NULL;
 
     if ((nargs < 1) || (nargs > 2)) {
 	xmlXPathSetArityError(ctxt);
@@ -362,11 +362,13 @@ exsltStrPaddingFunction (xmlXPathParserContextPtr ctxt, int nargs) {
     if (nargs == 2) {
 	str = xmlXPathPopString(ctxt);
 	str_len = xmlUTF8Strlen(str);
+	str_size = xmlStrlen(str);
     }
     if (str_len == 0) {
 	if (str != NULL) xmlFree(str);
 	str = xmlStrdup((const xmlChar *) " ");
 	str_len = 1;
+	str_size = 1;
     }
 
     number = (int) xmlXPathPopNumber(ctxt);
@@ -378,13 +380,13 @@ exsltStrPaddingFunction (xmlXPathParserContextPtr ctxt, int nargs) {
     }
 
     while (number >= str_len) {
-	ret = xmlStrncat(ret, str, str_len);
+	ret = xmlStrncat(ret, str, str_size);
 	number -= str_len;
     }
-    tmp = xmlUTF8Strndup (str, number);
-    ret = xmlStrcat(ret, tmp);
-    if (tmp != NULL)
-	xmlFree (tmp);
+    if (number > 0) {
+	str_size = xmlUTF8Strsize(str, number);
+	ret = xmlStrncat(ret, str, str_size);
+    }
 
     xmlXPathReturnString(ctxt, ret);
 
diff --git a/tests/exslt/strings/padding.1.out b/tests/exslt/strings/padding.1.out
new file mode 100644
index 0000000..1833a65
--- /dev/null
+++ b/tests/exslt/strings/padding.1.out
@@ -0,0 +1,27 @@
+<?xml version="1.0"?>
+<test-results>
+  <test-result>
+    <padding>     </padding>
+    <length-check>OK</length-check>
+  </test-result>
+  <test-result>
+    <padding>--------</padding>
+    <length-check>OK</length-check>
+  </test-result>
+  <test-result>
+    <padding>abcabcabca</padding>
+    <length-check>OK</length-check>
+  </test-result>
+  <test-result>
+    <padding>–––––––</padding>
+    <length-check>OK</length-check>
+  </test-result>
+  <test-result>
+    <padding>– – – – – –</padding>
+    <length-check>OK</length-check>
+  </test-result>
+  <test-result>
+    <padding>ÄÖÜÄÖÜ</padding>
+    <length-check>OK</length-check>
+  </test-result>
+</test-results>
diff --git a/tests/exslt/strings/padding.1.xml b/tests/exslt/strings/padding.1.xml
new file mode 100644
index 0000000..16d0824
--- /dev/null
+++ b/tests/exslt/strings/padding.1.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0"?>
+<test-cases>
+    <test-case length="5"/>
+    <test-case length="8">-</test-case>
+    <test-case length="10">abc</test-case>
+    <test-case length="7">&#x2013;</test-case>
+    <test-case length="11">&#x2013;&#xa0;</test-case>
+    <test-case length="6">ÄÖÜ</test-case>
+</test-cases>
+
diff --git a/tests/exslt/strings/padding.1.xsl b/tests/exslt/strings/padding.1.xsl
new file mode 100644
index 0000000..c5d621d
--- /dev/null
+++ b/tests/exslt/strings/padding.1.xsl
@@ -0,0 +1,40 @@
+<?xml version="1.0"?>
+<xsl:stylesheet version="1.0"
+    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+    xmlns:str="http://exslt.org/strings"
+    exclude-result-prefixes="str">
+
+<xsl:output indent="yes"/>
+
+<xsl:template match="test-cases">
+    <test-results>
+        <xsl:apply-templates select="test-case"/>
+    </test-results>
+</xsl:template>
+
+<xsl:template match="test-case">
+    <test-result>
+        <xsl:variable name="padding">
+            <xsl:choose>
+                <xsl:when test="string(.)">
+                    <xsl:value-of select="str:padding(@length, .)"/>
+                </xsl:when>
+                <xsl:otherwise>
+                    <xsl:value-of select="str:padding(@length)"/>
+                </xsl:otherwise>
+            </xsl:choose>
+        </xsl:variable>
+        <padding>
+            <xsl:value-of select="$padding"/>
+        </padding>
+        <length-check>
+            <xsl:choose>
+                <xsl:when test="string-length($padding) = @length">OK</xsl:when>
+                <xsl:otherwise>FAIL</xsl:otherwise>
+            </xsl:choose>
+        </length-check>
+    </test-result>
+</xsl:template>
+
+</xsl:stylesheet>
+
-- 
1.8.4.1

