ReactOS 0.4.17-dev-357-ga8f14ff
path.c
Go to the documentation of this file.
1/*
2 * Copyright 2018 Nikolay Sivov
3 * Copyright 2018 Zhiyi Zhang
4 * Copyright 2021-2023 Zebediah Figura
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 */
20
21#include <stdarg.h>
22#include <stdbool.h>
23#include <string.h>
24#include <wchar.h>
25
26#include "windef.h"
27#include "winbase.h"
28#include "pathcch.h"
29#include "strsafe.h"
30#include "shlwapi.h"
31#include "wininet.h"
32#include "intshcut.h"
33#include "winternl.h"
34
35#include "kernelbase.h"
36#include "wine/exception.h"
37#include "wine/debug.h"
38#include "wine/heap.h"
39
40#ifndef STATIC_PATHCCH
42#else
43#undef TRACE
44#define TRACE(...)
45#endif /* !STATIC_PATHCCH */
46
47#ifdef __REACTOS__
48
49/* The PathCch functions use size_t, but Wine's implementation uses SIZE_T,
50 * so temporarily change the define'd SIZE_T type to the compatible one... */
51#undef SIZE_T
52#define SIZE_T size_t
53
54#if (_WIN32_WINNT < _WIN32_WINNT_VISTA) || (DLL_EXPORT_VERSION < _WIN32_WINNT_VISTA)
55/* wcsnlen is an NT6+ function. To cover all cases, use a private implementation */
56static inline size_t compat_wcsnlen(const wchar_t* str, size_t size)
57{
59 return size;
60}
61#define wcsnlen compat_wcsnlen
62#endif /* _WIN32_WINNT || DLL_EXPORT_VERSION */
63
64#endif /* __REACTOS__ */
65
66#ifndef STATIC_PATHCCH
67
68static const char hexDigits[] = "0123456789ABCDEF";
69
70static const unsigned char hashdata_lookup[256] =
71{
72 0x01, 0x0e, 0x6e, 0x19, 0x61, 0xae, 0x84, 0x77, 0x8a, 0xaa, 0x7d, 0x76, 0x1b, 0xe9, 0x8c, 0x33,
73 0x57, 0xc5, 0xb1, 0x6b, 0xea, 0xa9, 0x38, 0x44, 0x1e, 0x07, 0xad, 0x49, 0xbc, 0x28, 0x24, 0x41,
74 0x31, 0xd5, 0x68, 0xbe, 0x39, 0xd3, 0x94, 0xdf, 0x30, 0x73, 0x0f, 0x02, 0x43, 0xba, 0xd2, 0x1c,
75 0x0c, 0xb5, 0x67, 0x46, 0x16, 0x3a, 0x4b, 0x4e, 0xb7, 0xa7, 0xee, 0x9d, 0x7c, 0x93, 0xac, 0x90,
76 0xb0, 0xa1, 0x8d, 0x56, 0x3c, 0x42, 0x80, 0x53, 0x9c, 0xf1, 0x4f, 0x2e, 0xa8, 0xc6, 0x29, 0xfe,
77 0xb2, 0x55, 0xfd, 0xed, 0xfa, 0x9a, 0x85, 0x58, 0x23, 0xce, 0x5f, 0x74, 0xfc, 0xc0, 0x36, 0xdd,
78 0x66, 0xda, 0xff, 0xf0, 0x52, 0x6a, 0x9e, 0xc9, 0x3d, 0x03, 0x59, 0x09, 0x2a, 0x9b, 0x9f, 0x5d,
79 0xa6, 0x50, 0x32, 0x22, 0xaf, 0xc3, 0x64, 0x63, 0x1a, 0x96, 0x10, 0x91, 0x04, 0x21, 0x08, 0xbd,
80 0x79, 0x40, 0x4d, 0x48, 0xd0, 0xf5, 0x82, 0x7a, 0x8f, 0x37, 0x69, 0x86, 0x1d, 0xa4, 0xb9, 0xc2,
81 0xc1, 0xef, 0x65, 0xf2, 0x05, 0xab, 0x7e, 0x0b, 0x4a, 0x3b, 0x89, 0xe4, 0x6c, 0xbf, 0xe8, 0x8b,
82 0x06, 0x18, 0x51, 0x14, 0x7f, 0x11, 0x5b, 0x5c, 0xfb, 0x97, 0xe1, 0xcf, 0x15, 0x62, 0x71, 0x70,
83 0x54, 0xe2, 0x12, 0xd6, 0xc7, 0xbb, 0x0d, 0x20, 0x5e, 0xdc, 0xe0, 0xd4, 0xf7, 0xcc, 0xc4, 0x2b,
84 0xf9, 0xec, 0x2d, 0xf4, 0x6f, 0xb6, 0x99, 0x88, 0x81, 0x5a, 0xd9, 0xca, 0x13, 0xa5, 0xe7, 0x47,
85 0xe6, 0x8e, 0x60, 0xe3, 0x3e, 0xb3, 0xf6, 0x72, 0xa2, 0x35, 0xa0, 0xd7, 0xcd, 0xb4, 0x2f, 0x6d,
86 0x2c, 0x26, 0x1f, 0x95, 0x87, 0x00, 0xd8, 0x34, 0x3f, 0x17, 0x25, 0x45, 0x27, 0x75, 0x92, 0xb8,
87 0xa3, 0xc8, 0xde, 0xeb, 0xf8, 0xf3, 0xdb, 0x0a, 0x98, 0x83, 0x7b, 0xe5, 0xcb, 0x4c, 0x78, 0xd1,
88};
89
91{
92 const WCHAR *scheme; /* [out] start of scheme */
93 DWORD scheme_len; /* [out] size of scheme (until colon) */
94 const WCHAR *username; /* [out] start of Username */
95 DWORD username_len; /* [out] size of Username (until ":" or "@") */
96 const WCHAR *password; /* [out] start of Password */
97 DWORD password_len; /* [out] size of Password (until "@") */
98 const WCHAR *hostname; /* [out] start of Hostname */
99 DWORD hostname_len; /* [out] size of Hostname (until ":" or "/") */
100 const WCHAR *port; /* [out] start of Port */
101 DWORD port_len; /* [out] size of Port (until "/" or eos) */
102 const WCHAR *query; /* [out] start of Query */
103 DWORD query_len; /* [out] size of Query (until eos) */
105};
106
107static WCHAR *heap_strdupAtoW(const char *str)
108{
109 WCHAR *ret = NULL;
110
111 if (str)
112 {
113 DWORD len;
114
115 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
116 ret = heap_alloc(len * sizeof(WCHAR));
118 }
119
120 return ret;
121}
122
123static bool array_reserve(void **elements, size_t *capacity, size_t count, size_t size)
124{
125 unsigned int new_capacity, max_capacity;
126 void *new_elements;
127
128 if (count <= *capacity)
129 return true;
130
131 max_capacity = ~(SIZE_T)0 / size;
132 if (count > max_capacity)
133 return false;
134
135 new_capacity = max(4, *capacity);
136 while (new_capacity < count && new_capacity <= max_capacity / 2)
137 new_capacity *= 2;
138 if (new_capacity < count)
139 new_capacity = max_capacity;
140
141 if (!(new_elements = heap_realloc( *elements, new_capacity * size )))
142 return false;
143
144 *elements = new_elements;
145 *capacity = new_capacity;
146
147 return true;
148}
149
150static bool is_slash( char c )
151{
152 return c == '/' || c == '\\';
153}
154
155static BOOL is_drive_specA( const char *str )
156{
157 return isalpha( str[0] ) && str[1] == ':';
158}
159
160#endif // !STATIC_PATHCCH
161
162static BOOL is_drive_spec( const WCHAR *str )
163{
164 return isalpha( str[0] ) && str[1] == ':';
165}
166
167#ifndef STATIC_PATHCCH
169{
170 return isalpha( str[0] ) && (str[1] == ':' || str[1] == '|');
171}
172#endif // !STATIC_PATHCCH
173
174static BOOL is_prefixed_unc(const WCHAR *string)
175{
176 return !wcsnicmp(string, L"\\\\?\\UNC\\", 8 );
177}
178
179static BOOL is_prefixed_disk(const WCHAR *string)
180{
181 return !wcsncmp(string, L"\\\\?\\", 4) && is_drive_spec( string + 4 );
182}
183
184static BOOL is_prefixed_volume(const WCHAR *string)
185{
186 const WCHAR *guid;
187 INT i = 0;
188
189 if (wcsnicmp( string, L"\\\\?\\Volume", 10 )) return FALSE;
190
191 guid = string + 10;
192
193 while (i <= 37)
194 {
195 switch (i)
196 {
197 case 0:
198 if (guid[i] != '{') return FALSE;
199 break;
200 case 9:
201 case 14:
202 case 19:
203 case 24:
204 if (guid[i] != '-') return FALSE;
205 break;
206 case 37:
207 if (guid[i] != '}') return FALSE;
208 break;
209 default:
210 if (!isxdigit(guid[i])) return FALSE;
211 break;
212 }
213 i++;
214 }
215
216 return TRUE;
217}
218
219/* Get the next character beyond end of the segment.
220 Return TRUE if the last segment ends with a backslash */
221static BOOL get_next_segment(const WCHAR *next, const WCHAR **next_segment)
222{
223 while (*next && *next != '\\') next++;
224 if (*next == '\\')
225 {
226 *next_segment = next + 1;
227 return TRUE;
228 }
229 else
230 {
231 *next_segment = next;
232 return FALSE;
233 }
234}
235
236/* Find the last character of the root in a path, if there is one, without any segments */
237static const WCHAR *get_root_end(const WCHAR *path)
238{
239 /* Find path root */
241 return path[48] == '\\' ? path + 48 : path + 47;
242 else if (is_prefixed_unc(path))
243 return path + 7;
244 else if (is_prefixed_disk(path))
245 return path[6] == '\\' ? path + 6 : path + 5;
246 /* \\ */
247 else if (path[0] == '\\' && path[1] == '\\')
248 return path + 1;
249 /* \ */
250 else if (path[0] == '\\')
251 return path;
252 /* X:\ */
253 else if (is_drive_spec( path ))
254 return path[2] == '\\' ? path + 2 : path + 1;
255 else
256 return NULL;
257}
258
260{
261 WCHAR *buffer, *dst;
262 const WCHAR *src;
263 const WCHAR *root_end;
265
266 TRACE("%s %#lx %p\n", debugstr_w(path_in), flags, path_out);
267
268 if (!path_in || !path_out
273 {
274 if (path_out) *path_out = NULL;
275 return E_INVALIDARG;
276 }
277
278 length = lstrlenW(path_in);
280 || (length + 1 > PATHCCH_MAX_CCH))
281 {
282 *path_out = NULL;
284 }
285
286 /* PATHCCH_ENSURE_IS_EXTENDED_LENGTH_PATH implies PATHCCH_DO_NOT_NORMALIZE_SEGMENTS */
288
289 /* path length + possible \\?\ addition + possible \ addition + NUL */
290 buffer_size = (length + 6) * sizeof(WCHAR);
292 if (!buffer)
293 {
294 *path_out = NULL;
295 return E_OUTOFMEMORY;
296 }
297
298 src = path_in;
299 dst = buffer;
300
301 root_end = get_root_end(path_in);
302 if (root_end) root_end = buffer + (root_end - path_in);
303
304 /* Copy path root */
305 if (root_end)
306 {
307 memcpy(dst, src, (root_end - buffer + 1) * sizeof(WCHAR));
308 src += root_end - buffer + 1;
309 if(PathCchStripPrefix(dst, length + 6) == S_OK)
310 {
311 /* Fill in \ in X:\ if the \ is missing */
312 if (is_drive_spec( dst ) && dst[2]!= '\\')
313 {
314 dst[2] = '\\';
315 dst[3] = 0;
316 }
318 root_end = dst;
319 }
320 else
321 dst += root_end - buffer + 1;
322 }
323
324 while (*src)
325 {
326 if (src[0] == '.')
327 {
328 if (src[1] == '.')
329 {
330 /* Keep one . after * */
331 if (dst > buffer && dst[-1] == '*')
332 {
333 *dst++ = *src++;
334 continue;
335 }
336
337 /* Keep the .. if not surrounded by \ */
338 if ((src[2] != '\\' && src[2]) || (dst > buffer && dst[-1] != '\\'))
339 {
340 *dst++ = *src++;
341 *dst++ = *src++;
342 continue;
343 }
344
345 /* Remove the \ before .. if the \ is not part of root */
346 if (dst > buffer && dst[-1] == '\\' && (!root_end || dst - 1 > root_end))
347 {
348 *--dst = '\0';
349 /* Remove characters until a \ is encountered */
350 while (dst > buffer)
351 {
352 if (dst[-1] == '\\')
353 {
354 *--dst = 0;
355 break;
356 }
357 else
358 *--dst = 0;
359 }
360 }
361 /* Remove the extra \ after .. if the \ before .. wasn't deleted */
362 else if (src[2] == '\\')
363 src++;
364
365 src += 2;
366 }
367 else
368 {
369 /* Keep the . if not surrounded by \ */
370 if ((src[1] != '\\' && src[1]) || (dst > buffer && dst[-1] != '\\'))
371 {
372 *dst++ = *src++;
373 continue;
374 }
375
376 /* Remove the \ before . if the \ is not part of root */
377 if (dst > buffer && dst[-1] == '\\' && (!root_end || dst - 1 > root_end)) dst--;
378 /* Remove the extra \ after . if the \ before . wasn't deleted */
379 else if (src[1] == '\\')
380 src++;
381
382 src++;
383 }
384
385 /* If X:\ is not complete, then complete it */
386 if (is_drive_spec( buffer ) && buffer[2] != '\\')
387 {
388 root_end = buffer + 2;
389 dst = buffer + 3;
390 buffer[2] = '\\';
391 /* If next character is \, use the \ to fill in */
392 if (src[0] == '\\') src++;
393 }
394 }
395 /* Copy over */
396 else
397 *dst++ = *src++;
398 }
399 /* End the path */
400 *dst = 0;
401
402 /* Strip multiple trailing . */
404 {
405 while (dst > buffer && dst[-1] == '.')
406 {
407 /* Keep a . after * */
408 if (dst - 1 > buffer && dst[-2] == '*')
409 break;
410 /* If . follow a : at the second character, remove the . and add a \ */
411 else if (dst - 1 > buffer && dst[-2] == ':' && dst - 2 == buffer + 1)
412 *--dst = '\\';
413 else
414 *--dst = 0;
415 }
416 }
417
418 /* If result path is empty, fill in \ */
419 if (!*buffer)
420 {
421 buffer[0] = '\\';
422 buffer[1] = 0;
423 }
424
425 /* Extend the path if needed */
427 if (((length + 1 > MAX_PATH && is_drive_spec( buffer ))
430 {
431 memmove(buffer + 4, buffer, (length + 1) * sizeof(WCHAR));
432 buffer[0] = '\\';
433 buffer[1] = '\\';
434 buffer[2] = '?';
435 buffer[3] = '\\';
436 }
437
438 /* Add a trailing backslash to the path if needed */
441
442 *path_out = buffer;
443 return S_OK;
444}
445
447{
448 SIZE_T combined_length, length2;
449 WCHAR *combined_path;
450 BOOL add_backslash = FALSE;
451 HRESULT hr;
452
453 TRACE("%s %s %#lx %p\n", wine_dbgstr_w(path1), wine_dbgstr_w(path2), flags, out);
454
455 if ((!path1 && !path2) || !out)
456 {
457 if (out) *out = NULL;
458 return E_INVALIDARG;
459 }
460
461 if (!path1 || !path2) return PathAllocCanonicalize(path1 ? path1 : path2, flags, out);
462
463 /* If path2 is fully qualified, use path2 only */
464 if (is_drive_spec( path2 ) || (path2[0] == '\\' && path2[1] == '\\'))
465 {
466 path1 = path2;
467 path2 = NULL;
468 add_backslash = (is_drive_spec(path1) && !path1[2])
469 || (is_prefixed_disk(path1) && !path1[6]);
470 }
471
472 length2 = path2 ? lstrlenW(path2) : 0;
473 /* path1 length + path2 length + possible backslash + NULL */
474 combined_length = lstrlenW(path1) + length2 + 2;
475
476 combined_path = HeapAlloc(GetProcessHeap(), 0, combined_length * sizeof(WCHAR));
477 if (!combined_path)
478 {
479 *out = NULL;
480 return E_OUTOFMEMORY;
481 }
482
483 lstrcpyW(combined_path, path1);
484 PathCchStripPrefix(combined_path, combined_length);
485 if (add_backslash) PathCchAddBackslashEx(combined_path, combined_length, NULL, NULL);
486
487 if (path2 && path2[0])
488 {
489 if (path2[0] == '\\' && path2[1] != '\\')
490 {
491 PathCchStripToRoot(combined_path, combined_length);
492 path2++;
493 }
494
495 PathCchAddBackslashEx(combined_path, combined_length, NULL, NULL);
496 lstrcatW(combined_path, path2);
497 }
498
499 hr = PathAllocCanonicalize(combined_path, flags, out);
500 HeapFree(GetProcessHeap(), 0, combined_path);
501 return hr;
502}
503
505{
507}
508
510{
511 BOOL needs_termination;
513
514 TRACE("%s, %Iu, %p, %p\n", debugstr_w(path), size, endptr, remaining);
515
517 needs_termination = size && length && path[length - 1] != '\\';
518
519 if (length >= (needs_termination ? size - 1 : size))
520 {
521 if (endptr) *endptr = NULL;
522 if (remaining) *remaining = 0;
524 }
525
526 if (!needs_termination)
527 {
528 if (endptr) *endptr = path + length;
529 if (remaining) *remaining = size - length;
530 return S_FALSE;
531 }
532
533 path[length++] = '\\';
534 path[length] = 0;
535
536 if (endptr) *endptr = path + length;
537 if (remaining) *remaining = size - length;
538
539 return S_OK;
540}
541
543{
544 const WCHAR *existing_extension, *next;
545 SIZE_T path_length, extension_length, dot_length;
546 BOOL has_dot;
547 HRESULT hr;
548
549 TRACE("%s %Iu %s\n", wine_dbgstr_w(path), size, wine_dbgstr_w(extension));
550
551 if (!path || !size || size > PATHCCH_MAX_CCH || !extension) return E_INVALIDARG;
552
553 next = extension;
554 while (*next)
555 {
556 if ((*next == '.' && next > extension) || *next == ' ' || *next == '\\') return E_INVALIDARG;
557 next++;
558 }
559
560 has_dot = extension[0] == '.';
561
562 hr = PathCchFindExtension(path, size, &existing_extension);
563 if (FAILED(hr)) return hr;
564 if (*existing_extension) return S_FALSE;
565
567 dot_length = has_dot ? 0 : 1;
568 extension_length = lstrlenW(extension);
569
570 if (path_length + dot_length + extension_length + 1 > size) return STRSAFE_E_INSUFFICIENT_BUFFER;
571
572 /* If extension is empty or only dot, return S_OK with path unchanged */
573 if (!extension[0] || (extension[0] == '.' && !extension[1])) return S_OK;
574
575 if (!has_dot)
576 {
577 path[path_length] = '.';
578 path_length++;
579 }
580
581 lstrcpyW(path + path_length, extension);
582 return S_OK;
583}
584
586{
587 TRACE("%s %Iu %s\n", wine_dbgstr_w(path1), size, wine_dbgstr_w(path2));
588
590}
591
593{
594 HRESULT hr;
595 WCHAR *result;
596
597 TRACE("%s %Iu %s %#lx\n", wine_dbgstr_w(path1), size, wine_dbgstr_w(path2), flags);
598
599 if (!path1 || !size) return E_INVALIDARG;
600
601 /* Create a temporary buffer for result because we need to keep path1 unchanged if error occurs.
602 * And PathCchCombineEx writes empty result if there is error so we can't just use path1 as output
603 * buffer for PathCchCombineEx */
604 result = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
605 if (!result) return E_OUTOFMEMORY;
606
607 /* Avoid the single backslash behavior with PathCchCombineEx when appending */
608 if (path2 && path2[0] == '\\' && path2[1] != '\\') path2++;
609
611 if (SUCCEEDED(hr)) memcpy(path1, result, size * sizeof(WCHAR));
612
614 return hr;
615}
616
618{
619 TRACE("%p %Iu %s\n", out, size, wine_dbgstr_w(in));
620
621 /* Not X:\ and path > MAX_PATH - 4, return HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE) */
622 if (lstrlenW(in) > MAX_PATH - 4 && !(is_drive_spec( in ) && in[2] == '\\'))
624
626}
627
629{
630 WCHAR *buffer;
632 HRESULT hr;
633
634 TRACE("%p %Iu %s %#lx\n", out, size, wine_dbgstr_w(in), flags);
635
636 if (!size) return E_INVALIDARG;
637
639 if (FAILED(hr)) return hr;
640
642 if (size < length + 1)
643 {
644 /* No root and path > MAX_PATH - 4, return HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE) */
645 if (length > MAX_PATH - 4 && !(in[0] == '\\' || (is_drive_spec( in ) && in[2] == '\\')))
647 else
649 }
650
651 if (SUCCEEDED(hr))
652 {
653 memcpy(out, buffer, (length + 1) * sizeof(WCHAR));
654
655 /* Fill a backslash at the end of X: */
656 if (is_drive_spec( out ) && !out[2] && size > 3)
657 {
658 out[2] = '\\';
659 out[3] = 0;
660 }
661 }
662
664 return hr;
665}
666
668{
669 TRACE("%p %s %s\n", out, wine_dbgstr_w(path1), wine_dbgstr_w(path2));
670
672}
673
675{
676 HRESULT hr;
677 WCHAR *buffer;
679
680 TRACE("%p %s %s %#lx\n", out, wine_dbgstr_w(path1), wine_dbgstr_w(path2), flags);
681
682 if (!out || !size || size > PATHCCH_MAX_CCH) return E_INVALIDARG;
683
685 if (FAILED(hr))
686 {
687 out[0] = 0;
688 return hr;
689 }
690
692 if (length + 1 > size)
693 {
694 out[0] = 0;
697 }
698 else
699 {
700 memcpy(out, buffer, (length + 1) * sizeof(WCHAR));
702 return S_OK;
703 }
704}
705
707{
708 const WCHAR *lastpoint = NULL;
709 SIZE_T counter = 0;
710
711 TRACE("%s %Iu %p\n", wine_dbgstr_w(path), size, extension);
712
713 if (!path || !size || size > PATHCCH_MAX_CCH)
714 {
715 *extension = NULL;
716 return E_INVALIDARG;
717 }
718
719 while (*path)
720 {
721 if (*path == '\\' || *path == ' ')
722 lastpoint = NULL;
723 else if (*path == '.')
724 lastpoint = path;
725
726 path++;
727 counter++;
728 if (counter == size || counter == PATHCCH_MAX_CCH)
729 {
730 *extension = NULL;
731 return E_INVALIDARG;
732 }
733 }
734
735 *extension = lastpoint ? lastpoint : path;
736 return S_OK;
737}
738
740{
741 const WCHAR *root_end;
742 const WCHAR *next;
743 BOOL is_unc;
744
745 TRACE("%s\n", wine_dbgstr_w(path));
746
747 if (!path || !*path) return FALSE;
748
749 root_end = get_root_end(path);
750 if (!root_end) return FALSE;
751
752 if ((is_unc = is_prefixed_unc(path)) || (path[0] == '\\' && path[1] == '\\' && path[2] != '?'))
753 {
754 next = root_end + 1;
755 /* No extra segments */
756 if ((is_unc && !*next) || (!is_unc && !*next)) return TRUE;
757
758 /* Has first segment with an ending backslash but no remaining characters */
759 if (get_next_segment(next, &next) && !*next) return FALSE;
760 /* Has first segment with no ending backslash */
761 else if (!*next)
762 return TRUE;
763 /* Has first segment with an ending backslash and has remaining characters*/
764 else
765 {
766 /* Second segment must have no backslash and no remaining characters */
767 return !get_next_segment(next, &next) && !*next;
768 }
769 }
770 else if (*root_end == '\\' && !root_end[1])
771 return TRUE;
772 else
773 return FALSE;
774}
775
777{
778 WCHAR *path_end;
779 SIZE_T free_size;
780
781 TRACE("%s %Iu\n", debugstr_w(path), path_size);
782
783 return PathCchRemoveBackslashEx(path, path_size, &path_end, &free_size);
784}
785
787{
788 const WCHAR *root_end;
790
791 TRACE("%s %Iu %p %p\n", debugstr_w(path), path_size, path_end, free_size);
792
793 if (!path_size || !path_end || !free_size)
794 {
795 if (path_end) *path_end = NULL;
796 if (free_size) *free_size = 0;
797 return E_INVALIDARG;
798 }
799
800 path_length = wcsnlen(path, path_size);
801 if (path_length == path_size && !path[path_length]) return E_INVALIDARG;
802
803 root_end = get_root_end(path);
804 if (path_length > 0 && path[path_length - 1] == '\\')
805 {
806 *path_end = path + path_length - 1;
807 *free_size = path_size - path_length + 1;
808 /* If the last character is beyond end of root */
809 if (!root_end || path + path_length - 1 > root_end)
810 {
811 path[path_length - 1] = 0;
812 return S_OK;
813 }
814 else
815 return S_FALSE;
816 }
817 else
818 {
819 *path_end = path + path_length;
820 *free_size = path_size - path_length;
821 return S_FALSE;
822 }
823}
824
826{
827 const WCHAR *extension;
828 WCHAR *next;
829 HRESULT hr;
830
831 TRACE("%s %Iu\n", wine_dbgstr_w(path), size);
832
833 if (!path || !size || size > PATHCCH_MAX_CCH) return E_INVALIDARG;
834
835 hr = PathCchFindExtension(path, size, &extension);
836 if (FAILED(hr)) return hr;
837
838 next = path + (extension - path);
839 while (next - path < size && *next) *next++ = 0;
840
841 return next == extension ? S_FALSE : S_OK;
842}
843
845{
846 WCHAR *last, *root_end;
847
848 TRACE("%s %Iu\n", wine_dbgstr_w(path), size);
849
850 if (!path || !size || size > PATHCCH_MAX_CCH) return E_INVALIDARG;
851
852 if (FAILED(PathCchSkipRoot(path, (const WCHAR **)&root_end)))
853 root_end = path;
854
855 /* The backslash at the end of UNC and \\* are not considered part of root in this case */
856 if (root_end > path && root_end[-1] == '\\' && ((is_prefixed_unc(path) && path[8])
857 || (path[0] == '\\' && path[1] == '\\' && path[2] && path[2] != '?')))
858 root_end--;
859
860 if (!(last = StrRChrW(root_end, NULL, '\\'))) last = root_end;
861 if (last > root_end && last[-1] == '\\' && last[1] != '?') --last;
862 if (last - path >= size) return E_INVALIDARG;
863 if (!*last) return S_FALSE;
864 *last = 0;
865 return S_OK;
866}
867
869{
870 HRESULT hr;
871
872 TRACE("%s %Iu %s\n", wine_dbgstr_w(path), size, wine_dbgstr_w(extension));
873
875 if (FAILED(hr)) return hr;
876
877 hr = PathCchAddExtension(path, size, extension);
878 return FAILED(hr) ? hr : S_OK;
879}
880
881HRESULT WINAPI PathCchSkipRoot(const WCHAR *path, const WCHAR **root_end)
882{
883 TRACE("%s %p\n", debugstr_w(path), root_end);
884
885 if (!path || !path[0] || !root_end
886 || (!wcsnicmp(path, L"\\\\?", 3) && !is_prefixed_volume(path) && !is_prefixed_unc(path)
888 return E_INVALIDARG;
889
890 *root_end = get_root_end(path);
891 if (*root_end)
892 {
893 (*root_end)++;
895 {
896 get_next_segment(*root_end, root_end);
897 get_next_segment(*root_end, root_end);
898 }
899 else if (path[0] == '\\' && path[1] == '\\' && path[2] != '?')
900 {
901 /* Skip share server */
902 get_next_segment(*root_end, root_end);
903 /* If mount point is empty, don't skip over mount point */
904 if (**root_end != '\\') get_next_segment(*root_end, root_end);
905 }
906 }
907
908 return *root_end ? S_OK : E_INVALIDARG;
909}
910
912{
913 TRACE("%s %Iu\n", wine_dbgstr_w(path), size);
914
915 if (!path || !size || size > PATHCCH_MAX_CCH) return E_INVALIDARG;
916
918 {
919 /* \\?\UNC\a -> \\a */
920 if (size < lstrlenW(path + 8) + 3) return E_INVALIDARG;
921 lstrcpyW(path + 2, path + 8);
922 return S_OK;
923 }
924 else if (is_prefixed_disk(path))
925 {
926 /* \\?\C:\ -> C:\ */
927 if (size < lstrlenW(path + 4) + 1) return E_INVALIDARG;
928 lstrcpyW(path, path + 4);
929 return S_OK;
930 }
931 else
932 return S_FALSE;
933}
934
936{
937 const WCHAR *root_end;
938 WCHAR *segment_end;
939
940 TRACE("%s %Iu\n", wine_dbgstr_w(path), size);
941
942 if (!path || !*path || !size || size > PATHCCH_MAX_CCH) return E_INVALIDARG;
943
944 if (PathCchSkipRoot(path, &root_end) == S_OK)
945 {
946 if (root_end && root_end > path && root_end[-1] == '\\'
947 && ((is_prefixed_unc(path) && path[8]) || (path[0] == '\\' && path[1] == '\\' && path[2] && path[2] != '?')))
948 root_end--;
949 if (root_end - path >= size) return E_INVALIDARG;
950
951 segment_end = path + (root_end - path);
952 if (!*segment_end) return S_FALSE;
953
954 *segment_end = 0;
955 return S_OK;
956 }
957 else
958 {
959 *path = 0;
960 return E_INVALIDARG;
961 }
962}
963
965{
966 const WCHAR *result = NULL;
967
968 TRACE("%s %p\n", wine_dbgstr_w(path), server);
969
971 result = path + 8;
972 else if (path[0] == '\\' && path[1] == '\\' && path[2] != '?')
973 result = path + 2;
974
975 if (server) *server = result;
976 return !!result;
977}
978
979#ifndef STATIC_PATHCCH
980/* Other functions not part of the PathCch library */
981
983{
984 TRACE("%s\n", wine_dbgstr_a(path));
985
986 return path && (path[0] == '\\') && (path[1] == '\\');
987}
988
990{
991 TRACE("%s\n", wine_dbgstr_w(path));
992
993 return path && (path[0] == '\\') && (path[1] == '\\');
994}
995
997{
998 TRACE("%s\n", wine_dbgstr_a(path));
999
1000 if (!path || !*path || IsDBCSLeadByte(*path))
1001 return TRUE;
1002
1003 return !(*path == '\\' || (*path && path[1] == ':'));
1004}
1005
1007{
1008 TRACE("%s\n", wine_dbgstr_w(path));
1009
1010 if (!path || !*path)
1011 return TRUE;
1012
1013 return !(*path == '\\' || (*path && path[1] == ':'));
1014}
1015
1017{
1018 BOOL seen_slash = FALSE;
1019
1020 TRACE("%s\n", wine_dbgstr_a(path));
1021
1022 if (path && *path++ == '\\' && *path++ == '\\')
1023 {
1024 while (*path)
1025 {
1026 if (*path == '\\')
1027 {
1028 if (seen_slash)
1029 return FALSE;
1030 seen_slash = TRUE;
1031 }
1032
1033 path = CharNextA(path);
1034 }
1035 }
1036
1037 return seen_slash;
1038}
1039
1041{
1042 BOOL seen_slash = FALSE;
1043
1044 TRACE("%s\n", wine_dbgstr_w(path));
1045
1046 if (path && *path++ == '\\' && *path++ == '\\')
1047 {
1048 while (*path)
1049 {
1050 if (*path == '\\')
1051 {
1052 if (seen_slash)
1053 return FALSE;
1054 seen_slash = TRUE;
1055 }
1056
1057 path++;
1058 }
1059 }
1060
1061 return seen_slash;
1062}
1063
1065{
1067
1068 TRACE("%s\n", wine_dbgstr_a(path));
1069
1071 return FALSE;
1073
1074 return PathIsRootW(pathW);
1075}
1076
1078{
1079 TRACE("%s\n", wine_dbgstr_w(path));
1080
1081 return PathCchIsRoot(path);
1082}
1083
1085{
1086 char *root_end = NULL, *ptr;
1087
1088 TRACE("%s\n", debugstr_a(path));
1089
1090 if (!path || !*path)
1091 return FALSE;
1092
1093 if (is_drive_specA(path))
1094 {
1095 root_end = path + 2;
1096 if (*root_end == '\\') ++root_end;
1097 }
1098 else
1099 {
1100 root_end = path;
1101 if (*root_end == '\\') ++root_end;
1102 if (root_end[1] != '?')
1103 {
1104 if (*root_end == '\\') ++root_end;
1105 if (root_end - path > 1 && is_drive_specA(root_end)) root_end += 2;
1106 if (*root_end == '\\' && root_end[1] && root_end[1] != '\\') ++root_end;
1107 }
1108 }
1109 ptr = StrRChrA(root_end, NULL, '\\');
1110 if (ptr && ptr != root_end)
1111 {
1112 if (ptr[-1] == '\\') --ptr;
1113 *ptr = 0;
1114 return TRUE;
1115 }
1116 if (!*root_end) return FALSE;
1117 *root_end = 0;
1118 return TRUE;
1119}
1120
1122{
1123 WCHAR *root_end = NULL, *ptr;
1124
1125 TRACE("%s\n", debugstr_w(path));
1126
1127 if (!path || !*path)
1128 return FALSE;
1129
1130 if (is_prefixed_volume(path)) root_end = path + 48;
1131 else if (is_prefixed_disk(path)) root_end = path + 6;
1132 else if (is_drive_spec(path)) root_end = path + 2;
1133 if (!root_end)
1134 {
1135 root_end = path;
1136 if (*root_end == '\\') ++root_end;
1137 if (root_end[1] != '?')
1138 {
1139 if (*root_end == '\\') ++root_end;
1140 if (root_end - path > 1 && is_drive_spec(root_end)) root_end += 2;
1141 if (*root_end == '\\' && root_end[1] && root_end[1] != '\\') ++root_end;
1142 }
1143 }
1144 else if (*root_end == '\\') ++root_end;
1145 ptr = StrRChrW(root_end, NULL, '\\');
1146 if (ptr && ptr != root_end)
1147 {
1148 if (ptr[-1] == '\\') --ptr;
1149 *ptr = 0;
1150 return TRUE;
1151 }
1152 if (!*root_end) return FALSE;
1153 *root_end = 0;
1154 return TRUE;
1155}
1156
1158{
1160
1161 TRACE("%s\n", wine_dbgstr_a(path));
1162
1163 if (!MultiByteToWideChar(CP_ACP, 0, path, -1, pathW, MAX_PATH)) return FALSE;
1164
1165 *path = 0;
1167 if (!PathStripToRootW(pathW)) return FALSE;
1168 return !!WideCharToMultiByte(CP_ACP, 0, pathW, -1, path, MAX_PATH, 0, 0);
1169}
1170
1172{
1173 TRACE("%s\n", wine_dbgstr_w(path));
1174
1176}
1177
1179{
1180 unsigned int len;
1181 char *prev = path;
1182
1183 TRACE("%s\n", wine_dbgstr_a(path));
1184
1185 if (!path || (len = strlen(path)) >= MAX_PATH)
1186 return NULL;
1187
1188 if (len)
1189 {
1190 do
1191 {
1192 path = CharNextA(prev);
1193 if (*path)
1194 prev = path;
1195 } while (*path);
1196
1197 if (*prev != '\\')
1198 {
1199 *path++ = '\\';
1200 *path = '\0';
1201 }
1202 }
1203
1204 return path;
1205}
1206
1208{
1209 unsigned int len;
1210
1211 TRACE("%s\n", wine_dbgstr_w(path));
1212
1213 if (!path || (len = lstrlenW(path)) >= MAX_PATH)
1214 return NULL;
1215
1216 if (len)
1217 {
1218 path += len;
1219 if (path[-1] != '\\')
1220 {
1221 *path++ = '\\';
1222 *path = '\0';
1223 }
1224 }
1225
1226 return path;
1227}
1228
1230{
1231 const char *lastpoint = NULL;
1232
1233 TRACE("%s\n", wine_dbgstr_a(path));
1234
1235 if (path)
1236 {
1237 while (*path)
1238 {
1239 if (*path == '\\' || *path == ' ')
1240 lastpoint = NULL;
1241 else if (*path == '.')
1242 lastpoint = path;
1243 path = CharNextA(path);
1244 }
1245 }
1246
1247 return (LPSTR)(lastpoint ? lastpoint : path);
1248}
1249
1251{
1252 const WCHAR *lastpoint = NULL;
1253
1254 TRACE("%s\n", wine_dbgstr_w(path));
1255
1256 if (path)
1257 {
1258 while (*path)
1259 {
1260 if (*path == '\\' || *path == ' ')
1261 lastpoint = NULL;
1262 else if (*path == '.')
1263 lastpoint = path;
1264 path++;
1265 }
1266 }
1267
1268 return (LPWSTR)(lastpoint ? lastpoint : path);
1269}
1270
1272{
1273 unsigned int len;
1274
1275 TRACE("%s, %s\n", wine_dbgstr_a(path), wine_dbgstr_a(ext));
1276
1277 if (!path || !ext || *(PathFindExtensionA(path)))
1278 return FALSE;
1279
1280 len = strlen(path);
1281 if (len + strlen(ext) >= MAX_PATH)
1282 return FALSE;
1283
1284 strcpy(path + len, ext);
1285 return TRUE;
1286}
1287
1289{
1290 unsigned int len;
1291
1292 TRACE("%s, %s\n", wine_dbgstr_w(path), wine_dbgstr_w(ext));
1293
1294 if (!path || !ext || *(PathFindExtensionW(path)))
1295 return FALSE;
1296
1297 len = lstrlenW(path);
1298 if (len + lstrlenW(ext) >= MAX_PATH)
1299 return FALSE;
1300
1301 lstrcpyW(path + len, ext);
1302 return TRUE;
1303}
1304
1306{
1307 const WCHAR *src = path;
1308 WCHAR *dst = buffer;
1309
1310 TRACE("%p, %s\n", buffer, wine_dbgstr_w(path));
1311
1312 if (dst)
1313 *dst = '\0';
1314
1315 if (!dst || !path)
1316 {
1318 return FALSE;
1319 }
1320
1321 if (!*path)
1322 {
1323 *buffer++ = '\\';
1324 *buffer = '\0';
1325 return TRUE;
1326 }
1327
1328 /* Copy path root */
1329 if (*src == '\\')
1330 {
1331 *dst++ = *src++;
1332 }
1333 else if (*src && src[1] == ':')
1334 {
1335 /* X:\ */
1336 *dst++ = *src++;
1337 *dst++ = *src++;
1338 if (*src == '\\')
1339 *dst++ = *src++;
1340 }
1341
1342 /* Canonicalize the rest of the path */
1343 while (*src)
1344 {
1345 if (*src == '.')
1346 {
1347 if (src[1] == '\\' && (src == path || src[-1] == '\\' || src[-1] == ':'))
1348 {
1349 src += 2; /* Skip .\ */
1350 }
1351 else if (src[1] == '.' && dst != buffer && dst[-1] == '\\')
1352 {
1353 /* \.. backs up a directory, over the root if it has no \ following X:.
1354 * .. is ignored if it would remove a UNC server name or initial \\
1355 */
1356 if (dst != buffer)
1357 {
1358 *dst = '\0'; /* Allow PathIsUNCServerShareA test on lpszBuf */
1359 if (dst > buffer + 1 && dst[-1] == '\\' && (dst[-2] != '\\' || dst > buffer + 2))
1360 {
1361 if (dst[-2] == ':' && (dst > buffer + 3 || dst[-3] == ':'))
1362 {
1363 dst -= 2;
1364 while (dst > buffer && *dst != '\\')
1365 dst--;
1366 if (*dst == '\\')
1367 dst++; /* Reset to last '\' */
1368 else
1369 dst = buffer; /* Start path again from new root */
1370 }
1371 else if (dst[-2] != ':' && !PathIsUNCServerShareW(buffer))
1372 dst -= 2;
1373 }
1374 while (dst > buffer && *dst != '\\')
1375 dst--;
1376 if (dst == buffer)
1377 {
1378 *dst++ = '\\';
1379 src++;
1380 }
1381 }
1382 src += 2; /* Skip .. in src path */
1383 }
1384 else
1385 *dst++ = *src++;
1386 }
1387 else
1388 *dst++ = *src++;
1389 }
1390
1391 /* Append \ to naked drive specs */
1392 if (dst - buffer == 2 && dst[-1] == ':')
1393 *dst++ = '\\';
1394 *dst++ = '\0';
1395 return TRUE;
1396}
1397
1399{
1400 WCHAR pathW[MAX_PATH], bufferW[MAX_PATH];
1401 BOOL ret;
1402 int len;
1403
1404 TRACE("%p, %s\n", buffer, wine_dbgstr_a(path));
1405
1406 if (buffer)
1407 *buffer = '\0';
1408
1409 if (!buffer || !path)
1410 {
1412 return FALSE;
1413 }
1414
1416 if (!len)
1417 return FALSE;
1418
1419 ret = PathCanonicalizeW(bufferW, pathW);
1420 WideCharToMultiByte(CP_ACP, 0, bufferW, -1, buffer, MAX_PATH, 0, 0);
1421
1422 return ret;
1423}
1424
1426{
1427 BOOL use_both = FALSE, strip = FALSE;
1428 WCHAR tmp[MAX_PATH];
1429
1430 TRACE("%p, %s, %s\n", dst, wine_dbgstr_w(dir), wine_dbgstr_w(file));
1431
1432 /* Invalid parameters */
1433 if (!dst)
1434 return NULL;
1435
1436 if (!dir && !file)
1437 {
1438 dst[0] = 0;
1439 return NULL;
1440 }
1441
1442 if ((!file || !*file) && dir)
1443 {
1444 /* Use dir only */
1445 lstrcpynW(tmp, dir, ARRAY_SIZE(tmp));
1446 }
1447 else if (!dir || !*dir || !PathIsRelativeW(file))
1448 {
1449 if (!dir || !*dir || *file != '\\' || PathIsUNCW(file))
1450 {
1451 /* Use file only */
1452 lstrcpynW(tmp, file, ARRAY_SIZE(tmp));
1453 }
1454 else
1455 {
1456 use_both = TRUE;
1457 strip = TRUE;
1458 }
1459 }
1460 else
1461 use_both = TRUE;
1462
1463 if (use_both)
1464 {
1465 lstrcpynW(tmp, dir, ARRAY_SIZE(tmp));
1466 if (strip)
1467 {
1468 PathStripToRootW(tmp);
1469 file++; /* Skip '\' */
1470 }
1471
1472 if (!PathAddBackslashW(tmp) || lstrlenW(tmp) + lstrlenW(file) >= MAX_PATH)
1473 {
1474 dst[0] = 0;
1475 return NULL;
1476 }
1477
1478 lstrcatW(tmp, file);
1479 }
1480
1481 PathCanonicalizeW(dst, tmp);
1482 return dst;
1483}
1484
1485LPSTR WINAPI PathCombineA(char *dst, const char *dir, const char *file)
1486{
1487 WCHAR dstW[MAX_PATH], dirW[MAX_PATH], fileW[MAX_PATH];
1488
1489 TRACE("%p, %s, %s\n", dst, wine_dbgstr_a(dir), wine_dbgstr_a(file));
1490
1491 /* Invalid parameters */
1492 if (!dst)
1493 return NULL;
1494
1495 if (!dir && !file)
1496 goto fail;
1497
1498 if (dir && !MultiByteToWideChar(CP_ACP, 0, dir, -1, dirW, ARRAY_SIZE(dirW)))
1499 goto fail;
1500
1502 goto fail;
1503
1504 if (PathCombineW(dstW, dir ? dirW : NULL, file ? fileW : NULL))
1505 if (WideCharToMultiByte(CP_ACP, 0, dstW, -1, dst, MAX_PATH, 0, 0))
1506 return dst;
1507fail:
1508 dst[0] = 0;
1509 return NULL;
1510}
1511
1512BOOL WINAPI PathAppendA(char *path, const char *append)
1513{
1515
1516 if (path && append)
1517 {
1518 if (!PathIsUNCA(append))
1519 while (*append == '\\')
1520 append++;
1521
1523 return TRUE;
1524 }
1525
1526 return FALSE;
1527}
1528
1530{
1532
1533 if (path && append)
1534 {
1535 if (!PathIsUNCW(append))
1536 while (*append == '\\')
1537 append++;
1538
1540 return TRUE;
1541 }
1542
1543 return FALSE;
1544}
1545
1546int WINAPI PathCommonPrefixA(const char *file1, const char *file2, char *path)
1547{
1548 const char *iter1 = file1;
1549 const char *iter2 = file2;
1550 unsigned int len = 0;
1551
1552 TRACE("%s, %s, %p.\n", wine_dbgstr_a(file1), wine_dbgstr_a(file2), path);
1553
1554 if (path)
1555 *path = '\0';
1556
1557 if (!file1 || !file2)
1558 return 0;
1559
1560 /* Handle roots first */
1561 if (PathIsUNCA(file1))
1562 {
1563 if (!PathIsUNCA(file2))
1564 return 0;
1565 iter1 += 2;
1566 iter2 += 2;
1567 }
1568 else if (PathIsUNCA(file2))
1569 return 0;
1570
1571 for (;;)
1572 {
1573 /* Update len */
1574 if ((!*iter1 || *iter1 == '\\') && (!*iter2 || *iter2 == '\\'))
1575 len = iter1 - file1; /* Common to this point */
1576
1577 if (!*iter1 || (tolower(*iter1) != tolower(*iter2)))
1578 break; /* Strings differ at this point */
1579
1580 iter1++;
1581 iter2++;
1582 }
1583
1584 if (len == 2)
1585 len++; /* Feature/Bug compatible with Win32 */
1586
1587 if (len && path)
1588 {
1589 memcpy(path, file1, len);
1590 path[len] = '\0';
1591 }
1592
1593 return len;
1594}
1595
1596int WINAPI PathCommonPrefixW(const WCHAR *file1, const WCHAR *file2, WCHAR *path)
1597{
1598 const WCHAR *iter1 = file1;
1599 const WCHAR *iter2 = file2;
1600 unsigned int len = 0;
1601
1602 TRACE("%s, %s, %p\n", wine_dbgstr_w(file1), wine_dbgstr_w(file2), path);
1603
1604 if (path)
1605 *path = '\0';
1606
1607 if (!file1 || !file2)
1608 return 0;
1609
1610 /* Handle roots first */
1611 if (PathIsUNCW(file1))
1612 {
1613 if (!PathIsUNCW(file2))
1614 return 0;
1615 iter1 += 2;
1616 iter2 += 2;
1617 }
1618 else if (PathIsUNCW(file2))
1619 return 0;
1620
1621 for (;;)
1622 {
1623 /* Update len */
1624 if ((!*iter1 || *iter1 == '\\') && (!*iter2 || *iter2 == '\\'))
1625 len = iter1 - file1; /* Common to this point */
1626
1627 if (!*iter1 || (towupper(*iter1) != towupper(*iter2)))
1628 break; /* Strings differ at this point */
1629
1630 iter1++;
1631 iter2++;
1632 }
1633
1634 if (len == 2)
1635 len++; /* Feature/Bug compatible with Win32 */
1636
1637 if (len && path)
1638 {
1639 memcpy(path, file1, len * sizeof(WCHAR));
1640 path[len] = '\0';
1641 }
1642
1643 return len;
1644}
1645
1646BOOL WINAPI PathIsPrefixA(const char *prefix, const char *path)
1647{
1649
1651}
1652
1654{
1656
1658}
1659
1660char * WINAPI PathFindFileNameA(const char *path)
1661{
1662 const char *last_slash = path;
1663
1664 TRACE("%s\n", wine_dbgstr_a(path));
1665
1666 while (path && *path)
1667 {
1668 if ((*path == '\\' || *path == '/' || *path == ':') &&
1669 path[1] && path[1] != '\\' && path[1] != '/')
1670 last_slash = path + 1;
1671 path = CharNextA(path);
1672 }
1673
1674 return (char *)last_slash;
1675}
1676
1678{
1679 const WCHAR *last_slash = path;
1680
1681 TRACE("%s\n", wine_dbgstr_w(path));
1682
1683 while (path && *path)
1684 {
1685 if ((*path == '\\' || *path == '/' || *path == ':') &&
1686 path[1] && path[1] != '\\' && path[1] != '/')
1687 last_slash = path + 1;
1688 path++;
1689 }
1690
1691 return (WCHAR *)last_slash;
1692}
1693
1694char * WINAPI PathGetArgsA(const char *path)
1695{
1696 BOOL seen_quote = FALSE;
1697
1698 TRACE("%s\n", wine_dbgstr_a(path));
1699
1700 if (!path)
1701 return NULL;
1702
1703 while (*path)
1704 {
1705 if (*path == ' ' && !seen_quote)
1706 return (char *)path + 1;
1707
1708 if (*path == '"')
1709 seen_quote = !seen_quote;
1710 path = CharNextA(path);
1711 }
1712
1713 return (char *)path;
1714}
1715
1717{
1718 BOOL seen_quote = FALSE;
1719
1720 TRACE("%s\n", wine_dbgstr_w(path));
1721
1722 if (!path)
1723 return NULL;
1724
1725 while (*path)
1726 {
1727 if (*path == ' ' && !seen_quote)
1728 return (WCHAR *)path + 1;
1729
1730 if (*path == '"')
1731 seen_quote = !seen_quote;
1732 path++;
1733 }
1734
1735 return (WCHAR *)path;
1736}
1737
1739{
1740 UINT flags = 0;
1741
1742 TRACE("%#x\n", ch);
1743
1744 if (!ch || ch < ' ' || ch == '<' || ch == '>' || ch == '"' || ch == '|' || ch == '/')
1745 flags = GCT_INVALID; /* Invalid */
1746 else if (ch == '*' || ch == '?')
1747 flags = GCT_WILD; /* Wildchars */
1748 else if (ch == '\\' || ch == ':')
1749 return GCT_SEPARATOR; /* Path separators */
1750 else
1751 {
1752 if (ch < 126)
1753 {
1754 if (((ch & 0x1) && ch != ';') || !ch || iswalnum(ch) || ch == '$' || ch == '&' || ch == '(' ||
1755 ch == '.' || ch == '@' || ch == '^' || ch == '\'' || ch == '`')
1756 {
1757 flags |= GCT_SHORTCHAR; /* All these are valid for DOS */
1758 }
1759 }
1760 else
1761 flags |= GCT_SHORTCHAR; /* Bug compatible with win32 */
1762
1763 flags |= GCT_LFNCHAR; /* Valid for long file names */
1764 }
1765
1766 return flags;
1767}
1768
1770{
1771 return PathGetCharTypeW(ch);
1772}
1773
1775{
1776 TRACE("%s\n", wine_dbgstr_a(path));
1777
1778 if (path && *path && path[1] == ':')
1779 {
1780 if (*path >= 'a' && *path <= 'z') return *path - 'a';
1781 if (*path >= 'A' && *path <= 'Z') return *path - 'A';
1782 }
1783 return -1;
1784}
1785
1787{
1788 TRACE("%s\n", wine_dbgstr_w(path));
1789
1790 if (!path)
1791 return -1;
1792
1793 if (!wcsncmp(path, L"\\\\?\\", 4)) path += 4;
1794
1795 if (!path[0] || path[1] != ':') return -1;
1796 if (path[0] >= 'A' && path[0] <= 'Z') return path[0] - 'A';
1797 if (path[0] >= 'a' && path[0] <= 'z') return path[0] - 'a';
1798 return -1;
1799}
1800
1802{
1803 TRACE("%s\n", wine_dbgstr_a(path));
1804
1805 if (!path)
1806 return FALSE;
1807
1808 while (*path)
1809 {
1810 if (*path == '\\' || *path == ':')
1811 return FALSE;
1812 path = CharNextA(path);
1813 }
1814
1815 return TRUE;
1816}
1817
1819{
1820 TRACE("%s\n", wine_dbgstr_w(path));
1821
1822 if (!path)
1823 return FALSE;
1824
1825 while (*path)
1826 {
1827 if (*path == '\\' || *path == ':')
1828 return FALSE;
1829 path++;
1830 }
1831
1832 return TRUE;
1833}
1834
1836{
1837 TRACE("%s\n", wine_dbgstr_a(path));
1838
1839 if (!(path && path[0] == '\\' && path[1] == '\\'))
1840 return FALSE;
1841
1842 while (*path)
1843 {
1844 if (*path == '\\')
1845 return FALSE;
1846 path = CharNextA(path);
1847 }
1848
1849 return TRUE;
1850}
1851
1853{
1854 TRACE("%s\n", wine_dbgstr_w(path));
1855
1856 if (!(path && path[0] == '\\' && path[1] == '\\'))
1857 return FALSE;
1858
1859 return !wcschr(path + 2, '\\');
1860}
1861
1863{
1864 char *start, *first;
1865
1866 TRACE("%s\n", wine_dbgstr_a(path));
1867
1868 if (!path || !*path)
1869 return;
1870
1871 start = first = path;
1872
1873 while (*path == ' ')
1874 path = CharNextA(path);
1875
1876 while (*path)
1877 *start++ = *path++;
1878
1879 if (start != first)
1880 while (start[-1] == ' ')
1881 start--;
1882
1883 *start = '\0';
1884}
1885
1887{
1888 WCHAR *start, *first;
1889
1890 TRACE("%s\n", wine_dbgstr_w(path));
1891
1892 if (!path || !*path)
1893 return;
1894
1895 start = first = path;
1896
1897 while (*path == ' ')
1898 path++;
1899
1900 while (*path)
1901 *start++ = *path++;
1902
1903 if (start != first)
1904 while (start[-1] == ' ')
1905 start--;
1906
1907 *start = '\0';
1908}
1909
1911{
1912 TRACE("%s\n", wine_dbgstr_a(path));
1913
1914 if (!path)
1915 return;
1916
1918 if (path && *path)
1919 *path = '\0';
1920}
1921
1923{
1924 TRACE("%s\n", wine_dbgstr_w(path));
1925
1926 if (!path)
1927 return;
1928
1930 if (path && *path)
1931 *path = '\0';
1932}
1933
1935{
1936 char *extension;
1937
1938 TRACE("%s, %s\n", wine_dbgstr_a(path), wine_dbgstr_a(ext));
1939
1940 extension = PathFindExtensionA(path);
1941
1942 if (!extension || (extension - path + strlen(ext) >= MAX_PATH))
1943 return FALSE;
1944
1945 strcpy(extension, ext);
1946 return TRUE;
1947}
1948
1950{
1951 WCHAR *extension;
1952
1953 TRACE("%s, %s\n", wine_dbgstr_w(path), wine_dbgstr_w(ext));
1954
1955 extension = PathFindExtensionW(path);
1956
1957 if (!extension || (extension - path + lstrlenW(ext) >= MAX_PATH))
1958 return FALSE;
1959
1960 lstrcpyW(extension, ext);
1961 return TRUE;
1962}
1963
1965{
1966 unsigned int len;
1967
1968 TRACE("%s\n", wine_dbgstr_a(path));
1969
1970 if (!path || *path != '"')
1971 return;
1972
1973 len = strlen(path) - 1;
1974 if (path[len] == '"')
1975 {
1976 path[len] = '\0';
1977 for (; *path; path++)
1978 *path = path[1];
1979 }
1980}
1981
1983{
1984 unsigned int len;
1985
1986 TRACE("%s\n", wine_dbgstr_w(path));
1987
1988 if (!path || *path != '"')
1989 return;
1990
1991 len = lstrlenW(path) - 1;
1992 if (path[len] == '"')
1993 {
1994 path[len] = '\0';
1995 for (; *path; path++)
1996 *path = path[1];
1997 }
1998}
1999
2001{
2002 char *ptr;
2003
2004 TRACE("%s\n", wine_dbgstr_a(path));
2005
2006 if (!path)
2007 return NULL;
2008
2010 if (!PathIsRootA(path) && *ptr == '\\')
2011 *ptr = '\0';
2012
2013 return ptr;
2014}
2015
2017{
2018 WCHAR *ptr;
2019
2020 TRACE("%s\n", wine_dbgstr_w(path));
2021
2022 if (!path)
2023 return NULL;
2024
2025 ptr = path + lstrlenW(path);
2026 if (ptr > path) ptr--;
2027 if (!PathIsRootW(path) && *ptr == '\\')
2028 *ptr = '\0';
2029
2030 return ptr;
2031}
2032
2034{
2035 unsigned int name_len = 0, ext_len = 0;
2036
2037 TRACE("%s\n", wine_dbgstr_a(path));
2038
2039 if (!path)
2040 return FALSE;
2041
2042 while (*path)
2043 {
2044 if (*path == ' ')
2045 return TRUE; /* DOS names cannot have spaces */
2046 if (*path == '.')
2047 {
2048 if (ext_len)
2049 return TRUE; /* DOS names have only one dot */
2050 ext_len = 1;
2051 }
2052 else if (ext_len)
2053 {
2054 ext_len++;
2055 if (ext_len > 4)
2056 return TRUE; /* DOS extensions are <= 3 chars*/
2057 }
2058 else
2059 {
2060 name_len++;
2061 if (name_len > 8)
2062 return TRUE; /* DOS names are <= 8 chars */
2063 }
2064 path = CharNextA(path);
2065 }
2066
2067 return FALSE; /* Valid DOS path */
2068}
2069
2071{
2072 unsigned int name_len = 0, ext_len = 0;
2073
2074 TRACE("%s\n", wine_dbgstr_w(path));
2075
2076 if (!path)
2077 return FALSE;
2078
2079 while (*path)
2080 {
2081 if (*path == ' ')
2082 return TRUE; /* DOS names cannot have spaces */
2083 if (*path == '.')
2084 {
2085 if (ext_len)
2086 return TRUE; /* DOS names have only one dot */
2087 ext_len = 1;
2088 }
2089 else if (ext_len)
2090 {
2091 ext_len++;
2092 if (ext_len > 4)
2093 return TRUE; /* DOS extensions are <= 3 chars*/
2094 }
2095 else
2096 {
2097 name_len++;
2098 if (name_len > 8)
2099 return TRUE; /* DOS names are <= 8 chars */
2100 }
2101 path++;
2102 }
2103
2104 return FALSE; /* Valid DOS path */
2105}
2106
2107#define PATH_CHAR_CLASS_LETTER 0x00000001
2108#define PATH_CHAR_CLASS_ASTERIX 0x00000002
2109#define PATH_CHAR_CLASS_DOT 0x00000004
2110#define PATH_CHAR_CLASS_BACKSLASH 0x00000008
2111#define PATH_CHAR_CLASS_COLON 0x00000010
2112#define PATH_CHAR_CLASS_SEMICOLON 0x00000020
2113#define PATH_CHAR_CLASS_COMMA 0x00000040
2114#define PATH_CHAR_CLASS_SPACE 0x00000080
2115#define PATH_CHAR_CLASS_OTHER_VALID 0x00000100
2116#define PATH_CHAR_CLASS_DOUBLEQUOTE 0x00000200
2117
2118#define PATH_CHAR_CLASS_INVALID 0x00000000
2119#define PATH_CHAR_CLASS_ANY 0xffffffff
2120
2121static const DWORD path_charclass[] =
2122{
2123 /* 0x00 */ PATH_CHAR_CLASS_INVALID, /* 0x01 */ PATH_CHAR_CLASS_INVALID,
2124 /* 0x02 */ PATH_CHAR_CLASS_INVALID, /* 0x03 */ PATH_CHAR_CLASS_INVALID,
2125 /* 0x04 */ PATH_CHAR_CLASS_INVALID, /* 0x05 */ PATH_CHAR_CLASS_INVALID,
2126 /* 0x06 */ PATH_CHAR_CLASS_INVALID, /* 0x07 */ PATH_CHAR_CLASS_INVALID,
2127 /* 0x08 */ PATH_CHAR_CLASS_INVALID, /* 0x09 */ PATH_CHAR_CLASS_INVALID,
2128 /* 0x0a */ PATH_CHAR_CLASS_INVALID, /* 0x0b */ PATH_CHAR_CLASS_INVALID,
2129 /* 0x0c */ PATH_CHAR_CLASS_INVALID, /* 0x0d */ PATH_CHAR_CLASS_INVALID,
2130 /* 0x0e */ PATH_CHAR_CLASS_INVALID, /* 0x0f */ PATH_CHAR_CLASS_INVALID,
2131 /* 0x10 */ PATH_CHAR_CLASS_INVALID, /* 0x11 */ PATH_CHAR_CLASS_INVALID,
2132 /* 0x12 */ PATH_CHAR_CLASS_INVALID, /* 0x13 */ PATH_CHAR_CLASS_INVALID,
2133 /* 0x14 */ PATH_CHAR_CLASS_INVALID, /* 0x15 */ PATH_CHAR_CLASS_INVALID,
2134 /* 0x16 */ PATH_CHAR_CLASS_INVALID, /* 0x17 */ PATH_CHAR_CLASS_INVALID,
2135 /* 0x18 */ PATH_CHAR_CLASS_INVALID, /* 0x19 */ PATH_CHAR_CLASS_INVALID,
2136 /* 0x1a */ PATH_CHAR_CLASS_INVALID, /* 0x1b */ PATH_CHAR_CLASS_INVALID,
2137 /* 0x1c */ PATH_CHAR_CLASS_INVALID, /* 0x1d */ PATH_CHAR_CLASS_INVALID,
2138 /* 0x1e */ PATH_CHAR_CLASS_INVALID, /* 0x1f */ PATH_CHAR_CLASS_INVALID,
2146 /* '.' */ PATH_CHAR_CLASS_DOT, /* '/' */ PATH_CHAR_CLASS_INVALID,
2156 /* 'B' */ PATH_CHAR_CLASS_ANY, /* 'C' */ PATH_CHAR_CLASS_ANY,
2157 /* 'D' */ PATH_CHAR_CLASS_ANY, /* 'E' */ PATH_CHAR_CLASS_ANY,
2158 /* 'F' */ PATH_CHAR_CLASS_ANY, /* 'G' */ PATH_CHAR_CLASS_ANY,
2159 /* 'H' */ PATH_CHAR_CLASS_ANY, /* 'I' */ PATH_CHAR_CLASS_ANY,
2160 /* 'J' */ PATH_CHAR_CLASS_ANY, /* 'K' */ PATH_CHAR_CLASS_ANY,
2161 /* 'L' */ PATH_CHAR_CLASS_ANY, /* 'M' */ PATH_CHAR_CLASS_ANY,
2162 /* 'N' */ PATH_CHAR_CLASS_ANY, /* 'O' */ PATH_CHAR_CLASS_ANY,
2163 /* 'P' */ PATH_CHAR_CLASS_ANY, /* 'Q' */ PATH_CHAR_CLASS_ANY,
2164 /* 'R' */ PATH_CHAR_CLASS_ANY, /* 'S' */ PATH_CHAR_CLASS_ANY,
2165 /* 'T' */ PATH_CHAR_CLASS_ANY, /* 'U' */ PATH_CHAR_CLASS_ANY,
2166 /* 'V' */ PATH_CHAR_CLASS_ANY, /* 'W' */ PATH_CHAR_CLASS_ANY,
2167 /* 'X' */ PATH_CHAR_CLASS_ANY, /* 'Y' */ PATH_CHAR_CLASS_ANY,
2172 /* 'b' */ PATH_CHAR_CLASS_ANY, /* 'c' */ PATH_CHAR_CLASS_ANY,
2173 /* 'd' */ PATH_CHAR_CLASS_ANY, /* 'e' */ PATH_CHAR_CLASS_ANY,
2174 /* 'f' */ PATH_CHAR_CLASS_ANY, /* 'g' */ PATH_CHAR_CLASS_ANY,
2175 /* 'h' */ PATH_CHAR_CLASS_ANY, /* 'i' */ PATH_CHAR_CLASS_ANY,
2176 /* 'j' */ PATH_CHAR_CLASS_ANY, /* 'k' */ PATH_CHAR_CLASS_ANY,
2177 /* 'l' */ PATH_CHAR_CLASS_ANY, /* 'm' */ PATH_CHAR_CLASS_ANY,
2178 /* 'n' */ PATH_CHAR_CLASS_ANY, /* 'o' */ PATH_CHAR_CLASS_ANY,
2179 /* 'p' */ PATH_CHAR_CLASS_ANY, /* 'q' */ PATH_CHAR_CLASS_ANY,
2180 /* 'r' */ PATH_CHAR_CLASS_ANY, /* 's' */ PATH_CHAR_CLASS_ANY,
2181 /* 't' */ PATH_CHAR_CLASS_ANY, /* 'u' */ PATH_CHAR_CLASS_ANY,
2182 /* 'v' */ PATH_CHAR_CLASS_ANY, /* 'w' */ PATH_CHAR_CLASS_ANY,
2183 /* 'x' */ PATH_CHAR_CLASS_ANY, /* 'y' */ PATH_CHAR_CLASS_ANY,
2187};
2188
2190{
2191 if ((unsigned)c > 0x7e)
2192 return class & PATH_CHAR_CLASS_OTHER_VALID;
2193
2194 return class & path_charclass[(unsigned)c];
2195}
2196
2198{
2199 if (c > 0x7e)
2200 return class & PATH_CHAR_CLASS_OTHER_VALID;
2201
2202 return class & path_charclass[c];
2203}
2204
2206{
2207 char *slash;
2208
2209 TRACE("%s\n", wine_dbgstr_a(path));
2210
2211 if (!path || !*path)
2212 return NULL;
2213
2214 if ((slash = StrChrA(path, '\\')))
2215 {
2216 if (slash[1] == '\\')
2217 slash++;
2218 return slash + 1;
2219 }
2220
2221 return (char *)path + strlen(path);
2222}
2223
2225{
2226 WCHAR *slash;
2227
2228 TRACE("%s\n", wine_dbgstr_w(path));
2229
2230 if (!path || !*path)
2231 return NULL;
2232
2233 if ((slash = StrChrW(path, '\\')))
2234 {
2235 if (slash[1] == '\\')
2236 slash++;
2237 return slash + 1;
2238 }
2239
2240 return (WCHAR *)path + lstrlenW(path);
2241}
2242
2243char * WINAPI PathSkipRootA(const char *path)
2244{
2245 TRACE("%s\n", wine_dbgstr_a(path));
2246
2247 if (!path || !*path)
2248 return NULL;
2249
2250 if (*path == '\\' && path[1] == '\\')
2251 {
2252 /* Network share: skip share server and mount point */
2253 path += 2;
2254 if ((path = StrChrA(path, '\\')) && (path = StrChrA(path + 1, '\\')))
2255 path++;
2256 return (char *)path;
2257 }
2258
2259 if (IsDBCSLeadByte(*path))
2260 return NULL;
2261
2262 /* Check x:\ */
2263 if (path[0] && path[1] == ':' && path[2] == '\\')
2264 return (char *)path + 3;
2265
2266 return NULL;
2267}
2268
2270{
2271 TRACE("%s\n", wine_dbgstr_w(path));
2272
2273 if (!path || !*path)
2274 return NULL;
2275
2276 if (*path == '\\' && path[1] == '\\')
2277 {
2278 /* Network share: skip share server and mount point */
2279 path += 2;
2280 if ((path = StrChrW(path, '\\')) && (path = StrChrW(path + 1, '\\')))
2281 path++;
2282 return (WCHAR *)path;
2283 }
2284
2285 /* Check x:\ */
2286 if (path[0] && path[1] == ':' && path[2] == '\\')
2287 return (WCHAR *)path + 3;
2288
2289 return NULL;
2290}
2291
2293{
2294 TRACE("%s\n", wine_dbgstr_a(path));
2295
2296 if (path)
2297 {
2299 if (filename != path)
2301 }
2302}
2303
2305{
2306 WCHAR *filename;
2307
2308 TRACE("%s\n", wine_dbgstr_w(path));
2310 if (filename != path)
2311 RtlMoveMemory(path, filename, (lstrlenW(filename) + 1) * sizeof(WCHAR));
2312}
2313
2315{
2316 TRACE("%s, %p, %u\n", wine_dbgstr_a(path), buffer, length);
2317
2319 return TRUE;
2320
2321 return !!GetFullPathNameA(path, length, buffer, NULL);
2322}
2323
2325{
2326 TRACE("%s, %p, %u\n", wine_dbgstr_w(path), buffer, length);
2327
2329 return TRUE;
2330 return !!GetFullPathNameW(path, length, buffer, NULL);
2331}
2332
2333BOOL WINAPI PathRelativePathToA(char *path, const char *from, DWORD attributes_from, const char *to,
2334 DWORD attributes_to)
2335{
2336 WCHAR pathW[MAX_PATH], fromW[MAX_PATH], toW[MAX_PATH];
2337 BOOL ret;
2338
2339 TRACE("%p, %s, %#lx, %s, %#lx\n", path, wine_dbgstr_a(from), attributes_from, wine_dbgstr_a(to), attributes_to);
2340
2341 if (!path || !from || !to)
2342 return FALSE;
2343
2344 MultiByteToWideChar(CP_ACP, 0, from, -1, fromW, ARRAY_SIZE(fromW));
2345 MultiByteToWideChar(CP_ACP, 0, to, -1, toW, ARRAY_SIZE(toW));
2346 ret = PathRelativePathToW(pathW, fromW, attributes_from, toW, attributes_to);
2347 WideCharToMultiByte(CP_ACP, 0, pathW, -1, path, MAX_PATH, 0, 0);
2348
2349 return ret;
2350}
2351
2352BOOL WINAPI PathRelativePathToW(WCHAR *path, const WCHAR *from, DWORD attributes_from, const WCHAR *to,
2353 DWORD attributes_to)
2354{
2355 WCHAR fromW[MAX_PATH], toW[MAX_PATH];
2356 DWORD len;
2357
2358 TRACE("%p, %s, %#lx, %s, %#lx\n", path, wine_dbgstr_w(from), attributes_from, wine_dbgstr_w(to), attributes_to);
2359
2360 if (!path || !from || !to)
2361 return FALSE;
2362
2363 *path = '\0';
2364 lstrcpynW(fromW, from, ARRAY_SIZE(fromW));
2365 lstrcpynW(toW, to, ARRAY_SIZE(toW));
2366
2367 if (!(attributes_from & FILE_ATTRIBUTE_DIRECTORY))
2368 PathRemoveFileSpecW(fromW);
2369 if (!(attributes_to & FILE_ATTRIBUTE_DIRECTORY))
2371
2372 /* Paths can only be relative if they have a common root */
2373 if (!(len = PathCommonPrefixW(fromW, toW, 0)))
2374 return FALSE;
2375
2376 /* Strip off 'from' components to the root, by adding "..\" */
2377 from = fromW + len;
2378 if (!*from)
2379 {
2380 path[0] = '.';
2381 path[1] = '\0';
2382 }
2383 if (*from == '\\')
2384 from++;
2385
2386 while (*from)
2387 {
2389 lstrcatW(path, *from ? L"..\\" : L"..");
2390 }
2391
2392 /* From the root add the components of 'to' */
2393 to += len;
2394 /* We check to[-1] to avoid skipping end of string. See the notes for this function. */
2395 if (*to && to[-1])
2396 {
2397 if (*to != '\\')
2398 to--;
2399 len = lstrlenW(path);
2400 if (len + lstrlenW(to) >= MAX_PATH)
2401 {
2402 *path = '\0';
2403 return FALSE;
2404 }
2405 lstrcpyW(path + len, to);
2406 }
2407
2408 return TRUE;
2409}
2410
2412{
2413 WCHAR *pathW, *maskW;
2414 HRESULT ret;
2415
2416 TRACE("%s, %s\n", wine_dbgstr_a(path), wine_dbgstr_a(mask));
2417
2418 if (flags)
2419 FIXME("Ignoring flags %#lx.\n", flags);
2420
2421 if (!lstrcmpA(mask, "*.*"))
2422 return S_OK; /* Matches every path */
2423
2425 maskW = heap_strdupAtoW( mask );
2426 ret = PathMatchSpecExW( pathW, maskW, flags );
2427 heap_free( pathW );
2428 heap_free( maskW );
2429 return ret;
2430}
2431
2432BOOL WINAPI PathMatchSpecA(const char *path, const char *mask)
2433{
2434 return PathMatchSpecExA(path, mask, 0) == S_OK;
2435}
2436
2438{
2439 while (*name && *mask && *mask != ';')
2440 {
2441 if (*mask == '*')
2442 {
2443 do
2444 {
2445 if (path_match_maskW(name, mask + 1))
2446 return TRUE; /* try substrings */
2447 } while (*name++);
2448 return FALSE;
2449 }
2450
2451 if (towupper(*mask) != towupper(*name) && *mask != '?')
2452 return FALSE;
2453
2454 name++;
2455 mask++;
2456 }
2457
2458 if (!*name)
2459 {
2460 while (*mask == '*')
2461 mask++;
2462 if (!*mask || *mask == ';')
2463 return TRUE;
2464 }
2465
2466 return FALSE;
2467}
2468
2470{
2471 TRACE("%s, %s\n", wine_dbgstr_w(path), wine_dbgstr_w(mask));
2472
2473 if (flags)
2474 FIXME("Ignoring flags %#lx.\n", flags);
2475
2476 if (!lstrcmpW(mask, L"*.*"))
2477 return S_OK; /* Matches every path */
2478
2479 while (*mask)
2480 {
2481 while (*mask == ' ')
2482 mask++; /* Eat leading spaces */
2483
2485 return S_OK; /* Matches the current path */
2486
2487 while (*mask && *mask != ';')
2488 mask++; /* masks separated by ';' */
2489
2490 if (*mask == ';')
2491 mask++;
2492 }
2493
2494 return S_FALSE;
2495}
2496
2498{
2499 return PathMatchSpecExW(path, mask, 0) == S_OK;
2500}
2501
2503{
2504 TRACE("%s\n", wine_dbgstr_a(path));
2505
2506 if (path && StrChrA(path, ' '))
2507 {
2508 size_t len = strlen(path) + 1;
2509
2510 if (len + 2 < MAX_PATH)
2511 {
2512 memmove(path + 1, path, len);
2513 path[0] = '"';
2514 path[len] = '"';
2515 path[len + 1] = '\0';
2516 }
2517 }
2518}
2519
2521{
2522 TRACE("%s\n", wine_dbgstr_w(path));
2523
2524 if (path && StrChrW(path, ' '))
2525 {
2526 int len = lstrlenW(path) + 1;
2527
2528 if (len + 2 < MAX_PATH)
2529 {
2530 memmove(path + 1, path, len * sizeof(WCHAR));
2531 path[0] = '"';
2532 path[len] = '"';
2533 path[len + 1] = '\0';
2534 }
2535 }
2536}
2537
2538BOOL WINAPI PathIsSameRootA(const char *path1, const char *path2)
2539{
2540 const char *start;
2541 int len;
2542
2544
2545 if (!path1 || !path2 || !(start = PathSkipRootA(path1)))
2546 return FALSE;
2547
2549 return start - path1 <= len;
2550}
2551
2553{
2554 const WCHAR *start;
2555 int len;
2556
2558
2559 if (!path1 || !path2 || !(start = PathSkipRootW(path1)))
2560 return FALSE;
2561
2563 return start - path1 <= len;
2564}
2565
2567{
2568 UINT prev_mode;
2569 DWORD attrs;
2570
2571 TRACE("%s\n", wine_dbgstr_a(path));
2572
2573 if (!path)
2574 return FALSE;
2575
2576 /* Prevent a dialog box if path is on a disk that has been ejected. */
2578 attrs = GetFileAttributesA(path);
2579 SetErrorMode(prev_mode);
2580 return attrs != INVALID_FILE_ATTRIBUTES;
2581}
2582
2584{
2585 UINT prev_mode;
2586 DWORD attrs;
2587
2588 TRACE("%s\n", wine_dbgstr_w(path));
2589
2590 if (!path)
2591 return FALSE;
2592
2594 attrs = GetFileAttributesW(path);
2595 SetErrorMode(prev_mode);
2596 return attrs != INVALID_FILE_ATTRIBUTES;
2597}
2598
2600{
2601 int ret = 0;
2602 char *comma;
2603
2604 TRACE("%s\n", debugstr_a(path));
2605
2606 if (!path)
2607 return 0;
2608
2609 if ((comma = strchr(path, ',')))
2610 {
2611 *comma++ = '\0';
2612 ret = StrToIntA(comma);
2613 }
2616
2617 return ret;
2618}
2619
2621{
2622 WCHAR *comma;
2623 int ret = 0;
2624
2625 TRACE("%s\n", debugstr_w(path));
2626
2627 if (!path)
2628 return 0;
2629
2630 if ((comma = StrChrW(path, ',')))
2631 {
2632 *comma++ = '\0';
2633 ret = StrToIntW(comma);
2634 }
2637
2638 return ret;
2639}
2640
2642{
2643 WCHAR bufferW[MAX_PATH], *pathW;
2644 DWORD len;
2645 BOOL ret;
2646
2647 TRACE("%s, %p, %d\n", debugstr_a(path), buffer, buf_len);
2648
2650 if (!pathW) return FALSE;
2651
2654 if (!ret) return FALSE;
2655
2656 len = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
2657 if (buf_len < len + 1) return FALSE;
2658
2659 WideCharToMultiByte(CP_ACP, 0, bufferW, -1, buffer, buf_len, NULL, NULL);
2660 return TRUE;
2661}
2662
2664{
2665 const WCHAR *var;
2668};
2669
2671{
2672 while (map->var)
2673 {
2674 map->len = ExpandEnvironmentStringsW(map->var, map->path, ARRAY_SIZE(map->path));
2675 /* exclude null from length */
2676 if (map->len) map->len--;
2677 map++;
2678 }
2679}
2680
2682{
2683 static struct envvars_map null_var = {L"", {0}, 0};
2684 struct envvars_map *match = &null_var, *cur;
2685 struct envvars_map envvars[] =
2686 {
2687 { L"%ALLUSERSPROFILE%" },
2688 { L"%APPDATA%" },
2689 { L"%ProgramFiles%" },
2690 { L"%SystemRoot%" },
2691 { L"%SystemDrive%" },
2692 { L"%USERPROFILE%" },
2693 { NULL }
2694 };
2695 DWORD pathlen;
2696 UINT needed;
2697
2698 TRACE("%s, %p, %d\n", debugstr_w(path), buffer, buf_len);
2699
2700 pathlen = lstrlenW(path);
2701 init_envvars_map(envvars);
2702 cur = envvars;
2703 while (cur->var)
2704 {
2705 /* path can't contain expanded value or value wasn't retrieved */
2706 if (cur->len == 0 || cur->len > pathlen ||
2707 CompareStringOrdinal( cur->path, cur->len, path, cur->len, TRUE ) != CSTR_EQUAL)
2708 {
2709 cur++;
2710 continue;
2711 }
2712
2713 if (cur->len > match->len)
2714 match = cur;
2715 cur++;
2716 }
2717
2718 needed = lstrlenW(match->var) + 1 + pathlen - match->len;
2719 if (match->len == 0 || needed > buf_len) return FALSE;
2720
2721 lstrcpyW(buffer, match->var);
2722 lstrcatW(buffer, &path[match->len]);
2723 TRACE("ret %s\n", debugstr_w(buffer));
2724
2725 return TRUE;
2726}
2727
2728static const struct
2729{
2732}
2733url_schemes[] =
2734{
2735 { URL_SCHEME_FTP, L"ftp"},
2736 { URL_SCHEME_HTTP, L"http"},
2737 { URL_SCHEME_GOPHER, L"gopher"},
2738 { URL_SCHEME_MAILTO, L"mailto"},
2739 { URL_SCHEME_NEWS, L"news"},
2740 { URL_SCHEME_NNTP, L"nntp"},
2741 { URL_SCHEME_TELNET, L"telnet"},
2742 { URL_SCHEME_WAIS, L"wais"},
2743 { URL_SCHEME_FILE, L"file"},
2744 { URL_SCHEME_MK, L"mk"},
2745 { URL_SCHEME_HTTPS, L"https"},
2746 { URL_SCHEME_SHELL, L"shell"},
2747 { URL_SCHEME_SNEWS, L"snews"},
2748 { URL_SCHEME_LOCAL, L"local"},
2749 { URL_SCHEME_JAVASCRIPT, L"javascript"},
2750 { URL_SCHEME_VBSCRIPT, L"vbscript"},
2751 { URL_SCHEME_ABOUT, L"about"},
2752 { URL_SCHEME_RES, L"res"},
2754
2755static const WCHAR *parse_scheme( const WCHAR *p )
2756{
2757 while (*p <= 0x7f && (iswalnum( *p ) || *p == '+' || *p == '-' || *p == '.'))
2758 ++p;
2759 return p;
2760}
2761
2762static DWORD get_scheme_code(const WCHAR *scheme, DWORD scheme_len)
2763{
2764 unsigned int i;
2765
2766 for (i = 0; i < ARRAY_SIZE(url_schemes); ++i)
2767 {
2768 if (scheme_len == lstrlenW(url_schemes[i].scheme_name)
2769 && !wcsnicmp(scheme, url_schemes[i].scheme_name, scheme_len))
2770 return url_schemes[i].scheme_number;
2771 }
2772
2773 return URL_SCHEME_UNKNOWN;
2774}
2775
2777{
2779 const char *ptr = url;
2780 int len;
2781
2782 TRACE("%s, %p\n", wine_dbgstr_a(url), result);
2783
2784 if (result->cbSize != sizeof(*result))
2785 return E_INVALIDARG;
2786
2787 while (*ptr && (isalnum( *ptr ) || *ptr == '-' || *ptr == '+' || *ptr == '.'))
2788 ptr++;
2789
2790 if (*ptr != ':' || ptr <= url + 1)
2791 {
2792 result->pszProtocol = NULL;
2793 return URL_E_INVALID_SYNTAX;
2794 }
2795
2796 result->pszProtocol = url;
2797 result->cchProtocol = ptr - url;
2798 result->pszSuffix = ptr + 1;
2799 result->cchSuffix = strlen(result->pszSuffix);
2800
2802 result->nScheme = get_scheme_code(scheme, len);
2803
2804 return S_OK;
2805}
2806
2808{
2809 const WCHAR *ptr = url;
2810
2811 TRACE("%s, %p\n", wine_dbgstr_w(url), result);
2812
2813 if (result->cbSize != sizeof(*result))
2814 return E_INVALIDARG;
2815
2816 while (*ptr && (iswalnum(*ptr) || *ptr == '-' || *ptr == '+' || *ptr == '.'))
2817 ptr++;
2818
2819 if (*ptr != ':' || ptr <= url + 1)
2820 {
2821 result->pszProtocol = NULL;
2822 return URL_E_INVALID_SYNTAX;
2823 }
2824
2825 result->pszProtocol = url;
2826 result->cchProtocol = ptr - url;
2827 result->pszSuffix = ptr + 1;
2828 result->cchSuffix = lstrlenW(result->pszSuffix);
2829 result->nScheme = get_scheme_code(url, ptr - url);
2830
2831 return S_OK;
2832}
2833
2834HRESULT WINAPI UrlUnescapeA(char *url, char *unescaped, DWORD *unescaped_len, DWORD flags)
2835{
2836 BOOL stop_unescaping = FALSE;
2837 const char *src;
2838 char *dst, next;
2839 DWORD needed;
2840 HRESULT hr;
2841
2842 TRACE("%s, %p, %p, %#lx\n", wine_dbgstr_a(url), unescaped, unescaped_len, flags);
2843
2844 if (!url)
2845 return E_INVALIDARG;
2846
2848 dst = url;
2849 else
2850 {
2851 if (!unescaped || !unescaped_len) return E_INVALIDARG;
2852 dst = unescaped;
2853 }
2854
2855 for (src = url, needed = 0; *src; src++, needed++)
2856 {
2857 if (flags & URL_DONT_UNESCAPE_EXTRA_INFO && (*src == '#' || *src == '?'))
2858 {
2859 stop_unescaping = TRUE;
2860 next = *src;
2861 }
2862 else if (*src == '%' && isxdigit(*(src + 1)) && isxdigit(*(src + 2)) && !stop_unescaping)
2863 {
2864 INT ih;
2865 char buf[3];
2866 memcpy(buf, src + 1, 2);
2867 buf[2] = '\0';
2868 ih = strtol(buf, NULL, 16);
2869 next = (CHAR) ih;
2870 src += 2; /* Advance to end of escape */
2871 }
2872 else
2873 next = *src;
2874
2875 if (flags & URL_UNESCAPE_INPLACE || needed < *unescaped_len)
2876 *dst++ = next;
2877 }
2878
2879 if (flags & URL_UNESCAPE_INPLACE || needed < *unescaped_len)
2880 {
2881 *dst = '\0';
2882 hr = S_OK;
2883 }
2884 else
2885 {
2886 needed++; /* add one for the '\0' */
2887 hr = E_POINTER;
2888 }
2889
2890 if (!(flags & URL_UNESCAPE_INPLACE))
2891 *unescaped_len = needed;
2892
2893 if (hr == S_OK)
2894 TRACE("result %s\n", flags & URL_UNESCAPE_INPLACE ? wine_dbgstr_a(url) : wine_dbgstr_a(unescaped));
2895
2896 return hr;
2897}
2898
2899static int get_utf8_len(unsigned char code)
2900{
2901 if (code < 0x80)
2902 return 1;
2903 else if ((code & 0xe0) == 0xc0)
2904 return 2;
2905 else if ((code & 0xf0) == 0xe0)
2906 return 3;
2907 else if ((code & 0xf8) == 0xf0)
2908 return 4;
2909 return 0;
2910}
2911
2912HRESULT WINAPI UrlUnescapeW(WCHAR *url, WCHAR *unescaped, DWORD *unescaped_len, DWORD flags)
2913{
2914 WCHAR *dst, next, utf16_buf[4];
2915 BOOL stop_unescaping = FALSE;
2916 int utf8_len, utf16_len, i;
2917 const WCHAR *src;
2918 char utf8_buf[4];
2919 DWORD needed;
2920 HRESULT hr;
2921
2922 TRACE("%s, %p, %p, %#lx\n", wine_dbgstr_w(url), unescaped, unescaped_len, flags);
2923
2924 if (!url)
2925 return E_INVALIDARG;
2926
2928 dst = url;
2929 else
2930 {
2931 if (!unescaped || !unescaped_len) return E_INVALIDARG;
2932 dst = unescaped;
2933 }
2934
2935 for (src = url, needed = 0; *src; src++, needed++)
2936 {
2937 utf16_len = 0;
2938 if (flags & URL_DONT_UNESCAPE_EXTRA_INFO && (*src == '#' || *src == '?'))
2939 {
2940 stop_unescaping = TRUE;
2941 next = *src;
2942 }
2943 else if (*src == '%' && isxdigit(*(src + 1)) && isxdigit(*(src + 2)) && !stop_unescaping)
2944 {
2945 INT ih;
2946 WCHAR buf[5] = L"0x";
2947
2948 memcpy(buf + 2, src + 1, 2*sizeof(WCHAR));
2949 buf[4] = 0;
2951 src += 2; /* Advance to end of escape */
2952
2954 {
2955 utf8_buf[0] = ih;
2956 utf8_len = get_utf8_len(ih);
2957 for (i = 1; i < utf8_len && *(src + 1) == '%' && *(src + 2) && *(src + 3); i++)
2958 {
2959 memcpy(buf + 2, src + 2, 2 * sizeof(WCHAR));
2961 /* Check if it is a valid continuation byte. */
2962 if ((ih & 0xc0) == 0x80)
2963 {
2964 utf8_buf[i] = ih;
2965 src += 3;
2966 }
2967 else
2968 break;
2969 }
2970
2972 utf8_buf, i, utf16_buf, ARRAYSIZE(utf16_buf));
2973 if (utf16_len)
2974 needed += utf16_len - 1;
2975 else
2976 next = 0xfffd;
2977 }
2978 else
2979 next = (WCHAR) ih;
2980 }
2981 else
2982 next = *src;
2983
2984 if (flags & URL_UNESCAPE_INPLACE || needed < *unescaped_len)
2985 {
2986 if (utf16_len)
2987 {
2988 memcpy(dst, utf16_buf, utf16_len * sizeof(*utf16_buf));
2989 dst += utf16_len;
2990 }
2991 else
2992 *dst++ = next;
2993 }
2994 }
2995
2996 if (flags & URL_UNESCAPE_INPLACE || needed < *unescaped_len)
2997 {
2998 *dst = '\0';
2999 hr = S_OK;
3000 }
3001 else
3002 {
3003 needed++; /* add one for the '\0' */
3004 hr = E_POINTER;
3005 }
3006
3007 if (!(flags & URL_UNESCAPE_INPLACE))
3008 *unescaped_len = needed;
3009
3010 if (hr == S_OK)
3011 TRACE("result %s\n", flags & URL_UNESCAPE_INPLACE ? wine_dbgstr_w(url) : wine_dbgstr_w(unescaped));
3012
3013 return hr;
3014}
3015
3016HRESULT WINAPI PathCreateFromUrlA(const char *pszUrl, char *pszPath, DWORD *pcchPath, DWORD dwReserved)
3017{
3018 WCHAR bufW[MAX_PATH];
3019 WCHAR *pathW = bufW;
3020 UNICODE_STRING urlW;
3021 HRESULT ret;
3022 DWORD lenW = ARRAY_SIZE(bufW), lenA;
3023
3024 if (!pszUrl || !pszPath || !pcchPath || !*pcchPath)
3025 return E_INVALIDARG;
3026
3027 if(!RtlCreateUnicodeStringFromAsciiz(&urlW, pszUrl))
3028 return E_INVALIDARG;
3029 if((ret = PathCreateFromUrlW(urlW.Buffer, pathW, &lenW, dwReserved)) == E_POINTER) {
3030 pathW = HeapAlloc(GetProcessHeap(), 0, lenW * sizeof(WCHAR));
3031 ret = PathCreateFromUrlW(urlW.Buffer, pathW, &lenW, dwReserved);
3032 }
3033 if(ret == S_OK) {
3034 RtlUnicodeToMultiByteSize(&lenA, pathW, lenW * sizeof(WCHAR));
3035 if(*pcchPath > lenA) {
3036 RtlUnicodeToMultiByteN(pszPath, *pcchPath - 1, &lenA, pathW, lenW * sizeof(WCHAR));
3037 pszPath[lenA] = 0;
3038 *pcchPath = lenA;
3039 } else {
3040 *pcchPath = lenA + 1;
3041 ret = E_POINTER;
3042 }
3043 }
3044 if(pathW != bufW) HeapFree(GetProcessHeap(), 0, pathW);
3045 RtlFreeUnicodeString(&urlW);
3046 return ret;
3047}
3048
3050{
3051 DWORD nslashes, unescape, len;
3052 const WCHAR *src;
3053 WCHAR *tpath, *dst;
3054 HRESULT hr = S_OK;
3055
3056 TRACE("%s, %p, %p, %#lx\n", wine_dbgstr_w(url), path, pcchPath, dwReserved);
3057
3058 if (!url || !path || !pcchPath || !*pcchPath)
3059 return E_INVALIDARG;
3060
3061 if (wcsnicmp( url, L"file:", 5))
3062 return E_INVALIDARG;
3063
3064 url += 5;
3065
3066 src = url;
3067 nslashes = 0;
3068 while (*src == '/' || *src == '\\')
3069 {
3070 nslashes++;
3071 src++;
3072 }
3073
3074 /* We need a temporary buffer so we can compute what size to ask for.
3075 * We know that the final string won't be longer than the current pszUrl
3076 * plus at most two backslashes. All the other transformations make it
3077 * shorter.
3078 */
3079 len = 2 + lstrlenW(url) + 1;
3080 if (*pcchPath < len)
3081 tpath = heap_alloc(len * sizeof(WCHAR));
3082 else
3083 tpath = path;
3084
3085 len = 0;
3086 dst = tpath;
3087 unescape = 1;
3088 switch (nslashes)
3089 {
3090 case 0:
3091 /* 'file:' + escaped DOS path */
3092 break;
3093 case 1:
3094 /* 'file:/' + escaped DOS path */
3095 /* fall through */
3096 case 3:
3097 /* 'file:///' (implied localhost) + escaped DOS path */
3098 if (!is_escaped_drive_spec( src ))
3099 src -= 1;
3100 break;
3101 case 2:
3102 if (lstrlenW(src) >= 10 && !wcsnicmp( src, L"localhost", 9) && (src[9] == '/' || src[9] == '\\'))
3103 {
3104 /* 'file://localhost/' + escaped DOS path */
3105 src += 10;
3106 }
3107 else if (is_escaped_drive_spec( src ))
3108 {
3109 /* 'file://' + unescaped DOS path */
3110 unescape = 0;
3111 }
3112 else
3113 {
3114 /* 'file://hostname:port/path' (where path is escaped)
3115 * or 'file:' + escaped UNC path (\\server\share\path)
3116 * The second form is clearly specific to Windows and it might
3117 * even be doing a network lookup to try to figure it out.
3118 */
3119 while (*src && *src != '/' && *src != '\\')
3120 src++;
3121 len = src - url;
3122 StrCpyNW(dst, url, len + 1);
3123 dst += len;
3124 if (*src && is_escaped_drive_spec( src + 1 ))
3125 {
3126 /* 'Forget' to add a trailing '/', just like Windows */
3127 src++;
3128 }
3129 }
3130 break;
3131 case 4:
3132 /* 'file://' + unescaped UNC path (\\server\share\path) */
3133 unescape = 0;
3135 break;
3136 /* fall through */
3137 default:
3138 /* 'file:/...' + escaped UNC path (\\server\share\path) */
3139 src -= 2;
3140 }
3141
3142 /* Copy the remainder of the path */
3143 len += lstrlenW(src);
3144 lstrcpyW(dst, src);
3145
3146 /* First do the Windows-specific path conversions */
3147 for (dst = tpath; *dst; dst++)
3148 if (*dst == '/') *dst = '\\';
3149 if (is_escaped_drive_spec( tpath ))
3150 tpath[1] = ':'; /* c| -> c: */
3151
3152 /* And only then unescape the path (i.e. escaped slashes are left as is) */
3153 if (unescape)
3154 {
3156 if (hr == S_OK)
3157 {
3158 /* When working in-place UrlUnescapeW() does not set len */
3159 len = lstrlenW(tpath);
3160 }
3161 }
3162
3163 if (*pcchPath < len + 1)
3164 {
3165 hr = E_POINTER;
3166 *pcchPath = len + 1;
3167 }
3168 else
3169 {
3170 *pcchPath = len;
3171 if (tpath != path)
3172 lstrcpyW(path, tpath);
3173 }
3174 if (tpath != path)
3175 heap_free(tpath);
3176
3177 TRACE("Returning (%lu) %s\n", *pcchPath, wine_dbgstr_w(path));
3178 return hr;
3179}
3180
3182{
3184 DWORD size;
3185 HRESULT hr;
3186
3187 size = MAX_PATH;
3189 if (SUCCEEDED(hr))
3190 {
3191 /* Yes, this is supposed to crash if 'path' is NULL */
3192 *path = StrDupW(pathW);
3193 }
3194
3195 return hr;
3196}
3197
3199{
3201 HRESULT hr;
3202
3203 TRACE("%s\n", wine_dbgstr_a(path));
3204
3205 if (!path || !*path)
3206 return FALSE;
3207
3208 /* get protocol */
3209 base.cbSize = sizeof(base);
3210 hr = ParseURLA(path, &base);
3211 return hr == S_OK && (base.nScheme != URL_SCHEME_INVALID);
3212}
3213
3215{
3217 HRESULT hr;
3218
3219 TRACE("%s\n", wine_dbgstr_w(path));
3220
3221 if (!path || !*path)
3222 return FALSE;
3223
3224 /* get protocol */
3225 base.cbSize = sizeof(base);
3226 hr = ParseURLW(path, &base);
3227 return hr == S_OK && (base.nScheme != URL_SCHEME_INVALID);
3228}
3229
3230#define WINE_URL_BASH_AS_SLASH 0x01
3231#define WINE_URL_COLLAPSE_SLASHES 0x02
3232#define WINE_URL_ESCAPE_SLASH 0x04
3233#define WINE_URL_ESCAPE_HASH 0x08
3234#define WINE_URL_ESCAPE_QUESTION 0x10
3235#define WINE_URL_STOP_ON_HASH 0x20
3236#define WINE_URL_STOP_ON_QUESTION 0x40
3237
3239{
3241 return ch == ' ';
3242
3243 if ((flags & URL_ESCAPE_PERCENT) && (ch == '%'))
3244 return TRUE;
3245
3246 if ((flags & URL_ESCAPE_AS_UTF8) && (ch >= 0x80))
3247 return TRUE;
3248
3249 if (ch <= 31 || (ch >= 127 && ch <= 255) )
3250 return TRUE;
3251
3252 if (iswalnum(ch))
3253 return FALSE;
3254
3255 switch (ch) {
3256 case ' ':
3257 case '<':
3258 case '>':
3259 case '\"':
3260 case '{':
3261 case '}':
3262 case '|':
3263 case '\\':
3264 case '^':
3265 case ']':
3266 case '[':
3267 case '`':
3268 case '&':
3269 return TRUE;
3270 case '/':
3271 return !!(int_flags & WINE_URL_ESCAPE_SLASH);
3272 case '?':
3273 return !!(int_flags & WINE_URL_ESCAPE_QUESTION);
3274 case '#':
3275 return !!(int_flags & WINE_URL_ESCAPE_HASH);
3276 default:
3277 return FALSE;
3278 }
3279}
3280
3281HRESULT WINAPI UrlEscapeA(const char *url, char *escaped, DWORD *escaped_len, DWORD flags)
3282{
3284 WCHAR *escapedW = bufW;
3285 UNICODE_STRING urlW;
3286 HRESULT hr;
3287 DWORD lenW = ARRAY_SIZE(bufW), lenA;
3288
3289 if (!escaped || !escaped_len || !*escaped_len)
3290 return E_INVALIDARG;
3291
3293 return E_INVALIDARG;
3294
3296 {
3297 RtlFreeUnicodeString(&urlW);
3298 return E_NOTIMPL;
3299 }
3300
3301 if ((hr = UrlEscapeW(urlW.Buffer, escapedW, &lenW, flags)) == E_POINTER)
3302 {
3303 escapedW = heap_alloc(lenW * sizeof(WCHAR));
3304 hr = UrlEscapeW(urlW.Buffer, escapedW, &lenW, flags);
3305 }
3306
3307 if (hr == S_OK)
3308 {
3309 RtlUnicodeToMultiByteSize(&lenA, escapedW, lenW * sizeof(WCHAR));
3310 if (*escaped_len > lenA)
3311 {
3312 RtlUnicodeToMultiByteN(escaped, *escaped_len - 1, &lenA, escapedW, lenW * sizeof(WCHAR));
3313 escaped[lenA] = 0;
3314 *escaped_len = lenA;
3315 }
3316 else
3317 {
3318 *escaped_len = lenA + 1;
3319 hr = E_POINTER;
3320 }
3321 }
3322 if (escapedW != bufW)
3323 heap_free(escapedW);
3324 RtlFreeUnicodeString(&urlW);
3325 return hr;
3326}
3327
3328HRESULT WINAPI UrlEscapeW(const WCHAR *url, WCHAR *escaped, DWORD *escaped_len, DWORD flags)
3329{
3330 DWORD needed = 0, slashes = 0, int_flags;
3331 WCHAR next[12], *dst, *dst_ptr;
3332 BOOL stop_escaping = FALSE;
3334 const WCHAR *src;
3335 INT i, len;
3336 HRESULT hr;
3337
3338 TRACE("%p, %s, %p, %p, %#lx\n", url, wine_dbgstr_w(url), escaped, escaped_len, flags);
3339
3340 if (!url || !escaped_len || !escaped || *escaped_len == 0)
3341 return E_INVALIDARG;
3342
3345 {
3346 FIXME("Unimplemented flags: %08lx\n", flags);
3347 }
3348
3349 dst_ptr = dst = heap_alloc(*escaped_len * sizeof(WCHAR));
3350 if (!dst_ptr)
3351 return E_OUTOFMEMORY;
3352
3353 /* fix up flags */
3355 /* if SPACES_ONLY specified, reset the other controls */
3357 else
3358 /* if SPACES_ONLY *not* specified the assume DONT_ESCAPE_EXTRA_INFO */
3360
3361 int_flags = 0;
3364 else
3365 {
3366 parsed_url.cbSize = sizeof(parsed_url);
3367 if (ParseURLW(url, &parsed_url) != S_OK)
3369
3370 TRACE("scheme = %d (%s)\n", parsed_url.nScheme, debugstr_wn(parsed_url.pszProtocol, parsed_url.cchProtocol));
3371
3374
3375 switch(parsed_url.nScheme) {
3376 case URL_SCHEME_FILE:
3378 int_flags &= ~WINE_URL_STOP_ON_HASH;
3379 break;
3380
3381 case URL_SCHEME_HTTP:
3382 case URL_SCHEME_HTTPS:
3383 int_flags |= WINE_URL_BASH_AS_SLASH;
3384 if(parsed_url.pszSuffix[0] != '/' && parsed_url.pszSuffix[0] != '\\')
3385 int_flags |= WINE_URL_ESCAPE_SLASH;
3386 break;
3387
3388 case URL_SCHEME_MAILTO:
3391 break;
3392
3393 case URL_SCHEME_INVALID:
3394 break;
3395
3396 case URL_SCHEME_FTP:
3397 default:
3398 if(parsed_url.pszSuffix[0] != '/')
3399 int_flags |= WINE_URL_ESCAPE_SLASH;
3400 break;
3401 }
3402 }
3403
3404 for (src = url; *src; )
3405 {
3406 WCHAR cur = *src;
3407 len = 0;
3408
3409 if ((int_flags & WINE_URL_COLLAPSE_SLASHES) && src == url + parsed_url.cchProtocol + 1)
3410 {
3411 while (cur == '/' || cur == '\\')
3412 {
3413 slashes++;
3414 cur = *++src;
3415 }
3416 if (slashes == 2 && !wcsnicmp(src, L"localhost", 9)) { /* file://localhost/ -> file:/// */
3417 if(src[9] == '/' || src[9] == '\\') src += 10;
3418 slashes = 3;
3419 }
3420
3421 switch (slashes)
3422 {
3423 case 1:
3424 case 3:
3425 next[0] = next[1] = next[2] = '/';
3426 len = 3;
3427 break;
3428 case 0:
3429 len = 0;
3430 break;
3431 default:
3432 next[0] = next[1] = '/';
3433 len = 2;
3434 break;
3435 }
3436 }
3437 if (len == 0)
3438 {
3439 if (cur == '#' && (int_flags & WINE_URL_STOP_ON_HASH))
3440 stop_escaping = TRUE;
3441
3442 if (cur == '?' && (int_flags & WINE_URL_STOP_ON_QUESTION))
3443 stop_escaping = TRUE;
3444
3445 if (cur == '\\' && (int_flags & WINE_URL_BASH_AS_SLASH) && !stop_escaping) cur = '/';
3446
3447 if (url_needs_escape(cur, flags, int_flags) && !stop_escaping)
3448 {
3450 {
3451 char utf[16];
3452
3453 if ((cur >= 0xd800 && cur <= 0xdfff) && (src[1] >= 0xdc00 && src[1] <= 0xdfff))
3454 {
3455 len = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, src, 2, utf, sizeof(utf), NULL, NULL);
3456 src++;
3457 }
3458 else
3459 len = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, &cur, 1, utf, sizeof(utf), NULL, NULL);
3460
3461 if (!len)
3462 {
3463 utf[0] = 0xef;
3464 utf[1] = 0xbf;
3465 utf[2] = 0xbd;
3466 len = 3;
3467 }
3468
3469 for (i = 0; i < len; ++i)
3470 {
3471 next[i*3+0] = '%';
3472 next[i*3+1] = hexDigits[(utf[i] >> 4) & 0xf];
3473 next[i*3+2] = hexDigits[utf[i] & 0xf];
3474 }
3475 len *= 3;
3476 }
3477 else
3478 {
3479 next[0] = '%';
3480 next[1] = hexDigits[(cur >> 4) & 0xf];
3481 next[2] = hexDigits[cur & 0xf];
3482 len = 3;
3483 }
3484 }
3485 else
3486 {
3487 next[0] = cur;
3488 len = 1;
3489 }
3490 src++;
3491 }
3492
3493 if (needed + len <= *escaped_len)
3494 {
3495 memcpy(dst, next, len*sizeof(WCHAR));
3496 dst += len;
3497 }
3498 needed += len;
3499 }
3500
3501 if (needed < *escaped_len)
3502 {
3503 *dst = '\0';
3504 memcpy(escaped, dst_ptr, (needed+1)*sizeof(WCHAR));
3505 hr = S_OK;
3506 }
3507 else
3508 {
3509 needed++; /* add one for the '\0' */
3510 hr = E_POINTER;
3511 }
3512 *escaped_len = needed;
3513
3514 heap_free(dst_ptr);
3515 return hr;
3516}
3517
3518HRESULT WINAPI UrlCanonicalizeA(const char *src_url, char *canonicalized, DWORD *canonicalized_len, DWORD flags)
3519{
3520 LPWSTR url, canonical;
3521 HRESULT hr;
3522
3523 TRACE("%s, %p, %p, %#lx\n", wine_dbgstr_a(src_url), canonicalized, canonicalized_len, flags);
3524
3525 if (!src_url || !canonicalized || !canonicalized_len || !*canonicalized_len)
3526 return E_INVALIDARG;
3527
3528 url = heap_strdupAtoW(src_url);
3529 canonical = heap_alloc(*canonicalized_len * sizeof(WCHAR));
3530 if (!url || !canonical)
3531 {
3532 heap_free(url);
3533 heap_free(canonical);
3534 return E_OUTOFMEMORY;
3535 }
3536
3537 hr = UrlCanonicalizeW(url, canonical, canonicalized_len, flags);
3538 if (hr == S_OK)
3539 WideCharToMultiByte(CP_ACP, 0, canonical, -1, canonicalized, *canonicalized_len + 1, NULL, NULL);
3540
3541 heap_free(url);
3542 heap_free(canonical);
3543 return hr;
3544}
3545
3547{
3548 switch (scheme)
3549 {
3550 case URL_SCHEME_ABOUT:
3552 case URL_SCHEME_MAILTO:
3553 case URL_SCHEME_SHELL:
3555 return true;
3556
3557 default:
3558 return false;
3559 }
3560}
3561
3563{
3564 switch (scheme)
3565 {
3566 case URL_SCHEME_FTP:
3567 case URL_SCHEME_INVALID:
3568 case URL_SCHEME_LOCAL:
3569 case URL_SCHEME_MK:
3570 case URL_SCHEME_RES:
3571 case URL_SCHEME_UNKNOWN:
3572 case URL_SCHEME_WAIS:
3573 return true;
3574
3575 default:
3576 return false;
3577 }
3578}
3579
3581{
3582 switch (scheme)
3583 {
3584 case URL_SCHEME_ABOUT:
3586 case URL_SCHEME_MAILTO:
3587 case URL_SCHEME_MK:
3588 case URL_SCHEME_SHELL:
3590 return false;
3591
3592 default:
3593 return true;
3594 }
3595}
3596
3598{
3599 if (c == '/')
3600 return true;
3601 if (c == '\\' && scheme != URL_SCHEME_INVALID && scheme != URL_SCHEME_UNKNOWN)
3602 return true;
3603 return false;
3604}
3605
3607{
3608 switch (c)
3609 {
3610 case 0:
3611 case '/':
3612 return true;
3613 case '\\':
3615 case '?':
3617 case '#':
3618 return scheme != URL_SCHEME_FILE;
3619 default:
3620 return false;
3621 }
3622}
3623
3625{
3626 switch (c)
3627 {
3628 case 0:
3629 case '/':
3630 case '?':
3631 return true;
3632 case '#':
3634 case '\\':
3636 default:
3637 return false;
3638 }
3639}
3640
3641/* There are essentially two types of behaviour concerning dot simplification,
3642 * not counting opaque schemes:
3643 *
3644 * 1) Simplify dots if and only if the first element is not a single or double
3645 * dot. If a double dot would rewind past the root, ignore it. For example:
3646 *
3647 * http://hostname/a/../../b/. -> http://hostname/b/
3648 * http://hostname/./../../b/. -> http://hostname/./../../b/.
3649 *
3650 * 2) Effectively treat all paths as relative. Always simplify, except if a
3651 * double dot would rewind past the root, in which case emit it verbatim.
3652 * For example:
3653 *
3654 * wine://hostname/a/../../b/. -> wine://hostname/../b/
3655 * wine://hostname/./../../b/. -> wine://hostname/../b/
3656 *
3657 * For unclear reasons, this behaviour also correlates with whether a final
3658 * slash is always emitted after a single or double dot (e.g. if
3659 * URL_DONT_SIMPLIFY is specified). The former type does not emit a slash; the
3660 * latter does.
3661 */
3663{
3664 switch (scheme)
3665 {
3666 case URL_SCHEME_INVALID:
3667 case URL_SCHEME_UNKNOWN:
3668 return true;
3669
3670 case URL_SCHEME_FILE:
3672
3673 default:
3674 return false;
3675 }
3676}
3677
3679{
3681 size_t len, capacity;
3682};
3683
3684static void append_string( struct string_buffer *buffer, const WCHAR *str, size_t len )
3685{
3686 array_reserve( (void **)&buffer->string, &buffer->capacity, buffer->len + len, sizeof(WCHAR) );
3687 memcpy( buffer->string + buffer->len, str, len * sizeof(WCHAR) );
3688 buffer->len += len;
3689}
3690
3691static void append_char( struct string_buffer *buffer, WCHAR c )
3692{
3693 append_string( buffer, &c, 1 );
3694}
3695
3696static char get_slash_dir( URL_SCHEME scheme, DWORD flags, char src, const struct string_buffer *dst )
3697{
3699 return src;
3700
3702 && !wmemchr( dst->string, '#', dst->len ))
3703 return '\\';
3704
3705 return '/';
3706}
3707
3708static void rewrite_url( struct string_buffer *dst, const WCHAR *url, DWORD *flags_ptr )
3709{
3710 DWORD flags = *flags_ptr;
3712 bool is_relative = false, has_hostname = false, has_initial_slash = false;
3713 const WCHAR *query = NULL, *hash = NULL;
3715 size_t query_len = 0, hash_len = 0;
3716 const WCHAR *scheme_end, *src_end;
3717 const WCHAR *hostname = NULL;
3718 size_t hostname_len = 0;
3719 const WCHAR *src = url;
3720 size_t root_offset;
3721
3722 /* Determine the scheme. */
3723
3724 scheme_end = parse_scheme( url );
3725
3726 if (*scheme_end == ':' && scheme_end >= url + 2)
3727 {
3728 size_t scheme_len = scheme_end + 1 - url;
3729
3730 scheme = get_scheme_code( url, scheme_len - 1 );
3731
3732 for (size_t i = 0; i < scheme_len; ++i)
3733 append_char( dst, tolower( *src++ ));
3734 }
3735 else if (url[0] == '\\' && url[1] == '\\')
3736 {
3737 append_string( dst, L"file:", 5 );
3738 if (!pathurl && !(flags & URL_UNESCAPE))
3741
3742 has_hostname = true;
3743 }
3744
3746 {
3747 append_string( dst, L"file://", 7 );
3748 if (!pathurl && !(flags & URL_UNESCAPE))
3751
3752 hostname_len = 0;
3753 has_hostname = true;
3754 }
3755 else if (scheme == URL_SCHEME_MK)
3756 {
3757 if (src[0] == '@')
3758 {
3759 while (*src && *src != '/')
3760 append_char( dst, *src++ );
3761 if (*src == '/')
3762 append_char( dst, *src++ );
3763 else
3764 append_char( dst, '/' );
3765
3766 if ((src[0] == '.' && scheme_char_is_dot_separator( scheme, flags, src[1] )) ||
3767 (src[0] == '.' && src[1] == '.' && scheme_char_is_dot_separator( scheme, flags, src[2] )))
3768 is_relative = true;
3769 }
3770 }
3773 {
3776 src += 2;
3777 if (scheme == URL_SCHEME_FILE && is_slash( src[0] ) && is_slash( src[1] ))
3778 {
3779 while (is_slash( *src ))
3780 ++src;
3781 }
3782
3783 hostname = src;
3784
3786 ++src;
3787 hostname_len = src - hostname;
3788 has_hostname = true;
3789 has_initial_slash = true;
3790 }
3791 else if (scheme_char_is_separator( scheme, src[0] ))
3792 {
3793 has_initial_slash = true;
3794
3796 {
3797 /* Special case: an unknown scheme starting with a single slash
3798 * considers the "root" to be the single slash.
3799 * Most other schemes treat it as an empty path segment instead. */
3800 append_char( dst, *src++ );
3801
3802 if (*src == '\\')
3803 ++src;
3804 }
3805 else if (scheme == URL_SCHEME_FILE)
3806 {
3807 src++;
3808
3809 append_string( dst, L"//", 2 );
3810
3811 hostname_len = 0;
3812 has_hostname = true;
3813 }
3814 }
3815 else
3816 {
3817 if (scheme == URL_SCHEME_FILE)
3818 {
3820 {
3821 append_string( dst, L"//", 2 );
3822 hostname_len = 0;
3823 has_hostname = true;
3824 }
3825 else
3826 {
3828 append_string( dst, L"//", 2 );
3829 }
3830 }
3831 }
3832
3835
3836 *flags_ptr = flags;
3837
3838 if (has_hostname)
3839 {
3840 if (scheme == URL_SCHEME_FILE)
3841 {
3842 bool is_drive = false;
3843
3844 if (is_slash( *src ))
3845 ++src;
3846
3847 if (hostname_len >= 2 && is_escaped_drive_spec( hostname ))
3848 {
3849 hostname_len = 0;
3850 src = hostname;
3851 is_drive = true;
3852 }
3853 else if (is_escaped_drive_spec( src ))
3854 {
3855 is_drive = true;
3856 }
3857
3858 if (pathurl)
3859 {
3860 if (hostname_len == 9 && !wcsnicmp( hostname, L"localhost", 9 ))
3861 {
3862 hostname_len = 0;
3863 if (is_slash( *src ))
3864 ++src;
3866 is_drive = true;
3867 }
3868
3869 if (!is_drive)
3870 {
3871 if (hostname_len)
3872 {
3873 append_string( dst, L"\\\\", 2 );
3874 append_string( dst, hostname, hostname_len );
3875 }
3876
3877 if ((*src && *src != '?') || (flags & URL_WININET_COMPATIBILITY))
3879 }
3880 }
3881 else
3882 {
3883 if (hostname_len)
3884 append_string( dst, hostname, hostname_len );
3885 append_char( dst, '/' );
3886 }
3887
3888 if (is_drive)
3889 {
3890 /* Root starts after the first slash when file flags are in use,
3891 * but directly after the drive specification if not. */
3892 if (pathurl)
3893 {
3895 append_char( dst, *src++ );
3896 if (is_slash( *src ))
3897 {
3898 append_char( dst, '\\' );
3899 src++;
3900 }
3901 }
3902 else
3903 {
3904 append_char( dst, *src++ );
3905 append_char( dst, *src++ );
3906 if (is_slash( *src ))
3907 {
3908 append_char( dst, '/' );
3909 src++;
3910 }
3911 }
3912 }
3913 }
3914 else
3915 {
3916 for (size_t i = 0; i < hostname_len; ++i)
3917 {
3920 else
3922 }
3923
3924 if (*src == '/' || *src == '\\')
3925 {
3927 src++;
3928 }
3929 else
3930 {
3931 append_char( dst, '/' );
3932 }
3933 }
3934
3935 if ((src[0] == '.' && scheme_char_is_dot_separator( scheme, flags, src[1] )) ||
3936 (src[0] == '.' && src[1] == '.' && scheme_char_is_dot_separator( scheme, flags, src[2] )))
3937 {
3939 is_relative = true;
3940 }
3941 }
3942
3943 /* root_offset now points to the point past which we will not rewind.
3944 * If there is a hostname, it points to the character after the closing
3945 * slash. */
3946
3947 root_offset = dst->len;
3948
3949 /* Break up the rest of the URL into the body, query, and hash parts. */
3950
3951 src_end = src + wcslen( src );
3952
3953 if (scheme_is_opaque( scheme ))
3954 {
3955 /* +1 for null terminator */
3956 append_string( dst, src, src_end + 1 - src );
3957 return;
3958 }
3959
3960 if (scheme == URL_SCHEME_FILE)
3961 {
3962 if (!pathurl)
3963 {
3964 if (src[0] == '#')
3965 hash = src;
3966 else if (is_slash( src[0] ) && src[1] == '#')
3967 hash = src + 1;
3968
3969 if (src[0] == '?')
3970 query = src;
3971 else if (is_slash( src[0] ) && src[1] == '?')
3972 query = src + 1;
3973 }
3974 else
3975 {
3976 query = wcschr( src, '?' );
3977 }
3978
3979 if (!hash)
3980 {
3981 for (const WCHAR *p = src; p < src_end; ++p)
3982 {
3983 if (!wcsnicmp( p, L".htm#" , 5))
3984 hash = p + 4;
3985 else if (!wcsnicmp( p, L".html#", 6 ))
3986 hash = p + 5;
3987 }
3988 }
3989 }
3990 else
3991 {
3992 query = wcschr( src, '?' );
3993 hash = wcschr( src, '#' );
3994 }
3995
3996 if (query)
3997 query_len = ((hash && hash > query) ? hash : src_end) - query;
3998 if (hash)
3999 hash_len = ((query && query > hash) ? query : src_end) - hash;
4000
4001 if (query)
4002 src_end = query;
4003 if (hash && hash < src_end)
4004 src_end = hash;
4005
4006 if (scheme == URL_SCHEME_UNKNOWN && !has_initial_slash)
4007 {
4008 if (!(flags & URL_DONT_SIMPLIFY) && src[0] == '.' && src_end == src + 1)
4009 src++;
4011 }
4012
4013 while (src < src_end)
4014 {
4015 bool is_dots = false;
4016 size_t len;
4017
4018 for (len = 0; src + len < src_end && !scheme_char_is_separator( scheme, src[len] ); ++len)
4019 ;
4020
4021 if (src[0] == '.' && scheme_char_is_dot_separator( scheme, flags, src[1] ))
4022 {
4023 if (!is_relative)
4024 {
4026 {
4027 is_dots = true;
4028 }
4029 else
4030 {
4031 ++src;
4032 if (*src == '/' || *src == '\\')
4033 ++src;
4034 continue;
4035 }
4036 }
4037 }
4038 else if (src[0] == '.' && src[1] == '.' && scheme_char_is_dot_separator( scheme, flags, src[2] ))
4039 {
4040 if (!is_relative)
4041 {
4043 {
4044 is_dots = true;
4045 }
4046 else if (dst->len == root_offset && scheme_is_always_relative( scheme, flags ))
4047 {
4048 /* We could also use is_dots here, except that we need to
4049 * update root afterwards. */
4050
4051 append_char( dst, *src++ );
4052 append_char( dst, *src++ );
4053 if (*src == '/' || *src == '\\')
4055 else
4057 root_offset = dst->len;
4058 continue;
4059 }
4060 else
4061 {
4062 if (dst->len > root_offset)
4063 --dst->len; /* rewind past the last slash */
4064
4065 while (dst->len > root_offset && !scheme_char_is_separator( scheme, dst->string[dst->len - 1] ))
4066 --dst->len;
4067
4068 src += 2;
4069 if (*src == '/' || *src == '\\')
4070 ++src;
4071 continue;
4072 }
4073 }
4074 }
4075
4076 if (len)
4077 {
4078 append_string( dst, src, len );
4079 src += len;
4080 }
4081
4082 if (*src == '?' || *src == '#' || !*src)
4083 {
4084 if (scheme == URL_SCHEME_UNKNOWN && !has_initial_slash)
4085 is_dots = false;
4086
4087 if (is_dots && scheme_is_always_relative( scheme, flags ))
4089 }
4090 else /* slash */
4091 {
4093 }
4094 }
4095
4096 /* If the source was non-empty but collapsed to an empty string, output a
4097 * single slash. */
4098 if (!dst->len && src_end != url)
4099 append_char( dst, '/' );
4100
4101 /* UNKNOWN and FILE schemes usually reorder the ? before the #, but others
4102 * emit them in the original order. */
4104 {
4105 if (query < hash)
4106 {
4107 append_string( dst, query, query_len );
4108 append_string( dst, hash, hash_len );
4109 }
4110 else
4111 {
4112 append_string( dst, hash, hash_len );
4113 append_string( dst, query, query_len );
4114 }
4115 }
4116 else if (!(scheme == URL_SCHEME_FILE && (flags & URL_FILE_USE_PATHURL)))
4117 {
4118 if (query)
4119 append_string( dst, query, query_len );
4120
4121 if (hash)
4122 append_string( dst, hash, hash_len );
4123 }
4124
4125 append_char( dst, 0 );
4126}
4127
4128HRESULT WINAPI UrlCanonicalizeW(const WCHAR *src_url, WCHAR *canonicalized, DWORD *canonicalized_len, DWORD flags)
4129{
4130 struct string_buffer rewritten = {0};
4132 HRESULT hr = S_OK;
4133 const WCHAR *src;
4134 WCHAR *url, *dst;
4135 DWORD len;
4136
4137 TRACE("%s, %p, %p, %#lx\n", wine_dbgstr_w(src_url), canonicalized, canonicalized_len, flags);
4138
4139 if (!src_url || !canonicalized || !canonicalized_len || !*canonicalized_len)
4140 return E_INVALIDARG;
4141
4142 if (!*src_url)
4143 {
4144 *canonicalized = 0;
4145 return S_OK;
4146 }
4147
4148 /* PATHURL takes precedence. */
4150 flags &= ~URL_WININET_COMPATIBILITY;
4151
4152 /* strip initial and final C0 control characters and space */
4153 src = src_url;
4154 while (*src > 0 && *src <= 0x20)
4155 ++src;
4156 len = wcslen( src );
4157 while (len && src[len - 1] > 0 && src[len - 1] <= 0x20)
4158 --len;
4159
4160 if (!(url = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) )))
4161 return E_OUTOFMEMORY;
4162
4163 dst = url;
4164 for (size_t i = 0; i < len; ++i)
4165 {
4166 if (src[i] != '\t' && src[i] != '\n' && src[i] != '\r')
4167 *dst++ = src[i];
4168 }
4169 *dst++ = 0;
4170
4171 rewrite_url( &rewritten, url, &flags );
4172
4173 if (flags & URL_UNESCAPE)
4174 {
4175 len = rewritten.len;
4177 rewritten.len = wcslen( rewritten.string ) + 1;
4178 }
4179
4180 /* URL_ESCAPE_SEGMENT_ONLY seems to be ignored. */
4183
4184 if (escape_flags)
4185 {
4186 escape_flags &= ~URL_ESCAPE_UNSAFE;
4187 hr = UrlEscapeW( rewritten.string, canonicalized, canonicalized_len, escape_flags );
4188 }
4189 else
4190 {
4191 /* No escaping needed, just copy the string */
4192 if (rewritten.len <= *canonicalized_len)
4193 {
4194 memcpy( canonicalized, rewritten.string, rewritten.len * sizeof(WCHAR) );
4195 *canonicalized_len = rewritten.len - 1;
4196 }
4197 else
4198 {
4199 hr = E_POINTER;
4200 *canonicalized_len = rewritten.len;
4201 }
4202 }
4203
4204 heap_free( rewritten.string );
4205 heap_free( url );
4206
4207 if (hr == S_OK)
4208 TRACE("result %s\n", wine_dbgstr_w(canonicalized));
4209
4210 return hr;
4211}
4212
4213HRESULT WINAPI UrlApplySchemeA(const char *url, char *out, DWORD *out_len, DWORD flags)
4214{
4215 LPWSTR inW, outW;
4216 HRESULT hr;
4217 DWORD len;
4218
4219 TRACE("%s, %p, %p:out size %ld, %#lx\n", wine_dbgstr_a(url), out, out_len, out_len ? *out_len : 0, flags);
4220
4221 if (!url || !out || !out_len)
4222 return E_INVALIDARG;
4223
4224 inW = heap_alloc(2 * INTERNET_MAX_URL_LENGTH * sizeof(WCHAR));
4226
4229
4230 hr = UrlApplySchemeW(inW, outW, &len, flags);
4231 if (hr != S_OK)
4232 {
4233 heap_free(inW);
4234 return hr;
4235 }
4236
4237 len = WideCharToMultiByte(CP_ACP, 0, outW, -1, NULL, 0, NULL, NULL);
4238 if (len > *out_len)
4239 {
4240 hr = E_POINTER;
4241 goto cleanup;
4242 }
4243
4244 WideCharToMultiByte(CP_ACP, 0, outW, -1, out, *out_len, NULL, NULL);
4245 len--;
4246
4247cleanup:
4248 *out_len = len;
4249 heap_free(inW);
4250 return hr;
4251}
4252
4253static HRESULT url_guess_scheme(const WCHAR *url, WCHAR *out, DWORD *out_len)
4254{
4255 WCHAR reg_path[MAX_PATH], value[MAX_PATH], data[MAX_PATH];
4256 DWORD value_len, data_len, dwType, i;
4257 WCHAR Wxx, Wyy;
4258 HKEY newkey;
4259 INT index;
4260 BOOL j;
4261
4263 "Software\\Microsoft\\Windows\\CurrentVersion\\URL\\Prefixes", -1, reg_path, MAX_PATH);
4264 RegOpenKeyExW(HKEY_LOCAL_MACHINE, reg_path, 0, 1, &newkey);
4265 index = 0;
4266 while (value_len = data_len = MAX_PATH,
4267 RegEnumValueW(newkey, index, value, &value_len, 0, &dwType, (LPVOID)data, &data_len) == 0)
4268 {
4269 TRACE("guess %d %s is %s\n", index, wine_dbgstr_w(value), wine_dbgstr_w(data));
4270
4271 j = FALSE;
4272 for (i = 0; i < value_len; ++i)
4273 {
4274 Wxx = url[i];
4275 Wyy = value[i];
4276 /* remember that TRUE is not-equal */
4277 j = ChrCmpIW(Wxx, Wyy);
4278 if (j) break;
4279 }
4280 if ((i == value_len) && !j)
4281 {
4282 if (lstrlenW(data) + lstrlenW(url) + 1 > *out_len)
4283 {
4284 *out_len = lstrlenW(data) + lstrlenW(url) + 1;
4285 RegCloseKey(newkey);
4286 return E_POINTER;
4287 }
4288 lstrcpyW(out, data);
4289 lstrcatW(out, url);
4290 *out_len = lstrlenW(out);
4291 TRACE("matched and set to %s\n", wine_dbgstr_w(out));
4292 RegCloseKey(newkey);
4293 return S_OK;
4294 }
4295 index++;
4296 }
4297 RegCloseKey(newkey);
4298 return E_FAIL;
4299}
4300
4302{
4304 WCHAR *new_url;
4305 DWORD needed;
4306 HRESULT hr;
4307
4308 parsed_url.cbSize = sizeof(parsed_url);
4309 if (ParseURLW(path, &parsed_url) == S_OK)
4310 {
4311 if (parsed_url.nScheme != URL_SCHEME_INVALID && parsed_url.cchProtocol > 1)
4312 {
4313 needed = lstrlenW(path);
4314 if (needed >= *url_len)
4315 {
4316 *url_len = needed + 1;
4317 return E_POINTER;
4318 }
4319 else
4320 {
4321 *url_len = needed;
4322 return S_FALSE;
4323 }
4324 }
4325 }
4326
4327 new_url = heap_alloc((lstrlenW(path) + 9) * sizeof(WCHAR)); /* "file:///" + path length + 1 */
4328 lstrcpyW(new_url, L"file:");
4329 if (is_drive_spec( path )) lstrcatW(new_url, L"///");
4330 lstrcatW(new_url, path);
4331 hr = UrlEscapeW(new_url, url, url_len, URL_ESCAPE_PERCENT);
4332 heap_free(new_url);
4333 return hr;
4334}
4335
4337{
4338 DWORD data_len, dwType;
4340 HKEY newkey;
4341
4342 /* get and prepend default */
4343 RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\URL\\DefaultPrefix",
4344 0, 1, &newkey);
4345 data_len = sizeof(data);
4346 RegQueryValueExW(newkey, NULL, 0, &dwType, (BYTE *)data, &data_len);
4347 RegCloseKey(newkey);
4348 if (lstrlenW(data) + lstrlenW(url) + 1 > *length)
4349 {
4350 *length = lstrlenW(data) + lstrlenW(url) + 1;
4351 return E_POINTER;
4352 }
4353 lstrcpyW(out, data);
4354 lstrcatW(out, url);
4355 *length = lstrlenW(out);
4356 TRACE("used default %s\n", wine_dbgstr_w(out));
4357 return S_OK;
4358}
4359
4361{
4362 PARSEDURLW in_scheme;
4363 DWORD res1;
4364 HRESULT hr;
4365
4366 TRACE("%s, %p, %p:out size %ld, %#lx\n", wine_dbgstr_w(url), out, length, length ? *length : 0, flags);
4367
4368 if (!url || !out || !length)
4369 return E_INVALIDARG;
4370
4372 {
4373 if ((*length > 1 && ':' == url[1]) || PathIsUNCW(url))
4374 {
4375 res1 = *length;
4376 hr = url_create_from_path(url, out, &res1);
4377 if (hr == S_OK || hr == E_POINTER)
4378 {
4379 *length = res1;
4380 return hr;
4381 }
4382 else if (hr == S_FALSE)
4383 {
4384 return hr;
4385 }
4386 }
4387 }
4388
4389 in_scheme.cbSize = sizeof(in_scheme);
4390 /* See if the base has a scheme */
4391 res1 = ParseURLW(url, &in_scheme);
4392 if (res1)
4393 {
4394 /* no scheme in input, need to see if we need to guess */
4396 {
4397 if ((hr = url_guess_scheme(url, out, length)) != E_FAIL)
4398 return hr;
4399 }
4400 }
4401
4402 /* If we are here, then either invalid scheme,
4403 * or no scheme and can't/failed guess.
4404 */
4405 if ((((res1 == 0) && (flags & URL_APPLY_FORCEAPPLY)) || ((res1 != 0)) ) && (flags & URL_APPLY_DEFAULT))
4407
4408 return S_FALSE;
4409}
4410
4411INT WINAPI UrlCompareA(const char *url1, const char *url2, BOOL ignore_slash)
4412{
4413 INT ret, len, len1, len2;
4414
4415 if (!ignore_slash)
4416 return strcmp(url1, url2);
4417 len1 = strlen(url1);
4418 if (url1[len1-1] == '/') len1--;
4419 len2 = strlen(url2);
4420 if (url2[len2-1] == '/') len2--;
4421 if (len1 == len2)
4422 return strncmp(url1, url2, len1);
4423 len = min(len1, len2);
4424 ret = strncmp(url1, url2, len);
4425 if (ret) return ret;
4426 if (len1 > len2) return 1;
4427 return -1;
4428}
4429
4430INT WINAPI UrlCompareW(const WCHAR *url1, const WCHAR *url2, BOOL ignore_slash)
4431{
4432 size_t len, len1, len2;
4433 INT ret;
4434
4435 if (!ignore_slash)
4436 return lstrcmpW(url1, url2);
4437 len1 = lstrlenW(url1);
4438 if (url1[len1-1] == '/') len1--;
4439 len2 = lstrlenW(url2);
4440 if (url2[len2-1] == '/') len2--;
4441 if (len1 == len2)
4442 return wcsncmp(url1, url2, len1);
4443 len = min(len1, len2);
4444 ret = wcsncmp(url1, url2, len);
4445 if (ret) return ret;
4446 if (len1 > len2) return 1;
4447 return -1;
4448}
4449
4450HRESULT WINAPI UrlFixupW(const WCHAR *url, WCHAR *translatedUrl, DWORD maxChars)
4451{
4452 DWORD srcLen;
4453
4454 FIXME("%s, %p, %ld stub\n", wine_dbgstr_w(url), translatedUrl, maxChars);
4455
4456 if (!url)
4457 return E_FAIL;
4458
4459 srcLen = lstrlenW(url) + 1;
4460
4461 /* For now just copy the URL directly */
4462 lstrcpynW(translatedUrl, url, (maxChars < srcLen) ? maxChars : srcLen);
4463
4464 return S_OK;
4465}
4466
4467const char * WINAPI UrlGetLocationA(const char *url)
4468{
4470
4471 base.cbSize = sizeof(base);
4472 if (ParseURLA(url, &base) != S_OK) return NULL; /* invalid scheme */
4473
4474 /* if scheme is file: then never return pointer */
4475 if (!strncmp(base.pszProtocol, "file", min(4, base.cchProtocol)))
4476 return NULL;
4477
4478 /* Look for '#' and return its addr */
4479 return strchr(base.pszSuffix, '#');
4480}
4481
4483{
4485
4486 base.cbSize = sizeof(base);
4487 if (ParseURLW(url, &base) != S_OK) return NULL; /* invalid scheme */
4488
4489 /* if scheme is file: then never return pointer */
4490 if (!wcsncmp(base.pszProtocol, L"file", min(4, base.cchProtocol)))
4491 return NULL;
4492
4493 /* Look for '#' and return its addr */
4494 return wcschr(base.pszSuffix, '#');
4495}
4496
4497HRESULT WINAPI UrlGetPartA(const char *url, char *out, DWORD *out_len, DWORD part, DWORD flags)
4498{
4499 LPWSTR inW, outW;
4500 DWORD len, len2;
4501 HRESULT hr;
4502
4503 if (!url || !out || !out_len || !*out_len)
4504 return E_INVALIDARG;
4505
4506 inW = heap_alloc(2 * INTERNET_MAX_URL_LENGTH * sizeof(WCHAR));
4508
4510
4512 hr = UrlGetPartW(inW, outW, &len, part, flags);
4513 if (FAILED(hr))
4514 {
4515 heap_free(inW);
4516 return hr;
4517 }
4518
4519 len2 = WideCharToMultiByte(CP_ACP, 0, outW, len + 1, NULL, 0, NULL, NULL);
4520 if (len2 > *out_len)
4521 {
4522 *out_len = len2;
4523 heap_free(inW);
4524 return E_POINTER;
4525 }
4526 len2 = WideCharToMultiByte(CP_ACP, 0, outW, len + 1, out, *out_len, NULL, NULL);
4527 *out_len = len2 - 1;
4528 heap_free(inW);
4529 if (hr == S_OK && !*out_len) hr = S_FALSE;
4530 return hr;
4531}
4532
4533static const WCHAR *parse_url_element( const WCHAR *url, const WCHAR *separators )
4534{
4535 const WCHAR *p;
4536
4537 if ((p = wcspbrk( url, separators )))
4538 return p;
4539 return url + wcslen( url );
4540}
4541
4542static void parse_url( const WCHAR *url, struct parsed_url *pl )
4543{
4544 const WCHAR *work;
4545
4546 memset(pl, 0, sizeof(*pl));
4547 pl->scheme = url;
4548 work = parse_scheme( pl->scheme );
4549 if (work < url + 2 || *work != ':') return;
4550 pl->scheme_len = work - pl->scheme;
4551 work++;
4553 if (!is_slash( work[0] ) || !is_slash( work[1] ))
4554 {
4555 if (pl->scheme_number != URL_SCHEME_FILE)
4557 return;
4558 }
4559 work += 2;
4560
4561 if (pl->scheme_number != URL_SCHEME_FILE)
4562 {
4563 pl->username = work;
4564 work = parse_url_element( pl->username, L":@/\\?#" );
4565 pl->username_len = work - pl->username;
4566 if (*work == ':')
4567 {
4568 pl->password = work + 1;
4569 work = parse_url_element( pl->password, L"@/\\?#" );
4570 pl->password_len = work - pl->password;
4571 if (*work == '@')
4572 {
4573 work++;
4574 }
4575 else
4576 {
4577 /* what we just parsed must be the hostname and port
4578 * so reset pointers and clear then let it parse */
4579 pl->username_len = pl->password_len = 0;
4580 work = pl->username;
4581 pl->username = pl->password = 0;
4582 }
4583 }
4584 else if (*work == '@')
4585 {
4586 /* no password */
4587 pl->password_len = 0;
4588 pl->password = 0;
4589 work++;
4590 }
4591 else
4592 {
4593 /* what was parsed was hostname, so reset pointers and let it parse */
4594 pl->username_len = pl->password_len = 0;
4595 work = pl->username;
4596 pl->username = pl->password = 0;
4597 }
4598 }
4599
4600 pl->hostname = work;
4601 if (pl->scheme_number == URL_SCHEME_FILE)
4602 {
4603 work = parse_url_element( pl->hostname, L"/\\?#" );
4604 pl->hostname_len = work - pl->hostname;
4605 if (pl->hostname_len >= 2 && pl->hostname[1] == ':')
4606 pl->hostname_len = 0;
4607 }
4608 else
4609 {
4610 work = parse_url_element( pl->hostname, L":/\\?#" );
4611 pl->hostname_len = work - pl->hostname;
4612
4613 if (*work == ':')
4614 {
4615 pl->port = work + 1;
4616 work = parse_url_element( pl->port, L"/\\?#" );
4617 pl->port_len = work - pl->port;
4618 }
4619 }
4620
4621 if ((pl->query = wcschr( work, '?' )))
4622 {
4623 ++pl->query;
4624 pl->query_len = lstrlenW(pl->query);
4625 }
4626}
4627
4629{
4630 LPCWSTR addr, schaddr;
4631 struct parsed_url pl;
4632 DWORD size, schsize;
4633
4634 TRACE("%s, %p, %p(%ld), %#lx, %#lx\n", wine_dbgstr_w(url), out, out_len, *out_len, part, flags);
4635
4636 if (!url || !out || !out_len || !*out_len)
4637 return E_INVALIDARG;
4638
4639 parse_url(url, &pl);
4640
4641 switch (pl.scheme_number)
4642 {
4643 case URL_SCHEME_FTP:
4644 case URL_SCHEME_GOPHER:
4645 case URL_SCHEME_HTTP:
4646 case URL_SCHEME_HTTPS:
4647 case URL_SCHEME_TELNET:
4648 case URL_SCHEME_NEWS:
4649 case URL_SCHEME_NNTP:
4650 case URL_SCHEME_SNEWS:
4651 break;
4652
4653 case URL_SCHEME_FILE:
4654 if (part != URL_PART_SCHEME && part != URL_PART_QUERY && part != URL_PART_HOSTNAME)
4655 return E_FAIL;
4656 break;
4657
4658 default:
4659 if (part != URL_PART_SCHEME && part != URL_PART_QUERY)
4660 return E_FAIL;
4661 }
4662
4663 switch (part)
4664 {
4665 case URL_PART_SCHEME:
4666 flags &= ~URL_PARTFLAG_KEEPSCHEME;
4667 addr = pl.scheme;
4668 size = pl.scheme_len;
4669 break;
4670
4671 case URL_PART_HOSTNAME:
4672 addr = pl.hostname;
4673 size = pl.hostname_len;
4674 break;
4675
4676 case URL_PART_USERNAME:
4677 if (!pl.username)
4678 return E_INVALIDARG;
4679 addr = pl.username;
4680 size = pl.username_len;
4681 break;
4682
4683 case URL_PART_PASSWORD:
4684 if (!pl.password)
4685 return E_INVALIDARG;
4686 addr = pl.password;
4687 size = pl.password_len;
4688 break;
4689
4690 case URL_PART_PORT:
4691 if (!pl.port)
4692 return E_INVALIDARG;
4693 addr = pl.port;
4694 size = pl.port_len;
4695 break;
4696
4697 case URL_PART_QUERY:
4698 flags &= ~URL_PARTFLAG_KEEPSCHEME;
4699 addr = pl.query;
4700 size = pl.query_len;
4701 break;
4702
4703 default:
4704 return E_INVALIDARG;
4705 }
4706
4708 {
4709 if (!pl.scheme || !pl.scheme_len)
4710 return E_FAIL;
4711 schaddr = pl.scheme;
4712 schsize = pl.scheme_len;
4713 if (*out_len < schsize + size + 2)
4714 {
4715 *out_len = schsize + size + 2;
4716 return E_POINTER;
4717 }
4718 memcpy(out, schaddr, schsize*sizeof(WCHAR));
4719 out[schsize] = ':';
4720 memcpy(out + schsize+1, addr, size*sizeof(WCHAR));
4721 out[schsize+1+size] = 0;
4722 *out_len = schsize + 1 + size;
4723 }
4724 else
4725 {
4726 if (*out_len < size + 1)
4727 {
4728 *out_len = size + 1;
4729 return E_POINTER;
4730 }
4731
4732 if (part == URL_PART_SCHEME)
4733 {
4734 unsigned int i;
4735
4736 for (i = 0; i < size; ++i)
4737 out[i] = tolower( addr[i] );
4738 }
4739 else
4740 {
4741 memcpy( out, addr, size * sizeof(WCHAR) );
4742 }
4743 out[size] = 0;
4744 *out_len = size;
4745 }
4746 TRACE("len=%ld %s\n", *out_len, wine_dbgstr_w(out));
4747
4748 return S_OK;
4749}
4750
4751BOOL WINAPI UrlIsA(const char *url, URLIS Urlis)
4752{
4753 const char *last;
4755
4756 TRACE("%s, %d\n", debugstr_a(url), Urlis);
4757
4758 if (!url)
4759 return FALSE;
4760
4761 switch (Urlis) {
4762
4763 case URLIS_OPAQUE:
4764 base.cbSize = sizeof(base);
4765 if (ParseURLA(url, &base) != S_OK) return FALSE; /* invalid scheme */
4766 return scheme_is_opaque( base.nScheme );
4767
4768 case URLIS_FILEURL:
4769 return (CompareStringA(LOCALE_INVARIANT, NORM_IGNORECASE, url, 5, "file:", 5) == CSTR_EQUAL);
4770
4771 case URLIS_DIRECTORY:
4772 last = url + strlen(url) - 1;
4773 return (last >= url && (*last == '/' || *last == '\\' ));
4774
4775 case URLIS_URL:
4776 return PathIsURLA(url);
4777
4778 case URLIS_NOHISTORY:
4779 case URLIS_APPLIABLE:
4780 case URLIS_HASQUERY:
4781 default:
4782 FIXME("(%s %d): stub\n", debugstr_a(url), Urlis);
4783 }
4784
4785 return FALSE;
4786}
4787
4789{
4790 const WCHAR *last;
4792
4793 TRACE("%s, %d\n", debugstr_w(url), Urlis);
4794
4795 if (!url)
4796 return FALSE;
4797
4798 switch (Urlis)
4799 {
4800 case URLIS_OPAQUE:
4801 base.cbSize = sizeof(base);
4802 if (ParseURLW(url, &base) != S_OK) return FALSE; /* invalid scheme */
4803 switch (base.nScheme)
4804 {
4805 case URL_SCHEME_MAILTO:
4806 case URL_SCHEME_SHELL:
4809 case URL_SCHEME_ABOUT:
4810 return TRUE;
4811 }
4812 return FALSE;
4813
4814 case URLIS_FILEURL:
4815 return !wcsnicmp( url, L"file:", 5 );
4816
4817 case URLIS_DIRECTORY:
4818 last = url + lstrlenW(url) - 1;
4819 return (last >= url && (*last == '/' || *last == '\\'));
4820
4821 case URLIS_URL:
4822 return PathIsURLW(url);
4823
4824 case URLIS_NOHISTORY:
4825 case URLIS_APPLIABLE:
4826 case URLIS_HASQUERY:
4827 default:
4828 FIXME("(%s %d): stub\n", debugstr_w(url), Urlis);
4829 }
4830
4831 return FALSE;
4832}
4833
4835{
4836 return UrlIsA(url, URLIS_OPAQUE);
4837}
4838
4840{
4841 return UrlIsW(url, URLIS_OPAQUE);
4842}
4843
4845{
4846 return UrlIsA(url, URLIS_NOHISTORY);
4847}
4848
4850{
4851 return UrlIsW(url, URLIS_NOHISTORY);
4852}
4853
4855{
4857 DWORD lenW = ARRAY_SIZE(bufW), lenA;
4859 WCHAR *urlW = bufW;
4860 HRESULT hr;
4861
4863 return E_INVALIDARG;
4864
4865 if ((hr = UrlCreateFromPathW(pathW.Buffer, urlW, &lenW, reserved)) == E_POINTER)
4866 {
4867 urlW = heap_alloc(lenW * sizeof(WCHAR));
4868 hr = UrlCreateFromPathW(pathW.Buffer, urlW, &lenW, reserved);
4869 }
4870
4871 if (SUCCEEDED(hr))
4872 {
4873 RtlUnicodeToMultiByteSize(&lenA, urlW, lenW * sizeof(WCHAR));
4874 if (*url_len > lenA)
4875 {
4876 RtlUnicodeToMultiByteN(url, *url_len - 1, &lenA, urlW, lenW * sizeof(WCHAR));
4877 url[lenA] = 0;
4878 *url_len = lenA;
4879 }
4880 else
4881 {
4882 *url_len = lenA + 1;
4883 hr = E_POINTER;
4884 }
4885 }
4886 if (urlW != bufW)
4887 heap_free(urlW);
4889 return hr;
4890}
4891
4893{
4894 HRESULT hr;
4895
4896 TRACE("%s, %p, %p, %#lx\n", debugstr_w(path), url, url_len, reserved);
4897
4898 if (reserved || !url || !url_len)
4899 return E_INVALIDARG;
4900
4901 hr = url_create_from_path(path, url, url_len);
4902 if (hr == S_FALSE)
4903 lstrcpyW(url, path);
4904
4905 return hr;
4906}
4907
4908HRESULT WINAPI UrlCombineA(const char *base, const char *relative, char *combined, DWORD *combined_len, DWORD flags)
4909{
4910 WCHAR *baseW, *relativeW, *combinedW;
4911 DWORD len, len2;
4912 HRESULT hr;
4913
4914 TRACE("%s, %s, %ld, %#lx\n", debugstr_a(base), debugstr_a(relative), combined_len ? *combined_len : 0, flags);
4915
4916 if (!base || !relative || !combined_len)
4917 return E_INVALIDARG;
4918
4920 relativeW = baseW + INTERNET_MAX_URL_LENGTH;
4921 combinedW = relativeW + INTERNET_MAX_URL_LENGTH;
4922
4924 MultiByteToWideChar(CP_ACP, 0, relative, -1, relativeW, INTERNET_MAX_URL_LENGTH);
4925 len = *combined_len;
4926
4927 hr = UrlCombineW(baseW, relativeW, combined ? combinedW : NULL, &len, flags);
4928 if (hr != S_OK)
4929 {
4930 *combined_len = len;
4932 return hr;
4933 }
4934
4935 len2 = WideCharToMultiByte(CP_ACP, 0, combinedW, len, NULL, 0, NULL, NULL);
4936 if (len2 > *combined_len)
4937 {
4938 *combined_len = len2;
4940 return E_POINTER;
4941 }
4942 WideCharToMultiByte(CP_ACP, 0, combinedW, len+1, combined, *combined_len + 1, NULL, NULL);
4943 *combined_len = len2;
4945 return S_OK;
4946}
4947
4948HRESULT WINAPI UrlCombineW(const WCHAR *baseW, const WCHAR *relativeW, WCHAR *combined, DWORD *combined_len, DWORD flags)
4949{
4950 DWORD i, len, process_case = 0, myflags, sizeloc = 0;
4951 LPWSTR work, preliminary, mbase, canonicalized;
4952 PARSEDURLW base, relative;
4953 HRESULT hr;
4954
4955 TRACE("%s, %s, %ld, %#lx\n", debugstr_w(baseW), debugstr_w(relativeW), combined_len ? *combined_len : 0, flags);
4956
4957 if (!baseW || !relativeW || !combined_len)
4958 return E_INVALIDARG;
4959
4960 base.cbSize = sizeof(base);
4961 relative.cbSize = sizeof(relative);
4962
4963 /* Get space for duplicates of the input and the output */
4964 preliminary = heap_alloc(3 * INTERNET_MAX_URL_LENGTH * sizeof(WCHAR));
4965 mbase = preliminary + INTERNET_MAX_URL_LENGTH;
4966 canonicalized = mbase + INTERNET_MAX_URL_LENGTH;
4967 *preliminary = '\0';
4968
4969 /* Canonicalize the base input prior to looking for the scheme */
4970 myflags = flags & (URL_DONT_SIMPLIFY | URL_UNESCAPE);
4972 UrlCanonicalizeW(baseW, mbase, &len, myflags);
4973
4974 /* See if the base has a scheme */
4975 if (ParseURLW(mbase, &base) != S_OK)
4976 {
4977 /* If base has no scheme return relative. */
4978 TRACE("no scheme detected in Base\n");
4979 process_case = 1;
4980 }
4981 else do
4982 {
4983 BOOL manual_search = FALSE;
4984
4985 work = (LPWSTR)base.pszProtocol;
4986 for (i = 0; i < base.cchProtocol; ++i)
4987 work[i] = RtlDowncaseUnicodeChar(work[i]);
4988
4989 /* mk is a special case */
4990 if (base.nScheme == URL_SCHEME_MK)
4991 {
4992 WCHAR *ptr = wcsstr(base.pszSuffix, L"::");
4993 if (ptr)
4994 {
4995 int delta;
4996
4997 ptr += 2;
4998 delta = ptr-base.pszSuffix;
4999 base.cchProtocol += delta;
5000 base.pszSuffix += delta;
5001 base.cchSuffix -= delta;
5002 }
5003 }
5004 else
5005 {
5006 /* get size of location field (if it exists) */
5007 work = (LPWSTR)base.pszSuffix;
5008 sizeloc = 0;
5009 if (*work++ == '/')
5010 {
5011 if (*work++ == '/')
5012 {
5013 /* At this point have start of location and
5014 * it ends at next '/' or end of string.
5015 */
5016 while (*work && (*work != '/')) work++;
5017 sizeloc = (DWORD)(work - base.pszSuffix);
5018 }
5019 }
5020 }
5021
5022 /* If there is a '?', then the remaining part can only contain a
5023 * query string or fragment, so start looking for the last leaf
5024 * from the '?'. Otherwise, if there is a '#' and the characters
5025 * immediately preceding it are ".htm[l]", then begin looking for
5026 * the last leaf starting from the '#'. Otherwise the '#' is not
5027 * meaningful and just start looking from the end. */
5028 if ((work = wcspbrk(base.pszSuffix + sizeloc, L"#?")))
5029 {
5030 if (*work == '?' || base.nScheme == URL_SCHEME_HTTP || base.nScheme == URL_SCHEME_HTTPS)
5031 manual_search = TRUE;
5032 else if (work - base.pszSuffix > 4)
5033 {
5034 if (!wcsnicmp(work - 4, L".htm", 4)) manual_search = TRUE;
5035 }
5036
5037 if (!manual_search && work - base.pszSuffix > 5)
5038 {
5039 if (!wcsnicmp(work - 5, L".html", 5)) manual_search = TRUE;
5040 }
5041 }
5042
5043 if (manual_search)
5044 {
5045 /* search backwards starting from the current position */
5046 while (*work != '/' && work > base.pszSuffix + sizeloc)
5047 --work;
5048 base.cchSuffix = work - base.pszSuffix + 1;
5049 }
5050 else
5051 {
5052 /* search backwards starting from the end of the string */
5053 work = wcsrchr((base.pszSuffix+sizeloc), '/');
5054 if (work)
5055 {
5056 len = (DWORD)(work - base.pszSuffix + 1);
5057 base.cchSuffix = len;
5058 }
5059 else
5060 base.cchSuffix = sizeloc;
5061 }
5062
5063 /*
5064 * At this point:
5065 * .pszSuffix points to location (starting with '//')
5066 * .cchSuffix length of location (above) and rest less the last
5067 * leaf (if any)
5068 * sizeloc length of location (above) up to but not including
5069 * the last '/'
5070 */
5071
5072 if (ParseURLW(relativeW, &relative) != S_OK)
5073 {
5074 /* No scheme in relative */
5075 TRACE("no scheme detected in Relative\n");
5076 relative.pszSuffix = relativeW; /* case 3,4,5 depends on this */
5077 relative.cchSuffix = lstrlenW( relativeW );
5078 if (*relativeW == ':')
5079 {
5080 /* Case that is either left alone or uses base. */
5082 {
5083 process_case = 5;
5084 break;
5085 }
5086 process_case = 1;
5087 break;
5088 }
5089 if (is_drive_spec( relativeW ))
5090 {
5091 /* case that becomes "file:///" */
5092 lstrcpyW(preliminary, L"file:///");
5093 process_case = 1;
5094 break;
5095 }
5096 if ((relativeW[0] == '/' || relativeW[0] == '\\') &&
5097 (relativeW[1] == '/' || relativeW[1] == '\\'))
5098 {
5099 /* Relative has location and the rest. */
5100 process_case = 3;
5101 break;
5102 }
5103 if (*relativeW == '/' || *relativeW == '\\')
5104 {
5105 /* Relative is root to location. */
5106 process_case = 4;
5107 break;
5108 }
5109 if (*relativeW == '#')
5110 {
5111 if (!(work = wcschr(base.pszSuffix+base.cchSuffix, '#')))
5112 work = (LPWSTR)base.pszSuffix + lstrlenW(base.pszSuffix);
5113
5114 memcpy(preliminary, base.pszProtocol, (work-base.pszProtocol)*sizeof(WCHAR));
5115 preliminary[work-base.pszProtocol] = '\0';
5116 process_case = 1;
5117 break;
5118 }
5119 process_case = (*base.pszSuffix == '/' || base.nScheme == URL_SCHEME_MK) ? 5 : 3;
5120 break;
5121 }
5122 else
5123 {
5124 work = (LPWSTR)relative.pszProtocol;
5125 for (i = 0; i < relative.cchProtocol; ++i)
5126 work[i] = RtlDowncaseUnicodeChar(work[i]);
5127 }
5128
5129 /* Handle cases where relative has scheme. */
5130 if ((base.cchProtocol == relative.cchProtocol) && !wcsncmp(base.pszProtocol, relative.pszProtocol, base.cchProtocol))
5131 {
5132 /* since the schemes are the same */
5133 if (*relative.pszSuffix == '/' && *(relative.pszSuffix+1) == '/')
5134 {
5135 /* Relative replaces location and what follows. */
5136 process_case = 3;
5137 break;
5138 }
5139 if (*relative.pszSuffix == '/')
5140 {
5141 /* Relative is root to location */
5142 process_case = 4;
5143 break;
5144 }
5145 /* replace either just location if base's location starts with a
5146 * slash or otherwise everything */
5147 process_case = (*base.pszSuffix == '/') ? 5 : 1;
5148 break;
5149 }
5150
5151 if (*relative.pszSuffix == '/' && *(relative.pszSuffix+1) == '/')
5152 {
5153 /* Relative replaces scheme, location, and following and handles PLUGGABLE */
5154 process_case = 2;
5155 break;
5156 }
5157 process_case = 1;
5158 break;
5159 } while (FALSE); /* a little trick to allow easy exit from nested if's */
5160
5161 hr = S_OK;
5162 switch (process_case)
5163 {
5164 case 1:
5165 /* Return relative appended to whatever is in combined (which may the string "file:///" */
5166 lstrcatW(preliminary, relativeW);
5167 break;
5168
5169 case 2:
5170 /* Relative replaces scheme and location */
5171 lstrcpyW(preliminary, relativeW);
5172 break;
5173
5174 case 3:
5175 /* Return the base scheme with relative. Basically keeps the scheme and replaces the domain and following. */
5176 memcpy(preliminary, base.pszProtocol, (base.cchProtocol + 1)*sizeof(WCHAR));
5177 work = preliminary + base.cchProtocol + 1;
5178 lstrcpyW(work, relative.pszSuffix);
5179 break;
5180
5181 case 4:
5182 /* Return the base scheme and location but everything after the location is relative. (Replace document from root on.) */
5183 memcpy(preliminary, base.pszProtocol, (base.cchProtocol+1+sizeloc)*sizeof(WCHAR));
5184 work = preliminary + base.cchProtocol + 1 + sizeloc;
5186 *(work++) = '/';
5187 lstrcpyW(work, relative.pszSuffix);
5188 break;
5189
5190 case 5:
5191 /* Return the base without its document (if any) and append relative after its scheme. */
5192 memcpy(preliminary, base.pszProtocol, (base.cchProtocol + 1 + base.cchSuffix)*sizeof(WCHAR));
5193 work = preliminary + base.cchProtocol + 1 + base.cchSuffix - 1;
5194 if (*work++ != '/')
5195 *(work++) = '/';
5196 lstrcpyW(work, relative.pszSuffix);
5197 break;
5198
5199 default:
5200 FIXME("Unexpected case %ld.\n", process_case);
5201 hr = E_INVALIDARG;
5202 }
5203
5204 if (hr == S_OK)
5205 {
5206 if (*combined_len == 0)
5207 *combined_len = 1;
5208 hr = UrlCanonicalizeW(preliminary, canonicalized, combined_len, flags & ~URL_FILE_USE_PATHURL);
5209 if (SUCCEEDED(hr) && combined)
5210 lstrcpyW( combined, canonicalized );
5211
5212 TRACE("return-%ld len=%ld, %s\n", process_case, *combined_len, debugstr_w(combined));
5213 }
5214
5215 heap_free(preliminary);
5216 return hr;
5217}
5218
5219HRESULT WINAPI HashData(const unsigned char *src, DWORD src_len, unsigned char *dest, DWORD dest_len)
5220{
5221 INT src_count = src_len - 1, dest_count = dest_len - 1;
5222
5223 if (!src || !dest)
5224 return E_INVALIDARG;
5225
5226 while (dest_count >= 0)
5227 {
5228 dest[dest_count] = (dest_count & 0xff);
5229 dest_count--;
5230 }
5231
5232 while (src_count >= 0)
5233 {
5234 dest_count = dest_len - 1;
5235 while (dest_count >= 0)
5236 {
5237 dest[dest_count] = hashdata_lookup[src[src_count] ^ dest[dest_count]];
5238 dest_count--;
5239 }
5240 src_count--;
5241 }
5242
5243 return S_OK;
5244}
5245
5246HRESULT WINAPI UrlHashA(const char *url, unsigned char *dest, DWORD dest_len)
5247{
5248 __TRY
5249 {
5250 HashData((const BYTE *)url, (int)strlen(url), dest, dest_len);
5251 }
5253 {
5254 return E_INVALIDARG;
5255 }
5256 __ENDTRY
5257 return S_OK;
5258}
5259
5260HRESULT WINAPI UrlHashW(const WCHAR *url, unsigned char *dest, DWORD dest_len)
5261{
5262 char urlA[MAX_PATH];
5263
5264 TRACE("%s, %p, %ld\n", debugstr_w(url), dest, dest_len);
5265
5266 __TRY
5267 {
5268 WideCharToMultiByte(CP_ACP, 0, url, -1, urlA, MAX_PATH, NULL, NULL);
5269 HashData((const BYTE *)urlA, (int)strlen(urlA), dest, dest_len);
5270 }
5272 {
5273 return E_INVALIDARG;
5274 }
5275 __ENDTRY
5276 return S_OK;
5277}
5278
5280{
5281 FIXME(": stub\n");
5282 return FALSE;
5283}
5284
5285#endif // !STATIC_PATHCCH
static WCHAR baseW[MAX_PATH]
Definition: FindFiles.c:24
#define isalpha(c)
Definition: acclib.h:74
#define isxdigit(c)
Definition: acclib.h:70
static long path_length
Definition: maze.c:116
unsigned int dir
Definition: maze.c:112
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 WINE_DEFAULT_DEBUG_CHANNEL(t)
Definition: precomp.h:23
#define index(s, c)
Definition: various.h:29
char * hostname
Definition: ftp.c:88
#define ARRAY_SIZE(A)
Definition: main.h:20
#define CHAR(Char)
#define FIXME(fmt,...)
Definition: precomp.h:53
#define RegCloseKey(hKey)
Definition: registry.h:49
Definition: _map.h:48
#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
HRESULT hr
Definition: delayimp.cpp:582
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define ARRAYSIZE(array)
Definition: filtermapper.c:47
LONG WINAPI RegOpenKeyExW(HKEY hKey, LPCWSTR lpSubKey, DWORD ulOptions, REGSAM samDesired, PHKEY phkResult)
Definition: reg.c:3333
LONG WINAPI RegEnumValueW(_In_ HKEY hKey, _In_ DWORD index, _Out_ LPWSTR value, _Inout_ PDWORD val_count, _Reserved_ PDWORD reserved, _Out_opt_ PDWORD type, _Out_opt_ LPBYTE data, _Inout_opt_ PDWORD count)
Definition: reg.c:2830
LONG WINAPI RegQueryValueExW(_In_ HKEY hkeyorg, _In_ LPCWSTR name, _In_ LPDWORD reserved, _In_ LPDWORD type, _In_ LPBYTE data, _In_ LPDWORD count)
Definition: reg.c:4103
INT WINAPI StrToIntW(LPCWSTR lpString)
Definition: string.c:407
LPWSTR WINAPI StrChrW(LPCWSTR lpszStr, WCHAR ch)
Definition: string.c:464
LPWSTR WINAPI StrRChrW(LPCWSTR str, LPCWSTR end, WORD ch)
Definition: string.c:552
LPSTR WINAPI StrRChrA(LPCSTR lpszStr, LPCSTR lpszEnd, WORD ch)
Definition: string.c:521
INT WINAPI StrToIntA(LPCSTR lpszStr)
Definition: string.c:370
LPSTR WINAPI StrChrA(LPCSTR lpszStr, WORD ch)
Definition: string.c:266
#define wcschr
Definition: compat.h:17
#define GetProcessHeap()
Definition: compat.h:736
#define ERROR_INVALID_PARAMETER
Definition: compat.h:101
#define wcsnicmp
Definition: compat.h:14
#define wcsrchr
Definition: compat.h:16
#define CP_ACP
Definition: compat.h:109
#define SetLastError(x)
Definition: compat.h:752
#define HeapAlloc
Definition: compat.h:733
#define __TRY
Definition: compat.h:80
#define MAX_PATH
Definition: compat.h:34
#define HeapFree(x, y, z)
Definition: compat.h:735
#define __ENDTRY
Definition: compat.h:82
#define lstrcpyW
Definition: compat.h:749
#define WideCharToMultiByte
Definition: compat.h:111
#define MultiByteToWideChar
Definition: compat.h:110
#define __EXCEPT_PAGE_FAULT
Definition: compat.h:81
#define lstrcpynW
Definition: compat.h:738
#define lstrlenW
Definition: compat.h:750
static const WCHAR *const ext[]
Definition: module.c:53
static void cleanup(void)
Definition: main.c:1335
DWORD WINAPI ExpandEnvironmentStringsW(IN LPCWSTR lpSrc, IN LPWSTR lpDst, IN DWORD nSize)
Definition: environ.c:492
UINT WINAPI SetErrorMode(IN UINT uMode)
Definition: except.c:751
DWORD WINAPI GetFileAttributesW(LPCWSTR lpFileName)
Definition: fileinfo.c:636
DWORD WINAPI GetFileAttributesA(LPCSTR lpFileName)
Definition: fileinfo.c:620
DWORD WINAPI SearchPathA(IN LPCSTR lpPath OPTIONAL, IN LPCSTR lpFileName, IN LPCSTR lpExtension OPTIONAL, IN DWORD nBufferLength, OUT LPSTR lpBuffer, OUT LPSTR *lpFilePart OPTIONAL)
Definition: path.c:1123
DWORD WINAPI SearchPathW(IN LPCWSTR lpPath OPTIONAL, IN LPCWSTR lpFileName, IN LPCWSTR lpExtension OPTIONAL, IN DWORD nBufferLength, OUT LPWSTR lpBuffer, OUT LPWSTR *lpFilePart OPTIONAL)
Definition: path.c:1298
DWORD WINAPI GetFullPathNameA(IN LPCSTR lpFileName, IN DWORD nBufferLength, OUT LPSTR lpBuffer, OUT LPSTR *lpFilePart)
Definition: path.c:993
DWORD WINAPI GetFullPathNameW(IN LPCWSTR lpFileName, IN DWORD nBufferLength, OUT LPWSTR lpBuffer, OUT LPWSTR *lpFilePart)
Definition: path.c:1106
BOOL WINAPI IsDBCSLeadByte(BYTE testchar)
Definition: locale.c:2126
INT WINAPI CompareStringA(LCID lcid, DWORD flags, LPCSTR str1, INT len1, LPCSTR str2, INT len2)
Definition: locale.c:4015
int WINAPI lstrcmpW(LPCWSTR str1, LPCWSTR str2)
Definition: locale.c:4152
int WINAPI lstrcmpA(LPCSTR str1, LPCSTR str2)
Definition: locale.c:4104
int WINAPI PathCommonPrefixW(const WCHAR *file1, const WCHAR *file2, WCHAR *path)
Definition: path.c:1596
HRESULT WINAPI PathCchRemoveFileSpec(WCHAR *path, SIZE_T size)
Definition: path.c:844
HRESULT WINAPI UrlCreateFromPathW(const WCHAR *path, WCHAR *url, DWORD *url_len, DWORD reserved)
Definition: path.c:4892
HRESULT WINAPI ParseURLW(const WCHAR *url, PARSEDURLW *result)
Definition: path.c:2807
BOOL WINAPI PathIsRootA(const char *path)
Definition: path.c:1064
#define WINE_URL_STOP_ON_QUESTION
Definition: path.c:3236
static int get_utf8_len(unsigned char code)
Definition: path.c:2899
#define PATH_CHAR_CLASS_DOUBLEQUOTE
Definition: path.c:2116
static bool array_reserve(void **elements, size_t *capacity, size_t count, size_t size)
Definition: path.c:123
HRESULT WINAPI UrlApplySchemeA(const char *url, char *out, DWORD *out_len, DWORD flags)
Definition: path.c:4213
BOOL WINAPI PathMatchSpecA(const char *path, const char *mask)
Definition: path.c:2432
BOOL WINAPI PathIsSameRootW(const WCHAR *path1, const WCHAR *path2)
Definition: path.c:2552
HRESULT WINAPI PathCchAppendEx(WCHAR *path1, SIZE_T size, const WCHAR *path2, DWORD flags)
Definition: path.c:592
void WINAPI PathRemoveExtensionW(WCHAR *path)
Definition: path.c:1922
#define PATH_CHAR_CLASS_OTHER_VALID
Definition: path.c:2115
void WINAPI PathRemoveBlanksW(WCHAR *path)
Definition: path.c:1886
BOOL WINAPI PathIsUNCW(const WCHAR *path)
Definition: path.c:989
HRESULT WINAPI PathMatchSpecExA(const char *path, const char *mask, DWORD flags)
Definition: path.c:2411
const WCHAR *WINAPI UrlGetLocationW(const WCHAR *url)
Definition: path.c:4482
LPSTR WINAPI PathFindExtensionA(const char *path)
Definition: path.c:1229
INT WINAPI UrlCompareW(const WCHAR *url1, const WCHAR *url2, BOOL ignore_slash)
Definition: path.c:4430
BOOL WINAPI PathIsPrefixA(const char *prefix, const char *path)
Definition: path.c:1646
HRESULT WINAPI PathMatchSpecExW(const WCHAR *path, const WCHAR *mask, DWORD flags)
Definition: path.c:2469
BOOL WINAPI IsInternetESCEnabled(void)
Definition: path.c:5279
HRESULT WINAPI UrlCombineW(const WCHAR *baseW, const WCHAR *relativeW, WCHAR *combined, DWORD *combined_len, DWORD flags)
Definition: path.c:4948
HRESULT WINAPI PathCchFindExtension(const WCHAR *path, SIZE_T size, const WCHAR **extension)
Definition: path.c:706
HRESULT WINAPI UrlUnescapeW(WCHAR *url, WCHAR *unescaped, DWORD *unescaped_len, DWORD flags)
Definition: path.c:2912
static WCHAR * heap_strdupAtoW(const char *str)
Definition: path.c:107
int WINAPI PathCommonPrefixA(const char *file1, const char *file2, char *path)
Definition: path.c:1546
static BOOL is_prefixed_unc(const WCHAR *string)
Definition: path.c:174
void WINAPI PathRemoveBlanksA(char *path)
Definition: path.c:1862
static const WCHAR * parse_url_element(const WCHAR *url, const WCHAR *separators)
Definition: path.c:4533
void WINAPI PathUnquoteSpacesW(WCHAR *path)
Definition: path.c:1982
int WINAPI PathGetDriveNumberW(const WCHAR *path)
Definition: path.c:1786
#define PATH_CHAR_CLASS_SPACE
Definition: path.c:2114
#define PATH_CHAR_CLASS_ASTERIX
Definition: path.c:2108
void WINAPI PathQuoteSpacesA(char *path)
Definition: path.c:2502
HRESULT WINAPI PathCchStripPrefix(WCHAR *path, SIZE_T size)
Definition: path.c:911
BOOL WINAPI PathRemoveFileSpecA(char *path)
Definition: path.c:1084
WCHAR *WINAPI PathRemoveBackslashW(WCHAR *path)
Definition: path.c:2016
BOOL WINAPI UrlIsNoHistoryA(const char *url)
Definition: path.c:4844
HRESULT WINAPI PathCreateFromUrlW(const WCHAR *url, WCHAR *path, DWORD *pcchPath, DWORD dwReserved)
Definition: path.c:3049
#define WINE_URL_ESCAPE_SLASH
Definition: path.c:3232
const WCHAR * scheme_name
Definition: path.c:2731
BOOL WINAPI PathIsUNCServerShareW(const WCHAR *path)
Definition: path.c:1040
BOOL WINAPI PathIsUNCServerA(const char *path)
Definition: path.c:1835
BOOL WINAPI PathIsFileSpecA(const char *path)
Definition: path.c:1801
INT WINAPI UrlCompareA(const char *url1, const char *url2, BOOL ignore_slash)
Definition: path.c:4411
WCHAR *WINAPI PathFindFileNameW(const WCHAR *path)
Definition: path.c:1677
const char *WINAPI UrlGetLocationA(const char *url)
Definition: path.c:4467
HRESULT WINAPI PathCchCombine(WCHAR *out, SIZE_T size, const WCHAR *path1, const WCHAR *path2)
Definition: path.c:667
BOOL WINAPI PathFileExistsA(const char *path)
Definition: path.c:2566
static BOOL is_prefixed_volume(const WCHAR *string)
Definition: path.c:184
BOOL WINAPI UrlIsW(const WCHAR *url, URLIS Urlis)
Definition: path.c:4788
UINT WINAPI PathGetCharTypeA(UCHAR ch)
Definition: path.c:1769
BOOL WINAPI UrlIsOpaqueA(const char *url)
Definition: path.c:4834
HRESULT WINAPI HashData(const unsigned char *src, DWORD src_len, unsigned char *dest, DWORD dest_len)
Definition: path.c:5219
BOOL WINAPI PathRelativePathToA(char *path, const char *from, DWORD attributes_from, const char *to, DWORD attributes_to)
Definition: path.c:2333
HRESULT WINAPI UrlFixupW(const WCHAR *url, WCHAR *translatedUrl, DWORD maxChars)
Definition: path.c:4450
static BOOL is_prefixed_disk(const WCHAR *string)
Definition: path.c:179
HRESULT WINAPI PathCchAddBackslashEx(WCHAR *path, SIZE_T size, WCHAR **endptr, SIZE_T *remaining)
Definition: path.c:509
HRESULT WINAPI UrlCanonicalizeA(const char *src_url, char *canonicalized, DWORD *canonicalized_len, DWORD flags)
Definition: path.c:3518
HRESULT WINAPI PathCreateFromUrlA(const char *pszUrl, char *pszPath, DWORD *pcchPath, DWORD dwReserved)
Definition: path.c:3016
#define PATH_CHAR_CLASS_ANY
Definition: path.c:2119
HRESULT WINAPI UrlCombineA(const char *base, const char *relative, char *combined, DWORD *combined_len, DWORD flags)
Definition: path.c:4908
HRESULT WINAPI UrlEscapeW(const WCHAR *url, WCHAR *escaped, DWORD *escaped_len, DWORD flags)
Definition: path.c:3328
HRESULT WINAPI PathCchAppend(WCHAR *path1, SIZE_T size, const WCHAR *path2)
Definition: path.c:585
static void append_string(struct string_buffer *buffer, const WCHAR *str, size_t len)
Definition: path.c:3684
HRESULT WINAPI UrlGetPartW(const WCHAR *url, WCHAR *out, DWORD *out_len, DWORD part, DWORD flags)
Definition: path.c:4628
static const DWORD path_charclass[]
Definition: path.c:2121
static BOOL path_match_maskW(const WCHAR *name, const WCHAR *mask)
Definition: path.c:2437
char *WINAPI PathFindNextComponentA(const char *path)
Definition: path.c:2205
char *WINAPI PathGetArgsA(const char *path)
Definition: path.c:1694
#define PATH_CHAR_CLASS_LETTER
Definition: path.c:2107
BOOL WINAPI PathSearchAndQualifyA(const char *path, char *buffer, UINT length)
Definition: path.c:2314
HRESULT WINAPI PathCchCanonicalizeEx(WCHAR *out, SIZE_T size, const WCHAR *in, DWORD flags)
Definition: path.c:628
static bool scheme_uses_hostname(URL_SCHEME scheme)
Definition: path.c:3580
#define WINE_URL_ESCAPE_HASH
Definition: path.c:3233
BOOL WINAPI UrlIsOpaqueW(const WCHAR *url)
Definition: path.c:4839
void WINAPI PathStripPathA(char *path)
Definition: path.c:2292
static bool scheme_is_always_relative(URL_SCHEME scheme, DWORD flags)
Definition: path.c:3662
void WINAPI PathStripPathW(WCHAR *path)
Definition: path.c:2304
static void parse_url(const WCHAR *url, struct parsed_url *pl)
Definition: path.c:4542
HRESULT WINAPI PathCchStripToRoot(WCHAR *path, SIZE_T size)
Definition: path.c:935
static void append_char(struct string_buffer *buffer, WCHAR c)
Definition: path.c:3691
BOOL WINAPI PathRemoveFileSpecW(WCHAR *path)
Definition: path.c:1121
void WINAPI PathRemoveExtensionA(char *path)
Definition: path.c:1910
static BOOL is_drive_spec(const WCHAR *str)
Definition: path.c:162
HRESULT WINAPI PathCchRemoveExtension(WCHAR *path, SIZE_T size)
Definition: path.c:825
LPWSTR WINAPI PathFindExtensionW(const WCHAR *path)
Definition: path.c:1250
static HRESULT url_create_from_path(const WCHAR *path, WCHAR *url, DWORD *url_len)
Definition: path.c:4301
char *WINAPI PathSkipRootA(const char *path)
Definition: path.c:2243
BOOL WINAPI PathUnExpandEnvStringsW(const WCHAR *path, WCHAR *buffer, UINT buf_len)
Definition: path.c:2681
static bool scheme_char_is_hostname_separator(URL_SCHEME scheme, DWORD flags, WCHAR c)
Definition: path.c:3606
int WINAPI PathGetDriveNumberA(const char *path)
Definition: path.c:1774
HRESULT WINAPI UrlUnescapeA(char *url, char *unescaped, DWORD *unescaped_len, DWORD flags)
Definition: path.c:2834
HRESULT WINAPI UrlCanonicalizeW(const WCHAR *src_url, WCHAR *canonicalized, DWORD *canonicalized_len, DWORD flags)
Definition: path.c:4128
#define PATH_CHAR_CLASS_SEMICOLON
Definition: path.c:2112
HRESULT WINAPI PathCchRenameExtension(WCHAR *path, SIZE_T size, const WCHAR *extension)
Definition: path.c:868
BOOL WINAPI PathIsRelativeA(const char *path)
Definition: path.c:996
HRESULT WINAPI PathAllocCombine(const WCHAR *path1, const WCHAR *path2, DWORD flags, WCHAR **out)
Definition: path.c:446
BOOL WINAPI PathCchIsRoot(const WCHAR *path)
Definition: path.c:739
#define WINE_URL_STOP_ON_HASH
Definition: path.c:3235
int WINAPI PathParseIconLocationA(char *path)
Definition: path.c:2599
static DWORD get_scheme_code(const WCHAR *scheme, DWORD scheme_len)
Definition: path.c:2762
void WINAPI PathUnquoteSpacesA(char *path)
Definition: path.c:1964
static bool scheme_is_opaque(URL_SCHEME scheme)
Definition: path.c:3546
#define PATH_CHAR_CLASS_COLON
Definition: path.c:2111
BOOL WINAPI PathIsRelativeW(const WCHAR *path)
Definition: path.c:1006
HRESULT WINAPI PathAllocCanonicalize(const WCHAR *path_in, DWORD flags, WCHAR **path_out)
Definition: path.c:259
int WINAPI PathParseIconLocationW(WCHAR *path)
Definition: path.c:2620
static HRESULT url_apply_default_scheme(const WCHAR *url, WCHAR *out, DWORD *length)
Definition: path.c:4336
BOOL WINAPI UrlIsA(const char *url, URLIS Urlis)
Definition: path.c:4751
HRESULT WINAPI PathCchAddExtension(WCHAR *path, SIZE_T size, const WCHAR *extension)
Definition: path.c:542
static bool scheme_char_is_separator(URL_SCHEME scheme, WCHAR c)
Definition: path.c:3597
#define WINE_URL_BASH_AS_SLASH
Definition: path.c:3230
BOOL WINAPI PathSearchAndQualifyW(const WCHAR *path, WCHAR *buffer, UINT length)
Definition: path.c:2324
static bool scheme_char_is_dot_separator(URL_SCHEME scheme, DWORD flags, WCHAR c)
Definition: path.c:3624
HRESULT WINAPI PathCchCanonicalize(WCHAR *out, SIZE_T size, const WCHAR *in)
Definition: path.c:617
static BOOL url_needs_escape(WCHAR ch, DWORD flags, DWORD int_flags)
Definition: path.c:3238
char *WINAPI PathRemoveBackslashA(char *path)
Definition: path.c:2000
BOOL WINAPI PathStripToRootW(WCHAR *path)
Definition: path.c:1171
static bool scheme_preserves_backslashes(URL_SCHEME scheme)
Definition: path.c:3562
static const char hexDigits[]
Definition: path.c:68
BOOL WINAPI PathStripToRootA(char *path)
Definition: path.c:1157
HRESULT WINAPI UrlHashW(const WCHAR *url, unsigned char *dest, DWORD dest_len)
Definition: path.c:5260
BOOL WINAPI PathIsSameRootA(const char *path1, const char *path2)
Definition: path.c:2538
BOOL WINAPI UrlIsNoHistoryW(const WCHAR *url)
Definition: path.c:4849
static const struct @479 url_schemes[]
HRESULT WINAPI UrlApplySchemeW(const WCHAR *url, WCHAR *out, DWORD *length, DWORD flags)
Definition: path.c:4360
URL_SCHEME scheme_number
Definition: path.c:2730
BOOL WINAPI PathIsUNCServerW(const WCHAR *path)
Definition: path.c:1852
static void init_envvars_map(struct envvars_map *map)
Definition: path.c:2670
HRESULT WINAPI PathCreateFromUrlAlloc(const WCHAR *url, WCHAR **path, DWORD reserved)
Definition: path.c:3181
BOOL WINAPI PathIsURLW(const WCHAR *path)
Definition: path.c:3214
#define WINE_URL_COLLAPSE_SLASHES
Definition: path.c:3231
BOOL WINAPI PathIsUNCEx(const WCHAR *path, const WCHAR **server)
Definition: path.c:964
BOOL WINAPI PathIsValidCharW(WCHAR c, DWORD class)
Definition: path.c:2197
HRESULT WINAPI UrlGetPartA(const char *url, char *out, DWORD *out_len, DWORD part, DWORD flags)
Definition: path.c:4497
BOOL WINAPI PathMatchSpecW(const WCHAR *path, const WCHAR *mask)
Definition: path.c:2497
static void rewrite_url(struct string_buffer *dst, const WCHAR *url, DWORD *flags_ptr)
Definition: path.c:3708
WCHAR *WINAPI PathGetArgsW(const WCHAR *path)
Definition: path.c:1716
BOOL WINAPI PathIsLFNFileSpecA(const char *path)
Definition: path.c:2033
UINT WINAPI PathGetCharTypeW(WCHAR ch)
Definition: path.c:1738
static const WCHAR * get_root_end(const WCHAR *path)
Definition: path.c:237
BOOL WINAPI PathIsValidCharA(char c, DWORD class)
Definition: path.c:2189
static bool is_slash(char c)
Definition: path.c:150
HRESULT WINAPI PathCchAddBackslash(WCHAR *path, SIZE_T size)
Definition: path.c:504
WCHAR *WINAPI PathSkipRootW(const WCHAR *path)
Definition: path.c:2269
#define PATH_CHAR_CLASS_COMMA
Definition: path.c:2113
static BOOL is_drive_specA(const char *str)
Definition: path.c:155
static BOOL is_escaped_drive_spec(const WCHAR *str)
Definition: path.c:168
BOOL WINAPI PathRelativePathToW(WCHAR *path, const WCHAR *from, DWORD attributes_from, const WCHAR *to, DWORD attributes_to)
Definition: path.c:2352
HRESULT WINAPI PathCchRemoveBackslashEx(WCHAR *path, SIZE_T path_size, WCHAR **path_end, SIZE_T *free_size)
Definition: path.c:786
HRESULT WINAPI UrlEscapeA(const char *url, char *escaped, DWORD *escaped_len, DWORD flags)
Definition: path.c:3281
BOOL WINAPI PathFileExistsW(const WCHAR *path)
Definition: path.c:2583
static BOOL get_next_segment(const WCHAR *next, const WCHAR **next_segment)
Definition: path.c:221
BOOL WINAPI PathUnExpandEnvStringsA(const char *path, char *buffer, UINT buf_len)
Definition: path.c:2641
#define PATH_CHAR_CLASS_INVALID
Definition: path.c:2118
static HRESULT url_guess_scheme(const WCHAR *url, WCHAR *out, DWORD *out_len)
Definition: path.c:4253
char *WINAPI PathFindFileNameA(const char *path)
Definition: path.c:1660
static char get_slash_dir(URL_SCHEME scheme, DWORD flags, char src, const struct string_buffer *dst)
Definition: path.c:3696
HRESULT WINAPI UrlCreateFromPathA(const char *path, char *url, DWORD *url_len, DWORD reserved)
Definition: path.c:4854
BOOL WINAPI PathIsFileSpecW(const WCHAR *path)
Definition: path.c:1818
HRESULT WINAPI PathCchRemoveBackslash(WCHAR *path, SIZE_T path_size)
Definition: path.c:776
BOOL WINAPI PathIsRootW(const WCHAR *path)
Definition: path.c:1077
HRESULT WINAPI ParseURLA(const char *url, PARSEDURLA *result)
Definition: path.c:2776
static const unsigned char hashdata_lookup[256]
Definition: path.c:70
HRESULT WINAPI PathCchSkipRoot(const WCHAR *path, const WCHAR **root_end)
Definition: path.c:881
BOOL WINAPI PathIsLFNFileSpecW(const WCHAR *path)
Definition: path.c:2070
BOOL WINAPI PathIsPrefixW(const WCHAR *prefix, const WCHAR *path)
Definition: path.c:1653
#define PATH_CHAR_CLASS_BACKSLASH
Definition: path.c:2110
HRESULT WINAPI UrlHashA(const char *url, unsigned char *dest, DWORD dest_len)
Definition: path.c:5246
#define PATH_CHAR_CLASS_DOT
Definition: path.c:2109
WCHAR *WINAPI PathFindNextComponentW(const WCHAR *path)
Definition: path.c:2224
BOOL WINAPI PathIsUNCA(const char *path)
Definition: path.c:982
BOOL WINAPI PathIsUNCServerShareA(const char *path)
Definition: path.c:1016
#define WINE_URL_ESCAPE_QUESTION
Definition: path.c:3234
HRESULT WINAPI PathCchCombineEx(WCHAR *out, SIZE_T size, const WCHAR *path1, const WCHAR *path2, DWORD flags)
Definition: path.c:674
BOOL WINAPI PathIsURLA(const char *path)
Definition: path.c:3198
static const WCHAR * parse_scheme(const WCHAR *p)
Definition: path.c:2755
void WINAPI PathQuoteSpacesW(WCHAR *path)
Definition: path.c:2520
BOOL WINAPI ChrCmpIW(WCHAR ch1, WCHAR ch2)
Definition: string.c:349
BOOL WINAPI StrToIntExW(const WCHAR *str, DWORD flags, INT *ret)
Definition: string.c:1012
LPSTR WINAPI CharNextA(const char *ptr)
Definition: string.c:1151
WCHAR *WINAPI StrDupW(const WCHAR *str)
Definition: string.c:317
LPSTR WINAPI CharPrevA(const char *start, const char *ptr)
Definition: string.c:1172
WCHAR *WINAPI StrCpyNW(WCHAR *dst, const WCHAR *src, int count)
Definition: string.c:470
GUID guid
Definition: version.c:147
unsigned char ch[4][2]
Definition: console.c:118
int CDECL isalnum(int c)
Definition: ctype.c:214
int CDECL tolower(int c)
Definition: ctype.c:572
_ACRTIMP wchar_t *__cdecl wcspbrk(const wchar_t *, const wchar_t *)
Definition: wcs.c:2021
_ACRTIMP size_t __cdecl wcslen(const wchar_t *)
Definition: wcs.c:2988
_ACRTIMP wchar_t *__cdecl wcsstr(const wchar_t *, const wchar_t *)
Definition: wcs.c:2998
_ACRTIMP size_t __cdecl wcsnlen(const wchar_t *, size_t)
Definition: wcs.c:2925
_ACRTIMP int __cdecl wcsncmp(const wchar_t *, const wchar_t *, size_t)
Definition: wcs.c:523
_ACRTIMP __msvcrt_long __cdecl strtol(const char *, char **, int)
Definition: string.c:1838
_ACRTIMP char *__cdecl strchr(const char *, int)
Definition: string.c:3291
_ACRTIMP size_t __cdecl strlen(const char *)
Definition: string.c:1597
_ACRTIMP int __cdecl strcmp(const char *, const char *)
Definition: string.c:3324
_ACRTIMP int __cdecl strncmp(const char *, const char *, size_t)
Definition: string.c:3335
static wchar_t * wmemchr(const wchar_t *s, wchar_t c, size_t n)
Definition: wchar.h:48
static const WCHAR fileW[]
Definition: sec_mgr.c:40
unsigned int(__cdecl typeof(jpeg_read_scanlines))(struct jpeg_decompress_struct *
Definition: typeof.h:31
return ret
Definition: mutex.c:146
#define L(x)
Definition: resources.c:13
r reserved
Definition: btrfs.c:3006
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned long DWORD
Definition: ntddk_ex.h:95
FxCollectionEntry * cur
GLuint start
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
GLenum src
Definition: glext.h:6340
GLuint buffer
Definition: glext.h:5915
GLsizeiptr size
Definition: glext.h:5919
const GLubyte * c
Definition: glext.h:8905
GLuint index
Definition: glext.h:6031
GLenum GLint GLuint mask
Definition: glext.h:6028
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: glext.h:7751
GLuint in
Definition: glext.h:9616
GLenum GLenum dst
Definition: glext.h:6340
GLbitfield flags
Definition: glext.h:7161
GLuint GLsizei GLsizei * length
Definition: glext.h:6040
GLuint GLenum GLenum GLenum GLenum outW
Definition: glext.h:9616
const GLint * first
Definition: glext.h:5794
GLenum const GLvoid * addr
Definition: glext.h:9621
GLuint64EXT * result
Definition: glext.h:11304
GLfloat GLfloat p
Definition: glext.h:8902
GLenum GLsizei len
Definition: glext.h:6722
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
HLOCAL NTAPI LocalAlloc(UINT uFlags, SIZE_T dwBytes)
Definition: heapmem.c:1390
HLOCAL NTAPI LocalFree(HLOCAL hMem)
Definition: heapmem.c:1594
#define WC_ERR_INVALID_CHARS
Definition: unicode.h:47
#define MB_ERR_INVALID_CHARS
Definition: unicode.h:41
#define S_OK
Definition: intsafe.h:52
#define SUCCEEDED(hr)
Definition: intsafe.h:50
#define FAILED(hr)
Definition: intsafe.h:51
#define URL_E_INVALID_SYNTAX
Definition: intshcut.h:32
const char * filename
Definition: ioapi.h:137
BOOL unescape(WCHAR *str, size_t *len)
Definition: lex.c:227
#define c
Definition: ke_i.h:80
INT WINAPI CompareStringOrdinal(const WCHAR *str1, INT len1, const WCHAR *str2, INT len2, BOOL ignore_case)
Definition: vista.c:749
#define debugstr_a
Definition: kernel32.h:31
#define debugstr_wn
Definition: kernel32.h:33
#define debugstr_w
Definition: kernel32.h:32
#define wine_dbgstr_w
Definition: kernel32.h:34
if(dx< 0)
Definition: linetemp.h:194
LPWSTR WINAPI lstrcatW(LPWSTR lpString1, LPCWSTR lpString2)
Definition: lstring.c:274
static void append(struct dump_context *dc, const void *data, unsigned size)
Definition: minidump.c:397
#define LMEM_ZEROINIT
Definition: minwinbase.h:85
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
#define memmove(s1, s2, n)
Definition: mkisofs.h:881
static PVOID ptr
Definition: dispmode.c:27
static const WCHAR url[]
Definition: encode.c:1384
static LPWSTR PDWORD pcchPath
Definition: asmcache.c:747
static const WCHAR pathW[]
Definition: path.c:2368
static const LARGE_INTEGER *static const HANDLE const LARGE_INTEGER *static PSLIST_ENTRY PSLIST_ENTRY last
Definition: sync.c:64
static char * dest
Definition: rtl.c:149
static unsigned(__cdecl *hash_bstr)(bstr_t s)
static const WCHAR url1[]
Definition: misc.c:300
static const WCHAR url2[]
Definition: misc.c:302
static const WCHAR path1[]
Definition: path.c:28
static const WCHAR path2[]
Definition: path.c:29
#define min(a, b)
Definition: monoChain.cc:55
_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
NTSYSAPI BOOLEAN NTAPI RtlCreateUnicodeStringFromAsciiz(_Out_ PUNICODE_STRING Destination, _In_ PCSZ Source)
#define SEM_FAILCRITICALERRORS
Definition: rtltypes.h:69
_Use_decl_annotations_ NTSTATUS NTAPI RtlUnicodeToMultiByteN(_Out_ PCHAR MbString, _In_ ULONG MbSize, _Out_opt_ PULONG ResultSize, _In_ PCWCH UnicodeString, _In_ ULONG UnicodeSize)
Definition: nlsboot.c:108
WCHAR NTAPI RtlDowncaseUnicodeChar(_In_ WCHAR Source)
Definition: nlsboot.c:54
_Use_decl_annotations_ NTSTATUS NTAPI RtlUnicodeToMultiByteSize(_Out_ PULONG MbSize, _In_ PCWCH UnicodeString, _In_ ULONG UnicodeSize)
Definition: nlsboot.c:146
#define FILE_ATTRIBUTE_DIRECTORY
Definition: nt_native.h:705
NTSYSAPI VOID NTAPI RtlFreeUnicodeString(PUNICODE_STRING UnicodeString)
#define DWORD
Definition: nt_native.h:44
#define LOCALE_INVARIANT
@ PATHCCH_ENSURE_TRAILING_SLASH
Definition: pathcch.h:45
@ PATHCCH_FORCE_ENABLE_LONG_NAME_PROCESS
Definition: pathcch.h:41
@ PATHCCH_ALLOW_LONG_PATHS
Definition: pathcch.h:40
@ PATHCCH_DO_NOT_NORMALIZE_SEGMENTS
Definition: pathcch.h:43
@ PATHCCH_FORCE_DISABLE_LONG_NAME_PROCESS
Definition: pathcch.h:42
@ PATHCCH_ENSURE_IS_EXTENDED_LENGTH_PATH
Definition: pathcch.h:44
@ PATHCCH_NONE
Definition: pathcch.h:39
#define PathAddExtensionA
Definition: pathcch.h:305
#define PathCanonicalizeA
Definition: pathcch.h:313
#define PathAddExtensionW
Definition: pathcch.h:306
#define PathCombineA
Definition: pathcch.h:317
#define PathAppendA
Definition: pathcch.h:309
#define PathCanonicalizeW
Definition: pathcch.h:314
#define PathAddBackslashA
Definition: pathcch.h:301
#define PathCombineW
Definition: pathcch.h:318
#define PATHCCH_MAX_CCH
Definition: pathcch.h:52
#define PathRenameExtensionA
Definition: pathcch.h:321
#define PathRenameExtensionW
Definition: pathcch.h:322
#define PathAddBackslashW
Definition: pathcch.h:302
#define PathAppendW
Definition: pathcch.h:310
short WCHAR
Definition: pedump.c:58
URLIS
Definition: shlwapi.h:596
@ URLIS_NOHISTORY
Definition: shlwapi.h:599
@ URLIS_OPAQUE
Definition: shlwapi.h:598
@ URLIS_APPLIABLE
Definition: shlwapi.h:601
@ URLIS_DIRECTORY
Definition: shlwapi.h:602
@ URLIS_FILEURL
Definition: shlwapi.h:600
@ URLIS_URL
Definition: shlwapi.h:597
@ URLIS_HASQUERY
Definition: shlwapi.h:603
#define GCT_SHORTCHAR
Definition: shlwapi.h:273
#define URL_ESCAPE_UNSAFE
Definition: shlwapi.h:533
#define GCT_LFNCHAR
Definition: shlwapi.h:272
URL_SCHEME
Definition: shlwapi.h:542
@ URL_SCHEME_SNEWS
Definition: shlwapi.h:557
@ URL_SCHEME_MAILTO
Definition: shlwapi.h:548
@ URL_SCHEME_LOCAL
Definition: shlwapi.h:558
@ URL_SCHEME_MK
Definition: shlwapi.h:554
@ URL_SCHEME_TELNET
Definition: shlwapi.h:551
@ URL_SCHEME_UNKNOWN
Definition: shlwapi.h:544
@ URL_SCHEME_WAIS
Definition: shlwapi.h:552
@ URL_SCHEME_HTTPS
Definition: shlwapi.h:555
@ URL_SCHEME_FTP
Definition: shlwapi.h:545
@ URL_SCHEME_RES
Definition: shlwapi.h:562
@ URL_SCHEME_NEWS
Definition: shlwapi.h:549
@ URL_SCHEME_HTTP
Definition: shlwapi.h:546
@ URL_SCHEME_FILE
Definition: shlwapi.h:553
@ URL_SCHEME_ABOUT
Definition: shlwapi.h:561
@ URL_SCHEME_NNTP
Definition: shlwapi.h:550
@ URL_SCHEME_INVALID
Definition: shlwapi.h:543
@ URL_SCHEME_SHELL
Definition: shlwapi.h:556
@ URL_SCHEME_VBSCRIPT
Definition: shlwapi.h:560
@ URL_SCHEME_GOPHER
Definition: shlwapi.h:547
@ URL_SCHEME_JAVASCRIPT
Definition: shlwapi.h:559
#define URL_WININET_COMPATIBILITY
Definition: shlwapi.h:535
@ URL_PART_SCHEME
Definition: shlwapi.h:586
@ URL_PART_QUERY
Definition: shlwapi.h:591
@ URL_PART_HOSTNAME
Definition: shlwapi.h:587
@ URL_PART_USERNAME
Definition: shlwapi.h:588
@ URL_PART_PORT
Definition: shlwapi.h:590
@ URL_PART_PASSWORD
Definition: shlwapi.h:589
#define STIF_SUPPORT_HEX
Definition: shlwapi.h:1059
#define URL_DONT_ESCAPE_EXTRA_INFO
Definition: shlwapi.h:529
#define URL_UNESCAPE
Definition: shlwapi.h:532
#define URL_UNESCAPE_AS_UTF8
Definition: shlwapi.h:536
#define URL_APPLY_FORCEAPPLY
Definition: shlwapi.h:520
#define URL_ESCAPE_AS_UTF8
Definition: shlwapi.h:524
#define URL_APPLY_GUESSSCHEME
Definition: shlwapi.h:518
#define URL_APPLY_DEFAULT
Definition: shlwapi.h:517
#define URL_PLUGGABLE_PROTOCOL
Definition: shlwapi.h:534
#define GCT_SEPARATOR
Definition: shlwapi.h:275
#define URL_ESCAPE_SPACES_ONLY
Definition: shlwapi.h:530
#define URL_ESCAPE_SEGMENT_ONLY
Definition: shlwapi.h:522
#define URL_DONT_SIMPLIFY
Definition: shlwapi.h:531
#define URL_UNESCAPE_INPLACE
Definition: shlwapi.h:525
#define URL_FILE_USE_PATHURL
Definition: shlwapi.h:523
#define GCT_INVALID
Definition: shlwapi.h:271
#define URL_DONT_UNESCAPE_EXTRA_INFO
Definition: shlwapi.h:539
#define URL_PARTFLAG_KEEPSCHEME
Definition: shlwapi.h:594
#define URL_APPLY_GUESSFILE
Definition: shlwapi.h:519
#define URL_ESCAPE_PERCENT
Definition: shlwapi.h:521
#define GCT_WILD
Definition: shlwapi.h:274
for(i=0;i< sizeof(testsuite)/sizeof(testsuite[0]);++i) ok(call_test(testsuite[i].func)
static unsigned __int64 next
Definition: rand_nt.c:6
escape_flags
Definition: request.c:2054
const WCHAR * str
DWORD scheme
#define iswalnum(_c)
Definition: ctype.h:671
#define CP_UTF8
Definition: nls.h:20
strcpy
Definition: string.h:131
const char int int int static __inline const char * wine_dbgstr_a(const char *s)
Definition: debug.h:152
#define memset(x, y, z)
Definition: compat.h:39
#define towupper(c)
Definition: wctype.h:99
#define TRACE(s)
Definition: solgame.cpp:4
CardRegion * from
Definition: spigame.cpp:19
wchar_t const *const size_t const buffer_size
Definition: stat.cpp:95
STRSAFEAPI StringCchLengthW(STRSAFE_LPCWSTR psz, size_t cchMax, size_t *pcchLength)
Definition: strsafe.h:842
#define STRSAFE_E_INSUFFICIENT_BUFFER
Definition: strsafe.h:103
Definition: inflate.c:139
WCHAR path[MAX_PATH]
Definition: path.c:2666
DWORD len
Definition: path.c:2667
const WCHAR * var
Definition: path.c:2665
Definition: fci.c:127
Definition: _hash_fun.h:40
Definition: match.c:28
Definition: name.c:39
DWORD scheme_number
Definition: path.c:104
const WCHAR * query
Definition: path.c:102
DWORD password_len
Definition: path.c:97
const WCHAR * username
Definition: path.c:94
const WCHAR * port
Definition: path.c:100
DWORD hostname_len
Definition: path.c:99
const WCHAR * scheme
Definition: path.c:92
DWORD port_len
Definition: path.c:101
DWORD query_len
Definition: path.c:103
DWORD username_len
Definition: path.c:95
const WCHAR * hostname
Definition: path.c:98
DWORD scheme_len
Definition: path.c:93
const WCHAR * password
Definition: path.c:96
WCHAR * string
Definition: path.c:3680
size_t len
Definition: path.c:3681
size_t capacity
Definition: path.c:3681
UINT cchProtocol
Definition: shlwapi.h:618
LPCWSTR pszSuffix
Definition: shlwapi.h:619
DWORD cbSize
Definition: shlwapi.h:616
UINT cchSuffix
Definition: shlwapi.h:620
LPCWSTR pszProtocol
Definition: shlwapi.h:617
#define max(a, b)
Definition: svc.c:63
Character const *const prefix
Definition: tempnam.cpp:195
const uint16_t * LPCWSTR
Definition: typedefs.h:57
unsigned char UCHAR
Definition: typedefs.h:53
uint16_t * LPWSTR
Definition: typedefs.h:56
ULONG_PTR SIZE_T
Definition: typedefs.h:80
char * LPSTR
Definition: typedefs.h:51
int32_t INT
Definition: typedefs.h:58
#define RtlMoveMemory(Destination, Source, Length)
Definition: typedefs.h:264
Definition: pdh_main.c:96
#define INVALID_FILE_ATTRIBUTES
Definition: vfdcmd.c:23
static rfbScreenInfoPtr server
Definition: vnc.c:74
wchar_t tm const _CrtWcstime_Writes_and_advances_ptr_ count wchar_t ** out
Definition: wcsftime.cpp:383
#define WINAPI
Definition: msvc.h:6
#define S_FALSE
Definition: winerror.h:3451
static HRESULT HRESULT_FROM_WIN32(unsigned int x)
Definition: winerror.h:210
#define ERROR_FILENAME_EXCED_RANGE
Definition: winerror.h:385
#define E_POINTER
Definition: winerror.h:3480
#define INTERNET_MAX_URL_LENGTH
Definition: wininet.h:51
#define INTERNET_MAX_SCHEME_LENGTH
Definition: wininet.h:50
#define NORM_IGNORECASE
Definition: winnls.h:191
#define CSTR_EQUAL
Definition: winnls.h:510
#define HKEY_LOCAL_MACHINE
Definition: winreg.h:12
unsigned char BYTE
Definition: xxhash.c:193