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 10cdf0e10cSrcweir * 11*89b56da7SAndrew Rist * http://www.apache.org/licenses/LICENSE-2.0 12cdf0e10cSrcweir * 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. 19cdf0e10cSrcweir * 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 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 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 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