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