Avoid potential negative array index access to cached text.
[LibreOffice.git] / sal / osl / unx / file_path_helper.cxx
blob472ab880af93a5279ba26370b41e75fcba5695fb
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <sal/config.h>
22 #include <cassert>
23 #include <utility>
24 #include <unistd.h>
26 #include "file_path_helper.hxx"
27 #include "uunxapi.hxx"
29 #include <osl/diagnose.h>
30 #include <rtl/ustring.hxx>
31 #include <sal/log.hxx>
33 const sal_Unicode FPH_CHAR_PATH_SEPARATOR = '/';
34 const sal_Unicode FPH_CHAR_DOT = '.';
35 const sal_Unicode FPH_CHAR_COLON = ':';
37 void osl_systemPathRemoveSeparator(rtl_String* pstrPath)
39 OSL_PRECOND(nullptr != pstrPath, "osl_systemPathRemoveSeparator: Invalid parameter");
40 if (pstrPath == nullptr)
41 return;
43 // maybe there are more than one separator at end
44 // so we run in a loop
45 while ((pstrPath->length > 1) && (pstrPath->buffer[pstrPath->length - 1] == FPH_CHAR_PATH_SEPARATOR))
47 pstrPath->length--;
48 pstrPath->buffer[pstrPath->length] = '\0';
51 SAL_WARN_IF( !((0 == pstrPath->length) || (1 == pstrPath->length) ||
52 (pstrPath->length > 1 && pstrPath->buffer[pstrPath->length - 1] != FPH_CHAR_PATH_SEPARATOR)),
53 "sal.osl",
54 "osl_systemPathRemoveSeparator: Post condition failed");
57 namespace {
59 template<typename T> void systemPathEnsureSeparator(T* ppstrPath)
61 assert(nullptr != ppstrPath);
62 sal_Int32 lp = ppstrPath->getLength();
63 sal_Int32 i = ppstrPath->lastIndexOf(FPH_CHAR_PATH_SEPARATOR);
65 if ((lp > 1 && i != (lp - 1)) || ((lp < 2) && i < 0))
67 *ppstrPath += "/";
70 SAL_WARN_IF( !ppstrPath->endsWith("/"),
71 "sal.osl",
72 "systemPathEnsureSeparator: Post condition failed");
77 bool osl_systemPathIsRelativePath(const rtl_uString* pustrPath)
79 OSL_PRECOND(nullptr != pustrPath, "osl_systemPathIsRelativePath: Invalid parameter");
80 return ((pustrPath == nullptr) || (pustrPath->length == 0) || (pustrPath->buffer[0] != FPH_CHAR_PATH_SEPARATOR));
83 namespace {
85 template<typename T> T systemPathMakeAbsolutePath_(
86 const T& BasePath,
87 const T& RelPath)
89 T base(BasePath);
91 if (!base.isEmpty())
92 systemPathEnsureSeparator(&base);
94 return base + RelPath;
99 OString osl::systemPathMakeAbsolutePath(
100 const OString& BasePath,
101 const OString& RelPath)
103 return systemPathMakeAbsolutePath_(BasePath, RelPath);
106 OUString osl::systemPathMakeAbsolutePath(
107 const OUString& BasePath,
108 const OUString& RelPath)
110 return systemPathMakeAbsolutePath_(BasePath, RelPath);
113 void osl_systemPathGetFileNameOrLastDirectoryPart(
114 const rtl_String* pstrPath,
115 rtl_String** ppstrFileNameOrLastDirPart)
117 OSL_PRECOND(pstrPath && ppstrFileNameOrLastDirPart,
118 "osl_systemPathGetFileNameOrLastDirectoryPart: Invalid parameter");
120 OString path(const_cast<rtl_String*>(pstrPath));
122 osl_systemPathRemoveSeparator(path.pData);
124 OString last_part;
126 if (path.getLength() > 1 || (path.getLength() == 1 && path[0] != FPH_CHAR_PATH_SEPARATOR))
128 sal_Int32 idx_ps = path.lastIndexOf(FPH_CHAR_PATH_SEPARATOR);
129 idx_ps++; // always right to increment by one even if idx_ps == -1!
130 last_part = path.copy(idx_ps);
132 rtl_string_assign(ppstrFileNameOrLastDirPart, last_part.pData);
135 bool osl_systemPathIsHiddenFileOrDirectoryEntry(
136 const rtl_String* pstrPath)
138 OSL_PRECOND(nullptr != pstrPath, "osl_systemPathIsHiddenFileOrDirectoryEntry: Invalid parameter");
139 if ((pstrPath == nullptr) || (pstrPath->length == 0))
140 return false;
142 OString fdp;
143 osl_systemPathGetFileNameOrLastDirectoryPart(pstrPath, &fdp.pData);
145 return ((fdp.pData->length > 0) &&
146 (fdp.pData->buffer[0] == FPH_CHAR_DOT) &&
147 !osl_systemPathIsLocalOrParentDirectoryEntry(fdp.pData));
150 bool osl_systemPathIsLocalOrParentDirectoryEntry(
151 const rtl_String* pstrPath)
153 OSL_PRECOND(pstrPath, "osl_systemPathIsLocalOrParentDirectoryEntry: Invalid parameter");
155 OString dirent;
157 osl_systemPathGetFileNameOrLastDirectoryPart(pstrPath, &dirent.pData);
159 return (dirent == "." ||
160 dirent == "..");
163 namespace {
165 /** Simple iterator for a path list separated by the specified character
167 class path_list_iterator
169 public:
171 /* after construction get_current_item
172 returns the first path in list, no need
173 to call reset first
175 path_list_iterator(OUString path_list, sal_Unicode list_separator = FPH_CHAR_COLON) :
176 m_path_list(std::move(path_list)),
177 m_end(m_path_list.getStr() + m_path_list.getLength() + 1),
178 m_separator(list_separator)
180 reset();
183 path_list_iterator(const path_list_iterator&) = delete;
184 path_list_iterator& operator=(const path_list_iterator&) = delete;
186 void reset()
188 m_path_segment_begin = m_path_segment_end = m_path_list.getStr();
189 advance();
192 void next()
194 OSL_PRECOND(!done(), "path_list_iterator: Already done!");
196 m_path_segment_begin = ++m_path_segment_end;
197 advance();
200 bool done() const
202 return (m_path_segment_end >= m_end);
205 OUString get_current_item() const
207 return OUString(
208 m_path_segment_begin,
209 (m_path_segment_end - m_path_segment_begin));
212 private:
213 /* move m_path_end to the next separator or
214 to the end of the string
216 void advance()
218 while (!done() && *m_path_segment_end && (*m_path_segment_end != m_separator))
219 ++m_path_segment_end;
221 OSL_ASSERT(m_path_segment_end <= m_end);
224 private:
225 OUString m_path_list;
226 const sal_Unicode* m_end;
227 const sal_Unicode m_separator;
228 const sal_Unicode* m_path_segment_begin;
229 const sal_Unicode* m_path_segment_end;
234 bool osl_searchPath(
235 const rtl_uString* pustrFilePath,
236 const rtl_uString* pustrSearchPathList,
237 rtl_uString** ppustrPathFound)
239 OSL_PRECOND(pustrFilePath && pustrSearchPathList && ppustrPathFound, "osl_searchPath: Invalid parameter");
241 bool bfound = false;
242 OUString fp(const_cast<rtl_uString*>(pustrFilePath));
243 OUString pl(const_cast<rtl_uString*>(pustrSearchPathList));
244 path_list_iterator pli(pl);
246 while (!pli.done())
248 OUString p = pli.get_current_item();
249 systemPathEnsureSeparator(&p);
250 p += fp;
252 if (osl::access(osl::OUStringToOString(p), F_OK) > -1)
254 bfound = true;
255 rtl_uString_assign(ppustrPathFound, p.pData);
256 break;
258 pli.next();
260 return bfound;
263 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */