ReactOS 0.4.17-dev-573-g8315b8c
uri.c
Go to the documentation of this file.
1/*
2 * Copyright 2010 Jacek Caban for CodeWeavers
3 * Copyright 2010 Thomas Mullaly
4 *
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.
9 *
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.
14 *
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
18 */
19
20#include <limits.h>
21#include <wchar.h>
22
23#include "urlmon_main.h"
24#include "wine/debug.h"
25
26#define NO_SHLWAPI_REG
27#include "shlwapi.h"
28
29#include "strsafe.h"
30#include "winternl.h"
31#include "inaddr.h"
32#include "in6addr.h"
33#include "ip2string.h"
34
35#define URI_DISPLAY_NO_ABSOLUTE_URI 0x1
36#define URI_DISPLAY_NO_DEFAULT_PORT_AUTH 0x2
37
38#define ALLOW_NULL_TERM_SCHEME 0x01
39#define ALLOW_NULL_TERM_USER_NAME 0x02
40#define ALLOW_NULL_TERM_PASSWORD 0x04
41#define ALLOW_BRACKETLESS_IP_LITERAL 0x08
42#define SKIP_IP_FUTURE_CHECK 0x10
43#define IGNORE_PORT_DELIMITER 0x20
44
45#define RAW_URI_FORCE_PORT_DISP 0x1
46#define RAW_URI_CONVERT_TO_DOS_PATH 0x2
47
48#define COMBINE_URI_FORCE_FLAG_USE 0x1
49
51
52static const IID IID_IUriObj = {0x4b364760,0x9f51,0x11df,{0x98,0x1c,0x08,0x00,0x20,0x0c,0x9a,0x66}};
53
54typedef struct {
59
61
63
64 /* Information about the canonicalized URI's buffer. */
70
74
78
81 Uri_HOST_TYPE host_type;
82
86
89
91
95
98
101} Uri;
102
103typedef struct {
106
109
112
115
118
121
124
127
130
133} UriBuilder;
134
135typedef struct {
137
144
145 const WCHAR *scheme;
148
151
154
155 const WCHAR *host;
157 Uri_HOST_TYPE host_type;
158
160
162 const WCHAR *port;
165
166 const WCHAR *path;
168
169 const WCHAR *query;
171
174} parse_data;
175
176static const CHAR hexDigits[] = "0123456789ABCDEF";
177
178/* List of scheme types/scheme names that are recognized by the IUri interface as of IE 7. */
179static const struct {
182} recognized_schemes[] = {
183 {URL_SCHEME_FTP, L"ftp"},
184 {URL_SCHEME_HTTP, L"http"},
185 {URL_SCHEME_GOPHER, L"gopher"},
186 {URL_SCHEME_MAILTO, L"mailto"},
187 {URL_SCHEME_NEWS, L"news"},
188 {URL_SCHEME_NNTP, L"nntp"},
189 {URL_SCHEME_TELNET, L"telnet"},
190 {URL_SCHEME_WAIS, L"wais"},
191 {URL_SCHEME_FILE, L"file"},
192 {URL_SCHEME_MK, L"mk"},
193 {URL_SCHEME_HTTPS, L"https"},
194 {URL_SCHEME_SHELL, L"shell"},
195 {URL_SCHEME_SNEWS, L"snews"},
196 {URL_SCHEME_LOCAL, L"local"},
197 {URL_SCHEME_JAVASCRIPT, L"javascript"},
198 {URL_SCHEME_VBSCRIPT, L"vbscript"},
199 {URL_SCHEME_ABOUT, L"about"},
200 {URL_SCHEME_RES, L"res"},
201 {URL_SCHEME_MSSHELLROOTED, L"ms-shell-rooted"},
202 {URL_SCHEME_MSSHELLIDLIST, L"ms-shell-idlist"},
203 {URL_SCHEME_MSHELP, L"hcp"},
206
207/* List of default ports Windows recognizes. */
208static const struct {
211} default_ports[] = {
212 {URL_SCHEME_FTP, 21},
213 {URL_SCHEME_HTTP, 80},
214 {URL_SCHEME_GOPHER, 70},
215 {URL_SCHEME_NNTP, 119},
216 {URL_SCHEME_TELNET, 23},
217 {URL_SCHEME_WAIS, 210},
218 {URL_SCHEME_HTTPS, 443},
220
221/* List of 3-character top level domain names Windows seems to recognize.
222 * There might be more, but, these are the only ones I've found so far.
223 */
224static const struct {
226} recognized_tlds[] = {
227 {L"com"},
228 {L"edu"},
229 {L"gov"},
230 {L"int"},
231 {L"mil"},
232 {L"net"},
233 {L"org"}
235
237{
238 Uri *ret;
240
241 hres = IUri_QueryInterface(uri, &IID_IUriObj, (void**)&ret);
242 return SUCCEEDED(hres) ? ret : NULL;
243}
244
245static inline BOOL is_alpha(WCHAR val) {
246 return ((val >= 'a' && val <= 'z') || (val >= 'A' && val <= 'Z'));
247}
248
249static inline BOOL is_num(WCHAR val) {
250 return (val >= '0' && val <= '9');
251}
252
253static inline BOOL is_drive_path(const WCHAR *str) {
254 return (is_alpha(str[0]) && (str[1] == ':' || str[1] == '|'));
255}
256
257static inline BOOL is_unc_path(const WCHAR *str) {
258 return (str[0] == '\\' && str[1] == '\\');
259}
260
262 return (val == '>' || val == '<' || val == '\"');
263}
264
265/* A URI is implicitly a file path if it begins with
266 * a drive letter (e.g. X:) or starts with "\\" (UNC path).
267 */
268static inline BOOL is_implicit_file_path(const WCHAR *str) {
269 return (is_unc_path(str) || (is_alpha(str[0]) && str[1] == ':'));
270}
271
272/* Checks if the URI is a hierarchical URI. A hierarchical
273 * URI is one that has "//" after the scheme.
274 */
276 const WCHAR *start = *ptr;
277
278 if(**ptr != '/')
279 return FALSE;
280
281 ++(*ptr);
282 if(**ptr != '/') {
283 *ptr = start;
284 return FALSE;
285 }
286
287 ++(*ptr);
288 return TRUE;
289}
290
291/* unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" */
292static inline BOOL is_unreserved(WCHAR val) {
293 return (is_alpha(val) || is_num(val) || val == '-' || val == '.' ||
294 val == '_' || val == '~');
295}
296
297/* sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
298 * / "*" / "+" / "," / ";" / "="
299 */
300static inline BOOL is_subdelim(WCHAR val) {
301 return (val == '!' || val == '$' || val == '&' ||
302 val == '\'' || val == '(' || val == ')' ||
303 val == '*' || val == '+' || val == ',' ||
304 val == ';' || val == '=');
305}
306
307/* gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@" */
308static inline BOOL is_gendelim(WCHAR val) {
309 return (val == ':' || val == '/' || val == '?' ||
310 val == '#' || val == '[' || val == ']' ||
311 val == '@');
312}
313
314/* Characters that delimit the end of the authority
315 * section of a URI. Sometimes a '\\' is considered
316 * an authority delimiter.
317 */
318static inline BOOL is_auth_delim(WCHAR val, BOOL acceptSlash) {
319 return (val == '#' || val == '/' || val == '?' ||
320 val == '\0' || (acceptSlash && val == '\\'));
321}
322
323/* reserved = gen-delims / sub-delims */
324static inline BOOL is_reserved(WCHAR val) {
325 return (is_subdelim(val) || is_gendelim(val));
326}
327
328static inline BOOL is_hexdigit(WCHAR val) {
329 return ((val >= 'a' && val <= 'f') ||
330 (val >= 'A' && val <= 'F') ||
331 (val >= '0' && val <= '9'));
332}
333
335 return (!val || (val == '#' && scheme != URL_SCHEME_FILE) || val == '?');
336}
337
338static inline BOOL is_slash(WCHAR c)
339{
340 return c == '/' || c == '\\';
341}
342
343static inline BOOL is_ascii(WCHAR c)
344{
345 return c < 0x80;
346}
347
349 DWORD i;
350
351 for(i = 0; i < ARRAY_SIZE(default_ports); ++i) {
353 return TRUE;
354 }
355
356 return FALSE;
357}
358
359/* List of schemes types Windows seems to expect to be hierarchical. */
361 return(type == URL_SCHEME_HTTP || type == URL_SCHEME_FTP ||
366}
367
368/* Checks if 'flags' contains an invalid combination of Uri_CREATE flags. */
370 return((flags & Uri_CREATE_DECODE_EXTRA_INFO && flags & Uri_CREATE_NO_DECODE_EXTRA_INFO) ||
371 (flags & Uri_CREATE_CANONICALIZE && flags & Uri_CREATE_NO_CANONICALIZE) ||
372 (flags & Uri_CREATE_CRACK_UNKNOWN_SCHEMES && flags & Uri_CREATE_NO_CRACK_UNKNOWN_SCHEMES) ||
373 (flags & Uri_CREATE_PRE_PROCESS_HTML_URI && flags & Uri_CREATE_NO_PRE_PROCESS_HTML_URI) ||
374 (flags & Uri_CREATE_IE_SETTINGS && flags & Uri_CREATE_NO_IE_SETTINGS));
375}
376
377/* Applies each default Uri_CREATE flags to 'flags' if it
378 * doesn't cause a flag conflict.
379 */
381 if(!(*flags & Uri_CREATE_NO_CANONICALIZE))
382 *flags |= Uri_CREATE_CANONICALIZE;
383 if(!(*flags & Uri_CREATE_NO_DECODE_EXTRA_INFO))
384 *flags |= Uri_CREATE_DECODE_EXTRA_INFO;
385 if(!(*flags & Uri_CREATE_NO_CRACK_UNKNOWN_SCHEMES))
386 *flags |= Uri_CREATE_CRACK_UNKNOWN_SCHEMES;
387 if(!(*flags & Uri_CREATE_NO_PRE_PROCESS_HTML_URI))
388 *flags |= Uri_CREATE_PRE_PROCESS_HTML_URI;
389 if(!(*flags & Uri_CREATE_IE_SETTINGS))
390 *flags |= Uri_CREATE_NO_IE_SETTINGS;
391}
392
393/* Determines if the URI is hierarchical using the information already parsed into
394 * data and using the current location of parsing in the URI string.
395 *
396 * Windows considers a URI hierarchical if one of the following is true:
397 * A.) It's a wildcard scheme.
398 * B.) It's an implicit file scheme.
399 * C.) It's a known hierarchical scheme and it has two '\\' after the scheme name.
400 * (the '\\' will be converted into "//" during canonicalization).
401 * D.) "//" appears after the scheme name (or at the beginning if no scheme is given).
402 */
403static inline BOOL is_hierarchical_uri(const WCHAR **ptr, const parse_data *data) {
404 const WCHAR *start = *ptr;
405
406 if(data->scheme_type == URL_SCHEME_WILDCARD)
407 return TRUE;
408 else if(data->scheme_type == URL_SCHEME_FILE && data->has_implicit_scheme)
409 return TRUE;
410 else if(is_hierarchical_scheme(data->scheme_type) && (*ptr)[0] == '\\' && (*ptr)[1] == '\\') {
411 *ptr += 2;
412 return TRUE;
413 } else if(data->scheme_type != URL_SCHEME_MAILTO && check_hierarchical(ptr))
414 return TRUE;
415
416 *ptr = start;
417 return FALSE;
418}
419
420/* Taken from dlls/jscript/lex.c */
421static int hex_to_int(WCHAR val) {
422 if(val >= '0' && val <= '9')
423 return val - '0';
424 else if(val >= 'a' && val <= 'f')
425 return val - 'a' + 10;
426 else if(val >= 'A' && val <= 'F')
427 return val - 'A' + 10;
428
429 return -1;
430}
431
432/* Helper function for converting a percent encoded string
433 * representation of a WCHAR value into its actual WCHAR value. If
434 * the two characters following the '%' aren't valid hex values then
435 * this function returns the NULL character.
436 *
437 * E.g.
438 * "%2E" will result in '.' being returned by this function.
439 */
441 WCHAR ret = '\0';
442
443 if(*ptr == '%' && is_hexdigit(*(ptr + 1)) && is_hexdigit(*(ptr + 2))) {
444 INT a = hex_to_int(*(ptr + 1));
445 INT b = hex_to_int(*(ptr + 2));
446
447 ret = a << 4;
448 ret += b;
449 }
450
451 return ret;
452}
453
454/* Helper function for percent encoding a given character
455 * and storing the encoded value into a given buffer (dest).
456 *
457 * It's up to the calling function to ensure that there is
458 * at least enough space in 'dest' for the percent encoded
459 * value to be stored (so dest + 3 spaces available).
460 */
461static inline void pct_encode_val(WCHAR val, WCHAR *dest) {
462 dest[0] = '%';
463 dest[1] = hexDigits[(val >> 4) & 0xf];
464 dest[2] = hexDigits[val & 0xf];
465}
466
467/* Attempts to parse the domain name from the host.
468 *
469 * This function also includes the Top-level Domain (TLD) name
470 * of the host when it tries to find the domain name. If it finds
471 * a valid domain name it will assign 'domain_start' the offset
472 * into 'host' where the domain name starts.
473 *
474 * It's implied that if there is a domain name its range is:
475 * [host+domain_start, host+host_len).
476 */
477void find_domain_name(const WCHAR *host, DWORD host_len,
478 INT *domain_start) {
479 const WCHAR *last_tld, *sec_last_tld, *end, *p;
480
481 end = host+host_len-1;
482
483 *domain_start = -1;
484
485 /* There has to be at least enough room for a '.' followed by a
486 * 3-character TLD for a domain to even exist in the host name.
487 */
488 if(host_len < 4)
489 return;
490
491 for (last_tld = sec_last_tld = NULL, p = host; p <= end; p++)
492 {
493 if (*p == '.')
494 {
495 sec_last_tld = last_tld;
496 last_tld = p;
497 }
498 }
499 if(!last_tld)
500 /* http://hostname -> has no domain name. */
501 return;
502
503 if(!sec_last_tld) {
504 /* If the '.' is at the beginning of the host there
505 * has to be at least 3 characters in the TLD for it
506 * to be valid.
507 * Ex: .com -> .com as the domain name.
508 * .co -> has no domain name.
509 */
510 if(last_tld-host == 0) {
511 if(end-(last_tld-1) < 3)
512 return;
513 } else if(last_tld-host == 3) {
514 DWORD i;
515
516 /* If there are three characters in front of last_tld and
517 * they are on the list of recognized TLDs, then this
518 * host doesn't have a domain (since the host only contains
519 * a TLD name.
520 * Ex: edu.uk -> has no domain name.
521 * foo.uk -> foo.uk as the domain name.
522 */
523 for(i = 0; i < ARRAY_SIZE(recognized_tlds); ++i) {
525 return;
526 }
527 } else if(last_tld-host < 3)
528 {
529 /* Anything less than 3 ASCII characters is considered part
530 * of the TLD name.
531 * Ex: ak.uk -> Has no domain name.
532 */
533 for(p = host; p < last_tld; p++) {
534 if(!is_ascii(*p))
535 break;
536 }
537
538 if(p == last_tld)
539 return;
540 }
541
542 /* Otherwise the domain name is the whole host name. */
543 *domain_start = 0;
544 } else if(end+1-last_tld > 3) {
545 /* If the last_tld has more than 3 characters, then it's automatically
546 * considered the TLD of the domain name.
547 * Ex: www.winehq.org.uk.test -> uk.test as the domain name.
548 */
549 *domain_start = (sec_last_tld+1)-host;
550 } else if(last_tld - (sec_last_tld+1) < 4) {
551 DWORD i;
552 /* If the sec_last_tld is 3 characters long it HAS to be on the list of
553 * recognized to still be considered part of the TLD name, otherwise
554 * it's considered the domain name.
555 * Ex: www.google.com.uk -> google.com.uk as the domain name.
556 * www.google.foo.uk -> foo.uk as the domain name.
557 */
558 if(last_tld - (sec_last_tld+1) == 3) {
559 for(i = 0; i < ARRAY_SIZE(recognized_tlds); ++i) {
560 if(!StrCmpNIW(sec_last_tld+1, recognized_tlds[i].tld_name, 3)) {
561 for (p = sec_last_tld; p > host; p--) if (p[-1] == '.') break;
562 *domain_start = p - host;
563 TRACE("Found domain name %s\n", debugstr_wn(host+*domain_start,
564 (host+host_len)-(host+*domain_start)));
565 return;
566 }
567 }
568
569 *domain_start = (sec_last_tld+1)-host;
570 } else {
571 /* Since the sec_last_tld is less than 3 characters it's considered
572 * part of the TLD.
573 * Ex: www.google.fo.uk -> google.fo.uk as the domain name.
574 */
575 for (p = sec_last_tld; p > host; p--) if (p[-1] == '.') break;
576 *domain_start = p - host;
577 }
578 } else {
579 /* The second to last TLD has more than 3 characters making it
580 * the domain name.
581 * Ex: www.google.test.us -> test.us as the domain name.
582 */
583 *domain_start = (sec_last_tld+1)-host;
584 }
585
586 TRACE("Found domain name %s\n", debugstr_wn(host+*domain_start,
587 (host+host_len)-(host+*domain_start)));
588}
589
590/* Removes the dot segments from a hierarchical URIs path component. This
591 * function performs the removal in place.
592 *
593 * This function returns the new length of the path string.
594 */
596 WCHAR *out = path;
597 const WCHAR *in = out;
598 const WCHAR *end = out + path_len;
599 DWORD len;
600
601 while(in < end) {
602 /* Move the first path segment in the input buffer to the end of
603 * the output buffer, and any subsequent characters up to, including
604 * the next "/" character (if any) or the end of the input buffer.
605 */
606 while(in < end && !is_slash(*in))
607 *out++ = *in++;
608 if(in == end)
609 break;
610 *out++ = *in++;
611
612 while(in < end) {
613 if(*in != '.')
614 break;
615
616 /* Handle ending "/." */
617 if(in + 1 == end) {
618 ++in;
619 break;
620 }
621
622 /* Handle "/./" */
623 if(is_slash(in[1])) {
624 in += 2;
625 continue;
626 }
627
628 /* If we don't have "/../" or ending "/.." */
629 if(in[1] != '.' || (in + 2 != end && !is_slash(in[2])))
630 break;
631
632 /* Find the slash preceding out pointer and move out pointer to it */
633 if(out > path+1 && is_slash(*--out))
634 --out;
635 while(out > path && !is_slash(*(--out)));
636 if(is_slash(*out))
637 ++out;
638 in += 2;
639 if(in != end)
640 ++in;
641 }
642 }
643
644 len = out - path;
645 TRACE("(%p %ld): Path after dot segments removed %s len=%ld\n", path, path_len,
647 return len;
648}
649
650/* Attempts to find the file extension in a given path. */
652 const WCHAR *end;
653
654 for(end = path+path_len-1; end >= path && *end != '/' && *end != '\\'; --end) {
655 if(*end == '.')
656 return end-path;
657 }
658
659 return -1;
660}
661
662/* Removes all the leading and trailing white spaces or
663 * control characters from the URI and removes all control
664 * characters inside of the URI string.
665 */
667 const WCHAR *start, *end, *ptr;
668 WCHAR *ptr2;
669 DWORD len;
670 BSTR ret;
671
672 start = uri;
673 /* Skip leading controls and whitespace. */
674 while(*start && (iswcntrl(*start) || iswspace(*start))) ++start;
675
676 /* URI consisted only of control/whitespace. */
677 if(!*start)
678 return SysAllocStringLen(NULL, 0);
679
680 end = start + lstrlenW(start);
681 while(--end > start && (iswcntrl(*end) || iswspace(*end)));
682
683 len = ++end - start;
684 for(ptr = start; ptr < end; ptr++) {
685 if(iswcntrl(*ptr))
686 len--;
687 }
688
690 if(!ret)
691 return NULL;
692
693 for(ptr = start, ptr2=ret; ptr < end; ptr++) {
694 if(!iswcntrl(*ptr))
695 *ptr2++ = *ptr;
696 }
697
698 return ret;
699}
700
701/* Converts an IPv4 address in numerical form into its fully qualified
702 * string form. This function returns the number of characters written
703 * to 'dest'. If 'dest' is NULL this function will return the number of
704 * characters that would have been written.
705 *
706 * It's up to the caller to ensure there's enough space in 'dest' for the
707 * address.
708 */
710 DWORD ret = 0;
711 UCHAR digits[4];
712
713 digits[0] = (address >> 24) & 0xff;
714 digits[1] = (address >> 16) & 0xff;
715 digits[2] = (address >> 8) & 0xff;
716 digits[3] = address & 0xff;
717
718 if(!dest) {
719 WCHAR tmp[16];
720 ret = swprintf(tmp, ARRAY_SIZE(tmp), L"%u.%u.%u.%u", digits[0], digits[1], digits[2], digits[3]);
721 } else
722 ret = swprintf(dest, 16, L"%u.%u.%u.%u", digits[0], digits[1], digits[2], digits[3]);
723
724 return ret;
725}
726
728 DWORD ret = 0;
729
730 if(!dest) {
731 WCHAR tmp[11];
732 ret = swprintf(tmp, ARRAY_SIZE(tmp), L"%u", value);
733 } else
734 ret = swprintf(dest, 11, L"%u", value);
735
736 return ret;
737}
738
739/* Checks if the characters pointed to by 'ptr' are
740 * a percent encoded data octet.
741 *
742 * pct-encoded = "%" HEXDIG HEXDIG
743 */
745 const WCHAR *start = *ptr;
746
747 if(**ptr != '%')
748 return FALSE;
749
750 ++(*ptr);
751 if(!is_hexdigit(**ptr)) {
752 *ptr = start;
753 return FALSE;
754 }
755
756 ++(*ptr);
757 if(!is_hexdigit(**ptr)) {
758 *ptr = start;
759 return FALSE;
760 }
761
762 ++(*ptr);
763 return TRUE;
764}
765
766/* dec-octet = DIGIT ; 0-9
767 * / %x31-39 DIGIT ; 10-99
768 * / "1" 2DIGIT ; 100-199
769 * / "2" %x30-34 DIGIT ; 200-249
770 * / "25" %x30-35 ; 250-255
771 */
772static BOOL check_dec_octet(const WCHAR **ptr) {
773 const WCHAR *c1, *c2, *c3;
774
775 c1 = *ptr;
776 /* A dec-octet must be at least 1 digit long. */
777 if(*c1 < '0' || *c1 > '9')
778 return FALSE;
779
780 ++(*ptr);
781
782 c2 = *ptr;
783 /* Since the 1-digit requirement was met, it doesn't
784 * matter if this is a DIGIT value, it's considered a
785 * dec-octet.
786 */
787 if(*c2 < '0' || *c2 > '9')
788 return TRUE;
789
790 ++(*ptr);
791
792 c3 = *ptr;
793 /* Same explanation as above. */
794 if(*c3 < '0' || *c3 > '9')
795 return TRUE;
796
797 /* Anything > 255 isn't a valid IP dec-octet. */
798 if(*c1 >= '2' && *c2 >= '5' && *c3 >= '5') {
799 *ptr = c1;
800 return FALSE;
801 }
802
803 ++(*ptr);
804 return TRUE;
805}
806
807/* Checks if there is an implicit IPv4 address in the host component of the URI.
808 * The max value of an implicit IPv4 address is UINT_MAX.
809 *
810 * Ex:
811 * "234567" would be considered an implicit IPv4 address.
812 */
814 const WCHAR *start = *ptr;
815 ULONGLONG ret = 0;
816 *val = 0;
817
818 while(is_num(**ptr)) {
819 ret = ret*10 + (**ptr - '0');
820
821 if(ret > UINT_MAX) {
822 *ptr = start;
823 return FALSE;
824 }
825 ++(*ptr);
826 }
827
828 if(*ptr == start)
829 return FALSE;
830
831 *val = ret;
832 return TRUE;
833}
834
835/* Checks if the string contains an IPv4 address.
836 *
837 * This function has a strict mode or a non-strict mode of operation
838 * When 'strict' is set to FALSE this function will return TRUE if
839 * the string contains at least 'dec-octet "." dec-octet' since partial
840 * IPv4 addresses will be normalized out into full IPv4 addresses. When
841 * 'strict' is set this function expects there to be a full IPv4 address.
842 *
843 * IPv4address = dec-octet "." dec-octet "." dec-octet "." dec-octet
844 */
846 const WCHAR *start = *ptr;
847
848 if(!check_dec_octet(ptr)) {
849 *ptr = start;
850 return FALSE;
851 }
852
853 if(**ptr != '.') {
854 *ptr = start;
855 return FALSE;
856 }
857
858 ++(*ptr);
859 if(!check_dec_octet(ptr)) {
860 *ptr = start;
861 return FALSE;
862 }
863
864 if(**ptr != '.') {
865 if(strict) {
866 *ptr = start;
867 return FALSE;
868 } else
869 return TRUE;
870 }
871
872 ++(*ptr);
873 if(!check_dec_octet(ptr)) {
874 *ptr = start;
875 return FALSE;
876 }
877
878 if(**ptr != '.') {
879 if(strict) {
880 *ptr = start;
881 return FALSE;
882 } else
883 return TRUE;
884 }
885
886 ++(*ptr);
887 if(!check_dec_octet(ptr)) {
888 *ptr = start;
889 return FALSE;
890 }
891
892 /* Found a four digit ip address. */
893 return TRUE;
894}
895/* Tries to parse the scheme name of the URI.
896 *
897 * scheme = ALPHA *(ALPHA | NUM | '+' | '-' | '.') as defined by RFC 3896.
898 * NOTE: Windows accepts a number as the first character of a scheme.
899 */
901 const WCHAR *start = *ptr;
902
903 data->scheme = NULL;
904 data->scheme_len = 0;
905
906 while(**ptr) {
907 if(**ptr == '*' && *ptr == start) {
908 /* Might have found a wildcard scheme. If it is the next
909 * char has to be a ':' for it to be a valid URI
910 */
911 ++(*ptr);
912 break;
913 } else if(!is_num(**ptr) && !is_alpha(**ptr) && **ptr != '+' &&
914 **ptr != '-' && **ptr != '.')
915 break;
916
917 (*ptr)++;
918 }
919
920 if(*ptr == start)
921 return FALSE;
922
923 /* Schemes must end with a ':' */
924 if(**ptr != ':' && !((extras & ALLOW_NULL_TERM_SCHEME) && !**ptr)) {
925 *ptr = start;
926 return FALSE;
927 }
928
929 data->scheme = start;
930 data->scheme_len = *ptr - start;
931
932 ++(*ptr);
933 return TRUE;
934}
935
936/* Tries to deduce the corresponding URL_SCHEME for the given URI. Stores
937 * the deduced URL_SCHEME in data->scheme_type.
938 */
940 /* If there's scheme data then see if it's a recognized scheme. */
941 if(data->scheme && data->scheme_len) {
942 DWORD i;
943
944 for(i = 0; i < ARRAY_SIZE(recognized_schemes); ++i) {
945 if(lstrlenW(recognized_schemes[i].scheme_name) == data->scheme_len) {
946 /* Has to be a case insensitive compare. */
947 if(!StrCmpNIW(recognized_schemes[i].scheme_name, data->scheme, data->scheme_len)) {
948 data->scheme_type = recognized_schemes[i].scheme;
949 return TRUE;
950 }
951 }
952 }
953
954 /* If we get here it means it's not a recognized scheme. */
955 data->scheme_type = URL_SCHEME_UNKNOWN;
956 return TRUE;
957 } else if(data->is_relative) {
958 /* Relative URI's have no scheme. */
959 data->scheme_type = URL_SCHEME_UNKNOWN;
960 return TRUE;
961 } else {
962 /* Should never reach here! what happened... */
963 FIXME("(%p): Unable to determine scheme type for URI %s\n", data, debugstr_w(data->uri));
964 return FALSE;
965 }
966}
967
968/* Tries to parse (or deduce) the scheme_name of a URI. If it can't
969 * parse a scheme from the URI it will try to deduce the scheme_name and scheme_type
970 * using the flags specified in 'flags' (if any). Flags that affect how this function
971 * operates are the Uri_CREATE_ALLOW_* flags.
972 *
973 * All parsed/deduced information will be stored in 'data' when the function returns.
974 *
975 * Returns TRUE if it was able to successfully parse the information.
976 */
978 /* First check to see if the uri could implicitly be a file path. */
980 if(flags & Uri_CREATE_ALLOW_IMPLICIT_FILE_SCHEME) {
981 data->scheme = L"file";
982 data->scheme_len = lstrlenW(L"file");
983 data->has_implicit_scheme = TRUE;
984
985 TRACE("(%p %p %lx): URI is an implicit file path.\n", ptr, data, flags);
986 } else {
987 /* Windows does not consider anything that can implicitly be a file
988 * path to be a valid URI if the ALLOW_IMPLICIT_FILE_SCHEME flag is not set...
989 */
990 TRACE("(%p %p %lx): URI is implicitly a file path, but, the ALLOW_IMPLICIT_FILE_SCHEME flag wasn't set.\n",
991 ptr, data, flags);
992 return FALSE;
993 }
994 } else if(!parse_scheme_name(ptr, data, extras)) {
995 /* No scheme was found, this means it could be:
996 * a) an implicit Wildcard scheme
997 * b) a relative URI
998 * c) an invalid URI.
999 */
1000 if(flags & Uri_CREATE_ALLOW_IMPLICIT_WILDCARD_SCHEME) {
1001 data->scheme = L"*";
1002 data->scheme_len = lstrlenW(L"*");
1003 data->has_implicit_scheme = TRUE;
1004
1005 TRACE("(%p %p %lx): URI is an implicit wildcard scheme.\n", ptr, data, flags);
1006 } else if (flags & Uri_CREATE_ALLOW_RELATIVE) {
1007 data->is_relative = TRUE;
1008 TRACE("(%p %p %lx): URI is relative.\n", ptr, data, flags);
1009 } else {
1010 TRACE("(%p %p %lx): Malformed URI found. Unable to deduce scheme name.\n", ptr, data, flags);
1011 return FALSE;
1012 }
1013 }
1014
1015 if(!data->is_relative)
1016 TRACE("(%p %p %lx): Found scheme=%s scheme_len=%ld\n", ptr, data, flags,
1017 debugstr_wn(data->scheme, data->scheme_len), data->scheme_len);
1018
1020 return FALSE;
1021
1022 TRACE("(%p %p %lx): Assigned %d as the URL_SCHEME.\n", ptr, data, flags, data->scheme_type);
1023 return TRUE;
1024}
1025
1027 data->username = *ptr;
1028
1029 while(**ptr != ':' && **ptr != '@') {
1030 if(**ptr == '%') {
1031 if(!check_pct_encoded(ptr)) {
1032 if(data->scheme_type != URL_SCHEME_UNKNOWN) {
1033 *ptr = data->username;
1034 data->username = NULL;
1035 return FALSE;
1036 }
1037 } else
1038 continue;
1039 } else if(extras & ALLOW_NULL_TERM_USER_NAME && !**ptr)
1040 break;
1041 else if(is_auth_delim(**ptr, data->scheme_type != URL_SCHEME_UNKNOWN)) {
1042 *ptr = data->username;
1043 data->username = NULL;
1044 return FALSE;
1045 }
1046
1047 ++(*ptr);
1048 }
1049
1050 data->username_len = *ptr - data->username;
1051 return TRUE;
1052}
1053
1055 data->password = *ptr;
1056
1057 while(**ptr != '@') {
1058 if(**ptr == '%') {
1059 if(!check_pct_encoded(ptr)) {
1060 if(data->scheme_type != URL_SCHEME_UNKNOWN) {
1061 *ptr = data->password;
1062 data->password = NULL;
1063 return FALSE;
1064 }
1065 } else
1066 continue;
1067 } else if(extras & ALLOW_NULL_TERM_PASSWORD && !**ptr)
1068 break;
1069 else if(is_auth_delim(**ptr, data->scheme_type != URL_SCHEME_UNKNOWN)) {
1070 *ptr = data->password;
1071 data->password = NULL;
1072 return FALSE;
1073 }
1074
1075 ++(*ptr);
1076 }
1077
1078 data->password_len = *ptr - data->password;
1079 return TRUE;
1080}
1081
1082/* Parses the userinfo part of the URI (if it exists). The userinfo field of
1083 * a URI can consist of "username:password@", or just "username@".
1084 *
1085 * RFC def:
1086 * userinfo = *( unreserved / pct-encoded / sub-delims / ":" )
1087 *
1088 * NOTES:
1089 * 1) If there is more than one ':' in the userinfo part of the URI Windows
1090 * uses the first occurrence of ':' to delimit the username and password
1091 * components.
1092 *
1093 * ex:
1094 * ftp://user:pass:word@winehq.org
1095 *
1096 * would yield "user" as the username and "pass:word" as the password.
1097 *
1098 * 2) Windows allows any character to appear in the "userinfo" part of
1099 * a URI, as long as it's not an authority delimiter character set.
1100 */
1102 const WCHAR *start = *ptr;
1103
1104 if(!parse_username(ptr, data, flags, 0)) {
1105 TRACE("(%p %p %lx): URI contained no userinfo.\n", ptr, data, flags);
1106 return;
1107 }
1108
1109 if(**ptr == ':') {
1110 ++(*ptr);
1111 if(!parse_password(ptr, data, flags, 0)) {
1112 *ptr = start;
1113 data->username = NULL;
1114 data->username_len = 0;
1115 TRACE("(%p %p %lx): URI contained no userinfo.\n", ptr, data, flags);
1116 return;
1117 }
1118 }
1119
1120 if(**ptr != '@') {
1121 *ptr = start;
1122 data->username = NULL;
1123 data->username_len = 0;
1124 data->password = NULL;
1125 data->password_len = 0;
1126
1127 TRACE("(%p %p %lx): URI contained no userinfo.\n", ptr, data, flags);
1128 return;
1129 }
1130
1131 if(data->username)
1132 TRACE("(%p %p %lx): Found username %s len=%ld.\n", ptr, data, flags,
1133 debugstr_wn(data->username, data->username_len), data->username_len);
1134
1135 if(data->password)
1136 TRACE("(%p %p %lx): Found password %s len=%ld.\n", ptr, data, flags,
1137 debugstr_wn(data->password, data->password_len), data->password_len);
1138
1139 ++(*ptr);
1140}
1141
1142/* Attempts to parse a port from the URI.
1143 *
1144 * NOTES:
1145 * Windows seems to have a cap on what the maximum value
1146 * for a port can be. The max value is USHORT_MAX.
1147 *
1148 * port = *DIGIT
1149 */
1151 UINT port = 0;
1152 data->port = *ptr;
1153
1154 while(!is_auth_delim(**ptr, data->scheme_type != URL_SCHEME_UNKNOWN)) {
1155 if(!is_num(**ptr)) {
1156 *ptr = data->port;
1157 data->port = NULL;
1158 return FALSE;
1159 }
1160
1161 port = port*10 + (**ptr-'0');
1162
1163 if(port > USHRT_MAX) {
1164 *ptr = data->port;
1165 data->port = NULL;
1166 return FALSE;
1167 }
1168
1169 ++(*ptr);
1170 }
1171
1172 data->has_port = TRUE;
1173 data->port_value = port;
1174 data->port_len = *ptr - data->port;
1175
1176 TRACE("(%p %p): Found port %s len=%ld value=%lu\n", ptr, data,
1177 debugstr_wn(data->port, data->port_len), data->port_len, data->port_value);
1178 return TRUE;
1179}
1180
1181/* Attempts to parse a IPv4 address from the URI.
1182 *
1183 * NOTES:
1184 * Windows normalizes IPv4 addresses, This means there are three
1185 * possibilities for the URI to contain an IPv4 address.
1186 * 1) A well formed address (ex. 192.2.2.2).
1187 * 2) A partially formed address. For example "192.0" would
1188 * normalize to "192.0.0.0" during canonicalization.
1189 * 3) An implicit IPv4 address. For example "256" would
1190 * normalize to "0.0.1.0" during canonicalization. Also
1191 * note that the maximum value for an implicit IP address
1192 * is UINT_MAX, if the value in the URI exceeds this then
1193 * it is not considered an IPv4 address.
1194 */
1196 const BOOL is_unknown = data->scheme_type == URL_SCHEME_UNKNOWN;
1197 data->host = *ptr;
1198
1199 if(!check_ipv4address(ptr, FALSE)) {
1200 if(!check_implicit_ipv4(ptr, &data->implicit_ipv4)) {
1201 TRACE("(%p %p): URI didn't contain anything looking like an IPv4 address.\n", ptr, data);
1202 *ptr = data->host;
1203 data->host = NULL;
1204 return FALSE;
1205 } else
1206 data->has_implicit_ip = TRUE;
1207 }
1208
1209 data->host_len = *ptr - data->host;
1210 data->host_type = Uri_HOST_IPV4;
1211
1212 /* Check if what we found is the only part of the host name (if it isn't
1213 * we don't have an IPv4 address).
1214 */
1215 if(**ptr == ':') {
1216 ++(*ptr);
1217 if(!parse_port(ptr, data)) {
1218 *ptr = data->host;
1219 data->host = NULL;
1220 return FALSE;
1221 }
1222 } else if(!is_auth_delim(**ptr, !is_unknown)) {
1223 /* Found more data which belongs to the host, so this isn't an IPv4. */
1224 *ptr = data->host;
1225 data->host = NULL;
1226 data->has_implicit_ip = FALSE;
1227 return FALSE;
1228 }
1229
1230 TRACE("(%p %p): IPv4 address found. host=%s host_len=%ld host_type=%d\n",
1231 ptr, data, debugstr_wn(data->host, data->host_len),
1232 data->host_len, data->host_type);
1233 return TRUE;
1234}
1235
1236/* Attempts to parse the reg-name from the URI.
1237 *
1238 * Because of the way Windows handles ':' this function also
1239 * handles parsing the port.
1240 *
1241 * reg-name = *( unreserved / pct-encoded / sub-delims )
1242 *
1243 * NOTE:
1244 * Windows allows everything, but, the characters in "auth_delims" and ':'
1245 * to appear in a reg-name, unless it's an unknown scheme type then ':' is
1246 * allowed to appear (even if a valid port isn't after it).
1247 *
1248 * Windows doesn't like host names which start with '[' and end with ']'
1249 * and don't contain a valid IP literal address in between them.
1250 *
1251 * On Windows if a '[' is encountered in the host name the ':' no longer
1252 * counts as a delimiter until you reach the next ']' or an "authority delimiter".
1253 *
1254 * A reg-name CAN be empty.
1255 */
1256static BOOL parse_reg_name(const WCHAR **ptr, parse_data *data, DWORD extras) {
1257 const BOOL has_start_bracket = **ptr == '[';
1258 const BOOL known_scheme = data->scheme_type != URL_SCHEME_UNKNOWN;
1259 const BOOL is_res = data->scheme_type == URL_SCHEME_RES;
1260 BOOL inside_brackets = has_start_bracket;
1261
1262 /* res URIs don't have ports. */
1263 BOOL ignore_col = (extras & IGNORE_PORT_DELIMITER) || is_res;
1264
1265 /* We have to be careful with file schemes. */
1266 if(data->scheme_type == URL_SCHEME_FILE) {
1267 /* This is because an implicit file scheme could be "C:\\test" and it
1268 * would trick this function into thinking the host is "C", when after
1269 * canonicalization the host would end up being an empty string. A drive
1270 * path can also have a '|' instead of a ':' after the drive letter.
1271 */
1272 if(is_drive_path(*ptr)) {
1273 /* Regular old drive paths have no host type (or host name). */
1274 data->host_type = Uri_HOST_UNKNOWN;
1275 data->host = *ptr;
1276 data->host_len = 0;
1277 return TRUE;
1278 } else if(is_unc_path(*ptr))
1279 /* Skip past the "\\" of a UNC path. */
1280 *ptr += 2;
1281 }
1282
1283 data->host = *ptr;
1284
1285 /* For res URIs, everything before the first '/' is
1286 * considered the host.
1287 */
1288 while((!is_res && !is_auth_delim(**ptr, known_scheme)) ||
1289 (is_res && **ptr && **ptr != '/')) {
1290 if(**ptr == ':' && !ignore_col) {
1291 /* We can ignore ':' if we are inside brackets.*/
1292 if(!inside_brackets) {
1293 const WCHAR *tmp = (*ptr)++;
1294
1295 /* Attempt to parse the port. */
1296 if(!parse_port(ptr, data)) {
1297 /* Windows expects there to be a valid port for known scheme types. */
1298 if(data->scheme_type != URL_SCHEME_UNKNOWN) {
1299 *ptr = data->host;
1300 data->host = NULL;
1301 TRACE("(%p %p %lx): Expected valid port\n", ptr, data, extras);
1302 return FALSE;
1303 } else
1304 /* Windows gives up on trying to parse a port when it
1305 * encounters an invalid port.
1306 */
1307 ignore_col = TRUE;
1308 } else {
1309 data->host_len = tmp - data->host;
1310 break;
1311 }
1312 }
1313 } else if(**ptr == '%' && (known_scheme && !is_res)) {
1314 /* Has to be a legit % encoded value. */
1315 if(!check_pct_encoded(ptr)) {
1316 *ptr = data->host;
1317 data->host = NULL;
1318 return FALSE;
1319 } else
1320 continue;
1321 } else if(is_res && is_forbidden_dos_path_char(**ptr)) {
1322 *ptr = data->host;
1323 data->host = NULL;
1324 return FALSE;
1325 } else if(**ptr == ']')
1326 inside_brackets = FALSE;
1327 else if(**ptr == '[')
1328 inside_brackets = TRUE;
1329
1330 ++(*ptr);
1331 }
1332
1333 if(has_start_bracket) {
1334 /* Make sure the last character of the host wasn't a ']'. */
1335 if(*(*ptr-1) == ']') {
1336 TRACE("(%p %p %lx): Expected an IP literal inside of the host\n", ptr, data, extras);
1337 *ptr = data->host;
1338 data->host = NULL;
1339 return FALSE;
1340 }
1341 }
1342
1343 /* Don't overwrite our length if we found a port earlier. */
1344 if(!data->port)
1345 data->host_len = *ptr - data->host;
1346
1347 /* If the host is empty, then it's an unknown host type. */
1348 if(data->host_len == 0 || is_res)
1349 data->host_type = Uri_HOST_UNKNOWN;
1350 else {
1351 unsigned int i;
1352
1353 data->host_type = Uri_HOST_DNS;
1354
1355 for(i = 0; i < data->host_len; i++) {
1356 if(!is_ascii(data->host[i])) {
1357 data->host_type = Uri_HOST_IDN;
1358 break;
1359 }
1360 }
1361 }
1362
1363 TRACE("(%p %p %lx): Parsed reg-name. host=%s len=%ld type=%d\n", ptr, data, extras,
1364 debugstr_wn(data->host, data->host_len), data->host_len, data->host_type);
1365 return TRUE;
1366}
1367
1368/* Attempts to parse an IPv6 address out of the URI.
1369 *
1370 * IPv6address = 6( h16 ":" ) ls32
1371 * / "::" 5( h16 ":" ) ls32
1372 * / [ h16 ] "::" 4( h16 ":" ) ls32
1373 * / [ *1( h16 ":" ) h16 ] "::" 3( h16 ":" ) ls32
1374 * / [ *2( h16 ":" ) h16 ] "::" 2( h16 ":" ) ls32
1375 * / [ *3( h16 ":" ) h16 ] "::" h16 ":" ls32
1376 * / [ *4( h16 ":" ) h16 ] "::" ls32
1377 * / [ *5( h16 ":" ) h16 ] "::" h16
1378 * / [ *6( h16 ":" ) h16 ] "::"
1379 *
1380 * ls32 = ( h16 ":" h16 ) / IPv4address
1381 * ; least-significant 32 bits of address.
1382 *
1383 * h16 = 1*4HEXDIG
1384 * ; 16 bits of address represented in hexadecimal.
1385 */
1387 const WCHAR *terminator;
1388
1389 if(RtlIpv6StringToAddressW(*ptr, &terminator, &data->ipv6_address))
1390 return FALSE;
1391 if(*terminator != ']' && !is_auth_delim(*terminator, data->scheme_type != URL_SCHEME_UNKNOWN))
1392 return FALSE;
1393
1394 *ptr = terminator;
1395 data->host_type = Uri_HOST_IPV6;
1396 return TRUE;
1397}
1398
1399/* IPvFuture = "v" 1*HEXDIG "." 1*( unreserved / sub-delims / ":" ) */
1401 const WCHAR *start = *ptr;
1402
1403 /* IPvFuture has to start with a 'v' or 'V'. */
1404 if(**ptr != 'v' && **ptr != 'V')
1405 return FALSE;
1406
1407 /* Following the v there must be at least 1 hex digit. */
1408 ++(*ptr);
1409 if(!is_hexdigit(**ptr)) {
1410 *ptr = start;
1411 return FALSE;
1412 }
1413
1414 ++(*ptr);
1415 while(is_hexdigit(**ptr))
1416 ++(*ptr);
1417
1418 /* End of the hexdigit sequence must be a '.' */
1419 if(**ptr != '.') {
1420 *ptr = start;
1421 return FALSE;
1422 }
1423
1424 ++(*ptr);
1425 if(!is_unreserved(**ptr) && !is_subdelim(**ptr) && **ptr != ':') {
1426 *ptr = start;
1427 return FALSE;
1428 }
1429
1430 ++(*ptr);
1431 while(is_unreserved(**ptr) || is_subdelim(**ptr) || **ptr == ':')
1432 ++(*ptr);
1433
1434 data->host_type = Uri_HOST_UNKNOWN;
1435
1436 TRACE("(%p %p): Parsed IPvFuture address %s len=%d\n", ptr, data,
1437 debugstr_wn(start, *ptr-start), (int)(*ptr-start));
1438
1439 return TRUE;
1440}
1441
1442/* IP-literal = "[" ( IPv6address / IPvFuture ) "]" */
1444 data->host = *ptr;
1445
1446 if(**ptr != '[' && !(extras & ALLOW_BRACKETLESS_IP_LITERAL)) {
1447 data->host = NULL;
1448 return FALSE;
1449 } else if(**ptr == '[')
1450 ++(*ptr);
1451
1452 if(!parse_ipv6address(ptr, data)) {
1453 if(extras & SKIP_IP_FUTURE_CHECK || !parse_ipvfuture(ptr, data)) {
1454 *ptr = data->host;
1455 data->host = NULL;
1456 return FALSE;
1457 }
1458 }
1459
1460 if(**ptr != ']' && !(extras & ALLOW_BRACKETLESS_IP_LITERAL)) {
1461 *ptr = data->host;
1462 data->host = NULL;
1463 return FALSE;
1464 } else if(!**ptr && extras & ALLOW_BRACKETLESS_IP_LITERAL) {
1465 /* The IP literal didn't contain brackets and was followed by
1466 * a NULL terminator, so no reason to even check the port.
1467 */
1468 data->host_len = *ptr - data->host;
1469 return TRUE;
1470 }
1471
1472 ++(*ptr);
1473 if(**ptr == ':') {
1474 ++(*ptr);
1475 /* If a valid port is not found, then let it trickle down to
1476 * parse_reg_name.
1477 */
1478 if(!parse_port(ptr, data)) {
1479 *ptr = data->host;
1480 data->host = NULL;
1481 return FALSE;
1482 }
1483 } else
1484 data->host_len = *ptr - data->host;
1485
1486 return TRUE;
1487}
1488
1489/* Parses the host information from the URI.
1490 *
1491 * host = IP-literal / IPv4address / reg-name
1492 */
1493static BOOL parse_host(const WCHAR **ptr, parse_data *data, DWORD extras) {
1494 if(!parse_ip_literal(ptr, data, extras)) {
1495 if(!parse_ipv4address(ptr, data)) {
1496 if(!parse_reg_name(ptr, data, extras)) {
1497 TRACE("(%p %p %lx): Malformed URI, Unknown host type.\n", ptr, data, extras);
1498 return FALSE;
1499 }
1500 }
1501 }
1502
1503 return TRUE;
1504}
1505
1506/* Parses the authority information from the URI.
1507 *
1508 * authority = [ userinfo "@" ] host [ ":" port ]
1509 */
1512
1513 /* Parsing the port will happen during one of the host parsing
1514 * routines (if the URI has a port).
1515 */
1516 if(!parse_host(ptr, data, 0))
1517 return FALSE;
1518
1519 return TRUE;
1520}
1521
1522/* Attempts to parse the path information of a hierarchical URI. */
1524 const WCHAR *start = *ptr;
1525 const BOOL is_file = data->scheme_type == URL_SCHEME_FILE;
1526
1527 if(is_path_delim(data->scheme_type, **ptr)) {
1528 if(data->scheme_type == URL_SCHEME_WILDCARD && !data->must_have_path) {
1529 data->path = NULL;
1530 data->path_len = 0;
1531 } else if(!(flags & Uri_CREATE_NO_CANONICALIZE)) {
1532 /* If the path component is empty, then a '/' is added. */
1533 data->path = L"/";
1534 data->path_len = 1;
1535 }
1536 } else {
1537 while(!is_path_delim(data->scheme_type, **ptr)) {
1538 if(**ptr == '%' && data->scheme_type != URL_SCHEME_UNKNOWN && !is_file) {
1539 if(!check_pct_encoded(ptr)) {
1540 *ptr = start;
1541 return FALSE;
1542 } else
1543 continue;
1544 } else if(is_forbidden_dos_path_char(**ptr) && is_file &&
1545 (flags & Uri_CREATE_FILE_USE_DOS_PATH)) {
1546 /* File schemes with USE_DOS_PATH set aren't allowed to have
1547 * a '<' or '>' or '\"' appear in them.
1548 */
1549 *ptr = start;
1550 return FALSE;
1551 } else if(**ptr == '\\') {
1552 /* Not allowed to have a backslash if NO_CANONICALIZE is set
1553 * and the scheme is known type (but not a file scheme).
1554 */
1555 if(flags & Uri_CREATE_NO_CANONICALIZE) {
1556 if(data->scheme_type != URL_SCHEME_FILE &&
1557 data->scheme_type != URL_SCHEME_UNKNOWN) {
1558 *ptr = start;
1559 return FALSE;
1560 }
1561 }
1562 }
1563
1564 ++(*ptr);
1565 }
1566
1567 /* The only time a URI doesn't have a path is when
1568 * the NO_CANONICALIZE flag is set and the raw URI
1569 * didn't contain one.
1570 */
1571 if(*ptr == start) {
1572 data->path = NULL;
1573 data->path_len = 0;
1574 } else {
1575 data->path = start;
1576 data->path_len = *ptr - start;
1577 }
1578 }
1579
1580 if(data->path)
1581 TRACE("(%p %p %lx): Parsed path %s len=%ld\n", ptr, data, flags,
1582 debugstr_wn(data->path, data->path_len), data->path_len);
1583 else
1584 TRACE("(%p %p %lx): The URI contained no path\n", ptr, data, flags);
1585
1586 return TRUE;
1587}
1588
1589/* Parses the path of an opaque URI (much less strict than the parser
1590 * for a hierarchical URI).
1591 *
1592 * NOTE:
1593 * Windows allows invalid % encoded data to appear in opaque URI paths
1594 * for unknown scheme types.
1595 *
1596 * File schemes with USE_DOS_PATH set aren't allowed to have '<', '>', or '\"'
1597 * appear in them.
1598 */
1600 const BOOL known_scheme = data->scheme_type != URL_SCHEME_UNKNOWN;
1601 const BOOL is_file = data->scheme_type == URL_SCHEME_FILE;
1602 const BOOL is_mailto = data->scheme_type == URL_SCHEME_MAILTO;
1603
1604 if (is_mailto && (*ptr)[0] == '/' && (*ptr)[1] == '/')
1605 {
1606 if ((*ptr)[2]) data->path = *ptr + 2;
1607 else data->path = NULL;
1608 }
1609 else
1610 data->path = *ptr;
1611
1612 while(!is_path_delim(data->scheme_type, **ptr)) {
1613 if(**ptr == '%' && known_scheme) {
1614 if(!check_pct_encoded(ptr)) {
1615 *ptr = data->path;
1616 data->path = NULL;
1617 return FALSE;
1618 } else
1619 continue;
1620 } else if(is_forbidden_dos_path_char(**ptr) && is_file &&
1621 (flags & Uri_CREATE_FILE_USE_DOS_PATH)) {
1622 *ptr = data->path;
1623 data->path = NULL;
1624 return FALSE;
1625 }
1626
1627 ++(*ptr);
1628 }
1629
1630 if (data->path) data->path_len = *ptr - data->path;
1631 TRACE("(%p %p %lx): Parsed opaque URI path %s len=%ld\n", ptr, data, flags,
1632 debugstr_wn(data->path, data->path_len), data->path_len);
1633 return TRUE;
1634}
1635
1636/* Determines how the URI should be parsed after the scheme information.
1637 *
1638 * If the scheme is followed by "//", then it is treated as a hierarchical URI
1639 * which then the authority and path information will be parsed out. Otherwise, the
1640 * URI will be treated as an opaque URI which the authority information is not parsed
1641 * out.
1642 *
1643 * RFC 3896 definition of hier-part:
1644 *
1645 * hier-part = "//" authority path-abempty
1646 * / path-absolute
1647 * / path-rootless
1648 * / path-empty
1649 *
1650 * MSDN opaque URI definition:
1651 * scheme ":" path [ "#" fragment ]
1652 *
1653 * NOTES:
1654 * If the URI is of an unknown scheme type and has a "//" following the scheme then it
1655 * is treated as a hierarchical URI, but, if the CREATE_NO_CRACK_UNKNOWN_SCHEMES flag is
1656 * set then it is considered an opaque URI regardless of what follows the scheme information
1657 * (per MSDN documentation).
1658 */
1660 const WCHAR *start = *ptr;
1661
1662 data->must_have_path = FALSE;
1663
1664 /* For javascript: URIs, simply set everything as a path */
1665 if(data->scheme_type == URL_SCHEME_JAVASCRIPT) {
1666 data->path = *ptr;
1667 data->path_len = lstrlenW(*ptr);
1668 data->is_opaque = TRUE;
1669 *ptr += data->path_len;
1670 return TRUE;
1671 }
1672
1673 /* Checks if the authority information needs to be parsed. */
1675 /* Only treat it as a hierarchical URI if the scheme_type is known or
1676 * the Uri_CREATE_NO_CRACK_UNKNOWN_SCHEMES flag is not set.
1677 */
1678 if(data->scheme_type != URL_SCHEME_UNKNOWN ||
1679 !(flags & Uri_CREATE_NO_CRACK_UNKNOWN_SCHEMES)) {
1680 TRACE("(%p %p %lx): Treating URI as an hierarchical URI.\n", ptr, data, flags);
1681 data->is_opaque = FALSE;
1682
1683 if(data->scheme_type == URL_SCHEME_WILDCARD && !data->has_implicit_scheme) {
1684 if(**ptr == '/' && *(*ptr+1) == '/') {
1685 data->must_have_path = TRUE;
1686 *ptr += 2;
1687 }
1688 }
1689
1690 /* TODO: Handle hierarchical URI's, parse authority then parse the path. */
1692 return FALSE;
1693
1695 } else
1696 /* Reset ptr to its starting position so opaque path parsing
1697 * begins at the correct location.
1698 */
1699 *ptr = start;
1700 }
1701
1702 /* If it reaches here, then the URI will be treated as an opaque
1703 * URI.
1704 */
1705
1706 TRACE("(%p %p %lx): Treating URI as an opaque URI.\n", ptr, data, flags);
1707
1708 data->is_opaque = TRUE;
1710 return FALSE;
1711
1712 return TRUE;
1713}
1714
1715/* Attempts to parse the query string from the URI.
1716 *
1717 * NOTES:
1718 * If NO_DECODE_EXTRA_INFO flag is set, then invalid percent encoded
1719 * data is allowed to appear in the query string. For unknown scheme types
1720 * invalid percent encoded data is allowed to appear regardless.
1721 */
1723 const BOOL known_scheme = data->scheme_type != URL_SCHEME_UNKNOWN;
1724
1725 if(**ptr != '?') {
1726 TRACE("(%p %p %lx): URI didn't contain a query string.\n", ptr, data, flags);
1727 return TRUE;
1728 }
1729
1730 data->query = *ptr;
1731
1732 ++(*ptr);
1733 while(**ptr && **ptr != '#') {
1734 if(**ptr == '%' && known_scheme &&
1735 !(flags & Uri_CREATE_NO_DECODE_EXTRA_INFO)) {
1736 if(!check_pct_encoded(ptr)) {
1737 *ptr = data->query;
1738 data->query = NULL;
1739 return FALSE;
1740 } else
1741 continue;
1742 }
1743
1744 ++(*ptr);
1745 }
1746
1747 data->query_len = *ptr - data->query;
1748
1749 TRACE("(%p %p %lx): Parsed query string %s len=%ld\n", ptr, data, flags,
1750 debugstr_wn(data->query, data->query_len), data->query_len);
1751 return TRUE;
1752}
1753
1754/* Attempts to parse the fragment from the URI.
1755 *
1756 * NOTES:
1757 * If NO_DECODE_EXTRA_INFO flag is set, then invalid percent encoded
1758 * data is allowed to appear in the query string. For unknown scheme types
1759 * invalid percent encoded data is allowed to appear regardless.
1760 */
1762 const BOOL known_scheme = data->scheme_type != URL_SCHEME_UNKNOWN;
1763
1764 if(**ptr != '#') {
1765 TRACE("(%p %p %lx): URI didn't contain a fragment.\n", ptr, data, flags);
1766 return TRUE;
1767 }
1768
1769 data->fragment = *ptr;
1770
1771 ++(*ptr);
1772 while(**ptr) {
1773 if(**ptr == '%' && known_scheme &&
1774 !(flags & Uri_CREATE_NO_DECODE_EXTRA_INFO)) {
1775 if(!check_pct_encoded(ptr)) {
1776 *ptr = data->fragment;
1777 data->fragment = NULL;
1778 return FALSE;
1779 } else
1780 continue;
1781 }
1782
1783 ++(*ptr);
1784 }
1785
1786 data->fragment_len = *ptr - data->fragment;
1787
1788 TRACE("(%p %p %lx): Parsed fragment %s len=%ld\n", ptr, data, flags,
1789 debugstr_wn(data->fragment, data->fragment_len), data->fragment_len);
1790 return TRUE;
1791}
1792
1793/* Parses and validates the components of the specified by data->uri
1794 * and stores the information it parses into 'data'.
1795 *
1796 * Returns TRUE if it successfully parsed the URI. False otherwise.
1797 */
1799 const WCHAR *ptr;
1800 const WCHAR **pptr;
1801
1802 ptr = data->uri;
1803 pptr = &ptr;
1804
1805 TRACE("(%p %lx): BEGINNING TO PARSE URI %s.\n", data, flags, debugstr_w(data->uri));
1806
1807 if(!parse_scheme(pptr, data, flags, 0))
1808 return FALSE;
1809
1810 if(!parse_hierpart(pptr, data, flags))
1811 return FALSE;
1812
1813 if(!parse_query(pptr, data, flags))
1814 return FALSE;
1815
1816 if(!parse_fragment(pptr, data, flags))
1817 return FALSE;
1818
1819 TRACE("(%p %lx): FINISHED PARSING URI.\n", data, flags);
1820 return TRUE;
1821}
1822
1824 const WCHAR *ptr;
1825
1826 if(!data->username) {
1827 uri->userinfo_start = -1;
1828 return TRUE;
1829 }
1830
1831 uri->userinfo_start = uri->canon_len;
1832 for(ptr = data->username; ptr < data->username+data->username_len; ++ptr) {
1833 if(*ptr == '%') {
1834 /* Only decode % encoded values for known scheme types. */
1835 if(data->scheme_type != URL_SCHEME_UNKNOWN) {
1836 /* See if the value really needs decoding. */
1838 if(is_unreserved(val)) {
1839 if(!computeOnly)
1840 uri->canon_uri[uri->canon_len] = val;
1841
1842 ++uri->canon_len;
1843
1844 /* Move pass the hex characters. */
1845 ptr += 2;
1846 continue;
1847 }
1848 }
1849 } else if(is_ascii(*ptr) && !is_reserved(*ptr) && !is_unreserved(*ptr) && *ptr != '\\') {
1850 /* Only percent encode forbidden characters if the NO_ENCODE_FORBIDDEN_CHARACTERS flag
1851 * is NOT set.
1852 */
1853 if(!(flags & Uri_CREATE_NO_ENCODE_FORBIDDEN_CHARACTERS)) {
1854 if(!computeOnly)
1855 pct_encode_val(*ptr, uri->canon_uri + uri->canon_len);
1856
1857 uri->canon_len += 3;
1858 continue;
1859 }
1860 }
1861
1862 if(!computeOnly)
1863 /* Nothing special, so just copy the character over. */
1864 uri->canon_uri[uri->canon_len] = *ptr;
1865 ++uri->canon_len;
1866 }
1867
1868 return TRUE;
1869}
1870
1872 const WCHAR *ptr;
1873
1874 if(!data->password) {
1875 uri->userinfo_split = -1;
1876 return TRUE;
1877 }
1878
1879 if(uri->userinfo_start == -1)
1880 /* Has a password, but, doesn't have a username. */
1881 uri->userinfo_start = uri->canon_len;
1882
1883 uri->userinfo_split = uri->canon_len - uri->userinfo_start;
1884
1885 /* Add the ':' to the userinfo component. */
1886 if(!computeOnly)
1887 uri->canon_uri[uri->canon_len] = ':';
1888 ++uri->canon_len;
1889
1890 for(ptr = data->password; ptr < data->password+data->password_len; ++ptr) {
1891 if(*ptr == '%') {
1892 /* Only decode % encoded values for known scheme types. */
1893 if(data->scheme_type != URL_SCHEME_UNKNOWN) {
1894 /* See if the value really needs decoding. */
1896 if(is_unreserved(val)) {
1897 if(!computeOnly)
1898 uri->canon_uri[uri->canon_len] = val;
1899
1900 ++uri->canon_len;
1901
1902 /* Move pass the hex characters. */
1903 ptr += 2;
1904 continue;
1905 }
1906 }
1907 } else if(is_ascii(*ptr) && !is_reserved(*ptr) && !is_unreserved(*ptr) && *ptr != '\\') {
1908 /* Only percent encode forbidden characters if the NO_ENCODE_FORBIDDEN_CHARACTERS flag
1909 * is NOT set.
1910 */
1911 if(!(flags & Uri_CREATE_NO_ENCODE_FORBIDDEN_CHARACTERS)) {
1912 if(!computeOnly)
1913 pct_encode_val(*ptr, uri->canon_uri + uri->canon_len);
1914
1915 uri->canon_len += 3;
1916 continue;
1917 }
1918 }
1919
1920 if(!computeOnly)
1921 /* Nothing special, so just copy the character over. */
1922 uri->canon_uri[uri->canon_len] = *ptr;
1923 ++uri->canon_len;
1924 }
1925
1926 return TRUE;
1927}
1928
1929/* Canonicalizes the userinfo of the URI represented by the parse_data.
1930 *
1931 * Canonicalization of the userinfo is a simple process. If there are any percent
1932 * encoded characters that fall in the "unreserved" character set, they are decoded
1933 * to their actual value. If a character is not in the "unreserved" or "reserved" sets
1934 * then it is percent encoded. Other than that the characters are copied over without
1935 * change.
1936 */
1938 uri->userinfo_start = uri->userinfo_split = -1;
1939 uri->userinfo_len = 0;
1940
1941 if(!data->username && !data->password)
1942 /* URI doesn't have userinfo, so nothing to do here. */
1943 return TRUE;
1944
1945 if(!canonicalize_username(data, uri, flags, computeOnly))
1946 return FALSE;
1947
1948 if(!canonicalize_password(data, uri, flags, computeOnly))
1949 return FALSE;
1950
1951 uri->userinfo_len = uri->canon_len - uri->userinfo_start;
1952 if(!computeOnly)
1953 TRACE("(%p %p %lx %d): Canonicalized userinfo, userinfo_start=%d, userinfo=%s, userinfo_split=%d userinfo_len=%ld.\n",
1954 data, uri, flags, computeOnly, uri->userinfo_start, debugstr_wn(uri->canon_uri + uri->userinfo_start, uri->userinfo_len),
1955 uri->userinfo_split, uri->userinfo_len);
1956
1957 /* Now insert the '@' after the userinfo. */
1958 if(!computeOnly)
1959 uri->canon_uri[uri->canon_len] = '@';
1960 ++uri->canon_len;
1961
1962 return TRUE;
1963}
1964
1965/* Attempts to canonicalize a reg_name.
1966 *
1967 * Things that happen:
1968 * 1) If Uri_CREATE_NO_CANONICALIZE flag is not set, then the reg_name is
1969 * lower cased. Unless it's an unknown scheme type, which case it's
1970 * no lower cased regardless.
1971 *
1972 * 2) Unreserved % encoded characters are decoded for known
1973 * scheme types.
1974 *
1975 * 3) Forbidden characters are % encoded as long as
1976 * Uri_CREATE_NO_ENCODE_FORBIDDEN_CHARACTERS flag is not set and
1977 * it isn't an unknown scheme type.
1978 *
1979 * 4) If it's a file scheme and the host is "localhost" it's removed.
1980 *
1981 * 5) If it's a file scheme and Uri_CREATE_FILE_USE_DOS_PATH is set,
1982 * then the UNC path characters are added before the host name.
1983 */
1985 DWORD flags, BOOL computeOnly) {
1986 const WCHAR *ptr;
1987 const BOOL known_scheme = data->scheme_type != URL_SCHEME_UNKNOWN;
1988
1989 if(data->scheme_type == URL_SCHEME_FILE &&
1990 data->host_len == lstrlenW(L"localhost")) {
1991 if(!StrCmpNIW(data->host, L"localhost", data->host_len)) {
1992 uri->host_start = -1;
1993 uri->host_len = 0;
1994 uri->host_type = Uri_HOST_UNKNOWN;
1995 return TRUE;
1996 }
1997 }
1998
1999 if(data->scheme_type == URL_SCHEME_FILE && flags & Uri_CREATE_FILE_USE_DOS_PATH) {
2000 if(!computeOnly) {
2001 uri->canon_uri[uri->canon_len] = '\\';
2002 uri->canon_uri[uri->canon_len+1] = '\\';
2003 }
2004 uri->canon_len += 2;
2005 uri->authority_start = uri->canon_len;
2006 }
2007
2008 uri->host_start = uri->canon_len;
2009
2010 for(ptr = data->host; ptr < data->host+data->host_len; ++ptr) {
2011 if(*ptr == '%' && known_scheme) {
2013 if(is_unreserved(val)) {
2014 /* If NO_CANONICALIZE is not set, then windows lower cases the
2015 * decoded value.
2016 */
2017 if(!(flags & Uri_CREATE_NO_CANONICALIZE) && iswupper(val)) {
2018 if(!computeOnly)
2019 uri->canon_uri[uri->canon_len] = towlower(val);
2020 } else {
2021 if(!computeOnly)
2022 uri->canon_uri[uri->canon_len] = val;
2023 }
2024 ++uri->canon_len;
2025
2026 /* Skip past the % encoded character. */
2027 ptr += 2;
2028 continue;
2029 } else {
2030 /* Just copy the % over. */
2031 if(!computeOnly)
2032 uri->canon_uri[uri->canon_len] = *ptr;
2033 ++uri->canon_len;
2034 }
2035 } else if(*ptr == '\\') {
2036 /* Only unknown scheme types could have made it here with a '\\' in the host name. */
2037 if(!computeOnly)
2038 uri->canon_uri[uri->canon_len] = *ptr;
2039 ++uri->canon_len;
2040 } else if(!(flags & Uri_CREATE_NO_ENCODE_FORBIDDEN_CHARACTERS) && is_ascii(*ptr) &&
2041 !is_unreserved(*ptr) && !is_reserved(*ptr) && known_scheme) {
2042 if(!computeOnly) {
2043 pct_encode_val(*ptr, uri->canon_uri+uri->canon_len);
2044
2045 /* The percent encoded value gets lower cased also. */
2046 if(!(flags & Uri_CREATE_NO_CANONICALIZE)) {
2047 uri->canon_uri[uri->canon_len+1] = towlower(uri->canon_uri[uri->canon_len+1]);
2048 uri->canon_uri[uri->canon_len+2] = towlower(uri->canon_uri[uri->canon_len+2]);
2049 }
2050 }
2051
2052 uri->canon_len += 3;
2053 } else {
2054 if(!computeOnly) {
2055 if(!(flags & Uri_CREATE_NO_CANONICALIZE) && known_scheme)
2056 uri->canon_uri[uri->canon_len] = towlower(*ptr);
2057 else
2058 uri->canon_uri[uri->canon_len] = *ptr;
2059 }
2060
2061 ++uri->canon_len;
2062 }
2063 }
2064
2065 uri->host_len = uri->canon_len - uri->host_start;
2066
2067 if(!computeOnly)
2068 TRACE("(%p %p %lx %d): Canonicalize reg_name=%s len=%ld\n", data, uri, flags,
2069 computeOnly, debugstr_wn(uri->canon_uri+uri->host_start, uri->host_len),
2070 uri->host_len);
2071
2072 if(!computeOnly)
2073 find_domain_name(uri->canon_uri+uri->host_start, uri->host_len,
2074 &(uri->domain_offset));
2075
2076 return TRUE;
2077}
2078
2079/* Attempts to canonicalize an implicit IPv4 address. */
2081 uri->host_start = uri->canon_len;
2082
2083 TRACE("%u\n", data->implicit_ipv4);
2084 /* For unknown scheme types Windows doesn't convert
2085 * the value into an IP address, but it still considers
2086 * it an IPv4 address.
2087 */
2088 if(data->scheme_type == URL_SCHEME_UNKNOWN) {
2089 if(!computeOnly)
2090 memcpy(uri->canon_uri+uri->canon_len, data->host, data->host_len*sizeof(WCHAR));
2091 uri->canon_len += data->host_len;
2092 } else {
2093 if(!computeOnly)
2094 uri->canon_len += ui2ipv4(uri->canon_uri+uri->canon_len, data->implicit_ipv4);
2095 else
2096 uri->canon_len += ui2ipv4(NULL, data->implicit_ipv4);
2097 }
2098
2099 uri->host_len = uri->canon_len - uri->host_start;
2100 uri->host_type = Uri_HOST_IPV4;
2101
2102 if(!computeOnly)
2103 TRACE("%p %p %lx %d): Canonicalized implicit IP address=%s len=%ld\n",
2104 data, uri, flags, computeOnly,
2105 debugstr_wn(uri->canon_uri+uri->host_start, uri->host_len),
2106 uri->host_len);
2107
2108 return TRUE;
2109}
2110
2111/* Attempts to canonicalize an IPv4 address.
2112 *
2113 * If the parse_data represents a URI that has an implicit IPv4 address
2114 * (ex. http://256/, this function will convert 256 into 0.0.1.0). If
2115 * the implicit IP address exceeds the value of UINT_MAX (maximum value
2116 * for an IPv4 address) it's canonicalized as if it were a reg-name.
2117 *
2118 * If the parse_data contains a partial or full IPv4 address it normalizes it.
2119 * A partial IPv4 address is something like "192.0" and would be normalized to
2120 * "192.0.0.0". With a full (or partial) IPv4 address like "192.002.01.003" would
2121 * be normalized to "192.2.1.3".
2122 *
2123 * NOTES:
2124 * Windows ONLY normalizes IPv4 address for known scheme types (one that isn't
2125 * URL_SCHEME_UNKNOWN). For unknown scheme types, it simply copies the data from
2126 * the original URI into the canonicalized URI, but, it still recognizes URI's
2127 * host type as HOST_IPV4.
2128 */
2130 if(data->has_implicit_ip)
2131 return canonicalize_implicit_ipv4address(data, uri, flags, computeOnly);
2132 else {
2133 uri->host_start = uri->canon_len;
2134
2135 /* Windows only normalizes for known scheme types. */
2136 if(data->scheme_type != URL_SCHEME_UNKNOWN) {
2137 /* parse_data contains a partial or full IPv4 address, so normalize it. */
2138 DWORD i, octetDigitCount = 0, octetCount = 0;
2139 BOOL octetHasDigit = FALSE;
2140
2141 for(i = 0; i < data->host_len; ++i) {
2142 if(data->host[i] == '0' && !octetHasDigit) {
2143 /* Can ignore leading zeros if:
2144 * 1) It isn't the last digit of the octet.
2145 * 2) i+1 != data->host_len
2146 * 3) i+1 != '.'
2147 */
2148 if(octetDigitCount == 2 ||
2149 i+1 == data->host_len ||
2150 data->host[i+1] == '.') {
2151 if(!computeOnly)
2152 uri->canon_uri[uri->canon_len] = data->host[i];
2153 ++uri->canon_len;
2154 TRACE("Adding zero\n");
2155 }
2156 } else if(data->host[i] == '.') {
2157 if(!computeOnly)
2158 uri->canon_uri[uri->canon_len] = data->host[i];
2159 ++uri->canon_len;
2160
2161 octetDigitCount = 0;
2162 octetHasDigit = FALSE;
2163 ++octetCount;
2164 } else {
2165 if(!computeOnly)
2166 uri->canon_uri[uri->canon_len] = data->host[i];
2167 ++uri->canon_len;
2168
2169 ++octetDigitCount;
2170 octetHasDigit = TRUE;
2171 }
2172 }
2173
2174 /* Make sure the canonicalized IP address has 4 dec-octets.
2175 * If doesn't add "0" ones until there is 4;
2176 */
2177 for( ; octetCount < 3; ++octetCount) {
2178 if(!computeOnly) {
2179 uri->canon_uri[uri->canon_len] = '.';
2180 uri->canon_uri[uri->canon_len+1] = '0';
2181 }
2182
2183 uri->canon_len += 2;
2184 }
2185 } else {
2186 /* Windows doesn't normalize addresses in unknown schemes. */
2187 if(!computeOnly)
2188 memcpy(uri->canon_uri+uri->canon_len, data->host, data->host_len*sizeof(WCHAR));
2189 uri->canon_len += data->host_len;
2190 }
2191
2192 uri->host_len = uri->canon_len - uri->host_start;
2193 if(!computeOnly)
2194 TRACE("(%p %p %lx %d): Canonicalized IPv4 address, ip=%s len=%ld\n",
2195 data, uri, flags, computeOnly,
2196 debugstr_wn(uri->canon_uri+uri->host_start, uri->host_len),
2197 uri->host_len);
2198 }
2199
2200 return TRUE;
2201}
2202
2203/* Attempts to canonicalize the IPv6 address of the URI.
2204 *
2205 * Multiple things happen during the canonicalization of an IPv6 address:
2206 * 1) Any leading zero's in a h16 component are removed.
2207 * Ex: [0001:0022::] -> [1:22::]
2208 *
2209 * 2) The longest sequence of zero h16 components are compressed
2210 * into a "::" (elision). If there's a tie, the first is chosen.
2211 *
2212 * Ex: [0:0:0:0:1:6:7:8] -> [::1:6:7:8]
2213 * [0:0:0:0:1:2::] -> [::1:2:0:0]
2214 * [0:0:1:2:0:0:7:8] -> [::1:2:0:0:7:8]
2215 *
2216 * 3) If an IPv4 address is attached to the IPv6 address, it's
2217 * also normalized.
2218 * Ex: [::001.002.022.000] -> [::1.2.22.0]
2219 *
2220 * 4) If an elision is present, but, only represents one h16 component
2221 * it's expanded.
2222 *
2223 * Ex: [1::2:3:4:5:6:7] -> [1:0:2:3:4:5:6:7]
2224 *
2225 * 5) If the IPv6 address contains an IPv4 address and there exists
2226 * at least 1 non-zero h16 component the IPv4 address is converted
2227 * into two h16 components, otherwise it's normalized and kept as is.
2228 *
2229 * Ex: [::192.200.003.4] -> [::192.200.3.4]
2230 * [ffff::192.200.003.4] -> [ffff::c0c8:3041]
2231 *
2232 * NOTE:
2233 * For unknown scheme types Windows simply copies the address over without any
2234 * changes.
2235 *
2236 * IPv4 address can be included in an elision if all its components are 0's.
2237 */
2239 DWORD flags, BOOL computeOnly) {
2240 uri->host_start = uri->canon_len;
2241
2242 if(data->scheme_type == URL_SCHEME_UNKNOWN) {
2243 if(!computeOnly)
2244 memcpy(uri->canon_uri+uri->canon_len, data->host, data->host_len*sizeof(WCHAR));
2245 uri->canon_len += data->host_len;
2246 } else {
2247 WCHAR buffer[46];
2249
2250 if(computeOnly) {
2251 RtlIpv6AddressToStringExW(&data->ipv6_address, 0, 0, buffer, &size);
2252 uri->canon_len += size + 1;
2253 } else {
2254 uri->canon_uri[uri->canon_len++] = '[';
2255 RtlIpv6AddressToStringExW(&data->ipv6_address, 0, 0, uri->canon_uri + uri->canon_len, &size);
2256 uri->canon_len += size - 1;
2257 uri->canon_uri[uri->canon_len++] = ']';
2258 }
2259 }
2260
2261 uri->host_len = uri->canon_len - uri->host_start;
2262
2263 if(!computeOnly)
2264 TRACE("(%p %p %lx %d): Canonicalized IPv6 address %s, len=%ld\n", data, uri, flags,
2265 computeOnly, debugstr_wn(uri->canon_uri+uri->host_start, uri->host_len),
2266 uri->host_len);
2267
2268 return TRUE;
2269}
2270
2271/* Attempts to canonicalize the host of the URI (if any). */
2272static BOOL canonicalize_host(const parse_data *data, Uri *uri, DWORD flags, BOOL computeOnly) {
2273 uri->host_start = -1;
2274 uri->host_len = 0;
2275 uri->domain_offset = -1;
2276
2277 if(data->host) {
2278 switch(data->host_type) {
2279 case Uri_HOST_DNS:
2280 uri->host_type = Uri_HOST_DNS;
2281 if(!canonicalize_reg_name(data, uri, flags, computeOnly))
2282 return FALSE;
2283
2284 break;
2285 case Uri_HOST_IPV4:
2286 uri->host_type = Uri_HOST_IPV4;
2287 if(!canonicalize_ipv4address(data, uri, flags, computeOnly))
2288 return FALSE;
2289
2290 break;
2291 case Uri_HOST_IPV6:
2292 if(!canonicalize_ipv6address(data, uri, flags, computeOnly))
2293 return FALSE;
2294
2295 uri->host_type = Uri_HOST_IPV6;
2296 break;
2297
2298 case Uri_HOST_IDN:
2299 uri->host_type = Uri_HOST_IDN;
2300 if(!canonicalize_reg_name(data, uri, flags, computeOnly))
2301 return FALSE;
2302
2303 break;
2304 case Uri_HOST_UNKNOWN:
2305 if(data->host_len > 0 || data->scheme_type != URL_SCHEME_FILE) {
2306 uri->host_start = uri->canon_len;
2307
2308 /* Nothing happens to unknown host types. */
2309 if(!computeOnly)
2310 memcpy(uri->canon_uri+uri->canon_len, data->host, data->host_len*sizeof(WCHAR));
2311 uri->canon_len += data->host_len;
2312 uri->host_len = data->host_len;
2313 }
2314
2315 uri->host_type = Uri_HOST_UNKNOWN;
2316 break;
2317 default:
2318 FIXME("(%p %p %lx %d): Canonicalization for host type %d not supported.\n", data,
2319 uri, flags, computeOnly, data->host_type);
2320 return FALSE;
2321 }
2322 }
2323
2324 return TRUE;
2325}
2326
2327static BOOL canonicalize_port(const parse_data *data, Uri *uri, DWORD flags, BOOL computeOnly) {
2328 BOOL has_default_port = FALSE;
2329 USHORT default_port = 0;
2330 DWORD i;
2331
2332 uri->port_offset = -1;
2333
2334 /* Check if the scheme has a default port. */
2335 for(i = 0; i < ARRAY_SIZE(default_ports); ++i) {
2336 if(default_ports[i].scheme == data->scheme_type) {
2337 has_default_port = TRUE;
2338 default_port = default_ports[i].port;
2339 break;
2340 }
2341 }
2342
2343 uri->has_port = data->has_port || has_default_port;
2344
2345 /* Possible cases:
2346 * 1) Has a port which is the default port.
2347 * 2) Has a port (not the default).
2348 * 3) Doesn't have a port, but, scheme has a default port.
2349 * 4) No port.
2350 */
2351 if(has_default_port && data->has_port && data->port_value == default_port) {
2352 /* If it's the default port and this flag isn't set, don't do anything. */
2353 if(flags & Uri_CREATE_NO_CANONICALIZE) {
2354 uri->port_offset = uri->canon_len-uri->authority_start;
2355 if(!computeOnly)
2356 uri->canon_uri[uri->canon_len] = ':';
2357 ++uri->canon_len;
2358
2359 if(data->port) {
2360 /* Copy the original port over. */
2361 if(!computeOnly)
2362 memcpy(uri->canon_uri+uri->canon_len, data->port, data->port_len*sizeof(WCHAR));
2363 uri->canon_len += data->port_len;
2364 } else {
2365 if(!computeOnly)
2366 uri->canon_len += ui2str(uri->canon_uri+uri->canon_len, data->port_value);
2367 else
2368 uri->canon_len += ui2str(NULL, data->port_value);
2369 }
2370 }
2371
2372 uri->port = default_port;
2373 } else if(data->has_port) {
2374 uri->port_offset = uri->canon_len-uri->authority_start;
2375 if(!computeOnly)
2376 uri->canon_uri[uri->canon_len] = ':';
2377 ++uri->canon_len;
2378
2379 if(flags & Uri_CREATE_NO_CANONICALIZE && data->port) {
2380 /* Copy the original over without changes. */
2381 if(!computeOnly)
2382 memcpy(uri->canon_uri+uri->canon_len, data->port, data->port_len*sizeof(WCHAR));
2383 uri->canon_len += data->port_len;
2384 } else {
2385 if(!computeOnly)
2386 uri->canon_len += ui2str(uri->canon_uri+uri->canon_len, data->port_value);
2387 else
2388 uri->canon_len += ui2str(NULL, data->port_value);
2389 }
2390
2391 uri->port = data->port_value;
2392 } else if(has_default_port)
2393 uri->port = default_port;
2394
2395 return TRUE;
2396}
2397
2398/* Canonicalizes the authority of the URI represented by the parse_data. */
2400 uri->authority_start = uri->canon_len;
2401 uri->authority_len = 0;
2402
2403 if(!canonicalize_userinfo(data, uri, flags, computeOnly))
2404 return FALSE;
2405
2406 if(!canonicalize_host(data, uri, flags, computeOnly))
2407 return FALSE;
2408
2409 if(!canonicalize_port(data, uri, flags, computeOnly))
2410 return FALSE;
2411
2412 if(uri->host_start != -1 || (data->is_relative && (data->password || data->username)))
2413 uri->authority_len = uri->canon_len - uri->authority_start;
2414 else
2415 uri->authority_start = -1;
2416
2417 return TRUE;
2418}
2419
2420/* Attempts to canonicalize the path of a hierarchical URI.
2421 *
2422 * Things that happen:
2423 * 1). Forbidden characters are percent encoded, unless the NO_ENCODE_FORBIDDEN
2424 * flag is set or it's a file URI. Forbidden characters are always encoded
2425 * for file schemes regardless and forbidden characters are never encoded
2426 * for unknown scheme types.
2427 *
2428 * 2). For known scheme types '\\' are changed to '/'.
2429 *
2430 * 3). Percent encoded, unreserved characters are decoded to their actual values.
2431 * Unless the scheme type is unknown. For file schemes any percent encoded
2432 * character in the unreserved or reserved set is decoded.
2433 *
2434 * 4). For File schemes if the path is starts with a drive letter and doesn't
2435 * start with a '/' then one is appended.
2436 * Ex: file://c:/test.mp3 -> file:///c:/test.mp3
2437 *
2438 * 5). Dot segments are removed from the path for all scheme types
2439 * unless NO_CANONICALIZE flag is set. Dot segments aren't removed
2440 * for wildcard scheme types.
2441 *
2442 * NOTES:
2443 * file://c:/test%20test -> file:///c:/test%2520test
2444 * file://c:/test%3Etest -> file:///c:/test%253Etest
2445 * if Uri_CREATE_FILE_USE_DOS_PATH is not set:
2446 * file:///c:/test%20test -> file:///c:/test%20test
2447 * file:///c:/test%test -> file:///c:/test%25test
2448 */
2450 BOOL is_implicit_scheme, WCHAR *ret_path) {
2451 const BOOL known_scheme = scheme_type != URL_SCHEME_UNKNOWN;
2452 const BOOL is_file = scheme_type == URL_SCHEME_FILE;
2453 const BOOL is_res = scheme_type == URL_SCHEME_RES;
2454 const WCHAR *ptr;
2455 BOOL escape_pct = FALSE;
2456 DWORD len = 0;
2457
2458 if(!path)
2459 return 0;
2460
2461 ptr = path;
2462
2463 if(is_file && !has_host) {
2464 /* Check if a '/' needs to be appended for the file scheme. */
2465 if(path_len > 1 && is_drive_path(ptr) && !(flags & Uri_CREATE_FILE_USE_DOS_PATH)) {
2466 if(ret_path)
2467 ret_path[len] = '/';
2468 len++;
2469 escape_pct = TRUE;
2470 } else if(*ptr == '/') {
2471 if(!(flags & Uri_CREATE_FILE_USE_DOS_PATH)) {
2472 /* Copy the extra '/' over. */
2473 if(ret_path)
2474 ret_path[len] = '/';
2475 len++;
2476 }
2477 ++ptr;
2478 }
2479
2480 if(is_drive_path(ptr)) {
2481 if(ret_path) {
2482 ret_path[len] = *ptr;
2483 /* If there's a '|' after the drive letter, convert it to a ':'. */
2484 ret_path[len+1] = ':';
2485 }
2486 ptr += 2;
2487 len += 2;
2488 }
2489 }
2490
2491 if(!is_file && *path && *path != '/') {
2492 /* Prepend a '/' to the path if it doesn't have one. */
2493 if(ret_path)
2494 ret_path[len] = '/';
2495 len++;
2496 }
2497
2498 for(; ptr < path+path_len; ++ptr) {
2499 BOOL do_default_action = TRUE;
2500
2501 if(*ptr == '%' && !is_res) {
2502 const WCHAR *tmp = ptr;
2503 WCHAR val;
2504
2505 /* Check if the % represents a valid encoded char, or if it needs encoding. */
2506 BOOL force_encode = !check_pct_encoded(&tmp) && is_file && !(flags&Uri_CREATE_FILE_USE_DOS_PATH);
2508
2509 if(force_encode || escape_pct) {
2510 /* Escape the percent sign in the file URI. */
2511 if(ret_path)
2512 pct_encode_val(*ptr, ret_path+len);
2513 len += 3;
2514 do_default_action = FALSE;
2515 } else if((is_unreserved(val) && known_scheme) ||
2516 (is_file && !is_implicit_scheme && (is_unreserved(val) || is_reserved(val) ||
2517 (val && flags&Uri_CREATE_FILE_USE_DOS_PATH && !is_forbidden_dos_path_char(val))))) {
2518 if(ret_path)
2519 ret_path[len] = val;
2520 len++;
2521
2522 ptr += 2;
2523 continue;
2524 }
2525 } else if(*ptr == '/' && is_file && (flags & Uri_CREATE_FILE_USE_DOS_PATH)) {
2526 /* Convert the '/' back to a '\\'. */
2527 if(ret_path)
2528 ret_path[len] = '\\';
2529 len++;
2530 do_default_action = FALSE;
2531 } else if(*ptr == '\\' && known_scheme) {
2532 if(!(is_file && (flags & Uri_CREATE_FILE_USE_DOS_PATH))) {
2533 /* Convert '\\' into a '/'. */
2534 if(ret_path)
2535 ret_path[len] = '/';
2536 len++;
2537 do_default_action = FALSE;
2538 }
2539 } else if(known_scheme && !is_res && is_ascii(*ptr) && !is_unreserved(*ptr) && !is_reserved(*ptr) &&
2540 (!(flags & Uri_CREATE_NO_ENCODE_FORBIDDEN_CHARACTERS) || is_file)) {
2541 if(!is_file || !(flags & Uri_CREATE_FILE_USE_DOS_PATH)) {
2542 /* Escape the forbidden character. */
2543 if(ret_path)
2544 pct_encode_val(*ptr, ret_path+len);
2545 len += 3;
2546 do_default_action = FALSE;
2547 }
2548 }
2549
2550 if(do_default_action) {
2551 if(ret_path)
2552 ret_path[len] = *ptr;
2553 len++;
2554 }
2555 }
2556
2557 /* Removing the dot segments only happens when it's not in
2558 * computeOnly mode and it's not a wildcard scheme. File schemes
2559 * with USE_DOS_PATH set don't get dot segments removed.
2560 */
2561 if(!(is_file && (flags & Uri_CREATE_FILE_USE_DOS_PATH)) &&
2562 scheme_type != URL_SCHEME_WILDCARD) {
2563 if(!(flags & Uri_CREATE_NO_CANONICALIZE) && ret_path) {
2564 /* Remove the dot segments (if any) and reset everything to the new
2565 * correct length.
2566 */
2567 len = remove_dot_segments(ret_path, len);
2568 }
2569 }
2570
2571 if(ret_path)
2572 TRACE("Canonicalized path %s len=%ld\n", debugstr_wn(ret_path, len), len);
2573 return len;
2574}
2575
2576/* Attempts to canonicalize the path for an opaque URI.
2577 *
2578 * For known scheme types:
2579 * 1) forbidden characters are percent encoded if
2580 * NO_ENCODE_FORBIDDEN_CHARACTERS isn't set.
2581 *
2582 * 2) Percent encoded, unreserved characters are decoded
2583 * to their actual values, for known scheme types.
2584 *
2585 * 3) '\\' are changed to '/' for known scheme types
2586 * except for mailto schemes.
2587 *
2588 * 4) For file schemes, if USE_DOS_PATH is set all '/'
2589 * are converted to backslashes.
2590 *
2591 * 5) For file schemes, if USE_DOS_PATH isn't set all '\'
2592 * are converted to forward slashes.
2593 */
2595 const WCHAR *ptr;
2596 const BOOL known_scheme = data->scheme_type != URL_SCHEME_UNKNOWN;
2597 const BOOL is_file = data->scheme_type == URL_SCHEME_FILE;
2598 const BOOL is_mk = data->scheme_type == URL_SCHEME_MK;
2599
2600 if(!data->path) {
2601 uri->path_start = -1;
2602 uri->path_len = 0;
2603 return TRUE;
2604 }
2605
2606 uri->path_start = uri->canon_len;
2607
2608 if(is_mk){
2609 /* hijack this flag for SCHEME_MK to tell the function when to start
2610 * converting slashes */
2611 flags |= Uri_CREATE_FILE_USE_DOS_PATH;
2612 }
2613
2614 /* For javascript: URIs, simply copy path part without any canonicalization */
2615 if(data->scheme_type == URL_SCHEME_JAVASCRIPT) {
2616 if(!computeOnly)
2617 memcpy(uri->canon_uri+uri->canon_len, data->path, data->path_len*sizeof(WCHAR));
2618 uri->path_len = data->path_len;
2619 uri->canon_len += data->path_len;
2620 return TRUE;
2621 }
2622
2623 /* Windows doesn't allow a "//" to appear after the scheme
2624 * of a URI, if it's an opaque URI.
2625 */
2626 if(data->scheme && *(data->path) == '/' && *(data->path+1) == '/') {
2627 /* So it inserts a "/." before the "//" if it exists. */
2628 if(!computeOnly) {
2629 uri->canon_uri[uri->canon_len] = '/';
2630 uri->canon_uri[uri->canon_len+1] = '.';
2631 }
2632
2633 uri->canon_len += 2;
2634 }
2635
2636 for(ptr = data->path; ptr < data->path+data->path_len; ++ptr) {
2637 BOOL do_default_action = TRUE;
2638
2639 if(*ptr == '%' && known_scheme) {
2641
2642 if(is_unreserved(val)) {
2643 if(!computeOnly)
2644 uri->canon_uri[uri->canon_len] = val;
2645 ++uri->canon_len;
2646
2647 ptr += 2;
2648 continue;
2649 }
2650 } else if(*ptr == '/' && is_file && (flags & Uri_CREATE_FILE_USE_DOS_PATH)) {
2651 if(!computeOnly)
2652 uri->canon_uri[uri->canon_len] = '\\';
2653 ++uri->canon_len;
2654 do_default_action = FALSE;
2655 } else if(*ptr == '\\') {
2656 if((data->is_relative || is_mk || is_file) && !(flags & Uri_CREATE_FILE_USE_DOS_PATH)) {
2657 /* Convert to a '/'. */
2658 if(!computeOnly)
2659 uri->canon_uri[uri->canon_len] = '/';
2660 ++uri->canon_len;
2661 do_default_action = FALSE;
2662 }
2663 } else if(is_mk && *ptr == ':' && ptr + 1 < data->path + data->path_len && *(ptr + 1) == ':') {
2664 flags &= ~Uri_CREATE_FILE_USE_DOS_PATH;
2665 } else if(known_scheme && is_ascii(*ptr) && !is_unreserved(*ptr) && !is_reserved(*ptr) &&
2666 !(flags & Uri_CREATE_NO_ENCODE_FORBIDDEN_CHARACTERS)) {
2667 if(!(is_file && (flags & Uri_CREATE_FILE_USE_DOS_PATH))) {
2668 if(!computeOnly)
2669 pct_encode_val(*ptr, uri->canon_uri+uri->canon_len);
2670 uri->canon_len += 3;
2671 do_default_action = FALSE;
2672 }
2673 }
2674
2675 if(do_default_action) {
2676 if(!computeOnly)
2677 uri->canon_uri[uri->canon_len] = *ptr;
2678 ++uri->canon_len;
2679 }
2680 }
2681
2682 if(is_mk && !computeOnly && !(flags & Uri_CREATE_NO_CANONICALIZE)) {
2683 DWORD new_len = remove_dot_segments(uri->canon_uri + uri->path_start,
2684 uri->canon_len - uri->path_start);
2685 uri->canon_len = uri->path_start + new_len;
2686 }
2687
2688 uri->path_len = uri->canon_len - uri->path_start;
2689
2690 if(!computeOnly)
2691 TRACE("(%p %p %lx %d): Canonicalized opaque URI path %s len=%ld\n", data, uri, flags, computeOnly,
2692 debugstr_wn(uri->canon_uri+uri->path_start, uri->path_len), uri->path_len);
2693 return TRUE;
2694}
2695
2696/* Determines how the URI represented by the parse_data should be canonicalized.
2697 *
2698 * Essentially, if the parse_data represents an hierarchical URI then it calls
2699 * canonicalize_authority and the canonicalization functions for the path. If the
2700 * URI is opaque it canonicalizes the path of the URI.
2701 */
2703 if(!data->is_opaque || (data->is_relative && (data->password || data->username))) {
2704 /* "//" is only added for non-wildcard scheme types.
2705 *
2706 * A "//" is only added to a relative URI if it has a
2707 * host or port component (this only happens if a IUriBuilder
2708 * is generating an IUri).
2709 */
2710 if((data->is_relative && (data->host || data->has_port)) ||
2711 (!data->is_relative && data->scheme_type != URL_SCHEME_WILDCARD)) {
2712 if(data->scheme_type == URL_SCHEME_WILDCARD)
2713 FIXME("Here\n");
2714
2715 if(!computeOnly) {
2716 INT pos = uri->canon_len;
2717
2718 uri->canon_uri[pos] = '/';
2719 uri->canon_uri[pos+1] = '/';
2720 }
2721 uri->canon_len += 2;
2722 }
2723
2724 if(!canonicalize_authority(data, uri, flags, computeOnly))
2725 return FALSE;
2726
2727 if(data->is_relative && (data->password || data->username)) {
2728 if(!canonicalize_path_opaque(data, uri, flags, computeOnly))
2729 return FALSE;
2730 } else {
2731 if(!computeOnly)
2732 uri->path_start = uri->canon_len;
2733 uri->path_len = canonicalize_path_hierarchical(data->path, data->path_len, data->scheme_type, data->host_len != 0,
2734 flags, data->has_implicit_scheme, computeOnly ? NULL : uri->canon_uri+uri->canon_len);
2735 uri->canon_len += uri->path_len;
2736 if(!computeOnly && !uri->path_len)
2737 uri->path_start = -1;
2738 }
2739 } else {
2740 /* Opaque URI's don't have an authority. */
2741 uri->userinfo_start = uri->userinfo_split = -1;
2742 uri->userinfo_len = 0;
2743 uri->host_start = -1;
2744 uri->host_len = 0;
2745 uri->host_type = Uri_HOST_UNKNOWN;
2746 uri->has_port = FALSE;
2747 uri->authority_start = -1;
2748 uri->authority_len = 0;
2749 uri->domain_offset = -1;
2750 uri->port_offset = -1;
2751
2752 if(is_hierarchical_scheme(data->scheme_type)) {
2753 DWORD i;
2754
2755 /* Absolute URIs aren't displayed for known scheme types
2756 * which should be hierarchical URIs.
2757 */
2758 uri->display_modifiers |= URI_DISPLAY_NO_ABSOLUTE_URI;
2759
2760 /* Windows also sets the port for these (if they have one). */
2761 for(i = 0; i < ARRAY_SIZE(default_ports); ++i) {
2762 if(data->scheme_type == default_ports[i].scheme) {
2763 uri->has_port = TRUE;
2764 uri->port = default_ports[i].port;
2765 break;
2766 }
2767 }
2768 }
2769
2770 if(!canonicalize_path_opaque(data, uri, flags, computeOnly))
2771 return FALSE;
2772 }
2773
2774 if(uri->path_start > -1 && !computeOnly)
2775 /* Finding file extensions happens for both types of URIs. */
2776 uri->extension_offset = find_file_extension(uri->canon_uri+uri->path_start, uri->path_len);
2777 else
2778 uri->extension_offset = -1;
2779
2780 return TRUE;
2781}
2782
2783/* Attempts to canonicalize the query string of the URI.
2784 *
2785 * Things that happen:
2786 * 1) For known scheme types forbidden characters
2787 * are percent encoded, unless the NO_DECODE_EXTRA_INFO flag is set
2788 * or NO_ENCODE_FORBIDDEN_CHARACTERS is set.
2789 *
2790 * 2) For known scheme types, percent encoded, unreserved characters
2791 * are decoded as long as the NO_DECODE_EXTRA_INFO flag isn't set.
2792 */
2793static BOOL canonicalize_query(const parse_data *data, Uri *uri, DWORD flags, BOOL computeOnly) {
2794 const WCHAR *ptr, *end;
2795 const BOOL known_scheme = data->scheme_type != URL_SCHEME_UNKNOWN;
2796
2797 if(!data->query) {
2798 uri->query_start = -1;
2799 uri->query_len = 0;
2800 return TRUE;
2801 }
2802
2803 uri->query_start = uri->canon_len;
2804
2805 end = data->query+data->query_len;
2806 for(ptr = data->query; ptr < end; ++ptr) {
2807 if(*ptr == '%') {
2808 if(known_scheme && !(flags & Uri_CREATE_NO_DECODE_EXTRA_INFO)) {
2810 if(is_unreserved(val)) {
2811 if(!computeOnly)
2812 uri->canon_uri[uri->canon_len] = val;
2813 ++uri->canon_len;
2814
2815 ptr += 2;
2816 continue;
2817 }
2818 }
2819 } else if(known_scheme && is_ascii(*ptr) && !is_unreserved(*ptr) && !is_reserved(*ptr)) {
2820 if(!(flags & Uri_CREATE_NO_ENCODE_FORBIDDEN_CHARACTERS) &&
2821 !(flags & Uri_CREATE_NO_DECODE_EXTRA_INFO)) {
2822 if(!computeOnly)
2823 pct_encode_val(*ptr, uri->canon_uri+uri->canon_len);
2824 uri->canon_len += 3;
2825 continue;
2826 }
2827 }
2828
2829 if(!computeOnly)
2830 uri->canon_uri[uri->canon_len] = *ptr;
2831 ++uri->canon_len;
2832 }
2833
2834 uri->query_len = uri->canon_len - uri->query_start;
2835
2836 if(!computeOnly)
2837 TRACE("(%p %p %lx %d): Canonicalized query string %s len=%ld\n", data, uri, flags,
2838 computeOnly, debugstr_wn(uri->canon_uri+uri->query_start, uri->query_len),
2839 uri->query_len);
2840 return TRUE;
2841}
2842
2844 const WCHAR *ptr, *end;
2845 const BOOL known_scheme = data->scheme_type != URL_SCHEME_UNKNOWN;
2846
2847 if(!data->fragment) {
2848 uri->fragment_start = -1;
2849 uri->fragment_len = 0;
2850 return TRUE;
2851 }
2852
2853 uri->fragment_start = uri->canon_len;
2854
2855 end = data->fragment + data->fragment_len;
2856 for(ptr = data->fragment; ptr < end; ++ptr) {
2857 if(*ptr == '%') {
2858 if(known_scheme && !(flags & Uri_CREATE_NO_DECODE_EXTRA_INFO)) {
2860 if(is_unreserved(val)) {
2861 if(!computeOnly)
2862 uri->canon_uri[uri->canon_len] = val;
2863 ++uri->canon_len;
2864
2865 ptr += 2;
2866 continue;
2867 }
2868 }
2869 } else if(known_scheme && is_ascii(*ptr) && !is_unreserved(*ptr) && !is_reserved(*ptr)) {
2870 if(!(flags & Uri_CREATE_NO_ENCODE_FORBIDDEN_CHARACTERS) &&
2871 !(flags & Uri_CREATE_NO_DECODE_EXTRA_INFO)) {
2872 if(!computeOnly)
2873 pct_encode_val(*ptr, uri->canon_uri+uri->canon_len);
2874 uri->canon_len += 3;
2875 continue;
2876 }
2877 }
2878
2879 if(!computeOnly)
2880 uri->canon_uri[uri->canon_len] = *ptr;
2881 ++uri->canon_len;
2882 }
2883
2884 uri->fragment_len = uri->canon_len - uri->fragment_start;
2885
2886 if(!computeOnly)
2887 TRACE("(%p %p %lx %d): Canonicalized fragment %s len=%ld\n", data, uri, flags,
2888 computeOnly, debugstr_wn(uri->canon_uri+uri->fragment_start, uri->fragment_len),
2889 uri->fragment_len);
2890 return TRUE;
2891}
2892
2893/* Canonicalizes the scheme information specified in the parse_data using the specified flags. */
2895 uri->scheme_start = -1;
2896 uri->scheme_len = 0;
2897
2898 if(!data->scheme) {
2899 /* The only type of URI that doesn't have to have a scheme is a relative
2900 * URI.
2901 */
2902 if(!data->is_relative) {
2903 FIXME("(%p %p %lx): Unable to determine the scheme type of %s.\n", data,
2904 uri, flags, debugstr_w(data->uri));
2905 return FALSE;
2906 }
2907 } else {
2908 if(!computeOnly) {
2909 DWORD i;
2910 INT pos = uri->canon_len;
2911
2912 for(i = 0; i < data->scheme_len; ++i) {
2913 /* Scheme name must be lower case after canonicalization. */
2914 uri->canon_uri[i + pos] = towlower(data->scheme[i]);
2915 }
2916
2917 uri->canon_uri[i + pos] = ':';
2918 uri->scheme_start = pos;
2919
2920 TRACE("(%p %p %lx): Canonicalized scheme=%s, len=%ld.\n", data, uri, flags,
2921 debugstr_wn(uri->canon_uri+uri->scheme_start, data->scheme_len), data->scheme_len);
2922 }
2923
2924 /* This happens in both computation modes. */
2925 uri->canon_len += data->scheme_len + 1;
2926 uri->scheme_len = data->scheme_len;
2927 }
2928 return TRUE;
2929}
2930
2931/* Computes what the length of the URI specified by the parse_data will be
2932 * after canonicalization occurs using the specified flags.
2933 *
2934 * This function will return a non-zero value indicating the length of the canonicalized
2935 * URI, or -1 on error.
2936 */
2938 Uri uri;
2939
2940 memset(&uri, 0, sizeof(Uri));
2941
2942 TRACE("(%p %lx): Beginning to compute canonicalized length for URI %s\n", data, flags,
2943 debugstr_w(data->uri));
2944
2946 ERR("(%p %lx): Failed to compute URI scheme length.\n", data, flags);
2947 return -1;
2948 }
2949
2951 ERR("(%p %lx): Failed to compute URI hierpart length.\n", data, flags);
2952 return -1;
2953 }
2954
2956 ERR("(%p %lx): Failed to compute query string length.\n", data, flags);
2957 return -1;
2958 }
2959
2961 ERR("(%p %lx): Failed to compute fragment length.\n", data, flags);
2962 return -1;
2963 }
2964
2965 TRACE("(%p %lx): Finished computing canonicalized URI length. length=%ld\n", data, flags, uri.canon_len);
2966
2967 return uri.canon_len;
2968}
2969
2970/* Canonicalizes the URI data specified in the parse_data, using the given flags. If the
2971 * canonicalization succeeds it will store all the canonicalization information
2972 * in the pointer to the Uri.
2973 *
2974 * To canonicalize a URI this function first computes what the length of the URI
2975 * specified by the parse_data will be. Once this is done it will then perform the actual
2976 * canonicalization of the URI.
2977 */
2979 INT len;
2980
2981 uri->canon_uri = NULL;
2982 uri->canon_size = uri->canon_len = 0;
2983
2984 TRACE("(%p %p %lx): beginning to canonicalize URI %s.\n", data, uri, flags, debugstr_w(data->uri));
2985
2986 /* First try to compute the length of the URI. */
2988 if(len == -1) {
2989 ERR("(%p %p %lx): Could not compute the canonicalized length of %s.\n", data, uri, flags,
2990 debugstr_w(data->uri));
2991 return E_INVALIDARG;
2992 }
2993
2994 uri->canon_uri = malloc((len + 1) * sizeof(WCHAR));
2995 if(!uri->canon_uri)
2996 return E_OUTOFMEMORY;
2997
2998 uri->canon_size = len;
3000 ERR("(%p %p %lx): Unable to canonicalize the scheme of the URI.\n", data, uri, flags);
3001 return E_INVALIDARG;
3002 }
3003 uri->scheme_type = data->scheme_type;
3004
3006 ERR("(%p %p %lx): Unable to canonicalize the hierpart of the URI\n", data, uri, flags);
3007 return E_INVALIDARG;
3008 }
3009
3011 ERR("(%p %p %lx): Unable to canonicalize query string of the URI.\n",
3012 data, uri, flags);
3013 return E_INVALIDARG;
3014 }
3015
3017 ERR("(%p %p %lx): Unable to canonicalize fragment of the URI.\n",
3018 data, uri, flags);
3019 return E_INVALIDARG;
3020 }
3021
3022 /* There's a possibility we didn't use all the space we allocated
3023 * earlier.
3024 */
3025 if(uri->canon_len < uri->canon_size) {
3026 /* This happens if the URI is hierarchical and dot
3027 * segments were removed from its path.
3028 */
3029 WCHAR *tmp = realloc(uri->canon_uri, (uri->canon_len + 1) * sizeof(WCHAR));
3030 if(!tmp)
3031 return E_OUTOFMEMORY;
3032
3033 uri->canon_uri = tmp;
3034 uri->canon_size = uri->canon_len;
3035 }
3036
3037 uri->canon_uri[uri->canon_len] = '\0';
3038 TRACE("(%p %p %lx): finished canonicalizing the URI. uri=%s\n", data, uri, flags, debugstr_w(uri->canon_uri));
3039
3040 return S_OK;
3041}
3042
3043static HRESULT get_builder_component(LPWSTR *component, DWORD *component_len,
3044 LPCWSTR source, DWORD source_len,
3045 LPCWSTR *output, DWORD *output_len)
3046{
3047 if(!output_len) {
3048 if(output)
3049 *output = NULL;
3050 return E_POINTER;
3051 }
3052
3053 if(!output) {
3054 *output_len = 0;
3055 return E_POINTER;
3056 }
3057
3058 if(!(*component) && source) {
3059 /* Allocate 'component', and copy the contents from 'source'
3060 * into the new allocation.
3061 */
3062 *component = malloc((source_len + 1) * sizeof(WCHAR));
3063 if(!(*component))
3064 return E_OUTOFMEMORY;
3065
3066 memcpy(*component, source, source_len*sizeof(WCHAR));
3067 (*component)[source_len] = '\0';
3068 *component_len = source_len;
3069 }
3070
3071 *output = *component;
3072 *output_len = *component_len;
3073 return *output ? S_OK : S_FALSE;
3074}
3075
3076/* Allocates 'component' and copies the string from 'new_value' into 'component'.
3077 * If 'prefix' is set and 'new_value' isn't NULL, then it checks if 'new_value'
3078 * starts with 'prefix'. If it doesn't then 'prefix' is prepended to 'component'.
3079 *
3080 * If everything is successful, then will set 'success_flag' in 'flags'.
3081 */
3082static HRESULT set_builder_component(LPWSTR *component, DWORD *component_len, LPCWSTR new_value,
3083 WCHAR prefix, DWORD *flags, DWORD success_flag)
3084{
3085 free(*component);
3086
3087 if(!new_value) {
3088 *component = NULL;
3089 *component_len = 0;
3090 } else {
3091 BOOL add_prefix = FALSE;
3092 DWORD len = lstrlenW(new_value);
3093 DWORD pos = 0;
3094
3095 if(prefix && *new_value != prefix) {
3096 add_prefix = TRUE;
3097 *component = malloc((len + 2) * sizeof(WCHAR));
3098 } else
3099 *component = malloc((len + 1) * sizeof(WCHAR));
3100
3101 if(!(*component))
3102 return E_OUTOFMEMORY;
3103
3104 if(add_prefix)
3105 (*component)[pos++] = prefix;
3106
3107 memcpy(*component+pos, new_value, (len+1)*sizeof(WCHAR));
3108 *component_len = len+pos;
3109 }
3110
3111 *flags |= success_flag;
3112 return S_OK;
3113}
3114
3115static void reset_builder(UriBuilder *builder) {
3116 if(builder->uri)
3117 IUri_Release(&builder->uri->IUri_iface);
3118 builder->uri = NULL;
3119
3120 free(builder->fragment);
3121 builder->fragment = NULL;
3122 builder->fragment_len = 0;
3123
3124 free(builder->host);
3125 builder->host = NULL;
3126 builder->host_len = 0;
3127
3128 free(builder->password);
3129 builder->password = NULL;
3130 builder->password_len = 0;
3131
3132 free(builder->path);
3133 builder->path = NULL;
3134 builder->path_len = 0;
3135
3136 free(builder->query);
3137 builder->query = NULL;
3138 builder->query_len = 0;
3139
3140 free(builder->scheme);
3141 builder->scheme = NULL;
3142 builder->scheme_len = 0;
3143
3144 free(builder->username);
3145 builder->username = NULL;
3146 builder->username_len = 0;
3147
3148 builder->has_port = FALSE;
3149 builder->port = 0;
3150 builder->modified_props = 0;
3151}
3152
3154 const WCHAR *component;
3155 const WCHAR *ptr;
3156 const WCHAR **pptr;
3157 DWORD expected_len;
3158
3159 if(builder->scheme) {
3160 ptr = builder->scheme;
3161 expected_len = builder->scheme_len;
3162 } else if(builder->uri && builder->uri->scheme_start > -1) {
3163 ptr = builder->uri->canon_uri+builder->uri->scheme_start;
3164 expected_len = builder->uri->scheme_len;
3165 } else {
3166 ptr = L"";
3167 expected_len = 0;
3168 }
3169
3170 component = ptr;
3171 pptr = &ptr;
3173 data->scheme_len == expected_len) {
3174 if(data->scheme)
3175 TRACE("(%p %p %lx): Found valid scheme component %s len=%ld.\n", builder, data, flags,
3176 debugstr_wn(data->scheme, data->scheme_len), data->scheme_len);
3177 } else {
3178 TRACE("(%p %p %lx): Invalid scheme component found %s.\n", builder, data, flags,
3179 debugstr_wn(component, expected_len));
3180 return INET_E_INVALID_URL;
3181 }
3182
3183 return S_OK;
3184}
3185
3187 const WCHAR *ptr;
3188 const WCHAR **pptr;
3189 DWORD expected_len;
3190
3191 if(builder->username) {
3192 ptr = builder->username;
3193 expected_len = builder->username_len;
3194 } else if(!(builder->modified_props & Uri_HAS_USER_NAME) && builder->uri &&
3195 builder->uri->userinfo_start > -1 && builder->uri->userinfo_split != 0) {
3196 /* Just use the username from the base Uri. */
3197 data->username = builder->uri->canon_uri+builder->uri->userinfo_start;
3198 data->username_len = (builder->uri->userinfo_split > -1) ?
3199 builder->uri->userinfo_split : builder->uri->userinfo_len;
3200 ptr = NULL;
3201 } else {
3202 ptr = NULL;
3203 expected_len = 0;
3204 }
3205
3206 if(ptr) {
3207 const WCHAR *component = ptr;
3208 pptr = &ptr;
3210 data->username_len == expected_len)
3211 TRACE("(%p %p %lx): Found valid username component %s len=%ld.\n", builder, data, flags,
3212 debugstr_wn(data->username, data->username_len), data->username_len);
3213 else {
3214 TRACE("(%p %p %lx): Invalid username component found %s.\n", builder, data, flags,
3215 debugstr_wn(component, expected_len));
3216 return INET_E_INVALID_URL;
3217 }
3218 }
3219
3220 return S_OK;
3221}
3222
3224 const WCHAR *ptr;
3225 const WCHAR **pptr;
3226 DWORD expected_len;
3227
3228 if(builder->password) {
3229 ptr = builder->password;
3230 expected_len = builder->password_len;
3231 } else if(!(builder->modified_props & Uri_HAS_PASSWORD) && builder->uri &&
3232 builder->uri->userinfo_split > -1) {
3233 data->password = builder->uri->canon_uri+builder->uri->userinfo_start+builder->uri->userinfo_split+1;
3234 data->password_len = builder->uri->userinfo_len-builder->uri->userinfo_split-1;
3235 ptr = NULL;
3236 } else {
3237 ptr = NULL;
3238 expected_len = 0;
3239 }
3240
3241 if(ptr) {
3242 const WCHAR *component = ptr;
3243 pptr = &ptr;
3245 data->password_len == expected_len)
3246 TRACE("(%p %p %lx): Found valid password component %s len=%ld.\n", builder, data, flags,
3247 debugstr_wn(data->password, data->password_len), data->password_len);
3248 else {
3249 TRACE("(%p %p %lx): Invalid password component found %s.\n", builder, data, flags,
3250 debugstr_wn(component, expected_len));
3251 return INET_E_INVALID_URL;
3252 }
3253 }
3254
3255 return S_OK;
3256}
3257
3259 HRESULT hr;
3260
3261 hr = validate_username(builder, data, flags);
3262 if(FAILED(hr))
3263 return hr;
3264
3265 hr = validate_password(builder, data, flags);
3266 if(FAILED(hr))
3267 return hr;
3268
3269 return S_OK;
3270}
3271
3273 const WCHAR *ptr;
3274 const WCHAR **pptr;
3275 DWORD expected_len;
3276
3277 if(builder->host) {
3278 ptr = builder->host;
3279 expected_len = builder->host_len;
3280 } else if(!(builder->modified_props & Uri_HAS_HOST) && builder->uri && builder->uri->host_start > -1) {
3281 ptr = builder->uri->canon_uri + builder->uri->host_start;
3282 expected_len = builder->uri->host_len;
3283 } else
3284 ptr = NULL;
3285
3286 if(ptr) {
3287 const WCHAR *component = ptr;
3289 pptr = &ptr;
3290
3291 if(parse_host(pptr, data, extras) && data->host_len == expected_len)
3292 TRACE("(%p %p): Found valid host name %s len=%ld type=%d.\n", builder, data,
3293 debugstr_wn(data->host, data->host_len), data->host_len, data->host_type);
3294 else {
3295 TRACE("(%p %p): Invalid host name found %s.\n", builder, data,
3296 debugstr_wn(component, expected_len));
3297 return INET_E_INVALID_URL;
3298 }
3299 }
3300
3301 return S_OK;
3302}
3303
3304static void setup_port(const UriBuilder *builder, parse_data *data, DWORD flags) {
3305 if(builder->modified_props & Uri_HAS_PORT) {
3306 if(builder->has_port) {
3307 data->has_port = TRUE;
3308 data->port_value = builder->port;
3309 }
3310 } else if(builder->uri && builder->uri->has_port) {
3311 data->has_port = TRUE;
3312 data->port_value = builder->uri->port;
3313 }
3314
3315 if(data->has_port)
3316 TRACE("(%p %p %lx): Using %lu as port for IUri.\n", builder, data, flags, data->port_value);
3317}
3318
3320 const WCHAR *ptr = NULL;
3321 const WCHAR *component;
3322 const WCHAR **pptr;
3323 DWORD expected_len;
3324 BOOL check_len = TRUE;
3325 BOOL valid = FALSE;
3326
3327 if(builder->path) {
3328 ptr = builder->path;
3329 expected_len = builder->path_len;
3330 } else if(!(builder->modified_props & Uri_HAS_PATH) &&
3331 builder->uri && builder->uri->path_start > -1) {
3332 ptr = builder->uri->canon_uri+builder->uri->path_start;
3333 expected_len = builder->uri->path_len;
3334 } else {
3335 ptr = L"";
3336 check_len = FALSE;
3337 expected_len = -1;
3338 }
3339
3340 component = ptr;
3341 pptr = &ptr;
3342
3343 /* How the path is validated depends on what type of
3344 * URI it is.
3345 */
3346 valid = data->is_opaque ?
3348
3349 if(!valid || (check_len && expected_len != data->path_len)) {
3350 TRACE("(%p %p %lx): Invalid path component %s.\n", builder, data, flags,
3351 debugstr_wn(component, expected_len) );
3352 return INET_E_INVALID_URL;
3353 }
3354
3355 TRACE("(%p %p %lx): Valid path component %s len=%ld.\n", builder, data, flags,
3356 debugstr_wn(data->path, data->path_len), data->path_len);
3357
3358 return S_OK;
3359}
3360
3362 const WCHAR *ptr = NULL;
3363 const WCHAR **pptr;
3364 DWORD expected_len;
3365
3366 if(builder->query) {
3367 ptr = builder->query;
3368 expected_len = builder->query_len;
3369 } else if(!(builder->modified_props & Uri_HAS_QUERY) && builder->uri &&
3370 builder->uri->query_start > -1) {
3371 ptr = builder->uri->canon_uri+builder->uri->query_start;
3372 expected_len = builder->uri->query_len;
3373 }
3374
3375 if(ptr) {
3376 const WCHAR *component = ptr;
3377 pptr = &ptr;
3378
3379 if(parse_query(pptr, data, flags) && expected_len == data->query_len)
3380 TRACE("(%p %p %lx): Valid query component %s len=%ld.\n", builder, data, flags,
3381 debugstr_wn(data->query, data->query_len), data->query_len);
3382 else {
3383 TRACE("(%p %p %lx): Invalid query component %s.\n", builder, data, flags,
3384 debugstr_wn(component, expected_len));
3385 return INET_E_INVALID_URL;
3386 }
3387 }
3388
3389 return S_OK;
3390}
3391
3393 const WCHAR *ptr = NULL;
3394 const WCHAR **pptr;
3395 DWORD expected_len;
3396
3397 if(builder->fragment) {
3398 ptr = builder->fragment;
3399 expected_len = builder->fragment_len;
3400 } else if(!(builder->modified_props & Uri_HAS_FRAGMENT) && builder->uri &&
3401 builder->uri->fragment_start > -1) {
3402 ptr = builder->uri->canon_uri+builder->uri->fragment_start;
3403 expected_len = builder->uri->fragment_len;
3404 }
3405
3406 if(ptr) {
3407 const WCHAR *component = ptr;
3408 pptr = &ptr;
3409
3410 if(parse_fragment(pptr, data, flags) && expected_len == data->fragment_len)
3411 TRACE("(%p %p %lx): Valid fragment component %s len=%ld.\n", builder, data, flags,
3412 debugstr_wn(data->fragment, data->fragment_len), data->fragment_len);
3413 else {
3414 TRACE("(%p %p %lx): Invalid fragment component %s.\n", builder, data, flags,
3415 debugstr_wn(component, expected_len));
3416 return INET_E_INVALID_URL;
3417 }
3418 }
3419
3420 return S_OK;
3421}
3422
3424 HRESULT hr;
3425
3426 memset(data, 0, sizeof(parse_data));
3427
3428 TRACE("(%p %p %lx): Beginning to validate builder components.\n", builder, data, flags);
3429
3430 hr = validate_scheme_name(builder, data, flags);
3431 if(FAILED(hr))
3432 return hr;
3433
3434 /* Extra validation for file schemes. */
3435 if(data->scheme_type == URL_SCHEME_FILE) {
3436 if((builder->password || (builder->uri && builder->uri->userinfo_split > -1)) ||
3437 (builder->username || (builder->uri && builder->uri->userinfo_start > -1))) {
3438 TRACE("(%p %p %lx): File schemes can't contain a username or password.\n",
3439 builder, data, flags);
3440 return INET_E_INVALID_URL;
3441 }
3442 }
3443
3444 hr = validate_userinfo(builder, data, flags);
3445 if(FAILED(hr))
3446 return hr;
3447
3448 hr = validate_host(builder, data);
3449 if(FAILED(hr))
3450 return hr;
3451
3452 setup_port(builder, data, flags);
3453
3454 /* The URI is opaque if it doesn't have an authority component. */
3455 if(!data->is_relative)
3456 data->is_opaque = !data->username && !data->password && !data->host && !data->has_port
3457 && data->scheme_type != URL_SCHEME_FILE;
3458 else
3459 data->is_opaque = !data->host && !data->has_port;
3460
3461 hr = validate_path(builder, data, flags);
3462 if(FAILED(hr))
3463 return hr;
3464
3465 hr = validate_query(builder, data, flags);
3466 if(FAILED(hr))
3467 return hr;
3468
3469 hr = validate_fragment(builder, data, flags);
3470 if(FAILED(hr))
3471 return hr;
3472
3473 TRACE("(%p %p %lx): Finished validating builder components.\n", builder, data, flags);
3474
3475 return S_OK;
3476}
3477
3478static HRESULT compare_file_paths(const Uri *a, const Uri *b, BOOL *ret)
3479{
3480 WCHAR *canon_path_a, *canon_path_b;
3481 DWORD len_a, len_b;
3482
3483 if(!a->path_len) {
3484 *ret = !b->path_len;
3485 return S_OK;
3486 }
3487
3488 if(!b->path_len) {
3489 *ret = FALSE;
3490 return S_OK;
3491 }
3492
3493 /* Fast path */
3494 if(a->path_len == b->path_len && !wcsnicmp(a->canon_uri+a->path_start, b->canon_uri+b->path_start, a->path_len)) {
3495 *ret = TRUE;
3496 return S_OK;
3497 }
3498
3499 len_a = canonicalize_path_hierarchical(a->canon_uri+a->path_start, a->path_len, a->scheme_type, FALSE, 0, FALSE, NULL);
3500 len_b = canonicalize_path_hierarchical(b->canon_uri+b->path_start, b->path_len, b->scheme_type, FALSE, 0, FALSE, NULL);
3501
3502 canon_path_a = malloc(len_a * sizeof(WCHAR));
3503 if(!canon_path_a)
3504 return E_OUTOFMEMORY;
3505 canon_path_b = malloc(len_b * sizeof(WCHAR));
3506 if(!canon_path_b) {
3507 free(canon_path_a);
3508 return E_OUTOFMEMORY;
3509 }
3510
3511 len_a = canonicalize_path_hierarchical(a->canon_uri+a->path_start, a->path_len, a->scheme_type, FALSE, 0, FALSE, canon_path_a);
3512 len_b = canonicalize_path_hierarchical(b->canon_uri+b->path_start, b->path_len, b->scheme_type, FALSE, 0, FALSE, canon_path_b);
3513
3514 *ret = len_a == len_b && !wcsnicmp(canon_path_a, canon_path_b, len_a);
3515
3516 free(canon_path_a);
3517 free(canon_path_b);
3518 return S_OK;
3519}
3520
3521/* Checks if the two Uri's are logically equivalent. It's a simple
3522 * comparison, since they are both of type Uri, and it can access
3523 * the properties of each Uri directly without the need to go
3524 * through the "IUri_Get*" interface calls.
3525 */
3526static HRESULT compare_uris(const Uri *a, const Uri *b, BOOL *ret) {
3527 const BOOL known_scheme = a->scheme_type != URL_SCHEME_UNKNOWN;
3528 const BOOL are_hierarchical = a->authority_start > -1 && b->authority_start > -1;
3529 HRESULT hres;
3530
3531 *ret = FALSE;
3532
3533 if(a->scheme_type != b->scheme_type)
3534 return S_OK;
3535
3536 /* Only compare the scheme names (if any) if their unknown scheme types. */
3537 if(!known_scheme) {
3538 if((a->scheme_start > -1 && b->scheme_start > -1) &&
3539 (a->scheme_len == b->scheme_len)) {
3540 /* Make sure the schemes are the same. */
3541 if(StrCmpNW(a->canon_uri+a->scheme_start, b->canon_uri+b->scheme_start, a->scheme_len))
3542 return S_OK;
3543 } else if(a->scheme_len != b->scheme_len)
3544 /* One of the Uri's has a scheme name, while the other doesn't. */
3545 return S_OK;
3546 }
3547
3548 /* If they have a userinfo component, perform case sensitive compare. */
3549 if((a->userinfo_start > -1 && b->userinfo_start > -1) &&
3550 (a->userinfo_len == b->userinfo_len)) {
3551 if(StrCmpNW(a->canon_uri+a->userinfo_start, b->canon_uri+b->userinfo_start, a->userinfo_len))
3552 return S_OK;
3553 } else if(a->userinfo_len != b->userinfo_len)
3554 /* One of the Uri's had a userinfo, while the other one doesn't. */
3555 return S_OK;
3556
3557 /* Check if they have a host name. */
3558 if((a->host_start > -1 && b->host_start > -1) &&
3559 (a->host_len == b->host_len)) {
3560 /* Perform a case insensitive compare if they are a known scheme type. */
3561 if(known_scheme) {
3562 if(StrCmpNIW(a->canon_uri+a->host_start, b->canon_uri+b->host_start, a->host_len))
3563 return S_OK;
3564 } else if(StrCmpNW(a->canon_uri+a->host_start, b->canon_uri+b->host_start, a->host_len))
3565 return S_OK;
3566 } else if(a->host_len != b->host_len)
3567 /* One of the Uri's had a host, while the other one didn't. */
3568 return S_OK;
3569
3570 if(a->has_port && b->has_port) {
3571 if(a->port != b->port)
3572 return S_OK;
3573 } else if(a->has_port || b->has_port)
3574 /* One had a port, while the other one didn't. */
3575 return S_OK;
3576
3577 /* Windows is weird with how it handles paths. For example
3578 * One URI could be "http://google.com" (after canonicalization)
3579 * and one could be "http://google.com/" and the IsEqual function
3580 * would still evaluate to TRUE, but, only if they are both hierarchical
3581 * URIs.
3582 */
3583 if(a->scheme_type == URL_SCHEME_FILE) {
3584 BOOL cmp;
3585
3587 if(FAILED(hres) || !cmp)
3588 return hres;
3589 } else if((a->path_start > -1 && b->path_start > -1) &&
3590 (a->path_len == b->path_len)) {
3591 if(StrCmpNW(a->canon_uri+a->path_start, b->canon_uri+b->path_start, a->path_len))
3592 return S_OK;
3593 } else if(are_hierarchical && a->path_len == -1 && b->path_len == 0) {
3594 if(*(a->canon_uri+a->path_start) != '/')
3595 return S_OK;
3596 } else if(are_hierarchical && b->path_len == 1 && a->path_len == 0) {
3597 if(*(b->canon_uri+b->path_start) != '/')
3598 return S_OK;
3599 } else if(a->path_len != b->path_len)
3600 return S_OK;
3601
3602 /* Compare the query strings of the two URIs. */
3603 if((a->query_start > -1 && b->query_start > -1) &&
3604 (a->query_len == b->query_len)) {
3605 if(StrCmpNW(a->canon_uri+a->query_start, b->canon_uri+b->query_start, a->query_len))
3606 return S_OK;
3607 } else if(a->query_len != b->query_len)
3608 return S_OK;
3609
3610 if((a->fragment_start > -1 && b->fragment_start > -1) &&
3611 (a->fragment_len == b->fragment_len)) {
3612 if(StrCmpNW(a->canon_uri+a->fragment_start, b->canon_uri+b->fragment_start, a->fragment_len))
3613 return S_OK;
3614 } else if(a->fragment_len != b->fragment_len)
3615 return S_OK;
3616
3617 /* If we get here, the two URIs are equivalent. */
3618 *ret = TRUE;
3619 return S_OK;
3620}
3621
3623 WCHAR *output, DWORD *output_len)
3624{
3625 const WCHAR *ptr = path;
3626
3627 if(path_len > 3 && *ptr == '/' && is_drive_path(path+1))
3628 /* Skip over the leading / before the drive path. */
3629 ++ptr;
3630
3631 for(; ptr < path+path_len; ++ptr) {
3632 if(*ptr == '/') {
3633 if(output)
3634 *output++ = '\\';
3635 (*output_len)++;
3636 } else {
3637 if(output)
3638 *output++ = *ptr;
3639 (*output_len)++;
3640 }
3641 }
3642}
3643
3644/* Generates a raw uri string using the parse_data. */
3646 DWORD length = 0;
3647
3648 if(data->scheme) {
3649 if(uri) {
3650 memcpy(uri, data->scheme, data->scheme_len*sizeof(WCHAR));
3651 uri[data->scheme_len] = ':';
3652 }
3653 length += data->scheme_len+1;
3654 }
3655
3656 if(!data->is_opaque) {
3657 /* For the "//" which appears before the authority component. */
3658 if(uri) {
3659 uri[length] = '/';
3660 uri[length+1] = '/';
3661 }
3662 length += 2;
3663
3664 /* Check if we need to add the "\\" before the host name
3665 * of a UNC server name in a DOS path.
3666 */
3668 data->scheme_type == URL_SCHEME_FILE && data->host) {
3669 if(uri) {
3670 uri[length] = '\\';
3671 uri[length+1] = '\\';
3672 }
3673 length += 2;
3674 }
3675 }
3676
3677 if(data->username) {
3678 if(uri)
3679 memcpy(uri+length, data->username, data->username_len*sizeof(WCHAR));
3680 length += data->username_len;
3681 }
3682
3683 if(data->password) {
3684 if(uri) {
3685 uri[length] = ':';
3686 memcpy(uri+length+1, data->password, data->password_len*sizeof(WCHAR));
3687 }
3688 length += data->password_len+1;
3689 }
3690
3691 if(data->password || data->username) {
3692 if(uri)
3693 uri[length] = '@';
3694 ++length;
3695 }
3696
3697 if(data->host) {
3698 /* IPv6 addresses get the brackets added around them if they don't already
3699 * have them.
3700 */
3701 const BOOL add_brackets = data->host_type == Uri_HOST_IPV6 && *(data->host) != '[';
3702 if(add_brackets) {
3703 if(uri)
3704 uri[length] = '[';
3705 ++length;
3706 }
3707
3708 if(uri)
3709 memcpy(uri+length, data->host, data->host_len*sizeof(WCHAR));
3710 length += data->host_len;
3711
3712 if(add_brackets) {
3713 if(uri)
3714 uri[length] = ']';
3715 length++;
3716 }
3717 }
3718
3719 if(data->has_port) {
3720 /* The port isn't included in the raw uri if it's the default
3721 * port for the scheme type.
3722 */
3723 DWORD i;
3724 BOOL is_default = FALSE;
3725
3726 for(i = 0; i < ARRAY_SIZE(default_ports); ++i) {
3727 if(data->scheme_type == default_ports[i].scheme &&
3728 data->port_value == default_ports[i].port)
3729 is_default = TRUE;
3730 }
3731
3732 if(!is_default || flags & RAW_URI_FORCE_PORT_DISP) {
3733 if(uri)
3734 uri[length] = ':';
3735 ++length;
3736
3737 if(uri)
3738 length += ui2str(uri+length, data->port_value);
3739 else
3740 length += ui2str(NULL, data->port_value);
3741 }
3742 }
3743
3744 /* Check if a '/' should be added before the path for hierarchical URIs. */
3745 if(!data->is_opaque && data->path && *(data->path) != '/') {
3746 if(uri)
3747 uri[length] = '/';
3748 ++length;
3749 }
3750
3751 if(data->path) {
3752 if(!data->is_opaque && data->scheme_type == URL_SCHEME_FILE &&
3754 DWORD len = 0;
3755
3756 if(uri)
3757 convert_to_dos_path(data->path, data->path_len, uri+length, &len);
3758 else
3759 convert_to_dos_path(data->path, data->path_len, NULL, &len);
3760
3761 length += len;
3762 } else {
3763 if(uri)
3764 memcpy(uri+length, data->path, data->path_len*sizeof(WCHAR));
3765 length += data->path_len;
3766 }
3767 }
3768
3769 if(data->query) {
3770 if(uri)
3771 memcpy(uri+length, data->query, data->query_len*sizeof(WCHAR));
3772 length += data->query_len;
3773 }
3774
3775 if(data->fragment) {
3776 if(uri)
3777 memcpy(uri+length, data->fragment, data->fragment_len*sizeof(WCHAR));
3778 length += data->fragment_len;
3779 }
3780
3781 if(uri)
3782 TRACE("(%p %p): Generated raw uri=%s len=%ld\n", data, uri, debugstr_wn(uri, length), length);
3783 else
3784 TRACE("(%p %p): Computed raw uri len=%ld\n", data, uri, length);
3785
3786 return length;
3787}
3788
3789static HRESULT generate_uri(const UriBuilder *builder, const parse_data *data, Uri *uri, DWORD flags) {
3790 HRESULT hr;
3792 uri->raw_uri = SysAllocStringLen(NULL, length);
3793 if(!uri->raw_uri)
3794 return E_OUTOFMEMORY;
3795
3796 generate_raw_uri(data, uri->raw_uri, 0);
3797
3799 if(FAILED(hr)) {
3800 if(hr == E_INVALIDARG)
3801 return INET_E_INVALID_URL;
3802 return hr;
3803 }
3804
3805 uri->create_flags = flags;
3806 return S_OK;
3807}
3808
3809static inline Uri* impl_from_IUri(IUri *iface)
3810{
3811 return CONTAINING_RECORD(iface, Uri, IUri_iface);
3812}
3813
3814static inline void destroy_uri_obj(Uri *This)
3815{
3816 SysFreeString(This->raw_uri);
3817 free(This->canon_uri);
3818 free(This);
3819}
3820
3822{
3823 Uri *This = impl_from_IUri(iface);
3824
3826 TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
3827 *ppv = &This->IUri_iface;
3828 }else if(IsEqualGUID(&IID_IUri, riid)) {
3829 TRACE("(%p)->(IID_IUri %p)\n", This, ppv);
3830 *ppv = &This->IUri_iface;
3831 }else if(IsEqualGUID(&IID_IUriBuilderFactory, riid)) {
3832 TRACE("(%p)->(IID_IUriBuilderFactory %p)\n", This, ppv);
3833 *ppv = &This->IUriBuilderFactory_iface;
3834 }else if(IsEqualGUID(&IID_IPersistStream, riid)) {
3835 TRACE("(%p)->(IID_IPersistStream %p)\n", This, ppv);
3836 *ppv = &This->IPersistStream_iface;
3837 }else if(IsEqualGUID(&IID_IMarshal, riid)) {
3838 TRACE("(%p)->(IID_IMarshal %p)\n", This, ppv);
3839 *ppv = &This->IMarshal_iface;
3840 }else if(IsEqualGUID(&IID_IUriObj, riid)) {
3841 TRACE("(%p)->(IID_IUriObj %p)\n", This, ppv);
3842 *ppv = This;
3843 return S_OK;
3844 }else {
3845 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
3846 *ppv = NULL;
3847 return E_NOINTERFACE;
3848 }
3849
3850 IUnknown_AddRef((IUnknown*)*ppv);
3851 return S_OK;
3852}
3853
3855{
3856 Uri *This = impl_from_IUri(iface);
3858
3859 TRACE("(%p) ref=%ld\n", This, ref);
3860
3861 return ref;
3862}
3863
3865{
3866 Uri *This = impl_from_IUri(iface);
3868
3869 TRACE("(%p) ref=%ld\n", This, ref);
3870
3871 if(!ref)
3873
3874 return ref;
3875}
3876
3877static HRESULT WINAPI Uri_GetPropertyBSTR(IUri *iface, Uri_PROPERTY uriProp, BSTR *pbstrProperty, DWORD dwFlags)
3878{
3879 Uri *This = impl_from_IUri(iface);
3880 HRESULT hres;
3881 TRACE("(%p %s)->(%d %p %lx)\n", This, debugstr_w(This->canon_uri), uriProp, pbstrProperty, dwFlags);
3882
3883 if(!This->create_flags)
3884 return E_UNEXPECTED;
3885 if(!pbstrProperty)
3886 return E_POINTER;
3887
3888 if(uriProp > Uri_PROPERTY_STRING_LAST) {
3889 /* It only returns S_FALSE for the ZONE property... */
3890 if(uriProp == Uri_PROPERTY_ZONE) {
3891 *pbstrProperty = SysAllocStringLen(NULL, 0);
3892 if(!(*pbstrProperty))
3893 return E_OUTOFMEMORY;
3894 return S_FALSE;
3895 }
3896
3897 *pbstrProperty = NULL;
3898 return E_INVALIDARG;
3899 }
3900
3901 if(dwFlags != 0 && dwFlags != Uri_DISPLAY_NO_FRAGMENT && dwFlags != Uri_PUNYCODE_IDN_HOST
3902 && dwFlags != Uri_DISPLAY_IDN_HOST)
3903 return E_INVALIDARG;
3904
3905 if((dwFlags == Uri_DISPLAY_NO_FRAGMENT && uriProp != Uri_PROPERTY_DISPLAY_URI)
3906 || (dwFlags == Uri_PUNYCODE_IDN_HOST && uriProp != Uri_PROPERTY_ABSOLUTE_URI
3907 && uriProp != Uri_PROPERTY_DOMAIN && uriProp != Uri_PROPERTY_HOST)
3908 || (dwFlags == Uri_DISPLAY_IDN_HOST && uriProp != Uri_PROPERTY_ABSOLUTE_URI
3909 && uriProp != Uri_PROPERTY_DOMAIN && uriProp != Uri_PROPERTY_HOST))
3910 return E_INVALIDARG;
3911
3912 switch(uriProp) {
3913 case Uri_PROPERTY_ABSOLUTE_URI:
3914 if(This->display_modifiers & URI_DISPLAY_NO_ABSOLUTE_URI) {
3915 *pbstrProperty = SysAllocStringLen(NULL, 0);
3916 hres = S_FALSE;
3917 }
3918 /* Uri_PUNYCODE_IDN_HOST doesn't remove user info containing only "@" and ":@" */
3919 else if (dwFlags == Uri_PUNYCODE_IDN_HOST && This->host_type == Uri_HOST_IDN && This->host_start > -1) {
3920 unsigned int punycode_host_len;
3921
3922 punycode_host_len = IdnToAscii(0, This->canon_uri+This->host_start, This->host_len, NULL, 0);
3923 *pbstrProperty = SysAllocStringLen(NULL, This->canon_len-This->host_len+punycode_host_len);
3924 hres = S_OK;
3925 if(*pbstrProperty) {
3926 memcpy(*pbstrProperty, This->canon_uri, This->host_start*sizeof(WCHAR));
3927 IdnToAscii(0, This->canon_uri+This->host_start, This->host_len, *pbstrProperty+This->host_start, punycode_host_len);
3928 memcpy(*pbstrProperty+This->host_start+punycode_host_len,
3929 This->canon_uri+This->host_start+This->host_len,
3930 (This->canon_len-This->host_start-This->host_len)*sizeof(WCHAR));
3931 }
3932 } else {
3933 if(This->scheme_type != URL_SCHEME_UNKNOWN && This->userinfo_start > -1) {
3934 if(This->userinfo_len == 0) {
3935 /* Don't include the '@' after the userinfo component. */
3936 *pbstrProperty = SysAllocStringLen(NULL, This->canon_len-1);
3937 hres = S_OK;
3938 if(*pbstrProperty) {
3939 /* Copy everything before it. */
3940 memcpy(*pbstrProperty, This->canon_uri, This->userinfo_start*sizeof(WCHAR));
3941
3942 /* And everything after it. */
3943 memcpy(*pbstrProperty+This->userinfo_start, This->canon_uri+This->userinfo_start+1,
3944 (This->canon_len-This->userinfo_start-1)*sizeof(WCHAR));
3945 }
3946 } else if(This->userinfo_split == 0 && This->userinfo_len == 1) {
3947 /* Don't include the ":@" */
3948 *pbstrProperty = SysAllocStringLen(NULL, This->canon_len-2);
3949 hres = S_OK;
3950 if(*pbstrProperty) {
3951 memcpy(*pbstrProperty, This->canon_uri, This->userinfo_start*sizeof(WCHAR));
3952 memcpy(*pbstrProperty+This->userinfo_start, This->canon_uri+This->userinfo_start+2,
3953 (This->canon_len-This->userinfo_start-2)*sizeof(WCHAR));
3954 }
3955 } else {
3956 *pbstrProperty = SysAllocString(This->canon_uri);
3957 hres = S_OK;
3958 }
3959 } else {
3960 *pbstrProperty = SysAllocString(This->canon_uri);
3961 hres = S_OK;
3962 }
3963 }
3964
3965 if(!(*pbstrProperty))
3967
3968 break;
3969 case Uri_PROPERTY_AUTHORITY:
3970 if(This->authority_start > -1) {
3971 if(This->port_offset > -1 && is_default_port(This->scheme_type, This->port) &&
3972 This->display_modifiers & URI_DISPLAY_NO_DEFAULT_PORT_AUTH)
3973 /* Don't include the port in the authority component. */
3974 *pbstrProperty = SysAllocStringLen(This->canon_uri+This->authority_start, This->port_offset);
3975 else
3976 *pbstrProperty = SysAllocStringLen(This->canon_uri+This->authority_start, This->authority_len);
3977 hres = S_OK;
3978 } else {
3979 *pbstrProperty = SysAllocStringLen(NULL, 0);
3980 hres = S_FALSE;
3981 }
3982
3983 if(!(*pbstrProperty))
3985
3986 break;
3987 case Uri_PROPERTY_DISPLAY_URI:
3988 /* The Display URI contains everything except for the userinfo for known
3989 * scheme types.
3990 */
3991 if(This->scheme_type != URL_SCHEME_UNKNOWN && This->userinfo_start > -1) {
3992 unsigned int length = This->canon_len-This->userinfo_len;
3993
3994 /* Skip fragment if Uri_DISPLAY_NO_FRAGMENT is specified */
3995 if(dwFlags == Uri_DISPLAY_NO_FRAGMENT && This->fragment_start > -1)
3996 length -= This->fragment_len;
3997
3998 *pbstrProperty = SysAllocStringLen(NULL, length);
3999
4000 if(*pbstrProperty) {
4001 /* Copy everything before the userinfo over. */
4002 memcpy(*pbstrProperty, This->canon_uri, This->userinfo_start*sizeof(WCHAR));
4003
4004 /* Copy everything after the userinfo over. */
4005 length -= This->userinfo_start+1;
4006 memcpy(*pbstrProperty+This->userinfo_start,
4007 This->canon_uri+This->userinfo_start+This->userinfo_len+1, length*sizeof(WCHAR));
4008 }
4009 } else {
4010 unsigned int length = This->canon_len;
4011
4012 /* Skip fragment if Uri_DISPLAY_NO_FRAGMENT is specified */
4013 if(dwFlags == Uri_DISPLAY_NO_FRAGMENT && This->fragment_start > -1)
4014 length -= This->fragment_len;
4015
4016 *pbstrProperty = SysAllocStringLen(This->canon_uri, length);
4017 }
4018
4019 if(!(*pbstrProperty))
4021 else
4022 hres = S_OK;
4023
4024 break;
4025 case Uri_PROPERTY_DOMAIN:
4026 if(This->domain_offset > -1) {
4027 if(dwFlags == Uri_PUNYCODE_IDN_HOST && This->host_type == Uri_HOST_IDN) {
4028 unsigned int punycode_length;
4029
4030 punycode_length = IdnToAscii(0, This->canon_uri+This->host_start+This->domain_offset,
4031 This->host_len-This->domain_offset, NULL, 0);
4032 *pbstrProperty = SysAllocStringLen(NULL, punycode_length);
4033 if (*pbstrProperty)
4034 IdnToAscii(0, This->canon_uri+This->host_start+This->domain_offset,
4035 This->host_len-This->domain_offset, *pbstrProperty, punycode_length);
4036 } else {
4037 *pbstrProperty = SysAllocStringLen(This->canon_uri+This->host_start+This->domain_offset,
4038 This->host_len-This->domain_offset);
4039 }
4040
4041 hres = S_OK;
4042 } else {
4043 *pbstrProperty = SysAllocStringLen(NULL, 0);
4044 hres = S_FALSE;
4045 }
4046
4047 if(!(*pbstrProperty))
4049
4050 break;
4051 case Uri_PROPERTY_EXTENSION:
4052 if(This->extension_offset > -1) {
4053 *pbstrProperty = SysAllocStringLen(This->canon_uri+This->path_start+This->extension_offset,
4054 This->path_len-This->extension_offset);
4055 hres = S_OK;
4056 } else {
4057 *pbstrProperty = SysAllocStringLen(NULL, 0);
4058 hres = S_FALSE;
4059 }
4060
4061 if(!(*pbstrProperty))
4063
4064 break;
4065 case Uri_PROPERTY_FRAGMENT:
4066 if(This->fragment_start > -1) {
4067 *pbstrProperty = SysAllocStringLen(This->canon_uri+This->fragment_start, This->fragment_len);
4068 hres = S_OK;
4069 } else {
4070 *pbstrProperty = SysAllocStringLen(NULL, 0);
4071 hres = S_FALSE;
4072 }
4073
4074 if(!(*pbstrProperty))
4076
4077 break;
4078 case Uri_PROPERTY_HOST:
4079 if(This->host_start > -1) {
4080 /* The '[' and ']' aren't included for IPv6 addresses. */
4081 if(This->host_type == Uri_HOST_IPV6)
4082 *pbstrProperty = SysAllocStringLen(This->canon_uri+This->host_start+1, This->host_len-2);
4083 else if(dwFlags == Uri_PUNYCODE_IDN_HOST && This->host_type == Uri_HOST_IDN) {
4084 unsigned int punycode_length;
4085
4086 punycode_length = IdnToAscii(0, This->canon_uri+This->host_start, This->host_len, NULL, 0);
4087 *pbstrProperty = SysAllocStringLen(NULL, punycode_length);
4088 if (*pbstrProperty)
4089 IdnToAscii(0, This->canon_uri+This->host_start, This->host_len, *pbstrProperty, punycode_length);
4090 }
4091 else
4092 *pbstrProperty = SysAllocStringLen(This->canon_uri+This->host_start, This->host_len);
4093
4094 hres = S_OK;
4095 } else {
4096 *pbstrProperty = SysAllocStringLen(NULL, 0);
4097 hres = S_FALSE;
4098 }
4099
4100 if(!(*pbstrProperty))
4102
4103 break;
4104 case Uri_PROPERTY_PASSWORD:
4105 if(This->userinfo_split > -1) {
4106 *pbstrProperty = SysAllocStringLen(
4107 This->canon_uri+This->userinfo_start+This->userinfo_split+1,
4108 This->userinfo_len-This->userinfo_split-1);
4109 hres = S_OK;
4110 } else {
4111 *pbstrProperty = SysAllocStringLen(NULL, 0);
4112 hres = S_FALSE;
4113 }
4114
4115 if(!(*pbstrProperty))
4116 return E_OUTOFMEMORY;
4117
4118 break;
4119 case Uri_PROPERTY_PATH:
4120 if(This->path_start > -1) {
4121 *pbstrProperty = SysAllocStringLen(This->canon_uri+This->path_start, This->path_len);
4122 hres = S_OK;
4123 } else {
4124 *pbstrProperty = SysAllocStringLen(NULL, 0);
4125 hres = S_FALSE;
4126 }
4127
4128 if(!(*pbstrProperty))
4130
4131 break;
4132 case Uri_PROPERTY_PATH_AND_QUERY:
4133 if(This->path_start > -1) {
4134 *pbstrProperty = SysAllocStringLen(This->canon_uri+This->path_start, This->path_len+This->query_len);
4135 hres = S_OK;
4136 } else if(This->query_start > -1) {
4137 *pbstrProperty = SysAllocStringLen(This->canon_uri+This->query_start, This->query_len);
4138 hres = S_OK;
4139 } else {
4140 *pbstrProperty = SysAllocStringLen(NULL, 0);
4141 hres = S_FALSE;
4142 }
4143
4144 if(!(*pbstrProperty))
4146
4147 break;
4148 case Uri_PROPERTY_QUERY:
4149 if(This->query_start > -1) {
4150 *pbstrProperty = SysAllocStringLen(This->canon_uri+This->query_start, This->query_len);
4151 hres = S_OK;
4152 } else {
4153 *pbstrProperty = SysAllocStringLen(NULL, 0);
4154 hres = S_FALSE;
4155 }
4156
4157 if(!(*pbstrProperty))
4159
4160 break;
4161 case Uri_PROPERTY_RAW_URI:
4162 *pbstrProperty = SysAllocString(This->raw_uri);
4163 if(!(*pbstrProperty))
4165 else
4166 hres = S_OK;
4167 break;
4168 case Uri_PROPERTY_SCHEME_NAME:
4169 if(This->scheme_start > -1) {
4170 *pbstrProperty = SysAllocStringLen(This->canon_uri + This->scheme_start, This->scheme_len);
4171 hres = S_OK;
4172 } else {
4173 *pbstrProperty = SysAllocStringLen(NULL, 0);
4174 hres = S_FALSE;
4175 }
4176
4177 if(!(*pbstrProperty))
4179
4180 break;
4181 case Uri_PROPERTY_USER_INFO:
4182 if(This->userinfo_start > -1) {
4183 *pbstrProperty = SysAllocStringLen(This->canon_uri+This->userinfo_start, This->userinfo_len);
4184 hres = S_OK;
4185 } else {
4186 *pbstrProperty = SysAllocStringLen(NULL, 0);
4187 hres = S_FALSE;
4188 }
4189
4190 if(!(*pbstrProperty))
4192
4193 break;
4194 case Uri_PROPERTY_USER_NAME:
4195 if(This->userinfo_start > -1 && This->userinfo_split != 0) {
4196 /* If userinfo_split is set, that means a password exists
4197 * so the username is only from userinfo_start to userinfo_split.
4198 */
4199 if(This->userinfo_split > -1) {
4200 *pbstrProperty = SysAllocStringLen(This->canon_uri + This->userinfo_start, This->userinfo_split);
4201 hres = S_OK;
4202 } else {
4203 *pbstrProperty = SysAllocStringLen(This->canon_uri + This->userinfo_start, This->userinfo_len);
4204 hres = S_OK;
4205 }
4206 } else {
4207 *pbstrProperty = SysAllocStringLen(NULL, 0);
4208 hres = S_FALSE;
4209 }
4210
4211 if(!(*pbstrProperty))
4212 return E_OUTOFMEMORY;
4213
4214 break;
4215 default:
4216 FIXME("(%p)->(%d %p %lx)\n", This, uriProp, pbstrProperty, dwFlags);
4217 hres = E_NOTIMPL;
4218 }
4219
4220 return hres;
4221}
4222
4223static HRESULT WINAPI Uri_GetPropertyLength(IUri *iface, Uri_PROPERTY uriProp, DWORD *pcchProperty, DWORD dwFlags)
4224{
4225 Uri *This = impl_from_IUri(iface);
4226 HRESULT hres;
4227 TRACE("(%p %s)->(%d %p %lx)\n", This, debugstr_w(This->canon_uri), uriProp, pcchProperty, dwFlags);
4228
4229 if(!This->create_flags)
4230 return E_UNEXPECTED;
4231 if(!pcchProperty)
4232 return E_INVALIDARG;
4233
4234 /* Can only return a length for a property if it's a string. */
4235 if(uriProp > Uri_PROPERTY_STRING_LAST)
4236 return E_INVALIDARG;
4237
4238 if(dwFlags != 0 && dwFlags != Uri_DISPLAY_NO_FRAGMENT && dwFlags != Uri_PUNYCODE_IDN_HOST
4239 && dwFlags != Uri_DISPLAY_IDN_HOST) {
4240 *pcchProperty = 0;
4241 return E_INVALIDARG;
4242 }
4243
4244 switch(uriProp) {
4245 case Uri_PROPERTY_ABSOLUTE_URI:
4246 if(This->display_modifiers & URI_DISPLAY_NO_ABSOLUTE_URI) {
4247 *pcchProperty = 0;
4248 hres = S_FALSE;
4249 }
4250 /* Uri_PUNYCODE_IDN_HOST doesn't remove user info containing only "@" and ":@" */
4251 else if(dwFlags == Uri_PUNYCODE_IDN_HOST && This->host_type == Uri_HOST_IDN && This->host_start > -1) {
4252 unsigned int punycode_host_len = IdnToAscii(0, This->canon_uri+This->host_start, This->host_len, NULL, 0);
4253 *pcchProperty = This->canon_len - This->host_len + punycode_host_len;
4254 hres = S_OK;
4255 } else {
4256 if(This->scheme_type != URL_SCHEME_UNKNOWN) {
4257 if(This->userinfo_start > -1 && This->userinfo_len == 0)
4258 /* Don't include the '@' in the length. */
4259 *pcchProperty = This->canon_len-1;
4260 else if(This->userinfo_start > -1 && This->userinfo_len == 1 &&
4261 This->userinfo_split == 0)
4262 /* Don't include the ":@" in the length. */
4263 *pcchProperty = This->canon_len-2;
4264 else
4265 *pcchProperty = This->canon_len;
4266 } else
4267 *pcchProperty = This->canon_len;
4268
4269 hres = S_OK;
4270 }
4271
4272 break;
4273 case Uri_PROPERTY_AUTHORITY:
4274 if(This->port_offset > -1 &&
4275 This->display_modifiers & URI_DISPLAY_NO_DEFAULT_PORT_AUTH &&
4276 is_default_port(This->scheme_type, This->port))
4277 /* Only count up until the port in the authority. */
4278 *pcchProperty = This->port_offset;
4279 else
4280 *pcchProperty = This->authority_len;
4281 hres = (This->authority_start > -1) ? S_OK : S_FALSE;
4282 break;
4283 case Uri_PROPERTY_DISPLAY_URI:
4284 if(This->scheme_type != URL_SCHEME_UNKNOWN && This->userinfo_start > -1)
4285 *pcchProperty = This->canon_len-This->userinfo_len-1;
4286 else
4287 *pcchProperty = This->canon_len;
4288
4289 if(dwFlags == Uri_DISPLAY_NO_FRAGMENT && This->fragment_start > -1)
4290 *pcchProperty -= This->fragment_len;
4291
4292 hres = S_OK;
4293 break;
4294 case Uri_PROPERTY_DOMAIN:
4295 if(This->domain_offset > -1) {
4296 if(dwFlags == Uri_PUNYCODE_IDN_HOST && This->host_type == Uri_HOST_IDN)
4297 *pcchProperty = IdnToAscii(0, This->canon_uri+This->host_start+This->domain_offset, This->host_len-This->domain_offset, NULL, 0);
4298 else
4299 *pcchProperty = This->host_len - This->domain_offset;
4300 }
4301 else
4302 *pcchProperty = 0;
4303
4304 hres = (This->domain_offset > -1) ? S_OK : S_FALSE;
4305 break;
4306 case Uri_PROPERTY_EXTENSION:
4307 if(This->extension_offset > -1) {
4308 *pcchProperty = This->path_len - This->extension_offset;
4309 hres = S_OK;
4310 } else {
4311 *pcchProperty = 0;
4312 hres = S_FALSE;
4313 }
4314
4315 break;
4316 case Uri_PROPERTY_FRAGMENT:
4317 *pcchProperty = This->fragment_len;
4318 hres = (This->fragment_start > -1) ? S_OK : S_FALSE;
4319 break;
4320 case Uri_PROPERTY_HOST:
4321 *pcchProperty = This->host_len;
4322
4323 /* '[' and ']' aren't included in the length. */
4324 if(This->host_type == Uri_HOST_IPV6)
4325 *pcchProperty -= 2;
4326 else if(dwFlags == Uri_PUNYCODE_IDN_HOST && This->host_type == Uri_HOST_IDN && This->host_start > -1)
4327 *pcchProperty = IdnToAscii(0, This->canon_uri+This->host_start, This->host_len, NULL, 0);
4328
4329 hres = (This->host_start > -1) ? S_OK : S_FALSE;
4330 break;
4331 case Uri_PROPERTY_PASSWORD:
4332 *pcchProperty = (This->userinfo_split > -1) ? This->userinfo_len-This->userinfo_split-1 : 0;
4333 hres = (This->userinfo_split > -1) ? S_OK : S_FALSE;
4334 break;
4335 case Uri_PROPERTY_PATH:
4336 *pcchProperty = This->path_len;
4337 hres = (This->path_start > -1) ? S_OK : S_FALSE;
4338 break;
4339 case Uri_PROPERTY_PATH_AND_QUERY:
4340 *pcchProperty = This->path_len+This->query_len;
4341 hres = (This->path_start > -1 || This->query_start > -1) ? S_OK : S_FALSE;
4342 break;
4343 case Uri_PROPERTY_QUERY:
4344 *pcchProperty = This->query_len;
4345 hres = (This->query_start > -1) ? S_OK : S_FALSE;
4346 break;
4347 case Uri_PROPERTY_RAW_URI:
4348 *pcchProperty = SysStringLen(This->raw_uri);
4349 hres = S_OK;
4350 break;
4351 case Uri_PROPERTY_SCHEME_NAME:
4352 *pcchProperty = This->scheme_len;
4353 hres = (This->scheme_start > -1) ? S_OK : S_FALSE;
4354 break;
4355 case Uri_PROPERTY_USER_INFO:
4356 *pcchProperty = This->userinfo_len;
4357 hres = (This->userinfo_start > -1) ? S_OK : S_FALSE;
4358 break;
4359 case Uri_PROPERTY_USER_NAME:
4360 *pcchProperty = (This->userinfo_split > -1) ? This->userinfo_split : This->userinfo_len;
4361 if(This->userinfo_split == 0)
4362 hres = S_FALSE;
4363 else
4364 hres = (This->userinfo_start > -1) ? S_OK : S_FALSE;
4365 break;
4366 default:
4367 FIXME("(%p)->(%d %p %lx)\n", This, uriProp, pcchProperty, dwFlags);
4368 hres = E_NOTIMPL;
4369 }
4370
4371 if(hres == S_OK
4372 && ((dwFlags == Uri_DISPLAY_NO_FRAGMENT && uriProp != Uri_PROPERTY_DISPLAY_URI)
4373 || (dwFlags == Uri_PUNYCODE_IDN_HOST && uriProp != Uri_PROPERTY_ABSOLUTE_URI
4374 && uriProp != Uri_PROPERTY_DOMAIN && uriProp != Uri_PROPERTY_HOST)
4375 || (dwFlags == Uri_DISPLAY_IDN_HOST && uriProp != Uri_PROPERTY_ABSOLUTE_URI
4376 && uriProp != Uri_PROPERTY_DOMAIN && uriProp != Uri_PROPERTY_HOST))) {
4377 *pcchProperty = 0;
4379 }
4380
4381 return hres;
4382}
4383
4384static HRESULT WINAPI Uri_GetPropertyDWORD(IUri *iface, Uri_PROPERTY uriProp, DWORD *pcchProperty, DWORD dwFlags)
4385{
4386 Uri *This = impl_from_IUri(iface);
4387 HRESULT hres;
4388
4389 TRACE("(%p %s)->(%d %p %lx)\n", This, debugstr_w(This->canon_uri), uriProp, pcchProperty, dwFlags);
4390
4391 if(!This->create_flags)
4392 return E_UNEXPECTED;
4393 if(!pcchProperty)
4394 return E_INVALIDARG;
4395
4396 /* Microsoft's implementation for the ZONE property of a URI seems to be lacking...
4397 * From what I can tell, instead of checking which URLZONE the URI belongs to it
4398 * simply assigns URLZONE_INVALID and returns E_NOTIMPL. This also applies to the GetZone
4399 * function.
4400 */
4401 if(uriProp == Uri_PROPERTY_ZONE) {
4402 *pcchProperty = URLZONE_INVALID;
4403 return E_NOTIMPL;
4404 }
4405
4406 if(uriProp < Uri_PROPERTY_DWORD_START) {
4407 *pcchProperty = 0;
4408 return E_INVALIDARG;
4409 }
4410
4411 switch(uriProp) {
4412 case Uri_PROPERTY_HOST_TYPE:
4413 *pcchProperty = This->host_type;
4414 hres = S_OK;
4415 break;
4416 case Uri_PROPERTY_PORT:
4417 if(!This->has_port) {
4418 *pcchProperty = 0;
4419 hres = S_FALSE;
4420 } else {
4421 *pcchProperty = This->port;
4422 hres = S_OK;
4423 }
4424
4425 break;
4426 case Uri_PROPERTY_SCHEME:
4427 *pcchProperty = This->scheme_type;
4428 hres = S_OK;
4429 break;
4430 default:
4431 FIXME("(%p)->(%d %p %lx)\n", This, uriProp, pcchProperty, dwFlags);
4432 hres = E_NOTIMPL;
4433 }
4434
4435 return hres;
4436}
4437
4438static HRESULT WINAPI Uri_HasProperty(IUri *iface, Uri_PROPERTY uriProp, BOOL *pfHasProperty)
4439{
4440 Uri *This = impl_from_IUri(iface);
4441
4442 TRACE("(%p %s)->(%d %p)\n", This, debugstr_w(This->canon_uri), uriProp, pfHasProperty);
4443
4444 if(!pfHasProperty)
4445 return E_INVALIDARG;
4446
4447 switch(uriProp) {
4448 case Uri_PROPERTY_ABSOLUTE_URI:
4449 *pfHasProperty = !(This->display_modifiers & URI_DISPLAY_NO_ABSOLUTE_URI);
4450 break;
4451 case Uri_PROPERTY_AUTHORITY:
4452 *pfHasProperty = This->authority_start > -1;
4453 break;
4454 case Uri_PROPERTY_DISPLAY_URI:
4455 *pfHasProperty = TRUE;
4456 break;
4457 case Uri_PROPERTY_DOMAIN:
4458 *pfHasProperty = This->domain_offset > -1;
4459 break;
4460 case Uri_PROPERTY_EXTENSION:
4461 *pfHasProperty = This->extension_offset > -1;
4462 break;
4463 case Uri_PROPERTY_FRAGMENT:
4464 *pfHasProperty = This->fragment_start > -1;
4465 break;
4466 case Uri_PROPERTY_HOST:
4467 *pfHasProperty = This->host_start > -1;
4468 break;
4469 case Uri_PROPERTY_PASSWORD:
4470 *pfHasProperty = This->userinfo_split > -1;
4471 break;
4472 case Uri_PROPERTY_PATH:
4473 *pfHasProperty = This->path_start > -1;
4474 break;
4475 case Uri_PROPERTY_PATH_AND_QUERY:
4476 *pfHasProperty = (This->path_start > -1 || This->query_start > -1);
4477 break;
4478 case Uri_PROPERTY_QUERY:
4479 *pfHasProperty = This->query_start > -1;
4480 break;
4481 case Uri_PROPERTY_RAW_URI:
4482 *pfHasProperty = TRUE;
4483 break;
4484 case Uri_PROPERTY_SCHEME_NAME:
4485 *pfHasProperty = This->scheme_start > -1;
4486 break;
4487 case Uri_PROPERTY_USER_INFO:
4488 *pfHasProperty = This->userinfo_start > -1;
4489 break;
4490 case Uri_PROPERTY_USER_NAME:
4491 if(This->userinfo_split == 0)
4492 *pfHasProperty = FALSE;
4493 else
4494 *pfHasProperty = This->userinfo_start > -1;
4495 break;
4496 case Uri_PROPERTY_HOST_TYPE:
4497 *pfHasProperty = TRUE;
4498 break;
4499 case Uri_PROPERTY_PORT:
4500 *pfHasProperty = This->has_port;
4501 break;
4502 case Uri_PROPERTY_SCHEME:
4503 *pfHasProperty = TRUE;
4504 break;
4505 case Uri_PROPERTY_ZONE:
4506 *pfHasProperty = FALSE;
4507 break;
4508 default:
4509 FIXME("(%p)->(%d %p): Unsupported property type.\n", This, uriProp, pfHasProperty);
4510 return E_NOTIMPL;
4511 }
4512
4513 return S_OK;
4514}
4515
4516static HRESULT WINAPI Uri_GetAbsoluteUri(IUri *iface, BSTR *pstrAbsoluteUri)
4517{
4518 TRACE("(%p)->(%p)\n", iface, pstrAbsoluteUri);
4519 return IUri_GetPropertyBSTR(iface, Uri_PROPERTY_ABSOLUTE_URI, pstrAbsoluteUri, 0);
4520}
4521
4522static HRESULT WINAPI Uri_GetAuthority(IUri *iface, BSTR *pstrAuthority)
4523{
4524 TRACE("(%p)->(%p)\n", iface, pstrAuthority);
4525 return IUri_GetPropertyBSTR(iface, Uri_PROPERTY_AUTHORITY, pstrAuthority, 0);
4526}
4527
4528static HRESULT WINAPI Uri_GetDisplayUri(IUri *iface, BSTR *pstrDisplayUri)
4529{
4530 TRACE("(%p)->(%p)\n", iface, pstrDisplayUri);
4531 return IUri_GetPropertyBSTR(iface, Uri_PROPERTY_DISPLAY_URI, pstrDisplayUri, 0);
4532}
4533
4534static HRESULT WINAPI Uri_GetDomain(IUri *iface, BSTR *pstrDomain)
4535{
4536 TRACE("(%p)->(%p)\n", iface, pstrDomain);
4537 return IUri_GetPropertyBSTR(iface, Uri_PROPERTY_DOMAIN, pstrDomain, 0);
4538}
4539
4540static HRESULT WINAPI Uri_GetExtension(IUri *iface, BSTR *pstrExtension)
4541{
4542 TRACE("(%p)->(%p)\n", iface, pstrExtension);
4543 return IUri_GetPropertyBSTR(iface, Uri_PROPERTY_EXTENSION, pstrExtension, 0);
4544}
4545
4546static HRESULT WINAPI Uri_GetFragment(IUri *iface, BSTR *pstrFragment)
4547{
4548 TRACE("(%p)->(%p)\n", iface, pstrFragment);
4549 return IUri_GetPropertyBSTR(iface, Uri_PROPERTY_FRAGMENT, pstrFragment, 0);
4550}
4551
4552static HRESULT WINAPI Uri_GetHost(IUri *iface, BSTR *pstrHost)
4553{
4554 TRACE("(%p)->(%p)\n", iface, pstrHost);
4555 return IUri_GetPropertyBSTR(iface, Uri_PROPERTY_HOST, pstrHost, 0);
4556}
4557
4558static HRESULT WINAPI Uri_GetPassword(IUri *iface, BSTR *pstrPassword)
4559{
4560 TRACE("(%p)->(%p)\n", iface, pstrPassword);
4561 return IUri_GetPropertyBSTR(iface, Uri_PROPERTY_PASSWORD, pstrPassword, 0);
4562}
4563
4564static HRESULT WINAPI Uri_GetPath(IUri *iface, BSTR *pstrPath)
4565{
4566 TRACE("(%p)->(%p)\n", iface, pstrPath);
4567 return IUri_GetPropertyBSTR(iface, Uri_PROPERTY_PATH, pstrPath, 0);
4568}
4569
4570static HRESULT WINAPI Uri_GetPathAndQuery(IUri *iface, BSTR *pstrPathAndQuery)
4571{
4572 TRACE("(%p)->(%p)\n", iface, pstrPathAndQuery);
4573 return IUri_GetPropertyBSTR(iface, Uri_PROPERTY_PATH_AND_QUERY, pstrPathAndQuery, 0);
4574}
4575
4576static HRESULT WINAPI Uri_GetQuery(IUri *iface, BSTR *pstrQuery)
4577{
4578 TRACE("(%p)->(%p)\n", iface, pstrQuery);
4579 return IUri_GetPropertyBSTR(iface, Uri_PROPERTY_QUERY, pstrQuery, 0);
4580}
4581
4582static HRESULT WINAPI Uri_GetRawUri(IUri *iface, BSTR *pstrRawUri)
4583{
4584 TRACE("(%p)->(%p)\n", iface, pstrRawUri);
4585 return IUri_GetPropertyBSTR(iface, Uri_PROPERTY_RAW_URI, pstrRawUri, 0);
4586}
4587
4588static HRESULT WINAPI Uri_GetSchemeName(IUri *iface, BSTR *pstrSchemeName)
4589{
4590 TRACE("(%p)->(%p)\n", iface, pstrSchemeName);
4591 return IUri_GetPropertyBSTR(iface, Uri_PROPERTY_SCHEME_NAME, pstrSchemeName, 0);
4592}
4593
4594static HRESULT WINAPI Uri_GetUserInfo(IUri *iface, BSTR *pstrUserInfo)
4595{
4596 TRACE("(%p)->(%p)\n", iface, pstrUserInfo);
4597 return IUri_GetPropertyBSTR(iface, Uri_PROPERTY_USER_INFO, pstrUserInfo, 0);
4598}
4599
4600static HRESULT WINAPI Uri_GetUserName(IUri *iface, BSTR *pstrUserName)
4601{
4602 TRACE("(%p)->(%p)\n", iface, pstrUserName);
4603 return IUri_GetPropertyBSTR(iface, Uri_PROPERTY_USER_NAME, pstrUserName, 0);
4604}
4605
4606static HRESULT WINAPI Uri_GetHostType(IUri *iface, DWORD *pdwHostType)
4607{
4608 TRACE("(%p)->(%p)\n", iface, pdwHostType);
4609 return IUri_GetPropertyDWORD(iface, Uri_PROPERTY_HOST_TYPE, pdwHostType, 0);
4610}
4611
4612static HRESULT WINAPI Uri_GetPort(IUri *iface, DWORD *pdwPort)
4613{
4614 TRACE("(%p)->(%p)\n", iface, pdwPort);
4615 return IUri_GetPropertyDWORD(iface, Uri_PROPERTY_PORT, pdwPort, 0);
4616}
4617
4618static HRESULT WINAPI Uri_GetScheme(IUri *iface, DWORD *pdwScheme)
4619{
4620 TRACE("(%p)->(%p)\n", iface, pdwScheme);
4621 return IUri_GetPropertyDWORD(iface, Uri_PROPERTY_SCHEME, pdwScheme, 0);
4622}
4623
4624static HRESULT WINAPI Uri_GetZone(IUri *iface, DWORD *pdwZone)
4625{
4626 TRACE("(%p)->(%p)\n", iface, pdwZone);
4627 return IUri_GetPropertyDWORD(iface, Uri_PROPERTY_ZONE,pdwZone, 0);
4628}
4629
4630static HRESULT WINAPI Uri_GetProperties(IUri *iface, DWORD *pdwProperties)
4631{
4632 Uri *This = impl_from_IUri(iface);
4633 TRACE("(%p %s)->(%p)\n", This, debugstr_w(This->canon_uri), pdwProperties);
4634
4635 if(!This->create_flags)
4636 return E_UNEXPECTED;
4637 if(!pdwProperties)
4638 return E_INVALIDARG;
4639
4640 /* All URIs have these. */
4641 *pdwProperties = Uri_HAS_DISPLAY_URI|Uri_HAS_RAW_URI|Uri_HAS_SCHEME|Uri_HAS_HOST_TYPE;
4642
4643 if(!(This->display_modifiers & URI_DISPLAY_NO_ABSOLUTE_URI))
4644 *pdwProperties |= Uri_HAS_ABSOLUTE_URI;
4645
4646 if(This->scheme_start > -1)
4647 *pdwProperties |= Uri_HAS_SCHEME_NAME;
4648
4649 if(This->authority_start > -1) {
4650 *pdwProperties |= Uri_HAS_AUTHORITY;
4651 if(This->userinfo_start > -1) {
4652 *pdwProperties |= Uri_HAS_USER_INFO;
4653 if(This->userinfo_split != 0)
4654 *pdwProperties |= Uri_HAS_USER_NAME;
4655 }
4656 if(This->userinfo_split > -1)
4657 *pdwProperties |= Uri_HAS_PASSWORD;
4658 if(This->host_start > -1)
4659 *pdwProperties |= Uri_HAS_HOST;
4660 if(This->domain_offset > -1)
4661 *pdwProperties |= Uri_HAS_DOMAIN;
4662 }
4663
4664 if(This->has_port)
4665 *pdwProperties |= Uri_HAS_PORT;
4666 if(This->path_start > -1)
4667 *pdwProperties |= Uri_HAS_PATH|Uri_HAS_PATH_AND_QUERY;
4668 if(This->query_start > -1)
4669 *pdwProperties |= Uri_HAS_QUERY|Uri_HAS_PATH_AND_QUERY;
4670
4671 if(This->extension_offset > -1)
4672 *pdwProperties |= Uri_HAS_EXTENSION;
4673
4674 if(This->fragment_start > -1)
4675 *pdwProperties |= Uri_HAS_FRAGMENT;
4676
4677 return S_OK;
4678}
4679
4680static HRESULT WINAPI Uri_IsEqual(IUri *iface, IUri *pUri, BOOL *pfEqual)
4681{
4682 Uri *This = impl_from_IUri(iface);
4683 Uri *other;
4684
4685 TRACE("(%p %s)->(%p %p)\n", This, debugstr_w(This->canon_uri), pUri, pfEqual);
4686
4687 if(!This->create_flags)
4688 return E_UNEXPECTED;
4689 if(!pfEqual)
4690 return E_POINTER;
4691
4692 if(!pUri) {
4693 *pfEqual = FALSE;
4694
4695 /* For some reason Windows returns S_OK here... */
4696 return S_OK;
4697 }
4698
4699 /* Try to convert it to a Uri (allows for a more simple comparison). */
4700 if(!(other = get_uri_obj(pUri))) {
4701 FIXME("(%p)->(%p %p) No support for unknown IUri's yet.\n", iface, pUri, pfEqual);
4702 return E_NOTIMPL;
4703 }
4704
4705 TRACE("comparing to %s\n", debugstr_w(other->canon_uri));
4706 return compare_uris(This, other, pfEqual);
4707}
4708
4709static const IUriVtbl UriVtbl = {
4711 Uri_AddRef,
4738};
4739
4741{
4742 return CONTAINING_RECORD(iface, Uri, IUriBuilderFactory_iface);
4743}
4744
4746{
4748 return IUri_QueryInterface(&This->IUri_iface, riid, ppv);
4749}
4750
4752{
4754 return IUri_AddRef(&This->IUri_iface);
4755}
4756
4758{
4760 return IUri_Release(&This->IUri_iface);
4761}
4762
4764 DWORD dwFlags,
4766 IUriBuilder **ppIUriBuilder)
4767{
4769 TRACE("(%p)->(%08lx %08Ix %p)\n", This, dwFlags, dwReserved, ppIUriBuilder);
4770
4771 if(!ppIUriBuilder)
4772 return E_POINTER;
4773
4774 if(dwFlags || dwReserved) {
4775 *ppIUriBuilder = NULL;
4776 return E_INVALIDARG;
4777 }
4778
4779 return CreateIUriBuilder(NULL, 0, 0, ppIUriBuilder);
4780}
4781
4783 DWORD dwFlags,
4785 IUriBuilder **ppIUriBuilder)
4786{
4788 TRACE("(%p)->(%08lx %08Ix %p)\n", This, dwFlags, dwReserved, ppIUriBuilder);
4789
4790 if(!ppIUriBuilder)
4791 return E_POINTER;
4792
4793 if(dwFlags || dwReserved) {
4794 *ppIUriBuilder = NULL;
4795 return E_INVALIDARG;
4796 }
4797
4798 return CreateIUriBuilder(&This->IUri_iface, 0, 0, ppIUriBuilder);
4799}
4800
4801static const IUriBuilderFactoryVtbl UriBuilderFactoryVtbl = {
4807};
4808
4810{
4811 return CONTAINING_RECORD(iface, Uri, IPersistStream_iface);
4812}
4813
4815{
4817 return IUri_QueryInterface(&This->IUri_iface, riid, ppvObject);
4818}
4819
4821{
4823 return IUri_AddRef(&This->IUri_iface);
4824}
4825
4827{
4829 return IUri_Release(&This->IUri_iface);
4830}
4831
4833{
4835 TRACE("(%p)->(%p)\n", This, pClassID);
4836
4837 if(!pClassID)
4838 return E_INVALIDARG;
4839
4840 *pClassID = CLSID_CUri;
4841 return S_OK;
4842}
4843
4845{
4847 TRACE("(%p)\n", This);
4848 return S_FALSE;
4849}
4850
4858};
4859
4861{
4863 struct persist_uri *data;
4864 parse_data parse;
4865 DWORD size;
4866 HRESULT hr;
4867
4868 TRACE("(%p)->(%p)\n", This, pStm);
4869
4870 if(This->create_flags)
4871 return E_UNEXPECTED;
4872 if(!pStm)
4873 return E_INVALIDARG;
4874
4875 hr = IStream_Read(pStm, &size, sizeof(DWORD), NULL);
4876 if(FAILED(hr))
4877 return hr;
4878 data = malloc(size);
4879 if(!data)
4880 return E_OUTOFMEMORY;
4881 hr = IStream_Read(pStm, data->unk1, size-sizeof(DWORD)-2, NULL);
4882 if(FAILED(hr)) {
4883 free(data);
4884 return hr;
4885 }
4886
4887 if(size < sizeof(struct persist_uri)) {
4888 free(data);
4889 return S_OK;
4890 }
4891
4892 if(*(DWORD*)data->data != Uri_PROPERTY_RAW_URI) {
4893 free(data);
4894 ERR("Can't find raw_uri\n");
4895 return E_UNEXPECTED;
4896 }
4897
4898 This->raw_uri = SysAllocString((WCHAR*)(data->data+sizeof(DWORD)*2));
4899 if(!This->raw_uri) {
4900 free(data);
4901 return E_OUTOFMEMORY;
4902 }
4903 This->create_flags = data->create_flags;
4904 free(data);
4905 TRACE("%lx %s\n", This->create_flags, debugstr_w(This->raw_uri));
4906
4907 memset(&parse, 0, sizeof(parse_data));
4908 parse.uri = This->raw_uri;
4909 if(!parse_uri(&parse, This->create_flags)) {
4910 SysFreeString(This->raw_uri);
4911 This->create_flags = 0;
4912 return E_UNEXPECTED;
4913 }
4914
4915 hr = canonicalize_uri(&parse, This, This->create_flags);
4916 if(FAILED(hr)) {
4917 SysFreeString(This->raw_uri);
4918 This->create_flags = 0;
4919 return hr;
4920 }
4921
4922 return S_OK;
4923}
4924
4926{
4927 len *= sizeof(WCHAR);
4928 *(DWORD*)p = type;
4929 p += sizeof(DWORD);
4930 *(DWORD*)p = len+sizeof(WCHAR);
4931 p += sizeof(DWORD);
4932 memcpy(p, data, len);
4933 p += len;
4934 *(WCHAR*)p = 0;
4935 return p+sizeof(WCHAR);
4936}
4937
4938static inline void persist_stream_save(Uri *This, IStream *pStm, BOOL marshal, struct persist_uri *data)
4939{
4940 BYTE *p = NULL;
4941
4942 data->create_flags = This->create_flags;
4943
4944 if(This->create_flags) {
4945 data->fields_no = 1;
4946 p = persist_stream_add_strprop(This, data->data, Uri_PROPERTY_RAW_URI,
4947 SysStringLen(This->raw_uri), This->raw_uri);
4948 }
4949 if(This->scheme_type!=URL_SCHEME_HTTP && This->scheme_type!=URL_SCHEME_HTTPS
4950 && This->scheme_type!=URL_SCHEME_FTP)
4951 return;
4952
4953 if(This->fragment_len) {
4954 data->fields_no++;
4955 p = persist_stream_add_strprop(This, p, Uri_PROPERTY_FRAGMENT,
4956 This->fragment_len, This->canon_uri+This->fragment_start);
4957 }
4958
4959 if(This->host_len) {
4960 data->fields_no++;
4961 if(This->host_type == Uri_HOST_IPV6)
4962 p = persist_stream_add_strprop(This, p, Uri_PROPERTY_HOST,
4963 This->host_len-2, This->canon_uri+This->host_start+1);
4964 else
4965 p = persist_stream_add_strprop(This, p, Uri_PROPERTY_HOST,
4966 This->host_len, This->canon_uri+This->host_start);
4967 }
4968
4969 if(This->userinfo_split > -1) {
4970 data->fields_no++;
4971 p = persist_stream_add_strprop(This, p, Uri_PROPERTY_PASSWORD,
4972 This->userinfo_len-This->userinfo_split-1,
4973 This->canon_uri+This->userinfo_start+This->userinfo_split+1);
4974 }
4975
4976 if(This->path_len) {
4977 data->fields_no++;
4978 p = persist_stream_add_strprop(This, p, Uri_PROPERTY_PATH,
4979 This->path_len, This->canon_uri+This->path_start);
4980 } else if(marshal) {
4981 WCHAR no_path = '/';
4982 data->fields_no++;
4983 p = persist_stream_add_strprop(This, p, Uri_PROPERTY_PATH, 1, &no_path);
4984 }
4985
4986 if(This->has_port) {
4987 data->fields_no++;
4988 *(DWORD*)p = Uri_PROPERTY_PORT;
4989 p += sizeof(DWORD);
4990 *(DWORD*)p = sizeof(DWORD);
4991 p += sizeof(DWORD);
4992 *(DWORD*)p = This->port;
4993 p += sizeof(DWORD);
4994 }
4995
4996 if(This->query_len) {
4997 data->fields_no++;
4998 p = persist_stream_add_strprop(This, p, Uri_PROPERTY_QUERY,
4999 This->query_len, This->canon_uri+This->query_start);
5000 }
5001
5002 if(This->scheme_len) {
5003 data->fields_no++;
5004 p = persist_stream_add_strprop(This, p, Uri_PROPERTY_SCHEME_NAME,
5005 This->scheme_len, This->canon_uri+This->scheme_start);
5006 }
5007
5008 if(This->userinfo_start>-1 && This->userinfo_split!=0) {
5009 data->fields_no++;
5010 if(This->userinfo_split > -1)
5011 p = persist_stream_add_strprop(This, p, Uri_PROPERTY_USER_NAME,
5012 This->userinfo_split, This->canon_uri+This->userinfo_start);
5013 else
5014 p = persist_stream_add_strprop(This, p, Uri_PROPERTY_USER_NAME,
5015 This->userinfo_len, This->canon_uri+This->userinfo_start);
5016 }
5017}
5018
5020{
5022 struct persist_uri *data;
5024 HRESULT hres;
5025
5026 TRACE("(%p)->(%p %x)\n", This, pStm, fClearDirty);
5027
5028 if(!pStm)
5029 return E_INVALIDARG;
5030
5031 hres = IPersistStream_GetSizeMax(&This->IPersistStream_iface, &size);
5032 if(FAILED(hres))
5033 return hres;
5034
5035 data = calloc(1, size.u.LowPart);
5036 if(!data)
5037 return E_OUTOFMEMORY;
5038 data->size = size.u.LowPart;
5040
5041 hres = IStream_Write(pStm, data, data->size-2, NULL);
5042 free(data);
5043 return hres;
5044}
5045
5047{
5049 TRACE("(%p)->(%p)\n", This, pcbSize);
5050
5051 if(!pcbSize)
5052 return E_INVALIDARG;
5053
5054 pcbSize->u.LowPart = 2+sizeof(struct persist_uri);
5055 pcbSize->u.HighPart = 0;
5056 if(This->create_flags)
5057 pcbSize->u.LowPart += (SysStringLen(This->raw_uri)+1)*sizeof(WCHAR) + 2*sizeof(DWORD);
5058 else /* there's no place for fields no */
5059 pcbSize->u.LowPart -= sizeof(DWORD);
5060 if(This->scheme_type!=URL_SCHEME_HTTP && This->scheme_type!=URL_SCHEME_HTTPS
5061 && This->scheme_type!=URL_SCHEME_FTP)
5062 return S_OK;
5063
5064 if(This->fragment_len)
5065 pcbSize->u.LowPart += (This->fragment_len+1)*sizeof(WCHAR) + 2*sizeof(DWORD);
5066 if(This->host_len) {
5067 if(This->host_type == Uri_HOST_IPV6)
5068 pcbSize->u.LowPart += (This->host_len-1)*sizeof(WCHAR) + 2*sizeof(DWORD);
5069 else
5070 pcbSize->u.LowPart += (This->host_len+1)*sizeof(WCHAR) + 2*sizeof(DWORD);
5071 }
5072 if(This->userinfo_split > -1)
5073 pcbSize->u.LowPart += (This->userinfo_len-This->userinfo_split)*sizeof(WCHAR) + 2*sizeof(DWORD);
5074 if(This->path_len)
5075 pcbSize->u.LowPart += (This->path_len+1)*sizeof(WCHAR) + 2*sizeof(DWORD);
5076 if(This->has_port)
5077 pcbSize->u.LowPart += 3*sizeof(DWORD);
5078 if(This->query_len)
5079 pcbSize->u.LowPart += (This->query_len+1)*sizeof(WCHAR) + 2*sizeof(DWORD);
5080 if(This->scheme_len)
5081 pcbSize->u.LowPart += (This->scheme_len+1)*sizeof(WCHAR) + 2*sizeof(DWORD);
5082 if(This->userinfo_start>-1 && This->userinfo_split!=0) {
5083 if(This->userinfo_split > -1)
5084 pcbSize->u.LowPart += (This->userinfo_split+1)*sizeof(WCHAR) + 2*sizeof(DWORD);
5085 else
5086 pcbSize->u.LowPart += (This->userinfo_len+1)*sizeof(WCHAR) + 2*sizeof(DWORD);
5087 }
5088 return S_OK;
5089}
5090
5091static const IPersistStreamVtbl PersistStreamVtbl = {
5100};
5101
5102static inline Uri* impl_from_IMarshal(IMarshal *iface)
5103{
5104 return CONTAINING_RECORD(iface, Uri, IMarshal_iface);
5105}
5106
5107static HRESULT WINAPI Marshal_QueryInterface(IMarshal *iface, REFIID riid, void **ppvObject)
5108{
5109 Uri *This = impl_from_IMarshal(iface);
5110 return IUri_QueryInterface(&This->IUri_iface, riid, ppvObject);
5111}
5112
5114{
5115 Uri *This = impl_from_IMarshal(iface);
5116 return IUri_AddRef(&This->IUri_iface);
5117}
5118
5120{
5121 Uri *This = impl_from_IMarshal(iface);
5122 return IUri_Release(&This->IUri_iface);
5123}
5124
5126 DWORD dwDestContext, void *pvDestContext, DWORD mshlflags, CLSID *pCid)
5127{
5128 Uri *This = impl_from_IMarshal(iface);
5129 TRACE("(%p)->(%s %p %lx %p %lx %p)\n", This, debugstr_guid(riid), pv,
5130 dwDestContext, pvDestContext, mshlflags, pCid);
5131
5132 if(!pCid || (dwDestContext!=MSHCTX_LOCAL && dwDestContext!=MSHCTX_NOSHAREDMEM
5133 && dwDestContext!=MSHCTX_INPROC))
5134 return E_INVALIDARG;
5135
5136 *pCid = CLSID_CUri;
5137 return S_OK;
5138}
5139
5143 DWORD unk[4]; /* process identifier? */
5145};
5146
5148 DWORD dwDestContext, void *pvDestContext, DWORD mshlflags, DWORD *pSize)
5149{
5150 Uri *This = impl_from_IMarshal(iface);
5152 HRESULT hres;
5153 TRACE("(%p)->(%s %p %lx %p %lx %p)\n", This, debugstr_guid(riid), pv,
5154 dwDestContext, pvDestContext, mshlflags, pSize);
5155
5156 if(!pSize || (dwDestContext!=MSHCTX_LOCAL && dwDestContext!=MSHCTX_NOSHAREDMEM
5157 && dwDestContext!=MSHCTX_INPROC))
5158 return E_INVALIDARG;
5159
5160 if(dwDestContext == MSHCTX_INPROC) {
5161 *pSize = sizeof(struct inproc_marshal_uri);
5162 return S_OK;
5163 }
5164
5165 hres = IPersistStream_GetSizeMax(&This->IPersistStream_iface, &size);
5166 if(FAILED(hres))
5167 return hres;
5168 if(!This->path_len && (This->scheme_type==URL_SCHEME_HTTP
5169 || This->scheme_type==URL_SCHEME_HTTPS
5170 || This->scheme_type==URL_SCHEME_FTP))
5171 size.u.LowPart += 3*sizeof(DWORD);
5172 *pSize = size.u.LowPart+2*sizeof(DWORD);
5173 return S_OK;
5174}
5175
5177 void *pv, DWORD dwDestContext, void *pvDestContext, DWORD mshlflags)
5178{
5179 Uri *This = impl_from_IMarshal(iface);
5180 DWORD *data;
5181 DWORD size;
5182 HRESULT hres;
5183
5184 TRACE("(%p)->(%p %s %p %lx %p %lx)\n", This, pStm, debugstr_guid(riid), pv,
5185 dwDestContext, pvDestContext, mshlflags);
5186
5187 if(!pStm || mshlflags!=MSHLFLAGS_NORMAL || (dwDestContext!=MSHCTX_LOCAL
5188 && dwDestContext!=MSHCTX_NOSHAREDMEM && dwDestContext!=MSHCTX_INPROC))
5189 return E_INVALIDARG;
5190
5191 if(dwDestContext == MSHCTX_INPROC) {
5192 struct inproc_marshal_uri data;
5193
5194 data.size = sizeof(data);
5195 data.mshlflags = MSHCTX_INPROC;
5196 data.unk[0] = 0;
5197 data.unk[1] = 0;
5198 data.unk[2] = 0;
5199 data.unk[3] = 0;
5200 data.uri = This;
5201
5202 hres = IStream_Write(pStm, &data, data.size, NULL);
5203 if(FAILED(hres))
5204 return hres;
5205
5206 IUri_AddRef(&This->IUri_iface);
5207 return S_OK;
5208 }
5209
5210 hres = IMarshal_GetMarshalSizeMax(iface, riid, pv, dwDestContext,
5211 pvDestContext, mshlflags, &size);
5212 if(FAILED(hres))
5213 return hres;
5214
5215 data = calloc(1, size);
5216 if(!data)
5217 return E_OUTOFMEMORY;
5218
5219 data[0] = size;
5220 data[1] = dwDestContext;
5221 data[2] = size-2*sizeof(DWORD);
5222 persist_stream_save(This, pStm, TRUE, (struct persist_uri*)(data+2));
5223
5224 hres = IStream_Write(pStm, data, data[0]-2, NULL);
5225 free(data);
5226 return hres;
5227}
5228
5230 IStream *pStm, REFIID riid, void **ppv)
5231{
5232 Uri *This = impl_from_IMarshal(iface);
5233 DWORD header[2];
5234 HRESULT hres;
5235
5236 TRACE("(%p)->(%p %s %p)\n", This, pStm, debugstr_guid(riid), ppv);
5237
5238 if(This->create_flags)
5239 return E_UNEXPECTED;
5240 if(!pStm || !riid || !ppv)
5241 return E_INVALIDARG;
5242
5243 hres = IStream_Read(pStm, header, sizeof(header), NULL);
5244 if(FAILED(hres))
5245 return hres;
5246
5247 if(header[1]!=MSHCTX_LOCAL && header[1]!=MSHCTX_NOSHAREDMEM
5248 && header[1]!=MSHCTX_INPROC)
5249 return E_UNEXPECTED;
5250
5251 if(header[1] == MSHCTX_INPROC) {
5252 struct inproc_marshal_uri data;
5253 parse_data parse;
5254
5255 hres = IStream_Read(pStm, data.unk, sizeof(data)-2*sizeof(DWORD), NULL);
5256 if(FAILED(hres))
5257 return hres;
5258
5259 This->raw_uri = SysAllocString(data.uri->raw_uri);
5260 if(!This->raw_uri) {
5261 return E_OUTOFMEMORY;
5262 }
5263
5264 memset(&parse, 0, sizeof(parse_data));
5265 parse.uri = This->raw_uri;
5266
5267 if(!parse_uri(&parse, data.uri->create_flags))
5268 return E_INVALIDARG;
5269
5270 hres = canonicalize_uri(&parse, This, data.uri->create_flags);
5271 if(FAILED(hres))
5272 return hres;
5273
5274 This->create_flags = data.uri->create_flags;
5275 IUri_Release(&data.uri->IUri_iface);
5276
5277 return IUri_QueryInterface(&This->IUri_iface, riid, ppv);
5278 }
5279
5280 hres = IPersistStream_Load(&This->IPersistStream_iface, pStm);
5281 if(FAILED(hres))
5282 return hres;
5283
5284 return IUri_QueryInterface(&This->IUri_iface, riid, ppv);
5285}
5286
5288{
5289 Uri *This = impl_from_IMarshal(iface);
5290 LARGE_INTEGER off;
5291 DWORD header[2];
5292 HRESULT hres;
5293
5294 TRACE("(%p)->(%p)\n", This, pStm);
5295
5296 if(!pStm)
5297 return E_INVALIDARG;
5298
5299 hres = IStream_Read(pStm, header, 2*sizeof(DWORD), NULL);
5300 if(FAILED(hres))
5301 return hres;
5302
5303 if(header[1] == MSHCTX_INPROC) {
5304 struct inproc_marshal_uri data;
5305
5306 hres = IStream_Read(pStm, data.unk, sizeof(data)-2*sizeof(DWORD), NULL);
5307 if(FAILED(hres))
5308 return hres;
5309
5310 IUri_Release(&data.uri->IUri_iface);
5311 return S_OK;
5312 }
5313
5314 off.u.LowPart = header[0]-sizeof(header)-2;
5315 off.u.HighPart = 0;
5316 return IStream_Seek(pStm, off, STREAM_SEEK_CUR, NULL);
5317}
5318
5320{
5321 Uri *This = impl_from_IMarshal(iface);
5322 TRACE("(%p)->(%lx)\n", This, dwReserved);
5323 return S_OK;
5324}
5325
5326static const IMarshalVtbl MarshalVtbl = {
5336};
5337
5339{
5340 Uri *ret = calloc(1, sizeof(Uri));
5341
5342 TRACE("(%p %p)\n", pUnkOuter, ppobj);
5343
5344 *ppobj = ret;
5345 if(!ret)
5346 return E_OUTOFMEMORY;
5347
5348 ret->IUri_iface.lpVtbl = &UriVtbl;
5349 ret->IUriBuilderFactory_iface.lpVtbl = &UriBuilderFactoryVtbl;
5350 ret->IPersistStream_iface.lpVtbl = &PersistStreamVtbl;
5351 ret->IMarshal_iface.lpVtbl = &MarshalVtbl;
5352 ret->ref = 1;
5353
5354 *ppobj = &ret->IUri_iface;
5355 return S_OK;
5356}
5357
5358/***********************************************************************
5359 * CreateUri (urlmon.@)
5360 *
5361 * Creates a new IUri object using the URI represented by pwzURI. This function
5362 * parses and validates the components of pwzURI and then canonicalizes the
5363 * parsed components.
5364 *
5365 * PARAMS
5366 * pwzURI [I] The URI to parse, validate, and canonicalize.
5367 * dwFlags [I] Flags which can affect how the parsing/canonicalization is performed.
5368 * dwReserved [I] Reserved (not used).
5369 * ppURI [O] The resulting IUri after parsing/canonicalization occurs.
5370 *
5371 * RETURNS
5372 * Success: Returns S_OK. ppURI contains the pointer to the newly allocated IUri.
5373 * Failure: E_INVALIDARG if there are invalid flag combinations in dwFlags, or an
5374 * invalid parameter, or pwzURI doesn't represent a valid URI.
5375 * E_OUTOFMEMORY if any memory allocation fails.
5376 *
5377 * NOTES
5378 * Default flags:
5379 * Uri_CREATE_CANONICALIZE, Uri_CREATE_DECODE_EXTRA_INFO, Uri_CREATE_CRACK_UNKNOWN_SCHEMES,
5380 * Uri_CREATE_PRE_PROCESS_HTML_URI, Uri_CREATE_NO_IE_SETTINGS.
5381 */
5383{
5384 const DWORD supported_flags = Uri_CREATE_ALLOW_RELATIVE|Uri_CREATE_ALLOW_IMPLICIT_WILDCARD_SCHEME|
5385 Uri_CREATE_ALLOW_IMPLICIT_FILE_SCHEME|Uri_CREATE_NO_CANONICALIZE|Uri_CREATE_CANONICALIZE|
5386 Uri_CREATE_DECODE_EXTRA_INFO|Uri_CREATE_NO_DECODE_EXTRA_INFO|Uri_CREATE_CRACK_UNKNOWN_SCHEMES|
5387 Uri_CREATE_NO_CRACK_UNKNOWN_SCHEMES|Uri_CREATE_PRE_PROCESS_HTML_URI|Uri_CREATE_NO_PRE_PROCESS_HTML_URI|
5388 Uri_CREATE_NO_IE_SETTINGS|Uri_CREATE_NO_ENCODE_FORBIDDEN_CHARACTERS|Uri_CREATE_FILE_USE_DOS_PATH;
5389 Uri *ret;
5390 HRESULT hr;
5392
5393 TRACE("(%s %lx %Ix %p)\n", debugstr_w(pwzURI), dwFlags, dwReserved, ppURI);
5394
5395 if(!ppURI)
5396 return E_INVALIDARG;
5397
5398 if(!pwzURI) {
5399 *ppURI = NULL;
5400 return E_INVALIDARG;
5401 }
5402
5403 /* Check for invalid flags. */
5405 *ppURI = NULL;
5406 return E_INVALIDARG;
5407 }
5408
5409 /* Currently unsupported. */
5410 if(dwFlags & ~supported_flags)
5411 FIXME("Ignoring unsupported flag(s) %lx\n", dwFlags & ~supported_flags);
5412
5413 hr = Uri_Construct(NULL, (void**)&ret);
5414 if(FAILED(hr)) {
5415 *ppURI = NULL;
5416 return hr;
5417 }
5418
5419 /* Explicitly set the default flags if it doesn't cause a flag conflict. */
5421
5422 /* Pre process the URI, unless told otherwise. */
5423 if(!(dwFlags & Uri_CREATE_NO_PRE_PROCESS_HTML_URI))
5424 ret->raw_uri = pre_process_uri(pwzURI);
5425 else
5426 ret->raw_uri = SysAllocString(pwzURI);
5427
5428 if(!ret->raw_uri) {
5429 free(ret);
5430 return E_OUTOFMEMORY;
5431 }
5432
5433 memset(&data, 0, sizeof(parse_data));
5434 data.uri = ret->raw_uri;
5435
5436 /* Validate and parse the URI into its components. */
5437 if(!parse_uri(&data, dwFlags)) {
5438 /* Encountered an unsupported or invalid URI */
5439 IUri_Release(&ret->IUri_iface);
5440 *ppURI = NULL;
5441 return E_INVALIDARG;
5442 }
5443
5444 /* Canonicalize the URI. */
5446 if(FAILED(hr)) {
5447 IUri_Release(&ret->IUri_iface);
5448 *ppURI = NULL;
5449 return hr;
5450 }
5451
5452 ret->create_flags = dwFlags;
5453
5454 *ppURI = &ret->IUri_iface;
5455 return S_OK;
5456}
5457
5458/***********************************************************************
5459 * CreateUriWithFragment (urlmon.@)
5460 *
5461 * Creates a new IUri object. This is almost the same as CreateUri, expect that
5462 * it allows you to explicitly specify a fragment (pwzFragment) for pwzURI.
5463 *
5464 * PARAMS
5465 * pwzURI [I] The URI to parse and perform canonicalization on.
5466 * pwzFragment [I] The explicit fragment string which should be added to pwzURI.
5467 * dwFlags [I] The flags which will be passed to CreateUri.
5468 * dwReserved [I] Reserved (not used).
5469 * ppURI [O] The resulting IUri after parsing/canonicalization.
5470 *
5471 * RETURNS
5472 * Success: S_OK. ppURI contains the pointer to the newly allocated IUri.
5473 * Failure: E_INVALIDARG if pwzURI already contains a fragment and pwzFragment
5474 * isn't NULL. Will also return E_INVALIDARG for the same reasons as
5475 * CreateUri will. E_OUTOFMEMORY if any allocation fails.
5476 */
5478 DWORD_PTR dwReserved, IUri **ppURI)
5479{
5480 HRESULT hres;
5481 TRACE("(%s %s %lx %Ix %p)\n", debugstr_w(pwzURI), debugstr_w(pwzFragment), dwFlags, dwReserved, ppURI);
5482
5483 if(!ppURI)
5484 return E_INVALIDARG;
5485
5486 if(!pwzURI) {
5487 *ppURI = NULL;
5488 return E_INVALIDARG;
5489 }
5490
5491 /* Check if a fragment should be appended to the URI string. */
5492 if(pwzFragment) {
5493 WCHAR *uriW;
5494 DWORD uri_len, frag_len;
5495 BOOL add_pound;
5496
5497 /* Check if the original URI already has a fragment component. */
5498 if(StrChrW(pwzURI, '#')) {
5499 *ppURI = NULL;
5500 return E_INVALIDARG;
5501 }
5502
5503 uri_len = lstrlenW(pwzURI);
5504 frag_len = lstrlenW(pwzFragment);
5505
5506 /* If the fragment doesn't start with a '#', one will be added. */
5507 add_pound = *pwzFragment != '#';
5508
5509 if(add_pound)
5510 uriW = malloc((uri_len + frag_len + 2) * sizeof(WCHAR));
5511 else
5512 uriW = malloc((uri_len + frag_len + 1) * sizeof(WCHAR));
5513
5514 if(!uriW)
5515 return E_OUTOFMEMORY;
5516
5517 memcpy(uriW, pwzURI, uri_len*sizeof(WCHAR));
5518 if(add_pound)
5519 uriW[uri_len++] = '#';
5520 memcpy(uriW+uri_len, pwzFragment, (frag_len+1)*sizeof(WCHAR));
5521
5522 hres = CreateUri(uriW, dwFlags, 0, ppURI);
5523
5524 free(uriW);
5525 } else
5526 /* A fragment string wasn't specified, so just forward the call. */
5527 hres = CreateUri(pwzURI, dwFlags, 0, ppURI);
5528
5529 return hres;
5530}
5531
5533 DWORD use_orig_flags, DWORD encoding_mask)
5534{
5535 HRESULT hr;
5537 Uri *ret;
5538
5539 if(!uri)
5540 return E_POINTER;
5541
5542 if(encoding_mask && (!builder->uri || builder->modified_props)) {
5543 *uri = NULL;
5544 return E_NOTIMPL;
5545 }
5546
5547 /* Decide what flags should be used when creating the Uri. */
5548 if((use_orig_flags & UriBuilder_USE_ORIGINAL_FLAGS) && builder->uri)
5549 create_flags = builder->uri->create_flags;
5550 else {
5552 *uri = NULL;
5553 return E_INVALIDARG;
5554 }
5555
5556 /* Set the default flags if they don't cause a conflict. */
5558 }
5559
5560 /* Return the base IUri if no changes have been made and the create_flags match. */
5561 if(builder->uri && !builder->modified_props && builder->uri->create_flags == create_flags) {
5562 *uri = &builder->uri->IUri_iface;
5563 IUri_AddRef(*uri);
5564 return S_OK;
5565 }
5566
5568 if(FAILED(hr)) {
5569 *uri = NULL;
5570 return hr;
5571 }
5572
5573 hr = Uri_Construct(NULL, (void**)&ret);
5574 if(FAILED(hr)) {
5575 *uri = NULL;
5576 return hr;
5577 }
5578
5579 hr = generate_uri(builder, &data, ret, create_flags);
5580 if(FAILED(hr)) {
5581 IUri_Release(&ret->IUri_iface);
5582 *uri = NULL;
5583 return hr;
5584 }
5585
5586 *uri = &ret->IUri_iface;
5587 return S_OK;
5588}
5589
5591{
5592 return CONTAINING_RECORD(iface, UriBuilder, IUriBuilder_iface);
5593}
5594
5596{
5598
5600 TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
5601 *ppv = &This->IUriBuilder_iface;
5602 }else if(IsEqualGUID(&IID_IUriBuilder, riid)) {
5603 TRACE("(%p)->(IID_IUriBuilder %p)\n", This, ppv);
5604 *ppv = &This->IUriBuilder_iface;
5605 }else {
5606 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
5607 *ppv = NULL;
5608 return E_NOINTERFACE;
5609 }
5610
5611 IUnknown_AddRef((IUnknown*)*ppv);
5612 return S_OK;
5613}
5614
5616{
5619
5620 TRACE("(%p) ref=%ld\n", This, ref);
5621
5622 return ref;
5623}
5624
5626{
5629
5630 TRACE("(%p) ref=%ld\n", This, ref);
5631
5632 if(!ref) {
5633 if(This->uri) IUri_Release(&This->uri->IUri_iface);
5634 free(This->fragment);
5635 free(This->host);
5636 free(This->password);
5637 free(This->path);
5638 free(This->query);
5639 free(This->scheme);
5640 free(This->username);
5641 free(This);
5642 }
5643
5644 return ref;
5645}
5646
5648 DWORD dwAllowEncodingPropertyMask,
5650 IUri **ppIUri)
5651{
5653 HRESULT hr;
5654 TRACE("(%p)->(%ld %Id %p)\n", This, dwAllowEncodingPropertyMask, dwReserved, ppIUri);
5655
5656 hr = build_uri(This, ppIUri, 0, UriBuilder_USE_ORIGINAL_FLAGS, dwAllowEncodingPropertyMask);
5657 if(hr == E_NOTIMPL)
5658 FIXME("(%p)->(%ld %Id %p)\n", This, dwAllowEncodingPropertyMask, dwReserved, ppIUri);
5659 return hr;
5660}
5661
5663 DWORD dwCreateFlags,
5664 DWORD dwAllowEncodingPropertyMask,
5666 IUri **ppIUri)
5667{
5669 HRESULT hr;
5670 TRACE("(%p)->(0x%08lx %ld %Id %p)\n", This, dwCreateFlags, dwAllowEncodingPropertyMask, dwReserved, ppIUri);
5671
5672 if(dwCreateFlags == -1)
5673 hr = build_uri(This, ppIUri, 0, UriBuilder_USE_ORIGINAL_FLAGS, dwAllowEncodingPropertyMask);
5674 else
5675 hr = build_uri(This, ppIUri, dwCreateFlags, 0, dwAllowEncodingPropertyMask);
5676
5677 if(hr == E_NOTIMPL)
5678 FIXME("(%p)->(0x%08lx %ld %Id %p)\n", This, dwCreateFlags, dwAllowEncodingPropertyMask, dwReserved, ppIUri);
5679 return hr;
5680}
5681
5683 DWORD dwCreateFlags,
5684 DWORD dwUriBuilderFlags,
5685 DWORD dwAllowEncodingPropertyMask,
5687 IUri **ppIUri)
5688{
5690 HRESULT hr;
5691 TRACE("(%p)->(0x%08lx 0x%08lx %ld %Id %p)\n", This, dwCreateFlags, dwUriBuilderFlags,
5692 dwAllowEncodingPropertyMask, dwReserved, ppIUri);
5693
5694 hr = build_uri(This, ppIUri, dwCreateFlags, dwUriBuilderFlags, dwAllowEncodingPropertyMask);
5695 if(hr == E_NOTIMPL)
5696 FIXME("(%p)->(0x%08lx 0x%08lx %ld %Id %p)\n", This, dwCreateFlags, dwUriBuilderFlags,
5697 dwAllowEncodingPropertyMask, dwReserved, ppIUri);
5698 return hr;
5699}
5700
5702{
5704 TRACE("(%p)->(%p)\n", This, ppIUri);
5705
5706 if(!ppIUri)
5707 return E_POINTER;
5708
5709 if(This->uri) {
5710 IUri *uri = &This->uri->IUri_iface;
5711 IUri_AddRef(uri);
5712 *ppIUri = uri;
5713 } else
5714 *ppIUri = NULL;
5715
5716 return S_OK;
5717}
5718
5720{
5722 TRACE("(%p)->(%p)\n", This, pIUri);
5723
5724 if(pIUri) {
5725 Uri *uri;
5726
5727 if((uri = get_uri_obj(pIUri))) {
5728 /* Only reset the builder if its Uri isn't the same as
5729 * the Uri passed to the function.
5730 */
5731 if(This->uri != uri) {
5733
5734 This->uri = uri;
5735 if(uri->has_port)
5736 This->port = uri->port;
5737
5738 IUri_AddRef(pIUri);
5739 }
5740 } else {
5741 FIXME("(%p)->(%p) Unknown IUri types not supported yet.\n", This, pIUri);
5742 return E_NOTIMPL;
5743 }
5744 } else if(This->uri)
5745 /* Only reset the builder if its Uri isn't NULL. */
5747
5748 return S_OK;
5749}
5750
5751static HRESULT WINAPI UriBuilder_GetFragment(IUriBuilder *iface, DWORD *pcchFragment, LPCWSTR *ppwzFragment)
5752{
5754 TRACE("(%p)->(%p %p)\n", This, pcchFragment, ppwzFragment);
5755
5756 if(!This->uri || This->uri->fragment_start == -1 || This->modified_props & Uri_HAS_FRAGMENT)
5757 return get_builder_component(&This->fragment, &This->fragment_len, NULL, 0, ppwzFragment, pcchFragment);
5758 else
5759 return get_builder_component(&This->fragment, &This->fragment_len, This->uri->canon_uri+This->uri->fragment_start,
5760 This->uri->fragment_len, ppwzFragment, pcchFragment);
5761}
5762
5763static HRESULT WINAPI UriBuilder_GetHost(IUriBuilder *iface, DWORD *pcchHost, LPCWSTR *ppwzHost)
5764{
5766 TRACE("(%p)->(%p %p)\n", This, pcchHost, ppwzHost);
5767
5768 if(!This->uri || This->uri->host_start == -1 || This->modified_props & Uri_HAS_HOST)
5769 return get_builder_component(&This->host, &This->host_len, NULL, 0, ppwzHost, pcchHost);
5770 else {
5771 if(This->uri->host_type == Uri_HOST_IPV6)
5772 /* Don't include the '[' and ']' around the address. */
5773 return get_builder_component(&This->host, &This->host_len, This->uri->canon_uri+This->uri->host_start+1,
5774 This->uri->host_len-2, ppwzHost, pcchHost);
5775 else
5776 return get_builder_component(&This->host, &This->host_len, This->uri->canon_uri+This->uri->host_start,
5777 This->uri->host_len, ppwzHost, pcchHost);
5778 }
5779}
5780
5781static HRESULT WINAPI UriBuilder_GetPassword(IUriBuilder *iface, DWORD *pcchPassword, LPCWSTR *ppwzPassword)
5782{
5784 TRACE("(%p)->(%p %p)\n", This, pcchPassword, ppwzPassword);
5785
5786 if(!This->uri || This->uri->userinfo_split == -1 || This->modified_props & Uri_HAS_PASSWORD)
5787 return get_builder_component(&This->password, &This->password_len, NULL, 0, ppwzPassword, pcchPassword);
5788 else {
5789 const WCHAR *start = This->uri->canon_uri+This->uri->userinfo_start+This->uri->userinfo_split+1;
5790 DWORD len = This->uri->userinfo_len-This->uri->userinfo_split-1;
5791 return get_builder_component(&This->password, &This->password_len, start, len, ppwzPassword, pcchPassword);
5792 }
5793}
5794
5796{
5798 TRACE("(%p)->(%p %p)\n", This, pcchPath, ppwzPath);
5799
5800 if(!This->uri || This->uri->path_start == -1 || This->modified_props & Uri_HAS_PATH)
5801 return get_builder_component(&This->path, &This->path_len, NULL, 0, ppwzPath, pcchPath);
5802 else
5803 return get_builder_component(&This->path, &This->path_len, This->uri->canon_uri+This->uri->path_start,
5804 This->uri->path_len, ppwzPath, pcchPath);
5805}
5806
5807static HRESULT WINAPI UriBuilder_GetPort(IUriBuilder *iface, BOOL *pfHasPort, DWORD *pdwPort)
5808{
5810 TRACE("(%p)->(%p %p)\n", This, pfHasPort, pdwPort);
5811
5812 if(!pfHasPort) {
5813 if(pdwPort)
5814 *pdwPort = 0;
5815 return E_POINTER;
5816 }
5817
5818 if(!pdwPort) {
5819 *pfHasPort = FALSE;
5820 return E_POINTER;
5821 }
5822
5823 *pfHasPort = This->has_port;
5824 *pdwPort = This->port;
5825 return S_OK;
5826}
5827
5828static HRESULT WINAPI UriBuilder_GetQuery(IUriBuilder *iface, DWORD *pcchQuery, LPCWSTR *ppwzQuery)
5829{
5831 TRACE("(%p)->(%p %p)\n", This, pcchQuery, ppwzQuery);
5832
5833 if(!This->uri || This->uri->query_start == -1 || This->modified_props & Uri_HAS_QUERY)
5834 return get_builder_component(&This->query, &This->query_len, NULL, 0, ppwzQuery, pcchQuery);
5835 else
5836 return get_builder_component(&This->query, &This->query_len, This->uri->canon_uri+This->uri->query_start,
5837 This->uri->query_len, ppwzQuery, pcchQuery);
5838}
5839
5840static HRESULT WINAPI UriBuilder_GetSchemeName(IUriBuilder *iface, DWORD *pcchSchemeName, LPCWSTR *ppwzSchemeName)
5841{
5843 TRACE("(%p)->(%p %p)\n", This, pcchSchemeName, ppwzSchemeName);
5844
5845 if(!This->uri || This->uri->scheme_start == -1 || This->modified_props & Uri_HAS_SCHEME_NAME)
5846 return get_builder_component(&This->scheme, &This->scheme_len, NULL, 0, ppwzSchemeName, pcchSchemeName);
5847 else
5848 return get_builder_component(&This->scheme, &This->scheme_len, This->uri->canon_uri+This->uri->scheme_start,
5849 This->uri->scheme_len, ppwzSchemeName, pcchSchemeName);
5850}
5851
5852static HRESULT WINAPI UriBuilder_GetUserName(IUriBuilder *iface, DWORD *pcchUserName, LPCWSTR *ppwzUserName)
5853{
5855 TRACE("(%p)->(%p %p)\n", This, pcchUserName, ppwzUserName);
5856
5857 if(!This->uri || This->uri->userinfo_start == -1 || This->uri->userinfo_split == 0 ||
5858 This->modified_props & Uri_HAS_USER_NAME)
5859 return get_builder_component(&This->username, &This->username_len, NULL, 0, ppwzUserName, pcchUserName);
5860 else {
5861 const WCHAR *start = This->uri->canon_uri+This->uri->userinfo_start;
5862
5863 /* Check if there's a password in the userinfo section. */
5864 if(This->uri->userinfo_split > -1)
5865 /* Don't include the password. */
5866 return get_builder_component(&This->username, &This->username_len, start,
5867 This->uri->userinfo_split, ppwzUserName, pcchUserName);
5868 else
5869 return get_builder_component(&This->username, &This->username_len, start,
5870 This->uri->userinfo_len, ppwzUserName, pcchUserName);
5871 }
5872}
5873
5875{
5877 TRACE("(%p)->(%s)\n", This, debugstr_w(pwzNewValue));
5878 return set_builder_component(&This->fragment, &This->fragment_len, pwzNewValue, '#',
5879 &This->modified_props, Uri_HAS_FRAGMENT);
5880}
5881
5883{
5885 TRACE("(%p)->(%s)\n", This, debugstr_w(pwzNewValue));
5886
5887 /* Host name can't be set to NULL. */
5888 if(!pwzNewValue)
5889 return E_INVALIDARG;
5890
5891 return set_builder_component(&This->host, &This->host_len, pwzNewValue, 0,
5892 &This->modified_props, Uri_HAS_HOST);
5893}
5894
5896{
5898 TRACE("(%p)->(%s)\n", This, debugstr_w(pwzNewValue));
5899 return set_builder_component(&This->password, &This->password_len, pwzNewValue, 0,
5900 &This->modified_props, Uri_HAS_PASSWORD);
5901}
5902
5904{
5906 TRACE("(%p)->(%s)\n", This, debugstr_w(pwzNewValue));
5907 return set_builder_component(&This->path, &This->path_len, pwzNewValue, 0,
5908 &This->modified_props, Uri_HAS_PATH);
5909}
5910
5911static HRESULT WINAPI UriBuilder_SetPort(IUriBuilder *iface, BOOL fHasPort, DWORD dwNewValue)
5912{
5914 TRACE("(%p)->(%d %ld)\n", This, fHasPort, dwNewValue);
5915
5916 This->has_port = fHasPort;
5917 This->port = dwNewValue;
5918 This->modified_props |= Uri_HAS_PORT;
5919 return S_OK;
5920}
5921
5923{
5925 TRACE("(%p)->(%s)\n", This, debugstr_w(pwzNewValue));
5926 return set_builder_component(&This->query, &This->query_len, pwzNewValue, '?',
5927 &This->modified_props, Uri_HAS_QUERY);
5928}
5929
5931{
5933 TRACE("(%p)->(%s)\n", This, debugstr_w(pwzNewValue));
5934
5935 /* Only set the scheme name if it's not NULL or empty. */
5936 if(!pwzNewValue || !*pwzNewValue)
5937 return E_INVALIDARG;
5938
5939 return set_builder_component(&This->scheme, &This->scheme_len, pwzNewValue, 0,
5940 &This->modified_props, Uri_HAS_SCHEME_NAME);
5941}
5942
5944{
5946 TRACE("(%p)->(%s)\n", This, debugstr_w(pwzNewValue));
5947 return set_builder_component(&This->username, &This->username_len, pwzNewValue, 0,
5948 &This->modified_props, Uri_HAS_USER_NAME);
5949}
5950
5952{
5953 const DWORD accepted_flags = Uri_HAS_AUTHORITY|Uri_HAS_DOMAIN|Uri_HAS_EXTENSION|Uri_HAS_FRAGMENT|Uri_HAS_HOST|
5954 Uri_HAS_PASSWORD|Uri_HAS_PATH|Uri_HAS_PATH_AND_QUERY|Uri_HAS_QUERY|
5955 Uri_HAS_USER_INFO|Uri_HAS_USER_NAME;
5956
5958 TRACE("(%p)->(0x%08lx)\n", This, dwPropertyMask);
5959
5960 if(dwPropertyMask & ~accepted_flags)
5961 return E_INVALIDARG;
5962
5963 if(dwPropertyMask & Uri_HAS_FRAGMENT)
5965
5966 /* Even though you can't set the host name to NULL or an
5967 * empty string, you can still remove it... for some reason.
5968 */
5969 if(dwPropertyMask & Uri_HAS_HOST)
5970 set_builder_component(&This->host, &This->host_len, NULL, 0,
5971 &This->modified_props, Uri_HAS_HOST);
5972
5973 if(dwPropertyMask & Uri_HAS_PASSWORD)
5975
5976 if(dwPropertyMask & Uri_HAS_PATH)
5977 UriBuilder_SetPath(iface, NULL);
5978
5979 if(dwPropertyMask & Uri_HAS_PORT)
5980 UriBuilder_SetPort(iface, FALSE, 0);
5981
5982 if(dwPropertyMask & Uri_HAS_QUERY)
5983 UriBuilder_SetQuery(iface, NULL);
5984
5985 if(dwPropertyMask & Uri_HAS_USER_NAME)
5987
5988 return S_OK;
5989}
5990
5992{
5994 TRACE("(%p)->(%p)\n", This, pfModified);
5995
5996 if(!pfModified)
5997 return E_POINTER;
5998
5999 *pfModified = This->modified_props > 0;
6000 return S_OK;
6001}
6002
6003static const IUriBuilderVtbl UriBuilderVtbl = {
6030};
6031
6032/***********************************************************************
6033 * CreateIUriBuilder (urlmon.@)
6034 */
6036{
6037 UriBuilder *ret;
6038
6039 TRACE("(%p %lx %Ix %p)\n", pIUri, dwFlags, dwReserved, ppIUriBuilder);
6040
6041 if(!ppIUriBuilder)
6042 return E_POINTER;
6043
6044 ret = calloc(1, sizeof(UriBuilder));
6045 if(!ret)
6046 return E_OUTOFMEMORY;
6047
6048 ret->IUriBuilder_iface.lpVtbl = &UriBuilderVtbl;
6049 ret->ref = 1;
6050
6051 if(pIUri) {
6052 Uri *uri;
6053
6054 if((uri = get_uri_obj(pIUri))) {
6055 if(!uri->create_flags) {
6056 free(ret);
6057 return E_UNEXPECTED;
6058 }
6059 IUri_AddRef(pIUri);
6060 ret->uri = uri;
6061
6062 if(uri->has_port)
6063 /* Windows doesn't set 'has_port' to TRUE in this case. */
6064 ret->port = uri->port;
6065
6066 } else {
6067 free(ret);
6068 *ppIUriBuilder = NULL;
6069 FIXME("(%p %lx %Ix %p): Unknown IUri types not supported yet.\n", pIUri, dwFlags,
6070 dwReserved, ppIUriBuilder);
6071 return E_NOTIMPL;
6072 }
6073 }
6074
6075 *ppIUriBuilder = &ret->IUriBuilder_iface;
6076 return S_OK;
6077}
6078
6079/* Merges the base path with the relative path and stores the resulting path
6080 * and path len in 'result' and 'result_len'.
6081 */
6082static HRESULT merge_paths(parse_data *data, const WCHAR *base, DWORD base_len, const WCHAR *relative,
6083 DWORD relative_len, WCHAR **result, DWORD *result_len, DWORD flags)
6084{
6085 const WCHAR *end = NULL;
6086 DWORD base_copy_len = 0;
6087 WCHAR *ptr;
6088
6089 if(base_len) {
6090 if(data->scheme_type == URL_SCHEME_MK && *relative == '/') {
6091 /* Find '::' segment */
6092 for(end = base; end < base+base_len-1; end++) {
6093 if(end[0] == ':' && end[1] == ':') {
6094 end++;
6095 break;
6096 }
6097 }
6098
6099 /* If not found, try finding the end of @xxx: */
6100 if(end == base+base_len-1)
6101 end = *base == '@' ? wmemchr(base, ':', base_len) : NULL;
6102 }else {
6103 /* Find the characters that will be copied over from the base path. */
6104 for (end = base + base_len - 1; end >= base; end--) if (*end == '/') break;
6105 if(end < base && data->scheme_type == URL_SCHEME_FILE)
6106 /* Try looking for a '\\'. */
6107 for (end = base + base_len - 1; end >= base; end--) if (*end == '\\') break;
6108 }
6109 }
6110
6111 if (end) base_copy_len = (end+1)-base;
6112 *result = malloc((base_copy_len + relative_len + 1) * sizeof(WCHAR));
6113
6114 if(!(*result)) {
6115 *result_len = 0;
6116 return E_OUTOFMEMORY;
6117 }
6118
6119 ptr = *result;
6120 memcpy(ptr, base, base_copy_len*sizeof(WCHAR));
6121 ptr += base_copy_len;
6122
6123 memcpy(ptr, relative, relative_len*sizeof(WCHAR));
6124 ptr += relative_len;
6125 *ptr = '\0';
6126
6127 *result_len = (ptr-*result);
6128 TRACE("ret %s\n", debugstr_wn(*result, *result_len));
6129 return S_OK;
6130}
6131
6132static HRESULT combine_uri(Uri *base, Uri *relative, DWORD flags, IUri **result, DWORD extras) {
6133 Uri *ret;
6134 HRESULT hr;
6136 Uri *proc_uri = base;
6137 DWORD create_flags = 0, len = 0;
6138
6139 memset(&data, 0, sizeof(parse_data));
6140
6141 /* Base case is when the relative Uri has a scheme name,
6142 * if it does, then 'result' will contain the same data
6143 * as the relative Uri.
6144 */
6145 if(relative->scheme_start > -1) {
6146 data.uri = SysAllocString(relative->raw_uri);
6147 if(!data.uri) {
6148 *result = NULL;
6149 return E_OUTOFMEMORY;
6150 }
6151
6152 parse_uri(&data, Uri_CREATE_ALLOW_IMPLICIT_FILE_SCHEME);
6153
6154 hr = Uri_Construct(NULL, (void**)&ret);
6155 if(FAILED(hr)) {
6156 *result = NULL;
6157 return hr;
6158 }
6159
6160 if(extras & COMBINE_URI_FORCE_FLAG_USE) {
6162 create_flags |= Uri_CREATE_NO_CANONICALIZE;
6164 create_flags |= Uri_CREATE_NO_DECODE_EXTRA_INFO;
6165 }
6166
6167 ret->raw_uri = data.uri;
6169 if(FAILED(hr)) {
6170 IUri_Release(&ret->IUri_iface);
6171 *result = NULL;
6172 return hr;
6173 }
6174
6176 ret->create_flags = create_flags;
6177
6178 *result = &ret->IUri_iface;
6179 } else {
6180 WCHAR *path = NULL;
6181 DWORD raw_flags = 0;
6182
6183 if(base->scheme_start > -1) {
6184 data.scheme = base->canon_uri+base->scheme_start;
6185 data.scheme_len = base->scheme_len;
6186 data.scheme_type = base->scheme_type;
6187 } else {
6188 data.is_relative = TRUE;
6189 data.scheme_type = URL_SCHEME_UNKNOWN;
6190 create_flags |= Uri_CREATE_ALLOW_RELATIVE;
6191 }
6192
6193 if(relative->authority_start > -1)
6194 proc_uri = relative;
6195
6196 if(proc_uri->authority_start > -1) {
6197 if(proc_uri->userinfo_start > -1 && proc_uri->userinfo_split != 0) {
6198 data.username = proc_uri->canon_uri+proc_uri->userinfo_start;
6199 data.username_len = (proc_uri->userinfo_split > -1) ? proc_uri->userinfo_split : proc_uri->userinfo_len;
6200 }
6201
6202 if(proc_uri->userinfo_split > -1) {
6203 data.password = proc_uri->canon_uri+proc_uri->userinfo_start+proc_uri->userinfo_split+1;
6204 data.password_len = proc_uri->userinfo_len-proc_uri->userinfo_split-1;
6205 }
6206
6207 if(proc_uri->host_start > -1) {
6208 const WCHAR *host = proc_uri->canon_uri+proc_uri->host_start;
6209 parse_host(&host, &data, 0);
6210 }
6211
6212 if(proc_uri->has_port) {
6213 data.has_port = TRUE;
6214 data.port_value = proc_uri->port;
6215 }
6216 } else if(base->scheme_type != URL_SCHEME_FILE)
6217 data.is_opaque = TRUE;
6218
6219 if(proc_uri == relative || relative->path_start == -1 || !relative->path_len) {
6220 if(proc_uri->path_start > -1) {
6221 data.path = proc_uri->canon_uri+proc_uri->path_start;
6222 data.path_len = proc_uri->path_len;
6223 } else if(!data.is_opaque) {
6224 /* Just set the path as a '/' if the base didn't have
6225 * one and if it's a hierarchical URI.
6226 */
6227 data.path = L"/";
6228 data.path_len = 1;
6229 }
6230
6231 if(relative->query_start > -1)
6232 proc_uri = relative;
6233
6234 if(proc_uri->query_start > -1) {
6235 data.query = proc_uri->canon_uri+proc_uri->query_start;
6236 data.query_len = proc_uri->query_len;
6237 }
6238 } else {
6239 const WCHAR *ptr, **pptr;
6240 DWORD path_offset = 0, path_len = 0;
6241
6242 /* There's two possibilities on what will happen to the path component
6243 * of the result IUri. First, if the relative path begins with a '/'
6244 * then the resulting path will just be the relative path. Second, if
6245 * relative path doesn't begin with a '/' then the base path and relative
6246 * path are merged together.
6247 */
6248 if(relative->path_len && *(relative->canon_uri+relative->path_start) == '/' && data.scheme_type != URL_SCHEME_MK) {
6249 WCHAR *tmp = NULL;
6250 BOOL copy_drive_path = FALSE;
6251
6252 /* If the relative IUri's path starts with a '/', then we
6253 * don't use the base IUri's path. Unless the base IUri
6254 * is a file URI, in which case it uses the drive path of
6255 * the base IUri (if it has any) in the new path.
6256 */
6257 if(base->scheme_type == URL_SCHEME_FILE) {
6258 if(base->path_len > 3 && *(base->canon_uri+base->path_start) == '/' &&
6259 is_drive_path(base->canon_uri+base->path_start+1)) {
6260 path_len += 3;
6261 copy_drive_path = TRUE;
6262 }
6263 }
6264
6265 path_len += relative->path_len;
6266
6267 path = malloc((path_len + 1) * sizeof(WCHAR));
6268 if(!path) {
6269 *result = NULL;
6270 return E_OUTOFMEMORY;
6271 }
6272
6273 tmp = path;
6274
6275 /* Copy the base paths, drive path over. */
6276 if(copy_drive_path) {
6277 memcpy(tmp, base->canon_uri+base->path_start, 3*sizeof(WCHAR));
6278 tmp += 3;
6279 }
6280
6281 memcpy(tmp, relative->canon_uri+relative->path_start, relative->path_len*sizeof(WCHAR));
6282 path[path_len] = '\0';
6283 } else {
6284 /* Merge the base path with the relative path. */
6285 hr = merge_paths(&data, base->canon_uri+base->path_start, base->path_len,
6286 relative->canon_uri+relative->path_start, relative->path_len,
6287 &path, &path_len, flags);
6288 if(FAILED(hr)) {
6289 *result = NULL;
6290 return hr;
6291 }
6292
6293 /* If the resulting IUri is a file URI, the drive path isn't
6294 * reduced out when the dot segments are removed.
6295 */
6296 if(path_len >= 3 && data.scheme_type == URL_SCHEME_FILE && !data.host) {
6297 if(*path == '/' && is_drive_path(path+1))
6298 path_offset = 2;
6299 else if(is_drive_path(path))
6300 path_offset = 1;
6301 }
6302 }
6303
6304 /* Check if the dot segments need to be removed from the path. */
6305 if(!(flags & URL_DONT_SIMPLIFY) && !data.is_opaque) {
6306 DWORD offset = (path_offset > 0) ? path_offset+1 : 0;
6308
6309 if(new_len != path_len) {
6310 WCHAR *tmp = realloc(path, (offset + new_len + 1) * sizeof(WCHAR));
6311 if(!tmp) {
6312 free(path);
6313 *result = NULL;
6314 return E_OUTOFMEMORY;
6315 }
6316
6317 tmp[new_len+offset] = '\0';
6318 path = tmp;
6319 path_len = new_len+offset;
6320 }
6321 }
6322
6323 if(relative->query_start > -1) {
6324 data.query = relative->canon_uri+relative->query_start;
6325 data.query_len = relative->query_len;
6326 }
6327
6328 /* Make sure the path component is valid. */
6329 ptr = path;
6330 pptr = &ptr;
6331 if((data.is_opaque && !parse_path_opaque(pptr, &data, 0)) ||
6332 (!data.is_opaque && !parse_path_hierarchical(pptr, &data, 0))) {
6333 free(path);
6334 *result = NULL;
6335 return E_INVALIDARG;
6336 }
6337 }
6338
6339 if(relative->fragment_start > -1) {
6340 data.fragment = relative->canon_uri+relative->fragment_start;
6341 data.fragment_len = relative->fragment_len;
6342 }
6343
6345 raw_flags |= RAW_URI_FORCE_PORT_DISP;
6347 raw_flags |= RAW_URI_CONVERT_TO_DOS_PATH;
6348
6349 len = generate_raw_uri(&data, data.uri, raw_flags);
6351 if(!data.uri) {
6352 free(path);
6353 *result = NULL;
6354 return E_OUTOFMEMORY;
6355 }
6356
6357 generate_raw_uri(&data, data.uri, raw_flags);
6358
6359 hr = Uri_Construct(NULL, (void**)&ret);
6360 if(FAILED(hr)) {
6361 SysFreeString(data.uri);
6362 free(path);
6363 *result = NULL;
6364 return hr;
6365 }
6366
6368 create_flags |= Uri_CREATE_NO_CANONICALIZE;
6370 create_flags |= Uri_CREATE_FILE_USE_DOS_PATH;
6371
6372 ret->raw_uri = data.uri;
6374 if(FAILED(hr)) {
6375 IUri_Release(&ret->IUri_iface);
6376 *result = NULL;
6377 return hr;
6378 }
6379
6381 ret->display_modifiers |= URI_DISPLAY_NO_DEFAULT_PORT_AUTH;
6382
6384 ret->create_flags = create_flags;
6385 *result = &ret->IUri_iface;
6386
6387 free(path);
6388 }
6389
6390 return S_OK;
6391}
6392
6393/***********************************************************************
6394 * CoInternetCombineIUri (urlmon.@)
6395 */
6396HRESULT WINAPI CoInternetCombineIUri(IUri *pBaseUri, IUri *pRelativeUri, DWORD dwCombineFlags,
6397 IUri **ppCombinedUri, DWORD_PTR dwReserved)
6398{
6399 HRESULT hr;
6401 Uri *relative, *base;
6402 TRACE("(%p %p %lx %p %Ix)\n", pBaseUri, pRelativeUri, dwCombineFlags, ppCombinedUri, dwReserved);
6403
6404 if(!ppCombinedUri)
6405 return E_INVALIDARG;
6406
6407 if(!pBaseUri || !pRelativeUri) {
6408 *ppCombinedUri = NULL;
6409 return E_INVALIDARG;
6410 }
6411
6412 relative = get_uri_obj(pRelativeUri);
6413 base = get_uri_obj(pBaseUri);
6414 if(!relative || !base) {
6415 *ppCombinedUri = NULL;
6416 FIXME("(%p %p %lx %p %Ix) Unknown IUri types not supported yet.\n",
6417 pBaseUri, pRelativeUri, dwCombineFlags, ppCombinedUri, dwReserved);
6418 return E_NOTIMPL;
6419 }
6420
6421 info = get_protocol_info(base->canon_uri);
6422 if(info) {
6424 DWORD result_len = 0;
6425
6426 hr = IInternetProtocolInfo_CombineUrl(info, base->canon_uri, relative->canon_uri, dwCombineFlags,
6427 result, INTERNET_MAX_URL_LENGTH+1, &result_len, 0);
6428 IInternetProtocolInfo_Release(info);
6429 if(SUCCEEDED(hr)) {
6430 hr = CreateUri(result, Uri_CREATE_ALLOW_RELATIVE, 0, ppCombinedUri);
6431 if(SUCCEEDED(hr))
6432 return hr;
6433 }
6434 }
6435
6436 return combine_uri(base, relative, dwCombineFlags, ppCombinedUri, 0);
6437}
6438
6439/***********************************************************************
6440 * CoInternetCombineUrlEx (urlmon.@)
6441 */
6442HRESULT WINAPI CoInternetCombineUrlEx(IUri *pBaseUri, LPCWSTR pwzRelativeUrl, DWORD dwCombineFlags,
6443 IUri **ppCombinedUri, DWORD_PTR dwReserved)
6444{
6445 IUri *relative;
6446 Uri *base;
6447 HRESULT hr;
6449
6450 TRACE("(%p %s %lx %p %Ix)\n", pBaseUri, debugstr_w(pwzRelativeUrl), dwCombineFlags,
6451 ppCombinedUri, dwReserved);
6452
6453 if(!ppCombinedUri)
6454 return E_POINTER;
6455
6456 if(!pwzRelativeUrl) {
6457 *ppCombinedUri = NULL;
6458 return E_UNEXPECTED;
6459 }
6460
6461 if(!pBaseUri) {
6462 *ppCombinedUri = NULL;
6463 return E_INVALIDARG;
6464 }
6465
6466 base = get_uri_obj(pBaseUri);
6467 if(!base) {
6468 *ppCombinedUri = NULL;
6469 FIXME("(%p %s %lx %p %Ix) Unknown IUri's not supported yet.\n", pBaseUri, debugstr_w(pwzRelativeUrl),
6470 dwCombineFlags, ppCombinedUri, dwReserved);
6471 return E_NOTIMPL;
6472 }
6473
6474 info = get_protocol_info(base->canon_uri);
6475 if(info) {
6477 DWORD result_len = 0;
6478
6479 hr = IInternetProtocolInfo_CombineUrl(info, base->canon_uri, pwzRelativeUrl, dwCombineFlags,
6480 result, INTERNET_MAX_URL_LENGTH+1, &result_len, 0);
6481 IInternetProtocolInfo_Release(info);
6482 if(SUCCEEDED(hr)) {
6483 hr = CreateUri(result, Uri_CREATE_ALLOW_RELATIVE, 0, ppCombinedUri);
6484 if(SUCCEEDED(hr))
6485 return hr;
6486 }
6487 }
6488
6489 hr = CreateUri(pwzRelativeUrl, Uri_CREATE_ALLOW_RELATIVE|Uri_CREATE_ALLOW_IMPLICIT_FILE_SCHEME, 0, &relative);
6490 if(FAILED(hr)) {
6491 *ppCombinedUri = NULL;
6492 return hr;
6493 }
6494
6495 hr = combine_uri(base, get_uri_obj(relative), dwCombineFlags, ppCombinedUri, COMBINE_URI_FORCE_FLAG_USE);
6496
6497 IUri_Release(relative);
6498 return hr;
6499}
6500
6502 DWORD output_len, DWORD *result_len)
6503{
6504 const WCHAR *ptr = NULL;
6505 WCHAR *path = NULL;
6506 const WCHAR **pptr;
6507 DWORD len = 0;
6508 BOOL reduce_path;
6509
6510 /* URL_UNESCAPE only has effect if none of the URL_ESCAPE flags are set. */
6511 const BOOL allow_unescape = !(flags & URL_ESCAPE_UNSAFE) &&
6514
6515
6516 /* Check if the dot segments need to be removed from the
6517 * path component.
6518 */
6519 if(uri->scheme_start > -1 && uri->path_start > -1) {
6520 ptr = uri->canon_uri+uri->scheme_start+uri->scheme_len+1;
6521 pptr = &ptr;
6522 }
6523 reduce_path = !(flags & URL_DONT_SIMPLIFY) &&
6524 ptr && check_hierarchical(pptr);
6525
6526 for(ptr = uri->canon_uri; ptr < uri->canon_uri+uri->canon_len; ++ptr) {
6527 BOOL do_default_action = TRUE;
6528
6529 /* Keep track of the path if we need to remove dot segments from
6530 * it later.
6531 */
6532 if(reduce_path && !path && ptr == uri->canon_uri+uri->path_start)
6533 path = output+len;
6534
6535 /* Check if it's time to reduce the path. */
6536 if(reduce_path && ptr == uri->canon_uri+uri->path_start+uri->path_len) {
6537 DWORD current_path_len = (output+len) - path;
6538 DWORD new_path_len = remove_dot_segments(path, current_path_len);
6539
6540 /* Update the current length. */
6541 len -= (current_path_len-new_path_len);
6542 reduce_path = FALSE;
6543 }
6544
6545 if(*ptr == '%') {
6546 const WCHAR decoded = decode_pct_val(ptr);
6547 if(decoded) {
6548 if(allow_unescape && (flags & URL_UNESCAPE)) {
6549 if(len < output_len)
6550 output[len] = decoded;
6551 len++;
6552 ptr += 2;
6553 do_default_action = FALSE;
6554 }
6555 }
6556
6557 /* See if %'s needed to encoded. */
6558 if(do_default_action && (flags & URL_ESCAPE_PERCENT)) {
6559 if(len + 3 < output_len)
6560 pct_encode_val(*ptr, output+len);
6561 len += 3;
6562 do_default_action = FALSE;
6563 }
6564 } else if(*ptr == ' ') {
6566 !(flags & URL_ESCAPE_UNSAFE)) {
6567 if(len + 3 < output_len)
6568 pct_encode_val(*ptr, output+len);
6569 len += 3;
6570 do_default_action = FALSE;
6571 }
6572 } else if(is_ascii(*ptr) && !is_reserved(*ptr) && !is_unreserved(*ptr)) {
6573 if(flags & URL_ESCAPE_UNSAFE) {
6574 if(len + 3 < output_len)
6575 pct_encode_val(*ptr, output+len);
6576 len += 3;
6577 do_default_action = FALSE;
6578 }
6579 }
6580
6581 if(do_default_action) {
6582 if(len < output_len)
6583 output[len] = *ptr;
6584 len++;
6585 }
6586 }
6587
6588 /* Sometimes the path is the very last component of the IUri, so
6589 * see if the dot segments need to be reduced now.
6590 */
6591 if(reduce_path && path) {
6592 DWORD current_path_len = (output+len) - path;
6593 DWORD new_path_len = remove_dot_segments(path, current_path_len);
6594
6595 /* Update the current length. */
6596 len -= (current_path_len-new_path_len);
6597 }
6598
6599 if(len < output_len)
6600 output[len] = 0;
6601 else
6602 output[output_len-1] = 0;
6603
6604 /* The null terminator isn't included in the length. */
6605 *result_len = len;
6606 if(len >= output_len)
6608
6609 return S_OK;
6610}
6611
6612static HRESULT parse_friendly(IUri *uri, LPWSTR output, DWORD output_len,
6613 DWORD *result_len)
6614{
6615 HRESULT hr;
6616 DWORD display_len;
6617 BSTR display;
6618
6619 hr = IUri_GetPropertyLength(uri, Uri_PROPERTY_DISPLAY_URI, &display_len, 0);
6620 if(FAILED(hr)) {
6621 *result_len = 0;
6622 return hr;
6623 }
6624
6625 *result_len = display_len;
6626 if(display_len+1 > output_len)
6628
6629 hr = IUri_GetDisplayUri(uri, &display);
6630 if(FAILED(hr)) {
6631 *result_len = 0;
6632 return hr;
6633 }
6634
6635 memcpy(output, display, (display_len+1)*sizeof(WCHAR));
6637 return S_OK;
6638}
6639
6640static HRESULT parse_rootdocument(const Uri *uri, LPWSTR output, DWORD output_len,
6641 DWORD *result_len)
6642{
6643 static const WCHAR colon_slashesW[] = {':','/','/'};
6644
6645 WCHAR *ptr;
6646 DWORD len = 0;
6647
6648 /* Windows only returns the root document if the URI has an authority
6649 * and it's not an unknown scheme type or a file scheme type.
6650 */
6651 if(uri->authority_start == -1 ||
6652 uri->scheme_type == URL_SCHEME_UNKNOWN ||
6653 uri->scheme_type == URL_SCHEME_FILE) {
6654 *result_len = 0;
6655 if(!output_len)
6657
6658 output[0] = 0;
6659 return S_OK;
6660 }
6661
6662 len = uri->scheme_len+uri->authority_len;
6663 /* For the "://" and '/' which will be added. */
6664 len += 4;
6665
6666 if(len+1 > output_len) {
6667 *result_len = len;
6669 }
6670
6671 ptr = output;
6672 memcpy(ptr, uri->canon_uri+uri->scheme_start, uri->scheme_len*sizeof(WCHAR));
6673
6674 /* Add the "://". */
6675 ptr += uri->scheme_len;
6676 memcpy(ptr, colon_slashesW, sizeof(colon_slashesW));
6677
6678 /* Add the authority. */
6679 ptr += ARRAY_SIZE(colon_slashesW);
6680 memcpy(ptr, uri->canon_uri+uri->authority_start, uri->authority_len*sizeof(WCHAR));
6681
6682 /* Add the '/' after the authority. */
6683 ptr += uri->authority_len;
6684 *ptr = '/';
6685 ptr[1] = 0;
6686
6687 *result_len = len;
6688 return S_OK;
6689}
6690
6691static HRESULT parse_document(const Uri *uri, LPWSTR output, DWORD output_len,
6692 DWORD *result_len)
6693{
6694 DWORD len = 0;
6695
6696 /* It has to be a known scheme type, but, it can't be a file
6697 * scheme. It also has to hierarchical.
6698 */
6699 if(uri->scheme_type == URL_SCHEME_UNKNOWN ||
6700 uri->scheme_type == URL_SCHEME_FILE ||
6701 uri->authority_start == -1) {
6702 *result_len = 0;
6703 if(output_len < 1)
6705
6706 output[0] = 0;
6707 return S_OK;
6708 }
6709
6710 if(uri->fragment_start > -1)
6711 len = uri->fragment_start;
6712 else
6713 len = uri->canon_len;
6714
6715 *result_len = len;
6716 if(len+1 > output_len)
6718
6719 memcpy(output, uri->canon_uri, len*sizeof(WCHAR));
6720 output[len] = 0;
6721 return S_OK;
6722}
6723
6724static HRESULT parse_path_from_url(const Uri *uri, LPWSTR output, DWORD output_len,
6725 DWORD *result_len)
6726{
6727 const WCHAR *path_ptr;
6729 WCHAR *ptr;
6730
6731 if(uri->scheme_type != URL_SCHEME_FILE) {
6732 *result_len = 0;
6733 if(output_len > 0)
6734 output[0] = 0;
6735 return E_INVALIDARG;
6736 }
6737
6738 ptr = buffer;
6739 if(uri->host_start > -1) {
6740 static const WCHAR slash_slashW[] = {'\\','\\'};
6741
6742 memcpy(ptr, slash_slashW, sizeof(slash_slashW));
6743 ptr += ARRAY_SIZE(slash_slashW);
6744 memcpy(ptr, uri->canon_uri+uri->host_start, uri->host_len*sizeof(WCHAR));
6745 ptr += uri->host_len;
6746 }
6747
6748 path_ptr = uri->canon_uri+uri->path_start;
6749 if(uri->path_len > 3 && *path_ptr == '/' && is_drive_path(path_ptr+1))
6750 /* Skip past the '/' in front of the drive path. */
6751 ++path_ptr;
6752
6753 for(; path_ptr < uri->canon_uri+uri->path_start+uri->path_len; ++path_ptr, ++ptr) {
6754 BOOL do_default_action = TRUE;
6755
6756 if(*path_ptr == '%') {
6757 const WCHAR decoded = decode_pct_val(path_ptr);
6758 if(decoded) {
6759 *ptr = decoded;
6760 path_ptr += 2;
6761 do_default_action = FALSE;
6762 }
6763 } else if(*path_ptr == '/') {
6764 *ptr = '\\';
6765 do_default_action = FALSE;
6766 }
6767
6768 if(do_default_action)
6769 *ptr = *path_ptr;
6770 }
6771
6772 *ptr = 0;
6773
6774 *result_len = ptr-buffer;
6775 if(*result_len+1 > output_len)
6777
6778 memcpy(output, buffer, (*result_len+1)*sizeof(WCHAR));
6779 return S_OK;
6780}
6781
6782static HRESULT parse_url_from_path(IUri *uri, LPWSTR output, DWORD output_len,
6783 DWORD *result_len)
6784{
6785 HRESULT hr;
6786 BSTR received;
6787 DWORD len = 0;
6788
6789 hr = IUri_GetPropertyLength(uri, Uri_PROPERTY_ABSOLUTE_URI, &len, 0);
6790 if(FAILED(hr)) {
6791 *result_len = 0;
6792 return hr;
6793 }
6794
6795 *result_len = len;
6796 if(len+1 > output_len)
6798
6799 hr = IUri_GetAbsoluteUri(uri, &received);
6800 if(FAILED(hr)) {
6801 *result_len = 0;
6802 return hr;
6803 }
6804
6805 memcpy(output, received, (len+1)*sizeof(WCHAR));
6807
6808 return S_OK;
6809}
6810
6811static HRESULT parse_schema(IUri *uri, LPWSTR output, DWORD output_len,
6812 DWORD *result_len)
6813{
6814 HRESULT hr;
6815 DWORD len;
6816 BSTR received;
6817
6818 hr = IUri_GetPropertyLength(uri, Uri_PROPERTY_SCHEME_NAME, &len, 0);
6819 if(FAILED(hr)) {
6820 *result_len = 0;
6821 return hr;
6822 }
6823
6824 *result_len = len;
6825 if(len+1 > output_len)
6827
6828 hr = IUri_GetSchemeName(uri, &received);
6829 if(FAILED(hr)) {
6830 *result_len = 0;
6831 return hr;
6832 }
6833
6834 memcpy(output, received, (len+1)*sizeof(WCHAR));
6836
6837 return S_OK;
6838}
6839
6840static HRESULT parse_site(IUri *uri, LPWSTR output, DWORD output_len, DWORD *result_len)
6841{
6842 HRESULT hr;
6843 DWORD len;
6844 BSTR received;
6845
6846 hr = IUri_GetPropertyLength(uri, Uri_PROPERTY_HOST, &len, 0);
6847 if(FAILED(hr)) {
6848 *result_len = 0;
6849 return hr;
6850 }
6851
6852 *result_len = len;
6853 if(len+1 > output_len)
6855
6856 hr = IUri_GetHost(uri, &received);
6857 if(FAILED(hr)) {
6858 *result_len = 0;
6859 return hr;
6860 }
6861
6862 memcpy(output, received, (len+1)*sizeof(WCHAR));
6864
6865 return S_OK;
6866}
6867
6868static HRESULT parse_domain(IUri *uri, LPWSTR output, DWORD output_len, DWORD *result_len)
6869{
6870 HRESULT hr;
6871 DWORD len;
6872 BSTR received;
6873
6874 hr = IUri_GetPropertyLength(uri, Uri_PROPERTY_DOMAIN, &len, 0);
6875 if(FAILED(hr)) {
6876 *result_len = 0;
6877 return hr;
6878 }
6879
6880 *result_len = len;
6881 if(len+1 > output_len)
6883
6884 hr = IUri_GetDomain(uri, &received);
6885 if(FAILED(hr)) {
6886 *result_len = 0;
6887 return hr;
6888 }
6889
6890 memcpy(output, received, (len+1)*sizeof(WCHAR));
6892
6893 return S_OK;
6894}
6895
6896static HRESULT parse_anchor(IUri *uri, LPWSTR output, DWORD output_len, DWORD *result_len)
6897{
6898 HRESULT hr;
6899 DWORD len;
6900 BSTR received;
6901
6902 hr = IUri_GetPropertyLength(uri, Uri_PROPERTY_FRAGMENT, &len, 0);
6903 if(FAILED(hr)) {
6904 *result_len = 0;
6905 return hr;
6906 }
6907
6908 *result_len = len;
6909 if(len+1 > output_len)
6911
6912 hr = IUri_GetFragment(uri, &received);
6913 if(FAILED(hr)) {
6914 *result_len = 0;
6915 return hr;
6916 }
6917
6918 memcpy(output, received, (len+1)*sizeof(WCHAR));
6920
6921 return S_OK;
6922}
6923
6924/***********************************************************************
6925 * CoInternetParseIUri (urlmon.@)
6926 */
6928 LPWSTR pwzResult, DWORD cchResult, DWORD *pcchResult,
6930{
6931 HRESULT hr;
6932 Uri *uri;
6934
6935 TRACE("(%p %d %lx %p %ld %p %Ix)\n", pIUri, ParseAction, dwFlags, pwzResult,
6936 cchResult, pcchResult, dwReserved);
6937
6938 if(!pcchResult)
6939 return E_POINTER;
6940
6941 if(!pwzResult || !pIUri) {
6942 *pcchResult = 0;
6943 return E_INVALIDARG;
6944 }
6945
6946 if(!(uri = get_uri_obj(pIUri))) {
6947 *pcchResult = 0;
6948 FIXME("(%p %d %lx %p %ld %p %Ix) Unknown IUri's not supported for this action.\n",
6949 pIUri, ParseAction, dwFlags, pwzResult, cchResult, pcchResult, dwReserved);
6950 return E_NOTIMPL;
6951 }
6952
6953 info = get_protocol_info(uri->canon_uri);
6954 if(info) {
6955 hr = IInternetProtocolInfo_ParseUrl(info, uri->canon_uri, ParseAction, dwFlags,
6956 pwzResult, cchResult, pcchResult, 0);
6957 IInternetProtocolInfo_Release(info);
6958 if(SUCCEEDED(hr)) return hr;
6959 }
6960
6961 switch(ParseAction) {
6962 case PARSE_CANONICALIZE:
6963 hr = parse_canonicalize(uri, dwFlags, pwzResult, cchResult, pcchResult);
6964 break;
6965 case PARSE_FRIENDLY:
6966 hr = parse_friendly(pIUri, pwzResult, cchResult, pcchResult);
6967 break;
6968 case PARSE_ROOTDOCUMENT:
6969 hr = parse_rootdocument(uri, pwzResult, cchResult, pcchResult);
6970 break;
6971 case PARSE_DOCUMENT:
6972 hr = parse_document(uri, pwzResult, cchResult, pcchResult);
6973 break;
6974 case PARSE_PATH_FROM_URL:
6975 hr = parse_path_from_url(uri, pwzResult, cchResult, pcchResult);
6976 break;
6977 case PARSE_URL_FROM_PATH:
6978 hr = parse_url_from_path(pIUri, pwzResult, cchResult, pcchResult);
6979 break;
6980 case PARSE_SCHEMA:
6981 hr = parse_schema(pIUri, pwzResult, cchResult, pcchResult);
6982 break;
6983 case PARSE_SITE:
6984 hr = parse_site(pIUri, pwzResult, cchResult, pcchResult);
6985 break;
6986 case PARSE_DOMAIN:
6987 hr = parse_domain(pIUri, pwzResult, cchResult, pcchResult);
6988 break;
6989 case PARSE_LOCATION:
6990 case PARSE_ANCHOR:
6991 hr = parse_anchor(pIUri, pwzResult, cchResult, pcchResult);
6992 break;
6993 case PARSE_SECURITY_URL:
6994 case PARSE_MIME:
6995 case PARSE_SERVER:
6996 case PARSE_SECURITY_DOMAIN:
6997 *pcchResult = 0;
6998 hr = E_FAIL;
6999 break;
7000 default:
7001 *pcchResult = 0;
7002 hr = E_NOTIMPL;
7003 FIXME("(%p %d %lx %p %ld %p %Ix) Partial stub.\n", pIUri, ParseAction, dwFlags,
7004 pwzResult, cchResult, pcchResult, dwReserved);
7005 }
7006
7007 return hr;
7008}
INT WINAPI IdnToAscii(DWORD dwFlags, LPCWSTR lpUnicodeCharStr, INT cchUnicodeChar, LPWSTR lpASCIICharStr, INT cchASCIIChar)
Definition: IdnToAscii.c:249
#define InterlockedIncrement
Definition: armddk.h:53
#define InterlockedDecrement
Definition: armddk.h:52
#define WINE_DEFAULT_DEBUG_CHANNEL(t)
Definition: precomp.h:23
#define ARRAY_SIZE(A)
Definition: main.h:20
#define FIXME(fmt,...)
Definition: precomp.h:53
#define ERR(fmt,...)
Definition: precomp.h:57
const GUID IID_IUnknown
#define E_OUTOFMEMORY
Definition: ddrawi.h:100
#define E_INVALIDARG
Definition: ddrawi.h:101
#define E_NOTIMPL
Definition: ddrawi.h:99
#define E_FAIL
Definition: ddrawi.h:102
#define realloc
Definition: debug_ros.c:6
#define free
Definition: debug_ros.c:5
#define malloc
Definition: debug_ros.c:4
HRESULT hr
Definition: delayimp.cpp:582
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
LPWSTR WINAPI StrChrW(LPCWSTR lpszStr, WCHAR ch)
Definition: string.c:464
INT WINAPI StrCmpNIW(LPCWSTR lpszStr, LPCWSTR lpszComp, INT iLen)
Definition: string.c:307
INT WINAPI StrCmpNW(LPCWSTR lpszStr, LPCWSTR lpszComp, INT iLen)
Definition: string.c:500
#define wcsnicmp
Definition: compat.h:14
OLECHAR * BSTR
Definition: compat.h:2293
#define lstrlenW
Definition: compat.h:750
#define USHRT_MAX
Definition: limits.h:23
#define UINT_MAX
Definition: limits.h:27
static wchar_t * wmemchr(const wchar_t *s, wchar_t c, size_t n)
Definition: wchar.h:48
IInternetProtocolInfo * get_protocol_info(LPCWSTR url)
Definition: session.c:173
static HRESULT WINAPI UriBuilderFactory_QueryInterface(IUriBuilderFactory *iface, REFIID riid, void **ppv)
Definition: uri.c:4745
static HRESULT get_builder_component(LPWSTR *component, DWORD *component_len, LPCWSTR source, DWORD source_len, LPCWSTR *output, DWORD *output_len)
Definition: uri.c:3043
static HRESULT parse_site(IUri *uri, LPWSTR output, DWORD output_len, DWORD *result_len)
Definition: uri.c:6840
static BOOL is_reserved(WCHAR val)
Definition: uri.c:324
static HRESULT compare_uris(const Uri *a, const Uri *b, BOOL *ret)
Definition: uri.c:3526
static ULONG WINAPI Marshal_AddRef(IMarshal *iface)
Definition: uri.c:5113
static BOOL has_invalid_flag_combination(DWORD flags)
Definition: uri.c:369
static BOOL is_unc_path(const WCHAR *str)
Definition: uri.c:257
void find_domain_name(const WCHAR *host, DWORD host_len, INT *domain_start)
Definition: uri.c:477
static HRESULT parse_domain(IUri *uri, LPWSTR output, DWORD output_len, DWORD *result_len)
Definition: uri.c:6868
static UriBuilder * impl_from_IUriBuilder(IUriBuilder *iface)
Definition: uri.c:5590
#define URI_DISPLAY_NO_DEFAULT_PORT_AUTH
Definition: uri.c:36
static const IID IID_IUriObj
Definition: uri.c:52
static BOOL is_hierarchical_uri(const WCHAR **ptr, const parse_data *data)
Definition: uri.c:403
static void reset_builder(UriBuilder *builder)
Definition: uri.c:3115
static HRESULT WINAPI Marshal_ReleaseMarshalData(IMarshal *iface, IStream *pStm)
Definition: uri.c:5287
static BOOL parse_hierpart(const WCHAR **ptr, parse_data *data, DWORD flags)
Definition: uri.c:1659
static BOOL parse_path_opaque(const WCHAR **ptr, parse_data *data, DWORD flags)
Definition: uri.c:1599
static BOOL is_default_port(URL_SCHEME scheme, DWORD port)
Definition: uri.c:348
static HRESULT WINAPI Marshal_MarshalInterface(IMarshal *iface, IStream *pStm, REFIID riid, void *pv, DWORD dwDestContext, void *pvDestContext, DWORD mshlflags)
Definition: uri.c:5176
static const IMarshalVtbl MarshalVtbl
Definition: uri.c:5326
static const CHAR hexDigits[]
Definition: uri.c:176
static HRESULT WINAPI UriBuilder_GetIUri(IUriBuilder *iface, IUri **ppIUri)
Definition: uri.c:5701
static BOOL is_gendelim(WCHAR val)
Definition: uri.c:308
static int compute_canonicalized_length(const parse_data *data, DWORD flags)
Definition: uri.c:2937
static HRESULT WINAPI Uri_GetPathAndQuery(IUri *iface, BSTR *pstrPathAndQuery)
Definition: uri.c:4570
HRESULT WINAPI CoInternetCombineIUri(IUri *pBaseUri, IUri *pRelativeUri, DWORD dwCombineFlags, IUri **ppCombinedUri, DWORD_PTR dwReserved)
Definition: uri.c:6396
static HRESULT WINAPI Uri_GetPropertyDWORD(IUri *iface, Uri_PROPERTY uriProp, DWORD *pcchProperty, DWORD dwFlags)
Definition: uri.c:4384
#define RAW_URI_FORCE_PORT_DISP
Definition: uri.c:45
static const IUriBuilderVtbl UriBuilderVtbl
Definition: uri.c:6003
static BOOL parse_path_hierarchical(const WCHAR **ptr, parse_data *data, DWORD flags)
Definition: uri.c:1523
HRESULT WINAPI CreateUri(LPCWSTR pwzURI, DWORD dwFlags, DWORD_PTR dwReserved, IUri **ppURI)
Definition: uri.c:5382
HRESULT WINAPI CoInternetCombineUrlEx(IUri *pBaseUri, LPCWSTR pwzRelativeUrl, DWORD dwCombineFlags, IUri **ppCombinedUri, DWORD_PTR dwReserved)
Definition: uri.c:6442
static BOOL canonicalize_ipv4address(const parse_data *data, Uri *uri, DWORD flags, BOOL computeOnly)
Definition: uri.c:2129
static HRESULT WINAPI Marshal_GetUnmarshalClass(IMarshal *iface, REFIID riid, void *pv, DWORD dwDestContext, void *pvDestContext, DWORD mshlflags, CLSID *pCid)
Definition: uri.c:5125
static const IUriVtbl UriVtbl
Definition: uri.c:4709
static BOOL parse_password(const WCHAR **ptr, parse_data *data, DWORD flags, DWORD extras)
Definition: uri.c:1054
static BOOL parse_ipv4address(const WCHAR **ptr, parse_data *data)
Definition: uri.c:1195
static BOOL is_hexdigit(WCHAR val)
Definition: uri.c:328
static BOOL parse_username(const WCHAR **ptr, parse_data *data, DWORD flags, DWORD extras)
Definition: uri.c:1026
static HRESULT WINAPI UriBuilder_GetPort(IUriBuilder *iface, BOOL *pfHasPort, DWORD *pdwPort)
Definition: uri.c:5807
static HRESULT WINAPI Uri_GetAbsoluteUri(IUri *iface, BSTR *pstrAbsoluteUri)
Definition: uri.c:4516
static HRESULT WINAPI PersistStream_IsDirty(IPersistStream *iface)
Definition: uri.c:4844
static HRESULT WINAPI UriBuilder_GetUserName(IUriBuilder *iface, DWORD *pcchUserName, LPCWSTR *ppwzUserName)
Definition: uri.c:5852
static BOOL canonicalize_userinfo(const parse_data *data, Uri *uri, DWORD flags, BOOL computeOnly)
Definition: uri.c:1937
#define URI_DISPLAY_NO_ABSOLUTE_URI
Definition: uri.c:35
static BOOL is_forbidden_dos_path_char(WCHAR val)
Definition: uri.c:261
static ULONG WINAPI UriBuilderFactory_AddRef(IUriBuilderFactory *iface)
Definition: uri.c:4751
static HRESULT validate_path(const UriBuilder *builder, parse_data *data, DWORD flags)
Definition: uri.c:3319
static HRESULT combine_uri(Uri *base, Uri *relative, DWORD flags, IUri **result, DWORD extras)
Definition: uri.c:6132
static BOOL check_ipv4address(const WCHAR **ptr, BOOL strict)
Definition: uri.c:845
static BOOL is_path_delim(URL_SCHEME scheme, WCHAR val)
Definition: uri.c:334
WCHAR tld_name[4]
Definition: uri.c:225
static HRESULT WINAPI Marshal_DisconnectObject(IMarshal *iface, DWORD dwReserved)
Definition: uri.c:5319
static HRESULT WINAPI PersistStream_Load(IPersistStream *iface, IStream *pStm)
Definition: uri.c:4860
static ULONG WINAPI Marshal_Release(IMarshal *iface)
Definition: uri.c:5119
static BYTE * persist_stream_add_strprop(Uri *This, BYTE *p, DWORD type, DWORD len, WCHAR *data)
Definition: uri.c:4925
static BOOL parse_ipvfuture(const WCHAR **ptr, parse_data *data)
Definition: uri.c:1400
HRESULT WINAPI CoInternetParseIUri(IUri *pIUri, PARSEACTION ParseAction, DWORD dwFlags, LPWSTR pwzResult, DWORD cchResult, DWORD *pcchResult, DWORD_PTR dwReserved)
Definition: uri.c:6927
static BOOL parse_port(const WCHAR **ptr, parse_data *data)
Definition: uri.c:1150
static HRESULT WINAPI UriBuilder_RemoveProperties(IUriBuilder *iface, DWORD dwPropertyMask)
Definition: uri.c:5951
static HRESULT WINAPI Uri_HasProperty(IUri *iface, Uri_PROPERTY uriProp, BOOL *pfHasProperty)
Definition: uri.c:4438
static BOOL parse_host(const WCHAR **ptr, parse_data *data, DWORD extras)
Definition: uri.c:1493
static BOOL parse_authority(const WCHAR **ptr, parse_data *data, DWORD flags)
Definition: uri.c:1510
static HRESULT WINAPI Uri_GetProperties(IUri *iface, DWORD *pdwProperties)
Definition: uri.c:4630
static void persist_stream_save(Uri *This, IStream *pStm, BOOL marshal, struct persist_uri *data)
Definition: uri.c:4938
static HRESULT WINAPI UriBuilder_GetQuery(IUriBuilder *iface, DWORD *pcchQuery, LPCWSTR *ppwzQuery)
Definition: uri.c:5828
static BOOL parse_scheme_name(const WCHAR **ptr, parse_data *data, DWORD extras)
Definition: uri.c:900
static WCHAR decode_pct_val(const WCHAR *ptr)
Definition: uri.c:440
static HRESULT WINAPI UriBuilder_SetPath(IUriBuilder *iface, LPCWSTR pwzNewValue)
Definition: uri.c:5903
#define ALLOW_BRACKETLESS_IP_LITERAL
Definition: uri.c:41
static HRESULT WINAPI UriBuilder_CreateUriWithFlags(IUriBuilder *iface, DWORD dwCreateFlags, DWORD dwUriBuilderFlags, DWORD dwAllowEncodingPropertyMask, DWORD_PTR dwReserved, IUri **ppIUri)
Definition: uri.c:5682
static HRESULT WINAPI UriBuilder_GetPath(IUriBuilder *iface, DWORD *pcchPath, LPCWSTR *ppwzPath)
Definition: uri.c:5795
static HRESULT WINAPI Marshal_GetMarshalSizeMax(IMarshal *iface, REFIID riid, void *pv, DWORD dwDestContext, void *pvDestContext, DWORD mshlflags, DWORD *pSize)
Definition: uri.c:5147
#define COMBINE_URI_FORCE_FLAG_USE
Definition: uri.c:48
static BOOL canonicalize_authority(const parse_data *data, Uri *uri, DWORD flags, BOOL computeOnly)
Definition: uri.c:2399
#define SKIP_IP_FUTURE_CHECK
Definition: uri.c:42
static BOOL is_auth_delim(WCHAR val, BOOL acceptSlash)
Definition: uri.c:318
static HRESULT WINAPI UriBuilder_SetIUri(IUriBuilder *iface, IUri *pIUri)
Definition: uri.c:5719
static HRESULT generate_uri(const UriBuilder *builder, const parse_data *data, Uri *uri, DWORD flags)
Definition: uri.c:3789
static HRESULT WINAPI UriBuilder_QueryInterface(IUriBuilder *iface, REFIID riid, void **ppv)
Definition: uri.c:5595
HRESULT WINAPI CreateUriWithFragment(LPCWSTR pwzURI, LPCWSTR pwzFragment, DWORD dwFlags, DWORD_PTR dwReserved, IUri **ppURI)
Definition: uri.c:5477
static void convert_to_dos_path(const WCHAR *path, DWORD path_len, WCHAR *output, DWORD *output_len)
Definition: uri.c:3622
static HRESULT WINAPI Uri_GetQuery(IUri *iface, BSTR *pstrQuery)
Definition: uri.c:4576
#define ALLOW_NULL_TERM_SCHEME
Definition: uri.c:38
static DWORD ui2str(WCHAR *dest, UINT value)
Definition: uri.c:727
static const IPersistStreamVtbl PersistStreamVtbl
Definition: uri.c:5091
#define ALLOW_NULL_TERM_USER_NAME
Definition: uri.c:39
static void destroy_uri_obj(Uri *This)
Definition: uri.c:3814
static BOOL canonicalize_fragment(const parse_data *data, Uri *uri, DWORD flags, BOOL computeOnly)
Definition: uri.c:2843
static BOOL check_hierarchical(const WCHAR **ptr)
Definition: uri.c:275
#define IGNORE_PORT_DELIMITER
Definition: uri.c:43
static HRESULT WINAPI UriBuilder_SetSchemeName(IUriBuilder *iface, LPCWSTR pwzNewValue)
Definition: uri.c:5930
static HRESULT WINAPI Uri_GetZone(IUri *iface, DWORD *pdwZone)
Definition: uri.c:4624
static HRESULT parse_anchor(IUri *uri, LPWSTR output, DWORD output_len, DWORD *result_len)
Definition: uri.c:6896
static BOOL parse_scheme(const WCHAR **ptr, parse_data *data, DWORD flags, DWORD extras)
Definition: uri.c:977
static const struct @614 recognized_tlds[]
static HRESULT WINAPI Marshal_UnmarshalInterface(IMarshal *iface, IStream *pStm, REFIID riid, void **ppv)
Definition: uri.c:5229
HRESULT WINAPI CreateIUriBuilder(IUri *pIUri, DWORD dwFlags, DWORD_PTR dwReserved, IUriBuilder **ppIUriBuilder)
Definition: uri.c:6035
static HRESULT WINAPI UriBuilder_CreateUri(IUriBuilder *iface, DWORD dwCreateFlags, DWORD dwAllowEncodingPropertyMask, DWORD_PTR dwReserved, IUri **ppIUri)
Definition: uri.c:5662
static HRESULT WINAPI Uri_IsEqual(IUri *iface, IUri *pUri, BOOL *pfEqual)
Definition: uri.c:4680
static HRESULT WINAPI UriBuilder_GetFragment(IUriBuilder *iface, DWORD *pcchFragment, LPCWSTR *ppwzFragment)
Definition: uri.c:5751
static HRESULT parse_path_from_url(const Uri *uri, LPWSTR output, DWORD output_len, DWORD *result_len)
Definition: uri.c:6724
static ULONG WINAPI UriBuilderFactory_Release(IUriBuilderFactory *iface)
Definition: uri.c:4757
static BOOL check_implicit_ipv4(const WCHAR **ptr, UINT *val)
Definition: uri.c:813
static HRESULT WINAPI Uri_GetDomain(IUri *iface, BSTR *pstrDomain)
Definition: uri.c:4534
static HRESULT WINAPI Uri_GetPropertyBSTR(IUri *iface, Uri_PROPERTY uriProp, BSTR *pbstrProperty, DWORD dwFlags)
Definition: uri.c:3877
static HRESULT WINAPI UriBuilder_SetPort(IUriBuilder *iface, BOOL fHasPort, DWORD dwNewValue)
Definition: uri.c:5911
static HRESULT WINAPI Uri_GetPropertyLength(IUri *iface, Uri_PROPERTY uriProp, DWORD *pcchProperty, DWORD dwFlags)
Definition: uri.c:4223
static HRESULT WINAPI Uri_GetUserInfo(IUri *iface, BSTR *pstrUserInfo)
Definition: uri.c:4594
static DWORD canonicalize_path_hierarchical(const WCHAR *path, DWORD path_len, URL_SCHEME scheme_type, BOOL has_host, DWORD flags, BOOL is_implicit_scheme, WCHAR *ret_path)
Definition: uri.c:2449
static const struct @613 default_ports[]
static BOOL is_unreserved(WCHAR val)
Definition: uri.c:292
static HRESULT WINAPI UriBuilder_CreateUriSimple(IUriBuilder *iface, DWORD dwAllowEncodingPropertyMask, DWORD_PTR dwReserved, IUri **ppIUri)
Definition: uri.c:5647
static ULONG WINAPI PersistStream_Release(IPersistStream *iface)
Definition: uri.c:4826
static HRESULT WINAPI Uri_GetPassword(IUri *iface, BSTR *pstrPassword)
Definition: uri.c:4558
static HRESULT WINAPI Uri_GetScheme(IUri *iface, DWORD *pdwScheme)
Definition: uri.c:4618
static HRESULT parse_rootdocument(const Uri *uri, LPWSTR output, DWORD output_len, DWORD *result_len)
Definition: uri.c:6640
HRESULT Uri_Construct(IUnknown *pUnkOuter, LPVOID *ppobj)
Definition: uri.c:5338
static HRESULT validate_userinfo(const UriBuilder *builder, parse_data *data, DWORD flags)
Definition: uri.c:3258
static HRESULT WINAPI Uri_GetUserName(IUri *iface, BSTR *pstrUserName)
Definition: uri.c:4600
static HRESULT WINAPI PersistStream_Save(IPersistStream *iface, IStream *pStm, BOOL fClearDirty)
Definition: uri.c:5019
static BOOL canonicalize_reg_name(const parse_data *data, Uri *uri, DWORD flags, BOOL computeOnly)
Definition: uri.c:1984
static BOOL canonicalize_username(const parse_data *data, Uri *uri, DWORD flags, BOOL computeOnly)
Definition: uri.c:1823
static Uri * impl_from_IMarshal(IMarshal *iface)
Definition: uri.c:5102
static BOOL parse_ipv6address(const WCHAR **ptr, parse_data *data)
Definition: uri.c:1386
static BOOL is_slash(WCHAR c)
Definition: uri.c:338
static void apply_default_flags(DWORD *flags)
Definition: uri.c:380
static BOOL is_implicit_file_path(const WCHAR *str)
Definition: uri.c:268
static HRESULT validate_query(const UriBuilder *builder, parse_data *data, DWORD flags)
Definition: uri.c:3361
static BOOL parse_scheme_type(parse_data *data)
Definition: uri.c:939
static HRESULT WINAPI Marshal_QueryInterface(IMarshal *iface, REFIID riid, void **ppvObject)
Definition: uri.c:5107
static BOOL is_hierarchical_scheme(URL_SCHEME type)
Definition: uri.c:360
#define ALLOW_NULL_TERM_PASSWORD
Definition: uri.c:40
URL_SCHEME scheme
Definition: uri.c:180
static void setup_port(const UriBuilder *builder, parse_data *data, DWORD flags)
Definition: uri.c:3304
static Uri * impl_from_IUriBuilderFactory(IUriBuilderFactory *iface)
Definition: uri.c:4740
static HRESULT WINAPI UriBuilderFactory_CreateInitializedIUriBuilder(IUriBuilderFactory *iface, DWORD dwFlags, DWORD_PTR dwReserved, IUriBuilder **ppIUriBuilder)
Definition: uri.c:4782
static HRESULT validate_fragment(const UriBuilder *builder, parse_data *data, DWORD flags)
Definition: uri.c:3392
static HRESULT merge_paths(parse_data *data, const WCHAR *base, DWORD base_len, const WCHAR *relative, DWORD relative_len, WCHAR **result, DWORD *result_len, DWORD flags)
Definition: uri.c:6082
#define RAW_URI_CONVERT_TO_DOS_PATH
Definition: uri.c:46
static HRESULT WINAPI Uri_GetExtension(IUri *iface, BSTR *pstrExtension)
Definition: uri.c:4540
static BOOL canonicalize_scheme(const parse_data *data, Uri *uri, DWORD flags, BOOL computeOnly)
Definition: uri.c:2894
static DWORD generate_raw_uri(const parse_data *data, BSTR uri, DWORD flags)
Definition: uri.c:3645
static BOOL is_subdelim(WCHAR val)
Definition: uri.c:300
static HRESULT WINAPI Uri_GetPath(IUri *iface, BSTR *pstrPath)
Definition: uri.c:4564
static ULONG WINAPI Uri_Release(IUri *iface)
Definition: uri.c:3864
static HRESULT WINAPI Uri_GetFragment(IUri *iface, BSTR *pstrFragment)
Definition: uri.c:4546
static BOOL canonicalize_host(const parse_data *data, Uri *uri, DWORD flags, BOOL computeOnly)
Definition: uri.c:2272
static ULONG WINAPI UriBuilder_AddRef(IUriBuilder *iface)
Definition: uri.c:5615
WCHAR scheme_name[16]
Definition: uri.c:181
static HRESULT WINAPI PersistStream_GetClassID(IPersistStream *iface, CLSID *pClassID)
Definition: uri.c:4832
static Uri * get_uri_obj(IUri *uri)
Definition: uri.c:236
static DWORD ui2ipv4(WCHAR *dest, UINT address)
Definition: uri.c:709
static HRESULT parse_canonicalize(const Uri *uri, DWORD flags, LPWSTR output, DWORD output_len, DWORD *result_len)
Definition: uri.c:6501
static ULONG WINAPI PersistStream_AddRef(IPersistStream *iface)
Definition: uri.c:4820
static BOOL parse_fragment(const WCHAR **ptr, parse_data *data, DWORD flags)
Definition: uri.c:1761
static BOOL parse_reg_name(const WCHAR **ptr, parse_data *data, DWORD extras)
Definition: uri.c:1256
static HRESULT WINAPI UriBuilder_SetPassword(IUriBuilder *iface, LPCWSTR pwzNewValue)
Definition: uri.c:5895
static BOOL parse_uri(parse_data *data, DWORD flags)
Definition: uri.c:1798
static HRESULT WINAPI UriBuilder_GetSchemeName(IUriBuilder *iface, DWORD *pcchSchemeName, LPCWSTR *ppwzSchemeName)
Definition: uri.c:5840
static HRESULT WINAPI UriBuilder_HasBeenModified(IUriBuilder *iface, BOOL *pfModified)
Definition: uri.c:5991
static HRESULT WINAPI Uri_GetHost(IUri *iface, BSTR *pstrHost)
Definition: uri.c:4552
static ULONG WINAPI Uri_AddRef(IUri *iface)
Definition: uri.c:3854
static BOOL canonicalize_query(const parse_data *data, Uri *uri, DWORD flags, BOOL computeOnly)
Definition: uri.c:2793
static HRESULT validate_host(const UriBuilder *builder, parse_data *data)
Definition: uri.c:3272
static BOOL is_ascii(WCHAR c)
Definition: uri.c:343
static BOOL canonicalize_implicit_ipv4address(const parse_data *data, Uri *uri, DWORD flags, BOOL computeOnly)
Definition: uri.c:2080
static const IUriBuilderFactoryVtbl UriBuilderFactoryVtbl
Definition: uri.c:4801
static HRESULT WINAPI Uri_GetPort(IUri *iface, DWORD *pdwPort)
Definition: uri.c:4612
static BOOL parse_ip_literal(const WCHAR **ptr, parse_data *data, DWORD extras)
Definition: uri.c:1443
static void pct_encode_val(WCHAR val, WCHAR *dest)
Definition: uri.c:461
static HRESULT validate_password(const UriBuilder *builder, parse_data *data, DWORD flags)
Definition: uri.c:3223
static BOOL check_pct_encoded(const WCHAR **ptr)
Definition: uri.c:744
static HRESULT WINAPI Uri_GetAuthority(IUri *iface, BSTR *pstrAuthority)
Definition: uri.c:4522
static HRESULT parse_document(const Uri *uri, LPWSTR output, DWORD output_len, DWORD *result_len)
Definition: uri.c:6691
static const struct @612 recognized_schemes[]
static BOOL canonicalize_password(const parse_data *data, Uri *uri, DWORD flags, BOOL computeOnly)
Definition: uri.c:1871
static BOOL check_dec_octet(const WCHAR **ptr)
Definition: uri.c:772
static HRESULT parse_url_from_path(IUri *uri, LPWSTR output, DWORD output_len, DWORD *result_len)
Definition: uri.c:6782
static HRESULT WINAPI UriBuilder_SetFragment(IUriBuilder *iface, LPCWSTR pwzNewValue)
Definition: uri.c:5874
static int hex_to_int(WCHAR val)
Definition: uri.c:421
static HRESULT validate_scheme_name(const UriBuilder *builder, parse_data *data, DWORD flags)
Definition: uri.c:3153
static BOOL canonicalize_port(const parse_data *data, Uri *uri, DWORD flags, BOOL computeOnly)
Definition: uri.c:2327
static HRESULT WINAPI UriBuilderFactory_CreateIUriBuilder(IUriBuilderFactory *iface, DWORD dwFlags, DWORD_PTR dwReserved, IUriBuilder **ppIUriBuilder)
Definition: uri.c:4763
static HRESULT WINAPI UriBuilder_SetHost(IUriBuilder *iface, LPCWSTR pwzNewValue)
Definition: uri.c:5882
static HRESULT parse_schema(IUri *uri, LPWSTR output, DWORD output_len, DWORD *result_len)
Definition: uri.c:6811
static ULONG WINAPI UriBuilder_Release(IUriBuilder *iface)
Definition: uri.c:5625
static HRESULT WINAPI UriBuilder_GetPassword(IUriBuilder *iface, DWORD *pcchPassword, LPCWSTR *ppwzPassword)
Definition: uri.c:5781
static BOOL canonicalize_path_opaque(const parse_data *data, Uri *uri, DWORD flags, BOOL computeOnly)
Definition: uri.c:2594
static HRESULT validate_components(const UriBuilder *builder, parse_data *data, DWORD flags)
Definition: uri.c:3423
static Uri * impl_from_IPersistStream(IPersistStream *iface)
Definition: uri.c:4809
static BSTR pre_process_uri(LPCWSTR uri)
Definition: uri.c:666
static Uri * impl_from_IUri(IUri *iface)
Definition: uri.c:3809
static DWORD remove_dot_segments(WCHAR *path, DWORD path_len)
Definition: uri.c:595
static HRESULT WINAPI Uri_GetRawUri(IUri *iface, BSTR *pstrRawUri)
Definition: uri.c:4582
static HRESULT parse_friendly(IUri *uri, LPWSTR output, DWORD output_len, DWORD *result_len)
Definition: uri.c:6612
static BOOL is_num(WCHAR val)
Definition: uri.c:249
static BOOL is_drive_path(const WCHAR *str)
Definition: uri.c:253
static HRESULT WINAPI UriBuilder_SetUserName(IUriBuilder *iface, LPCWSTR pwzNewValue)
Definition: uri.c:5943
static HRESULT WINAPI Uri_GetSchemeName(IUri *iface, BSTR *pstrSchemeName)
Definition: uri.c:4588
static HRESULT build_uri(const UriBuilder *builder, IUri **uri, DWORD create_flags, DWORD use_orig_flags, DWORD encoding_mask)
Definition: uri.c:5532
static INT find_file_extension(const WCHAR *path, DWORD path_len)
Definition: uri.c:651
static HRESULT WINAPI Uri_QueryInterface(IUri *iface, REFIID riid, void **ppv)
Definition: uri.c:3821
static HRESULT WINAPI UriBuilder_GetHost(IUriBuilder *iface, DWORD *pcchHost, LPCWSTR *ppwzHost)
Definition: uri.c:5763
static HRESULT canonicalize_uri(const parse_data *data, Uri *uri, DWORD flags)
Definition: uri.c:2978
static BOOL parse_query(const WCHAR **ptr, parse_data *data, DWORD flags)
Definition: uri.c:1722
static HRESULT WINAPI PersistStream_GetSizeMax(IPersistStream *iface, ULARGE_INTEGER *pcbSize)
Definition: uri.c:5046
static BOOL canonicalize_hierpart(const parse_data *data, Uri *uri, DWORD flags, BOOL computeOnly)
Definition: uri.c:2702
static void parse_userinfo(const WCHAR **ptr, parse_data *data, DWORD flags)
Definition: uri.c:1101
static HRESULT validate_username(const UriBuilder *builder, parse_data *data, DWORD flags)
Definition: uri.c:3186
static HRESULT set_builder_component(LPWSTR *component, DWORD *component_len, LPCWSTR new_value, WCHAR prefix, DWORD *flags, DWORD success_flag)
Definition: uri.c:3082
static HRESULT compare_file_paths(const Uri *a, const Uri *b, BOOL *ret)
Definition: uri.c:3478
static HRESULT WINAPI UriBuilder_SetQuery(IUriBuilder *iface, LPCWSTR pwzNewValue)
Definition: uri.c:5922
static HRESULT WINAPI Uri_GetDisplayUri(IUri *iface, BSTR *pstrDisplayUri)
Definition: uri.c:4528
USHORT port
Definition: uri.c:210
static HRESULT WINAPI Uri_GetHostType(IUri *iface, DWORD *pdwHostType)
Definition: uri.c:4606
static HRESULT WINAPI PersistStream_QueryInterface(IPersistStream *iface, REFIID riid, void **ppvObject)
Definition: uri.c:4814
static BOOL canonicalize_ipv6address(const parse_data *data, Uri *uri, DWORD flags, BOOL computeOnly)
Definition: uri.c:2238
#define swprintf
Definition: precomp.h:40
return ret
Definition: mutex.c:146
#define L(x)
Definition: resources.c:13
r received
Definition: btrfs.c:3005
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned long DWORD
Definition: ntddk_ex.h:95
BOOLEAN valid
GLuint start
Definition: gl.h:1545
GLuint GLuint GLsizei GLenum type
Definition: gl.h:1545
GLuint GLuint end
Definition: gl.h:1545
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: gl.h:1950
GLuint address
Definition: glext.h:9393
GLuint buffer
Definition: glext.h:5915
GLsizeiptr size
Definition: glext.h:5919
GLintptr offset
Definition: glext.h:5920
const GLubyte * c
Definition: glext.h:8905
GLboolean GLboolean GLboolean b
Definition: glext.h:6204
GLuint in
Definition: glext.h:9616
GLbitfield flags
Definition: glext.h:7161
GLuint GLsizei GLsizei * length
Definition: glext.h:6040
GLuint GLfloat * val
Definition: glext.h:7180
GLuint64EXT * result
Definition: glext.h:11304
GLfloat GLfloat p
Definition: glext.h:8902
GLenum GLsizei len
Definition: glext.h:6722
GLboolean GLboolean GLboolean GLboolean a
Definition: glext.h:6204
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
unsigned int UINT
Definition: sysinfo.c:13
REFIID riid
Definition: atlbase.h:39
REFIID LPVOID * ppv
Definition: atlbase.h:39
#define S_OK
Definition: intsafe.h:52
#define SUCCEEDED(hr)
Definition: intsafe.h:50
#define FAILED(hr)
Definition: intsafe.h:51
static const int digits[]
Definition: decode.c:71
#define b
Definition: ke_i.h:79
#define debugstr_guid
Definition: kernel32.h:35
#define debugstr_wn
Definition: kernel32.h:33
#define debugstr_w
Definition: kernel32.h:32
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
static PVOID ptr
Definition: dispmode.c:27
static DWORD path_len
Definition: batch.c:31
static LPWSTR PDWORD pcchPath
Definition: asmcache.c:747
HRESULT hres
Definition: protocol.c:465
#define cmp(status, error)
Definition: error.c:118
static int strict
Definition: error.c:55
static char * dest
Definition: rtl.c:149
static PARSEACTION
Definition: misc.c:71
const WCHAR * uri
Definition: sec_mgr.c:1564
DWORD create_flags
Definition: sec_mgr.c:1565
static WCHAR password[]
Definition: url.c:33
static WCHAR username[]
Definition: url.c:32
int other
Definition: msacm.c:1376
_In_ HANDLE _In_ DWORD _In_ DWORD _Inout_opt_ LPOVERLAPPED _In_opt_ LPTRANSMIT_FILE_BUFFERS _In_ DWORD dwReserved
Definition: mswsock.h:95
NTSYSAPI NTSTATUS NTAPI RtlIpv6StringToAddressW(_In_ PCWSTR String, _Out_ PCWSTR *Terminator, _Out_ struct in6_addr *Addr)
Definition: network.c:1005
NTSYSAPI NTSTATUS NTAPI RtlIpv6AddressToStringExW(_In_ const struct in6_addr *Address, _In_ ULONG ScopeId, _In_ USHORT Port, _Out_writes_to_(*AddressStringLength, *AddressStringLength) PWCHAR AddressString, _Inout_ PULONG AddressStringLength)
Definition: network.c:649
_In_ LPWSTR _In_ DWORD _In_ DWORD _In_ DWORD dwFlags
Definition: netsh.h:141
#define DWORD
Definition: nt_native.h:44
BSTR WINAPI SysAllocString(LPCOLESTR str)
Definition: oleaut.c:240
UINT WINAPI SysStringLen(BSTR str)
Definition: oleaut.c:198
void WINAPI DECLSPEC_HOTPATCH SysFreeString(BSTR str)
Definition: oleaut.c:273
BSTR WINAPI SysAllocStringLen(const OLECHAR *str, unsigned int len)
Definition: oleaut.c:341
short WCHAR
Definition: pedump.c:58
long LONG
Definition: pedump.c:60
unsigned short USHORT
Definition: pedump.c:61
char CHAR
Definition: pedump.c:57
const GUID IID_IPersistStream
Definition: proxy.cpp:13
#define IsEqualGUID(rguid1, rguid2)
Definition: guiddef.h:147
#define REFIID
Definition: guiddef.h:118
#define URL_ESCAPE_UNSAFE
Definition: shlwapi.h:533
URL_SCHEME
Definition: shlwapi.h:542
@ URL_SCHEME_SNEWS
Definition: shlwapi.h:557
@ URL_SCHEME_MAILTO
Definition: shlwapi.h:548
@ URL_SCHEME_LOCAL
Definition: shlwapi.h:558
@ URL_SCHEME_MK
Definition: shlwapi.h:554
@ URL_SCHEME_TELNET
Definition: shlwapi.h:551
@ URL_SCHEME_UNKNOWN
Definition: shlwapi.h:544
@ URL_SCHEME_MSSHELLROOTED
Definition: shlwapi.h:564
@ URL_SCHEME_WAIS
Definition: shlwapi.h:552
@ URL_SCHEME_HTTPS
Definition: shlwapi.h:555
@ URL_SCHEME_FTP
Definition: shlwapi.h:545
@ URL_SCHEME_RES
Definition: shlwapi.h:562
@ URL_SCHEME_NEWS
Definition: shlwapi.h:549
@ URL_SCHEME_MSSHELLIDLIST
Definition: shlwapi.h:565
@ URL_SCHEME_HTTP
Definition: shlwapi.h:546
@ URL_SCHEME_FILE
Definition: shlwapi.h:553
@ URL_SCHEME_WILDCARD
Definition: shlwapi.h:570
@ URL_SCHEME_ABOUT
Definition: shlwapi.h:561
@ URL_SCHEME_NNTP
Definition: shlwapi.h:550
@ URL_SCHEME_SHELL
Definition: shlwapi.h:556
@ URL_SCHEME_VBSCRIPT
Definition: shlwapi.h:560
@ URL_SCHEME_MSHELP
Definition: shlwapi.h:566
@ URL_SCHEME_GOPHER
Definition: shlwapi.h:547
@ URL_SCHEME_JAVASCRIPT
Definition: shlwapi.h:559
#define URL_UNESCAPE
Definition: shlwapi.h:532
#define URL_ESCAPE_SPACES_ONLY
Definition: shlwapi.h:530
#define URL_DONT_SIMPLIFY
Definition: shlwapi.h:531
#define URL_FILE_USE_PATHURL
Definition: shlwapi.h:523
#define URL_DONT_UNESCAPE_EXTRA_INFO
Definition: shlwapi.h:539
#define URL_ESCAPE_PERCENT
Definition: shlwapi.h:521
#define calloc
Definition: rosglue.h:14
const WCHAR * str
#define iswcntrl(_c)
Definition: ctype.h:674
#define iswspace(_c)
Definition: ctype.h:669
#define iswupper(_c)
Definition: ctype.h:665
#define memset(x, y, z)
Definition: compat.h:39
#define is_alpha(c)
Definition: main.cpp:28
#define towlower(c)
Definition: wctype.h:97
#define TRACE(s)
Definition: solgame.cpp:4
#define STRSAFE_E_INSUFFICIENT_BUFFER
Definition: strsafe.h:103
BOOL has_port
Definition: uri.c:122
WCHAR * scheme
Definition: uri.c:128
DWORD password_len
Definition: uri.c:117
DWORD modified_props
Definition: uri.c:108
LONG ref
Definition: uri.c:105
WCHAR * username
Definition: uri.c:131
WCHAR * query
Definition: uri.c:125
DWORD query_len
Definition: uri.c:126
DWORD path_len
Definition: uri.c:120
WCHAR * fragment
Definition: uri.c:110
IUriBuilder IUriBuilder_iface
Definition: uri.c:104
DWORD port
Definition: uri.c:123
Uri * uri
Definition: uri.c:107
DWORD host_len
Definition: uri.c:114
DWORD scheme_len
Definition: uri.c:129
WCHAR * path
Definition: uri.c:119
WCHAR * host
Definition: uri.c:113
DWORD username_len
Definition: uri.c:132
DWORD fragment_len
Definition: uri.c:111
WCHAR * password
Definition: uri.c:116
Definition: uri.c:54
INT path_start
Definition: uri.c:92
DWORD path_len
Definition: uri.c:93
BSTR raw_uri
Definition: uri.c:62
DWORD query_len
Definition: uri.c:97
LONG ref
Definition: uri.c:60
INT fragment_start
Definition: uri.c:99
DWORD scheme_len
Definition: uri.c:72
IUriBuilderFactory IUriBuilderFactory_iface
Definition: uri.c:56
INT query_start
Definition: uri.c:96
IUri IUri_iface
Definition: uri.c:55
DWORD canon_len
Definition: uri.c:67
BOOL has_port
Definition: uri.c:85
INT userinfo_split
Definition: uri.c:77
IMarshal IMarshal_iface
Definition: uri.c:58
WCHAR * canon_uri
Definition: uri.c:65
URL_SCHEME scheme_type
Definition: uri.c:73
INT port_offset
Definition: uri.c:83
INT domain_offset
Definition: uri.c:90
INT userinfo_start
Definition: uri.c:75
DWORD create_flags
Definition: uri.c:69
IPersistStream IPersistStream_iface
Definition: uri.c:57
DWORD fragment_len
Definition: uri.c:100
INT extension_offset
Definition: uri.c:94
Uri_HOST_TYPE host_type
Definition: uri.c:81
DWORD canon_size
Definition: uri.c:66
DWORD host_len
Definition: uri.c:80
INT authority_start
Definition: uri.c:87
DWORD authority_len
Definition: uri.c:88
INT host_start
Definition: uri.c:79
INT scheme_start
Definition: uri.c:71
BOOL display_modifiers
Definition: uri.c:68
DWORD port
Definition: uri.c:84
DWORD userinfo_len
Definition: uri.c:76
struct _ULARGE_INTEGER::@4637 u
Definition: txthost.c:37
Definition: inet.h:67
DWORD unk[4]
Definition: uri.c:5143
DWORD mshlflags
Definition: uri.c:5142
DWORD query_len
Definition: uri.c:170
BOOL has_port
Definition: uri.c:161
DWORD host_len
Definition: uri.c:156
DWORD password_len
Definition: uri.c:153
const WCHAR * username
Definition: uri.c:149
DWORD path_len
Definition: uri.c:167
IN6_ADDR ipv6_address
Definition: uri.c:159
BOOL has_implicit_scheme
Definition: uri.c:140
URL_SCHEME scheme_type
Definition: uri.c:147
DWORD port_len
Definition: uri.c:163
DWORD port_value
Definition: uri.c:164
UINT implicit_ipv4
Definition: uri.c:142
DWORD username_len
Definition: uri.c:150
Uri_HOST_TYPE host_type
Definition: uri.c:157
BSTR uri
Definition: uri.c:136
BOOL is_relative
Definition: uri.c:138
BOOL is_opaque
Definition: uri.c:139
const WCHAR * scheme
Definition: uri.c:145
BOOL must_have_path
Definition: uri.c:143
const WCHAR * password
Definition: uri.c:152
DWORD fragment_len
Definition: uri.c:173
const WCHAR * host
Definition: uri.c:155
const WCHAR * path
Definition: uri.c:166
const WCHAR * fragment
Definition: uri.c:172
const WCHAR * query
Definition: uri.c:169
DWORD scheme_len
Definition: uri.c:146
BOOL has_implicit_ip
Definition: uri.c:141
const WCHAR * port
Definition: uri.c:162
DWORD size
Definition: uri.c:4852
DWORD unk1[2]
Definition: uri.c:4853
DWORD create_flags
Definition: uri.c:4854
DWORD unk2[3]
Definition: uri.c:4855
DWORD fields_no
Definition: uri.c:4856
Definition: send.c:48
Character const *const prefix
Definition: tempnam.cpp:195
const uint16_t * LPCWSTR
Definition: typedefs.h:57
unsigned char UCHAR
Definition: typedefs.h:53
uint32_t DWORD_PTR
Definition: typedefs.h:65
uint16_t * LPWSTR
Definition: typedefs.h:56
int32_t INT
Definition: typedefs.h:58
uint64_t ULONGLONG
Definition: typedefs.h:67
#define CONTAINING_RECORD(address, type, field)
Definition: typedefs.h:260
uint32_t ULONG
Definition: typedefs.h:59
struct _LARGE_INTEGER::@2527 u
Definition: pdh_main.c:96
GUID const CLSID_CUri
wchar_t tm const _CrtWcstime_Writes_and_advances_ptr_ count wchar_t ** out
Definition: wcsftime.cpp:383
#define WINAPI
Definition: msvc.h:6
#define S_FALSE
Definition: winerror.h:3451
#define E_NOINTERFACE
Definition: winerror.h:3479
#define INET_E_INVALID_URL
Definition: winerror.h:4652
#define E_UNEXPECTED
Definition: winerror.h:3528
#define E_POINTER
Definition: winerror.h:3480
#define INTERNET_MAX_URL_LENGTH
Definition: wininet.h:51
int * display
Definition: x11stubs.c:12
unsigned char BYTE
Definition: xxhash.c:193