From: Thomas Csovscity thc.fr13nd@gmail.com
--- dlls/kernelbase/path.c | 15 +- dlls/shlwapi/tests/url.c | 307 +++++++++++++++++++++++++++++++++++++++ include/shlwapi.h | 2 + 3 files changed, 323 insertions(+), 1 deletion(-)
diff --git a/dlls/kernelbase/path.c b/dlls/kernelbase/path.c index 7eda9bd483c..be4e156bbac 100644 --- a/dlls/kernelbase/path.c +++ b/dlls/kernelbase/path.c @@ -4088,7 +4088,20 @@ INT WINAPI UrlCompareW(const WCHAR *url1, const WCHAR *url2, BOOL ignore_slash) return -1; }
-HRESULT WINAPI UrlFixupW(const WCHAR *url, WCHAR *translatedUrl, DWORD maxChars) +/* + * from Documentation: + * https://docs.microsoft.com/en-us/windows/desktop/api/shlwapi/nf-shlwapi-urlf... + * + * UrlFixupW attempts to correct a URL whose protocol identifier is incorrect. + * For example, htttp will be changed to http. + * + * LWSTDAPI UrlFixupW( + * [in] PCWSTR pcszUrl, + * [out] PWSTR pszTranslatedUrl, + * DWORD cchMax + * ); +*/ +HRESULT WINAPI UrlFixupW(PCWSTR url, PWSTR translatedUrl, DWORD maxChars) { DWORD srcLen;
diff --git a/dlls/shlwapi/tests/url.c b/dlls/shlwapi/tests/url.c index 6870de4ee5f..20c246da076 100644 --- a/dlls/shlwapi/tests/url.c +++ b/dlls/shlwapi/tests/url.c @@ -1609,6 +1609,312 @@ static void test_HashData(void) } }
+/* + * Documentation: https://docs.microsoft.com/en-us/windows/desktop/api/shlwapi/nf-shlwapi-urlf... +*/ +static const struct parse_urlfixupw_test_t { + PCWSTR pcszUrl; + PCWSTR pszTranslatedUrl; + HRESULT res; +} parse_urlfixupw_tests[] = { + {L"ftp:", L"ftp://", S_OK}, + {L"http:", L"http://", S_OK}, + {L"gopher:", L"gopher:", S_OK}, + {L"mailto:", L"mailto:", S_OK}, + {L"news:", L"news:", S_OK}, + {L"nntp:", L"nntp:", S_OK}, + {L"telnet:", L"telnet:", S_OK}, + {L"wais:", L"wais:", S_OK}, + {L"file:", L"file:", S_OK}, + {L"mk:", L"mk:", S_OK}, + {L"https:", L"https://", S_OK}, + {L"shell:", L"shell:", S_OK}, + {L"snews:", L"snews:", S_OK}, + {L"local:", L"local:", S_OK}, + {L"javascript:", L"javascript:", S_OK}, + {L"vbscript:", L"vbscript:", S_OK}, + {L"about:", L"about:", S_OK}, + {L"res:", L"res:", S_OK}, + {L"ms-shell-rooted:", L"ms-shell-rooted:", S_OK}, + {L"ms-shell-idlist:", L"ms-shell-idlist:", S_OK}, + {L"hcp:", L"hcp:", S_OK}, + +//not in winxp {L"*:", L"*://", S_OK}, +//not in winxp {L"search-ms:", L"search-ms://", S_OK}, +//not in winxp {L"search:", L"search://", S_OK}, +//not in winxp {L"knownfolder:", L"knownfolder://", S_OK}, + + /* proposed URL is already acceptable */ + {L"mailto:abc@abc.de", L"mailto:abc@abc.de", S_OK}, + {L"ftp://", L"ftp://", S_OK}, + {L"http://", L"http://", S_OK}, + {L"https:", L"https://", S_OK}, + + /* typos in front one letter */ + {L"aftp://", L"ftp://", S_OK}, + {L"ahttp://", L"http://", S_OK}, + {L"agopher://", L"gopher://", S_OK}, + {L"amailto://", L"mailto://", S_OK}, + {L"anews://", L"snews://", S_OK}, + {L"anntp://", L"nntp://", S_OK}, + {L"atelnet://", L"telnet://", S_OK}, + {L"awais://", L"wais://", S_OK}, + {L"afile://", L"file://", S_OK}, + {L"amk://", L"mk://", S_OK}, + {L"ahttps://", L"http://", S_OK}, + {L"ashell://", L"shell://", S_OK}, + {L"asnews://", L"snews://", S_OK}, + {L"alocal://", L"local://", S_OK}, + {L"ajavascript://", L"javascript://", S_OK}, + {L"avbscript://", L"vbscript://", S_OK}, + {L"aabout://", L"about://", S_OK}, + {L"ares://", L"res://", S_OK}, + {L"ams-shell-rooted://", L"ms-shell-rooted://", S_OK}, + {L"ams-shell-idlist://", L"ms-shell-idlist://", S_OK}, + {L"ahcp://", L"hcp://", S_OK}, + + /* typos in front two letters */ + {L"bahttp://", L"about://", S_OK}, + {L"banews://", L"snews://", S_OK}, + {L"bavbscript://", L"javascript://", S_OK}, + + /* typos in front three letters */ + {L"cbavbscript://", L"javascript://", S_OK}, + + /* typos mixed up letters */ + {L"ftt://", L"ftp://", S_OK}, + {L"gophsr://", L"gopher://", S_OK}, + {L"gophs://", L"gopher://", S_OK}, + {L"gophss://", L"gopher://", S_OK}, + {L"gophsss://", L"gopher://", S_OK}, + {L"gophsss://", L"gopher://", S_OK}, + {L"mkilto://", L"mailto://", S_OK}, + {L"mkklto://", L"mailto://", S_OK}, + {L"mkikto://", L"mailto://", S_OK}, + {L"mkiktoo://", L"mailto://", S_OK}, + {L"ma://", L"mk://", S_OK}, + {L"hftp:", L"http://", S_OK}, + + /* typos missed letters */ + {L"ft:", L"ftp://", S_OK}, + {L"ft://", L"ftp://", S_OK}, + {L"htt://", L"http://", S_OK}, + {L"gophe://", L"gopher://", S_OK}, + {L"goph://", L"gopher://", S_OK}, + {L"mailt://", L"mailto://", S_OK}, + {L"mail://", L"mailto://", S_OK}, + + {L"new://", L"news://", S_OK}, + {L"ne://", L"news://", S_OK}, + {L"snews://", L"snews://", S_OK}, + {L"newss://", L"snews://", S_OK}, + {L"newsss://", L"snews://", S_OK}, + {L"newssss://", L"snews://", S_OK}, + {L"newsssss://", L"snews://", S_OK}, + + /* typos letters behind*/ + {L"mks://", L"mk://", S_OK}, + {L"mkss://", L"mk://", S_OK}, + {L"mailtooo://", L"mailto://", S_OK}, + {L"mailtoooo://", L"mailto://", S_OK}, + {L"mailtooooo://", L"mailto://", S_OK}, + + /* typos fixing two letters */ + {L"cc:", L"hcp:", S_OK}, + {L"ee:", L"res:", S_OK}, + {L"ff:", L"ftp://", S_OK}, + {L"hh:", L"hcp:", S_OK}, + {L"kk:", L"mk:", S_OK}, + {L"mm:", L"mk:", S_OK}, + {L"nn:", L"nntp:", S_OK}, + {L"rr:", L"res:", S_OK}, + {L"tt:", L"ftp://", S_OK}, + + /* reporting false */ + {L"baftp://", NULL, S_FALSE}, + {L"bagopher://", NULL, S_FALSE}, + {L"bamailto://", NULL, S_FALSE}, + {L"banntp://", NULL, S_FALSE}, + {L"batelnet://", NULL, S_FALSE}, + {L"bawais://", NULL, S_FALSE}, + {L"bafile://", NULL, S_FALSE}, + {L"bamk://", NULL, S_FALSE}, + {L"bahttps://", NULL, S_FALSE}, + {L"bashell://", NULL, S_FALSE}, + {L"basnews://", NULL, S_FALSE}, + {L"balocal://", NULL, S_FALSE}, + {L"bajavascript://", NULL, S_FALSE}, + {L"baabout://", NULL, S_FALSE}, + {L"bares://", NULL, S_FALSE}, + {L"bams-shell-rooted://", NULL, S_FALSE}, + {L"bams-shell-idlist://", NULL, S_FALSE}, + {L"bahcp://", NULL, S_FALSE}, + + {L"cbaftp://", NULL, S_FALSE}, + {L"cbahttp://", NULL, S_FALSE}, + {L"cbanews://", NULL, S_FALSE}, + {L"cbagopher://", NULL, S_FALSE}, + {L"cbamailto://", NULL, S_FALSE}, + {L"cbanntp://", NULL, S_FALSE}, + {L"cbatelnet://", NULL, S_FALSE}, + {L"cbawais://", NULL, S_FALSE}, + {L"cbafile://", NULL, S_FALSE}, + {L"cbamk://", NULL, S_FALSE}, + {L"cbahttps://", NULL, S_FALSE}, + {L"cbashell://", NULL, S_FALSE}, + {L"cbasnews://", NULL, S_FALSE}, + {L"cbalocal://", NULL, S_FALSE}, + {L"cbajavascript://", NULL, S_FALSE}, + {L"cbaabout://", NULL, S_FALSE}, + {L"cbares://", NULL, S_FALSE}, + {L"cbams-shell-rooted://", NULL, S_FALSE}, + {L"cbams-shell-idlist://", NULL, S_FALSE}, + {L"cbahcp://", NULL, S_FALSE}, + + /* without ":" never matched in winxp */ + {L"a", NULL, S_FALSE}, + {L"mk", NULL, S_FALSE}, + {L"ftp", NULL, S_FALSE}, + + /* one letter never matched in winxp */ + {L"a:", NULL, S_FALSE}, + {L"b:", NULL, S_FALSE}, + {L"c:", NULL, S_FALSE}, + {L"d:", NULL, S_FALSE}, + {L"e:", NULL, S_FALSE}, + {L"f:", NULL, S_FALSE}, + {L"g:", NULL, S_FALSE}, + {L"h:", NULL, S_FALSE}, + {L"i:", NULL, S_FALSE}, + {L"j:", NULL, S_FALSE}, + {L"k:", NULL, S_FALSE}, + {L"l:", NULL, S_FALSE}, + {L"m:", NULL, S_FALSE}, + {L"n:", NULL, S_FALSE}, + {L"o:", NULL, S_FALSE}, + {L"p:", NULL, S_FALSE}, + {L"q:", NULL, S_FALSE}, + {L"r:", NULL, S_FALSE}, + {L"s:", NULL, S_FALSE}, + {L"t:", NULL, S_FALSE}, + {L"u:", NULL, S_FALSE}, + {L"v:", NULL, S_FALSE}, + {L"w:", NULL, S_FALSE}, + {L"x:", NULL, S_FALSE}, + {L"y:", NULL, S_FALSE}, + {L"z:", NULL, S_FALSE}, + + {L"gophssss://", NULL, S_FALSE}, + {L"gop://", NULL, S_FALSE}, + {L"go://", NULL, S_FALSE}, + {L"mai://", NULL, S_FALSE}, + + {L"mkkkto://", NULL, S_FALSE}, + {L"mailtoooooo://", NULL, S_FALSE}, + {L"mailtooooop://", NULL, S_FALSE}, + {L"newssssss://", NULL, S_FALSE}, + {L"mkikkoo://", NULL, S_FALSE}, + {L"mksss://", NULL, S_FALSE}, + {L"ft", NULL, S_FALSE}, + + /* mixed tests */ + {L"aa:", NULL, S_FALSE}, + {L"bb:", NULL, S_FALSE}, + {L"dd:", NULL, S_FALSE}, + {L"gg:", NULL, S_FALSE}, + {L"ii:", NULL, S_FALSE}, + {L"jj:", NULL, S_FALSE}, + {L"ll:", NULL, S_FALSE}, + {L"oo:", NULL, S_FALSE}, + {L"pp:", NULL, S_FALSE}, + {L"qq:", NULL, S_FALSE}, + {L"ss:", NULL, S_FALSE}, + {L"uu:", NULL, S_FALSE}, + {L"vv:", NULL, S_FALSE}, + {L"ww:", NULL, S_FALSE}, + {L"xx:", NULL, S_FALSE}, + {L"yy:", NULL, S_FALSE}, + {L"zz:", NULL, S_FALSE}, + + /* taken from example in documentation */ + {L"http://www.microsoft.com", L"http://www.microsoft.com", S_OK}, + {L"http:www.microsoft.com", L"http://www.microsoft.com", S_OK}, + {L"mail:someone@example.com", L"mailto:someone@example.com", S_OK}, + {L"htpp:wwwmicrosoft.com", L"http://wwwmicrosoft.com", S_OK}, + {L"htps:\www.microsoft.com", L"http://www.microsoft.com", S_OK}, + {L"http:someone@example.com", L"http://someone@example.com", S_OK}, + {L"abc:def", NULL, S_FALSE}, + {L"someone@example.com", NULL, S_FALSE}, + + {L"fztzp:", NULL, S_FALSE}, + {L"zfztzp:", NULL, S_FALSE}, + {L"zfztp:", NULL, S_FALSE}, + {L"zftzp:", NULL, S_FALSE}, + {L"zftpz:", NULL, S_FALSE}, + + {L"htztps:", L"http://", S_OK}, + {L"hzttps:", L"http://", S_OK}, + {L"htzztps:", NULL, S_FALSE}, + {L"hzzzzzzzzzzzzzztp:", NULL, S_FALSE}, + {L"hzzzzzzzzzzzzzztpz:", NULL, S_FALSE}, + {L"zhzzzzzzzzzzzzzztp:", NULL, S_FALSE}, + {L"zhzzzzzzzzzzzzzztpz:", NULL, S_FALSE}, + {L"zzzzzzhzzzzzzzzzzzzzztzzzzzzpzzzzzz:", NULL, S_FALSE}, + + {L"hfttp:", L"http://", S_OK}, + {L"hfttpz:", L"http://", S_OK}, + {L"zhftp:", NULL, S_FALSE}, + {L"hftftpz:", NULL, S_FALSE}, + {L"hftddtpz:", NULL, S_FALSE}, + {L"hftddtddpz:", NULL, S_FALSE}, + + {L"hfftp:", L"http://", S_OK}, + {L"hftpz:", L"http://", S_OK}, + {L"hztpz:", L"http://", S_OK}, + + {L"httpz:", L"http://", S_OK}, + {L"httpsz:", L"http://", S_OK}, + {L"httpzz:", L"http://", S_OK}, + {L"httpzzz:", L"http://", S_OK}, + {L"httpzzzz:", NULL, S_FALSE}, + {L"httpzzzzz:", NULL, S_FALSE}, +}; + +#define MAX_URL 256 + +static void test_UrlFixupW(void) +{ + const struct parse_urlfixupw_test_t *test; + WCHAR pszTranslatedUrl[MAX_URL]; + LPWSTR TranslatedUrl = pszTranslatedUrl; + HRESULT hres; + + trace("test_UrlFixupW\n"); + for (test = parse_urlfixupw_tests; test < parse_urlfixupw_tests + ARRAY_SIZE(parse_urlfixupw_tests); test++) { + pszTranslatedUrl[0] = 0; + hres = UrlFixupW(test->pcszUrl, TranslatedUrl,MAX_URL); + if (test->res == hres ) { + if (S_OK == hres) { + ok(_wcsicmp(TranslatedUrl, test->pszTranslatedUrl) == 0, "Expected %s got %s for %s\n", + wine_dbgstr_w(test->pszTranslatedUrl), wine_dbgstr_w(TranslatedUrl), wine_dbgstr_w(test->pcszUrl)); + } else if (S_FALSE == hres) { + ok(test->res == hres, "Expected %lu got %lu for %s\n", + test->res, hres, wine_dbgstr_w(test->pcszUrl)); + } else { + printf("failed %S with %lu \n", test->pcszUrl, hres); + } + } else { + if (S_OK == hres) { + ok(test->res == hres, "Expected %lu got %lu for %s fixed: %s\n", + test->res, hres, wine_dbgstr_w(test->pcszUrl), wine_dbgstr_w(TranslatedUrl)); + } else { + ok(test->res == hres, "Expected %lu got %lu for %s\n", + test->res, hres, wine_dbgstr_w(test->pcszUrl)); + } + } + } +} + /* ########################### */
START_TEST(url) @@ -1626,4 +1932,5 @@ START_TEST(url) test_UrlUnescape(); test_ParseURL(); test_HashData(); + test_UrlFixupW(); } diff --git a/include/shlwapi.h b/include/shlwapi.h index eee41abf0dc..b3a27b5c403 100644 --- a/include/shlwapi.h +++ b/include/shlwapi.h @@ -701,6 +701,8 @@ WINSHLWAPI INT WINAPI UrlCompareA(LPCSTR,LPCSTR,BOOL); WINSHLWAPI INT WINAPI UrlCompareW(LPCWSTR,LPCWSTR,BOOL); #define UrlCompare WINELIB_NAME_AW(UrlCompare)
+WINSHLWAPI HRESULT WINAPI UrlFixupW(PCWSTR,PWSTR,DWORD); + WINSHLWAPI HRESULT WINAPI UrlEscapeA(LPCSTR,LPSTR,LPDWORD,DWORD); WINSHLWAPI HRESULT WINAPI UrlEscapeW(LPCWSTR,LPWSTR,LPDWORD,DWORD); #define UrlEscape WINELIB_NAME_AW(UrlEscape)