📄 url.c
字号:
/* case of /./ -> skip the ./ */
wk1 += 2;
}
else if (wk1[1] == '.') {
/* found /.. look for next / */
TRACE("found '/..'\n");
if (wk1[2] == '/' || wk1[2] == '\\' ||wk1[2] == '?'
|| wk1[2] == '#' || !wk1[2]) {
/* case /../ -> need to backup wk2 */
TRACE("found '/../'\n");
*(wk2-1) = L'\0'; /* set end of string */
mp = strrchrW(root, slash);
if (mp && (mp >= root)) {
/* found valid backup point */
wk2 = mp + 1;
if(wk1[2] != '/' && wk1[2] != '\\')
wk1 += 2;
else
wk1 += 3;
}
else {
/* did not find point, restore '/' */
*(wk2-1) = slash;
}
}
}
}
}
*wk2 = L'\0';
break;
default:
FIXME("how did we get here - state=%d\n", state);
HeapFree(GetProcessHeap(), 0, lpszUrlCpy);
return E_INVALIDARG;
}
}
*wk2 = L'\0';
TRACE("Simplified, orig <%s>, simple <%s>\n",
debugstr_w(pszUrl), debugstr_w(lpszUrlCpy));
}
nLen = lstrlenW(lpszUrlCpy);
while ((nLen > 0) && ((lpszUrlCpy[nLen-1] == '\r')||(lpszUrlCpy[nLen-1] == '\n')))
lpszUrlCpy[--nLen]=0;
if(dwFlags & (URL_UNESCAPE | URL_FILE_USE_PATHURL))
UrlUnescapeW(lpszUrlCpy, NULL, &nLen, URL_UNESCAPE_INPLACE);
if((EscapeFlags = dwFlags & (URL_ESCAPE_UNSAFE |
URL_ESCAPE_SPACES_ONLY |
URL_ESCAPE_PERCENT |
URL_DONT_ESCAPE_EXTRA_INFO |
URL_ESCAPE_SEGMENT_ONLY ))) {
EscapeFlags &= ~URL_ESCAPE_UNSAFE;
hr = UrlEscapeW(lpszUrlCpy, pszCanonicalized, pcchCanonicalized,
EscapeFlags);
} else { /* No escaping needed, just copy the string */
nLen = lstrlenW(lpszUrlCpy);
if(nLen < *pcchCanonicalized)
memcpy(pszCanonicalized, lpszUrlCpy, (nLen + 1)*sizeof(WCHAR));
else {
hr = E_POINTER;
nLen++;
}
*pcchCanonicalized = nLen;
}
HeapFree(GetProcessHeap(), 0, lpszUrlCpy);
if (hr == S_OK)
TRACE("result %s\n", debugstr_w(pszCanonicalized));
return hr;
}
/*************************************************************************
* UrlCombineA [SHLWAPI.@]
*
* Combine two Urls.
*
* PARAMS
* pszBase [I] Base Url
* pszRelative [I] Url to combine with pszBase
* pszCombined [O] Destination for combined Url
* pcchCombined [O] Destination for length of pszCombined
* dwFlags [I] URL_ flags from "shlwapi.h"
*
* RETURNS
* Success: S_OK. pszCombined contains the combined Url, pcchCombined
* contains its length.
* Failure: An HRESULT error code indicating the error.
*/
HRESULT WINAPI UrlCombineA(LPCSTR pszBase, LPCSTR pszRelative,
LPSTR pszCombined, LPDWORD pcchCombined,
DWORD dwFlags)
{
LPWSTR base, relative, combined;
DWORD ret, len, len2;
TRACE("(base %s, Relative %s, Combine size %ld, flags %08lx) using W version\n",
debugstr_a(pszBase),debugstr_a(pszRelative),
pcchCombined?*pcchCombined:0,dwFlags);
if(!pszBase || !pszRelative || !pcchCombined)
return E_INVALIDARG;
base = HeapAlloc(GetProcessHeap(), 0,
(3*INTERNET_MAX_URL_LENGTH) * sizeof(WCHAR));
relative = base + INTERNET_MAX_URL_LENGTH;
combined = relative + INTERNET_MAX_URL_LENGTH;
MultiByteToWideChar(0, 0, pszBase, -1, base, INTERNET_MAX_URL_LENGTH);
MultiByteToWideChar(0, 0, pszRelative, -1, relative, INTERNET_MAX_URL_LENGTH);
len = *pcchCombined;
ret = UrlCombineW(base, relative, pszCombined?combined:NULL, &len, dwFlags);
if (ret != S_OK) {
*pcchCombined = len;
HeapFree(GetProcessHeap(), 0, base);
return ret;
}
len2 = WideCharToMultiByte(0, 0, combined, len, 0, 0, 0, 0);
if (len2 > *pcchCombined) {
*pcchCombined = len2;
HeapFree(GetProcessHeap(), 0, base);
return E_POINTER;
}
WideCharToMultiByte(0, 0, combined, len+1, pszCombined, (*pcchCombined)+1,
0, 0);
*pcchCombined = len2;
HeapFree(GetProcessHeap(), 0, base);
return S_OK;
}
/*************************************************************************
* UrlCombineW [SHLWAPI.@]
*
* See UrlCombineA.
*/
HRESULT WINAPI UrlCombineW(LPCWSTR pszBase, LPCWSTR pszRelative,
LPWSTR pszCombined, LPDWORD pcchCombined,
DWORD dwFlags)
{
PARSEDURLW base, relative;
DWORD myflags, sizeloc = 0;
DWORD len, res1, res2, process_case = 0;
LPWSTR work, preliminary, mbase, mrelative;
static const WCHAR myfilestr[] = {'f','i','l','e',':','/','/','/','\0'};
static const WCHAR single_slash[] = {'/','\0'};
HRESULT ret;
TRACE("(base %s, Relative %s, Combine size %ld, flags %08lx)\n",
debugstr_w(pszBase),debugstr_w(pszRelative),
pcchCombined?*pcchCombined:0,dwFlags);
if(!pszBase || !pszRelative || !pcchCombined)
return E_INVALIDARG;
base.cbSize = sizeof(base);
relative.cbSize = sizeof(relative);
/* Get space for duplicates of the input and the output */
preliminary = HeapAlloc(GetProcessHeap(), 0, (3*INTERNET_MAX_URL_LENGTH) *
sizeof(WCHAR));
mbase = preliminary + INTERNET_MAX_URL_LENGTH;
mrelative = mbase + INTERNET_MAX_URL_LENGTH;
*preliminary = L'\0';
/* Canonicalize the base input prior to looking for the scheme */
myflags = dwFlags & (URL_DONT_SIMPLIFY | URL_UNESCAPE);
len = INTERNET_MAX_URL_LENGTH;
ret = UrlCanonicalizeW(pszBase, mbase, &len, myflags);
/* Canonicalize the relative input prior to looking for the scheme */
len = INTERNET_MAX_URL_LENGTH;
ret = UrlCanonicalizeW(pszRelative, mrelative, &len, myflags);
/* See if the base has a scheme */
res1 = ParseURLW(mbase, &base);
if (res1) {
/* if pszBase has no scheme, then return pszRelative */
TRACE("no scheme detected in Base\n");
process_case = 1;
}
else do {
/* get size of location field (if it exists) */
work = (LPWSTR)base.pszSuffix;
sizeloc = 0;
if (*work++ == L'/') {
if (*work++ == L'/') {
/* At this point have start of location and
* it ends at next '/' or end of string.
*/
while(*work && (*work != L'/')) work++;
sizeloc = (DWORD)(work - base.pszSuffix);
}
}
/* Change .sizep2 to not have the last leaf in it,
* Note: we need to start after the location (if it exists)
*/
work = strrchrW((base.pszSuffix+sizeloc), L'/');
if (work) {
len = (DWORD)(work - base.pszSuffix + 1);
base.cchSuffix = len;
}
/*
* At this point:
* .pszSuffix points to location (starting with '//')
* .cchSuffix length of location (above) and rest less the last
* leaf (if any)
* sizeloc length of location (above) up to but not including
* the last '/'
*/
res2 = ParseURLW(mrelative, &relative);
if (res2) {
/* no scheme in pszRelative */
TRACE("no scheme detected in Relative\n");
relative.pszSuffix = mrelative; /* case 3,4,5 depends on this */
relative.cchSuffix = strlenW(mrelative);
if (*pszRelative == L':') {
/* case that is either left alone or uses pszBase */
if (dwFlags & URL_PLUGGABLE_PROTOCOL) {
process_case = 5;
break;
}
process_case = 1;
break;
}
if (isalnum(*mrelative) && (*(mrelative + 1) == L':')) {
/* case that becomes "file:///" */
strcpyW(preliminary, myfilestr);
process_case = 1;
break;
}
if ((*mrelative == L'/') && (*(mrelative+1) == L'/')) {
/* pszRelative has location and rest */
process_case = 3;
break;
}
if (*mrelative == L'/') {
/* case where pszRelative is root to location */
process_case = 4;
break;
}
process_case = (*base.pszSuffix == L'/') ? 5 : 3;
break;
}
/* handle cases where pszRelative has scheme */
if ((base.cchProtocol == relative.cchProtocol) &&
(strncmpW(base.pszProtocol, relative.pszProtocol, base.cchProtocol) == 0)) {
/* since the schemes are the same */
if ((*relative.pszSuffix == L'/') && (*(relative.pszSuffix+1) == L'/')) {
/* case where pszRelative replaces location and following */
process_case = 3;
break;
}
if (*relative.pszSuffix == L'/') {
/* case where pszRelative is root to location */
process_case = 4;
break;
}
/* case where scheme is followed by document path */
process_case = 5;
break;
}
if ((*relative.pszSuffix == L'/') && (*(relative.pszSuffix+1) == L'/')) {
/* case where pszRelative replaces scheme, location,
* and following and handles PLUGGABLE
*/
process_case = 2;
break;
}
process_case = 1;
break;
} while(FALSE); /* a litte trick to allow easy exit from nested if's */
ret = S_OK;
switch (process_case) {
case 1: /*
* Return pszRelative appended to what ever is in pszCombined,
* (which may the string "file:///"
*/
strcatW(preliminary, mrelative);
break;
case 2: /*
* Same as case 1, but if URL_PLUGGABLE_PROTOCOL was specified
* and pszRelative starts with "//", then append a "/"
*/
strcpyW(preliminary, mrelative);
if (!(dwFlags & URL_PLUGGABLE_PROTOCOL) &&
URL_JustLocation(relative.pszSuffix))
strcatW(preliminary, single_slash);
break;
case 3: /*
* Return the pszBase scheme with pszRelative. Basically
* keeps the scheme and replaces the domain and following.
*/
memcpy(preliminary, base.pszProtocol, (base.cchProtocol + 1)*sizeof(WCHAR));
work = preliminary + base.cchProtocol + 1;
strcpyW(work, relative.pszSuffix);
if (!(dwFlags & URL_PLUGGABLE_PROTOCOL) &&
URL_JustLocation(relative.pszSuffix))
strcatW(work, single_slash);
break;
case 4: /*
* Return the pszBase scheme and location but everything
* after the location is pszRelative. (Replace document
* from root on.)
*/
memcpy(preliminary, base.pszProtocol, (base.cchProtocol+1+sizeloc)*sizeof(WCHAR));
work = preliminary + base.cchProtocol + 1 + sizeloc;
if (dwFlags & URL_PLUGGABLE_PROTOCOL)
*(work++) = L'/';
strcpyW(work, relative.pszSuffix);
break;
case 5: /*
* Return the pszBase without its document (if any) and
* append pszRelative after its scheme.
*/
memcpy(preliminary, base.pszProtocol,
(base.cchProtocol+1+base.cchSuffix)*sizeof(WCHAR));
work = preliminary + base.cchProtocol+1+base.cchSuffix - 1;
if (*work++ != L'/')
*(work++) = L'/';
strcpyW(work, relative.pszSuffix);
break;
default:
FIXME("How did we get here????? process_case=%ld\n", process_case);
ret = E_INVALIDARG;
}
if (ret == S_OK) {
/* Reuse mrelative as temp storage as its already allocated and not needed anymore */
ret = UrlCanonicalizeW(preliminary, mrelative, pcchCombined, dwFlags);
if(SUCCEEDED(ret) && pszCombined) {
lstrcpyW(pszCombined, mrelative);
}
TRACE("return-%ld len=%ld, %s\n",
process_case, *pcchCombined, debugstr_w(pszCombined));
}
HeapFree(GetProcessHeap(), 0, preliminary);
return ret;
}
/*************************************************************************
* 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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -