xref: /trunk/main/cli_ure/source/native/path.cxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 #include "sal/config.h"
29 
30 #if defined WNT
31 
32 #include <cstddef>
33 
34 #define WIN32_LEAN_AND_MEAN
35 #include <windows.h>
36 
37 #include "sal/types.h"
38 //#include "tools/pathutils.hxx"
39 
40 namespace cli_ure {
41 
42 WCHAR * filename(WCHAR * path) {
43     WCHAR * f = path;
44     for (WCHAR * p = path;;) {
45         switch (*p++) {
46         case L'\0':
47             return f;
48         case L'\\':
49             f = p;
50             break;
51         }
52     }
53 }
54 
55 WCHAR * buildPath(
56     WCHAR * path, WCHAR const * frontBegin, WCHAR const * frontEnd,
57     WCHAR const * backBegin, std::size_t backLength)
58 {
59     // Remove leading ".." segments in the second path together with matching
60     // segments in the first path that are neither empty nor "." nor ".." nor
61     // end in ":" (which is not foolprove, as it can erroneously erase the start
62     // of a UNC path, but only if the input is bad data):
63     while (backLength >= 2 && backBegin[0] == L'.' && backBegin[1] == L'.' &&
64            (backLength == 2 || backBegin[2] == L'\\'))
65     {
66         if (frontEnd - frontBegin < 2 || frontEnd[-1] != L'\\' ||
67             frontEnd[-2] == L'\\' || frontEnd[-2] == L':' ||
68             (frontEnd[-2] == L'.' &&
69              (frontEnd - frontBegin < 3 || frontEnd[-3] == L'\\' ||
70               (frontEnd[-3] == L'.' &&
71                (frontEnd - frontBegin < 4 || frontEnd[-4] == L'\\')))))
72         {
73             break;
74         }
75         WCHAR const * p = frontEnd - 1;
76         while (p != frontBegin && p[-1] != L'\\') {
77             --p;
78         }
79         if (p == frontBegin) {
80             break;
81         }
82         frontEnd = p;
83         if (backLength == 2) {
84             backBegin += 2;
85             backLength -= 2;
86         } else {
87             backBegin += 3;
88             backLength -= 3;
89         }
90     }
91     if (backLength <
92         static_cast< std::size_t >(MAX_PATH - (frontEnd - frontBegin)))
93         // hopefully std::size_t is large enough
94     {
95         WCHAR * p;
96         if (frontBegin == path) {
97             p = const_cast< WCHAR * >(frontEnd);
98         } else {
99             p = path;
100             while (frontBegin != frontEnd) {
101                 *p++ = *frontBegin++;
102             }
103         }
104         for (; backLength > 0; --backLength) {
105             *p++ = *backBegin++;
106         }
107         *p = L'\0';
108         return p;
109     } else {
110         SetLastError(ERROR_FILENAME_EXCED_RANGE);
111         return NULL;
112     }
113 }
114 
115 WCHAR * resolveLink(WCHAR * path) {
116     HANDLE h = CreateFileW(
117         path, FILE_READ_DATA, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
118     if (h == INVALID_HANDLE_VALUE) {
119         return NULL;
120     }
121     char p1[MAX_PATH];
122     DWORD n;
123     BOOL ok = ReadFile(h, p1, MAX_PATH, &n, NULL);
124     CloseHandle(h);
125     if (!ok) {
126         return NULL;
127     }
128     WCHAR p2[MAX_PATH];
129     std::size_t n2 = 0;
130     bool colon = false;
131     for (DWORD i = 0; i < n;) {
132         unsigned char c = static_cast< unsigned char >(p1[i++]);
133         switch (c) {
134         case '\0':
135             SetLastError(ERROR_BAD_PATHNAME);
136             return NULL;
137         case '\x0A':
138         case '\x0D':
139             if (n2 == MAX_PATH) {
140                 SetLastError(ERROR_FILENAME_EXCED_RANGE);
141                 return NULL;
142             }
143             p2[n2] = L'\0';
144             break;
145         case ':':
146             colon = true;
147             // fall through
148         default:
149             // Convert from UTF-8 to UTF-16:
150             if (c <= 0x7F) {
151                 p2[n2++] = c;
152             } else if (c >= 0xC2 && c <= 0xDF && i < n &&
153                        static_cast< unsigned char >(p1[i]) >= 0x80 &&
154                        static_cast< unsigned char >(p1[i]) <= 0xBF)
155             {
156                 p2[n2++] = ((c & 0x1F) << 6) |
157                     (static_cast< unsigned char >(p1[i++]) & 0x3F);
158             } else if (n - i > 1 &&
159                        ((c == 0xE0 &&
160                          static_cast< unsigned char >(p1[i]) >= 0xA0 &&
161                          static_cast< unsigned char >(p1[i]) <= 0xBF) ||
162                         ((c >= 0xE1 && c <= 0xEC || c >= 0xEE && c <= 0xEF) &&
163                          static_cast< unsigned char >(p1[i]) >= 0x80 &&
164                          static_cast< unsigned char >(p1[i]) <= 0xBF) ||
165                         (c == 0xED &&
166                          static_cast< unsigned char >(p1[i]) >= 0x80 &&
167                          static_cast< unsigned char >(p1[i]) <= 0x9F)) &&
168                        static_cast< unsigned char >(p1[i + 1]) >= 0x80 &&
169                        static_cast< unsigned char >(p1[i + 1]) <= 0xBF)
170             {
171                 p2[n2++] = ((c & 0x0F) << 12) |
172                     ((static_cast< unsigned char >(p1[i]) & 0x3F) << 6) |
173                     (static_cast< unsigned char >(p1[i + 1]) & 0x3F);
174                 i += 2;
175             } else if (n - 2 > 1 &&
176                        ((c == 0xF0 &&
177                          static_cast< unsigned char >(p1[i]) >= 0x90 &&
178                          static_cast< unsigned char >(p1[i]) <= 0xBF) ||
179                         (c >= 0xF1 && c <= 0xF3 &&
180                          static_cast< unsigned char >(p1[i]) >= 0x80 &&
181                          static_cast< unsigned char >(p1[i]) <= 0xBF) ||
182                         (c == 0xF4 &&
183                          static_cast< unsigned char >(p1[i]) >= 0x80 &&
184                          static_cast< unsigned char >(p1[i]) <= 0x8F)) &&
185                        static_cast< unsigned char >(p1[i + 1]) >= 0x80 &&
186                        static_cast< unsigned char >(p1[i + 1]) <= 0xBF &&
187                        static_cast< unsigned char >(p1[i + 2]) >= 0x80 &&
188                        static_cast< unsigned char >(p1[i + 2]) <= 0xBF)
189             {
190                 sal_Int32 u = ((c & 0x07) << 18) |
191                     ((static_cast< unsigned char >(p1[i]) & 0x3F) << 12) |
192                     ((static_cast< unsigned char >(p1[i + 1]) & 0x3F) << 6) |
193                     (static_cast< unsigned char >(p1[i + 2]) & 0x3F);
194                 i += 3;
195                 p2[n2++] = static_cast< WCHAR >(((u - 0x10000) >> 10) | 0xD800);
196                 p2[n2++] = static_cast< WCHAR >(
197                     ((u - 0x10000) & 0x3FF) | 0xDC00);
198             } else {
199                 SetLastError(ERROR_BAD_PATHNAME);
200                 return NULL;
201             }
202             break;
203         }
204     }
205     WCHAR * end;
206     if (colon || p2[0] == L'\\') {
207         // Interpret p2 as an absolute path:
208         end = path;
209     } else {
210         // Interpret p2 as a relative path:
211         end = filename(path);
212     }
213     return buildPath(path, path, end, p2, n2);
214 }
215 
216 }
217 
218 #endif
219