Line data Source code
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 : * Permission is hereby granted, free of charge, to any person obtaining a
12 : * copy of this software and associated documentation files (the "Software"),
13 : * to deal in the Software without restriction, including without limitation
14 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 : * and/or sell copies of the Software, and to permit persons to whom the
16 : * Software is furnished to do so, subject to the following conditions:
17 : *
18 : * The above copyright notice and this permission notice shall be included
19 : * in all copies or substantial portions of the Software.
20 : *
21 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 : * DEALINGS IN THE SOFTWARE.
28 : ****************************************************************************/
29 :
30 : #include "cpl_port.h"
31 : #include "cpl_conv.h"
32 :
33 : #include <cstddef>
34 :
35 : #include "cpl_multiproc.h"
36 : #include "cpl_string.h"
37 : #include "cpl_vsi.h"
38 :
39 : typedef struct
40 : {
41 : bool bFinderInitialized;
42 : int nFileFinders;
43 : CPLFileFinder *papfnFinders;
44 : char **papszFinderLocations;
45 : } FindFileTLS;
46 :
47 : /************************************************************************/
48 : /* CPLFindFileDeinitTLS() */
49 : /************************************************************************/
50 :
51 : static void CPLPopFinderLocationInternal(FindFileTLS *pTLSData);
52 : static CPLFileFinder CPLPopFileFinderInternal(FindFileTLS *pTLSData);
53 :
54 852 : static void CPLFindFileFreeTLS(void *pData)
55 : {
56 852 : FindFileTLS *pTLSData = reinterpret_cast<FindFileTLS *>(pData);
57 852 : if (pTLSData != nullptr && pTLSData->bFinderInitialized)
58 : {
59 372 : while (pTLSData->papszFinderLocations != nullptr)
60 248 : CPLPopFinderLocationInternal(pTLSData);
61 248 : while (CPLPopFileFinderInternal(pTLSData) != nullptr)
62 : {
63 : }
64 :
65 124 : pTLSData->bFinderInitialized = false;
66 : }
67 852 : CPLFree(pTLSData);
68 852 : }
69 :
70 : /************************************************************************/
71 : /* CPLGetFindFileTLS() */
72 : /************************************************************************/
73 :
74 7094 : static FindFileTLS *CPLGetFindFileTLS()
75 : {
76 7094 : int bMemoryError = FALSE;
77 : FindFileTLS *pTLSData = reinterpret_cast<FindFileTLS *>(
78 7094 : CPLGetTLSEx(CTLS_FINDFILE, &bMemoryError));
79 7094 : if (bMemoryError)
80 0 : return nullptr;
81 7094 : if (pTLSData == nullptr)
82 : {
83 : pTLSData = static_cast<FindFileTLS *>(
84 926 : VSI_CALLOC_VERBOSE(1, sizeof(FindFileTLS)));
85 926 : if (pTLSData == nullptr)
86 0 : return nullptr;
87 926 : CPLSetTLSWithFreeFunc(CTLS_FINDFILE, pTLSData, CPLFindFileFreeTLS);
88 : }
89 7094 : return pTLSData;
90 : }
91 :
92 : /************************************************************************/
93 : /* CPLFinderInit() */
94 : /************************************************************************/
95 :
96 3421 : static FindFileTLS *CPLFinderInit()
97 :
98 : {
99 3421 : FindFileTLS *pTLSData = CPLGetFindFileTLS();
100 3421 : if (pTLSData != nullptr && !pTLSData->bFinderInitialized)
101 : {
102 198 : pTLSData->bFinderInitialized = true;
103 198 : CPLPushFileFinder(CPLDefaultFindFile);
104 :
105 198 : CPLPushFinderLocation(".");
106 :
107 198 : if (CPLGetConfigOption("GDAL_DATA", nullptr) != nullptr)
108 : {
109 196 : CPLPushFinderLocation(CPLGetConfigOption("GDAL_DATA", nullptr));
110 : }
111 : else
112 : {
113 : #ifdef INST_DATA
114 2 : CPLPushFinderLocation(INST_DATA);
115 : #endif
116 : #ifdef GDAL_PREFIX
117 : #ifdef MACOSX_FRAMEWORK
118 : CPLPushFinderLocation(GDAL_PREFIX "/Resources/gdal");
119 : #else
120 2 : CPLPushFinderLocation(GDAL_PREFIX "/share/gdal");
121 : #endif
122 : #endif
123 : }
124 : }
125 3421 : return pTLSData;
126 : }
127 :
128 : /************************************************************************/
129 : /* CPLFinderClean() */
130 : /************************************************************************/
131 :
132 : /** CPLFinderClean */
133 852 : void CPLFinderClean()
134 :
135 : {
136 852 : FindFileTLS *pTLSData = CPLGetFindFileTLS();
137 852 : CPLFindFileFreeTLS(pTLSData);
138 852 : int bMemoryError = FALSE;
139 852 : CPLSetTLSWithFreeFuncEx(CTLS_FINDFILE, nullptr, nullptr, &bMemoryError);
140 : // TODO: if( bMemoryError ) {}
141 852 : }
142 :
143 : /************************************************************************/
144 : /* CPLDefaultFindFile() */
145 : /************************************************************************/
146 :
147 : /** CPLDefaultFindFile */
148 2821 : const char *CPLDefaultFindFile(const char *pszClass, const char *pszBasename)
149 :
150 : {
151 2821 : FindFileTLS *pTLSData = CPLGetFindFileTLS();
152 2821 : if (pTLSData == nullptr)
153 0 : return nullptr;
154 2821 : const int nLocations = CSLCount(pTLSData->papszFinderLocations);
155 :
156 3859 : for (int i = nLocations - 1; i >= 0; i--)
157 : {
158 6680 : const char *pszResult = CPLFormFilename(
159 3340 : pTLSData->papszFinderLocations[i], pszBasename, nullptr);
160 :
161 : VSIStatBufL sStat;
162 3340 : if (VSIStatL(pszResult, &sStat) == 0)
163 2302 : return pszResult;
164 : }
165 :
166 519 : if (EQUAL(pszClass, "gdal") && !CPLGetConfigOption("GDAL_DATA", nullptr))
167 : {
168 0 : CPLError(CE_Warning, CPLE_FileIO,
169 : "Cannot find %s (GDAL_DATA is not defined)", pszBasename);
170 : }
171 :
172 519 : return nullptr;
173 : }
174 :
175 : /************************************************************************/
176 : /* CPLFindFile() */
177 : /************************************************************************/
178 :
179 : /** CPLFindFile */
180 2821 : const char *CPLFindFile(const char *pszClass, const char *pszBasename)
181 :
182 : {
183 2821 : FindFileTLS *pTLSData = CPLFinderInit();
184 2821 : if (pTLSData == nullptr)
185 0 : return nullptr;
186 :
187 3340 : for (int i = pTLSData->nFileFinders - 1; i >= 0; i--)
188 : {
189 : const char *pszResult =
190 2821 : (pTLSData->papfnFinders[i])(pszClass, pszBasename);
191 2821 : if (pszResult != nullptr)
192 2302 : return pszResult;
193 : }
194 :
195 519 : return nullptr;
196 : }
197 :
198 : /************************************************************************/
199 : /* CPLPushFileFinder() */
200 : /************************************************************************/
201 :
202 : /** CPLPushFileFinder */
203 198 : void CPLPushFileFinder(CPLFileFinder pfnFinder)
204 :
205 : {
206 198 : FindFileTLS *pTLSData = CPLFinderInit();
207 198 : if (pTLSData == nullptr)
208 0 : return;
209 :
210 396 : pTLSData->papfnFinders = static_cast<CPLFileFinder *>(
211 396 : CPLRealloc(pTLSData->papfnFinders,
212 198 : sizeof(CPLFileFinder) * ++pTLSData->nFileFinders));
213 198 : pTLSData->papfnFinders[pTLSData->nFileFinders - 1] = pfnFinder;
214 : }
215 :
216 : /************************************************************************/
217 : /* CPLPopFileFinder() */
218 : /************************************************************************/
219 :
220 248 : CPLFileFinder CPLPopFileFinderInternal(FindFileTLS *pTLSData)
221 :
222 : {
223 248 : if (pTLSData == nullptr)
224 0 : return nullptr;
225 248 : if (pTLSData->nFileFinders == 0)
226 124 : return nullptr;
227 :
228 124 : CPLFileFinder pfnReturn = pTLSData->papfnFinders[--pTLSData->nFileFinders];
229 :
230 124 : if (pTLSData->nFileFinders == 0)
231 : {
232 124 : CPLFree(pTLSData->papfnFinders);
233 124 : pTLSData->papfnFinders = nullptr;
234 : }
235 :
236 124 : return pfnReturn;
237 : }
238 :
239 : /** CPLPopFileFinder */
240 0 : CPLFileFinder CPLPopFileFinder()
241 :
242 : {
243 0 : return CPLPopFileFinderInternal(CPLFinderInit());
244 : }
245 :
246 : /************************************************************************/
247 : /* CPLPushFinderLocation() */
248 : /************************************************************************/
249 :
250 : /** CPLPushFinderLocation */
251 402 : void CPLPushFinderLocation(const char *pszLocation)
252 :
253 : {
254 402 : FindFileTLS *pTLSData = CPLFinderInit();
255 402 : if (pTLSData == nullptr)
256 0 : return;
257 : // Check if location already is in list.
258 402 : if (CSLFindStringCaseSensitive(pTLSData->papszFinderLocations,
259 402 : pszLocation) > -1)
260 6 : return;
261 396 : pTLSData->papszFinderLocations =
262 396 : CSLAddStringMayFail(pTLSData->papszFinderLocations, pszLocation);
263 : }
264 :
265 : /************************************************************************/
266 : /* CPLPopFinderLocation() */
267 : /************************************************************************/
268 :
269 248 : static void CPLPopFinderLocationInternal(FindFileTLS *pTLSData)
270 :
271 : {
272 248 : if (pTLSData == nullptr || pTLSData->papszFinderLocations == nullptr)
273 0 : return;
274 :
275 248 : const int nCount = CSLCount(pTLSData->papszFinderLocations);
276 248 : if (nCount == 0)
277 0 : return;
278 :
279 248 : CPLFree(pTLSData->papszFinderLocations[nCount - 1]);
280 248 : pTLSData->papszFinderLocations[nCount - 1] = nullptr;
281 :
282 248 : if (nCount == 1)
283 : {
284 124 : CPLFree(pTLSData->papszFinderLocations);
285 124 : pTLSData->papszFinderLocations = nullptr;
286 : }
287 : }
288 :
289 : /** CPLPopFinderLocation */
290 0 : void CPLPopFinderLocation()
291 : {
292 0 : CPLPopFinderLocationInternal(CPLFinderInit());
293 0 : }
|