xref: /trunk/main/tools/source/misc/pathutils.cxx (revision 89b56da7)
1*89b56da7SAndrew Rist /**************************************************************
2cdf0e10cSrcweir  *
3*89b56da7SAndrew Rist  * Licensed to the Apache Software Foundation (ASF) under one
4*89b56da7SAndrew Rist  * or more contributor license agreements.  See the NOTICE file
5*89b56da7SAndrew Rist  * distributed with this work for additional information
6*89b56da7SAndrew Rist  * regarding copyright ownership.  The ASF licenses this file
7*89b56da7SAndrew Rist  * to you under the Apache License, Version 2.0 (the
8*89b56da7SAndrew Rist  * "License"); you may not use this file except in compliance
9*89b56da7SAndrew Rist  * with the License.  You may obtain a copy of the License at
10*89b56da7SAndrew Rist  *
11*89b56da7SAndrew Rist  *   http://www.apache.org/licenses/LICENSE-2.0
12*89b56da7SAndrew Rist  *
13*89b56da7SAndrew Rist  * Unless required by applicable law or agreed to in writing,
14*89b56da7SAndrew Rist  * software distributed under the License is distributed on an
15*89b56da7SAndrew Rist  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16*89b56da7SAndrew Rist  * KIND, either express or implied.  See the License for the
17*89b56da7SAndrew Rist  * specific language governing permissions and limitations
18*89b56da7SAndrew Rist  * under the License.
19*89b56da7SAndrew Rist  *
20*89b56da7SAndrew Rist  *************************************************************/
21*89b56da7SAndrew Rist 
22*89b56da7SAndrew Rist 
23cdf0e10cSrcweir 
24cdf0e10cSrcweir #include "sal/config.h"
25cdf0e10cSrcweir 
26cdf0e10cSrcweir #if defined WNT
27cdf0e10cSrcweir 
28cdf0e10cSrcweir #include <cstddef>
29cdf0e10cSrcweir 
30cdf0e10cSrcweir #define WIN32_LEAN_AND_MEAN
31cdf0e10cSrcweir #include <windows.h>
32cdf0e10cSrcweir 
33cdf0e10cSrcweir #include "sal/types.h"
34cdf0e10cSrcweir #include "tools/pathutils.hxx"
35cdf0e10cSrcweir 
36cdf0e10cSrcweir namespace tools {
37cdf0e10cSrcweir 
filename(WCHAR * path)38cdf0e10cSrcweir WCHAR * filename(WCHAR * path) {
39cdf0e10cSrcweir     WCHAR * f = path;
40cdf0e10cSrcweir     for (WCHAR * p = path;;) {
41cdf0e10cSrcweir         switch (*p++) {
42cdf0e10cSrcweir         case L'\0':
43cdf0e10cSrcweir             return f;
44cdf0e10cSrcweir         case L'\\':
45cdf0e10cSrcweir             f = p;
46cdf0e10cSrcweir             break;
47cdf0e10cSrcweir         }
48cdf0e10cSrcweir     }
49cdf0e10cSrcweir }
50cdf0e10cSrcweir 
buildPath(WCHAR * path,WCHAR const * frontBegin,WCHAR const * frontEnd,WCHAR const * backBegin,std::size_t backLength)51cdf0e10cSrcweir WCHAR * buildPath(
52cdf0e10cSrcweir     WCHAR * path, WCHAR const * frontBegin, WCHAR const * frontEnd,
53cdf0e10cSrcweir     WCHAR const * backBegin, std::size_t backLength)
54cdf0e10cSrcweir {
55cdf0e10cSrcweir     // Remove leading ".." segments in the second path together with matching
56cdf0e10cSrcweir     // segments in the first path that are neither empty nor "." nor ".." nor
57cdf0e10cSrcweir     // end in ":" (which is not foolprove, as it can erroneously erase the start
58cdf0e10cSrcweir     // of a UNC path, but only if the input is bad data):
59cdf0e10cSrcweir     while (backLength >= 2 && backBegin[0] == L'.' && backBegin[1] == L'.' &&
60cdf0e10cSrcweir            (backLength == 2 || backBegin[2] == L'\\'))
61cdf0e10cSrcweir     {
62cdf0e10cSrcweir         if (frontEnd - frontBegin < 2 || frontEnd[-1] != L'\\' ||
63cdf0e10cSrcweir             frontEnd[-2] == L'\\' || frontEnd[-2] == L':' ||
64cdf0e10cSrcweir             (frontEnd[-2] == L'.' &&
65cdf0e10cSrcweir              (frontEnd - frontBegin < 3 || frontEnd[-3] == L'\\' ||
66cdf0e10cSrcweir               (frontEnd[-3] == L'.' &&
67cdf0e10cSrcweir                (frontEnd - frontBegin < 4 || frontEnd[-4] == L'\\')))))
68cdf0e10cSrcweir         {
69cdf0e10cSrcweir             break;
70cdf0e10cSrcweir         }
71cdf0e10cSrcweir         WCHAR const * p = frontEnd - 1;
72cdf0e10cSrcweir         while (p != frontBegin && p[-1] != L'\\') {
73cdf0e10cSrcweir             --p;
74cdf0e10cSrcweir         }
75cdf0e10cSrcweir         if (p == frontBegin) {
76cdf0e10cSrcweir             break;
77cdf0e10cSrcweir         }
78cdf0e10cSrcweir         frontEnd = p;
79cdf0e10cSrcweir         if (backLength == 2) {
80cdf0e10cSrcweir             backBegin += 2;
81cdf0e10cSrcweir             backLength -= 2;
82cdf0e10cSrcweir         } else {
83cdf0e10cSrcweir             backBegin += 3;
84cdf0e10cSrcweir             backLength -= 3;
85cdf0e10cSrcweir         }
86cdf0e10cSrcweir     }
87cdf0e10cSrcweir     if (backLength <
88cdf0e10cSrcweir         static_cast< std::size_t >(MAX_PATH - (frontEnd - frontBegin)))
89cdf0e10cSrcweir         // hopefully std::size_t is large enough
90cdf0e10cSrcweir     {
91cdf0e10cSrcweir         WCHAR * p;
92cdf0e10cSrcweir         if (frontBegin == path) {
93cdf0e10cSrcweir             p = const_cast< WCHAR * >(frontEnd);
94cdf0e10cSrcweir         } else {
95cdf0e10cSrcweir             p = path;
96cdf0e10cSrcweir             while (frontBegin != frontEnd) {
97cdf0e10cSrcweir                 *p++ = *frontBegin++;
98cdf0e10cSrcweir             }
99cdf0e10cSrcweir         }
100cdf0e10cSrcweir         for (; backLength > 0; --backLength) {
101cdf0e10cSrcweir             *p++ = *backBegin++;
102cdf0e10cSrcweir         }
103cdf0e10cSrcweir         *p = L'\0';
104cdf0e10cSrcweir         return p;
105cdf0e10cSrcweir     } else {
106cdf0e10cSrcweir         SetLastError(ERROR_FILENAME_EXCED_RANGE);
107cdf0e10cSrcweir         return NULL;
108cdf0e10cSrcweir     }
109cdf0e10cSrcweir }
110cdf0e10cSrcweir 
resolveLink(WCHAR * path)111cdf0e10cSrcweir WCHAR * resolveLink(WCHAR * path) {
112cdf0e10cSrcweir     HANDLE h = CreateFileW(
113cdf0e10cSrcweir         path, FILE_READ_DATA, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
114cdf0e10cSrcweir     if (h == INVALID_HANDLE_VALUE) {
115cdf0e10cSrcweir         return NULL;
116cdf0e10cSrcweir     }
117cdf0e10cSrcweir     char p1[MAX_PATH];
118cdf0e10cSrcweir     DWORD n;
119cdf0e10cSrcweir     BOOL ok = ReadFile(h, p1, MAX_PATH, &n, NULL);
120cdf0e10cSrcweir     CloseHandle(h);
121cdf0e10cSrcweir     if (!ok) {
122cdf0e10cSrcweir         return NULL;
123cdf0e10cSrcweir     }
124cdf0e10cSrcweir     WCHAR p2[MAX_PATH];
125cdf0e10cSrcweir     std::size_t n2 = 0;
126cdf0e10cSrcweir     bool colon = false;
127cdf0e10cSrcweir     for (DWORD i = 0; i < n;) {
128cdf0e10cSrcweir         unsigned char c = static_cast< unsigned char >(p1[i++]);
129cdf0e10cSrcweir         switch (c) {
130cdf0e10cSrcweir         case '\0':
131cdf0e10cSrcweir             SetLastError(ERROR_BAD_PATHNAME);
132cdf0e10cSrcweir             return NULL;
133cdf0e10cSrcweir         case '\x0A':
134cdf0e10cSrcweir         case '\x0D':
135cdf0e10cSrcweir             if (n2 == MAX_PATH) {
136cdf0e10cSrcweir                 SetLastError(ERROR_FILENAME_EXCED_RANGE);
137cdf0e10cSrcweir                 return NULL;
138cdf0e10cSrcweir             }
139cdf0e10cSrcweir             p2[n2] = L'\0';
140cdf0e10cSrcweir             break;
141cdf0e10cSrcweir         case ':':
142cdf0e10cSrcweir             colon = true;
143cdf0e10cSrcweir             // fall through
144cdf0e10cSrcweir         default:
145cdf0e10cSrcweir             // Convert from UTF-8 to UTF-16:
146cdf0e10cSrcweir             if (c <= 0x7F) {
147cdf0e10cSrcweir                 p2[n2++] = c;
148cdf0e10cSrcweir             } else if (c >= 0xC2 && c <= 0xDF && i < n &&
149cdf0e10cSrcweir                        static_cast< unsigned char >(p1[i]) >= 0x80 &&
150cdf0e10cSrcweir                        static_cast< unsigned char >(p1[i]) <= 0xBF)
151cdf0e10cSrcweir             {
152cdf0e10cSrcweir                 p2[n2++] = ((c & 0x1F) << 6) |
153cdf0e10cSrcweir                     (static_cast< unsigned char >(p1[i++]) & 0x3F);
154cdf0e10cSrcweir             } else if (n - i > 1 &&
155cdf0e10cSrcweir                        ((c == 0xE0 &&
156cdf0e10cSrcweir                          static_cast< unsigned char >(p1[i]) >= 0xA0 &&
157cdf0e10cSrcweir                          static_cast< unsigned char >(p1[i]) <= 0xBF) ||
158cdf0e10cSrcweir                         ((c >= 0xE1 && c <= 0xEC || c >= 0xEE && c <= 0xEF) &&
159cdf0e10cSrcweir                          static_cast< unsigned char >(p1[i]) >= 0x80 &&
160cdf0e10cSrcweir                          static_cast< unsigned char >(p1[i]) <= 0xBF) ||
161cdf0e10cSrcweir                         (c == 0xED &&
162cdf0e10cSrcweir                          static_cast< unsigned char >(p1[i]) >= 0x80 &&
163cdf0e10cSrcweir                          static_cast< unsigned char >(p1[i]) <= 0x9F)) &&
164cdf0e10cSrcweir                        static_cast< unsigned char >(p1[i + 1]) >= 0x80 &&
165cdf0e10cSrcweir                        static_cast< unsigned char >(p1[i + 1]) <= 0xBF)
166cdf0e10cSrcweir             {
167cdf0e10cSrcweir                 p2[n2++] = ((c & 0x0F) << 12) |
168cdf0e10cSrcweir                     ((static_cast< unsigned char >(p1[i]) & 0x3F) << 6) |
169cdf0e10cSrcweir                     (static_cast< unsigned char >(p1[i + 1]) & 0x3F);
170cdf0e10cSrcweir                 i += 2;
171cdf0e10cSrcweir             } else if (n - 2 > 1 &&
172cdf0e10cSrcweir                        ((c == 0xF0 &&
173cdf0e10cSrcweir                          static_cast< unsigned char >(p1[i]) >= 0x90 &&
174cdf0e10cSrcweir                          static_cast< unsigned char >(p1[i]) <= 0xBF) ||
175cdf0e10cSrcweir                         (c >= 0xF1 && c <= 0xF3 &&
176cdf0e10cSrcweir                          static_cast< unsigned char >(p1[i]) >= 0x80 &&
177cdf0e10cSrcweir                          static_cast< unsigned char >(p1[i]) <= 0xBF) ||
178cdf0e10cSrcweir                         (c == 0xF4 &&
179cdf0e10cSrcweir                          static_cast< unsigned char >(p1[i]) >= 0x80 &&
180cdf0e10cSrcweir                          static_cast< unsigned char >(p1[i]) <= 0x8F)) &&
181cdf0e10cSrcweir                        static_cast< unsigned char >(p1[i + 1]) >= 0x80 &&
182cdf0e10cSrcweir                        static_cast< unsigned char >(p1[i + 1]) <= 0xBF &&
183cdf0e10cSrcweir                        static_cast< unsigned char >(p1[i + 2]) >= 0x80 &&
184cdf0e10cSrcweir                        static_cast< unsigned char >(p1[i + 2]) <= 0xBF)
185cdf0e10cSrcweir             {
186cdf0e10cSrcweir                 sal_Int32 u = ((c & 0x07) << 18) |
187cdf0e10cSrcweir                     ((static_cast< unsigned char >(p1[i]) & 0x3F) << 12) |
188cdf0e10cSrcweir                     ((static_cast< unsigned char >(p1[i + 1]) & 0x3F) << 6) |
189cdf0e10cSrcweir                     (static_cast< unsigned char >(p1[i + 2]) & 0x3F);
190cdf0e10cSrcweir                 i += 3;
191cdf0e10cSrcweir                 p2[n2++] = static_cast< WCHAR >(((u - 0x10000) >> 10) | 0xD800);
192cdf0e10cSrcweir                 p2[n2++] = static_cast< WCHAR >(
193cdf0e10cSrcweir                     ((u - 0x10000) & 0x3FF) | 0xDC00);
194cdf0e10cSrcweir             } else {
195cdf0e10cSrcweir                 SetLastError(ERROR_BAD_PATHNAME);
196cdf0e10cSrcweir                 return NULL;
197cdf0e10cSrcweir             }
198cdf0e10cSrcweir             break;
199cdf0e10cSrcweir         }
200cdf0e10cSrcweir     }
201cdf0e10cSrcweir     WCHAR * end;
202cdf0e10cSrcweir     if (colon || p2[0] == L'\\') {
203cdf0e10cSrcweir         // Interpret p2 as an absolute path:
204cdf0e10cSrcweir         end = path;
205cdf0e10cSrcweir     } else {
206cdf0e10cSrcweir         // Interpret p2 as a relative path:
207cdf0e10cSrcweir         end = filename(path);
208cdf0e10cSrcweir     }
209cdf0e10cSrcweir     return buildPath(path, path, end, p2, n2);
210cdf0e10cSrcweir }
211cdf0e10cSrcweir 
212cdf0e10cSrcweir }
213cdf0e10cSrcweir 
214cdf0e10cSrcweir #endif
215