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