1 /* 2 * Url functions 3 * 4 * Copyright 2000 Huw D M Davies for CodeWeavers. 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 19 */ 20 21 #include "precomp.h" 22 23 #include <wininet.h> 24 #include <intshcut.h> 25 26 HMODULE WINAPI MLLoadLibraryW(LPCWSTR,HMODULE,DWORD); 27 BOOL WINAPI MLFreeLibrary(HMODULE); 28 HRESULT WINAPI MLBuildResURLW(LPCWSTR,HMODULE,DWORD,LPCWSTR,LPWSTR,DWORD); 29 30 static inline WCHAR *heap_strdupAtoW(const char *str) 31 { 32 LPWSTR ret = NULL; 33 34 if(str) { 35 DWORD len; 36 37 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0); 38 ret = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR)); 39 MultiByteToWideChar(CP_ACP, 0, str, -1, ret, len); 40 } 41 42 return ret; 43 } 44 45 /* The following schemes were identified in the native version of 46 * SHLWAPI.DLL version 5.50 47 */ 48 static const struct { 49 URL_SCHEME scheme_number; 50 WCHAR scheme_name[12]; 51 } shlwapi_schemes[] = { 52 {URL_SCHEME_FTP, {'f','t','p',0}}, 53 {URL_SCHEME_HTTP, {'h','t','t','p',0}}, 54 {URL_SCHEME_GOPHER, {'g','o','p','h','e','r',0}}, 55 {URL_SCHEME_MAILTO, {'m','a','i','l','t','o',0}}, 56 {URL_SCHEME_NEWS, {'n','e','w','s',0}}, 57 {URL_SCHEME_NNTP, {'n','n','t','p',0}}, 58 {URL_SCHEME_TELNET, {'t','e','l','n','e','t',0}}, 59 {URL_SCHEME_WAIS, {'w','a','i','s',0}}, 60 {URL_SCHEME_FILE, {'f','i','l','e',0}}, 61 {URL_SCHEME_MK, {'m','k',0}}, 62 {URL_SCHEME_HTTPS, {'h','t','t','p','s',0}}, 63 {URL_SCHEME_SHELL, {'s','h','e','l','l',0}}, 64 {URL_SCHEME_SNEWS, {'s','n','e','w','s',0}}, 65 {URL_SCHEME_LOCAL, {'l','o','c','a','l',0}}, 66 {URL_SCHEME_JAVASCRIPT, {'j','a','v','a','s','c','r','i','p','t',0}}, 67 {URL_SCHEME_VBSCRIPT, {'v','b','s','c','r','i','p','t',0}}, 68 {URL_SCHEME_ABOUT, {'a','b','o','u','t',0}}, 69 {URL_SCHEME_RES, {'r','e','s',0}}, 70 }; 71 72 typedef struct { 73 LPCWSTR pScheme; /* [out] start of scheme */ 74 DWORD szScheme; /* [out] size of scheme (until colon) */ 75 LPCWSTR pUserName; /* [out] start of Username */ 76 DWORD szUserName; /* [out] size of Username (until ":" or "@") */ 77 LPCWSTR pPassword; /* [out] start of Password */ 78 DWORD szPassword; /* [out] size of Password (until "@") */ 79 LPCWSTR pHostName; /* [out] start of Hostname */ 80 DWORD szHostName; /* [out] size of Hostname (until ":" or "/") */ 81 LPCWSTR pPort; /* [out] start of Port */ 82 DWORD szPort; /* [out] size of Port (until "/" or eos) */ 83 LPCWSTR pQuery; /* [out] start of Query */ 84 DWORD szQuery; /* [out] size of Query (until eos) */ 85 } WINE_PARSE_URL; 86 87 typedef enum { 88 SCHEME, 89 HOST, 90 PORT, 91 USERPASS, 92 } WINE_URL_SCAN_TYPE; 93 94 static const CHAR hexDigits[] = "0123456789ABCDEF"; 95 96 static const WCHAR fileW[] = {'f','i','l','e','\0'}; 97 98 static const unsigned char HashDataLookup[256] = { 99 0x01, 0x0E, 0x6E, 0x19, 0x61, 0xAE, 0x84, 0x77, 0x8A, 0xAA, 0x7D, 0x76, 0x1B, 100 0xE9, 0x8C, 0x33, 0x57, 0xC5, 0xB1, 0x6B, 0xEA, 0xA9, 0x38, 0x44, 0x1E, 0x07, 101 0xAD, 0x49, 0xBC, 0x28, 0x24, 0x41, 0x31, 0xD5, 0x68, 0xBE, 0x39, 0xD3, 0x94, 102 0xDF, 0x30, 0x73, 0x0F, 0x02, 0x43, 0xBA, 0xD2, 0x1C, 0x0C, 0xB5, 0x67, 0x46, 103 0x16, 0x3A, 0x4B, 0x4E, 0xB7, 0xA7, 0xEE, 0x9D, 0x7C, 0x93, 0xAC, 0x90, 0xB0, 104 0xA1, 0x8D, 0x56, 0x3C, 0x42, 0x80, 0x53, 0x9C, 0xF1, 0x4F, 0x2E, 0xA8, 0xC6, 105 0x29, 0xFE, 0xB2, 0x55, 0xFD, 0xED, 0xFA, 0x9A, 0x85, 0x58, 0x23, 0xCE, 0x5F, 106 0x74, 0xFC, 0xC0, 0x36, 0xDD, 0x66, 0xDA, 0xFF, 0xF0, 0x52, 0x6A, 0x9E, 0xC9, 107 0x3D, 0x03, 0x59, 0x09, 0x2A, 0x9B, 0x9F, 0x5D, 0xA6, 0x50, 0x32, 0x22, 0xAF, 108 0xC3, 0x64, 0x63, 0x1A, 0x96, 0x10, 0x91, 0x04, 0x21, 0x08, 0xBD, 0x79, 0x40, 109 0x4D, 0x48, 0xD0, 0xF5, 0x82, 0x7A, 0x8F, 0x37, 0x69, 0x86, 0x1D, 0xA4, 0xB9, 110 0xC2, 0xC1, 0xEF, 0x65, 0xF2, 0x05, 0xAB, 0x7E, 0x0B, 0x4A, 0x3B, 0x89, 0xE4, 111 0x6C, 0xBF, 0xE8, 0x8B, 0x06, 0x18, 0x51, 0x14, 0x7F, 0x11, 0x5B, 0x5C, 0xFB, 112 0x97, 0xE1, 0xCF, 0x15, 0x62, 0x71, 0x70, 0x54, 0xE2, 0x12, 0xD6, 0xC7, 0xBB, 113 0x0D, 0x20, 0x5E, 0xDC, 0xE0, 0xD4, 0xF7, 0xCC, 0xC4, 0x2B, 0xF9, 0xEC, 0x2D, 114 0xF4, 0x6F, 0xB6, 0x99, 0x88, 0x81, 0x5A, 0xD9, 0xCA, 0x13, 0xA5, 0xE7, 0x47, 115 0xE6, 0x8E, 0x60, 0xE3, 0x3E, 0xB3, 0xF6, 0x72, 0xA2, 0x35, 0xA0, 0xD7, 0xCD, 116 0xB4, 0x2F, 0x6D, 0x2C, 0x26, 0x1F, 0x95, 0x87, 0x00, 0xD8, 0x34, 0x3F, 0x17, 117 0x25, 0x45, 0x27, 0x75, 0x92, 0xB8, 0xA3, 0xC8, 0xDE, 0xEB, 0xF8, 0xF3, 0xDB, 118 0x0A, 0x98, 0x83, 0x7B, 0xE5, 0xCB, 0x4C, 0x78, 0xD1 }; 119 120 static DWORD get_scheme_code(LPCWSTR scheme, DWORD scheme_len) 121 { 122 unsigned int i; 123 124 for(i=0; i < sizeof(shlwapi_schemes)/sizeof(shlwapi_schemes[0]); i++) { 125 if(scheme_len == strlenW(shlwapi_schemes[i].scheme_name) 126 && !memicmpW(scheme, shlwapi_schemes[i].scheme_name, scheme_len)) 127 return shlwapi_schemes[i].scheme_number; 128 } 129 130 return URL_SCHEME_UNKNOWN; 131 } 132 133 /************************************************************************* 134 * @ [SHLWAPI.1] 135 * 136 * Parse a Url into its constituent parts. 137 * 138 * PARAMS 139 * x [I] Url to parse 140 * y [O] Undocumented structure holding the parsed information 141 * 142 * RETURNS 143 * Success: S_OK. y contains the parsed Url details. 144 * Failure: An HRESULT error code. 145 */ 146 HRESULT WINAPI ParseURLA(LPCSTR x, PARSEDURLA *y) 147 { 148 WCHAR scheme[INTERNET_MAX_SCHEME_LENGTH]; 149 const char *ptr = x; 150 int len; 151 152 TRACE("%s %p\n", debugstr_a(x), y); 153 154 if(y->cbSize != sizeof(*y)) 155 return E_INVALIDARG; 156 157 while(*ptr && (isalnum(*ptr) || *ptr == '-' || *ptr == '+' || *ptr == '.')) 158 ptr++; 159 160 if (*ptr != ':' || ptr <= x+1) { 161 y->pszProtocol = NULL; 162 return URL_E_INVALID_SYNTAX; 163 } 164 165 y->pszProtocol = x; 166 y->cchProtocol = ptr-x; 167 y->pszSuffix = ptr+1; 168 y->cchSuffix = strlen(y->pszSuffix); 169 170 len = MultiByteToWideChar(CP_ACP, 0, x, ptr-x, 171 scheme, sizeof(scheme)/sizeof(WCHAR)); 172 y->nScheme = get_scheme_code(scheme, len); 173 174 return S_OK; 175 } 176 177 /************************************************************************* 178 * @ [SHLWAPI.2] 179 * 180 * Unicode version of ParseURLA. 181 */ 182 HRESULT WINAPI ParseURLW(LPCWSTR x, PARSEDURLW *y) 183 { 184 const WCHAR *ptr = x; 185 186 TRACE("%s %p\n", debugstr_w(x), y); 187 188 if(y->cbSize != sizeof(*y)) 189 return E_INVALIDARG; 190 191 while(*ptr && (isalnumW(*ptr) || *ptr == '-' || *ptr == '+' || *ptr == '.')) 192 ptr++; 193 194 if (*ptr != ':' || ptr <= x+1) { 195 y->pszProtocol = NULL; 196 return URL_E_INVALID_SYNTAX; 197 } 198 199 y->pszProtocol = x; 200 y->cchProtocol = ptr-x; 201 y->pszSuffix = ptr+1; 202 y->cchSuffix = strlenW(y->pszSuffix); 203 y->nScheme = get_scheme_code(x, ptr-x); 204 205 return S_OK; 206 } 207 208 /************************************************************************* 209 * UrlCanonicalizeA [SHLWAPI.@] 210 * 211 * Canonicalize a Url. 212 * 213 * PARAMS 214 * pszUrl [I] Url to cCanonicalize 215 * pszCanonicalized [O] Destination for converted Url. 216 * pcchCanonicalized [I/O] Length of pszUrl, destination for length of pszCanonicalized 217 * dwFlags [I] Flags controlling the conversion. 218 * 219 * RETURNS 220 * Success: S_OK. The pszCanonicalized contains the converted Url. 221 * Failure: E_POINTER, if *pcchCanonicalized is too small. 222 * 223 * MSDN incorrectly describes the flags for this function. They should be: 224 *| URL_DONT_ESCAPE_EXTRA_INFO 0x02000000 225 *| URL_ESCAPE_SPACES_ONLY 0x04000000 226 *| URL_ESCAPE_PERCENT 0x00001000 227 *| URL_ESCAPE_UNSAFE 0x10000000 228 *| URL_UNESCAPE 0x10000000 229 *| URL_DONT_SIMPLIFY 0x08000000 230 *| URL_ESCAPE_SEGMENT_ONLY 0x00002000 231 */ 232 HRESULT WINAPI UrlCanonicalizeA(LPCSTR pszUrl, LPSTR pszCanonicalized, 233 LPDWORD pcchCanonicalized, DWORD dwFlags) 234 { 235 LPWSTR url, canonical; 236 HRESULT ret; 237 238 TRACE("(%s, %p, %p, 0x%08x) *pcchCanonicalized: %d\n", debugstr_a(pszUrl), pszCanonicalized, 239 pcchCanonicalized, dwFlags, pcchCanonicalized ? *pcchCanonicalized : -1); 240 241 if(!pszUrl || !pszCanonicalized || !pcchCanonicalized || !*pcchCanonicalized) 242 return E_INVALIDARG; 243 244 url = heap_strdupAtoW(pszUrl); 245 canonical = HeapAlloc(GetProcessHeap(), 0, *pcchCanonicalized*sizeof(WCHAR)); 246 if(!url || !canonical) { 247 HeapFree(GetProcessHeap(), 0, url); 248 HeapFree(GetProcessHeap(), 0, canonical); 249 return E_OUTOFMEMORY; 250 } 251 252 ret = UrlCanonicalizeW(url, canonical, pcchCanonicalized, dwFlags); 253 if(ret == S_OK) 254 WideCharToMultiByte(CP_ACP, 0, canonical, -1, pszCanonicalized, 255 *pcchCanonicalized+1, NULL, NULL); 256 257 HeapFree(GetProcessHeap(), 0, url); 258 HeapFree(GetProcessHeap(), 0, canonical); 259 return ret; 260 } 261 262 /************************************************************************* 263 * UrlCanonicalizeW [SHLWAPI.@] 264 * 265 * See UrlCanonicalizeA. 266 */ 267 HRESULT WINAPI UrlCanonicalizeW(LPCWSTR pszUrl, LPWSTR pszCanonicalized, 268 LPDWORD pcchCanonicalized, DWORD dwFlags) 269 { 270 HRESULT hr = S_OK; 271 DWORD EscapeFlags; 272 LPCWSTR wk1, root; 273 LPWSTR lpszUrlCpy, url, wk2, mp, mp2; 274 INT state; 275 DWORD nByteLen, nLen, nWkLen; 276 BOOL is_file_url; 277 WCHAR slash = '\0'; 278 279 static const WCHAR wszFile[] = {'f','i','l','e',':'}; 280 static const WCHAR wszRes[] = {'r','e','s',':'}; 281 static const WCHAR wszHttp[] = {'h','t','t','p',':'}; 282 static const WCHAR wszLocalhost[] = {'l','o','c','a','l','h','o','s','t'}; 283 static const WCHAR wszFilePrefix[] = {'f','i','l','e',':','/','/','/'}; 284 285 TRACE("(%s, %p, %p, 0x%08x) *pcchCanonicalized: %d\n", debugstr_w(pszUrl), pszCanonicalized, 286 pcchCanonicalized, dwFlags, pcchCanonicalized ? *pcchCanonicalized : -1); 287 288 if(!pszUrl || !pszCanonicalized || !pcchCanonicalized || !*pcchCanonicalized) 289 return E_INVALIDARG; 290 291 if(!*pszUrl) { 292 *pszCanonicalized = 0; 293 return S_OK; 294 } 295 296 /* Remove '\t' characters from URL */ 297 nByteLen = (strlenW(pszUrl) + 1) * sizeof(WCHAR); /* length in bytes */ 298 url = HeapAlloc(GetProcessHeap(), 0, nByteLen); 299 if(!url) 300 return E_OUTOFMEMORY; 301 302 wk1 = pszUrl; 303 wk2 = url; 304 do { 305 while(*wk1 == '\t') 306 wk1++; 307 *wk2++ = *wk1; 308 } while(*wk1++); 309 310 /* Allocate memory for simplified URL (before escaping) */ 311 nByteLen = (wk2-url)*sizeof(WCHAR); 312 lpszUrlCpy = HeapAlloc(GetProcessHeap(), 0, 313 nByteLen+sizeof(wszFilePrefix)+sizeof(WCHAR)); 314 if(!lpszUrlCpy) { 315 HeapFree(GetProcessHeap(), 0, url); 316 return E_OUTOFMEMORY; 317 } 318 319 is_file_url = !strncmpW(wszFile, url, sizeof(wszFile)/sizeof(WCHAR)); 320 321 if ((nByteLen >= sizeof(wszHttp) && 322 !memcmp(wszHttp, url, sizeof(wszHttp))) || is_file_url) 323 slash = '/'; 324 325 if((dwFlags & (URL_FILE_USE_PATHURL | URL_WININET_COMPATIBILITY)) && is_file_url) 326 slash = '\\'; 327 328 if(nByteLen >= sizeof(wszRes) && !memcmp(wszRes, url, sizeof(wszRes))) { 329 dwFlags &= ~URL_FILE_USE_PATHURL; 330 slash = '\0'; 331 } 332 333 /* 334 * state = 335 * 0 initial 1,3 336 * 1 have 2[+] alnum 2,3 337 * 2 have scheme (found :) 4,6,3 338 * 3 failed (no location) 339 * 4 have // 5,3 340 * 5 have 1[+] alnum 6,3 341 * 6 have location (found /) save root location 342 */ 343 344 wk1 = url; 345 wk2 = lpszUrlCpy; 346 state = 0; 347 348 if(url[1] == ':') { /* Assume path */ 349 memcpy(wk2, wszFilePrefix, sizeof(wszFilePrefix)); 350 wk2 += sizeof(wszFilePrefix)/sizeof(WCHAR); 351 if (dwFlags & (URL_FILE_USE_PATHURL | URL_WININET_COMPATIBILITY)) 352 { 353 slash = '\\'; 354 --wk2; 355 } 356 else 357 dwFlags |= URL_ESCAPE_UNSAFE; 358 state = 5; 359 is_file_url = TRUE; 360 } else if(url[0] == '/') { 361 state = 5; 362 is_file_url = TRUE; 363 } 364 365 while (*wk1) { 366 switch (state) { 367 case 0: 368 if (!isalnumW(*wk1)) {state = 3; break;} 369 *wk2++ = *wk1++; 370 if (!isalnumW(*wk1)) {state = 3; break;} 371 *wk2++ = *wk1++; 372 state = 1; 373 break; 374 case 1: 375 *wk2++ = *wk1; 376 if (*wk1++ == ':') state = 2; 377 break; 378 case 2: 379 *wk2++ = *wk1++; 380 if (*wk1 != '/') {state = 6; break;} 381 *wk2++ = *wk1++; 382 if((dwFlags & URL_FILE_USE_PATHURL) && nByteLen >= sizeof(wszLocalhost) 383 && is_file_url 384 && !memcmp(wszLocalhost, wk1, sizeof(wszLocalhost))){ 385 wk1 += sizeof(wszLocalhost)/sizeof(WCHAR); 386 while(*wk1 == '\\' && (dwFlags & URL_FILE_USE_PATHURL)) 387 wk1++; 388 } 389 390 if(*wk1 == '/' && (dwFlags & URL_FILE_USE_PATHURL)){ 391 wk1++; 392 }else if(is_file_url){ 393 const WCHAR *body = wk1; 394 395 while(*body == '/') 396 ++body; 397 398 if(isalnumW(*body) && *(body+1) == ':'){ 399 if(!(dwFlags & (URL_WININET_COMPATIBILITY | URL_FILE_USE_PATHURL))){ 400 if(slash) 401 *wk2++ = slash; 402 else 403 *wk2++ = '/'; 404 } 405 }else{ 406 if(dwFlags & URL_WININET_COMPATIBILITY){ 407 if(*wk1 == '/' && *(wk1+1) != '/'){ 408 *wk2++ = '\\'; 409 }else{ 410 *wk2++ = '\\'; 411 *wk2++ = '\\'; 412 } 413 }else{ 414 if(*wk1 == '/' && *(wk1+1) != '/'){ 415 if(slash) 416 *wk2++ = slash; 417 else 418 *wk2++ = '/'; 419 } 420 } 421 } 422 wk1 = body; 423 } 424 state = 4; 425 break; 426 case 3: 427 nWkLen = strlenW(wk1); 428 memcpy(wk2, wk1, (nWkLen + 1) * sizeof(WCHAR)); 429 mp = wk2; 430 wk1 += nWkLen; 431 wk2 += nWkLen; 432 433 if(slash) { 434 while(mp < wk2) { 435 if(*mp == '/' || *mp == '\\') 436 *mp = slash; 437 mp++; 438 } 439 } 440 break; 441 case 4: 442 if (!isalnumW(*wk1) && (*wk1 != '-') && (*wk1 != '.') && (*wk1 != ':')) 443 {state = 3; break;} 444 while(isalnumW(*wk1) || (*wk1 == '-') || (*wk1 == '.') || (*wk1 == ':')) 445 *wk2++ = *wk1++; 446 state = 5; 447 if (!*wk1) { 448 if(slash) 449 *wk2++ = slash; 450 else 451 *wk2++ = '/'; 452 } 453 break; 454 case 5: 455 if (*wk1 != '/' && *wk1 != '\\') {state = 3; break;} 456 while(*wk1 == '/' || *wk1 == '\\') { 457 if(slash) 458 *wk2++ = slash; 459 else 460 *wk2++ = *wk1; 461 wk1++; 462 } 463 state = 6; 464 break; 465 case 6: 466 if(dwFlags & URL_DONT_SIMPLIFY) { 467 state = 3; 468 break; 469 } 470 471 /* Now at root location, cannot back up any more. */ 472 /* "root" will point at the '/' */ 473 474 root = wk2-1; 475 while (*wk1) { 476 mp = strchrW(wk1, '/'); 477 mp2 = strchrW(wk1, '\\'); 478 if(mp2 && (!mp || mp2 < mp)) 479 mp = mp2; 480 if (!mp) { 481 nWkLen = strlenW(wk1); 482 memcpy(wk2, wk1, (nWkLen + 1) * sizeof(WCHAR)); 483 wk1 += nWkLen; 484 wk2 += nWkLen; 485 continue; 486 } 487 nLen = mp - wk1; 488 if(nLen) { 489 memcpy(wk2, wk1, nLen * sizeof(WCHAR)); 490 wk2 += nLen; 491 wk1 += nLen; 492 } 493 if(slash) 494 *wk2++ = slash; 495 else 496 *wk2++ = *wk1; 497 wk1++; 498 499 while (*wk1 == '.') { 500 TRACE("found '/.'\n"); 501 if (wk1[1] == '/' || wk1[1] == '\\') { 502 /* case of /./ -> skip the ./ */ 503 wk1 += 2; 504 } 505 else if (wk1[1] == '.' && (wk1[2] == '/' 506 || wk1[2] == '\\' || wk1[2] == '?' 507 || wk1[2] == '#' || !wk1[2])) { 508 /* case /../ -> need to backup wk2 */ 509 TRACE("found '/../'\n"); 510 *(wk2-1) = '\0'; /* set end of string */ 511 mp = strrchrW(root, '/'); 512 mp2 = strrchrW(root, '\\'); 513 if(mp2 && (!mp || mp2 < mp)) 514 mp = mp2; 515 if (mp && (mp >= root)) { 516 /* found valid backup point */ 517 wk2 = mp + 1; 518 if(wk1[2] != '/' && wk1[2] != '\\') 519 wk1 += 2; 520 else 521 wk1 += 3; 522 } 523 else { 524 /* did not find point, restore '/' */ 525 *(wk2-1) = slash; 526 break; 527 } 528 } 529 else 530 break; 531 } 532 } 533 *wk2 = '\0'; 534 break; 535 default: 536 FIXME("how did we get here - state=%d\n", state); 537 HeapFree(GetProcessHeap(), 0, lpszUrlCpy); 538 HeapFree(GetProcessHeap(), 0, url); 539 return E_INVALIDARG; 540 } 541 *wk2 = '\0'; 542 TRACE("Simplified, orig <%s>, simple <%s>\n", 543 debugstr_w(pszUrl), debugstr_w(lpszUrlCpy)); 544 } 545 nLen = lstrlenW(lpszUrlCpy); 546 while ((nLen > 0) && ((lpszUrlCpy[nLen-1] <= ' '))) 547 lpszUrlCpy[--nLen]=0; 548 549 if((dwFlags & URL_UNESCAPE) || 550 ((dwFlags & URL_FILE_USE_PATHURL) && nByteLen >= sizeof(wszFile) 551 && !memcmp(wszFile, url, sizeof(wszFile)))) 552 UrlUnescapeW(lpszUrlCpy, NULL, &nLen, URL_UNESCAPE_INPLACE); 553 554 if((EscapeFlags = dwFlags & (URL_ESCAPE_UNSAFE | 555 URL_ESCAPE_SPACES_ONLY | 556 URL_ESCAPE_PERCENT | 557 URL_DONT_ESCAPE_EXTRA_INFO | 558 URL_ESCAPE_SEGMENT_ONLY ))) { 559 EscapeFlags &= ~URL_ESCAPE_UNSAFE; 560 hr = UrlEscapeW(lpszUrlCpy, pszCanonicalized, pcchCanonicalized, 561 EscapeFlags); 562 } else { /* No escaping needed, just copy the string */ 563 nLen = lstrlenW(lpszUrlCpy); 564 if(nLen < *pcchCanonicalized) 565 memcpy(pszCanonicalized, lpszUrlCpy, (nLen + 1)*sizeof(WCHAR)); 566 else { 567 hr = E_POINTER; 568 nLen++; 569 } 570 *pcchCanonicalized = nLen; 571 } 572 573 HeapFree(GetProcessHeap(), 0, lpszUrlCpy); 574 HeapFree(GetProcessHeap(), 0, url); 575 576 if (hr == S_OK) 577 TRACE("result %s\n", debugstr_w(pszCanonicalized)); 578 579 return hr; 580 } 581 582 /************************************************************************* 583 * UrlCombineA [SHLWAPI.@] 584 * 585 * Combine two Urls. 586 * 587 * PARAMS 588 * pszBase [I] Base Url 589 * pszRelative [I] Url to combine with pszBase 590 * pszCombined [O] Destination for combined Url 591 * pcchCombined [O] Destination for length of pszCombined 592 * dwFlags [I] URL_ flags from "shlwapi.h" 593 * 594 * RETURNS 595 * Success: S_OK. pszCombined contains the combined Url, pcchCombined 596 * contains its length. 597 * Failure: An HRESULT error code indicating the error. 598 */ 599 HRESULT WINAPI UrlCombineA(LPCSTR pszBase, LPCSTR pszRelative, 600 LPSTR pszCombined, LPDWORD pcchCombined, 601 DWORD dwFlags) 602 { 603 LPWSTR base, relative, combined; 604 DWORD ret, len, len2; 605 606 TRACE("(base %s, Relative %s, Combine size %d, flags %08x) using W version\n", 607 debugstr_a(pszBase),debugstr_a(pszRelative), 608 pcchCombined?*pcchCombined:0,dwFlags); 609 610 if(!pszBase || !pszRelative || !pcchCombined) 611 return E_INVALIDARG; 612 613 base = HeapAlloc(GetProcessHeap(), 0, 614 (3*INTERNET_MAX_URL_LENGTH) * sizeof(WCHAR)); 615 relative = base + INTERNET_MAX_URL_LENGTH; 616 combined = relative + INTERNET_MAX_URL_LENGTH; 617 618 MultiByteToWideChar(CP_ACP, 0, pszBase, -1, base, INTERNET_MAX_URL_LENGTH); 619 MultiByteToWideChar(CP_ACP, 0, pszRelative, -1, relative, INTERNET_MAX_URL_LENGTH); 620 len = *pcchCombined; 621 622 ret = UrlCombineW(base, relative, pszCombined?combined:NULL, &len, dwFlags); 623 if (ret != S_OK) { 624 *pcchCombined = len; 625 HeapFree(GetProcessHeap(), 0, base); 626 return ret; 627 } 628 629 len2 = WideCharToMultiByte(CP_ACP, 0, combined, len, NULL, 0, NULL, NULL); 630 if (len2 > *pcchCombined) { 631 *pcchCombined = len2; 632 HeapFree(GetProcessHeap(), 0, base); 633 return E_POINTER; 634 } 635 WideCharToMultiByte(CP_ACP, 0, combined, len+1, pszCombined, (*pcchCombined)+1, 636 NULL, NULL); 637 *pcchCombined = len2; 638 HeapFree(GetProcessHeap(), 0, base); 639 return S_OK; 640 } 641 642 /************************************************************************* 643 * UrlCombineW [SHLWAPI.@] 644 * 645 * See UrlCombineA. 646 */ 647 HRESULT WINAPI UrlCombineW(LPCWSTR pszBase, LPCWSTR pszRelative, 648 LPWSTR pszCombined, LPDWORD pcchCombined, 649 DWORD dwFlags) 650 { 651 PARSEDURLW base, relative; 652 DWORD myflags, sizeloc = 0; 653 DWORD i, len, res1, res2, process_case = 0; 654 LPWSTR work, preliminary, mbase, mrelative; 655 static const WCHAR myfilestr[] = {'f','i','l','e',':','/','/','/','\0'}; 656 static const WCHAR fragquerystr[] = {'#','?',0}; 657 HRESULT ret; 658 659 TRACE("(base %s, Relative %s, Combine size %d, flags %08x)\n", 660 debugstr_w(pszBase),debugstr_w(pszRelative), 661 pcchCombined?*pcchCombined:0,dwFlags); 662 663 if(!pszBase || !pszRelative || !pcchCombined) 664 return E_INVALIDARG; 665 666 base.cbSize = sizeof(base); 667 relative.cbSize = sizeof(relative); 668 669 /* Get space for duplicates of the input and the output */ 670 preliminary = HeapAlloc(GetProcessHeap(), 0, (3*INTERNET_MAX_URL_LENGTH) * 671 sizeof(WCHAR)); 672 mbase = preliminary + INTERNET_MAX_URL_LENGTH; 673 mrelative = mbase + INTERNET_MAX_URL_LENGTH; 674 *preliminary = '\0'; 675 676 /* Canonicalize the base input prior to looking for the scheme */ 677 myflags = dwFlags & (URL_DONT_SIMPLIFY | URL_UNESCAPE); 678 len = INTERNET_MAX_URL_LENGTH; 679 UrlCanonicalizeW(pszBase, mbase, &len, myflags); 680 681 /* Canonicalize the relative input prior to looking for the scheme */ 682 len = INTERNET_MAX_URL_LENGTH; 683 UrlCanonicalizeW(pszRelative, mrelative, &len, myflags); 684 685 /* See if the base has a scheme */ 686 res1 = ParseURLW(mbase, &base); 687 if (res1) { 688 /* if pszBase has no scheme, then return pszRelative */ 689 TRACE("no scheme detected in Base\n"); 690 process_case = 1; 691 } 692 else do { 693 BOOL manual_search = FALSE; 694 695 work = (LPWSTR)base.pszProtocol; 696 for(i=0; i<base.cchProtocol; i++) 697 work[i] = tolowerW(work[i]); 698 699 /* mk is a special case */ 700 if(base.nScheme == URL_SCHEME_MK) { 701 static const WCHAR wsz[] = {':',':',0}; 702 703 WCHAR *ptr = strstrW(base.pszSuffix, wsz); 704 if(ptr) { 705 int delta; 706 707 ptr += 2; 708 delta = ptr-base.pszSuffix; 709 base.cchProtocol += delta; 710 base.pszSuffix += delta; 711 base.cchSuffix -= delta; 712 } 713 }else { 714 /* get size of location field (if it exists) */ 715 work = (LPWSTR)base.pszSuffix; 716 sizeloc = 0; 717 if (*work++ == '/') { 718 if (*work++ == '/') { 719 /* At this point have start of location and 720 * it ends at next '/' or end of string. 721 */ 722 while(*work && (*work != '/')) work++; 723 sizeloc = (DWORD)(work - base.pszSuffix); 724 } 725 } 726 } 727 728 /* If there is a '?', then the remaining part can only contain a 729 * query string or fragment, so start looking for the last leaf 730 * from the '?'. Otherwise, if there is a '#' and the characters 731 * immediately preceding it are ".htm[l]", then begin looking for 732 * the last leaf starting from the '#'. Otherwise the '#' is not 733 * meaningful and just start looking from the end. */ 734 if ((work = strpbrkW(base.pszSuffix + sizeloc, fragquerystr))) { 735 const WCHAR htmlW[] = {'.','h','t','m','l',0}; 736 const int len_htmlW = 5; 737 const WCHAR htmW[] = {'.','h','t','m',0}; 738 const int len_htmW = 4; 739 740 if (*work == '?' || base.nScheme == URL_SCHEME_HTTP || base.nScheme == URL_SCHEME_HTTPS) 741 manual_search = TRUE; 742 else if (work - base.pszSuffix > len_htmW) { 743 work -= len_htmW; 744 if (strncmpiW(work, htmW, len_htmW) == 0) 745 manual_search = TRUE; 746 work += len_htmW; 747 } 748 749 if (!manual_search && 750 work - base.pszSuffix > len_htmlW) { 751 work -= len_htmlW; 752 if (strncmpiW(work, htmlW, len_htmlW) == 0) 753 manual_search = TRUE; 754 work += len_htmlW; 755 } 756 } 757 758 if (manual_search) { 759 /* search backwards starting from the current position */ 760 while (*work != '/' && work > base.pszSuffix + sizeloc) 761 --work; 762 base.cchSuffix = work - base.pszSuffix + 1; 763 }else { 764 /* search backwards starting from the end of the string */ 765 work = strrchrW((base.pszSuffix+sizeloc), '/'); 766 if (work) { 767 len = (DWORD)(work - base.pszSuffix + 1); 768 base.cchSuffix = len; 769 }else 770 base.cchSuffix = sizeloc; 771 } 772 773 /* 774 * At this point: 775 * .pszSuffix points to location (starting with '//') 776 * .cchSuffix length of location (above) and rest less the last 777 * leaf (if any) 778 * sizeloc length of location (above) up to but not including 779 * the last '/' 780 */ 781 782 res2 = ParseURLW(mrelative, &relative); 783 if (res2) { 784 /* no scheme in pszRelative */ 785 TRACE("no scheme detected in Relative\n"); 786 relative.pszSuffix = mrelative; /* case 3,4,5 depends on this */ 787 relative.cchSuffix = strlenW(mrelative); 788 if (*pszRelative == ':') { 789 /* case that is either left alone or uses pszBase */ 790 if (dwFlags & URL_PLUGGABLE_PROTOCOL) { 791 process_case = 5; 792 break; 793 } 794 process_case = 1; 795 break; 796 } 797 if (isalnumW(*mrelative) && (*(mrelative + 1) == ':')) { 798 /* case that becomes "file:///" */ 799 strcpyW(preliminary, myfilestr); 800 process_case = 1; 801 break; 802 } 803 if ((*mrelative == '/') && (*(mrelative+1) == '/')) { 804 /* pszRelative has location and rest */ 805 process_case = 3; 806 break; 807 } 808 if (*mrelative == '/') { 809 /* case where pszRelative is root to location */ 810 process_case = 4; 811 break; 812 } 813 if (*mrelative == '#') { 814 if(!(work = strchrW(base.pszSuffix+base.cchSuffix, '#'))) 815 work = (LPWSTR)base.pszSuffix + strlenW(base.pszSuffix); 816 817 memcpy(preliminary, base.pszProtocol, (work-base.pszProtocol)*sizeof(WCHAR)); 818 preliminary[work-base.pszProtocol] = '\0'; 819 process_case = 1; 820 break; 821 } 822 process_case = (*base.pszSuffix == '/' || base.nScheme == URL_SCHEME_MK) ? 5 : 3; 823 break; 824 }else { 825 work = (LPWSTR)relative.pszProtocol; 826 for(i=0; i<relative.cchProtocol; i++) 827 work[i] = tolowerW(work[i]); 828 } 829 830 /* handle cases where pszRelative has scheme */ 831 if ((base.cchProtocol == relative.cchProtocol) && 832 (strncmpW(base.pszProtocol, relative.pszProtocol, base.cchProtocol) == 0)) { 833 834 /* since the schemes are the same */ 835 if ((*relative.pszSuffix == '/') && (*(relative.pszSuffix+1) == '/')) { 836 /* case where pszRelative replaces location and following */ 837 process_case = 3; 838 break; 839 } 840 if (*relative.pszSuffix == '/') { 841 /* case where pszRelative is root to location */ 842 process_case = 4; 843 break; 844 } 845 /* replace either just location if base's location starts with a 846 * slash or otherwise everything */ 847 process_case = (*base.pszSuffix == '/') ? 5 : 1; 848 break; 849 } 850 if ((*relative.pszSuffix == '/') && (*(relative.pszSuffix+1) == '/')) { 851 /* case where pszRelative replaces scheme, location, 852 * and following and handles PLUGGABLE 853 */ 854 process_case = 2; 855 break; 856 } 857 process_case = 1; 858 break; 859 } while(FALSE); /* a little trick to allow easy exit from nested if's */ 860 861 ret = S_OK; 862 switch (process_case) { 863 864 case 1: /* 865 * Return pszRelative appended to what ever is in pszCombined, 866 * (which may the string "file:///" 867 */ 868 strcatW(preliminary, mrelative); 869 break; 870 871 case 2: /* case where pszRelative replaces scheme, and location */ 872 strcpyW(preliminary, mrelative); 873 break; 874 875 case 3: /* 876 * Return the pszBase scheme with pszRelative. Basically 877 * keeps the scheme and replaces the domain and following. 878 */ 879 memcpy(preliminary, base.pszProtocol, (base.cchProtocol + 1)*sizeof(WCHAR)); 880 work = preliminary + base.cchProtocol + 1; 881 strcpyW(work, relative.pszSuffix); 882 break; 883 884 case 4: /* 885 * Return the pszBase scheme and location but everything 886 * after the location is pszRelative. (Replace document 887 * from root on.) 888 */ 889 memcpy(preliminary, base.pszProtocol, (base.cchProtocol+1+sizeloc)*sizeof(WCHAR)); 890 work = preliminary + base.cchProtocol + 1 + sizeloc; 891 if (dwFlags & URL_PLUGGABLE_PROTOCOL) 892 *(work++) = '/'; 893 strcpyW(work, relative.pszSuffix); 894 break; 895 896 case 5: /* 897 * Return the pszBase without its document (if any) and 898 * append pszRelative after its scheme. 899 */ 900 memcpy(preliminary, base.pszProtocol, 901 (base.cchProtocol+1+base.cchSuffix)*sizeof(WCHAR)); 902 work = preliminary + base.cchProtocol+1+base.cchSuffix - 1; 903 if (*work++ != '/') 904 *(work++) = '/'; 905 strcpyW(work, relative.pszSuffix); 906 break; 907 908 default: 909 FIXME("How did we get here????? process_case=%d\n", process_case); 910 ret = E_INVALIDARG; 911 } 912 913 if (ret == S_OK) { 914 /* Reuse mrelative as temp storage as it's already allocated and not needed anymore */ 915 if(*pcchCombined == 0) 916 *pcchCombined = 1; 917 ret = UrlCanonicalizeW(preliminary, mrelative, pcchCombined, (dwFlags & ~URL_FILE_USE_PATHURL)); 918 if(SUCCEEDED(ret) && pszCombined) { 919 lstrcpyW(pszCombined, mrelative); 920 } 921 TRACE("return-%d len=%d, %s\n", 922 process_case, *pcchCombined, debugstr_w(pszCombined)); 923 } 924 HeapFree(GetProcessHeap(), 0, preliminary); 925 return ret; 926 } 927 928 /************************************************************************* 929 * UrlEscapeA [SHLWAPI.@] 930 */ 931 932 HRESULT WINAPI UrlEscapeA( 933 LPCSTR pszUrl, 934 LPSTR pszEscaped, 935 LPDWORD pcchEscaped, 936 DWORD dwFlags) 937 { 938 WCHAR bufW[INTERNET_MAX_URL_LENGTH]; 939 WCHAR *escapedW = bufW; 940 UNICODE_STRING urlW; 941 HRESULT ret; 942 DWORD lenW = sizeof(bufW)/sizeof(WCHAR), lenA; 943 944 if (!pszEscaped || !pcchEscaped || !*pcchEscaped) 945 return E_INVALIDARG; 946 947 if(!RtlCreateUnicodeStringFromAsciiz(&urlW, pszUrl)) 948 return E_INVALIDARG; 949 if(dwFlags & URL_ESCAPE_AS_UTF8) { 950 RtlFreeUnicodeString(&urlW); 951 return E_NOTIMPL; 952 } 953 if((ret = UrlEscapeW(urlW.Buffer, escapedW, &lenW, dwFlags)) == E_POINTER) { 954 escapedW = HeapAlloc(GetProcessHeap(), 0, lenW * sizeof(WCHAR)); 955 ret = UrlEscapeW(urlW.Buffer, escapedW, &lenW, dwFlags); 956 } 957 if(ret == S_OK) { 958 RtlUnicodeToMultiByteSize(&lenA, escapedW, lenW * sizeof(WCHAR)); 959 if(*pcchEscaped > lenA) { 960 RtlUnicodeToMultiByteN(pszEscaped, *pcchEscaped - 1, &lenA, escapedW, lenW * sizeof(WCHAR)); 961 pszEscaped[lenA] = 0; 962 *pcchEscaped = lenA; 963 } else { 964 *pcchEscaped = lenA + 1; 965 ret = E_POINTER; 966 } 967 } 968 if(escapedW != bufW) HeapFree(GetProcessHeap(), 0, escapedW); 969 RtlFreeUnicodeString(&urlW); 970 return ret; 971 } 972 973 #define WINE_URL_BASH_AS_SLASH 0x01 974 #define WINE_URL_COLLAPSE_SLASHES 0x02 975 #define WINE_URL_ESCAPE_SLASH 0x04 976 #define WINE_URL_ESCAPE_HASH 0x08 977 #define WINE_URL_ESCAPE_QUESTION 0x10 978 #define WINE_URL_STOP_ON_HASH 0x20 979 #define WINE_URL_STOP_ON_QUESTION 0x40 980 981 static inline BOOL URL_NeedEscapeW(WCHAR ch, DWORD flags, DWORD int_flags) 982 { 983 if (flags & URL_ESCAPE_SPACES_ONLY) 984 return ch == ' '; 985 986 if ((flags & URL_ESCAPE_PERCENT) && (ch == '%')) 987 return TRUE; 988 989 if ((flags & URL_ESCAPE_AS_UTF8) && (ch >= 0x80)) 990 return TRUE; 991 992 if (ch <= 31 || (ch >= 127 && ch <= 255) ) 993 return TRUE; 994 995 if (isalnumW(ch)) 996 return FALSE; 997 998 switch (ch) { 999 case ' ': 1000 case '<': 1001 case '>': 1002 case '\"': 1003 case '{': 1004 case '}': 1005 case '|': 1006 case '\\': 1007 case '^': 1008 case ']': 1009 case '[': 1010 case '`': 1011 case '&': 1012 return TRUE; 1013 case '/': 1014 return !!(int_flags & WINE_URL_ESCAPE_SLASH); 1015 case '?': 1016 return !!(int_flags & WINE_URL_ESCAPE_QUESTION); 1017 case '#': 1018 return !!(int_flags & WINE_URL_ESCAPE_HASH); 1019 default: 1020 return FALSE; 1021 } 1022 } 1023 1024 1025 /************************************************************************* 1026 * UrlEscapeW [SHLWAPI.@] 1027 * 1028 * Converts unsafe characters in a Url into escape sequences. 1029 * 1030 * PARAMS 1031 * pszUrl [I] Url to modify 1032 * pszEscaped [O] Destination for modified Url 1033 * pcchEscaped [I/O] Length of pszUrl, destination for length of pszEscaped 1034 * dwFlags [I] URL_ flags from "shlwapi.h" 1035 * 1036 * RETURNS 1037 * Success: S_OK. pszEscaped contains the escaped Url, pcchEscaped 1038 * contains its length. 1039 * Failure: E_POINTER, if pszEscaped is not large enough. In this case 1040 * pcchEscaped is set to the required length. 1041 * 1042 * Converts unsafe characters into their escape sequences. 1043 * 1044 * NOTES 1045 * - By default this function stops converting at the first '?' or 1046 * '#' character. 1047 * - If dwFlags contains URL_ESCAPE_SPACES_ONLY then only spaces are 1048 * converted, but the conversion continues past a '?' or '#'. 1049 * - Note that this function did not work well (or at all) in shlwapi version 4. 1050 * 1051 * BUGS 1052 * Only the following flags are implemented: 1053 *| URL_ESCAPE_SPACES_ONLY 1054 *| URL_DONT_ESCAPE_EXTRA_INFO 1055 *| URL_ESCAPE_SEGMENT_ONLY 1056 *| URL_ESCAPE_PERCENT 1057 */ 1058 HRESULT WINAPI UrlEscapeW( 1059 LPCWSTR pszUrl, 1060 LPWSTR pszEscaped, 1061 LPDWORD pcchEscaped, 1062 DWORD dwFlags) 1063 { 1064 LPCWSTR src; 1065 DWORD needed = 0, ret; 1066 BOOL stop_escaping = FALSE; 1067 WCHAR next[12], *dst, *dst_ptr; 1068 INT i, len; 1069 PARSEDURLW parsed_url; 1070 DWORD int_flags; 1071 DWORD slashes = 0; 1072 static const WCHAR localhost[] = {'l','o','c','a','l','h','o','s','t',0}; 1073 1074 TRACE("(%p(%s) %p %p 0x%08x)\n", pszUrl, debugstr_w(pszUrl), 1075 pszEscaped, pcchEscaped, dwFlags); 1076 1077 if(!pszUrl || !pcchEscaped || !pszEscaped || *pcchEscaped == 0) 1078 return E_INVALIDARG; 1079 1080 if(dwFlags & ~(URL_ESCAPE_SPACES_ONLY | 1081 URL_ESCAPE_SEGMENT_ONLY | 1082 URL_DONT_ESCAPE_EXTRA_INFO | 1083 URL_ESCAPE_PERCENT | 1084 URL_ESCAPE_AS_UTF8)) 1085 FIXME("Unimplemented flags: %08x\n", dwFlags); 1086 1087 dst_ptr = dst = HeapAlloc(GetProcessHeap(), 0, *pcchEscaped*sizeof(WCHAR)); 1088 if(!dst_ptr) 1089 return E_OUTOFMEMORY; 1090 1091 /* fix up flags */ 1092 if (dwFlags & URL_ESCAPE_SPACES_ONLY) 1093 /* if SPACES_ONLY specified, reset the other controls */ 1094 dwFlags &= ~(URL_DONT_ESCAPE_EXTRA_INFO | 1095 URL_ESCAPE_PERCENT | 1096 URL_ESCAPE_SEGMENT_ONLY); 1097 1098 else 1099 /* if SPACES_ONLY *not* specified the assume DONT_ESCAPE_EXTRA_INFO */ 1100 dwFlags |= URL_DONT_ESCAPE_EXTRA_INFO; 1101 1102 1103 int_flags = 0; 1104 if(dwFlags & URL_ESCAPE_SEGMENT_ONLY) { 1105 int_flags = WINE_URL_ESCAPE_QUESTION | WINE_URL_ESCAPE_HASH | WINE_URL_ESCAPE_SLASH; 1106 } else { 1107 parsed_url.cbSize = sizeof(parsed_url); 1108 if(ParseURLW(pszUrl, &parsed_url) != S_OK) 1109 parsed_url.nScheme = URL_SCHEME_INVALID; 1110 1111 TRACE("scheme = %d (%s)\n", parsed_url.nScheme, debugstr_wn(parsed_url.pszProtocol, parsed_url.cchProtocol)); 1112 1113 if(dwFlags & URL_DONT_ESCAPE_EXTRA_INFO) 1114 int_flags = WINE_URL_STOP_ON_HASH | WINE_URL_STOP_ON_QUESTION; 1115 1116 switch(parsed_url.nScheme) { 1117 case URL_SCHEME_FILE: 1118 int_flags |= WINE_URL_BASH_AS_SLASH | WINE_URL_COLLAPSE_SLASHES | WINE_URL_ESCAPE_HASH; 1119 int_flags &= ~WINE_URL_STOP_ON_HASH; 1120 break; 1121 1122 case URL_SCHEME_HTTP: 1123 case URL_SCHEME_HTTPS: 1124 int_flags |= WINE_URL_BASH_AS_SLASH; 1125 if(parsed_url.pszSuffix[0] != '/' && parsed_url.pszSuffix[0] != '\\') 1126 int_flags |= WINE_URL_ESCAPE_SLASH; 1127 break; 1128 1129 case URL_SCHEME_MAILTO: 1130 int_flags |= WINE_URL_ESCAPE_SLASH | WINE_URL_ESCAPE_QUESTION | WINE_URL_ESCAPE_HASH; 1131 int_flags &= ~(WINE_URL_STOP_ON_QUESTION | WINE_URL_STOP_ON_HASH); 1132 break; 1133 1134 case URL_SCHEME_INVALID: 1135 break; 1136 1137 case URL_SCHEME_FTP: 1138 default: 1139 if(parsed_url.pszSuffix[0] != '/') 1140 int_flags |= WINE_URL_ESCAPE_SLASH; 1141 break; 1142 } 1143 } 1144 1145 for(src = pszUrl; *src; ) { 1146 WCHAR cur = *src; 1147 len = 0; 1148 1149 if((int_flags & WINE_URL_COLLAPSE_SLASHES) && src == pszUrl + parsed_url.cchProtocol + 1) { 1150 int localhost_len = sizeof(localhost)/sizeof(WCHAR) - 1; 1151 while(cur == '/' || cur == '\\') { 1152 slashes++; 1153 cur = *++src; 1154 } 1155 if(slashes == 2 && !strncmpiW(src, localhost, localhost_len)) { /* file://localhost/ -> file:/// */ 1156 if(*(src + localhost_len) == '/' || *(src + localhost_len) == '\\') 1157 src += localhost_len + 1; 1158 slashes = 3; 1159 } 1160 1161 switch(slashes) { 1162 case 1: 1163 case 3: 1164 next[0] = next[1] = next[2] = '/'; 1165 len = 3; 1166 break; 1167 case 0: 1168 len = 0; 1169 break; 1170 default: 1171 next[0] = next[1] = '/'; 1172 len = 2; 1173 break; 1174 } 1175 } 1176 if(len == 0) { 1177 1178 if(cur == '#' && (int_flags & WINE_URL_STOP_ON_HASH)) 1179 stop_escaping = TRUE; 1180 1181 if(cur == '?' && (int_flags & WINE_URL_STOP_ON_QUESTION)) 1182 stop_escaping = TRUE; 1183 1184 if(cur == '\\' && (int_flags & WINE_URL_BASH_AS_SLASH) && !stop_escaping) cur = '/'; 1185 1186 if(URL_NeedEscapeW(cur, dwFlags, int_flags) && stop_escaping == FALSE) { 1187 if(dwFlags & URL_ESCAPE_AS_UTF8) { 1188 char utf[16]; 1189 1190 if ((cur >= 0xd800 && cur <= 0xdfff) && 1191 (src[1] >= 0xdc00 && src[1] <= 0xdfff)) 1192 { 1193 #ifdef __REACTOS__ 1194 len = WideCharToMultiByte( CP_UTF8, 0, src, 2, 1195 utf, sizeof(utf), NULL, NULL ); 1196 #else 1197 len = WideCharToMultiByte( CP_UTF8, WC_ERR_INVALID_CHARS, src, 2, 1198 utf, sizeof(utf), NULL, NULL ); 1199 #endif 1200 src++; 1201 } 1202 else 1203 #ifdef __REACTOS__ 1204 len = WideCharToMultiByte( CP_UTF8, 0, &cur, 1, 1205 utf, sizeof(utf), NULL, NULL ); 1206 #else 1207 len = WideCharToMultiByte( CP_UTF8, WC_ERR_INVALID_CHARS, &cur, 1, 1208 utf, sizeof(utf), NULL, NULL ); 1209 #endif 1210 1211 if (!len) { 1212 utf[0] = 0xef; 1213 utf[1] = 0xbf; 1214 utf[2] = 0xbd; 1215 len = 3; 1216 } 1217 1218 for(i = 0; i < len; i++) { 1219 next[i*3+0] = '%'; 1220 next[i*3+1] = hexDigits[(utf[i] >> 4) & 0xf]; 1221 next[i*3+2] = hexDigits[utf[i] & 0xf]; 1222 } 1223 len *= 3; 1224 } else { 1225 next[0] = '%'; 1226 next[1] = hexDigits[(cur >> 4) & 0xf]; 1227 next[2] = hexDigits[cur & 0xf]; 1228 len = 3; 1229 } 1230 } else { 1231 next[0] = cur; 1232 len = 1; 1233 } 1234 src++; 1235 } 1236 1237 if(needed + len <= *pcchEscaped) { 1238 memcpy(dst, next, len*sizeof(WCHAR)); 1239 dst += len; 1240 } 1241 needed += len; 1242 } 1243 1244 if(needed < *pcchEscaped) { 1245 *dst = '\0'; 1246 memcpy(pszEscaped, dst_ptr, (needed+1)*sizeof(WCHAR)); 1247 1248 ret = S_OK; 1249 } else { 1250 needed++; /* add one for the '\0' */ 1251 ret = E_POINTER; 1252 } 1253 *pcchEscaped = needed; 1254 1255 HeapFree(GetProcessHeap(), 0, dst_ptr); 1256 return ret; 1257 } 1258 1259 1260 /************************************************************************* 1261 * UrlUnescapeA [SHLWAPI.@] 1262 * 1263 * Converts Url escape sequences back to ordinary characters. 1264 * 1265 * PARAMS 1266 * pszUrl [I/O] Url to convert 1267 * pszUnescaped [O] Destination for converted Url 1268 * pcchUnescaped [I/O] Size of output string 1269 * dwFlags [I] URL_ESCAPE_ Flags from "shlwapi.h" 1270 * 1271 * RETURNS 1272 * Success: S_OK. The converted value is in pszUnescaped, or in pszUrl if 1273 * dwFlags includes URL_ESCAPE_INPLACE. 1274 * Failure: E_POINTER if the converted Url is bigger than pcchUnescaped. In 1275 * this case pcchUnescaped is set to the size required. 1276 * NOTES 1277 * If dwFlags includes URL_DONT_ESCAPE_EXTRA_INFO, the conversion stops at 1278 * the first occurrence of either a '?' or '#' character. 1279 */ 1280 HRESULT WINAPI UrlUnescapeA( 1281 LPSTR pszUrl, 1282 LPSTR pszUnescaped, 1283 LPDWORD pcchUnescaped, 1284 DWORD dwFlags) 1285 { 1286 char *dst, next; 1287 LPCSTR src; 1288 HRESULT ret; 1289 DWORD needed; 1290 BOOL stop_unescaping = FALSE; 1291 1292 TRACE("(%s, %p, %p, 0x%08x)\n", debugstr_a(pszUrl), pszUnescaped, 1293 pcchUnescaped, dwFlags); 1294 1295 if (!pszUrl) return E_INVALIDARG; 1296 1297 if(dwFlags & URL_UNESCAPE_INPLACE) 1298 dst = pszUrl; 1299 else 1300 { 1301 if (!pszUnescaped || !pcchUnescaped) return E_INVALIDARG; 1302 dst = pszUnescaped; 1303 } 1304 1305 for(src = pszUrl, needed = 0; *src; src++, needed++) { 1306 if(dwFlags & URL_DONT_UNESCAPE_EXTRA_INFO && 1307 (*src == '#' || *src == '?')) { 1308 stop_unescaping = TRUE; 1309 next = *src; 1310 } else if(*src == '%' && isxdigit(*(src + 1)) && isxdigit(*(src + 2)) 1311 && stop_unescaping == FALSE) { 1312 INT ih; 1313 char buf[3]; 1314 memcpy(buf, src + 1, 2); 1315 buf[2] = '\0'; 1316 ih = strtol(buf, NULL, 16); 1317 next = (CHAR) ih; 1318 src += 2; /* Advance to end of escape */ 1319 } else 1320 next = *src; 1321 1322 if(dwFlags & URL_UNESCAPE_INPLACE || needed < *pcchUnescaped) 1323 *dst++ = next; 1324 } 1325 1326 if(dwFlags & URL_UNESCAPE_INPLACE || needed < *pcchUnescaped) { 1327 *dst = '\0'; 1328 ret = S_OK; 1329 } else { 1330 needed++; /* add one for the '\0' */ 1331 ret = E_POINTER; 1332 } 1333 if(!(dwFlags & URL_UNESCAPE_INPLACE)) 1334 *pcchUnescaped = needed; 1335 1336 if (ret == S_OK) { 1337 TRACE("result %s\n", (dwFlags & URL_UNESCAPE_INPLACE) ? 1338 debugstr_a(pszUrl) : debugstr_a(pszUnescaped)); 1339 } 1340 1341 return ret; 1342 } 1343 1344 /************************************************************************* 1345 * UrlUnescapeW [SHLWAPI.@] 1346 * 1347 * See UrlUnescapeA. 1348 */ 1349 HRESULT WINAPI UrlUnescapeW( 1350 LPWSTR pszUrl, 1351 LPWSTR pszUnescaped, 1352 LPDWORD pcchUnescaped, 1353 DWORD dwFlags) 1354 { 1355 WCHAR *dst, next; 1356 LPCWSTR src; 1357 HRESULT ret; 1358 DWORD needed; 1359 BOOL stop_unescaping = FALSE; 1360 1361 TRACE("(%s, %p, %p, 0x%08x)\n", debugstr_w(pszUrl), pszUnescaped, 1362 pcchUnescaped, dwFlags); 1363 1364 if(!pszUrl) return E_INVALIDARG; 1365 1366 if(dwFlags & URL_UNESCAPE_INPLACE) 1367 dst = pszUrl; 1368 else 1369 { 1370 if (!pszUnescaped || !pcchUnescaped) return E_INVALIDARG; 1371 dst = pszUnescaped; 1372 } 1373 1374 for(src = pszUrl, needed = 0; *src; src++, needed++) { 1375 if(dwFlags & URL_DONT_UNESCAPE_EXTRA_INFO && 1376 (*src == '#' || *src == '?')) { 1377 stop_unescaping = TRUE; 1378 next = *src; 1379 } else if(*src == '%' && isxdigitW(*(src + 1)) && isxdigitW(*(src + 2)) 1380 && stop_unescaping == FALSE) { 1381 INT ih; 1382 WCHAR buf[5] = {'0','x',0}; 1383 memcpy(buf + 2, src + 1, 2*sizeof(WCHAR)); 1384 buf[4] = 0; 1385 StrToIntExW(buf, STIF_SUPPORT_HEX, &ih); 1386 next = (WCHAR) ih; 1387 src += 2; /* Advance to end of escape */ 1388 } else 1389 next = *src; 1390 1391 if(dwFlags & URL_UNESCAPE_INPLACE || needed < *pcchUnescaped) 1392 *dst++ = next; 1393 } 1394 1395 if(dwFlags & URL_UNESCAPE_INPLACE || needed < *pcchUnescaped) { 1396 *dst = '\0'; 1397 ret = S_OK; 1398 } else { 1399 needed++; /* add one for the '\0' */ 1400 ret = E_POINTER; 1401 } 1402 if(!(dwFlags & URL_UNESCAPE_INPLACE)) 1403 *pcchUnescaped = needed; 1404 1405 if (ret == S_OK) { 1406 TRACE("result %s\n", (dwFlags & URL_UNESCAPE_INPLACE) ? 1407 debugstr_w(pszUrl) : debugstr_w(pszUnescaped)); 1408 } 1409 1410 return ret; 1411 } 1412 1413 /************************************************************************* 1414 * UrlGetLocationA [SHLWAPI.@] 1415 * 1416 * Get the location from a Url. 1417 * 1418 * PARAMS 1419 * pszUrl [I] Url to get the location from 1420 * 1421 * RETURNS 1422 * A pointer to the start of the location in pszUrl, or NULL if there is 1423 * no location. 1424 * 1425 * NOTES 1426 * - MSDN erroneously states that "The location is the segment of the Url 1427 * starting with a '?' or '#' character". Neither V4 nor V5 of shlwapi.dll 1428 * stop at '?' and always return a NULL in this case. 1429 * - MSDN also erroneously states that "If a file URL has a query string, 1430 * the returned string is the query string". In all tested cases, if the 1431 * Url starts with "fi" then a NULL is returned. V5 gives the following results: 1432 *| Result Url 1433 *| ------ --- 1434 *| NULL file://aa/b/cd#hohoh 1435 *| #hohoh http://aa/b/cd#hohoh 1436 *| NULL fi://aa/b/cd#hohoh 1437 *| #hohoh ff://aa/b/cd#hohoh 1438 */ 1439 LPCSTR WINAPI UrlGetLocationA( 1440 LPCSTR pszUrl) 1441 { 1442 PARSEDURLA base; 1443 DWORD res1; 1444 1445 base.cbSize = sizeof(base); 1446 res1 = ParseURLA(pszUrl, &base); 1447 if (res1) return NULL; /* invalid scheme */ 1448 1449 /* if scheme is file: then never return pointer */ 1450 if (strncmp(base.pszProtocol, "file", min(4,base.cchProtocol)) == 0) return NULL; 1451 1452 /* Look for '#' and return its addr */ 1453 return strchr(base.pszSuffix, '#'); 1454 } 1455 1456 /************************************************************************* 1457 * UrlGetLocationW [SHLWAPI.@] 1458 * 1459 * See UrlGetLocationA. 1460 */ 1461 LPCWSTR WINAPI UrlGetLocationW( 1462 LPCWSTR pszUrl) 1463 { 1464 PARSEDURLW base; 1465 DWORD res1; 1466 1467 base.cbSize = sizeof(base); 1468 res1 = ParseURLW(pszUrl, &base); 1469 if (res1) return NULL; /* invalid scheme */ 1470 1471 /* if scheme is file: then never return pointer */ 1472 if (strncmpW(base.pszProtocol, fileW, min(4,base.cchProtocol)) == 0) return NULL; 1473 1474 /* Look for '#' and return its addr */ 1475 return strchrW(base.pszSuffix, '#'); 1476 } 1477 1478 /************************************************************************* 1479 * UrlCompareA [SHLWAPI.@] 1480 * 1481 * Compare two Urls. 1482 * 1483 * PARAMS 1484 * pszUrl1 [I] First Url to compare 1485 * pszUrl2 [I] Url to compare to pszUrl1 1486 * fIgnoreSlash [I] TRUE = compare only up to a final slash 1487 * 1488 * RETURNS 1489 * less than zero, zero, or greater than zero indicating pszUrl2 is greater 1490 * than, equal to, or less than pszUrl1 respectively. 1491 */ 1492 INT WINAPI UrlCompareA( 1493 LPCSTR pszUrl1, 1494 LPCSTR pszUrl2, 1495 BOOL fIgnoreSlash) 1496 { 1497 INT ret, len, len1, len2; 1498 1499 if (!fIgnoreSlash) 1500 return strcmp(pszUrl1, pszUrl2); 1501 len1 = strlen(pszUrl1); 1502 if (pszUrl1[len1-1] == '/') len1--; 1503 len2 = strlen(pszUrl2); 1504 if (pszUrl2[len2-1] == '/') len2--; 1505 if (len1 == len2) 1506 return strncmp(pszUrl1, pszUrl2, len1); 1507 len = min(len1, len2); 1508 ret = strncmp(pszUrl1, pszUrl2, len); 1509 if (ret) return ret; 1510 if (len1 > len2) return 1; 1511 return -1; 1512 } 1513 1514 /************************************************************************* 1515 * UrlCompareW [SHLWAPI.@] 1516 * 1517 * See UrlCompareA. 1518 */ 1519 INT WINAPI UrlCompareW( 1520 LPCWSTR pszUrl1, 1521 LPCWSTR pszUrl2, 1522 BOOL fIgnoreSlash) 1523 { 1524 INT ret; 1525 size_t len, len1, len2; 1526 1527 if (!fIgnoreSlash) 1528 return strcmpW(pszUrl1, pszUrl2); 1529 len1 = strlenW(pszUrl1); 1530 if (pszUrl1[len1-1] == '/') len1--; 1531 len2 = strlenW(pszUrl2); 1532 if (pszUrl2[len2-1] == '/') len2--; 1533 if (len1 == len2) 1534 return strncmpW(pszUrl1, pszUrl2, len1); 1535 len = min(len1, len2); 1536 ret = strncmpW(pszUrl1, pszUrl2, len); 1537 if (ret) return ret; 1538 if (len1 > len2) return 1; 1539 return -1; 1540 } 1541 1542 /************************************************************************* 1543 * HashData [SHLWAPI.@] 1544 * 1545 * Hash an input block into a variable sized digest. 1546 * 1547 * PARAMS 1548 * lpSrc [I] Input block 1549 * nSrcLen [I] Length of lpSrc 1550 * lpDest [I] Output for hash digest 1551 * nDestLen [I] Length of lpDest 1552 * 1553 * RETURNS 1554 * Success: TRUE. lpDest is filled with the computed hash value. 1555 * Failure: FALSE, if any argument is invalid. 1556 */ 1557 HRESULT WINAPI HashData(const unsigned char *lpSrc, DWORD nSrcLen, 1558 unsigned char *lpDest, DWORD nDestLen) 1559 { 1560 INT srcCount = nSrcLen - 1, destCount = nDestLen - 1; 1561 1562 if (!lpSrc || !lpDest) 1563 return E_INVALIDARG; 1564 1565 while (destCount >= 0) 1566 { 1567 lpDest[destCount] = (destCount & 0xff); 1568 destCount--; 1569 } 1570 1571 while (srcCount >= 0) 1572 { 1573 destCount = nDestLen - 1; 1574 while (destCount >= 0) 1575 { 1576 lpDest[destCount] = HashDataLookup[lpSrc[srcCount] ^ lpDest[destCount]]; 1577 destCount--; 1578 } 1579 srcCount--; 1580 } 1581 return S_OK; 1582 } 1583 1584 /************************************************************************* 1585 * UrlHashA [SHLWAPI.@] 1586 * 1587 * Produce a Hash from a Url. 1588 * 1589 * PARAMS 1590 * pszUrl [I] Url to hash 1591 * lpDest [O] Destinationh for hash 1592 * nDestLen [I] Length of lpDest 1593 * 1594 * RETURNS 1595 * Success: S_OK. lpDest is filled with the computed hash value. 1596 * Failure: E_INVALIDARG, if any argument is invalid. 1597 */ 1598 HRESULT WINAPI UrlHashA(LPCSTR pszUrl, unsigned char *lpDest, DWORD nDestLen) 1599 { 1600 if (IsBadStringPtrA(pszUrl, -1) || IsBadWritePtr(lpDest, nDestLen)) 1601 return E_INVALIDARG; 1602 1603 HashData((const BYTE*)pszUrl, (int)strlen(pszUrl), lpDest, nDestLen); 1604 return S_OK; 1605 } 1606 1607 /************************************************************************* 1608 * UrlHashW [SHLWAPI.@] 1609 * 1610 * See UrlHashA. 1611 */ 1612 HRESULT WINAPI UrlHashW(LPCWSTR pszUrl, unsigned char *lpDest, DWORD nDestLen) 1613 { 1614 char szUrl[MAX_PATH]; 1615 1616 TRACE("(%s,%p,%d)\n",debugstr_w(pszUrl), lpDest, nDestLen); 1617 1618 if (IsBadStringPtrW(pszUrl, -1) || IsBadWritePtr(lpDest, nDestLen)) 1619 return E_INVALIDARG; 1620 1621 /* Win32 hashes the data as an ASCII string, presumably so that both A+W 1622 * return the same digests for the same URL. 1623 */ 1624 WideCharToMultiByte(CP_ACP, 0, pszUrl, -1, szUrl, MAX_PATH, NULL, NULL); 1625 HashData((const BYTE*)szUrl, (int)strlen(szUrl), lpDest, nDestLen); 1626 return S_OK; 1627 } 1628 1629 /************************************************************************* 1630 * UrlApplySchemeA [SHLWAPI.@] 1631 * 1632 * Apply a scheme to a Url. 1633 * 1634 * PARAMS 1635 * pszIn [I] Url to apply scheme to 1636 * pszOut [O] Destination for modified Url 1637 * pcchOut [I/O] Length of pszOut/destination for length of pszOut 1638 * dwFlags [I] URL_ flags from "shlwapi.h" 1639 * 1640 * RETURNS 1641 * Success: S_OK: pszOut contains the modified Url, pcchOut contains its length. 1642 * Failure: An HRESULT error code describing the error. 1643 */ 1644 HRESULT WINAPI UrlApplySchemeA(LPCSTR pszIn, LPSTR pszOut, LPDWORD pcchOut, DWORD dwFlags) 1645 { 1646 LPWSTR in, out; 1647 HRESULT ret; 1648 DWORD len; 1649 1650 TRACE("(%s, %p, %p:out size %d, 0x%08x)\n", debugstr_a(pszIn), 1651 pszOut, pcchOut, pcchOut ? *pcchOut : 0, dwFlags); 1652 1653 if (!pszIn || !pszOut || !pcchOut) return E_INVALIDARG; 1654 1655 in = HeapAlloc(GetProcessHeap(), 0, 1656 (2*INTERNET_MAX_URL_LENGTH) * sizeof(WCHAR)); 1657 out = in + INTERNET_MAX_URL_LENGTH; 1658 1659 MultiByteToWideChar(CP_ACP, 0, pszIn, -1, in, INTERNET_MAX_URL_LENGTH); 1660 len = INTERNET_MAX_URL_LENGTH; 1661 1662 ret = UrlApplySchemeW(in, out, &len, dwFlags); 1663 if (ret != S_OK) { 1664 HeapFree(GetProcessHeap(), 0, in); 1665 return ret; 1666 } 1667 1668 len = WideCharToMultiByte(CP_ACP, 0, out, -1, NULL, 0, NULL, NULL); 1669 if (len > *pcchOut) { 1670 ret = E_POINTER; 1671 goto cleanup; 1672 } 1673 1674 WideCharToMultiByte(CP_ACP, 0, out, -1, pszOut, *pcchOut, NULL, NULL); 1675 len--; 1676 1677 cleanup: 1678 *pcchOut = len; 1679 HeapFree(GetProcessHeap(), 0, in); 1680 return ret; 1681 } 1682 1683 static HRESULT URL_GuessScheme(LPCWSTR pszIn, LPWSTR pszOut, LPDWORD pcchOut) 1684 { 1685 HKEY newkey; 1686 BOOL j; 1687 INT index; 1688 DWORD value_len, data_len, dwType, i; 1689 WCHAR reg_path[MAX_PATH]; 1690 WCHAR value[MAX_PATH], data[MAX_PATH]; 1691 WCHAR Wxx, Wyy; 1692 1693 MultiByteToWideChar(CP_ACP, 0, 1694 "Software\\Microsoft\\Windows\\CurrentVersion\\URL\\Prefixes", 1695 -1, reg_path, MAX_PATH); 1696 RegOpenKeyExW(HKEY_LOCAL_MACHINE, reg_path, 0, 1, &newkey); 1697 index = 0; 1698 while(value_len = data_len = MAX_PATH, 1699 RegEnumValueW(newkey, index, value, &value_len, 1700 0, &dwType, (LPVOID)data, &data_len) == 0) { 1701 TRACE("guess %d %s is %s\n", 1702 index, debugstr_w(value), debugstr_w(data)); 1703 1704 j = FALSE; 1705 for(i=0; i<value_len; i++) { 1706 Wxx = pszIn[i]; 1707 Wyy = value[i]; 1708 /* remember that TRUE is not-equal */ 1709 j = ChrCmpIW(Wxx, Wyy); 1710 if (j) break; 1711 } 1712 if ((i == value_len) && !j) { 1713 if (strlenW(data) + strlenW(pszIn) + 1 > *pcchOut) { 1714 *pcchOut = strlenW(data) + strlenW(pszIn) + 1; 1715 RegCloseKey(newkey); 1716 return E_POINTER; 1717 } 1718 strcpyW(pszOut, data); 1719 strcatW(pszOut, pszIn); 1720 *pcchOut = strlenW(pszOut); 1721 TRACE("matched and set to %s\n", debugstr_w(pszOut)); 1722 RegCloseKey(newkey); 1723 return S_OK; 1724 } 1725 index++; 1726 } 1727 RegCloseKey(newkey); 1728 return E_FAIL; 1729 } 1730 1731 static HRESULT URL_CreateFromPath(LPCWSTR pszPath, LPWSTR pszUrl, LPDWORD pcchUrl) 1732 { 1733 DWORD needed; 1734 HRESULT ret = S_OK; 1735 WCHAR *pszNewUrl; 1736 WCHAR file_colonW[] = {'f','i','l','e',':',0}; 1737 WCHAR three_slashesW[] = {'/','/','/',0}; 1738 PARSEDURLW parsed_url; 1739 1740 parsed_url.cbSize = sizeof(parsed_url); 1741 if(ParseURLW(pszPath, &parsed_url) == S_OK) { 1742 if(parsed_url.nScheme != URL_SCHEME_INVALID && parsed_url.cchProtocol > 1) { 1743 needed = strlenW(pszPath); 1744 if (needed >= *pcchUrl) { 1745 *pcchUrl = needed + 1; 1746 return E_POINTER; 1747 } else { 1748 *pcchUrl = needed; 1749 return S_FALSE; 1750 } 1751 } 1752 } 1753 1754 pszNewUrl = HeapAlloc(GetProcessHeap(), 0, (strlenW(pszPath) + 9) * sizeof(WCHAR)); /* "file:///" + pszPath_len + 1 */ 1755 strcpyW(pszNewUrl, file_colonW); 1756 if(isalphaW(pszPath[0]) && pszPath[1] == ':') 1757 strcatW(pszNewUrl, three_slashesW); 1758 strcatW(pszNewUrl, pszPath); 1759 ret = UrlEscapeW(pszNewUrl, pszUrl, pcchUrl, URL_ESCAPE_PERCENT); 1760 HeapFree(GetProcessHeap(), 0, pszNewUrl); 1761 return ret; 1762 } 1763 1764 static HRESULT URL_ApplyDefault(LPCWSTR pszIn, LPWSTR pszOut, LPDWORD pcchOut) 1765 { 1766 HKEY newkey; 1767 DWORD data_len, dwType; 1768 WCHAR data[MAX_PATH]; 1769 1770 static const WCHAR prefix_keyW[] = 1771 {'S','o','f','t','w','a','r','e', 1772 '\\','M','i','c','r','o','s','o','f','t', 1773 '\\','W','i','n','d','o','w','s', 1774 '\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n', 1775 '\\','U','R','L', 1776 '\\','D','e','f','a','u','l','t','P','r','e','f','i','x',0}; 1777 1778 /* get and prepend default */ 1779 RegOpenKeyExW(HKEY_LOCAL_MACHINE, prefix_keyW, 0, 1, &newkey); 1780 data_len = sizeof(data); 1781 RegQueryValueExW(newkey, NULL, 0, &dwType, (LPBYTE)data, &data_len); 1782 RegCloseKey(newkey); 1783 if (strlenW(data) + strlenW(pszIn) + 1 > *pcchOut) { 1784 *pcchOut = strlenW(data) + strlenW(pszIn) + 1; 1785 return E_POINTER; 1786 } 1787 strcpyW(pszOut, data); 1788 strcatW(pszOut, pszIn); 1789 *pcchOut = strlenW(pszOut); 1790 TRACE("used default %s\n", debugstr_w(pszOut)); 1791 return S_OK; 1792 } 1793 1794 /************************************************************************* 1795 * UrlApplySchemeW [SHLWAPI.@] 1796 * 1797 * See UrlApplySchemeA. 1798 */ 1799 HRESULT WINAPI UrlApplySchemeW(LPCWSTR pszIn, LPWSTR pszOut, LPDWORD pcchOut, DWORD dwFlags) 1800 { 1801 PARSEDURLW in_scheme; 1802 DWORD res1; 1803 HRESULT ret; 1804 1805 TRACE("(%s, %p, %p:out size %d, 0x%08x)\n", debugstr_w(pszIn), 1806 pszOut, pcchOut, pcchOut ? *pcchOut : 0, dwFlags); 1807 1808 if (!pszIn || !pszOut || !pcchOut) return E_INVALIDARG; 1809 1810 if (dwFlags & URL_APPLY_GUESSFILE) { 1811 if (*pcchOut > 1 && ':' == pszIn[1]) { 1812 res1 = *pcchOut; 1813 ret = URL_CreateFromPath(pszIn, pszOut, &res1); 1814 if (ret == S_OK || ret == E_POINTER){ 1815 *pcchOut = res1; 1816 return ret; 1817 } 1818 else if (ret == S_FALSE) 1819 { 1820 return ret; 1821 } 1822 } 1823 } 1824 1825 in_scheme.cbSize = sizeof(in_scheme); 1826 /* See if the base has a scheme */ 1827 res1 = ParseURLW(pszIn, &in_scheme); 1828 if (res1) { 1829 /* no scheme in input, need to see if we need to guess */ 1830 if (dwFlags & URL_APPLY_GUESSSCHEME) { 1831 if ((ret = URL_GuessScheme(pszIn, pszOut, pcchOut)) != E_FAIL) 1832 return ret; 1833 } 1834 } 1835 1836 /* If we are here, then either invalid scheme, 1837 * or no scheme and can't/failed guess. 1838 */ 1839 if ( ( ((res1 == 0) && (dwFlags & URL_APPLY_FORCEAPPLY)) || 1840 ((res1 != 0)) ) && 1841 (dwFlags & URL_APPLY_DEFAULT)) { 1842 /* find and apply default scheme */ 1843 return URL_ApplyDefault(pszIn, pszOut, pcchOut); 1844 } 1845 1846 return S_FALSE; 1847 } 1848 1849 /************************************************************************* 1850 * UrlIsA [SHLWAPI.@] 1851 * 1852 * Determine if a Url is of a certain class. 1853 * 1854 * PARAMS 1855 * pszUrl [I] Url to check 1856 * Urlis [I] URLIS_ constant from "shlwapi.h" 1857 * 1858 * RETURNS 1859 * TRUE if pszUrl belongs to the class type in Urlis. 1860 * FALSE Otherwise. 1861 */ 1862 BOOL WINAPI UrlIsA(LPCSTR pszUrl, URLIS Urlis) 1863 { 1864 PARSEDURLA base; 1865 DWORD res1; 1866 LPCSTR last; 1867 1868 TRACE("(%s %d)\n", debugstr_a(pszUrl), Urlis); 1869 1870 if(!pszUrl) 1871 return FALSE; 1872 1873 switch (Urlis) { 1874 1875 case URLIS_OPAQUE: 1876 base.cbSize = sizeof(base); 1877 res1 = ParseURLA(pszUrl, &base); 1878 if (res1) return FALSE; /* invalid scheme */ 1879 switch (base.nScheme) 1880 { 1881 case URL_SCHEME_MAILTO: 1882 case URL_SCHEME_SHELL: 1883 case URL_SCHEME_JAVASCRIPT: 1884 case URL_SCHEME_VBSCRIPT: 1885 case URL_SCHEME_ABOUT: 1886 return TRUE; 1887 } 1888 return FALSE; 1889 1890 case URLIS_FILEURL: 1891 return (CompareStringA(LOCALE_INVARIANT, NORM_IGNORECASE, pszUrl, 5, 1892 "file:", 5) == CSTR_EQUAL); 1893 1894 case URLIS_DIRECTORY: 1895 last = pszUrl + strlen(pszUrl) - 1; 1896 return (last >= pszUrl && (*last == '/' || *last == '\\' )); 1897 1898 case URLIS_URL: 1899 return PathIsURLA(pszUrl); 1900 1901 case URLIS_NOHISTORY: 1902 case URLIS_APPLIABLE: 1903 case URLIS_HASQUERY: 1904 default: 1905 FIXME("(%s %d): stub\n", debugstr_a(pszUrl), Urlis); 1906 } 1907 return FALSE; 1908 } 1909 1910 /************************************************************************* 1911 * UrlIsW [SHLWAPI.@] 1912 * 1913 * See UrlIsA. 1914 */ 1915 BOOL WINAPI UrlIsW(LPCWSTR pszUrl, URLIS Urlis) 1916 { 1917 static const WCHAR file_colon[] = { 'f','i','l','e',':',0 }; 1918 PARSEDURLW base; 1919 DWORD res1; 1920 LPCWSTR last; 1921 1922 TRACE("(%s %d)\n", debugstr_w(pszUrl), Urlis); 1923 1924 if(!pszUrl) 1925 return FALSE; 1926 1927 switch (Urlis) { 1928 1929 case URLIS_OPAQUE: 1930 base.cbSize = sizeof(base); 1931 res1 = ParseURLW(pszUrl, &base); 1932 if (res1) return FALSE; /* invalid scheme */ 1933 switch (base.nScheme) 1934 { 1935 case URL_SCHEME_MAILTO: 1936 case URL_SCHEME_SHELL: 1937 case URL_SCHEME_JAVASCRIPT: 1938 case URL_SCHEME_VBSCRIPT: 1939 case URL_SCHEME_ABOUT: 1940 return TRUE; 1941 } 1942 return FALSE; 1943 1944 case URLIS_FILEURL: 1945 return (CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, pszUrl, 5, 1946 file_colon, 5) == CSTR_EQUAL); 1947 1948 case URLIS_DIRECTORY: 1949 last = pszUrl + strlenW(pszUrl) - 1; 1950 return (last >= pszUrl && (*last == '/' || *last == '\\')); 1951 1952 case URLIS_URL: 1953 return PathIsURLW(pszUrl); 1954 1955 case URLIS_NOHISTORY: 1956 case URLIS_APPLIABLE: 1957 case URLIS_HASQUERY: 1958 default: 1959 FIXME("(%s %d): stub\n", debugstr_w(pszUrl), Urlis); 1960 } 1961 return FALSE; 1962 } 1963 1964 /************************************************************************* 1965 * UrlIsNoHistoryA [SHLWAPI.@] 1966 * 1967 * Determine if a Url should not be stored in the users history list. 1968 * 1969 * PARAMS 1970 * pszUrl [I] Url to check 1971 * 1972 * RETURNS 1973 * TRUE, if pszUrl should be excluded from the history list, 1974 * FALSE otherwise. 1975 */ 1976 BOOL WINAPI UrlIsNoHistoryA(LPCSTR pszUrl) 1977 { 1978 return UrlIsA(pszUrl, URLIS_NOHISTORY); 1979 } 1980 1981 /************************************************************************* 1982 * UrlIsNoHistoryW [SHLWAPI.@] 1983 * 1984 * See UrlIsNoHistoryA. 1985 */ 1986 BOOL WINAPI UrlIsNoHistoryW(LPCWSTR pszUrl) 1987 { 1988 return UrlIsW(pszUrl, URLIS_NOHISTORY); 1989 } 1990 1991 /************************************************************************* 1992 * UrlIsOpaqueA [SHLWAPI.@] 1993 * 1994 * Determine if a Url is opaque. 1995 * 1996 * PARAMS 1997 * pszUrl [I] Url to check 1998 * 1999 * RETURNS 2000 * TRUE if pszUrl is opaque, 2001 * FALSE Otherwise. 2002 * 2003 * NOTES 2004 * An opaque Url is one that does not start with "<protocol>://". 2005 */ 2006 BOOL WINAPI UrlIsOpaqueA(LPCSTR pszUrl) 2007 { 2008 return UrlIsA(pszUrl, URLIS_OPAQUE); 2009 } 2010 2011 /************************************************************************* 2012 * UrlIsOpaqueW [SHLWAPI.@] 2013 * 2014 * See UrlIsOpaqueA. 2015 */ 2016 BOOL WINAPI UrlIsOpaqueW(LPCWSTR pszUrl) 2017 { 2018 return UrlIsW(pszUrl, URLIS_OPAQUE); 2019 } 2020 2021 /************************************************************************* 2022 * Scans for characters of type "type" and when not matching found, 2023 * returns pointer to it and length in size. 2024 * 2025 * Characters tested based on RFC 1738 2026 */ 2027 static LPCWSTR URL_ScanID(LPCWSTR start, LPDWORD size, WINE_URL_SCAN_TYPE type) 2028 { 2029 static DWORD alwayszero = 0; 2030 BOOL cont = TRUE; 2031 2032 *size = 0; 2033 2034 switch(type){ 2035 2036 case SCHEME: 2037 while (cont) { 2038 if ( (islowerW(*start) && isalphaW(*start)) || 2039 isdigitW(*start) || 2040 (*start == '+') || 2041 (*start == '-') || 2042 (*start == '.')) { 2043 start++; 2044 (*size)++; 2045 } 2046 else 2047 cont = FALSE; 2048 } 2049 2050 if(*start != ':') 2051 *size = 0; 2052 2053 break; 2054 2055 case USERPASS: 2056 while (cont) { 2057 if ( isalphaW(*start) || 2058 isdigitW(*start) || 2059 /* user/password only characters */ 2060 (*start == ';') || 2061 (*start == '?') || 2062 (*start == '&') || 2063 (*start == '=') || 2064 /* *extra* characters */ 2065 (*start == '!') || 2066 (*start == '*') || 2067 (*start == '\'') || 2068 (*start == '(') || 2069 (*start == ')') || 2070 (*start == ',') || 2071 /* *safe* characters */ 2072 (*start == '$') || 2073 (*start == '_') || 2074 (*start == '+') || 2075 (*start == '-') || 2076 (*start == '.') || 2077 (*start == ' ')) { 2078 start++; 2079 (*size)++; 2080 } else if (*start == '%') { 2081 if (isxdigitW(*(start+1)) && 2082 isxdigitW(*(start+2))) { 2083 start += 3; 2084 *size += 3; 2085 } else 2086 cont = FALSE; 2087 } else 2088 cont = FALSE; 2089 } 2090 break; 2091 2092 case PORT: 2093 while (cont) { 2094 if (isdigitW(*start)) { 2095 start++; 2096 (*size)++; 2097 } 2098 else 2099 cont = FALSE; 2100 } 2101 break; 2102 2103 case HOST: 2104 while (cont) { 2105 if (isalnumW(*start) || 2106 (*start == '-') || 2107 (*start == '.') || 2108 (*start == ' ') || 2109 (*start == '*') ) { 2110 start++; 2111 (*size)++; 2112 } 2113 else 2114 cont = FALSE; 2115 } 2116 break; 2117 default: 2118 FIXME("unknown type %d\n", type); 2119 return (LPWSTR)&alwayszero; 2120 } 2121 /* TRACE("scanned %d characters next char %p<%c>\n", 2122 *size, start, *start); */ 2123 return start; 2124 } 2125 2126 /************************************************************************* 2127 * Attempt to parse URL into pieces. 2128 */ 2129 static LONG URL_ParseUrl(LPCWSTR pszUrl, WINE_PARSE_URL *pl) 2130 { 2131 LPCWSTR work; 2132 2133 memset(pl, 0, sizeof(WINE_PARSE_URL)); 2134 pl->pScheme = pszUrl; 2135 work = URL_ScanID(pl->pScheme, &pl->szScheme, SCHEME); 2136 if (!*work || (*work != ':')) goto ErrorExit; 2137 work++; 2138 if ((*work != '/') || (*(work+1) != '/')) goto SuccessExit; 2139 pl->pUserName = work + 2; 2140 work = URL_ScanID(pl->pUserName, &pl->szUserName, USERPASS); 2141 if (*work == ':' ) { 2142 /* parse password */ 2143 work++; 2144 pl->pPassword = work; 2145 work = URL_ScanID(pl->pPassword, &pl->szPassword, USERPASS); 2146 if (*work != '@') { 2147 /* what we just parsed must be the hostname and port 2148 * so reset pointers and clear then let it parse */ 2149 pl->szUserName = pl->szPassword = 0; 2150 work = pl->pUserName - 1; 2151 pl->pUserName = pl->pPassword = 0; 2152 } 2153 } else if (*work == '@') { 2154 /* no password */ 2155 pl->szPassword = 0; 2156 pl->pPassword = 0; 2157 } else if (!*work || (*work == '/') || (*work == '.')) { 2158 /* what was parsed was hostname, so reset pointers and let it parse */ 2159 pl->szUserName = pl->szPassword = 0; 2160 work = pl->pUserName - 1; 2161 pl->pUserName = pl->pPassword = 0; 2162 } else goto ErrorExit; 2163 2164 /* now start parsing hostname or hostnumber */ 2165 work++; 2166 pl->pHostName = work; 2167 work = URL_ScanID(pl->pHostName, &pl->szHostName, HOST); 2168 if (*work == ':') { 2169 /* parse port */ 2170 work++; 2171 pl->pPort = work; 2172 work = URL_ScanID(pl->pPort, &pl->szPort, PORT); 2173 } 2174 if (*work == '/') { 2175 /* see if query string */ 2176 pl->pQuery = strchrW(work, '?'); 2177 if (pl->pQuery) pl->szQuery = strlenW(pl->pQuery); 2178 } 2179 SuccessExit: 2180 TRACE("parse successful: scheme=%p(%d), user=%p(%d), pass=%p(%d), host=%p(%d), port=%p(%d), query=%p(%d)\n", 2181 pl->pScheme, pl->szScheme, 2182 pl->pUserName, pl->szUserName, 2183 pl->pPassword, pl->szPassword, 2184 pl->pHostName, pl->szHostName, 2185 pl->pPort, pl->szPort, 2186 pl->pQuery, pl->szQuery); 2187 return S_OK; 2188 ErrorExit: 2189 FIXME("failed to parse %s\n", debugstr_w(pszUrl)); 2190 return E_INVALIDARG; 2191 } 2192 2193 /************************************************************************* 2194 * UrlGetPartA [SHLWAPI.@] 2195 * 2196 * Retrieve part of a Url. 2197 * 2198 * PARAMS 2199 * pszIn [I] Url to parse 2200 * pszOut [O] Destination for part of pszIn requested 2201 * pcchOut [I] Size of pszOut 2202 * [O] length of pszOut string EXCLUDING '\0' if S_OK, otherwise 2203 * needed size of pszOut INCLUDING '\0'. 2204 * dwPart [I] URL_PART_ enum from "shlwapi.h" 2205 * dwFlags [I] URL_ flags from "shlwapi.h" 2206 * 2207 * RETURNS 2208 * Success: S_OK. pszOut contains the part requested, pcchOut contains its length. 2209 * Failure: An HRESULT error code describing the error. 2210 */ 2211 HRESULT WINAPI UrlGetPartA(LPCSTR pszIn, LPSTR pszOut, LPDWORD pcchOut, 2212 DWORD dwPart, DWORD dwFlags) 2213 { 2214 LPWSTR in, out; 2215 DWORD ret, len, len2; 2216 2217 if(!pszIn || !pszOut || !pcchOut || *pcchOut <= 0) 2218 return E_INVALIDARG; 2219 2220 in = HeapAlloc(GetProcessHeap(), 0, 2221 (2*INTERNET_MAX_URL_LENGTH) * sizeof(WCHAR)); 2222 out = in + INTERNET_MAX_URL_LENGTH; 2223 2224 MultiByteToWideChar(CP_ACP, 0, pszIn, -1, in, INTERNET_MAX_URL_LENGTH); 2225 2226 len = INTERNET_MAX_URL_LENGTH; 2227 ret = UrlGetPartW(in, out, &len, dwPart, dwFlags); 2228 2229 if (FAILED(ret)) { 2230 HeapFree(GetProcessHeap(), 0, in); 2231 return ret; 2232 } 2233 2234 len2 = WideCharToMultiByte(CP_ACP, 0, out, len, NULL, 0, NULL, NULL); 2235 if (len2 > *pcchOut) { 2236 *pcchOut = len2+1; 2237 HeapFree(GetProcessHeap(), 0, in); 2238 return E_POINTER; 2239 } 2240 len2 = WideCharToMultiByte(CP_ACP, 0, out, len+1, pszOut, *pcchOut, NULL, NULL); 2241 *pcchOut = len2-1; 2242 HeapFree(GetProcessHeap(), 0, in); 2243 return ret; 2244 } 2245 2246 /************************************************************************* 2247 * UrlGetPartW [SHLWAPI.@] 2248 * 2249 * See UrlGetPartA. 2250 */ 2251 HRESULT WINAPI UrlGetPartW(LPCWSTR pszIn, LPWSTR pszOut, LPDWORD pcchOut, 2252 DWORD dwPart, DWORD dwFlags) 2253 { 2254 WINE_PARSE_URL pl; 2255 HRESULT ret; 2256 DWORD scheme, size, schsize; 2257 LPCWSTR addr, schaddr; 2258 2259 TRACE("(%s %p %p(%d) %08x %08x)\n", 2260 debugstr_w(pszIn), pszOut, pcchOut, *pcchOut, dwPart, dwFlags); 2261 2262 if(!pszIn || !pszOut || !pcchOut || *pcchOut <= 0) 2263 return E_INVALIDARG; 2264 2265 *pszOut = '\0'; 2266 2267 addr = strchrW(pszIn, ':'); 2268 if(!addr) 2269 scheme = URL_SCHEME_UNKNOWN; 2270 else 2271 scheme = get_scheme_code(pszIn, addr-pszIn); 2272 2273 ret = URL_ParseUrl(pszIn, &pl); 2274 2275 switch (dwPart) { 2276 case URL_PART_SCHEME: 2277 if (!pl.szScheme) { 2278 *pcchOut = 0; 2279 return S_FALSE; 2280 } 2281 addr = pl.pScheme; 2282 size = pl.szScheme; 2283 break; 2284 2285 case URL_PART_HOSTNAME: 2286 switch(scheme) { 2287 case URL_SCHEME_FTP: 2288 case URL_SCHEME_HTTP: 2289 case URL_SCHEME_GOPHER: 2290 case URL_SCHEME_TELNET: 2291 case URL_SCHEME_FILE: 2292 case URL_SCHEME_HTTPS: 2293 break; 2294 default: 2295 *pcchOut = 0; 2296 return E_FAIL; 2297 } 2298 2299 if(scheme==URL_SCHEME_FILE && (!pl.szHostName || 2300 (pl.szHostName==1 && *(pl.pHostName+1)==':'))) { 2301 *pcchOut = 0; 2302 return S_FALSE; 2303 } 2304 2305 if (!pl.szHostName) { 2306 *pcchOut = 0; 2307 return S_FALSE; 2308 } 2309 addr = pl.pHostName; 2310 size = pl.szHostName; 2311 break; 2312 2313 case URL_PART_USERNAME: 2314 if (!pl.szUserName) { 2315 *pcchOut = 0; 2316 return S_FALSE; 2317 } 2318 addr = pl.pUserName; 2319 size = pl.szUserName; 2320 break; 2321 2322 case URL_PART_PASSWORD: 2323 if (!pl.szPassword) { 2324 *pcchOut = 0; 2325 return S_FALSE; 2326 } 2327 addr = pl.pPassword; 2328 size = pl.szPassword; 2329 break; 2330 2331 case URL_PART_PORT: 2332 if (!pl.szPort) { 2333 *pcchOut = 0; 2334 return S_FALSE; 2335 } 2336 addr = pl.pPort; 2337 size = pl.szPort; 2338 break; 2339 2340 case URL_PART_QUERY: 2341 if (!pl.szQuery) { 2342 *pcchOut = 0; 2343 return S_FALSE; 2344 } 2345 addr = pl.pQuery; 2346 size = pl.szQuery; 2347 break; 2348 2349 default: 2350 *pcchOut = 0; 2351 return E_INVALIDARG; 2352 } 2353 2354 if (dwFlags == URL_PARTFLAG_KEEPSCHEME) { 2355 if(!pl.pScheme || !pl.szScheme) { 2356 *pcchOut = 0; 2357 return E_FAIL; 2358 } 2359 schaddr = pl.pScheme; 2360 schsize = pl.szScheme; 2361 if (*pcchOut < schsize + size + 2) { 2362 *pcchOut = schsize + size + 2; 2363 return E_POINTER; 2364 } 2365 memcpy(pszOut, schaddr, schsize*sizeof(WCHAR)); 2366 pszOut[schsize] = ':'; 2367 memcpy(pszOut+schsize+1, addr, size*sizeof(WCHAR)); 2368 pszOut[schsize+1+size] = 0; 2369 *pcchOut = schsize + 1 + size; 2370 } 2371 else { 2372 if (*pcchOut < size + 1) {*pcchOut = size+1; return E_POINTER;} 2373 memcpy(pszOut, addr, size*sizeof(WCHAR)); 2374 pszOut[size] = 0; 2375 *pcchOut = size; 2376 } 2377 TRACE("len=%d %s\n", *pcchOut, debugstr_w(pszOut)); 2378 2379 return ret; 2380 } 2381 2382 /************************************************************************* 2383 * PathIsURLA [SHLWAPI.@] 2384 * 2385 * Check if the given path is a Url. 2386 * 2387 * PARAMS 2388 * lpszPath [I] Path to check. 2389 * 2390 * RETURNS 2391 * TRUE if lpszPath is a Url. 2392 * FALSE if lpszPath is NULL or not a Url. 2393 */ 2394 BOOL WINAPI PathIsURLA(LPCSTR lpstrPath) 2395 { 2396 PARSEDURLA base; 2397 HRESULT hres; 2398 2399 TRACE("%s\n", debugstr_a(lpstrPath)); 2400 2401 if (!lpstrPath || !*lpstrPath) return FALSE; 2402 2403 /* get protocol */ 2404 base.cbSize = sizeof(base); 2405 hres = ParseURLA(lpstrPath, &base); 2406 return hres == S_OK && (base.nScheme != URL_SCHEME_INVALID); 2407 } 2408 2409 /************************************************************************* 2410 * PathIsURLW [SHLWAPI.@] 2411 * 2412 * See PathIsURLA. 2413 */ 2414 BOOL WINAPI PathIsURLW(LPCWSTR lpstrPath) 2415 { 2416 PARSEDURLW base; 2417 HRESULT hres; 2418 2419 TRACE("%s\n", debugstr_w(lpstrPath)); 2420 2421 if (!lpstrPath || !*lpstrPath) return FALSE; 2422 2423 /* get protocol */ 2424 base.cbSize = sizeof(base); 2425 hres = ParseURLW(lpstrPath, &base); 2426 return hres == S_OK && (base.nScheme != URL_SCHEME_INVALID); 2427 } 2428 2429 /************************************************************************* 2430 * UrlCreateFromPathA [SHLWAPI.@] 2431 * 2432 * See UrlCreateFromPathW 2433 */ 2434 HRESULT WINAPI UrlCreateFromPathA(LPCSTR pszPath, LPSTR pszUrl, LPDWORD pcchUrl, DWORD dwReserved) 2435 { 2436 WCHAR bufW[INTERNET_MAX_URL_LENGTH]; 2437 WCHAR *urlW = bufW; 2438 UNICODE_STRING pathW; 2439 HRESULT ret; 2440 DWORD lenW = sizeof(bufW)/sizeof(WCHAR), lenA; 2441 2442 if(!RtlCreateUnicodeStringFromAsciiz(&pathW, pszPath)) 2443 return E_INVALIDARG; 2444 if((ret = UrlCreateFromPathW(pathW.Buffer, urlW, &lenW, dwReserved)) == E_POINTER) { 2445 urlW = HeapAlloc(GetProcessHeap(), 0, lenW * sizeof(WCHAR)); 2446 ret = UrlCreateFromPathW(pathW.Buffer, urlW, &lenW, dwReserved); 2447 } 2448 if(ret == S_OK || ret == S_FALSE) { 2449 RtlUnicodeToMultiByteSize(&lenA, urlW, lenW * sizeof(WCHAR)); 2450 if(*pcchUrl > lenA) { 2451 RtlUnicodeToMultiByteN(pszUrl, *pcchUrl - 1, &lenA, urlW, lenW * sizeof(WCHAR)); 2452 pszUrl[lenA] = 0; 2453 *pcchUrl = lenA; 2454 } else { 2455 *pcchUrl = lenA + 1; 2456 ret = E_POINTER; 2457 } 2458 } 2459 if(urlW != bufW) HeapFree(GetProcessHeap(), 0, urlW); 2460 RtlFreeUnicodeString(&pathW); 2461 return ret; 2462 } 2463 2464 /************************************************************************* 2465 * UrlCreateFromPathW [SHLWAPI.@] 2466 * 2467 * Create a Url from a file path. 2468 * 2469 * PARAMS 2470 * pszPath [I] Path to convert 2471 * pszUrl [O] Destination for the converted Url 2472 * pcchUrl [I/O] Length of pszUrl 2473 * dwReserved [I] Reserved, must be 0 2474 * 2475 * RETURNS 2476 * Success: S_OK pszUrl contains the converted path, S_FALSE if the path is already a Url 2477 * Failure: An HRESULT error code. 2478 */ 2479 HRESULT WINAPI UrlCreateFromPathW(LPCWSTR pszPath, LPWSTR pszUrl, LPDWORD pcchUrl, DWORD dwReserved) 2480 { 2481 HRESULT ret; 2482 2483 TRACE("(%s, %p, %p, 0x%08x)\n", debugstr_w(pszPath), pszUrl, pcchUrl, dwReserved); 2484 2485 /* Validate arguments */ 2486 if (dwReserved != 0) 2487 return E_INVALIDARG; 2488 if (!pszUrl || !pcchUrl) 2489 return E_INVALIDARG; 2490 2491 ret = URL_CreateFromPath(pszPath, pszUrl, pcchUrl); 2492 2493 if (S_FALSE == ret) 2494 strcpyW(pszUrl, pszPath); 2495 2496 return ret; 2497 } 2498 2499 /************************************************************************* 2500 * SHAutoComplete [SHLWAPI.@] 2501 * 2502 * Enable auto-completion for an edit control. 2503 * 2504 * PARAMS 2505 * hwndEdit [I] Handle of control to enable auto-completion for 2506 * dwFlags [I] SHACF_ flags from "shlwapi.h" 2507 * 2508 * RETURNS 2509 * Success: S_OK. Auto-completion is enabled for the control. 2510 * Failure: An HRESULT error code indicating the error. 2511 */ 2512 HRESULT WINAPI SHAutoComplete(HWND hwndEdit, DWORD dwFlags) 2513 { 2514 FIXME("stub\n"); 2515 return S_FALSE; 2516 } 2517 2518 /************************************************************************* 2519 * MLBuildResURLA [SHLWAPI.405] 2520 * 2521 * Create a Url pointing to a resource in a module. 2522 * 2523 * PARAMS 2524 * lpszLibName [I] Name of the module containing the resource 2525 * hMod [I] Callers module handle 2526 * dwFlags [I] Undocumented flags for loading the module 2527 * lpszRes [I] Resource name 2528 * lpszDest [O] Destination for resulting Url 2529 * dwDestLen [I] Length of lpszDest 2530 * 2531 * RETURNS 2532 * Success: S_OK. lpszDest contains the resource Url. 2533 * Failure: E_INVALIDARG, if any argument is invalid, or 2534 * E_FAIL if dwDestLen is too small. 2535 */ 2536 HRESULT WINAPI MLBuildResURLA(LPCSTR lpszLibName, HMODULE hMod, DWORD dwFlags, 2537 LPCSTR lpszRes, LPSTR lpszDest, DWORD dwDestLen) 2538 { 2539 WCHAR szLibName[MAX_PATH], szRes[MAX_PATH], szDest[MAX_PATH]; 2540 HRESULT hRet; 2541 2542 if (lpszLibName) 2543 MultiByteToWideChar(CP_ACP, 0, lpszLibName, -1, szLibName, sizeof(szLibName)/sizeof(WCHAR)); 2544 2545 if (lpszRes) 2546 MultiByteToWideChar(CP_ACP, 0, lpszRes, -1, szRes, sizeof(szRes)/sizeof(WCHAR)); 2547 2548 if (dwDestLen > sizeof(szLibName)/sizeof(WCHAR)) 2549 dwDestLen = sizeof(szLibName)/sizeof(WCHAR); 2550 2551 hRet = MLBuildResURLW(lpszLibName ? szLibName : NULL, hMod, dwFlags, 2552 lpszRes ? szRes : NULL, lpszDest ? szDest : NULL, dwDestLen); 2553 if (SUCCEEDED(hRet) && lpszDest) 2554 WideCharToMultiByte(CP_ACP, 0, szDest, -1, lpszDest, dwDestLen, NULL, NULL); 2555 2556 return hRet; 2557 } 2558 2559 /************************************************************************* 2560 * MLBuildResURLA [SHLWAPI.406] 2561 * 2562 * See MLBuildResURLA. 2563 */ 2564 HRESULT WINAPI MLBuildResURLW(LPCWSTR lpszLibName, HMODULE hMod, DWORD dwFlags, 2565 LPCWSTR lpszRes, LPWSTR lpszDest, DWORD dwDestLen) 2566 { 2567 static const WCHAR szRes[] = { 'r','e','s',':','/','/','\0' }; 2568 #define szResLen ((sizeof(szRes) - sizeof(WCHAR))/sizeof(WCHAR)) 2569 HRESULT hRet = E_FAIL; 2570 2571 TRACE("(%s,%p,0x%08x,%s,%p,%d)\n", debugstr_w(lpszLibName), hMod, dwFlags, 2572 debugstr_w(lpszRes), lpszDest, dwDestLen); 2573 2574 if (!lpszLibName || !hMod || hMod == INVALID_HANDLE_VALUE || !lpszRes || 2575 !lpszDest || (dwFlags && dwFlags != 2)) 2576 return E_INVALIDARG; 2577 2578 if (dwDestLen >= szResLen + 1) 2579 { 2580 dwDestLen -= (szResLen + 1); 2581 memcpy(lpszDest, szRes, sizeof(szRes)); 2582 2583 hMod = MLLoadLibraryW(lpszLibName, hMod, dwFlags); 2584 2585 if (hMod) 2586 { 2587 WCHAR szBuff[MAX_PATH]; 2588 DWORD len; 2589 2590 len = GetModuleFileNameW(hMod, szBuff, sizeof(szBuff)/sizeof(WCHAR)); 2591 if (len && len < sizeof(szBuff)/sizeof(WCHAR)) 2592 { 2593 DWORD dwPathLen = strlenW(szBuff) + 1; 2594 2595 if (dwDestLen >= dwPathLen) 2596 { 2597 DWORD dwResLen; 2598 2599 dwDestLen -= dwPathLen; 2600 memcpy(lpszDest + szResLen, szBuff, dwPathLen * sizeof(WCHAR)); 2601 2602 dwResLen = strlenW(lpszRes) + 1; 2603 if (dwDestLen >= dwResLen + 1) 2604 { 2605 lpszDest[szResLen + dwPathLen-1] = '/'; 2606 memcpy(lpszDest + szResLen + dwPathLen, lpszRes, dwResLen * sizeof(WCHAR)); 2607 hRet = S_OK; 2608 } 2609 } 2610 } 2611 MLFreeLibrary(hMod); 2612 } 2613 } 2614 return hRet; 2615 } 2616 2617 /*********************************************************************** 2618 * UrlFixupW [SHLWAPI.462] 2619 * 2620 * Checks the scheme part of a URL and attempts to correct misspellings. 2621 * 2622 * PARAMS 2623 * lpszUrl [I] Pointer to the URL to be corrected 2624 * lpszTranslatedUrl [O] Pointer to a buffer to store corrected URL 2625 * dwMaxChars [I] Maximum size of corrected URL 2626 * 2627 * RETURNS 2628 * success: S_OK if URL corrected or already correct 2629 * failure: S_FALSE if unable to correct / COM error code if other error 2630 * 2631 */ 2632 HRESULT WINAPI UrlFixupW(LPCWSTR url, LPWSTR translatedUrl, DWORD maxChars) 2633 { 2634 DWORD srcLen; 2635 2636 FIXME("(%s,%p,%d) STUB\n", debugstr_w(url), translatedUrl, maxChars); 2637 2638 if (!url) 2639 return E_FAIL; 2640 2641 srcLen = lstrlenW(url) + 1; 2642 2643 /* For now just copy the URL directly */ 2644 lstrcpynW(translatedUrl, url, (maxChars < srcLen) ? maxChars : srcLen); 2645 2646 return S_OK; 2647 } 2648 2649 /************************************************************************* 2650 * IsInternetESCEnabled [SHLWAPI.@] 2651 */ 2652 BOOL WINAPI IsInternetESCEnabled(void) 2653 { 2654 FIXME(": stub\n"); 2655 return FALSE; 2656 } 2657