UrlEscape has different rules depending on the protocol.

Added a load of tests.
This commit is contained in:
Huw Davies 2004-10-04 19:08:50 +00:00 committed by Alexandre Julliard
parent 477aa4501b
commit 7458de56ce
2 changed files with 289 additions and 204 deletions

View File

@ -76,6 +76,77 @@ const TEST_URL_ESCAPE TEST_ESCAPE[] = {
{"http://www.winehq.org/tests4\r", URL_ESCAPE_SPACES_ONLY, 0, S_OK, "http://www.winehq.org/tests4\r"}, {"http://www.winehq.org/tests4\r", URL_ESCAPE_SPACES_ONLY, 0, S_OK, "http://www.winehq.org/tests4\r"},
{"http://www.winehq.org/tests5\r", URL_WININET_COMPATIBILITY|URL_ESCAPE_SPACES_ONLY, 0, S_OK, "http://www.winehq.org/tests5\r"}, {"http://www.winehq.org/tests5\r", URL_WININET_COMPATIBILITY|URL_ESCAPE_SPACES_ONLY, 0, S_OK, "http://www.winehq.org/tests5\r"},
{"/direct/swhelp/series6/6.2i_latestservicepack.dat\r", URL_ESCAPE_SPACES_ONLY, 0, S_OK, "/direct/swhelp/series6/6.2i_latestservicepack.dat\r"}, {"/direct/swhelp/series6/6.2i_latestservicepack.dat\r", URL_ESCAPE_SPACES_ONLY, 0, S_OK, "/direct/swhelp/series6/6.2i_latestservicepack.dat\r"},
{"file://////foo/bar\\baz", 0, 0, S_OK, "file://foo/bar/baz"},
{"file://///foo/bar\\baz", 0, 0, S_OK, "file://foo/bar/baz"},
{"file:////foo/bar\\baz", 0, 0, S_OK, "file://foo/bar/baz"},
{"file:///localhost/foo/bar\\baz", 0, 0, S_OK, "file:///localhost/foo/bar/baz"},
{"file:///foo/bar\\baz", 0, 0, S_OK, "file:///foo/bar/baz"},
{"file://loCalHost/foo/bar\\baz", 0, 0, S_OK, "file:///foo/bar/baz"},
{"file://foo/bar\\baz", 0, 0, S_OK, "file://foo/bar/baz"},
{"file:/localhost/foo/bar\\baz", 0, 0, S_OK, "file:///localhost/foo/bar/baz"},
{"file:/foo/bar\\baz", 0, 0, S_OK, "file:///foo/bar/baz"},
{"file:foo/bar\\baz", 0, 0, S_OK, "file:foo/bar/baz"},
{"file:\\foo/bar\\baz", 0, 0, S_OK, "file:///foo/bar/baz"},
{"file:\\\\foo/bar\\baz", 0, 0, S_OK, "file://foo/bar/baz"},
{"file:\\\\\\foo/bar\\baz", 0, 0, S_OK, "file:///foo/bar/baz"},
{"file:\\\\localhost\\foo/bar\\baz", 0, 0, S_OK, "file:///foo/bar/baz"},
{"file:///f oo/b?a r\\baz", 0, 0, S_OK, "file:///f%20oo/b?a r\\baz"},
{"file:///foo/b#a r\\baz", 0, 0, S_OK, "file:///foo/b%23a%20r/baz"},
{"file:///f o^&`{}|][\"<>\\%o/b#a r\\baz", 0, 0, S_OK, "file:///f%20o%5E%26%60%7B%7D%7C%5D%5B%22%3C%3E/%o/b%23a%20r/baz"},
{"file:///f o%o/b?a r\\b%az", URL_ESCAPE_PERCENT, 0, S_OK, "file:///f%20o%25o/b?a r\\b%az"},
{"file:/foo/bar\\baz", URL_ESCAPE_SEGMENT_ONLY, 0, S_OK, "file:%2Ffoo%2Fbar%5Cbaz"},
{"foo/b%ar\\ba?z\\", URL_ESCAPE_SEGMENT_ONLY, 0, S_OK, "foo%2Fb%ar%5Cba%3Fz%5C"},
{"foo/b%ar\\ba?z\\", URL_ESCAPE_PERCENT | URL_ESCAPE_SEGMENT_ONLY, 0, S_OK, "foo%2Fb%25ar%5Cba%3Fz%5C"},
{"foo/bar\\ba?z\\", 0, 0, S_OK, "foo/bar%5Cba?z\\"},
{"/foo/bar\\ba?z\\", 0, 0, S_OK, "/foo/bar%5Cba?z\\"},
{"/foo/bar\\ba#z\\", 0, 0, S_OK, "/foo/bar%5Cba#z\\"},
{"/foo/%5C", 0, 0, S_OK, "/foo/%5C"},
{"/foo/%5C", URL_ESCAPE_PERCENT, 0, S_OK, "/foo/%255C"},
{"http://////foo/bar\\baz", 0, 0, S_OK, "http://////foo/bar/baz"},
{"http://///foo/bar\\baz", 0, 0, S_OK, "http://///foo/bar/baz"},
{"http:////foo/bar\\baz", 0, 0, S_OK, "http:////foo/bar/baz"},
{"http:///foo/bar\\baz", 0, 0, S_OK, "http:///foo/bar/baz"},
{"http://localhost/foo/bar\\baz", 0, 0, S_OK, "http://localhost/foo/bar/baz"},
{"http://foo/bar\\baz", 0, 0, S_OK, "http://foo/bar/baz"},
{"http:/foo/bar\\baz", 0, 0, S_OK, "http:/foo/bar/baz"},
{"http:foo/bar\\ba?z\\", 0, 0, S_OK, "http:foo%2Fbar%2Fba?z\\"},
{"http:foo/bar\\ba#z\\", 0, 0, S_OK, "http:foo%2Fbar%2Fba#z\\"},
{"http:\\foo/bar\\baz", 0, 0, S_OK, "http:/foo/bar/baz"},
{"http:\\\\foo/bar\\baz", 0, 0, S_OK, "http://foo/bar/baz"},
{"http:\\\\\\foo/bar\\baz", 0, 0, S_OK, "http:///foo/bar/baz"},
{"http:\\\\\\\\foo/bar\\baz", 0, 0, S_OK, "http:////foo/bar/baz"},
{"http:/fo ?o/b ar\\baz", 0, 0, S_OK, "http:/fo%20?o/b ar\\baz"},
{"http:fo ?o/b ar\\baz", 0, 0, S_OK, "http:fo%20?o/b ar\\baz"},
{"http:/foo/bar\\baz", URL_ESCAPE_SEGMENT_ONLY, 0, S_OK, "http:%2Ffoo%2Fbar%5Cbaz"},
{"https://foo/bar\\baz", 0, 0, S_OK, "https://foo/bar/baz"},
{"https:/foo/bar\\baz", 0, 0, S_OK, "https:/foo/bar/baz"},
{"https:\\foo/bar\\baz", 0, 0, S_OK, "https:/foo/bar/baz"},
{"foo:////foo/bar\\baz", 0, 0, S_OK, "foo:////foo/bar%5Cbaz"},
{"foo:///foo/bar\\baz", 0, 0, S_OK, "foo:///foo/bar%5Cbaz"},
{"foo://localhost/foo/bar\\baz", 0, 0, S_OK, "foo://localhost/foo/bar%5Cbaz"},
{"foo://foo/bar\\baz", 0, 0, S_OK, "foo://foo/bar%5Cbaz"},
{"foo:/foo/bar\\baz", 0, 0, S_OK, "foo:/foo/bar%5Cbaz"},
{"foo:foo/bar\\baz", 0, 0, S_OK, "foo:foo%2Fbar%5Cbaz"},
{"foo:\\foo/bar\\baz", 0, 0, S_OK, "foo:%5Cfoo%2Fbar%5Cbaz"},
{"foo:/foo/bar\\ba?\\z", 0, 0, S_OK, "foo:/foo/bar%5Cba?\\z"},
{"foo:/foo/bar\\ba#\\z", 0, 0, S_OK, "foo:/foo/bar%5Cba#\\z"},
{"mailto:/fo/o@b\\%a?\\r.b#\\az", 0, 0, S_OK, "mailto:%2Ffo%2Fo@b%5C%a%3F%5Cr.b%23%5Caz"},
{"mailto:fo/o@b\\%a?\\r.b#\\az", 0, 0, S_OK, "mailto:fo%2Fo@b%5C%a%3F%5Cr.b%23%5Caz"},
{"mailto:fo/o@b\\%a?\\r.b#\\az", URL_ESCAPE_PERCENT, 0, S_OK, "mailto:fo%2Fo@b%5C%25a%3F%5Cr.b%23%5Caz"},
{"ftp:fo/o@bar.baz/foo/bar", 0, 0, S_OK, "ftp:fo%2Fo@bar.baz%2Ffoo%2Fbar"},
{"ftp:/fo/o@bar.baz/foo/bar", 0, 0, S_OK, "ftp:/fo/o@bar.baz/foo/bar"},
{"ftp://fo/o@bar.baz/fo?o\\bar", 0, 0, S_OK, "ftp://fo/o@bar.baz/fo?o\\bar"},
{"ftp://fo/o@bar.baz/fo#o\\bar", 0, 0, S_OK, "ftp://fo/o@bar.baz/fo#o\\bar"},
{"ftp://localhost/o@bar.baz/fo#o\\bar", 0, 0, S_OK, "ftp://localhost/o@bar.baz/fo#o\\bar"},
{"ftp:///fo/o@bar.baz/foo/bar", 0, 0, S_OK, "ftp:///fo/o@bar.baz/foo/bar"},
{"ftp:////fo/o@bar.baz/foo/bar", 0, 0, S_OK, "ftp:////fo/o@bar.baz/foo/bar"}
}; };
typedef struct _TEST_URL_COMBINE { typedef struct _TEST_URL_COMBINE {
@ -178,10 +249,22 @@ static void test_url_escape(const char *szUrl, DWORD dwFlags, HRESULT dwExpectRe
{ {
CHAR szReturnUrl[INTERNET_MAX_URL_LENGTH]; CHAR szReturnUrl[INTERNET_MAX_URL_LENGTH];
DWORD dwEscaped; DWORD dwEscaped;
WCHAR ret_urlW[INTERNET_MAX_URL_LENGTH];
WCHAR *urlW, *expected_urlW;
dwEscaped=INTERNET_MAX_URL_LENGTH; dwEscaped=INTERNET_MAX_URL_LENGTH;
ok(UrlEscapeA(szUrl, szReturnUrl, &dwEscaped, dwFlags) == dwExpectReturn, "UrlEscapeA didn't return 0x%08lx\n", dwExpectReturn);
ok(strcmp(szReturnUrl,szExpectUrl)==0, "Expected \"%s\", but got \"%s\"\n", szExpectUrl, szReturnUrl); ok(UrlEscapeA(szUrl, szReturnUrl, &dwEscaped, dwFlags) == dwExpectReturn, "UrlEscapeA didn't return 0x%08lx from \"%s\"\n", dwExpectReturn, szUrl);
ok(strcmp(szReturnUrl,szExpectUrl)==0, "Expected \"%s\", but got \"%s\" from \"%s\"\n", szExpectUrl, szReturnUrl, szUrl);
dwEscaped = INTERNET_MAX_URL_LENGTH;
urlW = GetWideString(szUrl);
expected_urlW = GetWideString(szExpectUrl);
ok(UrlEscapeW(urlW, ret_urlW, &dwEscaped, dwFlags) == dwExpectReturn, "UrlEscapeW didn't return 0x%08lx from \"%s\"\n", dwExpectReturn, szUrl);
WideCharToMultiByte(CP_ACP,0,ret_urlW,-1,szReturnUrl,INTERNET_MAX_URL_LENGTH,0,0);
ok(strcmpW(ret_urlW, expected_urlW)==0, "Expected \"%s\", but got \"%s\" from \"%s\" flags %08lx\n", szExpectUrl, szReturnUrl, szUrl, dwFlags);
FreeWideString(urlW);
FreeWideString(expected_urlW);
} }
static void test_url_canonicalize(const char *szUrl, DWORD dwFlags, HRESULT dwExpectReturn, const char *szExpectUrl) static void test_url_canonicalize(const char *szUrl, DWORD dwFlags, HRESULT dwExpectReturn, const char *szExpectUrl)
{ {

View File

@ -30,6 +30,7 @@
#include "wine/unicode.h" #include "wine/unicode.h"
#include "wininet.h" #include "wininet.h"
#include "winreg.h" #include "winreg.h"
#include "winternl.h"
#define NO_SHLWAPI_STREAM #define NO_SHLWAPI_STREAM
#include "shlwapi.h" #include "shlwapi.h"
#include "wine/debug.h" #include "wine/debug.h"
@ -118,96 +119,6 @@ static const unsigned char HashDataLookup[256] = {
0x25, 0x45, 0x27, 0x75, 0x92, 0xB8, 0xA3, 0xC8, 0xDE, 0xEB, 0xF8, 0xF3, 0xDB, 0x25, 0x45, 0x27, 0x75, 0x92, 0xB8, 0xA3, 0xC8, 0xDE, 0xEB, 0xF8, 0xF3, 0xDB,
0x0A, 0x98, 0x83, 0x7B, 0xE5, 0xCB, 0x4C, 0x78, 0xD1 }; 0x0A, 0x98, 0x83, 0x7B, 0xE5, 0xCB, 0x4C, 0x78, 0xD1 };
static inline BOOL URL_NeedEscapeA(CHAR ch, DWORD dwFlags)
{
if (isalnum(ch))
return FALSE;
if(dwFlags & URL_ESCAPE_SPACES_ONLY) {
if(ch == ' ')
return TRUE;
else
return FALSE;
}
if ((dwFlags & URL_ESCAPE_PERCENT) && (ch == '%'))
return TRUE;
if (ch <= 31 || ch >= 127)
return TRUE;
else {
switch (ch) {
case ' ':
case '<':
case '>':
case '\"':
case '{':
case '}':
case '|':
/* case '\\': */
case '^':
case ']':
case '[':
case '`':
case '&':
return TRUE;
case '/':
case '?':
if (dwFlags & URL_ESCAPE_SEGMENT_ONLY) return TRUE;
default:
return FALSE;
}
}
}
static inline BOOL URL_NeedEscapeW(WCHAR ch, DWORD dwFlags)
{
if (isalnumW(ch))
return FALSE;
if(dwFlags & URL_ESCAPE_SPACES_ONLY) {
if(ch == L' ')
return TRUE;
else
return FALSE;
}
if ((dwFlags & URL_ESCAPE_PERCENT) && (ch == L'%'))
return TRUE;
if (ch <= 31 || ch >= 127)
return TRUE;
else {
switch (ch) {
case L' ':
case L'<':
case L'>':
case L'\"':
case L'{':
case L'}':
case L'|':
case L'\\':
case L'^':
case L']':
case L'[':
case L'`':
case L'&':
return TRUE;
case L'/':
case L'?':
if (dwFlags & URL_ESCAPE_SEGMENT_ONLY) return TRUE;
default:
return FALSE;
}
}
}
static BOOL URL_JustLocation(LPCWSTR str) static BOOL URL_JustLocation(LPCWSTR str)
{ {
while(*str && (*str == L'/')) str++; while(*str && (*str == L'/')) str++;
@ -857,6 +768,107 @@ HRESULT WINAPI UrlCombineW(LPCWSTR pszBase, LPCWSTR pszRelative,
/************************************************************************* /*************************************************************************
* UrlEscapeA [SHLWAPI.@] * UrlEscapeA [SHLWAPI.@]
*/
HRESULT WINAPI UrlEscapeA(
LPCSTR pszUrl,
LPSTR pszEscaped,
LPDWORD pcchEscaped,
DWORD dwFlags)
{
WCHAR bufW[INTERNET_MAX_URL_LENGTH];
WCHAR *escapedW = bufW;
UNICODE_STRING urlW;
HRESULT ret;
DWORD lenW = sizeof(bufW)/sizeof(WCHAR), lenA;
if(!RtlCreateUnicodeStringFromAsciiz(&urlW, pszUrl))
return E_INVALIDARG;
if((ret = UrlEscapeW(urlW.Buffer, escapedW, &lenW, dwFlags)) == E_POINTER) {
escapedW = HeapAlloc(GetProcessHeap(), 0, lenW * sizeof(WCHAR));
ret = UrlEscapeW(urlW.Buffer, escapedW, &lenW, dwFlags);
}
if(ret == S_OK) {
RtlUnicodeToMultiByteSize(&lenA, escapedW, lenW * sizeof(WCHAR));
if(*pcchEscaped > lenA) {
RtlUnicodeToMultiByteN(pszEscaped, *pcchEscaped - 1, &lenA, escapedW, lenW * sizeof(WCHAR));
pszEscaped[lenA] = 0;
*pcchEscaped = lenA;
} else {
*pcchEscaped = lenA + 1;
ret = E_POINTER;
}
}
if(escapedW != bufW) HeapFree(GetProcessHeap(), 0, escapedW);
RtlFreeUnicodeString(&urlW);
return ret;
}
#define WINE_URL_BASH_AS_SLASH 0x01
#define WINE_URL_COLLAPSE_SLASHES 0x02
#define WINE_URL_ESCAPE_SLASH 0x04
#define WINE_URL_ESCAPE_HASH 0x08
#define WINE_URL_ESCAPE_QUESTION 0x10
#define WINE_URL_STOP_ON_HASH 0x20
#define WINE_URL_STOP_ON_QUESTION 0x40
static inline BOOL URL_NeedEscapeW(WCHAR ch, DWORD dwFlags, DWORD int_flags)
{
if (isalnumW(ch))
return FALSE;
if(dwFlags & URL_ESCAPE_SPACES_ONLY) {
if(ch == ' ')
return TRUE;
else
return FALSE;
}
if ((dwFlags & URL_ESCAPE_PERCENT) && (ch == '%'))
return TRUE;
if (ch <= 31 || ch >= 127)
return TRUE;
else {
switch (ch) {
case ' ':
case '<':
case '>':
case '\"':
case '{':
case '}':
case '|':
case '\\':
case '^':
case ']':
case '[':
case '`':
case '&':
return TRUE;
case '/':
if (int_flags & WINE_URL_ESCAPE_SLASH) return TRUE;
return FALSE;
case '?':
if (int_flags & WINE_URL_ESCAPE_QUESTION) return TRUE;
return FALSE;
case '#':
if (int_flags & WINE_URL_ESCAPE_HASH) return TRUE;
return FALSE;
default:
return FALSE;
}
}
}
/*************************************************************************
* UrlEscapeW [SHLWAPI.@]
* *
* Converts unsafe characters in a Url into escape sequences. * Converts unsafe characters in a Url into escape sequences.
* *
@ -871,12 +883,12 @@ HRESULT WINAPI UrlCombineW(LPCWSTR pszBase, LPCWSTR pszRelative,
* contains its length. * contains its length.
* Failure: E_POINTER, if pszEscaped is not large enough. In this case * Failure: E_POINTER, if pszEscaped is not large enough. In this case
* pcchEscaped is set to the required length. * pcchEscaped is set to the required length.
*
* Converts unsafe characters into their escape sequences. * Converts unsafe characters into their escape sequences.
* *
* NOTES * NOTES
* - By default this function stops converting at the first '?' or * - By default this function stops converting at the first '?' or
* '#' character (MSDN does not document this). * '#' character.
* - If dwFlags contains URL_ESCAPE_SPACES_ONLY then only spaces are * - If dwFlags contains URL_ESCAPE_SPACES_ONLY then only spaces are
* converted, but the conversion continues past a '?' or '#'. * converted, but the conversion continues past a '?' or '#'.
* - Note that this function did not work well (or at all) in shlwapi version 4. * - Note that this function did not work well (or at all) in shlwapi version 4.
@ -888,82 +900,6 @@ HRESULT WINAPI UrlCombineW(LPCWSTR pszBase, LPCWSTR pszRelative,
*| URL_ESCAPE_SEGMENT_ONLY *| URL_ESCAPE_SEGMENT_ONLY
*| URL_ESCAPE_PERCENT *| URL_ESCAPE_PERCENT
*/ */
HRESULT WINAPI UrlEscapeA(
LPCSTR pszUrl,
LPSTR pszEscaped,
LPDWORD pcchEscaped,
DWORD dwFlags)
{
LPCSTR src;
DWORD needed = 0, ret;
BOOL stop_escaping = FALSE;
char next[3], *dst = pszEscaped;
INT len;
TRACE("(%s %p %lx 0x%08lx)\n", debugstr_a(pszUrl), pszEscaped,
pcchEscaped?*pcchEscaped:0, dwFlags);
if(!pszUrl || !pszEscaped || !pcchEscaped)
return E_INVALIDARG;
if(dwFlags & ~(URL_ESCAPE_SPACES_ONLY |
URL_ESCAPE_SEGMENT_ONLY |
URL_DONT_ESCAPE_EXTRA_INFO |
URL_ESCAPE_PERCENT))
FIXME("Unimplemented flags: %08lx\n", dwFlags);
/* fix up flags */
if (dwFlags & URL_ESCAPE_SPACES_ONLY)
/* if SPACES_ONLY specified, reset the other controls */
dwFlags &= ~(URL_DONT_ESCAPE_EXTRA_INFO |
URL_ESCAPE_PERCENT |
URL_ESCAPE_SEGMENT_ONLY);
else
/* if SPACES_ONLY *not* specified then assume DONT_ESCAPE_EXTRA_INFO */
dwFlags |= URL_DONT_ESCAPE_EXTRA_INFO;
for(src = pszUrl; *src; src++) {
if(!(dwFlags & URL_ESCAPE_SEGMENT_ONLY) &&
(dwFlags & URL_DONT_ESCAPE_EXTRA_INFO) &&
(*src == '#' || *src == '?'))
stop_escaping = TRUE;
if(URL_NeedEscapeA(*src, dwFlags) && stop_escaping == FALSE) {
/* TRACE("escaping %c\n", *src); */
next[0] = '%';
next[1] = hexDigits[(*src >> 4) & 0xf];
next[2] = hexDigits[*src & 0xf];
len = 3;
} else {
/* TRACE("passing %c\n", *src); */
next[0] = *src;
len = 1;
}
if(needed + len <= *pcchEscaped) {
memcpy(dst, next, len);
dst += len;
}
needed += len;
}
if(needed < *pcchEscaped) {
*dst = '\0';
ret = S_OK;
} else {
needed++; /* add one for the '\0' */
ret = E_POINTER;
}
*pcchEscaped = needed;
return ret;
}
/*************************************************************************
* UrlEscapeW [SHLWAPI.@]
*
* See UrlEscapeA.
*/
HRESULT WINAPI UrlEscapeW( HRESULT WINAPI UrlEscapeW(
LPCWSTR pszUrl, LPCWSTR pszUrl,
LPWSTR pszEscaped, LPWSTR pszEscaped,
@ -975,6 +911,10 @@ HRESULT WINAPI UrlEscapeW(
BOOL stop_escaping = FALSE; BOOL stop_escaping = FALSE;
WCHAR next[5], *dst = pszEscaped; WCHAR next[5], *dst = pszEscaped;
INT len; INT len;
PARSEDURLW parsed_url;
DWORD int_flags;
DWORD slashes = 0;
static const WCHAR localhost[] = {'l','o','c','a','l','h','o','s','t',0};
TRACE("(%s %p %p 0x%08lx)\n", debugstr_w(pszUrl), pszEscaped, TRACE("(%s %p %p 0x%08lx)\n", debugstr_w(pszUrl), pszEscaped,
pcchEscaped, dwFlags); pcchEscaped, dwFlags);
@ -999,39 +939,101 @@ HRESULT WINAPI UrlEscapeW(
/* if SPACES_ONLY *not* specified the assume DONT_ESCAPE_EXTRA_INFO */ /* if SPACES_ONLY *not* specified the assume DONT_ESCAPE_EXTRA_INFO */
dwFlags |= URL_DONT_ESCAPE_EXTRA_INFO; dwFlags |= URL_DONT_ESCAPE_EXTRA_INFO;
for(src = pszUrl; *src; src++) {
/*
* if(!(dwFlags & URL_ESCAPE_SPACES_ONLY) &&
* (*src == L'#' || *src == L'?'))
* stop_escaping = TRUE;
*/
if(!(dwFlags & URL_ESCAPE_SEGMENT_ONLY) &&
(dwFlags & URL_DONT_ESCAPE_EXTRA_INFO) &&
(*src == L'#' || *src == L'?'))
stop_escaping = TRUE;
if(URL_NeedEscapeW(*src, dwFlags) && stop_escaping == FALSE) { int_flags = 0;
/* TRACE("escaping %c\n", *src); */ if(dwFlags & URL_ESCAPE_SEGMENT_ONLY) {
next[0] = L'%'; int_flags = WINE_URL_ESCAPE_QUESTION | WINE_URL_ESCAPE_HASH | WINE_URL_ESCAPE_SLASH;
/* } else {
* I would have assumed that the W form would escape parsed_url.cbSize = sizeof(parsed_url);
* the character with 4 hex digits (or even 8), if(ParseURLW(pszUrl, &parsed_url) != S_OK)
* however, experiments show that native shlwapi escapes parsed_url.nScheme = URL_SCHEME_INVALID;
* with only 2 hex digits.
* next[1] = hexDigits[(*src >> 12) & 0xf]; TRACE("scheme = %d (%s)\n", parsed_url.nScheme, debugstr_wn(parsed_url.pszProtocol, parsed_url.cchProtocol));
* next[2] = hexDigits[(*src >> 8) & 0xf];
* next[3] = hexDigits[(*src >> 4) & 0xf]; if(dwFlags & URL_DONT_ESCAPE_EXTRA_INFO)
* next[4] = hexDigits[*src & 0xf]; int_flags = WINE_URL_STOP_ON_HASH | WINE_URL_STOP_ON_QUESTION;
* len = 5;
*/ switch(parsed_url.nScheme) {
next[1] = hexDigits[(*src >> 4) & 0xf]; case URL_SCHEME_FILE:
next[2] = hexDigits[*src & 0xf]; int_flags |= WINE_URL_BASH_AS_SLASH | WINE_URL_COLLAPSE_SLASHES | WINE_URL_ESCAPE_HASH;
len = 3; int_flags &= ~WINE_URL_STOP_ON_HASH;
} else { break;
/* TRACE("passing %c\n", *src); */
next[0] = *src; case URL_SCHEME_HTTP:
len = 1; case URL_SCHEME_HTTPS:
} int_flags |= WINE_URL_BASH_AS_SLASH;
if(parsed_url.pszSuffix[0] != '/' && parsed_url.pszSuffix[0] != '\\')
int_flags |= WINE_URL_ESCAPE_SLASH;
break;
case URL_SCHEME_MAILTO:
int_flags |= WINE_URL_ESCAPE_SLASH | WINE_URL_ESCAPE_QUESTION | WINE_URL_ESCAPE_HASH;
int_flags &= ~(WINE_URL_STOP_ON_QUESTION | WINE_URL_STOP_ON_HASH);
break;
case URL_SCHEME_INVALID:
break;
case URL_SCHEME_FTP:
default:
if(parsed_url.pszSuffix[0] != '/')
int_flags |= WINE_URL_ESCAPE_SLASH;
break;
}
}
for(src = pszUrl; *src; ) {
WCHAR cur = *src;
len = 0;
if((int_flags & WINE_URL_COLLAPSE_SLASHES) && src == pszUrl + parsed_url.cchProtocol + 1) {
int localhost_len = sizeof(localhost)/sizeof(WCHAR) - 1;
while(cur == '/' || cur == '\\') {
slashes++;
cur = *++src;
}
if(slashes == 2 && !strncmpiW(src, localhost, localhost_len)) { /* file://localhost/ -> file:/// */
if(*(src + localhost_len) == '/' || *(src + localhost_len) == '\\')
src += localhost_len + 1;
slashes = 3;
}
switch(slashes) {
case 1:
case 3:
next[0] = next[1] = next[2] = '/';
len = 3;
break;
case 0:
len = 0;
break;
default:
next[0] = next[1] = '/';
len = 2;
break;
}
}
if(len == 0) {
if(cur == '#' && (int_flags & WINE_URL_STOP_ON_HASH))
stop_escaping = TRUE;
if(cur == '?' && (int_flags & WINE_URL_STOP_ON_QUESTION))
stop_escaping = TRUE;
if(cur == '\\' && (int_flags & WINE_URL_BASH_AS_SLASH) && !stop_escaping) cur = '/';
if(URL_NeedEscapeW(cur, dwFlags, int_flags) && stop_escaping == FALSE) {
next[0] = L'%';
next[1] = hexDigits[(cur >> 4) & 0xf];
next[2] = hexDigits[cur & 0xf];
len = 3;
} else {
next[0] = cur;
len = 1;
}
src++;
}
if(needed + len <= *pcchEscaped) { if(needed + len <= *pcchEscaped) {
memcpy(dst, next, len*sizeof(WCHAR)); memcpy(dst, next, len*sizeof(WCHAR));
@ -1041,7 +1043,7 @@ HRESULT WINAPI UrlEscapeW(
} }
if(needed < *pcchEscaped) { if(needed < *pcchEscaped) {
*dst = L'\0'; *dst = '\0';
ret = S_OK; ret = S_OK;
} else { } else {
needed++; /* add one for the '\0' */ needed++; /* add one for the '\0' */