Coverage Report

Created: 2025-06-13 06:18

/src/gdal/port/cpl_findfile.cpp
Line
Count
Source (jump to first uncovered line)
1
/******************************************************************************
2
 *
3
 * Project:  CPL - Common Portability Library
4
 * Purpose:  Generic data file location finder, with application hooking.
5
 * Author:   Frank Warmerdam, warmerdam@pobox.com
6
 *
7
 ******************************************************************************
8
 * Copyright (c) 2000, Frank Warmerdam
9
 * Copyright (c) 2009-2010, Even Rouault <even dot rouault at spatialys.com>
10
 *
11
 * SPDX-License-Identifier: MIT
12
 ****************************************************************************/
13
14
#include "cpl_port.h"
15
#include "cpl_conv.h"
16
17
#include <cstddef>
18
19
#include "cpl_multiproc.h"
20
#include "cpl_string.h"
21
#include "cpl_vsi.h"
22
23
typedef struct
24
{
25
    bool bFinderInitialized;
26
    int nFileFinders;
27
    CPLFileFinder *papfnFinders;
28
    char **papszFinderLocations;
29
} FindFileTLS;
30
31
/************************************************************************/
32
/*                      CPLFindFileDeinitTLS()                          */
33
/************************************************************************/
34
35
static void CPLPopFinderLocationInternal(FindFileTLS *pTLSData);
36
static CPLFileFinder CPLPopFileFinderInternal(FindFileTLS *pTLSData);
37
38
static void CPLFindFileFreeTLS(void *pData)
39
0
{
40
0
    FindFileTLS *pTLSData = reinterpret_cast<FindFileTLS *>(pData);
41
0
    if (pTLSData != nullptr && pTLSData->bFinderInitialized)
42
0
    {
43
0
        while (pTLSData->papszFinderLocations != nullptr)
44
0
            CPLPopFinderLocationInternal(pTLSData);
45
0
        while (CPLPopFileFinderInternal(pTLSData) != nullptr)
46
0
        {
47
0
        }
48
49
0
        pTLSData->bFinderInitialized = false;
50
0
    }
51
0
    CPLFree(pTLSData);
52
0
}
53
54
/************************************************************************/
55
/*                       CPLGetFindFileTLS()                            */
56
/************************************************************************/
57
58
static FindFileTLS *CPLGetFindFileTLS()
59
0
{
60
0
    int bMemoryError = FALSE;
61
0
    FindFileTLS *pTLSData = reinterpret_cast<FindFileTLS *>(
62
0
        CPLGetTLSEx(CTLS_FINDFILE, &bMemoryError));
63
0
    if (bMemoryError)
64
0
        return nullptr;
65
0
    if (pTLSData == nullptr)
66
0
    {
67
0
        pTLSData = static_cast<FindFileTLS *>(
68
0
            VSI_CALLOC_VERBOSE(1, sizeof(FindFileTLS)));
69
0
        if (pTLSData == nullptr)
70
0
            return nullptr;
71
0
        CPLSetTLSWithFreeFunc(CTLS_FINDFILE, pTLSData, CPLFindFileFreeTLS);
72
0
    }
73
0
    return pTLSData;
74
0
}
75
76
/************************************************************************/
77
/*                           CPLFinderInit()                            */
78
/************************************************************************/
79
80
static FindFileTLS *CPLFinderInit()
81
82
0
{
83
0
    FindFileTLS *pTLSData = CPLGetFindFileTLS();
84
0
    if (pTLSData != nullptr && !pTLSData->bFinderInitialized)
85
0
    {
86
0
        pTLSData->bFinderInitialized = true;
87
0
        CPLPushFileFinder(CPLDefaultFindFile);
88
89
0
        CPLPushFinderLocation(".");
90
91
0
        if (CPLGetConfigOption("GDAL_DATA", nullptr) != nullptr)
92
0
        {
93
0
            CPLPushFinderLocation(CPLGetConfigOption("GDAL_DATA", nullptr));
94
0
        }
95
0
        else
96
0
        {
97
0
#ifdef INST_DATA
98
0
            CPLPushFinderLocation(INST_DATA);
99
0
#endif
100
0
#ifdef GDAL_PREFIX
101
#ifdef MACOSX_FRAMEWORK
102
            CPLPushFinderLocation(GDAL_PREFIX "/Resources/gdal");
103
#else
104
0
            CPLPushFinderLocation(GDAL_PREFIX "/share/gdal");
105
0
#endif
106
0
#endif
107
0
        }
108
0
    }
109
0
    return pTLSData;
110
0
}
111
112
/************************************************************************/
113
/*                           CPLFinderClean()                           */
114
/************************************************************************/
115
116
/** CPLFinderClean */
117
void CPLFinderClean()
118
119
0
{
120
0
    FindFileTLS *pTLSData = CPLGetFindFileTLS();
121
0
    CPLFindFileFreeTLS(pTLSData);
122
0
    int bMemoryError = FALSE;
123
0
    CPLSetTLSWithFreeFuncEx(CTLS_FINDFILE, nullptr, nullptr, &bMemoryError);
124
    // TODO: if( bMemoryError ) {}
125
0
}
126
127
/************************************************************************/
128
/*                         CPLDefaultFindFile()                         */
129
/************************************************************************/
130
131
/** CPLDefaultFindFile */
132
const char *CPLDefaultFindFile(const char *pszClass, const char *pszBasename)
133
134
0
{
135
0
    FindFileTLS *pTLSData = CPLGetFindFileTLS();
136
0
    if (pTLSData == nullptr)
137
0
        return nullptr;
138
0
    const int nLocations = CSLCount(pTLSData->papszFinderLocations);
139
140
0
    for (int i = nLocations - 1; i >= 0; i--)
141
0
    {
142
0
        const std::string osResult = CPLFormFilenameSafe(
143
0
            pTLSData->papszFinderLocations[i], pszBasename, nullptr);
144
145
0
        VSIStatBufL sStat;
146
0
        if (VSIStatL(osResult.c_str(), &sStat) == 0)
147
0
            return CPLSPrintf("%s", osResult.c_str());
148
0
    }
149
150
0
    if (EQUAL(pszClass, "gdal") && !CPLGetConfigOption("GDAL_DATA", nullptr))
151
0
    {
152
0
        CPLError(CE_Warning, CPLE_FileIO,
153
0
                 "Cannot find %s (GDAL_DATA is not defined)", pszBasename);
154
0
    }
155
156
0
    return nullptr;
157
0
}
158
159
/************************************************************************/
160
/*                            CPLFindFile()                             */
161
/************************************************************************/
162
163
/** CPLFindFile */
164
const char *CPLFindFile(const char *pszClass, const char *pszBasename)
165
166
0
{
167
0
    FindFileTLS *pTLSData = CPLFinderInit();
168
0
    if (pTLSData == nullptr)
169
0
        return nullptr;
170
171
0
    for (int i = pTLSData->nFileFinders - 1; i >= 0; i--)
172
0
    {
173
0
        const char *pszResult =
174
0
            (pTLSData->papfnFinders[i])(pszClass, pszBasename);
175
0
        if (pszResult != nullptr)
176
0
            return pszResult;
177
0
    }
178
179
0
    return nullptr;
180
0
}
181
182
/************************************************************************/
183
/*                         CPLPushFileFinder()                          */
184
/************************************************************************/
185
186
/** CPLPushFileFinder */
187
void CPLPushFileFinder(CPLFileFinder pfnFinder)
188
189
0
{
190
0
    FindFileTLS *pTLSData = CPLFinderInit();
191
0
    if (pTLSData == nullptr)
192
0
        return;
193
194
0
    pTLSData->papfnFinders = static_cast<CPLFileFinder *>(
195
0
        CPLRealloc(pTLSData->papfnFinders,
196
0
                   sizeof(CPLFileFinder) * ++pTLSData->nFileFinders));
197
0
    pTLSData->papfnFinders[pTLSData->nFileFinders - 1] = pfnFinder;
198
0
}
199
200
/************************************************************************/
201
/*                          CPLPopFileFinder()                          */
202
/************************************************************************/
203
204
CPLFileFinder CPLPopFileFinderInternal(FindFileTLS *pTLSData)
205
206
0
{
207
0
    if (pTLSData == nullptr)
208
0
        return nullptr;
209
0
    if (pTLSData->nFileFinders == 0)
210
0
        return nullptr;
211
212
0
    CPLFileFinder pfnReturn = pTLSData->papfnFinders[--pTLSData->nFileFinders];
213
214
0
    if (pTLSData->nFileFinders == 0)
215
0
    {
216
0
        CPLFree(pTLSData->papfnFinders);
217
0
        pTLSData->papfnFinders = nullptr;
218
0
    }
219
220
0
    return pfnReturn;
221
0
}
222
223
/** CPLPopFileFinder */
224
CPLFileFinder CPLPopFileFinder()
225
226
0
{
227
0
    return CPLPopFileFinderInternal(CPLFinderInit());
228
0
}
229
230
/************************************************************************/
231
/*                       CPLPushFinderLocation()                        */
232
/************************************************************************/
233
234
/** CPLPushFinderLocation */
235
void CPLPushFinderLocation(const char *pszLocation)
236
237
0
{
238
0
    FindFileTLS *pTLSData = CPLFinderInit();
239
0
    if (pTLSData == nullptr)
240
0
        return;
241
    // Check if location already is in list.
242
0
    if (CSLFindStringCaseSensitive(pTLSData->papszFinderLocations,
243
0
                                   pszLocation) > -1)
244
0
        return;
245
0
    pTLSData->papszFinderLocations =
246
0
        CSLAddStringMayFail(pTLSData->papszFinderLocations, pszLocation);
247
0
}
248
249
/************************************************************************/
250
/*                       CPLPopFinderLocation()                         */
251
/************************************************************************/
252
253
static void CPLPopFinderLocationInternal(FindFileTLS *pTLSData)
254
255
0
{
256
0
    if (pTLSData == nullptr || pTLSData->papszFinderLocations == nullptr)
257
0
        return;
258
259
0
    const int nCount = CSLCount(pTLSData->papszFinderLocations);
260
0
    if (nCount == 0)
261
0
        return;
262
263
0
    CPLFree(pTLSData->papszFinderLocations[nCount - 1]);
264
0
    pTLSData->papszFinderLocations[nCount - 1] = nullptr;
265
266
0
    if (nCount == 1)
267
0
    {
268
0
        CPLFree(pTLSData->papszFinderLocations);
269
0
        pTLSData->papszFinderLocations = nullptr;
270
0
    }
271
0
}
272
273
/** CPLPopFinderLocation */
274
void CPLPopFinderLocation()
275
0
{
276
0
    CPLPopFinderLocationInternal(CPLFinderInit());
277
0
}