| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| #include "sal/config.h" |
| |
| #if defined WNT |
| |
| #include <cstddef> |
| |
| #define WIN32_LEAN_AND_MEAN |
| #include <windows.h> |
| |
| #include "sal/types.h" |
| //#include "tools/pathutils.hxx" |
| |
| namespace cli_ure { |
| |
| WCHAR * filename(WCHAR * path) { |
| WCHAR * f = path; |
| for (WCHAR * p = path;;) { |
| switch (*p++) { |
| case L'\0': |
| return f; |
| case L'\\': |
| f = p; |
| break; |
| } |
| } |
| } |
| |
| WCHAR * buildPath( |
| WCHAR * path, WCHAR const * frontBegin, WCHAR const * frontEnd, |
| WCHAR const * backBegin, std::size_t backLength) |
| { |
| // Remove leading ".." segments in the second path together with matching |
| // segments in the first path that are neither empty nor "." nor ".." nor |
| // end in ":" (which is not foolprove, as it can erroneously erase the start |
| // of a UNC path, but only if the input is bad data): |
| while (backLength >= 2 && backBegin[0] == L'.' && backBegin[1] == L'.' && |
| (backLength == 2 || backBegin[2] == L'\\')) |
| { |
| if (frontEnd - frontBegin < 2 || frontEnd[-1] != L'\\' || |
| frontEnd[-2] == L'\\' || frontEnd[-2] == L':' || |
| (frontEnd[-2] == L'.' && |
| (frontEnd - frontBegin < 3 || frontEnd[-3] == L'\\' || |
| (frontEnd[-3] == L'.' && |
| (frontEnd - frontBegin < 4 || frontEnd[-4] == L'\\'))))) |
| { |
| break; |
| } |
| WCHAR const * p = frontEnd - 1; |
| while (p != frontBegin && p[-1] != L'\\') { |
| --p; |
| } |
| if (p == frontBegin) { |
| break; |
| } |
| frontEnd = p; |
| if (backLength == 2) { |
| backBegin += 2; |
| backLength -= 2; |
| } else { |
| backBegin += 3; |
| backLength -= 3; |
| } |
| } |
| if (backLength < |
| static_cast< std::size_t >(MAX_PATH - (frontEnd - frontBegin))) |
| // hopefully std::size_t is large enough |
| { |
| WCHAR * p; |
| if (frontBegin == path) { |
| p = const_cast< WCHAR * >(frontEnd); |
| } else { |
| p = path; |
| while (frontBegin != frontEnd) { |
| *p++ = *frontBegin++; |
| } |
| } |
| for (; backLength > 0; --backLength) { |
| *p++ = *backBegin++; |
| } |
| *p = L'\0'; |
| return p; |
| } else { |
| SetLastError(ERROR_FILENAME_EXCED_RANGE); |
| return NULL; |
| } |
| } |
| |
| WCHAR * resolveLink(WCHAR * path) { |
| HANDLE h = CreateFileW( |
| path, FILE_READ_DATA, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); |
| if (h == INVALID_HANDLE_VALUE) { |
| return NULL; |
| } |
| char p1[MAX_PATH]; |
| DWORD n; |
| BOOL ok = ReadFile(h, p1, MAX_PATH, &n, NULL); |
| CloseHandle(h); |
| if (!ok) { |
| return NULL; |
| } |
| WCHAR p2[MAX_PATH]; |
| std::size_t n2 = 0; |
| bool colon = false; |
| for (DWORD i = 0; i < n;) { |
| unsigned char c = static_cast< unsigned char >(p1[i++]); |
| switch (c) { |
| case '\0': |
| SetLastError(ERROR_BAD_PATHNAME); |
| return NULL; |
| case '\x0A': |
| case '\x0D': |
| if (n2 == MAX_PATH) { |
| SetLastError(ERROR_FILENAME_EXCED_RANGE); |
| return NULL; |
| } |
| p2[n2] = L'\0'; |
| break; |
| case ':': |
| colon = true; |
| // fall through |
| default: |
| // Convert from UTF-8 to UTF-16: |
| if (c <= 0x7F) { |
| p2[n2++] = c; |
| } else if (c >= 0xC2 && c <= 0xDF && i < n && |
| static_cast< unsigned char >(p1[i]) >= 0x80 && |
| static_cast< unsigned char >(p1[i]) <= 0xBF) |
| { |
| p2[n2++] = ((c & 0x1F) << 6) | |
| (static_cast< unsigned char >(p1[i++]) & 0x3F); |
| } else if (n - i > 1 && |
| ((c == 0xE0 && |
| static_cast< unsigned char >(p1[i]) >= 0xA0 && |
| static_cast< unsigned char >(p1[i]) <= 0xBF) || |
| ((c >= 0xE1 && c <= 0xEC || c >= 0xEE && c <= 0xEF) && |
| static_cast< unsigned char >(p1[i]) >= 0x80 && |
| static_cast< unsigned char >(p1[i]) <= 0xBF) || |
| (c == 0xED && |
| static_cast< unsigned char >(p1[i]) >= 0x80 && |
| static_cast< unsigned char >(p1[i]) <= 0x9F)) && |
| static_cast< unsigned char >(p1[i + 1]) >= 0x80 && |
| static_cast< unsigned char >(p1[i + 1]) <= 0xBF) |
| { |
| p2[n2++] = ((c & 0x0F) << 12) | |
| ((static_cast< unsigned char >(p1[i]) & 0x3F) << 6) | |
| (static_cast< unsigned char >(p1[i + 1]) & 0x3F); |
| i += 2; |
| } else if (n - 2 > 1 && |
| ((c == 0xF0 && |
| static_cast< unsigned char >(p1[i]) >= 0x90 && |
| static_cast< unsigned char >(p1[i]) <= 0xBF) || |
| (c >= 0xF1 && c <= 0xF3 && |
| static_cast< unsigned char >(p1[i]) >= 0x80 && |
| static_cast< unsigned char >(p1[i]) <= 0xBF) || |
| (c == 0xF4 && |
| static_cast< unsigned char >(p1[i]) >= 0x80 && |
| static_cast< unsigned char >(p1[i]) <= 0x8F)) && |
| static_cast< unsigned char >(p1[i + 1]) >= 0x80 && |
| static_cast< unsigned char >(p1[i + 1]) <= 0xBF && |
| static_cast< unsigned char >(p1[i + 2]) >= 0x80 && |
| static_cast< unsigned char >(p1[i + 2]) <= 0xBF) |
| { |
| sal_Int32 u = ((c & 0x07) << 18) | |
| ((static_cast< unsigned char >(p1[i]) & 0x3F) << 12) | |
| ((static_cast< unsigned char >(p1[i + 1]) & 0x3F) << 6) | |
| (static_cast< unsigned char >(p1[i + 2]) & 0x3F); |
| i += 3; |
| p2[n2++] = static_cast< WCHAR >(((u - 0x10000) >> 10) | 0xD800); |
| p2[n2++] = static_cast< WCHAR >( |
| ((u - 0x10000) & 0x3FF) | 0xDC00); |
| } else { |
| SetLastError(ERROR_BAD_PATHNAME); |
| return NULL; |
| } |
| break; |
| } |
| } |
| WCHAR * end; |
| if (colon || p2[0] == L'\\') { |
| // Interpret p2 as an absolute path: |
| end = path; |
| } else { |
| // Interpret p2 as a relative path: |
| end = filename(path); |
| } |
| return buildPath(path, path, end, p2, n2); |
| } |
| |
| } |
| |
| #endif |