1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20 #include <sal/config.h>
21
22 #include <cassert>
23
24 #include "file_path_helper.hxx"
25 #include "uunxapi.hxx"
26
27 #include <osl/diagnose.h>
28 #include <rtl/ustring.hxx>
29 #include <sal/log.hxx>
30
31 const sal_Unicode FPH_CHAR_PATH_SEPARATOR = '/';
32 const sal_Unicode FPH_CHAR_DOT = '.';
33 const sal_Unicode FPH_CHAR_COLON = ':';
34
osl_systemPathRemoveSeparator(rtl_String * pstrPath)35 void osl_systemPathRemoveSeparator(rtl_String* pstrPath)
36 {
37 OSL_PRECOND(nullptr != pstrPath, "osl_systemPathRemoveSeparator: Invalid parameter");
38 if (pstrPath == nullptr)
39 return;
40
41 // maybe there are more than one separator at end
42 // so we run in a loop
43 while ((pstrPath->length > 1) && (pstrPath->buffer[pstrPath->length - 1] == FPH_CHAR_PATH_SEPARATOR))
44 {
45 pstrPath->length--;
46 pstrPath->buffer[pstrPath->length] = '\0';
47 }
48
49 SAL_WARN_IF( !((0 == pstrPath->length) || (1 == pstrPath->length) ||
50 (pstrPath->length > 1 && pstrPath->buffer[pstrPath->length - 1] != FPH_CHAR_PATH_SEPARATOR)),
51 "sal.osl",
52 "osl_systemPathRemoveSeparator: Post condition failed");
53 }
54
55 namespace {
56
systemPathEnsureSeparator(T * ppstrPath)57 template<typename T> void systemPathEnsureSeparator(T* ppstrPath)
58 {
59 assert(nullptr != ppstrPath);
60 sal_Int32 lp = ppstrPath->getLength();
61 sal_Int32 i = ppstrPath->lastIndexOf(FPH_CHAR_PATH_SEPARATOR);
62
63 if ((lp > 1 && i != (lp - 1)) || ((lp < 2) && i < 0))
64 {
65 *ppstrPath += "/";
66 }
67
68 SAL_WARN_IF( !ppstrPath->endsWith("/"),
69 "sal.osl",
70 "systemPathEnsureSeparator: Post condition failed");
71 }
72
73 }
74
osl_systemPathIsRelativePath(const rtl_uString * pustrPath)75 bool osl_systemPathIsRelativePath(const rtl_uString* pustrPath)
76 {
77 OSL_PRECOND(nullptr != pustrPath, "osl_systemPathIsRelativePath: Invalid parameter");
78 return ((pustrPath == nullptr) || (pustrPath->length == 0) || (pustrPath->buffer[0] != FPH_CHAR_PATH_SEPARATOR));
79 }
80
81 namespace {
82
systemPathMakeAbsolutePath_(const T & BasePath,const T & RelPath)83 template<typename T> T systemPathMakeAbsolutePath_(
84 const T& BasePath,
85 const T& RelPath)
86 {
87 T base(BasePath);
88
89 if (!base.isEmpty())
90 systemPathEnsureSeparator(&base);
91
92 return base + RelPath;
93 }
94
95 }
96
systemPathMakeAbsolutePath(const OString & BasePath,const OString & RelPath)97 OString osl::systemPathMakeAbsolutePath(
98 const OString& BasePath,
99 const OString& RelPath)
100 {
101 return systemPathMakeAbsolutePath_(BasePath, RelPath);
102 }
103
systemPathMakeAbsolutePath(const OUString & BasePath,const OUString & RelPath)104 OUString osl::systemPathMakeAbsolutePath(
105 const OUString& BasePath,
106 const OUString& RelPath)
107 {
108 return systemPathMakeAbsolutePath_(BasePath, RelPath);
109 }
110
osl_systemPathGetFileNameOrLastDirectoryPart(const rtl_String * pstrPath,rtl_String ** ppstrFileNameOrLastDirPart)111 void osl_systemPathGetFileNameOrLastDirectoryPart(
112 const rtl_String* pstrPath,
113 rtl_String** ppstrFileNameOrLastDirPart)
114 {
115 OSL_PRECOND(pstrPath && ppstrFileNameOrLastDirPart,
116 "osl_systemPathGetFileNameOrLastDirectoryPart: Invalid parameter");
117
118 OString path(const_cast<rtl_String*>(pstrPath));
119
120 osl_systemPathRemoveSeparator(path.pData);
121
122 OString last_part;
123
124 if (path.getLength() > 1 || (path.getLength() == 1 && path[0] != FPH_CHAR_PATH_SEPARATOR))
125 {
126 sal_Int32 idx_ps = path.lastIndexOf(FPH_CHAR_PATH_SEPARATOR);
127 idx_ps++; // always right to increment by one even if idx_ps == -1!
128 last_part = path.copy(idx_ps);
129 }
130 rtl_string_assign(ppstrFileNameOrLastDirPart, last_part.pData);
131 }
132
osl_systemPathIsHiddenFileOrDirectoryEntry(const rtl_String * pstrPath)133 bool osl_systemPathIsHiddenFileOrDirectoryEntry(
134 const rtl_String* pstrPath)
135 {
136 OSL_PRECOND(nullptr != pstrPath, "osl_systemPathIsHiddenFileOrDirectoryEntry: Invalid parameter");
137 if ((pstrPath == nullptr) || (pstrPath->length == 0))
138 return false;
139
140 OString fdp;
141 osl_systemPathGetFileNameOrLastDirectoryPart(pstrPath, &fdp.pData);
142
143 return ((fdp.pData->length > 0) &&
144 (fdp.pData->buffer[0] == FPH_CHAR_DOT) &&
145 !osl_systemPathIsLocalOrParentDirectoryEntry(fdp.pData));
146 }
147
osl_systemPathIsLocalOrParentDirectoryEntry(const rtl_String * pstrPath)148 bool osl_systemPathIsLocalOrParentDirectoryEntry(
149 const rtl_String* pstrPath)
150 {
151 OSL_PRECOND(pstrPath, "osl_systemPathIsLocalOrParentDirectoryEntry: Invalid parameter");
152
153 OString dirent;
154
155 osl_systemPathGetFileNameOrLastDirectoryPart(pstrPath, &dirent.pData);
156
157 return (dirent == "." ||
158 dirent == "..");
159 }
160
161 namespace {
162
163 /** Simple iterator for a path list separated by the specified character
164 */
165 class path_list_iterator
166 {
167 public:
168
169 /* after construction get_current_item
170 returns the first path in list, no need
171 to call reset first
172 */
path_list_iterator(const OUString & path_list,sal_Unicode list_separator=FPH_CHAR_COLON)173 path_list_iterator(const OUString& path_list, sal_Unicode list_separator = FPH_CHAR_COLON) :
174 m_path_list(path_list),
175 m_end(m_path_list.getStr() + m_path_list.getLength() + 1),
176 m_separator(list_separator)
177 {
178 reset();
179 }
180
181 path_list_iterator(const path_list_iterator&) = delete;
182 path_list_iterator& operator=(const path_list_iterator&) = delete;
183
reset()184 void reset()
185 {
186 m_path_segment_begin = m_path_segment_end = m_path_list.getStr();
187 advance();
188 }
189
next()190 void next()
191 {
192 OSL_PRECOND(!done(), "path_list_iterator: Already done!");
193
194 m_path_segment_begin = ++m_path_segment_end;
195 advance();
196 }
197
done() const198 bool done() const
199 {
200 return (m_path_segment_end >= m_end);
201 }
202
get_current_item() const203 OUString get_current_item() const
204 {
205 return OUString(
206 m_path_segment_begin,
207 (m_path_segment_end - m_path_segment_begin));
208 }
209
210 private:
211 /* move m_path_end to the next separator or
212 to the end of the string
213 */
advance()214 void advance()
215 {
216 while (!done() && *m_path_segment_end && (*m_path_segment_end != m_separator))
217 ++m_path_segment_end;
218
219 OSL_ASSERT(m_path_segment_end <= m_end);
220 }
221
222 private:
223 OUString m_path_list;
224 const sal_Unicode* m_end;
225 const sal_Unicode m_separator;
226 const sal_Unicode* m_path_segment_begin;
227 const sal_Unicode* m_path_segment_end;
228 };
229
230 }
231
osl_searchPath(const rtl_uString * pustrFilePath,const rtl_uString * pustrSearchPathList,rtl_uString ** ppustrPathFound)232 bool osl_searchPath(
233 const rtl_uString* pustrFilePath,
234 const rtl_uString* pustrSearchPathList,
235 rtl_uString** ppustrPathFound)
236 {
237 OSL_PRECOND(pustrFilePath && pustrSearchPathList && ppustrPathFound, "osl_searchPath: Invalid parameter");
238
239 bool bfound = false;
240 OUString fp(const_cast<rtl_uString*>(pustrFilePath));
241 OUString pl(const_cast<rtl_uString*>(pustrSearchPathList));
242 path_list_iterator pli(pl);
243
244 while (!pli.done())
245 {
246 OUString p = pli.get_current_item();
247 systemPathEnsureSeparator(&p);
248 p += fp;
249
250 if (osl::access(osl::OUStringToOString(p), F_OK) > -1)
251 {
252 bfound = true;
253 rtl_uString_assign(ppustrPathFound, p.pData);
254 break;
255 }
256 pli.next();
257 }
258 return bfound;
259 }
260
261 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
262