LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/tiger - ogrtigerdatasource.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 62 289 21.5 %
Date: 2024-11-21 22:18:42 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         510 : OGRTigerDataSource::OGRTigerDataSource()
     221         510 :     : nLayers(0), papoLayers(nullptr), poSpatialRef(new OGRSpatialReference()),
     222             :       papszOptions(nullptr), pszPath(nullptr), nModules(0),
     223         510 :       papszModules(nullptr), nVersionCode(0), nVersion(TIGER_Unknown)
     224             : {
     225         510 :     poSpatialRef->SetWellKnownGeogCS("NAD83");
     226         510 :     poSpatialRef->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
     227         510 : }
     228             : 
     229             : /************************************************************************/
     230             : /*                        ~OGRTigerDataSource()                         */
     231             : /************************************************************************/
     232             : 
     233        1020 : OGRTigerDataSource::~OGRTigerDataSource()
     234             : 
     235             : {
     236         510 :     for (int i = 0; i < nLayers; i++)
     237           0 :         delete papoLayers[i];
     238             : 
     239         510 :     CPLFree(papoLayers);
     240             : 
     241         510 :     CPLFree(pszPath);
     242             : 
     243         510 :     CSLDestroy(papszOptions);
     244             : 
     245         510 :     CSLDestroy(papszModules);
     246             : 
     247         510 :     delete poSpatialRef;
     248        1020 : }
     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         510 : 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         510 :     if (VSIStatExL(pszFilename, &stat,
     317        1020 :                    VSI_STAT_EXISTS_FLAG | VSI_STAT_NATURE_FLAG) != 0 ||
     318         510 :         (!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         510 :     char **papszFileList = nullptr;
     333         510 :     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(CPLGetPath(pszFilename));
     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         486 :         char **candidateFileList = VSIReadDir(pszFilename);
     356             : 
     357         486 :         pszPath = CPLStrdup(pszFilename);
     358             : 
     359       24374 :         for (int i = 0;
     360       24374 :              candidateFileList != nullptr && candidateFileList[i] != nullptr;
     361             :              i++)
     362             :         {
     363       23888 :             size_t nCandidateLen = strlen(candidateFileList[i]);
     364             : 
     365       23888 :             if (papszLimitedFileList != nullptr &&
     366           0 :                 CSLFindString(papszLimitedFileList,
     367           0 :                               CPLGetBasename(candidateFileList[i])) == -1)
     368             :             {
     369           0 :                 continue;
     370             :             }
     371             : 
     372       23888 :             if (nCandidateLen > 4 &&
     373       23025 :                 candidateFileList[i][nCandidateLen - 4] == '.' &&
     374        6378 :                 candidateFileList[i][nCandidateLen - 1] == '1')
     375             :             {
     376             :                 char szModule[128];
     377             : 
     378           0 :                 snprintf(szModule, sizeof(szModule), "%s",
     379           0 :                          candidateFileList[i]);
     380           0 :                 const size_t nLen = strlen(szModule);
     381           0 :                 if (nLen)
     382           0 :                     szModule[nLen - 1] = '\0';
     383             : 
     384           0 :                 papszFileList = CSLAddString(papszFileList, szModule);
     385             :             }
     386             :         }
     387             : 
     388         486 :         CSLDestroy(candidateFileList);
     389             : 
     390         486 :         if (CSLCount(papszFileList) == 0)
     391             :         {
     392         486 :             if (!bTestOpen)
     393           0 :                 CPLError(CE_Failure, CPLE_OpenFailed,
     394             :                          "No candidate Tiger files (TGR*.RT1) found in\n"
     395             :                          "directory: %s",
     396             :                          pszFilename);
     397         486 :             CSLDestroy(papszFileList);
     398         486 :             return FALSE;
     399             :         }
     400             :     }
     401             : 
     402             :     /* -------------------------------------------------------------------- */
     403             :     /*      Loop over all these files trying to open them.  In testopen     */
     404             :     /*      mode we first read the first 80 characters, to verify that      */
     405             :     /*      it looks like an Tiger file.  Note that we don't keep the file  */
     406             :     /*      open ... we don't want to occupy a lot of file handles when      */
     407             :     /*      handling a whole directory.                                     */
     408             :     /* -------------------------------------------------------------------- */
     409          24 :     papszModules = nullptr;
     410             : 
     411          48 :     for (int i = 0; papszFileList && papszFileList[i] != nullptr; i++)
     412             :     {
     413          24 :         if (bTestOpen || i == 0)
     414             :         {
     415          24 :             char *l_pszFilename = BuildFilename(papszFileList[i], "1");
     416             : 
     417          24 :             VSILFILE *fp = VSIFOpenL(l_pszFilename, "rb");
     418          24 :             CPLFree(l_pszFilename);
     419             : 
     420          24 :             if (fp == nullptr)
     421          24 :                 continue;
     422             : 
     423           0 :             char szHeader[500] = {};
     424           0 :             if (VSIFReadL(szHeader, sizeof(szHeader) - 1, 1, fp) < 1)
     425             :             {
     426           0 :                 VSIFCloseL(fp);
     427           0 :                 continue;
     428             :             }
     429             : 
     430           0 :             VSIFCloseL(fp);
     431             : 
     432           0 :             char *pszRecStart = szHeader;
     433           0 :             szHeader[sizeof(szHeader) - 1] = '\0';
     434             : 
     435           0 :             bool bIsGDT = false;
     436             : 
     437           0 :             if (STARTS_WITH_CI(pszRecStart, "Copyright (C)") &&
     438           0 :                 strstr(pszRecStart, "Geographic Data Tech") != nullptr)
     439             :             {
     440           0 :                 bIsGDT = true;
     441             : 
     442           0 :                 while (*pszRecStart != '\0' && *pszRecStart != 10 &&
     443           0 :                        *pszRecStart != 13)
     444           0 :                     pszRecStart++;
     445             : 
     446           0 :                 while (*pszRecStart == 10 || *pszRecStart == 13)
     447           0 :                     pszRecStart++;
     448             :             }
     449             : 
     450           0 :             if (pszRecStart[0] != '1')
     451           0 :                 continue;
     452             : 
     453           0 :             if (!isdigit(static_cast<unsigned char>(pszRecStart[1])) ||
     454           0 :                 !isdigit(static_cast<unsigned char>(pszRecStart[2])) ||
     455           0 :                 !isdigit(static_cast<unsigned char>(pszRecStart[3])) ||
     456           0 :                 !isdigit(static_cast<unsigned char>(pszRecStart[4])))
     457           0 :                 continue;
     458             : 
     459           0 :             nVersionCode = atoi(TigerFileBase::GetField(pszRecStart, 2, 5));
     460           0 :             nVersion = TigerClassifyVersion(nVersionCode);
     461           0 :             nVersion = TigerCheckVersion(nVersion, papszFileList[i]);
     462             : 
     463           0 :             CPLDebug("OGR", "Tiger Version Code=%d, Classified as %s ",
     464             :                      nVersionCode, TigerVersionString(nVersion));
     465             : 
     466           0 :             if (nVersionCode != 0 && nVersionCode != 2 && nVersionCode != 3 &&
     467           0 :                 nVersionCode != 5 && nVersionCode != 21 && nVersionCode != 24 &&
     468           0 :                 pszRecStart[3] != '9' && pszRecStart[3] != DIGIT_ZERO &&
     469           0 :                 !bIsGDT)
     470           0 :                 continue;
     471             : 
     472             :             // we could (and should) add a bunch more validation here.
     473             :         }
     474             : 
     475           0 :         papszModules = CSLAddString(papszModules, papszFileList[i]);
     476             :     }
     477             : 
     478          24 :     CSLDestroy(papszFileList);
     479             : 
     480          24 :     nModules = CSLCount(papszModules);
     481             : 
     482          24 :     if (nModules == 0 || papszModules == nullptr)
     483             :     {
     484          24 :         if (!bTestOpen)
     485             :         {
     486           0 :             if (VSI_ISREG(stat.st_mode))
     487           0 :                 CPLError(CE_Failure, CPLE_OpenFailed,
     488             :                          "No TIGER/Line files (TGR*.RT1) found in\n"
     489             :                          "directory: %s",
     490             :                          pszFilename);
     491             :             else
     492           0 :                 CPLError(
     493             :                     CE_Failure, CPLE_OpenFailed,
     494             :                     "File %s does not appear to be a TIGER/Line .RT1 file.",
     495             :                     pszFilename);
     496             :         }
     497             : 
     498          24 :         return FALSE;
     499             :     }
     500             : 
     501             :     /* -------------------------------------------------------------------- */
     502             :     /*      Do we have a user provided version override?                    */
     503             :     /* -------------------------------------------------------------------- */
     504             :     const char *pszRequestedVersion =
     505           0 :         CPLGetConfigOption("TIGER_VERSION", nullptr);
     506           0 :     if (pszRequestedVersion != nullptr)
     507             :     {
     508             : 
     509           0 :         if (STARTS_WITH_CI(pszRequestedVersion, "TIGER_"))
     510             :         {
     511           0 :             int iCode = 1;  // Used after for.
     512             : 
     513           0 :             for (; iCode < TIGER_Unknown; iCode++)
     514             :             {
     515           0 :                 if (EQUAL(TigerVersionString((TigerVersion)iCode),
     516             :                           pszRequestedVersion))
     517             :                 {
     518           0 :                     nVersion = (TigerVersion)iCode;
     519           0 :                     break;
     520             :                 }
     521             :             }
     522             : 
     523           0 :             if (iCode == TIGER_Unknown)
     524             :             {
     525           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
     526             :                          "Failed to recognise TIGER_VERSION setting: %s",
     527             :                          pszRequestedVersion);
     528           0 :                 return FALSE;
     529             :             }
     530             : 
     531           0 :             CPLDebug("OGR", "OVERRIDE Tiger Version %s ",
     532             :                      TigerVersionString(nVersion));
     533             :         }
     534             :         else
     535             :         {
     536           0 :             nVersionCode = atoi(pszRequestedVersion);
     537           0 :             nVersion = TigerClassifyVersion(nVersionCode);
     538             : 
     539           0 :             CPLDebug("OGR", "OVERRIDE Tiger Version Code=%d, Classified as %s ",
     540             :                      nVersionCode, TigerVersionString(nVersion));
     541             :         }
     542             :     }
     543             : 
     544             :     /* -------------------------------------------------------------------- */
     545             :     /*      Create the layers which appear to exist.                        */
     546             :     /* -------------------------------------------------------------------- */
     547             :     // RT1, RT2, RT3
     548           0 :     AddLayer(
     549           0 :         new OGRTigerLayer(this, new TigerCompleteChain(this, papszModules[0])));
     550             : 
     551             :     /* should we have kept track of whether we encountered an RT4 file? */
     552             :     // RT4
     553           0 :     AddLayer(new OGRTigerLayer(this, new TigerAltName(this, papszModules[0])));
     554             : 
     555             :     // RT5
     556           0 :     AddLayer(
     557           0 :         new OGRTigerLayer(this, new TigerFeatureIds(this, papszModules[0])));
     558             : 
     559             :     // RT6
     560           0 :     AddLayer(new OGRTigerLayer(this, new TigerZipCodes(this, papszModules[0])));
     561             :     // RT7
     562           0 :     AddLayer(
     563           0 :         new OGRTigerLayer(this, new TigerLandmarks(this, papszModules[0])));
     564             : 
     565             :     // RT8
     566           0 :     AddLayer(
     567           0 :         new OGRTigerLayer(this, new TigerAreaLandmarks(this, papszModules[0])));
     568             : 
     569             :     // RT9
     570           0 :     if (nVersion < TIGER_2002)
     571             :     {
     572           0 :         AddLayer(new OGRTigerLayer(
     573           0 :             this, new TigerKeyFeatures(this, papszModules[0])));
     574             :     }
     575             : 
     576             :     // RTA, RTS
     577           0 :     AddLayer(new OGRTigerLayer(this, new TigerPolygon(this, papszModules[0])));
     578             : 
     579             :     // RTB
     580           0 :     if (nVersion >= TIGER_2002)
     581             :     {
     582           0 :         AddLayer(new OGRTigerLayer(
     583           0 :             this, new TigerPolygonCorrections(this, papszModules[0])));
     584             :     }
     585             : 
     586             :     // RTC
     587           0 :     AddLayer(
     588           0 :         new OGRTigerLayer(this, new TigerEntityNames(this, papszModules[0])));
     589             : 
     590             :     // RTE
     591           0 :     if (nVersion >= TIGER_2002)
     592             :     {
     593           0 :         AddLayer(new OGRTigerLayer(
     594           0 :             this, new TigerPolygonEconomic(this, papszModules[0])));
     595             :     }
     596             : 
     597             :     // RTH
     598           0 :     AddLayer(
     599           0 :         new OGRTigerLayer(this, new TigerIDHistory(this, papszModules[0])));
     600             : 
     601             :     // RTI
     602           0 :     AddLayer(
     603           0 :         new OGRTigerLayer(this, new TigerPolyChainLink(this, papszModules[0])));
     604             : 
     605             :     // RTM
     606           0 :     AddLayer(new OGRTigerLayer(
     607           0 :         this, new TigerSpatialMetadata(this, papszModules[0])));
     608             : 
     609             :     // RTP
     610           0 :     AddLayer(new OGRTigerLayer(this, new TigerPIP(this, papszModules[0])));
     611             : 
     612             :     // RTR
     613           0 :     AddLayer(
     614           0 :         new OGRTigerLayer(this, new TigerTLIDRange(this, papszModules[0])));
     615             : 
     616             :     // RTT
     617           0 :     if (nVersion >= TIGER_2002)
     618             :     {
     619           0 :         AddLayer(new OGRTigerLayer(this,
     620           0 :                                    new TigerZeroCellID(this, papszModules[0])));
     621             :     }
     622             : 
     623             :     // RTU
     624           0 :     if (nVersion >= TIGER_2002)
     625             :     {
     626           0 :         AddLayer(
     627           0 :             new OGRTigerLayer(this, new TigerOverUnder(this, papszModules[0])));
     628             :     }
     629             : 
     630             :     // RTZ
     631           0 :     AddLayer(new OGRTigerLayer(this, new TigerZipPlus4(this, papszModules[0])));
     632             : 
     633           0 :     return TRUE;
     634             : }
     635             : 
     636             : /************************************************************************/
     637             : /*                             GetOption()                              */
     638             : /************************************************************************/
     639             : 
     640           0 : const char *OGRTigerDataSource::GetOption(const char *pszOption)
     641             : 
     642             : {
     643           0 :     return CSLFetchNameValue(papszOptions, pszOption);
     644             : }
     645             : 
     646             : /************************************************************************/
     647             : /*                             GetModule()                              */
     648             : /************************************************************************/
     649             : 
     650           0 : const char *OGRTigerDataSource::GetModule(int iModule)
     651             : 
     652             : {
     653           0 :     if (iModule < 0 || iModule >= nModules)
     654           0 :         return nullptr;
     655             :     else
     656           0 :         return papszModules[iModule];
     657             : }
     658             : 
     659             : /************************************************************************/
     660             : /*                            CheckModule()                             */
     661             : /*                                                                      */
     662             : /*      This is used by the writer to check if this module has been     */
     663             : /*      written to before.                                              */
     664             : /************************************************************************/
     665             : 
     666           0 : bool OGRTigerDataSource::CheckModule(const char *pszModule)
     667             : 
     668             : {
     669           0 :     for (int i = 0; i < nModules; i++)
     670             :     {
     671           0 :         if (EQUAL(pszModule, papszModules[i]))
     672           0 :             return true;
     673             :     }
     674           0 :     return false;
     675             : }
     676             : 
     677             : /************************************************************************/
     678             : /*                             AddModule()                              */
     679             : /************************************************************************/
     680             : 
     681           0 : void OGRTigerDataSource::AddModule(const char *pszModule)
     682             : 
     683             : {
     684           0 :     if (CheckModule(pszModule))
     685           0 :         return;
     686             : 
     687           0 :     papszModules = CSLAddString(papszModules, pszModule);
     688           0 :     nModules++;
     689             : }
     690             : 
     691             : /************************************************************************/
     692             : /*                           BuildFilename()                            */
     693             : /************************************************************************/
     694             : 
     695          24 : char *OGRTigerDataSource::BuildFilename(const char *pszModuleName,
     696             :                                         const char *pszExtension)
     697             : 
     698             : {
     699             :     /* -------------------------------------------------------------------- */
     700             :     /*      Force the record type to lower case if the filename appears     */
     701             :     /*      to be in lower case.                                            */
     702             :     /* -------------------------------------------------------------------- */
     703          24 :     char szLCExtension[3] = {};
     704          24 :     if (*pszExtension >= 'A' && *pszExtension <= 'Z' && *pszModuleName == 't')
     705             :     {
     706           0 :         szLCExtension[0] = (*pszExtension) + 'a' - 'A';
     707           0 :         szLCExtension[1] = '\0';
     708           0 :         pszExtension = szLCExtension;
     709             :     }
     710             : 
     711             :     /* -------------------------------------------------------------------- */
     712             :     /*      Build the filename.                                             */
     713             :     /* -------------------------------------------------------------------- */
     714          24 :     const size_t nFilenameLen = strlen(GetDirPath()) + strlen(pszModuleName) +
     715          24 :                                 strlen(pszExtension) + 10;
     716          24 :     char *pszFilename = (char *)CPLMalloc(nFilenameLen);
     717             : 
     718          24 :     if (strlen(GetDirPath()) == 0)
     719           0 :         snprintf(pszFilename, nFilenameLen, "%s%s", pszModuleName,
     720             :                  pszExtension);
     721             :     else
     722          24 :         snprintf(pszFilename, nFilenameLen, "%s/%s%s", GetDirPath(),
     723             :                  pszModuleName, pszExtension);
     724             : 
     725          24 :     return pszFilename;
     726             : }

Generated by: LCOV version 1.14