4 * Copyright 2000 Huw D M Davies for CodeWeavers.
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.
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.
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 #include "wine/unicode.h"
30 #define NO_SHLWAPI_STREAM
32 #include "wine/debug.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(shell
);
38 LPCWSTR pScheme
; /* [out] start of scheme */
39 DWORD szScheme
; /* [out] size of scheme (until colon) */
40 LPCWSTR pUserName
; /* [out] start of Username */
41 DWORD szUserName
; /* [out] size of Username (until ":" or "@") */
42 LPCWSTR pPassword
; /* [out] start of Password */
43 DWORD szPassword
; /* [out] size of Password (until "@") */
44 LPCWSTR pHostName
; /* [out] start of Hostname */
45 DWORD szHostName
; /* [out] size of Hostname (until ":" or "/") */
46 LPCWSTR pPort
; /* [out] start of Port */
47 DWORD szPort
; /* [out] size of Port (until "/" or eos) */
48 LPCWSTR pQuery
; /* [out] start of Query */
49 DWORD szQuery
; /* [out] size of Query (until eos) */
59 static const WCHAR fileW
[] = {'f','i','l','e','\0'};
61 static const unsigned char HashDataLookup
[256] = {
62 0x01, 0x0E, 0x6E, 0x19, 0x61, 0xAE, 0x84, 0x77, 0x8A, 0xAA, 0x7D, 0x76, 0x1B,
63 0xE9, 0x8C, 0x33, 0x57, 0xC5, 0xB1, 0x6B, 0xEA, 0xA9, 0x38, 0x44, 0x1E, 0x07,
64 0xAD, 0x49, 0xBC, 0x28, 0x24, 0x41, 0x31, 0xD5, 0x68, 0xBE, 0x39, 0xD3, 0x94,
65 0xDF, 0x30, 0x73, 0x0F, 0x02, 0x43, 0xBA, 0xD2, 0x1C, 0x0C, 0xB5, 0x67, 0x46,
66 0x16, 0x3A, 0x4B, 0x4E, 0xB7, 0xA7, 0xEE, 0x9D, 0x7C, 0x93, 0xAC, 0x90, 0xB0,
67 0xA1, 0x8D, 0x56, 0x3C, 0x42, 0x80, 0x53, 0x9C, 0xF1, 0x4F, 0x2E, 0xA8, 0xC6,
68 0x29, 0xFE, 0xB2, 0x55, 0xFD, 0xED, 0xFA, 0x9A, 0x85, 0x58, 0x23, 0xCE, 0x5F,
69 0x74, 0xFC, 0xC0, 0x36, 0xDD, 0x66, 0xDA, 0xFF, 0xF0, 0x52, 0x6A, 0x9E, 0xC9,
70 0x3D, 0x03, 0x59, 0x09, 0x2A, 0x9B, 0x9F, 0x5D, 0xA6, 0x50, 0x32, 0x22, 0xAF,
71 0xC3, 0x64, 0x63, 0x1A, 0x96, 0x10, 0x91, 0x04, 0x21, 0x08, 0xBD, 0x79, 0x40,
72 0x4D, 0x48, 0xD0, 0xF5, 0x82, 0x7A, 0x8F, 0x37, 0x69, 0x86, 0x1D, 0xA4, 0xB9,
73 0xC2, 0xC1, 0xEF, 0x65, 0xF2, 0x05, 0xAB, 0x7E, 0x0B, 0x4A, 0x3B, 0x89, 0xE4,
74 0x6C, 0xBF, 0xE8, 0x8B, 0x06, 0x18, 0x51, 0x14, 0x7F, 0x11, 0x5B, 0x5C, 0xFB,
75 0x97, 0xE1, 0xCF, 0x15, 0x62, 0x71, 0x70, 0x54, 0xE2, 0x12, 0xD6, 0xC7, 0xBB,
76 0x0D, 0x20, 0x5E, 0xDC, 0xE0, 0xD4, 0xF7, 0xCC, 0xC4, 0x2B, 0xF9, 0xEC, 0x2D,
77 0xF4, 0x6F, 0xB6, 0x99, 0x88, 0x81, 0x5A, 0xD9, 0xCA, 0x13, 0xA5, 0xE7, 0x47,
78 0xE6, 0x8E, 0x60, 0xE3, 0x3E, 0xB3, 0xF6, 0x72, 0xA2, 0x35, 0xA0, 0xD7, 0xCD,
79 0xB4, 0x2F, 0x6D, 0x2C, 0x26, 0x1F, 0x95, 0x87, 0x00, 0xD8, 0x34, 0x3F, 0x17,
80 0x25, 0x45, 0x27, 0x75, 0x92, 0xB8, 0xA3, 0xC8, 0xDE, 0xEB, 0xF8, 0xF3, 0xDB,
81 0x0A, 0x98, 0x83, 0x7B, 0xE5, 0xCB, 0x4C, 0x78, 0xD1 };
83 static BOOL
URL_NeedEscapeA(CHAR ch
, DWORD dwFlags
)
89 if(dwFlags
& URL_ESCAPE_SPACES_ONLY
) {
96 if ((dwFlags
& URL_ESCAPE_PERCENT
) && (ch
== '%'))
99 if (ch
<= 31 || ch
>= 127)
121 if (dwFlags
& URL_ESCAPE_SEGMENT_ONLY
) return TRUE
;
128 static BOOL
URL_NeedEscapeW(WCHAR ch
, DWORD dwFlags
)
134 if(dwFlags
& URL_ESCAPE_SPACES_ONLY
) {
141 if ((dwFlags
& URL_ESCAPE_PERCENT
) && (ch
== L
'%'))
144 if (ch
<= 31 || ch
>= 127)
166 if (dwFlags
& URL_ESCAPE_SEGMENT_ONLY
) return TRUE
;
173 static BOOL
URL_JustLocation(LPCWSTR str
)
175 while(*str
&& (*str
== L
'/')) str
++;
177 while (*str
&& ((*str
== L
'-') ||
179 isalnumW(*str
))) str
++;
180 if (*str
== L
'/') return FALSE
;
186 /*************************************************************************
187 * UrlCanonicalizeA [SHLWAPI.@]
189 * Uses the W version to do job.
191 HRESULT WINAPI
UrlCanonicalizeA(LPCSTR pszUrl
, LPSTR pszCanonicalized
,
192 LPDWORD pcchCanonicalized
, DWORD dwFlags
)
194 LPWSTR base
, canonical
;
195 DWORD ret
, len
, len2
;
197 TRACE("(%s %p %p 0x%08lx) using W version\n",
198 debugstr_a(pszUrl
), pszCanonicalized
,
199 pcchCanonicalized
, dwFlags
);
201 base
= (LPWSTR
) HeapAlloc(GetProcessHeap(), 0,
202 (2*INTERNET_MAX_URL_LENGTH
) * sizeof(WCHAR
));
203 canonical
= base
+ INTERNET_MAX_URL_LENGTH
;
205 MultiByteToWideChar(0, 0, pszUrl
, -1, base
, INTERNET_MAX_URL_LENGTH
);
206 len
= INTERNET_MAX_URL_LENGTH
;
208 ret
= UrlCanonicalizeW(base
, canonical
, &len
, dwFlags
);
210 HeapFree(GetProcessHeap(), 0, base
);
214 len2
= WideCharToMultiByte(0, 0, canonical
, len
, 0, 0, 0, 0);
215 if (len2
> *pcchCanonicalized
) {
216 *pcchCanonicalized
= len
;
217 HeapFree(GetProcessHeap(), 0, base
);
220 WideCharToMultiByte(0, 0, canonical
, len
+1, pszCanonicalized
,
221 *pcchCanonicalized
, 0, 0);
222 *pcchCanonicalized
= len2
;
223 HeapFree(GetProcessHeap(), 0, base
);
227 /*************************************************************************
228 * UrlCanonicalizeW [SHLWAPI.@]
231 * MSDN is wrong (at 10/30/01 - go figure). This should support the
232 * following flags: GLA
233 * URL_DONT_ESCAPE_EXTRA_INFO 0x02000000
234 * URL_ESCAPE_SPACES_ONLY 0x04000000
235 * URL_ESCAPE_PERCENT 0x00001000
236 * URL_ESCAPE_UNSAFE 0x10000000
237 * URL_UNESCAPE 0x10000000
238 * URL_DONT_SIMPLIFY 0x08000000
239 * URL_ESCAPE_SEGMENT_ONLY 0x00002000
241 HRESULT WINAPI
UrlCanonicalizeW(LPCWSTR pszUrl
, LPWSTR pszCanonicalized
,
242 LPDWORD pcchCanonicalized
, DWORD dwFlags
)
246 LPWSTR lpszUrlCpy
, wk1
, wk2
, mp
, root
;
247 INT nLen
, nByteLen
, state
;
249 TRACE("(%s %p %p 0x%08lx)\n", debugstr_w(pszUrl
), pszCanonicalized
,
250 pcchCanonicalized
, dwFlags
);
252 nByteLen
= (lstrlenW(pszUrl
) + 1) * sizeof(WCHAR
); /* length in bytes */
253 lpszUrlCpy
= HeapAlloc(GetProcessHeap(), 0, nByteLen
);
255 if (dwFlags
& URL_DONT_SIMPLIFY
)
256 memcpy(lpszUrlCpy
, pszUrl
, nByteLen
);
262 * 1 have 2[+] alnum 2,3
263 * 2 have scheme (found :) 4,6,3
264 * 3 failed (no location)
266 * 5 have 1[+] alnum 6,3
267 * 6 have location (found /) save root location
270 wk1
= (LPWSTR
)pszUrl
;
276 if (!isalnumW(*wk1
)) {state
= 3; break;}
278 if (!isalnumW(*wk1
)) {state
= 3; break;}
284 if (*wk1
++ == L
':') state
= 2;
287 if (*wk1
!= L
'/') {state
= 3; break;}
289 if (*wk1
!= L
'/') {state
= 6; break;}
299 if (!isalnumW(*wk1
) && (*wk1
!= L
'-')) {state
= 3; break;}
300 while(isalnumW(*wk1
) || (*wk1
== L
'-')) *wk2
++ = *wk1
++;
304 if (*wk1
!= L
'/') {state
= 3; break;}
309 /* Now at root location, cannot back up any more. */
310 /* "root" will point at the '/' */
313 TRACE("wk1=%c\n", (CHAR
)*wk1
);
314 mp
= strchrW(wk1
, L
'/');
322 strncpyW(wk2
, wk1
, nLen
);
326 TRACE("found '/.'\n");
327 if (*(wk1
+1) == L
'/') {
328 /* case of /./ -> skip the ./ */
331 else if (*(wk1
+1) == L
'.') {
332 /* found /.. look for next / */
333 TRACE("found '/..'\n");
334 if (*(wk1
+2) == L
'/') {
335 /* case /../ -> need to backup wk2 */
336 TRACE("found '/../'\n");
337 *(wk2
-1) = L
'\0'; /* set end of string */
338 mp
= strrchrW(root
, L
'/');
339 if (mp
&& (mp
>= root
)) {
340 /* found valid backup point */
345 /* did not find point, restore '/' */
355 FIXME("how did we get here - state=%d\n", state
);
360 TRACE("Simplified, orig <%s>, simple <%s>\n",
361 debugstr_w(pszUrl
), debugstr_w(lpszUrlCpy
));
364 if(dwFlags
& URL_UNESCAPE
)
365 UrlUnescapeW(lpszUrlCpy
, NULL
, NULL
, URL_UNESCAPE_INPLACE
);
367 if((EscapeFlags
= dwFlags
& (URL_ESCAPE_UNSAFE
|
368 URL_ESCAPE_SPACES_ONLY
|
370 URL_DONT_ESCAPE_EXTRA_INFO
|
371 URL_ESCAPE_SEGMENT_ONLY
))) {
372 EscapeFlags
&= ~URL_ESCAPE_UNSAFE
;
373 hr
= UrlEscapeW(lpszUrlCpy
, pszCanonicalized
, pcchCanonicalized
,
375 } else { /* No escaping needed, just copy the string */
376 nLen
= lstrlenW(lpszUrlCpy
);
377 if(nLen
< *pcchCanonicalized
)
378 memcpy(pszCanonicalized
, lpszUrlCpy
, (nLen
+ 1)*sizeof(WCHAR
));
383 *pcchCanonicalized
= nLen
;
386 HeapFree(GetProcessHeap(), 0, lpszUrlCpy
);
389 TRACE("result %s\n", debugstr_w(pszCanonicalized
));
394 /*************************************************************************
395 * UrlCombineA [SHLWAPI.@]
397 * Uses the W version to do job.
399 HRESULT WINAPI
UrlCombineA(LPCSTR pszBase
, LPCSTR pszRelative
,
400 LPSTR pszCombined
, LPDWORD pcchCombined
,
403 LPWSTR base
, relative
, combined
;
404 DWORD ret
, len
, len2
;
406 TRACE("(base %s, Relative %s, Combine size %ld, flags %08lx) using W version\n",
407 debugstr_a(pszBase
),debugstr_a(pszRelative
),
408 *pcchCombined
,dwFlags
);
410 base
= (LPWSTR
) HeapAlloc(GetProcessHeap(), 0,
411 (3*INTERNET_MAX_URL_LENGTH
) * sizeof(WCHAR
));
412 relative
= base
+ INTERNET_MAX_URL_LENGTH
;
413 combined
= relative
+ INTERNET_MAX_URL_LENGTH
;
415 MultiByteToWideChar(0, 0, pszBase
, -1, base
, INTERNET_MAX_URL_LENGTH
);
416 MultiByteToWideChar(0, 0, pszRelative
, -1, relative
, INTERNET_MAX_URL_LENGTH
);
417 len
= INTERNET_MAX_URL_LENGTH
;
419 ret
= UrlCombineW(base
, relative
, combined
, &len
, dwFlags
);
421 HeapFree(GetProcessHeap(), 0, base
);
425 len2
= WideCharToMultiByte(0, 0, combined
, len
, 0, 0, 0, 0);
426 if (len2
> *pcchCombined
) {
427 *pcchCombined
= len2
;
428 HeapFree(GetProcessHeap(), 0, base
);
431 WideCharToMultiByte(0, 0, combined
, len
+1, pszCombined
, *pcchCombined
,
433 *pcchCombined
= len2
;
434 HeapFree(GetProcessHeap(), 0, base
);
438 /*************************************************************************
439 * UrlCombineW [SHLWAPI.@]
441 HRESULT WINAPI
UrlCombineW(LPCWSTR pszBase
, LPCWSTR pszRelative
,
442 LPWSTR pszCombined
, LPDWORD pcchCombined
,
445 UNKNOWN_SHLWAPI_2 base
, relative
;
446 DWORD myflags
, sizeloc
= 0;
447 DWORD len
, res1
, res2
, process_case
= 0;
448 LPWSTR work
, preliminary
, mbase
, mrelative
;
449 WCHAR myfilestr
[] = {'f','i','l','e',':','/','/','/','\0'};
450 WCHAR single_slash
[] = {'/','\0'};
453 TRACE("(base %s, Relative %s, Combine size %ld, flags %08lx)\n",
454 debugstr_w(pszBase
),debugstr_w(pszRelative
),
455 *pcchCombined
,dwFlags
);
460 /* Get space for duplicates of the input and the output */
461 preliminary
= HeapAlloc(GetProcessHeap(), 0, (3*INTERNET_MAX_URL_LENGTH
) *
463 mbase
= preliminary
+ INTERNET_MAX_URL_LENGTH
;
464 mrelative
= mbase
+ INTERNET_MAX_URL_LENGTH
;
465 *preliminary
= L
'\0';
467 /* Canonicalize the base input prior to looking for the scheme */
468 myflags
= dwFlags
& (URL_DONT_SIMPLIFY
| URL_UNESCAPE
);
469 len
= INTERNET_MAX_URL_LENGTH
;
470 ret
= UrlCanonicalizeW(pszBase
, mbase
, &len
, myflags
);
472 /* Canonicalize the relative input prior to looking for the scheme */
473 len
= INTERNET_MAX_URL_LENGTH
;
474 ret
= UrlCanonicalizeW(pszRelative
, mrelative
, &len
, myflags
);
476 /* See if the base has a scheme */
477 res1
= SHLWAPI_2(mbase
, &base
);
479 /* if pszBase has no scheme, then return pszRelative */
480 TRACE("no scheme detected in Base\n");
485 /* get size of location field (if it exists) */
486 work
= (LPWSTR
)base
.ap2
;
488 if (*work
++ == L
'/') {
489 if (*work
++ == L
'/') {
490 /* At this point have start of location and
491 * it ends at next '/' or end of string.
493 while(*work
&& (*work
!= L
'/')) work
++;
494 sizeloc
= work
- base
.ap2
;
498 /* Change .sizep2 to not have the last leaf in it,
499 * Note: we need to start after the location (if it exists)
501 work
= strrchrW((base
.ap2
+sizeloc
), L
'/');
503 len
= work
- base
.ap2
+ 1;
508 * .ap2 points to location (starting with '//')
509 * .sizep2 length of location (above) and rest less the last
511 * sizeloc length of location (above) up to but not including
515 res2
= SHLWAPI_2(mrelative
, &relative
);
517 /* no scheme in pszRelative */
518 TRACE("no scheme detected in Relative\n");
519 relative
.ap2
= mrelative
; /* case 3,4,5 depends on this */
520 relative
.sizep2
= strlenW(mrelative
);
521 if (*pszRelative
== L
':') {
522 /* case that is either left alone or uses pszBase */
523 if (dwFlags
& URL_PLUGGABLE_PROTOCOL
) {
530 if (isalnum(*mrelative
) && (*(mrelative
+ 1) == L
':')) {
531 /* case that becomes "file:///" */
532 strcpyW(preliminary
, myfilestr
);
536 if ((*mrelative
== L
'/') && (*(mrelative
+1) == L
'/')) {
537 /* pszRelative has location and rest */
541 if (*mrelative
== L
'/') {
542 /* case where pszRelative is root to location */
546 process_case
= (*base
.ap2
== L
'/') ? 5 : 3;
550 /* handle cases where pszRelative has scheme */
551 if ((base
.sizep1
== relative
.sizep1
) &&
552 (strncmpW(base
.ap1
, relative
.ap1
, base
.sizep1
) == 0)) {
554 /* since the schemes are the same */
555 if ((*relative
.ap2
== L
'/') && (*(relative
.ap2
+1) == L
'/')) {
556 /* case where pszRelative replaces location and following */
560 if (*relative
.ap2
== L
'/') {
561 /* case where pszRelative is root to location */
565 /* case where scheme is followed by document path */
569 if ((*relative
.ap2
== L
'/') && (*(relative
.ap2
+1) == L
'/')) {
570 /* case where pszRelative replaces scheme, location,
571 * and following and handles PLUGGABLE
578 } while(FALSE
); /* a litte trick to allow easy exit from nested if's */
582 switch (process_case
) {
585 * Return pszRelative appended to what ever is in pszCombined,
586 * (which may the string "file:///"
588 len
= strlenW(mrelative
) + strlenW(preliminary
);
589 if (len
+1 > *pcchCombined
) {
594 strcatW(preliminary
, mrelative
);
598 * Same as case 1, but if URL_PLUGGABLE_PROTOCOL was specified
599 * and pszRelative starts with "//", then append a "/"
601 len
= strlenW(mrelative
) + 1;
602 if (len
+1 > *pcchCombined
) {
607 strcpyW(preliminary
, mrelative
);
608 if (!(dwFlags
& URL_PLUGGABLE_PROTOCOL
) &&
609 URL_JustLocation(relative
.ap2
))
610 strcatW(preliminary
, single_slash
);
614 * Return the pszBase scheme with pszRelative. Basicly
615 * keeps the scheme and replaces the domain and following.
617 len
= base
.sizep1
+ 1 + relative
.sizep2
+ 1;
618 if (len
+1 > *pcchCombined
) {
623 strncpyW(preliminary
, base
.ap1
, base
.sizep1
+ 1);
624 work
= preliminary
+ base
.sizep1
+ 1;
625 strcpyW(work
, relative
.ap2
);
626 if (!(dwFlags
& URL_PLUGGABLE_PROTOCOL
) &&
627 URL_JustLocation(relative
.ap2
))
628 strcatW(work
, single_slash
);
632 * Return the pszBase scheme and location but everything
633 * after the location is pszRelative. (Replace document
636 len
= base
.sizep1
+ 1 + sizeloc
+ relative
.sizep2
+ 1;
637 if (len
+1 > *pcchCombined
) {
642 strncpyW(preliminary
, base
.ap1
, base
.sizep1
+1+sizeloc
);
643 work
= preliminary
+ base
.sizep1
+ 1 + sizeloc
;
644 if (dwFlags
& URL_PLUGGABLE_PROTOCOL
)
646 strcpyW(work
, relative
.ap2
);
650 * Return the pszBase without its document (if any) and
651 * append pszRelative after its scheme.
653 len
= base
.sizep1
+ 1 + base
.sizep2
+ relative
.sizep2
;
654 if (len
+1 > *pcchCombined
) {
659 strncpyW(preliminary
, base
.ap1
, base
.sizep1
+1+base
.sizep2
);
660 work
= preliminary
+ base
.sizep1
+1+base
.sizep2
- 1;
663 strcpyW(work
, relative
.ap2
);
667 FIXME("How did we get here????? process_case=%ld\n", process_case
);
673 * Now that the combining is done, process the escape options if
674 * necessary, otherwise just copy the string.
676 myflags
= dwFlags
& (URL_ESCAPE_PERCENT
|
677 URL_ESCAPE_SPACES_ONLY
|
678 URL_DONT_ESCAPE_EXTRA_INFO
|
679 URL_ESCAPE_SEGMENT_ONLY
);
681 ret
= UrlEscapeW(preliminary
, pszCombined
,
682 pcchCombined
, myflags
);
684 len
= (strlenW(preliminary
) + 1) * sizeof(WCHAR
);
685 memcpy(pszCombined
, preliminary
, len
);
686 *pcchCombined
= strlenW(preliminary
);
688 TRACE("return-%ld len=%ld, %s\n",
689 process_case
, *pcchCombined
, debugstr_w(pszCombined
));
691 HeapFree(GetProcessHeap(), 0, preliminary
);
695 /*************************************************************************
696 * UrlEscapeA [SHLWAPI.@]
698 * Converts unsafe characters into their escape sequences.
700 * The converted string is returned in pszEscaped if the buffer size
701 * (which should be supplied in pcchEscaped) is large enough, in this
702 * case the function returns S_OK and pcchEscaped contains the length
703 * of the escaped string. If the buffer is not large enough the
704 * function returns E_POINTER and pcchEscaped contains the required
705 * buffer size (including room for the '\0').
707 * By default the function stops converting at the first '?' or
708 * '#'. [MSDN says differently]. If URL_ESCAPE_SPACE_ONLY flag is set
709 * then only spaces are converted, but the conversion continues past a
713 * Have now implemented the following flags:
714 * URL_ESCAPE_SPACES_ONLY
715 * URL_DONT_ESCAPE_EXTRA_INFO
716 * URL_ESCAPE_SEGMENT_ONLY
718 * Initial testing seems to indicate that this is now working like
719 * native shlwapi version 5. Note that these functions did not work
720 * well (or at all) in shlwapi version 4.
723 HRESULT WINAPI
UrlEscapeA(
730 DWORD needed
= 0, ret
;
731 BOOL stop_escaping
= FALSE
;
732 char next
[3], *dst
= pszEscaped
;
733 char hex
[] = "0123456789ABCDEF";
736 TRACE("(%s %p %p 0x%08lx)\n", debugstr_a(pszUrl
), pszEscaped
,
737 pcchEscaped
, dwFlags
);
739 if(dwFlags
& ~(URL_ESCAPE_SPACES_ONLY
|
740 URL_ESCAPE_SEGMENT_ONLY
|
741 URL_DONT_ESCAPE_EXTRA_INFO
|
743 FIXME("Unimplemented flags: %08lx\n", dwFlags
);
746 if (dwFlags
& URL_ESCAPE_SPACES_ONLY
)
747 /* if SPACES_ONLY specified, reset the other controls */
748 dwFlags
&= ~(URL_DONT_ESCAPE_EXTRA_INFO
|
750 URL_ESCAPE_SEGMENT_ONLY
);
753 /* if SPACES_ONLY *not* specified the assume DONT_ESCAPE_EXTRA_INFO */
754 dwFlags
|= URL_DONT_ESCAPE_EXTRA_INFO
;
756 for(src
= pszUrl
; *src
; src
++) {
757 if(!(dwFlags
& URL_ESCAPE_SEGMENT_ONLY
) &&
758 (dwFlags
& URL_DONT_ESCAPE_EXTRA_INFO
) &&
759 (*src
== '#' || *src
== '?'))
760 stop_escaping
= TRUE
;
762 if(URL_NeedEscapeA(*src
, dwFlags
) && stop_escaping
== FALSE
) {
763 /* TRACE("escaping %c\n", *src); */
765 next
[1] = hex
[(*src
>> 4) & 0xf];
766 next
[2] = hex
[*src
& 0xf];
769 /* TRACE("passing %c\n", *src); */
774 if(needed
+ len
<= *pcchEscaped
) {
775 memcpy(dst
, next
, len
);
781 if(needed
< *pcchEscaped
) {
785 needed
++; /* add one for the '\0' */
788 *pcchEscaped
= needed
;
792 /*************************************************************************
793 * UrlEscapeW [SHLWAPI.@]
795 * See UrlEscapeA for list of assumptions, bugs, and FIXMEs
797 HRESULT WINAPI
UrlEscapeW(
804 DWORD needed
= 0, ret
;
805 BOOL stop_escaping
= FALSE
;
806 WCHAR next
[5], *dst
= pszEscaped
;
807 CHAR hex
[] = "0123456789ABCDEF";
810 TRACE("(%s %p %p 0x%08lx)\n", debugstr_w(pszUrl
), pszEscaped
,
811 pcchEscaped
, dwFlags
);
813 if(dwFlags
& ~(URL_ESCAPE_SPACES_ONLY
|
814 URL_ESCAPE_SEGMENT_ONLY
|
815 URL_DONT_ESCAPE_EXTRA_INFO
|
817 FIXME("Unimplemented flags: %08lx\n", dwFlags
);
820 if (dwFlags
& URL_ESCAPE_SPACES_ONLY
)
821 /* if SPACES_ONLY specified, reset the other controls */
822 dwFlags
&= ~(URL_DONT_ESCAPE_EXTRA_INFO
|
824 URL_ESCAPE_SEGMENT_ONLY
);
827 /* if SPACES_ONLY *not* specified the assume DONT_ESCAPE_EXTRA_INFO */
828 dwFlags
|= URL_DONT_ESCAPE_EXTRA_INFO
;
830 for(src
= pszUrl
; *src
; src
++) {
832 * if(!(dwFlags & URL_ESCAPE_SPACES_ONLY) &&
833 * (*src == L'#' || *src == L'?'))
834 * stop_escaping = TRUE;
836 if(!(dwFlags
& URL_ESCAPE_SEGMENT_ONLY
) &&
837 (dwFlags
& URL_DONT_ESCAPE_EXTRA_INFO
) &&
838 (*src
== L
'#' || *src
== L
'?'))
839 stop_escaping
= TRUE
;
841 if(URL_NeedEscapeW(*src
, dwFlags
) && stop_escaping
== FALSE
) {
842 /* TRACE("escaping %c\n", *src); */
845 * I would have assumed that the W form would escape
846 * the character with 4 hex digits (or even 8),
847 * however, experiments show that native shlwapi escapes
848 * with only 2 hex digits.
849 * next[1] = hex[(*src >> 12) & 0xf];
850 * next[2] = hex[(*src >> 8) & 0xf];
851 * next[3] = hex[(*src >> 4) & 0xf];
852 * next[4] = hex[*src & 0xf];
855 next
[1] = hex
[(*src
>> 4) & 0xf];
856 next
[2] = hex
[*src
& 0xf];
859 /* TRACE("passing %c\n", *src); */
864 if(needed
+ len
<= *pcchEscaped
) {
865 memcpy(dst
, next
, len
*sizeof(WCHAR
));
871 if(needed
< *pcchEscaped
) {
875 needed
++; /* add one for the '\0' */
878 *pcchEscaped
= needed
;
883 /*************************************************************************
884 * UrlUnescapeA [SHLWAPI.@]
886 * Converts escape sequences back to ordinary characters.
888 * If URL_ESCAPE_INPLACE is set in dwFlags then pszUnescaped and
889 * pcchUnescaped are ignored and the converted string is returned in
890 * pszUrl, otherwise the string is returned in pszUnescaped.
891 * pcchUnescaped should contain the size of pszUnescaped on calling
892 * and will contain the length the the returned string on return if
893 * the buffer is big enough else it will contain the buffer size
894 * required (including room for the '\0'). The function returns S_OK
895 * on success or E_POINTER if the buffer is not large enough. If the
896 * URL_DONT_ESCAPE_EXTRA_INFO flag is set then the conversion stops at
897 * the first occurrence of either '?' or '#'.
900 HRESULT WINAPI
UrlUnescapeA(
903 LPDWORD pcchUnescaped
,
910 BOOL stop_unescaping
= FALSE
;
912 TRACE("(%s, %p, %p, 0x%08lx)\n", debugstr_a(pszUrl
), pszUnescaped
,
913 pcchUnescaped
, dwFlags
);
915 if(dwFlags
& URL_UNESCAPE_INPLACE
)
920 for(src
= pszUrl
, needed
= 0; *src
; src
++, needed
++) {
921 if(dwFlags
& URL_DONT_UNESCAPE_EXTRA_INFO
&&
922 (*src
== '#' || *src
== '?')) {
923 stop_unescaping
= TRUE
;
925 } else if(*src
== '%' && isxdigit(*(src
+ 1)) && isxdigit(*(src
+ 2))
926 && stop_unescaping
== FALSE
) {
929 memcpy(buf
, src
+ 1, 2);
931 ih
= strtol(buf
, NULL
, 16);
933 src
+= 2; /* Advance to end of escape */
937 if(dwFlags
& URL_UNESCAPE_INPLACE
|| needed
< *pcchUnescaped
)
941 if(dwFlags
& URL_UNESCAPE_INPLACE
|| needed
< *pcchUnescaped
) {
945 needed
++; /* add one for the '\0' */
948 if(!(dwFlags
& URL_UNESCAPE_INPLACE
))
949 *pcchUnescaped
= needed
;
952 TRACE("result %s\n", (dwFlags
& URL_UNESCAPE_INPLACE
) ?
953 debugstr_a(pszUrl
) : debugstr_a(pszUnescaped
));
959 /*************************************************************************
960 * UrlUnescapeW [SHLWAPI.@]
962 * See UrlUnescapeA for list of assumptions, bugs, and FIXMEs
964 HRESULT WINAPI
UrlUnescapeW(
967 LPDWORD pcchUnescaped
,
974 BOOL stop_unescaping
= FALSE
;
976 TRACE("(%s, %p, %p, 0x%08lx)\n", debugstr_w(pszUrl
), pszUnescaped
,
977 pcchUnescaped
, dwFlags
);
979 if(dwFlags
& URL_UNESCAPE_INPLACE
)
980 dst
= (WCHAR
*)pszUrl
;
984 for(src
= pszUrl
, needed
= 0; *src
; src
++, needed
++) {
985 if(dwFlags
& URL_DONT_UNESCAPE_EXTRA_INFO
&&
986 (*src
== L
'#' || *src
== L
'?')) {
987 stop_unescaping
= TRUE
;
989 } else if(*src
== L
'%' && isxdigitW(*(src
+ 1)) && isxdigitW(*(src
+ 2))
990 && stop_unescaping
== FALSE
) {
993 memcpy(buf
, src
+ 1, 2*sizeof(WCHAR
));
997 src
+= 2; /* Advance to end of escape */
1001 if(dwFlags
& URL_UNESCAPE_INPLACE
|| needed
< *pcchUnescaped
)
1005 if(dwFlags
& URL_UNESCAPE_INPLACE
|| needed
< *pcchUnescaped
) {
1009 needed
++; /* add one for the '\0' */
1012 if(!(dwFlags
& URL_UNESCAPE_INPLACE
))
1013 *pcchUnescaped
= needed
;
1016 TRACE("result %s\n", (dwFlags
& URL_UNESCAPE_INPLACE
) ?
1017 debugstr_w(pszUrl
) : debugstr_w(pszUnescaped
));
1023 /*************************************************************************
1024 * UrlGetLocationA [SHLWAPI.@]
1027 * MSDN (as of 2001-11-01) says that:
1028 * "The location is the segment of the URL starting with a ?
1030 * Neither V4 nor V5 of shlwapi.dll implement the '?' and always return
1032 * MSDN further states that:
1033 * "If a file URL has a query string, ther returned string
1034 * the query string."
1035 * In all test cases if the scheme starts with "fi" then a NULL is
1036 * returned. V5 gives the following results:
1037 * NULL file://aa/b/cd#hohoh
1038 * #hohoh http://aa/b/cd#hohoh
1039 * NULL fi://aa/b/cd#hohoh
1040 * #hohoh ff://aa/b/cd#hohoh
1042 LPCSTR WINAPI
UrlGetLocationA(
1045 UNKNOWN_SHLWAPI_1 base
;
1049 res1
= SHLWAPI_1(pszUrl
, &base
);
1050 if (res1
) return NULL
; /* invalid scheme */
1052 /* if scheme is file: then never return pointer */
1053 if (strncmp(base
.ap1
, "file", min(4,base
.sizep1
)) == 0) return NULL
;
1055 /* Look for '#' and return its addr */
1056 return strchr(base
.ap2
, '#');
1059 /*************************************************************************
1060 * UrlGetLocationW [SHLWAPI.@]
1062 * See UrlGetLocationA for list of assumptions, bugs, and FIXMEs
1064 LPCWSTR WINAPI
UrlGetLocationW(
1067 UNKNOWN_SHLWAPI_2 base
;
1071 res1
= SHLWAPI_2(pszUrl
, &base
);
1072 if (res1
) return NULL
; /* invalid scheme */
1074 /* if scheme is file: then never return pointer */
1075 if (strncmpW(base
.ap1
, fileW
, min(4,base
.sizep1
)) == 0) return NULL
;
1077 /* Look for '#' and return its addr */
1078 return strchrW(base
.ap2
, L
'#');
1081 /*************************************************************************
1082 * UrlCompareA [SHLWAPI.@]
1084 INT WINAPI
UrlCompareA(
1089 INT ret
, len
, len1
, len2
;
1092 return strcmp(pszUrl1
, pszUrl2
);
1093 len1
= strlen(pszUrl1
);
1094 if (pszUrl1
[len1
-1] == L
'/') len1
--;
1095 len2
= strlen(pszUrl2
);
1096 if (pszUrl2
[len2
-1] == L
'/') len2
--;
1098 return strncmp(pszUrl1
, pszUrl2
, len1
);
1099 len
= min(len1
, len2
);
1100 ret
= strncmp(pszUrl1
, pszUrl2
, len
);
1101 if (ret
) return ret
;
1102 if (len1
> len2
) return 1;
1106 /*************************************************************************
1107 * UrlCompareW [SHLWAPI.@]
1109 INT WINAPI
UrlCompareW(
1114 INT ret
, len
, len1
, len2
;
1117 return strcmpW(pszUrl1
, pszUrl2
);
1118 len1
= strlenW(pszUrl1
);
1119 if (pszUrl1
[len1
-1] == L
'/') len1
--;
1120 len2
= strlenW(pszUrl2
);
1121 if (pszUrl2
[len2
-1] == L
'/') len2
--;
1123 return strncmpW(pszUrl1
, pszUrl2
, len1
);
1124 len
= min(len1
, len2
);
1125 ret
= strncmpW(pszUrl1
, pszUrl2
, len
);
1126 if (ret
) return ret
;
1127 if (len1
> len2
) return 1;
1131 /*************************************************************************
1132 * HashData [SHLWAPI.@]
1134 * Hash an input block into a variable sized digest.
1136 BOOL WINAPI
HashData(const unsigned char *lpSrc
, INT nSrcLen
,
1137 unsigned char *lpDest
, INT nDestLen
)
1139 INT srcCount
= nSrcLen
- 1, destCount
= nDestLen
- 1;
1141 if (IsBadReadPtr(lpSrc
, nSrcLen
) ||
1142 IsBadWritePtr(lpDest
, nDestLen
))
1145 while (destCount
>= 0)
1147 lpDest
[destCount
] = (destCount
& 0xff);
1151 while (srcCount
>= 0)
1153 destCount
= nDestLen
- 1;
1154 while (destCount
>= 0)
1156 lpDest
[destCount
] = HashDataLookup
[lpSrc
[srcCount
] ^ lpDest
[destCount
]];
1164 /*************************************************************************
1165 * UrlHashA [SHLWAPI.@]
1167 * Hash an ASCII URL.
1169 HRESULT WINAPI
UrlHashA(LPCSTR pszUrl
, unsigned char *lpDest
, INT nDestLen
)
1171 if (IsBadStringPtrA(pszUrl
, -1) || IsBadWritePtr(lpDest
, nDestLen
))
1172 return E_INVALIDARG
;
1174 HashData(pszUrl
, strlen(pszUrl
), lpDest
, nDestLen
);
1178 /*************************************************************************
1179 * UrlApplySchemeA [SHLWAPI.@]
1181 HRESULT WINAPI
UrlApplySchemeA(LPCSTR pszIn
, LPSTR pszOut
, LPDWORD pcchOut
, DWORD dwFlags
)
1184 DWORD ret
, len
, len2
;
1186 TRACE("(in %s, out size %ld, flags %08lx) using W version\n",
1187 debugstr_a(pszIn
), *pcchOut
, dwFlags
);
1189 in
= (LPWSTR
) HeapAlloc(GetProcessHeap(), 0,
1190 (2*INTERNET_MAX_URL_LENGTH
) * sizeof(WCHAR
));
1191 out
= in
+ INTERNET_MAX_URL_LENGTH
;
1193 MultiByteToWideChar(0, 0, pszIn
, -1, in
, INTERNET_MAX_URL_LENGTH
);
1194 len
= INTERNET_MAX_URL_LENGTH
;
1196 ret
= UrlApplySchemeW(in
, out
, &len
, dwFlags
);
1197 if ((ret
!= S_OK
) && (ret
!= S_FALSE
)) {
1198 HeapFree(GetProcessHeap(), 0, in
);
1202 len2
= WideCharToMultiByte(0, 0, out
, len
+1, 0, 0, 0, 0);
1203 if (len2
> *pcchOut
) {
1205 HeapFree(GetProcessHeap(), 0, in
);
1208 WideCharToMultiByte(0, 0, out
, len
+1, pszOut
, *pcchOut
, 0, 0);
1210 HeapFree(GetProcessHeap(), 0, in
);
1214 HRESULT
URL_GuessScheme(LPCWSTR pszIn
, LPWSTR pszOut
, LPDWORD pcchOut
)
1219 DWORD value_len
, data_len
, dwType
;
1220 WCHAR reg_path
[MAX_PATH
];
1221 WCHAR value
[MAX_PATH
], data
[MAX_PATH
];
1224 MultiByteToWideChar(0, 0,
1225 "Software\\Microsoft\\Windows\\CurrentVersion\\URL\\Prefixes",
1226 -1, reg_path
, MAX_PATH
);
1227 RegOpenKeyExW(HKEY_LOCAL_MACHINE
, reg_path
, 0, 1, &newkey
);
1229 while(value_len
= data_len
= MAX_PATH
,
1230 RegEnumValueW(newkey
, index
, value
, &value_len
,
1231 0, &dwType
, (LPVOID
)data
, &data_len
) == 0) {
1232 TRACE("guess %d %s is %s\n",
1233 index
, debugstr_w(value
), debugstr_w(data
));
1236 for(i
=0; i
<value_len
; i
++) {
1239 /* remember that TRUE is not-equal */
1240 j
= ChrCmpIW(Wxx
, Wyy
);
1243 if ((i
== value_len
) && !j
) {
1244 if (strlenW(data
) + strlenW(pszIn
) + 1 > *pcchOut
) {
1245 *pcchOut
= strlenW(data
) + strlenW(pszIn
) + 1;
1246 RegCloseKey(newkey
);
1249 strcpyW(pszOut
, data
);
1250 strcatW(pszOut
, pszIn
);
1251 *pcchOut
= strlenW(pszOut
);
1252 TRACE("matched and set to %s\n", debugstr_w(pszOut
));
1253 RegCloseKey(newkey
);
1258 RegCloseKey(newkey
);
1262 HRESULT
URL_ApplyDefault(LPCWSTR pszIn
, LPWSTR pszOut
, LPDWORD pcchOut
)
1265 DWORD data_len
, dwType
;
1266 WCHAR reg_path
[MAX_PATH
];
1267 WCHAR value
[MAX_PATH
], data
[MAX_PATH
];
1269 /* get and prepend default */
1270 MultiByteToWideChar(0, 0,
1271 "Software\\Microsoft\\Windows\\CurrentVersion\\URL\\DefaultPrefix",
1272 -1, reg_path
, MAX_PATH
);
1273 RegOpenKeyExW(HKEY_LOCAL_MACHINE
, reg_path
, 0, 1, &newkey
);
1274 data_len
= MAX_PATH
;
1277 RegQueryValueExW(newkey
, value
, 0, &dwType
, (LPBYTE
)data
, &data_len
);
1278 RegCloseKey(newkey
);
1279 if (strlenW(data
) + strlenW(pszIn
) + 1 > *pcchOut
) {
1280 *pcchOut
= strlenW(data
) + strlenW(pszIn
) + 1;
1283 strcpyW(pszOut
, data
);
1284 strcatW(pszOut
, pszIn
);
1285 *pcchOut
= strlenW(pszOut
);
1286 TRACE("used default %s\n", debugstr_w(pszOut
));
1290 /*************************************************************************
1291 * UrlApplySchemeW [SHLWAPI.@]
1293 HRESULT WINAPI
UrlApplySchemeW(LPCWSTR pszIn
, LPWSTR pszOut
, LPDWORD pcchOut
, DWORD dwFlags
)
1295 UNKNOWN_SHLWAPI_2 in_scheme
;
1299 TRACE("(in %s, out size %ld, flags %08lx)\n",
1300 debugstr_w(pszIn
), *pcchOut
, dwFlags
);
1302 if (dwFlags
& URL_APPLY_GUESSFILE
) {
1303 FIXME("(%s %p %p(%ld) 0x%08lx): stub URL_APPLY_GUESSFILE not implemented\n",
1304 debugstr_w(pszIn
), pszOut
, pcchOut
, *pcchOut
, dwFlags
);
1305 strcpyW(pszOut
, pszIn
);
1306 *pcchOut
= strlenW(pszOut
);
1310 in_scheme
.size
= 24;
1311 /* See if the base has a scheme */
1312 res1
= SHLWAPI_2(pszIn
, &in_scheme
);
1314 /* no scheme in input, need to see if we need to guess */
1315 if (dwFlags
& URL_APPLY_GUESSSCHEME
) {
1316 if ((ret
= URL_GuessScheme(pszIn
, pszOut
, pcchOut
)) != -1)
1321 /* we have a scheme, see if valid (known scheme) */
1322 if (in_scheme
.fcncde
) {
1323 /* have valid scheme, so just copy and exit */
1324 if (strlenW(pszIn
) + 1 > *pcchOut
) {
1325 *pcchOut
= strlenW(pszIn
) + 1;
1328 strcpyW(pszOut
, pszIn
);
1329 *pcchOut
= strlenW(pszOut
);
1330 TRACE("valid scheme, returing copy\n");
1335 /* If we are here, then either invalid scheme,
1336 * or no scheme and can't/failed guess.
1338 if ( ( ((res1
== 0) && (dwFlags
& URL_APPLY_FORCEAPPLY
)) ||
1340 (dwFlags
& URL_APPLY_DEFAULT
)) {
1341 /* find and apply default scheme */
1342 return URL_ApplyDefault(pszIn
, pszOut
, pcchOut
);
1345 /* just copy and give proper return code */
1346 if (strlenW(pszIn
) + 1 > *pcchOut
) {
1347 *pcchOut
= strlenW(pszIn
) + 1;
1350 strcpyW(pszOut
, pszIn
);
1351 *pcchOut
= strlenW(pszOut
);
1352 TRACE("returing copy, left alone\n");
1356 /*************************************************************************
1357 * UrlIsA [SHLWAPI.@]
1359 BOOL WINAPI
UrlIsA(LPCSTR pszUrl
, URLIS Urlis
)
1361 UNKNOWN_SHLWAPI_1 base
;
1368 res1
= SHLWAPI_1(pszUrl
, &base
);
1369 if (res1
) return FALSE
; /* invalid scheme */
1370 if ((*base
.ap2
== '/') && (*(base
.ap2
+1) == '/'))
1371 /* has scheme followed by 2 '/' */
1376 case URLIS_NOHISTORY
:
1378 case URLIS_APPLIABLE
:
1379 case URLIS_DIRECTORY
:
1380 case URLIS_HASQUERY
:
1382 FIXME("(%s %d): stub\n", debugstr_a(pszUrl
), Urlis
);
1387 /*************************************************************************
1388 * UrlIsW [SHLWAPI.@]
1390 BOOL WINAPI
UrlIsW(LPCWSTR pszUrl
, URLIS Urlis
)
1392 UNKNOWN_SHLWAPI_2 base
;
1399 res1
= SHLWAPI_2(pszUrl
, &base
);
1400 if (res1
) return FALSE
; /* invalid scheme */
1401 if ((*base
.ap2
== L
'/') && (*(base
.ap2
+1) == L
'/'))
1402 /* has scheme followed by 2 '/' */
1407 case URLIS_NOHISTORY
:
1409 case URLIS_APPLIABLE
:
1410 case URLIS_DIRECTORY
:
1411 case URLIS_HASQUERY
:
1413 FIXME("(%s %d): stub\n", debugstr_w(pszUrl
), Urlis
);
1418 /*************************************************************************
1419 * UrlIsNoHistoryA [SHLWAPI.@]
1421 BOOL WINAPI
UrlIsNoHistoryA(LPCSTR pszUrl
)
1423 return UrlIsA(pszUrl
, URLIS_NOHISTORY
);
1426 /*************************************************************************
1427 * UrlIsNoHistoryW [SHLWAPI.@]
1429 BOOL WINAPI
UrlIsNoHistoryW(LPCWSTR pszUrl
)
1431 return UrlIsW(pszUrl
, URLIS_NOHISTORY
);
1434 /*************************************************************************
1435 * UrlIsOpaqueA [SHLWAPI.@]
1437 BOOL WINAPI
UrlIsOpaqueA(LPCSTR pszUrl
)
1439 return UrlIsA(pszUrl
, URLIS_OPAQUE
);
1442 /*************************************************************************
1443 * UrlIsOpaqueW [SHLWAPI.@]
1445 BOOL WINAPI
UrlIsOpaqueW(LPCWSTR pszUrl
)
1447 return UrlIsW(pszUrl
, URLIS_OPAQUE
);
1450 /*************************************************************************
1451 * Scans for characters of type "type" and when not matching found,
1452 * returns pointer to it and length in size.
1454 * Characters tested based on RFC 1738
1456 LPCWSTR
URL_ScanID(LPCWSTR start
, LPDWORD size
, WINE_URL_SCAN_TYPE type
)
1458 static DWORD alwayszero
= 0;
1467 if ( (islowerW(*start
) && isalphaW(*start
)) ||
1482 if ( isalphaW(*start
) ||
1484 /* user/password only characters */
1489 /* *extra* characters */
1492 (*start
== L
'\'') ||
1496 /* *safe* characters */
1504 } else if (*start
== L
'%') {
1505 if (isxdigitW(*(start
+1)) &&
1506 isxdigitW(*(start
+2))) {
1518 if (isdigitW(*start
)) {
1529 if (isalnumW(*start
) ||
1531 (*start
== L
'.') ) {
1540 FIXME("unknown type %d\n", type
);
1541 return (LPWSTR
)&alwayszero
;
1543 /* TRACE("scanned %ld characters next char %p<%c>\n",
1544 *size, start, *start); */
1548 /*************************************************************************
1549 * Attempt to parse URL into pieces.
1551 LONG
URL_ParseUrl(LPCWSTR pszUrl
, WINE_PARSE_URL
*pl
)
1555 memset(pl
, 0, sizeof(WINE_PARSE_URL
));
1556 pl
->pScheme
= pszUrl
;
1557 work
= URL_ScanID(pl
->pScheme
, &pl
->szScheme
, SCHEME
);
1558 if (!*work
|| (*work
!= L
':')) goto ERROR
;
1560 if ((*work
!= L
'/') || (*(work
+1) != L
'/')) goto ERROR
;
1561 pl
->pUserName
= work
+ 2;
1562 work
= URL_ScanID(pl
->pUserName
, &pl
->szUserName
, USERPASS
);
1563 if (*work
== L
':' ) {
1564 /* parse password */
1566 pl
->pPassword
= work
;
1567 work
= URL_ScanID(pl
->pPassword
, &pl
->szPassword
, USERPASS
);
1568 if (*work
!= L
'@') {
1569 /* what we just parsed must be the hostname and port
1570 * so reset pointers and clear then let it parse */
1571 pl
->szUserName
= pl
->szPassword
= 0;
1572 work
= pl
->pUserName
- 1;
1573 pl
->pUserName
= pl
->pPassword
= 0;
1575 } else if (*work
== L
'@') {
1579 } else if (!*work
|| (*work
== L
'/') || (*work
== L
'.')) {
1580 /* what was parsed was hostname, so reset pointers and let it parse */
1581 pl
->szUserName
= pl
->szPassword
= 0;
1582 work
= pl
->pUserName
- 1;
1583 pl
->pUserName
= pl
->pPassword
= 0;
1586 /* now start parsing hostname or hostnumber */
1588 pl
->pHostName
= work
;
1589 work
= URL_ScanID(pl
->pHostName
, &pl
->szHostName
, HOST
);
1590 if (*work
== L
':') {
1594 work
= URL_ScanID(pl
->pPort
, &pl
->szPort
, PORT
);
1596 if (*work
== L
'/') {
1597 /* see if query string */
1598 pl
->pQuery
= strchrW(work
, L
'?');
1599 if (pl
->pQuery
) pl
->szQuery
= strlenW(pl
->pQuery
);
1601 TRACE("parse successful: scheme=%p(%ld), user=%p(%ld), pass=%p(%ld), host=%p(%ld), port=%p(%ld), query=%p(%ld)\n",
1602 pl
->pScheme
, pl
->szScheme
,
1603 pl
->pUserName
, pl
->szUserName
,
1604 pl
->pPassword
, pl
->szPassword
,
1605 pl
->pHostName
, pl
->szHostName
,
1606 pl
->pPort
, pl
->szPort
,
1607 pl
->pQuery
, pl
->szQuery
);
1610 FIXME("failed to parse %s\n", debugstr_w(pszUrl
));
1611 return E_INVALIDARG
;
1614 /*************************************************************************
1615 * UrlGetPartA [SHLWAPI.@]
1617 HRESULT WINAPI
UrlGetPartA(LPCSTR pszIn
, LPSTR pszOut
, LPDWORD pcchOut
,
1618 DWORD dwPart
, DWORD dwFlags
)
1621 DWORD ret
, len
, len2
;
1623 in
= (LPWSTR
) HeapAlloc(GetProcessHeap(), 0,
1624 (2*INTERNET_MAX_URL_LENGTH
) * sizeof(WCHAR
));
1625 out
= in
+ INTERNET_MAX_URL_LENGTH
;
1627 MultiByteToWideChar(0, 0, pszIn
, -1, in
, INTERNET_MAX_URL_LENGTH
);
1629 len
= INTERNET_MAX_URL_LENGTH
;
1630 ret
= UrlGetPartW(in
, out
, &len
, dwPart
, dwFlags
);
1633 HeapFree(GetProcessHeap(), 0, in
);
1637 len2
= WideCharToMultiByte(0, 0, out
, len
, 0, 0, 0, 0);
1638 if (len2
> *pcchOut
) {
1640 HeapFree(GetProcessHeap(), 0, in
);
1643 WideCharToMultiByte(0, 0, out
, len
+1, pszOut
, *pcchOut
, 0, 0);
1645 HeapFree(GetProcessHeap(), 0, in
);
1649 /*************************************************************************
1650 * UrlGetPartW [SHLWAPI.@]
1652 HRESULT WINAPI
UrlGetPartW(LPCWSTR pszIn
, LPWSTR pszOut
, LPDWORD pcchOut
,
1653 DWORD dwPart
, DWORD dwFlags
)
1657 DWORD size
, schsize
;
1658 LPCWSTR addr
, schaddr
;
1661 TRACE("(%s %p %p(%ld) %08lx %08lx)\n",
1662 debugstr_w(pszIn
), pszOut
, pcchOut
, *pcchOut
, dwPart
, dwFlags
);
1664 ret
= URL_ParseUrl(pszIn
, &pl
);
1666 schaddr
= pl
.pScheme
;
1667 schsize
= pl
.szScheme
;
1670 case URL_PART_SCHEME
:
1671 if (!pl
.szScheme
) return E_INVALIDARG
;
1676 case URL_PART_HOSTNAME
:
1677 if (!pl
.szHostName
) return E_INVALIDARG
;
1678 addr
= pl
.pHostName
;
1679 size
= pl
.szHostName
;
1682 case URL_PART_USERNAME
:
1683 if (!pl
.szUserName
) return E_INVALIDARG
;
1684 addr
= pl
.pUserName
;
1685 size
= pl
.szUserName
;
1688 case URL_PART_PASSWORD
:
1689 if (!pl
.szPassword
) return E_INVALIDARG
;
1690 addr
= pl
.pPassword
;
1691 size
= pl
.szPassword
;
1695 if (!pl
.szPort
) return E_INVALIDARG
;
1700 case URL_PART_QUERY
:
1701 if (!pl
.szQuery
) return E_INVALIDARG
;
1707 return E_INVALIDARG
;
1710 if (dwFlags
== URL_PARTFLAG_KEEPSCHEME
) {
1711 if (*pcchOut
< size
+ schsize
+ 2) {
1712 *pcchOut
= size
+ schsize
+ 2;
1715 strncpyW(pszOut
, schaddr
, schsize
);
1716 work
= pszOut
+ schsize
;
1718 strncpyW(work
+1, addr
, size
);
1719 *pcchOut
= size
+ schsize
+ 1;
1724 if (*pcchOut
< size
+ 1) {*pcchOut
= size
+1; return E_POINTER
;}
1725 strncpyW(pszOut
, addr
, size
);
1727 work
= pszOut
+ size
;
1730 TRACE("len=%ld %s\n", *pcchOut
, debugstr_w(pszOut
));