Implementation of turn restriction exceptions

This commit is contained in:
DennisOSRM 2013-01-05 19:20:25 +01:00
parent 5de2aa1cbf
commit ffdaa71086
6 changed files with 761 additions and 692 deletions

View File

@ -1,17 +1,17 @@
/* /*
open source routing machine open source routing machine
Copyright (C) Dennis Luxen, others 2010 Copyright (C) Dennis Luxen, others 2010
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU AFFERO General Public License as published by it under the terms of the GNU AFFERO General Public License as published by
the Free Software Foundation; either version 3 of the License, or the Free Software Foundation; either version 3 of the License, or
any later version. any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU Affero General Public License You should have received a copy of the GNU Affero General Public License
along with this program; if not, write to the Free Software along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
@ -21,489 +21,524 @@
#include "PBFParser.h" #include "PBFParser.h"
PBFParser::PBFParser(const char * fileName) : externalMemory(NULL){ PBFParser::PBFParser(const char * fileName) : externalMemory(NULL){
GOOGLE_PROTOBUF_VERIFY_VERSION; GOOGLE_PROTOBUF_VERIFY_VERSION;
//TODO: What is the bottleneck here? Filling the queue or reading the stuff from disk? //TODO: What is the bottleneck here? Filling the queue or reading the stuff from disk?
//NOTE: With Lua scripting, it is parsing the stuff. I/O is virtually for free. //NOTE: With Lua scripting, it is parsing the stuff. I/O is virtually for free.
threadDataQueue = boost::make_shared<ConcurrentQueue<_ThreadData*> >( 2500 ); /* Max 2500 items in queue, hardcoded. */ threadDataQueue = boost::make_shared<ConcurrentQueue<_ThreadData*> >( 2500 ); /* Max 2500 items in queue, hardcoded. */
input.open(fileName, std::ios::in | std::ios::binary); input.open(fileName, std::ios::in | std::ios::binary);
if (!input) { if (!input) {
std::cerr << fileName << ": File not found." << std::endl; std::cerr << fileName << ": File not found." << std::endl;
} }
#ifndef NDEBUG #ifndef NDEBUG
blockCount = 0; blockCount = 0;
groupCount = 0; groupCount = 0;
#endif #endif
} }
void PBFParser::RegisterCallbacks(ExtractorCallbacks * em) { void PBFParser::RegisterCallbacks(ExtractorCallbacks * em) {
externalMemory = em; externalMemory = em;
} }
void PBFParser::RegisterScriptingEnvironment(ScriptingEnvironment & _se) { void PBFParser::RegisterScriptingEnvironment(ScriptingEnvironment & _se) {
scriptingEnvironment = _se; scriptingEnvironment = _se;
if(lua_function_exists(scriptingEnvironment.getLuaStateForThreadID(0), "get_exceptions" )) {
//get list of turn restriction exceptions
try {
luabind::call_function<void>(
scriptingEnvironment.getLuaStateForThreadID(0),
"get_exceptions",
boost::ref(restriction_exceptions_vector)
);
INFO("Found " << restriction_exceptions_vector.size() << " exceptions to turn restriction");
BOOST_FOREACH(std::string & str, restriction_exceptions_vector) {
INFO("ignoring: " << str);
}
} catch (const luabind::error &er) {
lua_State* Ler=er.state();
report_errors(Ler, -1);
ERR(er.what());
}
} else {
INFO("Found no exceptions to turn restrictions");
}
} }
PBFParser::~PBFParser() { PBFParser::~PBFParser() {
if(input.is_open()) if(input.is_open())
input.close(); input.close();
// Clean up any leftover ThreadData objects in the queue // Clean up any leftover ThreadData objects in the queue
_ThreadData* td; _ThreadData* td;
while (threadDataQueue->try_pop(td)) { while (threadDataQueue->try_pop(td)) {
delete td; delete td;
} }
google::protobuf::ShutdownProtobufLibrary(); google::protobuf::ShutdownProtobufLibrary();
#ifndef NDEBUG #ifndef NDEBUG
DEBUG("parsed " << blockCount << " blocks from pbf with " << groupCount << " groups"); DEBUG("parsed " << blockCount << " blocks from pbf with " << groupCount << " groups");
#endif #endif
} }
inline bool PBFParser::Init() { inline bool PBFParser::Init() {
_ThreadData initData; _ThreadData initData;
/** read Header */ /** read Header */
if(!readPBFBlobHeader(input, &initData)) { if(!readPBFBlobHeader(input, &initData)) {
return false; return false;
} }
if(readBlob(input, &initData)) { if(readBlob(input, &initData)) {
if(!initData.PBFHeaderBlock.ParseFromArray(&(initData.charBuffer[0]), initData.charBuffer.size() ) ) { if(!initData.PBFHeaderBlock.ParseFromArray(&(initData.charBuffer[0]), initData.charBuffer.size() ) ) {
std::cerr << "[error] Header not parseable!" << std::endl; std::cerr << "[error] Header not parseable!" << std::endl;
return false; return false;
} }
for(int i = 0, featureSize = initData.PBFHeaderBlock.required_features_size(); i < featureSize; ++i) { for(int i = 0, featureSize = initData.PBFHeaderBlock.required_features_size(); i < featureSize; ++i) {
const std::string& feature = initData.PBFHeaderBlock.required_features( i ); const std::string& feature = initData.PBFHeaderBlock.required_features( i );
bool supported = false; bool supported = false;
if ( "OsmSchema-V0.6" == feature ) if ( "OsmSchema-V0.6" == feature )
supported = true; supported = true;
else if ( "DenseNodes" == feature ) else if ( "DenseNodes" == feature )
supported = true; supported = true;
if ( !supported ) { if ( !supported ) {
std::cerr << "[error] required feature not supported: " << feature.data() << std::endl; std::cerr << "[error] required feature not supported: " << feature.data() << std::endl;
return false; return false;
} }
} }
} else { } else {
std::cerr << "[error] blob not loaded!" << std::endl; std::cerr << "[error] blob not loaded!" << std::endl;
} }
return true; return true;
} }
inline void PBFParser::ReadData() { inline void PBFParser::ReadData() {
bool keepRunning = true; bool keepRunning = true;
do { do {
_ThreadData *threadData = new _ThreadData(); _ThreadData *threadData = new _ThreadData();
keepRunning = readNextBlock(input, threadData); keepRunning = readNextBlock(input, threadData);
if (keepRunning) if (keepRunning)
threadDataQueue->push(threadData); threadDataQueue->push(threadData);
else { else {
threadDataQueue->push(NULL); // No more data to read, parse stops when NULL encountered threadDataQueue->push(NULL); // No more data to read, parse stops when NULL encountered
delete threadData; delete threadData;
} }
} while(keepRunning); } while(keepRunning);
} }
inline void PBFParser::ParseData() { inline void PBFParser::ParseData() {
while (true) { while (true) {
_ThreadData *threadData; _ThreadData *threadData;
threadDataQueue->wait_and_pop(threadData); threadDataQueue->wait_and_pop(threadData);
if (threadData == NULL) { if (threadData == NULL) {
INFO("Parse Data Thread Finished"); INFO("Parse Data Thread Finished");
threadDataQueue->push(NULL); // Signal end of data for other threads threadDataQueue->push(NULL); // Signal end of data for other threads
break; break;
} }
loadBlock(threadData); loadBlock(threadData);
for(int i = 0, groupSize = threadData->PBFprimitiveBlock.primitivegroup_size(); i < groupSize; ++i) { for(int i = 0, groupSize = threadData->PBFprimitiveBlock.primitivegroup_size(); i < groupSize; ++i) {
threadData->currentGroupID = i; threadData->currentGroupID = i;
loadGroup(threadData); loadGroup(threadData);
if(threadData->entityTypeIndicator == TypeNode) if(threadData->entityTypeIndicator == TypeNode)
parseNode(threadData); parseNode(threadData);
if(threadData->entityTypeIndicator == TypeWay) if(threadData->entityTypeIndicator == TypeWay)
parseWay(threadData); parseWay(threadData);
if(threadData->entityTypeIndicator == TypeRelation) if(threadData->entityTypeIndicator == TypeRelation)
parseRelation(threadData); parseRelation(threadData);
if(threadData->entityTypeIndicator == TypeDenseNode) if(threadData->entityTypeIndicator == TypeDenseNode)
parseDenseNode(threadData); parseDenseNode(threadData);
} }
delete threadData; delete threadData;
threadData = NULL; threadData = NULL;
} }
} }
inline bool PBFParser::Parse() { inline bool PBFParser::Parse() {
// Start the read and parse threads // Start the read and parse threads
boost::thread readThread(boost::bind(&PBFParser::ReadData, this)); boost::thread readThread(boost::bind(&PBFParser::ReadData, this));
//Open several parse threads that are synchronized before call to //Open several parse threads that are synchronized before call to
boost::thread parseThread(boost::bind(&PBFParser::ParseData, this)); boost::thread parseThread(boost::bind(&PBFParser::ParseData, this));
// Wait for the threads to finish // Wait for the threads to finish
readThread.join(); readThread.join();
parseThread.join(); parseThread.join();
return true; return true;
} }
inline void PBFParser::parseDenseNode(_ThreadData * threadData) { inline void PBFParser::parseDenseNode(_ThreadData * threadData) {
const OSMPBF::DenseNodes& dense = threadData->PBFprimitiveBlock.primitivegroup( threadData->currentGroupID ).dense(); const OSMPBF::DenseNodes& dense = threadData->PBFprimitiveBlock.primitivegroup( threadData->currentGroupID ).dense();
int denseTagIndex = 0; int denseTagIndex = 0;
int m_lastDenseID = 0; int m_lastDenseID = 0;
int m_lastDenseLatitude = 0; int m_lastDenseLatitude = 0;
int m_lastDenseLongitude = 0; int m_lastDenseLongitude = 0;
ImportNode n; ImportNode n;
std::vector<ImportNode> nodesToParse; std::vector<ImportNode> nodesToParse;
for(int i = 0, idSize = dense.id_size(); i < idSize; ++i) { for(int i = 0, idSize = dense.id_size(); i < idSize; ++i) {
n.Clear(); n.Clear();
m_lastDenseID += dense.id( i ); m_lastDenseID += dense.id( i );
m_lastDenseLatitude += dense.lat( i ); m_lastDenseLatitude += dense.lat( i );
m_lastDenseLongitude += dense.lon( i ); m_lastDenseLongitude += dense.lon( i );
n.id = m_lastDenseID; n.id = m_lastDenseID;
n.lat = 100000*( ( double ) m_lastDenseLatitude * threadData->PBFprimitiveBlock.granularity() +threadData-> PBFprimitiveBlock.lat_offset() ) / NANO; n.lat = 100000*( ( double ) m_lastDenseLatitude * threadData->PBFprimitiveBlock.granularity() +threadData-> PBFprimitiveBlock.lat_offset() ) / NANO;
n.lon = 100000*( ( double ) m_lastDenseLongitude * threadData->PBFprimitiveBlock.granularity() + threadData->PBFprimitiveBlock.lon_offset() ) / NANO; n.lon = 100000*( ( double ) m_lastDenseLongitude * threadData->PBFprimitiveBlock.granularity() + threadData->PBFprimitiveBlock.lon_offset() ) / NANO;
while (denseTagIndex < dense.keys_vals_size()) { while (denseTagIndex < dense.keys_vals_size()) {
const int tagValue = dense.keys_vals( denseTagIndex ); const int tagValue = dense.keys_vals( denseTagIndex );
if(tagValue == 0) { if(tagValue == 0) {
++denseTagIndex; ++denseTagIndex;
break; break;
} }
const int keyValue = dense.keys_vals ( denseTagIndex+1 ); const int keyValue = dense.keys_vals ( denseTagIndex+1 );
const std::string & key = threadData->PBFprimitiveBlock.stringtable().s(tagValue).data(); const std::string & key = threadData->PBFprimitiveBlock.stringtable().s(tagValue).data();
const std::string & value = threadData->PBFprimitiveBlock.stringtable().s(keyValue).data(); const std::string & value = threadData->PBFprimitiveBlock.stringtable().s(keyValue).data();
n.keyVals.Add(key, value); n.keyVals.Add(key, value);
denseTagIndex += 2; denseTagIndex += 2;
} }
nodesToParse.push_back(n); nodesToParse.push_back(n);
} }
unsigned endi_nodes = nodesToParse.size(); unsigned endi_nodes = nodesToParse.size();
#pragma omp parallel for schedule ( guided ) #pragma omp parallel for schedule ( guided )
for(unsigned i = 0; i < endi_nodes; ++i) { for(unsigned i = 0; i < endi_nodes; ++i) {
ImportNode &n = nodesToParse[i]; ImportNode &n = nodesToParse[i];
/** Pass the unpacked node to the LUA call back **/ /** Pass the unpacked node to the LUA call back **/
try { try {
luabind::call_function<int>( luabind::call_function<int>(
scriptingEnvironment.getLuaStateForThreadID(omp_get_thread_num()), scriptingEnvironment.getLuaStateForThreadID(omp_get_thread_num()),
"node_function", "node_function",
boost::ref(n) boost::ref(n)
); );
} catch (const luabind::error &er) { } catch (const luabind::error &er) {
lua_State* Ler=er.state(); lua_State* Ler=er.state();
report_errors(Ler, -1); report_errors(Ler, -1);
ERR(er.what()); ERR(er.what());
} }
// catch (...) { // catch (...) {
// ERR("Unknown error occurred during PBF dense node parsing!"); // ERR("Unknown error occurred during PBF dense node parsing!");
// } // }
} }
BOOST_FOREACH(ImportNode &n, nodesToParse) { BOOST_FOREACH(ImportNode &n, nodesToParse) {
if(!externalMemory->nodeFunction(n)) if(!externalMemory->nodeFunction(n))
std::cerr << "[PBFParser] dense node not parsed" << std::endl; std::cerr << "[PBFParser] dense node not parsed" << std::endl;
} }
} }
inline void PBFParser::parseNode(_ThreadData * ) { inline void PBFParser::parseNode(_ThreadData * ) {
ERR("Parsing of simple nodes not supported. PBF should use dense nodes"); ERR("Parsing of simple nodes not supported. PBF should use dense nodes");
} }
inline void PBFParser::parseRelation(_ThreadData * threadData) { inline void PBFParser::parseRelation(_ThreadData * threadData) {
//TODO: leave early, if relatio is not a restriction //TODO: leave early, if relation is not a restriction
//TODO: reuse rawRestriction container //TODO: reuse rawRestriction container
const OSMPBF::PrimitiveGroup& group = threadData->PBFprimitiveBlock.primitivegroup( threadData->currentGroupID ); const OSMPBF::PrimitiveGroup& group = threadData->PBFprimitiveBlock.primitivegroup( threadData->currentGroupID );
for(int i = 0; i < group.relations_size(); ++i ) { for(int i = 0; i < group.relations_size(); ++i ) {
const OSMPBF::Relation& inputRelation = threadData->PBFprimitiveBlock.primitivegroup( threadData->currentGroupID ).relations(i); std::string exception_of_restriction_tag;
bool isRestriction = false; const OSMPBF::Relation& inputRelation = threadData->PBFprimitiveBlock.primitivegroup( threadData->currentGroupID ).relations(i);
bool isOnlyRestriction = false; bool isRestriction = false;
for(int k = 0, endOfKeys = inputRelation.keys_size(); k < endOfKeys; ++k) { bool isOnlyRestriction = false;
const std::string & key = threadData->PBFprimitiveBlock.stringtable().s(inputRelation.keys(k)); for(int k = 0, endOfKeys = inputRelation.keys_size(); k < endOfKeys; ++k) {
const std::string & val = threadData->PBFprimitiveBlock.stringtable().s(inputRelation.vals(k)); const std::string & key = threadData->PBFprimitiveBlock.stringtable().s(inputRelation.keys(k));
if ("type" == key) { const std::string & val = threadData->PBFprimitiveBlock.stringtable().s(inputRelation.vals(k));
if( "restriction" == val) if ("type" == key) {
isRestriction = true; if( "restriction" == val)
else isRestriction = true;
break; else
} break;
if ("restriction" == key) { }
if(val.find("only_") == 0) if ("restriction" == key) {
isOnlyRestriction = true; if(val.find("only_") == 0)
} isOnlyRestriction = true;
}
} if ("except" == key) {
if(isRestriction) { exception_of_restriction_tag = val;
long long lastRef = 0; }
_RawRestrictionContainer currentRestrictionContainer(isOnlyRestriction); }
for(int rolesIndex = 0; rolesIndex < inputRelation.roles_sid_size(); ++rolesIndex) {
std::string role(threadData->PBFprimitiveBlock.stringtable().s( inputRelation.roles_sid( rolesIndex ) ).data()); //Check if restriction shall be ignored
lastRef += inputRelation.memids(rolesIndex); if(isRestriction && ("" != exception_of_restriction_tag) ) {
//Be warned, this is quadratic work here, but we assume that
if(false == ("from" == role || "to" == role || "via" == role)) { //only a few exceptions are actually defined.
continue; std::vector<std::string> tokenized_exception_tags_of_restriction;
} boost::algorithm::split_regex(tokenized_exception_tags_of_restriction, exception_of_restriction_tag, boost::regex("[;][ ]*"));
BOOST_FOREACH(std::string & str, tokenized_exception_tags_of_restriction) {
switch(inputRelation.types(rolesIndex)) { if(restriction_exceptions_vector.end() != std::find(restriction_exceptions_vector.begin(), restriction_exceptions_vector.end(), str)) {
case 0: //node isRestriction = false;
if("from" == role || "to" == role) //Only via should be a node break; //BOOST_FOREACH
continue; }
assert("via" == role); }
if(UINT_MAX != currentRestrictionContainer.viaNode) }
currentRestrictionContainer.viaNode = UINT_MAX;
assert(UINT_MAX == currentRestrictionContainer.viaNode);
currentRestrictionContainer.restriction.viaNode = lastRef; if(isRestriction) {
break; long long lastRef = 0;
case 1: //way _RawRestrictionContainer currentRestrictionContainer(isOnlyRestriction);
assert("from" == role || "to" == role || "via" == role); for(int rolesIndex = 0; rolesIndex < inputRelation.roles_sid_size(); ++rolesIndex) {
if("from" == role) { std::string role(threadData->PBFprimitiveBlock.stringtable().s( inputRelation.roles_sid( rolesIndex ) ).data());
currentRestrictionContainer.fromWay = lastRef; lastRef += inputRelation.memids(rolesIndex);
}
if ("to" == role) { if(!("from" == role || "to" == role || "via" == role)) {
currentRestrictionContainer.toWay = lastRef; continue;
} }
if ("via" == role) {
assert(currentRestrictionContainer.restriction.toNode == UINT_MAX); switch(inputRelation.types(rolesIndex)) {
currentRestrictionContainer.viaNode = lastRef; case 0: //node
} if("from" == role || "to" == role) //Only via should be a node
break; continue;
case 2: //relation, not used. relations relating to relations are evil. assert("via" == role);
continue; if(UINT_MAX != currentRestrictionContainer.viaNode)
assert(false); currentRestrictionContainer.viaNode = UINT_MAX;
break; assert(UINT_MAX == currentRestrictionContainer.viaNode);
currentRestrictionContainer.restriction.viaNode = lastRef;
default: //should not happen break;
//cout << "unknown"; case 1: //way
assert(false); assert("from" == role || "to" == role || "via" == role);
break; if("from" == role) {
} currentRestrictionContainer.fromWay = lastRef;
} }
// if(UINT_MAX != currentRestriction.viaNode) { if ("to" == role) {
// cout << "restr from " << currentRestriction.from << " via "; currentRestrictionContainer.toWay = lastRef;
// cout << "node " << currentRestriction.viaNode; }
// cout << " to " << currentRestriction.to << endl; if ("via" == role) {
// } assert(currentRestrictionContainer.restriction.toNode == UINT_MAX);
if(!externalMemory->restrictionFunction(currentRestrictionContainer)) currentRestrictionContainer.viaNode = lastRef;
std::cerr << "[PBFParser] relation not parsed" << std::endl; }
} break;
} case 2: //relation, not used. relations relating to relations are evil.
continue;
assert(false);
break;
default: //should not happen
//cout << "unknown";
assert(false);
break;
}
}
if(!externalMemory->restrictionFunction(currentRestrictionContainer))
std::cerr << "[PBFParser] relation not parsed" << std::endl;
}
}
} }
inline void PBFParser::parseWay(_ThreadData * threadData) { inline void PBFParser::parseWay(_ThreadData * threadData) {
_Way w; _Way w;
std::vector<_Way> waysToParse(threadData->PBFprimitiveBlock.primitivegroup( threadData->currentGroupID ).ways_size()); std::vector<_Way> waysToParse(threadData->PBFprimitiveBlock.primitivegroup( threadData->currentGroupID ).ways_size());
for(int i = 0, ways_size = threadData->PBFprimitiveBlock.primitivegroup( threadData->currentGroupID ).ways_size(); i < ways_size; ++i) { for(int i = 0, ways_size = threadData->PBFprimitiveBlock.primitivegroup( threadData->currentGroupID ).ways_size(); i < ways_size; ++i) {
w.Clear(); w.Clear();
const OSMPBF::Way& inputWay = threadData->PBFprimitiveBlock.primitivegroup( threadData->currentGroupID ).ways( i ); const OSMPBF::Way& inputWay = threadData->PBFprimitiveBlock.primitivegroup( threadData->currentGroupID ).ways( i );
w.id = inputWay.id(); w.id = inputWay.id();
unsigned pathNode(0); unsigned pathNode(0);
for(int i = 0; i < inputWay.refs_size(); ++i) { for(int i = 0; i < inputWay.refs_size(); ++i) {
pathNode += inputWay.refs(i); pathNode += inputWay.refs(i);
w.path.push_back(pathNode); w.path.push_back(pathNode);
} }
assert(inputWay.keys_size() == inputWay.vals_size()); assert(inputWay.keys_size() == inputWay.vals_size());
for(int i = 0; i < inputWay.keys_size(); ++i) { for(int i = 0; i < inputWay.keys_size(); ++i) {
const std::string & key = threadData->PBFprimitiveBlock.stringtable().s(inputWay.keys(i)); const std::string & key = threadData->PBFprimitiveBlock.stringtable().s(inputWay.keys(i));
const std::string & val = threadData->PBFprimitiveBlock.stringtable().s(inputWay.vals(i)); const std::string & val = threadData->PBFprimitiveBlock.stringtable().s(inputWay.vals(i));
w.keyVals.Add(key, val); w.keyVals.Add(key, val);
} }
waysToParse.push_back(w); waysToParse.push_back(w);
} }
unsigned endi_ways = waysToParse.size(); unsigned endi_ways = waysToParse.size();
#pragma omp parallel for schedule ( guided ) #pragma omp parallel for schedule ( guided )
for(unsigned i = 0; i < endi_ways; ++i) { for(unsigned i = 0; i < endi_ways; ++i) {
_Way & w = waysToParse[i]; _Way & w = waysToParse[i];
/** Pass the unpacked way to the LUA call back **/ /** Pass the unpacked way to the LUA call back **/
try { try {
luabind::call_function<int>( luabind::call_function<int>(
scriptingEnvironment.getLuaStateForThreadID(omp_get_thread_num()), scriptingEnvironment.getLuaStateForThreadID(omp_get_thread_num()),
"way_function", "way_function",
boost::ref(w), boost::ref(w),
w.path.size() w.path.size()
); );
} catch (const luabind::error &er) { } catch (const luabind::error &er) {
lua_State* Ler=er.state(); lua_State* Ler=er.state();
report_errors(Ler, -1); report_errors(Ler, -1);
ERR(er.what()); ERR(er.what());
} }
// catch (...) { // catch (...) {
// ERR("Unknown error!"); // ERR("Unknown error!");
// } // }
} }
BOOST_FOREACH(_Way & w, waysToParse) { BOOST_FOREACH(_Way & w, waysToParse) {
if(!externalMemory->wayFunction(w)) { if(!externalMemory->wayFunction(w)) {
std::cerr << "[PBFParser] way not parsed" << std::endl; std::cerr << "[PBFParser] way not parsed" << std::endl;
} }
} }
} }
inline void PBFParser::loadGroup(_ThreadData * threadData) { inline void PBFParser::loadGroup(_ThreadData * threadData) {
#ifndef NDEBUG #ifndef NDEBUG
++groupCount; ++groupCount;
#endif #endif
const OSMPBF::PrimitiveGroup& group = threadData->PBFprimitiveBlock.primitivegroup( threadData->currentGroupID ); const OSMPBF::PrimitiveGroup& group = threadData->PBFprimitiveBlock.primitivegroup( threadData->currentGroupID );
threadData->entityTypeIndicator = 0; threadData->entityTypeIndicator = 0;
if ( group.nodes_size() != 0 ) { if ( group.nodes_size() != 0 ) {
threadData->entityTypeIndicator = TypeNode; threadData->entityTypeIndicator = TypeNode;
} }
if ( group.ways_size() != 0 ) { if ( group.ways_size() != 0 ) {
threadData->entityTypeIndicator = TypeWay; threadData->entityTypeIndicator = TypeWay;
} }
if ( group.relations_size() != 0 ) { if ( group.relations_size() != 0 ) {
threadData->entityTypeIndicator = TypeRelation; threadData->entityTypeIndicator = TypeRelation;
} }
if ( group.has_dense() ) { if ( group.has_dense() ) {
threadData->entityTypeIndicator = TypeDenseNode; threadData->entityTypeIndicator = TypeDenseNode;
assert( group.dense().id_size() != 0 ); assert( group.dense().id_size() != 0 );
} }
assert( threadData->entityTypeIndicator != 0 ); assert( threadData->entityTypeIndicator != 0 );
} }
inline void PBFParser::loadBlock(_ThreadData * threadData) { inline void PBFParser::loadBlock(_ThreadData * threadData) {
#ifndef NDEBUG #ifndef NDEBUG
++blockCount; ++blockCount;
#endif #endif
threadData->currentGroupID = 0; threadData->currentGroupID = 0;
threadData->currentEntityID = 0; threadData->currentEntityID = 0;
} }
inline bool PBFParser::readPBFBlobHeader(std::fstream& stream, _ThreadData * threadData) { inline bool PBFParser::readPBFBlobHeader(std::fstream& stream, _ThreadData * threadData) {
int size(0); int size(0);
stream.read((char *)&size, sizeof(int)); stream.read((char *)&size, sizeof(int));
size = swapEndian(size); size = swapEndian(size);
if(stream.eof()) { if(stream.eof()) {
return false; return false;
} }
if ( size > MAX_BLOB_HEADER_SIZE || size < 0 ) { if ( size > MAX_BLOB_HEADER_SIZE || size < 0 ) {
return false; return false;
} }
char *data = new char[size]; char *data = new char[size];
stream.read(data, size*sizeof(data[0])); stream.read(data, size*sizeof(data[0]));
bool dataSuccessfullyParsed = (threadData->PBFBlobHeader).ParseFromArray( data, size); bool dataSuccessfullyParsed = (threadData->PBFBlobHeader).ParseFromArray( data, size);
delete[] data; delete[] data;
return dataSuccessfullyParsed; return dataSuccessfullyParsed;
} }
inline bool PBFParser::unpackZLIB(std::fstream &, _ThreadData * threadData) { inline bool PBFParser::unpackZLIB(std::fstream &, _ThreadData * threadData) {
unsigned rawSize = threadData->PBFBlob.raw_size(); unsigned rawSize = threadData->PBFBlob.raw_size();
char* unpackedDataArray = new char[rawSize]; char* unpackedDataArray = new char[rawSize];
z_stream compressedDataStream; z_stream compressedDataStream;
compressedDataStream.next_in = ( unsigned char* ) threadData->PBFBlob.zlib_data().data(); compressedDataStream.next_in = ( unsigned char* ) threadData->PBFBlob.zlib_data().data();
compressedDataStream.avail_in = threadData->PBFBlob.zlib_data().size(); compressedDataStream.avail_in = threadData->PBFBlob.zlib_data().size();
compressedDataStream.next_out = ( unsigned char* ) unpackedDataArray; compressedDataStream.next_out = ( unsigned char* ) unpackedDataArray;
compressedDataStream.avail_out = rawSize; compressedDataStream.avail_out = rawSize;
compressedDataStream.zalloc = Z_NULL; compressedDataStream.zalloc = Z_NULL;
compressedDataStream.zfree = Z_NULL; compressedDataStream.zfree = Z_NULL;
compressedDataStream.opaque = Z_NULL; compressedDataStream.opaque = Z_NULL;
int ret = inflateInit( &compressedDataStream ); int ret = inflateInit( &compressedDataStream );
if ( ret != Z_OK ) { if ( ret != Z_OK ) {
std::cerr << "[error] failed to init zlib stream" << std::endl; std::cerr << "[error] failed to init zlib stream" << std::endl;
delete[] unpackedDataArray; delete[] unpackedDataArray;
return false; return false;
} }
ret = inflate( &compressedDataStream, Z_FINISH ); ret = inflate( &compressedDataStream, Z_FINISH );
if ( ret != Z_STREAM_END ) { if ( ret != Z_STREAM_END ) {
std::cerr << "[error] failed to inflate zlib stream" << std::endl; std::cerr << "[error] failed to inflate zlib stream" << std::endl;
std::cerr << "[error] Error type: " << ret << std::endl; std::cerr << "[error] Error type: " << ret << std::endl;
delete[] unpackedDataArray; delete[] unpackedDataArray;
return false; return false;
} }
ret = inflateEnd( &compressedDataStream ); ret = inflateEnd( &compressedDataStream );
if ( ret != Z_OK ) { if ( ret != Z_OK ) {
std::cerr << "[error] failed to deinit zlib stream" << std::endl; std::cerr << "[error] failed to deinit zlib stream" << std::endl;
delete[] unpackedDataArray; delete[] unpackedDataArray;
return false; return false;
} }
threadData->charBuffer.clear(); threadData->charBuffer.resize(rawSize); threadData->charBuffer.clear(); threadData->charBuffer.resize(rawSize);
std::copy(unpackedDataArray, unpackedDataArray + rawSize, threadData->charBuffer.begin()); std::copy(unpackedDataArray, unpackedDataArray + rawSize, threadData->charBuffer.begin());
delete[] unpackedDataArray; delete[] unpackedDataArray;
return true; return true;
} }
inline bool PBFParser::unpackLZMA(std::fstream &, _ThreadData * ) { inline bool PBFParser::unpackLZMA(std::fstream &, _ThreadData * ) {
return false; return false;
} }
inline bool PBFParser::readBlob(std::fstream& stream, _ThreadData * threadData) { inline bool PBFParser::readBlob(std::fstream& stream, _ThreadData * threadData) {
if(stream.eof()) if(stream.eof())
return false; return false;
const int size = threadData->PBFBlobHeader.datasize(); const int size = threadData->PBFBlobHeader.datasize();
if ( size < 0 || size > MAX_BLOB_SIZE ) { if ( size < 0 || size > MAX_BLOB_SIZE ) {
std::cerr << "[error] invalid Blob size:" << size << std::endl; std::cerr << "[error] invalid Blob size:" << size << std::endl;
return false; return false;
} }
char* data = new char[size]; char* data = new char[size];
stream.read(data, sizeof(data[0])*size); stream.read(data, sizeof(data[0])*size);
if ( !threadData->PBFBlob.ParseFromArray( data, size ) ) { if ( !threadData->PBFBlob.ParseFromArray( data, size ) ) {
std::cerr << "[error] failed to parse blob" << std::endl; std::cerr << "[error] failed to parse blob" << std::endl;
delete[] data; delete[] data;
return false; return false;
} }
if ( threadData->PBFBlob.has_raw() ) { if ( threadData->PBFBlob.has_raw() ) {
const std::string& data = threadData->PBFBlob.raw(); const std::string& data = threadData->PBFBlob.raw();
threadData->charBuffer.clear(); threadData->charBuffer.clear();
threadData->charBuffer.resize( data.size() ); threadData->charBuffer.resize( data.size() );
std::copy(data.begin(), data.end(), threadData->charBuffer.begin()); std::copy(data.begin(), data.end(), threadData->charBuffer.begin());
} else if ( threadData->PBFBlob.has_zlib_data() ) { } else if ( threadData->PBFBlob.has_zlib_data() ) {
if ( !unpackZLIB(stream, threadData) ) { if ( !unpackZLIB(stream, threadData) ) {
std::cerr << "[error] zlib data encountered that could not be unpacked" << std::endl; std::cerr << "[error] zlib data encountered that could not be unpacked" << std::endl;
delete[] data; delete[] data;
return false; return false;
} }
} else if ( threadData->PBFBlob.has_lzma_data() ) { } else if ( threadData->PBFBlob.has_lzma_data() ) {
if ( !unpackLZMA(stream, threadData) ) if ( !unpackLZMA(stream, threadData) )
std::cerr << "[error] lzma data encountered that could not be unpacked" << std::endl; std::cerr << "[error] lzma data encountered that could not be unpacked" << std::endl;
delete[] data; delete[] data;
return false; return false;
} else { } else {
std::cerr << "[error] Blob contains no data" << std::endl; std::cerr << "[error] Blob contains no data" << std::endl;
delete[] data; delete[] data;
return false; return false;
} }
delete[] data; delete[] data;
return true; return true;
} }
bool PBFParser::readNextBlock(std::fstream& stream, _ThreadData * threadData) { bool PBFParser::readNextBlock(std::fstream& stream, _ThreadData * threadData) {
if(stream.eof()) { if(stream.eof()) {
return false; return false;
} }
if ( !readPBFBlobHeader(stream, threadData) ){ if ( !readPBFBlobHeader(stream, threadData) ){
return false; return false;
} }
if ( threadData->PBFBlobHeader.type() != "OSMData" ) { if ( threadData->PBFBlobHeader.type() != "OSMData" ) {
return false; return false;
} }
if ( !readBlob(stream, threadData) ) { if ( !readBlob(stream, threadData) ) {
return false; return false;
} }
if ( !threadData->PBFprimitiveBlock.ParseFromArray( &(threadData->charBuffer[0]), threadData-> charBuffer.size() ) ) { if ( !threadData->PBFprimitiveBlock.ParseFromArray( &(threadData->charBuffer[0]), threadData-> charBuffer.size() ) ) {
ERR("failed to parse PrimitiveBlock"); ERR("failed to parse PrimitiveBlock");
return false; return false;
} }
return true; return true;
} }

View File

@ -106,6 +106,8 @@ private:
/* ThreadData Queue */ /* ThreadData Queue */
boost::shared_ptr<ConcurrentQueue < _ThreadData* > > threadDataQueue; boost::shared_ptr<ConcurrentQueue < _ThreadData* > > threadDataQueue;
ScriptingEnvironment scriptingEnvironment; ScriptingEnvironment scriptingEnvironment;
std::vector<std::string> restriction_exceptions_vector;
}; };
#endif /* PBFPARSER_H_ */ #endif /* PBFPARSER_H_ */

View File

@ -18,16 +18,7 @@
or see http://www.gnu.org/licenses/agpl.txt. or see http://www.gnu.org/licenses/agpl.txt.
*/ */
extern "C" {
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
}
#include "ScriptingEnvironment.h" #include "ScriptingEnvironment.h"
#include "../typedefs.h"
#include "../Util/LuaUtil.h"
#include "../Util/OpenMPWrapper.h"
ScriptingEnvironment::ScriptingEnvironment() {} ScriptingEnvironment::ScriptingEnvironment() {}
ScriptingEnvironment::ScriptingEnvironment(const char * fileName) { ScriptingEnvironment::ScriptingEnvironment(const char * fileName) {
@ -45,6 +36,8 @@ ScriptingEnvironment::ScriptingEnvironment(const char * fileName) {
//open utility libraries string library; //open utility libraries string library;
luaL_openlibs(myLuaState); luaL_openlibs(myLuaState);
luaAddScriptFolderToLoadPath( myLuaState, fileName );
// Add our function to the state's global scope // Add our function to the state's global scope
luabind::module(myLuaState) [ luabind::module(myLuaState) [
luabind::def("print", LUA_print<std::string>), luabind::def("print", LUA_print<std::string>),
@ -53,17 +46,6 @@ ScriptingEnvironment::ScriptingEnvironment(const char * fileName) {
luabind::def("parseDuration", parseDuration) luabind::def("parseDuration", parseDuration)
]; ];
luaAddScriptFolderToLoadPath( myLuaState, fileName );
//#pragma omp critical
// {
// if(0 != luaL_dostring(
// myLuaState,
// "print('Initializing LUA engine')\n"
// )) {
// ERR(lua_tostring(myLuaState,-1)<< " occured in scripting block");
// }
// }
luabind::module(myLuaState) [ luabind::module(myLuaState) [
luabind::class_<HashTable<std::string, std::string> >("keyVals") luabind::class_<HashTable<std::string, std::string> >("keyVals")
.def("Add", &HashTable<std::string, std::string>::Add) .def("Add", &HashTable<std::string, std::string>::Add)
@ -96,13 +78,17 @@ ScriptingEnvironment::ScriptingEnvironment(const char * fileName) {
.def_readwrite("tags", &_Way::keyVals) .def_readwrite("tags", &_Way::keyVals)
.def_readwrite("direction", &_Way::direction) .def_readwrite("direction", &_Way::direction)
.enum_("constants") .enum_("constants")
[ [
luabind::value("notSure", 0), luabind::value("notSure", 0),
luabind::value("oneway", 1), luabind::value("oneway", 1),
luabind::value("bidirectional", 2), luabind::value("bidirectional", 2),
luabind::value("opposite", 3) luabind::value("opposite", 3)
] ]
]; ];
luabind::module(myLuaState) [
luabind::class_<std::vector<std::string> >("vector")
.def("Add", &std::vector<std::string>::push_back)
];
// Now call our function in a lua script // Now call our function in a lua script
//#pragma omp critical //#pragma omp critical

View File

@ -31,7 +31,10 @@ extern "C" {
#include "ExtractionHelperFunctions.h" #include "ExtractionHelperFunctions.h"
#include "ExtractorStructs.h" #include "ExtractorStructs.h"
#include "../typedefs.h"
#include "../DataStructures/ImportNode.h" #include "../DataStructures/ImportNode.h"
#include "../Util/LuaUtil.h"
#include "../Util/OpenMPWrapper.h"
class ScriptingEnvironment { class ScriptingEnvironment {
public: public:

View File

@ -1,17 +1,17 @@
/* /*
open source routing machine open source routing machine
Copyright (C) Dennis Luxen, others 2010 Copyright (C) Dennis Luxen, others 2010
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU AFFERO General Public License as published by it under the terms of the GNU AFFERO General Public License as published by
the Free Software Foundation; either version 3 of the License, or the Free Software Foundation; either version 3 of the License, or
any later version. any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU Affero General Public License You should have received a copy of the GNU Affero General Public License
along with this program; if not, write to the Free Software along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
@ -28,263 +28,304 @@
XMLParser::XMLParser(const char * filename) : externalMemory(NULL), myLuaState(NULL){ XMLParser::XMLParser(const char * filename) : externalMemory(NULL), myLuaState(NULL){
WARN("Parsing plain .osm/.osm.bz2 is deprecated. Switch to .pbf"); WARN("Parsing plain .osm/.osm.bz2 is deprecated. Switch to .pbf");
inputReader = inputReaderFactory(filename); inputReader = inputReaderFactory(filename);
} }
XMLParser::~XMLParser() {} XMLParser::~XMLParser() {}
void XMLParser::RegisterCallbacks(ExtractorCallbacks * em) { void XMLParser::RegisterCallbacks(ExtractorCallbacks * em) {
externalMemory = em; externalMemory = em;
} }
void XMLParser::RegisterScriptingEnvironment(ScriptingEnvironment & _se) { void XMLParser::RegisterScriptingEnvironment(ScriptingEnvironment & _se) {
myLuaState = _se.getLuaStateForThreadID(0); myLuaState = _se.getLuaStateForThreadID(0);
if(lua_function_exists(myLuaState, "get_exceptions" )) {
//get list of turn restriction exceptions
try {
luabind::call_function<void>(
myLuaState,
"get_exceptions",
boost::ref(restriction_exceptions_vector)
);
INFO("Found " << restriction_exceptions_vector.size() << " exceptions to turn restriction");
BOOST_FOREACH(std::string & str, restriction_exceptions_vector) {
INFO(" " << str);
}
} catch (const luabind::error &er) {
lua_State* Ler=er.state();
report_errors(Ler, -1);
ERR(er.what());
}
} else {
INFO("Found no exceptions to turn restrictions");
}
} }
bool XMLParser::Init() { bool XMLParser::Init() {
return (xmlTextReaderRead( inputReader ) == 1); return (xmlTextReaderRead( inputReader ) == 1);
} }
bool XMLParser::Parse() { bool XMLParser::Parse() {
while ( xmlTextReaderRead( inputReader ) == 1 ) { while ( xmlTextReaderRead( inputReader ) == 1 ) {
const int type = xmlTextReaderNodeType( inputReader ); const int type = xmlTextReaderNodeType( inputReader );
//1 is Element //1 is Element
if ( type != 1 ) if ( type != 1 )
continue; continue;
xmlChar* currentName = xmlTextReaderName( inputReader ); xmlChar* currentName = xmlTextReaderName( inputReader );
if ( currentName == NULL ) if ( currentName == NULL )
continue; continue;
if ( xmlStrEqual( currentName, ( const xmlChar* ) "node" ) == 1 ) { if ( xmlStrEqual( currentName, ( const xmlChar* ) "node" ) == 1 ) {
ImportNode n = _ReadXMLNode( ); ImportNode n = _ReadXMLNode( );
/** Pass the unpacked node to the LUA call back **/ /** Pass the unpacked node to the LUA call back **/
try { try {
luabind::call_function<int>( luabind::call_function<int>(
myLuaState, myLuaState,
"node_function", "node_function",
boost::ref(n) boost::ref(n)
); );
if(!externalMemory->nodeFunction(n)) if(!externalMemory->nodeFunction(n))
std::cerr << "[XMLParser] dense node not parsed" << std::endl; std::cerr << "[XMLParser] dense node not parsed" << std::endl;
} catch (const luabind::error &er) { } catch (const luabind::error &er) {
std::cerr << er.what() << std::endl; std::cerr << er.what() << std::endl;
lua_State* Ler=er.state(); lua_State* Ler=er.state();
report_errors(Ler, -1); report_errors(Ler, -1);
} catch (std::exception & e) { } catch (std::exception & e) {
ERR(e.what()); ERR(e.what());
} catch (...) { } catch (...) {
ERR("Unknown error occurred during XML node parsing!"); ERR("Unknown error occurred during XML node parsing!");
} }
} }
if ( xmlStrEqual( currentName, ( const xmlChar* ) "way" ) == 1 ) { if ( xmlStrEqual( currentName, ( const xmlChar* ) "way" ) == 1 ) {
_Way way = _ReadXMLWay( ); _Way way = _ReadXMLWay( );
/** Pass the unpacked way to the LUA call back **/ /** Pass the unpacked way to the LUA call back **/
try { try {
luabind::call_function<int>( luabind::call_function<int>(
myLuaState, myLuaState,
"way_function", "way_function",
boost::ref(way), boost::ref(way),
way.path.size() way.path.size()
); );
if(!externalMemory->wayFunction(way)) { if(!externalMemory->wayFunction(way)) {
std::cerr << "[PBFParser] way not parsed" << std::endl; std::cerr << "[PBFParser] way not parsed" << std::endl;
} }
} catch (const luabind::error &er) { } catch (const luabind::error &er) {
std::cerr << er.what() << std::endl; std::cerr << er.what() << std::endl;
lua_State* Ler=er.state(); lua_State* Ler=er.state();
report_errors(Ler, -1); report_errors(Ler, -1);
} catch (std::exception & e) { } catch (std::exception & e) {
ERR(e.what()); ERR(e.what());
} catch (...) { } catch (...) {
ERR("Unknown error occurred during XML way parsing!"); ERR("Unknown error occurred during XML way parsing!");
} }
} }
if ( xmlStrEqual( currentName, ( const xmlChar* ) "relation" ) == 1 ) { if ( xmlStrEqual( currentName, ( const xmlChar* ) "relation" ) == 1 ) {
_RawRestrictionContainer r = _ReadXMLRestriction(); _RawRestrictionContainer r = _ReadXMLRestriction();
if(r.fromWay != UINT_MAX) { if(r.fromWay != UINT_MAX) {
if(!externalMemory->restrictionFunction(r)) { if(!externalMemory->restrictionFunction(r)) {
std::cerr << "[XMLParser] restriction not parsed" << std::endl; std::cerr << "[XMLParser] restriction not parsed" << std::endl;
} }
} }
} }
xmlFree( currentName ); xmlFree( currentName );
} }
return true; return true;
} }
_RawRestrictionContainer XMLParser::_ReadXMLRestriction() { _RawRestrictionContainer XMLParser::_ReadXMLRestriction() {
_RawRestrictionContainer restriction; _RawRestrictionContainer restriction;
std::string exception_of_restriction_tag;
if ( xmlTextReaderIsEmptyElement( inputReader ) != 1 ) { bool restriction_is_excepted = false;
const int depth = xmlTextReaderDepth( inputReader );while ( xmlTextReaderRead( inputReader ) == 1 ) {
const int childType = xmlTextReaderNodeType( inputReader ); if ( xmlTextReaderIsEmptyElement( inputReader ) != 1 ) {
if ( childType != 1 && childType != 15 ) const int depth = xmlTextReaderDepth( inputReader );while ( xmlTextReaderRead( inputReader ) == 1 ) {
continue; const int childType = xmlTextReaderNodeType( inputReader );
const int childDepth = xmlTextReaderDepth( inputReader ); if ( childType != 1 && childType != 15 )
xmlChar* childName = xmlTextReaderName( inputReader ); continue;
if ( childName == NULL ) const int childDepth = xmlTextReaderDepth( inputReader );
continue; xmlChar* childName = xmlTextReaderName( inputReader );
if ( childName == NULL )
if ( depth == childDepth && childType == 15 && xmlStrEqual( childName, ( const xmlChar* ) "relation" ) == 1 ) { continue;
xmlFree( childName );
break; if ( depth == childDepth && childType == 15 && xmlStrEqual( childName, ( const xmlChar* ) "relation" ) == 1 ) {
} xmlFree( childName );
if ( childType != 1 ) { break;
xmlFree( childName ); }
continue; if ( childType != 1 ) {
} xmlFree( childName );
continue;
if ( xmlStrEqual( childName, ( const xmlChar* ) "tag" ) == 1 ) { }
xmlChar* k = xmlTextReaderGetAttribute( inputReader, ( const xmlChar* ) "k" );
xmlChar* value = xmlTextReaderGetAttribute( inputReader, ( const xmlChar* ) "v" ); if ( xmlStrEqual( childName, ( const xmlChar* ) "tag" ) == 1 ) {
if ( k != NULL && value != NULL ) { xmlChar* k = xmlTextReaderGetAttribute( inputReader, ( const xmlChar* ) "k" );
if(xmlStrEqual(k, ( const xmlChar* ) "restriction" )){ xmlChar* value = xmlTextReaderGetAttribute( inputReader, ( const xmlChar* ) "v" );
if(0 == std::string((const char *) value).find("only_")) if ( k != NULL && value != NULL ) {
restriction.restriction.flags.isOnly = true; if(xmlStrEqual(k, ( const xmlChar* ) "restriction" )){
} if(0 == std::string((const char *) value).find("only_"))
restriction.restriction.flags.isOnly = true;
} }
if ( k != NULL ) }
xmlFree( k ); if ( xmlStrEqual(k, (const xmlChar *) "except") ) {
if ( value != NULL ) exception_of_restriction_tag = (const char*) value;
xmlFree( value ); }
} else if ( xmlStrEqual( childName, ( const xmlChar* ) "member" ) == 1 ) {
xmlChar* ref = xmlTextReaderGetAttribute( inputReader, ( const xmlChar* ) "ref" ); if ( k != NULL )
if ( ref != NULL ) { xmlFree( k );
xmlChar * role = xmlTextReaderGetAttribute( inputReader, ( const xmlChar* ) "role" ); if ( value != NULL )
xmlChar * type = xmlTextReaderGetAttribute( inputReader, ( const xmlChar* ) "type" ); xmlFree( value );
if(xmlStrEqual(role, (const xmlChar *) "to") && xmlStrEqual(type, (const xmlChar *) "way")) { } else if ( xmlStrEqual( childName, ( const xmlChar* ) "member" ) == 1 ) {
restriction.toWay = atoi((const char*) ref); xmlChar* ref = xmlTextReaderGetAttribute( inputReader, ( const xmlChar* ) "ref" );
} if ( ref != NULL ) {
if(xmlStrEqual(role, (const xmlChar *) "from") && xmlStrEqual(type, (const xmlChar *) "way")) { xmlChar * role = xmlTextReaderGetAttribute( inputReader, ( const xmlChar* ) "role" );
restriction.fromWay = atoi((const char*) ref); xmlChar * type = xmlTextReaderGetAttribute( inputReader, ( const xmlChar* ) "type" );
}
if(xmlStrEqual(role, (const xmlChar *) "via") && xmlStrEqual(type, (const xmlChar *) "node")) { if(xmlStrEqual(role, (const xmlChar *) "to") && xmlStrEqual(type, (const xmlChar *) "way")) {
restriction.restriction.viaNode = atoi((const char*) ref); restriction.toWay = atoi((const char*) ref);
} }
if(xmlStrEqual(role, (const xmlChar *) "from") && xmlStrEqual(type, (const xmlChar *) "way")) {
if(NULL != type) restriction.fromWay = atoi((const char*) ref);
xmlFree( type ); }
if(NULL != role) if(xmlStrEqual(role, (const xmlChar *) "via") && xmlStrEqual(type, (const xmlChar *) "node")) {
xmlFree( role ); restriction.restriction.viaNode = atoi((const char*) ref);
if(NULL != ref) }
xmlFree( ref );
} if(NULL != type)
} xmlFree( type );
xmlFree( childName ); if(NULL != role)
} xmlFree( role );
} if(NULL != ref)
return restriction; xmlFree( ref );
}
}
xmlFree( childName );
}
}
//Check if restriction shall be ignored
if( "" != exception_of_restriction_tag ) {
//Be warned, this is quadratic work here, but we assume that
//only a few exceptions are actually defined.
std::vector<std::string> tokenized_exception_tags_of_restriction;
boost::algorithm::split_regex(tokenized_exception_tags_of_restriction, exception_of_restriction_tag, boost::regex("[;][ ]*"));
BOOST_FOREACH(std::string & str, tokenized_exception_tags_of_restriction) {
if(restriction_exceptions_vector.end() != std::find(restriction_exceptions_vector.begin(), restriction_exceptions_vector.end(), str)) {
restriction.fromWay = UINT_MAX; //workaround to ignore the restriction
break; //BOOST_FOREACH
}
}
}
return restriction;
} }
_Way XMLParser::_ReadXMLWay() { _Way XMLParser::_ReadXMLWay() {
_Way way; _Way way;
if ( xmlTextReaderIsEmptyElement( inputReader ) != 1 ) { if ( xmlTextReaderIsEmptyElement( inputReader ) != 1 ) {
const int depth = xmlTextReaderDepth( inputReader ); const int depth = xmlTextReaderDepth( inputReader );
while ( xmlTextReaderRead( inputReader ) == 1 ) { while ( xmlTextReaderRead( inputReader ) == 1 ) {
const int childType = xmlTextReaderNodeType( inputReader ); const int childType = xmlTextReaderNodeType( inputReader );
if ( childType != 1 && childType != 15 ) if ( childType != 1 && childType != 15 )
continue; continue;
const int childDepth = xmlTextReaderDepth( inputReader ); const int childDepth = xmlTextReaderDepth( inputReader );
xmlChar* childName = xmlTextReaderName( inputReader ); xmlChar* childName = xmlTextReaderName( inputReader );
if ( childName == NULL ) if ( childName == NULL )
continue; continue;
if ( depth == childDepth && childType == 15 && xmlStrEqual( childName, ( const xmlChar* ) "way" ) == 1 ) { if ( depth == childDepth && childType == 15 && xmlStrEqual( childName, ( const xmlChar* ) "way" ) == 1 ) {
xmlChar* id = xmlTextReaderGetAttribute( inputReader, ( const xmlChar* ) "id" ); xmlChar* id = xmlTextReaderGetAttribute( inputReader, ( const xmlChar* ) "id" );
way.id = atoi((char*)id); way.id = atoi((char*)id);
xmlFree(id); xmlFree(id);
xmlFree( childName ); xmlFree( childName );
break; break;
} }
if ( childType != 1 ) { if ( childType != 1 ) {
xmlFree( childName ); xmlFree( childName );
continue; continue;
} }
if ( xmlStrEqual( childName, ( const xmlChar* ) "tag" ) == 1 ) { if ( xmlStrEqual( childName, ( const xmlChar* ) "tag" ) == 1 ) {
xmlChar* k = xmlTextReaderGetAttribute( inputReader, ( const xmlChar* ) "k" ); xmlChar* k = xmlTextReaderGetAttribute( inputReader, ( const xmlChar* ) "k" );
xmlChar* value = xmlTextReaderGetAttribute( inputReader, ( const xmlChar* ) "v" ); xmlChar* value = xmlTextReaderGetAttribute( inputReader, ( const xmlChar* ) "v" );
// cout << "->k=" << k << ", v=" << value << endl; // cout << "->k=" << k << ", v=" << value << endl;
if ( k != NULL && value != NULL ) { if ( k != NULL && value != NULL ) {
way.keyVals.Add(std::string( (char *) k ), std::string( (char *) value)); way.keyVals.Add(std::string( (char *) k ), std::string( (char *) value));
} }
if ( k != NULL ) if ( k != NULL )
xmlFree( k ); xmlFree( k );
if ( value != NULL ) if ( value != NULL )
xmlFree( value ); xmlFree( value );
} else if ( xmlStrEqual( childName, ( const xmlChar* ) "nd" ) == 1 ) { } else if ( xmlStrEqual( childName, ( const xmlChar* ) "nd" ) == 1 ) {
xmlChar* ref = xmlTextReaderGetAttribute( inputReader, ( const xmlChar* ) "ref" ); xmlChar* ref = xmlTextReaderGetAttribute( inputReader, ( const xmlChar* ) "ref" );
if ( ref != NULL ) { if ( ref != NULL ) {
way.path.push_back( atoi(( const char* ) ref ) ); way.path.push_back( atoi(( const char* ) ref ) );
xmlFree( ref ); xmlFree( ref );
} }
} }
xmlFree( childName ); xmlFree( childName );
} }
} }
return way; return way;
} }
ImportNode XMLParser::_ReadXMLNode() { ImportNode XMLParser::_ReadXMLNode() {
ImportNode node; ImportNode node;
xmlChar* attribute = xmlTextReaderGetAttribute( inputReader, ( const xmlChar* ) "lat" ); xmlChar* attribute = xmlTextReaderGetAttribute( inputReader, ( const xmlChar* ) "lat" );
if ( attribute != NULL ) { if ( attribute != NULL ) {
node.lat = static_cast<NodeID>(100000.*atof(( const char* ) attribute ) ); node.lat = static_cast<NodeID>(100000.*atof(( const char* ) attribute ) );
xmlFree( attribute ); xmlFree( attribute );
} }
attribute = xmlTextReaderGetAttribute( inputReader, ( const xmlChar* ) "lon" ); attribute = xmlTextReaderGetAttribute( inputReader, ( const xmlChar* ) "lon" );
if ( attribute != NULL ) { if ( attribute != NULL ) {
node.lon = static_cast<NodeID>(100000.*atof(( const char* ) attribute )); node.lon = static_cast<NodeID>(100000.*atof(( const char* ) attribute ));
xmlFree( attribute ); xmlFree( attribute );
} }
attribute = xmlTextReaderGetAttribute( inputReader, ( const xmlChar* ) "id" ); attribute = xmlTextReaderGetAttribute( inputReader, ( const xmlChar* ) "id" );
if ( attribute != NULL ) { if ( attribute != NULL ) {
node.id = atoi(( const char* ) attribute ); node.id = atoi(( const char* ) attribute );
xmlFree( attribute ); xmlFree( attribute );
} }
if ( xmlTextReaderIsEmptyElement( inputReader ) != 1 ) { if ( xmlTextReaderIsEmptyElement( inputReader ) != 1 ) {
const int depth = xmlTextReaderDepth( inputReader ); const int depth = xmlTextReaderDepth( inputReader );
while ( xmlTextReaderRead( inputReader ) == 1 ) { while ( xmlTextReaderRead( inputReader ) == 1 ) {
const int childType = xmlTextReaderNodeType( inputReader ); const int childType = xmlTextReaderNodeType( inputReader );
// 1 = Element, 15 = EndElement // 1 = Element, 15 = EndElement
if ( childType != 1 && childType != 15 ) if ( childType != 1 && childType != 15 )
continue; continue;
const int childDepth = xmlTextReaderDepth( inputReader ); const int childDepth = xmlTextReaderDepth( inputReader );
xmlChar* childName = xmlTextReaderName( inputReader ); xmlChar* childName = xmlTextReaderName( inputReader );
if ( childName == NULL ) if ( childName == NULL )
continue; continue;
if ( depth == childDepth && childType == 15 && xmlStrEqual( childName, ( const xmlChar* ) "node" ) == 1 ) { if ( depth == childDepth && childType == 15 && xmlStrEqual( childName, ( const xmlChar* ) "node" ) == 1 ) {
xmlFree( childName ); xmlFree( childName );
break; break;
} }
if ( childType != 1 ) { if ( childType != 1 ) {
xmlFree( childName ); xmlFree( childName );
continue; continue;
} }
if ( xmlStrEqual( childName, ( const xmlChar* ) "tag" ) == 1 ) { if ( xmlStrEqual( childName, ( const xmlChar* ) "tag" ) == 1 ) {
xmlChar* k = xmlTextReaderGetAttribute( inputReader, ( const xmlChar* ) "k" ); xmlChar* k = xmlTextReaderGetAttribute( inputReader, ( const xmlChar* ) "k" );
xmlChar* value = xmlTextReaderGetAttribute( inputReader, ( const xmlChar* ) "v" ); xmlChar* value = xmlTextReaderGetAttribute( inputReader, ( const xmlChar* ) "v" );
if ( k != NULL && value != NULL ) { if ( k != NULL && value != NULL ) {
node.keyVals.Add(std::string( reinterpret_cast<char*>(k) ), std::string( reinterpret_cast<char*>(value))); node.keyVals.Add(std::string( reinterpret_cast<char*>(k) ), std::string( reinterpret_cast<char*>(value)));
} }
if ( k != NULL ) if ( k != NULL )
xmlFree( k ); xmlFree( k );
if ( value != NULL ) if ( value != NULL )
xmlFree( value ); xmlFree( value );
} }
xmlFree( childName ); xmlFree( childName );
} }
} }
return node; return node;
} }

View File

@ -45,6 +45,8 @@ private:
xmlTextReaderPtr inputReader; xmlTextReaderPtr inputReader;
ExtractorCallbacks * externalMemory; ExtractorCallbacks * externalMemory;
lua_State *myLuaState; lua_State *myLuaState;
std::vector<std::string> restriction_exceptions_vector;
}; };
#endif /* XMLPARSER_H_ */ #endif /* XMLPARSER_H_ */