update cppgtfs, support ZIP reading and writing for GTFS feeds

This commit is contained in:
Patrick Brosi 2022-10-11 15:04:24 +02:00
parent b4b08baeca
commit 9a8e5d4e31
10 changed files with 441 additions and 298 deletions

View file

@ -42,7 +42,7 @@ make install
## Generating shapes for a GTFS feed ## Generating shapes for a GTFS feed
``` ```
pfaedle -x <OSM FILE> <GTFS INPUT FOLDER> pfaedle -x <OSM FILE> <GTFS INPUT FEED>
``` ```
A shape'd version of the input GTFS feed will be written to `./gtfs-out`. A shape'd version of the input GTFS feed will be written to `./gtfs-out`.
@ -53,9 +53,9 @@ input feed. To drop all existing shapes, use the `-D` flag.
For example, you may generate (and replace existing, see -D parameter) shapes for the GTFS dataset for Freiburg like this: For example, you may generate (and replace existing, see -D parameter) shapes for the GTFS dataset for Freiburg like this:
``` ```
$ wget https://fritz.freiburg.de/csv_Downloads/VAGFR.zip && unzip VAGFR.zip $ wget https://fritz.freiburg.de/csv_Downloads/VAGFR.zip
$ wget http://download.geofabrik.de/europe/germany/baden-wuerttemberg/freiburg-regbez-latest.osm.bz2 && bunzip2 freiburg-regbez-latest.osm.bz2 $ wget http://download.geofabrik.de/europe/germany/baden-wuerttemberg/freiburg-regbez-latest.osm.bz2 && bunzip2 freiburg-regbez-latest.osm.bz2
$ pfaedle -D -x freiburg-regbez-latest.osm . $ pfaedle -D -x freiburg-regbez-latest.osm VAGFR.zip
``` ```
## Generating shapes for a specific MOT ## Generating shapes for a specific MOT

@ -1 +1 @@
Subproject commit aa2714065e1ee8a4773f25aec598d781985086b4 Subproject commit d79469fa692d52cae56f5e797561451edcf3016a

View file

@ -31,33 +31,4 @@
#define BOX_PADDING 2500 #define BOX_PADDING 2500
namespace pfaedle {
// _____________________________________________________________________________
inline std::string getTmpFName(std::string dir, std::string postf) {
if (postf.size()) postf = "-" + postf;
if (!dir.size()) dir = util::getTmpDir();
if (dir.size() && dir.back() != '/') dir = dir + "/";
std::string f = dir + ".pfaedle-tmp" + postf;
size_t c = 0;
while (access(f.c_str(), F_OK) != -1) {
c++;
if (c > 10000) {
// giving up...
LOG(ERROR) << "Could not find temporary file name!";
exit(1);
}
std::stringstream ss;
ss << dir << ".pfaedle-tmp" << postf << "-" << std::rand();
f = ss.str().c_str();
}
return f;
}
} // namespace pfaedle
#endif // PFAEDLE_DEF_H_ #endif // PFAEDLE_DEF_H_

View file

@ -135,8 +135,8 @@ int main(int argc, char** argv) {
if (!cfg.writeOverpass && !cfg.writeOsmfilter) if (!cfg.writeOverpass && !cfg.writeOsmfilter)
LOG(INFO) << "Reading GTFS feed " << cfg.feedPaths[0] << " ..."; LOG(INFO) << "Reading GTFS feed " << cfg.feedPaths[0] << " ...";
try { try {
ad::cppgtfs::Parser p; ad::cppgtfs::Parser p(cfg.feedPaths[0]);
p.parse(&gtfs[0], cfg.feedPaths[0]); p.parse(&gtfs[0]);
} catch (const ad::cppgtfs::ParserException& ex) { } catch (const ad::cppgtfs::ParserException& ex) {
LOG(ERROR) << "Could not parse input GTFS feed, reason was:"; LOG(ERROR) << "Could not parse input GTFS feed, reason was:";
std::cerr << ex.what() << std::endl; std::cerr << ex.what() << std::endl;
@ -146,9 +146,9 @@ int main(int argc, char** argv) {
for (size_t i = 0; i < cfg.feedPaths.size(); i++) { for (size_t i = 0; i < cfg.feedPaths.size(); i++) {
if (!cfg.writeOverpass && !cfg.writeOsmfilter) if (!cfg.writeOverpass && !cfg.writeOsmfilter)
LOG(INFO) << "Reading GTFS feed " << cfg.feedPaths[i] << " ..."; LOG(INFO) << "Reading GTFS feed " << cfg.feedPaths[i] << " ...";
ad::cppgtfs::Parser p;
try { try {
p.parse(&gtfs[i], cfg.feedPaths[i]); ad::cppgtfs::Parser p(cfg.feedPaths[i]);
p.parse(&gtfs[i]);
} catch (const ad::cppgtfs::ParserException& ex) { } catch (const ad::cppgtfs::ParserException& ex) {
LOG(ERROR) << "Could not parse input GTFS feed, reason was:"; LOG(ERROR) << "Could not parse input GTFS feed, reason was:";
std::cerr << ex.what() << std::endl; std::cerr << ex.what() << std::endl;
@ -427,7 +427,6 @@ int main(int argc, char** argv) {
if (cfg.feedPaths.size()) { if (cfg.feedPaths.size()) {
try { try {
mkdir(cfg.outputPath.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
LOG(INFO) << "Writing output GTFS to " << cfg.outputPath << " ..."; LOG(INFO) << "Writing output GTFS to " << cfg.outputPath << " ...";
pfaedle::gtfs::Writer w; pfaedle::gtfs::Writer w;
w.write(&gtfs[0], cfg.outputPath); w.write(&gtfs[0], cfg.outputPath);

View file

@ -6,6 +6,7 @@
#define PFAEDLE_GTFS_FEED_H_ #define PFAEDLE_GTFS_FEED_H_
#include <string> #include <string>
#include "Service.h" #include "Service.h"
#include "ShapeContainer.h" #include "ShapeContainer.h"
#include "StopTime.h" #include "StopTime.h"
@ -22,10 +23,10 @@ namespace gtfs {
typedef ad::cppgtfs::gtfs::FeedB< typedef ad::cppgtfs::gtfs::FeedB<
ad::cppgtfs::gtfs::Agency, ad::cppgtfs::gtfs::Route, ad::cppgtfs::gtfs::Agency, ad::cppgtfs::gtfs::Route,
ad::cppgtfs::gtfs::Stop, Service, StopTime, Shape, ad::cppgtfs::gtfs::Fare, ad::cppgtfs::gtfs::Stop, Service, StopTime, Shape, ad::cppgtfs::gtfs::Fare,
ad::cppgtfs::gtfs::Container, ad::cppgtfs::gtfs::Container, ad::cppgtfs::gtfs::Level, ad::cppgtfs::gtfs::Container,
ad::cppgtfs::gtfs::NullContainer, ad::cppgtfs::gtfs::ContContainer, ad::cppgtfs::gtfs::Container, ad::cppgtfs::gtfs::NullContainer,
ad::cppgtfs::gtfs::ContContainer, ShapeContainer, ad::cppgtfs::gtfs::ContContainer, ad::cppgtfs::gtfs::ContContainer,
ad::cppgtfs::gtfs::Container> ShapeContainer, ad::cppgtfs::gtfs::Container, ad::cppgtfs::gtfs::Container>
Feed; Feed;
typedef ad::cppgtfs::gtfs::TripB<StopTime<ad::cppgtfs::gtfs::Stop>, Service, typedef ad::cppgtfs::gtfs::TripB<StopTime<ad::cppgtfs::gtfs::Stop>, Service,
ad::cppgtfs::gtfs::Route, Shape> ad::cppgtfs::gtfs::Route, Shape>

View file

@ -8,7 +8,7 @@
// ____________________________________________________________________________ // ____________________________________________________________________________
template <typename T> template <typename T>
ShapeContainer<T>::ShapeContainer() : _lastBuff(0) { ShapeContainer<T>::ShapeContainer() : _lastBuff(0) {
std::string f = pfaedle::getTmpFName("", ""); std::string f = util::getTmpFName("<tmp>", ".pfaedle-tmp", "");
_storage.open(f, std::fstream::in | std::fstream::out | std::fstream::trunc); _storage.open(f, std::fstream::in | std::fstream::out | std::fstream::trunc);
// immediately unlink // immediately unlink

View file

@ -2,11 +2,16 @@
// Chair of Algorithms and Data Structures. // Chair of Algorithms and Data Structures.
// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de> // Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
#include <stdio.h>
#include <zip.h>
#include <cstdio> #include <cstdio>
#include <fstream> #include <fstream>
#include <map> #include <map>
#include <memory>
#include <string> #include <string>
#include <utility> #include <utility>
#include "ad/cppgtfs/Parser.h" #include "ad/cppgtfs/Parser.h"
#include "ad/cppgtfs/Writer.h" #include "ad/cppgtfs/Writer.h"
#include "ad/cppgtfs/gtfs/flat/Agency.h" #include "ad/cppgtfs/gtfs/flat/Agency.h"
@ -15,373 +20,490 @@
using ad::cppgtfs::Parser; using ad::cppgtfs::Parser;
using ad::util::CsvWriter; using ad::util::CsvWriter;
using pfaedle::getTmpFName; using ad::util::ZipCsvParser;
using pfaedle::gtfs::Writer; using pfaedle::gtfs::Writer;
using util::getTmpFName;
// ____________________________________________________________________________ // ____________________________________________________________________________
void Writer::write(gtfs::Feed* sourceFeed, const std::string& path) const { void Writer::write(gtfs::Feed* sourceFeed, const std::string& path) const {
bool toZip =
(path.size() > 3 && 0 == path.compare(path.size() - 4, 4, ".zip"));
std::ofstream fs; std::ofstream fs;
std::ifstream is;
std::string gtfsPath(path); std::string gtfsPath(path);
std::string curFile; std::string curFile;
std::string curFileTg; std::string curFileTg;
curFile = getTmpFName(gtfsPath, "agency.txt"); std::string tmpZip;
curFileTg = gtfsPath + "/agency.txt"; std::string zipFileName;
fs.open(curFile.c_str());
if (!fs.good()) cannotWrite(curFile, curFileTg);
writeAgency(sourceFeed, &fs);
fs.close();
if (std::rename(curFile.c_str(), curFileTg.c_str())) cannotWrite(curFileTg);
curFile = getTmpFName(gtfsPath, "stops.txt"); if (gtfsPath.size() == 0) gtfsPath = ".";
curFileTg = gtfsPath + "/stops.txt";
fs.open(curFile.c_str());
if (!fs.good()) cannotWrite(curFile, curFileTg);
writeStops(sourceFeed, &fs);
fs.close();
if (std::rename(curFile.c_str(), curFileTg.c_str())) cannotWrite(curFileTg);
curFile = getTmpFName(gtfsPath, "routes.txt"); zip* za = 0;
curFileTg = gtfsPath + "/routes.txt";
fs.open(curFile.c_str());
if (!fs.good()) cannotWrite(curFile, curFileTg);
writeRoutes(sourceFeed, &fs);
fs.close();
if (std::rename(curFile.c_str(), curFileTg.c_str())) cannotWrite(curFileTg);
is.open((sourceFeed->getPath() + "/calendar.txt").c_str()); if (toZip) {
if (is.good()) { const size_t slashIdx = path.rfind('/');
is.close(); if (slashIdx != std::string::npos) {
curFile = getTmpFName(gtfsPath, "calendar.txt"); zipFileName = path.substr(slashIdx, -1);
curFileTg = gtfsPath + "/calendar.txt"; gtfsPath = path.substr(0, slashIdx);
fs.open(curFile.c_str()); } else {
if (!fs.good()) cannotWrite(curFile, curFileTg); zipFileName = path;
writeCalendar(sourceFeed, &fs); gtfsPath = ".";
fs.close(); }
if (std::rename(curFile.c_str(), curFileTg.c_str())) cannotWrite(curFileTg);
tmpZip = getTmpFName(gtfsPath, ".pfaedle-tmp", zipFileName);
int zipErr = 0;
za = zip_open(tmpZip.c_str(), ZIP_CREATE | ZIP_TRUNCATE, &zipErr);
if (zipErr != 0) {
char errBuf[100];
zip_error_to_str(errBuf, sizeof(errBuf), zipErr, errno);
cannotWrite(tmpZip, gtfsPath + "/" + zipFileName);
std::stringstream ss;
ss << "(temporary file for " << (gtfsPath + "/" + zipFileName)
<< ") Could not open ZIP file, reason was: " << errBuf;
throw ad::cppgtfs::WriterException(ss.str(), tmpZip);
}
} else {
mkdir(path.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
} }
is.open((sourceFeed->getPath() + "/calendar_dates.txt").c_str()); try {
if (is.good()) { Parser ip(sourceFeed->getPath());
is.close();
curFile = getTmpFName(gtfsPath, "calendar_dates.txt"); curFile = getTmpFName(gtfsPath, ".pfaedle-tmp", "agency.txt");
curFileTg = gtfsPath + "/calendar_dates.txt"; curFileTg = gtfsPath + "/agency.txt";
fs.open(curFile.c_str()); fs.open(curFile.c_str());
if (!fs.good()) cannotWrite(curFile, curFileTg); if (!fs.good()) cannotWrite(curFile, curFileTg);
writeCalendarDates(sourceFeed, &fs); writeAgency(sourceFeed, &fs);
fs.close(); fs.close();
if (std::rename(curFile.c_str(), curFileTg.c_str())) cannotWrite(curFileTg);
if (toZip) {
moveIntoZip(za, curFile, "agency.txt");
} else {
if (std::rename(curFile.c_str(), curFileTg.c_str()))
cannotWrite(curFileTg);
}
curFile = getTmpFName(gtfsPath, ".pfaedle-tmp", "stops.txt");
curFileTg = gtfsPath + "/stops.txt";
fs.open(curFile.c_str());
if (!fs.good()) cannotWrite(curFile, curFileTg);
writeStops(sourceFeed, &fs);
fs.close();
if (toZip) {
moveIntoZip(za, curFile, "stops.txt");
} else {
if (std::rename(curFile.c_str(), curFileTg.c_str()))
cannotWrite(curFileTg);
}
curFile = getTmpFName(gtfsPath, ".pfaedle-tmp", "routes.txt");
curFileTg = gtfsPath + "/routes.txt";
fs.open(curFile.c_str());
if (!fs.good()) cannotWrite(curFile, curFileTg);
writeRoutes(sourceFeed, &fs);
fs.close();
if (toZip) {
moveIntoZip(za, curFile, "routes.txt");
} else {
if (std::rename(curFile.c_str(), curFileTg.c_str()))
cannotWrite(curFileTg);
}
auto csvp = ip.getCsvParser("calendar.txt");
if (csvp->isGood()) {
curFile = getTmpFName(gtfsPath, ".pfaedle-tmp", "calendar.txt");
curFileTg = gtfsPath + "/calendar.txt";
fs.open(curFile.c_str());
if (!fs.good()) cannotWrite(curFile, curFileTg);
writeCalendar(sourceFeed, &fs);
fs.close();
if (toZip) {
moveIntoZip(za, curFile, "calendar.txt");
} else {
if (std::rename(curFile.c_str(), curFileTg.c_str()))
cannotWrite(curFileTg);
}
}
csvp = ip.getCsvParser("calendar_dates.txt");
if (csvp->isGood()) {
curFile = getTmpFName(gtfsPath, ".pfaedle-tmp", "calendar_dates.txt");
curFileTg = gtfsPath + "/calendar_dates.txt";
fs.open(curFile.c_str());
if (!fs.good()) cannotWrite(curFile, curFileTg);
writeCalendarDates(sourceFeed, &fs);
fs.close();
if (toZip) {
moveIntoZip(za, curFile, "calendar_dates.txt");
} else {
if (std::rename(curFile.c_str(), curFileTg.c_str()))
cannotWrite(curFileTg);
}
}
csvp = ip.getCsvParser("transfers.txt");
if (csvp->isGood()) {
curFile = getTmpFName(gtfsPath, ".pfaedle-tmp", "transfers.txt");
curFileTg = gtfsPath + "/transfers.txt";
fs.open(curFile.c_str());
if (!fs.good()) cannotWrite(curFile, curFileTg);
writeTransfers(sourceFeed, &fs);
fs.close();
if (toZip) {
moveIntoZip(za, curFile, "transfers.txt");
} else {
if (std::rename(curFile.c_str(), curFileTg.c_str()))
cannotWrite(curFileTg);
}
}
csvp = ip.getCsvParser("fare_attributes.txt");
if (csvp->isGood()) {
curFile = getTmpFName(gtfsPath, ".pfaedle-tmp", "fare_attributes.txt");
curFileTg = gtfsPath + "/fare_attributes.txt";
fs.open(curFile.c_str());
if (!fs.good()) cannotWrite(curFile, curFileTg);
writeFares(sourceFeed, &fs);
fs.close();
if (toZip) {
moveIntoZip(za, curFile, "fare_attributes.txt");
} else {
if (std::rename(curFile.c_str(), curFileTg.c_str()))
cannotWrite(curFileTg);
}
}
csvp = ip.getCsvParser("fare_rules.txt");
if (csvp->isGood()) {
curFile = getTmpFName(gtfsPath, ".pfaedle-tmp", "fare_rules.txt");
curFileTg = gtfsPath + "/fare_rules.txt";
fs.open(curFile.c_str());
if (!fs.good()) cannotWrite(curFile, curFileTg);
writeFareRules(sourceFeed, &fs);
fs.close();
if (toZip) {
moveIntoZip(za, curFile, "fare_rules.txt");
} else {
if (std::rename(curFile.c_str(), curFileTg.c_str()))
cannotWrite(curFileTg);
}
}
csvp = ip.getCsvParser("levels.txt");
if (csvp->isGood()) {
curFile = getTmpFName(gtfsPath, ".pfaedle-tmp", "levels.txt");
curFileTg = gtfsPath + "/levels.txt";
fs.open(curFile.c_str());
if (!fs.good()) cannotWrite(curFile, curFileTg);
writeLevels(sourceFeed, &fs);
fs.close();
if (toZip) {
moveIntoZip(za, curFile, "levels.txt");
} else {
if (std::rename(curFile.c_str(), curFileTg.c_str()))
cannotWrite(curFileTg);
}
}
curFile = getTmpFName(gtfsPath, ".pfaedle-tmp", "shapes.txt");
curFileTg = gtfsPath + "/shapes.txt";
fs.open(curFile.c_str());
if (!fs.good()) cannotWrite(curFile, curFileTg);
writeShapes(sourceFeed, &fs);
fs.close();
if (toZip) {
moveIntoZip(za, curFile, "shapes.txt");
} else {
if (std::rename(curFile.c_str(), curFileTg.c_str()))
cannotWrite(curFileTg);
}
curFile = getTmpFName(gtfsPath, ".pfaedle-tmp", "trips.txt");
curFileTg = gtfsPath + "/trips.txt";
fs.open(curFile.c_str());
if (!fs.good()) cannotWrite(curFile, curFileTg);
bool hasFreqs = writeTrips(sourceFeed, &fs);
fs.close();
if (toZip) {
moveIntoZip(za, curFile, "trips.txt");
} else {
if (std::rename(curFile.c_str(), curFileTg.c_str()))
cannotWrite(curFileTg);
}
csvp = ip.getCsvParser("frequencies.txt");
if (hasFreqs && csvp->isGood()) {
curFile = getTmpFName(gtfsPath, ".pfaedle-tmp", "frequencies.txt");
curFileTg = gtfsPath + "/frequencies.txt";
fs.open(curFile.c_str());
if (!fs.good()) cannotWrite(curFile, curFileTg);
writeFrequencies(sourceFeed, &fs);
fs.close();
if (toZip) {
moveIntoZip(za, curFile, "frequencies.txt");
} else {
if (std::rename(curFile.c_str(), curFileTg.c_str()))
cannotWrite(curFileTg);
}
}
curFile = getTmpFName(gtfsPath, ".pfaedle-tmp", "stop_times.txt");
curFileTg = gtfsPath + "/stop_times.txt";
fs.open(curFile.c_str());
if (!fs.good()) cannotWrite(curFile, curFileTg);
writeStopTimes(sourceFeed, &fs);
fs.close();
if (toZip) {
moveIntoZip(za, curFile, "stop_times.txt");
} else {
if (std::rename(curFile.c_str(), curFileTg.c_str()))
cannotWrite(curFileTg);
}
if (!sourceFeed->getPublisherUrl().empty() &&
!sourceFeed->getPublisherName().empty()) {
curFile = getTmpFName(gtfsPath, ".pfaedle-tmp", "feed_info.txt");
curFileTg = gtfsPath + "/feed_info.txt";
fs.open(curFile.c_str());
if (!fs.good()) cannotWrite(curFile, curFileTg);
writeFeedInfo(sourceFeed, &fs);
fs.close();
if (toZip) {
moveIntoZip(za, curFile, "feed_info.txt");
} else {
if (std::rename(curFile.c_str(), curFileTg.c_str()))
cannotWrite(curFileTg);
}
}
} catch (...) {
zip_discard(za);
throw;
} }
is.open((sourceFeed->getPath() + "/transfers.txt").c_str()); if (toZip) {
if (is.good()) { std::string targetZipPath = gtfsPath + "/" + zipFileName;
is.close(); if (!za) cannotWrite(targetZipPath);
curFile = getTmpFName(gtfsPath, "transfers.txt"); zip_close(za);
curFileTg = gtfsPath + "/transfers.txt"; if (std::rename(tmpZip.c_str(), targetZipPath.c_str()))
fs.open(curFile.c_str()); cannotWrite(targetZipPath);
if (!fs.good()) cannotWrite(curFile, curFileTg);
writeTransfers(sourceFeed, &fs);
fs.close();
if (std::rename(curFile.c_str(), curFileTg.c_str())) cannotWrite(curFileTg);
}
is.open((sourceFeed->getPath() + "/fare_attributes.txt").c_str());
if (is.good()) {
is.close();
curFile = getTmpFName(gtfsPath, "fare_attributes.txt");
curFileTg = gtfsPath + "/fare_attributes.txt";
fs.open(curFile.c_str());
if (!fs.good()) cannotWrite(curFile, curFileTg);
writeFares(sourceFeed, &fs);
fs.close();
if (std::rename(curFile.c_str(), curFileTg.c_str())) cannotWrite(curFileTg);
}
is.open((sourceFeed->getPath() + "/fare_rules.txt").c_str());
if (is.good()) {
is.close();
curFile = getTmpFName(gtfsPath, "fare_rules.txt");
curFileTg = gtfsPath + "/fare_rules.txt";
fs.open(curFile.c_str());
if (!fs.good()) cannotWrite(curFile, curFileTg);
writeFareRules(sourceFeed, &fs);
fs.close();
if (std::rename(curFile.c_str(), curFileTg.c_str())) cannotWrite(curFileTg);
}
is.close();
curFile = getTmpFName(gtfsPath, "shapes.txt");
curFileTg = gtfsPath + "/shapes.txt";
fs.open(curFile.c_str());
if (!fs.good()) cannotWrite(curFile, curFileTg);
writeShapes(sourceFeed, &fs);
fs.close();
if (std::rename(curFile.c_str(), curFileTg.c_str())) cannotWrite(curFileTg);
is.close();
curFile = getTmpFName(gtfsPath, "trips.txt");
curFileTg = gtfsPath + "/trips.txt";
fs.open(curFile.c_str());
if (!fs.good()) cannotWrite(curFile, curFileTg);
bool hasFreqs = writeTrips(sourceFeed, &fs);
fs.close();
if (std::rename(curFile.c_str(), curFileTg.c_str())) cannotWrite(curFileTg);
is.open((sourceFeed->getPath() + "/frequencies.txt").c_str());
if (hasFreqs && is.good()) {
is.close();
curFile = getTmpFName(gtfsPath, "frequencies.txt");
curFileTg = gtfsPath + "/frequencies.txt";
fs.open(curFile.c_str());
if (!fs.good()) cannotWrite(curFile, curFileTg);
writeFrequencies(sourceFeed, &fs);
fs.close();
if (std::rename(curFile.c_str(), curFileTg.c_str())) cannotWrite(curFileTg);
}
is.close();
curFile = getTmpFName(gtfsPath, "stop_times.txt");
curFileTg = gtfsPath + "/stop_times.txt";
fs.open(curFile.c_str());
if (!fs.good()) cannotWrite(curFile, curFileTg);
writeStopTimes(sourceFeed, &fs);
fs.close();
if (std::rename(curFile.c_str(), curFileTg.c_str())) cannotWrite(curFileTg);
if (!sourceFeed->getPublisherUrl().empty() &&
!sourceFeed->getPublisherName().empty()) {
curFile = getTmpFName(gtfsPath, "feed_info.txt");
curFileTg = gtfsPath + "/feed_info.txt";
fs.open(curFile.c_str());
if (!fs.good()) cannotWrite(curFile, curFileTg);
writeFeedInfo(sourceFeed, &fs);
fs.close();
if (std::rename(curFile.c_str(), curFileTg.c_str())) cannotWrite(curFileTg);
} }
} }
// ____________________________________________________________________________ // ____________________________________________________________________________
void Writer::writeFeedInfo(gtfs::Feed* f, std::ostream* os) const { void Writer::writeFeedInfo(gtfs::Feed* f, std::ostream* os) const {
auto csvw = ad::cppgtfs::Writer::getFeedInfoCsvw(os); auto csvw = ad::cppgtfs::Writer::getFeedInfoCsvw(os);
csvw.flushLine(); csvw->flushLine();
csvw.writeString(f->getPublisherName()); csvw->writeString(f->getPublisherName());
csvw.writeString(f->getPublisherUrl()); csvw->writeString(f->getPublisherUrl());
csvw.writeString(f->getLang()); csvw->writeString(f->getLang());
if (!f->getStartDate().empty()) if (!f->getStartDate().empty())
csvw.writeInt(f->getStartDate().getYYYYMMDD()); csvw->writeInt(f->getStartDate().getYYYYMMDD());
else else
csvw.skip(); csvw->skip();
if (!f->getEndDate().empty()) if (!f->getEndDate().empty())
csvw.writeInt(f->getEndDate().getYYYYMMDD()); csvw->writeInt(f->getEndDate().getYYYYMMDD());
else else
csvw.skip(); csvw->skip();
csvw.writeString(f->getVersion()); csvw->writeString(f->getVersion());
csvw.flushLine(); csvw->flushLine();
}
// ____________________________________________________________________________
void Writer::writeLevels(gtfs::Feed* sourceFeed, std::ostream* os) const {
Parser p(sourceFeed->getPath());
auto csvp = p.getCsvParser("levels.txt");
ad::cppgtfs::Writer w;
auto csvw = ad::cppgtfs::Writer::getLevelCsvw(os);
csvw->flushLine();
ad::cppgtfs::gtfs::flat::Level fa;
auto flds = Parser::getLevelFlds(csvp.get());
while (p.nextLevel(csvp.get(), &fa, flds)) {
w.writeLevel(fa, csvw.get());
}
} }
// ____________________________________________________________________________ // ____________________________________________________________________________
void Writer::writeAgency(gtfs::Feed* sourceFeed, std::ostream* os) const { void Writer::writeAgency(gtfs::Feed* sourceFeed, std::ostream* os) const {
std::ifstream fs; Parser p(sourceFeed->getPath());
fs.open((sourceFeed->getPath() + "/agency.txt").c_str()); auto csvp = p.getCsvParser("agency.txt");
CsvParser csvp(&fs);
Parser p;
ad::cppgtfs::Writer w; ad::cppgtfs::Writer w;
CsvWriter csvw = ad::cppgtfs::Writer::getAgencyCsvw(os); auto csvw = ad::cppgtfs::Writer::getAgencyCsvw(os);
csvw.flushLine(); csvw->flushLine();
ad::cppgtfs::gtfs::flat::Agency fa; ad::cppgtfs::gtfs::flat::Agency fa;
auto flds = Parser::getAgencyFlds(&csvp); auto flds = Parser::getAgencyFlds(csvp.get());
while (p.nextAgency(&csvp, &fa, flds)) { while (p.nextAgency(csvp.get(), &fa, flds)) {
w.writeAgency(fa, &csvw); w.writeAgency(fa, csvw.get());
} }
fs.close();
} }
// ____________________________________________________________________________ // ____________________________________________________________________________
void Writer::writeStops(gtfs::Feed* sourceFeed, std::ostream* os) const { void Writer::writeStops(gtfs::Feed* sourceFeed, std::ostream* os) const {
std::ifstream fs; Parser p(sourceFeed->getPath());
fs.open((sourceFeed->getPath() + "/stops.txt").c_str()); auto csvp = p.getCsvParser("stops.txt");
CsvParser csvp(&fs);
Parser p;
ad::cppgtfs::Writer w; ad::cppgtfs::Writer w;
CsvWriter csvw = ad::cppgtfs::Writer::getStopsCsvw(os); auto csvw = ad::cppgtfs::Writer::getStopsCsvw(os);
csvw.flushLine(); csvw->flushLine();
ad::cppgtfs::gtfs::flat::Stop s; ad::cppgtfs::gtfs::flat::Stop s;
auto flds = Parser::getStopFlds(&csvp); auto flds = Parser::getStopFlds(csvp.get());
while (p.nextStop(&csvp, &s, flds)) { while (p.nextStop(csvp.get(), &s, flds)) {
w.writeStop(s, &csvw); w.writeStop(s, csvw.get());
} }
fs.close();
} }
// ____________________________________________________________________________ // ____________________________________________________________________________
void Writer::writeRoutes(gtfs::Feed* sourceFeed, std::ostream* os) const { void Writer::writeRoutes(gtfs::Feed* sourceFeed, std::ostream* os) const {
ad::cppgtfs::Writer w; ad::cppgtfs::Writer w;
CsvWriter csvw = ad::cppgtfs::Writer::getRoutesCsvw(os); auto csvw = ad::cppgtfs::Writer::getRoutesCsvw(os);
csvw.flushLine(); csvw->flushLine();
for (auto r : sourceFeed->getRoutes()) { for (auto r : sourceFeed->getRoutes()) {
w.writeRoute(r.second->getFlat(), &csvw); w.writeRoute(r.second->getFlat(), csvw.get());
} }
} }
// ____________________________________________________________________________ // ____________________________________________________________________________
void Writer::writeCalendar(gtfs::Feed* sourceFeed, std::ostream* os) const { void Writer::writeCalendar(gtfs::Feed* sourceFeed, std::ostream* os) const {
std::ifstream fs; Parser p(sourceFeed->getPath());
fs.open((sourceFeed->getPath() + "/calendar.txt").c_str()); auto csvp = p.getCsvParser("calendar.txt");
CsvParser csvp(&fs);
Parser p;
ad::cppgtfs::Writer w; ad::cppgtfs::Writer w;
CsvWriter csvw = ad::cppgtfs::Writer::getCalendarCsvw(os); auto csvw = ad::cppgtfs::Writer::getCalendarCsvw(os);
csvw.flushLine(); csvw->flushLine();
ad::cppgtfs::gtfs::flat::Calendar c; ad::cppgtfs::gtfs::flat::Calendar c;
auto flds = Parser::getCalendarFlds(&csvp); auto flds = Parser::getCalendarFlds(csvp.get());
while (p.nextCalendar(&csvp, &c, flds)) { while (p.nextCalendar(csvp.get(), &c, flds)) {
w.writeCalendar(c, &csvw); w.writeCalendar(c, csvw.get());
} }
fs.close();
} }
// ____________________________________________________________________________ // ____________________________________________________________________________
void Writer::writeCalendarDates(gtfs::Feed* sourceFeed, void Writer::writeCalendarDates(gtfs::Feed* sourceFeed,
std::ostream* os) const { std::ostream* os) const {
std::ifstream fs; Parser p(sourceFeed->getPath());
fs.open((sourceFeed->getPath() + "/calendar_dates.txt").c_str()); auto csvp = p.getCsvParser("calendar_dates.txt");
CsvParser csvp(&fs);
Parser p;
ad::cppgtfs::Writer w; ad::cppgtfs::Writer w;
CsvWriter csvw = ad::cppgtfs::Writer::getCalendarDatesCsvw(os); auto csvw = ad::cppgtfs::Writer::getCalendarDatesCsvw(os);
csvw.flushLine(); csvw->flushLine();
ad::cppgtfs::gtfs::flat::CalendarDate c; ad::cppgtfs::gtfs::flat::CalendarDate c;
auto flds = Parser::getCalendarDateFlds(&csvp); auto flds = Parser::getCalendarDateFlds(csvp.get());
while (p.nextCalendarDate(&csvp, &c, flds)) { while (p.nextCalendarDate(csvp.get(), &c, flds)) {
w.writeCalendarDate(c, &csvw); w.writeCalendarDate(c, csvw.get());
} }
fs.close();
} }
// ____________________________________________________________________________ // ____________________________________________________________________________
void Writer::writeFrequencies(gtfs::Feed* sourceFeed, std::ostream* os) const { void Writer::writeFrequencies(gtfs::Feed* sourceFeed, std::ostream* os) const {
std::ifstream fs; Parser p(sourceFeed->getPath());
fs.open((sourceFeed->getPath() + "/frequencies.txt").c_str()); auto csvp = p.getCsvParser("frequencies.txt");
CsvParser csvp(&fs);
Parser p;
ad::cppgtfs::Writer w; ad::cppgtfs::Writer w;
CsvWriter csvw = ad::cppgtfs::Writer::getFrequencyCsvw(os); auto csvw = ad::cppgtfs::Writer::getFrequencyCsvw(os);
csvw.flushLine(); csvw->flushLine();
ad::cppgtfs::gtfs::flat::Frequency f; ad::cppgtfs::gtfs::flat::Frequency f;
auto flds = Parser::getFrequencyFlds(&csvp); auto flds = Parser::getFrequencyFlds(csvp.get());
while (p.nextFrequency(&csvp, &f, flds)) { while (p.nextFrequency(csvp.get(), &f, flds)) {
w.writeFrequency(f, &csvw); w.writeFrequency(f, csvw.get());
} }
fs.close();
} }
// ____________________________________________________________________________ // ____________________________________________________________________________
void Writer::writeTransfers(gtfs::Feed* sourceFeed, std::ostream* os) const { void Writer::writeTransfers(gtfs::Feed* sourceFeed, std::ostream* os) const {
std::ifstream fs; Parser p(sourceFeed->getPath());
fs.open((sourceFeed->getPath() + "/transfers.txt").c_str()); auto csvp = p.getCsvParser("transfers.txt");
CsvParser csvp(&fs);
Parser p;
ad::cppgtfs::Writer w; ad::cppgtfs::Writer w;
CsvWriter csvw = ad::cppgtfs::Writer::getTransfersCsvw(os); auto csvw = ad::cppgtfs::Writer::getTransfersCsvw(os);
csvw.flushLine(); csvw->flushLine();
ad::cppgtfs::gtfs::flat::Transfer t; ad::cppgtfs::gtfs::flat::Transfer t;
auto flds = Parser::getTransfersFlds(&csvp); auto flds = Parser::getTransfersFlds(csvp.get());
while (p.nextTransfer(&csvp, &t, flds)) { while (p.nextTransfer(csvp.get(), &t, flds)) {
w.writeTransfer(t, &csvw); w.writeTransfer(t, csvw.get());
} }
fs.close();
} }
// ____________________________________________________________________________ // ____________________________________________________________________________
void Writer::writeFares(gtfs::Feed* sourceFeed, std::ostream* os) const { void Writer::writeFares(gtfs::Feed* sourceFeed, std::ostream* os) const {
std::ifstream fs; Parser p(sourceFeed->getPath());
fs.open((sourceFeed->getPath() + "/fare_attributes.txt").c_str()); auto csvp = p.getCsvParser("fare_attributes.txt");
CsvParser csvp(&fs);
Parser p;
ad::cppgtfs::Writer w; ad::cppgtfs::Writer w;
CsvWriter csvw = ad::cppgtfs::Writer::getFaresCsvw(os); auto csvw = ad::cppgtfs::Writer::getFaresCsvw(os);
csvw.flushLine(); csvw->flushLine();
ad::cppgtfs::gtfs::flat::Fare f; ad::cppgtfs::gtfs::flat::Fare f;
auto flds = Parser::getFareFlds(&csvp); auto flds = Parser::getFareFlds(csvp.get());
while (p.nextFare(&csvp, &f, flds)) { while (p.nextFare(csvp.get(), &f, flds)) {
w.writeFare(f, &csvw); w.writeFare(f, csvw.get());
} }
fs.close();
} }
// ____________________________________________________________________________ // ____________________________________________________________________________
void Writer::writeFareRules(gtfs::Feed* sourceFeed, std::ostream* os) const { void Writer::writeFareRules(gtfs::Feed* sourceFeed, std::ostream* os) const {
std::ifstream fs; Parser p(sourceFeed->getPath());
fs.open((sourceFeed->getPath() + "/fare_rules.txt").c_str()); auto csvp = p.getCsvParser("fare_rules.txt");
CsvParser csvp(&fs);
Parser p;
ad::cppgtfs::Writer w; ad::cppgtfs::Writer w;
CsvWriter csvw = ad::cppgtfs::Writer::getFareRulesCsvw(os); auto csvw = ad::cppgtfs::Writer::getFareRulesCsvw(os);
csvw.flushLine(); csvw->flushLine();
ad::cppgtfs::gtfs::flat::FareRule f; ad::cppgtfs::gtfs::flat::FareRule f;
auto flds = Parser::getFareRuleFlds(&csvp); auto flds = Parser::getFareRuleFlds(csvp.get());
while (p.nextFareRule(&csvp, &f, flds)) { while (p.nextFareRule(csvp.get(), &f, flds)) {
w.writeFareRule(f, &csvw); w.writeFareRule(f, csvw.get());
} }
fs.close();
} }
// ____________________________________________________________________________ // ____________________________________________________________________________
void Writer::writeShapes(gtfs::Feed* sourceFeed, std::ostream* os) const { void Writer::writeShapes(gtfs::Feed* sourceFeed, std::ostream* os) const {
std::ifstream fs; auto csvw = ad::cppgtfs::Writer::getShapesCsvw(os);
fs.open((sourceFeed->getPath() + "/shapes.txt").c_str()); csvw->flushLine();
CsvWriter csvw = ad::cppgtfs::Writer::getShapesCsvw(os);
csvw.flushLine();
ad::cppgtfs::gtfs::flat::ShapePoint sp; ad::cppgtfs::gtfs::flat::ShapePoint sp;
ad::cppgtfs::Writer w; ad::cppgtfs::Writer w;
if (fs.good()) { Parser p(sourceFeed->getPath());
CsvParser csvp(&fs); auto csvp = p.getCsvParser("shapes.txt");
Parser p;
auto flds = Parser::getShapeFlds(&csvp); if (csvp->isGood()) {
auto flds = Parser::getShapeFlds(csvp.get());
std::string curShapeId; std::string curShapeId;
std::string curSkipShapeId; std::string curSkipShapeId;
while (p.nextShapePoint(&csvp, &sp, flds)) { while (p.nextShapePoint(csvp.get(), &sp, flds)) {
if (sp.id == curSkipShapeId) continue; if (sp.id == curSkipShapeId) continue;
if (sp.id != curShapeId) { if (sp.id != curShapeId) {
if (sourceFeed->getShapes().has(sp.id)) { if (sourceFeed->getShapes().has(sp.id)) {
@ -392,16 +514,14 @@ void Writer::writeShapes(gtfs::Feed* sourceFeed, std::ostream* os) const {
} }
} }
w.writeShapePoint(sp, &csvw); w.writeShapePoint(sp, csvw.get());
} }
} }
sourceFeed->getShapes().open(); sourceFeed->getShapes().open();
while (sourceFeed->getShapes().nextStoragePt(&sp)) { while (sourceFeed->getShapes().nextStoragePt(&sp)) {
w.writeShapePoint(sp, &csvw); w.writeShapePoint(sp, csvw.get());
} }
fs.close();
} }
// ____________________________________________________________________________ // ____________________________________________________________________________
@ -409,12 +529,12 @@ bool Writer::writeTrips(gtfs::Feed* sourceFeed, std::ostream* os) const {
ad::cppgtfs::Writer w; ad::cppgtfs::Writer w;
bool hasFreqs = false; bool hasFreqs = false;
CsvWriter csvw = ad::cppgtfs::Writer::getTripsCsvw(os); auto csvw = ad::cppgtfs::Writer::getTripsCsvw(os);
csvw.flushLine(); csvw->flushLine();
for (auto t : sourceFeed->getTrips()) { for (auto t : sourceFeed->getTrips()) {
if (t.getFrequencies().size()) hasFreqs = true; if (t.getFrequencies().size()) hasFreqs = true;
w.writeTrip(t.getFlat(), &csvw); w.writeTrip(t.getFlat(), csvw.get());
} }
return hasFreqs; return hasFreqs;
@ -422,23 +542,20 @@ bool Writer::writeTrips(gtfs::Feed* sourceFeed, std::ostream* os) const {
// ____________________________________________________________________________ // ____________________________________________________________________________
void Writer::writeStopTimes(gtfs::Feed* sourceFeed, std::ostream* os) const { void Writer::writeStopTimes(gtfs::Feed* sourceFeed, std::ostream* os) const {
std::ifstream fs; Parser p(sourceFeed->getPath());
fs.open((sourceFeed->getPath() + "/stop_times.txt").c_str()); auto csvp = p.getCsvParser("stop_times.txt");
CsvParser csvp(&fs);
Parser p;
ad::cppgtfs::Writer w; ad::cppgtfs::Writer w;
CsvWriter csvw = ad::cppgtfs::Writer::getStopTimesCsvw(os); auto csvw = ad::cppgtfs::Writer::getStopTimesCsvw(os);
csvw.flushLine(); csvw->flushLine();
ad::cppgtfs::gtfs::flat::StopTime st; ad::cppgtfs::gtfs::flat::StopTime st;
auto flds = Parser::getStopTimeFlds(&csvp); auto flds = Parser::getStopTimeFlds(csvp.get());
std::string curTripId; std::string curTripId;
Trip* cur = 0; Trip* cur = 0;
while (p.nextStopTime(&csvp, &st, flds)) { while (p.nextStopTime(csvp.get(), &st, flds)) {
// we may have changed to distance field // we may have changed to distance field
if (curTripId != st.trip) { if (curTripId != st.trip) {
cur = sourceFeed->getTrips().get(st.trip); cur = sourceFeed->getTrips().get(st.trip);
@ -449,9 +566,8 @@ void Writer::writeStopTimes(gtfs::Feed* sourceFeed, std::ostream* os) const {
st.shapeDistTravelled = stN.getShapeDistanceTravelled(); st.shapeDistTravelled = stN.getShapeDistanceTravelled();
} }
w.writeStopTime(st, &csvw); w.writeStopTime(st, csvw.get());
} }
fs.close();
} }
// ___________________________________________________________________________ // ___________________________________________________________________________
@ -467,3 +583,24 @@ void Writer::cannotWrite(const std::string& file, const std::string& file2) {
ss << "(temporary file for " << file2 << ") Could not write to file"; ss << "(temporary file for " << file2 << ") Could not write to file";
throw ad::cppgtfs::WriterException(ss.str(), file); throw ad::cppgtfs::WriterException(ss.str(), file);
} }
// ___________________________________________________________________________
void Writer::moveIntoZip(zip* za, const std::string& sourcePath,
const std::string& targetPath) {
zip_source_t* s;
FILE* fp = fopen(sourcePath.c_str(), "r");
if (fp == 0) {
std::stringstream ss;
ss << "(temporary file for " << targetPath << ") Could not open file";
throw ad::cppgtfs::WriterException(ss.str(), sourcePath);
}
// immediately unlink
unlink(sourcePath.c_str());
if ((s = zip_source_filep(za, fp, 0, -1)) == 0 ||
zip_file_add(za, targetPath.c_str(), s, ZIP_FL_ENC_UTF_8) < 0) {
zip_source_free(s);
cannotWrite(targetPath);
}
}

View file

@ -5,9 +5,12 @@
#ifndef PFAEDLE_GTFS_WRITER_H_ #ifndef PFAEDLE_GTFS_WRITER_H_
#define PFAEDLE_GTFS_WRITER_H_ #define PFAEDLE_GTFS_WRITER_H_
#include <memory>
#include <string> #include <string>
#include "ad/cppgtfs/Writer.h"
#include "Feed.h" #include "Feed.h"
#include "ad/cppgtfs/Parser.h"
#include "ad/cppgtfs/Writer.h"
namespace pfaedle { namespace pfaedle {
namespace gtfs { namespace gtfs {
@ -32,9 +35,15 @@ class Writer {
void writeShapes(Feed* f, std::ostream* os) const; void writeShapes(Feed* f, std::ostream* os) const;
bool writeTrips(Feed* f, std::ostream* os) const; bool writeTrips(Feed* f, std::ostream* os) const;
void writeStopTimes(Feed* f, std::ostream* os) const; void writeStopTimes(Feed* f, std::ostream* os) const;
void writeLevels(Feed* f, std::ostream* os) const;
static void cannotWrite(const std::string& file, const std::string& file2); static void cannotWrite(const std::string& file, const std::string& file2);
static void cannotWrite(const std::string& file); static void cannotWrite(const std::string& file);
static void moveIntoZip(zip* za, const std::string& sourcePath,
const std::string& targetPath);
mutable std::ifstream _ifs;
}; };
} // namespace gtfs } // namespace gtfs

View file

@ -306,7 +306,7 @@ uint32_t OsmIdSet::jenkins(uint32_t in) const {
// _____________________________________________________________________________ // _____________________________________________________________________________
int OsmIdSet::openTmpFile() const { int OsmIdSet::openTmpFile() const {
const std::string& fname = getTmpFName("", ""); const std::string& fname = util::getTmpFName("<tmp>", ".pfaedle-tmp", "");
int file = open(fname.c_str(), O_RDWR | O_CREAT, 0666); int file = open(fname.c_str(), O_RDWR | O_CREAT, 0666);
// immediately unlink // immediately unlink

View file

@ -304,6 +304,32 @@ inline std::string getTmpDir() {
return getHomeDir(); return getHomeDir();
} }
// _____________________________________________________________________________
inline std::string getTmpFName(std::string dir, std::string name,
std::string postf) {
if (postf.size()) postf = "-" + postf;
if (dir == "<tmp>") dir = util::getTmpDir();
if (dir.size() && dir.back() != '/') dir = dir + "/";
std::string f = dir + name + postf;
size_t c = 0;
while (access(f.c_str(), F_OK) != -1) {
c++;
if (c > 10000) {
// giving up...
std::cerr << "Could not find temporary file name!" << std::endl;
exit(1);
}
std::stringstream ss;
ss << dir << name << postf << "-" << std::rand();
f = ss.str().c_str();
}
return f;
}
// _____________________________________________________________________________ // _____________________________________________________________________________
class approx { class approx {
public: public: