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 933 : static void CPLFindFileFreeTLS(void *pData) 39 : { 40 933 : FindFileTLS *pTLSData = reinterpret_cast<FindFileTLS *>(pData); 41 933 : 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 933 : CPLFree(pTLSData); 52 933 : } 53 : 54 : /************************************************************************/ 55 : /* CPLGetFindFileTLS() */ 56 : /************************************************************************/ 57 : 58 7432 : static FindFileTLS *CPLGetFindFileTLS() 59 : { 60 7432 : int bMemoryError = FALSE; 61 : FindFileTLS *pTLSData = reinterpret_cast<FindFileTLS *>( 62 7432 : CPLGetTLSEx(CTLS_FINDFILE, &bMemoryError)); 63 7432 : if (bMemoryError) 64 0 : return nullptr; 65 7432 : if (pTLSData == nullptr) 66 : { 67 : pTLSData = static_cast<FindFileTLS *>( 68 1012 : VSI_CALLOC_VERBOSE(1, sizeof(FindFileTLS))); 69 1012 : if (pTLSData == nullptr) 70 0 : return nullptr; 71 1012 : CPLSetTLSWithFreeFunc(CTLS_FINDFILE, pTLSData, CPLFindFileFreeTLS); 72 : } 73 7432 : return pTLSData; 74 : } 75 : 76 : /************************************************************************/ 77 : /* CPLFinderInit() */ 78 : /************************************************************************/ 79 : 80 3563 : static FindFileTLS *CPLFinderInit() 81 : 82 : { 83 3563 : FindFileTLS *pTLSData = CPLGetFindFileTLS(); 84 3563 : if (pTLSData != nullptr && !pTLSData->bFinderInitialized) 85 : { 86 207 : pTLSData->bFinderInitialized = true; 87 207 : CPLPushFileFinder(CPLDefaultFindFile); 88 : 89 207 : CPLPushFinderLocation("."); 90 : 91 207 : if (CPLGetConfigOption("GDAL_DATA", nullptr) != nullptr) 92 : { 93 205 : 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 3563 : return pTLSData; 110 : } 111 : 112 : /************************************************************************/ 113 : /* CPLFinderClean() */ 114 : /************************************************************************/ 115 : 116 : /** CPLFinderClean */ 117 933 : void CPLFinderClean() 118 : 119 : { 120 933 : FindFileTLS *pTLSData = CPLGetFindFileTLS(); 121 933 : CPLFindFileFreeTLS(pTLSData); 122 933 : int bMemoryError = FALSE; 123 933 : CPLSetTLSWithFreeFuncEx(CTLS_FINDFILE, nullptr, nullptr, &bMemoryError); 124 : // TODO: if( bMemoryError ) {} 125 933 : } 126 : 127 : /************************************************************************/ 128 : /* CPLDefaultFindFile() */ 129 : /************************************************************************/ 130 : 131 : /** CPLDefaultFindFile */ 132 2936 : const char *CPLDefaultFindFile(const char *pszClass, const char *pszBasename) 133 : 134 : { 135 2936 : FindFileTLS *pTLSData = CPLGetFindFileTLS(); 136 2936 : if (pTLSData == nullptr) 137 0 : return nullptr; 138 2936 : const int nLocations = CSLCount(pTLSData->papszFinderLocations); 139 : 140 3974 : for (int i = nLocations - 1; i >= 0; i--) 141 : { 142 6910 : const char *pszResult = CPLFormFilename( 143 3455 : pTLSData->papszFinderLocations[i], pszBasename, nullptr); 144 : 145 : VSIStatBufL sStat; 146 3455 : if (VSIStatL(pszResult, &sStat) == 0) 147 2417 : return pszResult; 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 2936 : const char *CPLFindFile(const char *pszClass, const char *pszBasename) 165 : 166 : { 167 2936 : FindFileTLS *pTLSData = CPLFinderInit(); 168 2936 : if (pTLSData == nullptr) 169 0 : return nullptr; 170 : 171 3455 : for (int i = pTLSData->nFileFinders - 1; i >= 0; i--) 172 : { 173 : const char *pszResult = 174 2936 : (pTLSData->papfnFinders[i])(pszClass, pszBasename); 175 2936 : if (pszResult != nullptr) 176 2417 : return pszResult; 177 : } 178 : 179 519 : return nullptr; 180 : } 181 : 182 : /************************************************************************/ 183 : /* CPLPushFileFinder() */ 184 : /************************************************************************/ 185 : 186 : /** CPLPushFileFinder */ 187 207 : void CPLPushFileFinder(CPLFileFinder pfnFinder) 188 : 189 : { 190 207 : FindFileTLS *pTLSData = CPLFinderInit(); 191 207 : if (pTLSData == nullptr) 192 0 : return; 193 : 194 414 : pTLSData->papfnFinders = static_cast<CPLFileFinder *>( 195 414 : CPLRealloc(pTLSData->papfnFinders, 196 207 : sizeof(CPLFileFinder) * ++pTLSData->nFileFinders)); 197 207 : 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 420 : void CPLPushFinderLocation(const char *pszLocation) 236 : 237 : { 238 420 : FindFileTLS *pTLSData = CPLFinderInit(); 239 420 : if (pTLSData == nullptr) 240 0 : return; 241 : // Check if location already is in list. 242 420 : if (CSLFindStringCaseSensitive(pTLSData->papszFinderLocations, 243 420 : pszLocation) > -1) 244 6 : return; 245 414 : pTLSData->papszFinderLocations = 246 414 : 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 : }