📄 url.c
字号:
#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.
*
* PARAMS
* pszUrl [I] Url to modify
* pszEscaped [O] Destination for modified Url
* pcchEscaped [I/O] Length of pszUrl, destination for length of pszEscaped
* dwFlags [I] URL_ flags from "shlwapi.h"
*
* RETURNS
* Success: S_OK. pszEscaped contains the escaped Url, pcchEscaped
* contains its length.
* Failure: E_POINTER, if pszEscaped is not large enough. In this case
* pcchEscaped is set to the required length.
*
* Converts unsafe characters into their escape sequences.
*
* NOTES
* - By default this function stops converting at the first '?' or
* '#' character.
* - If dwFlags contains URL_ESCAPE_SPACES_ONLY then only spaces are
* converted, but the conversion continues past a '?' or '#'.
* - Note that this function did not work well (or at all) in shlwapi version 4.
*
* BUGS
* Only the following flags are implemented:
*| URL_ESCAPE_SPACES_ONLY
*| URL_DONT_ESCAPE_EXTRA_INFO
*| URL_ESCAPE_SEGMENT_ONLY
*| URL_ESCAPE_PERCENT
*/
HRESULT WINAPI UrlEscapeW(
LPCWSTR pszUrl,
LPWSTR pszEscaped,
LPDWORD pcchEscaped,
DWORD dwFlags)
{
LPCWSTR src;
DWORD needed = 0, ret;
BOOL stop_escaping = FALSE;
WCHAR next[5], *dst = pszEscaped;
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%08x)\n", debugstr_w(pszUrl), pszEscaped,
pcchEscaped, dwFlags);
if(!pszUrl || !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: %08x\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 the assume DONT_ESCAPE_EXTRA_INFO */
dwFlags |= URL_DONT_ESCAPE_EXTRA_INFO;
int_flags = 0;
if(dwFlags & URL_ESCAPE_SEGMENT_ONLY) {
int_flags = WINE_URL_ESCAPE_QUESTION | WINE_URL_ESCAPE_HASH | WINE_URL_ESCAPE_SLASH;
} else {
parsed_url.cbSize = sizeof(parsed_url);
if(ParseURLW(pszUrl, &parsed_url) != S_OK)
parsed_url.nScheme = URL_SCHEME_INVALID;
TRACE("scheme = %d (%s)\n", parsed_url.nScheme, debugstr_wn(parsed_url.pszProtocol, parsed_url.cchProtocol));
if(dwFlags & URL_DONT_ESCAPE_EXTRA_INFO)
int_flags = WINE_URL_STOP_ON_HASH | WINE_URL_STOP_ON_QUESTION;
switch(parsed_url.nScheme) {
case URL_SCHEME_FILE:
int_flags |= WINE_URL_BASH_AS_SLASH | WINE_URL_COLLAPSE_SLASHES | WINE_URL_ESCAPE_HASH;
int_flags &= ~WINE_URL_STOP_ON_HASH;
break;
case URL_SCHEME_HTTP:
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] = '%';
next[1] = hexDigits[(cur >> 4) & 0xf];
next[2] = hexDigits[cur & 0xf];
len = 3;
} else {
next[0] = cur;
len = 1;
}
src++;
}
if(needed + len <= *pcchEscaped) {
memcpy(dst, next, len*sizeof(WCHAR));
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;
}
/*************************************************************************
* UrlUnescapeA [SHLWAPI.@]
*
* Converts Url escape sequences back to ordinary characters.
*
* PARAMS
* pszUrl [I/O] Url to convert
* pszUnescaped [O] Destination for converted Url
* pcchUnescaped [I/O] Size of output string
* dwFlags [I] URL_ESCAPE_ Flags from "shlwapi.h"
*
* RETURNS
* Success: S_OK. The converted value is in pszUnescaped, or in pszUrl if
* dwFlags includes URL_ESCAPE_INPLACE.
* Failure: E_POINTER if the converted Url is bigger than pcchUnescaped. In
* this case pcchUnescaped is set to the size required.
* NOTES
* If dwFlags includes URL_DONT_ESCAPE_EXTRA_INFO, the conversion stops at
* the first occurrence of either a '?' or '#' character.
*/
HRESULT WINAPI UrlUnescapeA(
LPSTR pszUrl,
LPSTR pszUnescaped,
LPDWORD pcchUnescaped,
DWORD dwFlags)
{
char *dst, next;
LPCSTR src;
HRESULT ret;
DWORD needed;
BOOL stop_unescaping = FALSE;
TRACE("(%s, %p, %p, 0x%08x)\n", debugstr_a(pszUrl), pszUnescaped,
pcchUnescaped, dwFlags);
if(!pszUrl || (!pszUnescaped && !(dwFlags & URL_UNESCAPE_INPLACE)) || !pcchUnescaped)
return E_INVALIDARG;
if(dwFlags & URL_UNESCAPE_INPLACE)
dst = pszUrl;
else
dst = pszUnescaped;
for(src = pszUrl, needed = 0; *src; src++, needed++) {
if(dwFlags & URL_DONT_UNESCAPE_EXTRA_INFO &&
(*src == '#' || *src == '?')) {
stop_unescaping = TRUE;
next = *src;
} else if(*src == '%' && isxdigit(*(src + 1)) && isxdigit(*(src + 2))
&& stop_unescaping == FALSE) {
INT ih;
char buf[3];
memcpy(buf, src + 1, 2);
buf[2] = '\0';
ih = strtol(buf, NULL, 16);
next = (CHAR) ih;
src += 2; /* Advance to end of escape */
} else
next = *src;
if(dwFlags & URL_UNESCAPE_INPLACE || needed < *pcchUnescaped)
*dst++ = next;
}
if(dwFlags & URL_UNESCAPE_INPLACE || needed < *pcchUnescaped) {
*dst = '\0';
ret = S_OK;
} else {
needed++; /* add one for the '\0' */
ret = E_POINTER;
}
if(!(dwFlags & URL_UNESCAPE_INPLACE))
*pcchUnescaped = needed;
if (ret == S_OK) {
TRACE("result %s\n", (dwFlags & URL_UNESCAPE_INPLACE) ?
debugstr_a(pszUrl) : debugstr_a(pszUnescaped));
}
return ret;
}
/*************************************************************************
* UrlUnescapeW [SHLWAPI.@]
*
* See UrlUnescapeA.
*/
HRESULT WINAPI UrlUnescapeW(
LPWSTR pszUrl,
LPWSTR pszUnescaped,
LPDWORD pcchUnescaped,
DWORD dwFlags)
{
WCHAR *dst, next;
LPCWSTR src;
HRESULT ret;
DWORD needed;
BOOL stop_unescaping = FALSE;
TRACE("(%s, %p, %p, 0x%08x)\n", debugstr_w(pszUrl), pszUnescaped,
pcchUnescaped, dwFlags);
if(!pszUrl || (!pszUnescaped && !(dwFlags & URL_UNESCAPE_INPLACE))|| !pcchUnescaped)
return E_INVALIDARG;
if(dwFlags & URL_UNESCAPE_INPLACE)
dst = pszUrl;
else
dst = pszUnescaped;
for(src = pszUrl, needed = 0; *src; src++, needed++) {
if(dwFlags & URL_DONT_UNESCAPE_EXTRA_INFO &&
(*src == '#' || *src == '?')) {
stop_unescaping = TRUE;
next = *src;
} else if(*src == '%' && isxdigitW(*(src + 1)) && isxdigitW(*(src + 2))
&& stop_unescaping == FALSE) {
INT ih;
WCHAR buf[5] = {'0','x',0};
memcpy(buf + 2, src + 1, 2*sizeof(WCHAR));
buf[4] = 0;
StrToIntExW(buf, STIF_SUPPORT_HEX, &ih);
next = (WCHAR) ih;
src += 2; /* Advance to end of escape */
} else
next = *src;
if(dwFlags & URL_UNESCAPE_INPLACE || needed < *pcchUnescaped)
*dst++ = next;
}
if(dwFlags & URL_UNESCAPE_INPLACE || needed < *pcchUnescaped) {
*dst = '\0';
ret = S_OK;
} else {
needed++; /* add one for the '\0' */
ret = E_POINTER;
}
if(!(dwFlags & URL_UNESCAPE_INPLACE))
*pcchUnescaped = needed;
if (ret == S_OK) {
TRACE("result %s\n", (dwFlags & URL_UNESCAPE_INPLACE) ?
debugstr_w(pszUrl) : debugstr_w(pszUnescaped));
}
return ret;
}
/*************************************************************************
* UrlGetLocationA [SHLWAPI.@]
*
* Get the location from a Url.
*
* PARAMS
* pszUrl [I] Url to get the location from
*
* RETURNS
* A pointer to the start of the location in pszUrl, or NULL if there is
* no location.
*
* NOTES
* - MSDN erroneously states that "The location is the segment of the Url
* starting with a '?' or '#' character". Neither V4 nor V5 of shlwapi.dll
* stop at '?' and always return a NULL in this case.
* - MSDN also erroneously states that "If a file URL has a query string,
* the returned string is the query string". In all tested cases, if the
* Url starts with "fi" then a NULL is returned. V5 gives the following results:
*| Result Url
*| ------ ---
*| NULL file://aa/b/cd#hohoh
*| #hohoh http://aa/b/cd#hohoh
*| NULL fi://aa/b/cd#hohoh
*| #hohoh ff://aa/b/cd#hohoh
*/
LPCSTR WINAPI UrlGetLocationA(
LPCSTR pszUrl)
{
PARSEDURLA base;
DWORD res1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -