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