/* * This file is a part of AllPlaceFinder library * and is distributed under the 2-Clause BSD licence. * Author: Tomasz Sowa */ /* * Copyright (c) 2021, Tomasz Sowa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * */ #include #include #include "finder.h" #include "utf8/utf8.h" #include "misc.h" #include "convert/convert.h" #include "space/spaceparser.h" namespace allplacefinder { Finder::Finder() { params = nullptr; } bool Finder::create_lookup_dir(Params & params) { if( params.osm_file.empty() ) { std::cerr << "you have to provide a path to osm file in --osm-file parameter" << std::endl; return false; } if( params.lookup_dir.empty() ) { std::cerr << "you have to provide a path to lookup dir in --lookup-dir parameter" << std::endl; return false; } if( !open_file(params.osm_file, osm_file_str, "I cannot open the osm file for reading") ) return false; if( !dir_exists(params.lookup_dir ) ) { std::cerr << "There is no the lookup directory" << std::endl; return false; } this->params = ¶ms; return create_lookup_dir(); } bool Finder::create_lookup_dir() { pt::HTMLParser parser; pt::Space space; std::string file_path; pt::wide_to_utf8(params->osm_file, file_path); nodes = 0; ways = 0; parser.set_item_parsed_listener(this); pt::HTMLParser::Status status = parser.parse_xml_file(file_path, space, false); switch(status) { case pt::HTMLParser::cant_open_file: std::cerr << "I cannot open the input file: " << file_path << std::endl; break; case pt::HTMLParser::syntax_error: std::cerr << "Syntax error: " << file_path << ":" << parser.get_last_parsed_line() << std::endl; break; case pt::HTMLParser::ok: //std::cout << space.serialize_to_json_str(true) << std::endl; break; } //std::cout << "nodes: " << nodes << std::endl; //std::cout << "ways: " << ways << std::endl; return true; } bool Finder::item_parsed(const pt::HTMLParser::Item & item) { std::string name_utf8; pt::wide_to_utf8(item.name, name_utf8); //std::cout << name_utf8 << std::endl; if( item.name == L"node" ) { nodes += 1; parse_node(*item.space); return false; } if( item.name == L"way" ) { ways += 1; parse_way(*item.space); return false; } return true; } void Finder::parse_node(pt::Space & node) { pt::Space * attr = node.get_space(L"attr"); pt::Space out; if( attr ) { pt::Space * id = attr->get_space(L"id"); pt::Space * lat = attr->get_space(L"lat"); pt::Space * lon = attr->get_space(L"lon"); if( id && lat && lon ) { long id_long = id->to_long(); if( id_long >= 0 ) { out.add(L"id", id_long); out.add(L"lat", lat->to_wstr()); out.add(L"lon", lon->to_wstr()); if( !save_file(L"node", id_long, out) ) { std::cout << "I cannot save node file with id: " << id_long << std::endl; } //pt::Space * childs = node.get_space(L"childs"); } else { std::cout << "Skipping node with negative id" << std::endl; } } else { std::cout << "Skipping node" << std::endl; } } //std::cout << out.serialize_to_json_str(true) << std::endl; } void Finder::parse_way(pt::Space & way) { pt::Space * attr = way.get_space(L"attr"); pt::Space out; if( attr ) { pt::Space * id = attr->get_space(L"id"); if( id ) { long id_long = id->to_long(); if( id_long >= 0 ) { out.add(L"id", id_long); pt::Space * childs = way.get_space(L"childs"); if( childs ) { if( parse_way_childs(out, *childs) ) { std::string str; str = out.serialize_to_json_str(false); std::cout << str << std::endl; // if( !save_file(L"way", id_long, out) ) // { // std::cout << "I cannot save way file with id: " << id_long << std::endl; // } } } } } } //std::cout << out.serialize_to_json_str(true) << std::endl; } bool Finder::parse_way_childs(pt::Space & out, pt::Space & childs) { size_t nd_len = 0; bool has_name = false; bool has_node = false; if( childs.is_table() ) { for(pt::Space * child : childs.value.value_table) { std::wstring * name = child->get_wstr(L"name"); if( name ) { if( *name == L"nd" ) { nd_len += 1; } if( *name == L"tag" ) { pt::Space * attr = child->get_space(L"attr"); if( attr ) { std::wstring * k = attr->get_wstr(L"k"); std::wstring * v = attr->get_wstr(L"v"); if( k && v && *k == L"name" ) { has_name = true; out.add(L"name", *v); } } } } } if( nd_len > 0 && has_name ) { size_t nd_mid = (nd_len / 2); size_t index = 0; for(pt::Space * child : childs.value.value_table) { std::wstring * name = child->get_wstr(L"name"); if( name && *name == L"nd" ) { if( index == nd_mid ) { pt::Space * attr = child->get_space(L"attr"); if( attr ) { std::wstring * ref = attr->get_wstr(L"ref"); if( ref ) { out.add(L"node_id", *ref); long node_id = pt::Tol(ref->c_str()); has_node = get_node(node_id, out); } } break; } index += 1; } } } } return nd_len > 0 && has_name && has_node; } bool Finder::get_node(long node_id, pt::Space & out) { std::vector subdirs; create_id_str(node_id, subdirs); std::wstring path; path = params->lookup_dir; path += L"/"; path += L"node"; for(std::wstring & str : subdirs) { path += L"/"; path += str; } pt::SpaceParser parser; pt::Space node; pt::SpaceParser::Status status = parser.parse_json_file(path, node); if( status == pt::SpaceParser::ok ) { std::wstring * lat = node.get_wstr(L"lat"); std::wstring * lon = node.get_wstr(L"lon"); if( lat && lon ) { out.add(L"lat", *lat); out.add(L"lon", *lon); return true; } } return false; } bool Finder::save_file(const wchar_t * subdir, long id, pt::Space & space) { std::vector subdirs; //std::string p; create_id_str(id, subdirs); // for(size_t i = 0 ; i < path.size() ; ++i) // { // pt::wide_to_utf8(path[i], p); // std::cout << p << " / "; // } // // std::cout << std::endl; std::wstring path; path = params->lookup_dir; path += L"/"; path += subdir; if( !create_dir_if_not_exists(path) ) return false; for(size_t i = 0 ; i + 1 < subdirs.size() ; ++i) { path += L"/"; path += subdirs[i]; if( !create_dir_if_not_exists(path) ) return false; } if( !subdirs.empty() ) { path += L"/"; path += subdirs.back(); std::string path_utf8; pt::wide_to_utf8(path, path_utf8); std::ofstream str(path_utf8, std::ios_base::out | std::ios_base::binary); if( str ) { text_stream.clear(); space.serialize_to_json_stream(text_stream, true); text_stream << '\n'; save_stream(text_stream, str); } else { return false; } str.close(); if( !str ) return false; } return true; } } // namespace