2 * Copyright 2010 Jacek Caban for CodeWeavers
3 * Copyright 2010 Thomas Mullaly
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 #include "urlmon_main.h"
21 #include "wine/debug.h"
23 #define NO_SHLWAPI_REG
26 #define UINT_MAX 0xffffffff
28 WINE_DEFAULT_DEBUG_CHANNEL(urlmon
);
31 const IUriVtbl
*lpIUriVtbl
;
36 /* Information about the canonicalized URI's buffer. */
43 URL_SCHEME scheme_type
;
51 Uri_HOST_TYPE host_type
;
55 const IUriBuilderVtbl
*lpIUriBuilderVtbl
;
64 BOOL has_implicit_scheme
;
70 URL_SCHEME scheme_type
;
72 const WCHAR
*userinfo
;
78 Uri_HOST_TYPE host_type
;
81 static const CHAR hexDigits
[] = "0123456789ABCDEF";
83 /* List of scheme types/scheme names that are recognized by the IUri interface as of IE 7. */
86 WCHAR scheme_name
[16];
87 } recognized_schemes
[] = {
88 {URL_SCHEME_FTP
, {'f','t','p',0}},
89 {URL_SCHEME_HTTP
, {'h','t','t','p',0}},
90 {URL_SCHEME_GOPHER
, {'g','o','p','h','e','r',0}},
91 {URL_SCHEME_MAILTO
, {'m','a','i','l','t','o',0}},
92 {URL_SCHEME_NEWS
, {'n','e','w','s',0}},
93 {URL_SCHEME_NNTP
, {'n','n','t','p',0}},
94 {URL_SCHEME_TELNET
, {'t','e','l','n','e','t',0}},
95 {URL_SCHEME_WAIS
, {'w','a','i','s',0}},
96 {URL_SCHEME_FILE
, {'f','i','l','e',0}},
97 {URL_SCHEME_MK
, {'m','k',0}},
98 {URL_SCHEME_HTTPS
, {'h','t','t','p','s',0}},
99 {URL_SCHEME_SHELL
, {'s','h','e','l','l',0}},
100 {URL_SCHEME_SNEWS
, {'s','n','e','w','s',0}},
101 {URL_SCHEME_LOCAL
, {'l','o','c','a','l',0}},
102 {URL_SCHEME_JAVASCRIPT
, {'j','a','v','a','s','c','r','i','p','t',0}},
103 {URL_SCHEME_VBSCRIPT
, {'v','b','s','c','r','i','p','t',0}},
104 {URL_SCHEME_ABOUT
, {'a','b','o','u','t',0}},
105 {URL_SCHEME_RES
, {'r','e','s',0}},
106 {URL_SCHEME_MSSHELLROOTED
, {'m','s','-','s','h','e','l','l','-','r','o','o','t','e','d',0}},
107 {URL_SCHEME_MSSHELLIDLIST
, {'m','s','-','s','h','e','l','l','-','i','d','l','i','s','t',0}},
108 {URL_SCHEME_MSHELP
, {'h','c','p',0}},
109 {URL_SCHEME_WILDCARD
, {'*',0}}
112 static inline BOOL
is_alpha(WCHAR val
) {
113 return ((val
>= 'a' && val
<= 'z') || (val
>= 'A' && val
<= 'Z'));
116 static inline BOOL
is_num(WCHAR val
) {
117 return (val
>= '0' && val
<= '9');
120 /* A URI is implicitly a file path if it begins with
121 * a drive letter (eg X:) or starts with "\\" (UNC path).
123 static inline BOOL
is_implicit_file_path(const WCHAR
*str
) {
124 if(is_alpha(str
[0]) && str
[1] == ':')
126 else if(str
[0] == '\\' && str
[1] == '\\')
132 /* Checks if the URI is a hierarchical URI. A hierarchical
133 * URI is one that has "//" after the scheme.
135 static BOOL
check_hierarchical(const WCHAR
**ptr
) {
136 const WCHAR
*start
= *ptr
;
151 /* unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" */
152 static inline BOOL
is_unreserved(WCHAR val
) {
153 return (is_alpha(val
) || is_num(val
) || val
== '-' || val
== '.' ||
154 val
== '_' || val
== '~');
157 /* sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
158 * / "*" / "+" / "," / ";" / "="
160 static inline BOOL
is_subdelim(WCHAR val
) {
161 return (val
== '!' || val
== '$' || val
== '&' ||
162 val
== '\'' || val
== '(' || val
== ')' ||
163 val
== '*' || val
== '+' || val
== ',' ||
164 val
== ';' || val
== '=');
167 /* gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@" */
168 static inline BOOL
is_gendelim(WCHAR val
) {
169 return (val
== ':' || val
== '/' || val
== '?' ||
170 val
== '#' || val
== '[' || val
== ']' ||
174 /* Characters that delimit the end of the authority
175 * section of a URI. Sometimes a '\\' is considered
176 * an authority delimeter.
178 static inline BOOL
is_auth_delim(WCHAR val
, BOOL acceptSlash
) {
179 return (val
== '#' || val
== '/' || val
== '?' ||
180 val
== '\0' || (acceptSlash
&& val
== '\\'));
183 /* reserved = gen-delims / sub-delims */
184 static inline BOOL
is_reserved(WCHAR val
) {
185 return (is_subdelim(val
) || is_gendelim(val
));
188 static inline BOOL
is_hexdigit(WCHAR val
) {
189 return ((val
>= 'a' && val
<= 'f') ||
190 (val
>= 'A' && val
<= 'F') ||
191 (val
>= '0' && val
<= '9'));
194 /* Taken from dlls/jscript/lex.c */
195 static int hex_to_int(WCHAR val
) {
196 if(val
>= '0' && val
<= '9')
198 else if(val
>= 'a' && val
<= 'f')
199 return val
- 'a' + 10;
200 else if(val
>= 'A' && val
<= 'F')
201 return val
- 'A' + 10;
206 /* Helper function for converting a percent encoded string
207 * representation of a WCHAR value into its actual WCHAR value. If
208 * the two characters following the '%' aren't valid hex values then
209 * this function returns the NULL character.
212 * "%2E" will result in '.' being returned by this function.
214 static WCHAR
decode_pct_val(const WCHAR
*ptr
) {
217 if(*ptr
== '%' && is_hexdigit(*(ptr
+ 1)) && is_hexdigit(*(ptr
+ 2))) {
218 INT a
= hex_to_int(*(ptr
+ 1));
219 INT b
= hex_to_int(*(ptr
+ 2));
228 /* Helper function for percent encoding a given character
229 * and storing the encoded value into a given buffer (dest).
231 * It's up to the calling function to ensure that there is
232 * at least enough space in 'dest' for the percent encoded
233 * value to be stored (so dest + 3 spaces available).
235 static inline void pct_encode_val(WCHAR val
, WCHAR
*dest
) {
237 dest
[1] = hexDigits
[(val
>> 4) & 0xf];
238 dest
[2] = hexDigits
[val
& 0xf];
241 /* Converts an IPv4 address in numerical form into it's fully qualified
242 * string form. This function returns the number of characters written
243 * to 'dest'. If 'dest' is NULL this function will return the number of
244 * characters that would have been written.
246 * It's up to the caller to ensure there's enough space in 'dest' for the
249 static DWORD
ui2ipv4(WCHAR
*dest
, UINT address
) {
250 static const WCHAR formatW
[] =
251 {'%','u','.','%','u','.','%','u','.','%','u',0};
255 digits
[0] = (address
>> 24) & 0xff;
256 digits
[1] = (address
>> 16) & 0xff;
257 digits
[2] = (address
>> 8) & 0xff;
258 digits
[3] = address
& 0xff;
262 ret
= sprintfW(tmp
, formatW
, digits
[0], digits
[1], digits
[2], digits
[3]);
264 ret
= sprintfW(dest
, formatW
, digits
[0], digits
[1], digits
[2], digits
[3]);
269 /* Checks if the characters pointed to by 'ptr' are
270 * a percent encoded data octet.
272 * pct-encoded = "%" HEXDIG HEXDIG
274 static BOOL
check_pct_encoded(const WCHAR
**ptr
) {
275 const WCHAR
*start
= *ptr
;
281 if(!is_hexdigit(**ptr
)) {
287 if(!is_hexdigit(**ptr
)) {
296 /* dec-octet = DIGIT ; 0-9
297 * / %x31-39 DIGIT ; 10-99
298 * / "1" 2DIGIT ; 100-199
299 * / "2" %x30-34 DIGIT ; 200-249
300 * / "25" %x30-35 ; 250-255
302 static BOOL
check_dec_octet(const WCHAR
**ptr
) {
303 const WCHAR
*c1
, *c2
, *c3
;
306 /* A dec-octet must be at least 1 digit long. */
307 if(*c1
< '0' || *c1
> '9')
313 /* Since the 1 digit requirment was meet, it doesn't
314 * matter if this is a DIGIT value, it's considered a
317 if(*c2
< '0' || *c2
> '9')
323 /* Same explanation as above. */
324 if(*c3
< '0' || *c3
> '9')
327 /* Anything > 255 isn't a valid IP dec-octet. */
328 if(*c1
>= '2' && *c2
>= '5' && *c3
>= '5') {
337 /* Checks if there is an implicit IPv4 address in the host component of the URI.
338 * The max value of an implicit IPv4 address is UINT_MAX.
341 * "234567" would be considered an implicit IPv4 address.
343 static BOOL
check_implicit_ipv4(const WCHAR
**ptr
, UINT
*val
) {
344 const WCHAR
*start
= *ptr
;
348 while(is_num(**ptr
)) {
349 ret
= ret
*10 + (**ptr
- '0');
365 /* Checks if the string contains an IPv4 address.
367 * This function has a strict mode or a non-strict mode of operation
368 * When 'strict' is set to FALSE this function will return TRUE if
369 * the string contains at least 'dec-octet "." dec-octet' since partial
370 * IPv4 addresses will be normalized out into full IPv4 addresses. When
371 * 'strict' is set this function expects there to be a full IPv4 address.
373 * IPv4address = dec-octet "." dec-octet "." dec-octet "." dec-octet
375 static BOOL
check_ipv4address(const WCHAR
**ptr
, BOOL strict
) {
376 const WCHAR
*start
= *ptr
;
378 if(!check_dec_octet(ptr
)) {
389 if(!check_dec_octet(ptr
)) {
403 if(!check_dec_octet(ptr
)) {
417 if(!check_dec_octet(ptr
)) {
422 /* Found a four digit ip address. */
425 /* Tries to parse the scheme name of the URI.
427 * scheme = ALPHA *(ALPHA | NUM | '+' | '-' | '.') as defined by RFC 3896.
428 * NOTE: Windows accepts a number as the first character of a scheme.
430 static BOOL
parse_scheme_name(const WCHAR
**ptr
, parse_data
*data
) {
431 const WCHAR
*start
= *ptr
;
434 data
->scheme_len
= 0;
437 if(**ptr
== '*' && *ptr
== start
) {
438 /* Might have found a wildcard scheme. If it is the next
439 * char has to be a ':' for it to be a valid URI
443 } else if(!is_num(**ptr
) && !is_alpha(**ptr
) && **ptr
!= '+' &&
444 **ptr
!= '-' && **ptr
!= '.')
453 /* Schemes must end with a ':' */
459 data
->scheme
= start
;
460 data
->scheme_len
= *ptr
- start
;
466 /* Tries to deduce the corresponding URL_SCHEME for the given URI. Stores
467 * the deduced URL_SCHEME in data->scheme_type.
469 static BOOL
parse_scheme_type(parse_data
*data
) {
470 /* If there's scheme data then see if it's a recognized scheme. */
471 if(data
->scheme
&& data
->scheme_len
) {
474 for(i
= 0; i
< sizeof(recognized_schemes
)/sizeof(recognized_schemes
[0]); ++i
) {
475 if(lstrlenW(recognized_schemes
[i
].scheme_name
) == data
->scheme_len
) {
476 /* Has to be a case insensitive compare. */
477 if(!StrCmpNIW(recognized_schemes
[i
].scheme_name
, data
->scheme
, data
->scheme_len
)) {
478 data
->scheme_type
= recognized_schemes
[i
].scheme
;
484 /* If we get here it means it's not a recognized scheme. */
485 data
->scheme_type
= URL_SCHEME_UNKNOWN
;
487 } else if(data
->is_relative
) {
488 /* Relative URI's have no scheme. */
489 data
->scheme_type
= URL_SCHEME_UNKNOWN
;
492 /* Should never reach here! what happened... */
493 FIXME("(%p): Unable to determine scheme type for URI %s\n", data
, debugstr_w(data
->uri
));
498 /* Tries to parse (or deduce) the scheme_name of a URI. If it can't
499 * parse a scheme from the URI it will try to deduce the scheme_name and scheme_type
500 * using the flags specified in 'flags' (if any). Flags that affect how this function
501 * operates are the Uri_CREATE_ALLOW_* flags.
503 * All parsed/deduced information will be stored in 'data' when the function returns.
505 * Returns TRUE if it was able to successfully parse the information.
507 static BOOL
parse_scheme(const WCHAR
**ptr
, parse_data
*data
, DWORD flags
) {
508 static const WCHAR fileW
[] = {'f','i','l','e',0};
509 static const WCHAR wildcardW
[] = {'*',0};
511 /* First check to see if the uri could implicitly be a file path. */
512 if(is_implicit_file_path(*ptr
)) {
513 if(flags
& Uri_CREATE_ALLOW_IMPLICIT_FILE_SCHEME
) {
514 data
->scheme
= fileW
;
515 data
->scheme_len
= lstrlenW(fileW
);
516 data
->has_implicit_scheme
= TRUE
;
518 TRACE("(%p %p %x): URI is an implicit file path.\n", ptr
, data
, flags
);
520 /* Window's does not consider anything that can implicitly be a file
521 * path to be a valid URI if the ALLOW_IMPLICIT_FILE_SCHEME flag is not set...
523 TRACE("(%p %p %x): URI is implicitly a file path, but, the ALLOW_IMPLICIT_FILE_SCHEME flag wasn't set.\n",
527 } else if(!parse_scheme_name(ptr
, data
)) {
528 /* No Scheme was found, this means it could be:
529 * a) an implicit Wildcard scheme
533 if(flags
& Uri_CREATE_ALLOW_IMPLICIT_WILDCARD_SCHEME
) {
534 data
->scheme
= wildcardW
;
535 data
->scheme_len
= lstrlenW(wildcardW
);
536 data
->has_implicit_scheme
= TRUE
;
538 TRACE("(%p %p %x): URI is an implicit wildcard scheme.\n", ptr
, data
, flags
);
539 } else if (flags
& Uri_CREATE_ALLOW_RELATIVE
) {
540 data
->is_relative
= TRUE
;
541 TRACE("(%p %p %x): URI is relative.\n", ptr
, data
, flags
);
543 TRACE("(%p %p %x): Malformed URI found. Unable to deduce scheme name.\n", ptr
, data
, flags
);
548 if(!data
->is_relative
)
549 TRACE("(%p %p %x): Found scheme=%s scheme_len=%d\n", ptr
, data
, flags
,
550 debugstr_wn(data
->scheme
, data
->scheme_len
), data
->scheme_len
);
552 if(!parse_scheme_type(data
))
555 TRACE("(%p %p %x): Assigned %d as the URL_SCHEME.\n", ptr
, data
, flags
, data
->scheme_type
);
559 /* Parses the userinfo part of the URI (if it exists). The userinfo field of
560 * a URI can consist of "username:password@", or just "username@".
563 * userinfo = *( unreserved / pct-encoded / sub-delims / ":" )
566 * 1) If there is more than one ':' in the userinfo part of the URI Windows
567 * uses the first occurence of ':' to delimit the username and password
571 * ftp://user:pass:word@winehq.org
573 * Would yield, "user" as the username and "pass:word" as the password.
575 * 2) Windows allows any character to appear in the "userinfo" part of
576 * a URI, as long as it's not an authority delimeter character set.
578 static void parse_userinfo(const WCHAR
**ptr
, parse_data
*data
, DWORD flags
) {
579 data
->userinfo
= *ptr
;
580 data
->userinfo_split
= -1;
582 while(**ptr
!= '@') {
583 if(**ptr
== ':' && data
->userinfo_split
== -1)
584 data
->userinfo_split
= *ptr
- data
->userinfo
;
585 else if(**ptr
== '%') {
586 /* If it's a known scheme type, it has to be a valid percent
589 if(!check_pct_encoded(ptr
)) {
590 if(data
->scheme_type
!= URL_SCHEME_UNKNOWN
) {
591 *ptr
= data
->userinfo
;
592 data
->userinfo
= NULL
;
593 data
->userinfo_split
= -1;
595 TRACE("(%p %p %x): URI contained no userinfo.\n", ptr
, data
, flags
);
600 } else if(is_auth_delim(**ptr
, data
->scheme_type
!= URL_SCHEME_UNKNOWN
))
607 *ptr
= data
->userinfo
;
608 data
->userinfo
= NULL
;
609 data
->userinfo_split
= -1;
611 TRACE("(%p %p %x): URI contained no userinfo.\n", ptr
, data
, flags
);
615 data
->userinfo_len
= *ptr
- data
->userinfo
;
616 TRACE("(%p %p %x): Found userinfo=%s userinfo_len=%d split=%d.\n", ptr
, data
, flags
,
617 debugstr_wn(data
->userinfo
, data
->userinfo_len
), data
->userinfo_len
, data
->userinfo_split
);
621 /* Attempts to parse a IPv4 address from the URI.
624 * Window's normalizes IPv4 addresses, This means there's three
625 * possibilities for the URI to contain an IPv4 address.
626 * 1) A well formed address (ex. 192.2.2.2).
627 * 2) A partially formed address. For example "192.0" would
628 * normalize to "192.0.0.0" during canonicalization.
629 * 3) An implicit IPv4 address. For example "256" would
630 * normalize to "0.0.1.0" during canonicalization. Also
631 * note that the maximum value for an implicit IP address
632 * is UINT_MAX, if the value in the URI exceeds this then
633 * it is not considered an IPv4 address.
635 static BOOL
parse_ipv4address(const WCHAR
**ptr
, parse_data
*data
, DWORD flags
) {
636 const BOOL is_unknown
= data
->scheme_type
== URL_SCHEME_UNKNOWN
;
639 if(!check_ipv4address(ptr
, FALSE
)) {
640 if(!check_implicit_ipv4(ptr
, &data
->implicit_ipv4
)) {
641 TRACE("(%p %p %x): URI didn't contain anything looking like an IPv4 address.\n",
647 data
->has_implicit_ip
= TRUE
;
650 /* Check if what we found is the only part of the host name (if it isn't
651 * we don't have an IPv4 address).
653 if(!is_auth_delim(**ptr
, !is_unknown
) && **ptr
!= ':') {
656 data
->has_implicit_ip
= FALSE
;
660 data
->host_len
= *ptr
- data
->host
;
661 data
->host_type
= Uri_HOST_IPV4
;
662 TRACE("(%p %p %x): IPv4 address found. host=%s host_len=%d host_type=%d\n",
663 ptr
, data
, flags
, debugstr_wn(data
->host
, data
->host_len
),
664 data
->host_len
, data
->host_type
);
668 /* Parses the host information from the URI.
670 * host = IP-literal / IPv4address / reg-name
672 static BOOL
parse_host(const WCHAR
**ptr
, parse_data
*data
, DWORD flags
) {
673 if(!parse_ipv4address(ptr
, data
, flags
)) {
674 WARN("(%p %p %x): Only IPv4 parsing is implemented so far.\n", ptr
, data
, flags
);
675 data
->host_type
= Uri_HOST_UNKNOWN
;
678 /* TODO parse IP-Literal / reg-name. */
683 /* Parses the authority information from the URI.
685 * authority = [ userinfo "@" ] host [ ":" port ]
687 static BOOL
parse_authority(const WCHAR
**ptr
, parse_data
*data
, DWORD flags
) {
688 parse_userinfo(ptr
, data
, flags
);
690 if(!parse_host(ptr
, data
, flags
))
696 /* Determines how the URI should be parsed after the scheme information.
698 * If the scheme is followed, by "//" then, it is treated as an hierarchical URI
699 * which then the authority and path information will be parsed out. Otherwise, the
700 * URI will be treated as an opaque URI which the authority information is not parsed
703 * RFC 3896 definition of hier-part:
705 * hier-part = "//" authority path-abempty
710 * MSDN opaque URI definition:
711 * scheme ":" path [ "#" fragment ]
714 * If the URI is of an unknown scheme type and has a "//" following the scheme then it
715 * is treated as a hierarchical URI, but, if the CREATE_NO_CRACK_UNKNOWN_SCHEMES flag is
716 * set then it is considered an opaque URI reguardless of what follows the scheme information
717 * (per MSDN documentation).
719 static BOOL
parse_hierpart(const WCHAR
**ptr
, parse_data
*data
, DWORD flags
) {
720 /* Checks if the authority information needs to be parsed.
722 * Relative URI's aren't hierarchical URI's, but, they could trick
723 * "check_hierarchical" into thinking it is, so we need to explicitly
724 * make sure it's not relative. Also, if the URI is an implicit file
725 * scheme it might not contain a "//", but, it's considered hierarchical
726 * anyways. Wildcard Schemes are always considered hierarchical
728 if(data
->scheme_type
== URL_SCHEME_WILDCARD
||
729 data
->scheme_type
== URL_SCHEME_FILE
||
730 (!data
->is_relative
&& check_hierarchical(ptr
))) {
731 /* Only treat it as a hierarchical URI if the scheme_type is known or
732 * the Uri_CREATE_NO_CRACK_UNKNOWN_SCHEMES flag is not set.
734 if(data
->scheme_type
!= URL_SCHEME_UNKNOWN
||
735 !(flags
& Uri_CREATE_NO_CRACK_UNKNOWN_SCHEMES
)) {
736 TRACE("(%p %p %x): Treating URI as an hierarchical URI.\n", ptr
, data
, flags
);
737 data
->is_opaque
= FALSE
;
739 /* TODO: Handle hierarchical URI's, parse authority then parse the path. */
740 if(!parse_authority(ptr
, data
, flags
))
747 /* If it reaches here, then the URI will be treated as an opaque
751 TRACE("(%p %p %x): Treating URI as an opaque URI.\n", ptr
, data
, flags
);
753 data
->is_opaque
= TRUE
;
754 /* TODO: Handle opaque URI's, parse path. */
758 /* Parses and validates the components of the specified by data->uri
759 * and stores the information it parses into 'data'.
761 * Returns TRUE if it successfully parsed the URI. False otherwise.
763 static BOOL
parse_uri(parse_data
*data
, DWORD flags
) {
770 TRACE("(%p %x): BEGINNING TO PARSE URI %s.\n", data
, flags
, debugstr_w(data
->uri
));
772 if(!parse_scheme(pptr
, data
, flags
))
775 if(!parse_hierpart(pptr
, data
, flags
))
778 TRACE("(%p %x): FINISHED PARSING URI.\n", data
, flags
);
782 /* Canonicalizes the userinfo of the URI represented by the parse_data.
784 * Canonicalization of the userinfo is a simple process. If there are any percent
785 * encoded characters that fall in the "unreserved" character set, they are decoded
786 * to their actual value. If a character is not in the "unreserved" or "reserved" sets
787 * then it is percent encoded. Other than that the characters are copied over without
790 static BOOL
canonicalize_userinfo(const parse_data
*data
, Uri
*uri
, DWORD flags
, BOOL computeOnly
) {
793 uri
->userinfo_start
= uri
->userinfo_split
= -1;
794 uri
->userinfo_len
= 0;
797 /* URI doesn't have userinfo, so nothing to do here. */
800 uri
->userinfo_start
= uri
->canon_len
;
802 while(i
< data
->userinfo_len
) {
803 if(data
->userinfo
[i
] == ':' && uri
->userinfo_split
== -1)
804 /* Windows only considers the first ':' as the delimiter. */
805 uri
->userinfo_split
= uri
->canon_len
- uri
->userinfo_start
;
806 else if(data
->userinfo
[i
] == '%') {
807 /* Only decode % encoded values for known scheme types. */
808 if(data
->scheme_type
!= URL_SCHEME_UNKNOWN
) {
809 /* See if the value really needs decoded. */
810 WCHAR val
= decode_pct_val(data
->userinfo
+ i
);
811 if(is_unreserved(val
)) {
813 uri
->canon_uri
[uri
->canon_len
] = val
;
817 /* Move pass the hex characters. */
822 } else if(!is_reserved(data
->userinfo
[i
]) && !is_unreserved(data
->userinfo
[i
]) &&
823 data
->userinfo
[i
] != '\\') {
824 /* Only percent encode forbidden characters if the NO_ENCODE_FORBIDDEN_CHARACTERS flag
827 if(!(flags
& Uri_CREATE_NO_ENCODE_FORBIDDEN_CHARACTERS
)) {
829 pct_encode_val(data
->userinfo
[i
], uri
->canon_uri
+ uri
->canon_len
);
838 /* Nothing special, so just copy the character over. */
839 uri
->canon_uri
[uri
->canon_len
] = data
->userinfo
[i
];
845 uri
->userinfo_len
= uri
->canon_len
- uri
->userinfo_start
;
847 TRACE("(%p %p %x %d): Canonicalized userinfo, userinfo_start=%d, userinfo=%s, userinfo_split=%d userinfo_len=%d.\n",
848 data
, uri
, flags
, computeOnly
, uri
->userinfo_start
, debugstr_wn(uri
->canon_uri
+ uri
->userinfo_start
, uri
->userinfo_len
),
849 uri
->userinfo_split
, uri
->userinfo_len
);
851 /* Now insert the '@' after the userinfo. */
853 uri
->canon_uri
[uri
->canon_len
] = '@';
859 /* Attempts to canonicalize an implicit IPv4 address. */
860 static BOOL
canonicalize_implicit_ipv4address(const parse_data
*data
, Uri
*uri
, DWORD flags
, BOOL computeOnly
) {
861 uri
->host_start
= uri
->canon_len
;
863 TRACE("%u\n", data
->implicit_ipv4
);
864 /* For unknown scheme types Window's doesn't convert
865 * the value into an IP address, but, it still considers
866 * it an IPv4 address.
868 if(data
->scheme_type
== URL_SCHEME_UNKNOWN
) {
870 memcpy(uri
->canon_uri
+uri
->canon_len
, data
->host
, data
->host_len
*sizeof(WCHAR
));
871 uri
->canon_len
+= data
->host_len
;
874 uri
->canon_len
+= ui2ipv4(uri
->canon_uri
+uri
->canon_len
, data
->implicit_ipv4
);
876 uri
->canon_len
+= ui2ipv4(NULL
, data
->implicit_ipv4
);
879 uri
->host_len
= uri
->canon_len
- uri
->host_start
;
880 uri
->host_type
= Uri_HOST_IPV4
;
883 TRACE("%p %p %x %d): Canonicalized implicit IP address=%s len=%d\n",
884 data
, uri
, flags
, computeOnly
,
885 debugstr_wn(uri
->canon_uri
+uri
->host_start
, uri
->host_len
),
891 /* Attempts to canonicalize an IPv4 address.
893 * If the parse_data represents a URI that has an implicit IPv4 address
894 * (ex. http://256/, this function will convert 256 into 0.0.1.0). If
895 * the implicit IP address exceeds the value of UINT_MAX (maximum value
896 * for an IPv4 address) it's canonicalized as if were a reg-name.
898 * If the parse_data contains a partial or full IPv4 address it normalizes it.
899 * A partial IPv4 address is something like "192.0" and would be normalized to
900 * "192.0.0.0". With a full (or partial) IPv4 address like "192.002.01.003" would
901 * be normalized to "192.2.1.3".
904 * Window's ONLY normalizes IPv4 address for known scheme types (one that isn't
905 * URL_SCHEME_UNKNOWN). For unknown scheme types, it simply copies the data from
906 * the original URI into the canonicalized URI, but, it still recognizes URI's
907 * host type as HOST_IPV4.
909 static BOOL
canonicalize_ipv4address(const parse_data
*data
, Uri
*uri
, DWORD flags
, BOOL computeOnly
) {
910 if(data
->has_implicit_ip
)
911 return canonicalize_implicit_ipv4address(data
, uri
, flags
, computeOnly
);
913 uri
->host_start
= uri
->canon_len
;
915 /* Windows only normalizes for known scheme types. */
916 if(data
->scheme_type
!= URL_SCHEME_UNKNOWN
) {
917 /* parse_data contains a partial or full IPv4 address, so normalize it. */
918 DWORD i
, octetDigitCount
= 0, octetCount
= 0;
919 BOOL octetHasDigit
= FALSE
;
921 for(i
= 0; i
< data
->host_len
; ++i
) {
922 if(data
->host
[i
] == '0' && !octetHasDigit
) {
923 /* Can ignore leading zeros if:
924 * 1) It isn't the last digit of the octet.
925 * 2) i+1 != data->host_len
928 if(octetDigitCount
== 2 ||
929 i
+1 == data
->host_len
||
930 data
->host
[i
+1] == '.') {
932 uri
->canon_uri
[uri
->canon_len
] = data
->host
[i
];
934 TRACE("Adding zero\n");
936 } else if(data
->host
[i
] == '.') {
938 uri
->canon_uri
[uri
->canon_len
] = data
->host
[i
];
942 octetHasDigit
= FALSE
;
946 uri
->canon_uri
[uri
->canon_len
] = data
->host
[i
];
950 octetHasDigit
= TRUE
;
954 /* Make sure the canonicalized IP address has 4 dec-octets.
955 * If doesn't add "0" ones until there is 4;
957 for( ; octetCount
< 3; ++octetCount
) {
959 uri
->canon_uri
[uri
->canon_len
] = '.';
960 uri
->canon_uri
[uri
->canon_len
+1] = '0';
966 /* Windows doesn't normalize addresses in unknown schemes. */
968 memcpy(uri
->canon_uri
+uri
->canon_len
, data
->host
, data
->host_len
*sizeof(WCHAR
));
969 uri
->canon_len
+= data
->host_len
;
972 uri
->host_len
= uri
->canon_len
- uri
->host_start
;
974 TRACE("(%p %p %x %d): Canonicalized IPv4 address, ip=%s len=%d\n",
975 data
, uri
, flags
, computeOnly
,
976 debugstr_wn(uri
->canon_uri
+uri
->host_start
, uri
->host_len
),
983 static BOOL
canonicalize_host(const parse_data
*data
, Uri
*uri
, DWORD flags
, BOOL computeOnly
) {
984 uri
->host_start
= -1;
988 switch(data
->host_type
) {
990 uri
->host_type
= Uri_HOST_IPV4
;
991 if(!canonicalize_ipv4address(data
, uri
, flags
, computeOnly
))
996 WARN("(%p %p %x %d): Canonicalization not supported yet\n", data
,
997 uri
, flags
, computeOnly
);
1004 /* Canonicalizes the authority of the URI represented by the parse_data. */
1005 static BOOL
canonicalize_authority(const parse_data
*data
, Uri
*uri
, DWORD flags
, BOOL computeOnly
) {
1006 if(!canonicalize_userinfo(data
, uri
, flags
, computeOnly
))
1009 if(!canonicalize_host(data
, uri
, flags
, computeOnly
))
1012 /* TODO Canonicalize port information. */
1017 /* Determines how the URI represented by the parse_data should be canonicalized.
1019 * Essentially, if the parse_data represents an hierarchical URI then it calls
1020 * canonicalize_authority and the canonicalization functions for the path. If the
1021 * URI is opaque it canonicalizes the path of the URI.
1023 static BOOL
canonicalize_hierpart(const parse_data
*data
, Uri
*uri
, DWORD flags
, BOOL computeOnly
) {
1024 if(!data
->is_opaque
) {
1025 /* "//" is only added for non-wildcard scheme types. */
1026 if(data
->scheme_type
!= URL_SCHEME_WILDCARD
) {
1028 INT pos
= uri
->canon_len
;
1030 uri
->canon_uri
[pos
] = '/';
1031 uri
->canon_uri
[pos
+1] = '/';
1033 uri
->canon_len
+= 2;
1036 if(!canonicalize_authority(data
, uri
, flags
, computeOnly
))
1039 /* TODO: Canonicalize the path of the URI. */
1042 /* Opaque URI's don't have userinfo. */
1043 uri
->userinfo_start
= uri
->userinfo_split
= -1;
1044 uri
->userinfo_len
= 0;
1050 /* Canonicalizes the scheme information specified in the parse_data using the specified flags. */
1051 static BOOL
canonicalize_scheme(const parse_data
*data
, Uri
*uri
, DWORD flags
, BOOL computeOnly
) {
1052 uri
->scheme_start
= -1;
1053 uri
->scheme_len
= 0;
1056 /* The only type of URI that doesn't have to have a scheme is a relative
1059 if(!data
->is_relative
) {
1060 FIXME("(%p %p %x): Unable to determine the scheme type of %s.\n", data
,
1061 uri
, flags
, debugstr_w(data
->uri
));
1067 INT pos
= uri
->canon_len
;
1069 for(i
= 0; i
< data
->scheme_len
; ++i
) {
1070 /* Scheme name must be lower case after canonicalization. */
1071 uri
->canon_uri
[i
+ pos
] = tolowerW(data
->scheme
[i
]);
1074 uri
->canon_uri
[i
+ pos
] = ':';
1075 uri
->scheme_start
= pos
;
1077 TRACE("(%p %p %x): Canonicalized scheme=%s, len=%d.\n", data
, uri
, flags
,
1078 debugstr_wn(uri
->canon_uri
, uri
->scheme_len
), data
->scheme_len
);
1081 /* This happens in both computation modes. */
1082 uri
->canon_len
+= data
->scheme_len
+ 1;
1083 uri
->scheme_len
= data
->scheme_len
;
1088 /* Compute's what the length of the URI specified by the parse_data will be
1089 * after canonicalization occurs using the specified flags.
1091 * This function will return a non-zero value indicating the length of the canonicalized
1092 * URI, or -1 on error.
1094 static int compute_canonicalized_length(const parse_data
*data
, DWORD flags
) {
1097 memset(&uri
, 0, sizeof(Uri
));
1099 TRACE("(%p %x): Beginning to compute canonicalized length for URI %s\n", data
, flags
,
1100 debugstr_w(data
->uri
));
1102 if(!canonicalize_scheme(data
, &uri
, flags
, TRUE
)) {
1103 ERR("(%p %x): Failed to compute URI scheme length.\n", data
, flags
);
1107 if(!canonicalize_hierpart(data
, &uri
, flags
, TRUE
)) {
1108 ERR("(%p %x): Failed to compute URI hierpart length.\n", data
, flags
);
1112 TRACE("(%p %x): Finished computing canonicalized URI length. length=%d\n", data
, flags
, uri
.canon_len
);
1114 return uri
.canon_len
;
1117 /* Canonicalizes the URI data specified in the parse_data, using the given flags. If the
1118 * canonicalization succeededs it will store all the canonicalization information
1119 * in the pointer to the Uri.
1121 * To canonicalize a URI this function first computes what the length of the URI
1122 * specified by the parse_data will be. Once this is done it will then perfom the actual
1123 * canonicalization of the URI.
1125 static HRESULT
canonicalize_uri(const parse_data
*data
, Uri
*uri
, DWORD flags
) {
1128 uri
->canon_uri
= NULL
;
1129 len
= uri
->canon_size
= uri
->canon_len
= 0;
1131 TRACE("(%p %p %x): beginning to canonicalize URI %s.\n", data
, uri
, flags
, debugstr_w(data
->uri
));
1133 /* First try to compute the length of the URI. */
1134 len
= compute_canonicalized_length(data
, flags
);
1136 ERR("(%p %p %x): Could not compute the canonicalized length of %s.\n", data
, uri
, flags
,
1137 debugstr_w(data
->uri
));
1138 return E_INVALIDARG
;
1141 uri
->canon_uri
= heap_alloc((len
+1)*sizeof(WCHAR
));
1143 return E_OUTOFMEMORY
;
1145 if(!canonicalize_scheme(data
, uri
, flags
, FALSE
)) {
1146 ERR("(%p %p %x): Unable to canonicalize the scheme of the URI.\n", data
, uri
, flags
);
1147 heap_free(uri
->canon_uri
);
1148 return E_INVALIDARG
;
1150 uri
->scheme_type
= data
->scheme_type
;
1152 if(!canonicalize_hierpart(data
, uri
, flags
, FALSE
)) {
1153 ERR("(%p %p %x): Unable to canonicalize the heirpart of the URI\n", data
, uri
, flags
);
1154 heap_free(uri
->canon_uri
);
1155 return E_INVALIDARG
;
1158 uri
->canon_uri
[uri
->canon_len
] = '\0';
1159 TRACE("(%p %p %x): finished canonicalizing the URI.\n", data
, uri
, flags
);
1164 #define URI(x) ((IUri*) &(x)->lpIUriVtbl)
1165 #define URIBUILDER(x) ((IUriBuilder*) &(x)->lpIUriBuilderVtbl)
1167 #define URI_THIS(iface) DEFINE_THIS(Uri, IUri, iface)
1169 static HRESULT WINAPI
Uri_QueryInterface(IUri
*iface
, REFIID riid
, void **ppv
)
1171 Uri
*This
= URI_THIS(iface
);
1173 if(IsEqualGUID(&IID_IUnknown
, riid
)) {
1174 TRACE("(%p)->(IID_IUnknown %p)\n", This
, ppv
);
1176 }else if(IsEqualGUID(&IID_IUri
, riid
)) {
1177 TRACE("(%p)->(IID_IUri %p)\n", This
, ppv
);
1180 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), ppv
);
1182 return E_NOINTERFACE
;
1185 IUnknown_AddRef((IUnknown
*)*ppv
);
1189 static ULONG WINAPI
Uri_AddRef(IUri
*iface
)
1191 Uri
*This
= URI_THIS(iface
);
1192 LONG ref
= InterlockedIncrement(&This
->ref
);
1194 TRACE("(%p) ref=%d\n", This
, ref
);
1199 static ULONG WINAPI
Uri_Release(IUri
*iface
)
1201 Uri
*This
= URI_THIS(iface
);
1202 LONG ref
= InterlockedDecrement(&This
->ref
);
1204 TRACE("(%p) ref=%d\n", This
, ref
);
1207 SysFreeString(This
->raw_uri
);
1208 heap_free(This
->canon_uri
);
1215 static HRESULT WINAPI
Uri_GetPropertyBSTR(IUri
*iface
, Uri_PROPERTY uriProp
, BSTR
*pbstrProperty
, DWORD dwFlags
)
1217 Uri
*This
= URI_THIS(iface
);
1219 TRACE("(%p)->(%d %p %x)\n", This
, uriProp
, pbstrProperty
, dwFlags
);
1224 if(uriProp
> Uri_PROPERTY_STRING_LAST
) {
1225 /* Windows allocates an empty BSTR for invalid Uri_PROPERTY's. */
1226 *pbstrProperty
= SysAllocStringLen(NULL
, 0);
1227 if(!(*pbstrProperty
))
1228 return E_OUTOFMEMORY
;
1230 /* It only returns S_FALSE for the ZONE property... */
1231 if(uriProp
== Uri_PROPERTY_ZONE
)
1237 /* Don't have support for flags yet. */
1239 FIXME("(%p)->(%d %p %x)\n", This
, uriProp
, pbstrProperty
, dwFlags
);
1244 case Uri_PROPERTY_HOST
:
1245 if(This
->host_start
> -1) {
1246 *pbstrProperty
= SysAllocStringLen(This
->canon_uri
+This
->host_start
, This
->host_len
);
1249 /* Canonicalizing/parsing the host of a URI is only partially
1250 * implemented, so return E_NOTIMPL for now.
1252 FIXME("(%p)->(%d %p %x) Partially implemented\n", This
, uriProp
, pbstrProperty
, dwFlags
);
1256 if(!(*pbstrProperty
))
1257 hres
= E_OUTOFMEMORY
;
1260 case Uri_PROPERTY_PASSWORD
:
1261 if(This
->userinfo_split
> -1) {
1262 *pbstrProperty
= SysAllocStringLen(
1263 This
->canon_uri
+This
->userinfo_start
+This
->userinfo_split
+1,
1264 This
->userinfo_len
-This
->userinfo_split
-1);
1267 *pbstrProperty
= SysAllocStringLen(NULL
, 0);
1271 if(!(*pbstrProperty
))
1272 return E_OUTOFMEMORY
;
1275 case Uri_PROPERTY_RAW_URI
:
1276 *pbstrProperty
= SysAllocString(This
->raw_uri
);
1277 if(!(*pbstrProperty
))
1278 hres
= E_OUTOFMEMORY
;
1282 case Uri_PROPERTY_SCHEME_NAME
:
1283 if(This
->scheme_start
> -1) {
1284 *pbstrProperty
= SysAllocStringLen(This
->canon_uri
+ This
->scheme_start
, This
->scheme_len
);
1287 *pbstrProperty
= SysAllocStringLen(NULL
, 0);
1291 if(!(*pbstrProperty
))
1292 hres
= E_OUTOFMEMORY
;
1295 case Uri_PROPERTY_USER_INFO
:
1296 if(This
->userinfo_start
> -1) {
1297 *pbstrProperty
= SysAllocStringLen(This
->canon_uri
+This
->userinfo_start
, This
->userinfo_len
);
1300 *pbstrProperty
= SysAllocStringLen(NULL
, 0);
1304 if(!(*pbstrProperty
))
1305 hres
= E_OUTOFMEMORY
;
1308 case Uri_PROPERTY_USER_NAME
:
1309 if(This
->userinfo_start
> -1) {
1310 /* If userinfo_split is set, that means a password exists
1311 * so the username is only from userinfo_start to userinfo_split.
1313 if(This
->userinfo_split
> -1) {
1314 *pbstrProperty
= SysAllocStringLen(This
->canon_uri
+ This
->userinfo_start
, This
->userinfo_split
);
1317 *pbstrProperty
= SysAllocStringLen(This
->canon_uri
+ This
->userinfo_start
, This
->userinfo_len
);
1321 *pbstrProperty
= SysAllocStringLen(NULL
, 0);
1325 if(!(*pbstrProperty
))
1326 return E_OUTOFMEMORY
;
1330 FIXME("(%p)->(%d %p %x)\n", This
, uriProp
, pbstrProperty
, dwFlags
);
1337 static HRESULT WINAPI
Uri_GetPropertyLength(IUri
*iface
, Uri_PROPERTY uriProp
, DWORD
*pcchProperty
, DWORD dwFlags
)
1339 Uri
*This
= URI_THIS(iface
);
1341 TRACE("(%p)->(%d %p %x)\n", This
, uriProp
, pcchProperty
, dwFlags
);
1344 return E_INVALIDARG
;
1346 /* Can only return a length for a property if it's a string. */
1347 if(uriProp
> Uri_PROPERTY_STRING_LAST
)
1348 return E_INVALIDARG
;
1350 /* Don't have support for flags yet. */
1352 FIXME("(%p)->(%d %p %x)\n", This
, uriProp
, pcchProperty
, dwFlags
);
1357 case Uri_PROPERTY_HOST
:
1358 if(This
->host_start
== -1) {
1359 /* Canonicalizing/parsing the host of a URI is only partially
1360 * implemented, so return E_NOTIMPL for now.
1362 FIXME("(%p)->(%d %p %x) Partially implemented\n", This
, uriProp
, pcchProperty
, dwFlags
);
1366 *pcchProperty
= This
->host_len
;
1367 hres
= (This
->host_start
> -1) ? S_OK
: S_FALSE
;
1369 case Uri_PROPERTY_PASSWORD
:
1370 *pcchProperty
= (This
->userinfo_split
> -1) ? This
->userinfo_len
-This
->userinfo_split
-1 : 0;
1371 hres
= (This
->userinfo_split
> -1) ? S_OK
: S_FALSE
;
1373 case Uri_PROPERTY_RAW_URI
:
1374 *pcchProperty
= SysStringLen(This
->raw_uri
);
1377 case Uri_PROPERTY_SCHEME_NAME
:
1378 *pcchProperty
= This
->scheme_len
;
1379 hres
= (This
->scheme_start
> -1) ? S_OK
: S_FALSE
;
1381 case Uri_PROPERTY_USER_INFO
:
1382 *pcchProperty
= This
->userinfo_len
;
1383 hres
= (This
->userinfo_start
> -1) ? S_OK
: S_FALSE
;
1385 case Uri_PROPERTY_USER_NAME
:
1386 *pcchProperty
= (This
->userinfo_split
> -1) ? This
->userinfo_split
: This
->userinfo_len
;
1387 hres
= (This
->userinfo_start
> -1) ? S_OK
: S_FALSE
;
1390 FIXME("(%p)->(%d %p %x)\n", This
, uriProp
, pcchProperty
, dwFlags
);
1397 static HRESULT WINAPI
Uri_GetPropertyDWORD(IUri
*iface
, Uri_PROPERTY uriProp
, DWORD
*pcchProperty
, DWORD dwFlags
)
1399 Uri
*This
= URI_THIS(iface
);
1402 TRACE("(%p)->(%d %p %x)\n", This
, uriProp
, pcchProperty
, dwFlags
);
1405 return E_INVALIDARG
;
1407 /* Microsoft's implementation for the ZONE property of a URI seems to be lacking...
1408 * From what I can tell, instead of checking which URLZONE the URI belongs to it
1409 * simply assigns URLZONE_INVALID and returns E_NOTIMPL. This also applies to the GetZone
1412 if(uriProp
== Uri_PROPERTY_ZONE
) {
1413 *pcchProperty
= URLZONE_INVALID
;
1417 if(uriProp
< Uri_PROPERTY_DWORD_START
) {
1419 return E_INVALIDARG
;
1423 case Uri_PROPERTY_SCHEME
:
1424 *pcchProperty
= This
->scheme_type
;
1428 FIXME("(%p)->(%d %p %x)\n", This
, uriProp
, pcchProperty
, dwFlags
);
1435 static HRESULT WINAPI
Uri_HasProperty(IUri
*iface
, Uri_PROPERTY uriProp
, BOOL
*pfHasProperty
)
1437 Uri
*This
= URI_THIS(iface
);
1438 FIXME("(%p)->(%d %p)\n", This
, uriProp
, pfHasProperty
);
1441 return E_INVALIDARG
;
1446 static HRESULT WINAPI
Uri_GetAbsoluteUri(IUri
*iface
, BSTR
*pstrAbsoluteUri
)
1448 Uri
*This
= URI_THIS(iface
);
1449 FIXME("(%p)->(%p)\n", This
, pstrAbsoluteUri
);
1451 if(!pstrAbsoluteUri
)
1457 static HRESULT WINAPI
Uri_GetAuthority(IUri
*iface
, BSTR
*pstrAuthority
)
1459 Uri
*This
= URI_THIS(iface
);
1460 FIXME("(%p)->(%p)\n", This
, pstrAuthority
);
1468 static HRESULT WINAPI
Uri_GetDisplayUri(IUri
*iface
, BSTR
*pstrDisplayUri
)
1470 Uri
*This
= URI_THIS(iface
);
1471 FIXME("(%p)->(%p)\n", This
, pstrDisplayUri
);
1479 static HRESULT WINAPI
Uri_GetDomain(IUri
*iface
, BSTR
*pstrDomain
)
1481 Uri
*This
= URI_THIS(iface
);
1482 FIXME("(%p)->(%p)\n", This
, pstrDomain
);
1490 static HRESULT WINAPI
Uri_GetExtension(IUri
*iface
, BSTR
*pstrExtension
)
1492 Uri
*This
= URI_THIS(iface
);
1493 FIXME("(%p)->(%p)\n", This
, pstrExtension
);
1501 static HRESULT WINAPI
Uri_GetFragment(IUri
*iface
, BSTR
*pstrFragment
)
1503 Uri
*This
= URI_THIS(iface
);
1504 FIXME("(%p)->(%p)\n", This
, pstrFragment
);
1512 static HRESULT WINAPI
Uri_GetHost(IUri
*iface
, BSTR
*pstrHost
)
1514 TRACE("(%p)->(%p)\n", iface
, pstrHost
);
1515 return Uri_GetPropertyBSTR(iface
, Uri_PROPERTY_HOST
, pstrHost
, 0);
1518 static HRESULT WINAPI
Uri_GetPassword(IUri
*iface
, BSTR
*pstrPassword
)
1520 TRACE("(%p)->(%p)\n", iface
, pstrPassword
);
1521 return Uri_GetPropertyBSTR(iface
, Uri_PROPERTY_PASSWORD
, pstrPassword
, 0);
1524 static HRESULT WINAPI
Uri_GetPath(IUri
*iface
, BSTR
*pstrPath
)
1526 Uri
*This
= URI_THIS(iface
);
1527 FIXME("(%p)->(%p)\n", This
, pstrPath
);
1535 static HRESULT WINAPI
Uri_GetPathAndQuery(IUri
*iface
, BSTR
*pstrPathAndQuery
)
1537 Uri
*This
= URI_THIS(iface
);
1538 FIXME("(%p)->(%p)\n", This
, pstrPathAndQuery
);
1540 if(!pstrPathAndQuery
)
1546 static HRESULT WINAPI
Uri_GetQuery(IUri
*iface
, BSTR
*pstrQuery
)
1548 Uri
*This
= URI_THIS(iface
);
1549 FIXME("(%p)->(%p)\n", This
, pstrQuery
);
1557 static HRESULT WINAPI
Uri_GetRawUri(IUri
*iface
, BSTR
*pstrRawUri
)
1559 Uri
*This
= URI_THIS(iface
);
1560 TRACE("(%p)->(%p)\n", This
, pstrRawUri
);
1562 /* Just forward the call to GetPropertyBSTR. */
1563 return Uri_GetPropertyBSTR(iface
, Uri_PROPERTY_RAW_URI
, pstrRawUri
, 0);
1566 static HRESULT WINAPI
Uri_GetSchemeName(IUri
*iface
, BSTR
*pstrSchemeName
)
1568 Uri
*This
= URI_THIS(iface
);
1569 TRACE("(%p)->(%p)\n", This
, pstrSchemeName
);
1570 return Uri_GetPropertyBSTR(iface
, Uri_PROPERTY_SCHEME_NAME
, pstrSchemeName
, 0);
1573 static HRESULT WINAPI
Uri_GetUserInfo(IUri
*iface
, BSTR
*pstrUserInfo
)
1575 TRACE("(%p)->(%p)\n", iface
, pstrUserInfo
);
1576 return Uri_GetPropertyBSTR(iface
, Uri_PROPERTY_USER_INFO
, pstrUserInfo
, 0);
1579 static HRESULT WINAPI
Uri_GetUserName(IUri
*iface
, BSTR
*pstrUserName
)
1581 TRACE("(%p)->(%p)\n", iface
, pstrUserName
);
1582 return Uri_GetPropertyBSTR(iface
, Uri_PROPERTY_USER_NAME
, pstrUserName
, 0);
1585 static HRESULT WINAPI
Uri_GetHostType(IUri
*iface
, DWORD
*pdwHostType
)
1587 Uri
*This
= URI_THIS(iface
);
1588 FIXME("(%p)->(%p)\n", This
, pdwHostType
);
1591 return E_INVALIDARG
;
1596 static HRESULT WINAPI
Uri_GetPort(IUri
*iface
, DWORD
*pdwPort
)
1598 Uri
*This
= URI_THIS(iface
);
1599 FIXME("(%p)->(%p)\n", This
, pdwPort
);
1602 return E_INVALIDARG
;
1607 static HRESULT WINAPI
Uri_GetScheme(IUri
*iface
, DWORD
*pdwScheme
)
1609 Uri
*This
= URI_THIS(iface
);
1610 TRACE("(%p)->(%p)\n", This
, pdwScheme
);
1611 return Uri_GetPropertyDWORD(iface
, Uri_PROPERTY_SCHEME
, pdwScheme
, 0);
1614 static HRESULT WINAPI
Uri_GetZone(IUri
*iface
, DWORD
*pdwZone
)
1616 Uri
*This
= URI_THIS(iface
);
1617 FIXME("(%p)->(%p)\n", This
, pdwZone
);
1620 return E_INVALIDARG
;
1622 /* Microsoft doesn't seem to have this implemented yet... See
1623 * the comment in Uri_GetPropertyDWORD for more about this.
1625 *pdwZone
= URLZONE_INVALID
;
1629 static HRESULT WINAPI
Uri_GetProperties(IUri
*iface
, DWORD
*pdwProperties
)
1631 Uri
*This
= URI_THIS(iface
);
1632 FIXME("(%p)->(%p)\n", This
, pdwProperties
);
1635 return E_INVALIDARG
;
1640 static HRESULT WINAPI
Uri_IsEqual(IUri
*iface
, IUri
*pUri
, BOOL
*pfEqual
)
1642 Uri
*This
= URI_THIS(iface
);
1643 TRACE("(%p)->(%p %p)\n", This
, pUri
, pfEqual
);
1651 /* For some reason Windows returns S_OK here... */
1655 FIXME("(%p)->(%p %p)\n", This
, pUri
, pfEqual
);
1661 static const IUriVtbl UriVtbl
= {
1665 Uri_GetPropertyBSTR
,
1666 Uri_GetPropertyLength
,
1667 Uri_GetPropertyDWORD
,
1678 Uri_GetPathAndQuery
,
1692 /***********************************************************************
1693 * CreateUri (urlmon.@)
1695 HRESULT WINAPI
CreateUri(LPCWSTR pwzURI
, DWORD dwFlags
, DWORD_PTR dwReserved
, IUri
**ppURI
)
1701 TRACE("(%s %x %x %p)\n", debugstr_w(pwzURI
), dwFlags
, (DWORD
)dwReserved
, ppURI
);
1704 return E_INVALIDARG
;
1708 return E_INVALIDARG
;
1711 ret
= heap_alloc(sizeof(Uri
));
1713 return E_OUTOFMEMORY
;
1715 ret
->lpIUriVtbl
= &UriVtbl
;
1718 /* Create a copy of pwzURI and store it as the raw_uri. */
1719 ret
->raw_uri
= SysAllocString(pwzURI
);
1722 return E_OUTOFMEMORY
;
1725 memset(&data
, 0, sizeof(parse_data
));
1726 data
.uri
= ret
->raw_uri
;
1728 /* Validate and parse the URI into it's components. */
1729 if(!parse_uri(&data
, dwFlags
)) {
1730 /* Encountered an unsupported or invalid URI */
1731 SysFreeString(ret
->raw_uri
);
1734 return E_INVALIDARG
;
1737 /* Canonicalize the URI. */
1738 hr
= canonicalize_uri(&data
, ret
, dwFlags
);
1740 SysFreeString(ret
->raw_uri
);
1750 #define URIBUILDER_THIS(iface) DEFINE_THIS(UriBuilder, IUriBuilder, iface)
1752 static HRESULT WINAPI
UriBuilder_QueryInterface(IUriBuilder
*iface
, REFIID riid
, void **ppv
)
1754 UriBuilder
*This
= URIBUILDER_THIS(iface
);
1756 if(IsEqualGUID(&IID_IUnknown
, riid
)) {
1757 TRACE("(%p)->(IID_IUnknown %p)\n", This
, ppv
);
1758 *ppv
= URIBUILDER(This
);
1759 }else if(IsEqualGUID(&IID_IUriBuilder
, riid
)) {
1760 TRACE("(%p)->(IID_IUri %p)\n", This
, ppv
);
1761 *ppv
= URIBUILDER(This
);
1763 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), ppv
);
1765 return E_NOINTERFACE
;
1768 IUnknown_AddRef((IUnknown
*)*ppv
);
1772 static ULONG WINAPI
UriBuilder_AddRef(IUriBuilder
*iface
)
1774 UriBuilder
*This
= URIBUILDER_THIS(iface
);
1775 LONG ref
= InterlockedIncrement(&This
->ref
);
1777 TRACE("(%p) ref=%d\n", This
, ref
);
1782 static ULONG WINAPI
UriBuilder_Release(IUriBuilder
*iface
)
1784 UriBuilder
*This
= URIBUILDER_THIS(iface
);
1785 LONG ref
= InterlockedDecrement(&This
->ref
);
1787 TRACE("(%p) ref=%d\n", This
, ref
);
1795 static HRESULT WINAPI
UriBuilder_CreateUriSimple(IUriBuilder
*iface
,
1796 DWORD dwAllowEncodingPropertyMask
,
1797 DWORD_PTR dwReserved
,
1800 UriBuilder
*This
= URIBUILDER_THIS(iface
);
1801 FIXME("(%p)->(%d %d %p)\n", This
, dwAllowEncodingPropertyMask
, (DWORD
)dwReserved
, ppIUri
);
1805 static HRESULT WINAPI
UriBuilder_CreateUri(IUriBuilder
*iface
,
1806 DWORD dwCreateFlags
,
1807 DWORD dwAllowEncodingPropertyMask
,
1808 DWORD_PTR dwReserved
,
1811 UriBuilder
*This
= URIBUILDER_THIS(iface
);
1812 FIXME("(%p)->(0x%08x %d %d %p)\n", This
, dwCreateFlags
, dwAllowEncodingPropertyMask
, (DWORD
)dwReserved
, ppIUri
);
1816 static HRESULT WINAPI
UriBuilder_CreateUriWithFlags(IUriBuilder
*iface
,
1817 DWORD dwCreateFlags
,
1818 DWORD dwUriBuilderFlags
,
1819 DWORD dwAllowEncodingPropertyMask
,
1820 DWORD_PTR dwReserved
,
1823 UriBuilder
*This
= URIBUILDER_THIS(iface
);
1824 FIXME("(%p)->(0x%08x 0x%08x %d %d %p)\n", This
, dwCreateFlags
, dwUriBuilderFlags
,
1825 dwAllowEncodingPropertyMask
, (DWORD
)dwReserved
, ppIUri
);
1829 static HRESULT WINAPI
UriBuilder_GetIUri(IUriBuilder
*iface
, IUri
**ppIUri
)
1831 UriBuilder
*This
= URIBUILDER_THIS(iface
);
1832 FIXME("(%p)->(%p)\n", This
, ppIUri
);
1836 static HRESULT WINAPI
UriBuilder_SetIUri(IUriBuilder
*iface
, IUri
*pIUri
)
1838 UriBuilder
*This
= URIBUILDER_THIS(iface
);
1839 FIXME("(%p)->(%p)\n", This
, pIUri
);
1843 static HRESULT WINAPI
UriBuilder_GetFragment(IUriBuilder
*iface
, DWORD
*pcchFragment
, LPCWSTR
*ppwzFragment
)
1845 UriBuilder
*This
= URIBUILDER_THIS(iface
);
1846 FIXME("(%p)->(%p %p)\n", This
, pcchFragment
, ppwzFragment
);
1850 static HRESULT WINAPI
UriBuilder_GetHost(IUriBuilder
*iface
, DWORD
*pcchHost
, LPCWSTR
*ppwzHost
)
1852 UriBuilder
*This
= URIBUILDER_THIS(iface
);
1853 FIXME("(%p)->(%p %p)\n", This
, pcchHost
, ppwzHost
);
1857 static HRESULT WINAPI
UriBuilder_GetPassword(IUriBuilder
*iface
, DWORD
*pcchPassword
, LPCWSTR
*ppwzPassword
)
1859 UriBuilder
*This
= URIBUILDER_THIS(iface
);
1860 FIXME("(%p)->(%p %p)\n", This
, pcchPassword
, ppwzPassword
);
1864 static HRESULT WINAPI
UriBuilder_GetPath(IUriBuilder
*iface
, DWORD
*pcchPath
, LPCWSTR
*ppwzPath
)
1866 UriBuilder
*This
= URIBUILDER_THIS(iface
);
1867 FIXME("(%p)->(%p %p)\n", This
, pcchPath
, ppwzPath
);
1871 static HRESULT WINAPI
UriBuilder_GetPort(IUriBuilder
*iface
, BOOL
*pfHasPort
, DWORD
*pdwPort
)
1873 UriBuilder
*This
= URIBUILDER_THIS(iface
);
1874 FIXME("(%p)->(%p %p)\n", This
, pfHasPort
, pdwPort
);
1878 static HRESULT WINAPI
UriBuilder_GetQuery(IUriBuilder
*iface
, DWORD
*pcchQuery
, LPCWSTR
*ppwzQuery
)
1880 UriBuilder
*This
= URIBUILDER_THIS(iface
);
1881 FIXME("(%p)->(%p %p)\n", This
, pcchQuery
, ppwzQuery
);
1885 static HRESULT WINAPI
UriBuilder_GetSchemeName(IUriBuilder
*iface
, DWORD
*pcchSchemeName
, LPCWSTR
*ppwzSchemeName
)
1887 UriBuilder
*This
= URIBUILDER_THIS(iface
);
1888 FIXME("(%p)->(%p %p)\n", This
, pcchSchemeName
, ppwzSchemeName
);
1892 static HRESULT WINAPI
UriBuilder_GetUserName(IUriBuilder
*iface
, DWORD
*pcchUserName
, LPCWSTR
*ppwzUserName
)
1894 UriBuilder
*This
= URIBUILDER_THIS(iface
);
1895 FIXME("(%p)->(%p %p)\n", This
, pcchUserName
, ppwzUserName
);
1899 static HRESULT WINAPI
UriBuilder_SetFragment(IUriBuilder
*iface
, LPCWSTR pwzNewValue
)
1901 UriBuilder
*This
= URIBUILDER_THIS(iface
);
1902 FIXME("(%p)->(%s)\n", This
, debugstr_w(pwzNewValue
));
1906 static HRESULT WINAPI
UriBuilder_SetHost(IUriBuilder
*iface
, LPCWSTR pwzNewValue
)
1908 UriBuilder
*This
= URIBUILDER_THIS(iface
);
1909 FIXME("(%p)->(%s)\n", This
, debugstr_w(pwzNewValue
));
1913 static HRESULT WINAPI
UriBuilder_SetPassword(IUriBuilder
*iface
, LPCWSTR pwzNewValue
)
1915 UriBuilder
*This
= URIBUILDER_THIS(iface
);
1916 FIXME("(%p)->(%s)\n", This
, debugstr_w(pwzNewValue
));
1920 static HRESULT WINAPI
UriBuilder_SetPath(IUriBuilder
*iface
, LPCWSTR pwzNewValue
)
1922 UriBuilder
*This
= URIBUILDER_THIS(iface
);
1923 FIXME("(%p)->(%s)\n", This
, debugstr_w(pwzNewValue
));
1927 static HRESULT WINAPI
UriBuilder_SetPort(IUriBuilder
*iface
, BOOL fHasPort
, DWORD dwNewValue
)
1929 UriBuilder
*This
= URIBUILDER_THIS(iface
);
1930 FIXME("(%p)->(%d %d)\n", This
, fHasPort
, dwNewValue
);
1934 static HRESULT WINAPI
UriBuilder_SetQuery(IUriBuilder
*iface
, LPCWSTR pwzNewValue
)
1936 UriBuilder
*This
= URIBUILDER_THIS(iface
);
1937 FIXME("(%p)->(%s)\n", This
, debugstr_w(pwzNewValue
));
1941 static HRESULT WINAPI
UriBuilder_SetSchemeName(IUriBuilder
*iface
, LPCWSTR pwzNewValue
)
1943 UriBuilder
*This
= URIBUILDER_THIS(iface
);
1944 FIXME("(%p)->(%s)\n", This
, debugstr_w(pwzNewValue
));
1948 static HRESULT WINAPI
UriBuilder_SetUserName(IUriBuilder
*iface
, LPCWSTR pwzNewValue
)
1950 UriBuilder
*This
= URIBUILDER_THIS(iface
);
1951 FIXME("(%p)->(%s)\n", This
, debugstr_w(pwzNewValue
));
1955 static HRESULT WINAPI
UriBuilder_RemoveProperties(IUriBuilder
*iface
, DWORD dwPropertyMask
)
1957 UriBuilder
*This
= URIBUILDER_THIS(iface
);
1958 FIXME("(%p)->(0x%08x)\n", This
, dwPropertyMask
);
1962 static HRESULT WINAPI
UriBuilder_HasBeenModified(IUriBuilder
*iface
, BOOL
*pfModified
)
1964 UriBuilder
*This
= URIBUILDER_THIS(iface
);
1965 FIXME("(%p)->(%p)\n", This
, pfModified
);
1969 #undef URIBUILDER_THIS
1971 static const IUriBuilderVtbl UriBuilderVtbl
= {
1972 UriBuilder_QueryInterface
,
1975 UriBuilder_CreateUriSimple
,
1976 UriBuilder_CreateUri
,
1977 UriBuilder_CreateUriWithFlags
,
1980 UriBuilder_GetFragment
,
1982 UriBuilder_GetPassword
,
1985 UriBuilder_GetQuery
,
1986 UriBuilder_GetSchemeName
,
1987 UriBuilder_GetUserName
,
1988 UriBuilder_SetFragment
,
1990 UriBuilder_SetPassword
,
1993 UriBuilder_SetQuery
,
1994 UriBuilder_SetSchemeName
,
1995 UriBuilder_SetUserName
,
1996 UriBuilder_RemoveProperties
,
1997 UriBuilder_HasBeenModified
,
2000 /***********************************************************************
2001 * CreateIUriBuilder (urlmon.@)
2003 HRESULT WINAPI
CreateIUriBuilder(IUri
*pIUri
, DWORD dwFlags
, DWORD_PTR dwReserved
, IUriBuilder
**ppIUriBuilder
)
2007 TRACE("(%p %x %x %p)\n", pIUri
, dwFlags
, (DWORD
)dwReserved
, ppIUriBuilder
);
2009 ret
= heap_alloc(sizeof(UriBuilder
));
2011 return E_OUTOFMEMORY
;
2013 ret
->lpIUriBuilderVtbl
= &UriBuilderVtbl
;
2016 *ppIUriBuilder
= URIBUILDER(ret
);