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 : }
|