LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/mitab - mitab_ogr_driver.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 105 107 98.1 %
Date: 2024-11-21 22:18:42 Functions: 6 6 100.0 %

          Line data    Source code
       1             : /**********************************************************************
       2             :  *
       3             :  * Name:     mitab_ogr_driver.cpp
       4             :  * Project:  MapInfo Mid/Mif, Tab ogr support
       5             :  * Language: C++
       6             :  * Purpose:  Implementation of the MIDDATAFile class used to handle
       7             :  *           reading/writing of the MID/MIF files
       8             :  * Author:   Stephane Villeneuve, stephane.v@videotron.ca
       9             :  *
      10             :  **********************************************************************
      11             :  * Copyright (c) 1999, 2000, Stephane Villeneuve
      12             :  * Copyright (c) 2014, Even Rouault <even.rouault at spatialys.com>
      13             :  *
      14             :  * SPDX-License-Identifier: MIT
      15             :  **********************************************************************/
      16             : 
      17             : #include "mitab_ogr_driver.h"
      18             : 
      19             : /************************************************************************/
      20             : /*                  OGRTABDriverIdentify()                              */
      21             : /************************************************************************/
      22             : 
      23       54187 : static int OGRTABDriverIdentify(GDALOpenInfo *poOpenInfo)
      24             : 
      25             : {
      26             :     // Files not ending with .tab, .mif or .mid are not handled by this driver.
      27       54187 :     if (!poOpenInfo->bStatOK)
      28       43114 :         return FALSE;
      29       11073 :     if (poOpenInfo->bIsDirectory)
      30        1383 :         return -1;  // Unsure.
      31        9690 :     if (poOpenInfo->fpL == nullptr)
      32          83 :         return FALSE;
      33       17480 :     if (EQUAL(CPLGetExtension(poOpenInfo->pszFilename), "MIF") ||
      34        7873 :         EQUAL(CPLGetExtension(poOpenInfo->pszFilename), "MID"))
      35             :     {
      36        1734 :         return TRUE;
      37             :     }
      38        7873 :     if (EQUAL(CPLGetExtension(poOpenInfo->pszFilename), "TAB"))
      39             :     {
      40      224878 :         for (int i = 0; i < poOpenInfo->nHeaderBytes; i++)
      41             :         {
      42      224878 :             const char *pszLine =
      43      224878 :                 reinterpret_cast<const char *>(poOpenInfo->pabyHeader) + i;
      44      224878 :             if (STARTS_WITH_CI(pszLine, "Fields"))
      45        2474 :                 return TRUE;
      46      222404 :             else if (STARTS_WITH_CI(pszLine, "create view"))
      47           4 :                 return TRUE;
      48      222400 :             else if (STARTS_WITH_CI(pszLine, "\"\\IsSeamless\" = \"TRUE\""))
      49           0 :                 return TRUE;
      50             :         }
      51             :     }
      52             : #ifdef DEBUG
      53             :     // For AFL, so that .cur_input is detected as the archive filename.
      54       10790 :     if (!STARTS_WITH(poOpenInfo->pszFilename, "/vsitar/") &&
      55        5395 :         EQUAL(CPLGetFilename(poOpenInfo->pszFilename), ".cur_input"))
      56             :     {
      57           4 :         return -1;
      58             :     }
      59             : #endif
      60        5391 :     return FALSE;
      61             : }
      62             : 
      63             : /************************************************************************/
      64             : /*                  OGRTABDriver::Open()                                */
      65             : /************************************************************************/
      66             : 
      67        2817 : static GDALDataset *OGRTABDriverOpen(GDALOpenInfo *poOpenInfo)
      68             : 
      69             : {
      70        2817 :     if (OGRTABDriverIdentify(poOpenInfo) == FALSE)
      71             :     {
      72           2 :         return nullptr;
      73             :     }
      74             : 
      75        4761 :     if (EQUAL(CPLGetExtension(poOpenInfo->pszFilename), "MIF") ||
      76        1946 :         EQUAL(CPLGetExtension(poOpenInfo->pszFilename), "MID"))
      77             :     {
      78         869 :         if (poOpenInfo->eAccess == GA_Update)
      79           0 :             return nullptr;
      80             :     }
      81             : 
      82             : #ifdef DEBUG
      83             :     // For AFL, so that .cur_input is detected as the archive filename.
      84        7744 :     if (poOpenInfo->fpL != nullptr &&
      85        4929 :         !STARTS_WITH(poOpenInfo->pszFilename, "/vsitar/") &&
      86        2114 :         EQUAL(CPLGetFilename(poOpenInfo->pszFilename), ".cur_input"))
      87             :     {
      88             :         GDALOpenInfo oOpenInfo(
      89           4 :             (CPLString("/vsitar/") + poOpenInfo->pszFilename).c_str(),
      90           6 :             poOpenInfo->nOpenFlags);
      91           2 :         oOpenInfo.papszOpenOptions = poOpenInfo->papszOpenOptions;
      92           2 :         return OGRTABDriverOpen(&oOpenInfo);
      93             :     }
      94             : #endif
      95             : 
      96        2813 :     OGRTABDataSource *poDS = new OGRTABDataSource();
      97        2813 :     if (!poDS->Open(poOpenInfo, TRUE))
      98             :     {
      99         730 :         delete poDS;
     100         730 :         return nullptr;
     101             :     }
     102             : 
     103        2083 :     return poDS;
     104             : }
     105             : 
     106             : /************************************************************************/
     107             : /*                              Create()                                */
     108             : /************************************************************************/
     109             : 
     110             : static GDALDataset *
     111         193 : OGRTABDriverCreate(const char *pszName, CPL_UNUSED int nBands,
     112             :                    CPL_UNUSED int nXSize, CPL_UNUSED int nYSize,
     113             :                    CPL_UNUSED GDALDataType eDT, char **papszOptions)
     114             : {
     115             :     // Try to create the data source.
     116         193 :     OGRTABDataSource *poDS = new OGRTABDataSource();
     117         193 :     if (!poDS->Create(pszName, papszOptions))
     118             :     {
     119           2 :         delete poDS;
     120           2 :         return nullptr;
     121             :     }
     122             : 
     123         191 :     return poDS;
     124             : }
     125             : 
     126             : /************************************************************************/
     127             : /*                              Delete()                                */
     128             : /************************************************************************/
     129             : 
     130          48 : static CPLErr OGRTABDriverDelete(const char *pszDataSource)
     131             : 
     132             : {
     133          48 :     GDALDataset *poDS = nullptr;
     134             :     {
     135             :         // Make sure that the file opened by GDALOpenInfo is closed
     136             :         // when the object goes out of scope
     137          48 :         GDALOpenInfo oOpenInfo(pszDataSource, GA_ReadOnly);
     138          48 :         poDS = OGRTABDriverOpen(&oOpenInfo);
     139             :     }
     140          48 :     if (poDS == nullptr)
     141          16 :         return CE_Failure;
     142          32 :     char **papszFileList = poDS->GetFileList();
     143          32 :     delete poDS;
     144             : 
     145          32 :     char **papszIter = papszFileList;
     146         216 :     while (papszIter && *papszIter)
     147             :     {
     148         184 :         VSIUnlink(*papszIter);
     149         184 :         papszIter++;
     150             :     }
     151          32 :     CSLDestroy(papszFileList);
     152             : 
     153             :     VSIStatBufL sStatBuf;
     154          32 :     if (VSIStatL(pszDataSource, &sStatBuf) == 0 && VSI_ISDIR(sStatBuf.st_mode))
     155             :     {
     156          16 :         VSIRmdir(pszDataSource);
     157             :     }
     158             : 
     159          32 :     return CE_None;
     160             : }
     161             : 
     162             : /************************************************************************/
     163             : /*                          OGRTABDriverUnload()                        */
     164             : /************************************************************************/
     165             : 
     166         933 : static void OGRTABDriverUnload(CPL_UNUSED GDALDriver *poDriver)
     167             : {
     168         933 :     MITABFreeCoordSysTable();
     169         933 : }
     170             : 
     171             : /************************************************************************/
     172             : /*              RegisterOGRTAB()                                        */
     173             : /************************************************************************/
     174             : 
     175        1595 : void RegisterOGRTAB()
     176             : 
     177             : {
     178        1595 :     if (GDALGetDriverByName("MapInfo File") != nullptr)
     179         302 :         return;
     180             : 
     181        1293 :     GDALDriver *poDriver = new GDALDriver();
     182             : 
     183        1293 :     poDriver->SetDescription("MapInfo File");
     184        1293 :     poDriver->SetMetadataItem(GDAL_DCAP_VECTOR, "YES");
     185        1293 :     poDriver->SetMetadataItem(GDAL_DCAP_CREATE_LAYER, "YES");
     186        1293 :     poDriver->SetMetadataItem(GDAL_DCAP_CREATE_FIELD, "YES");
     187        1293 :     poDriver->SetMetadataItem(GDAL_DCAP_DELETE_FIELD, "YES");
     188        1293 :     poDriver->SetMetadataItem(GDAL_DCAP_REORDER_FIELDS, "YES");
     189        1293 :     poDriver->SetMetadataItem(GDAL_DMD_SUPPORTED_SQL_DIALECTS, "OGRSQL SQLITE");
     190             : 
     191        1293 :     poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "MapInfo File");
     192        1293 :     poDriver->SetMetadataItem(GDAL_DMD_EXTENSIONS, "tab mif mid");
     193        1293 :     poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/vector/mitab.html");
     194        1293 :     poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
     195        1293 :     poDriver->SetMetadataItem(GDAL_DMD_NUMERIC_FIELD_WIDTH_INCLUDES_SIGN,
     196        1293 :                               "YES");
     197        1293 :     poDriver->SetMetadataItem(
     198        1293 :         GDAL_DMD_NUMERIC_FIELD_WIDTH_INCLUDES_DECIMAL_SEPARATOR, "YES");
     199             : 
     200        1293 :     poDriver->SetMetadataItem(
     201             :         GDAL_DS_LAYER_CREATIONOPTIONLIST,
     202             :         "<LayerCreationOptionList>"
     203             :         "  <Option name='BOUNDS' type='string' "
     204             :         "description='Custom bounds. Expect format is "
     205             :         "xmin,ymin,xmax,ymax'/>"
     206             :         "  <Option name='ENCODING' type='string' "
     207             :         "description='to override the encoding "
     208             :         "interpretation of the DAT/MID with any encoding "
     209             :         "supported by CPLRecode or to \"\" to avoid any "
     210             :         "recoding (Neutral charset)'/>"
     211             :         "  <Option name='DESCRIPTION' type='string' "
     212             :         "description='Friendly name of table. Only for tab "
     213             :         "format.'/>"  // See
     214             :         // https://support.pitneybowes.com/SearchArticles/VFP05_KnowledgeWithSidebarHowTo?id=kA180000000CtuHCAS&popup=false&lang=en_US
     215             :         "  <Option name='STRICT_FIELDS_NAME_LAUNDERING' type='boolean' "
     216             :         "default='YES' description='Field name consisting of alphanumeric "
     217             :         "only, maximum length 31'/>"
     218        1293 :         "</LayerCreationOptionList>");
     219             : 
     220        1293 :     poDriver->SetMetadataItem(
     221             :         GDAL_DMD_CREATIONOPTIONLIST,
     222             :         "<CreationOptionList>"
     223             :         "  <Option name='FORMAT' type='string-select' description='type of "
     224             :         "MapInfo format'>"
     225             :         "    <Value>MIF</Value>"
     226             :         "    <Value>TAB</Value>"
     227             :         "  </Option>"
     228             :         "  <Option name='SPATIAL_INDEX_MODE' type='string-select' "
     229             :         "description='type of spatial index' default='QUICK'>"
     230             :         "    <Value>QUICK</Value>"
     231             :         "    <Value>OPTIMIZED</Value>"
     232             :         "  </Option>"
     233             :         "  <Option name='BLOCKSIZE' type='int' description='.map block size' "
     234             :         "min='512' max='32256' default='512'/>"
     235             :         "  <Option name='ENCODING' type='string' description='to override the "
     236             :         "encoding interpretation of the DAT/MID with any encoding supported by "
     237             :         "CPLRecode or to \"\" to avoid any recoding (Neutral charset)'/>"
     238             :         "  <Option name='STRICT_FIELDS_NAME_LAUNDERING' type='boolean' "
     239             :         "default='YES' description='Field name consisting of alphanumeric "
     240             :         "only, maximum length 31'/>"
     241        1293 :         "</CreationOptionList>");
     242             : 
     243        1293 :     poDriver->SetMetadataItem(
     244             :         GDAL_DMD_CREATIONFIELDDATATYPES,
     245        1293 :         "Integer Integer64 Real String Date DateTime Time");
     246        1293 :     poDriver->SetMetadataItem(GDAL_DMD_CREATIONFIELDDATASUBTYPES, "Boolean");
     247        1293 :     poDriver->SetMetadataItem(GDAL_DMD_CREATION_FIELD_DEFN_FLAGS,
     248        1293 :                               "WidthPrecision");
     249        1293 :     poDriver->SetMetadataItem(GDAL_DMD_ALTER_FIELD_DEFN_FLAGS,
     250        1293 :                               "Name Type WidthPrecision");
     251        1293 :     poDriver->SetMetadataItem(GDAL_DCAP_FEATURE_STYLES, "YES");
     252        1293 :     poDriver->SetMetadataItem(GDAL_DCAP_FEATURE_STYLES_READ, "YES");
     253        1293 :     poDriver->SetMetadataItem(GDAL_DCAP_FEATURE_STYLES_WRITE, "YES");
     254             : 
     255        1293 :     poDriver->pfnOpen = OGRTABDriverOpen;
     256        1293 :     poDriver->pfnIdentify = OGRTABDriverIdentify;
     257        1293 :     poDriver->pfnCreate = OGRTABDriverCreate;
     258        1293 :     poDriver->pfnDelete = OGRTABDriverDelete;
     259        1293 :     poDriver->pfnUnloadDriver = OGRTABDriverUnload;
     260             : 
     261        1293 :     GetGDALDriverManager()->RegisterDriver(poDriver);
     262             : }

Generated by: LCOV version 1.14