LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/gtfs - ogrgtfsdriver.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 311 326 95.4 %
Date: 2024-05-15 13:15:52 Functions: 25 25 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  GDAL
       4             :  * Purpose:  Implements GTFS driver.
       5             :  * Author:   Even Rouault, <even dot rouault at spatialys.com>
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2023, Even Rouault <even dot rouault at spatialys.com>
       9             :  *
      10             :  * Permission is hereby granted, free of charge, to any person obtaining a
      11             :  * copy of this software and associated documentation files (the "Software"),
      12             :  * to deal in the Software without restriction, including without limitation
      13             :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      14             :  * and/or sell copies of the Software, and to permit persons to whom the
      15             :  * Software is furnished to do so, subject to the following conditions:
      16             :  *
      17             :  * The above copyright notice and this permission notice shall be included
      18             :  * in all copies or substantial portions of the Software.
      19             :  *
      20             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      21             :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      22             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      23             :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      24             :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      25             :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      26             :  * DEALINGS IN THE SOFTWARE.
      27             :  ****************************************************************************/
      28             : 
      29             : #include "cpl_port.h"
      30             : #include "gdal_priv.h"
      31             : #include "ogrsf_frmts.h"
      32             : 
      33             : #include <map>
      34             : #include <new>
      35             : #include <utility>
      36             : 
      37             : /***********************************************************************/
      38             : /*                         OGRGTFSDataset                              */
      39             : /***********************************************************************/
      40             : 
      41             : class OGRGTFSDataset final : public GDALDataset
      42             : {
      43             :     std::vector<std::unique_ptr<OGRLayer>> m_apoLayers{};
      44             : 
      45             :   public:
      46           8 :     OGRGTFSDataset() = default;
      47             : 
      48         965 :     int GetLayerCount() override
      49             :     {
      50         965 :         return static_cast<int>(m_apoLayers.size());
      51             :     }
      52             : 
      53             :     OGRLayer *GetLayer(int nIdx) override;
      54             : 
      55             :     static int Identify(GDALOpenInfo *poOpenInfo);
      56             :     static GDALDataset *Open(GDALOpenInfo *poOpenInfo);
      57             : };
      58             : 
      59             : /***********************************************************************/
      60             : /*                              GetLayer()                             */
      61             : /***********************************************************************/
      62             : 
      63         960 : OGRLayer *OGRGTFSDataset::GetLayer(int nIdx)
      64             : {
      65         958 :     return nIdx >= 0 && nIdx < static_cast<int>(m_apoLayers.size())
      66        1918 :                ? m_apoLayers[nIdx].get()
      67         960 :                : nullptr;
      68             : }
      69             : 
      70             : /***********************************************************************/
      71             : /*                           OGRGTFSLayer                              */
      72             : /***********************************************************************/
      73             : 
      74             : class OGRGTFSLayer final : public OGRLayer
      75             : {
      76             :     std::string m_osDirname{};
      77             :     std::unique_ptr<GDALDataset> m_poUnderlyingDS{};
      78             :     OGRLayer *m_poUnderlyingLayer = nullptr;  // owned by m_poUnderlyingDS
      79             :     OGRFeatureDefn *m_poFeatureDefn = nullptr;
      80             :     int m_nTripIdIdx = -1;
      81             :     int m_nLatIdx = -1;
      82             :     int m_nLonIdx = -1;
      83             :     bool m_bIsTrips = false;
      84             :     bool m_bPrepared = false;
      85             :     std::map<std::string, std::pair<double, double>> m_oMapStopIdToLonLat{};
      86             :     std::map<std::string, std::map<int, std::string>> m_oMapTripIdToStopIds{};
      87             : 
      88             :     void PrepareTripsData();
      89             : 
      90             :   public:
      91             :     OGRGTFSLayer(const std::string &osDirname, const char *pszName,
      92             :                  std::unique_ptr<GDALDataset> &&poUnderlyingDS);
      93             :     ~OGRGTFSLayer() override;
      94             : 
      95             :     void ResetReading() override;
      96             :     OGRFeature *GetNextFeature() override;
      97             :     int TestCapability(const char *) override;
      98             :     GIntBig GetFeatureCount(int bForce) override;
      99             :     OGRErr SetAttributeFilter(const char *) override;
     100             : 
     101        4546 :     OGRFeatureDefn *GetLayerDefn() override
     102             :     {
     103        4546 :         return m_poFeatureDefn;
     104             :     }
     105             : };
     106             : 
     107             : /***********************************************************************/
     108             : /*                           OGRGTFSLayer()                            */
     109             : /***********************************************************************/
     110             : 
     111          56 : OGRGTFSLayer::OGRGTFSLayer(const std::string &osDirname, const char *pszName,
     112          56 :                            std::unique_ptr<GDALDataset> &&poUnderlyingDS)
     113          56 :     : m_osDirname(osDirname), m_poUnderlyingDS(std::move(poUnderlyingDS))
     114             : {
     115          56 :     m_poFeatureDefn = new OGRFeatureDefn(pszName);
     116          56 :     SetDescription(pszName);
     117          56 :     m_poFeatureDefn->SetGeomType(wkbNone);
     118          56 :     m_poFeatureDefn->Reference();
     119             : 
     120          56 :     m_poUnderlyingLayer = m_poUnderlyingDS->GetLayer(0);
     121             : 
     122          56 :     auto poSrcLayerDefn = m_poUnderlyingLayer->GetLayerDefn();
     123          56 :     const int nFieldCount = poSrcLayerDefn->GetFieldCount();
     124          56 :     m_nTripIdIdx = poSrcLayerDefn->GetFieldIndex("trip_id");
     125          56 :     if (EQUAL(pszName, "stops"))
     126             :     {
     127           7 :         m_nLatIdx = poSrcLayerDefn->GetFieldIndex("stop_lat");
     128           7 :         m_nLonIdx = poSrcLayerDefn->GetFieldIndex("stop_lon");
     129             :     }
     130          49 :     else if (EQUAL(pszName, "shapes"))
     131             :     {
     132           7 :         m_nLatIdx = poSrcLayerDefn->GetFieldIndex("shape_pt_lat");
     133           7 :         m_nLonIdx = poSrcLayerDefn->GetFieldIndex("shape_pt_lon");
     134             :     }
     135          56 :     m_bIsTrips = EQUAL(pszName, "trips") && m_nTripIdIdx >= 0;
     136             : 
     137          56 :     if (m_nLatIdx >= 0 && m_nLonIdx >= 0)
     138          14 :         m_poFeatureDefn->SetGeomType(wkbPoint);
     139          42 :     else if (m_bIsTrips)
     140           7 :         m_poFeatureDefn->SetGeomType(wkbLineString);
     141             : 
     142         518 :     for (int i = 0; i < nFieldCount; ++i)
     143             :     {
     144         924 :         OGRFieldDefn oFieldDefn(poSrcLayerDefn->GetFieldDefn(i));
     145         462 :         const char *pszFieldName = oFieldDefn.GetNameRef();
     146         462 :         if (i == m_nLatIdx || i == m_nLonIdx ||
     147         434 :             EQUAL(pszFieldName, "shape_dist_traveled"))
     148             :         {
     149          49 :             oFieldDefn.SetType(OFTReal);
     150             :         }
     151         413 :         else if (EQUAL(pszFieldName, "shape_pt_sequence"))
     152             :         {
     153           7 :             oFieldDefn.SetType(OFTInteger);
     154             :         }
     155         406 :         else if (EQUAL(pszFieldName, "date") ||
     156         399 :                  EQUAL(pszFieldName, "start_date") ||
     157         392 :                  EQUAL(pszFieldName, "end_date"))
     158             :         {
     159          21 :             oFieldDefn.SetType(OFTDate);
     160             :         }
     161         385 :         else if (EQUAL(pszFieldName, "arrival_time") ||
     162         371 :                  EQUAL(pszFieldName, "departure_time"))
     163             :         {
     164          28 :             oFieldDefn.SetType(OFTTime);
     165             :         }
     166         357 :         else if (strstr(pszFieldName, "_type") ||
     167         308 :                  EQUAL(pszFieldName, "stop_sequence"))
     168             :         {
     169          63 :             oFieldDefn.SetType(OFTInteger);
     170             :         }
     171         294 :         else if (EQUAL(pszFieldName, "monday") ||
     172         287 :                  EQUAL(pszFieldName, "tuesday") ||
     173         280 :                  EQUAL(pszFieldName, "wednesday") ||
     174         273 :                  EQUAL(pszFieldName, "thursday") ||
     175         266 :                  EQUAL(pszFieldName, "friday") ||
     176         259 :                  EQUAL(pszFieldName, "saturday") ||
     177         252 :                  EQUAL(pszFieldName, "sunday"))
     178             :         {
     179          49 :             oFieldDefn.SetType(OFTInteger);
     180          49 :             oFieldDefn.SetSubType(OFSTBoolean);
     181             :         }
     182         462 :         m_poFeatureDefn->AddFieldDefn(&oFieldDefn);
     183             :     }
     184          56 : }
     185             : 
     186             : /***********************************************************************/
     187             : /*                          ~OGRGTFSLayer()                            */
     188             : /***********************************************************************/
     189             : 
     190         112 : OGRGTFSLayer::~OGRGTFSLayer()
     191             : {
     192          56 :     m_poFeatureDefn->Release();
     193         112 : }
     194             : 
     195             : /***********************************************************************/
     196             : /*                          ResetReading()                             */
     197             : /***********************************************************************/
     198             : 
     199         410 : void OGRGTFSLayer::ResetReading()
     200             : {
     201         410 :     m_poUnderlyingLayer->ResetReading();
     202         410 : }
     203             : 
     204             : /***********************************************************************/
     205             : /*                        PrepareTripsData()                           */
     206             : /***********************************************************************/
     207             : 
     208           2 : void OGRGTFSLayer::PrepareTripsData()
     209             : {
     210           2 :     m_bPrepared = true;
     211             :     try
     212             :     {
     213             :         {
     214             :             auto poStopsDS = std::unique_ptr<GDALDataset>(GDALDataset::Open(
     215           2 :                 (m_osDirname + "/stops.txt").c_str(), GDAL_OF_VECTOR));
     216           2 :             if (!poStopsDS)
     217           0 :                 return;
     218           2 :             auto poStopsLyr = poStopsDS->GetLayer(0);
     219           2 :             if (!poStopsLyr)
     220           0 :                 return;
     221           2 :             const auto poStopsLyrDefn = poStopsLyr->GetLayerDefn();
     222           2 :             const int nStopIdIdx = poStopsLyrDefn->GetFieldIndex("stop_id");
     223           2 :             const int nStopLatIdx = poStopsLyrDefn->GetFieldIndex("stop_lat");
     224           2 :             const int nStopLonIdx = poStopsLyrDefn->GetFieldIndex("stop_lon");
     225           2 :             if (nStopIdIdx < 0 || nStopLatIdx < 0 || nStopLonIdx < 0)
     226           0 :                 return;
     227          72 :             for (auto &&poFeature : poStopsLyr)
     228             :             {
     229          70 :                 const char *pszStopId = poFeature->GetFieldAsString(nStopIdIdx);
     230          70 :                 if (pszStopId)
     231             :                 {
     232         140 :                     m_oMapStopIdToLonLat[pszStopId] = std::make_pair(
     233          70 :                         poFeature->GetFieldAsDouble(nStopLonIdx),
     234         280 :                         poFeature->GetFieldAsDouble(nStopLatIdx));
     235             :                 }
     236             :             }
     237             :         }
     238             : 
     239             :         auto poStopTimesDS = std::unique_ptr<GDALDataset>(GDALDataset::Open(
     240           2 :             (m_osDirname + "/stop_times.txt").c_str(), GDAL_OF_VECTOR));
     241           2 :         if (!poStopTimesDS)
     242           0 :             return;
     243           2 :         auto poStopTimesLyr = poStopTimesDS->GetLayer(0);
     244           2 :         if (!poStopTimesLyr)
     245           0 :             return;
     246           2 :         const auto poStopTimesLyrDefn = poStopTimesLyr->GetLayerDefn();
     247           2 :         const int nStopIdIdx = poStopTimesLyrDefn->GetFieldIndex("stop_id");
     248           2 :         const int nTripIdIdx = poStopTimesLyrDefn->GetFieldIndex("trip_id");
     249             :         const int nStopSequenceIdx =
     250           2 :             poStopTimesLyrDefn->GetFieldIndex("stop_sequence");
     251           2 :         if (nStopIdIdx < 0 || nTripIdIdx < 0 || nStopSequenceIdx < 0)
     252           0 :             return;
     253          72 :         for (auto &&poFeature : poStopTimesLyr)
     254             :         {
     255          70 :             const char *pszStopId = poFeature->GetFieldAsString(nStopIdIdx);
     256          70 :             const char *pszTripId = poFeature->GetFieldAsString(nTripIdIdx);
     257             :             const int nStopSequence =
     258          70 :                 poFeature->GetFieldAsInteger(nStopSequenceIdx);
     259          70 :             if (pszStopId && pszTripId)
     260             :             {
     261          70 :                 m_oMapTripIdToStopIds[pszTripId][nStopSequence] = pszStopId;
     262             :             }
     263             :         }
     264             :     }
     265           0 :     catch (const std::bad_alloc &)
     266             :     {
     267           0 :         CPLError(CE_Failure, CPLE_OutOfMemory, "Not enough memory");
     268             :     }
     269             : }
     270             : 
     271             : /***********************************************************************/
     272             : /*                          GetNextFeature()                           */
     273             : /***********************************************************************/
     274             : 
     275       13467 : OGRFeature *OGRGTFSLayer::GetNextFeature()
     276             : {
     277       13467 :     if (m_bIsTrips && !m_bPrepared)
     278           2 :         PrepareTripsData();
     279             : 
     280             :     while (true)
     281             :     {
     282             :         auto poSrcFeature =
     283       15531 :             std::unique_ptr<OGRFeature>(m_poUnderlyingLayer->GetNextFeature());
     284       15531 :         if (poSrcFeature == nullptr)
     285         157 :             return nullptr;
     286             : 
     287       15374 :         auto poFeature = std::make_unique<OGRFeature>(m_poFeatureDefn);
     288       15374 :         const int nFieldCount = poSrcFeature->GetFieldCount();
     289       15374 :         poFeature->SetFID(poSrcFeature->GetFID());
     290       15374 :         auto poSrcLayerDefn = m_poUnderlyingLayer->GetLayerDefn();
     291      106283 :         for (int i = 0; i < nFieldCount; ++i)
     292             :         {
     293       90909 :             const auto eType = m_poFeatureDefn->GetFieldDefn(i)->GetType();
     294       90909 :             if (poSrcLayerDefn->GetFieldDefn(i)->GetType() == eType)
     295             :             {
     296       25947 :                 poFeature->SetField(i, poSrcFeature->GetRawFieldRef(i));
     297             :             }
     298       64962 :             else if (eType == OFTDate)
     299             :             {
     300          62 :                 const char *pszVal = poSrcFeature->GetFieldAsString(i);
     301          62 :                 constexpr char ZERO_DIGIT = '0';
     302          62 :                 if (pszVal && strlen(pszVal) == 8)
     303             :                 {
     304          62 :                     const int nYear = (pszVal[0] - ZERO_DIGIT) * 1000 +
     305          62 :                                       (pszVal[1] - ZERO_DIGIT) * 100 +
     306          62 :                                       (pszVal[2] - ZERO_DIGIT) * 10 +
     307          62 :                                       (pszVal[3] - ZERO_DIGIT);
     308          62 :                     const int nMonth = (pszVal[4] - ZERO_DIGIT) * 10 +
     309          62 :                                        (pszVal[5] - ZERO_DIGIT);
     310          62 :                     const int nDay = (pszVal[6] - ZERO_DIGIT) * 10 +
     311          62 :                                      (pszVal[7] - ZERO_DIGIT);
     312          62 :                     poFeature->SetField(i, nYear, nMonth, nDay, 0, 0, 0, 0);
     313             :                 }
     314             :             }
     315       64900 :             else if (eType == OFTInteger)
     316             :             {
     317       18584 :                 poFeature->SetField(i, poSrcFeature->GetFieldAsInteger(i));
     318             :             }
     319             :             else
     320             :             {
     321       46316 :                 const char *pszVal = poSrcFeature->GetFieldAsString(i);
     322       46316 :                 poFeature->SetField(i, pszVal);
     323             :             }
     324             :         }
     325       15374 :         if (m_nLatIdx >= 0 && m_nLonIdx >= 0)
     326             :         {
     327       29088 :             poFeature->SetGeometryDirectly(
     328       14544 :                 new OGRPoint(poFeature->GetFieldAsDouble(m_nLonIdx),
     329       14544 :                              poFeature->GetFieldAsDouble(m_nLatIdx)));
     330             :         }
     331         830 :         else if (m_bIsTrips)
     332             :         {
     333          35 :             const char *pszTripId = poFeature->GetFieldAsString(m_nTripIdIdx);
     334          35 :             if (pszTripId)
     335             :             {
     336          35 :                 const auto oIter = m_oMapTripIdToStopIds.find(pszTripId);
     337          35 :                 if (oIter != m_oMapTripIdToStopIds.end())
     338             :                 {
     339          35 :                     OGRLineString *poLS = new OGRLineString();
     340        1260 :                     for (const auto &kv : oIter->second)
     341             :                     {
     342             :                         const auto oIter2 =
     343        1225 :                             m_oMapStopIdToLonLat.find(kv.second);
     344        1225 :                         if (oIter2 != m_oMapStopIdToLonLat.end())
     345        1225 :                             poLS->addPoint(oIter2->second.first,
     346        1225 :                                            oIter2->second.second);
     347             :                     }
     348          35 :                     poFeature->SetGeometryDirectly(poLS);
     349             :                 }
     350             :             }
     351             :         }
     352       21566 :         if (m_poFilterGeom == nullptr ||
     353        6192 :             FilterGeometry(poFeature->GetGeometryRef()))
     354             :         {
     355       13310 :             return poFeature.release();
     356             :         }
     357        2064 :     }
     358             : }
     359             : 
     360             : /***********************************************************************/
     361             : /*                       SetAttributeFilter()                          */
     362             : /***********************************************************************/
     363             : 
     364         314 : OGRErr OGRGTFSLayer::SetAttributeFilter(const char *pszFilter)
     365             : {
     366         314 :     return m_poUnderlyingLayer->SetAttributeFilter(pszFilter);
     367             : }
     368             : 
     369             : /***********************************************************************/
     370             : /*                          GetFeatureCount()                          */
     371             : /***********************************************************************/
     372             : 
     373          97 : GIntBig OGRGTFSLayer::GetFeatureCount(int bForce)
     374             : {
     375          97 :     if (m_poFilterGeom != nullptr)
     376          12 :         return OGRLayer::GetFeatureCount(bForce);
     377          85 :     return m_poUnderlyingLayer->GetFeatureCount(bForce);
     378             : }
     379             : 
     380             : /***********************************************************************/
     381             : /*                          TestCapability()                           */
     382             : /***********************************************************************/
     383             : 
     384         183 : int OGRGTFSLayer::TestCapability(const char *pszCap)
     385             : {
     386         183 :     return EQUAL(pszCap, OLCStringsAsUTF8);
     387             : }
     388             : 
     389             : /***********************************************************************/
     390             : /*                         OGRGTFSShapesGeomLayer                      */
     391             : /***********************************************************************/
     392             : 
     393             : class OGRGTFSShapesGeomLayer final : public OGRLayer
     394             : {
     395             :     std::unique_ptr<GDALDataset> m_poUnderlyingDS{};
     396             :     OGRLayer *m_poUnderlyingLayer = nullptr;  // owned by m_poUnderlyingDS
     397             :     OGRFeatureDefn *m_poFeatureDefn = nullptr;
     398             :     bool m_bPrepared = false;
     399             :     std::vector<std::unique_ptr<OGRFeature>> m_apoFeatures{};
     400             :     size_t m_nIdx = 0;
     401             : 
     402             :     void Prepare();
     403             : 
     404             :   public:
     405             :     explicit OGRGTFSShapesGeomLayer(
     406             :         std::unique_ptr<GDALDataset> &&poUnderlyingDS);
     407             :     ~OGRGTFSShapesGeomLayer() override;
     408             : 
     409             :     void ResetReading() override;
     410             :     OGRFeature *GetNextFeature() override;
     411             :     int TestCapability(const char *) override;
     412             : 
     413         196 :     OGRFeatureDefn *GetLayerDefn() override
     414             :     {
     415         196 :         return m_poFeatureDefn;
     416             :     }
     417             : 
     418             :     GIntBig GetFeatureCount(int bForce) override;
     419             : };
     420             : 
     421             : /***********************************************************************/
     422             : /*                       OGRGTFSShapesGeomLayer()                      */
     423             : /***********************************************************************/
     424             : 
     425           7 : OGRGTFSShapesGeomLayer::OGRGTFSShapesGeomLayer(
     426           7 :     std::unique_ptr<GDALDataset> &&poUnderlyingDS)
     427           7 :     : m_poUnderlyingDS(std::move(poUnderlyingDS))
     428             : {
     429           7 :     m_poFeatureDefn = new OGRFeatureDefn("shapes_geom");
     430           7 :     SetDescription("shapes_geom");
     431           7 :     m_poFeatureDefn->SetGeomType(wkbLineString);
     432           7 :     m_poFeatureDefn->Reference();
     433           7 :     OGRFieldDefn oField("shape_id", OFTString);
     434           7 :     m_poFeatureDefn->AddFieldDefn(&oField);
     435             : 
     436           7 :     m_poUnderlyingLayer = m_poUnderlyingDS->GetLayer(0);
     437           7 : }
     438             : 
     439             : /***********************************************************************/
     440             : /*                      ~OGRGTFSShapesGeomLayer()                      */
     441             : /***********************************************************************/
     442             : 
     443          14 : OGRGTFSShapesGeomLayer::~OGRGTFSShapesGeomLayer()
     444             : {
     445           7 :     m_poFeatureDefn->Release();
     446          14 : }
     447             : 
     448             : /***********************************************************************/
     449             : /*                          ResetReading()                             */
     450             : /***********************************************************************/
     451             : 
     452          96 : void OGRGTFSShapesGeomLayer::ResetReading()
     453             : {
     454          96 :     m_nIdx = 0;
     455          96 : }
     456             : 
     457             : /***********************************************************************/
     458             : /*                            Prepare()                                */
     459             : /***********************************************************************/
     460             : 
     461           2 : void OGRGTFSShapesGeomLayer::Prepare()
     462             : {
     463           2 :     m_bPrepared = true;
     464           2 :     const auto poSrcLayerDefn = m_poUnderlyingLayer->GetLayerDefn();
     465           2 :     const int nShapeIdIdx = poSrcLayerDefn->GetFieldIndex("shape_id");
     466           2 :     const int nLonIdx = poSrcLayerDefn->GetFieldIndex("shape_pt_lon");
     467           2 :     const int nLatIdx = poSrcLayerDefn->GetFieldIndex("shape_pt_lat");
     468           2 :     const int nSeqIdx = poSrcLayerDefn->GetFieldIndex("shape_pt_sequence");
     469           2 :     if (nShapeIdIdx < 0 || nLonIdx < 0 || nLatIdx < 0 || nSeqIdx < 0)
     470           0 :         return;
     471           4 :     std::map<std::string, std::map<int, std::pair<double, double>>> oMap;
     472             :     try
     473             :     {
     474        1306 :         for (auto &&poFeature : m_poUnderlyingLayer)
     475             :         {
     476        1304 :             const char *pszShapeId = poFeature->GetFieldAsString(nShapeIdIdx);
     477        1304 :             if (pszShapeId)
     478             :             {
     479        1304 :                 const int nSeq = poFeature->GetFieldAsInteger(nSeqIdx);
     480        1304 :                 const double dfLon = poFeature->GetFieldAsDouble(nLonIdx);
     481        1304 :                 const double dfLat = poFeature->GetFieldAsDouble(nLatIdx);
     482        1304 :                 oMap[pszShapeId][nSeq] = std::make_pair(dfLon, dfLat);
     483             :             }
     484             :         }
     485           4 :         for (const auto &kv : oMap)
     486             :         {
     487           2 :             const auto &osShapeId = kv.first;
     488           2 :             const auto &oMapPoints = kv.second;
     489           4 :             auto poFeature = std::make_unique<OGRFeature>(m_poFeatureDefn);
     490           2 :             poFeature->SetField(0, osShapeId.c_str());
     491           2 :             OGRLineString *poLS = new OGRLineString();
     492        1306 :             for (const auto &kv2 : oMapPoints)
     493             :             {
     494        1304 :                 poLS->addPoint(kv2.second.first, kv2.second.second);
     495             :             }
     496           2 :             poFeature->SetGeometryDirectly(poLS);
     497           2 :             poFeature->SetFID(static_cast<GIntBig>(m_apoFeatures.size()));
     498           2 :             m_apoFeatures.emplace_back(std::move(poFeature));
     499             :         }
     500             :     }
     501           0 :     catch (const std::bad_alloc &)
     502             :     {
     503           0 :         CPLError(CE_Failure, CPLE_OutOfMemory, "Not enough memory");
     504             :     }
     505             : }
     506             : 
     507             : /***********************************************************************/
     508             : /*                          GetNextFeature()                           */
     509             : /***********************************************************************/
     510             : 
     511          64 : OGRFeature *OGRGTFSShapesGeomLayer::GetNextFeature()
     512             : {
     513          64 :     if (!m_bPrepared)
     514           0 :         Prepare();
     515             :     while (true)
     516             :     {
     517          75 :         if (m_nIdx >= m_apoFeatures.size())
     518          32 :             return nullptr;
     519          97 :         if ((m_poFilterGeom == nullptr ||
     520          82 :              FilterGeometry(m_apoFeatures[m_nIdx]->GetGeometryRef())) &&
     521          39 :             (m_poAttrQuery == nullptr ||
     522          12 :              m_poAttrQuery->Evaluate(m_apoFeatures[m_nIdx].get())))
     523             :         {
     524          32 :             auto poRet = m_apoFeatures[m_nIdx]->Clone();
     525          32 :             m_nIdx++;
     526          32 :             return poRet;
     527             :         }
     528          11 :         m_nIdx++;
     529          11 :     }
     530             : }
     531             : 
     532             : /***********************************************************************/
     533             : /*                          TestCapability()                           */
     534             : /***********************************************************************/
     535             : 
     536          37 : int OGRGTFSShapesGeomLayer::TestCapability(const char *pszCap)
     537             : {
     538          37 :     return EQUAL(pszCap, OLCStringsAsUTF8);
     539             : }
     540             : 
     541             : /***********************************************************************/
     542             : /*                          GetFeatureCount()                          */
     543             : /***********************************************************************/
     544             : 
     545          16 : GIntBig OGRGTFSShapesGeomLayer::GetFeatureCount(int bForce)
     546             : {
     547          16 :     if (m_poAttrQuery != nullptr || m_poFilterGeom != nullptr)
     548           6 :         return OGRLayer::GetFeatureCount(bForce);
     549          10 :     if (!m_bPrepared)
     550           2 :         Prepare();
     551          10 :     return static_cast<GIntBig>(m_apoFeatures.size());
     552             : }
     553             : 
     554             : /***********************************************************************/
     555             : /*                              Identify()                             */
     556             : /***********************************************************************/
     557             : 
     558             : static const char *const apszRequiredFiles[] = {"agency.txt", "routes.txt",
     559             :                                                 "trips.txt",  "stop_times.txt",
     560             :                                                 "stops.txt",  "calendar.txt"};
     561             : 
     562       40572 : int OGRGTFSDataset::Identify(GDALOpenInfo *poOpenInfo)
     563             : {
     564       40572 :     if (STARTS_WITH(poOpenInfo->pszFilename, "GTFS:"))
     565           6 :         return TRUE;
     566             : 
     567       40566 :     if (!EQUAL(CPLGetExtension(poOpenInfo->pszFilename), "zip"))
     568       40508 :         return FALSE;
     569             : 
     570             :     // Check first filename in ZIP
     571             : 
     572          58 :     constexpr int OFFSET_FILENAME_SIZE = 26;
     573          58 :     constexpr int OFFSET_FILENAME_VAL = 30;
     574          58 :     if (poOpenInfo->nHeaderBytes < OFFSET_FILENAME_VAL ||
     575          44 :         memcmp(poOpenInfo->pabyHeader, "PK\x03\x04", 4) != 0)
     576             :     {
     577          14 :         return FALSE;
     578             :     }
     579             : 
     580         248 :     for (const char *pszFilename : apszRequiredFiles)
     581             :     {
     582         214 :         const int nLen = static_cast<int>(strlen(pszFilename));
     583         214 :         if (CPL_LSBSINT16PTR(poOpenInfo->pabyHeader + OFFSET_FILENAME_SIZE) ==
     584          10 :                 nLen &&
     585          10 :             poOpenInfo->nHeaderBytes > OFFSET_FILENAME_VAL + nLen &&
     586          10 :             memcmp(poOpenInfo->pabyHeader + OFFSET_FILENAME_VAL, pszFilename,
     587             :                    nLen) == 0)
     588             :         {
     589          10 :             return TRUE;
     590             :         }
     591             :     }
     592             : 
     593             :     static const char *const apszOptionalFiles[] = {
     594             :         "calendar_dates.txt", "fare_attributes.txt", "fare_rules.txt",
     595             :         "shapes.txt",         "frequencies.txt",     "transfers.txt",
     596             :         "feed_info.txt"};
     597         272 :     for (const char *pszFilename : apszOptionalFiles)
     598             :     {
     599         238 :         const int nLen = static_cast<int>(strlen(pszFilename));
     600         238 :         if (CPL_LSBSINT16PTR(poOpenInfo->pabyHeader + OFFSET_FILENAME_SIZE) ==
     601           2 :                 nLen &&
     602           2 :             poOpenInfo->nHeaderBytes > OFFSET_FILENAME_VAL + nLen &&
     603           2 :             memcmp(poOpenInfo->pabyHeader + OFFSET_FILENAME_VAL, pszFilename,
     604             :                    nLen) == 0)
     605             :         {
     606           0 :             return TRUE;
     607             :         }
     608             :     }
     609          34 :     return FALSE;
     610             : }
     611             : 
     612             : /***********************************************************************/
     613             : /*                              Open()                                 */
     614             : /***********************************************************************/
     615             : 
     616           8 : GDALDataset *OGRGTFSDataset::Open(GDALOpenInfo *poOpenInfo)
     617             : {
     618           8 :     if (!Identify(poOpenInfo))
     619           0 :         return nullptr;
     620             : 
     621           8 :     const char *pszFilename = poOpenInfo->pszFilename;
     622           8 :     if (STARTS_WITH(pszFilename, "GTFS:"))
     623           3 :         pszFilename += strlen("GTFS:");
     624             : 
     625          16 :     std::string osBaseDir(pszFilename);
     626          15 :     if (!STARTS_WITH(pszFilename, "/vsizip/") &&
     627           7 :         EQUAL(CPLGetExtension(pszFilename), "zip"))
     628             :     {
     629           6 :         osBaseDir = "/vsizip/{";
     630           6 :         osBaseDir += pszFilename;
     631           6 :         osBaseDir += '}';
     632             :     }
     633             : 
     634          24 :     const std::string osCSVBaseDirPrefix(std::string("CSV:") + osBaseDir);
     635             : 
     636          16 :     auto poDS = std::make_unique<OGRGTFSDataset>();
     637             : 
     638           8 :     char **papszFilenames = VSIReadDir(osBaseDir.c_str());
     639           8 :     size_t nCountFound = 0;
     640          16 :     std::string osShapesFilename;
     641          71 :     for (CSLConstList papszIter = papszFilenames; papszIter && *papszIter;
     642             :          ++papszIter)
     643             :     {
     644          63 :         if (!EQUAL(CPLGetExtension(*papszIter), "txt"))
     645           0 :             continue;
     646         294 :         for (const char *pszFilenameInDir : apszRequiredFiles)
     647             :         {
     648         273 :             if (EQUAL(*papszIter, pszFilenameInDir))
     649             :             {
     650          42 :                 nCountFound++;
     651          42 :                 break;
     652             :             }
     653             :         }
     654          63 :         if (EQUAL(*papszIter, "shapes.txt"))
     655           7 :             osShapesFilename = *papszIter;
     656             : 
     657             :         auto poCSVDataset = std::unique_ptr<GDALDataset>(
     658         126 :             GDALDataset::Open((osCSVBaseDirPrefix + '/' + *papszIter).c_str(),
     659         126 :                               GDAL_OF_VERBOSE_ERROR | GDAL_OF_VECTOR));
     660          63 :         if (poCSVDataset)
     661             :         {
     662          63 :             auto poUnderlyingLayer = poCSVDataset->GetLayer(0);
     663          63 :             if (poUnderlyingLayer)
     664             :             {
     665          63 :                 auto poSrcLayerDefn = poUnderlyingLayer->GetLayerDefn();
     666          63 :                 if (poSrcLayerDefn->GetFieldIndex("field_1") < 0)
     667             :                 {
     668          56 :                     poDS->m_apoLayers.emplace_back(
     669          56 :                         std::make_unique<OGRGTFSLayer>(
     670         112 :                             osCSVBaseDirPrefix, CPLGetBasename(*papszIter),
     671         112 :                             std::move(poCSVDataset)));
     672             :                 }
     673             :             }
     674             :         }
     675             :     }
     676           8 :     CSLDestroy(papszFilenames);
     677             : 
     678           8 :     if (nCountFound != sizeof(apszRequiredFiles) / sizeof(apszRequiredFiles[0]))
     679             :     {
     680           1 :         CPLError(CE_Failure, CPLE_AppDefined,
     681             :                  "GTFS: required .txt files missing");
     682           1 :         return nullptr;
     683             :     }
     684             : 
     685           7 :     if (!osShapesFilename.empty())
     686             :     {
     687             :         auto poCSVDataset = std::unique_ptr<GDALDataset>(GDALDataset::Open(
     688          14 :             (osCSVBaseDirPrefix + '/' + osShapesFilename).c_str(),
     689          14 :             GDAL_OF_VERBOSE_ERROR | GDAL_OF_VECTOR));
     690           7 :         if (poCSVDataset)
     691             :         {
     692           7 :             auto poUnderlyingLayer = poCSVDataset->GetLayer(0);
     693           7 :             if (poUnderlyingLayer)
     694             :             {
     695           7 :                 poDS->m_apoLayers.emplace_back(
     696          14 :                     std::make_unique<OGRGTFSShapesGeomLayer>(
     697          14 :                         std::move(poCSVDataset)));
     698             :             }
     699             :         }
     700             :     }
     701             : 
     702           7 :     return poDS.release();
     703             : }
     704             : 
     705             : /***********************************************************************/
     706             : /*                         RegisterOGRGTFS()                           */
     707             : /***********************************************************************/
     708             : 
     709        1523 : void RegisterOGRGTFS()
     710             : 
     711             : {
     712        1523 :     if (GDALGetDriverByName("GTFS") != nullptr)
     713         301 :         return;
     714             : 
     715        1222 :     GDALDriver *poDriver = new GDALDriver();
     716             : 
     717        1222 :     poDriver->SetDescription("GTFS");
     718        1222 :     poDriver->SetMetadataItem(GDAL_DMD_LONGNAME,
     719        1222 :                               "General Transit Feed Specification");
     720        1222 :     poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/vector/gtfs.html");
     721        1222 :     poDriver->SetMetadataItem(GDAL_DCAP_VECTOR, "YES");
     722        1222 :     poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
     723        1222 :     poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "zip");
     724             : 
     725        1222 :     poDriver->pfnOpen = OGRGTFSDataset::Open;
     726        1222 :     poDriver->pfnIdentify = OGRGTFSDataset::Identify;
     727             : 
     728        1222 :     GetGDALDriverManager()->RegisterDriver(poDriver);
     729             : }

Generated by: LCOV version 1.14