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