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