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 CPL_CVSID("$Id: cpl_findfile.cpp 36a6a8ceffd622ab2b2ecddf489b5f790f1c65a0 2019-08-12 23:56:02 +0200 Even Rouault $")
40
41 typedef struct
42 {
43 bool bFinderInitialized;
44 int nFileFinders;
45 CPLFileFinder *papfnFinders;
46 char **papszFinderLocations;
47 } FindFileTLS;
48
49 /************************************************************************/
50 /* CPLFindFileDeinitTLS() */
51 /************************************************************************/
52
53 static void CPLPopFinderLocationInternal( FindFileTLS* pTLSData );
54 static CPLFileFinder CPLPopFileFinderInternal( FindFileTLS* pTLSData );
55
CPLFindFileFreeTLS(void * pData)56 static void CPLFindFileFreeTLS( void* pData )
57 {
58 FindFileTLS* pTLSData = reinterpret_cast<FindFileTLS *>( pData );
59 if( pTLSData != nullptr && pTLSData->bFinderInitialized )
60 {
61 while( pTLSData->papszFinderLocations != nullptr )
62 CPLPopFinderLocationInternal(pTLSData);
63 while( CPLPopFileFinderInternal(pTLSData) != nullptr ) {}
64
65 pTLSData->bFinderInitialized = false;
66 }
67 CPLFree(pTLSData);
68 }
69
70 /************************************************************************/
71 /* CPLGetFindFileTLS() */
72 /************************************************************************/
73
CPLGetFindFileTLS()74 static FindFileTLS* CPLGetFindFileTLS()
75 {
76 int bMemoryError = FALSE;
77 FindFileTLS* pTLSData =
78 reinterpret_cast<FindFileTLS *>(
79 CPLGetTLSEx( CTLS_FINDFILE, &bMemoryError ) );
80 if( bMemoryError )
81 return nullptr;
82 if( pTLSData == nullptr )
83 {
84 pTLSData = static_cast<FindFileTLS *>(
85 VSI_CALLOC_VERBOSE(1, sizeof(FindFileTLS) ) );
86 if( pTLSData == nullptr )
87 return nullptr;
88 CPLSetTLSWithFreeFunc( CTLS_FINDFILE, pTLSData, CPLFindFileFreeTLS );
89 }
90 return pTLSData;
91 }
92
93 /************************************************************************/
94 /* CPLFinderInit() */
95 /************************************************************************/
96
CPLFinderInit()97 static FindFileTLS* CPLFinderInit()
98
99 {
100 FindFileTLS* pTLSData = CPLGetFindFileTLS();
101 if( pTLSData != nullptr && !pTLSData->bFinderInitialized )
102 {
103 pTLSData->bFinderInitialized = true;
104 CPLPushFileFinder( CPLDefaultFindFile );
105
106 CPLPushFinderLocation( "." );
107
108 if( CPLGetConfigOption( "GDAL_DATA", nullptr ) != nullptr )
109 {
110 CPLPushFinderLocation( CPLGetConfigOption( "GDAL_DATA", nullptr ) );
111 }
112 else
113 {
114 #ifdef INST_DATA
115 CPLPushFinderLocation( INST_DATA );
116 #endif
117 #ifdef GDAL_PREFIX
118 #ifdef MACOSX_FRAMEWORK
119 CPLPushFinderLocation( GDAL_PREFIX "/Resources/gdal" );
120 #else
121 CPLPushFinderLocation( GDAL_PREFIX "/share/gdal" );
122 #endif
123 #endif
124 }
125 }
126 return pTLSData;
127 }
128
129 /************************************************************************/
130 /* CPLFinderClean() */
131 /************************************************************************/
132
133 /** CPLFinderClean */
CPLFinderClean()134 void CPLFinderClean()
135
136 {
137 FindFileTLS* pTLSData = CPLGetFindFileTLS();
138 CPLFindFileFreeTLS(pTLSData);
139 int bMemoryError = FALSE;
140 CPLSetTLSWithFreeFuncEx( CTLS_FINDFILE, nullptr, nullptr, &bMemoryError );
141 // TODO: if( bMemoryError ) {}
142 }
143
144 /************************************************************************/
145 /* CPLDefaultFindFile() */
146 /************************************************************************/
147
148 /** CPLDefaultFindFile */
CPLDefaultFindFile(const char *,const char * pszBasename)149 const char *CPLDefaultFindFile( const char * /* pszClass */,
150 const char *pszBasename )
151
152 {
153 FindFileTLS* pTLSData = CPLGetFindFileTLS();
154 if( pTLSData == nullptr )
155 return nullptr;
156 const int nLocations = CSLCount( pTLSData->papszFinderLocations );
157
158 for( int i = nLocations-1; i >= 0; i-- )
159 {
160 const char *pszResult =
161 CPLFormFilename( pTLSData->papszFinderLocations[i], pszBasename,
162 nullptr );
163
164 VSIStatBufL sStat;
165 if( VSIStatL( pszResult, &sStat ) == 0 )
166 return pszResult;
167 }
168
169 return nullptr;
170 }
171
172 /************************************************************************/
173 /* CPLFindFile() */
174 /************************************************************************/
175
176 /** CPLFindFile */
CPLFindFile(const char * pszClass,const char * pszBasename)177 const char *CPLFindFile( const char *pszClass, const char *pszBasename )
178
179 {
180 FindFileTLS* pTLSData = CPLFinderInit();
181 if( pTLSData == nullptr )
182 return nullptr;
183
184 for( int i = pTLSData->nFileFinders-1; i >= 0; i-- )
185 {
186 const char * pszResult =
187 (pTLSData->papfnFinders[i])( pszClass, pszBasename );
188 if( pszResult != nullptr )
189 return pszResult;
190 }
191
192 return nullptr;
193 }
194
195 /************************************************************************/
196 /* CPLPushFileFinder() */
197 /************************************************************************/
198
199 /** CPLPushFileFinder */
CPLPushFileFinder(CPLFileFinder pfnFinder)200 void CPLPushFileFinder( CPLFileFinder pfnFinder )
201
202 {
203 FindFileTLS* pTLSData = CPLFinderInit();
204 if( pTLSData == nullptr )
205 return;
206
207 pTLSData->papfnFinders = static_cast<CPLFileFinder *>(
208 CPLRealloc(pTLSData->papfnFinders,
209 sizeof(CPLFileFinder) * ++pTLSData->nFileFinders) );
210 pTLSData->papfnFinders[pTLSData->nFileFinders-1] = pfnFinder;
211 }
212
213 /************************************************************************/
214 /* CPLPopFileFinder() */
215 /************************************************************************/
216
CPLPopFileFinderInternal(FindFileTLS * pTLSData)217 CPLFileFinder CPLPopFileFinderInternal( FindFileTLS* pTLSData )
218
219 {
220 if( pTLSData == nullptr )
221 return nullptr;
222 if( pTLSData->nFileFinders == 0 )
223 return nullptr;
224
225 CPLFileFinder pfnReturn = pTLSData->papfnFinders[--pTLSData->nFileFinders];
226
227 if( pTLSData->nFileFinders == 0)
228 {
229 CPLFree( pTLSData->papfnFinders );
230 pTLSData->papfnFinders = nullptr;
231 }
232
233 return pfnReturn;
234 }
235
236 /** CPLPopFileFinder */
CPLPopFileFinder()237 CPLFileFinder CPLPopFileFinder()
238
239 {
240 return CPLPopFileFinderInternal(CPLFinderInit());
241 }
242
243 /************************************************************************/
244 /* CPLPushFinderLocation() */
245 /************************************************************************/
246
247 /** CPLPushFinderLocation */
CPLPushFinderLocation(const char * pszLocation)248 void CPLPushFinderLocation( const char *pszLocation )
249
250 {
251 FindFileTLS* pTLSData = CPLFinderInit();
252 if( pTLSData == nullptr )
253 return;
254 // Check if location already is in list.
255 if( CSLFindStringCaseSensitive(pTLSData->papszFinderLocations,
256 pszLocation) > -1 )
257 return;
258 pTLSData->papszFinderLocations =
259 CSLAddStringMayFail( pTLSData->papszFinderLocations, pszLocation );
260 }
261
262 /************************************************************************/
263 /* CPLPopFinderLocation() */
264 /************************************************************************/
265
CPLPopFinderLocationInternal(FindFileTLS * pTLSData)266 static void CPLPopFinderLocationInternal( FindFileTLS* pTLSData )
267
268 {
269 if( pTLSData == nullptr || pTLSData->papszFinderLocations == nullptr )
270 return;
271
272 const int nCount = CSLCount(pTLSData->papszFinderLocations);
273 if( nCount == 0 )
274 return;
275
276 CPLFree( pTLSData->papszFinderLocations[nCount-1] );
277 pTLSData->papszFinderLocations[nCount-1] = nullptr;
278
279 if( nCount == 1 )
280 {
281 CPLFree( pTLSData->papszFinderLocations );
282 pTLSData->papszFinderLocations = nullptr;
283 }
284 }
285
286 /** CPLPopFinderLocation */
CPLPopFinderLocation()287 void CPLPopFinderLocation()
288 {
289 CPLPopFinderLocationInternal(CPLFinderInit());
290 }
291