LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/filegdb - FGdbDriver.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 88 113 77.9 %
Date: 2025-02-20 10:14:44 Functions: 7 8 87.5 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  OpenGIS Simple Features Reference Implementation
       4             :  * Purpose:  Implements FileGDB OGR driver.
       5             :  * Author:   Ragi Yaser Burhum, ragi@burhum.com
       6             :  *           Paul Ramsey, pramsey at cleverelephant.ca
       7             :  *
       8             :  ******************************************************************************
       9             :  * Copyright (c) 2010, Ragi Yaser Burhum
      10             :  * Copyright (c) 2011, Paul Ramsey <pramsey at cleverelephant.ca>
      11             :  * Copyright (c) 2011-2013, Even Rouault <even dot rouault at spatialys.com>
      12             :  *
      13             :  * SPDX-License-Identifier: MIT
      14             :  ****************************************************************************/
      15             : 
      16             : #include "ogr_fgdb.h"
      17             : #include "cpl_conv.h"
      18             : #include "FGdbUtils.h"
      19             : #include "cpl_multiproc.h"
      20             : #include "ogrmutexeddatasource.h"
      21             : #include "FGdbDriverCore.h"
      22             : 
      23             : extern "C" void RegisterOGRFileGDB();
      24             : 
      25             : static std::map<CPLString, FGdbDatabaseConnection *> *poMapConnections =
      26             :     nullptr;
      27             : CPLMutex *FGdbDriver::hMutex = nullptr;
      28             : 
      29             : /************************************************************************/
      30             : /*                     OGRFileGDBDriverUnload()                         */
      31             : /************************************************************************/
      32             : 
      33          11 : static void OGRFileGDBDriverUnload(GDALDriver *)
      34             : {
      35          11 :     if (poMapConnections && !poMapConnections->empty())
      36           0 :         CPLDebug("FileGDB", "Remaining %d connections. Bug?",
      37           0 :                  (int)poMapConnections->size());
      38          11 :     if (FGdbDriver::hMutex != nullptr)
      39           1 :         CPLDestroyMutex(FGdbDriver::hMutex);
      40          11 :     FGdbDriver::hMutex = nullptr;
      41          11 :     delete poMapConnections;
      42          11 :     poMapConnections = nullptr;
      43          11 : }
      44             : 
      45             : /************************************************************************/
      46             : /*                      OGRFileGDBDriverOpen()                          */
      47             : /************************************************************************/
      48             : 
      49          39 : static GDALDataset *OGRFileGDBDriverOpen(GDALOpenInfo *poOpenInfo)
      50             : {
      51          39 :     if (poOpenInfo->eAccess == GA_Update)
      52           1 :         return nullptr;
      53             : 
      54          38 :     const char *pszFilename = poOpenInfo->pszFilename;
      55             :     // @MAY_USE_OPENFILEGDB may be set to NO by the OpenFileGDB driver in its
      56             :     // Open() method when it detects that a dataset includes compressed tables
      57             :     // (.cdf), and thus calls the FileGDB driver to make it handle such
      58             :     // datasets. As the FileGDB driver would call, by default, OpenFileGDB for
      59             :     // assistance to get some information, OpenFileGDB needs to instruct it not
      60             :     // to do so to avoid a OpenFileGDB -> FileGDB -> OpenFileGDB cycle.
      61          38 :     const bool bUseOpenFileGDB = CPLTestBool(CSLFetchNameValueDef(
      62          38 :         poOpenInfo->papszOpenOptions, "@MAY_USE_OPENFILEGDB", "YES"));
      63             : 
      64          38 :     if (bUseOpenFileGDB)
      65             :     {
      66          36 :         if (OGRFileGDBDriverIdentifyInternal(poOpenInfo, pszFilename) ==
      67             :             GDAL_IDENTIFY_FALSE)
      68           0 :             return nullptr;
      69             : 
      70             :         // If this is a raster-only GDB, do not try to open it, to be consistent
      71             :         // with OpenFileGDB behavior.
      72          36 :         const char *const apszOpenFileGDBDriver[] = {"OpenFileGDB", nullptr};
      73             :         auto poOpenFileGDBDS = std::unique_ptr<GDALDataset>(
      74             :             GDALDataset::Open(pszFilename, GDAL_OF_RASTER,
      75          36 :                               apszOpenFileGDBDriver, nullptr, nullptr));
      76          36 :         if (poOpenFileGDBDS)
      77             :         {
      78           0 :             poOpenFileGDBDS.reset();
      79           0 :             poOpenFileGDBDS = std::unique_ptr<GDALDataset>(
      80             :                 GDALDataset::Open(pszFilename, GDAL_OF_VECTOR,
      81           0 :                                   apszOpenFileGDBDriver, nullptr, nullptr));
      82           0 :             if (!poOpenFileGDBDS)
      83           0 :                 return nullptr;
      84             :         }
      85             :     }
      86             : 
      87             :     long hr;
      88             : 
      89          76 :     CPLMutexHolderD(&FGdbDriver::hMutex);
      90          38 :     if (poMapConnections == nullptr)
      91           2 :         poMapConnections = new std::map<CPLString, FGdbDatabaseConnection *>();
      92             : 
      93          38 :     FGdbDatabaseConnection *pConnection = (*poMapConnections)[pszFilename];
      94          38 :     if (pConnection != nullptr)
      95             :     {
      96           4 :         pConnection->m_nRefCount++;
      97           4 :         CPLDebug("FileGDB", "ref_count of %s = %d now", pszFilename,
      98             :                  pConnection->m_nRefCount);
      99             :     }
     100             :     else
     101             :     {
     102          34 :         Geodatabase *pGeoDatabase = new Geodatabase;
     103          34 :         hr = ::OpenGeodatabase(StringToWString(pszFilename), *pGeoDatabase);
     104             : 
     105          34 :         if (FAILED(hr))
     106             :         {
     107           2 :             delete pGeoDatabase;
     108             : 
     109           2 :             if (OGRGetDriverByName("OpenFileGDB") != nullptr)
     110             :             {
     111           2 :                 std::wstring fgdb_error_desc_w;
     112           2 :                 std::string fgdb_error_desc("Unknown error");
     113             :                 fgdbError er;
     114           1 :                 er = FileGDBAPI::ErrorInfo::GetErrorDescription(
     115             :                     static_cast<fgdbError>(hr), fgdb_error_desc_w);
     116           1 :                 if (er == S_OK)
     117             :                 {
     118           1 :                     fgdb_error_desc = WStringToString(fgdb_error_desc_w);
     119             :                 }
     120           1 :                 CPLDebug("FileGDB",
     121             :                          "Cannot open %s with FileGDB driver: %s. Failing "
     122             :                          "silently so OpenFileGDB can be tried",
     123             :                          pszFilename, fgdb_error_desc.c_str());
     124             :             }
     125             :             else
     126             :             {
     127           1 :                 GDBErr(hr, "Failed to open Geodatabase");
     128             :             }
     129           2 :             poMapConnections->erase(pszFilename);
     130           2 :             return nullptr;
     131             :         }
     132             : 
     133          32 :         CPLDebug("FileGDB", "Really opening %s", pszFilename);
     134          32 :         pConnection = new FGdbDatabaseConnection(pszFilename, pGeoDatabase);
     135          32 :         (*poMapConnections)[pszFilename] = pConnection;
     136             :     }
     137             : 
     138             :     FGdbDataSource *pDS;
     139             : 
     140          36 :     pDS = new FGdbDataSource(true, pConnection, bUseOpenFileGDB);
     141             : 
     142          36 :     if (!pDS->Open(pszFilename, /*bUpdate = */ FALSE, nullptr))
     143             :     {
     144           0 :         delete pDS;
     145           0 :         return nullptr;
     146             :     }
     147             :     else
     148             :     {
     149             :         auto poMutexedDS =
     150          36 :             new OGRMutexedDataSource(pDS, TRUE, FGdbDriver::hMutex, TRUE);
     151          36 :         return poMutexedDS;
     152             :     }
     153             : }
     154             : 
     155             : /***********************************************************************/
     156             : /*                    OGRFileGDBDriverCreate()                         */
     157             : /***********************************************************************/
     158             : 
     159             : static GDALDataset *
     160           6 : OGRFileGDBDriverCreate(const char *pszName, CPL_UNUSED int nBands,
     161             :                        CPL_UNUSED int nXSize, CPL_UNUSED int nYSize,
     162             :                        CPL_UNUSED GDALDataType eDT, char **papszOptions)
     163             : {
     164             :     auto poOpenFileGDBDriver =
     165           6 :         GetGDALDriverManager()->GetDriverByName("OpenFileGDB");
     166           6 :     if (poOpenFileGDBDriver)
     167             :     {
     168           6 :         CPLError(
     169             :             CE_Warning, CPLE_AppDefined,
     170             :             "FileGDB driver has no longer any direct creation capabilities. "
     171             :             "Forwarding to OpenFileGDB driver");
     172           6 :         return poOpenFileGDBDriver->Create(pszName, 0, 0, 0, GDT_Unknown,
     173           6 :                                            papszOptions);
     174             :     }
     175           0 :     return nullptr;
     176             : }
     177             : 
     178             : /***********************************************************************/
     179             : /*                            Release()                                */
     180             : /***********************************************************************/
     181             : 
     182          36 : void FGdbDriver::Release(const char *pszName)
     183             : {
     184          72 :     CPLMutexHolderOptionalLockD(FGdbDriver::hMutex);
     185             : 
     186          36 :     if (poMapConnections == nullptr)
     187           0 :         poMapConnections = new std::map<CPLString, FGdbDatabaseConnection *>();
     188             : 
     189          36 :     FGdbDatabaseConnection *pConnection = (*poMapConnections)[pszName];
     190          36 :     if (pConnection != nullptr)
     191             :     {
     192          36 :         pConnection->m_nRefCount--;
     193          36 :         CPLDebug("FileGDB", "ref_count of %s = %d now", pszName,
     194             :                  pConnection->m_nRefCount);
     195          36 :         if (pConnection->m_nRefCount == 0)
     196             :         {
     197          32 :             pConnection->CloseGeodatabase();
     198          32 :             delete pConnection;
     199          32 :             poMapConnections->erase(pszName);
     200             :         }
     201             :     }
     202          36 : }
     203             : 
     204             : /***********************************************************************/
     205             : /*                         CloseGeodatabase()                          */
     206             : /***********************************************************************/
     207             : 
     208          32 : void FGdbDatabaseConnection::CloseGeodatabase()
     209             : {
     210          32 :     if (m_pGeodatabase != nullptr)
     211             :     {
     212          32 :         CPLDebug("FileGDB", "Really closing %s now", m_osName.c_str());
     213          32 :         ::CloseGeodatabase(*m_pGeodatabase);
     214          32 :         delete m_pGeodatabase;
     215          32 :         m_pGeodatabase = nullptr;
     216             :     }
     217          32 : }
     218             : 
     219             : /***********************************************************************/
     220             : /*                         OpenGeodatabase()                           */
     221             : /***********************************************************************/
     222             : 
     223           0 : int FGdbDatabaseConnection::OpenGeodatabase(const char *pszFSName)
     224             : {
     225           0 :     m_pGeodatabase = new Geodatabase;
     226           0 :     long hr = ::OpenGeodatabase(StringToWString(CPLString(pszFSName)),
     227           0 :                                 *m_pGeodatabase);
     228           0 :     if (FAILED(hr))
     229             :     {
     230           0 :         delete m_pGeodatabase;
     231           0 :         m_pGeodatabase = nullptr;
     232           0 :         return FALSE;
     233             :     }
     234           0 :     return TRUE;
     235             : }
     236             : 
     237             : /************************************************************************/
     238             : /*                     OGRFileGDBDeleteDataSource()                     */
     239             : /************************************************************************/
     240             : 
     241           1 : static CPLErr OGRFileGDBDeleteDataSource(const char *pszDataSource)
     242             : {
     243           2 :     CPLMutexHolderD(&FGdbDriver::hMutex);
     244             : 
     245           3 :     std::wstring wstr = StringToWString(pszDataSource);
     246             : 
     247           1 :     long hr = 0;
     248             : 
     249           1 :     if (S_OK != (hr = ::DeleteGeodatabase(wstr)))
     250             :     {
     251           0 :         GDBErr(hr, "Failed to delete Geodatabase");
     252           0 :         return CE_Failure;
     253             :     }
     254             : 
     255           1 :     return CE_None;
     256             : }
     257             : 
     258             : /***********************************************************************/
     259             : /*                       RegisterOGRFileGDB()                          */
     260             : /***********************************************************************/
     261             : 
     262          15 : void RegisterOGRFileGDB()
     263             : 
     264             : {
     265          15 :     if (GDALGetDriverByName(DRIVER_NAME) != nullptr)
     266           0 :         return;
     267             : 
     268          15 :     if (!GDAL_CHECK_VERSION("OGR FGDB"))
     269           0 :         return;
     270             : 
     271          15 :     GDALDriver *poDriver = new GDALDriver();
     272          15 :     OGRFileGDBDriverSetCommonMetadata(poDriver);
     273             : 
     274          15 :     poDriver->pfnOpen = OGRFileGDBDriverOpen;
     275          15 :     poDriver->pfnCreate = OGRFileGDBDriverCreate;
     276          15 :     poDriver->pfnDelete = OGRFileGDBDeleteDataSource;
     277          15 :     poDriver->pfnUnloadDriver = OGRFileGDBDriverUnload;
     278             : 
     279          15 :     GetGDALDriverManager()->RegisterDriver(poDriver);
     280             : }

Generated by: LCOV version 1.14