Daniel Lehman : shlwapi: Implement URL_ESCAPE_AS_UTF8.

Alexandre Julliard julliard at wine.codeweavers.com
Wed Dec 30 18:33:43 CST 2015


Module: wine
Branch: master
Commit: 74e71b664350f5ec89ff6b1ec9d15b80f2bd2baf
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=74e71b664350f5ec89ff6b1ec9d15b80f2bd2baf

Author: Daniel Lehman <dlehman at esri.com>
Date:   Mon Nov 23 17:34:24 2015 -0800

shlwapi: Implement URL_ESCAPE_AS_UTF8.

Signed-off-by: Daniel Lehman <dlehman at esri.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/shlwapi/tests/url.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++
 dlls/shlwapi/url.c       | 50 ++++++++++++++++++++++++++++++++------
 include/shlwapi.h        |  1 +
 3 files changed, 107 insertions(+), 7 deletions(-)

diff --git a/dlls/shlwapi/tests/url.c b/dlls/shlwapi/tests/url.c
index 857ed15..85da922 100644
--- a/dlls/shlwapi/tests/url.c
+++ b/dlls/shlwapi/tests/url.c
@@ -302,6 +302,45 @@ static const TEST_URL_ESCAPE TEST_ESCAPE[] = {
     {"ftp\x1f\1end/", 0, 0, S_OK, "ftp%1F%01end/"}
 };
 
+typedef struct _TEST_URL_ESCAPEW {
+    const WCHAR url[INTERNET_MAX_URL_LENGTH];
+    DWORD flags;
+    HRESULT expectret;
+    const WCHAR expecturl[INTERNET_MAX_URL_LENGTH];
+    const WCHAR win7url[INTERNET_MAX_URL_LENGTH];  /* <= Win7 */
+    const WCHAR vistaurl[INTERNET_MAX_URL_LENGTH]; /* <= Vista/2k8 */
+} TEST_URL_ESCAPEW;
+
+static const TEST_URL_ESCAPEW TEST_ESCAPEW[] = {
+    {{' ','<','>','"',0},  URL_ESCAPE_AS_UTF8, S_OK, {'%','2','0','%','3','C','%','3','E','%','2','2',0}},
+    {{'{','}','|','\\',0}, URL_ESCAPE_AS_UTF8, S_OK, {'%','7','B','%','7','D','%','7','C','%','5','C',0}},
+    {{'^',']','[','`',0},  URL_ESCAPE_AS_UTF8, S_OK, {'%','5','E','%','5','D','%','5','B','%','6','0',0}},
+    {{'&','/','?','#',0},  URL_ESCAPE_AS_UTF8, S_OK, {'%','2','6','/','?','#',0}},
+    {{'M','a','s','s',0},  URL_ESCAPE_AS_UTF8, S_OK, {'M','a','s','s',0}},
+
+    /* broken < Win8/10 */
+
+    {{'M','a',0xdf,0},  URL_ESCAPE_AS_UTF8, S_OK, {'M','a','%','C','3','%','9','F',0},
+                                                  {'M','a','%','D','F',0}},
+    /* 0x2070E */
+    {{0xd841,0xdf0e,0}, URL_ESCAPE_AS_UTF8, S_OK, {'%','F','0','%','A','0','%','9','C','%','8','E',0},
+                                                  {'%','E','F','%','B','F','%','B','D','%','E','F','%','B','F','%','B','D',0},
+                                                  {0xd841,0xdf0e,0}},
+    /* 0x27A3E */
+    {{0xd85e,0xde3e,0}, URL_ESCAPE_AS_UTF8, S_OK, {'%','F','0','%','A','7','%','A','8','%','B','E',0},
+                                                  {'%','E','F','%','B','F','%','B','D','%','E','F','%','B','F','%','B','D',0},
+                                                  {0xd85e,0xde3e,0}},
+
+    {{0xd85e,0},        URL_ESCAPE_AS_UTF8, S_OK, {'%','E','F','%','B','F','%','B','D',0},
+                                                  {0xd85e,0}},
+    {{0xd85e,0x41},     URL_ESCAPE_AS_UTF8, S_OK, {'%','E','F','%','B','F','%','B','D','A',0},
+                                                  {0xd85e,'A',0}},
+    {{0xdc00,0},        URL_ESCAPE_AS_UTF8, S_OK, {'%','E','F','%','B','F','%','B','D',0},
+                                                  {0xdc00,0}},
+    {{0xffff,0},        URL_ESCAPE_AS_UTF8, S_OK, {'%','E','F','%','B','F','%','B','F',0},
+                                                  {0xffff,0}},
+};
+
 /* ################ */
 
 typedef struct _TEST_URL_COMBINE {
@@ -862,6 +901,15 @@ static void test_UrlEscapeA(void)
     ok(size == 34, "got %d, expected %d\n", size, 34);
     ok(empty_string[0] == 127, "String has changed, empty_string[0] = %d\n", empty_string[0]);
 
+    size = 1;
+    empty_string[0] = 127;
+    ret = pUrlEscapeA("/woningplan/woonkamer basis.swf", empty_string, &size, URL_ESCAPE_AS_UTF8);
+    ok(ret == E_NOTIMPL || broken(ret == E_POINTER), /* < Win7/Win2k8 */
+        "got %x, expected %x\n", ret, E_NOTIMPL);
+    ok(size == 1 || broken(size == 34), /* < Win7/Win2k8 */
+        "got %d, expected %d\n", size, 1);
+    ok(empty_string[0] == 127, "String has changed, empty_string[0] = %d\n", empty_string[0]);
+
     for(i=0; i<sizeof(TEST_ESCAPE)/sizeof(TEST_ESCAPE[0]); i++) {
         CHAR ret_url[INTERNET_MAX_URL_LENGTH];
 
@@ -925,6 +973,21 @@ static void test_UrlEscapeW(void)
         FreeWideString(urlW);
         FreeWideString(expected_urlW);
     }
+
+    for(i=0; i<sizeof(TEST_ESCAPEW)/sizeof(TEST_ESCAPEW[0]); i++) {
+        WCHAR ret_url[INTERNET_MAX_URL_LENGTH];
+
+        size = INTERNET_MAX_URL_LENGTH;
+        ret = pUrlEscapeW(TEST_ESCAPEW[i].url, ret_url, &size, TEST_ESCAPEW[i].flags);
+        ok(ret == TEST_ESCAPEW[i].expectret, "UrlEscapeW returned 0x%08x instead of 0x%08x for \"%s\"\n",
+           ret, TEST_ESCAPEW[i].expectret, wine_dbgstr_w(TEST_ESCAPEW[i].url));
+        ok(!lstrcmpW(ret_url, TEST_ESCAPEW[i].expecturl) ||
+           broken(!lstrcmpW(ret_url, TEST_ESCAPEW[i].vistaurl)) ||
+           broken(!lstrcmpW(ret_url, TEST_ESCAPEW[i].win7url)),
+            "Expected \"%s\" or \"%s\" or \"%s\", but got \"%s\" for \"%s\"\n",
+            wine_dbgstr_w(TEST_ESCAPEW[i].expecturl), wine_dbgstr_w(TEST_ESCAPEW[i].vistaurl),
+            wine_dbgstr_w(TEST_ESCAPEW[i].win7url), wine_dbgstr_w(ret_url), wine_dbgstr_w(TEST_ESCAPEW[i].url));
+    }
 }
 
 /* ########################### */
diff --git a/dlls/shlwapi/url.c b/dlls/shlwapi/url.c
index 1a53252..0680a55 100644
--- a/dlls/shlwapi/url.c
+++ b/dlls/shlwapi/url.c
@@ -958,6 +958,8 @@ HRESULT WINAPI UrlEscapeA(
 
     if(!RtlCreateUnicodeStringFromAsciiz(&urlW, pszUrl))
         return E_INVALIDARG;
+    if(dwFlags & URL_ESCAPE_AS_UTF8)
+        return E_NOTIMPL;
     if((ret = UrlEscapeW(urlW.Buffer, escapedW, &lenW, dwFlags)) == E_POINTER) {
         escapedW = HeapAlloc(GetProcessHeap(), 0, lenW * sizeof(WCHAR));
         ret = UrlEscapeW(urlW.Buffer, escapedW, &lenW, dwFlags);
@@ -994,6 +996,9 @@ static inline BOOL URL_NeedEscapeW(WCHAR ch, DWORD flags, DWORD int_flags)
     if ((flags & URL_ESCAPE_PERCENT) && (ch == '%'))
 	return TRUE;
 
+    if ((flags & URL_ESCAPE_AS_UTF8) && (ch >= 0x80))
+	return TRUE;
+
     if (ch <= 31 || (ch >= 127 && ch <= 255) )
 	return TRUE;
 
@@ -1069,8 +1074,8 @@ HRESULT WINAPI UrlEscapeW(
     LPCWSTR src;
     DWORD needed = 0, ret;
     BOOL stop_escaping = FALSE;
-    WCHAR next[5], *dst, *dst_ptr;
-    INT len;
+    WCHAR next[12], *dst, *dst_ptr;
+    INT i, len;
     PARSEDURLW parsed_url;
     DWORD int_flags;
     DWORD slashes = 0;
@@ -1085,7 +1090,8 @@ HRESULT WINAPI UrlEscapeW(
     if(dwFlags & ~(URL_ESCAPE_SPACES_ONLY |
 		   URL_ESCAPE_SEGMENT_ONLY |
 		   URL_DONT_ESCAPE_EXTRA_INFO |
-		   URL_ESCAPE_PERCENT))
+		   URL_ESCAPE_PERCENT |
+		   URL_ESCAPE_AS_UTF8))
         FIXME("Unimplemented flags: %08x\n", dwFlags);
 
     dst_ptr = dst = HeapAlloc(GetProcessHeap(), 0, *pcchEscaped*sizeof(WCHAR));
@@ -1188,10 +1194,40 @@ HRESULT WINAPI UrlEscapeW(
             if(cur == '\\' && (int_flags & WINE_URL_BASH_AS_SLASH) && !stop_escaping) cur = '/';
 
             if(URL_NeedEscapeW(cur, dwFlags, int_flags) && stop_escaping == FALSE) {
-                next[0] = '%';
-                next[1] = hexDigits[(cur >> 4) & 0xf];
-                next[2] = hexDigits[cur & 0xf];
-                len = 3;
+                if(dwFlags & URL_ESCAPE_AS_UTF8) {
+                    char utf[16];
+
+                    if ((cur >= 0xd800 && cur <= 0xdfff) &&
+                        (src[1] >= 0xdc00 && src[1] <= 0xdfff))
+                    {
+                        WCHAR sur[2];
+
+                        sur[0] = cur;
+                        sur[1] = *++src;
+                        len = wine_utf8_wcstombs(WC_ERR_INVALID_CHARS, sur, 2, utf, sizeof(utf));
+                    }
+                    else
+                        len = wine_utf8_wcstombs(WC_ERR_INVALID_CHARS, &cur, 1, utf, sizeof(utf));
+
+                    if(len < 0) {
+                        utf[0] = 0xef;
+                        utf[1] = 0xbf;
+                        utf[2] = 0xbd;
+                        len = 3;
+                    }
+
+                    for(i = 0; i < len; i++) {
+                        next[i*3+0] = '%';
+                        next[i*3+1] = hexDigits[(utf[i] >> 4) & 0xf];
+                        next[i*3+2] = hexDigits[utf[i] & 0xf];
+                    }
+                    len *= 3;
+                } else {
+                    next[0] = '%';
+                    next[1] = hexDigits[(cur >> 4) & 0xf];
+                    next[2] = hexDigits[cur & 0xf];
+                    len = 3;
+                }
             } else {
                 next[0] = cur;
                 len = 1;
diff --git a/include/shlwapi.h b/include/shlwapi.h
index 205d5e6..e3b14b3 100644
--- a/include/shlwapi.h
+++ b/include/shlwapi.h
@@ -646,6 +646,7 @@ typedef enum {
 #define URL_UNESCAPE_INPLACE         0x00100000
 
 #define URL_FILE_USE_PATHURL         0x00010000
+#define URL_ESCAPE_AS_UTF8           0x00040000
 
 #define URL_ESCAPE_SEGMENT_ONLY      0x00002000
 #define URL_ESCAPE_PERCENT           0x00001000




More information about the wine-cvs mailing list