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-04-29 17:29:47 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             :  * Permission is hereby granted, free of charge, to any person obtaining a
      13             :  * copy of this software and associated documentation files (the "Software"),
      14             :  * to deal in the Software without restriction, including without limitation
      15             :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      16             :  * and/or sell copies of the Software, and to permit persons to whom the
      17             :  * Software is furnished to do so, subject to the following conditions:
      18             :  *
      19             :  * The above copyright notice and this permission notice shall be included
      20             :  * in all copies or substantial portions of the Software.
      21             :  *
      22             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      23             :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      24             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      25             :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      26             :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      27             :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      28             :  * DEALINGS IN THE SOFTWARE.
      29             :  ****************************************************************************/
      30             : 
      31             : #include "ogr_tiger.h"
      32             : #include "cpl_conv.h"
      33             : #include "cpl_error.h"
      34             : #include "cpl_string.h"
      35             : 
      36             : #include <cinttypes>
      37             : 
      38             : /************************************************************************/
      39             : /*                           TigerFileBase()                            */
      40             : /************************************************************************/
      41             : 
      42           0 : TigerFileBase::TigerFileBase(const TigerRecordInfo *psRTInfoIn,
      43           0 :                              const char *m_pszFileCodeIn)
      44             :     : poDS(nullptr), pszModule(nullptr), pszShortModule(nullptr),
      45             :       fpPrimary(nullptr), poFeatureDefn(nullptr), nFeatures(0),
      46             :       nRecordLength(0), nVersionCode(0), nVersion(TIGER_Unknown),
      47           0 :       psRTInfo(psRTInfoIn), m_pszFileCode(m_pszFileCodeIn)
      48             : {
      49           0 : }
      50             : 
      51             : /************************************************************************/
      52             : /*                           ~TigerFileBase()                           */
      53             : /************************************************************************/
      54             : 
      55           0 : TigerFileBase::~TigerFileBase()
      56             : 
      57             : {
      58           0 :     CPLFree(pszModule);
      59           0 :     CPLFree(pszShortModule);
      60             : 
      61           0 :     if (poFeatureDefn != nullptr)
      62             :     {
      63           0 :         poFeatureDefn->Release();
      64           0 :         poFeatureDefn = nullptr;
      65             :     }
      66             : 
      67           0 :     if (fpPrimary != nullptr)
      68             :     {
      69           0 :         VSIFCloseL(fpPrimary);
      70           0 :         fpPrimary = nullptr;
      71             :     }
      72           0 : }
      73             : 
      74             : /************************************************************************/
      75             : /*                              OpenFile()                              */
      76             : /************************************************************************/
      77             : 
      78           0 : int TigerFileBase::OpenFile(const char *pszModuleToOpen,
      79             :                             const char *pszExtension)
      80             : 
      81             : {
      82             : 
      83           0 :     CPLFree(pszModule);
      84           0 :     pszModule = nullptr;
      85           0 :     CPLFree(pszShortModule);
      86           0 :     pszShortModule = nullptr;
      87             : 
      88           0 :     if (fpPrimary != nullptr)
      89             :     {
      90           0 :         VSIFCloseL(fpPrimary);
      91           0 :         fpPrimary = nullptr;
      92             :     }
      93             : 
      94           0 :     if (pszModuleToOpen == nullptr)
      95           0 :         return TRUE;
      96             : 
      97           0 :     char *pszFilename = poDS->BuildFilename(pszModuleToOpen, pszExtension);
      98             : 
      99           0 :     fpPrimary = VSIFOpenL(pszFilename, "rb");
     100             : 
     101           0 :     CPLFree(pszFilename);
     102             : 
     103           0 :     if (fpPrimary == nullptr)
     104           0 :         return FALSE;
     105             : 
     106           0 :     pszModule = CPLStrdup(pszModuleToOpen);
     107           0 :     pszShortModule = CPLStrdup(pszModuleToOpen);
     108           0 :     for (int i = 0; pszShortModule[i] != '\0'; i++)
     109             :     {
     110           0 :         if (pszShortModule[i] == '.')
     111           0 :             pszShortModule[i] = '\0';
     112             :     }
     113             : 
     114           0 :     SetupVersion();
     115             : 
     116           0 :     return TRUE;
     117             : }
     118             : 
     119             : /************************************************************************/
     120             : /*                            SetupVersion()                            */
     121             : /************************************************************************/
     122             : 
     123           0 : void TigerFileBase::SetupVersion()
     124             : 
     125             : {
     126             :     char aszRecordHead[6];
     127             : 
     128           0 :     VSIFSeekL(fpPrimary, 0, SEEK_SET);
     129           0 :     VSIFReadL(aszRecordHead, 1, 5, fpPrimary);
     130           0 :     aszRecordHead[5] = '\0';
     131           0 :     nVersionCode = atoi(aszRecordHead + 1);
     132           0 :     VSIFSeekL(fpPrimary, 0, SEEK_SET);
     133             : 
     134           0 :     nVersion = TigerClassifyVersion(nVersionCode);
     135           0 : }
     136             : 
     137             : /************************************************************************/
     138             : /*                       EstablishRecordLength()                        */
     139             : /************************************************************************/
     140             : 
     141           0 : int TigerFileBase::EstablishRecordLength(VSILFILE *fp)
     142             : 
     143             : {
     144           0 :     if (fp == nullptr || VSIFSeekL(fp, 0, SEEK_SET) != 0)
     145           0 :         return -1;
     146             : 
     147             :     /* -------------------------------------------------------------------- */
     148             :     /*      Read through to the end of line.                                */
     149             :     /* -------------------------------------------------------------------- */
     150           0 :     int nRecLen = 0;
     151           0 :     char chCurrent = '\0';
     152           0 :     while (VSIFReadL(&chCurrent, 1, 1, fp) == 1 && chCurrent != 10 &&
     153           0 :            chCurrent != 13)
     154             :     {
     155           0 :         nRecLen++;
     156             :     }
     157             : 
     158             :     /* -------------------------------------------------------------------- */
     159             :     /*      Is the file zero length?                                        */
     160             :     /* -------------------------------------------------------------------- */
     161           0 :     if (nRecLen == 0)
     162             :     {
     163           0 :         return -1;
     164             :     }
     165             : 
     166           0 :     nRecLen++; /* for the 10 or 13 we encountered */
     167             : 
     168             :     /* -------------------------------------------------------------------- */
     169             :     /*      Read through line terminator characters.  We are trying to      */
     170             :     /*      handle cases of CR, CR/LF and LF/CR gracefully.                 */
     171             :     /* -------------------------------------------------------------------- */
     172           0 :     while (VSIFReadL(&chCurrent, 1, 1, fp) == 1 &&
     173           0 :            (chCurrent == 10 || chCurrent == 13))
     174             :     {
     175           0 :         nRecLen++;
     176             :     }
     177             : 
     178           0 :     VSIFSeekL(fp, 0, SEEK_SET);
     179             : 
     180           0 :     return nRecLen;
     181             : }
     182             : 
     183             : /************************************************************************/
     184             : /*                       EstablishFeatureCount()                        */
     185             : /************************************************************************/
     186             : 
     187           0 : void TigerFileBase::EstablishFeatureCount()
     188             : 
     189             : {
     190           0 :     if (fpPrimary == nullptr)
     191           0 :         return;
     192             : 
     193           0 :     nRecordLength = EstablishRecordLength(fpPrimary);
     194             : 
     195           0 :     if (nRecordLength == -1)
     196             :     {
     197           0 :         nRecordLength = 1;
     198           0 :         nFeatures = 0;
     199           0 :         return;
     200             :     }
     201             : 
     202             :     /* -------------------------------------------------------------------- */
     203             :     /*      Now we think we know the fixed record length for the file       */
     204             :     /*      (including line terminators).  Get the total file size, and     */
     205             :     /*      divide by this length to get the presumed number of records.    */
     206             :     /* -------------------------------------------------------------------- */
     207             : 
     208           0 :     VSIFSeekL(fpPrimary, 0, SEEK_END);
     209           0 :     const vsi_l_offset nFileSize = VSIFTellL(fpPrimary);
     210             : 
     211           0 :     if ((nFileSize % (vsi_l_offset)nRecordLength) != 0)
     212             :     {
     213           0 :         CPLError(CE_Warning, CPLE_FileIO,
     214             :                  "TigerFileBase::EstablishFeatureCount(): "
     215             :                  "File length %d doesn't divide by record length %d.\n",
     216           0 :                  (int)nFileSize, (int)nRecordLength);
     217             :     }
     218             : 
     219           0 :     if (nFileSize / (vsi_l_offset)nRecordLength > (vsi_l_offset)INT_MAX)
     220           0 :         nFeatures = INT_MAX;
     221             :     else
     222           0 :         nFeatures = static_cast<int>(nFileSize / (vsi_l_offset)nRecordLength);
     223             : }
     224             : 
     225             : /************************************************************************/
     226             : /*                              GetField()                              */
     227             : /************************************************************************/
     228             : 
     229           0 : const char *TigerFileBase::GetField(const char *pachRawDataRecord,
     230             :                                     int nStartChar, int nEndChar)
     231             : 
     232             : {
     233             :     char aszField[128];
     234           0 :     int nLength = nEndChar - nStartChar + 1;
     235             : 
     236           0 :     CPLAssert(nEndChar - nStartChar + 2 < (int)sizeof(aszField));
     237             : 
     238           0 :     strncpy(aszField, pachRawDataRecord + nStartChar - 1, nLength);
     239             : 
     240           0 :     aszField[nLength] = '\0';
     241           0 :     while (nLength > 0 && aszField[nLength - 1] == ' ')
     242           0 :         aszField[--nLength] = '\0';
     243             : 
     244           0 :     return CPLSPrintf("%s", aszField);
     245             : }
     246             : 
     247             : /************************************************************************/
     248             : /*                              SetField()                              */
     249             : /*                                                                      */
     250             : /*      Set a field on an OGRFeature from a tiger record, or leave      */
     251             : /*      NULL if the value isn't found.                                  */
     252             : /************************************************************************/
     253             : 
     254           0 : void TigerFileBase::SetField(OGRFeature *poFeature, const char *pszField,
     255             :                              const char *pachRecord, int nStart, int nEnd)
     256             : 
     257             : {
     258           0 :     const char *pszFieldValue = GetField(pachRecord, nStart, nEnd);
     259             : 
     260           0 :     if (pszFieldValue[0] == '\0')
     261           0 :         return;
     262             : 
     263           0 :     poFeature->SetField(pszField, pszFieldValue);
     264             : }
     265             : 
     266             : /************************************************************************/
     267             : /*                           AddFieldDefns()                            */
     268             : /************************************************************************/
     269           0 : void TigerFileBase::AddFieldDefns(const TigerRecordInfo *psRTInfoIn,
     270             :                                   OGRFeatureDefn *poFeatureDefnIn)
     271             : {
     272           0 :     OGRFieldDefn oField("", OFTInteger);
     273             :     int i, bLFieldHack;
     274             : 
     275           0 :     bLFieldHack =
     276           0 :         CPLTestBool(CPLGetConfigOption("TIGER_LFIELD_AS_STRING", "NO"));
     277             : 
     278           0 :     for (i = 0; i < psRTInfoIn->nFieldCount; ++i)
     279             :     {
     280           0 :         if (psRTInfoIn->pasFields[i].bDefine)
     281             :         {
     282           0 :             OGRFieldType eFT = (OGRFieldType)psRTInfoIn->pasFields[i].OGRtype;
     283             : 
     284           0 :             if (bLFieldHack && psRTInfoIn->pasFields[i].cFmt == 'L' &&
     285           0 :                 psRTInfoIn->pasFields[i].cType == 'N')
     286           0 :                 eFT = OFTString;
     287             : 
     288           0 :             oField.Set(psRTInfoIn->pasFields[i].pszFieldName, eFT,
     289           0 :                        psRTInfoIn->pasFields[i].nLen);
     290           0 :             poFeatureDefnIn->AddFieldDefn(&oField);
     291             :         }
     292             :     }
     293           0 : }
     294             : 
     295             : /************************************************************************/
     296             : /*                             SetFields()                              */
     297             : /************************************************************************/
     298             : 
     299           0 : void TigerFileBase::SetFields(const TigerRecordInfo *psRTInfoIn,
     300             :                               OGRFeature *poFeature, char *achRecord)
     301             : {
     302           0 :     for (int i = 0; i < psRTInfoIn->nFieldCount; ++i)
     303             :     {
     304           0 :         if (psRTInfoIn->pasFields[i].bSet)
     305             :         {
     306           0 :             SetField(poFeature, psRTInfoIn->pasFields[i].pszFieldName,
     307           0 :                      achRecord, psRTInfoIn->pasFields[i].nBeg,
     308           0 :                      psRTInfoIn->pasFields[i].nEnd);
     309             :         }
     310             :     }
     311           0 : }
     312             : 
     313             : /************************************************************************/
     314             : /*                             SetModule()                              */
     315             : /************************************************************************/
     316             : 
     317           0 : bool TigerFileBase::SetModule(const char *pszModuleIn)
     318             : 
     319             : {
     320           0 :     if (m_pszFileCode == nullptr)
     321           0 :         return false;
     322             : 
     323           0 :     if (!OpenFile(pszModuleIn, m_pszFileCode))
     324           0 :         return false;
     325             : 
     326           0 :     EstablishFeatureCount();
     327             : 
     328           0 :     return true;
     329             : }
     330             : 
     331             : /************************************************************************/
     332             : /*                             GetFeature()                             */
     333             : /************************************************************************/
     334             : 
     335           0 : OGRFeature *TigerFileBase::GetFeature(int nRecordId)
     336             : 
     337             : {
     338             :     char achRecord[OGR_TIGER_RECBUF_LEN];
     339             : 
     340           0 :     if (psRTInfo == nullptr)
     341           0 :         return nullptr;
     342             : 
     343           0 :     if (nRecordId < 0 || nRecordId >= nFeatures)
     344             :     {
     345           0 :         CPLError(CE_Failure, CPLE_FileIO,
     346             :                  "Request for out-of-range feature %d of %s", nRecordId,
     347             :                  pszModule);
     348           0 :         return nullptr;
     349             :     }
     350             : 
     351             :     /* -------------------------------------------------------------------- */
     352             :     /*      Read the raw record data from the file.                         */
     353             :     /* -------------------------------------------------------------------- */
     354           0 :     if (fpPrimary == nullptr)
     355           0 :         return nullptr;
     356             : 
     357             :     {
     358           0 :         const auto nOffset = static_cast<uint64_t>(nRecordId) * nRecordLength;
     359           0 :         if (VSIFSeekL(fpPrimary, nOffset, SEEK_SET) != 0)
     360             :         {
     361           0 :             CPLError(CE_Failure, CPLE_FileIO,
     362             :                      "Failed to seek to %" PRIu64 " of %s", nOffset, pszModule);
     363           0 :             return nullptr;
     364             :         }
     365             :     }
     366             : 
     367             :     // Overflow cannot happen since psRTInfo->nRecordLength is unsigned
     368             :     // char and sizeof(achRecord) == OGR_TIGER_RECBUF_LEN > 255
     369           0 :     if (VSIFReadL(achRecord, psRTInfo->nRecordLength, 1, fpPrimary) != 1)
     370             :     {
     371           0 :         CPLError(CE_Failure, CPLE_FileIO, "Failed to read record %d of %s",
     372             :                  nRecordId, pszModule);
     373           0 :         return nullptr;
     374             :     }
     375             : 
     376             :     /* -------------------------------------------------------------------- */
     377             :     /*      Set fields.                                                     */
     378             :     /* -------------------------------------------------------------------- */
     379           0 :     OGRFeature *poFeature = new OGRFeature(poFeatureDefn);
     380             : 
     381           0 :     SetFields(psRTInfo, poFeature, achRecord);
     382             : 
     383           0 :     return poFeature;
     384             : }

Generated by: LCOV version 1.14