LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/tiger - tigerfilebase.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 0 135 0.0 %
Date: 2024-11-21 22:18:42 Functions: 0 13 0.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  TIGER/Line Translator
       4             :  * Purpose:  Implements TigerBaseFile class, providing common services to all
       5             :  *           the tiger file readers.
       6             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       7             :  *
       8             :  ******************************************************************************
       9             :  * Copyright (c) 1999, Frank Warmerdam
      10             :  * Copyright (c) 2009-2013, Even Rouault <even dot rouault at spatialys.com>
      11             :  *
      12             :  * SPDX-License-Identifier: MIT
      13             :  ****************************************************************************/
      14             : 
      15             : #include "ogr_tiger.h"
      16             : #include "cpl_conv.h"
      17             : #include "cpl_error.h"
      18             : #include "cpl_string.h"
      19             : 
      20             : #include <cinttypes>
      21             : 
      22             : /************************************************************************/
      23             : /*                           TigerFileBase()                            */
      24             : /************************************************************************/
      25             : 
      26           0 : TigerFileBase::TigerFileBase(const TigerRecordInfo *psRTInfoIn,
      27           0 :                              const char *m_pszFileCodeIn)
      28             :     : poDS(nullptr), pszModule(nullptr), pszShortModule(nullptr),
      29             :       fpPrimary(nullptr), poFeatureDefn(nullptr), nFeatures(0),
      30             :       nRecordLength(0), nVersionCode(0), nVersion(TIGER_Unknown),
      31           0 :       psRTInfo(psRTInfoIn), m_pszFileCode(m_pszFileCodeIn)
      32             : {
      33           0 : }
      34             : 
      35             : /************************************************************************/
      36             : /*                           ~TigerFileBase()                           */
      37             : /************************************************************************/
      38             : 
      39           0 : TigerFileBase::~TigerFileBase()
      40             : 
      41             : {
      42           0 :     CPLFree(pszModule);
      43           0 :     CPLFree(pszShortModule);
      44             : 
      45           0 :     if (poFeatureDefn != nullptr)
      46             :     {
      47           0 :         poFeatureDefn->Release();
      48           0 :         poFeatureDefn = nullptr;
      49             :     }
      50             : 
      51           0 :     if (fpPrimary != nullptr)
      52             :     {
      53           0 :         VSIFCloseL(fpPrimary);
      54           0 :         fpPrimary = nullptr;
      55             :     }
      56           0 : }
      57             : 
      58             : /************************************************************************/
      59             : /*                              OpenFile()                              */
      60             : /************************************************************************/
      61             : 
      62           0 : int TigerFileBase::OpenFile(const char *pszModuleToOpen,
      63             :                             const char *pszExtension)
      64             : 
      65             : {
      66             : 
      67           0 :     CPLFree(pszModule);
      68           0 :     pszModule = nullptr;
      69           0 :     CPLFree(pszShortModule);
      70           0 :     pszShortModule = nullptr;
      71             : 
      72           0 :     if (fpPrimary != nullptr)
      73             :     {
      74           0 :         VSIFCloseL(fpPrimary);
      75           0 :         fpPrimary = nullptr;
      76             :     }
      77             : 
      78           0 :     if (pszModuleToOpen == nullptr)
      79           0 :         return TRUE;
      80             : 
      81           0 :     char *pszFilename = poDS->BuildFilename(pszModuleToOpen, pszExtension);
      82             : 
      83           0 :     fpPrimary = VSIFOpenL(pszFilename, "rb");
      84             : 
      85           0 :     CPLFree(pszFilename);
      86             : 
      87           0 :     if (fpPrimary == nullptr)
      88           0 :         return FALSE;
      89             : 
      90           0 :     pszModule = CPLStrdup(pszModuleToOpen);
      91           0 :     pszShortModule = CPLStrdup(pszModuleToOpen);
      92           0 :     for (int i = 0; pszShortModule[i] != '\0'; i++)
      93             :     {
      94           0 :         if (pszShortModule[i] == '.')
      95           0 :             pszShortModule[i] = '\0';
      96             :     }
      97             : 
      98           0 :     SetupVersion();
      99             : 
     100           0 :     return TRUE;
     101             : }
     102             : 
     103             : /************************************************************************/
     104             : /*                            SetupVersion()                            */
     105             : /************************************************************************/
     106             : 
     107           0 : void TigerFileBase::SetupVersion()
     108             : 
     109             : {
     110             :     char aszRecordHead[6];
     111             : 
     112           0 :     VSIFSeekL(fpPrimary, 0, SEEK_SET);
     113           0 :     VSIFReadL(aszRecordHead, 1, 5, fpPrimary);
     114           0 :     aszRecordHead[5] = '\0';
     115           0 :     nVersionCode = atoi(aszRecordHead + 1);
     116           0 :     VSIFSeekL(fpPrimary, 0, SEEK_SET);
     117             : 
     118           0 :     nVersion = TigerClassifyVersion(nVersionCode);
     119           0 : }
     120             : 
     121             : /************************************************************************/
     122             : /*                       EstablishRecordLength()                        */
     123             : /************************************************************************/
     124             : 
     125           0 : int TigerFileBase::EstablishRecordLength(VSILFILE *fp)
     126             : 
     127             : {
     128           0 :     if (fp == nullptr || VSIFSeekL(fp, 0, SEEK_SET) != 0)
     129           0 :         return -1;
     130             : 
     131             :     /* -------------------------------------------------------------------- */
     132             :     /*      Read through to the end of line.                                */
     133             :     /* -------------------------------------------------------------------- */
     134           0 :     int nRecLen = 0;
     135           0 :     char chCurrent = '\0';
     136           0 :     while (VSIFReadL(&chCurrent, 1, 1, fp) == 1 && chCurrent != 10 &&
     137           0 :            chCurrent != 13)
     138             :     {
     139           0 :         nRecLen++;
     140             :     }
     141             : 
     142             :     /* -------------------------------------------------------------------- */
     143             :     /*      Is the file zero length?                                        */
     144             :     /* -------------------------------------------------------------------- */
     145           0 :     if (nRecLen == 0)
     146             :     {
     147           0 :         return -1;
     148             :     }
     149             : 
     150           0 :     nRecLen++; /* for the 10 or 13 we encountered */
     151             : 
     152             :     /* -------------------------------------------------------------------- */
     153             :     /*      Read through line terminator characters.  We are trying to      */
     154             :     /*      handle cases of CR, CR/LF and LF/CR gracefully.                 */
     155             :     /* -------------------------------------------------------------------- */
     156           0 :     while (VSIFReadL(&chCurrent, 1, 1, fp) == 1 &&
     157           0 :            (chCurrent == 10 || chCurrent == 13))
     158             :     {
     159           0 :         nRecLen++;
     160             :     }
     161             : 
     162           0 :     VSIFSeekL(fp, 0, SEEK_SET);
     163             : 
     164           0 :     return nRecLen;
     165             : }
     166             : 
     167             : /************************************************************************/
     168             : /*                       EstablishFeatureCount()                        */
     169             : /************************************************************************/
     170             : 
     171           0 : void TigerFileBase::EstablishFeatureCount()
     172             : 
     173             : {
     174           0 :     if (fpPrimary == nullptr)
     175           0 :         return;
     176             : 
     177           0 :     nRecordLength = EstablishRecordLength(fpPrimary);
     178             : 
     179           0 :     if (nRecordLength == -1)
     180             :     {
     181           0 :         nRecordLength = 1;
     182           0 :         nFeatures = 0;
     183           0 :         return;
     184             :     }
     185             : 
     186             :     /* -------------------------------------------------------------------- */
     187             :     /*      Now we think we know the fixed record length for the file       */
     188             :     /*      (including line terminators).  Get the total file size, and     */
     189             :     /*      divide by this length to get the presumed number of records.    */
     190             :     /* -------------------------------------------------------------------- */
     191             : 
     192           0 :     VSIFSeekL(fpPrimary, 0, SEEK_END);
     193           0 :     const vsi_l_offset nFileSize = VSIFTellL(fpPrimary);
     194             : 
     195           0 :     if ((nFileSize % (vsi_l_offset)nRecordLength) != 0)
     196             :     {
     197           0 :         CPLError(CE_Warning, CPLE_FileIO,
     198             :                  "TigerFileBase::EstablishFeatureCount(): "
     199             :                  "File length %d doesn't divide by record length %d.\n",
     200           0 :                  (int)nFileSize, (int)nRecordLength);
     201             :     }
     202             : 
     203           0 :     if (nFileSize / (vsi_l_offset)nRecordLength > (vsi_l_offset)INT_MAX)
     204           0 :         nFeatures = INT_MAX;
     205             :     else
     206           0 :         nFeatures = static_cast<int>(nFileSize / (vsi_l_offset)nRecordLength);
     207             : }
     208             : 
     209             : /************************************************************************/
     210             : /*                              GetField()                              */
     211             : /************************************************************************/
     212             : 
     213           0 : const char *TigerFileBase::GetField(const char *pachRawDataRecord,
     214             :                                     int nStartChar, int nEndChar)
     215             : 
     216             : {
     217             :     char aszField[128];
     218           0 :     int nLength = nEndChar - nStartChar + 1;
     219             : 
     220           0 :     CPLAssert(nEndChar - nStartChar + 2 < (int)sizeof(aszField));
     221             : 
     222           0 :     strncpy(aszField, pachRawDataRecord + nStartChar - 1, nLength);
     223             : 
     224           0 :     aszField[nLength] = '\0';
     225           0 :     while (nLength > 0 && aszField[nLength - 1] == ' ')
     226           0 :         aszField[--nLength] = '\0';
     227             : 
     228           0 :     return CPLSPrintf("%s", aszField);
     229             : }
     230             : 
     231             : /************************************************************************/
     232             : /*                              SetField()                              */
     233             : /*                                                                      */
     234             : /*      Set a field on an OGRFeature from a tiger record, or leave      */
     235             : /*      NULL if the value isn't found.                                  */
     236             : /************************************************************************/
     237             : 
     238           0 : void TigerFileBase::SetField(OGRFeature *poFeature, const char *pszField,
     239             :                              const char *pachRecord, int nStart, int nEnd)
     240             : 
     241             : {
     242           0 :     const char *pszFieldValue = GetField(pachRecord, nStart, nEnd);
     243             : 
     244           0 :     if (pszFieldValue[0] == '\0')
     245           0 :         return;
     246             : 
     247           0 :     poFeature->SetField(pszField, pszFieldValue);
     248             : }
     249             : 
     250             : /************************************************************************/
     251             : /*                           AddFieldDefns()                            */
     252             : /************************************************************************/
     253           0 : void TigerFileBase::AddFieldDefns(const TigerRecordInfo *psRTInfoIn,
     254             :                                   OGRFeatureDefn *poFeatureDefnIn)
     255             : {
     256           0 :     OGRFieldDefn oField("", OFTInteger);
     257             :     int i, bLFieldHack;
     258             : 
     259           0 :     bLFieldHack =
     260           0 :         CPLTestBool(CPLGetConfigOption("TIGER_LFIELD_AS_STRING", "NO"));
     261             : 
     262           0 :     for (i = 0; i < psRTInfoIn->nFieldCount; ++i)
     263             :     {
     264           0 :         if (psRTInfoIn->pasFields[i].bDefine)
     265             :         {
     266           0 :             OGRFieldType eFT = (OGRFieldType)psRTInfoIn->pasFields[i].OGRtype;
     267             : 
     268           0 :             if (bLFieldHack && psRTInfoIn->pasFields[i].cFmt == 'L' &&
     269           0 :                 psRTInfoIn->pasFields[i].cType == 'N')
     270           0 :                 eFT = OFTString;
     271             : 
     272           0 :             oField.Set(psRTInfoIn->pasFields[i].pszFieldName, eFT,
     273           0 :                        psRTInfoIn->pasFields[i].nLen);
     274           0 :             poFeatureDefnIn->AddFieldDefn(&oField);
     275             :         }
     276             :     }
     277           0 : }
     278             : 
     279             : /************************************************************************/
     280             : /*                             SetFields()                              */
     281             : /************************************************************************/
     282             : 
     283           0 : void TigerFileBase::SetFields(const TigerRecordInfo *psRTInfoIn,
     284             :                               OGRFeature *poFeature, char *achRecord)
     285             : {
     286           0 :     for (int i = 0; i < psRTInfoIn->nFieldCount; ++i)
     287             :     {
     288           0 :         if (psRTInfoIn->pasFields[i].bSet)
     289             :         {
     290           0 :             SetField(poFeature, psRTInfoIn->pasFields[i].pszFieldName,
     291           0 :                      achRecord, psRTInfoIn->pasFields[i].nBeg,
     292           0 :                      psRTInfoIn->pasFields[i].nEnd);
     293             :         }
     294             :     }
     295           0 : }
     296             : 
     297             : /************************************************************************/
     298             : /*                             SetModule()                              */
     299             : /************************************************************************/
     300             : 
     301           0 : bool TigerFileBase::SetModule(const char *pszModuleIn)
     302             : 
     303             : {
     304           0 :     if (m_pszFileCode == nullptr)
     305           0 :         return false;
     306             : 
     307           0 :     if (!OpenFile(pszModuleIn, m_pszFileCode))
     308           0 :         return false;
     309             : 
     310           0 :     EstablishFeatureCount();
     311             : 
     312           0 :     return true;
     313             : }
     314             : 
     315             : /************************************************************************/
     316             : /*                             GetFeature()                             */
     317             : /************************************************************************/
     318             : 
     319           0 : OGRFeature *TigerFileBase::GetFeature(int nRecordId)
     320             : 
     321             : {
     322             :     char achRecord[OGR_TIGER_RECBUF_LEN];
     323             : 
     324           0 :     if (psRTInfo == nullptr)
     325           0 :         return nullptr;
     326             : 
     327           0 :     if (nRecordId < 0 || nRecordId >= nFeatures)
     328             :     {
     329           0 :         CPLError(CE_Failure, CPLE_FileIO,
     330             :                  "Request for out-of-range feature %d of %s", nRecordId,
     331             :                  pszModule);
     332           0 :         return nullptr;
     333             :     }
     334             : 
     335             :     /* -------------------------------------------------------------------- */
     336             :     /*      Read the raw record data from the file.                         */
     337             :     /* -------------------------------------------------------------------- */
     338           0 :     if (fpPrimary == nullptr)
     339           0 :         return nullptr;
     340             : 
     341             :     {
     342           0 :         const auto nOffset = static_cast<uint64_t>(nRecordId) * nRecordLength;
     343           0 :         if (VSIFSeekL(fpPrimary, nOffset, SEEK_SET) != 0)
     344             :         {
     345           0 :             CPLError(CE_Failure, CPLE_FileIO,
     346             :                      "Failed to seek to %" PRIu64 " of %s", nOffset, pszModule);
     347           0 :             return nullptr;
     348             :         }
     349             :     }
     350             : 
     351             :     // Overflow cannot happen since psRTInfo->nRecordLength is unsigned
     352             :     // char and sizeof(achRecord) == OGR_TIGER_RECBUF_LEN > 255
     353           0 :     if (VSIFReadL(achRecord, psRTInfo->nRecordLength, 1, fpPrimary) != 1)
     354             :     {
     355           0 :         CPLError(CE_Failure, CPLE_FileIO, "Failed to read record %d of %s",
     356             :                  nRecordId, pszModule);
     357           0 :         return nullptr;
     358             :     }
     359             : 
     360             :     /* -------------------------------------------------------------------- */
     361             :     /*      Set fields.                                                     */
     362             :     /* -------------------------------------------------------------------- */
     363           0 :     OGRFeature *poFeature = new OGRFeature(poFeatureDefn);
     364             : 
     365           0 :     SetFields(psRTInfo, poFeature, achRecord);
     366             : 
     367           0 :     return poFeature;
     368             : }

Generated by: LCOV version 1.14