| /* |
| * Url functions |
| * |
| * Copyright 2000 Huw D M Davies for CodeWeavers. |
| * |
| * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| */ |
| |
| #include <string.h> |
| #include <stdlib.h> |
| #include "windef.h" |
| #include "winnls.h" |
| #include "winbase.h" |
| #include "winerror.h" |
| #include "wine/unicode.h" |
| #include "wininet.h" |
| #include "winreg.h" |
| #define NO_SHLWAPI_STREAM |
| #include "shlwapi.h" |
| #include "wine/debug.h" |
| |
| WINE_DEFAULT_DEBUG_CHANNEL(shell); |
| |
| /* The following schemes were identified in the native version of |
| * SHLWAPI.DLL version 5.50 |
| */ |
| typedef enum { |
| URL_SCHEME_INVALID = -1, |
| URL_SCHEME_UNKNOWN = 0, |
| URL_SCHEME_FTP, |
| URL_SCHEME_HTTP, |
| URL_SCHEME_GOPHER, |
| URL_SCHEME_MAILTO, |
| URL_SCHEME_NEWS, |
| URL_SCHEME_NNTP, |
| URL_SCHEME_TELNET, |
| URL_SCHEME_WAIS, |
| URL_SCHEME_FILE, |
| URL_SCHEME_MK, |
| URL_SCHEME_HTTPS, |
| URL_SCHEME_SHELL, |
| URL_SCHEME_SNEWS, |
| URL_SCHEME_LOCAL, |
| URL_SCHEME_JAVASCRIPT, |
| URL_SCHEME_VBSCRIPT, |
| URL_SCHEME_ABOUT, |
| URL_SCHEME_RES, |
| URL_SCHEME_MAXVALUE |
| } URL_SCHEME; |
| |
| typedef struct { |
| URL_SCHEME scheme_number; |
| LPCSTR scheme_name; |
| } SHL_2_inet_scheme; |
| |
| static const SHL_2_inet_scheme shlwapi_schemes[] = { |
| {URL_SCHEME_FTP, "ftp"}, |
| {URL_SCHEME_HTTP, "http"}, |
| {URL_SCHEME_GOPHER, "gopher"}, |
| {URL_SCHEME_MAILTO, "mailto"}, |
| {URL_SCHEME_NEWS, "news"}, |
| {URL_SCHEME_NNTP, "nntp"}, |
| {URL_SCHEME_TELNET, "telnet"}, |
| {URL_SCHEME_WAIS, "wais"}, |
| {URL_SCHEME_FILE, "file"}, |
| {URL_SCHEME_MK, "mk"}, |
| {URL_SCHEME_HTTPS, "https"}, |
| {URL_SCHEME_SHELL, "shell"}, |
| {URL_SCHEME_SNEWS, "snews"}, |
| {URL_SCHEME_LOCAL, "local"}, |
| {URL_SCHEME_JAVASCRIPT, "javascript"}, |
| {URL_SCHEME_VBSCRIPT, "vbscript"}, |
| {URL_SCHEME_ABOUT, "about"}, |
| {URL_SCHEME_RES, "res"}, |
| {0, 0} |
| }; |
| |
| typedef struct { |
| LPCWSTR pScheme; /* [out] start of scheme */ |
| DWORD szScheme; /* [out] size of scheme (until colon) */ |
| LPCWSTR pUserName; /* [out] start of Username */ |
| DWORD szUserName; /* [out] size of Username (until ":" or "@") */ |
| LPCWSTR pPassword; /* [out] start of Password */ |
| DWORD szPassword; /* [out] size of Password (until "@") */ |
| LPCWSTR pHostName; /* [out] start of Hostname */ |
| DWORD szHostName; /* [out] size of Hostname (until ":" or "/") */ |
| LPCWSTR pPort; /* [out] start of Port */ |
| DWORD szPort; /* [out] size of Port (until "/" or eos) */ |
| LPCWSTR pQuery; /* [out] start of Query */ |
| DWORD szQuery; /* [out] size of Query (until eos) */ |
| } WINE_PARSE_URL; |
| |
| typedef enum { |
| SCHEME, |
| HOST, |
| PORT, |
| USERPASS, |
| } WINE_URL_SCAN_TYPE; |
| |
| typedef struct { |
| INT size; /* [in] (always 0x18) */ |
| LPCSTR ap1; /* [out] start of scheme */ |
| INT sizep1; /* [out] size of scheme (until colon) */ |
| LPCSTR ap2; /* [out] pointer following first colon */ |
| INT sizep2; /* [out] size of remainder */ |
| INT fcncde; /* [out] function match of p1 (0 if unknown) */ |
| } UNKNOWN_SHLWAPI_1; |
| |
| typedef struct { |
| INT size; /* [in] (always 0x18) */ |
| LPCWSTR ap1; /* [out] start of scheme */ |
| INT sizep1; /* [out] size of scheme (until colon) */ |
| LPCWSTR ap2; /* [out] pointer following first colon */ |
| INT sizep2; /* [out] size of remainder */ |
| INT fcncde; /* [out] function match of p1 (0 if unknown) */ |
| } UNKNOWN_SHLWAPI_2; |
| |
| static const CHAR hexDigits[] = "0123456789ABCDEF"; |
| |
| static const WCHAR fileW[] = {'f','i','l','e','\0'}; |
| |
| static const unsigned char HashDataLookup[256] = { |
| 0x01, 0x0E, 0x6E, 0x19, 0x61, 0xAE, 0x84, 0x77, 0x8A, 0xAA, 0x7D, 0x76, 0x1B, |
| 0xE9, 0x8C, 0x33, 0x57, 0xC5, 0xB1, 0x6B, 0xEA, 0xA9, 0x38, 0x44, 0x1E, 0x07, |
| 0xAD, 0x49, 0xBC, 0x28, 0x24, 0x41, 0x31, 0xD5, 0x68, 0xBE, 0x39, 0xD3, 0x94, |
| 0xDF, 0x30, 0x73, 0x0F, 0x02, 0x43, 0xBA, 0xD2, 0x1C, 0x0C, 0xB5, 0x67, 0x46, |
| 0x16, 0x3A, 0x4B, 0x4E, 0xB7, 0xA7, 0xEE, 0x9D, 0x7C, 0x93, 0xAC, 0x90, 0xB0, |
| 0xA1, 0x8D, 0x56, 0x3C, 0x42, 0x80, 0x53, 0x9C, 0xF1, 0x4F, 0x2E, 0xA8, 0xC6, |
| 0x29, 0xFE, 0xB2, 0x55, 0xFD, 0xED, 0xFA, 0x9A, 0x85, 0x58, 0x23, 0xCE, 0x5F, |
| 0x74, 0xFC, 0xC0, 0x36, 0xDD, 0x66, 0xDA, 0xFF, 0xF0, 0x52, 0x6A, 0x9E, 0xC9, |
| 0x3D, 0x03, 0x59, 0x09, 0x2A, 0x9B, 0x9F, 0x5D, 0xA6, 0x50, 0x32, 0x22, 0xAF, |
| 0xC3, 0x64, 0x63, 0x1A, 0x96, 0x10, 0x91, 0x04, 0x21, 0x08, 0xBD, 0x79, 0x40, |
| 0x4D, 0x48, 0xD0, 0xF5, 0x82, 0x7A, 0x8F, 0x37, 0x69, 0x86, 0x1D, 0xA4, 0xB9, |
| 0xC2, 0xC1, 0xEF, 0x65, 0xF2, 0x05, 0xAB, 0x7E, 0x0B, 0x4A, 0x3B, 0x89, 0xE4, |
| 0x6C, 0xBF, 0xE8, 0x8B, 0x06, 0x18, 0x51, 0x14, 0x7F, 0x11, 0x5B, 0x5C, 0xFB, |
| 0x97, 0xE1, 0xCF, 0x15, 0x62, 0x71, 0x70, 0x54, 0xE2, 0x12, 0xD6, 0xC7, 0xBB, |
| 0x0D, 0x20, 0x5E, 0xDC, 0xE0, 0xD4, 0xF7, 0xCC, 0xC4, 0x2B, 0xF9, 0xEC, 0x2D, |
| 0xF4, 0x6F, 0xB6, 0x99, 0x88, 0x81, 0x5A, 0xD9, 0xCA, 0x13, 0xA5, 0xE7, 0x47, |
| 0xE6, 0x8E, 0x60, 0xE3, 0x3E, 0xB3, 0xF6, 0x72, 0xA2, 0x35, 0xA0, 0xD7, 0xCD, |
| 0xB4, 0x2F, 0x6D, 0x2C, 0x26, 0x1F, 0x95, 0x87, 0x00, 0xD8, 0x34, 0x3F, 0x17, |
| 0x25, 0x45, 0x27, 0x75, 0x92, 0xB8, 0xA3, 0xC8, 0xDE, 0xEB, 0xF8, 0xF3, 0xDB, |
| 0x0A, 0x98, 0x83, 0x7B, 0xE5, 0xCB, 0x4C, 0x78, 0xD1 }; |
| |
| static 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 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) |
| { |
| while(*str && (*str == L'/')) str++; |
| if (*str) { |
| while (*str && ((*str == L'-') || |
| (*str == L'.') || |
| isalnumW(*str))) str++; |
| if (*str == L'/') return FALSE; |
| } |
| return TRUE; |
| } |
| |
| |
| /************************************************************************* |
| * @ [SHLWAPI.1] |
| * |
| * Identifies the Internet "scheme" in the passed string. ASCII based. |
| * Also determines start and length of item after the ':' |
| */ |
| DWORD WINAPI SHLWAPI_1 (LPCSTR x, UNKNOWN_SHLWAPI_1 *y) |
| { |
| DWORD cnt; |
| const SHL_2_inet_scheme *inet_pro; |
| |
| y->fcncde = URL_SCHEME_INVALID; |
| if (y->size != 0x18) return E_INVALIDARG; |
| /* FIXME: leading white space generates error of 0x80041001 which |
| * is undefined |
| */ |
| if (*x <= ' ') return 0x80041001; |
| cnt = 0; |
| y->sizep1 = 0; |
| y->ap1 = x; |
| while (*x) { |
| if (*x == ':') { |
| y->sizep1 = cnt; |
| cnt = -1; |
| y->ap2 = x+1; |
| break; |
| } |
| x++; |
| cnt++; |
| } |
| |
| /* check for no scheme in string start */ |
| /* (apparently schemes *must* be larger than a single character) */ |
| if ((*x == '\0') || (y->sizep1 <= 1)) { |
| y->ap1 = 0; |
| return 0x80041001; |
| } |
| |
| /* found scheme, set length of remainder */ |
| y->sizep2 = lstrlenA(y->ap2); |
| |
| /* see if known scheme and return indicator number */ |
| y->fcncde = URL_SCHEME_UNKNOWN; |
| inet_pro = shlwapi_schemes; |
| while (inet_pro->scheme_name) { |
| if (!strncasecmp(inet_pro->scheme_name, y->ap1, |
| min(y->sizep1, lstrlenA(inet_pro->scheme_name)))) { |
| y->fcncde = inet_pro->scheme_number; |
| break; |
| } |
| inet_pro++; |
| } |
| return S_OK; |
| } |
| |
| /************************************************************************* |
| * @ [SHLWAPI.2] |
| * |
| * Identifies the Internet "scheme" in the passed string. UNICODE based. |
| * Also determines start and length of item after the ':' |
| */ |
| DWORD WINAPI SHLWAPI_2 (LPCWSTR x, UNKNOWN_SHLWAPI_2 *y) |
| { |
| DWORD cnt; |
| const SHL_2_inet_scheme *inet_pro; |
| LPSTR cmpstr; |
| INT len; |
| |
| y->fcncde = URL_SCHEME_INVALID; |
| if (y->size != 0x18) return E_INVALIDARG; |
| /* FIXME: leading white space generates error of 0x80041001 which |
| * is undefined |
| */ |
| if (*x <= L' ') return 0x80041001; |
| cnt = 0; |
| y->sizep1 = 0; |
| y->ap1 = x; |
| while (*x) { |
| if (*x == L':') { |
| y->sizep1 = cnt; |
| cnt = -1; |
| y->ap2 = x+1; |
| break; |
| } |
| x++; |
| cnt++; |
| } |
| |
| /* check for no scheme in string start */ |
| /* (apparently schemes *must* be larger than a single character) */ |
| if ((*x == L'\0') || (y->sizep1 <= 1)) { |
| y->ap1 = 0; |
| return 0x80041001; |
| } |
| |
| /* found scheme, set length of remainder */ |
| y->sizep2 = lstrlenW(y->ap2); |
| |
| /* see if known scheme and return indicator number */ |
| len = WideCharToMultiByte(0, 0, y->ap1, y->sizep1, 0, 0, 0, 0); |
| cmpstr = (LPSTR)HeapAlloc(GetProcessHeap(), 0, len+1); |
| WideCharToMultiByte(0, 0, y->ap1, y->sizep1, cmpstr, len+1, 0, 0); |
| y->fcncde = URL_SCHEME_UNKNOWN; |
| inet_pro = shlwapi_schemes; |
| while (inet_pro->scheme_name) { |
| if (!strncasecmp(inet_pro->scheme_name, cmpstr, |
| min(len, lstrlenA(inet_pro->scheme_name)))) { |
| y->fcncde = inet_pro->scheme_number; |
| break; |
| } |
| inet_pro++; |
| } |
| HeapFree(GetProcessHeap(), 0, cmpstr); |
| return S_OK; |
| } |
| |
| /************************************************************************* |
| * UrlCanonicalizeA [SHLWAPI.@] |
| * |
| * Uses the W version to do job. |
| */ |
| HRESULT WINAPI UrlCanonicalizeA(LPCSTR pszUrl, LPSTR pszCanonicalized, |
| LPDWORD pcchCanonicalized, DWORD dwFlags) |
| { |
| LPWSTR base, canonical; |
| DWORD ret, len, len2; |
| |
| TRACE("(%s %p %p 0x%08lx) using W version\n", |
| debugstr_a(pszUrl), pszCanonicalized, |
| pcchCanonicalized, dwFlags); |
| |
| base = (LPWSTR) HeapAlloc(GetProcessHeap(), 0, |
| (2*INTERNET_MAX_URL_LENGTH) * sizeof(WCHAR)); |
| canonical = base + INTERNET_MAX_URL_LENGTH; |
| |
| MultiByteToWideChar(0, 0, pszUrl, -1, base, INTERNET_MAX_URL_LENGTH); |
| len = INTERNET_MAX_URL_LENGTH; |
| |
| ret = UrlCanonicalizeW(base, canonical, &len, dwFlags); |
| if (ret != S_OK) { |
| HeapFree(GetProcessHeap(), 0, base); |
| return ret; |
| } |
| |
| len2 = WideCharToMultiByte(0, 0, canonical, len, 0, 0, 0, 0); |
| if (len2 > *pcchCanonicalized) { |
| *pcchCanonicalized = len; |
| HeapFree(GetProcessHeap(), 0, base); |
| return E_POINTER; |
| } |
| WideCharToMultiByte(0, 0, canonical, len+1, pszCanonicalized, |
| *pcchCanonicalized, 0, 0); |
| *pcchCanonicalized = len2; |
| HeapFree(GetProcessHeap(), 0, base); |
| return S_OK; |
| } |
| |
| /************************************************************************* |
| * UrlCanonicalizeW [SHLWAPI.@] |
| * |
| * |
| * MSDN is wrong (at 10/30/01 - go figure). This should support the |
| * following flags: GLA |
| * URL_DONT_ESCAPE_EXTRA_INFO 0x02000000 |
| * URL_ESCAPE_SPACES_ONLY 0x04000000 |
| * URL_ESCAPE_PERCENT 0x00001000 |
| * URL_ESCAPE_UNSAFE 0x10000000 |
| * URL_UNESCAPE 0x10000000 |
| * URL_DONT_SIMPLIFY 0x08000000 |
| * URL_ESCAPE_SEGMENT_ONLY 0x00002000 |
| */ |
| HRESULT WINAPI UrlCanonicalizeW(LPCWSTR pszUrl, LPWSTR pszCanonicalized, |
| LPDWORD pcchCanonicalized, DWORD dwFlags) |
| { |
| HRESULT hr = S_OK; |
| DWORD EscapeFlags; |
| LPWSTR lpszUrlCpy, wk1, wk2, mp, root; |
| INT nLen, nByteLen, state; |
| |
| TRACE("(%s %p %p 0x%08lx)\n", debugstr_w(pszUrl), pszCanonicalized, |
| pcchCanonicalized, dwFlags); |
| |
| nByteLen = (lstrlenW(pszUrl) + 1) * sizeof(WCHAR); /* length in bytes */ |
| lpszUrlCpy = HeapAlloc(GetProcessHeap(), 0, nByteLen); |
| |
| if (dwFlags & URL_DONT_SIMPLIFY) |
| memcpy(lpszUrlCpy, pszUrl, nByteLen); |
| else { |
| |
| /* |
| * state = |
| * 0 initial 1,3 |
| * 1 have 2[+] alnum 2,3 |
| * 2 have scheme (found :) 4,6,3 |
| * 3 failed (no location) |
| * 4 have // 5,3 |
| * 5 have 1[+] alnum 6,3 |
| * 6 have location (found /) save root location |
| */ |
| |
| wk1 = (LPWSTR)pszUrl; |
| wk2 = lpszUrlCpy; |
| state = 0; |
| while (*wk1) { |
| switch (state) { |
| case 0: |
| if (!isalnumW(*wk1)) {state = 3; break;} |
| *wk2++ = *wk1++; |
| if (!isalnumW(*wk1)) {state = 3; break;} |
| *wk2++ = *wk1++; |
| state = 1; |
| break; |
| case 1: |
| *wk2++ = *wk1; |
| if (*wk1++ == L':') state = 2; |
| break; |
| case 2: |
| if (*wk1 != L'/') {state = 3; break;} |
| *wk2++ = *wk1++; |
| if (*wk1 != L'/') {state = 6; break;} |
| *wk2++ = *wk1++; |
| state = 4; |
| break; |
| case 3: |
| strcpyW(wk2, wk1); |
| wk1 += strlenW(wk1); |
| wk2 += strlenW(wk2); |
| break; |
| case 4: |
| if (!isalnumW(*wk1) && (*wk1 != L'-')) {state = 3; break;} |
| while(isalnumW(*wk1) || (*wk1 == L'-')) *wk2++ = *wk1++; |
| state = 5; |
| break; |
| case 5: |
| if (*wk1 != L'/') {state = 3; break;} |
| *wk2++ = *wk1++; |
| state = 6; |
| break; |
| case 6: |
| /* Now at root location, cannot back up any more. */ |
| /* "root" will point at the '/' */ |
| root = wk2-1; |
| while (*wk1) { |
| TRACE("wk1=%c\n", (CHAR)*wk1); |
| mp = strchrW(wk1, L'/'); |
| if (!mp) { |
| strcpyW(wk2, wk1); |
| wk1 += strlenW(wk1); |
| wk2 += strlenW(wk2); |
| continue; |
| } |
| nLen = mp - wk1 + 1; |
| strncpyW(wk2, wk1, nLen); |
| wk2 += nLen; |
| wk1 += nLen; |
| if (*wk1 == L'.') { |
| TRACE("found '/.'\n"); |
| if (*(wk1+1) == L'/') { |
| /* case of /./ -> skip the ./ */ |
| wk1 += 2; |
| } |
| else if (*(wk1+1) == L'.') { |
| /* found /.. look for next / */ |
| TRACE("found '/..'\n"); |
| if (*(wk1+2) == L'/') { |
| /* case /../ -> need to backup wk2 */ |
| TRACE("found '/../'\n"); |
| *(wk2-1) = L'\0'; /* set end of string */ |
| mp = strrchrW(root, L'/'); |
| if (mp && (mp >= root)) { |
| /* found valid backup point */ |
| wk2 = mp + 1; |
| wk1 += 3; |
| } |
| else { |
| /* did not find point, restore '/' */ |
| *(wk2-1) = L'/'; |
| } |
| } |
| } |
| } |
| } |
| *wk2 = L'\0'; |
| break; |
| default: |
| FIXME("how did we get here - state=%d\n", state); |
| return E_INVALIDARG; |
| } |
| } |
| *wk2 = L'\0'; |
| TRACE("Simplified, orig <%s>, simple <%s>\n", |
| debugstr_w(pszUrl), debugstr_w(lpszUrlCpy)); |
| } |
| |
| if(dwFlags & URL_UNESCAPE) |
| UrlUnescapeW(lpszUrlCpy, NULL, NULL, 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.@] |
| * |
| * Uses the W version to do job. |
| */ |
| 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,dwFlags); |
| |
| base = (LPWSTR) 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 = INTERNET_MAX_URL_LENGTH; |
| |
| ret = UrlCombineW(base, relative, combined, &len, dwFlags); |
| if (ret != S_OK) { |
| 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, |
| 0, 0); |
| *pcchCombined = len2; |
| HeapFree(GetProcessHeap(), 0, base); |
| return S_OK; |
| } |
| |
| /************************************************************************* |
| * UrlCombineW [SHLWAPI.@] |
| */ |
| HRESULT WINAPI UrlCombineW(LPCWSTR pszBase, LPCWSTR pszRelative, |
| LPWSTR pszCombined, LPDWORD pcchCombined, |
| DWORD dwFlags) |
| { |
| UNKNOWN_SHLWAPI_2 base, relative; |
| DWORD myflags, sizeloc = 0; |
| DWORD len, res1, res2, process_case = 0; |
| LPWSTR work, preliminary, mbase, mrelative; |
| WCHAR myfilestr[] = {'f','i','l','e',':','/','/','/','\0'}; |
| WCHAR single_slash[] = {'/','\0'}; |
| HRESULT ret; |
| |
| TRACE("(base %s, Relative %s, Combine size %ld, flags %08lx)\n", |
| debugstr_w(pszBase),debugstr_w(pszRelative), |
| *pcchCombined,dwFlags); |
| |
| base.size = 24; |
| relative.size = 24; |
| |
| /* 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 = SHLWAPI_2(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.ap2; |
| 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 = work - base.ap2; |
| } |
| } |
| |
| /* Change .sizep2 to not have the last leaf in it, |
| * Note: we need to start after the location (if it exists) |
| */ |
| work = strrchrW((base.ap2+sizeloc), L'/'); |
| if (work) { |
| len = work - base.ap2 + 1; |
| base.sizep2 = len; |
| } |
| /* |
| * At this point: |
| * .ap2 points to location (starting with '//') |
| * .sizep2 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 = SHLWAPI_2(mrelative, &relative); |
| if (res2) { |
| /* no scheme in pszRelative */ |
| TRACE("no scheme detected in Relative\n"); |
| relative.ap2 = mrelative; /* case 3,4,5 depends on this */ |
| relative.sizep2 = 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.ap2 == L'/') ? 5 : 3; |
| break; |
| } |
| |
| /* handle cases where pszRelative has scheme */ |
| if ((base.sizep1 == relative.sizep1) && |
| (strncmpW(base.ap1, relative.ap1, base.sizep1) == 0)) { |
| |
| /* since the schemes are the same */ |
| if ((*relative.ap2 == L'/') && (*(relative.ap2+1) == L'/')) { |
| /* case where pszRelative replaces location and following */ |
| process_case = 3; |
| break; |
| } |
| if (*relative.ap2 == 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.ap2 == L'/') && (*(relative.ap2+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:///" |
| */ |
| len = strlenW(mrelative) + strlenW(preliminary); |
| if (len+1 > *pcchCombined) { |
| *pcchCombined = len; |
| ret = E_POINTER; |
| break; |
| } |
| strcatW(preliminary, mrelative); |
| break; |
| |
| case 2: /* |
| * Same as case 1, but if URL_PLUGGABLE_PROTOCOL was specified |
| * and pszRelative starts with "//", then append a "/" |
| */ |
| len = strlenW(mrelative) + 1; |
| if (len+1 > *pcchCombined) { |
| *pcchCombined = len; |
| ret = E_POINTER; |
| break; |
| } |
| strcpyW(preliminary, mrelative); |
| if (!(dwFlags & URL_PLUGGABLE_PROTOCOL) && |
| URL_JustLocation(relative.ap2)) |
| strcatW(preliminary, single_slash); |
| break; |
| |
| case 3: /* |
| * Return the pszBase scheme with pszRelative. Basicly |
| * keeps the scheme and replaces the domain and following. |
| */ |
| len = base.sizep1 + 1 + relative.sizep2 + 1; |
| if (len+1 > *pcchCombined) { |
| *pcchCombined = len; |
| ret = E_POINTER; |
| break; |
| } |
| strncpyW(preliminary, base.ap1, base.sizep1 + 1); |
| work = preliminary + base.sizep1 + 1; |
| strcpyW(work, relative.ap2); |
| if (!(dwFlags & URL_PLUGGABLE_PROTOCOL) && |
| URL_JustLocation(relative.ap2)) |
| 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.) |
| */ |
| len = base.sizep1 + 1 + sizeloc + relative.sizep2 + 1; |
| if (len+1 > *pcchCombined) { |
| *pcchCombined = len; |
| ret = E_POINTER; |
| break; |
| } |
| strncpyW(preliminary, base.ap1, base.sizep1+1+sizeloc); |
| work = preliminary + base.sizep1 + 1 + sizeloc; |
| if (dwFlags & URL_PLUGGABLE_PROTOCOL) |
| *(work++) = L'/'; |
| strcpyW(work, relative.ap2); |
| break; |
| |
| case 5: /* |
| * Return the pszBase without its document (if any) and |
| * append pszRelative after its scheme. |
| */ |
| len = base.sizep1 + 1 + base.sizep2 + relative.sizep2; |
| if (len+1 > *pcchCombined) { |
| *pcchCombined = len; |
| ret = E_POINTER; |
| break; |
| } |
| strncpyW(preliminary, base.ap1, base.sizep1+1+base.sizep2); |
| work = preliminary + base.sizep1+1+base.sizep2 - 1; |
| if (*work++ != L'/') |
| *(work++) = L'/'; |
| strcpyW(work, relative.ap2); |
| break; |
| |
| default: |
| FIXME("How did we get here????? process_case=%ld\n", process_case); |
| ret = E_INVALIDARG; |
| } |
| |
| if (ret == S_OK) { |
| /* |
| * Now that the combining is done, process the escape options if |
| * necessary, otherwise just copy the string. |
| */ |
| myflags = dwFlags & (URL_ESCAPE_PERCENT | |
| URL_ESCAPE_SPACES_ONLY | |
| URL_DONT_ESCAPE_EXTRA_INFO | |
| URL_ESCAPE_SEGMENT_ONLY); |
| if (myflags) |
| ret = UrlEscapeW(preliminary, pszCombined, |
| pcchCombined, myflags); |
| else { |
| len = (strlenW(preliminary) + 1) * sizeof(WCHAR); |
| memcpy(pszCombined, preliminary, len); |
| *pcchCombined = strlenW(preliminary); |
| } |
| TRACE("return-%ld len=%ld, %s\n", |
| process_case, *pcchCombined, debugstr_w(pszCombined)); |
| } |
| HeapFree(GetProcessHeap(), 0, preliminary); |
| return ret; |
| } |
| |
| /************************************************************************* |
| * UrlEscapeA [SHLWAPI.@] |
| * |
| * Converts unsafe characters into their escape sequences. |
| * |
| * The converted string is returned in pszEscaped if the buffer size |
| * (which should be supplied in pcchEscaped) is large enough, in this |
| * case the function returns S_OK and pcchEscaped contains the length |
| * of the escaped string. If the buffer is not large enough the |
| * function returns E_POINTER and pcchEscaped contains the required |
| * buffer size (including room for the '\0'). |
| * |
| * By default the function stops converting at the first '?' or |
| * '#'. [MSDN says differently]. If URL_ESCAPE_SPACES_ONLY flag is set |
| * then only spaces are converted, but the conversion continues past a |
| * '?' or '#'. |
| * |
| * BUGS: |
| * Have now implemented the following flags: |
| * URL_ESCAPE_SPACES_ONLY |
| * URL_DONT_ESCAPE_EXTRA_INFO |
| * URL_ESCAPE_SEGMENT_ONLY |
| * URL_ESCAPE_PERCENT |
| * Initial testing seems to indicate that this is now working like |
| * native shlwapi version 5. Note that these functions did not work |
| * well (or at all) in shlwapi version 4. |
| * |
| */ |
| 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 %p 0x%08lx)\n", debugstr_a(pszUrl), pszEscaped, |
| pcchEscaped, dwFlags); |
| |
| 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 for list of assumptions, bugs, and FIXMEs |
| */ |
| 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; |
| |
| TRACE("(%s %p %p 0x%08lx)\n", debugstr_w(pszUrl), pszEscaped, |
| pcchEscaped, dwFlags); |
| |
| 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 the assume 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) { |
| /* TRACE("escaping %c\n", *src); */ |
| next[0] = L'%'; |
| /* |
| * I would have assumed that the W form would escape |
| * the character with 4 hex digits (or even 8), |
| * however, experiments show that native shlwapi escapes |
| * with only 2 hex digits. |
| * next[1] = hexDigits[(*src >> 12) & 0xf]; |
| * next[2] = hexDigits[(*src >> 8) & 0xf]; |
| * next[3] = hexDigits[(*src >> 4) & 0xf]; |
| * next[4] = hexDigits[*src & 0xf]; |
| * len = 5; |
| */ |
| 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*sizeof(WCHAR)); |
| dst += len; |
| } |
| needed += len; |
| } |
| |
| if(needed < *pcchEscaped) { |
| *dst = L'\0'; |
| ret = S_OK; |
| } else { |
| needed++; /* add one for the '\0' */ |
| ret = E_POINTER; |
| } |
| *pcchEscaped = needed; |
| return ret; |
| } |
| |
| |
| /************************************************************************* |
| * UrlUnescapeA [SHLWAPI.@] |
| * |
| * Converts escape sequences back to ordinary characters. |
| * |
| * If URL_ESCAPE_INPLACE is set in dwFlags then pszUnescaped and |
| * pcchUnescaped are ignored and the converted string is returned in |
| * pszUrl, otherwise the string is returned in pszUnescaped. |
| * pcchUnescaped should contain the size of pszUnescaped on calling |
| * and will contain the length the the returned string on return if |
| * the buffer is big enough else it will contain the buffer size |
| * required (including room for the '\0'). The function returns S_OK |
| * on success or E_POINTER if the buffer is not large enough. If the |
| * URL_DONT_ESCAPE_EXTRA_INFO flag is set then the conversion stops at |
| * the first occurrence of either '?' or '#'. |
| * |
| */ |
| HRESULT WINAPI UrlUnescapeA( |
| LPCSTR 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%08lx)\n", debugstr_a(pszUrl), pszUnescaped, |
| pcchUnescaped, dwFlags); |
| |
| if(dwFlags & URL_UNESCAPE_INPLACE) |
| dst = (char*)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 for list of assumptions, bugs, and FIXMEs |
| */ |
| HRESULT WINAPI UrlUnescapeW( |
| LPCWSTR 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%08lx)\n", debugstr_w(pszUrl), pszUnescaped, |
| pcchUnescaped, dwFlags); |
| |
| if(dwFlags & URL_UNESCAPE_INPLACE) |
| dst = (WCHAR*)pszUrl; |
| else |
| dst = pszUnescaped; |
| |
| for(src = pszUrl, needed = 0; *src; src++, needed++) { |
| if(dwFlags & URL_DONT_UNESCAPE_EXTRA_INFO && |
| (*src == L'#' || *src == L'?')) { |
| stop_unescaping = TRUE; |
| next = *src; |
| } else if(*src == L'%' && isxdigitW(*(src + 1)) && isxdigitW(*(src + 2)) |
| && stop_unescaping == FALSE) { |
| INT ih; |
| WCHAR buf[3]; |
| memcpy(buf, src + 1, 2*sizeof(WCHAR)); |
| buf[2] = L'\0'; |
| ih = StrToIntW(buf); |
| 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 = L'\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.@] |
| * |
| * Bugs/Features: |
| * MSDN (as of 2001-11-01) says that: |
| * "The location is the segment of the URL starting with a ? |
| * or # character." |
| * Neither V4 nor V5 of shlwapi.dll implement the '?' and always return |
| * a NULL. |
| * MSDN further states that: |
| * "If a file URL has a query string, the returned string is |
| * the query string." |
| * In all test cases if the scheme starts with "fi" then a NULL is |
| * returned. V5 gives the following results: |
| * 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) |
| { |
| UNKNOWN_SHLWAPI_1 base; |
| DWORD res1; |
| |
| base.size = 24; |
| res1 = SHLWAPI_1(pszUrl, &base); |
| if (res1) return NULL; /* invalid scheme */ |
| |
| /* if scheme is file: then never return pointer */ |
| if (strncmp(base.ap1, "file", min(4,base.sizep1)) == 0) return NULL; |
| |
| /* Look for '#' and return its addr */ |
| return strchr(base.ap2, '#'); |
| } |
| |
| /************************************************************************* |
| * UrlGetLocationW [SHLWAPI.@] |
| * |
| * See UrlGetLocationA for list of assumptions, bugs, and FIXMEs |
| */ |
| LPCWSTR WINAPI UrlGetLocationW( |
| LPCWSTR pszUrl) |
| { |
| UNKNOWN_SHLWAPI_2 base; |
| DWORD res1; |
| |
| base.size = 24; |
| res1 = SHLWAPI_2(pszUrl, &base); |
| if (res1) return NULL; /* invalid scheme */ |
| |
| /* if scheme is file: then never return pointer */ |
| if (strncmpW(base.ap1, fileW, min(4,base.sizep1)) == 0) return NULL; |
| |
| /* Look for '#' and return its addr */ |
| return strchrW(base.ap2, L'#'); |
| } |
| |
| /************************************************************************* |
| * UrlCompareA [SHLWAPI.@] |
| */ |
| INT WINAPI UrlCompareA( |
| LPCSTR pszUrl1, |
| LPCSTR pszUrl2, |
| BOOL fIgnoreSlash) |
| { |
| INT ret, len, len1, len2; |
| |
| if (!fIgnoreSlash) |
| return strcmp(pszUrl1, pszUrl2); |
| len1 = strlen(pszUrl1); |
| if (pszUrl1[len1-1] == L'/') len1--; |
| len2 = strlen(pszUrl2); |
| if (pszUrl2[len2-1] == L'/') len2--; |
| if (len1 == len2) |
| return strncmp(pszUrl1, pszUrl2, len1); |
| len = min(len1, len2); |
| ret = strncmp(pszUrl1, pszUrl2, len); |
| if (ret) return ret; |
| if (len1 > len2) return 1; |
| return -1; |
| } |
| |
| /************************************************************************* |
| * UrlCompareW [SHLWAPI.@] |
| */ |
| INT WINAPI UrlCompareW( |
| LPCWSTR pszUrl1, |
| LPCWSTR pszUrl2, |
| BOOL fIgnoreSlash) |
| { |
| INT ret, len, len1, len2; |
| |
| if (!fIgnoreSlash) |
| return strcmpW(pszUrl1, pszUrl2); |
| len1 = strlenW(pszUrl1); |
| if (pszUrl1[len1-1] == L'/') len1--; |
| len2 = strlenW(pszUrl2); |
| if (pszUrl2[len2-1] == L'/') len2--; |
| if (len1 == len2) |
| return strncmpW(pszUrl1, pszUrl2, len1); |
| len = min(len1, len2); |
| ret = strncmpW(pszUrl1, pszUrl2, len); |
| if (ret) return ret; |
| if (len1 > len2) return 1; |
| return -1; |
| } |
| |
| /************************************************************************* |
| * HashData [SHLWAPI.@] |
| * |
| * Hash an input block into a variable sized digest. |
| */ |
| BOOL WINAPI HashData(const unsigned char *lpSrc, INT nSrcLen, |
| unsigned char *lpDest, INT nDestLen) |
| { |
| INT srcCount = nSrcLen - 1, destCount = nDestLen - 1; |
| |
| if (IsBadReadPtr(lpSrc, nSrcLen) || |
| IsBadWritePtr(lpDest, nDestLen)) |
| return FALSE; |
| |
| while (destCount >= 0) |
| { |
| lpDest[destCount] = (destCount & 0xff); |
| destCount--; |
| } |
| |
| while (srcCount >= 0) |
| { |
| destCount = nDestLen - 1; |
| while (destCount >= 0) |
| { |
| lpDest[destCount] = HashDataLookup[lpSrc[srcCount] ^ lpDest[destCount]]; |
| destCount--; |
| } |
| srcCount--; |
| } |
| return TRUE; |
| } |
| |
| /************************************************************************* |
| * UrlHashA [SHLWAPI.@] |
| * |
| * Hash an ASCII URL. |
| */ |
| HRESULT WINAPI UrlHashA(LPCSTR pszUrl, unsigned char *lpDest, INT nDestLen) |
| { |
| if (IsBadStringPtrA(pszUrl, -1) || IsBadWritePtr(lpDest, nDestLen)) |
| return E_INVALIDARG; |
| |
| HashData(pszUrl, strlen(pszUrl), lpDest, nDestLen); |
| return S_OK; |
| } |
| |
| /************************************************************************* |
| * UrlHashW [SHLWAPI.@] |
| * |
| * See UrlHashA. |
| */ |
| HRESULT WINAPI UrlHashW(LPCWSTR pszUrl, unsigned char *lpDest, INT nDestLen) |
| { |
| char szUrl[MAX_PATH]; |
| |
| TRACE("(%s,%p,%d)\n",debugstr_w(pszUrl), lpDest, nDestLen); |
| |
| if (IsBadStringPtrW(pszUrl, -1) || IsBadWritePtr(lpDest, nDestLen)) |
| return E_INVALIDARG; |
| |
| /* Win32 hashes the data as an ASCII string, presumably so that both A+W |
| * return the same digests for the same URL. |
| */ |
| WideCharToMultiByte(0, 0, pszUrl, -1, szUrl, MAX_PATH, 0, 0); |
| HashData(szUrl, strlen(szUrl), lpDest, nDestLen); |
| return S_OK; |
| } |
| |
| /************************************************************************* |
| * UrlApplySchemeA [SHLWAPI.@] |
| */ |
| HRESULT WINAPI UrlApplySchemeA(LPCSTR pszIn, LPSTR pszOut, LPDWORD pcchOut, DWORD dwFlags) |
| { |
| LPWSTR in, out; |
| DWORD ret, len, len2; |
| |
| TRACE("(in %s, out size %ld, flags %08lx) using W version\n", |
| debugstr_a(pszIn), *pcchOut, dwFlags); |
| |
| in = (LPWSTR) HeapAlloc(GetProcessHeap(), 0, |
| (2*INTERNET_MAX_URL_LENGTH) * sizeof(WCHAR)); |
| out = in + INTERNET_MAX_URL_LENGTH; |
| |
| MultiByteToWideChar(0, 0, pszIn, -1, in, INTERNET_MAX_URL_LENGTH); |
| len = INTERNET_MAX_URL_LENGTH; |
| |
| ret = UrlApplySchemeW(in, out, &len, dwFlags); |
| if ((ret != S_OK) && (ret != S_FALSE)) { |
| HeapFree(GetProcessHeap(), 0, in); |
| return ret; |
| } |
| |
| len2 = WideCharToMultiByte(0, 0, out, len+1, 0, 0, 0, 0); |
| if (len2 > *pcchOut) { |
| *pcchOut = len2; |
| HeapFree(GetProcessHeap(), 0, in); |
| return E_POINTER; |
| } |
| WideCharToMultiByte(0, 0, out, len+1, pszOut, *pcchOut, 0, 0); |
| *pcchOut = len2; |
| HeapFree(GetProcessHeap(), 0, in); |
| return ret; |
| } |
| |
| HRESULT URL_GuessScheme(LPCWSTR pszIn, LPWSTR pszOut, LPDWORD pcchOut) |
| { |
| HKEY newkey; |
| BOOL j; |
| INT index, i; |
| DWORD value_len, data_len, dwType; |
| WCHAR reg_path[MAX_PATH]; |
| WCHAR value[MAX_PATH], data[MAX_PATH]; |
| WCHAR Wxx, Wyy; |
| |
| MultiByteToWideChar(0, 0, |
| "Software\\Microsoft\\Windows\\CurrentVersion\\URL\\Prefixes", |
| -1, reg_path, MAX_PATH); |
| RegOpenKeyExW(HKEY_LOCAL_MACHINE, reg_path, 0, 1, &newkey); |
| index = 0; |
| while(value_len = data_len = MAX_PATH, |
| RegEnumValueW(newkey, index, value, &value_len, |
| 0, &dwType, (LPVOID)data, &data_len) == 0) { |
| TRACE("guess %d %s is %s\n", |
| index, debugstr_w(value), debugstr_w(data)); |
| |
| j = FALSE; |
| for(i=0; i<value_len; i++) { |
| Wxx = pszIn[i]; |
| Wyy = value[i]; |
| /* remember that TRUE is not-equal */ |
| j = ChrCmpIW(Wxx, Wyy); |
| if (j) break; |
| } |
| if ((i == value_len) && !j) { |
| if (strlenW(data) + strlenW(pszIn) + 1 > *pcchOut) { |
| *pcchOut = strlenW(data) + strlenW(pszIn) + 1; |
| RegCloseKey(newkey); |
| return E_POINTER; |
| } |
| strcpyW(pszOut, data); |
| strcatW(pszOut, pszIn); |
| *pcchOut = strlenW(pszOut); |
| TRACE("matched and set to %s\n", debugstr_w(pszOut)); |
| RegCloseKey(newkey); |
| return S_OK; |
| } |
| index++; |
| } |
| RegCloseKey(newkey); |
| return -1; |
| } |
| |
| HRESULT URL_ApplyDefault(LPCWSTR pszIn, LPWSTR pszOut, LPDWORD pcchOut) |
| { |
| HKEY newkey; |
| DWORD data_len, dwType; |
| WCHAR reg_path[MAX_PATH]; |
| WCHAR value[MAX_PATH], data[MAX_PATH]; |
| |
| /* get and prepend default */ |
| MultiByteToWideChar(0, 0, |
| "Software\\Microsoft\\Windows\\CurrentVersion\\URL\\DefaultPrefix", |
| -1, reg_path, MAX_PATH); |
| RegOpenKeyExW(HKEY_LOCAL_MACHINE, reg_path, 0, 1, &newkey); |
| data_len = MAX_PATH; |
| value[0] = L'@'; |
| value[1] = L'\0'; |
| RegQueryValueExW(newkey, value, 0, &dwType, (LPBYTE)data, &data_len); |
| RegCloseKey(newkey); |
| if (strlenW(data) + strlenW(pszIn) + 1 > *pcchOut) { |
| *pcchOut = strlenW(data) + strlenW(pszIn) + 1; |
| return E_POINTER; |
| } |
| strcpyW(pszOut, data); |
| strcatW(pszOut, pszIn); |
| *pcchOut = strlenW(pszOut); |
| TRACE("used default %s\n", debugstr_w(pszOut)); |
| return S_OK; |
| } |
| |
| /************************************************************************* |
| * UrlApplySchemeW [SHLWAPI.@] |
| */ |
| HRESULT WINAPI UrlApplySchemeW(LPCWSTR pszIn, LPWSTR pszOut, LPDWORD pcchOut, DWORD dwFlags) |
| { |
| UNKNOWN_SHLWAPI_2 in_scheme; |
| DWORD res1; |
| HRESULT ret; |
| |
| TRACE("(in %s, out size %ld, flags %08lx)\n", |
| debugstr_w(pszIn), *pcchOut, dwFlags); |
| |
| if (dwFlags & URL_APPLY_GUESSFILE) { |
| FIXME("(%s %p %p(%ld) 0x%08lx): stub URL_APPLY_GUESSFILE not implemented\n", |
| debugstr_w(pszIn), pszOut, pcchOut, *pcchOut, dwFlags); |
| strcpyW(pszOut, pszIn); |
| *pcchOut = strlenW(pszOut); |
| return S_FALSE; |
| } |
| |
| in_scheme.size = 24; |
| /* See if the base has a scheme */ |
| res1 = SHLWAPI_2(pszIn, &in_scheme); |
| if (res1) { |
| /* no scheme in input, need to see if we need to guess */ |
| if (dwFlags & URL_APPLY_GUESSSCHEME) { |
| if ((ret = URL_GuessScheme(pszIn, pszOut, pcchOut)) != -1) |
| return ret; |
| } |
| } |
| else { |
| /* we have a scheme, see if valid (known scheme) */ |
| if (in_scheme.fcncde) { |
| /* have valid scheme, so just copy and exit */ |
| if (strlenW(pszIn) + 1 > *pcchOut) { |
| *pcchOut = strlenW(pszIn) + 1; |
| return E_POINTER; |
| } |
| strcpyW(pszOut, pszIn); |
| *pcchOut = strlenW(pszOut); |
| TRACE("valid scheme, returing copy\n"); |
| return S_OK; |
| } |
| } |
| |
| /* If we are here, then either invalid scheme, |
| * or no scheme and can't/failed guess. |
| */ |
| if ( ( ((res1 == 0) && (dwFlags & URL_APPLY_FORCEAPPLY)) || |
| ((res1 != 0)) ) && |
| (dwFlags & URL_APPLY_DEFAULT)) { |
| /* find and apply default scheme */ |
| return URL_ApplyDefault(pszIn, pszOut, pcchOut); |
| } |
| |
| /* just copy and give proper return code */ |
| if (strlenW(pszIn) + 1 > *pcchOut) { |
| *pcchOut = strlenW(pszIn) + 1; |
| return E_POINTER; |
| } |
| strcpyW(pszOut, pszIn); |
| *pcchOut = strlenW(pszOut); |
| TRACE("returning copy, left alone\n"); |
| return S_FALSE; |
| } |
| |
| /************************************************************************* |
| * UrlIsA [SHLWAPI.@] |
| */ |
| BOOL WINAPI UrlIsA(LPCSTR pszUrl, URLIS Urlis) |
| { |
| UNKNOWN_SHLWAPI_1 base; |
| DWORD res1; |
| |
| switch (Urlis) { |
| |
| case URLIS_OPAQUE: |
| base.size = 24; |
| res1 = SHLWAPI_1(pszUrl, &base); |
| if (res1) return FALSE; /* invalid scheme */ |
| if ((*base.ap2 == '/') && (*(base.ap2+1) == '/')) |
| /* has scheme followed by 2 '/' */ |
| return FALSE; |
| return TRUE; |
| |
| case URLIS_URL: |
| case URLIS_NOHISTORY: |
| case URLIS_FILEURL: |
| case URLIS_APPLIABLE: |
| case URLIS_DIRECTORY: |
| case URLIS_HASQUERY: |
| default: |
| FIXME("(%s %d): stub\n", debugstr_a(pszUrl), Urlis); |
| } |
| return FALSE; |
| } |
| |
| /************************************************************************* |
| * UrlIsW [SHLWAPI.@] |
| */ |
| BOOL WINAPI UrlIsW(LPCWSTR pszUrl, URLIS Urlis) |
| { |
| UNKNOWN_SHLWAPI_2 base; |
| DWORD res1; |
| |
| switch (Urlis) { |
| |
| case URLIS_OPAQUE: |
| base.size = 24; |
| res1 = SHLWAPI_2(pszUrl, &base); |
| if (res1) return FALSE; /* invalid scheme */ |
| if ((*base.ap2 == L'/') && (*(base.ap2+1) == L'/')) |
| /* has scheme followed by 2 '/' */ |
| return FALSE; |
| return TRUE; |
| |
| case URLIS_URL: |
| case URLIS_NOHISTORY: |
| case URLIS_FILEURL: |
| case URLIS_APPLIABLE: |
| case URLIS_DIRECTORY: |
| case URLIS_HASQUERY: |
| default: |
| FIXME("(%s %d): stub\n", debugstr_w(pszUrl), Urlis); |
| } |
| return FALSE; |
| } |
| |
| /************************************************************************* |
| * UrlIsNoHistoryA [SHLWAPI.@] |
| */ |
| BOOL WINAPI UrlIsNoHistoryA(LPCSTR pszUrl) |
| { |
| return UrlIsA(pszUrl, URLIS_NOHISTORY); |
| } |
| |
| /************************************************************************* |
| * UrlIsNoHistoryW [SHLWAPI.@] |
| */ |
| BOOL WINAPI UrlIsNoHistoryW(LPCWSTR pszUrl) |
| { |
| return UrlIsW(pszUrl, URLIS_NOHISTORY); |
| } |
| |
| /************************************************************************* |
| * UrlIsOpaqueA [SHLWAPI.@] |
| */ |
| BOOL WINAPI UrlIsOpaqueA(LPCSTR pszUrl) |
| { |
| return UrlIsA(pszUrl, URLIS_OPAQUE); |
| } |
| |
| /************************************************************************* |
| * UrlIsOpaqueW [SHLWAPI.@] |
| */ |
| BOOL WINAPI UrlIsOpaqueW(LPCWSTR pszUrl) |
| { |
| return UrlIsW(pszUrl, URLIS_OPAQUE); |
| } |
| |
| /************************************************************************* |
| * Scans for characters of type "type" and when not matching found, |
| * returns pointer to it and length in size. |
| * |
| * Characters tested based on RFC 1738 |
| */ |
| LPCWSTR URL_ScanID(LPCWSTR start, LPDWORD size, WINE_URL_SCAN_TYPE type) |
| { |
| static DWORD alwayszero = 0; |
| BOOL cont = TRUE; |
| |
| *size = 0; |
| |
| switch(type){ |
| |
| case SCHEME: |
| while (cont) { |
| if ( (islowerW(*start) && isalphaW(*start)) || |
| isdigitW(*start) || |
| (*start == L'+') || |
| (*start == L'-') || |
| (*start == L'.')) { |
| start++; |
| (*size)++; |
| } |
| else |
| cont = FALSE; |
| } |
| break; |
| |
| case USERPASS: |
| while (cont) { |
| if ( isalphaW(*start) || |
| isdigitW(*start) || |
| /* user/password only characters */ |
| (*start == L';') || |
| (*start == L'?') || |
| (*start == L'&') || |
| (*start == L'=') || |
| /* *extra* characters */ |
| (*start == L'!') || |
| (*start == L'*') || |
| (*start == L'\'') || |
| (*start == L'(') || |
| (*start == L')') || |
| (*start == L',') || |
| /* *safe* characters */ |
| (*start == L'$') || |
| (*start == L'_') || |
| (*start == L'+') || |
| (*start == L'-') || |
| (*start == L'.')) { |
| start++; |
| (*size)++; |
| } else if (*start == L'%') { |
| if (isxdigitW(*(start+1)) && |
| isxdigitW(*(start+2))) { |
| start += 3; |
| *size += 3; |
| } else |
| cont = FALSE; |
| } else |
| cont = FALSE; |
| } |
| break; |
| |
| case PORT: |
| while (cont) { |
| if (isdigitW(*start)) { |
| start++; |
| (*size)++; |
| } |
| else |
| cont = FALSE; |
| } |
| break; |
| |
| case HOST: |
| while (cont) { |
| if (isalnumW(*start) || |
| (*start == L'-') || |
| (*start == L'.') ) { |
| start++; |
| (*size)++; |
| } |
| else |
| cont = FALSE; |
| } |
| break; |
| default: |
| FIXME("unknown type %d\n", type); |
| return (LPWSTR)&alwayszero; |
| } |
| /* TRACE("scanned %ld characters next char %p<%c>\n", |
| *size, start, *start); */ |
| return start; |
| } |
| |
| /************************************************************************* |
| * Attempt to parse URL into pieces. |
| */ |
| LONG URL_ParseUrl(LPCWSTR pszUrl, WINE_PARSE_URL *pl) |
| { |
| LPCWSTR work; |
| |
| memset(pl, 0, sizeof(WINE_PARSE_URL)); |
| pl->pScheme = pszUrl; |
| work = URL_ScanID(pl->pScheme, &pl->szScheme, SCHEME); |
| if (!*work || (*work != L':')) goto ERROR; |
| work++; |
| if ((*work != L'/') || (*(work+1) != L'/')) goto ERROR; |
| pl->pUserName = work + 2; |
| work = URL_ScanID(pl->pUserName, &pl->szUserName, USERPASS); |
| if (*work == L':' ) { |
| /* parse password */ |
| work++; |
| pl->pPassword = work; |
| work = URL_ScanID(pl->pPassword, &pl->szPassword, USERPASS); |
| if (*work != L'@') { |
| /* what we just parsed must be the hostname and port |
| * so reset pointers and clear then let it parse */ |
| pl->szUserName = pl->szPassword = 0; |
| work = pl->pUserName - 1; |
| pl->pUserName = pl->pPassword = 0; |
| } |
| } else if (*work == L'@') { |
| /* no password */ |
| pl->szPassword = 0; |
| pl->pPassword = 0; |
| } else if (!*work || (*work == L'/') || (*work == L'.')) { |
| /* what was parsed was hostname, so reset pointers and let it parse */ |
| pl->szUserName = pl->szPassword = 0; |
| work = pl->pUserName - 1; |
| pl->pUserName = pl->pPassword = 0; |
| } else goto ERROR; |
| |
| /* now start parsing hostname or hostnumber */ |
| work++; |
| pl->pHostName = work; |
| work = URL_ScanID(pl->pHostName, &pl->szHostName, HOST); |
| if (*work == L':') { |
| /* parse port */ |
| work++; |
| pl->pPort = work; |
| work = URL_ScanID(pl->pPort, &pl->szPort, PORT); |
| } |
| if (*work == L'/') { |
| /* see if query string */ |
| pl->pQuery = strchrW(work, L'?'); |
| if (pl->pQuery) pl->szQuery = strlenW(pl->pQuery); |
| } |
| TRACE("parse successful: scheme=%p(%ld), user=%p(%ld), pass=%p(%ld), host=%p(%ld), port=%p(%ld), query=%p(%ld)\n", |
| pl->pScheme, pl->szScheme, |
| pl->pUserName, pl->szUserName, |
| pl->pPassword, pl->szPassword, |
| pl->pHostName, pl->szHostName, |
| pl->pPort, pl->szPort, |
| pl->pQuery, pl->szQuery); |
| return S_OK; |
| ERROR: |
| FIXME("failed to parse %s\n", debugstr_w(pszUrl)); |
| return E_INVALIDARG; |
| } |
| |
| /************************************************************************* |
| * UrlGetPartA [SHLWAPI.@] |
| */ |
| HRESULT WINAPI UrlGetPartA(LPCSTR pszIn, LPSTR pszOut, LPDWORD pcchOut, |
| DWORD dwPart, DWORD dwFlags) |
| { |
| LPWSTR in, out; |
| DWORD ret, len, len2; |
| |
| in = (LPWSTR) HeapAlloc(GetProcessHeap(), 0, |
| (2*INTERNET_MAX_URL_LENGTH) * sizeof(WCHAR)); |
| out = in + INTERNET_MAX_URL_LENGTH; |
| |
| MultiByteToWideChar(0, 0, pszIn, -1, in, INTERNET_MAX_URL_LENGTH); |
| |
| len = INTERNET_MAX_URL_LENGTH; |
| ret = UrlGetPartW(in, out, &len, dwPart, dwFlags); |
| |
| if (ret != S_OK) { |
| HeapFree(GetProcessHeap(), 0, in); |
| return ret; |
| } |
| |
| len2 = WideCharToMultiByte(0, 0, out, len, 0, 0, 0, 0); |
| if (len2 > *pcchOut) { |
| *pcchOut = len2; |
| HeapFree(GetProcessHeap(), 0, in); |
| return E_POINTER; |
| } |
| WideCharToMultiByte(0, 0, out, len+1, pszOut, *pcchOut, 0, 0); |
| *pcchOut = len2; |
| HeapFree(GetProcessHeap(), 0, in); |
| return S_OK; |
| } |
| |
| /************************************************************************* |
| * UrlGetPartW [SHLWAPI.@] |
| */ |
| HRESULT WINAPI UrlGetPartW(LPCWSTR pszIn, LPWSTR pszOut, LPDWORD pcchOut, |
| DWORD dwPart, DWORD dwFlags) |
| { |
| WINE_PARSE_URL pl; |
| HRESULT ret; |
| DWORD size, schsize; |
| LPCWSTR addr, schaddr; |
| LPWSTR work; |
| |
| TRACE("(%s %p %p(%ld) %08lx %08lx)\n", |
| debugstr_w(pszIn), pszOut, pcchOut, *pcchOut, dwPart, dwFlags); |
| |
| ret = URL_ParseUrl(pszIn, &pl); |
| if (!ret) { |
| schaddr = pl.pScheme; |
| schsize = pl.szScheme; |
| |
| switch (dwPart) { |
| case URL_PART_SCHEME: |
| if (!pl.szScheme) return E_INVALIDARG; |
| addr = pl.pScheme; |
| size = pl.szScheme; |
| break; |
| |
| case URL_PART_HOSTNAME: |
| if (!pl.szHostName) return E_INVALIDARG; |
| addr = pl.pHostName; |
| size = pl.szHostName; |
| break; |
| |
| case URL_PART_USERNAME: |
| if (!pl.szUserName) return E_INVALIDARG; |
| addr = pl.pUserName; |
| size = pl.szUserName; |
| break; |
| |
| case URL_PART_PASSWORD: |
| if (!pl.szPassword) return E_INVALIDARG; |
| addr = pl.pPassword; |
| size = pl.szPassword; |
| break; |
| |
| case URL_PART_PORT: |
| if (!pl.szPort) return E_INVALIDARG; |
| addr = pl.pPort; |
| size = pl.szPort; |
| break; |
| |
| case URL_PART_QUERY: |
| if (!pl.szQuery) return E_INVALIDARG; |
| addr = pl.pQuery; |
| size = pl.szQuery; |
| break; |
| |
| default: |
| return E_INVALIDARG; |
| } |
| |
| if (dwFlags == URL_PARTFLAG_KEEPSCHEME) { |
| if (*pcchOut < size + schsize + 2) { |
| *pcchOut = size + schsize + 2; |
| return E_POINTER; |
| } |
| strncpyW(pszOut, schaddr, schsize); |
| work = pszOut + schsize; |
| *work = L':'; |
| strncpyW(work+1, addr, size); |
| *pcchOut = size + schsize + 1; |
| work += (size + 1); |
| *work = L'\0'; |
| } |
| else { |
| if (*pcchOut < size + 1) {*pcchOut = size+1; return E_POINTER;} |
| strncpyW(pszOut, addr, size); |
| *pcchOut = size; |
| work = pszOut + size; |
| *work = L'\0'; |
| } |
| TRACE("len=%ld %s\n", *pcchOut, debugstr_w(pszOut)); |
| } |
| return ret; |
| } |
| |
| /************************************************************************* |
| * PathIsURLA [SHLWAPI.@] |
| * |
| * Check if the given path is a URL. |
| * |
| * PARAMS |
| * lpszPath [I] Path to check. |
| * |
| * RETURNS |
| * TRUE if lpszPath is a URL. |
| * FALSE if lpszPath is NULL or not a URL. |
| */ |
| BOOL WINAPI PathIsURLA(LPCSTR lpstrPath) |
| { |
| UNKNOWN_SHLWAPI_1 base; |
| DWORD res1; |
| |
| if (!lpstrPath || !*lpstrPath) return FALSE; |
| |
| /* get protocol */ |
| base.size = sizeof(base); |
| res1 = SHLWAPI_1(lpstrPath, &base); |
| return (base.fcncde > 0); |
| } |
| |
| /************************************************************************* |
| * PathIsURLW [SHLWAPI.@] |
| */ |
| BOOL WINAPI PathIsURLW(LPCWSTR lpstrPath) |
| { |
| UNKNOWN_SHLWAPI_2 base; |
| DWORD res1; |
| |
| if (!lpstrPath || !*lpstrPath) return FALSE; |
| |
| /* get protocol */ |
| base.size = sizeof(base); |
| res1 = SHLWAPI_2(lpstrPath, &base); |
| return (base.fcncde > 0); |
| } |