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