ReactOS 0.4.15-dev-8021-g7ce96fd
pathcch.c
Go to the documentation of this file.
1/*
2 * Copyright 2018 Nikolay Sivov
3 * Copyright 2018 Zhiyi Zhang
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18 */
19
20#include <stdarg.h>
21#include <string.h>
22
23/* Wine code is still stuck in the past... */
24#ifdef __REACTOS__
25#define wcsnicmp _wcsnicmp
26#endif
27
28#include <windef.h>
29#include <winbase.h>
30
31/* The PathCch functions use size_t, but Wine's implementation uses SIZE_T,
32 * so temporarily change the define'd SIZE_T type to the compatible one... */
33#ifdef __REACTOS__
34#undef SIZE_T
35#define SIZE_T size_t
36#endif
37
38/* This is the static implementation of the PathCch functions */
39#define STATIC_PATHCCH
40#ifdef __GNUC__ // GCC doesn't support #pragma deprecated()
41#undef DEPRECATE_SUPPORTED
42#endif
43#include <pathcch.h>
44
45#include <strsafe.h>
46
47#include "wine/debug.h"
48
50
51#ifdef __REACTOS__
52#if (_WIN32_WINNT < _WIN32_WINNT_VISTA) || (DLL_EXPORT_VERSION < _WIN32_WINNT_VISTA)
53/* wcsnlen is an NT6+ function. To cover all cases, use a private implementation */
54static inline size_t hacked_wcsnlen(const wchar_t* str, size_t size)
55{
57 return size;
58}
59#define wcsnlen hacked_wcsnlen
60#endif
61#endif /* __REACTOS__ */
62
63static BOOL is_drive_spec( const WCHAR *str )
64{
65 return isalpha( str[0] ) && str[1] == ':';
66}
67
68#if 0
69static BOOL is_escaped_drive_spec( const WCHAR *str )
70{
71 return isalpha( str[0] ) && (str[1] == ':' || str[1] == '|');
72}
73#endif
74
75static BOOL is_prefixed_unc(const WCHAR *string)
76{
77 return !wcsnicmp(string, L"\\\\?\\UNC\\", 8 );
78}
79
80static BOOL is_prefixed_disk(const WCHAR *string)
81{
82 return !wcsncmp(string, L"\\\\?\\", 4) && is_drive_spec( string + 4 );
83}
84
85static BOOL is_prefixed_volume(const WCHAR *string)
86{
87 const WCHAR *guid;
88 INT i = 0;
89
90 if (wcsnicmp( string, L"\\\\?\\Volume", 10 )) return FALSE;
91
92 guid = string + 10;
93
94 while (i <= 37)
95 {
96 switch (i)
97 {
98 case 0:
99 if (guid[i] != '{') return FALSE;
100 break;
101 case 9:
102 case 14:
103 case 19:
104 case 24:
105 if (guid[i] != '-') return FALSE;
106 break;
107 case 37:
108 if (guid[i] != '}') return FALSE;
109 break;
110 default:
111 if (!isxdigit(guid[i])) return FALSE;
112 break;
113 }
114 i++;
115 }
116
117 return TRUE;
118}
119
120/* Get the next character beyond end of the segment.
121 Return TRUE if the last segment ends with a backslash */
122static BOOL get_next_segment(const WCHAR *next, const WCHAR **next_segment)
123{
124 while (*next && *next != '\\') next++;
125 if (*next == '\\')
126 {
127 *next_segment = next + 1;
128 return TRUE;
129 }
130 else
131 {
132 *next_segment = next;
133 return FALSE;
134 }
135}
136
137/* Find the last character of the root in a path, if there is one, without any segments */
138static const WCHAR *get_root_end(const WCHAR *path)
139{
140 /* Find path root */
142 return path[48] == '\\' ? path + 48 : path + 47;
143 else if (is_prefixed_unc(path))
144 return path + 7;
145 else if (is_prefixed_disk(path))
146 return path[6] == '\\' ? path + 6 : path + 5;
147 /* \\ */
148 else if (path[0] == '\\' && path[1] == '\\')
149 return path + 1;
150 /* \ */
151 else if (path[0] == '\\')
152 return path;
153 /* X:\ */
154 else if (is_drive_spec( path ))
155 return path[2] == '\\' ? path + 2 : path + 1;
156 else
157 return NULL;
158}
159
160#ifdef __REACTOS__
164 _In_ PCWSTR path_in,
165 _In_ /* PATHCCH_OPTIONS */ ULONG flags,
166 _Outptr_ PWSTR* path_out)
167#else
169#endif
170{
171 WCHAR *buffer, *dst;
172 const WCHAR *src;
173 const WCHAR *root_end;
175
176 TRACE("%s %#lx %p\n", debugstr_w(path_in), flags, path_out);
177
178 if (!path_in || !path_out
183 {
184 if (path_out) *path_out = NULL;
185 return E_INVALIDARG;
186 }
187
188 length = lstrlenW(path_in);
190 || (length + 1 > PATHCCH_MAX_CCH))
191 {
192 *path_out = NULL;
194 }
195
196 /* PATHCCH_ENSURE_IS_EXTENDED_LENGTH_PATH implies PATHCCH_DO_NOT_NORMALIZE_SEGMENTS */
198
199 /* path length + possible \\?\ addition + possible \ addition + NUL */
200 buffer_size = (length + 6) * sizeof(WCHAR);
202 if (!buffer)
203 {
204 *path_out = NULL;
205 return E_OUTOFMEMORY;
206 }
207
208 src = path_in;
209 dst = buffer;
210
211 root_end = get_root_end(path_in);
212 if (root_end) root_end = buffer + (root_end - path_in);
213
214 /* Copy path root */
215 if (root_end)
216 {
217 memcpy(dst, src, (root_end - buffer + 1) * sizeof(WCHAR));
218 src += root_end - buffer + 1;
219 if(PathCchStripPrefix(dst, length + 6) == S_OK)
220 {
221 /* Fill in \ in X:\ if the \ is missing */
222 if (is_drive_spec( dst ) && dst[2]!= '\\')
223 {
224 dst[2] = '\\';
225 dst[3] = 0;
226 }
228 root_end = dst;
229 }
230 else
231 dst += root_end - buffer + 1;
232 }
233
234 while (*src)
235 {
236 if (src[0] == '.')
237 {
238 if (src[1] == '.')
239 {
240 /* Keep one . after * */
241 if (dst > buffer && dst[-1] == '*')
242 {
243 *dst++ = *src++;
244 continue;
245 }
246
247 /* Keep the .. if not surrounded by \ */
248 if ((src[2] != '\\' && src[2]) || (dst > buffer && dst[-1] != '\\'))
249 {
250 *dst++ = *src++;
251 *dst++ = *src++;
252 continue;
253 }
254
255 /* Remove the \ before .. if the \ is not part of root */
256 if (dst > buffer && dst[-1] == '\\' && (!root_end || dst - 1 > root_end))
257 {
258 *--dst = '\0';
259 /* Remove characters until a \ is encountered */
260 while (dst > buffer)
261 {
262 if (dst[-1] == '\\')
263 {
264 *--dst = 0;
265 break;
266 }
267 else
268 *--dst = 0;
269 }
270 }
271 /* Remove the extra \ after .. if the \ before .. wasn't deleted */
272 else if (src[2] == '\\')
273 src++;
274
275 src += 2;
276 }
277 else
278 {
279 /* Keep the . if not surrounded by \ */
280 if ((src[1] != '\\' && src[1]) || (dst > buffer && dst[-1] != '\\'))
281 {
282 *dst++ = *src++;
283 continue;
284 }
285
286 /* Remove the \ before . if the \ is not part of root */
287 if (dst > buffer && dst[-1] == '\\' && (!root_end || dst - 1 > root_end)) dst--;
288 /* Remove the extra \ after . if the \ before . wasn't deleted */
289 else if (src[1] == '\\')
290 src++;
291
292 src++;
293 }
294
295 /* If X:\ is not complete, then complete it */
296 if (is_drive_spec( buffer ) && buffer[2] != '\\')
297 {
298 root_end = buffer + 2;
299 dst = buffer + 3;
300 buffer[2] = '\\';
301 /* If next character is \, use the \ to fill in */
302 if (src[0] == '\\') src++;
303 }
304 }
305 /* Copy over */
306 else
307 *dst++ = *src++;
308 }
309 /* End the path */
310 *dst = 0;
311
312 /* Strip multiple trailing . */
314 {
315 while (dst > buffer && dst[-1] == '.')
316 {
317 /* Keep a . after * */
318 if (dst - 1 > buffer && dst[-2] == '*')
319 break;
320 /* If . follow a : at the second character, remove the . and add a \ */
321 else if (dst - 1 > buffer && dst[-2] == ':' && dst - 2 == buffer + 1)
322 *--dst = '\\';
323 else
324 *--dst = 0;
325 }
326 }
327
328 /* If result path is empty, fill in \ */
329 if (!*buffer)
330 {
331 buffer[0] = '\\';
332 buffer[1] = 0;
333 }
334
335 /* Extend the path if needed */
337 if (((length + 1 > MAX_PATH && is_drive_spec( buffer ))
340 {
341 memmove(buffer + 4, buffer, (length + 1) * sizeof(WCHAR));
342 buffer[0] = '\\';
343 buffer[1] = '\\';
344 buffer[2] = '?';
345 buffer[3] = '\\';
346 }
347
348 /* Add a trailing backslash to the path if needed */
351
352 *path_out = buffer;
353 return S_OK;
354}
355
356#ifdef __REACTOS__
362 _In_ /* PATHCCH_OPTIONS */ ULONG flags,
364#else
366#endif
367{
368 SIZE_T combined_length, length2;
369 WCHAR *combined_path;
370 BOOL add_backslash = FALSE;
371 HRESULT hr;
372
373 TRACE("%s %s %#lx %p\n", wine_dbgstr_w(path1), wine_dbgstr_w(path2), flags, out);
374
375 if ((!path1 && !path2) || !out)
376 {
377 if (out) *out = NULL;
378 return E_INVALIDARG;
379 }
380
381 if (!path1 || !path2) return PathAllocCanonicalize(path1 ? path1 : path2, flags, out);
382
383 /* If path2 is fully qualified, use path2 only */
384 if (is_drive_spec( path2 ) || (path2[0] == '\\' && path2[1] == '\\'))
385 {
386 path1 = path2;
387 path2 = NULL;
388 add_backslash = (is_drive_spec(path1) && !path1[2])
389 || (is_prefixed_disk(path1) && !path1[6]);
390 }
391
392 length2 = path2 ? lstrlenW(path2) : 0;
393 /* path1 length + path2 length + possible backslash + NULL */
394 combined_length = lstrlenW(path1) + length2 + 2;
395
396 combined_path = HeapAlloc(GetProcessHeap(), 0, combined_length * sizeof(WCHAR));
397 if (!combined_path)
398 {
399 *out = NULL;
400 return E_OUTOFMEMORY;
401 }
402
403 lstrcpyW(combined_path, path1);
404 PathCchStripPrefix(combined_path, combined_length);
405 if (add_backslash) PathCchAddBackslashEx(combined_path, combined_length, NULL, NULL);
406
407 if (path2 && path2[0])
408 {
409 if (path2[0] == '\\' && path2[1] != '\\')
410 {
411 PathCchStripToRoot(combined_path, combined_length);
412 path2++;
413 }
414
415 PathCchAddBackslashEx(combined_path, combined_length, NULL, NULL);
416 lstrcatW(combined_path, path2);
417 }
418
419 hr = PathAllocCanonicalize(combined_path, flags, out);
420 HeapFree(GetProcessHeap(), 0, combined_path);
421 return hr;
422}
423
424#ifdef __REACTOS__
429 _In_ size_t size)
430#else
432#endif
433{
435}
436
437#ifdef __REACTOS__
442 _In_ size_t size,
443 _Outptr_opt_result_buffer_(*remaining) PWSTR* endptr,
444 _Out_opt_ size_t* remaining)
445#else
447#endif
448{
449 BOOL needs_termination;
451
452 TRACE("%s, %Iu, %p, %p\n", debugstr_w(path), size, endptr, remaining);
453
455 needs_termination = size && length && path[length - 1] != '\\';
456
457 if (length >= (needs_termination ? size - 1 : size))
458 {
459 if (endptr) *endptr = NULL;
460 if (remaining) *remaining = 0;
462 }
463
464 if (!needs_termination)
465 {
466 if (endptr) *endptr = path + length;
467 if (remaining) *remaining = size - length;
468 return S_FALSE;
469 }
470
471 path[length++] = '\\';
472 path[length] = 0;
473
474 if (endptr) *endptr = path + length;
475 if (remaining) *remaining = size - length;
476
477 return S_OK;
478}
479
480#ifdef __REACTOS__
485 _In_ size_t size,
486 _In_ PCWSTR extension)
487#else
489#endif
490{
491 const WCHAR *existing_extension, *next;
492 SIZE_T path_length, extension_length, dot_length;
493 BOOL has_dot;
494 HRESULT hr;
495
496 TRACE("%s %Iu %s\n", wine_dbgstr_w(path), size, wine_dbgstr_w(extension));
497
498 if (!path || !size || size > PATHCCH_MAX_CCH || !extension) return E_INVALIDARG;
499
500 next = extension;
501 while (*next)
502 {
503 if ((*next == '.' && next > extension) || *next == ' ' || *next == '\\') return E_INVALIDARG;
504 next++;
505 }
506
507 has_dot = extension[0] == '.';
508
509 hr = PathCchFindExtension(path, size, &existing_extension);
510 if (FAILED(hr)) return hr;
511 if (*existing_extension) return S_FALSE;
512
513 path_length = wcsnlen(path, size);
514 dot_length = has_dot ? 0 : 1;
515 extension_length = lstrlenW(extension);
516
517 if (path_length + dot_length + extension_length + 1 > size) return STRSAFE_E_INSUFFICIENT_BUFFER;
518
519 /* If extension is empty or only dot, return S_OK with path unchanged */
520 if (!extension[0] || (extension[0] == '.' && !extension[1])) return S_OK;
521
522 if (!has_dot)
523 {
524 path[path_length] = '.';
525 path_length++;
526 }
527
528 lstrcpyW(path + path_length, extension);
529 return S_OK;
530}
531
532#ifdef __REACTOS__
537 _In_ size_t size,
539#else
541#endif
542{
543 TRACE("%s %Iu %s\n", wine_dbgstr_w(path1), size, wine_dbgstr_w(path2));
544
546}
547
548#ifdef __REACTOS__
553 _In_ size_t size,
555 _In_ /* PATHCCH_OPTIONS */ ULONG flags)
556#else
558#endif
559{
560 HRESULT hr;
561 WCHAR *result;
562
563 TRACE("%s %Iu %s %#lx\n", wine_dbgstr_w(path1), size, wine_dbgstr_w(path2), flags);
564
565 if (!path1 || !size) return E_INVALIDARG;
566
567 /* Create a temporary buffer for result because we need to keep path1 unchanged if error occurs.
568 * And PathCchCombineEx writes empty result if there is error so we can't just use path1 as output
569 * buffer for PathCchCombineEx */
570 result = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
571 if (!result) return E_OUTOFMEMORY;
572
573 /* Avoid the single backslash behavior with PathCchCombineEx when appending */
574 if (path2 && path2[0] == '\\' && path2[1] != '\\') path2++;
575
577 if (SUCCEEDED(hr)) memcpy(path1, result, size * sizeof(WCHAR));
578
580 return hr;
581}
582
583#ifdef __REACTOS__
588 _In_ size_t size,
589 _In_ PCWSTR in)
590#else
592#endif
593{
594 TRACE("%p %Iu %s\n", out, size, wine_dbgstr_w(in));
595
596 /* Not X:\ and path > MAX_PATH - 4, return HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE) */
597 if (lstrlenW(in) > MAX_PATH - 4 && !(is_drive_spec( in ) && in[2] == '\\'))
599
601}
602
603#ifdef __REACTOS__
608 _In_ size_t size,
609 _In_ PCWSTR in,
610 _In_ /* PATHCCH_OPTIONS */ ULONG flags)
611#else
613#endif
614{
615 WCHAR *buffer;
617 HRESULT hr;
618
619 TRACE("%p %Iu %s %#lx\n", out, size, wine_dbgstr_w(in), flags);
620
621 if (!size) return E_INVALIDARG;
622
624 if (FAILED(hr)) return hr;
625
627 if (size < length + 1)
628 {
629 /* No root and path > MAX_PATH - 4, return HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE) */
630 if (length > MAX_PATH - 4 && !(in[0] == '\\' || (is_drive_spec( in ) && in[2] == '\\')))
632 else
634 }
635
636 if (SUCCEEDED(hr))
637 {
638 memcpy(out, buffer, (length + 1) * sizeof(WCHAR));
639
640 /* Fill a backslash at the end of X: */
641 if (is_drive_spec( out ) && !out[2] && size > 3)
642 {
643 out[2] = '\\';
644 out[3] = 0;
645 }
646 }
647
649 return hr;
650}
651
652#ifdef __REACTOS__
657 _In_ size_t size,
660#else
662#endif
663{
664 TRACE("%p %s %s\n", out, wine_dbgstr_w(path1), wine_dbgstr_w(path2));
665
667}
668
669#ifdef __REACTOS__
674 _In_ size_t size,
677 _In_ /* PATHCCH_OPTIONS */ ULONG flags)
678#else
680#endif
681{
682 HRESULT hr;
683 WCHAR *buffer;
685
686 TRACE("%p %s %s %#lx\n", out, wine_dbgstr_w(path1), wine_dbgstr_w(path2), flags);
687
688 if (!out || !size || size > PATHCCH_MAX_CCH) return E_INVALIDARG;
689
691 if (FAILED(hr))
692 {
693 out[0] = 0;
694 return hr;
695 }
696
698 if (length + 1 > size)
699 {
700 out[0] = 0;
703 }
704 else
705 {
706 memcpy(out, buffer, (length + 1) * sizeof(WCHAR));
708 return S_OK;
709 }
710}
711
712#ifdef __REACTOS__
717 _In_ size_t size,
718 _Outptr_ PCWSTR* extension)
719#else
721#endif
722{
723 const WCHAR *lastpoint = NULL;
724 SIZE_T counter = 0;
725
726 TRACE("%s %Iu %p\n", wine_dbgstr_w(path), size, extension);
727
728 if (!path || !size || size > PATHCCH_MAX_CCH)
729 {
730 *extension = NULL;
731 return E_INVALIDARG;
732 }
733
734 while (*path)
735 {
736 if (*path == '\\' || *path == ' ')
737 lastpoint = NULL;
738 else if (*path == '.')
739 lastpoint = path;
740
741 path++;
742 counter++;
743 if (counter == size || counter == PATHCCH_MAX_CCH)
744 {
745 *extension = NULL;
746 return E_INVALIDARG;
747 }
748 }
749
750 *extension = lastpoint ? lastpoint : path;
751 return S_OK;
752}
753
754#ifdef __REACTOS__
755BOOL
759#else
761#endif
762{
763 const WCHAR *root_end;
764 const WCHAR *next;
765 BOOL is_unc;
766
767 TRACE("%s\n", wine_dbgstr_w(path));
768
769 if (!path || !*path) return FALSE;
770
771 root_end = get_root_end(path);
772 if (!root_end) return FALSE;
773
774 if ((is_unc = is_prefixed_unc(path)) || (path[0] == '\\' && path[1] == '\\' && path[2] != '?'))
775 {
776 next = root_end + 1;
777 /* No extra segments */
778 if ((is_unc && !*next) || (!is_unc && !*next)) return TRUE;
779
780 /* Has first segment with an ending backslash but no remaining characters */
781 if (get_next_segment(next, &next) && !*next) return FALSE;
782 /* Has first segment with no ending backslash */
783 else if (!*next)
784 return TRUE;
785 /* Has first segment with an ending backslash and has remaining characters*/
786 else
787 {
788 next++;
789 /* Second segment must have no backslash and no remaining characters */
790 return !get_next_segment(next, &next) && !*next;
791 }
792 }
793 else if (*root_end == '\\' && !root_end[1])
794 return TRUE;
795 else
796 return FALSE;
797}
798
799#ifdef __REACTOS__
803 _Inout_updates_(path_size) PWSTR path,
804 _In_ size_t path_size)
805#else
807#endif
808{
809 WCHAR *path_end;
810 SIZE_T free_size;
811
812 TRACE("%s %Iu\n", debugstr_w(path), path_size);
813
814 return PathCchRemoveBackslashEx(path, path_size, &path_end, &free_size);
815}
816
817#ifdef __REACTOS__
821 _Inout_updates_(path_size) PWSTR path,
822 _In_ size_t path_size,
823 _Outptr_opt_result_buffer_(*free_size) PWSTR* path_end,
824 _Out_opt_ size_t* free_size)
825#else
827#endif
828{
829 const WCHAR *root_end;
831
832 TRACE("%s %Iu %p %p\n", debugstr_w(path), path_size, path_end, free_size);
833
834 if (!path_size || !path_end || !free_size)
835 {
836 if (path_end) *path_end = NULL;
837 if (free_size) *free_size = 0;
838 return E_INVALIDARG;
839 }
840
841 path_length = wcsnlen(path, path_size);
842 if (path_length == path_size && !path[path_length]) return E_INVALIDARG;
843
844 root_end = get_root_end(path);
845 if (path_length > 0 && path[path_length - 1] == '\\')
846 {
847 *path_end = path + path_length - 1;
848 *free_size = path_size - path_length + 1;
849 /* If the last character is beyond end of root */
850 if (!root_end || path + path_length - 1 > root_end)
851 {
852 path[path_length - 1] = 0;
853 return S_OK;
854 }
855 else
856 return S_FALSE;
857 }
858 else
859 {
860 *path_end = path + path_length;
861 *free_size = path_size - path_length;
862 return S_FALSE;
863 }
864}
865
866#ifdef __REACTOS__
871 _In_ size_t size)
872#else
874#endif
875{
876 const WCHAR *extension;
877 WCHAR *next;
878 HRESULT hr;
879
880 TRACE("%s %Iu\n", wine_dbgstr_w(path), size);
881
882 if (!path || !size || size > PATHCCH_MAX_CCH) return E_INVALIDARG;
883
884 hr = PathCchFindExtension(path, size, &extension);
885 if (FAILED(hr)) return hr;
886
887 next = path + (extension - path);
888 while (next - path < size && *next) *next++ = 0;
889
890 return next == extension ? S_FALSE : S_OK;
891}
892
893#ifdef __REACTOS__
898 _In_ size_t size)
899#else
901#endif
902{
903 const WCHAR *root_end = NULL;
905 WCHAR *last;
906
907 TRACE("%s %Iu\n", wine_dbgstr_w(path), size);
908
909 if (!path || !size || size > PATHCCH_MAX_CCH) return E_INVALIDARG;
910
911 if (PathCchIsRoot(path)) return S_FALSE;
912
913 PathCchSkipRoot(path, &root_end);
914
915 /* The backslash at the end of UNC and \\* are not considered part of root in this case */
916 if (root_end && root_end > path && root_end[-1] == '\\'
917 && (is_prefixed_unc(path) || (path[0] == '\\' && path[1] == '\\' && path[2] != '?')))
918 root_end--;
919
921 last = path + length - 1;
922 while (last >= path && (!root_end || last >= root_end))
923 {
924 if (last - path >= size) return E_INVALIDARG;
925
926 if (*last == '\\')
927 {
928 *last-- = 0;
929 break;
930 }
931
932 *last-- = 0;
933 }
934
935 return last != path + length - 1 ? S_OK : S_FALSE;
936}
937
938#ifdef __REACTOS__
943 _In_ size_t size,
944 _In_ PCWSTR extension)
945#else
947#endif
948{
949 HRESULT hr;
950
951 TRACE("%s %Iu %s\n", wine_dbgstr_w(path), size, wine_dbgstr_w(extension));
952
954 if (FAILED(hr)) return hr;
955
956 hr = PathCchAddExtension(path, size, extension);
957 return FAILED(hr) ? hr : S_OK;
958}
959
960#ifdef __REACTOS__
965 _Outptr_ PCWSTR* root_end)
966#else
967HRESULT WINAPI PathCchSkipRoot(const WCHAR *path, const WCHAR **root_end)
968#endif
969{
970 TRACE("%s %p\n", debugstr_w(path), root_end);
971
972 if (!path || !path[0] || !root_end
973 || (!wcsnicmp(path, L"\\\\?", 3) && !is_prefixed_volume(path) && !is_prefixed_unc(path)
975 return E_INVALIDARG;
976
977 *root_end = get_root_end(path);
978 if (*root_end)
979 {
980 (*root_end)++;
982 {
983 get_next_segment(*root_end, root_end);
984 get_next_segment(*root_end, root_end);
985 }
986 else if (path[0] == '\\' && path[1] == '\\' && path[2] != '?')
987 {
988 /* Skip share server */
989 get_next_segment(*root_end, root_end);
990 /* If mount point is empty, don't skip over mount point */
991 if (**root_end != '\\') get_next_segment(*root_end, root_end);
992 }
993 }
994
995 return *root_end ? S_OK : E_INVALIDARG;
996}
997
998#ifdef __REACTOS__
1003 _In_ size_t size)
1004#else
1006#endif
1007{
1008 TRACE("%s %Iu\n", wine_dbgstr_w(path), size);
1009
1010 if (!path || !size || size > PATHCCH_MAX_CCH) return E_INVALIDARG;
1011
1012 if (is_prefixed_unc(path))
1013 {
1014 /* \\?\UNC\a -> \\a */
1015 if (size < lstrlenW(path + 8) + 3) return E_INVALIDARG;
1016 lstrcpyW(path + 2, path + 8);
1017 return S_OK;
1018 }
1019 else if (is_prefixed_disk(path))
1020 {
1021 /* \\?\C:\ -> C:\ */
1022 if (size < lstrlenW(path + 4) + 1) return E_INVALIDARG;
1023 lstrcpyW(path, path + 4);
1024 return S_OK;
1025 }
1026 else
1027 return S_FALSE;
1028}
1029
1030#ifdef __REACTOS__
1031HRESULT
1035 _In_ size_t size)
1036#else
1038#endif
1039{
1040 const WCHAR *root_end;
1041 WCHAR *segment_end;
1042 BOOL is_unc;
1043
1044 TRACE("%s %Iu\n", wine_dbgstr_w(path), size);
1045
1046 if (!path || !*path || !size || size > PATHCCH_MAX_CCH) return E_INVALIDARG;
1047
1048 /* \\\\?\\UNC\\* and \\\\* have to have at least two extra segments to be striped,
1049 * e.g. \\\\?\\UNC\\a\\b\\c -> \\\\?\\UNC\\a\\b
1050 * \\\\a\\b\\c -> \\\\a\\b */
1051 if ((is_unc = is_prefixed_unc(path)) || (path[0] == '\\' && path[1] == '\\' && path[2] != '?'))
1052 {
1053 root_end = is_unc ? path + 8 : path + 3;
1054 if (!get_next_segment(root_end, &root_end)) return S_FALSE;
1055 if (!get_next_segment(root_end, &root_end)) return S_FALSE;
1056
1057 if (root_end - path >= size) return E_INVALIDARG;
1058
1059 segment_end = path + (root_end - path) - 1;
1060 *segment_end = 0;
1061 return S_OK;
1062 }
1063 else if (PathCchSkipRoot(path, &root_end) == S_OK)
1064 {
1065 if (root_end - path >= size) return E_INVALIDARG;
1066
1067 segment_end = path + (root_end - path);
1068 if (!*segment_end) return S_FALSE;
1069
1070 *segment_end = 0;
1071 return S_OK;
1072 }
1073 else
1074 return E_INVALIDARG;
1075}
1076
1077#ifdef __REACTOS__
1078BOOL
1083#else
1085#endif
1086{
1087 const WCHAR *result = NULL;
1088
1089 TRACE("%s %p\n", wine_dbgstr_w(path), server);
1090
1091 if (is_prefixed_unc(path))
1092 result = path + 8;
1093 else if (path[0] == '\\' && path[1] == '\\' && path[2] != '?')
1094 result = path + 2;
1095
1096 if (server) *server = result;
1097 return !!result;
1098}
#define isalpha(c)
Definition: acclib.h:74
#define isxdigit(c)
Definition: acclib.h:70
static long path_length
Definition: maze.c:116
#define WINE_DEFAULT_DEBUG_CHANNEL(t)
Definition: precomp.h:23
#define E_OUTOFMEMORY
Definition: ddrawi.h:100
#define E_INVALIDARG
Definition: ddrawi.h:101
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define APIENTRY
Definition: api.h:79
#define GetProcessHeap()
Definition: compat.h:736
#define wcsnicmp
Definition: compat.h:14
#define HeapAlloc
Definition: compat.h:733
#define MAX_PATH
Definition: compat.h:34
#define HeapFree(x, y, z)
Definition: compat.h:735
#define lstrcpyW
Definition: compat.h:749
#define lstrlenW
Definition: compat.h:750
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned long DWORD
Definition: ntddk_ex.h:95
GLsizeiptr size
Definition: glext.h:5919
GLenum src
Definition: glext.h:6340
GLuint buffer
Definition: glext.h:5915
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
GLuint64EXT * result
Definition: glext.h:11304
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
HLOCAL NTAPI LocalAlloc(UINT uFlags, SIZE_T dwBytes)
Definition: heapmem.c:1390
HLOCAL NTAPI LocalFree(HLOCAL hMem)
Definition: heapmem.c:1594
#define S_OK
Definition: intsafe.h:52
#define SUCCEEDED(hr)
Definition: intsafe.h:50
#define FAILED(hr)
Definition: intsafe.h:51
#define debugstr_w
Definition: kernel32.h:32
#define wine_dbgstr_w
Definition: kernel32.h:34
LPWSTR WINAPI lstrcatW(LPWSTR lpString1, LPCWSTR lpString2)
Definition: lstring.c:274
const GUID * guid
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
#define memmove(s1, s2, n)
Definition: mkisofs.h:881
static UINT UINT last
Definition: font.c:45
static const WCHAR path1[]
Definition: path.c:28
static const WCHAR path2[]
Definition: path.c:29
#define _Outptr_opt_result_buffer_(size)
Definition: ms_sal.h:457
#define _Out_opt_
Definition: ms_sal.h:346
#define _Inout_updates_(size)
Definition: ms_sal.h:387
#define _Outptr_opt_
Definition: ms_sal.h:429
#define _Outptr_
Definition: ms_sal.h:427
#define _Out_writes_(size)
Definition: ms_sal.h:348
#define _In_
Definition: ms_sal.h:308
#define _In_opt_
Definition: ms_sal.h:309
#define _In_reads_(size)
Definition: ms_sal.h:319
#define L(x)
Definition: ntvdm.h:50
HRESULT WINAPI PathCchRemoveFileSpec(WCHAR *path, SIZE_T size)
Definition: pathcch.c:900
HRESULT WINAPI PathCchAppendEx(WCHAR *path1, SIZE_T size, const WCHAR *path2, DWORD flags)
Definition: pathcch.c:557
HRESULT WINAPI PathCchFindExtension(const WCHAR *path, SIZE_T size, const WCHAR **extension)
Definition: pathcch.c:720
static BOOL is_prefixed_unc(const WCHAR *string)
Definition: pathcch.c:75
HRESULT WINAPI PathCchStripPrefix(WCHAR *path, SIZE_T size)
Definition: pathcch.c:1005
HRESULT WINAPI PathCchCombine(WCHAR *out, SIZE_T size, const WCHAR *path1, const WCHAR *path2)
Definition: pathcch.c:661
static BOOL is_prefixed_volume(const WCHAR *string)
Definition: pathcch.c:85
static BOOL is_prefixed_disk(const WCHAR *string)
Definition: pathcch.c:80
HRESULT WINAPI PathCchAddBackslashEx(WCHAR *path, SIZE_T size, WCHAR **endptr, SIZE_T *remaining)
Definition: pathcch.c:446
HRESULT WINAPI PathCchAppend(WCHAR *path1, SIZE_T size, const WCHAR *path2)
Definition: pathcch.c:540
HRESULT WINAPI PathCchCanonicalizeEx(WCHAR *out, SIZE_T size, const WCHAR *in, DWORD flags)
Definition: pathcch.c:612
HRESULT WINAPI PathCchStripToRoot(WCHAR *path, SIZE_T size)
Definition: pathcch.c:1037
static BOOL is_drive_spec(const WCHAR *str)
Definition: pathcch.c:63
HRESULT WINAPI PathCchRemoveExtension(WCHAR *path, SIZE_T size)
Definition: pathcch.c:873
HRESULT WINAPI PathCchRenameExtension(WCHAR *path, SIZE_T size, const WCHAR *extension)
Definition: pathcch.c:946
HRESULT WINAPI PathAllocCombine(const WCHAR *path1, const WCHAR *path2, DWORD flags, WCHAR **out)
Definition: pathcch.c:365
BOOL WINAPI PathCchIsRoot(const WCHAR *path)
Definition: pathcch.c:760
HRESULT WINAPI PathAllocCanonicalize(const WCHAR *path_in, DWORD flags, WCHAR **path_out)
Definition: pathcch.c:168
HRESULT WINAPI PathCchAddExtension(WCHAR *path, SIZE_T size, const WCHAR *extension)
Definition: pathcch.c:488
HRESULT WINAPI PathCchCanonicalize(WCHAR *out, SIZE_T size, const WCHAR *in)
Definition: pathcch.c:591
BOOL WINAPI PathIsUNCEx(const WCHAR *path, const WCHAR **server)
Definition: pathcch.c:1084
static const WCHAR * get_root_end(const WCHAR *path)
Definition: pathcch.c:138
HRESULT WINAPI PathCchAddBackslash(WCHAR *path, SIZE_T size)
Definition: pathcch.c:431
HRESULT WINAPI PathCchRemoveBackslashEx(WCHAR *path, SIZE_T path_size, WCHAR **path_end, SIZE_T *free_size)
Definition: pathcch.c:826
static BOOL get_next_segment(const WCHAR *next, const WCHAR **next_segment)
Definition: pathcch.c:122
HRESULT WINAPI PathCchRemoveBackslash(WCHAR *path, SIZE_T path_size)
Definition: pathcch.c:806
HRESULT WINAPI PathCchSkipRoot(const WCHAR *path, const WCHAR **root_end)
Definition: pathcch.c:967
HRESULT WINAPI PathCchCombineEx(WCHAR *out, SIZE_T size, const WCHAR *path1, const WCHAR *path2, DWORD flags)
Definition: pathcch.c:679
#define PATHCCH_ENSURE_TRAILING_SLASH
Definition: pathcch.h:45
#define PATHCCH_FORCE_ENABLE_LONG_NAME_PROCESS
Definition: pathcch.h:41
#define PATHCCH_ALLOW_LONG_PATHS
Definition: pathcch.h:40
#define PATHCCH_ENSURE_IS_EXTENDED_LENGTH_PATH
Definition: pathcch.h:44
#define PATHCCH_NONE
Definition: pathcch.h:39
#define PATHCCH_MAX_CCH
Definition: pathcch.h:51
#define PATHCCH_DO_NOT_NORMALIZE_SEGMENTS
Definition: pathcch.h:43
#define PATHCCH_FORCE_DISABLE_LONG_NAME_PROCESS
Definition: pathcch.h:42
static unsigned __int64 next
Definition: rand_nt.c:6
static FILE * out
Definition: regtests2xml.c:44
const WCHAR * str
_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)
HRESULT hr
Definition: shlfolder.c:183
#define TRACE(s)
Definition: solgame.cpp:4
STRSAFEAPI StringCchLengthW(STRSAFE_LPCWSTR psz, size_t cchMax, size_t *pcchLength)
Definition: strsafe.h:842
#define STRSAFE_E_INSUFFICIENT_BUFFER
Definition: strsafe.h:103
static void buffer_size(GLcontext *ctx, GLuint *width, GLuint *height)
Definition: swimpl.c:888
uint16_t * PWSTR
Definition: typedefs.h:56
const uint16_t * PCWSTR
Definition: typedefs.h:57
ULONG_PTR SIZE_T
Definition: typedefs.h:80
int32_t INT
Definition: typedefs.h:58
uint32_t ULONG
Definition: typedefs.h:59
static rfbScreenInfoPtr server
Definition: vnc.c:74
#define LMEM_ZEROINIT
Definition: winbase.h:375
#define WINAPI
Definition: msvc.h:6
#define S_FALSE
Definition: winerror.h:2357
#define ERROR_FILENAME_EXCED_RANGE
Definition: winerror.h:263
#define HRESULT_FROM_WIN32(x)
Definition: winerror.h:92
__wchar_t WCHAR
Definition: xmlstorage.h:180