Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenurl.c
Go to the documentation of this file.
00001 /* 00002 * Url functions 00003 * 00004 * Copyright 2000 Huw D M Davies for CodeWeavers. 00005 * 00006 * This library is free software; you can redistribute it and/or 00007 * modify it under the terms of the GNU Lesser General Public 00008 * License as published by the Free Software Foundation; either 00009 * version 2.1 of the License, or (at your option) any later version. 00010 * 00011 * This library is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00014 * Lesser General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU Lesser General Public 00017 * License along with this library; if not, write to the Free Software 00018 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 00019 */ 00020 00021 #include "config.h" 00022 #include "wine/port.h" 00023 #include <stdarg.h> 00024 #include <string.h> 00025 #include <stdlib.h> 00026 #include "windef.h" 00027 #include "winbase.h" 00028 #include "winnls.h" 00029 #include "winerror.h" 00030 #include "wine/unicode.h" 00031 #include "wininet.h" 00032 #include "winreg.h" 00033 #include "winternl.h" 00034 #define NO_SHLWAPI_STREAM 00035 #include "shlwapi.h" 00036 #include "intshcut.h" 00037 #include "wine/debug.h" 00038 00039 HMODULE WINAPI MLLoadLibraryW(LPCWSTR,HMODULE,DWORD); 00040 BOOL WINAPI MLFreeLibrary(HMODULE); 00041 HRESULT WINAPI MLBuildResURLW(LPCWSTR,HMODULE,DWORD,LPCWSTR,LPWSTR,DWORD); 00042 00043 WINE_DEFAULT_DEBUG_CHANNEL(shell); 00044 00045 /* The following schemes were identified in the native version of 00046 * SHLWAPI.DLL version 5.50 00047 */ 00048 static const struct { 00049 URL_SCHEME scheme_number; 00050 WCHAR scheme_name[12]; 00051 } shlwapi_schemes[] = { 00052 {URL_SCHEME_FTP, {'f','t','p',0}}, 00053 {URL_SCHEME_HTTP, {'h','t','t','p',0}}, 00054 {URL_SCHEME_GOPHER, {'g','o','p','h','e','r',0}}, 00055 {URL_SCHEME_MAILTO, {'m','a','i','l','t','o',0}}, 00056 {URL_SCHEME_NEWS, {'n','e','w','s',0}}, 00057 {URL_SCHEME_NNTP, {'n','n','t','p',0}}, 00058 {URL_SCHEME_TELNET, {'t','e','l','n','e','t',0}}, 00059 {URL_SCHEME_WAIS, {'w','a','i','s',0}}, 00060 {URL_SCHEME_FILE, {'f','i','l','e',0}}, 00061 {URL_SCHEME_MK, {'m','k',0}}, 00062 {URL_SCHEME_HTTPS, {'h','t','t','p','s',0}}, 00063 {URL_SCHEME_SHELL, {'s','h','e','l','l',0}}, 00064 {URL_SCHEME_SNEWS, {'s','n','e','w','s',0}}, 00065 {URL_SCHEME_LOCAL, {'l','o','c','a','l',0}}, 00066 {URL_SCHEME_JAVASCRIPT, {'j','a','v','a','s','c','r','i','p','t',0}}, 00067 {URL_SCHEME_VBSCRIPT, {'v','b','s','c','r','i','p','t',0}}, 00068 {URL_SCHEME_ABOUT, {'a','b','o','u','t',0}}, 00069 {URL_SCHEME_RES, {'r','e','s',0}}, 00070 }; 00071 00072 typedef struct { 00073 LPCWSTR pScheme; /* [out] start of scheme */ 00074 DWORD szScheme; /* [out] size of scheme (until colon) */ 00075 LPCWSTR pUserName; /* [out] start of Username */ 00076 DWORD szUserName; /* [out] size of Username (until ":" or "@") */ 00077 LPCWSTR pPassword; /* [out] start of Password */ 00078 DWORD szPassword; /* [out] size of Password (until "@") */ 00079 LPCWSTR pHostName; /* [out] start of Hostname */ 00080 DWORD szHostName; /* [out] size of Hostname (until ":" or "/") */ 00081 LPCWSTR pPort; /* [out] start of Port */ 00082 DWORD szPort; /* [out] size of Port (until "/" or eos) */ 00083 LPCWSTR pQuery; /* [out] start of Query */ 00084 DWORD szQuery; /* [out] size of Query (until eos) */ 00085 } WINE_PARSE_URL; 00086 00087 typedef enum { 00088 SCHEME, 00089 HOST, 00090 PORT, 00091 USERPASS, 00092 } WINE_URL_SCAN_TYPE; 00093 00094 static const CHAR hexDigits[] = "0123456789ABCDEF"; 00095 00096 static const WCHAR fileW[] = {'f','i','l','e','\0'}; 00097 00098 static const unsigned char HashDataLookup[256] = { 00099 0x01, 0x0E, 0x6E, 0x19, 0x61, 0xAE, 0x84, 0x77, 0x8A, 0xAA, 0x7D, 0x76, 0x1B, 00100 0xE9, 0x8C, 0x33, 0x57, 0xC5, 0xB1, 0x6B, 0xEA, 0xA9, 0x38, 0x44, 0x1E, 0x07, 00101 0xAD, 0x49, 0xBC, 0x28, 0x24, 0x41, 0x31, 0xD5, 0x68, 0xBE, 0x39, 0xD3, 0x94, 00102 0xDF, 0x30, 0x73, 0x0F, 0x02, 0x43, 0xBA, 0xD2, 0x1C, 0x0C, 0xB5, 0x67, 0x46, 00103 0x16, 0x3A, 0x4B, 0x4E, 0xB7, 0xA7, 0xEE, 0x9D, 0x7C, 0x93, 0xAC, 0x90, 0xB0, 00104 0xA1, 0x8D, 0x56, 0x3C, 0x42, 0x80, 0x53, 0x9C, 0xF1, 0x4F, 0x2E, 0xA8, 0xC6, 00105 0x29, 0xFE, 0xB2, 0x55, 0xFD, 0xED, 0xFA, 0x9A, 0x85, 0x58, 0x23, 0xCE, 0x5F, 00106 0x74, 0xFC, 0xC0, 0x36, 0xDD, 0x66, 0xDA, 0xFF, 0xF0, 0x52, 0x6A, 0x9E, 0xC9, 00107 0x3D, 0x03, 0x59, 0x09, 0x2A, 0x9B, 0x9F, 0x5D, 0xA6, 0x50, 0x32, 0x22, 0xAF, 00108 0xC3, 0x64, 0x63, 0x1A, 0x96, 0x10, 0x91, 0x04, 0x21, 0x08, 0xBD, 0x79, 0x40, 00109 0x4D, 0x48, 0xD0, 0xF5, 0x82, 0x7A, 0x8F, 0x37, 0x69, 0x86, 0x1D, 0xA4, 0xB9, 00110 0xC2, 0xC1, 0xEF, 0x65, 0xF2, 0x05, 0xAB, 0x7E, 0x0B, 0x4A, 0x3B, 0x89, 0xE4, 00111 0x6C, 0xBF, 0xE8, 0x8B, 0x06, 0x18, 0x51, 0x14, 0x7F, 0x11, 0x5B, 0x5C, 0xFB, 00112 0x97, 0xE1, 0xCF, 0x15, 0x62, 0x71, 0x70, 0x54, 0xE2, 0x12, 0xD6, 0xC7, 0xBB, 00113 0x0D, 0x20, 0x5E, 0xDC, 0xE0, 0xD4, 0xF7, 0xCC, 0xC4, 0x2B, 0xF9, 0xEC, 0x2D, 00114 0xF4, 0x6F, 0xB6, 0x99, 0x88, 0x81, 0x5A, 0xD9, 0xCA, 0x13, 0xA5, 0xE7, 0x47, 00115 0xE6, 0x8E, 0x60, 0xE3, 0x3E, 0xB3, 0xF6, 0x72, 0xA2, 0x35, 0xA0, 0xD7, 0xCD, 00116 0xB4, 0x2F, 0x6D, 0x2C, 0x26, 0x1F, 0x95, 0x87, 0x00, 0xD8, 0x34, 0x3F, 0x17, 00117 0x25, 0x45, 0x27, 0x75, 0x92, 0xB8, 0xA3, 0xC8, 0xDE, 0xEB, 0xF8, 0xF3, 0xDB, 00118 0x0A, 0x98, 0x83, 0x7B, 0xE5, 0xCB, 0x4C, 0x78, 0xD1 }; 00119 00120 static DWORD get_scheme_code(LPCWSTR scheme, DWORD scheme_len) 00121 { 00122 unsigned int i; 00123 00124 for(i=0; i < sizeof(shlwapi_schemes)/sizeof(shlwapi_schemes[0]); i++) { 00125 if(scheme_len == strlenW(shlwapi_schemes[i].scheme_name) 00126 && !memcmp(scheme, shlwapi_schemes[i].scheme_name, scheme_len*sizeof(WCHAR))) 00127 return shlwapi_schemes[i].scheme_number; 00128 } 00129 00130 return URL_SCHEME_UNKNOWN; 00131 } 00132 00133 /************************************************************************* 00134 * @ [SHLWAPI.1] 00135 * 00136 * Parse a Url into its constituent parts. 00137 * 00138 * PARAMS 00139 * x [I] Url to parse 00140 * y [O] Undocumented structure holding the parsed information 00141 * 00142 * RETURNS 00143 * Success: S_OK. y contains the parsed Url details. 00144 * Failure: An HRESULT error code. 00145 */ 00146 HRESULT WINAPI ParseURLA(LPCSTR x, PARSEDURLA *y) 00147 { 00148 WCHAR scheme[INTERNET_MAX_SCHEME_LENGTH]; 00149 const char *ptr = x; 00150 int len; 00151 00152 TRACE("%s %p\n", debugstr_a(x), y); 00153 00154 if(y->cbSize != sizeof(*y)) 00155 return E_INVALIDARG; 00156 00157 while(*ptr && (isalnum(*ptr) || *ptr == '-')) 00158 ptr++; 00159 00160 if (*ptr != ':' || ptr <= x+1) { 00161 y->pszProtocol = NULL; 00162 return URL_E_INVALID_SYNTAX; 00163 } 00164 00165 y->pszProtocol = x; 00166 y->cchProtocol = ptr-x; 00167 y->pszSuffix = ptr+1; 00168 y->cchSuffix = strlen(y->pszSuffix); 00169 00170 len = MultiByteToWideChar(CP_ACP, 0, x, ptr-x, 00171 scheme, sizeof(scheme)/sizeof(WCHAR)); 00172 y->nScheme = get_scheme_code(scheme, len); 00173 00174 return S_OK; 00175 } 00176 00177 /************************************************************************* 00178 * @ [SHLWAPI.2] 00179 * 00180 * Unicode version of ParseURLA. 00181 */ 00182 HRESULT WINAPI ParseURLW(LPCWSTR x, PARSEDURLW *y) 00183 { 00184 const WCHAR *ptr = x; 00185 00186 TRACE("%s %p\n", debugstr_w(x), y); 00187 00188 if(y->cbSize != sizeof(*y)) 00189 return E_INVALIDARG; 00190 00191 while(*ptr && (isalnumW(*ptr) || *ptr == '-')) 00192 ptr++; 00193 00194 if (*ptr != ':' || ptr <= x+1) { 00195 y->pszProtocol = NULL; 00196 return URL_E_INVALID_SYNTAX; 00197 } 00198 00199 y->pszProtocol = x; 00200 y->cchProtocol = ptr-x; 00201 y->pszSuffix = ptr+1; 00202 y->cchSuffix = strlenW(y->pszSuffix); 00203 y->nScheme = get_scheme_code(x, ptr-x); 00204 00205 return S_OK; 00206 } 00207 00208 /************************************************************************* 00209 * UrlCanonicalizeA [SHLWAPI.@] 00210 * 00211 * Canonicalize a Url. 00212 * 00213 * PARAMS 00214 * pszUrl [I] Url to cCanonicalize 00215 * pszCanonicalized [O] Destination for converted Url. 00216 * pcchCanonicalized [I/O] Length of pszUrl, destination for length of pszCanonicalized 00217 * dwFlags [I] Flags controlling the conversion. 00218 * 00219 * RETURNS 00220 * Success: S_OK. The pszCanonicalized contains the converted Url. 00221 * Failure: E_POINTER, if *pcchCanonicalized is too small. 00222 * 00223 * MSDN incorrectly describes the flags for this function. They should be: 00224 *| URL_DONT_ESCAPE_EXTRA_INFO 0x02000000 00225 *| URL_ESCAPE_SPACES_ONLY 0x04000000 00226 *| URL_ESCAPE_PERCENT 0x00001000 00227 *| URL_ESCAPE_UNSAFE 0x10000000 00228 *| URL_UNESCAPE 0x10000000 00229 *| URL_DONT_SIMPLIFY 0x08000000 00230 *| URL_ESCAPE_SEGMENT_ONLY 0x00002000 00231 */ 00232 HRESULT WINAPI UrlCanonicalizeA(LPCSTR pszUrl, LPSTR pszCanonicalized, 00233 LPDWORD pcchCanonicalized, DWORD dwFlags) 00234 { 00235 LPWSTR url, canonical; 00236 HRESULT ret; 00237 DWORD len; 00238 00239 TRACE("(%s, %p, %p, 0x%08x) *pcchCanonicalized: %d\n", debugstr_a(pszUrl), pszCanonicalized, 00240 pcchCanonicalized, dwFlags, pcchCanonicalized ? *pcchCanonicalized : -1); 00241 00242 if(!pszUrl || !pszCanonicalized || !pcchCanonicalized || !*pcchCanonicalized) 00243 return E_INVALIDARG; 00244 00245 len = strlen(pszUrl)+1; 00246 url = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR)); 00247 canonical = HeapAlloc(GetProcessHeap(), 0, *pcchCanonicalized*sizeof(WCHAR)); 00248 if(!url || !canonical) { 00249 HeapFree(GetProcessHeap(), 0, url); 00250 HeapFree(GetProcessHeap(), 0, canonical); 00251 return E_OUTOFMEMORY; 00252 } 00253 00254 MultiByteToWideChar(0, 0, pszUrl, -1, url, len); 00255 00256 ret = UrlCanonicalizeW(url, canonical, pcchCanonicalized, dwFlags); 00257 if(ret == S_OK) 00258 WideCharToMultiByte(0, 0, canonical, -1, pszCanonicalized, 00259 *pcchCanonicalized+1, 0, 0); 00260 00261 HeapFree(GetProcessHeap(), 0, canonical); 00262 return ret; 00263 } 00264 00265 /************************************************************************* 00266 * UrlCanonicalizeW [SHLWAPI.@] 00267 * 00268 * See UrlCanonicalizeA. 00269 */ 00270 HRESULT WINAPI UrlCanonicalizeW(LPCWSTR pszUrl, LPWSTR pszCanonicalized, 00271 LPDWORD pcchCanonicalized, DWORD dwFlags) 00272 { 00273 HRESULT hr = S_OK; 00274 DWORD EscapeFlags; 00275 LPCWSTR wk1, root; 00276 LPWSTR lpszUrlCpy, wk2, mp, mp2; 00277 INT state; 00278 DWORD nByteLen, nLen, nWkLen; 00279 WCHAR slash = '\0'; 00280 00281 static const WCHAR wszFile[] = {'f','i','l','e',':'}; 00282 static const WCHAR wszRes[] = {'r','e','s',':'}; 00283 static const WCHAR wszHttp[] = {'h','t','t','p',':'}; 00284 static const WCHAR wszLocalhost[] = {'l','o','c','a','l','h','o','s','t'}; 00285 static const WCHAR wszFilePrefix[] = {'f','i','l','e',':','/','/','/'}; 00286 00287 TRACE("(%s, %p, %p, 0x%08x) *pcchCanonicalized: %d\n", debugstr_w(pszUrl), pszCanonicalized, 00288 pcchCanonicalized, dwFlags, pcchCanonicalized ? *pcchCanonicalized : -1); 00289 00290 if(!pszUrl || !pszCanonicalized || !pcchCanonicalized || !*pcchCanonicalized) 00291 return E_INVALIDARG; 00292 00293 if(!*pszUrl) { 00294 *pszCanonicalized = 0; 00295 return S_OK; 00296 } 00297 00298 nByteLen = (strlenW(pszUrl) + 1) * sizeof(WCHAR); /* length in bytes */ 00299 /* Allocate memory for simplified URL (before escaping) */ 00300 lpszUrlCpy = HeapAlloc(GetProcessHeap(), 0, 00301 nByteLen+sizeof(wszFilePrefix)+sizeof(WCHAR)); 00302 00303 if ((nByteLen >= sizeof(wszHttp) && 00304 !memcmp(wszHttp, pszUrl, sizeof(wszHttp))) || 00305 (nByteLen >= sizeof(wszFile) && 00306 !memcmp(wszFile, pszUrl, sizeof(wszFile)))) 00307 slash = '/'; 00308 00309 if((dwFlags & URL_FILE_USE_PATHURL) && nByteLen >= sizeof(wszFile) 00310 && !memcmp(wszFile, pszUrl, sizeof(wszFile))) 00311 slash = '\\'; 00312 00313 if(nByteLen >= sizeof(wszRes) && !memcmp(wszRes, pszUrl, sizeof(wszRes))) { 00314 dwFlags &= ~URL_FILE_USE_PATHURL; 00315 slash = '\0'; 00316 } 00317 00318 /* 00319 * state = 00320 * 0 initial 1,3 00321 * 1 have 2[+] alnum 2,3 00322 * 2 have scheme (found :) 4,6,3 00323 * 3 failed (no location) 00324 * 4 have // 5,3 00325 * 5 have 1[+] alnum 6,3 00326 * 6 have location (found /) save root location 00327 */ 00328 00329 wk1 = pszUrl; 00330 wk2 = lpszUrlCpy; 00331 state = 0; 00332 00333 if(pszUrl[1] == ':') { /* Assume path */ 00334 memcpy(wk2, wszFilePrefix, sizeof(wszFilePrefix)); 00335 wk2 += sizeof(wszFilePrefix)/sizeof(WCHAR); 00336 if (dwFlags & URL_FILE_USE_PATHURL) 00337 { 00338 slash = '\\'; 00339 --wk2; 00340 } 00341 else 00342 dwFlags |= URL_ESCAPE_UNSAFE; 00343 state = 5; 00344 } 00345 00346 while (*wk1) { 00347 switch (state) { 00348 case 0: 00349 if (!isalnumW(*wk1)) {state = 3; break;} 00350 *wk2++ = *wk1++; 00351 if (!isalnumW(*wk1)) {state = 3; break;} 00352 *wk2++ = *wk1++; 00353 state = 1; 00354 break; 00355 case 1: 00356 *wk2++ = *wk1; 00357 if (*wk1++ == ':') state = 2; 00358 break; 00359 case 2: 00360 *wk2++ = *wk1++; 00361 if (*wk1 != '/') {state = 6; break;} 00362 *wk2++ = *wk1++; 00363 if((dwFlags & URL_FILE_USE_PATHURL) && nByteLen >= sizeof(wszLocalhost) 00364 && !strncmpW(wszFile, pszUrl, sizeof(wszFile)/sizeof(WCHAR)) 00365 && !memcmp(wszLocalhost, wk1, sizeof(wszLocalhost))){ 00366 wk1 += sizeof(wszLocalhost)/sizeof(WCHAR); 00367 while(*wk1 == '\\' && (dwFlags & URL_FILE_USE_PATHURL)) 00368 wk1++; 00369 } 00370 if(*wk1 == '/' && (dwFlags & URL_FILE_USE_PATHURL)) 00371 wk1++; 00372 state = 4; 00373 break; 00374 case 3: 00375 nWkLen = strlenW(wk1); 00376 memcpy(wk2, wk1, (nWkLen + 1) * sizeof(WCHAR)); 00377 mp = wk2; 00378 wk1 += nWkLen; 00379 wk2 += nWkLen; 00380 00381 if(slash) { 00382 while(mp < wk2) { 00383 if(*mp == '/' || *mp == '\\') 00384 *mp = slash; 00385 mp++; 00386 } 00387 } 00388 break; 00389 case 4: 00390 if (!isalnumW(*wk1) && (*wk1 != '-') && (*wk1 != '.') && (*wk1 != ':')) 00391 {state = 3; break;} 00392 while(isalnumW(*wk1) || (*wk1 == '-') || (*wk1 == '.') || (*wk1 == ':')) 00393 *wk2++ = *wk1++; 00394 state = 5; 00395 if (!*wk1) { 00396 if(slash) 00397 *wk2++ = slash; 00398 else 00399 *wk2++ = '/'; 00400 } 00401 break; 00402 case 5: 00403 if (*wk1 != '/' && *wk1 != '\\') {state = 3; break;} 00404 while(*wk1 == '/' || *wk1 == '\\') { 00405 if(slash) 00406 *wk2++ = slash; 00407 else 00408 *wk2++ = *wk1; 00409 wk1++; 00410 } 00411 state = 6; 00412 break; 00413 case 6: 00414 if(dwFlags & URL_DONT_SIMPLIFY) { 00415 state = 3; 00416 break; 00417 } 00418 00419 /* Now at root location, cannot back up any more. */ 00420 /* "root" will point at the '/' */ 00421 00422 root = wk2-1; 00423 while (*wk1) { 00424 mp = strchrW(wk1, '/'); 00425 mp2 = strchrW(wk1, '\\'); 00426 if(mp2 && (!mp || mp2 < mp)) 00427 mp = mp2; 00428 if (!mp) { 00429 nWkLen = strlenW(wk1); 00430 memcpy(wk2, wk1, (nWkLen + 1) * sizeof(WCHAR)); 00431 wk1 += nWkLen; 00432 wk2 += nWkLen; 00433 continue; 00434 } 00435 nLen = mp - wk1; 00436 if(nLen) { 00437 memcpy(wk2, wk1, nLen * sizeof(WCHAR)); 00438 wk2 += nLen; 00439 wk1 += nLen; 00440 } 00441 if(slash) 00442 *wk2++ = slash; 00443 else 00444 *wk2++ = *wk1; 00445 wk1++; 00446 00447 while (*wk1 == '.') { 00448 TRACE("found '/.'\n"); 00449 if (wk1[1] == '/' || wk1[1] == '\\') { 00450 /* case of /./ -> skip the ./ */ 00451 wk1 += 2; 00452 } 00453 else if (wk1[1] == '.' && (wk1[2] == '/' 00454 || wk1[2] == '\\' || wk1[2] == '?' 00455 || wk1[2] == '#' || !wk1[2])) { 00456 /* case /../ -> need to backup wk2 */ 00457 TRACE("found '/../'\n"); 00458 *(wk2-1) = '\0'; /* set end of string */ 00459 mp = strrchrW(root, '/'); 00460 mp2 = strrchrW(root, '\\'); 00461 if(mp2 && (!mp || mp2 < mp)) 00462 mp = mp2; 00463 if (mp && (mp >= root)) { 00464 /* found valid backup point */ 00465 wk2 = mp + 1; 00466 if(wk1[2] != '/' && wk1[2] != '\\') 00467 wk1 += 2; 00468 else 00469 wk1 += 3; 00470 } 00471 else { 00472 /* did not find point, restore '/' */ 00473 *(wk2-1) = slash; 00474 break; 00475 } 00476 } 00477 else 00478 break; 00479 } 00480 } 00481 *wk2 = '\0'; 00482 break; 00483 default: 00484 FIXME("how did we get here - state=%d\n", state); 00485 HeapFree(GetProcessHeap(), 0, lpszUrlCpy); 00486 return E_INVALIDARG; 00487 } 00488 *wk2 = '\0'; 00489 TRACE("Simplified, orig <%s>, simple <%s>\n", 00490 debugstr_w(pszUrl), debugstr_w(lpszUrlCpy)); 00491 } 00492 nLen = lstrlenW(lpszUrlCpy); 00493 while ((nLen > 0) && ((lpszUrlCpy[nLen-1] <= ' '))) 00494 lpszUrlCpy[--nLen]=0; 00495 00496 if((dwFlags & URL_UNESCAPE) || 00497 ((dwFlags & URL_FILE_USE_PATHURL) && nByteLen >= sizeof(wszFile) 00498 && !memcmp(wszFile, pszUrl, sizeof(wszFile)))) 00499 UrlUnescapeW(lpszUrlCpy, NULL, &nLen, URL_UNESCAPE_INPLACE); 00500 00501 if((EscapeFlags = dwFlags & (URL_ESCAPE_UNSAFE | 00502 URL_ESCAPE_SPACES_ONLY | 00503 URL_ESCAPE_PERCENT | 00504 URL_DONT_ESCAPE_EXTRA_INFO | 00505 URL_ESCAPE_SEGMENT_ONLY ))) { 00506 EscapeFlags &= ~URL_ESCAPE_UNSAFE; 00507 hr = UrlEscapeW(lpszUrlCpy, pszCanonicalized, pcchCanonicalized, 00508 EscapeFlags); 00509 } else { /* No escaping needed, just copy the string */ 00510 nLen = lstrlenW(lpszUrlCpy); 00511 if(nLen < *pcchCanonicalized) 00512 memcpy(pszCanonicalized, lpszUrlCpy, (nLen + 1)*sizeof(WCHAR)); 00513 else { 00514 hr = E_POINTER; 00515 nLen++; 00516 } 00517 *pcchCanonicalized = nLen; 00518 } 00519 00520 HeapFree(GetProcessHeap(), 0, lpszUrlCpy); 00521 00522 if (hr == S_OK) 00523 TRACE("result %s\n", debugstr_w(pszCanonicalized)); 00524 00525 return hr; 00526 } 00527 00528 /************************************************************************* 00529 * UrlCombineA [SHLWAPI.@] 00530 * 00531 * Combine two Urls. 00532 * 00533 * PARAMS 00534 * pszBase [I] Base Url 00535 * pszRelative [I] Url to combine with pszBase 00536 * pszCombined [O] Destination for combined Url 00537 * pcchCombined [O] Destination for length of pszCombined 00538 * dwFlags [I] URL_ flags from "shlwapi.h" 00539 * 00540 * RETURNS 00541 * Success: S_OK. pszCombined contains the combined Url, pcchCombined 00542 * contains its length. 00543 * Failure: An HRESULT error code indicating the error. 00544 */ 00545 HRESULT WINAPI UrlCombineA(LPCSTR pszBase, LPCSTR pszRelative, 00546 LPSTR pszCombined, LPDWORD pcchCombined, 00547 DWORD dwFlags) 00548 { 00549 LPWSTR base, relative, combined; 00550 DWORD ret, len, len2; 00551 00552 TRACE("(base %s, Relative %s, Combine size %d, flags %08x) using W version\n", 00553 debugstr_a(pszBase),debugstr_a(pszRelative), 00554 pcchCombined?*pcchCombined:0,dwFlags); 00555 00556 if(!pszBase || !pszRelative || !pcchCombined) 00557 return E_INVALIDARG; 00558 00559 base = HeapAlloc(GetProcessHeap(), 0, 00560 (3*INTERNET_MAX_URL_LENGTH) * sizeof(WCHAR)); 00561 relative = base + INTERNET_MAX_URL_LENGTH; 00562 combined = relative + INTERNET_MAX_URL_LENGTH; 00563 00564 MultiByteToWideChar(0, 0, pszBase, -1, base, INTERNET_MAX_URL_LENGTH); 00565 MultiByteToWideChar(0, 0, pszRelative, -1, relative, INTERNET_MAX_URL_LENGTH); 00566 len = *pcchCombined; 00567 00568 ret = UrlCombineW(base, relative, pszCombined?combined:NULL, &len, dwFlags); 00569 if (ret != S_OK) { 00570 *pcchCombined = len; 00571 HeapFree(GetProcessHeap(), 0, base); 00572 return ret; 00573 } 00574 00575 len2 = WideCharToMultiByte(0, 0, combined, len, 0, 0, 0, 0); 00576 if (len2 > *pcchCombined) { 00577 *pcchCombined = len2; 00578 HeapFree(GetProcessHeap(), 0, base); 00579 return E_POINTER; 00580 } 00581 WideCharToMultiByte(0, 0, combined, len+1, pszCombined, (*pcchCombined)+1, 00582 0, 0); 00583 *pcchCombined = len2; 00584 HeapFree(GetProcessHeap(), 0, base); 00585 return S_OK; 00586 } 00587 00588 /************************************************************************* 00589 * UrlCombineW [SHLWAPI.@] 00590 * 00591 * See UrlCombineA. 00592 */ 00593 HRESULT WINAPI UrlCombineW(LPCWSTR pszBase, LPCWSTR pszRelative, 00594 LPWSTR pszCombined, LPDWORD pcchCombined, 00595 DWORD dwFlags) 00596 { 00597 PARSEDURLW base, relative; 00598 DWORD myflags, sizeloc = 0; 00599 DWORD len, res1, res2, process_case = 0; 00600 LPWSTR work, preliminary, mbase, mrelative; 00601 static const WCHAR myfilestr[] = {'f','i','l','e',':','/','/','/','\0'}; 00602 HRESULT ret; 00603 00604 TRACE("(base %s, Relative %s, Combine size %d, flags %08x)\n", 00605 debugstr_w(pszBase),debugstr_w(pszRelative), 00606 pcchCombined?*pcchCombined:0,dwFlags); 00607 00608 if(!pszBase || !pszRelative || !pcchCombined) 00609 return E_INVALIDARG; 00610 00611 base.cbSize = sizeof(base); 00612 relative.cbSize = sizeof(relative); 00613 00614 /* Get space for duplicates of the input and the output */ 00615 preliminary = HeapAlloc(GetProcessHeap(), 0, (3*INTERNET_MAX_URL_LENGTH) * 00616 sizeof(WCHAR)); 00617 mbase = preliminary + INTERNET_MAX_URL_LENGTH; 00618 mrelative = mbase + INTERNET_MAX_URL_LENGTH; 00619 *preliminary = '\0'; 00620 00621 /* Canonicalize the base input prior to looking for the scheme */ 00622 myflags = dwFlags & (URL_DONT_SIMPLIFY | URL_UNESCAPE); 00623 len = INTERNET_MAX_URL_LENGTH; 00624 ret = UrlCanonicalizeW(pszBase, mbase, &len, myflags); 00625 00626 /* Canonicalize the relative input prior to looking for the scheme */ 00627 len = INTERNET_MAX_URL_LENGTH; 00628 ret = UrlCanonicalizeW(pszRelative, mrelative, &len, myflags); 00629 00630 /* See if the base has a scheme */ 00631 res1 = ParseURLW(mbase, &base); 00632 if (res1) { 00633 /* if pszBase has no scheme, then return pszRelative */ 00634 TRACE("no scheme detected in Base\n"); 00635 process_case = 1; 00636 } 00637 else do { 00638 BOOL manual_search = FALSE; 00639 00640 /* mk is a special case */ 00641 if(base.nScheme == URL_SCHEME_MK) { 00642 static const WCHAR wsz[] = {':',':',0}; 00643 00644 WCHAR *ptr = strstrW(base.pszSuffix, wsz); 00645 if(ptr) { 00646 int delta; 00647 00648 ptr += 2; 00649 delta = ptr-base.pszSuffix; 00650 base.cchProtocol += delta; 00651 base.pszSuffix += delta; 00652 base.cchSuffix -= delta; 00653 } 00654 }else { 00655 /* get size of location field (if it exists) */ 00656 work = (LPWSTR)base.pszSuffix; 00657 sizeloc = 0; 00658 if (*work++ == '/') { 00659 if (*work++ == '/') { 00660 /* At this point have start of location and 00661 * it ends at next '/' or end of string. 00662 */ 00663 while(*work && (*work != '/')) work++; 00664 sizeloc = (DWORD)(work - base.pszSuffix); 00665 } 00666 } 00667 } 00668 00669 /* If there is a '#' and the characters immediately preceding it are 00670 * ".htm[l]", then begin looking for the last leaf starting from 00671 * the '#'. Otherwise the '#' is not meaningful and just start 00672 * looking from the end. */ 00673 if ((work = strchrW(base.pszSuffix + sizeloc, '#'))) { 00674 const WCHAR htmlW[] = {'.','h','t','m','l',0}; 00675 const int len_htmlW = 5; 00676 const WCHAR htmW[] = {'.','h','t','m',0}; 00677 const int len_htmW = 4; 00678 00679 if (work - base.pszSuffix > len_htmW * sizeof(WCHAR)) { 00680 work -= len_htmW; 00681 if (strncmpiW(work, htmW, len_htmW) == 0) 00682 manual_search = TRUE; 00683 work += len_htmW; 00684 } 00685 00686 if (!manual_search && 00687 work - base.pszSuffix > len_htmlW * sizeof(WCHAR)) { 00688 work -= len_htmlW; 00689 if (strncmpiW(work, htmlW, len_htmlW) == 0) 00690 manual_search = TRUE; 00691 work += len_htmlW; 00692 } 00693 } 00694 00695 if (manual_search) { 00696 /* search backwards starting from the current position */ 00697 while (*work != '/' && work > base.pszSuffix + sizeloc) 00698 --work; 00699 if (work > base.pszSuffix + sizeloc) 00700 base.cchSuffix = work - base.pszSuffix + 1; 00701 }else { 00702 /* search backwards starting from the end of the string */ 00703 work = strrchrW((base.pszSuffix+sizeloc), '/'); 00704 if (work) { 00705 len = (DWORD)(work - base.pszSuffix + 1); 00706 base.cchSuffix = len; 00707 } 00708 } 00709 00710 /* 00711 * At this point: 00712 * .pszSuffix points to location (starting with '//') 00713 * .cchSuffix length of location (above) and rest less the last 00714 * leaf (if any) 00715 * sizeloc length of location (above) up to but not including 00716 * the last '/' 00717 */ 00718 00719 res2 = ParseURLW(mrelative, &relative); 00720 if (res2) { 00721 /* no scheme in pszRelative */ 00722 TRACE("no scheme detected in Relative\n"); 00723 relative.pszSuffix = mrelative; /* case 3,4,5 depends on this */ 00724 relative.cchSuffix = strlenW(mrelative); 00725 if (*pszRelative == ':') { 00726 /* case that is either left alone or uses pszBase */ 00727 if (dwFlags & URL_PLUGGABLE_PROTOCOL) { 00728 process_case = 5; 00729 break; 00730 } 00731 process_case = 1; 00732 break; 00733 } 00734 if (isalnum(*mrelative) && (*(mrelative + 1) == ':')) { 00735 /* case that becomes "file:///" */ 00736 strcpyW(preliminary, myfilestr); 00737 process_case = 1; 00738 break; 00739 } 00740 if ((*mrelative == '/') && (*(mrelative+1) == '/')) { 00741 /* pszRelative has location and rest */ 00742 process_case = 3; 00743 break; 00744 } 00745 if (*mrelative == '/') { 00746 /* case where pszRelative is root to location */ 00747 process_case = 4; 00748 break; 00749 } 00750 process_case = (*base.pszSuffix == '/' || base.nScheme == URL_SCHEME_MK) ? 5 : 3; 00751 break; 00752 } 00753 00754 /* handle cases where pszRelative has scheme */ 00755 if ((base.cchProtocol == relative.cchProtocol) && 00756 (strncmpW(base.pszProtocol, relative.pszProtocol, base.cchProtocol) == 0)) { 00757 00758 /* since the schemes are the same */ 00759 if ((*relative.pszSuffix == '/') && (*(relative.pszSuffix+1) == '/')) { 00760 /* case where pszRelative replaces location and following */ 00761 process_case = 3; 00762 break; 00763 } 00764 if (*relative.pszSuffix == '/') { 00765 /* case where pszRelative is root to location */ 00766 process_case = 4; 00767 break; 00768 } 00769 /* replace either just location if base's location starts with a 00770 * slash or otherwise everything */ 00771 process_case = (*base.pszSuffix == '/') ? 5 : 1; 00772 break; 00773 } 00774 if ((*relative.pszSuffix == '/') && (*(relative.pszSuffix+1) == '/')) { 00775 /* case where pszRelative replaces scheme, location, 00776 * and following and handles PLUGGABLE 00777 */ 00778 process_case = 2; 00779 break; 00780 } 00781 process_case = 1; 00782 break; 00783 } while(FALSE); /* a little trick to allow easy exit from nested if's */ 00784 00785 ret = S_OK; 00786 switch (process_case) { 00787 00788 case 1: /* 00789 * Return pszRelative appended to what ever is in pszCombined, 00790 * (which may the string "file:///" 00791 */ 00792 strcatW(preliminary, mrelative); 00793 break; 00794 00795 case 2: /* case where pszRelative replaces scheme, and location */ 00796 strcpyW(preliminary, mrelative); 00797 break; 00798 00799 case 3: /* 00800 * Return the pszBase scheme with pszRelative. Basically 00801 * keeps the scheme and replaces the domain and following. 00802 */ 00803 memcpy(preliminary, base.pszProtocol, (base.cchProtocol + 1)*sizeof(WCHAR)); 00804 work = preliminary + base.cchProtocol + 1; 00805 strcpyW(work, relative.pszSuffix); 00806 break; 00807 00808 case 4: /* 00809 * Return the pszBase scheme and location but everything 00810 * after the location is pszRelative. (Replace document 00811 * from root on.) 00812 */ 00813 memcpy(preliminary, base.pszProtocol, (base.cchProtocol+1+sizeloc)*sizeof(WCHAR)); 00814 work = preliminary + base.cchProtocol + 1 + sizeloc; 00815 if (dwFlags & URL_PLUGGABLE_PROTOCOL) 00816 *(work++) = '/'; 00817 strcpyW(work, relative.pszSuffix); 00818 break; 00819 00820 case 5: /* 00821 * Return the pszBase without its document (if any) and 00822 * append pszRelative after its scheme. 00823 */ 00824 memcpy(preliminary, base.pszProtocol, 00825 (base.cchProtocol+1+base.cchSuffix)*sizeof(WCHAR)); 00826 work = preliminary + base.cchProtocol+1+base.cchSuffix - 1; 00827 if (*work++ != '/') 00828 *(work++) = '/'; 00829 strcpyW(work, relative.pszSuffix); 00830 break; 00831 00832 default: 00833 FIXME("How did we get here????? process_case=%d\n", process_case); 00834 ret = E_INVALIDARG; 00835 } 00836 00837 if (ret == S_OK) { 00838 /* Reuse mrelative as temp storage as its already allocated and not needed anymore */ 00839 if(*pcchCombined == 0) 00840 *pcchCombined = 1; 00841 ret = UrlCanonicalizeW(preliminary, mrelative, pcchCombined, (dwFlags & ~URL_FILE_USE_PATHURL)); 00842 if(SUCCEEDED(ret) && pszCombined) { 00843 lstrcpyW(pszCombined, mrelative); 00844 } 00845 TRACE("return-%d len=%d, %s\n", 00846 process_case, *pcchCombined, debugstr_w(pszCombined)); 00847 } 00848 HeapFree(GetProcessHeap(), 0, preliminary); 00849 return ret; 00850 } 00851 00852 /************************************************************************* 00853 * UrlEscapeA [SHLWAPI.@] 00854 */ 00855 00856 HRESULT WINAPI UrlEscapeA( 00857 LPCSTR pszUrl, 00858 LPSTR pszEscaped, 00859 LPDWORD pcchEscaped, 00860 DWORD dwFlags) 00861 { 00862 WCHAR bufW[INTERNET_MAX_URL_LENGTH]; 00863 WCHAR *escapedW = bufW; 00864 UNICODE_STRING urlW; 00865 HRESULT ret; 00866 DWORD lenW = sizeof(bufW)/sizeof(WCHAR), lenA; 00867 00868 if (!pszEscaped || !pcchEscaped || !*pcchEscaped) 00869 return E_INVALIDARG; 00870 00871 if(!RtlCreateUnicodeStringFromAsciiz(&urlW, pszUrl)) 00872 return E_INVALIDARG; 00873 if((ret = UrlEscapeW(urlW.Buffer, escapedW, &lenW, dwFlags)) == E_POINTER) { 00874 escapedW = HeapAlloc(GetProcessHeap(), 0, lenW * sizeof(WCHAR)); 00875 ret = UrlEscapeW(urlW.Buffer, escapedW, &lenW, dwFlags); 00876 } 00877 if(ret == S_OK) { 00878 RtlUnicodeToMultiByteSize(&lenA, escapedW, lenW * sizeof(WCHAR)); 00879 if(*pcchEscaped > lenA) { 00880 RtlUnicodeToMultiByteN(pszEscaped, *pcchEscaped - 1, &lenA, escapedW, lenW * sizeof(WCHAR)); 00881 pszEscaped[lenA] = 0; 00882 *pcchEscaped = lenA; 00883 } else { 00884 *pcchEscaped = lenA + 1; 00885 ret = E_POINTER; 00886 } 00887 } 00888 if(escapedW != bufW) HeapFree(GetProcessHeap(), 0, escapedW); 00889 RtlFreeUnicodeString(&urlW); 00890 return ret; 00891 } 00892 00893 #define WINE_URL_BASH_AS_SLASH 0x01 00894 #define WINE_URL_COLLAPSE_SLASHES 0x02 00895 #define WINE_URL_ESCAPE_SLASH 0x04 00896 #define WINE_URL_ESCAPE_HASH 0x08 00897 #define WINE_URL_ESCAPE_QUESTION 0x10 00898 #define WINE_URL_STOP_ON_HASH 0x20 00899 #define WINE_URL_STOP_ON_QUESTION 0x40 00900 00901 static inline BOOL URL_NeedEscapeW(WCHAR ch, DWORD dwFlags, DWORD int_flags) 00902 { 00903 00904 if (isalnumW(ch)) 00905 return FALSE; 00906 00907 if(dwFlags & URL_ESCAPE_SPACES_ONLY) { 00908 if(ch == ' ') 00909 return TRUE; 00910 else 00911 return FALSE; 00912 } 00913 00914 if ((dwFlags & URL_ESCAPE_PERCENT) && (ch == '%')) 00915 return TRUE; 00916 00917 if (ch <= 31 || ch >= 127) 00918 return TRUE; 00919 00920 else { 00921 switch (ch) { 00922 case ' ': 00923 case '<': 00924 case '>': 00925 case '\"': 00926 case '{': 00927 case '}': 00928 case '|': 00929 case '\\': 00930 case '^': 00931 case ']': 00932 case '[': 00933 case '`': 00934 case '&': 00935 return TRUE; 00936 00937 case '/': 00938 if (int_flags & WINE_URL_ESCAPE_SLASH) return TRUE; 00939 return FALSE; 00940 00941 case '?': 00942 if (int_flags & WINE_URL_ESCAPE_QUESTION) return TRUE; 00943 return FALSE; 00944 00945 case '#': 00946 if (int_flags & WINE_URL_ESCAPE_HASH) return TRUE; 00947 return FALSE; 00948 00949 default: 00950 return FALSE; 00951 } 00952 } 00953 } 00954 00955 00956 /************************************************************************* 00957 * UrlEscapeW [SHLWAPI.@] 00958 * 00959 * Converts unsafe characters in a Url into escape sequences. 00960 * 00961 * PARAMS 00962 * pszUrl [I] Url to modify 00963 * pszEscaped [O] Destination for modified Url 00964 * pcchEscaped [I/O] Length of pszUrl, destination for length of pszEscaped 00965 * dwFlags [I] URL_ flags from "shlwapi.h" 00966 * 00967 * RETURNS 00968 * Success: S_OK. pszEscaped contains the escaped Url, pcchEscaped 00969 * contains its length. 00970 * Failure: E_POINTER, if pszEscaped is not large enough. In this case 00971 * pcchEscaped is set to the required length. 00972 * 00973 * Converts unsafe characters into their escape sequences. 00974 * 00975 * NOTES 00976 * - By default this function stops converting at the first '?' or 00977 * '#' character. 00978 * - If dwFlags contains URL_ESCAPE_SPACES_ONLY then only spaces are 00979 * converted, but the conversion continues past a '?' or '#'. 00980 * - Note that this function did not work well (or at all) in shlwapi version 4. 00981 * 00982 * BUGS 00983 * Only the following flags are implemented: 00984 *| URL_ESCAPE_SPACES_ONLY 00985 *| URL_DONT_ESCAPE_EXTRA_INFO 00986 *| URL_ESCAPE_SEGMENT_ONLY 00987 *| URL_ESCAPE_PERCENT 00988 */ 00989 HRESULT WINAPI UrlEscapeW( 00990 LPCWSTR pszUrl, 00991 LPWSTR pszEscaped, 00992 LPDWORD pcchEscaped, 00993 DWORD dwFlags) 00994 { 00995 LPCWSTR src; 00996 DWORD needed = 0, ret; 00997 BOOL stop_escaping = FALSE; 00998 WCHAR next[5], *dst = pszEscaped; 00999 INT len; 01000 PARSEDURLW parsed_url; 01001 DWORD int_flags; 01002 DWORD slashes = 0; 01003 static const WCHAR localhost[] = {'l','o','c','a','l','h','o','s','t',0}; 01004 01005 TRACE("(%s %p %p 0x%08x)\n", debugstr_w(pszUrl), pszEscaped, 01006 pcchEscaped, dwFlags); 01007 01008 if(!pszUrl || !pcchEscaped) 01009 return E_INVALIDARG; 01010 01011 if(dwFlags & ~(URL_ESCAPE_SPACES_ONLY | 01012 URL_ESCAPE_SEGMENT_ONLY | 01013 URL_DONT_ESCAPE_EXTRA_INFO | 01014 URL_ESCAPE_PERCENT)) 01015 FIXME("Unimplemented flags: %08x\n", dwFlags); 01016 01017 /* fix up flags */ 01018 if (dwFlags & URL_ESCAPE_SPACES_ONLY) 01019 /* if SPACES_ONLY specified, reset the other controls */ 01020 dwFlags &= ~(URL_DONT_ESCAPE_EXTRA_INFO | 01021 URL_ESCAPE_PERCENT | 01022 URL_ESCAPE_SEGMENT_ONLY); 01023 01024 else 01025 /* if SPACES_ONLY *not* specified the assume DONT_ESCAPE_EXTRA_INFO */ 01026 dwFlags |= URL_DONT_ESCAPE_EXTRA_INFO; 01027 01028 01029 int_flags = 0; 01030 if(dwFlags & URL_ESCAPE_SEGMENT_ONLY) { 01031 int_flags = WINE_URL_ESCAPE_QUESTION | WINE_URL_ESCAPE_HASH | WINE_URL_ESCAPE_SLASH; 01032 } else { 01033 parsed_url.cbSize = sizeof(parsed_url); 01034 if(ParseURLW(pszUrl, &parsed_url) != S_OK) 01035 parsed_url.nScheme = URL_SCHEME_INVALID; 01036 01037 TRACE("scheme = %d (%s)\n", parsed_url.nScheme, debugstr_wn(parsed_url.pszProtocol, parsed_url.cchProtocol)); 01038 01039 if(dwFlags & URL_DONT_ESCAPE_EXTRA_INFO) 01040 int_flags = WINE_URL_STOP_ON_HASH | WINE_URL_STOP_ON_QUESTION; 01041 01042 switch(parsed_url.nScheme) { 01043 case URL_SCHEME_FILE: 01044 int_flags |= WINE_URL_BASH_AS_SLASH | WINE_URL_COLLAPSE_SLASHES | WINE_URL_ESCAPE_HASH; 01045 int_flags &= ~WINE_URL_STOP_ON_HASH; 01046 break; 01047 01048 case URL_SCHEME_HTTP: 01049 case URL_SCHEME_HTTPS: 01050 int_flags |= WINE_URL_BASH_AS_SLASH; 01051 if(parsed_url.pszSuffix[0] != '/' && parsed_url.pszSuffix[0] != '\\') 01052 int_flags |= WINE_URL_ESCAPE_SLASH; 01053 break; 01054 01055 case URL_SCHEME_MAILTO: 01056 int_flags |= WINE_URL_ESCAPE_SLASH | WINE_URL_ESCAPE_QUESTION | WINE_URL_ESCAPE_HASH; 01057 int_flags &= ~(WINE_URL_STOP_ON_QUESTION | WINE_URL_STOP_ON_HASH); 01058 break; 01059 01060 case URL_SCHEME_INVALID: 01061 break; 01062 01063 case URL_SCHEME_FTP: 01064 default: 01065 if(parsed_url.pszSuffix[0] != '/') 01066 int_flags |= WINE_URL_ESCAPE_SLASH; 01067 break; 01068 } 01069 } 01070 01071 for(src = pszUrl; *src; ) { 01072 WCHAR cur = *src; 01073 len = 0; 01074 01075 if((int_flags & WINE_URL_COLLAPSE_SLASHES) && src == pszUrl + parsed_url.cchProtocol + 1) { 01076 int localhost_len = sizeof(localhost)/sizeof(WCHAR) - 1; 01077 while(cur == '/' || cur == '\\') { 01078 slashes++; 01079 cur = *++src; 01080 } 01081 if(slashes == 2 && !strncmpiW(src, localhost, localhost_len)) { /* file://localhost/ -> file:/// */ 01082 if(*(src + localhost_len) == '/' || *(src + localhost_len) == '\\') 01083 src += localhost_len + 1; 01084 slashes = 3; 01085 } 01086 01087 switch(slashes) { 01088 case 1: 01089 case 3: 01090 next[0] = next[1] = next[2] = '/'; 01091 len = 3; 01092 break; 01093 case 0: 01094 len = 0; 01095 break; 01096 default: 01097 next[0] = next[1] = '/'; 01098 len = 2; 01099 break; 01100 } 01101 } 01102 if(len == 0) { 01103 01104 if(cur == '#' && (int_flags & WINE_URL_STOP_ON_HASH)) 01105 stop_escaping = TRUE; 01106 01107 if(cur == '?' && (int_flags & WINE_URL_STOP_ON_QUESTION)) 01108 stop_escaping = TRUE; 01109 01110 if(cur == '\\' && (int_flags & WINE_URL_BASH_AS_SLASH) && !stop_escaping) cur = '/'; 01111 01112 if(URL_NeedEscapeW(cur, dwFlags, int_flags) && stop_escaping == FALSE) { 01113 next[0] = '%'; 01114 next[1] = hexDigits[(cur >> 4) & 0xf]; 01115 next[2] = hexDigits[cur & 0xf]; 01116 len = 3; 01117 } else { 01118 next[0] = cur; 01119 len = 1; 01120 } 01121 src++; 01122 } 01123 01124 if(needed + len <= *pcchEscaped) { 01125 memcpy(dst, next, len*sizeof(WCHAR)); 01126 dst += len; 01127 } 01128 needed += len; 01129 } 01130 01131 if(needed < *pcchEscaped) { 01132 *dst = '\0'; 01133 ret = S_OK; 01134 } else { 01135 needed++; /* add one for the '\0' */ 01136 ret = E_POINTER; 01137 } 01138 *pcchEscaped = needed; 01139 return ret; 01140 } 01141 01142 01143 /************************************************************************* 01144 * UrlUnescapeA [SHLWAPI.@] 01145 * 01146 * Converts Url escape sequences back to ordinary characters. 01147 * 01148 * PARAMS 01149 * pszUrl [I/O] Url to convert 01150 * pszUnescaped [O] Destination for converted Url 01151 * pcchUnescaped [I/O] Size of output string 01152 * dwFlags [I] URL_ESCAPE_ Flags from "shlwapi.h" 01153 * 01154 * RETURNS 01155 * Success: S_OK. The converted value is in pszUnescaped, or in pszUrl if 01156 * dwFlags includes URL_ESCAPE_INPLACE. 01157 * Failure: E_POINTER if the converted Url is bigger than pcchUnescaped. In 01158 * this case pcchUnescaped is set to the size required. 01159 * NOTES 01160 * If dwFlags includes URL_DONT_ESCAPE_EXTRA_INFO, the conversion stops at 01161 * the first occurrence of either a '?' or '#' character. 01162 */ 01163 HRESULT WINAPI UrlUnescapeA( 01164 LPSTR pszUrl, 01165 LPSTR pszUnescaped, 01166 LPDWORD pcchUnescaped, 01167 DWORD dwFlags) 01168 { 01169 char *dst, next; 01170 LPCSTR src; 01171 HRESULT ret; 01172 DWORD needed; 01173 BOOL stop_unescaping = FALSE; 01174 01175 TRACE("(%s, %p, %p, 0x%08x)\n", debugstr_a(pszUrl), pszUnescaped, 01176 pcchUnescaped, dwFlags); 01177 01178 if (!pszUrl) return E_INVALIDARG; 01179 01180 if(dwFlags & URL_UNESCAPE_INPLACE) 01181 dst = pszUrl; 01182 else 01183 { 01184 if (!pszUnescaped || !pcchUnescaped) return E_INVALIDARG; 01185 dst = pszUnescaped; 01186 } 01187 01188 for(src = pszUrl, needed = 0; *src; src++, needed++) { 01189 if(dwFlags & URL_DONT_UNESCAPE_EXTRA_INFO && 01190 (*src == '#' || *src == '?')) { 01191 stop_unescaping = TRUE; 01192 next = *src; 01193 } else if(*src == '%' && isxdigit(*(src + 1)) && isxdigit(*(src + 2)) 01194 && stop_unescaping == FALSE) { 01195 INT ih; 01196 char buf[3]; 01197 memcpy(buf, src + 1, 2); 01198 buf[2] = '\0'; 01199 ih = strtol(buf, NULL, 16); 01200 next = (CHAR) ih; 01201 src += 2; /* Advance to end of escape */ 01202 } else 01203 next = *src; 01204 01205 if(dwFlags & URL_UNESCAPE_INPLACE || needed < *pcchUnescaped) 01206 *dst++ = next; 01207 } 01208 01209 if(dwFlags & URL_UNESCAPE_INPLACE || needed < *pcchUnescaped) { 01210 *dst = '\0'; 01211 ret = S_OK; 01212 } else { 01213 needed++; /* add one for the '\0' */ 01214 ret = E_POINTER; 01215 } 01216 if(!(dwFlags & URL_UNESCAPE_INPLACE)) 01217 *pcchUnescaped = needed; 01218 01219 if (ret == S_OK) { 01220 TRACE("result %s\n", (dwFlags & URL_UNESCAPE_INPLACE) ? 01221 debugstr_a(pszUrl) : debugstr_a(pszUnescaped)); 01222 } 01223 01224 return ret; 01225 } 01226 01227 /************************************************************************* 01228 * UrlUnescapeW [SHLWAPI.@] 01229 * 01230 * See UrlUnescapeA. 01231 */ 01232 HRESULT WINAPI UrlUnescapeW( 01233 LPWSTR pszUrl, 01234 LPWSTR pszUnescaped, 01235 LPDWORD pcchUnescaped, 01236 DWORD dwFlags) 01237 { 01238 WCHAR *dst, next; 01239 LPCWSTR src; 01240 HRESULT ret; 01241 DWORD needed; 01242 BOOL stop_unescaping = FALSE; 01243 01244 TRACE("(%s, %p, %p, 0x%08x)\n", debugstr_w(pszUrl), pszUnescaped, 01245 pcchUnescaped, dwFlags); 01246 01247 if(!pszUrl) return E_INVALIDARG; 01248 01249 if(dwFlags & URL_UNESCAPE_INPLACE) 01250 dst = pszUrl; 01251 else 01252 { 01253 if (!pszUnescaped || !pcchUnescaped) return E_INVALIDARG; 01254 dst = pszUnescaped; 01255 } 01256 01257 for(src = pszUrl, needed = 0; *src; src++, needed++) { 01258 if(dwFlags & URL_DONT_UNESCAPE_EXTRA_INFO && 01259 (*src == '#' || *src == '?')) { 01260 stop_unescaping = TRUE; 01261 next = *src; 01262 } else if(*src == '%' && isxdigitW(*(src + 1)) && isxdigitW(*(src + 2)) 01263 && stop_unescaping == FALSE) { 01264 INT ih; 01265 WCHAR buf[5] = {'0','x',0}; 01266 memcpy(buf + 2, src + 1, 2*sizeof(WCHAR)); 01267 buf[4] = 0; 01268 StrToIntExW(buf, STIF_SUPPORT_HEX, &ih); 01269 next = (WCHAR) ih; 01270 src += 2; /* Advance to end of escape */ 01271 } else 01272 next = *src; 01273 01274 if(dwFlags & URL_UNESCAPE_INPLACE || needed < *pcchUnescaped) 01275 *dst++ = next; 01276 } 01277 01278 if(dwFlags & URL_UNESCAPE_INPLACE || needed < *pcchUnescaped) { 01279 *dst = '\0'; 01280 ret = S_OK; 01281 } else { 01282 needed++; /* add one for the '\0' */ 01283 ret = E_POINTER; 01284 } 01285 if(!(dwFlags & URL_UNESCAPE_INPLACE)) 01286 *pcchUnescaped = needed; 01287 01288 if (ret == S_OK) { 01289 TRACE("result %s\n", (dwFlags & URL_UNESCAPE_INPLACE) ? 01290 debugstr_w(pszUrl) : debugstr_w(pszUnescaped)); 01291 } 01292 01293 return ret; 01294 } 01295 01296 /************************************************************************* 01297 * UrlGetLocationA [SHLWAPI.@] 01298 * 01299 * Get the location from a Url. 01300 * 01301 * PARAMS 01302 * pszUrl [I] Url to get the location from 01303 * 01304 * RETURNS 01305 * A pointer to the start of the location in pszUrl, or NULL if there is 01306 * no location. 01307 * 01308 * NOTES 01309 * - MSDN erroneously states that "The location is the segment of the Url 01310 * starting with a '?' or '#' character". Neither V4 nor V5 of shlwapi.dll 01311 * stop at '?' and always return a NULL in this case. 01312 * - MSDN also erroneously states that "If a file URL has a query string, 01313 * the returned string is the query string". In all tested cases, if the 01314 * Url starts with "fi" then a NULL is returned. V5 gives the following results: 01315 *| Result Url 01316 *| ------ --- 01317 *| NULL file://aa/b/cd#hohoh 01318 *| #hohoh http://aa/b/cd#hohoh 01319 *| NULL fi://aa/b/cd#hohoh 01320 *| #hohoh ff://aa/b/cd#hohoh 01321 */ 01322 LPCSTR WINAPI UrlGetLocationA( 01323 LPCSTR pszUrl) 01324 { 01325 PARSEDURLA base; 01326 DWORD res1; 01327 01328 base.cbSize = sizeof(base); 01329 res1 = ParseURLA(pszUrl, &base); 01330 if (res1) return NULL; /* invalid scheme */ 01331 01332 /* if scheme is file: then never return pointer */ 01333 if (strncmp(base.pszProtocol, "file", min(4,base.cchProtocol)) == 0) return NULL; 01334 01335 /* Look for '#' and return its addr */ 01336 return strchr(base.pszSuffix, '#'); 01337 } 01338 01339 /************************************************************************* 01340 * UrlGetLocationW [SHLWAPI.@] 01341 * 01342 * See UrlGetLocationA. 01343 */ 01344 LPCWSTR WINAPI UrlGetLocationW( 01345 LPCWSTR pszUrl) 01346 { 01347 PARSEDURLW base; 01348 DWORD res1; 01349 01350 base.cbSize = sizeof(base); 01351 res1 = ParseURLW(pszUrl, &base); 01352 if (res1) return NULL; /* invalid scheme */ 01353 01354 /* if scheme is file: then never return pointer */ 01355 if (strncmpW(base.pszProtocol, fileW, min(4,base.cchProtocol)) == 0) return NULL; 01356 01357 /* Look for '#' and return its addr */ 01358 return strchrW(base.pszSuffix, '#'); 01359 } 01360 01361 /************************************************************************* 01362 * UrlCompareA [SHLWAPI.@] 01363 * 01364 * Compare two Urls. 01365 * 01366 * PARAMS 01367 * pszUrl1 [I] First Url to compare 01368 * pszUrl2 [I] Url to compare to pszUrl1 01369 * fIgnoreSlash [I] TRUE = compare only up to a final slash 01370 * 01371 * RETURNS 01372 * less than zero, zero, or greater than zero indicating pszUrl2 is greater 01373 * than, equal to, or less than pszUrl1 respectively. 01374 */ 01375 INT WINAPI UrlCompareA( 01376 LPCSTR pszUrl1, 01377 LPCSTR pszUrl2, 01378 BOOL fIgnoreSlash) 01379 { 01380 INT ret, len, len1, len2; 01381 01382 if (!fIgnoreSlash) 01383 return strcmp(pszUrl1, pszUrl2); 01384 len1 = strlen(pszUrl1); 01385 if (pszUrl1[len1-1] == '/') len1--; 01386 len2 = strlen(pszUrl2); 01387 if (pszUrl2[len2-1] == '/') len2--; 01388 if (len1 == len2) 01389 return strncmp(pszUrl1, pszUrl2, len1); 01390 len = min(len1, len2); 01391 ret = strncmp(pszUrl1, pszUrl2, len); 01392 if (ret) return ret; 01393 if (len1 > len2) return 1; 01394 return -1; 01395 } 01396 01397 /************************************************************************* 01398 * UrlCompareW [SHLWAPI.@] 01399 * 01400 * See UrlCompareA. 01401 */ 01402 INT WINAPI UrlCompareW( 01403 LPCWSTR pszUrl1, 01404 LPCWSTR pszUrl2, 01405 BOOL fIgnoreSlash) 01406 { 01407 INT ret; 01408 size_t len, len1, len2; 01409 01410 if (!fIgnoreSlash) 01411 return strcmpW(pszUrl1, pszUrl2); 01412 len1 = strlenW(pszUrl1); 01413 if (pszUrl1[len1-1] == '/') len1--; 01414 len2 = strlenW(pszUrl2); 01415 if (pszUrl2[len2-1] == '/') len2--; 01416 if (len1 == len2) 01417 return strncmpW(pszUrl1, pszUrl2, len1); 01418 len = min(len1, len2); 01419 ret = strncmpW(pszUrl1, pszUrl2, len); 01420 if (ret) return ret; 01421 if (len1 > len2) return 1; 01422 return -1; 01423 } 01424 01425 /************************************************************************* 01426 * HashData [SHLWAPI.@] 01427 * 01428 * Hash an input block into a variable sized digest. 01429 * 01430 * PARAMS 01431 * lpSrc [I] Input block 01432 * nSrcLen [I] Length of lpSrc 01433 * lpDest [I] Output for hash digest 01434 * nDestLen [I] Length of lpDest 01435 * 01436 * RETURNS 01437 * Success: TRUE. lpDest is filled with the computed hash value. 01438 * Failure: FALSE, if any argument is invalid. 01439 */ 01440 HRESULT WINAPI HashData(const unsigned char *lpSrc, DWORD nSrcLen, 01441 unsigned char *lpDest, DWORD nDestLen) 01442 { 01443 INT srcCount = nSrcLen - 1, destCount = nDestLen - 1; 01444 01445 if (!lpSrc || !lpDest) 01446 return E_INVALIDARG; 01447 01448 while (destCount >= 0) 01449 { 01450 lpDest[destCount] = (destCount & 0xff); 01451 destCount--; 01452 } 01453 01454 while (srcCount >= 0) 01455 { 01456 destCount = nDestLen - 1; 01457 while (destCount >= 0) 01458 { 01459 lpDest[destCount] = HashDataLookup[lpSrc[srcCount] ^ lpDest[destCount]]; 01460 destCount--; 01461 } 01462 srcCount--; 01463 } 01464 return S_OK; 01465 } 01466 01467 /************************************************************************* 01468 * UrlHashA [SHLWAPI.@] 01469 * 01470 * Produce a Hash from a Url. 01471 * 01472 * PARAMS 01473 * pszUrl [I] Url to hash 01474 * lpDest [O] Destinationh for hash 01475 * nDestLen [I] Length of lpDest 01476 * 01477 * RETURNS 01478 * Success: S_OK. lpDest is filled with the computed hash value. 01479 * Failure: E_INVALIDARG, if any argument is invalid. 01480 */ 01481 HRESULT WINAPI UrlHashA(LPCSTR pszUrl, unsigned char *lpDest, DWORD nDestLen) 01482 { 01483 if (IsBadStringPtrA(pszUrl, -1) || IsBadWritePtr(lpDest, nDestLen)) 01484 return E_INVALIDARG; 01485 01486 HashData((const BYTE*)pszUrl, (int)strlen(pszUrl), lpDest, nDestLen); 01487 return S_OK; 01488 } 01489 01490 /************************************************************************* 01491 * UrlHashW [SHLWAPI.@] 01492 * 01493 * See UrlHashA. 01494 */ 01495 HRESULT WINAPI UrlHashW(LPCWSTR pszUrl, unsigned char *lpDest, DWORD nDestLen) 01496 { 01497 char szUrl[MAX_PATH]; 01498 01499 TRACE("(%s,%p,%d)\n",debugstr_w(pszUrl), lpDest, nDestLen); 01500 01501 if (IsBadStringPtrW(pszUrl, -1) || IsBadWritePtr(lpDest, nDestLen)) 01502 return E_INVALIDARG; 01503 01504 /* Win32 hashes the data as an ASCII string, presumably so that both A+W 01505 * return the same digests for the same URL. 01506 */ 01507 WideCharToMultiByte(0, 0, pszUrl, -1, szUrl, MAX_PATH, 0, 0); 01508 HashData((const BYTE*)szUrl, (int)strlen(szUrl), lpDest, nDestLen); 01509 return S_OK; 01510 } 01511 01512 /************************************************************************* 01513 * UrlApplySchemeA [SHLWAPI.@] 01514 * 01515 * Apply a scheme to a Url. 01516 * 01517 * PARAMS 01518 * pszIn [I] Url to apply scheme to 01519 * pszOut [O] Destination for modified Url 01520 * pcchOut [I/O] Length of pszOut/destination for length of pszOut 01521 * dwFlags [I] URL_ flags from "shlwapi.h" 01522 * 01523 * RETURNS 01524 * Success: S_OK: pszOut contains the modified Url, pcchOut contains its length. 01525 * Failure: An HRESULT error code describing the error. 01526 */ 01527 HRESULT WINAPI UrlApplySchemeA(LPCSTR pszIn, LPSTR pszOut, LPDWORD pcchOut, DWORD dwFlags) 01528 { 01529 LPWSTR in, out; 01530 HRESULT ret; 01531 DWORD len; 01532 01533 TRACE("(%s, %p, %p:out size %d, 0x%08x)\n", debugstr_a(pszIn), 01534 pszOut, pcchOut, pcchOut ? *pcchOut : 0, dwFlags); 01535 01536 if (!pszIn || !pszOut || !pcchOut) return E_INVALIDARG; 01537 01538 in = HeapAlloc(GetProcessHeap(), 0, 01539 (2*INTERNET_MAX_URL_LENGTH) * sizeof(WCHAR)); 01540 out = in + INTERNET_MAX_URL_LENGTH; 01541 01542 MultiByteToWideChar(CP_ACP, 0, pszIn, -1, in, INTERNET_MAX_URL_LENGTH); 01543 len = INTERNET_MAX_URL_LENGTH; 01544 01545 ret = UrlApplySchemeW(in, out, &len, dwFlags); 01546 if (ret != S_OK) { 01547 HeapFree(GetProcessHeap(), 0, in); 01548 return ret; 01549 } 01550 01551 len = WideCharToMultiByte(CP_ACP, 0, out, -1, NULL, 0, NULL, NULL); 01552 if (len > *pcchOut) { 01553 ret = E_POINTER; 01554 goto cleanup; 01555 } 01556 01557 WideCharToMultiByte(CP_ACP, 0, out, -1, pszOut, *pcchOut, NULL, NULL); 01558 len--; 01559 01560 cleanup: 01561 *pcchOut = len; 01562 HeapFree(GetProcessHeap(), 0, in); 01563 return ret; 01564 } 01565 01566 static HRESULT URL_GuessScheme(LPCWSTR pszIn, LPWSTR pszOut, LPDWORD pcchOut) 01567 { 01568 HKEY newkey; 01569 BOOL j; 01570 INT index; 01571 DWORD value_len, data_len, dwType, i; 01572 WCHAR reg_path[MAX_PATH]; 01573 WCHAR value[MAX_PATH], data[MAX_PATH]; 01574 WCHAR Wxx, Wyy; 01575 01576 MultiByteToWideChar(0, 0, 01577 "Software\\Microsoft\\Windows\\CurrentVersion\\URL\\Prefixes", 01578 -1, reg_path, MAX_PATH); 01579 RegOpenKeyExW(HKEY_LOCAL_MACHINE, reg_path, 0, 1, &newkey); 01580 index = 0; 01581 while(value_len = data_len = MAX_PATH, 01582 RegEnumValueW(newkey, index, value, &value_len, 01583 0, &dwType, (LPVOID)data, &data_len) == 0) { 01584 TRACE("guess %d %s is %s\n", 01585 index, debugstr_w(value), debugstr_w(data)); 01586 01587 j = FALSE; 01588 for(i=0; i<value_len; i++) { 01589 Wxx = pszIn[i]; 01590 Wyy = value[i]; 01591 /* remember that TRUE is not-equal */ 01592 j = ChrCmpIW(Wxx, Wyy); 01593 if (j) break; 01594 } 01595 if ((i == value_len) && !j) { 01596 if (strlenW(data) + strlenW(pszIn) + 1 > *pcchOut) { 01597 *pcchOut = strlenW(data) + strlenW(pszIn) + 1; 01598 RegCloseKey(newkey); 01599 return E_POINTER; 01600 } 01601 strcpyW(pszOut, data); 01602 strcatW(pszOut, pszIn); 01603 *pcchOut = strlenW(pszOut); 01604 TRACE("matched and set to %s\n", debugstr_w(pszOut)); 01605 RegCloseKey(newkey); 01606 return S_OK; 01607 } 01608 index++; 01609 } 01610 RegCloseKey(newkey); 01611 return E_FAIL; 01612 } 01613 01614 static HRESULT URL_ApplyDefault(LPCWSTR pszIn, LPWSTR pszOut, LPDWORD pcchOut) 01615 { 01616 HKEY newkey; 01617 DWORD data_len, dwType; 01618 WCHAR data[MAX_PATH]; 01619 01620 static const WCHAR prefix_keyW[] = 01621 {'S','o','f','t','w','a','r','e', 01622 '\\','M','i','c','r','o','s','o','f','t', 01623 '\\','W','i','n','d','o','w','s', 01624 '\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n', 01625 '\\','U','R','L', 01626 '\\','D','e','f','a','u','l','t','P','r','e','f','i','x',0}; 01627 01628 /* get and prepend default */ 01629 RegOpenKeyExW(HKEY_LOCAL_MACHINE, prefix_keyW, 0, 1, &newkey); 01630 data_len = sizeof(data); 01631 RegQueryValueExW(newkey, NULL, 0, &dwType, (LPBYTE)data, &data_len); 01632 RegCloseKey(newkey); 01633 if (strlenW(data) + strlenW(pszIn) + 1 > *pcchOut) { 01634 *pcchOut = strlenW(data) + strlenW(pszIn) + 1; 01635 return E_POINTER; 01636 } 01637 strcpyW(pszOut, data); 01638 strcatW(pszOut, pszIn); 01639 *pcchOut = strlenW(pszOut); 01640 TRACE("used default %s\n", debugstr_w(pszOut)); 01641 return S_OK; 01642 } 01643 01644 /************************************************************************* 01645 * UrlApplySchemeW [SHLWAPI.@] 01646 * 01647 * See UrlApplySchemeA. 01648 */ 01649 HRESULT WINAPI UrlApplySchemeW(LPCWSTR pszIn, LPWSTR pszOut, LPDWORD pcchOut, DWORD dwFlags) 01650 { 01651 PARSEDURLW in_scheme; 01652 DWORD res1; 01653 HRESULT ret; 01654 01655 TRACE("(%s, %p, %p:out size %d, 0x%08x)\n", debugstr_w(pszIn), 01656 pszOut, pcchOut, pcchOut ? *pcchOut : 0, dwFlags); 01657 01658 if (!pszIn || !pszOut || !pcchOut) return E_INVALIDARG; 01659 01660 if (dwFlags & URL_APPLY_GUESSFILE) { 01661 FIXME("(%s %p %p(%d) 0x%08x): stub URL_APPLY_GUESSFILE not implemented\n", 01662 debugstr_w(pszIn), pszOut, pcchOut, *pcchOut, dwFlags); 01663 strcpyW(pszOut, pszIn); 01664 *pcchOut = strlenW(pszOut); 01665 return S_FALSE; 01666 } 01667 01668 in_scheme.cbSize = sizeof(in_scheme); 01669 /* See if the base has a scheme */ 01670 res1 = ParseURLW(pszIn, &in_scheme); 01671 if (res1) { 01672 /* no scheme in input, need to see if we need to guess */ 01673 if (dwFlags & URL_APPLY_GUESSSCHEME) { 01674 if ((ret = URL_GuessScheme(pszIn, pszOut, pcchOut)) != E_FAIL) 01675 return ret; 01676 } 01677 } 01678 else { 01679 /* we have a scheme, see if valid (known scheme) */ 01680 if (in_scheme.nScheme) { 01681 /* have valid scheme, so just copy and exit */ 01682 if (strlenW(pszIn) + 1 > *pcchOut) { 01683 *pcchOut = strlenW(pszIn) + 1; 01684 return E_POINTER; 01685 } 01686 strcpyW(pszOut, pszIn); 01687 *pcchOut = strlenW(pszOut); 01688 TRACE("valid scheme, returning copy\n"); 01689 return S_OK; 01690 } 01691 } 01692 01693 /* If we are here, then either invalid scheme, 01694 * or no scheme and can't/failed guess. 01695 */ 01696 if ( ( ((res1 == 0) && (dwFlags & URL_APPLY_FORCEAPPLY)) || 01697 ((res1 != 0)) ) && 01698 (dwFlags & URL_APPLY_DEFAULT)) { 01699 /* find and apply default scheme */ 01700 return URL_ApplyDefault(pszIn, pszOut, pcchOut); 01701 } 01702 01703 return S_FALSE; 01704 } 01705 01706 /************************************************************************* 01707 * UrlIsA [SHLWAPI.@] 01708 * 01709 * Determine if a Url is of a certain class. 01710 * 01711 * PARAMS 01712 * pszUrl [I] Url to check 01713 * Urlis [I] URLIS_ constant from "shlwapi.h" 01714 * 01715 * RETURNS 01716 * TRUE if pszUrl belongs to the class type in Urlis. 01717 * FALSE Otherwise. 01718 */ 01719 BOOL WINAPI UrlIsA(LPCSTR pszUrl, URLIS Urlis) 01720 { 01721 PARSEDURLA base; 01722 DWORD res1; 01723 LPCSTR last; 01724 01725 TRACE("(%s %d)\n", debugstr_a(pszUrl), Urlis); 01726 01727 if(!pszUrl) 01728 return FALSE; 01729 01730 switch (Urlis) { 01731 01732 case URLIS_OPAQUE: 01733 base.cbSize = sizeof(base); 01734 res1 = ParseURLA(pszUrl, &base); 01735 if (res1) return FALSE; /* invalid scheme */ 01736 switch (base.nScheme) 01737 { 01738 case URL_SCHEME_MAILTO: 01739 case URL_SCHEME_SHELL: 01740 case URL_SCHEME_JAVASCRIPT: 01741 case URL_SCHEME_VBSCRIPT: 01742 case URL_SCHEME_ABOUT: 01743 return TRUE; 01744 } 01745 return FALSE; 01746 01747 case URLIS_FILEURL: 01748 return !StrCmpNA("file:", pszUrl, 5); 01749 01750 case URLIS_DIRECTORY: 01751 last = pszUrl + strlen(pszUrl) - 1; 01752 return (last >= pszUrl && (*last == '/' || *last == '\\' )); 01753 01754 case URLIS_URL: 01755 return PathIsURLA(pszUrl); 01756 01757 case URLIS_NOHISTORY: 01758 case URLIS_APPLIABLE: 01759 case URLIS_HASQUERY: 01760 default: 01761 FIXME("(%s %d): stub\n", debugstr_a(pszUrl), Urlis); 01762 } 01763 return FALSE; 01764 } 01765 01766 /************************************************************************* 01767 * UrlIsW [SHLWAPI.@] 01768 * 01769 * See UrlIsA. 01770 */ 01771 BOOL WINAPI UrlIsW(LPCWSTR pszUrl, URLIS Urlis) 01772 { 01773 static const WCHAR stemp[] = { 'f','i','l','e',':',0 }; 01774 PARSEDURLW base; 01775 DWORD res1; 01776 LPCWSTR last; 01777 01778 TRACE("(%s %d)\n", debugstr_w(pszUrl), Urlis); 01779 01780 if(!pszUrl) 01781 return FALSE; 01782 01783 switch (Urlis) { 01784 01785 case URLIS_OPAQUE: 01786 base.cbSize = sizeof(base); 01787 res1 = ParseURLW(pszUrl, &base); 01788 if (res1) return FALSE; /* invalid scheme */ 01789 switch (base.nScheme) 01790 { 01791 case URL_SCHEME_MAILTO: 01792 case URL_SCHEME_SHELL: 01793 case URL_SCHEME_JAVASCRIPT: 01794 case URL_SCHEME_VBSCRIPT: 01795 case URL_SCHEME_ABOUT: 01796 return TRUE; 01797 } 01798 return FALSE; 01799 01800 case URLIS_FILEURL: 01801 return !strncmpW(stemp, pszUrl, 5); 01802 01803 case URLIS_DIRECTORY: 01804 last = pszUrl + strlenW(pszUrl) - 1; 01805 return (last >= pszUrl && (*last == '/' || *last == '\\')); 01806 01807 case URLIS_URL: 01808 return PathIsURLW(pszUrl); 01809 01810 case URLIS_NOHISTORY: 01811 case URLIS_APPLIABLE: 01812 case URLIS_HASQUERY: 01813 default: 01814 FIXME("(%s %d): stub\n", debugstr_w(pszUrl), Urlis); 01815 } 01816 return FALSE; 01817 } 01818 01819 /************************************************************************* 01820 * UrlIsNoHistoryA [SHLWAPI.@] 01821 * 01822 * Determine if a Url should not be stored in the users history list. 01823 * 01824 * PARAMS 01825 * pszUrl [I] Url to check 01826 * 01827 * RETURNS 01828 * TRUE, if pszUrl should be excluded from the history list, 01829 * FALSE otherwise. 01830 */ 01831 BOOL WINAPI UrlIsNoHistoryA(LPCSTR pszUrl) 01832 { 01833 return UrlIsA(pszUrl, URLIS_NOHISTORY); 01834 } 01835 01836 /************************************************************************* 01837 * UrlIsNoHistoryW [SHLWAPI.@] 01838 * 01839 * See UrlIsNoHistoryA. 01840 */ 01841 BOOL WINAPI UrlIsNoHistoryW(LPCWSTR pszUrl) 01842 { 01843 return UrlIsW(pszUrl, URLIS_NOHISTORY); 01844 } 01845 01846 /************************************************************************* 01847 * UrlIsOpaqueA [SHLWAPI.@] 01848 * 01849 * Determine if a Url is opaque. 01850 * 01851 * PARAMS 01852 * pszUrl [I] Url to check 01853 * 01854 * RETURNS 01855 * TRUE if pszUrl is opaque, 01856 * FALSE Otherwise. 01857 * 01858 * NOTES 01859 * An opaque Url is one that does not start with "<protocol>://". 01860 */ 01861 BOOL WINAPI UrlIsOpaqueA(LPCSTR pszUrl) 01862 { 01863 return UrlIsA(pszUrl, URLIS_OPAQUE); 01864 } 01865 01866 /************************************************************************* 01867 * UrlIsOpaqueW [SHLWAPI.@] 01868 * 01869 * See UrlIsOpaqueA. 01870 */ 01871 BOOL WINAPI UrlIsOpaqueW(LPCWSTR pszUrl) 01872 { 01873 return UrlIsW(pszUrl, URLIS_OPAQUE); 01874 } 01875 01876 /************************************************************************* 01877 * Scans for characters of type "type" and when not matching found, 01878 * returns pointer to it and length in size. 01879 * 01880 * Characters tested based on RFC 1738 01881 */ 01882 static LPCWSTR URL_ScanID(LPCWSTR start, LPDWORD size, WINE_URL_SCAN_TYPE type) 01883 { 01884 static DWORD alwayszero = 0; 01885 BOOL cont = TRUE; 01886 01887 *size = 0; 01888 01889 switch(type){ 01890 01891 case SCHEME: 01892 while (cont) { 01893 if ( (islowerW(*start) && isalphaW(*start)) || 01894 isdigitW(*start) || 01895 (*start == '+') || 01896 (*start == '-') || 01897 (*start == '.')) { 01898 start++; 01899 (*size)++; 01900 } 01901 else 01902 cont = FALSE; 01903 } 01904 break; 01905 01906 case USERPASS: 01907 while (cont) { 01908 if ( isalphaW(*start) || 01909 isdigitW(*start) || 01910 /* user/password only characters */ 01911 (*start == ';') || 01912 (*start == '?') || 01913 (*start == '&') || 01914 (*start == '=') || 01915 /* *extra* characters */ 01916 (*start == '!') || 01917 (*start == '*') || 01918 (*start == '\'') || 01919 (*start == '(') || 01920 (*start == ')') || 01921 (*start == ',') || 01922 /* *safe* characters */ 01923 (*start == '$') || 01924 (*start == '_') || 01925 (*start == '+') || 01926 (*start == '-') || 01927 (*start == '.') || 01928 (*start == ' ')) { 01929 start++; 01930 (*size)++; 01931 } else if (*start == '%') { 01932 if (isxdigitW(*(start+1)) && 01933 isxdigitW(*(start+2))) { 01934 start += 3; 01935 *size += 3; 01936 } else 01937 cont = FALSE; 01938 } else 01939 cont = FALSE; 01940 } 01941 break; 01942 01943 case PORT: 01944 while (cont) { 01945 if (isdigitW(*start)) { 01946 start++; 01947 (*size)++; 01948 } 01949 else 01950 cont = FALSE; 01951 } 01952 break; 01953 01954 case HOST: 01955 while (cont) { 01956 if (isalnumW(*start) || 01957 (*start == '-') || 01958 (*start == '.') || 01959 (*start == ' ') ) { 01960 start++; 01961 (*size)++; 01962 } 01963 else 01964 cont = FALSE; 01965 } 01966 break; 01967 default: 01968 FIXME("unknown type %d\n", type); 01969 return (LPWSTR)&alwayszero; 01970 } 01971 /* TRACE("scanned %d characters next char %p<%c>\n", 01972 *size, start, *start); */ 01973 return start; 01974 } 01975 01976 /************************************************************************* 01977 * Attempt to parse URL into pieces. 01978 */ 01979 static LONG URL_ParseUrl(LPCWSTR pszUrl, WINE_PARSE_URL *pl) 01980 { 01981 LPCWSTR work; 01982 01983 memset(pl, 0, sizeof(WINE_PARSE_URL)); 01984 pl->pScheme = pszUrl; 01985 work = URL_ScanID(pl->pScheme, &pl->szScheme, SCHEME); 01986 if (!*work || (*work != ':')) goto ErrorExit; 01987 work++; 01988 if ((*work != '/') || (*(work+1) != '/')) goto SuccessExit; 01989 pl->pUserName = work + 2; 01990 work = URL_ScanID(pl->pUserName, &pl->szUserName, USERPASS); 01991 if (*work == ':' ) { 01992 /* parse password */ 01993 work++; 01994 pl->pPassword = work; 01995 work = URL_ScanID(pl->pPassword, &pl->szPassword, USERPASS); 01996 if (*work != '@') { 01997 /* what we just parsed must be the hostname and port 01998 * so reset pointers and clear then let it parse */ 01999 pl->szUserName = pl->szPassword = 0; 02000 work = pl->pUserName - 1; 02001 pl->pUserName = pl->pPassword = 0; 02002 } 02003 } else if (*work == '@') { 02004 /* no password */ 02005 pl->szPassword = 0; 02006 pl->pPassword = 0; 02007 } else if (!*work || (*work == '/') || (*work == '.')) { 02008 /* what was parsed was hostname, so reset pointers and let it parse */ 02009 pl->szUserName = pl->szPassword = 0; 02010 work = pl->pUserName - 1; 02011 pl->pUserName = pl->pPassword = 0; 02012 } else goto ErrorExit; 02013 02014 /* now start parsing hostname or hostnumber */ 02015 work++; 02016 pl->pHostName = work; 02017 work = URL_ScanID(pl->pHostName, &pl->szHostName, HOST); 02018 if (*work == ':') { 02019 /* parse port */ 02020 work++; 02021 pl->pPort = work; 02022 work = URL_ScanID(pl->pPort, &pl->szPort, PORT); 02023 } 02024 if (*work == '/') { 02025 /* see if query string */ 02026 pl->pQuery = strchrW(work, '?'); 02027 if (pl->pQuery) pl->szQuery = strlenW(pl->pQuery); 02028 } 02029 SuccessExit: 02030 TRACE("parse successful: scheme=%p(%d), user=%p(%d), pass=%p(%d), host=%p(%d), port=%p(%d), query=%p(%d)\n", 02031 pl->pScheme, pl->szScheme, 02032 pl->pUserName, pl->szUserName, 02033 pl->pPassword, pl->szPassword, 02034 pl->pHostName, pl->szHostName, 02035 pl->pPort, pl->szPort, 02036 pl->pQuery, pl->szQuery); 02037 return S_OK; 02038 ErrorExit: 02039 FIXME("failed to parse %s\n", debugstr_w(pszUrl)); 02040 return E_INVALIDARG; 02041 } 02042 02043 /************************************************************************* 02044 * UrlGetPartA [SHLWAPI.@] 02045 * 02046 * Retrieve part of a Url. 02047 * 02048 * PARAMS 02049 * pszIn [I] Url to parse 02050 * pszOut [O] Destination for part of pszIn requested 02051 * pcchOut [I] Size of pszOut 02052 * [O] length of pszOut string EXCLUDING '\0' if S_OK, otherwise 02053 * needed size of pszOut INCLUDING '\0'. 02054 * dwPart [I] URL_PART_ enum from "shlwapi.h" 02055 * dwFlags [I] URL_ flags from "shlwapi.h" 02056 * 02057 * RETURNS 02058 * Success: S_OK. pszOut contains the part requested, pcchOut contains its length. 02059 * Failure: An HRESULT error code describing the error. 02060 */ 02061 HRESULT WINAPI UrlGetPartA(LPCSTR pszIn, LPSTR pszOut, LPDWORD pcchOut, 02062 DWORD dwPart, DWORD dwFlags) 02063 { 02064 LPWSTR in, out; 02065 DWORD ret, len, len2; 02066 02067 if(!pszIn || !pszOut || !pcchOut || *pcchOut <= 0) 02068 return E_INVALIDARG; 02069 02070 in = HeapAlloc(GetProcessHeap(), 0, 02071 (2*INTERNET_MAX_URL_LENGTH) * sizeof(WCHAR)); 02072 out = in + INTERNET_MAX_URL_LENGTH; 02073 02074 MultiByteToWideChar(0, 0, pszIn, -1, in, INTERNET_MAX_URL_LENGTH); 02075 02076 len = INTERNET_MAX_URL_LENGTH; 02077 ret = UrlGetPartW(in, out, &len, dwPart, dwFlags); 02078 02079 if (FAILED(ret)) { 02080 HeapFree(GetProcessHeap(), 0, in); 02081 return ret; 02082 } 02083 02084 len2 = WideCharToMultiByte(0, 0, out, len, 0, 0, 0, 0); 02085 if (len2 > *pcchOut) { 02086 *pcchOut = len2+1; 02087 HeapFree(GetProcessHeap(), 0, in); 02088 return E_POINTER; 02089 } 02090 len2 = WideCharToMultiByte(0, 0, out, len+1, pszOut, *pcchOut, 0, 0); 02091 *pcchOut = len2-1; 02092 HeapFree(GetProcessHeap(), 0, in); 02093 return ret; 02094 } 02095 02096 /************************************************************************* 02097 * UrlGetPartW [SHLWAPI.@] 02098 * 02099 * See UrlGetPartA. 02100 */ 02101 HRESULT WINAPI UrlGetPartW(LPCWSTR pszIn, LPWSTR pszOut, LPDWORD pcchOut, 02102 DWORD dwPart, DWORD dwFlags) 02103 { 02104 WINE_PARSE_URL pl; 02105 HRESULT ret; 02106 DWORD scheme, size, schsize; 02107 LPCWSTR addr, schaddr; 02108 02109 TRACE("(%s %p %p(%d) %08x %08x)\n", 02110 debugstr_w(pszIn), pszOut, pcchOut, *pcchOut, dwPart, dwFlags); 02111 02112 if(!pszIn || !pszOut || !pcchOut || *pcchOut <= 0) 02113 return E_INVALIDARG; 02114 02115 *pszOut = '\0'; 02116 02117 addr = strchrW(pszIn, ':'); 02118 if(!addr) 02119 scheme = URL_SCHEME_UNKNOWN; 02120 else 02121 scheme = get_scheme_code(pszIn, addr-pszIn); 02122 02123 ret = URL_ParseUrl(pszIn, &pl); 02124 02125 switch (dwPart) { 02126 case URL_PART_SCHEME: 02127 if (!pl.szScheme || scheme == URL_SCHEME_UNKNOWN) { 02128 *pcchOut = 0; 02129 return S_FALSE; 02130 } 02131 addr = pl.pScheme; 02132 size = pl.szScheme; 02133 break; 02134 02135 case URL_PART_HOSTNAME: 02136 switch(scheme) { 02137 case URL_SCHEME_FTP: 02138 case URL_SCHEME_HTTP: 02139 case URL_SCHEME_GOPHER: 02140 case URL_SCHEME_TELNET: 02141 case URL_SCHEME_FILE: 02142 case URL_SCHEME_HTTPS: 02143 break; 02144 default: 02145 *pcchOut = 0; 02146 return E_FAIL; 02147 } 02148 02149 if(scheme==URL_SCHEME_FILE && (!pl.szHostName || 02150 (pl.szHostName==1 && *(pl.pHostName+1)==':'))) { 02151 *pcchOut = 0; 02152 return S_FALSE; 02153 } 02154 02155 if (!pl.szHostName) { 02156 *pcchOut = 0; 02157 return S_FALSE; 02158 } 02159 addr = pl.pHostName; 02160 size = pl.szHostName; 02161 break; 02162 02163 case URL_PART_USERNAME: 02164 if (!pl.szUserName) { 02165 *pcchOut = 0; 02166 return S_FALSE; 02167 } 02168 addr = pl.pUserName; 02169 size = pl.szUserName; 02170 break; 02171 02172 case URL_PART_PASSWORD: 02173 if (!pl.szPassword) { 02174 *pcchOut = 0; 02175 return S_FALSE; 02176 } 02177 addr = pl.pPassword; 02178 size = pl.szPassword; 02179 break; 02180 02181 case URL_PART_PORT: 02182 if (!pl.szPort) { 02183 *pcchOut = 0; 02184 return S_FALSE; 02185 } 02186 addr = pl.pPort; 02187 size = pl.szPort; 02188 break; 02189 02190 case URL_PART_QUERY: 02191 if (!pl.szQuery) { 02192 *pcchOut = 0; 02193 return S_FALSE; 02194 } 02195 addr = pl.pQuery; 02196 size = pl.szQuery; 02197 break; 02198 02199 default: 02200 *pcchOut = 0; 02201 return E_INVALIDARG; 02202 } 02203 02204 if (dwFlags == URL_PARTFLAG_KEEPSCHEME) { 02205 if(!pl.pScheme || !pl.szScheme) { 02206 *pcchOut = 0; 02207 return E_FAIL; 02208 } 02209 schaddr = pl.pScheme; 02210 schsize = pl.szScheme; 02211 if (*pcchOut < schsize + size + 2) { 02212 *pcchOut = schsize + size + 2; 02213 return E_POINTER; 02214 } 02215 memcpy(pszOut, schaddr, schsize*sizeof(WCHAR)); 02216 pszOut[schsize] = ':'; 02217 memcpy(pszOut+schsize+1, addr, size*sizeof(WCHAR)); 02218 pszOut[schsize+1+size] = 0; 02219 *pcchOut = schsize + 1 + size; 02220 } 02221 else { 02222 if (*pcchOut < size + 1) {*pcchOut = size+1; return E_POINTER;} 02223 memcpy(pszOut, addr, size*sizeof(WCHAR)); 02224 pszOut[size] = 0; 02225 *pcchOut = size; 02226 } 02227 TRACE("len=%d %s\n", *pcchOut, debugstr_w(pszOut)); 02228 02229 return ret; 02230 } 02231 02232 /************************************************************************* 02233 * PathIsURLA [SHLWAPI.@] 02234 * 02235 * Check if the given path is a Url. 02236 * 02237 * PARAMS 02238 * lpszPath [I] Path to check. 02239 * 02240 * RETURNS 02241 * TRUE if lpszPath is a Url. 02242 * FALSE if lpszPath is NULL or not a Url. 02243 */ 02244 BOOL WINAPI PathIsURLA(LPCSTR lpstrPath) 02245 { 02246 PARSEDURLA base; 02247 HRESULT hres; 02248 02249 TRACE("%s\n", debugstr_a(lpstrPath)); 02250 02251 if (!lpstrPath || !*lpstrPath) return FALSE; 02252 02253 /* get protocol */ 02254 base.cbSize = sizeof(base); 02255 hres = ParseURLA(lpstrPath, &base); 02256 return hres == S_OK && (base.nScheme != URL_SCHEME_INVALID); 02257 } 02258 02259 /************************************************************************* 02260 * PathIsURLW [SHLWAPI.@] 02261 * 02262 * See PathIsURLA. 02263 */ 02264 BOOL WINAPI PathIsURLW(LPCWSTR lpstrPath) 02265 { 02266 PARSEDURLW base; 02267 HRESULT hres; 02268 02269 TRACE("%s\n", debugstr_w(lpstrPath)); 02270 02271 if (!lpstrPath || !*lpstrPath) return FALSE; 02272 02273 /* get protocol */ 02274 base.cbSize = sizeof(base); 02275 hres = ParseURLW(lpstrPath, &base); 02276 return hres == S_OK && (base.nScheme != URL_SCHEME_INVALID); 02277 } 02278 02279 /************************************************************************* 02280 * UrlCreateFromPathA [SHLWAPI.@] 02281 * 02282 * See UrlCreateFromPathW 02283 */ 02284 HRESULT WINAPI UrlCreateFromPathA(LPCSTR pszPath, LPSTR pszUrl, LPDWORD pcchUrl, DWORD dwReserved) 02285 { 02286 WCHAR bufW[INTERNET_MAX_URL_LENGTH]; 02287 WCHAR *urlW = bufW; 02288 UNICODE_STRING pathW; 02289 HRESULT ret; 02290 DWORD lenW = sizeof(bufW)/sizeof(WCHAR), lenA; 02291 02292 if(!RtlCreateUnicodeStringFromAsciiz(&pathW, pszPath)) 02293 return E_INVALIDARG; 02294 if((ret = UrlCreateFromPathW(pathW.Buffer, urlW, &lenW, dwReserved)) == E_POINTER) { 02295 urlW = HeapAlloc(GetProcessHeap(), 0, lenW * sizeof(WCHAR)); 02296 ret = UrlCreateFromPathW(pathW.Buffer, urlW, &lenW, dwReserved); 02297 } 02298 if(ret == S_OK || ret == S_FALSE) { 02299 RtlUnicodeToMultiByteSize(&lenA, urlW, lenW * sizeof(WCHAR)); 02300 if(*pcchUrl > lenA) { 02301 RtlUnicodeToMultiByteN(pszUrl, *pcchUrl - 1, &lenA, urlW, lenW * sizeof(WCHAR)); 02302 pszUrl[lenA] = 0; 02303 *pcchUrl = lenA; 02304 } else { 02305 *pcchUrl = lenA + 1; 02306 ret = E_POINTER; 02307 } 02308 } 02309 if(urlW != bufW) HeapFree(GetProcessHeap(), 0, urlW); 02310 RtlFreeUnicodeString(&pathW); 02311 return ret; 02312 } 02313 02314 /************************************************************************* 02315 * UrlCreateFromPathW [SHLWAPI.@] 02316 * 02317 * Create a Url from a file path. 02318 * 02319 * PARAMS 02320 * pszPath [I] Path to convert 02321 * pszUrl [O] Destination for the converted Url 02322 * pcchUrl [I/O] Length of pszUrl 02323 * dwReserved [I] Reserved, must be 0 02324 * 02325 * RETURNS 02326 * Success: S_OK pszUrl contains the converted path, S_FALSE if the path is already a Url 02327 * Failure: An HRESULT error code. 02328 */ 02329 HRESULT WINAPI UrlCreateFromPathW(LPCWSTR pszPath, LPWSTR pszUrl, LPDWORD pcchUrl, DWORD dwReserved) 02330 { 02331 DWORD needed; 02332 HRESULT ret; 02333 WCHAR *pszNewUrl; 02334 WCHAR file_colonW[] = {'f','i','l','e',':',0}; 02335 WCHAR three_slashesW[] = {'/','/','/',0}; 02336 PARSEDURLW parsed_url; 02337 02338 TRACE("(%s, %p, %p, 0x%08x)\n", debugstr_w(pszPath), pszUrl, pcchUrl, dwReserved); 02339 02340 /* Validate arguments */ 02341 if (dwReserved != 0) 02342 return E_INVALIDARG; 02343 if (!pszUrl || !pcchUrl) 02344 return E_INVALIDARG; 02345 02346 02347 parsed_url.cbSize = sizeof(parsed_url); 02348 if(ParseURLW(pszPath, &parsed_url) == S_OK) { 02349 if(parsed_url.nScheme != URL_SCHEME_INVALID && parsed_url.cchProtocol > 1) { 02350 needed = strlenW(pszPath); 02351 if (needed >= *pcchUrl) { 02352 *pcchUrl = needed + 1; 02353 return E_POINTER; 02354 } else { 02355 *pcchUrl = needed; 02356 strcpyW(pszUrl, pszPath); 02357 return S_FALSE; 02358 } 02359 } 02360 } 02361 02362 pszNewUrl = HeapAlloc(GetProcessHeap(), 0, (strlenW(pszPath) + 9) * sizeof(WCHAR)); /* "file:///" + pszPath_len + 1 */ 02363 strcpyW(pszNewUrl, file_colonW); 02364 if(isalphaW(pszPath[0]) && pszPath[1] == ':') 02365 strcatW(pszNewUrl, three_slashesW); 02366 strcatW(pszNewUrl, pszPath); 02367 ret = UrlEscapeW(pszNewUrl, pszUrl, pcchUrl, URL_ESCAPE_PERCENT); 02368 02369 HeapFree(GetProcessHeap(), 0, pszNewUrl); 02370 return ret; 02371 } 02372 02373 /************************************************************************* 02374 * SHAutoComplete [SHLWAPI.@] 02375 * 02376 * Enable auto-completion for an edit control. 02377 * 02378 * PARAMS 02379 * hwndEdit [I] Handle of control to enable auto-completion for 02380 * dwFlags [I] SHACF_ flags from "shlwapi.h" 02381 * 02382 * RETURNS 02383 * Success: S_OK. Auto-completion is enabled for the control. 02384 * Failure: An HRESULT error code indicating the error. 02385 */ 02386 HRESULT WINAPI SHAutoComplete(HWND hwndEdit, DWORD dwFlags) 02387 { 02388 FIXME("stub\n"); 02389 return S_FALSE; 02390 } 02391 02392 /************************************************************************* 02393 * MLBuildResURLA [SHLWAPI.405] 02394 * 02395 * Create a Url pointing to a resource in a module. 02396 * 02397 * PARAMS 02398 * lpszLibName [I] Name of the module containing the resource 02399 * hMod [I] Callers module handle 02400 * dwFlags [I] Undocumented flags for loading the module 02401 * lpszRes [I] Resource name 02402 * lpszDest [O] Destination for resulting Url 02403 * dwDestLen [I] Length of lpszDest 02404 * 02405 * RETURNS 02406 * Success: S_OK. lpszDest contains the resource Url. 02407 * Failure: E_INVALIDARG, if any argument is invalid, or 02408 * E_FAIL if dwDestLen is too small. 02409 */ 02410 HRESULT WINAPI MLBuildResURLA(LPCSTR lpszLibName, HMODULE hMod, DWORD dwFlags, 02411 LPCSTR lpszRes, LPSTR lpszDest, DWORD dwDestLen) 02412 { 02413 WCHAR szLibName[MAX_PATH], szRes[MAX_PATH], szDest[MAX_PATH]; 02414 HRESULT hRet; 02415 02416 if (lpszLibName) 02417 MultiByteToWideChar(CP_ACP, 0, lpszLibName, -1, szLibName, sizeof(szLibName)/sizeof(WCHAR)); 02418 02419 if (lpszRes) 02420 MultiByteToWideChar(CP_ACP, 0, lpszRes, -1, szRes, sizeof(szRes)/sizeof(WCHAR)); 02421 02422 if (dwDestLen > sizeof(szLibName)/sizeof(WCHAR)) 02423 dwDestLen = sizeof(szLibName)/sizeof(WCHAR); 02424 02425 hRet = MLBuildResURLW(lpszLibName ? szLibName : NULL, hMod, dwFlags, 02426 lpszRes ? szRes : NULL, lpszDest ? szDest : NULL, dwDestLen); 02427 if (SUCCEEDED(hRet) && lpszDest) 02428 WideCharToMultiByte(CP_ACP, 0, szDest, -1, lpszDest, dwDestLen, 0, 0); 02429 02430 return hRet; 02431 } 02432 02433 /************************************************************************* 02434 * MLBuildResURLA [SHLWAPI.406] 02435 * 02436 * See MLBuildResURLA. 02437 */ 02438 HRESULT WINAPI MLBuildResURLW(LPCWSTR lpszLibName, HMODULE hMod, DWORD dwFlags, 02439 LPCWSTR lpszRes, LPWSTR lpszDest, DWORD dwDestLen) 02440 { 02441 static const WCHAR szRes[] = { 'r','e','s',':','/','/','\0' }; 02442 #define szResLen ((sizeof(szRes) - sizeof(WCHAR))/sizeof(WCHAR)) 02443 HRESULT hRet = E_FAIL; 02444 02445 TRACE("(%s,%p,0x%08x,%s,%p,%d)\n", debugstr_w(lpszLibName), hMod, dwFlags, 02446 debugstr_w(lpszRes), lpszDest, dwDestLen); 02447 02448 if (!lpszLibName || !hMod || hMod == INVALID_HANDLE_VALUE || !lpszRes || 02449 !lpszDest || (dwFlags && dwFlags != 2)) 02450 return E_INVALIDARG; 02451 02452 if (dwDestLen >= szResLen + 1) 02453 { 02454 dwDestLen -= (szResLen + 1); 02455 memcpy(lpszDest, szRes, sizeof(szRes)); 02456 02457 hMod = MLLoadLibraryW(lpszLibName, hMod, dwFlags); 02458 02459 if (hMod) 02460 { 02461 WCHAR szBuff[MAX_PATH]; 02462 DWORD len; 02463 02464 len = GetModuleFileNameW(hMod, szBuff, sizeof(szBuff)/sizeof(WCHAR)); 02465 if (len && len < sizeof(szBuff)/sizeof(WCHAR)) 02466 { 02467 DWORD dwPathLen = strlenW(szBuff) + 1; 02468 02469 if (dwDestLen >= dwPathLen) 02470 { 02471 DWORD dwResLen; 02472 02473 dwDestLen -= dwPathLen; 02474 memcpy(lpszDest + szResLen, szBuff, dwPathLen * sizeof(WCHAR)); 02475 02476 dwResLen = strlenW(lpszRes) + 1; 02477 if (dwDestLen >= dwResLen + 1) 02478 { 02479 lpszDest[szResLen + dwPathLen-1] = '/'; 02480 memcpy(lpszDest + szResLen + dwPathLen, lpszRes, dwResLen * sizeof(WCHAR)); 02481 hRet = S_OK; 02482 } 02483 } 02484 } 02485 MLFreeLibrary(hMod); 02486 } 02487 } 02488 return hRet; 02489 } 02490 02491 /*********************************************************************** 02492 * UrlFixupW [SHLWAPI.462] 02493 * 02494 * Checks the scheme part of a URL and attempts to correct misspellings. 02495 * 02496 * PARAMS 02497 * lpszUrl [I] Pointer to the URL to be corrected 02498 * lpszTranslatedUrl [O] Pointer to a buffer to store corrected URL 02499 * dwMaxChars [I] Maximum size of corrected URL 02500 * 02501 * RETURNS 02502 * success: S_OK if URL corrected or already correct 02503 * failure: S_FALSE if unable to correct / COM error code if other error 02504 * 02505 */ 02506 HRESULT WINAPI UrlFixupW(LPCWSTR url, LPWSTR translatedUrl, DWORD maxChars) 02507 { 02508 DWORD srcLen; 02509 02510 FIXME("(%s,%p,%d) STUB\n", debugstr_w(url), translatedUrl, maxChars); 02511 02512 if (!url) 02513 return E_FAIL; 02514 02515 srcLen = lstrlenW(url) + 1; 02516 02517 /* For now just copy the URL directly */ 02518 lstrcpynW(translatedUrl, url, (maxChars < srcLen) ? maxChars : srcLen); 02519 02520 return S_OK; 02521 } Generated on Sat May 26 2012 04:25:08 for ReactOS by
1.7.6.1
|