Jacek Caban : jscript: Fix handling empty string regexp matches in String.prototype.split implementation.

Alexandre Julliard julliard at winehq.org
Mon Apr 22 16:30:38 CDT 2019


Module: wine
Branch: master
Commit: b48cc9614e924198d41569db6a3a36295904f9c9
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=b48cc9614e924198d41569db6a3a36295904f9c9

Author: Jacek Caban <jacek at codeweavers.com>
Date:   Mon Apr 22 13:04:37 2019 +0200

jscript: Fix handling empty string regexp matches in String.prototype.split implementation.

Signed-off-by: Jacek Caban <jacek at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/jscript/string.c     | 49 ++++++++++++++++++++++++++++++++---------------
 dlls/jscript/tests/api.js | 37 +++++++++++++++++++++++++++++++++++
 2 files changed, 71 insertions(+), 15 deletions(-)

diff --git a/dlls/jscript/string.c b/dlls/jscript/string.c
index 79d7884..d88ed1c 100644
--- a/dlls/jscript/string.c
+++ b/dlls/jscript/string.c
@@ -1131,21 +1131,20 @@ static HRESULT String_split(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsi
         jsval_t *r)
 {
     match_state_t match_result, *match_ptr = &match_result;
-    DWORD length, i, match_len = 0;
+    size_t length, i = 0, match_len = 0;
     const WCHAR *ptr, *ptr2, *str, *match_str = NULL;
     unsigned limit = ~0u;
     jsdisp_t *array, *regexp = NULL;
     jsstr_t *jsstr, *match_jsstr, *tmp_str;
     HRESULT hres;
 
-    TRACE("\n");
-
     hres = get_string_flat_val(ctx, jsthis, &jsstr, &str);
     if(FAILED(hres))
         return hres;
-
     length = jsstr_length(jsstr);
 
+    TRACE("%s\n", debugstr_wn(str, length));
+
     if(!argc || (is_undefined(argv[0]) && ctx->version >= SCRIPTLANGUAGEVERSION_ES5)) {
         if(!r)
             return S_OK;
@@ -1203,11 +1202,29 @@ static HRESULT String_split(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsi
     if(SUCCEEDED(hres)) {
         ptr = str;
         match_result.cp = str;
-        for(i=0; i<limit; i++) {
+        while(i < limit) {
             if(regexp) {
                 hres = regexp_match_next(ctx, regexp, REM_NO_PARENS, jsstr, &match_ptr);
                 if(hres != S_OK)
                     break;
+                TRACE("got match %d %d\n", (int)(match_result.cp - match_result.match_len - str), match_result.match_len);
+                if(!match_result.match_len) {
+                    /* If an empty string is matched, prevent including any match in the result */
+                    if(!length) {
+                        limit = 0;
+                        break;
+                    }
+                    if(match_result.cp == ptr) {
+                        match_result.cp++;
+                        hres = regexp_match_next(ctx, regexp, REM_NO_PARENS, jsstr, &match_ptr);
+                        if(hres != S_OK)
+                            break;
+                        TRACE("retried, got match %d %d\n", (int)(match_result.cp - match_result.match_len - str),
+                              match_result.match_len);
+                    }
+                    if(!match_result.match_len && match_result.cp == str + length)
+                        break;
+                }
                 ptr2 = match_result.cp - match_result.match_len;
             }else if(match_str) {
                 ptr2 = strstrW(ptr, match_str);
@@ -1219,16 +1236,18 @@ static HRESULT String_split(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsi
                 ptr2 = ptr+1;
             }
 
-            tmp_str = jsstr_alloc_len(ptr, ptr2-ptr);
-            if(!tmp_str) {
-                hres = E_OUTOFMEMORY;
-                break;
-            }
+            if(!regexp || ptr2 > ptr) {
+                tmp_str = jsstr_alloc_len(ptr, ptr2-ptr);
+                if(!tmp_str) {
+                    hres = E_OUTOFMEMORY;
+                    break;
+                }
 
-            hres = jsdisp_propput_idx(array, i, jsval_string(tmp_str));
-            jsstr_release(tmp_str);
-            if(FAILED(hres))
-                break;
+                hres = jsdisp_propput_idx(array, i++, jsval_string(tmp_str));
+                jsstr_release(tmp_str);
+                if(FAILED(hres))
+                    break;
+            }
 
             if(regexp)
                 ptr = match_result.cp;
@@ -1242,7 +1261,7 @@ static HRESULT String_split(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsi
     if(SUCCEEDED(hres) && (match_str || regexp) && i<limit) {
         DWORD len = (str+length) - ptr;
 
-        if(len || match_str) {
+        if(len || match_str || !length) {
             tmp_str = jsstr_alloc_len(ptr, len);
 
             if(tmp_str) {
diff --git a/dlls/jscript/tests/api.js b/dlls/jscript/tests/api.js
index 78c0958..f3d07f8 100644
--- a/dlls/jscript/tests/api.js
+++ b/dlls/jscript/tests/api.js
@@ -644,6 +644,43 @@ ok(typeof(r) === "object", "typeof(r) = " + typeof(r));
 ok(r.length === 1, "r.length = " + r.length);
 ok(r[0] === "", "r[0] = " + r[0]);
 
+(function() {
+    function test(string, separator, result) {
+        var r = string.split(separator);
+        ok(r == result, "\"" + string + "\".split(" + separator + ") returned " + r + " expected " + result);
+    }
+
+    test("test", /^|\s+/, "test");
+    test("test", /$|\s+/, "test");
+    test("test", /^|./, "t");
+    test("test", /.*/, "");
+    test("test", /x*/, "t,e,s,t");
+    test("test", /$|x*/, "t,e,s,t");
+    test("test", /^|x*/, "t,e,s,t");
+    test("test", /t*/, "e,s");
+    test("xaabaax", /a*|b*/, "x,b,x");
+    test("xaabaax", /a+|b+/, "x,x");
+    test("xaabaax", /a+|b*/, "x,x");
+    test("xaaxbaax", /b+|a+/, "x,x,x");
+    test("test", /^|t/, "tes");
+    test("test", /^|t/, "tes");
+    test("a,,b", /,/, "a,b");
+    test("ab", /a*/, "b");
+    test("aab", "a", ",,b");
+    test("a", "a", ",");
+
+    function test_length(string, separator, len) {
+        var r = string.split(separator);
+        ok(r.length === len, "\"" + string + "\".split(" + separator + ").length = "
+           + r.length + " expected " + len);
+    }
+
+    test_length("", /a*/, 0);
+    test_length("", /a+/, 1);
+    test_length("", "", 0);
+    test_length("", "x", 1);
+})();
+
 tmp = "abcd".indexOf("bc",0);
 ok(tmp === 1, "indexOf = " + tmp);
 tmp = "abcd".indexOf("bc",1);




More information about the wine-cvs mailing list