Coverage Report

Created: 2026-05-16 09:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/sal/osl/unx/file_path_helper.cxx
Line
Count
Source
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
#include <utility>
24
#include <unistd.h>
25
26
#include "file_path_helper.hxx"
27
#include "uunxapi.hxx"
28
29
#include <osl/diagnose.h>
30
#include <rtl/ustring.hxx>
31
#include <sal/log.hxx>
32
33
const sal_Unicode FPH_CHAR_PATH_SEPARATOR = '/';
34
const sal_Unicode FPH_CHAR_DOT            = '.';
35
const sal_Unicode FPH_CHAR_COLON          = ':';
36
37
void osl_systemPathRemoveSeparator(rtl_String* pstrPath)
38
2.17M
{
39
2.17M
    OSL_PRECOND(nullptr != pstrPath, "osl_systemPathRemoveSeparator: Invalid parameter");
40
2.17M
    if (pstrPath == nullptr)
41
0
        return;
42
43
    // maybe there are more than one separator at end
44
    // so we run in a loop
45
2.49M
    while ((pstrPath->length > 1) && (pstrPath->buffer[pstrPath->length - 1] == FPH_CHAR_PATH_SEPARATOR))
46
324k
    {
47
324k
        pstrPath->length--;
48
324k
        pstrPath->buffer[pstrPath->length] = '\0';
49
324k
    }
50
51
2.17M
    SAL_WARN_IF( !((0 == pstrPath->length) || (1 == pstrPath->length) ||
52
2.17M
                 (pstrPath->length > 1 && pstrPath->buffer[pstrPath->length - 1] != FPH_CHAR_PATH_SEPARATOR)),
53
2.17M
                 "sal.osl",
54
2.17M
                 "osl_systemPathRemoveSeparator: Post condition failed");
55
2.17M
}
56
57
namespace {
58
59
template<typename T> void systemPathEnsureSeparator(T* ppstrPath)
60
102k
{
61
102k
    assert(nullptr != ppstrPath);
62
102k
    sal_Int32    lp = ppstrPath->getLength();
63
102k
    sal_Int32    i  = ppstrPath->lastIndexOf(FPH_CHAR_PATH_SEPARATOR);
64
65
102k
    if ((lp > 1 && i != (lp - 1)) || ((lp < 2) && i < 0))
66
102k
    {
67
102k
        *ppstrPath += "/";
68
102k
    }
69
70
102k
    SAL_WARN_IF( !ppstrPath->endsWith("/"),
71
102k
                 "sal.osl",
72
102k
                 "systemPathEnsureSeparator: Post condition failed");
73
102k
}
file_path_helper.cxx:void (anonymous namespace)::systemPathEnsureSeparator<rtl::OString>(rtl::OString*)
Line
Count
Source
60
102k
{
61
102k
    assert(nullptr != ppstrPath);
62
102k
    sal_Int32    lp = ppstrPath->getLength();
63
102k
    sal_Int32    i  = ppstrPath->lastIndexOf(FPH_CHAR_PATH_SEPARATOR);
64
65
102k
    if ((lp > 1 && i != (lp - 1)) || ((lp < 2) && i < 0))
66
102k
    {
67
102k
        *ppstrPath += "/";
68
102k
    }
69
70
102k
    SAL_WARN_IF( !ppstrPath->endsWith("/"),
71
102k
                 "sal.osl",
72
102k
                 "systemPathEnsureSeparator: Post condition failed");
73
102k
}
file_path_helper.cxx:void (anonymous namespace)::systemPathEnsureSeparator<rtl::OUString>(rtl::OUString*)
Line
Count
Source
60
87
{
61
87
    assert(nullptr != ppstrPath);
62
87
    sal_Int32    lp = ppstrPath->getLength();
63
87
    sal_Int32    i  = ppstrPath->lastIndexOf(FPH_CHAR_PATH_SEPARATOR);
64
65
87
    if ((lp > 1 && i != (lp - 1)) || ((lp < 2) && i < 0))
66
87
    {
67
87
        *ppstrPath += "/";
68
87
    }
69
70
87
    SAL_WARN_IF( !ppstrPath->endsWith("/"),
71
87
                 "sal.osl",
72
87
                 "systemPathEnsureSeparator: Post condition failed");
73
87
}
74
75
}
76
77
bool osl_systemPathIsRelativePath(const rtl_uString* pustrPath)
78
281
{
79
281
    OSL_PRECOND(nullptr != pustrPath, "osl_systemPathIsRelativePath: Invalid parameter");
80
281
    return ((pustrPath == nullptr) || (pustrPath->length == 0) || (pustrPath->buffer[0] != FPH_CHAR_PATH_SEPARATOR));
81
281
}
82
83
namespace {
84
85
template<typename T> T systemPathMakeAbsolutePath_(
86
    const T& BasePath,
87
    const T& RelPath)
88
102k
{
89
102k
    T base(BasePath);
90
91
102k
    if (!base.isEmpty())
92
102k
        systemPathEnsureSeparator(&base);
93
94
102k
    return base + RelPath;
95
102k
}
file_path_helper.cxx:rtl::OString (anonymous namespace)::systemPathMakeAbsolutePath_<rtl::OString>(rtl::OString const&, rtl::OString const&)
Line
Count
Source
88
102k
{
89
102k
    T base(BasePath);
90
91
102k
    if (!base.isEmpty())
92
102k
        systemPathEnsureSeparator(&base);
93
94
102k
    return base + RelPath;
95
102k
}
file_path_helper.cxx:rtl::OUString (anonymous namespace)::systemPathMakeAbsolutePath_<rtl::OUString>(rtl::OUString const&, rtl::OUString const&)
Line
Count
Source
88
87
{
89
87
    T base(BasePath);
90
91
87
    if (!base.isEmpty())
92
87
        systemPathEnsureSeparator(&base);
93
94
87
    return base + RelPath;
95
87
}
96
97
}
98
99
OString osl::systemPathMakeAbsolutePath(
100
    const OString& BasePath,
101
    const OString& RelPath)
102
102k
{
103
102k
    return systemPathMakeAbsolutePath_(BasePath, RelPath);
104
102k
}
105
106
OUString osl::systemPathMakeAbsolutePath(
107
    const OUString& BasePath,
108
    const OUString& RelPath)
109
87
{
110
87
    return systemPathMakeAbsolutePath_(BasePath, RelPath);
111
87
}
112
113
void osl_systemPathGetFileNameOrLastDirectoryPart(
114
    const rtl_String*     pstrPath,
115
    rtl_String**       ppstrFileNameOrLastDirPart)
116
236k
{
117
236k
    OSL_PRECOND(pstrPath && ppstrFileNameOrLastDirPart,
118
236k
                "osl_systemPathGetFileNameOrLastDirectoryPart: Invalid parameter");
119
120
236k
    OString path(const_cast<rtl_String*>(pstrPath));
121
122
236k
    osl_systemPathRemoveSeparator(path.pData);
123
124
236k
    OString last_part;
125
126
236k
    if (path.getLength() > 1 || (path.getLength() == 1 && path[0] != FPH_CHAR_PATH_SEPARATOR))
127
236k
    {
128
236k
        sal_Int32 idx_ps = path.lastIndexOf(FPH_CHAR_PATH_SEPARATOR);
129
236k
        idx_ps++; // always right to increment by one even if idx_ps == -1!
130
236k
        last_part = path.copy(idx_ps);
131
236k
    }
132
236k
    rtl_string_assign(ppstrFileNameOrLastDirPart, last_part.pData);
133
236k
}
134
135
bool osl_systemPathIsHiddenFileOrDirectoryEntry(
136
    const rtl_String* pstrPath)
137
133k
{
138
133k
    OSL_PRECOND(nullptr != pstrPath, "osl_systemPathIsHiddenFileOrDirectoryEntry: Invalid parameter");
139
133k
    if ((pstrPath == nullptr) || (pstrPath->length == 0))
140
0
        return false;
141
142
133k
    OString fdp;
143
133k
    osl_systemPathGetFileNameOrLastDirectoryPart(pstrPath, &fdp.pData);
144
145
133k
    return ((fdp.pData->length > 0) &&
146
133k
            (fdp.pData->buffer[0] == FPH_CHAR_DOT) &&
147
0
            !osl_systemPathIsLocalOrParentDirectoryEntry(fdp.pData));
148
133k
}
149
150
bool osl_systemPathIsLocalOrParentDirectoryEntry(
151
    const rtl_String* pstrPath)
152
0
{
153
0
    OSL_PRECOND(pstrPath, "osl_systemPathIsLocalOrParentDirectoryEntry: Invalid parameter");
154
155
0
    OString dirent;
156
157
0
    osl_systemPathGetFileNameOrLastDirectoryPart(pstrPath, &dirent.pData);
158
159
0
    return (dirent == "." ||
160
0
            dirent == "..");
161
0
}
162
163
namespace {
164
165
/** Simple iterator for a path list separated by the specified character
166
*/
167
class path_list_iterator
168
{
169
public:
170
171
    /* after construction get_current_item
172
       returns the first path in list, no need
173
       to call reset first
174
     */
175
    path_list_iterator(OUString path_list, sal_Unicode list_separator = FPH_CHAR_COLON) :
176
0
        m_path_list(std::move(path_list)),
177
0
        m_end(m_path_list.getStr() + m_path_list.getLength() + 1),
178
0
        m_separator(list_separator)
179
0
    {
180
0
        reset();
181
0
    }
182
183
    path_list_iterator(const path_list_iterator&) = delete;
184
    path_list_iterator& operator=(const path_list_iterator&) = delete;
185
186
    void reset()
187
0
    {
188
0
        m_path_segment_begin = m_path_segment_end = m_path_list.getStr();
189
0
        advance();
190
0
    }
191
192
    void next()
193
0
    {
194
0
        OSL_PRECOND(!done(), "path_list_iterator: Already done!");
195
196
0
        m_path_segment_begin = ++m_path_segment_end;
197
0
        advance();
198
0
    }
199
200
    bool done() const
201
0
    {
202
0
        return (m_path_segment_end >= m_end);
203
0
    }
204
205
    OUString get_current_item() const
206
0
    {
207
0
        return OUString(
208
0
            m_path_segment_begin,
209
0
            (m_path_segment_end - m_path_segment_begin));
210
0
    }
211
212
private:
213
    /* move m_path_end to the next separator or
214
       to the end of the string
215
     */
216
    void advance()
217
0
    {
218
0
        while (!done() && *m_path_segment_end && (*m_path_segment_end != m_separator))
219
0
            ++m_path_segment_end;
220
221
0
        OSL_ASSERT(m_path_segment_end <= m_end);
222
0
    }
223
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;
230
};
231
232
}
233
234
bool osl_searchPath(
235
    const rtl_uString* pustrFilePath,
236
    const rtl_uString* pustrSearchPathList,
237
    rtl_uString**      ppustrPathFound)
238
0
{
239
0
    OSL_PRECOND(pustrFilePath && pustrSearchPathList && ppustrPathFound, "osl_searchPath: Invalid parameter");
240
241
0
    bool               bfound = false;
242
0
    OUString      fp(const_cast<rtl_uString*>(pustrFilePath));
243
0
    OUString      pl(const_cast<rtl_uString*>(pustrSearchPathList));
244
0
    path_list_iterator pli(pl);
245
246
0
    while (!pli.done())
247
0
    {
248
0
        OUString p = pli.get_current_item();
249
0
        systemPathEnsureSeparator(&p);
250
0
        p += fp;
251
252
0
        if (osl::access(osl::OUStringToOString(p), F_OK) > -1)
253
0
        {
254
0
            bfound = true;
255
0
            rtl_uString_assign(ppustrPathFound, p.pData);
256
0
            break;
257
0
        }
258
0
        pli.next();
259
0
    }
260
0
    return bfound;
261
0
}
262
263
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */