diff options
Diffstat (limited to 'osm2navit.c')
-rw-r--r-- | osm2navit.c | 3460 |
1 files changed, 3460 insertions, 0 deletions
diff --git a/osm2navit.c b/osm2navit.c new file mode 100644 index 00000000..2daf86e3 --- /dev/null +++ b/osm2navit.c @@ -0,0 +1,3460 @@ +/** + * Navit, a modular navigation system. + * Copyright (C) 2005-2008 Navit Team + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + + +#define _FILE_OFFSET_BITS 64 +#define _LARGEFILE_SOURCE +#define _LARGEFILE64_SOURCE +#include <glib.h> +#include <assert.h> +#include <string.h> +#include <signal.h> +#include <stdlib.h> +#include <stdio.h> +#include <math.h> +#include <getopt.h> +#include <unistd.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <zlib.h> +#include "file.h" +#include "item.h" +#include "map.h" +#include "zipfile.h" +#include "main.h" +#include "config.h" +#include "linguistics.h" +#include "plugin.h" +#ifdef HAVE_POSTGRESQL +#include <libpq-fe.h> +#endif + +#define BUFFER_SIZE 1280 + +typedef long int osmid; + + +#if 1 +#define debug_tile(x) 0 +#else +#define debug_tile(x) (!strcmp(x,"bcdbd") || !strcmp(x,"bcdbd") || !strcmp(x,"bcdbda") || !strcmp(x,"bcdbdb") || !strcmp(x,"bcdbdba") || !strcmp(x,"bcdbdbb") || !strcmp(x,"bcdbdbba") || !strcmp(x,"bcdbdbaa") || !strcmp(x,"bcdbdbacaa") || !strcmp(x,"bcdbdbacab") || !strcmp(x,"bcdbdbacaba") || !strcmp(x,"bcdbdbacabaa") || !strcmp(x,"bcdbdbacabab") || !strcmp(x,"bcdbdbacababb") || !strcmp(x,"bcdbdbacababba") || !strcmp(x,"bcdbdbacababbb") || !strcmp(x,"bcdbdbacababbd") || !strcmp(x,"bcdbdbacababaa") || !strcmp(x,"bcdbdbacababab") || !strcmp(x,"bcdbdbacababac") || !strcmp(x,"bcdbdbacababad") || !strcmp(x,"bcdbdbacabaaa") || !strcmp(x,"bcdbdbacabaaba") || !strcmp(x,"bcdbdbacabaabb") || !strcmp(x,"bcdbdbacabaabc") || !strcmp(x,"bcdbdbacabaabd") || !strcmp(x,"bcdbdbacabaaaa") || !strcmp(x,"bcdbdbacabaaab") || !strcmp(x,"bcdbdbacabaaac") || !strcmp(x,"bcdbdbacabaaad") || 0) +#endif + + +static GHashTable *dedupe_ways_hash; + +static int attr_debug_level=1; +static int nodeid,wayid; +static int phase; +static int ignore_unkown = 0, coverage=0; + +long long slice_size=1024*1024*1024; +int slices; + + +static char *attrmap={ + "n *=* point_unkn\n" + "n Annehmlichkeit=Hochsitz poi_hunting_stand\n" + "n addr:housenumber=* house_number\n" + "n aeroway=aerodrome poi_airport\n" + "n aeroway=airport poi_airport\n" + "n aeroway=helipad poi_heliport\n" + "n aeroway=terminal poi_airport\n" + "n amenity=atm poi_bank\n" + "n amenity=bank poi_bank\n" + "n amenity=bench poi_bench\n" + "n amenity=biergarten poi_biergarten\n" + "n amenity=bus_station poi_bus_station\n" + "n amenity=cafe poi_cafe\n" + "n amenity=cinema poi_cinema\n" + "n amenity=college poi_school_college\n" + "n amenity=courthouse poi_justice\n" + "n amenity=drinking_water poi_potable_water\n" + "n amenity=fast_food poi_fastfood\n" + "n amenity=fire_station poi_firebrigade\n" + "n amenity=fountain poi_fountain\n" + "n amenity=fuel poi_fuel\n" + "n amenity=grave_yard poi_cemetery\n" + "n amenity=hospital poi_hospital\n" + "n amenity=hunting_stand poi_hunting_stand\n" + "n amenity=kindergarten poi_kindergarten\n" + "n amenity=library poi_library\n" + "n amenity=park_bench poi_bench\n" + "n amenity=parking poi_car_parking\n" + "n amenity=pharmacy poi_pharmacy\n" + "n amenity=place_of_worship,religion=christian poi_church\n" + "n amenity=police poi_police\n" + "n amenity=post_box poi_post_box\n" + "n amenity=post_office poi_post_office\n" + "n amenity=prison poi_prison\n" + "n amenity=pub poi_bar\n" + "n amenity=public_building poi_public_office\n" + "n amenity=restaurant poi_restaurant\n" + "n amenity=school poi_school\n" + "n amenity=shelter poi_shelter\n" + "n amenity=taxi poi_taxi\n" + "n amenity=tec_common tec_common\n" + "n amenity=telephone poi_telephone\n" + "n amenity=theatre poi_theater\n" + "n amenity=toilets poi_restroom\n" + "n amenity=toilets poi_toilets\n" + "n amenity=townhall poi_townhall\n" + "n amenity=university poi_school_university\n" + "n car=car_rental poi_car_rent\n" + "n highway=bus_station poi_bus_station\n" + "n highway=bus_stop poi_bus_stop\n" + "n highway=mini_roundabout mini_roundabout\n" + "n highway=motorway_junction highway_exit\n" + "n highway=traffic_signals traffic_signals\n" + "n highway=turning_circle turning_circle\n" + "n historic=boundary_stone poi_boundary_stone\n" + "n historic=castle poi_castle\n" + "n historic=memorial poi_memorial\n" + "n historic=monument poi_monument\n" + "n historic=ruins poi_ruins\n" + "n landuse=cemetery poi_cemetery\n" + "n leisure=fishing poi_fish\n" + "n leisure=golf_course poi_golf\n" + "n leisure=marina poi_marine\n" + "n leisure=slipway poi_boat_ramp\n" + "n leisure=sports_centre poi_sport\n" + "n leisure=stadium poi_stadium\n" + "n man_made=tower poi_tower\n" + "n military=airfield poi_military\n" + "n military=barracks poi_military\n" + "n military=bunker poi_military\n" + "n military=danger_area poi_danger_area\n" + "n military=range poi_military\n" + "n natural=bay poi_bay\n" + "n natural=peak poi_peak\n" + "n place=city town_label_2e5\n" + "n place=hamlet town_label_2e2\n" + "n place=locality town_label_2e0\n" + "n place=suburb district_label\n" + "n place=town town_label_2e4\n" + "n place=village town_label_2e3\n" + "n power=tower power_tower\n" + "n railway=halt poi_rail_halt\n" + "n railway=level_crossing poi_level_crossing\n" + "n railway=station poi_rail_station\n" + "n railway=tram_stop poi_rail_tram_stop\n" + "n shop=baker poi_shop_baker\n" + "n shop=butcher poi_shop_butcher\n" + "n shop=car_repair poi_repair_service\n" + "n shop=convenience poi_shop_grocery\n" + "n shop=kiosk poi_shop_kiosk\n" + "n shop=supermarket poi_shopping\n" + "n sport=baseball poi_baseball\n" + "n sport=basketball poi_basketball\n" + "n sport=climbing poi_climbing\n" + "n sport=golf poi_golf\n" + "n sport=motor_sports poi_motor_sport\n" + "n sport=skiing poi_skiing\n" + "n sport=soccer poi_soccer\n" + "n sport=stadium poi_stadium\n" + "n sport=swimming poi_swimming\n" + "n sport=tennis poi_tennis\n" + "n tourism=attraction poi_attraction\n" + "n tourism=camp_site poi_camp_rv\n" + "n tourism=caravan_site poi_camp_rv\n" + "n tourism=guest_house poi_guesthouse\n" + "n tourism=hostel poi_hostel\n" + "n tourism=hotel poi_hotel\n" + "n tourism=information poi_information\n" + "n tourism=motel poi_motel\n" + "n tourism=museum poi_museum_history\n" + "n tourism=picnic_site poi_picnic\n" + "n tourism=theme_park poi_resort\n" + "n tourism=viewpoint poi_viewpoint\n" + "n tourism=zoo poi_zoo\n" + "w *=* street_unkn\n" + "w addr:interpolation=even house_number_interpolation_even\n" + "w addr:interpolation=odd house_number_interpolation_odd\n" + "w addr:interpolation=all house_number_interpolation_all\n" + "w addr:interpolation=alphabetic house_number_interpolation_alphabetic\n" + "w aerialway=cable_car lift_cable_car\n" + "w aerialway=chair_lift lift_chair\n" + "w aerialway=drag_lift lift_drag\n" + "w aeroway=aerodrome poly_airport\n" + "w aeroway=apron poly_apron\n" + "w aeroway=runway aeroway_runway\n" + "w aeroway=taxiway aeroway_taxiway\n" + "w aeroway=terminal poly_terminal\n" + "w amenity=college poly_college\n" + "w amenity=grave_yard poly_cemetery\n" + "w amenity=parking poly_car_parking\n" + "w amenity=place_of_worship poly_building\n" + "w amenity=university poly_university\n" + "w boundary=administrative border_country\n" + "w boundary=civil border_civil\n" + "w boundary=national_park border_national_park\n" + "w boundary=political border_political\n" + "w building=* poly_building\n" + "w contour_ext=elevation_major height_line_1\n" + "w contour_ext=elevation_medium height_line_2\n" + "w contour_ext=elevation_minor height_line_3\n" +#if 0 /* FIXME: Implement this as attribute */ + "w cycleway=track cycleway\n" +#endif + "w highway=bridleway bridleway\n" + "w highway=bus_guideway bus_guideway\n" + "w highway=construction street_construction\n" + "w highway=cyclepath cycleway\n" + "w highway=cycleway cycleway\n" + "w highway=footway footway\n" + "w highway=footway,piste:type=nordic footway_and_piste_nordic\n" + "w highway=living_street living_street\n" + "w highway=minor street_1_land\n" + "w highway=motorway highway_city\n" + "w highway=motorway_link ramp\n" + "w highway=parking_lane street_parking_lane\n" + "w highway=path path\n" + "w highway=path,bicycle=designated cycleway\n" + "w highway=path,foot=designated footway\n" + "w highway=path,horse=designated bridleway\n" + "w highway=path,sac_scale=alpine_hiking hiking_alpine\n" + "w highway=path,sac_scale=demanding_alpine_hiking hiking_alpine_demanding\n" + "w highway=path,sac_scale=demanding_mountain_hiking hiking_mountain_demanding\n" + "w highway=path,sac_scale=difficult_alpine_hiking hiking_alpine_difficult\n" + "w highway=path,sac_scale=hiking hiking\n" + "w highway=path,sac_scale=mountain_hiking hiking_mountain\n" + "w highway=pedestrian street_pedestrian\n" + "w highway=pedestrian,area=1 poly_pedestrian\n" + "w highway=plaza poly_plaza\n" + "w highway=primary street_4_city\n" + "w highway=primary_link ramp\n" + "w highway=residential street_1_city\n" + "w highway=residential,area=1 poly_street_1\n" + "w highway=road street_1_city\n" + "w highway=secondary street_3_city\n" + "w highway=secondary,area=1 poly_street_3\n" + "w highway=secondary_link ramp\n" + "w highway=service street_service\n" + "w highway=service,area=1 poly_service\n" + "w highway=service,service=parking_aisle street_parking_lane\n" + "w highway=steps steps\n" + "w highway=tertiary street_2_city\n" + "w highway=tertiary,area=1 poly_street_2\n" + "w highway=tertiary_link ramp\n" + "w highway=track track_gravelled\n" + "w highway=track,surface=grass track_grass\n" + "w highway=track,surface=gravel track_gravelled\n" + "w highway=track,surface=ground track_ground\n" + "w highway=track,surface=paved track_paved\n" + "w highway=track,surface=unpaved track_unpaved\n" + "w highway=track,tracktype=grade1 track_paved\n" + "w highway=track,tracktype=grade2 track_gravelled\n" + "w highway=track,tracktype=grade3 track_unpaved\n" + "w highway=track,tracktype=grade4 track_ground\n" + "w highway=track,tracktype=grade5 track_grass\n" + "w highway=trunk street_4_city\n" + "w highway=trunk_link ramp\n" + "w highway=unclassified street_1_city\n" + "w highway=unclassified,area=1 poly_street_1\n" + "w highway=unsurfaced track_gravelled\n" + "w historic=archaeological_site poly_archaeological_site\n" + "w historic=battlefield poly_battlefield\n" + "w historic=ruins poly_ruins\n" + "w historic=town gate poly_building\n" + "w landuse=allotments poly_allotments\n" + "w landuse=basin poly_basin\n" + "w landuse=brownfield poly_brownfield\n" + "w landuse=cemetery poly_cemetery\n" + "w landuse=commercial poly_commercial\n" + "w landuse=construction poly_construction\n" + "w landuse=farm poly_farm\n" + "w landuse=farmland poly_farm\n" + "w landuse=farmyard poly_town\n" + "w landuse=forest poly_wood\n" + "w landuse=greenfield poly_greenfield\n" + "w landuse=industrial poly_industry\n" + "w landuse=landfill poly_landfill\n" + "w landuse=military poly_military\n" + "w landuse=plaza poly_plaza\n" + "w landuse=quarry poly_quarry\n" + "w landuse=railway poly_railway\n" + "w landuse=recreation_ground poly_recreation_ground\n" + "w landuse=reservoir poly_reservoir\n" + "w landuse=residential poly_town\n" + "w landuse=residential,area=1 poly_town\n" + "w landuse=retail poly_retail\n" + "w landuse=village_green poly_village_green\n" + "w landuse=vineyard poly_farm\n" + "w leisure=common poly_common\n" + "w leisure=fishing poly_fishing\n" + "w leisure=garden poly_garden\n" + "w leisure=golf_course poly_golf_course\n" + "w leisure=marina poly_marina\n" + "w leisure=nature_reserve poly_nature_reserve\n" + "w leisure=park poly_park\n" + "w leisure=pitch poly_sports_pitch\n" + "w leisure=playground poly_playground\n" + "w leisure=sports_centre poly_sport\n" + "w leisure=stadium poly_sports_stadium\n" + "w leisure=track poly_sports_track\n" + "w leisure=water_park poly_water_park\n" + "w military=airfield poly_airfield\n" + "w military=barracks poly_barracks\n" + "w military=danger_area poly_danger_area\n" + "w military=naval_base poly_naval_base\n" + "w military=range poly_range\n" + "w natural=beach poly_beach\n" + "w natural=coastline water_line\n" + "w natural=fell poly_fell\n" + "w natural=glacier poly_glacier\n" + "w natural=heath poly_heath\n" + "w natural=land poly_land\n" + "w natural=marsh poly_marsh\n" + "w natural=mud poly_mud\n" + "w natural=scree poly_scree\n" + "w natural=scrub poly_scrub\n" + "w natural=water poly_water\n" + "w natural=wood poly_wood\n" + "w piste:type=downhill,piste:difficulty=advanced piste_downhill_advanced\n" + "w piste:type=downhill,piste:difficulty=easy piste_downhill_easy\n" + "w piste:type=downhill,piste:difficulty=expert piste_downhill_expert\n" + "w piste:type=downhill,piste:difficulty=freeride piste_downhill_freeride\n" + "w piste:type=downhill,piste:difficulty=intermediate piste_downhill_intermediate\n" + "w piste:type=downhill,piste:difficulty=novice piste_downhill_novice\n" + "w piste:type=nordic piste_nordic\n" + "w place=suburb poly_town\n" + "w place=town poly_town\n" + "w power=line powerline\n" + "w railway=abandoned rail_abandoned\n" + "w railway=disused rail_disused\n" + "w railway=light_rail rail_light\n" + "w railway=monorail rail_mono\n" + "w railway=narrow_gauge rail_narrow_gauge\n" + "w railway=preserved rail_preserved\n" + "w railway=rail rail\n" + "w railway=subway rail_subway\n" + "w railway=tram rail_tram\n" + "w route=ferry ferry\n" + "w route=ski piste_nordic\n" + "w sport=* poly_sport\n" + "w tourism=artwork poly_artwork\n" + "w tourism=attraction poly_attraction\n" + "w tourism=camp_site poly_camp_site\n" + "w tourism=caravan_site poly_caravan_site\n" + "w tourism=picnic_site poly_picnic_site\n" + "w tourism=theme_park poly_theme_park\n" + "w tourism=zoo poly_zoo\n" + "w waterway=canal water_canal\n" + "w waterway=drain water_drain\n" + "w waterway=river water_river\n" + "w waterway=riverbank poly_water\n" + "w waterway=stream water_stream\n" + "w barrier=ditch ditch\n" + "w barrier=hedge hedge\n" + "w barrier=fence fence\n" + "w barrier=wall wall\n" + "w barrier=retaining_wall retaining_wall\n" + "w barrier=city_wall city_wall\n" +}; + + +static char buffer[400000]; +static struct item_bin *item_bin=(struct item_bin *)(void *)buffer; + +struct coord coord_buffer[65536]; + +char *suffix=""; + +#define IS_REF(c) ((c).x >= (1 << 30)) +#define REF(c) ((c).y) +#define SET_REF(c,ref) do { (c).x = 1 << 30; (c).y = ref ; } while(0) + +struct rect { + struct coord l,h; +}; + +static void bbox_extend(struct coord *c, struct rect *r); + +GList *aux_tile_list; + +struct country_table { + int countryid; + char *names; + FILE *file; + int size; + struct rect r; +} country_table[] = { + { 36,"Australia,AUS"}, + { 40,"Austria,Österreich,AUT"}, + { 56,"Belgium"}, + {124,"Canada"}, + {152,"Chile"}, + {191,"Croatia,Republika Hrvatska,HR"}, + {203,"Czech Republic,Česká republika,CZ"}, + {208,"Denmark,Danmark,DK"}, + {246,"Finland,Suomi"}, + {250,"France,République française,FR"}, + {276,"Germany,Deutschland,Bundesrepublik Deutschland"}, + {348,"Hungary"}, + {380,"Italy,Italia"}, + {528,"Nederland,The Netherlands,Niederlande,NL"}, + {578,"Norway,Norge,Noreg,NO"}, + {616,"Poland,Polska,PL"}, + {703,"Slovakia,Slovensko,SK"}, + {705,"Slovenia,Republika Slovenija,SI"}, + {724,"Spain,Espana,Espana,Reino de Espana"}, + {752,"Sweden,Sverige,Konungariket Sverige,SE"}, + {756,"Schweiz"}, + {826,"United Kingdom,UK"}, + {840,"USA"}, + {999,"Unknown"}, +}; + +static GHashTable *country_table_hash; + +struct attr_mapping { + enum item_type type; + int attr_present_idx_count; + int attr_present_idx[0]; +}; + +static struct attr_mapping **attr_mapping_node; +static int attr_mapping_node_count; +static struct attr_mapping **attr_mapping_way; +static int attr_mapping_way_count; + +static char *attr_present; +static int attr_present_count; +static GHashTable *attr_hash; + + +static GHashTable *strings_hash = NULL; + + +static char* string_hash_lookup( const char* key ) +{ + char* key_ptr = NULL; + + if ( strings_hash == NULL ) { + strings_hash = g_hash_table_new(g_str_hash, g_str_equal); + } + + if ( ( key_ptr = g_hash_table_lookup(strings_hash, key )) == NULL ) { + key_ptr = g_strdup( key ); + g_hash_table_insert(strings_hash, key_ptr, (gpointer)key_ptr ); + + } + return key_ptr; +} + +static void +build_attrmap_line(char *line) +{ + char *t=NULL,*kvl=NULL,*i=NULL,*p,*kv; + struct attr_mapping ***attr_mapping_curr,*attr_mapping=g_malloc0(sizeof(struct attr_mapping)); + int idx,attr_mapping_count=0,*attr_mapping_curr_count; + t=line; + p=strchr(t,'\t'); + if (p) { + while (*p == '\t') + *p++='\0'; + kvl=p; + p=strchr(kvl,'\t'); + } + if (p) { + while (*p == '\t') + *p++='\0'; + i=p; + } + if (t[0] == 'w') { + if (! i) + i="street_unkn"; + attr_mapping_curr=&attr_mapping_way; + attr_mapping_curr_count=&attr_mapping_way_count; + } else { + if (! i) + i="point_unkn"; + attr_mapping_curr=&attr_mapping_node; + attr_mapping_curr_count=&attr_mapping_node_count; + } + attr_mapping->type=item_from_name(i); + while ((kv=strtok(kvl, ","))) { + kvl=NULL; + if (!(idx=(int)(long)g_hash_table_lookup(attr_hash, kv))) { + idx=attr_present_count++; + g_hash_table_insert(attr_hash, kv, (gpointer)(long)idx); + } + attr_mapping=g_realloc(attr_mapping, sizeof(struct attr_mapping)+(attr_mapping_count+1)*sizeof(int)); + attr_mapping->attr_present_idx[attr_mapping_count++]=idx; + attr_mapping->attr_present_idx_count=attr_mapping_count; + } + *attr_mapping_curr=g_realloc(*attr_mapping_curr, sizeof(**attr_mapping_curr)*(*attr_mapping_curr_count+1)); + (*attr_mapping_curr)[(*attr_mapping_curr_count)++]=attr_mapping; +} + +static void +build_attrmap(char *map) +{ + char *p; + attr_hash=g_hash_table_new(g_str_hash, g_str_equal); + attr_present_count=1; + while (map) { + p=strchr(map,'\n'); + if (p) + *p++='\0'; + if (strlen(map)) + build_attrmap_line(map); + map=p; + } + attr_present=g_malloc0(sizeof(*attr_present)*attr_present_count); +} + +static void +build_countrytable(void) +{ + int i; + char *names,*str,*tok; + country_table_hash=g_hash_table_new(g_str_hash, g_str_equal); + for (i = 0 ; i < sizeof(country_table)/sizeof(struct country_table) ; i++) { + names=g_strdup(country_table[i].names); + str=names; + while ((tok=strtok(str, ","))) { + str=NULL; + g_hash_table_insert(country_table_hash, tok, (gpointer)&country_table[i]); + } + } +} + + + +static int processed_nodes, processed_nodes_out, processed_ways, processed_relations, processed_tiles; +static int in_way, in_node, in_relation; + +static void +sig_alrm(int sig) +{ +#ifndef _WIN32 + signal(SIGALRM, sig_alrm); + alarm(30); +#endif + fprintf(stderr,"PROGRESS%d: Processed %d nodes (%d out) %d ways %d relations %d tiles\n", phase, processed_nodes, processed_nodes_out, processed_ways, processed_relations, processed_tiles); +} + +struct item_bin { + int len; + enum item_type type; + int clen; +} item; + +struct attr_bin { + int len; + enum attr_type type; +}; + +int maxspeed_attr_value; + +char debug_attr_buffer[BUFFER_SIZE]; + +int flags[4]; + +int flags_attr_value; + +struct attr_bin osmid_attr; +long int osmid_attr_value; + +char is_in_buffer[BUFFER_SIZE]; + +char attr_strings_buffer[BUFFER_SIZE*16]; +int attr_strings_buffer_len; + +enum attr_strings { + attr_string_phone, + attr_string_fax, + attr_string_email, + attr_string_url, + attr_string_street_name, + attr_string_street_name_systematic, + attr_string_house_number, + attr_string_label, + attr_string_last, +}; + +char *attr_strings[attr_string_last]; + +static void +attr_strings_clear(void) +{ + attr_strings_buffer_len=0; + memset(attr_strings, 0, sizeof(attr_strings)); +} + +static void +attr_strings_save(enum attr_strings id, char *str) +{ + attr_strings[id]=attr_strings_buffer+attr_strings_buffer_len; + strcpy(attr_strings[id], str); + attr_strings_buffer_len+=strlen(str)+1; +} + +static void +item_bin_init(struct item_bin *ib, enum item_type type) +{ + ib->clen=0; + ib->len=2; + ib->type=type; +} + +static void +item_bin_add_coord(struct item_bin *ib, struct coord *c, int count) +{ + struct coord *c2=(struct coord *)(ib+1); + c2+=ib->clen/2; + memcpy(c2, c, count*sizeof(struct coord)); + ib->clen+=count*2; + ib->len+=count*2; +} + +static void +item_bin_add_coord_rect(struct item_bin *ib, struct rect *r) +{ + item_bin_add_coord(ib, &r->l, 1); + item_bin_add_coord(ib, &r->h, 1); +} + +static void +item_bin_add_attr(struct item_bin *ib, struct attr *attr) +{ + struct attr_bin *ab=(struct attr_bin *)((int *)ib+ib->len+1); + int size=attr_data_size(attr); + int pad=(4-(size%4))%4; + ab->type=attr->type; + memcpy(ab+1, attr_data_get(attr), size); + memset((unsigned char *)(ab+1)+size, 0, pad); + ab->len=(size+pad)/4+1; + ib->len+=ab->len+1; +} + +static void +item_bin_add_attr_int(struct item_bin *ib, enum attr_type type, int val) +{ + struct attr attr; + attr.type=type; + attr.u.num=val; + item_bin_add_attr(ib, &attr); +} + +static void * +item_bin_get_attr(struct item_bin *ib, enum attr_type type) +{ + unsigned char *s=(unsigned char *)ib; + unsigned char *e=(unsigned char *)(ib+(ib->len+1)*4); + s+=sizeof(struct item_bin)+ib->clen*4; + while (s < e) { + struct attr_bin *ab=(struct attr_bin *)s; + s+=(ab->len+1)*4; + if (ab->type == type) { + return (ab+1); + } + } + return NULL; +} + +static long long +item_bin_get_wayid(struct item_bin *ib) +{ + long long *ret=item_bin_get_attr(ib, attr_osm_wayid); + if (ret) + return *ret; + return 0; +} + +static void +item_bin_add_attr_longlong(struct item_bin *ib, enum attr_type type, long long val) +{ + struct attr attr; + attr.type=type; + attr.u.num64=&val; + item_bin_add_attr(ib, &attr); +} + +static void +item_bin_add_attr_string(struct item_bin *ib, enum attr_type type, char *str) +{ + struct attr attr; + if (! str) + return; + attr.type=type; + attr.u.str=str; + item_bin_add_attr(ib, &attr); +} + +static void +item_bin_add_attr_range(struct item_bin *ib, enum attr_type type, short min, short max) +{ + struct attr attr; + attr.type=type; + attr.u.range.min=min; + attr.u.range.max=max; + item_bin_add_attr(ib, &attr); +} + +static void +item_bin_write(struct item_bin *ib, FILE *out) +{ + fwrite(buffer, (ib->len+1)*4, 1, out); +} + +static int +item_bin_read(struct item_bin *ib, FILE *in) +{ + if (fread(ib, 4, 1, in) == 0) + return 0; + if (!ib->len) + return 1; + if (fread((unsigned char *)ib+4, ib->len*4, 1, in)) + return 2; + return 0; +} + +static int +xml_get_attribute(char *xml, char *attribute, char *buffer, int buffer_size) +{ + int len=strlen(attribute); + char *pos,*i,s,attr[len+2]; + strcpy(attr, attribute); + strcpy(attr+len, "="); + pos=strstr(xml, attr); + if (! pos) + return 0; + pos+=len+1; + s=*pos++; + if (! s) + return 0; + i=strchr(pos, s); + if (! i) + return 0; + if (i - pos > buffer_size) { + fprintf(stderr,"Buffer overflow %ld vs %d\n", (long)(i-pos), buffer_size); + return 0; + } + strncpy(buffer, pos, i-pos); + buffer[i-pos]='\0'; + return 1; +} + +static int node_is_tagged; +static void relation_add_tag(char *k, char *v); + +static int +access_value(char *v) +{ + if (!strcmp(v,"yes")) + return 1; + if (!strcmp(v,"designated")) + return 1; + if (!strcmp(v,"permissive")) + return 1; + if (!strcmp(v,"no")) + return 2; + if (!strcmp(v,"agricultural")) + return 2; + if (!strcmp(v,"forestry")) + return 2; + if (!strcmp(v,"private")) + return 2; + if (!strcmp(v,"delivery")) + return 2; + if (!strcmp(v,"destination")) + return 2; + return 3; +} + +static void +add_tag(char *k, char *v) +{ + int idx,level=2; + char buffer[BUFFER_SIZE*2+2]; + if (! strcmp(k,"ele")) + level=9; + if (! strcmp(k,"time")) + level=9; + if (! strcmp(k,"created_by")) + level=9; + if (! strncmp(k,"tiger:",6) || !strcmp(k,"AND_nodes")) + level=9; + if (! strcmp(k,"converted_by") || ! strcmp(k,"source")) + level=8; + if (! strncmp(k,"osmarender:",11) || !strncmp(k,"svg:",4)) + level=8; + if (! strcmp(k,"layer")) + level=7; + if (! strcasecmp(v,"true") || ! strcasecmp(v,"yes")) + v="1"; + if (! strcmp(k,"oneway")) { + if (!strcmp(v,"1")) { + flags[0] |= AF_ONEWAY | AF_ROUNDABOUT_VALID; + } + if (! strcmp(v,"-1")) { + flags[0] |= AF_ONEWAYREV | AF_ROUNDABOUT_VALID; + } + if (!in_way) + level=6; + else + level=5; + } + if (! strcmp(k,"junction")) { + if (! strcmp(v,"roundabout")) + flags[0] |= AF_ONEWAY | AF_ROUNDABOUT | AF_ROUNDABOUT_VALID; + } + if (! strcmp(k,"maxspeed")) { + if (strstr(v, "mph")) { + maxspeed_attr_value = (int)floor(atof(v) * 1.609344); + } else { + maxspeed_attr_value = atoi(v); + } + if (maxspeed_attr_value) + flags[0] |= AF_SPEED_LIMIT; + level=5; + } + if (! strcmp(k,"access")) { + flags[access_value(v)] |= AF_DANGEROUS_GOODS|AF_EMERGENCY_VEHICLES|AF_TRANSPORT_TRUCK|AF_DELIVERY_TRUCK|AF_PUBLIC_BUS|AF_TAXI|AF_HIGH_OCCUPANCY_CAR|AF_CAR|AF_MOTORCYCLE|AF_MOPED|AF_HORSE|AF_BIKE|AF_PEDESTRIAN; + level=5; + } + if (! strcmp(k,"vehicle")) { + flags[access_value(v)] |= AF_DANGEROUS_GOODS|AF_EMERGENCY_VEHICLES|AF_TRANSPORT_TRUCK|AF_DELIVERY_TRUCK|AF_PUBLIC_BUS|AF_TAXI|AF_HIGH_OCCUPANCY_CAR|AF_CAR|AF_MOTORCYCLE|AF_MOPED|AF_BIKE; + level=5; + } + if (! strcmp(k,"motorvehicle")) { + flags[access_value(v)] |= AF_DANGEROUS_GOODS|AF_EMERGENCY_VEHICLES|AF_TRANSPORT_TRUCK|AF_DELIVERY_TRUCK|AF_PUBLIC_BUS|AF_TAXI|AF_HIGH_OCCUPANCY_CAR|AF_CAR|AF_MOTORCYCLE|AF_MOPED; + level=5; + } + if (! strcmp(k,"bicycle")) { + flags[access_value(v)] |= AF_BIKE; + level=5; + } + if (! strcmp(k,"foot")) { + flags[access_value(v)] |= AF_PEDESTRIAN; + level=5; + } + if (! strcmp(k,"horse")) { + flags[access_value(v)] |= AF_HORSE; + level=5; + } + if (! strcmp(k,"moped")) { + flags[access_value(v)] |= AF_MOPED; + level=5; + } + if (! strcmp(k,"motorcycle")) { + flags[access_value(v)] |= AF_MOTORCYCLE; + level=5; + } + if (! strcmp(k,"motorcar")) { + flags[access_value(v)] |= AF_CAR; + level=5; + } + if (! strcmp(k,"hov")) { + flags[access_value(v)] |= AF_HIGH_OCCUPANCY_CAR; + level=5; + } + if (! strcmp(k,"bus")) { + flags[access_value(v)] |= AF_PUBLIC_BUS; + level=5; + } + if (! strcmp(k,"taxi")) { + flags[access_value(v)] |= AF_TAXI; + level=5; + } + if (! strcmp(k,"goods")) { + flags[access_value(v)] |= AF_DELIVERY_TRUCK; + level=5; + } + if (! strcmp(k,"hgv")) { + flags[access_value(v)] |= AF_TRANSPORT_TRUCK; + level=5; + } + if (! strcmp(k,"emergency")) { + flags[access_value(v)] |= AF_EMERGENCY_VEHICLES; + level=5; + } + if (! strcmp(k,"hazmat")) { + flags[access_value(v)] |= AF_DANGEROUS_GOODS; + level=5; + } + if (! strcmp(k,"note")) + level=5; + if (! strcmp(k,"name")) { + attr_strings_save(attr_string_label, v); + level=5; + } + if (! strcmp(k,"addr:email")) { + attr_strings_save(attr_string_email, v); + level=5; + } + if (! strcmp(k,"addr:housenumber")) { + attr_strings_save(attr_string_house_number, v); + level=5; + } + if (! strcmp(k,"addr:street")) { + attr_strings_save(attr_string_street_name, v); + level=5; + } + if (! strcmp(k,"phone")) { + attr_strings_save(attr_string_phone, v); + level=5; + } + if (! strcmp(k,"fax")) { + attr_strings_save(attr_string_fax, v); + level=5; + } + if (! strcmp(k,"ref")) { + if (in_way) + attr_strings_save(attr_string_street_name_systematic, v); + level=5; + } + if (! strcmp(k,"is_in")) { + strcpy(is_in_buffer, v); + level=5; + } + if (! strcmp(k,"gnis:ST_alpha")) { + /* assume a gnis tag means it is part of the USA: + http://en.wikipedia.org/wiki/Geographic_Names_Information_System + many US towns do not have is_in tags + */ + strcpy(is_in_buffer, "USA"); + level=5; + } + if (! strcmp(k,"lanes")) { + level=5; + } + if (attr_debug_level >= level) { + int bytes_left = sizeof( debug_attr_buffer ) - strlen(debug_attr_buffer) - 1; + if ( bytes_left > 0 ) + { + snprintf(debug_attr_buffer+strlen(debug_attr_buffer), bytes_left, " %s=%s", k, v); + debug_attr_buffer[ sizeof( debug_attr_buffer ) - 1 ] = '\0'; + node_is_tagged=1; + } + } + if (level < 6) + node_is_tagged=1; + if (level >= 5) + return; + + strcpy(buffer,"*=*"); + if ((idx=(int)(long)g_hash_table_lookup(attr_hash, buffer))) + attr_present[idx]=1; + + sprintf(buffer,"%s=*", k); + if ((idx=(int)(long)g_hash_table_lookup(attr_hash, buffer))) + attr_present[idx]=2; + + sprintf(buffer,"*=%s", v); + if ((idx=(int)(long)g_hash_table_lookup(attr_hash, buffer))) + attr_present[idx]=2; + + sprintf(buffer,"%s=%s", k, v); + if ((idx=(int)(long)g_hash_table_lookup(attr_hash, buffer))) + attr_present[idx]=4; +} + +struct entity { + char *entity; + char c; +} entities[]= { + {""",'"'}, + {"'",'\''}, + {"&",'&'}, + {"<",'<'}, + {">",'>'}, +}; + +static void +decode_entities(char *buffer) +{ + char *pos=buffer; + int i,len,found; + + while ((pos=strchr(pos, '&'))) { + found=0; + for (i = 0 ; i < sizeof(entities)/sizeof(struct entity); i++) { + len=strlen(entities[i].entity); + if (!strncmp(pos, entities[i].entity, len)) { + *pos=entities[i].c; + memmove(pos+1, pos+len, strlen(pos+len)+1); + found=1; + break; + } + } + pos++; + } +} + +static int +parse_tag(char *p) +{ + char k_buffer[BUFFER_SIZE]; + char v_buffer[BUFFER_SIZE]; + if (!xml_get_attribute(p, "k", k_buffer, BUFFER_SIZE)) + return 0; + if (!xml_get_attribute(p, "v", v_buffer, BUFFER_SIZE)) + return 0; + decode_entities(v_buffer); + if (in_relation) + relation_add_tag(k_buffer, v_buffer); + else + add_tag(k_buffer, v_buffer); + return 1; +} + + +struct buffer { + int malloced_step; + long long malloced; + unsigned char *base; + long long size; +}; + +static void save_buffer(char *filename, struct buffer *b, long long offset); + +static struct tile_head { + int num_subtiles; + int total_size; + char *name; + char *zip_data; + int total_size_used; + int zipnum; + int process; + struct tile_head *next; + // char subtiles[0]; +} *tile_head_root; + + +int coord_count; + +struct node_item { + int id; + char ref_node; + char ref_way; + char ref_ref; + char dummy; + struct coord c; +}; + +static struct buffer node_buffer = { + 64*1024*1024, +}; + + +static char** th_get_subtile( const struct tile_head* th, int idx ) +{ + char* subtile_ptr = NULL; + subtile_ptr = (char*)th + sizeof( struct tile_head ) + idx * sizeof( char *); + return (char**)subtile_ptr; +} + +static void +extend_buffer(struct buffer *b) +{ + b->malloced+=b->malloced_step; + b->base=realloc(b->base, b->malloced); + if (b->base == NULL) { + fprintf(stderr,"realloc of %d bytes failed\n",(int)b->malloced); + exit(1); + } + +} + +int nodeid_last; +GHashTable *node_hash; + +static void +node_buffer_to_hash(void) +{ + int i,count=node_buffer.size/sizeof(struct node_item); + struct node_item *ni=(struct node_item *)node_buffer.base; + for (i = 0 ; i < count ; i++) + g_hash_table_insert(node_hash, (gpointer)(long)(ni[i].id), (gpointer)(long)i); +} + +static struct node_item *ni; + +static void +flush_nodes(int final) +{ + fprintf(stderr,"flush_nodes %d\n",final); + save_buffer("coords.tmp",&node_buffer,slices*slice_size); + if (!final) { + node_buffer.size=0; + } + slices++; +} + +static void +add_node(int id, double lat, double lon) +{ + if (node_buffer.size + sizeof(struct node_item) > node_buffer.malloced) + extend_buffer(&node_buffer); + attr_strings_clear(); + node_is_tagged=0; + nodeid=id; + item.type=type_point_unkn; + debug_attr_buffer[0]='\0'; + is_in_buffer[0]='\0'; + debug_attr_buffer[0]='\0'; + osmid_attr.type=attr_osm_nodeid; + osmid_attr.len=3; + osmid_attr_value=id; + if (node_buffer.size + sizeof(struct node_item) > slice_size) { + flush_nodes(0); + } + ni=(struct node_item *)(node_buffer.base+node_buffer.size); + ni->id=id; + ni->ref_node=0; + ni->ref_way=0; + ni->ref_ref=0; + ni->dummy=0; + ni->c.x=lon*6371000.0*M_PI/180; + ni->c.y=log(tan(M_PI_4+lat*M_PI/360))*6371000.0; + node_buffer.size+=sizeof(struct node_item); + if (! node_hash) { + if (ni->id > nodeid_last) { + nodeid_last=ni->id; + } else { + fprintf(stderr,"INFO: Nodes out of sequence (new %d vs old %d), adding hash\n", ni->id, nodeid_last); + node_hash=g_hash_table_new(NULL, NULL); + node_buffer_to_hash(); + } + } else + if (!g_hash_table_lookup(node_hash, (gpointer)(long)(ni->id))) + g_hash_table_insert(node_hash, (gpointer)(long)(ni->id), (gpointer)(long)(ni-(struct node_item *)node_buffer.base)); + else { + node_buffer.size-=sizeof(struct node_item); + nodeid=0; + } + +} + +static int +parse_node(char *p) +{ + char id_buffer[BUFFER_SIZE]; + char lat_buffer[BUFFER_SIZE]; + char lon_buffer[BUFFER_SIZE]; + if (!xml_get_attribute(p, "id", id_buffer, BUFFER_SIZE)) + return 0; + if (!xml_get_attribute(p, "lat", lat_buffer, BUFFER_SIZE)) + return 0; + if (!xml_get_attribute(p, "lon", lon_buffer, BUFFER_SIZE)) + return 0; + add_node(atoi(id_buffer), atof(lat_buffer), atof(lon_buffer)); + return 1; +} + + +static struct node_item * +node_item_get(int id) +{ + struct node_item *ni=(struct node_item *)(node_buffer.base); + int count=node_buffer.size/sizeof(struct node_item); + int interval=count/4; + int p=count/2; + if(interval==0) { + // If fewer than 4 nodes defined so far set interval to 1 to + // avoid infinite loop + interval = 1; + } + if (node_hash) { + int i; + i=(int)(long)(g_hash_table_lookup(node_hash, (gpointer)(long)id)); + return ni+i; + } + if (ni[0].id > id) + return NULL; + if (ni[count-1].id < id) + return NULL; + while (ni[p].id != id) { +#if 0 + fprintf(stderr,"p=%d count=%d interval=%d id=%d ni[p].id=%d\n", p, count, interval, id, ni[p].id); +#endif + if (ni[p].id < id) { + p+=interval; + if (interval == 1) { + if (p >= count) + return NULL; + if (ni[p].id > id) + return NULL; + } else { + if (p >= count) + p=count-1; + } + } else { + p-=interval; + if (interval == 1) { + if (p < 0) + return NULL; + if (ni[p].id < id) + return NULL; + } else { + if (p < 0) + p=0; + } + } + if (interval > 1) + interval/=2; + } + + return &ni[p]; +} + +static void +add_way(int id) +{ + wayid=id; + coord_count=0; + attr_strings_clear(); + item.type=type_street_unkn; + debug_attr_buffer[0]='\0'; + maxspeed_attr_value=0; + flags_attr_value = 0; + memset(flags, 0, sizeof(flags)); + debug_attr_buffer[0]='\0'; + osmid_attr_value=id; +} + +static int +parse_way(char *p) +{ + char id_buffer[BUFFER_SIZE]; + if (!xml_get_attribute(p, "id", id_buffer, BUFFER_SIZE)) + return 0; + add_way(atoi(id_buffer)); + return 1; +} + +static int +add_id_attr(char *p, enum attr_type attr_type) +{ + long long id; + struct attr idattr = { attr_type }; + char id_buffer[BUFFER_SIZE]; + if (!xml_get_attribute(p, "id", id_buffer, BUFFER_SIZE)) + return 0; + id=atoll(id_buffer); + idattr.u.num64=&id; + item_bin_add_attr(item_bin, &idattr); + return 1; +} + +char relation_type[BUFFER_SIZE]; + + +static int +parse_relation(char *p) +{ + debug_attr_buffer[0]='\0'; + relation_type[0]='\0'; + item_bin_init(item_bin, type_none); + if (!add_id_attr(p, attr_osm_relationid)) + return 0; + return 1; +} + +static void +end_relation(FILE *turn_restrictions) +{ + struct item_bin *ib=(struct item_bin *)buffer; + if (!strcmp(relation_type, "restriction") && (ib->type == type_street_turn_restriction_no || ib->type == type_street_turn_restriction_only)) + item_bin_write(item_bin, turn_restrictions); +} + +static int +parse_member(char *p) +{ + char type_buffer[BUFFER_SIZE]; + char ref_buffer[BUFFER_SIZE]; + char role_buffer[BUFFER_SIZE]; + char member_buffer[BUFFER_SIZE*3+3]; + struct attr memberattr = { attr_osm_member }; + if (!xml_get_attribute(p, "type", type_buffer, BUFFER_SIZE)) + return 0; + if (!xml_get_attribute(p, "ref", ref_buffer, BUFFER_SIZE)) + return 0; + if (!xml_get_attribute(p, "role", role_buffer, BUFFER_SIZE)) + return 0; + sprintf(member_buffer,"%s:%s:%s", type_buffer, ref_buffer, role_buffer); + memberattr.u.str=member_buffer; + item_bin_add_attr(item_bin, &memberattr); + + return 1; +} + + +static void +relation_add_tag(char *k, char *v) +{ + if (!strcmp(k,"type")) + strcpy(relation_type, v); + else if (!strcmp(k,"restriction")) { + if (strncmp(k,"no_",3)) { + item_bin->type=type_street_turn_restriction_no; + } else if (strncmp(k,"only_",5)) { + item_bin->type=type_street_turn_restriction_only; + } + } +} + + +static int +attr_longest_match(struct attr_mapping **mapping, int mapping_count, enum item_type *types, int types_count) +{ + int i,j,longest=0,ret=0,sum,val; + struct attr_mapping *curr; + for (i = 0 ; i < mapping_count ; i++) { + sum=0; + curr=mapping[i]; + for (j = 0 ; j < curr->attr_present_idx_count ; j++) { + val=attr_present[curr->attr_present_idx[j]]; + if (val) + sum+=val; + else { + sum=-1; + break; + } + } + if (sum > longest) { + longest=sum; + ret=0; + } + if (sum > 0 && sum == longest && ret < types_count) + types[ret++]=curr->type; + } + memset(attr_present, 0, sizeof(*attr_present)*attr_present_count); + return ret; +} + +static void +end_way(FILE *out) +{ + int i,count; + int *def_flags,add_flags; + enum item_type types[10]; + + if (! out) + return; + if (dedupe_ways_hash) { + if (g_hash_table_lookup(dedupe_ways_hash, (gpointer)(long)wayid)) + return; + g_hash_table_insert(dedupe_ways_hash, (gpointer)(long)wayid, (gpointer)1); + } + count=attr_longest_match(attr_mapping_way, attr_mapping_way_count, types, sizeof(types)/sizeof(enum item_type)); + if (!count) { + count=1; + types[0]=type_street_unkn; + } + if (count >= 10) { + fprintf(stderr,"way id %ld\n",osmid_attr_value); + assert(count < 10); + } + for (i = 0 ; i < count ; i++) { + add_flags=0; + item_bin_init(item_bin,types[i]); + item_bin_add_coord(item_bin, coord_buffer, coord_count); + def_flags=item_get_default_flags(types[i]); + if (def_flags) { + if (coverage) { + item.type=type_coverage; + } else { + flags_attr_value=(*def_flags | flags[0] | flags[1]) & ~flags[2]; + if (flags_attr_value != *def_flags) + add_flags=1; + } + } + item_bin_add_attr_string(item_bin, def_flags ? attr_street_name : attr_label, attr_strings[attr_string_label]); + item_bin_add_attr_string(item_bin, attr_street_name_systematic, attr_strings[attr_string_street_name_systematic]); + item_bin_add_attr_longlong(item_bin, attr_osm_wayid, osmid_attr_value); + if (debug_attr_buffer[0]) + item_bin_add_attr_string(item_bin, attr_debug, debug_attr_buffer); + if (add_flags) + item_bin_add_attr_int(item_bin, attr_flags, flags_attr_value); + if (maxspeed_attr_value) + item_bin_add_attr_int(item_bin, attr_maxspeed, maxspeed_attr_value); + item_bin_write(item_bin,out); + } +} + +static void +end_node(FILE *out) +{ + int conflict,count,i; + enum item_type types[10]; + struct country_table *result=NULL, *lookup; + if (!out || ! node_is_tagged || ! nodeid) + return; + count=attr_longest_match(attr_mapping_node, attr_mapping_node_count, types, sizeof(types)/sizeof(enum item_type)); + if (!count) { + types[0]=type_point_unkn; + count=1; + } + assert(count < 10); + for (i = 0 ; i < count ; i++) { + conflict=0; + item_bin_init(item_bin, types[i]); + item_bin_add_coord(item_bin, &ni->c, 1); + item_bin_add_attr_string(item_bin, item_is_town(*item_bin) ? attr_town_name : attr_label, attr_strings[attr_string_label]); + item_bin_add_attr_string(item_bin, attr_house_number, attr_strings[attr_string_house_number]); + item_bin_add_attr_string(item_bin, attr_street_name, attr_strings[attr_string_street_name]); + item_bin_add_attr_string(item_bin, attr_phone, attr_strings[attr_string_phone]); + item_bin_add_attr_string(item_bin, attr_fax, attr_strings[attr_string_fax]); + item_bin_add_attr_string(item_bin, attr_email, attr_strings[attr_string_email]); + item_bin_add_attr_string(item_bin, attr_url, attr_strings[attr_string_url]); + item_bin_add_attr_longlong(item_bin, attr_osm_nodeid, osmid_attr_value); + item_bin_add_attr_string(item_bin, attr_debug, debug_attr_buffer); + item_bin_write(item_bin,out); + if (item_is_town(*item_bin) && attr_strings[attr_string_label]) { + char *tok,*buf=is_in_buffer; + if (!buf[0]) + strcpy(is_in_buffer, "Unknown"); + while ((tok=strtok(buf, ","))) { + while (*tok==' ') + tok++; + lookup=g_hash_table_lookup(country_table_hash,tok); + if (lookup) { + if (result && result->countryid != lookup->countryid) { + fprintf(stderr,"conflict for %s %s country %d vs %d\n", attr_strings[attr_string_label], debug_attr_buffer, lookup->countryid, result->countryid); + conflict=1; + } else + result=lookup; + } + buf=NULL; + } + if (result && !conflict) { + if (!result->file) { + char *name=g_strdup_printf("country_%d.bin.unsorted", result->countryid); + result->file=fopen(name,"wb"); + g_free(name); + } + if (result->file) { + int i,words=0; + char *town_name=attr_strings[attr_string_label]; + char *word=town_name; + do { + for (i = 0 ; i < 3 ; i++) { + char *str=linguistics_expand_special(word, i); + if (str) { + item_bin_init(item_bin, item_bin->type); + item_bin_add_coord(item_bin, &ni->c, 1); + if (i || words) + item_bin_add_attr_string(item_bin, attr_town_name_match, str); + item_bin_add_attr_string(item_bin, attr_town_name, town_name); + item_bin_write(item_bin, result->file); + g_free(str); + } + } + word=linguistics_next_word(word); + words++; + } while (word); + } + + } + } + } + processed_nodes_out++; +} + +static int +sort_countries_compare(const void *p1, const void *p2) +{ + struct item_bin *ib1=*((struct item_bin **)p1),*ib2=*((struct item_bin **)p2); + struct attr_bin *attr1,*attr2; + char *s1,*s2; + assert(ib1->clen==2); + assert(ib2->clen==2); + attr1=(struct attr_bin *)((int *)(ib1+1)+ib1->clen); + attr2=(struct attr_bin *)((int *)(ib2+1)+ib1->clen); + assert(attr1->type == attr_town_name || attr1->type == attr_town_name_match); + assert(attr2->type == attr_town_name || attr2->type == attr_town_name_match); + s1=(char *)(attr1+1); + s2=(char *)(attr2+1); + return strcmp(s1, s2); +#if 0 + fprintf(stderr,"sort_countries_compare p1=%p p2=%p %s %s\n",p1,p2,s1,s2); +#endif + return 0; +} + +static void +sort_countries(int keep_tmpfiles) +{ + int i,j,count; + struct country_table *co; + struct coord *c; + struct item_bin *ib; + FILE *f; + char *name; + unsigned char *p,**idx,*buffer; + for (i = 0 ; i < sizeof(country_table)/sizeof(struct country_table) ; i++) { + co=&country_table[i]; + if (co->file) { + fclose(co->file); + co->file=NULL; + } + name=g_strdup_printf("country_%d.bin.unsorted", co->countryid); + if (file_get_contents(name, &buffer, &co->size)) { + if(!keep_tmpfiles) + unlink(name); + g_free(name); + ib=(struct item_bin *)buffer; + p=buffer; + count=0; + while (p < buffer+co->size) { + count++; + p+=(*((int *)p)+1)*4; + } + idx=malloc(count*sizeof(void *)); + assert(idx != NULL); + p=buffer; + for (j = 0 ; j < count ; j++) { + idx[j]=p; + p+=(*((int *)p)+1)*4; + } + qsort(idx, count, sizeof(void *), sort_countries_compare); + name=g_strdup_printf("country_%d.bin", co->countryid); + f=fopen(name,"wb"); + for (j = 0 ; j < count ; j++) { + ib=(struct item_bin *)(idx[j]); + c=(struct coord *)(ib+1); + fwrite(ib, (ib->len+1)*4, 1, f); + if (j) + bbox_extend(c, &co->r); + else { + co->r.l=*c; + co->r.h=*c; + } + } + fclose(f); + } + g_free(name); + } +} + +static void +node_ref_way(osmid node) +{ + struct node_item *ni; + ni=node_item_get(node); + if (ni) + ni->ref_way++; +} + +static int +resolve_ways(FILE *in, FILE *out) +{ + struct item_bin *ib=(struct item_bin *)buffer; + struct coord *c; + int i; + + fseek(in, 0, SEEK_SET); + for (;;) { + switch (item_bin_read(ib, in)) { + case 0: + return 0; + case 2: + c=(struct coord *)(ib+1); + for (i = 0 ; i < ib->clen/2 ; i++) { + node_ref_way(REF(c[i])); + } + default: + continue; + } + } + + +} + +static void +add_nd(char *p, osmid ref) +{ + SET_REF(coord_buffer[coord_count], ref); + node_ref_way(ref); + coord_count++; + if (coord_count > 65536) { + fprintf(stderr,"ERROR: Overflow\n"); + exit(1); + } +} + +static int +parse_nd(char *p) +{ + char ref_buffer[BUFFER_SIZE]; + if (!xml_get_attribute(p, "ref", ref_buffer, BUFFER_SIZE)) + return 0; + add_nd(p, atoi(ref_buffer)); + return 1; +} + + +static void +save_buffer(char *filename, struct buffer *b, long long offset) +{ + FILE *f; + f=fopen(filename,"rb+"); + if (! f) + f=fopen(filename,"wb+"); + + assert(f != NULL); + fseek(f, offset, SEEK_SET); + fwrite(b->base, b->size, 1, f); + fclose(f); +} + +static void +load_buffer(char *filename, struct buffer *b, long long offset, long long size) +{ + FILE *f; + long long len; + int ret; + if (b->base) + free(b->base); + b->malloced=0; + f=fopen(filename,"rb"); + fseek(f, 0, SEEK_END); + len=ftell(f); + if (offset+size > len) { + size=len-offset; + ret=1; + } + b->size=b->malloced=size; + fprintf(stderr,"reading %Ld bytes from %s at %Ld\n", b->size, filename, offset); + fseek(f, offset, SEEK_SET); + b->base=malloc(b->size); + assert(b->base != NULL); + fread(b->base, b->size, 1, f); + fclose(f); +} + +static int +phase1(FILE *in, FILE *out_ways, FILE *out_nodes, FILE *out_turn_restrictions) +{ + int size=BUFFER_SIZE; + char buffer[size]; + char *p; + sig_alrm(0); + while (fgets(buffer, size, in)) { + p=strchr(buffer,'<'); + if (! p) { + fprintf(stderr,"WARNING: wrong line %s\n", buffer); + continue; + } + if (!strncmp(p, "<?xml ",6)) { + } else if (!strncmp(p, "<osm ",5)) { + } else if (!strncmp(p, "<bound ",7)) { + } else if (!strncmp(p, "<node ",6)) { + if (!parse_node(p)) + fprintf(stderr,"WARNING: failed to parse %s\n", buffer); + in_node=1; + processed_nodes++; + } else if (!strncmp(p, "<tag ",5)) { + if (!parse_tag(p)) + fprintf(stderr,"WARNING: failed to parse %s\n", buffer); + } else if (!strncmp(p, "<way ",5)) { + in_way=1; + if (!parse_way(p)) + fprintf(stderr,"WARNING: failed to parse %s\n", buffer); + processed_ways++; + } else if (!strncmp(p, "<nd ",4)) { + if (!parse_nd(p)) + fprintf(stderr,"WARNING: failed to parse %s\n", buffer); + } else if (!strncmp(p, "<relation ",10)) { + in_relation=1; + if (!parse_relation(p)) + fprintf(stderr,"WARNING: failed to parse %s\n", buffer); + processed_relations++; + } else if (!strncmp(p, "<member ",8)) { + if (!parse_member(p)) + fprintf(stderr,"WARNING: failed to parse %s\n", buffer); + } else if (!strncmp(p, "</node>",7)) { + in_node=0; + end_node(out_nodes); + } else if (!strncmp(p, "</way>",6)) { + in_way=0; + end_way(out_ways); + } else if (!strncmp(p, "</relation>",11)) { + in_relation=0; + end_relation(out_turn_restrictions); + } else if (!strncmp(p, "</osm>",6)) { + } else { + fprintf(stderr,"WARNING: unknown tag in %s\n", buffer); + } + } + sig_alrm(0); +#ifndef _WIN32 + alarm(0); +#endif + return 1; +} + +#ifdef HAVE_POSTGRESQL +static int +phase1_db(char *dbstr, FILE *out_ways, FILE *out_nodes) +{ + PGconn *conn; + PGresult *res,*node,*way,*tag; + int count,tagged,i,j,k; + long min, max, id, tag_id, node_id; + char query[256]; + + sig_alrm(0); + conn=PQconnectdb(dbstr); + if (! conn) { + fprintf(stderr,"Failed to connect to database with '%s'\n",dbstr); + exit(1); + } + res=PQexec(conn, "begin"); + if (! res) { + fprintf(stderr, "Cannot begin transaction: %s\n", PQerrorMessage(conn)); + PQclear(res); + exit(1); + } + res=PQexec(conn, "set transaction isolation level serializable"); + if (! res) { + fprintf(stderr, "Cannot set isolation level: %s\n", PQerrorMessage(conn)); + PQclear(res); + exit(1); + } + res=PQexec(conn, "declare node cursor for select id,x(coordinate),y(coordinate) from node order by id"); + if (! res) { + fprintf(stderr, "Cannot setup cursor for nodes: %s\n", PQerrorMessage(conn)); + PQclear(res); + exit(1); + } + res=PQexec(conn, "declare way cursor for select id from way order by id"); + if (! res) { + fprintf(stderr, "Cannot setup cursor for nodes: %s\n", PQerrorMessage(conn)); + PQclear(res); + exit(1); + } + res=PQexec(conn, "declare relation cursor for select id from relation order by id"); + if (! res) { + fprintf(stderr, "Cannot setup cursor for nodes: %s\n", PQerrorMessage(conn)); + PQclear(res); + exit(1); + } + for (;;) { + node=PQexec(conn, "fetch 100000 from node"); + if (! node) { + fprintf(stderr, "Cannot setup cursor for nodes: %s\n", PQerrorMessage(conn)); + PQclear(node); + exit(1); + } + count=PQntuples(node); + if (! count) + break; + min=atol(PQgetvalue(node, 0, 0)); + max=atol(PQgetvalue(node, count-1, 0)); + sprintf(query,"select node_id,name,value from node_tag where node_id >= %ld and node_id <= %ld order by node_id", min, max); + tag=PQexec(conn, query); + if (! tag) { + fprintf(stderr, "Cannot query node_tag: %s\n", PQerrorMessage(conn)); + exit(1); + } + j=0; + for (i = 0 ; i < count ; i++) { + id=atol(PQgetvalue(node, i, 0)); + add_node(id, atof(PQgetvalue(node, i, 1)), atof(PQgetvalue(node, i, 2))); + tagged=0; + in_node=1; + processed_nodes++; + while (j < PQntuples(tag)) { + tag_id=atol(PQgetvalue(tag, j, 0)); + if (tag_id == id) { + add_tag(PQgetvalue(tag, j, 1), PQgetvalue(tag, j, 2)); + tagged=1; + j++; + } + if (tag_id < id) + j++; + if (tag_id > id) + break; + } + if (tagged) + end_node(out_nodes); + in_node=0; + } + PQclear(tag); + PQclear(node); + } + for (;;) { + way=PQexec(conn, "fetch 100000 from way"); + if (! way) { + fprintf(stderr, "Cannot setup cursor for ways: %s\n", PQerrorMessage(conn)); + PQclear(node); + exit(1); + } + count=PQntuples(way); + if (! count) + break; + min=atol(PQgetvalue(way, 0, 0)); + max=atol(PQgetvalue(way, count-1, 0)); + sprintf(query,"select way_id,node_id from way_node where way_id >= %ld and way_id <= %ld order by way_id,sequence_id", min, max); + node=PQexec(conn, query); + if (! node) { + fprintf(stderr, "Cannot query way_node: %s\n", PQerrorMessage(conn)); + exit(1); + } + sprintf(query,"select way_id,name,value from way_tag where way_id >= %ld and way_id <= %ld order by way_id", min, max); + tag=PQexec(conn, query); + if (! tag) { + fprintf(stderr, "Cannot query way_tag: %s\n", PQerrorMessage(conn)); + exit(1); + } + j=0; + k=0; + for (i = 0 ; i < count ; i++) { + id=atol(PQgetvalue(way, i, 0)); + add_way(id); + tagged=0; + in_way=1; + processed_ways++; + while (k < PQntuples(node)) { + node_id=atol(PQgetvalue(node, k, 0)); + if (node_id == id) { + add_nd("",atol(PQgetvalue(node, k, 1))); + tagged=1; + k++; + } + if (node_id < id) + k++; + if (node_id > id) + break; + } + while (j < PQntuples(tag)) { + tag_id=atol(PQgetvalue(tag, j, 0)); + if (tag_id == id) { + add_tag(PQgetvalue(tag, j, 1), PQgetvalue(tag, j, 2)); + tagged=1; + j++; + } + if (tag_id < id) + j++; + if (tag_id > id) + break; + } + if (tagged) + end_way(out_ways); + in_way=0; + } + PQclear(tag); + PQclear(node); + PQclear(way); + } + + res=PQexec(conn, "commit"); + if (! res) { + fprintf(stderr, "Cannot commit transaction: %s\n", PQerrorMessage(conn)); + PQclear(res); + exit(1); + } + sig_alrm(0); +#ifndef _WIN32 + alarm(0); +#endif + return 1; +} +#endif + + +static void +phase1_map(struct map *map, FILE *out_ways, FILE *out_nodes) +{ + struct map_rect *mr=map_rect_new(map, NULL); + struct item *item; + int count,max=16384; + struct coord ca[max]; + struct attr attr; + + while ((item = map_rect_get_item(mr))) { + count=item_coord_get(item, ca, item->type < type_line ? 1: max); + item_bin_init(item_bin, item->type); + item_bin_add_coord(item_bin, ca, count); + while (item_attr_get(item, attr_any, &attr)) { + item_bin_add_attr(item_bin, &attr); + } + if (item->type >= type_line) + item_bin_write(item_bin, out_ways); + else + item_bin_write(item_bin, out_nodes); + } + map_rect_destroy(mr); +} + + +int bytes_read=0; + +static struct item_bin * +read_item(FILE *in) +{ + struct item_bin *ib=(struct item_bin *) buffer; + int r,s; + r=fread(ib, sizeof(*ib), 1, in); + if (r != 1) + return NULL; + bytes_read+=r; + assert((ib->len+1)*4 < sizeof(buffer)); + s=(ib->len+1)*4-sizeof(*ib); + r=fread(ib+1, s, 1, in); + if (r != 1) + return NULL; + bytes_read+=r; + return ib; +} + +static void +bbox_extend(struct coord *c, struct rect *r) +{ + if (c->x < r->l.x) + r->l.x=c->x; + if (c->y < r->l.y) + r->l.y=c->y; + if (c->x > r->h.x) + r->h.x=c->x; + if (c->y > r->h.y) + r->h.y=c->y; +} + +static void +bbox(struct coord *c, int count, struct rect *r) +{ + if (! count) + return; + r->l=*c; + r->h=*c; + while (--count) { + c++; + bbox_extend(c, r); + } +} + +static int +contains_bbox(int xl, int yl, int xh, int yh, struct rect *r) +{ + if (r->h.x < xl || r->h.x > xh) { + return 0; + } + if (r->l.x > xh || r->l.x < xl) { + return 0; + } + if (r->h.y < yl || r->h.y > yh) { + return 0; + } + if (r->l.y > yh || r->l.y < yl) { + return 0; + } + return 1; + +} +struct rect world_bbox = { + { -20000000, -20000000}, + { 20000000, 20000000}, +}; + +int overlap=1; + +static void +tile(struct rect *r, char *suffix, char *ret, int max) +{ + int x0,x2,x4; + int y0,y2,y4; + int xo,yo; + int i; + x0=world_bbox.l.x; + y0=world_bbox.l.y; + x4=world_bbox.h.x; + y4=world_bbox.h.y; + for (i = 0 ; i < max ; i++) { + x2=(x0+x4)/2; + y2=(y0+y4)/2; + xo=(x4-x0)*overlap/100; + yo=(y4-y0)*overlap/100; + if ( contains_bbox(x0,y0,x2+xo,y2+yo,r)) { + strcat(ret,"d"); + x4=x2+xo; + y4=y2+yo; + } else if (contains_bbox(x2-xo,y0,x4,y2+yo,r)) { + strcat(ret,"c"); + x0=x2-xo; + y4=y2+yo; + } else if (contains_bbox(x0,y2-yo,x2+xo,y4,r)) { + strcat(ret,"b"); + x4=x2+xo; + y0=y2-yo; + } else if (contains_bbox(x2-xo,y2-yo,x4,y4,r)) { + strcat(ret,"a"); + x0=x2-xo; + y0=y2-yo; + } else + break; + } + if (suffix) + strcat(ret,suffix); +} + +static void +tile_bbox(char *tile, struct rect *r) +{ + struct coord c; + int xo,yo; + *r=world_bbox; + while (*tile) { + c.x=(r->l.x+r->h.x)/2; + c.y=(r->l.y+r->h.y)/2; + xo=(r->h.x-r->l.x)*overlap/100; + yo=(r->h.y-r->l.y)*overlap/100; + switch (*tile) { + case 'a': + r->l.x=c.x-xo; + r->l.y=c.y-yo; + break; + case 'b': + r->h.x=c.x+xo; + r->l.y=c.y-yo; + break; + case 'c': + r->l.x=c.x-xo; + r->h.y=c.y+yo; + break; + case 'd': + r->h.x=c.x+xo; + r->h.y=c.y+yo; + break; + } + tile++; + } +} + +static int +tile_len(char *tile) +{ + int ret=0; + while (tile[0] >= 'a' && tile[0] <= 'd') { + tile++; + ret++; + } + return ret; +} + +GHashTable *tile_hash; +GHashTable *tile_hash2; + +static void +tile_extend(char *tile, struct item_bin *ib, GList **tiles_list) +{ + struct tile_head *th=NULL; + if (debug_tile(tile)) + fprintf(stderr,"Tile:Writing %d bytes to '%s' (%p,%p)\n", (ib->len+1)*4, tile, g_hash_table_lookup(tile_hash, tile), tile_hash2 ? g_hash_table_lookup(tile_hash2, tile) : NULL); + if (tile_hash2) + th=g_hash_table_lookup(tile_hash2, tile); + if (!th) + th=g_hash_table_lookup(tile_hash, tile); + if (! th) { + th=malloc(sizeof(struct tile_head)+ sizeof( char* ) ); + assert(th != NULL); + // strcpy(th->subtiles, tile); + th->num_subtiles=1; + th->total_size=0; + th->total_size_used=0; + th->zipnum=0; + th->zip_data=NULL; + th->name=string_hash_lookup(tile); + *th_get_subtile( th, 0 ) = th->name; + + if (tile_hash2) + g_hash_table_insert(tile_hash2, string_hash_lookup( th->name ), th); + if (tiles_list) + *tiles_list=g_list_append(*tiles_list, string_hash_lookup( th->name ) ); + processed_tiles++; + if (debug_tile(tile)) + fprintf(stderr,"new '%s'\n", tile); + } + th->total_size+=ib->len*4+4; + if (debug_tile(tile)) + fprintf(stderr,"New total size of %s(%p):%d\n", th->name, th, th->total_size); + g_hash_table_insert(tile_hash, string_hash_lookup( th->name ), th); +} + +static int +tile_data_size(char *tile) +{ + struct tile_head *th; + th=g_hash_table_lookup(tile_hash, tile); + if (! th) + return 0; + return th->total_size; +} + +static int +merge_tile(char *base, char *sub) +{ + struct tile_head *thb, *ths; + thb=g_hash_table_lookup(tile_hash, base); + ths=g_hash_table_lookup(tile_hash, sub); + if (! ths) + return 0; + if (debug_tile(base) || debug_tile(sub)) + fprintf(stderr,"merging '%s'(%p) (%d) with '%s'(%p) (%d)\n", base, thb, thb ? thb->total_size : 0, sub, ths, ths->total_size); + if (! thb) { + thb=ths; + g_hash_table_remove(tile_hash, sub); + thb->name=string_hash_lookup(base); + g_hash_table_insert(tile_hash, string_hash_lookup( thb->name ), thb); + + } else { + thb=realloc(thb, sizeof(struct tile_head)+( ths->num_subtiles+thb->num_subtiles ) * sizeof( char*) ); + assert(thb != NULL); + memcpy( th_get_subtile( thb, thb->num_subtiles ), th_get_subtile( ths, 0 ), ths->num_subtiles * sizeof( char*) ); + thb->num_subtiles+=ths->num_subtiles; + thb->total_size+=ths->total_size; + g_hash_table_insert(tile_hash, string_hash_lookup( thb->name ), thb); + g_hash_table_remove(tile_hash, sub); + g_free(ths); + } + return 1; +} + + +static void +get_tiles_list_func(char *key, struct tile_head *th, GList **list) +{ + *list=g_list_prepend(*list, key); +} + +static GList * +get_tiles_list(void) +{ + GList *ret=NULL; + g_hash_table_foreach(tile_hash, (GHFunc)get_tiles_list_func, &ret); + return ret; +} + +#if 0 +static void +write_tile(char *key, struct tile_head *th, gpointer dummy) +{ + FILE *f; + char buffer[1024]; + fprintf(stderr,"DEBUG: Writing %s\n", key); + strcpy(buffer,"tiles/"); + strcat(buffer,key); +#if 0 + strcat(buffer,".bin"); +#endif + f=fopen(buffer, "wb+"); + while (th) { + fwrite(th->data, th->size, 1, f); + th=th->next; + } + fclose(f); +} +#endif + +static void +write_item(char *tile, struct item_bin *ib) +{ + struct tile_head *th; + int size; + + th=g_hash_table_lookup(tile_hash2, tile); + if (! th) + th=g_hash_table_lookup(tile_hash, tile); + if (th) { + if (th->process != 0 && th->process != 1) { + fprintf(stderr,"error with tile '%s' of length %d\n", tile, (int)strlen(tile)); + abort(); + } + if (! th->process) + return; + if (debug_tile(tile)) + fprintf(stderr,"Data:Writing %d bytes to '%s' (%p,%p)\n", (ib->len+1)*4, tile, g_hash_table_lookup(tile_hash, tile), tile_hash2 ? g_hash_table_lookup(tile_hash2, tile) : NULL); + size=(ib->len+1)*4; + if (th->total_size_used+size > th->total_size) { + fprintf(stderr,"Overflow in tile %s (used %d max %d item %d)\n", tile, th->total_size_used, th->total_size, size); + exit(1); + return; + } + memcpy(th->zip_data+th->total_size_used, ib, size); + th->total_size_used+=size; + } else { + fprintf(stderr,"no tile hash found for %s\n", tile); + exit(1); + } +} + +static void +write_item_part(FILE *out, FILE *out_graph, struct item_bin *orig, int first, int last) +{ + struct item_bin new; + struct coord *c=(struct coord *)(orig+1); + char *attr=(char *)(c+orig->clen/2); + int attr_len=orig->len-orig->clen-2; + processed_ways++; + new.type=orig->type; + new.clen=(last-first+1)*2; + new.len=new.clen+attr_len+2; +#if 0 + fprintf(stderr,"first %d last %d type 0x%x len %d clen %d attr_len %d\n", first, last, new.type, new.len, new.clen, attr_len); +#endif + fwrite(&new, sizeof(new), 1, out); + fwrite(c+first, new.clen*4, 1, out); + fwrite(attr, attr_len*4, 1, out); +#if 0 + fwrite(&new, sizeof(new), 1, out_graph); + fwrite(c+first, new.clen*4, 1, out_graph); + fwrite(attr, attr_len*4, 1, out_graph); +#endif +} + +static int +phase2(FILE *in, FILE *out, FILE *out_graph, FILE *out_coastline, int final) +{ + struct coord *c; + int i,ccount,last,remaining; + osmid ndref; + struct item_bin *ib; + struct node_item *ni; + + processed_nodes=processed_nodes_out=processed_ways=processed_relations=processed_tiles=0; + sig_alrm(0); + while ((ib=read_item(in))) { +#if 0 + fprintf(stderr,"type 0x%x len %d clen %d\n", ib->type, ib->len, ib->clen); +#endif + ccount=ib->clen/2; + if (ccount <= 1) + continue; + c=(struct coord *)(ib+1); + last=0; + for (i = 0 ; i < ccount ; i++) { + if (IS_REF(c[i])) { + ndref=REF(c[i]); + ni=node_item_get(ndref); + if (ni) { + c[i]=ni->c; + if (ni->ref_way > 1 && i != 0 && i != ccount-1 && i != last && item_get_default_flags(ib->type)) { + write_item_part(out, out_graph, ib, last, i); + last=i; + } + } else if (final) { + fprintf(stderr,"Non-existing node %Ld referenced from way %Ld\n", (long long)ndref, item_bin_get_wayid(ib)); + remaining=(ib->len+1)*4-sizeof(struct item_bin)-i*sizeof(struct coord); + memmove(&c[i], &c[i+1], remaining); + ib->clen-=2; + ib->len-=2; + i--; + ccount--; + } + } + } + if (ccount) { + write_item_part(out, out_graph, ib, last, ccount-1); + if (final && ib->type == type_water_line && out_coastline) { + write_item_part(out_coastline, NULL, ib, last, ccount-1); + } + } + } + sig_alrm(0); +#ifndef _WIN32 + alarm(0); +#endif + return 0; +} + +struct tile_info { + int write; + int maxlen; + char *suffix; + GList **tiles_list; + FILE *tilesdir_out; +}; + +struct zip_info { + int zipnum; + int dir_size; + long long offset; + int compression_level; + int maxnamelen; + FILE *res; + FILE *index; + FILE *dir; +}; + +static void write_zipmember(struct zip_info *zip_info, char *name, int filelen, char *data, int data_size); + +static void +tile_write_item_to_tile(struct tile_info *info, struct item_bin *ib, char *name) +{ + if (info->write) + write_item(name, ib); + else + tile_extend(name, ib, info->tiles_list); +} + +static void +tile_write_item_minmax(struct tile_info *info, struct item_bin *ib, int min, int max) +{ + struct rect r; + char buffer[1024]; + bbox((struct coord *)(ib+1), ib->clen/2, &r); + buffer[0]='\0'; + tile(&r, info->suffix, buffer, max); + tile_write_item_to_tile(info, ib, buffer); +} + +static void +phase34_process_file(struct tile_info *info, FILE *in) +{ + struct item_bin *ib; + int max; + + while ((ib=read_item(in))) { + if (ib->type < 0x80000000) + processed_nodes++; + else + processed_ways++; + max=14; + if (ib->type == type_street_n_lanes || ib->type == type_highway_city || ib->type == type_highway_land || ib->type == type_ramp) + max=8; + if (ib->type == type_street_3_city || ib->type == type_street_4_city || ib->type == type_street_3_land || ib->type == type_street_4_land) + max=12; + tile_write_item_minmax(info, ib, 0, max); + } +} + +static void +index_init(struct zip_info *info, int version) +{ + item_bin_init(item_bin, type_map_information); + item_bin_add_attr_int(item_bin, attr_version, version); + item_bin_write(item_bin, info->index); +} + +static void +index_submap_add(struct tile_info *info, struct tile_head *th) +{ + int tlen=tile_len(th->name); + int len=tlen; + char index_tile[len+1+strlen(suffix)]; + struct rect r; + + strcpy(index_tile, th->name); + if (len > 6) + len=6; + else + len=0; + index_tile[len]=0; + if (tlen) + strcat(index_tile, suffix); + tile_bbox(th->name, &r); + + item_bin_init(item_bin, type_submap); + item_bin_add_coord_rect(item_bin, &r); + item_bin_add_attr_range(item_bin, attr_order, (tlen > 4)?tlen-4 : 0, 255); + item_bin_add_attr_int(item_bin, attr_zipfile_ref, th->zipnum); + tile_write_item_to_tile(info, item_bin, index_tile); +} + +static int +add_tile_hash(struct tile_head *th) +{ + int idx,len,maxnamelen=0; + char **data; + +#if 0 + g_hash_table_insert(tile_hash2, string_hash_lookup( th->name ), th); +#endif + for( idx = 0; idx < th->num_subtiles; idx++ ) { + + data = th_get_subtile( th, idx ); + + if (debug_tile(data) || debug_tile(th->name)) { + fprintf(stderr,"Parent for '%s' is '%s'\n", *data, th->name); + } + + g_hash_table_insert(tile_hash2, *data, th); + + len = strlen( *data ); + + if (len > maxnamelen) { + maxnamelen=len; + } + } + return maxnamelen; +} + + +static int +create_tile_hash(void) +{ + struct tile_head *th; + int len,maxnamelen=0; + + tile_hash2=g_hash_table_new(g_str_hash, g_str_equal); + th=tile_head_root; + while (th) { + len=add_tile_hash(th); + if (len > maxnamelen) + maxnamelen=len; + th=th->next; + } + return maxnamelen; +} + +static void +create_tile_hash_list(GList *list) +{ + GList *next; + struct tile_head *th; + + tile_hash2=g_hash_table_new(g_str_hash, g_str_equal); + + next=g_list_first(list); + while (next) { + th=g_hash_table_lookup(tile_hash, next->data); + if (!th) { + fprintf(stderr,"No tile found for '%s'\n", (char *)(next->data)); + } + add_tile_hash(th); + next=g_list_next(next); + } +} + +#if 0 +static void +destroy_tile_hash(void) +{ + g_hash_table_destroy(tile_hash2); + tile_hash2=NULL; +} +#endif + +static void write_countrydir(struct zip_info *zip_info); + +static void +write_tilesdir(struct tile_info *info, struct zip_info *zip_info, FILE *out) +{ + int idx,len,maxlen; + GList *next,*tiles_list; + char **data; + struct tile_head *th,**last=NULL; + + tiles_list=get_tiles_list(); + info->tiles_list=&tiles_list; + if (phase == 3) + create_tile_hash_list(tiles_list); + next=g_list_first(tiles_list); + last=&tile_head_root; + maxlen=info->maxlen; + if (! maxlen) { + while (next) { + if (strlen(next->data) > maxlen) + maxlen=strlen(next->data); + next=g_list_next(next); + } + } + len=maxlen; + while (len >= 0) { +#if 0 + fprintf(stderr,"PROGRESS: collecting tiles with len=%d\n", len); +#endif + next=g_list_first(tiles_list); + while (next) { + if (strlen(next->data) == len) { + th=g_hash_table_lookup(tile_hash, next->data); + if (phase == 3) { + *last=th; + last=&th->next; + th->next=NULL; + th->zipnum=zip_info->zipnum; + fprintf(out,"%s:%d",(char *)next->data,th->total_size); + + for ( idx = 0; idx< th->num_subtiles; idx++ ){ + data= th_get_subtile( th, idx ); + fprintf(out,":%s", *data); + } + + fprintf(out,"\n"); + } + if (th->name[0]) + index_submap_add(info, th); + zip_info->zipnum++; + processed_tiles++; + } + next=g_list_next(next); + } + len--; + } +} + +static void +merge_tiles(struct tile_info *info) +{ + struct tile_head *th; + char basetile[1024]; + char subtile[1024]; + GList *tiles_list_sorted,*last; + int i,i_min,len,size_all,size[5],size_min,work_done; + long long zip_size; + + do { + tiles_list_sorted=get_tiles_list(); + fprintf(stderr,"PROGRESS: sorting %d tiles\n", g_list_length(tiles_list_sorted)); + tiles_list_sorted=g_list_sort(tiles_list_sorted, (GCompareFunc)strcmp); + fprintf(stderr,"PROGRESS: sorting %d tiles done\n", g_list_length(tiles_list_sorted)); + last=g_list_last(tiles_list_sorted); + zip_size=0; + while (last) { + th=g_hash_table_lookup(tile_hash, last->data); + zip_size+=th->total_size; + last=g_list_previous(last); + } + last=g_list_last(tiles_list_sorted); + work_done=0; + while (last) { + processed_tiles++; + len=tile_len(last->data); + if (len >= 1) { + strcpy(basetile,last->data); + basetile[len-1]='\0'; + strcat(basetile, info->suffix); + strcpy(subtile,last->data); + for (i = 0 ; i < 4 ; i++) { + subtile[len-1]='a'+i; + size[i]=tile_data_size(subtile); + } + size[4]=tile_data_size(basetile); + size_all=size[0]+size[1]+size[2]+size[3]+size[4]; + if (size_all < 65536 && size_all > 0 && size_all != size[4]) { + for (i = 0 ; i < 4 ; i++) { + subtile[len-1]='a'+i; + work_done+=merge_tile(basetile, subtile); + } + } else { + for (;;) { + size_min=size_all; + i_min=-1; + for (i = 0 ; i < 4 ; i++) { + if (size[i] && size[i] < size_min) { + size_min=size[i]; + i_min=i; + } + } + if (i_min == -1) + break; + if (size[4]+size_min >= 65536) + break; + subtile[len-1]='a'+i_min; + work_done+=merge_tile(basetile, subtile); + size[4]+=size[i_min]; + size[i_min]=0; + } + } + } + last=g_list_previous(last); + } + g_list_free(tiles_list_sorted); + fprintf(stderr,"PROGRESS: merged %d tiles\n", work_done); + } while (work_done); +} + +static void +index_country_add(struct zip_info *info, int country_id, int zipnum) +{ + item_bin_init(item_bin, type_countryindex); + item_bin_add_attr_int(item_bin, attr_country_id, country_id); + item_bin_add_attr_int(item_bin, attr_zipfile_ref, zipnum); + item_bin_write(item_bin, info->index); +} + +struct aux_tile { + char *name; + char *filename; + int size; +}; + +static int +add_aux_tile(struct zip_info *zip_info, char *name, char *filename, int size) +{ + struct aux_tile *at; + GList *l; + l=aux_tile_list; + while (l) { + at=l->data; + if (!strcmp(at->name, name)) { + fprintf(stderr,"exists %s vs %s\n",at->name, name); + return -1; + } + l=g_list_next(l); + } + at=g_new0(struct aux_tile, 1); + at->name=g_strdup(name); + at->filename=g_strdup(filename); + at->size=size; + aux_tile_list=g_list_append(aux_tile_list, at); + return zip_info->zipnum++; +} + +static int +write_aux_tiles(struct zip_info *zip_info) +{ + GList *l=aux_tile_list; + struct aux_tile *at; + char *buffer; + FILE *f; + int count=0; + + while (l) { + at=l->data; + buffer=malloc(at->size); + assert(buffer != NULL); + f=fopen(at->filename,"rb"); + assert(f != NULL); + fread(buffer, at->size, 1, f); + fclose(f); + write_zipmember(zip_info, at->name, zip_info->maxnamelen, buffer, at->size); + free(buffer); + count++; + l=g_list_next(l); + zip_info->zipnum++; + } + return count; +} + +static void +write_countrydir(struct zip_info *zip_info) +{ + int i,zipnum,num; + int max=11; + char tilename[32]; + char filename[32]; + char suffix[32]; + struct country_table *co; + for (i = 0 ; i < sizeof(country_table)/sizeof(struct country_table) ; i++) { + co=&country_table[i]; + if (co->size) { + num=0; + do { + tilename[0]='\0'; + sprintf(suffix,"s%d", num); + num++; + tile(&co->r, suffix, tilename, max); + sprintf(filename,"country_%d.bin", co->countryid); + zipnum=add_aux_tile(zip_info, tilename, filename, co->size); + } while (zipnum == -1); + index_country_add(zip_info,co->countryid,zipnum); + } + } +} + +static void +write_index(struct zip_info *info) +{ + int size=ftell(info->index); + char buffer[size]; + + fseek(info->index, 0, SEEK_SET); + fread(buffer, size, 1, info->index); + write_zipmember(info, "index", strlen("index"), buffer, size); + info->zipnum++; +} + +static void +remove_countryfiles(void) +{ + int i; + char filename[32]; + struct country_table *co; + + for (i = 0 ; i < sizeof(country_table)/sizeof(struct country_table) ; i++) { + co=&country_table[i]; + if (co->size) { + sprintf(filename,"country_%d.bin", co->countryid); + unlink(filename); + } + } +} + +static int +phase34(struct tile_info *info, struct zip_info *zip_info, FILE *ways_in, FILE *nodes_in) +{ + + processed_nodes=processed_nodes_out=processed_ways=processed_relations=processed_tiles=0; + bytes_read=0; + sig_alrm(0); + if (! info->write) + tile_hash=g_hash_table_new(g_str_hash, g_str_equal); + if (ways_in) + phase34_process_file(info, ways_in); + if (nodes_in) + phase34_process_file(info, nodes_in); + if (! info->write) + merge_tiles(info); + sig_alrm(0); +#ifndef _WIN32 + alarm(0); +#endif + write_tilesdir(info, zip_info, info->tilesdir_out); + + return 0; + +} + +static void +dump_coord(struct coord *c) +{ + printf("0x%x 0x%x",c->x, c->y); +} + +static void +dump(FILE *in) +{ + struct item_bin *ib; + struct coord *c; + struct attr_bin *a; + struct attr attr; + int *attr_start; + int *attr_end; + int i; + char *str; + while ((ib=read_item(in))) { + c=(struct coord *)(ib+1); + if (ib->type < type_line) { + dump_coord(c); + printf(" "); + } + attr_start=(int *)(ib+1)+ib->clen; + attr_end=(int *)ib+ib->len+1; + printf("type=%s", item_to_name(ib->type)); + while (attr_start < attr_end) { + a=(struct attr_bin *)(attr_start); + attr_start+=a->len+1; + attr.type=a->type; + attr_data_set(&attr, (a+1)); + str=attr_to_text(&attr, NULL, 1); + printf(" %s=\"%s\"", attr_to_name(a->type), str); + g_free(str); + } + printf(" debug=\"length=%d\"", ib->len); + printf("\n"); + if (ib->type >= type_line) { + for (i = 0 ; i < ib->clen/2 ; i++) { + dump_coord(c+i); + printf("\n"); + } + + } + } +} + +static int +phase4(FILE *ways_in, FILE *nodes_in, char *suffix, FILE *tilesdir_out, struct zip_info *zip_info) +{ + struct tile_info info; + info.write=0; + info.maxlen=0; + info.suffix=suffix; + info.tiles_list=NULL; + info.tilesdir_out=tilesdir_out; + return phase34(&info, zip_info, ways_in, nodes_in); +} + +static int +compress2_int(Byte *dest, uLongf *destLen, const Bytef *source, uLong sourceLen, int level) +{ + z_stream stream; + int err; + + stream.next_in = (Bytef*)source; + stream.avail_in = (uInt)sourceLen; + stream.next_out = dest; + stream.avail_out = (uInt)*destLen; + if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; + + stream.zalloc = (alloc_func)0; + stream.zfree = (free_func)0; + stream.opaque = (voidpf)0; + + err = deflateInit2(&stream, level, Z_DEFLATED, -15, 9, Z_DEFAULT_STRATEGY); + if (err != Z_OK) return err; + + err = deflate(&stream, Z_FINISH); + if (err != Z_STREAM_END) { + deflateEnd(&stream); + return err == Z_OK ? Z_BUF_ERROR : err; + } + *destLen = stream.total_out; + + err = deflateEnd(&stream); + return err; +} + +static void +write_zipmember(struct zip_info *zip_info, char *name, int filelen, char *data, int data_size) +{ + struct zip_lfh lfh = { + 0x04034b50, + 0x0a, + 0x0, + 0x0, + 0xbe2a, + 0x5d37, + 0x0, + 0x0, + 0x0, + filelen, + 0x0, + }; + struct zip_cd cd = { + 0x02014b50, + 0x17, + 0x00, + 0x0a, + 0x00, + 0x0000, + 0x0, + 0xbe2a, + 0x5d37, + 0x0, + 0x0, + 0x0, + filelen, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0, + zip_info->offset, + }; + char filename[filelen+1]; + int error,crc,len,comp_size=data_size; + uLongf destlen=data_size+data_size/500+12; + char *compbuffer; + + compbuffer = malloc(destlen); + if (!compbuffer) { + fprintf(stderr, "No more memory.\n"); + exit (1); + } + + crc=crc32(0, NULL, 0); + crc=crc32(crc, (unsigned char *)data, data_size); +#ifdef HAVE_ZLIB + if (zip_info->compression_level) { + error=compress2_int((Byte *)compbuffer, &destlen, (Bytef *)data, data_size, zip_info->compression_level); + if (error == Z_OK) { + if (destlen < data_size) { + data=compbuffer; + comp_size=destlen; + } + } else { + fprintf(stderr,"compress2 returned %d\n", error); + } + } +#endif + lfh.zipcrc=crc; + lfh.zipsize=comp_size; + lfh.zipuncmp=data_size; + lfh.zipmthd=zip_info->compression_level ? 8:0; + cd.zipccrc=crc; + cd.zipcsiz=comp_size; + cd.zipcunc=data_size; + cd.zipcmthd=zip_info->compression_level ? 8:0; + strcpy(filename, name); + len=strlen(filename); + while (len < filelen) { + filename[len++]='_'; + } + filename[filelen]='\0'; + fwrite(&lfh, sizeof(lfh), 1, zip_info->res); + fwrite(filename, filelen, 1, zip_info->res); + fwrite(data, comp_size, 1, zip_info->res); + zip_info->offset+=sizeof(lfh)+filelen+comp_size; + fwrite(&cd, sizeof(cd), 1, zip_info->dir); + fwrite(filename, filelen, 1, zip_info->dir); + zip_info->dir_size+=sizeof(cd)+filelen; + + free(compbuffer); +} + +static int +process_slice(FILE *ways_in, FILE *nodes_in, long long size, char *suffix, struct zip_info *zip_info) +{ + struct tile_head *th; + char *slice_data,*zip_data; + int zipfiles=0; + struct tile_info info; + + slice_data=malloc(size); + assert(slice_data != NULL); + zip_data=slice_data; + th=tile_head_root; + while (th) { + if (th->process) { + th->zip_data=zip_data; + zip_data+=th->total_size; + } + th=th->next; + } + if (ways_in) + fseek(ways_in, 0, SEEK_SET); + if (nodes_in) + fseek(nodes_in, 0, SEEK_SET); + info.write=1; + info.maxlen=zip_info->maxnamelen; + info.suffix=suffix; + info.tiles_list=NULL; + info.tilesdir_out=NULL; + phase34(&info, zip_info, ways_in, nodes_in); + + th=tile_head_root; + while (th) { + if (th->process) { + if (th->name[0]) { + if (th->total_size != th->total_size_used) { + fprintf(stderr,"Size error '%s': %d vs %d\n", th->name, th->total_size, th->total_size_used); + exit(1); + } + write_zipmember(zip_info, th->name, zip_info->maxnamelen, th->zip_data, th->total_size); + zipfiles++; + } else + fwrite(th->zip_data, th->total_size, 1, zip_info->index); + } + th=th->next; + } + free(slice_data); + + return zipfiles; +} + +static void +cat(FILE *in, FILE *out) +{ + size_t size; + char buffer[4096]; + while ((size=fread(buffer, 1, 4096, in))) + fwrite(buffer, 1, size, out); +} + +static int +phase5(FILE *ways_in, FILE *nodes_in, char *suffix, struct zip_info *zip_info) +{ + long long size; + int slices; + int zipnum,written_tiles; + struct tile_head *th,*th2; + create_tile_hash(); + + th=tile_head_root; + size=0; + slices=0; + fprintf(stderr, "Maximum slice size %Ld\n", slice_size); + while (th) { + if (size + th->total_size > slice_size) { + fprintf(stderr,"Slice %d is of size %Ld\n", slices, size); + size=0; + slices++; + } + size+=th->total_size; + th=th->next; + } + if (size) + fprintf(stderr,"Slice %d is of size %Ld\n", slices, size); + th=tile_head_root; + size=0; + slices=0; + while (th) { + th2=tile_head_root; + while (th2) { + th2->process=0; + th2=th2->next; + } + size=0; + while (th && size+th->total_size < slice_size) { + size+=th->total_size; + th->process=1; + th=th->next; + } + /* process_slice() modifies zip_info, but need to retain old info */ + zipnum=zip_info->zipnum; + written_tiles=process_slice(ways_in, nodes_in, size, suffix, zip_info); + zip_info->zipnum=zipnum+written_tiles; + slices++; + } + return 0; +} + +static int +phase5_write_directory(struct zip_info *info) +{ + struct zip_eoc eoc = { + 0x06054b50, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0, + 0x0, + 0x0, + }; + + fseek(info->dir, 0, SEEK_SET); + cat(info->dir, info->res); + eoc.zipenum=info->zipnum; + eoc.zipecenn=info->zipnum; + eoc.zipecsz=info->dir_size; + eoc.zipeofst=info->offset; + fwrite(&eoc, sizeof(eoc), 1, info->res); + sig_alrm(0); +#ifndef _WIN32 + alarm(0); +#endif + return 0; +} + + + +static void +usage(FILE *f) +{ + /* DEVELOPPERS : don't forget to update the manpage if you modify theses options */ + fprintf(f,"\n"); + fprintf(f,"osm2navit - parse osm textfile and converts to NavIt binfile format\n\n"); + fprintf(f,"Usage :\n"); + fprintf(f,"bzcat planet.osm.bz2 | osm2navit mymap.bin\n"); + fprintf(f,"Available switches:\n"); + fprintf(f,"-h (--help) : this screen\n"); + fprintf(f,"-N (--nodes-only) : process only nodes\n"); + fprintf(f,"-W (--ways-only) : process only ways\n"); + fprintf(f,"-a (--attr-debug-level) : control which data is included in the debug attribute\n"); + fprintf(f,"-c (--dump-coordinates) : dump coordinates after phase 1\n"); +#ifdef HAVE_POSTGRESQL + fprintf(f,"-d (--db) : get osm data out of a postgresql database with osm simple scheme and given connect string\n"); +#endif + fprintf(f,"-e (--end) : end at specified phase\n"); + fprintf(f,"-k (--keep-tmpfiles) : do not delete tmp files after processing. useful to reuse them\n\n"); + fprintf(f,"-o (--coverage) : map every street to item coverage\n"); + fprintf(f,"-s (--start) : start at specified phase\n"); + fprintf(f,"-i (--input-file) : specify the input file name (OSM), overrules default stdin\n"); + fprintf(f,"-w (--dedupe-ways) : ensure no duplicate ways or nodes. useful when using several input files\n"); + fprintf(f,"-z (--compression-level) : set the compression level\n"); + exit(1); +} + +static void +process_binfile(FILE *in, FILE *out) +{ + struct item_bin *ib; + while ((ib=read_item(in))) { + fwrite(ib, (ib->len+1)*4, 1, out); + } +} + +static struct plugins *plugins; + +static void add_plugin(char *path) +{ + struct attr **attrs; + + if (! plugins) + plugins=plugins_new(); + attrs=(struct attr*[]){&(struct attr){attr_path,{path}},NULL}; + plugin_new(&(struct attr){attr_plugins,.u.plugins=plugins}, attrs); +} + +static FILE * +tempfile(char *suffix, char *name, int write) +{ + char buffer[4096]; + sprintf(buffer,"%s_%s.tmp",name, suffix); + return fopen(buffer,write ? "wb+": "rb"); +} + +static void +tempfile_unlink(char *suffix, char *name) +{ + char buffer[4096]; + sprintf(buffer,"%s_%s.tmp",name, suffix); + unlink(buffer); +} + +static void +tempfile_rename(char *suffix, char *from, char *to) +{ + char buffer_from[4096],buffer_to[4096]; + sprintf(buffer_from,"%s_%s.tmp",from,suffix); + sprintf(buffer_to,"%s_%s.tmp",to,suffix); + assert(rename(buffer_from, buffer_to) == 0); + +} + +int main(int argc, char **argv) +{ + FILE *ways=NULL,*ways_split=NULL,*nodes=NULL,*turn_restrictions=NULL,*graph=NULL,*coastline=NULL,*tilesdir; + char *map=g_strdup(attrmap); + int zipnum,c,start=1,end=99,dump_coordinates=0; + int keep_tmpfiles=0; + int process_nodes=1, process_ways=1; +#ifdef HAVE_ZLIB + int compression_level=9; +#else + int compression_level=0; +#endif + int output=0; + int input=0; + char *result; +#ifdef HAVE_POSTGRESQL + char *dbstr=NULL; +#endif + FILE* input_file = stdin; + struct attr **attrs; + struct map *map_handle=NULL; +#if 0 + char *suffixes[]={"m0l0", "m0l1","m0l2","m0l3","m0l4","m0l5","m0l6"}; +#else + char *suffixes[]={""}; +#endif + int suffix_count=sizeof(suffixes)/sizeof(char *); + int i; + main_init(argv[0]); + struct zip_info zip_info; + + while (1) { +#if 0 + int this_option_optind = optind ? optind : 1; +#endif + int option_index = 0; + static struct option long_options[] = { + {"attr-debug-level", 1, 0, 'a'}, + {"binfile", 0, 0, 'b'}, + {"compression-level", 1, 0, 'z'}, + {"coverage", 0, 0, 'o'}, +#ifdef HAVE_POSTGRESQL + {"db", 1, 0, 'd'}, +#endif + {"dedupe-ways", 0, 0, 'w'}, + {"dump", 0, 0, 'D'}, + {"dump-coordinates", 0, 0, 'c'}, + {"end", 1, 0, 'e'}, + {"help", 0, 0, 'h'}, + {"keep-tmpfiles", 0, 0, 'k'}, + {"nodes-only", 0, 0, 'N'}, + {"map", 1, 0, 'm'}, + {"plugin", 1, 0, 'p'}, + {"start", 1, 0, 's'}, + {"input-file", 1, 0, 'i'}, + {"ignore-unknown", 0, 0, 'n'}, + {"ways-only", 0, 0, 'W'}, + {"slice-size", 1, 0, 'S'}, + {0, 0, 0, 0} + }; + c = getopt_long (argc, argv, "DNWS:a:bc" +#ifdef HAVE_POSTGRESQL + "d:" +#endif + "e:hi:knm:p:s:wz:", long_options, &option_index); + if (c == -1) + break; + switch (c) { + case 'D': + output=1; + break; + case 'N': + process_ways=0; + break; + case 'S': + slice_size=atoll(optarg); + break; + case 'W': + process_nodes=0; + break; + case 'a': + attr_debug_level=atoi(optarg); + break; + case 'b': + input=1; + break; + case 'c': + dump_coordinates=1; + break; +#ifdef HAVE_POSTGRESQL + case 'd': + dbstr=optarg; + break; +#endif + case 'e': + end=atoi(optarg); + break; + case 'h': + usage(stdout); + break; + case 'm': + attrs=(struct attr*[]){ + &(struct attr){attr_type,{"textfile"}}, + &(struct attr){attr_data,{optarg}}, + NULL}; + add_plugin("$NAVIT_LIBDIR/*/${NAVIT_LIBPREFIX}libmap_textfile.so"); + map_handle=map_new(NULL, attrs); + break; + case 'n': + fprintf(stderr,"I will IGNORE unknown types\n"); + ignore_unkown=1; + break; + case 'k': + fprintf(stderr,"I will KEEP tmp files\n"); + keep_tmpfiles=1; + break; + case 'o': + coverage=1; + break; + case 'p': + add_plugin(optarg); + break; + case 's': + start=atoi(optarg); + break; + case 'w': + dedupe_ways_hash=g_hash_table_new(NULL, NULL); + break; + case 'i': + input_file = fopen( optarg, "r" ); + if ( input_file == NULL ) + { + fprintf( stderr, "\nInput file (%s) not found\n", optarg ); + exit( -1 ); + } + break; +#ifdef HAVE_ZLIB + case 'z': + compression_level=atoi(optarg); + break; +#endif + case '?': + usage(stderr); + break; + default: + fprintf(stderr,"c=%d\n", c); + } + + } + if (optind != argc-(output == 1 ? 0:1)) + usage(stderr); + if (plugins) + plugins_init(plugins); + result=argv[optind]; + build_attrmap(map); + build_countrytable(); + + + if (input == 0) { + if (start == 1) { + unlink("coords.tmp"); + if (process_ways) + ways=tempfile(suffix,"ways",1); + if (process_nodes) + nodes=tempfile(suffix,"nodes",1); + if (process_ways && process_nodes) + turn_restrictions=tempfile(suffix,"turn_restrictions",1); + phase=1; + fprintf(stderr,"PROGRESS: Phase 1: collecting data\n"); +#ifdef HAVE_POSTGRESQL + if (dbstr) + phase1_db(dbstr,ways,nodes); + else +#endif + if (map_handle) { + phase1_map(map_handle,ways,nodes); + map_destroy(map_handle); + } + else + phase1(input_file,ways,nodes,turn_restrictions); + if (slices) { + fprintf(stderr,"%d slices\n",slices); + flush_nodes(1); + for (i = slices-2 ; i>=0 ; i--) { + fprintf(stderr, "slice %d of %d\n",slices-i-1,slices-1); + load_buffer("coords.tmp",&node_buffer, i*slice_size, slice_size); + resolve_ways(ways, NULL); + save_buffer("coords.tmp",&node_buffer, i*slice_size); + } + } + if (ways) + fclose(ways); + if (nodes) + fclose(nodes); + if (turn_restrictions) + fclose(turn_restrictions); + } + if (!slices) { + if (end == 1 || dump_coordinates) + flush_nodes(1); + else + slices++; + } + if (end == 1) + exit(0); + if (start == 2) { + load_buffer("coords.tmp",&node_buffer,0, slice_size); + } + if (start <= 2) { + if (process_ways) { + ways=tempfile(suffix,"ways",0); + phase=2; + fprintf(stderr,"PROGRESS: Phase 2: finding intersections\n"); + for (i = 0 ; i < slices ; i++) { + int final=(i >= slices-1); + ways_split=tempfile(suffix,"ways_split",1); + graph=tempfile(suffix,"graph",1); + /* coastline=tempfile(suffix,"coastline",1); */ + if (i) + load_buffer("coords.tmp",&node_buffer, i*slice_size, slice_size); + phase2(ways,ways_split,graph,coastline,final); + fclose(ways_split); + fclose(ways); + fclose(graph); + if (! final) { + tempfile_rename(suffix,"ways_split","ways_to_resolve"); + ways=tempfile(suffix,"ways_to_resolve",0); + } + } + if(!keep_tmpfiles) + tempfile_unlink(suffix,"ways"); + tempfile_unlink(suffix,"ways_to_resolve"); + } else + fprintf(stderr,"PROGRESS: Skipping Phase 2\n"); + } + free(node_buffer.base); + node_buffer.base=NULL; + node_buffer.malloced=0; + node_buffer.size=0; + if (end == 2) + exit(0); + } else { + ways_split=tempfile(suffix,"ways_split",0); + process_binfile(stdin, ways_split); + fclose(ways_split); + } + if (start <= 3) { + fprintf(stderr,"PROGRESS: Phase 3: sorting countries\n"); + sort_countries(keep_tmpfiles); + } + if (end == 3) + exit(0); + if (output == 1) { + fprintf(stderr,"PROGRESS: Phase 4: dumping\n"); + if (process_nodes) { + nodes=tempfile(suffix,"nodes",0); + if (nodes) { + dump(nodes); + fclose(nodes); + } + } + if (process_ways) { + ways_split=tempfile(suffix,"ways_split",0); + if (ways_split) { + dump(ways_split); + fclose(ways_split); + } + } + if (process_ways && process_nodes) { + turn_restrictions=tempfile(suffix,"turn_restrictions",0); + if (turn_restrictions) { + dump(turn_restrictions); + fclose(turn_restrictions); + } + } + exit(0); + } + for (i = 0 ; i < suffix_count ; i++) { + suffix=suffixes[i]; + if (start <= 4) { + phase=3; + if (i == 0) { + memset(&zip_info, 0, sizeof(zip_info)); + } + zipnum=zip_info.zipnum; + fprintf(stderr,"PROGRESS: Phase 4: generating tiles %s\n",suffix); + if (process_ways) + ways_split=tempfile(suffix,"ways_split",0); + if (process_nodes) + nodes=tempfile(suffix,"nodes",0); + tilesdir=tempfile(suffix,"tilesdir",1); + phase4(ways_split,nodes,suffix,tilesdir,&zip_info); + fclose(tilesdir); + if (nodes) + fclose(nodes); + if (ways_split) + fclose(ways_split); + zip_info.zipnum=zipnum; + } + if (end == 4) + exit(0); + if (start <= 5) { + phase=4; + fprintf(stderr,"PROGRESS: Phase 5: assembling map %s\n",suffix); + if (process_ways) + ways_split=tempfile(suffix,"ways_split",0); + if (process_nodes) + nodes=tempfile(suffix,"nodes",0); + if (i == 0) { + zip_info.dir_size=0; + zip_info.offset=0; + zip_info.maxnamelen=14+strlen(suffixes[0]); + zip_info.compression_level=compression_level; + zip_info.zipnum=0; + zip_info.dir=tempfile("zipdir","",1); + zip_info.index=tempfile("index","",1); + zip_info.res=fopen(result,"wb+"); + index_init(&zip_info, 1); + } + phase5(ways_split,nodes,suffix,&zip_info); + if (nodes) + fclose(nodes); + if (ways_split) + fclose(ways_split); + if(!keep_tmpfiles) { + tempfile_unlink(suffix,"nodes"); + tempfile_unlink(suffix,"ways_split"); + tempfile_unlink(suffix,"turn_restrictions"); + tempfile_unlink(suffix,"graph"); + tempfile_unlink(suffix,"tilesdir"); + tempfile_unlink("zipdir",""); + unlink("coords.tmp"); + } + if (i == suffix_count-1) { + zipnum=zip_info.zipnum; + write_countrydir(&zip_info); + zip_info.zipnum=zipnum; + write_aux_tiles(&zip_info); + write_index(&zip_info); + phase5_write_directory(&zip_info); + fclose(zip_info.index); + fclose(zip_info.dir); + fclose(zip_info.res); + if (!keep_tmpfiles) { + remove_countryfiles(); + tempfile_unlink("index",""); + } + } + } + } + return 0; +} |