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 941 : static void CPLFindFileFreeTLS(void *pData) 39 : { 40 941 : FindFileTLS *pTLSData = reinterpret_cast<FindFileTLS *>(pData); 41 941 : if (pTLSData != nullptr && pTLSData->bFinderInitialized) 42 : { 43 384 : while (pTLSData->papszFinderLocations != nullptr) 44 256 : CPLPopFinderLocationInternal(pTLSData); 45 256 : while (CPLPopFileFinderInternal(pTLSData) != nullptr) 46 : { 47 : } 48 : 49 128 : pTLSData->bFinderInitialized = false; 50 : } 51 941 : CPLFree(pTLSData); 52 941 : } 53 : 54 : /************************************************************************/ 55 : /* CPLGetFindFileTLS() */ 56 : /************************************************************************/ 57 : 58 7598 : static FindFileTLS *CPLGetFindFileTLS() 59 : { 60 7598 : int bMemoryError = FALSE; 61 : FindFileTLS *pTLSData = reinterpret_cast<FindFileTLS *>( 62 7598 : CPLGetTLSEx(CTLS_FINDFILE, &bMemoryError)); 63 7598 : if (bMemoryError) 64 0 : return nullptr; 65 7598 : if (pTLSData == nullptr) 66 : { 67 : pTLSData = static_cast<FindFileTLS *>( 68 1026 : VSI_CALLOC_VERBOSE(1, sizeof(FindFileTLS))); 69 1026 : if (pTLSData == nullptr) 70 0 : return nullptr; 71 1026 : CPLSetTLSWithFreeFunc(CTLS_FINDFILE, pTLSData, CPLFindFileFreeTLS); 72 : } 73 7598 : return pTLSData; 74 : } 75 : 76 : /************************************************************************/ 77 : /* CPLFinderInit() */ 78 : /************************************************************************/ 79 : 80 3651 : static FindFileTLS *CPLFinderInit() 81 : 82 : { 83 3651 : FindFileTLS *pTLSData = CPLGetFindFileTLS(); 84 3651 : if (pTLSData != nullptr && !pTLSData->bFinderInitialized) 85 : { 86 213 : pTLSData->bFinderInitialized = true; 87 213 : CPLPushFileFinder(CPLDefaultFindFile); 88 : 89 213 : CPLPushFinderLocation("."); 90 : 91 213 : if (CPLGetConfigOption("GDAL_DATA", nullptr) != nullptr) 92 : { 93 211 : 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 3651 : return pTLSData; 110 : } 111 : 112 : /************************************************************************/ 113 : /* CPLFinderClean() */ 114 : /************************************************************************/ 115 : 116 : /** CPLFinderClean */ 117 941 : void CPLFinderClean() 118 : 119 : { 120 941 : FindFileTLS *pTLSData = CPLGetFindFileTLS(); 121 941 : CPLFindFileFreeTLS(pTLSData); 122 941 : int bMemoryError = FALSE; 123 941 : CPLSetTLSWithFreeFuncEx(CTLS_FINDFILE, nullptr, nullptr, &bMemoryError); 124 : // TODO: if( bMemoryError ) {} 125 941 : } 126 : 127 : /************************************************************************/ 128 : /* CPLDefaultFindFile() */ 129 : /************************************************************************/ 130 : 131 : /** CPLDefaultFindFile */ 132 3006 : const char *CPLDefaultFindFile(const char *pszClass, const char *pszBasename) 133 : 134 : { 135 3006 : FindFileTLS *pTLSData = CPLGetFindFileTLS(); 136 3006 : if (pTLSData == nullptr) 137 0 : return nullptr; 138 3006 : const int nLocations = CSLCount(pTLSData->papszFinderLocations); 139 : 140 4044 : for (int i = nLocations - 1; i >= 0; i--) 141 : { 142 : const std::string osResult = CPLFormFilenameSafe( 143 3525 : pTLSData->papszFinderLocations[i], pszBasename, nullptr); 144 : 145 : VSIStatBufL sStat; 146 3525 : if (VSIStatL(osResult.c_str(), &sStat) == 0) 147 2487 : return CPLSPrintf("%s", osResult.c_str()); 148 : } 149 : 150 519 : 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 519 : return nullptr; 157 : } 158 : 159 : /************************************************************************/ 160 : /* CPLFindFile() */ 161 : /************************************************************************/ 162 : 163 : /** CPLFindFile */ 164 3006 : const char *CPLFindFile(const char *pszClass, const char *pszBasename) 165 : 166 : { 167 3006 : FindFileTLS *pTLSData = CPLFinderInit(); 168 3006 : if (pTLSData == nullptr) 169 0 : return nullptr; 170 : 171 3525 : for (int i = pTLSData->nFileFinders - 1; i >= 0; i--) 172 : { 173 : const char *pszResult = 174 3006 : (pTLSData->papfnFinders[i])(pszClass, pszBasename); 175 3006 : if (pszResult != nullptr) 176 2487 : return pszResult; 177 : } 178 : 179 519 : return nullptr; 180 : } 181 : 182 : /************************************************************************/ 183 : /* CPLPushFileFinder() */ 184 : /************************************************************************/ 185 : 186 : /** CPLPushFileFinder */ 187 213 : void CPLPushFileFinder(CPLFileFinder pfnFinder) 188 : 189 : { 190 213 : FindFileTLS *pTLSData = CPLFinderInit(); 191 213 : if (pTLSData == nullptr) 192 0 : return; 193 : 194 426 : pTLSData->papfnFinders = static_cast<CPLFileFinder *>( 195 426 : CPLRealloc(pTLSData->papfnFinders, 196 213 : sizeof(CPLFileFinder) * ++pTLSData->nFileFinders)); 197 213 : pTLSData->papfnFinders[pTLSData->nFileFinders - 1] = pfnFinder; 198 : } 199 : 200 : /************************************************************************/ 201 : /* CPLPopFileFinder() */ 202 : /************************************************************************/ 203 : 204 256 : CPLFileFinder CPLPopFileFinderInternal(FindFileTLS *pTLSData) 205 : 206 : { 207 256 : if (pTLSData == nullptr) 208 0 : return nullptr; 209 256 : if (pTLSData->nFileFinders == 0) 210 128 : return nullptr; 211 : 212 128 : CPLFileFinder pfnReturn = pTLSData->papfnFinders[--pTLSData->nFileFinders]; 213 : 214 128 : if (pTLSData->nFileFinders == 0) 215 : { 216 128 : CPLFree(pTLSData->papfnFinders); 217 128 : pTLSData->papfnFinders = nullptr; 218 : } 219 : 220 128 : 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 432 : void CPLPushFinderLocation(const char *pszLocation) 236 : 237 : { 238 432 : FindFileTLS *pTLSData = CPLFinderInit(); 239 432 : if (pTLSData == nullptr) 240 0 : return; 241 : // Check if location already is in list. 242 432 : if (CSLFindStringCaseSensitive(pTLSData->papszFinderLocations, 243 432 : pszLocation) > -1) 244 6 : return; 245 426 : pTLSData->papszFinderLocations = 246 426 : CSLAddStringMayFail(pTLSData->papszFinderLocations, pszLocation); 247 : } 248 : 249 : /************************************************************************/ 250 : /* CPLPopFinderLocation() */ 251 : /************************************************************************/ 252 : 253 256 : static void CPLPopFinderLocationInternal(FindFileTLS *pTLSData) 254 : 255 : { 256 256 : if (pTLSData == nullptr || pTLSData->papszFinderLocations == nullptr) 257 0 : return; 258 : 259 256 : const int nCount = CSLCount(pTLSData->papszFinderLocations); 260 256 : if (nCount == 0) 261 0 : return; 262 : 263 256 : CPLFree(pTLSData->papszFinderLocations[nCount - 1]); 264 256 : pTLSData->papszFinderLocations[nCount - 1] = nullptr; 265 : 266 256 : if (nCount == 1) 267 : { 268 128 : CPLFree(pTLSData->papszFinderLocations); 269 128 : pTLSData->papszFinderLocations = nullptr; 270 : } 271 : } 272 : 273 : /** CPLPopFinderLocation */ 274 0 : void CPLPopFinderLocation() 275 : { 276 0 : CPLPopFinderLocationInternal(CPLFinderInit()); 277 0 : }