From 6438bd65a98fc3274e764fcd635ed834f75c98a9 Mon Sep 17 00:00:00 2001
From: thc <thc.fr13nd@gmail.com>
Date: Wed, 2 Jan 2019 19:54:48 +0100
Subject: [PATCH] shlwapi: add apitests for UrlFixupW

---
 modules/rostests/apitests/shlwapi/CMakeLists.txt |   3 +-
 modules/rostests/apitests/shlwapi/UrlFixupW.c    | 326 +++++++++++++++++++++++
 modules/rostests/apitests/shlwapi/testlist.c     |   2 +
 sdk/include/psdk/shlwapi.h                       |  10 +
 4 files changed, 340 insertions(+), 1 deletion(-)
 create mode 100644 modules/rostests/apitests/shlwapi/UrlFixupW.c

diff --git a/modules/rostests/apitests/shlwapi/CMakeLists.txt b/modules/rostests/apitests/shlwapi/CMakeLists.txt
index a7d4e05d4f..68607e176a 100644
--- a/modules/rostests/apitests/shlwapi/CMakeLists.txt
+++ b/modules/rostests/apitests/shlwapi/CMakeLists.txt
@@ -9,7 +9,8 @@ list(APPEND SOURCE
     SHAreIconsEqual.c
     StrFormatByteSizeW.c
     testdata.rc
-    testlist.c)
+    testlist.c
+    UrlFixupW.c)
 
 add_executable(shlwapi_apitest ${SOURCE})
 set_module_type(shlwapi_apitest win32cui)
diff --git a/modules/rostests/apitests/shlwapi/UrlFixupW.c b/modules/rostests/apitests/shlwapi/UrlFixupW.c
new file mode 100644
index 0000000000..c8dab2c21b
--- /dev/null
+++ b/modules/rostests/apitests/shlwapi/UrlFixupW.c
@@ -0,0 +1,326 @@
+/*
+ * Copyright 2018 Thomas Csovcsity
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/* Documentation: https://docs.microsoft.com/en-us/windows/desktop/api/shlwapi/nf-shlwapi-urlfixupw 
+ */
+
+#include <apitest.h>
+#include <shlwapi.h>
+#include <strsafe.h>
+
+#define DO_TEST(exp, str, res) \
+do { \
+     pszTranslatedUrl[0] = 0; \
+     hres = UrlFixupW(exp, TranslatedUrl,cchMax); \
+     if (res == hres ) { \
+       if (S_OK == hres) { \
+         ok(_wcsicmp(TranslatedUrl, (str)) == 0, "Expected %s got %s for %s\n", \
+         wine_dbgstr_w((str)), wine_dbgstr_w((TranslatedUrl)), wine_dbgstr_w((exp))); \
+       } else if (S_FALSE == hres) { \
+         ok(res == hres, "Expected %lu got %lu for %s\n", \
+         res, hres, wine_dbgstr_w((exp))); \
+       } else { \
+         printf("failed %S with %lu \n", exp, hres); \
+       } \
+     } else { \
+       if (S_OK == hres) { \
+         ok(res == hres, "Expected %lu got %lu for %s fixed: %s\n", \
+         res, hres, wine_dbgstr_w((exp)), wine_dbgstr_w((TranslatedUrl))); \
+       } else { \
+         ok(res == hres, "Expected %lu got %lu for %s\n", \
+         res, hres, wine_dbgstr_w((exp))); \
+       } \
+     } \
+} while (0)
+
+/* Returns true if the user interface is in English. Note that this does not
+ * presume of the formatting of dates, numbers, etc.
+ * Taken from WINE.
+ */
+static BOOL is_lang_english(void)
+{
+    static HMODULE hkernel32 = NULL;
+    static LANGID (WINAPI *pGetThreadUILanguage)(void) = NULL;
+    static LANGID (WINAPI *pGetUserDefaultUILanguage)(void) = NULL;
+
+    if (!hkernel32)
+    {
+        hkernel32 = GetModuleHandleA("kernel32.dll");
+        pGetThreadUILanguage = (void*)GetProcAddress(hkernel32, "GetThreadUILanguage");
+        pGetUserDefaultUILanguage = (void*)GetProcAddress(hkernel32, "GetUserDefaultUILanguage");
+    }
+
+    if (pGetThreadUILanguage)
+        return PRIMARYLANGID(pGetThreadUILanguage()) == LANG_ENGLISH;
+    if (pGetUserDefaultUILanguage)
+        return PRIMARYLANGID(pGetUserDefaultUILanguage()) == LANG_ENGLISH;
+
+    return PRIMARYLANGID(GetUserDefaultLangID()) == LANG_ENGLISH;
+}
+
+/* Returns true if the dates, numbers, etc. are formatted using English
+ * conventions.
+ * Taken from WINE.
+ */
+static BOOL is_locale_english(void)
+{
+    /* Surprisingly GetThreadLocale() is irrelevant here */
+    LANGID langid = PRIMARYLANGID(GetUserDefaultLangID());
+    /* With the checks in DO_TEST, DUTCH can be used here as well.
+    TODO: Add other combinations that should work. */
+    return langid == LANG_ENGLISH || langid == LANG_DUTCH;
+}
+
+START_TEST(UrlFixupW)
+{
+    DWORD   cchMax=256;
+    WCHAR   pszTranslatedUrl[cchMax];
+    LPWSTR  TranslatedUrl = pszTranslatedUrl;
+    HRESULT hres;
+
+    /* Todo: check if test is valid with other locale setting */
+    /* language-dependent test */
+    if (!is_lang_english() || !is_locale_english())
+    {
+        skip("Maybe an English UI and locale is required for the StrFormat*Size tests\n");
+        return;
+    }
+    /* tested on winxp
+     *      url,          translated_url, HRESULT */
+    /* recognized schemes documented here:
+     * https://docs.microsoft.com/en-us/windows/desktop/api/shlwapi/ne-shlwapi-url_scheme
+     */
+    DO_TEST(L"ftp:",              L"ftp://",            S_OK);
+    DO_TEST(L"http:",             L"http://",           S_OK);
+    DO_TEST(L"gopher:",           L"gopher:",           S_OK);
+    DO_TEST(L"mailto:",           L"mailto:",           S_OK);
+    DO_TEST(L"news:",             L"news:",             S_OK);
+    DO_TEST(L"nntp:",             L"nntp:",             S_OK);
+    DO_TEST(L"telnet:",           L"telnet:",           S_OK);
+    DO_TEST(L"wais:",             L"wais:",             S_OK);
+    DO_TEST(L"file:",             L"file:",             S_OK);
+    DO_TEST(L"mk:",               L"mk:",               S_OK);
+    DO_TEST(L"https:",            L"https://",          S_OK);
+    DO_TEST(L"shell:",            L"shell:",            S_OK);
+    DO_TEST(L"snews:",            L"snews:",            S_OK);
+    DO_TEST(L"local:",            L"local:",            S_OK);
+    DO_TEST(L"javascript:",       L"javascript:",       S_OK);
+    DO_TEST(L"vbscript:",         L"vbscript:",         S_OK);
+    DO_TEST(L"about:",            L"about:",            S_OK);
+    DO_TEST(L"res:",              L"res:",              S_OK);
+    DO_TEST(L"ms-shell-rooted:",  L"ms-shell-rooted:",  S_OK);
+    DO_TEST(L"ms-shell-idlist:",  L"ms-shell-idlist:",  S_OK);
+    DO_TEST(L"hcp:",              L"hcp:",              S_OK);
+//not in winxp    DO_TEST(L"*:",                L"*://",                S_OK);
+//not in winxp    DO_TEST(L"search-ms:",        L"search-ms://",        S_OK);
+//not in winxp    DO_TEST(L"search:",           L"search://",           S_OK);
+//not in winxp    DO_TEST(L"knownfolder:",      L"knownfolder://",      S_OK);
+
+    /* proposed URL is already acceptable */
+    DO_TEST(L"mailto:abc@abc.de",    L"mailto:abc@abc.de",  S_OK);
+    DO_TEST(L"ftp://",               L"ftp://",             S_OK);
+    DO_TEST(L"http://",              L"http://",            S_OK);
+    DO_TEST(L"https:",               L"https://",           S_OK);
+
+    /* typos in front one letter */
+    DO_TEST(L"aftp://",              L"ftp://",             S_OK);
+    DO_TEST(L"ahttp://",             L"http://",            S_OK);
+    DO_TEST(L"agopher://",           L"gopher://",          S_OK);
+    DO_TEST(L"amailto://",           L"mailto://",          S_OK);
+    DO_TEST(L"anews://",             L"snews://",           S_OK);
+    DO_TEST(L"anntp://",             L"nntp://",            S_OK);
+    DO_TEST(L"atelnet://",           L"telnet://",          S_OK);
+    DO_TEST(L"awais://",             L"wais://",            S_OK);
+    DO_TEST(L"afile://",             L"file://",            S_OK);
+    DO_TEST(L"amk://",               L"mk://",              S_OK);
+    DO_TEST(L"ahttps://",            L"http://",            S_OK);
+    DO_TEST(L"ashell://",            L"shell://",           S_OK);
+    DO_TEST(L"asnews://",            L"snews://",           S_OK);
+    DO_TEST(L"alocal://",            L"local://",           S_OK);
+    DO_TEST(L"ajavascript://",       L"javascript://",      S_OK);
+    DO_TEST(L"avbscript://",         L"vbscript://",        S_OK);
+    DO_TEST(L"aabout://",            L"about://",           S_OK);
+    DO_TEST(L"ares://",              L"res://",             S_OK);
+    DO_TEST(L"ams-shell-rooted://",  L"ms-shell-rooted://", S_OK);
+    DO_TEST(L"ams-shell-idlist://",  L"ms-shell-idlist://", S_OK);
+    DO_TEST(L"ahcp://",              L"hcp://",             S_OK);
+
+    /* typos in front two letters */
+    DO_TEST(L"bahttp://",             L"about://",          S_OK);
+    DO_TEST(L"banews://",             L"snews://",          S_OK);
+    DO_TEST(L"bavbscript://",         L"javascript://",     S_OK);
+
+    /* typos in front three letters */
+    DO_TEST(L"cbavbscript://",        L"javascript://",     S_OK);
+
+    /* typos mixed up letters */
+    DO_TEST(L"ftt://",     L"ftp://",      S_OK);
+    DO_TEST(L"gophsr://",  L"gopher://",   S_OK);
+    DO_TEST(L"gophs://",   L"gopher://",   S_OK);
+    DO_TEST(L"gophss://",  L"gopher://",   S_OK);
+    DO_TEST(L"gophsss://", L"gopher://",   S_OK);
+    DO_TEST(L"gophsss://", L"gopher://",   S_OK);
+    DO_TEST(L"mkilto://",  L"mailto://",   S_OK);
+    DO_TEST(L"mkklto://",  L"mailto://",   S_OK);
+    DO_TEST(L"mkikto://",  L"mailto://",   S_OK);
+    DO_TEST(L"mkiktoo://", L"mailto://",   S_OK);
+    DO_TEST(L"ma://",      L"mk://",       S_OK);
+
+    /* typos missed letters */
+    DO_TEST(L"ft:",       L"ftp://",      S_OK);
+    DO_TEST(L"ft://",     L"ftp://",      S_OK);
+    DO_TEST(L"htt://",    L"http://",     S_OK);
+    DO_TEST(L"gophe://",  L"gopher://",   S_OK);
+    DO_TEST(L"goph://",   L"gopher://",   S_OK);
+    DO_TEST(L"mailt://",  L"mailto://",   S_OK);
+    DO_TEST(L"mail://",   L"mailto://",   S_OK);
+
+    DO_TEST(L"new://",      L"news://",   S_OK);
+    DO_TEST(L"ne://",       L"news://",   S_OK);
+    DO_TEST(L"snews://",    L"snews://",  S_OK);
+    DO_TEST(L"newss://",    L"snews://",  S_OK);
+    DO_TEST(L"newsss://",   L"snews://",  S_OK);
+    DO_TEST(L"newssss://",  L"snews://",  S_OK);
+    DO_TEST(L"newsssss://", L"snews://",  S_OK);
+
+    /* typos letters behind*/
+    DO_TEST(L"mks://",        L"mk://",       S_OK);
+    DO_TEST(L"mkss://",       L"mk://",       S_OK);
+    DO_TEST(L"mailtooo://",   L"mailto://",   S_OK);
+    DO_TEST(L"mailtoooo://",  L"mailto://",   S_OK);
+    DO_TEST(L"mailtooooo://", L"mailto://",   S_OK);
+
+    /* typos fixing two letters */
+    DO_TEST(L"cc:", L"hcp:",      S_OK);
+    DO_TEST(L"ee:", L"res:",      S_OK);
+    DO_TEST(L"ff:", L"ftp://",    S_OK);
+    DO_TEST(L"hh:", L"hcp:",      S_OK);
+    DO_TEST(L"kk:", L"mk:",       S_OK);
+    DO_TEST(L"mm:", L"mk:",       S_OK);
+    DO_TEST(L"nn:", L"nntp:",     S_OK);
+    DO_TEST(L"rr:", L"res:",      S_OK);
+    DO_TEST(L"tt:", L"ftp://",    S_OK);
+
+    /* reporting false */ 
+    DO_TEST(L"baftp://",             NULL, S_FALSE);
+    DO_TEST(L"bagopher://",          NULL, S_FALSE);
+    DO_TEST(L"bamailto://",          NULL, S_FALSE);
+    DO_TEST(L"banntp://",            NULL, S_FALSE);
+    DO_TEST(L"batelnet://",          NULL, S_FALSE);
+    DO_TEST(L"bawais://",            NULL, S_FALSE);
+    DO_TEST(L"bafile://",            NULL, S_FALSE);
+    DO_TEST(L"bamk://",              NULL, S_FALSE);
+    DO_TEST(L"bahttps://",           NULL, S_FALSE);
+    DO_TEST(L"bashell://",           NULL, S_FALSE);
+    DO_TEST(L"basnews://",           NULL, S_FALSE);
+    DO_TEST(L"balocal://",           NULL, S_FALSE);
+    DO_TEST(L"bajavascript://",      NULL, S_FALSE);
+    DO_TEST(L"baabout://",           NULL, S_FALSE);
+    DO_TEST(L"bares://",             NULL, S_FALSE);
+    DO_TEST(L"bams-shell-rooted://", NULL, S_FALSE);
+    DO_TEST(L"bams-shell-idlist://", NULL, S_FALSE);
+    DO_TEST(L"bahcp://",             NULL, S_FALSE);
+
+    DO_TEST(L"cbaftp://",             NULL, S_FALSE);
+    DO_TEST(L"cbahttp://",            NULL, S_FALSE);
+    DO_TEST(L"cbanews://",            NULL, S_FALSE);
+    DO_TEST(L"cbagopher://",          NULL, S_FALSE);
+    DO_TEST(L"cbamailto://",          NULL, S_FALSE);
+    DO_TEST(L"cbanntp://",            NULL, S_FALSE);
+    DO_TEST(L"cbatelnet://",          NULL, S_FALSE);
+    DO_TEST(L"cbawais://",            NULL, S_FALSE);
+    DO_TEST(L"cbafile://",            NULL, S_FALSE);
+    DO_TEST(L"cbamk://",              NULL, S_FALSE);
+    DO_TEST(L"cbahttps://",           NULL, S_FALSE);
+    DO_TEST(L"cbashell://",           NULL, S_FALSE);
+    DO_TEST(L"cbasnews://",           NULL, S_FALSE);
+    DO_TEST(L"cbalocal://",           NULL, S_FALSE);
+    DO_TEST(L"cbajavascript://",      NULL, S_FALSE);
+    DO_TEST(L"cbaabout://",           NULL, S_FALSE);
+    DO_TEST(L"cbares://",             NULL, S_FALSE);
+    DO_TEST(L"cbams-shell-rooted://", NULL, S_FALSE);
+    DO_TEST(L"cbams-shell-idlist://", NULL, S_FALSE);
+    DO_TEST(L"cbahcp://",             NULL, S_FALSE);
+    
+    /* without ":" never matched in winxp */
+    DO_TEST(L"a",         NULL, S_FALSE);
+    DO_TEST(L"mk",         NULL, S_FALSE);
+    DO_TEST(L"ftp",         NULL, S_FALSE);
+
+    /* one letter never matched in winxp */
+    DO_TEST(L"a:",         NULL, S_FALSE);
+    DO_TEST(L"b:",         NULL, S_FALSE);
+    DO_TEST(L"c:",         NULL, S_FALSE);
+    DO_TEST(L"d:",         NULL, S_FALSE);
+    DO_TEST(L"e:",         NULL, S_FALSE);
+    DO_TEST(L"f:",         NULL, S_FALSE);
+    DO_TEST(L"g:",         NULL, S_FALSE);
+    DO_TEST(L"h:",         NULL, S_FALSE);
+    DO_TEST(L"i:",         NULL, S_FALSE);
+    DO_TEST(L"j:",         NULL, S_FALSE);
+    DO_TEST(L"k:",         NULL, S_FALSE);
+    DO_TEST(L"l:",         NULL, S_FALSE);
+    DO_TEST(L"m:",         NULL, S_FALSE);
+    DO_TEST(L"n:",         NULL, S_FALSE);
+    DO_TEST(L"o:",         NULL, S_FALSE);
+    DO_TEST(L"p:",         NULL, S_FALSE);
+    DO_TEST(L"q:",         NULL, S_FALSE);
+    DO_TEST(L"r:",         NULL, S_FALSE);
+    DO_TEST(L"s:",         NULL, S_FALSE);
+    DO_TEST(L"t:",         NULL, S_FALSE);
+    DO_TEST(L"u:",         NULL, S_FALSE);
+    DO_TEST(L"v:",         NULL, S_FALSE);
+    DO_TEST(L"w:",         NULL, S_FALSE);
+    DO_TEST(L"x:",         NULL, S_FALSE);
+    DO_TEST(L"y:",         NULL, S_FALSE);
+    DO_TEST(L"z:",         NULL, S_FALSE);
+
+    DO_TEST(L"gophssss://", NULL, S_FALSE);
+    DO_TEST(L"gop://",      NULL, S_FALSE);
+    DO_TEST(L"go://",       NULL, S_FALSE);
+    DO_TEST(L"mai://",      NULL, S_FALSE);
+
+    DO_TEST(L"mkkkto://",      NULL, S_FALSE);
+    DO_TEST(L"mailtoooooo://", NULL, S_FALSE);
+    DO_TEST(L"mailtooooop://", NULL, S_FALSE);
+    DO_TEST(L"newssssss://",   NULL, S_FALSE);
+    DO_TEST(L"mkikkoo://",     NULL, S_FALSE);
+    DO_TEST(L"mksss://",       NULL, S_FALSE);
+    DO_TEST(L"ft",             NULL, S_FALSE);
+    
+    /* mixed tests */
+    DO_TEST(L"aa:",         NULL, S_FALSE);
+    DO_TEST(L"bb:",         NULL, S_FALSE);
+    DO_TEST(L"dd:",         NULL, S_FALSE);
+    DO_TEST(L"gg:",         NULL, S_FALSE);
+    DO_TEST(L"ii:",         NULL, S_FALSE);
+    DO_TEST(L"jj:",         NULL, S_FALSE);
+    DO_TEST(L"ll:",         NULL, S_FALSE);
+    DO_TEST(L"oo:",         NULL, S_FALSE);
+    DO_TEST(L"pp:",         NULL, S_FALSE);
+    DO_TEST(L"qq:",         NULL, S_FALSE);
+    DO_TEST(L"ss:",         NULL, S_FALSE);
+    DO_TEST(L"uu:",         NULL, S_FALSE);
+    DO_TEST(L"vv:",         NULL, S_FALSE);
+    DO_TEST(L"ww:",         NULL, S_FALSE);
+    DO_TEST(L"xx:",         NULL, S_FALSE);
+    DO_TEST(L"yy:",         NULL, S_FALSE);
+    DO_TEST(L"zz:",         NULL, S_FALSE);
+
+    
+}
diff --git a/modules/rostests/apitests/shlwapi/testlist.c b/modules/rostests/apitests/shlwapi/testlist.c
index 1ad20a3bf8..e9461670ed 100644
--- a/modules/rostests/apitests/shlwapi/testlist.c
+++ b/modules/rostests/apitests/shlwapi/testlist.c
@@ -9,6 +9,7 @@ extern void func_PathUnExpandEnvStrings(void);
 extern void func_PathUnExpandEnvStringsForUser(void);
 extern void func_SHAreIconsEqual(void);
 extern void func_StrFormatByteSizeW(void);
+extern void func_UrlFixupW(void);
 
 const struct test winetest_testlist[] =
 {
@@ -20,5 +21,6 @@ const struct test winetest_testlist[] =
     { "PathUnExpandEnvStringsForUser", func_PathUnExpandEnvStringsForUser },
     { "SHAreIconsEqual", func_SHAreIconsEqual },
     { "StrFormatByteSizeW", func_StrFormatByteSizeW },
+    { "UrlFixupW", func_UrlFixupW },
     { 0, 0 }
 };
diff --git a/sdk/include/psdk/shlwapi.h b/sdk/include/psdk/shlwapi.h
index 4782f64b43..c37501e678 100644
--- a/sdk/include/psdk/shlwapi.h
+++ b/sdk/include/psdk/shlwapi.h
@@ -1361,6 +1361,16 @@ UrlHashW(
 
 #define UrlHash WINELIB_NAME_AW(UrlHash)
 
+/*HRESULT
+WINAPI
+UrlFixupW(
+  _In_ LPCWSTR url,
+  _Out_writes_(cchMax) LPWSTR translatedUrl,
+  DWORD maxChars);
+*/
+HRESULT WINAPI UrlFixupW(LPCWSTR, LPWSTR, DWORD);
+
+
 BOOL    WINAPI UrlIsA(_In_ LPCSTR, URLIS);
 BOOL    WINAPI UrlIsW(_In_ LPCWSTR, URLIS);
 #define UrlIs WINELIB_NAME_AW(UrlIs)
-- 
2.11.0

