LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/tiger - ogrtigerdatasource.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 63 289 21.8 %
Date: 2025-01-18 12:42:00 Functions: 5 16 31.2 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  TIGER/Line Translator
       4             :  * Purpose:  Implements OGRTigerDataSource class
       5             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 1999, Frank Warmerdam <warmerdam@pobox.com>
       9             :  *
      10             :  * SPDX-License-Identifier: MIT
      11             :  ****************************************************************************/
      12             : 
      13             : #include "cpl_conv.h"
      14             : #include "cpl_string.h"
      15             : #include "ogr_tiger.h"
      16             : 
      17             : #include <cctype>
      18             : #include <algorithm>
      19             : 
      20             : #define DIGIT_ZERO '0'
      21             : 
      22             : /************************************************************************/
      23             : /*                        TigerClassifyVersion()                        */
      24             : /************************************************************************/
      25             : 
      26           0 : TigerVersion TigerClassifyVersion(int nVersionCode)
      27             : 
      28             : {
      29             :     TigerVersion nVersion;
      30             :     int nYear, nMonth;
      31             : 
      32             :     /*
      33             :     ** TIGER Versions
      34             :     **
      35             :     ** 0000           TIGER/Line Precensus Files, 1990
      36             :     ** 0002           TIGER/Line Initial Voting District Codes Files, 1990
      37             :     ** 0003           TIGER/Line Files, 1990
      38             :     ** 0005           TIGER/Line Files, 1992
      39             :     ** 0021           TIGER/Line Files, 1994
      40             :     ** 0024           TIGER/Line Files, 1995
      41             :     ** 9706 to 9810   TIGER/Line Files, 1997
      42             :     ** 9812 to 9904   TIGER/Line Files, 1998
      43             :     ** 0006 to 0008   TIGER/Line Files, 1999
      44             :     ** 0010 to 0011   TIGER/Line Files, Redistricting Census 2000
      45             :     ** 0103 to 0108   TIGER/Line Files, Census 2000
      46             :     **
      47             :     ** 0203 to 0205   TIGER/Line Files, UA 2000
      48             :     ** ????    ????
      49             :     **
      50             :     ** 0206 to 0299   TIGER/Line Files, 2002
      51             :     ** 0300 to 0399   TIGER/Line Files, 2003
      52             :     ** 0400+          TIGER/Line Files, 2004 - one sample is 0405
      53             :     ** ????
      54             :     */
      55             : 
      56           0 :     nVersion = TIGER_Unknown;
      57           0 :     if (nVersionCode == 0)
      58           0 :         nVersion = TIGER_1990_Precensus;
      59           0 :     else if (nVersionCode == 2)
      60           0 :         nVersion = TIGER_1990;
      61           0 :     else if (nVersionCode == 3)
      62           0 :         nVersion = TIGER_1992;
      63           0 :     else if (nVersionCode == 5)
      64           0 :         nVersion = TIGER_1994;
      65           0 :     else if (nVersionCode == 21)
      66           0 :         nVersion = TIGER_1994;
      67           0 :     else if (nVersionCode == 24)
      68           0 :         nVersion = TIGER_1995;
      69             : 
      70           0 :     else if (nVersionCode == 9999) /* special hack, fme bug 7625 */
      71           0 :         nVersion = TIGER_UA2000;
      72             : 
      73           0 :     nYear = nVersionCode % 100;
      74           0 :     nMonth = nVersionCode / 100;
      75             : 
      76           0 :     nVersionCode = nYear * 100 + nMonth;
      77             : 
      78           0 :     if (nVersion != TIGER_Unknown)
      79             :         /* do nothing */;
      80           0 :     else if (nVersionCode >= 9706 && nVersionCode <= 9810)
      81           0 :         nVersion = TIGER_1997;
      82           0 :     else if (nVersionCode >= 9812 && nVersionCode <= 9904)
      83           0 :         nVersion = TIGER_1998;
      84           0 :     else if (nVersionCode >= 6 /*0006*/ && nVersionCode <= 8 /*0008*/)
      85           0 :         nVersion = TIGER_1999;
      86           0 :     else if (nVersionCode >= 10 /*0010*/ && nVersionCode <= 11 /*0011*/)
      87           0 :         nVersion = TIGER_2000_Redistricting;
      88           0 :     else if (nVersionCode >= 103 /*0103*/ && nVersionCode <= 108 /*0108*/)
      89           0 :         nVersion = TIGER_2000_Census;
      90           0 :     else if (nVersionCode >= 203 /*0302*/ && nVersionCode <= 205 /*0502*/)
      91           0 :         nVersion = TIGER_UA2000;
      92           0 :     else if (nVersionCode >= 210 /*1002*/ && nVersionCode <= 306 /*0603*/)
      93           0 :         nVersion = TIGER_2002;
      94           0 :     else if (nVersionCode >= 312 /*1203*/ && nVersionCode <= 403 /*0304*/)
      95           0 :         nVersion = TIGER_2003;
      96           0 :     else if (nVersionCode >= 404)
      97           0 :         nVersion = TIGER_2004;
      98             : 
      99           0 :     return nVersion;
     100             : }
     101             : 
     102             : /************************************************************************/
     103             : /*                         TigerVersionString()                         */
     104             : /************************************************************************/
     105             : 
     106           0 : const char *TigerVersionString(TigerVersion nVersion)
     107             : {
     108             : 
     109           0 :     if (nVersion == TIGER_1990_Precensus)
     110             :     {
     111           0 :         return "TIGER_1990_Precensus";
     112             :     }
     113           0 :     if (nVersion == TIGER_1990)
     114             :     {
     115           0 :         return "TIGER_1990";
     116             :     }
     117           0 :     if (nVersion == TIGER_1992)
     118             :     {
     119           0 :         return "TIGER_1992";
     120             :     }
     121           0 :     if (nVersion == TIGER_1994)
     122             :     {
     123           0 :         return "TIGER_1994";
     124             :     }
     125           0 :     if (nVersion == TIGER_1995)
     126             :     {
     127           0 :         return "TIGER_1995";
     128             :     }
     129           0 :     if (nVersion == TIGER_1997)
     130             :     {
     131           0 :         return "TIGER_1997";
     132             :     }
     133           0 :     if (nVersion == TIGER_1998)
     134             :     {
     135           0 :         return "TIGER_1998";
     136             :     }
     137           0 :     if (nVersion == TIGER_1999)
     138             :     {
     139           0 :         return "TIGER_1999";
     140             :     }
     141           0 :     if (nVersion == TIGER_2000_Redistricting)
     142             :     {
     143           0 :         return "TIGER_2000_Redistricting";
     144             :     }
     145           0 :     if (nVersion == TIGER_UA2000)
     146             :     {
     147           0 :         return "TIGER_UA2000";
     148             :     }
     149           0 :     if (nVersion == TIGER_2002)
     150             :     {
     151           0 :         return "TIGER_2002";
     152             :     }
     153           0 :     if (nVersion == TIGER_2003)
     154             :     {
     155           0 :         return "TIGER_2003";
     156             :     }
     157           0 :     if (nVersion == TIGER_2004)
     158             :     {
     159           0 :         return "TIGER_2004";
     160             :     }
     161           0 :     if (nVersion == TIGER_Unknown)
     162             :     {
     163           0 :         return "TIGER_Unknown";
     164             :     }
     165           0 :     return "???";
     166             : }
     167             : 
     168             : /************************************************************************/
     169             : /*                         TigerCheckVersion()                          */
     170             : /*                                                                      */
     171             : /*      Some tiger products seem to be generated with version info      */
     172             : /*      that doesn't match the tiger specs.  We can sometimes           */
     173             : /*      recognise the wrongness by checking the record length of        */
     174             : /*      some well known changing files and adjusting the version        */
     175             : /*      based on this.                                                  */
     176             : /************************************************************************/
     177             : 
     178           0 : TigerVersion OGRTigerDataSource::TigerCheckVersion(TigerVersion nOldVersion,
     179             :                                                    const char *pszFilename)
     180             : 
     181             : {
     182           0 :     if (nOldVersion != TIGER_2002)
     183           0 :         return nOldVersion;
     184             : 
     185           0 :     char *pszRTCFilename = BuildFilename(pszFilename, "C");
     186           0 :     VSILFILE *fp = VSIFOpenL(pszRTCFilename, "rb");
     187           0 :     CPLFree(pszRTCFilename);
     188             : 
     189           0 :     if (fp == nullptr)
     190           0 :         return nOldVersion;
     191             : 
     192             :     char szHeader[115];
     193             : 
     194           0 :     if (VSIFReadL(szHeader, sizeof(szHeader) - 1, 1, fp) < 1)
     195             :     {
     196           0 :         VSIFCloseL(fp);
     197           0 :         return nOldVersion;
     198             :     }
     199             : 
     200           0 :     VSIFCloseL(fp);
     201             : 
     202             :     /* -------------------------------------------------------------------- */
     203             :     /*      Is the record length 112?  If so, it is an older version        */
     204             :     /*      than 2002.                                                      */
     205             :     /* -------------------------------------------------------------------- */
     206           0 :     if (szHeader[112] == 10 || szHeader[112] == 13)
     207             :     {
     208           0 :         CPLDebug("TIGER",
     209             :                  "Forcing version back to UA2000 since RTC records are short.");
     210           0 :         return TIGER_UA2000;
     211             :     }
     212             : 
     213           0 :     return nOldVersion;
     214             : }
     215             : 
     216             : /************************************************************************/
     217             : /*                         OGRTigerDataSource()                         */
     218             : /************************************************************************/
     219             : 
     220         511 : OGRTigerDataSource::OGRTigerDataSource()
     221         511 :     : nLayers(0), papoLayers(nullptr), poSpatialRef(new OGRSpatialReference()),
     222             :       papszOptions(nullptr), pszPath(nullptr), nModules(0),
     223         511 :       papszModules(nullptr), nVersionCode(0), nVersion(TIGER_Unknown)
     224             : {
     225         511 :     poSpatialRef->SetWellKnownGeogCS("NAD83");
     226         511 :     poSpatialRef->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
     227         511 : }
     228             : 
     229             : /************************************************************************/
     230             : /*                        ~OGRTigerDataSource()                         */
     231             : /************************************************************************/
     232             : 
     233        1022 : OGRTigerDataSource::~OGRTigerDataSource()
     234             : 
     235             : {
     236         511 :     for (int i = 0; i < nLayers; i++)
     237           0 :         delete papoLayers[i];
     238             : 
     239         511 :     CPLFree(papoLayers);
     240             : 
     241         511 :     CPLFree(pszPath);
     242             : 
     243         511 :     CSLDestroy(papszOptions);
     244             : 
     245         511 :     CSLDestroy(papszModules);
     246             : 
     247         511 :     delete poSpatialRef;
     248        1022 : }
     249             : 
     250             : /************************************************************************/
     251             : /*                              AddLayer()                              */
     252             : /************************************************************************/
     253             : 
     254           0 : void OGRTigerDataSource::AddLayer(OGRTigerLayer *poNewLayer)
     255             : 
     256             : {
     257           0 :     poNewLayer->SetDescription(poNewLayer->GetName());
     258           0 :     papoLayers = static_cast<OGRTigerLayer **>(
     259           0 :         CPLRealloc(papoLayers, sizeof(void *) * ++nLayers));
     260             : 
     261           0 :     papoLayers[nLayers - 1] = poNewLayer;
     262           0 : }
     263             : 
     264             : /************************************************************************/
     265             : /*                              GetLayer()                              */
     266             : /************************************************************************/
     267             : 
     268           0 : OGRLayer *OGRTigerDataSource::GetLayer(int iLayer)
     269             : 
     270             : {
     271           0 :     if (iLayer < 0 || iLayer >= nLayers)
     272           0 :         return nullptr;
     273             : 
     274           0 :     return papoLayers[iLayer];
     275             : }
     276             : 
     277             : /************************************************************************/
     278             : /*                              GetLayer()                              */
     279             : /************************************************************************/
     280             : 
     281           0 : OGRLayer *OGRTigerDataSource::GetLayer(const char *pszLayerName)
     282             : 
     283             : {
     284           0 :     for (int iLayer = 0; iLayer < nLayers; iLayer++)
     285             :     {
     286           0 :         if (EQUAL(papoLayers[iLayer]->GetLayerDefn()->GetName(), pszLayerName))
     287           0 :             return papoLayers[iLayer];
     288             :     }
     289             : 
     290           0 :     return nullptr;
     291             : }
     292             : 
     293             : /************************************************************************/
     294             : /*                           GetLayerCount()                            */
     295             : /************************************************************************/
     296             : 
     297           0 : int OGRTigerDataSource::GetLayerCount()
     298             : 
     299             : {
     300           0 :     return nLayers;
     301             : }
     302             : 
     303             : /************************************************************************/
     304             : /*                                Open()                                */
     305             : /************************************************************************/
     306             : 
     307         511 : int OGRTigerDataSource::Open(const char *pszFilename, int bTestOpen,
     308             :                              char **papszLimitedFileList)
     309             : 
     310             : {
     311             :     /* -------------------------------------------------------------------- */
     312             :     /*      Is the given path a directory or a regular file?                */
     313             :     /* -------------------------------------------------------------------- */
     314             :     VSIStatBufL stat;
     315             : 
     316         511 :     if (VSIStatExL(pszFilename, &stat,
     317        1022 :                    VSI_STAT_EXISTS_FLAG | VSI_STAT_NATURE_FLAG) != 0 ||
     318         511 :         (!VSI_ISDIR(stat.st_mode) && !VSI_ISREG(stat.st_mode)))
     319             :     {
     320           0 :         if (!bTestOpen)
     321           0 :             CPLError(
     322             :                 CE_Failure, CPLE_AppDefined,
     323             :                 "%s is neither a file or directory, Tiger access failed.\n",
     324             :                 pszFilename);
     325             : 
     326           0 :         return FALSE;
     327             :     }
     328             : 
     329             :     /* -------------------------------------------------------------------- */
     330             :     /*      Build a list of filenames we figure are Tiger files.            */
     331             :     /* -------------------------------------------------------------------- */
     332         511 :     char **papszFileList = nullptr;
     333         511 :     if (VSI_ISREG(stat.st_mode))
     334             :     {
     335             :         char szModule[128];
     336             : 
     337          24 :         if (strlen(CPLGetFilename(pszFilename)) == 0)
     338             :         {
     339           0 :             return FALSE;
     340             :         }
     341             : 
     342          24 :         pszPath = CPLStrdup(CPLGetPathSafe(pszFilename).c_str());
     343             : 
     344          24 :         strncpy(szModule, CPLGetFilename(pszFilename), sizeof(szModule) - 1);
     345             :         /* Make sure the buffer is 0 terminated */
     346          24 :         szModule[sizeof(szModule) - 1] = '\0';
     347             : 
     348             :         /* And now remove last character of filename */
     349          24 :         szModule[strlen(szModule) - 1] = '\0';
     350             : 
     351          24 :         papszFileList = CSLAddString(papszFileList, szModule);
     352             :     }
     353             :     else
     354             :     {
     355         487 :         char **candidateFileList = VSIReadDir(pszFilename);
     356             : 
     357         487 :         pszPath = CPLStrdup(pszFilename);
     358             : 
     359       24397 :         for (int i = 0;
     360       24397 :              candidateFileList != nullptr && candidateFileList[i] != nullptr;
     361             :              i++)
     362             :         {
     363       23910 :             size_t nCandidateLen = strlen(candidateFileList[i]);
     364             : 
     365       23910 :             if (papszLimitedFileList != nullptr &&
     366           0 :                 CSLFindString(
     367             :                     papszLimitedFileList,
     368       23910 :                     CPLGetBasenameSafe(candidateFileList[i]).c_str()) == -1)
     369             :             {
     370           0 :                 continue;
     371             :             }
     372             : 
     373       23910 :             if (nCandidateLen > 4 &&
     374       23044 :                 candidateFileList[i][nCandidateLen - 4] == '.' &&
     375        6379 :                 candidateFileList[i][nCandidateLen - 1] == '1')
     376             :             {
     377             :                 char szModule[128];
     378             : 
     379           0 :                 snprintf(szModule, sizeof(szModule), "%s",
     380           0 :                          candidateFileList[i]);
     381           0 :                 const size_t nLen = strlen(szModule);
     382           0 :                 if (nLen)
     383           0 :                     szModule[nLen - 1] = '\0';
     384             : 
     385           0 :                 papszFileList = CSLAddString(papszFileList, szModule);
     386             :             }
     387             :         }
     388             : 
     389         487 :         CSLDestroy(candidateFileList);
     390             : 
     391         487 :         if (CSLCount(papszFileList) == 0)
     392             :         {
     393         487 :             if (!bTestOpen)
     394           0 :                 CPLError(CE_Failure, CPLE_OpenFailed,
     395             :                          "No candidate Tiger files (TGR*.RT1) found in\n"
     396             :                          "directory: %s",
     397             :                          pszFilename);
     398         487 :             CSLDestroy(papszFileList);
     399         487 :             return FALSE;
     400             :         }
     401             :     }
     402             : 
     403             :     /* -------------------------------------------------------------------- */
     404             :     /*      Loop over all these files trying to open them.  In testopen     */
     405             :     /*      mode we first read the first 80 characters, to verify that      */
     406             :     /*      it looks like an Tiger file.  Note that we don't keep the file  */
     407             :     /*      open ... we don't want to occupy a lot of file handles when      */
     408             :     /*      handling a whole directory.                                     */
     409             :     /* -------------------------------------------------------------------- */
     410          24 :     papszModules = nullptr;
     411             : 
     412          48 :     for (int i = 0; papszFileList && papszFileList[i] != nullptr; i++)
     413             :     {
     414          24 :         if (bTestOpen || i == 0)
     415             :         {
     416          24 :             char *l_pszFilename = BuildFilename(papszFileList[i], "1");
     417             : 
     418          24 :             VSILFILE *fp = VSIFOpenL(l_pszFilename, "rb");
     419          24 :             CPLFree(l_pszFilename);
     420             : 
     421          24 :             if (fp == nullptr)
     422          24 :                 continue;
     423             : 
     424           0 :             char szHeader[500] = {};
     425           0 :             if (VSIFReadL(szHeader, sizeof(szHeader) - 1, 1, fp) < 1)
     426             :             {
     427           0 :                 VSIFCloseL(fp);
     428           0 :                 continue;
     429             :             }
     430             : 
     431           0 :             VSIFCloseL(fp);
     432             : 
     433           0 :             char *pszRecStart = szHeader;
     434           0 :             szHeader[sizeof(szHeader) - 1] = '\0';
     435             : 
     436           0 :             bool bIsGDT = false;
     437             : 
     438           0 :             if (STARTS_WITH_CI(pszRecStart, "Copyright (C)") &&
     439           0 :                 strstr(pszRecStart, "Geographic Data Tech") != nullptr)
     440             :             {
     441           0 :                 bIsGDT = true;
     442             : 
     443           0 :                 while (*pszRecStart != '\0' && *pszRecStart != 10 &&
     444           0 :                        *pszRecStart != 13)
     445           0 :                     pszRecStart++;
     446             : 
     447           0 :                 while (*pszRecStart == 10 || *pszRecStart == 13)
     448           0 :                     pszRecStart++;
     449             :             }
     450             : 
     451           0 :             if (pszRecStart[0] != '1')
     452           0 :                 continue;
     453             : 
     454           0 :             if (!isdigit(static_cast<unsigned char>(pszRecStart[1])) ||
     455           0 :                 !isdigit(static_cast<unsigned char>(pszRecStart[2])) ||
     456           0 :                 !isdigit(static_cast<unsigned char>(pszRecStart[3])) ||
     457           0 :                 !isdigit(static_cast<unsigned char>(pszRecStart[4])))
     458           0 :                 continue;
     459             : 
     460           0 :             nVersionCode = atoi(TigerFileBase::GetField(pszRecStart, 2, 5));
     461           0 :             nVersion = TigerClassifyVersion(nVersionCode);
     462           0 :             nVersion = TigerCheckVersion(nVersion, papszFileList[i]);
     463             : 
     464           0 :             CPLDebug("OGR", "Tiger Version Code=%d, Classified as %s ",
     465             :                      nVersionCode, TigerVersionString(nVersion));
     466             : 
     467           0 :             if (nVersionCode != 0 && nVersionCode != 2 && nVersionCode != 3 &&
     468           0 :                 nVersionCode != 5 && nVersionCode != 21 && nVersionCode != 24 &&
     469           0 :                 pszRecStart[3] != '9' && pszRecStart[3] != DIGIT_ZERO &&
     470           0 :                 !bIsGDT)
     471           0 :                 continue;
     472             : 
     473             :             // we could (and should) add a bunch more validation here.
     474             :         }
     475             : 
     476           0 :         papszModules = CSLAddString(papszModules, papszFileList[i]);
     477             :     }
     478             : 
     479          24 :     CSLDestroy(papszFileList);
     480             : 
     481          24 :     nModules = CSLCount(papszModules);
     482             : 
     483          24 :     if (nModules == 0 || papszModules == nullptr)
     484             :     {
     485          24 :         if (!bTestOpen)
     486             :         {
     487           0 :             if (VSI_ISREG(stat.st_mode))
     488           0 :                 CPLError(CE_Failure, CPLE_OpenFailed,
     489             :                          "No TIGER/Line files (TGR*.RT1) found in\n"
     490             :                          "directory: %s",
     491             :                          pszFilename);
     492             :             else
     493           0 :                 CPLError(
     494             :                     CE_Failure, CPLE_OpenFailed,
     495             :                     "File %s does not appear to be a TIGER/Line .RT1 file.",
     496             :                     pszFilename);
     497             :         }
     498             : 
     499          24 :         return FALSE;
     500             :     }
     501             : 
     502             :     /* -------------------------------------------------------------------- */
     503             :     /*      Do we have a user provided version override?                    */
     504             :     /* -------------------------------------------------------------------- */
     505             :     const char *pszRequestedVersion =
     506           0 :         CPLGetConfigOption("TIGER_VERSION", nullptr);
     507           0 :     if (pszRequestedVersion != nullptr)
     508             :     {
     509             : 
     510           0 :         if (STARTS_WITH_CI(pszRequestedVersion, "TIGER_"))
     511             :         {
     512           0 :             int iCode = 1;  // Used after for.
     513             : 
     514           0 :             for (; iCode < TIGER_Unknown; iCode++)
     515             :             {
     516           0 :                 if (EQUAL(TigerVersionString((TigerVersion)iCode),
     517             :                           pszRequestedVersion))
     518             :                 {
     519           0 :                     nVersion = (TigerVersion)iCode;
     520           0 :                     break;
     521             :                 }
     522             :             }
     523             : 
     524           0 :             if (iCode == TIGER_Unknown)
     525             :             {
     526           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
     527             :                          "Failed to recognise TIGER_VERSION setting: %s",
     528             :                          pszRequestedVersion);
     529           0 :                 return FALSE;
     530             :             }
     531             : 
     532           0 :             CPLDebug("OGR", "OVERRIDE Tiger Version %s ",
     533             :                      TigerVersionString(nVersion));
     534             :         }
     535             :         else
     536             :         {
     537           0 :             nVersionCode = atoi(pszRequestedVersion);
     538           0 :             nVersion = TigerClassifyVersion(nVersionCode);
     539             : 
     540           0 :             CPLDebug("OGR", "OVERRIDE Tiger Version Code=%d, Classified as %s ",
     541             :                      nVersionCode, TigerVersionString(nVersion));
     542             :         }
     543             :     }
     544             : 
     545             :     /* -------------------------------------------------------------------- */
     546             :     /*      Create the layers which appear to exist.                        */
     547             :     /* -------------------------------------------------------------------- */
     548             :     // RT1, RT2, RT3
     549           0 :     AddLayer(
     550           0 :         new OGRTigerLayer(this, new TigerCompleteChain(this, papszModules[0])));
     551             : 
     552             :     /* should we have kept track of whether we encountered an RT4 file? */
     553             :     // RT4
     554           0 :     AddLayer(new OGRTigerLayer(this, new TigerAltName(this, papszModules[0])));
     555             : 
     556             :     // RT5
     557           0 :     AddLayer(
     558           0 :         new OGRTigerLayer(this, new TigerFeatureIds(this, papszModules[0])));
     559             : 
     560             :     // RT6
     561           0 :     AddLayer(new OGRTigerLayer(this, new TigerZipCodes(this, papszModules[0])));
     562             :     // RT7
     563           0 :     AddLayer(
     564           0 :         new OGRTigerLayer(this, new TigerLandmarks(this, papszModules[0])));
     565             : 
     566             :     // RT8
     567           0 :     AddLayer(
     568           0 :         new OGRTigerLayer(this, new TigerAreaLandmarks(this, papszModules[0])));
     569             : 
     570             :     // RT9
     571           0 :     if (nVersion < TIGER_2002)
     572             :     {
     573           0 :         AddLayer(new OGRTigerLayer(
     574           0 :             this, new TigerKeyFeatures(this, papszModules[0])));
     575             :     }
     576             : 
     577             :     // RTA, RTS
     578           0 :     AddLayer(new OGRTigerLayer(this, new TigerPolygon(this, papszModules[0])));
     579             : 
     580             :     // RTB
     581           0 :     if (nVersion >= TIGER_2002)
     582             :     {
     583           0 :         AddLayer(new OGRTigerLayer(
     584           0 :             this, new TigerPolygonCorrections(this, papszModules[0])));
     585             :     }
     586             : 
     587             :     // RTC
     588           0 :     AddLayer(
     589           0 :         new OGRTigerLayer(this, new TigerEntityNames(this, papszModules[0])));
     590             : 
     591             :     // RTE
     592           0 :     if (nVersion >= TIGER_2002)
     593             :     {
     594           0 :         AddLayer(new OGRTigerLayer(
     595           0 :             this, new TigerPolygonEconomic(this, papszModules[0])));
     596             :     }
     597             : 
     598             :     // RTH
     599           0 :     AddLayer(
     600           0 :         new OGRTigerLayer(this, new TigerIDHistory(this, papszModules[0])));
     601             : 
     602             :     // RTI
     603           0 :     AddLayer(
     604           0 :         new OGRTigerLayer(this, new TigerPolyChainLink(this, papszModules[0])));
     605             : 
     606             :     // RTM
     607           0 :     AddLayer(new OGRTigerLayer(
     608           0 :         this, new TigerSpatialMetadata(this, papszModules[0])));
     609             : 
     610             :     // RTP
     611           0 :     AddLayer(new OGRTigerLayer(this, new TigerPIP(this, papszModules[0])));
     612             : 
     613             :     // RTR
     614           0 :     AddLayer(
     615           0 :         new OGRTigerLayer(this, new TigerTLIDRange(this, papszModules[0])));
     616             : 
     617             :     // RTT
     618           0 :     if (nVersion >= TIGER_2002)
     619             :     {
     620           0 :         AddLayer(new OGRTigerLayer(this,
     621           0 :                                    new TigerZeroCellID(this, papszModules[0])));
     622             :     }
     623             : 
     624             :     // RTU
     625           0 :     if (nVersion >= TIGER_2002)
     626             :     {
     627           0 :         AddLayer(
     628           0 :             new OGRTigerLayer(this, new TigerOverUnder(this, papszModules[0])));
     629             :     }
     630             : 
     631             :     // RTZ
     632           0 :     AddLayer(new OGRTigerLayer(this, new TigerZipPlus4(this, papszModules[0])));
     633             : 
     634           0 :     return TRUE;
     635             : }
     636             : 
     637             : /************************************************************************/
     638             : /*                             GetOption()                              */
     639             : /************************************************************************/
     640             : 
     641           0 : const char *OGRTigerDataSource::GetOption(const char *pszOption)
     642             : 
     643             : {
     644           0 :     return CSLFetchNameValue(papszOptions, pszOption);
     645             : }
     646             : 
     647             : /************************************************************************/
     648             : /*                             GetModule()                              */
     649             : /************************************************************************/
     650             : 
     651           0 : const char *OGRTigerDataSource::GetModule(int iModule)
     652             : 
     653             : {
     654           0 :     if (iModule < 0 || iModule >= nModules)
     655           0 :         return nullptr;
     656             :     else
     657           0 :         return papszModules[iModule];
     658             : }
     659             : 
     660             : /************************************************************************/
     661             : /*                            CheckModule()                             */
     662             : /*                                                                      */
     663             : /*      This is used by the writer to check if this module has been     */
     664             : /*      written to before.                                              */
     665             : /************************************************************************/
     666             : 
     667           0 : bool OGRTigerDataSource::CheckModule(const char *pszModule)
     668             : 
     669             : {
     670           0 :     for (int i = 0; i < nModules; i++)
     671             :     {
     672           0 :         if (EQUAL(pszModule, papszModules[i]))
     673           0 :             return true;
     674             :     }
     675           0 :     return false;
     676             : }
     677             : 
     678             : /************************************************************************/
     679             : /*                             AddModule()                              */
     680             : /************************************************************************/
     681             : 
     682           0 : void OGRTigerDataSource::AddModule(const char *pszModule)
     683             : 
     684             : {
     685           0 :     if (CheckModule(pszModule))
     686           0 :         return;
     687             : 
     688           0 :     papszModules = CSLAddString(papszModules, pszModule);
     689           0 :     nModules++;
     690             : }
     691             : 
     692             : /************************************************************************/
     693             : /*                           BuildFilename()                            */
     694             : /************************************************************************/
     695             : 
     696          24 : char *OGRTigerDataSource::BuildFilename(const char *pszModuleName,
     697             :                                         const char *pszExtension)
     698             : 
     699             : {
     700             :     /* -------------------------------------------------------------------- */
     701             :     /*      Force the record type to lower case if the filename appears     */
     702             :     /*      to be in lower case.                                            */
     703             :     /* -------------------------------------------------------------------- */
     704          24 :     char szLCExtension[3] = {};
     705          24 :     if (*pszExtension >= 'A' && *pszExtension <= 'Z' && *pszModuleName == 't')
     706             :     {
     707           0 :         szLCExtension[0] = (*pszExtension) + 'a' - 'A';
     708           0 :         szLCExtension[1] = '\0';
     709           0 :         pszExtension = szLCExtension;
     710             :     }
     711             : 
     712             :     /* -------------------------------------------------------------------- */
     713             :     /*      Build the filename.                                             */
     714             :     /* -------------------------------------------------------------------- */
     715          24 :     const size_t nFilenameLen = strlen(GetDirPath()) + strlen(pszModuleName) +
     716          24 :                                 strlen(pszExtension) + 10;
     717          24 :     char *pszFilename = (char *)CPLMalloc(nFilenameLen);
     718             : 
     719          24 :     if (strlen(GetDirPath()) == 0)
     720           0 :         snprintf(pszFilename, nFilenameLen, "%s%s", pszModuleName,
     721             :                  pszExtension);
     722             :     else
     723          24 :         snprintf(pszFilename, nFilenameLen, "%s/%s%s", GetDirPath(),
     724             :                  pszModuleName, pszExtension);
     725             : 
     726          24 :     return pszFilename;
     727             : }

Generated by: LCOV version 1.14