LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/tiger - tigercompletechain.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 0 176 0.0 %
Date: 2024-04-29 17:29:47 Functions: 0 7 0.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  TIGER/Line Translator
       4             :  * Purpose:  Implements TigerCompleteChain, providing access to RT1 and
       5             :  *           related files.
       6             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       7             :  *
       8             :  ******************************************************************************
       9             :  * Copyright (c) 1999, Frank Warmerdam
      10             :  *
      11             :  * Permission is hereby granted, free of charge, to any person obtaining a
      12             :  * copy of this software and associated documentation files (the "Software"),
      13             :  * to deal in the Software without restriction, including without limitation
      14             :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      15             :  * and/or sell copies of the Software, and to permit persons to whom the
      16             :  * Software is furnished to do so, subject to the following conditions:
      17             :  *
      18             :  * The above copyright notice and this permission notice shall be included
      19             :  * in all copies or substantial portions of the Software.
      20             :  *
      21             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      22             :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      23             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      24             :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      25             :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      26             :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      27             :  * DEALINGS IN THE SOFTWARE.
      28             :  ****************************************************************************/
      29             : 
      30             : #include "ogr_tiger.h"
      31             : #include "cpl_conv.h"
      32             : 
      33             : #include <cinttypes>
      34             : 
      35             : static const TigerFieldInfo rt1_2002_fields[] = {
      36             :     // fieldname    fmt  type OFTType      beg  end  len  bDefine bSet
      37             :     {"MODULE", ' ', ' ', OFTString, 0, 0, 8, 1, 0},
      38             :     {"TLID", 'R', 'N', OFTInteger, 6, 15, 10, 1, 1},
      39             :     {"SIDE1", 'R', 'N', OFTInteger, 16, 16, 1, 1, 1},
      40             :     {"SOURCE", 'L', 'A', OFTString, 17, 17, 1, 1, 1},
      41             :     {"FEDIRP", 'L', 'A', OFTString, 18, 19, 2, 1, 1},
      42             :     {"FENAME", 'L', 'A', OFTString, 20, 49, 30, 1, 1},
      43             :     {"FETYPE", 'L', 'A', OFTString, 50, 53, 4, 1, 1},
      44             :     {"FEDIRS", 'L', 'A', OFTString, 54, 55, 2, 1, 1},
      45             :     {"CFCC", 'L', 'A', OFTString, 56, 58, 3, 1, 1},
      46             :     {"FRADDL", 'R', 'A', OFTString, 59, 69, 11, 1, 1},
      47             :     {"TOADDL", 'R', 'A', OFTString, 70, 80, 11, 1, 1},
      48             :     {"FRADDR", 'R', 'A', OFTString, 81, 91, 11, 1, 1},
      49             :     {"TOADDR", 'R', 'A', OFTString, 92, 102, 11, 1, 1},
      50             :     {"FRIADDL", 'L', 'A', OFTString, 103, 103, 1, 1, 1},
      51             :     {"TOIADDL", 'L', 'A', OFTString, 104, 104, 1, 1, 1},
      52             :     {"FRIADDR", 'L', 'A', OFTString, 105, 105, 1, 1, 1},
      53             :     {"TOIADDR", 'L', 'A', OFTString, 106, 106, 1, 1, 1},
      54             :     {"ZIPL", 'L', 'N', OFTInteger, 107, 111, 5, 1, 1},
      55             :     {"ZIPR", 'L', 'N', OFTInteger, 112, 116, 5, 1, 1},
      56             :     {"AIANHHFPL", 'L', 'N', OFTInteger, 117, 121, 5, 1, 1},
      57             :     {"AIANHHFPR", 'L', 'N', OFTInteger, 122, 126, 5, 1, 1},
      58             :     {"AIHHTLIL", 'L', 'A', OFTString, 127, 127, 1, 1, 1},
      59             :     {"AIHHTLIR", 'L', 'A', OFTString, 128, 128, 1, 1, 1},
      60             :     {"CENSUS1", 'L', 'A', OFTString, 129, 129, 1, 1, 1},
      61             :     {"CENSUS2", 'L', 'A', OFTString, 130, 130, 1, 1, 1},
      62             :     {"STATEL", 'L', 'N', OFTInteger, 131, 132, 2, 1, 1},
      63             :     {"STATER", 'L', 'N', OFTInteger, 133, 134, 2, 1, 1},
      64             :     {"COUNTYL", 'L', 'N', OFTInteger, 135, 137, 3, 1, 1},
      65             :     {"COUNTYR", 'L', 'N', OFTInteger, 138, 140, 3, 1, 1},
      66             : 
      67             :     {"COUSUBL", 'L', 'N', OFTInteger, 141, 145, 5, 1, 1},
      68             :     {"COUSUBR", 'L', 'N', OFTInteger, 146, 150, 5, 1, 1},
      69             :     {"SUBMCDL", 'L', 'N', OFTInteger, 151, 155, 5, 1, 1},
      70             :     {"SUBMCDR", 'L', 'N', OFTInteger, 156, 160, 5, 1, 1},
      71             :     {"PLACEL", 'L', 'N', OFTInteger, 161, 165, 5, 1, 1},
      72             :     {"PLACER", 'L', 'N', OFTInteger, 166, 170, 5, 1, 1},
      73             :     {"TRACTL", 'L', 'N', OFTInteger, 171, 176, 6, 1, 1},
      74             :     {"TRACTR", 'L', 'N', OFTInteger, 177, 182, 6, 1, 1},
      75             :     {"BLOCKL", 'L', 'N', OFTInteger, 183, 186, 4, 1, 1},
      76             :     {"BLOCKR", 'L', 'N', OFTInteger, 187, 190, 4, 1, 1}};
      77             : static const TigerRecordInfo rt1_2002_info = {
      78             :     rt1_2002_fields, sizeof(rt1_2002_fields) / sizeof(TigerFieldInfo), 228};
      79             : 
      80             : static const TigerFieldInfo rt1_fields[] = {
      81             :     // fieldname    fmt  type OFTType      beg  end   len  bDefine bSet
      82             :     {"MODULE", ' ', ' ', OFTString, 0, 0, 8, 1, 0},
      83             :     {"TLID", 'R', 'N', OFTInteger, 6, 15, 10, 1, 1},
      84             :     {"SIDE1", 'R', 'N', OFTInteger, 16, 16, 1, 1, 1},
      85             :     {"SOURCE", 'L', 'A', OFTString, 17, 17, 1, 1, 1},
      86             :     {"FEDIRP", 'L', 'A', OFTString, 18, 19, 2, 1, 1},
      87             :     {"FENAME", 'L', 'A', OFTString, 20, 49, 30, 1, 1},
      88             :     {"FETYPE", 'L', 'A', OFTString, 50, 53, 4, 1, 1},
      89             :     {"FEDIRS", 'L', 'A', OFTString, 54, 55, 2, 1, 1},
      90             :     {"CFCC", 'L', 'A', OFTString, 56, 58, 3, 1, 1},
      91             :     {"FRADDL", 'R', 'A', OFTString, 59, 69, 11, 1, 1},
      92             :     {"TOADDL", 'R', 'A', OFTString, 70, 80, 11, 1, 1},
      93             :     {"FRADDR", 'R', 'A', OFTString, 81, 91, 11, 1, 1},
      94             :     {"TOADDR", 'R', 'A', OFTString, 92, 102, 11, 1, 1},
      95             :     {"FRIADDL", 'L', 'A', OFTInteger, 103, 103, 1, 1, 1},
      96             :     {"TOIADDL", 'L', 'A', OFTInteger, 104, 104, 1, 1, 1},
      97             :     {"FRIADDR", 'L', 'A', OFTInteger, 105, 105, 1, 1, 1},
      98             :     {"TOIADDR", 'L', 'A', OFTInteger, 106, 106, 1, 1, 1},
      99             :     {"ZIPL", 'L', 'N', OFTInteger, 107, 111, 5, 1, 1},
     100             :     {"ZIPR", 'L', 'N', OFTInteger, 112, 116, 5, 1, 1},
     101             :     {"FAIRL", 'L', 'N', OFTInteger, 117, 121, 5, 1, 1},
     102             :     {"FAIRR", 'L', 'N', OFTInteger, 122, 126, 5, 1, 1},
     103             :     {"TRUSTL", 'L', 'A', OFTString, 127, 127, 1, 1, 1},
     104             :     {"TRUSTR", 'L', 'A', OFTString, 128, 128, 1, 1, 1},
     105             :     {"CENSUS1", 'L', 'A', OFTString, 129, 129, 1, 1, 1},
     106             :     {"CENSUS2", 'L', 'A', OFTString, 130, 130, 1, 1, 1},
     107             :     {"STATEL", 'L', 'N', OFTInteger, 131, 132, 2, 1, 1},
     108             :     {"STATER", 'L', 'N', OFTInteger, 133, 134, 2, 1, 1},
     109             :     {"COUNTYL", 'L', 'N', OFTInteger, 135, 137, 3, 1, 1},
     110             :     {"COUNTYR", 'L', 'N', OFTInteger, 138, 140, 3, 1, 1},
     111             : 
     112             :     {"FMCDL", 'L', 'N', OFTInteger, 141, 145, 5, 1, 1},
     113             :     {"FMCDR", 'L', 'N', OFTInteger, 146, 150, 5, 1, 1},
     114             :     {"FSMCDL", 'L', 'N', OFTInteger, 151, 155, 5, 1, 1},
     115             :     {"FSMCDR", 'L', 'N', OFTInteger, 156, 160, 5, 1, 1},
     116             :     {"FPLL", 'L', 'N', OFTInteger, 161, 165, 5, 1, 1},
     117             :     {"FPLR", 'L', 'N', OFTInteger, 166, 170, 5, 1, 1},
     118             :     {"CTBNAL", 'L', 'N', OFTInteger, 171, 176, 6, 1, 1},
     119             :     {"CTBNAR", 'L', 'N', OFTInteger, 177, 182, 6, 1, 1},
     120             :     {"BLKL", 'L', 'N', OFTString, 183, 186, 4, 1, 1},
     121             :     {"BLKR", 'L', 'N', OFTString, 187, 190, 4, 1, 1}};
     122             : static const TigerRecordInfo rt1_info = {
     123             :     rt1_fields, sizeof(rt1_fields) / sizeof(TigerFieldInfo), 228};
     124             : 
     125             : static const TigerRecordInfo rt2_info = {
     126             :     nullptr,  // RT2 is handled specially in the code below; the only
     127             :     0,        // thing from this structure that is used is:
     128             :     208       // <--- nRecordLength
     129             : };
     130             : 
     131             : static const TigerFieldInfo rt3_2000_Redistricting_fields[] = {
     132             :     // fieldname    fmt  type OFTType       beg  end  len  bDefine bSet
     133             :     {"TLID", 'R', 'N', OFTInteger, 6, 15, 10, 0, 0},
     134             :     {"STATE90L", 'L', 'N', OFTInteger, 16, 17, 2, 1, 1},
     135             :     {"STATE90R", 'L', 'N', OFTInteger, 18, 19, 2, 1, 1},
     136             :     {"COUN90L", 'L', 'N', OFTInteger, 20, 22, 3, 1, 1},
     137             :     {"COUN90R", 'L', 'N', OFTInteger, 23, 25, 3, 1, 1},
     138             :     {"FMCD90L", 'L', 'N', OFTInteger, 26, 30, 5, 1, 1},
     139             :     {"FMCD90R", 'L', 'N', OFTInteger, 31, 35, 5, 1, 1},
     140             :     {"FPL90L", 'L', 'N', OFTInteger, 36, 40, 5, 1, 1},
     141             :     {"FPL90R", 'L', 'N', OFTInteger, 41, 45, 5, 1, 1},
     142             :     {"CTBNA90L", 'L', 'N', OFTInteger, 46, 51, 6, 1, 1},
     143             :     {"CTBNA90R", 'L', 'N', OFTInteger, 52, 57, 6, 1, 1},
     144             :     {"AIR90L", 'L', 'N', OFTInteger, 58, 61, 4, 1, 1},
     145             :     {"AIR90R", 'L', 'N', OFTInteger, 62, 65, 4, 1, 1},
     146             :     {"TRUST90L", 'L', 'A', OFTString, 66, 66, 1, 1, 1},
     147             :     {"TRUST90R", 'L', 'A', OFTString, 67, 67, 1, 1, 1},
     148             :     {"BLK90L", 'L', 'A', OFTString, 70, 73, 4, 1, 1},
     149             :     {"BLK90R", 'L', 'A', OFTString, 74, 77, 4, 1, 1},
     150             :     {"AIRL", 'L', 'N', OFTInteger, 78, 81, 4, 1, 1},
     151             :     {"AIRR", 'L', 'N', OFTInteger, 82, 85, 4, 1, 1},
     152             : 
     153             :     {"ANRCL", 'L', 'N', OFTInteger, 86, 90, 5, 1, 1},
     154             :     {"ANRCR", 'L', 'N', OFTInteger, 91, 95, 5, 1, 1},
     155             :     {"AITSCEL", 'L', 'N', OFTInteger, 96, 98, 3, 1, 1},
     156             :     {"AITSCER", 'L', 'N', OFTInteger, 99, 101, 3, 1, 1},
     157             :     {"AITSL", 'L', 'N', OFTInteger, 102, 106, 5, 1, 1},
     158             :     {"AITSR", 'L', 'N', OFTInteger, 107, 111, 5, 1, 1}};
     159             : static const TigerRecordInfo rt3_2000_Redistricting_info = {
     160             :     rt3_2000_Redistricting_fields,
     161             :     sizeof(rt3_2000_Redistricting_fields) / sizeof(TigerFieldInfo), 111};
     162             : 
     163             : static const TigerFieldInfo rt3_fields[] = {
     164             :     // fieldname    fmt  type OFTType       beg  end  len  bDefine bSet
     165             :     {"TLID", 'R', 'N', OFTInteger, 6, 15, 10, 0, 0},
     166             :     {"STATE90L", 'L', 'N', OFTInteger, 16, 17, 2, 1, 1},
     167             :     {"STATE90R", 'L', 'N', OFTInteger, 18, 19, 2, 1, 1},
     168             :     {"COUN90L", 'L', 'N', OFTInteger, 20, 22, 3, 1, 1},
     169             :     {"COUN90R", 'L', 'N', OFTInteger, 23, 25, 3, 1, 1},
     170             :     {"FMCD90L", 'L', 'N', OFTInteger, 26, 30, 5, 1, 1},
     171             :     {"FMCD90R", 'L', 'N', OFTInteger, 31, 35, 5, 1, 1},
     172             :     {"FPL90L", 'L', 'N', OFTInteger, 36, 40, 5, 1, 1},
     173             :     {"FPL90R", 'L', 'N', OFTInteger, 41, 45, 5, 1, 1},
     174             :     {"CTBNA90L", 'L', 'N', OFTInteger, 46, 51, 6, 1, 1},
     175             :     {"CTBNA90R", 'L', 'N', OFTInteger, 52, 57, 6, 1, 1},
     176             :     {"AIR90L", 'L', 'N', OFTInteger, 58, 61, 4, 1, 1},
     177             :     {"AIR90R", 'L', 'N', OFTInteger, 62, 65, 4, 1, 1},
     178             :     {"TRUST90L", 'L', 'A', OFTInteger, 66, 66, 1, 1, 1},
     179             :     {"TRUST90R", 'L', 'A', OFTInteger, 67, 67, 1, 1, 1},
     180             :     {"BLK90L", 'L', 'A', OFTString, 70, 73, 4, 1, 1},
     181             :     {"BLK90R", 'L', 'A', OFTString, 74, 77, 4, 1, 1},
     182             :     {"AIRL", 'L', 'N', OFTInteger, 78, 81, 4, 1, 1},
     183             :     {"AIRR", 'L', 'N', OFTInteger, 82, 85, 4, 1, 1},
     184             : 
     185             :     {"VTDL", 'L', 'A', OFTString, 104, 107, 4, 1, 1},
     186             :     {"VTDR", 'L', 'A', OFTString, 108, 111, 4, 1, 1}};
     187             : 
     188             : static const TigerRecordInfo rt3_info = {
     189             :     rt3_fields, sizeof(rt3_fields) / sizeof(TigerFieldInfo), 111};
     190             : 
     191             : /************************************************************************/
     192             : /*                         TigerCompleteChain()                         */
     193             : /************************************************************************/
     194             : 
     195           0 : TigerCompleteChain::TigerCompleteChain(OGRTigerDataSource *poDSIn,
     196           0 :                                        const char * /* pszPrototypeModule */)
     197             :     : fpShape(nullptr), panShapeRecordId(nullptr), fpRT3(nullptr),
     198             :       bUsingRT3(false), psRT1Info(nullptr), psRT2Info(nullptr),
     199           0 :       psRT3Info(nullptr)
     200             : {
     201           0 :     poDS = poDSIn;
     202           0 :     poFeatureDefn = new OGRFeatureDefn("CompleteChain");
     203           0 :     poFeatureDefn->Reference();
     204           0 :     poFeatureDefn->SetGeomType(wkbLineString);
     205             : 
     206           0 :     if (poDS->GetVersion() >= TIGER_2002)
     207             :     {
     208           0 :         psRT1Info = &rt1_2002_info;
     209             :         // bUsingRT3 = false;
     210             :     }
     211             :     else
     212             :     {
     213           0 :         psRT1Info = &rt1_info;
     214           0 :         bUsingRT3 = true;
     215             :     }
     216             : 
     217           0 :     psRT2Info = &rt2_info;
     218             : 
     219           0 :     nRT1RecOffset = 0;
     220             : 
     221           0 :     if (poDS->GetVersion() >= TIGER_2000_Redistricting)
     222             :     {
     223           0 :         psRT3Info = &rt3_2000_Redistricting_info;
     224             :     }
     225             :     else
     226             :     {
     227           0 :         psRT3Info = &rt3_info;
     228             :     }
     229             : 
     230             :     /* -------------------------------------------------------------------- */
     231             :     /*      Fields from type 1 record.                                      */
     232             :     /* -------------------------------------------------------------------- */
     233             : 
     234           0 :     AddFieldDefns(psRT1Info, poFeatureDefn);
     235             : 
     236             :     /* -------------------------------------------------------------------- */
     237             :     /*      Fields from type 3 record.  Eventually we should verify that    */
     238             :     /*      a .RT3 file is available before adding these fields.            */
     239             :     /* -------------------------------------------------------------------- */
     240           0 :     if (bUsingRT3)
     241             :     {
     242           0 :         AddFieldDefns(psRT3Info, poFeatureDefn);
     243             :     }
     244           0 : }
     245             : 
     246             : /************************************************************************/
     247             : /*                        ~TigerCompleteChain()                         */
     248             : /************************************************************************/
     249             : 
     250           0 : TigerCompleteChain::~TigerCompleteChain()
     251             : 
     252             : {
     253           0 :     CPLFree(panShapeRecordId);
     254             : 
     255           0 :     if (fpRT3 != nullptr)
     256           0 :         VSIFCloseL(fpRT3);
     257             : 
     258           0 :     if (fpShape != nullptr)
     259           0 :         VSIFCloseL(fpShape);
     260           0 : }
     261             : 
     262             : /************************************************************************/
     263             : /*                             SetModule()                              */
     264             : /************************************************************************/
     265             : 
     266           0 : bool TigerCompleteChain::SetModule(const char *pszModuleIn)
     267             : 
     268             : {
     269           0 :     if (!OpenFile(pszModuleIn, "1"))
     270           0 :         return false;
     271             : 
     272           0 :     EstablishFeatureCount();
     273             : 
     274             :     /* -------------------------------------------------------------------- */
     275             :     /*      Is this a copyright record inserted at the beginning of the     */
     276             :     /*      RT1 file by the folks at GDT?  If so, setup to ignore the       */
     277             :     /*      first record.                                                   */
     278             :     /* -------------------------------------------------------------------- */
     279           0 :     nRT1RecOffset = 0;
     280           0 :     if (pszModuleIn)
     281             :     {
     282             :         char achHeader[10];
     283             : 
     284           0 :         VSIFSeekL(fpPrimary, 0, SEEK_SET);
     285           0 :         VSIFReadL(achHeader, sizeof(achHeader), 1, fpPrimary);
     286             : 
     287           0 :         if (STARTS_WITH_CI(achHeader, "Copyright"))
     288             :         {
     289           0 :             nRT1RecOffset = 1;
     290           0 :             nFeatures--;
     291             :         }
     292             :     }
     293             : 
     294             :     /* -------------------------------------------------------------------- */
     295             :     /*      Open the RT3 file                                               */
     296             :     /* -------------------------------------------------------------------- */
     297           0 :     if (bUsingRT3)
     298             :     {
     299           0 :         if (fpRT3 != nullptr)
     300             :         {
     301           0 :             VSIFCloseL(fpRT3);
     302           0 :             fpRT3 = nullptr;
     303             :         }
     304             : 
     305           0 :         if (pszModuleIn)
     306             :         {
     307           0 :             char *pszFilename = poDS->BuildFilename(pszModuleIn, "3");
     308             : 
     309           0 :             fpRT3 = VSIFOpenL(pszFilename, "rb");
     310             : 
     311           0 :             CPLFree(pszFilename);
     312             :         }
     313             :     }
     314             : 
     315             :     /* -------------------------------------------------------------------- */
     316             :     /*      Close the shape point file, if open and free the list of        */
     317             :     /*      record ids.                                                     */
     318             :     /* -------------------------------------------------------------------- */
     319           0 :     if (fpShape != nullptr)
     320             :     {
     321           0 :         VSIFCloseL(fpShape);
     322           0 :         fpShape = nullptr;
     323             :     }
     324             : 
     325           0 :     CPLFree(panShapeRecordId);
     326           0 :     panShapeRecordId = nullptr;
     327             : 
     328             :     /* -------------------------------------------------------------------- */
     329             :     /*      Try to open the RT2 file corresponding to this RT1 file.        */
     330             :     /* -------------------------------------------------------------------- */
     331           0 :     if (pszModuleIn != nullptr)
     332             :     {
     333           0 :         char *pszFilename = poDS->BuildFilename(pszModuleIn, "2");
     334             : 
     335           0 :         fpShape = VSIFOpenL(pszFilename, "rb");
     336             : 
     337           0 :         if (fpShape == nullptr)
     338             :         {
     339           0 :             if (nRT1RecOffset == 0)
     340           0 :                 CPLError(CE_Warning, CPLE_OpenFailed,
     341             :                          "Failed to open %s, intermediate shape arcs will not "
     342             :                          "be available.\n",
     343             :                          pszFilename);
     344             :         }
     345             :         else
     346           0 :             panShapeRecordId =
     347           0 :                 (int *)CPLCalloc(sizeof(int), (size_t)GetFeatureCount());
     348             : 
     349           0 :         CPLFree(pszFilename);
     350             :     }
     351             : 
     352           0 :     return true;
     353             : }
     354             : 
     355             : /************************************************************************/
     356             : /*                             GetFeature()                             */
     357             : /************************************************************************/
     358             : 
     359           0 : OGRFeature *TigerCompleteChain::GetFeature(int nRecordId)
     360             : 
     361             : {
     362             :     char achRecord[OGR_TIGER_RECBUF_LEN];
     363             : 
     364           0 :     if (nRecordId < 0 || nRecordId >= nFeatures)
     365             :     {
     366           0 :         CPLError(CE_Failure, CPLE_FileIO,
     367             :                  "Request for out-of-range feature %d of %s1", nRecordId,
     368             :                  pszModule);
     369           0 :         return nullptr;
     370             :     }
     371             : 
     372             :     /* -------------------------------------------------------------------- */
     373             :     /*      Read the raw record data from the file.                         */
     374             :     /* -------------------------------------------------------------------- */
     375           0 :     if (fpPrimary == nullptr)
     376           0 :         return nullptr;
     377             : 
     378             :     {
     379           0 :         const auto nOffset =
     380           0 :             static_cast<uint64_t>(nRecordId + nRT1RecOffset) * nRecordLength;
     381           0 :         if (VSIFSeekL(fpPrimary, nOffset, SEEK_SET) != 0)
     382             :         {
     383           0 :             CPLError(CE_Failure, CPLE_FileIO,
     384             :                      "Failed to seek to %" PRIu64 " of %s1", nOffset,
     385             :                      pszModule);
     386           0 :             return nullptr;
     387             :         }
     388             :     }
     389             : 
     390             :     // Overflow cannot happen since psRTInfo->nRecordLength is unsigned
     391             :     // char and sizeof(achRecord) == OGR_TIGER_RECBUF_LEN > 255
     392           0 :     if (VSIFReadL(achRecord, psRT1Info->nRecordLength, 1, fpPrimary) != 1)
     393             :     {
     394           0 :         CPLError(CE_Failure, CPLE_FileIO,
     395             :                  "Failed to read %d bytes of record %d of %s1 at offset %d",
     396           0 :                  psRT1Info->nRecordLength, nRecordId, pszModule,
     397           0 :                  (nRecordId + nRT1RecOffset) * nRecordLength);
     398           0 :         return nullptr;
     399             :     }
     400             : 
     401             :     /* -------------------------------------------------------------------- */
     402             :     /*      Set fields.                                                     */
     403             :     /* -------------------------------------------------------------------- */
     404             : 
     405           0 :     auto poFeature = std::make_unique<OGRFeature>(poFeatureDefn);
     406             : 
     407           0 :     SetFields(psRT1Info, poFeature.get(), achRecord);
     408             : 
     409             :     /* -------------------------------------------------------------------- */
     410             :     /*      Read RT3 record, and apply fields.                              */
     411             :     /* -------------------------------------------------------------------- */
     412             : 
     413           0 :     if (fpRT3 != nullptr)
     414             :     {
     415             :         char achRT3Rec[OGR_TIGER_RECBUF_LEN];
     416           0 :         int nRT3RecLen =
     417           0 :             psRT3Info->nRecordLength + nRecordLength - psRT1Info->nRecordLength;
     418             : 
     419           0 :         const auto nOffset = static_cast<uint64_t>(nRecordId) * nRT3RecLen;
     420           0 :         if (VSIFSeekL(fpRT3, nOffset, SEEK_SET) != 0)
     421             :         {
     422           0 :             CPLError(CE_Failure, CPLE_FileIO,
     423             :                      "Failed to seek to %" PRIu64 " of %s3", nOffset,
     424             :                      pszModule);
     425           0 :             return nullptr;
     426             :         }
     427             : 
     428             :         // Overflow cannot happen since psRTInfo->nRecordLength is unsigned
     429             :         // char and sizeof(achRecord) == OGR_TIGER_RECBUF_LEN > 255
     430           0 :         if (VSIFReadL(achRT3Rec, psRT3Info->nRecordLength, 1, fpRT3) != 1)
     431             :         {
     432           0 :             CPLError(CE_Failure, CPLE_FileIO, "Failed to read record %d of %s3",
     433             :                      nRecordId, pszModule);
     434           0 :             return nullptr;
     435             :         }
     436             : 
     437           0 :         SetFields(psRT3Info, poFeature.get(), achRT3Rec);
     438             :     }
     439             : 
     440             :     /* -------------------------------------------------------------------- */
     441             :     /*      Set geometry                                                    */
     442             :     /* -------------------------------------------------------------------- */
     443           0 :     auto poLine = std::make_unique<OGRLineString>();
     444             : 
     445           0 :     poLine->setPoint(0, atoi(GetField(achRecord, 191, 200)) / 1000000.0,
     446           0 :                      atoi(GetField(achRecord, 201, 209)) / 1000000.0);
     447             : 
     448           0 :     if (!AddShapePoints(poFeature->GetFieldAsInteger("TLID"), nRecordId,
     449             :                         poLine.get(), 0))
     450             :     {
     451           0 :         return nullptr;
     452             :     }
     453             : 
     454           0 :     poLine->addPoint(atoi(GetField(achRecord, 210, 219)) / 1000000.0,
     455           0 :                      atoi(GetField(achRecord, 220, 228)) / 1000000.0);
     456             : 
     457           0 :     poFeature->SetGeometryDirectly(poLine.release());
     458             : 
     459           0 :     return poFeature.release();
     460             : }
     461             : 
     462             : /************************************************************************/
     463             : /*                           AddShapePoints()                           */
     464             : /*                                                                      */
     465             : /*      Record zero or more shape records associated with this line     */
     466             : /*      and add the points to the passed line geometry.                 */
     467             : /************************************************************************/
     468             : 
     469           0 : bool TigerCompleteChain::AddShapePoints(int nTLID, int nRecordId,
     470             :                                         OGRLineString *poLine,
     471             :                                         CPL_UNUSED int nSeqNum)
     472             : {
     473           0 :     int nShapeRecId = GetShapeRecordId(nRecordId, nTLID);
     474             : 
     475             :     // -2 means an error occurred.
     476           0 :     if (nShapeRecId == -2)
     477           0 :         return false;
     478             : 
     479             :     // -1 means there are no extra shape vertices, but things worked fine.
     480           0 :     if (nShapeRecId == -1)
     481           0 :         return true;
     482             : 
     483             :     /* -------------------------------------------------------------------- */
     484             :     /*      Read all the sequential records with the same TLID.             */
     485             :     /* -------------------------------------------------------------------- */
     486             :     char achShapeRec[OGR_TIGER_RECBUF_LEN];
     487           0 :     const int nShapeRecLen =
     488           0 :         psRT2Info->nRecordLength + nRecordLength - psRT1Info->nRecordLength;
     489             : 
     490           0 :     for (; true; nShapeRecId++)
     491             :     {
     492           0 :         int nBytesRead = 0;
     493             : 
     494           0 :         const auto nOffset =
     495           0 :             static_cast<uint64_t>(nShapeRecId - 1) * nShapeRecLen;
     496           0 :         if (VSIFSeekL(fpShape, nOffset, SEEK_SET) != 0)
     497             :         {
     498           0 :             CPLError(CE_Failure, CPLE_FileIO,
     499             :                      "Failed to seek to %" PRIu64 " of %s2", nOffset,
     500             :                      pszModule);
     501           0 :             return false;
     502             :         }
     503             : 
     504           0 :         nBytesRead = static_cast<int>(
     505           0 :             VSIFReadL(achShapeRec, 1, psRT2Info->nRecordLength, fpShape));
     506             : 
     507             :         /*
     508             :         ** Handle case where the last record in the file is full.  We will
     509             :         ** try to read another record but not find it.  We require that we
     510             :         ** have found at least one shape record for this case though.
     511             :         */
     512           0 :         if (nBytesRead <= 0 && VSIFEofL(fpShape) && poLine->getNumPoints() > 0)
     513           0 :             break;
     514             : 
     515           0 :         if (nBytesRead != psRT2Info->nRecordLength)
     516             :         {
     517           0 :             CPLError(CE_Failure, CPLE_FileIO,
     518             :                      "Failed to read %d bytes of record %d of %s2 at offset %d",
     519           0 :                      psRT2Info->nRecordLength, nShapeRecId, pszModule,
     520           0 :                      (nShapeRecId - 1) * nShapeRecLen);
     521           0 :             return false;
     522             :         }
     523             : 
     524           0 :         if (atoi(GetField(achShapeRec, 6, 15)) != nTLID)
     525           0 :             break;
     526             : 
     527             :         /* --------------------------------------------------------------------
     528             :          */
     529             :         /*      Translate the locations into OGRLineString vertices. */
     530             :         /* --------------------------------------------------------------------
     531             :          */
     532           0 :         int iVertex = 0;  // Used after for.
     533             : 
     534           0 :         for (; iVertex < 10; iVertex++)
     535             :         {
     536           0 :             const int iStart = 19 + 19 * iVertex;
     537           0 :             const int nX = atoi(GetField(achShapeRec, iStart, iStart + 9));
     538             :             const int nY =
     539           0 :                 atoi(GetField(achShapeRec, iStart + 10, iStart + 18));
     540             : 
     541           0 :             if (nX == 0 && nY == 0)
     542           0 :                 break;
     543             : 
     544           0 :             poLine->addPoint(nX / 1000000.0, nY / 1000000.0);
     545             :         }
     546             : 
     547             :         /* --------------------------------------------------------------------
     548             :          */
     549             :         /*      Don't get another record if this one was incomplete. */
     550             :         /* --------------------------------------------------------------------
     551             :          */
     552           0 :         if (iVertex < 10)
     553           0 :             break;
     554           0 :     }
     555             : 
     556           0 :     return true;
     557             : }
     558             : 
     559             : /************************************************************************/
     560             : /*                          GetShapeRecordId()                          */
     561             : /*                                                                      */
     562             : /*      Get the record id of the first record of shape points for       */
     563             : /*      the provided TLID (complete chain).                             */
     564             : /************************************************************************/
     565             : 
     566           0 : int TigerCompleteChain::GetShapeRecordId(int nChainId, int nTLID)
     567             : 
     568             : {
     569           0 :     CPLAssert(nChainId >= 0 && nChainId < GetFeatureCount());
     570             : 
     571           0 :     if (fpShape == nullptr || panShapeRecordId == nullptr)
     572           0 :         return -1;
     573             : 
     574             :     /* -------------------------------------------------------------------- */
     575             :     /*      Do we already have the answer?                                  */
     576             :     /* -------------------------------------------------------------------- */
     577           0 :     if (panShapeRecordId[nChainId] != 0)
     578           0 :         return panShapeRecordId[nChainId];
     579             : 
     580             :     /* -------------------------------------------------------------------- */
     581             :     /*      If we don't already have this value, then search from the       */
     582             :     /*      previous known record.                                          */
     583             :     /* -------------------------------------------------------------------- */
     584             :     int iTestChain, nWorkingRecId;
     585             : 
     586           0 :     for (iTestChain = nChainId - 1;
     587           0 :          iTestChain >= 0 && panShapeRecordId[iTestChain] <= 0; iTestChain--)
     588             :     {
     589             :     }
     590             : 
     591           0 :     if (iTestChain < 0)
     592             :     {
     593           0 :         iTestChain = -1;
     594           0 :         nWorkingRecId = 1;
     595             :     }
     596             :     else
     597             :     {
     598           0 :         nWorkingRecId = panShapeRecordId[iTestChain] + 1;
     599             :     }
     600             : 
     601             :     /* -------------------------------------------------------------------- */
     602             :     /*      If we have non existent records following (-1's) we can         */
     603             :     /*      narrow our search a bit.                                        */
     604             :     /* -------------------------------------------------------------------- */
     605           0 :     while (panShapeRecordId[iTestChain + 1] == -1)
     606             :     {
     607           0 :         iTestChain++;
     608             :     }
     609             : 
     610             :     /* -------------------------------------------------------------------- */
     611             :     /*      Read records up to the maximum distance that is possibly        */
     612             :     /*      required, looking for our target TLID.                          */
     613             :     /* -------------------------------------------------------------------- */
     614           0 :     int nMaxChainToRead = nChainId - iTestChain;
     615           0 :     int nChainsRead = 0;
     616             :     char achShapeRec[OGR_TIGER_RECBUF_LEN];
     617           0 :     int nShapeRecLen =
     618           0 :         psRT2Info->nRecordLength + nRecordLength - psRT1Info->nRecordLength;
     619             : 
     620           0 :     if (nShapeRecLen <= 0)
     621             :     {
     622           0 :         return -2;
     623             :     }
     624             : 
     625           0 :     while (nChainsRead < nMaxChainToRead)
     626             :     {
     627           0 :         const auto nOffset =
     628           0 :             static_cast<uint64_t>(nWorkingRecId - 1) * nShapeRecLen;
     629           0 :         if (VSIFSeekL(fpShape, nOffset, SEEK_SET) != 0)
     630             :         {
     631           0 :             CPLError(CE_Failure, CPLE_FileIO,
     632             :                      "Failed to seek to %" PRIu64 " of %s2", nOffset,
     633             :                      pszModule);
     634           0 :             return -2;
     635             :         }
     636             : 
     637           0 :         if (VSIFReadL(achShapeRec, psRT2Info->nRecordLength, 1, fpShape) != 1)
     638             :         {
     639           0 :             if (!VSIFEofL(fpShape))
     640             :             {
     641           0 :                 CPLError(CE_Failure, CPLE_FileIO,
     642             :                          "Failed to read record %d of %s2", nWorkingRecId - 1,
     643             :                          pszModule);
     644           0 :                 return -2;
     645             :             }
     646             :             else
     647           0 :                 return -1;
     648             :         }
     649             : 
     650           0 :         if (atoi(GetField(achShapeRec, 6, 15)) == nTLID)
     651             :         {
     652           0 :             panShapeRecordId[nChainId] = nWorkingRecId;
     653             : 
     654           0 :             return nWorkingRecId;
     655             :         }
     656             : 
     657           0 :         if (atoi(GetField(achShapeRec, 16, 18)) == 1)
     658             :         {
     659           0 :             nChainsRead++;
     660             :         }
     661             : 
     662           0 :         nWorkingRecId++;
     663             :     }
     664             : 
     665           0 :     panShapeRecordId[nChainId] = -1;
     666             : 
     667           0 :     return -1;
     668             : }

Generated by: LCOV version 1.14