new program osm2navit capable of processing planet.osm, improvements to binfile driver
authormartin-s <martin-s@ffa7fe5e-494d-0410-b361-a75ebd5db220>
Thu, 1 Nov 2007 15:21:39 +0000 (15:21 +0000)
committermartin-s <martin-s@ffa7fe5e-494d-0410-b361-a75ebd5db220>
Thu, 1 Nov 2007 15:21:39 +0000 (15:21 +0000)
git-svn-id: https://navit.svn.sourceforge.net/svnroot/navit/trunk@504 ffa7fe5e-494d-0410-b361-a75ebd5db220

navit/src/Makefile.am
navit/src/attr_def.h
navit/src/data/binfile/binfile.c
navit/src/item_def.h
navit/src/osm2navit.c [new file with mode: 0644]
navit/src/zipfile.h [new file with mode: 0644]

index 1736a98..93fc07d 100644 (file)
@@ -22,7 +22,7 @@ navit_SOURCES = attr.c callback.c compass.c coord.c country.c cursor.c data_wind
        param.h phrase.h plugin.h point.h plugin_def.h projection.h popup.h route.h profile.h search.h speech.h statusbar.h \
        transform.h track.h util.h vehicle.h xmlconfig.h
 
-osm2navit_SOURCES = osm2navit.c item.c debug.c
+osm2navit_SOURCES = osm2navit.c item.c debug.c zipfile.h
 
 navit_LDADD = @NAVIT_LIBS@ @GPSD_LIBS@ -Lfib-1.1 -lfib
 
index beb90ea..966e48f 100644 (file)
@@ -22,6 +22,7 @@ ATTR(x)
 ATTR(y)
 ATTR(flush_size)
 ATTR(flush_time)
+ATTR(zipfile_ref)
 /* boolean */
 ATTR(overwrite)
 ATTR2(0x0002ffff,type_int_end)
@@ -59,3 +60,4 @@ ATTR(navigation_long)
 ATTR(navigation_long_exact)
 ATTR(navigation_speech)
 ATTR2(0x0003ffff,type_string_end)
+ATTR(order_limit)
index 3387832..653bceb 100644 (file)
 #include "coord.h"
 #include "transform.h"
 #include "file.h"
+#include "zipfile.h"
 
 static int map_id;
 
-struct map_priv {
-       int id;
-       char *filename;
-       struct file *f;
-};
-
-struct map_rect_priv {
+struct tile {
        int *start;
+       int *end;
        int *pos;
        int *pos_coord_start;
        int *pos_coord;
        int *pos_attr_start;
        int *pos_attr;
        int *pos_next;
+       int zipfile_num;
+};
+
+struct map_priv {
+       int id;
+       char *filename;
+       struct file *fi;
+       struct zip_cd *index_cd;
+       int cde_size;
+       struct zip_eoc *eoc;
+};
+
+struct map_rect_priv {
+       int *start;
        int *end;
        enum attr_type attr_last;
         struct map_selection *sel;
         struct map_priv *m;
         struct item item;
+       int tile_depth;
+       struct tile tiles[8];
+       struct tile *t;
 };
 
 
@@ -49,21 +62,23 @@ static void
 binfile_coord_rewind(void *priv_data)
 {
        struct map_rect_priv *mr=priv_data;
-       mr->pos_coord=mr->pos_coord_start;
+       struct tile *t=mr->t;
+       t->pos_coord=t->pos_coord_start;
 }
 
 static int
 binfile_coord_get(void *priv_data, struct coord *c, int count)
 {
        struct map_rect_priv *mr=priv_data;
+       struct tile *t=mr->t;
        int ret=0;
        dbg(1,"binfile_coord_get %d\n",count);
        while (count--) {
-               dbg(1,"%p vs %p\n", mr->pos_coord, mr->pos_attr_start);
-               if (mr->pos_coord >= mr->pos_attr_start)
+               dbg(1,"%p vs %p\n", t->pos_coord, t->pos_attr_start);
+               if (t->pos_coord >= t->pos_attr_start)
                        break;
-               c->x=*(mr->pos_coord++);
-               c->y=*(mr->pos_coord++);
+               c->x=*(t->pos_coord++);
+               c->y=*(t->pos_coord++);
                c++;
                ret++;
        }
@@ -74,7 +89,8 @@ static void
 binfile_attr_rewind(void *priv_data)
 {
        struct map_rect_priv *mr=priv_data;
-       mr->pos_attr=mr->pos_attr_start;
+       struct tile *t=mr->t;
+       t->pos_attr=t->pos_attr_start;
        
 }
 
@@ -82,26 +98,27 @@ static int
 binfile_attr_get(void *priv_data, enum attr_type attr_type, struct attr *attr)
 {      
        struct map_rect_priv *mr=priv_data;
+       struct tile *t=mr->t;
        enum attr_type type;
        int size;
 
        if (attr_type != mr->attr_last) {
-               mr->pos_attr=mr->pos_attr_start;
+               t->pos_attr=t->pos_attr_start;
                mr->attr_last=attr_type;
        }
-       while (mr->pos_attr < mr->pos_next) {
-               size=*(mr->pos_attr++);
-               type=mr->pos_attr[0];
+       while (t->pos_attr < t->pos_next) {
+               size=*(t->pos_attr++);
+               type=t->pos_attr[0];
                if (type == attr_type || attr_type == attr_any) {
                        if (attr_type == attr_any) {
-                               dbg(0,"pos %p attr %s size %d\n", mr->pos_attr-1, attr_to_name(type), size);
+                               dbg(0,"pos %p attr %s size %d\n", t->pos_attr-1, attr_to_name(type), size);
                        }
                        attr->type=type;
-                       attr_data_set(attr, mr->pos_attr+1);
-                       mr->pos_attr+=size;
+                       attr_data_set(attr, t->pos_attr+1);
+                       t->pos_attr+=size;
                        return 1;
                } else {
-                       mr->pos_attr+=size;
+                       t->pos_attr+=size;
                }
        }
        return 0;
@@ -114,6 +131,49 @@ static struct item_methods methods_binfile = {
         binfile_attr_get,
 };
 
+static void
+push_tile(struct map_rect_priv *mr, struct tile *t)
+{
+       mr->t=&mr->tiles[mr->tile_depth++];
+       *(mr->t)=*t;
+       mr->t->pos=mr->t->pos_next=mr->t->start;
+}
+
+static int
+pop_tile(struct map_rect_priv *mr)
+{
+       if (mr->tile_depth <= 1)
+               return 0;
+       mr->t=&mr->tiles[--mr->tile_depth-1];
+       return 1;
+}
+
+
+static void
+zipfile_to_tile(struct file *f, struct zip_cd *cd, struct tile *t)
+{
+       char buffer[1024];
+       struct zip_lfh *lfh;
+       lfh=(struct zip_lfh *)(f->begin+cd->zipofst);
+       strncpy(buffer, lfh->zipname, lfh->zipfnln);
+       buffer[lfh->zipfnln]='\0';
+       dbg(0,"0x%x '%s' %d\n", lfh->ziplocsig, buffer, sizeof(*cd)+cd->zipcfnl);
+       t->start=(int *)(f->begin+cd->zipofst+sizeof(struct zip_lfh)+lfh->zipfnln);
+       t->end=t->start+lfh->zipuncmp/4;
+}
+
+static void
+push_zipfile_tile(struct map_rect_priv *mr, int zipfile)
+{
+        struct map_priv *m=mr->m;
+       struct file *f=m->fi;
+       struct tile t;
+       struct zip_cd *cd=(struct zip_cd *)(f->begin + m->eoc->zipeofst + zipfile*m->cde_size);
+       t.zipfile_num=zipfile;
+       zipfile_to_tile(f, cd, &t);
+       push_tile(mr, &t);
+}
+
 static struct map_rect_priv *
 map_rect_new_binfile(struct map_priv *map, struct map_selection *sel)
 {
@@ -123,10 +183,9 @@ map_rect_new_binfile(struct map_priv *map, struct map_selection *sel)
        mr=g_new0(struct map_rect_priv, 1);
        mr->m=map;
        mr->sel=sel;
-       mr->start=mr->pos=mr->pos_next=map->f->begin;
-       mr->end=map->f->end;
        mr->item.id_hi=0;
        mr->item.id_lo=0;
+       push_zipfile_tile(mr, map->eoc->zipecenn-1);
        mr->item.meth=&methods_binfile;
        mr->item.priv_data=mr;
        return mr;
@@ -143,12 +202,33 @@ static void
 setup_pos(struct map_rect_priv *mr)
 {
        int size,coord_size;
-       size=*(mr->pos++);
-       mr->pos_next=mr->pos+size;
-       mr->item.type=*(mr->pos++);
-       coord_size=*(mr->pos++);
-       mr->pos_coord_start=mr->pos_coord=mr->pos;
-       mr->pos_attr_start=mr->pos_attr=mr->pos_coord+coord_size;
+       struct tile *t=mr->t;
+       size=*(t->pos++);
+       if (size > 1024*1024 || size < 0) {
+               fprintf(stderr,"size=0x%x\n", size);
+#if 0
+               fprintf(stderr,"offset=%d\n", (unsigned char *)(mr->pos)-mr->m->f->begin);
+#endif
+               g_error("size error");
+       }
+       t->pos_next=t->pos+size;
+       mr->item.type=*(t->pos++);
+       coord_size=*(t->pos++);
+       t->pos_coord_start=t->pos_coord=t->pos;
+       t->pos_attr_start=t->pos_attr=t->pos_coord+coord_size;
+}
+
+static int
+selection_contains(struct map_selection *sel, struct coord_rect *r)
+{
+       if (! sel)
+               return 1;
+       while (sel) {
+               if (coord_rect_overlap(r, &sel->rect))
+                       return 1;
+               sel=sel->next;
+       }
+       return 0;
 }
 
 
@@ -156,19 +236,43 @@ setup_pos(struct map_rect_priv *mr)
 static struct item *
 map_rect_get_item_binfile(struct map_rect_priv *mr)
 {
-       mr->pos=mr->pos_next;
-       if (mr->pos >= mr->end)
-               return NULL;
-       mr->item.id_hi=0;
-       mr->item.id_lo=mr->pos-mr->start;
-       setup_pos(mr);
-       return &mr->item;
+       struct tile *t;
+       for (;;) {
+               t=mr->t;
+               t->pos=t->pos_next;
+               if (t->pos >= t->end) {
+                       if (pop_tile(mr))
+                               continue;
+                       return NULL;
+               }
+               mr->item.id_hi=t->zipfile_num;
+               mr->item.id_lo=t->pos-t->start;
+               setup_pos(mr);
+               if (mr->item.type == type_submap) {
+                       struct coord_rect r;
+                       r.lu.x=t->pos_coord[0];
+                       r.lu.y=t->pos_coord[3];
+                       r.rl.x=t->pos_coord[2];
+                       r.rl.y=t->pos_coord[1];
+                       if (!selection_contains(mr->sel, &r)) {
+                               continue;
+                       }
+                       dbg(1,"0x%x\n", t->pos_attr[5]);
+                       push_zipfile_tile(mr, t->pos_attr[5]);
+                       continue;
+                               
+               }
+               return &mr->item;
+       }
 }
 
 static struct item *
 map_rect_get_item_byid_binfile(struct map_rect_priv *mr, int id_hi, int id_lo)
 {
-       mr->pos=mr->start+id_lo;
+       struct tile *t;
+       push_zipfile_tile(mr, id_hi);
+       t=mr->t;
+       t->pos=t->start+id_lo;
        mr->item.id_hi=id_hi;
        mr->item.id_lo=id_lo;
        setup_pos(mr);
@@ -192,6 +296,7 @@ map_new_binfile(struct map_methods *meth, struct attr **attrs)
        struct attr *data=attr_search(attrs, NULL, attr_data);
        struct file_wordexp *wexp;
        char **wexp_data;
+       int *magic,cde_index_size;
        if (! data)
                return NULL;
 
@@ -204,8 +309,21 @@ map_new_binfile(struct map_methods *meth, struct attr **attrs)
        m->id=++map_id;
        m->filename=g_strdup(wexp_data[0]);
        dbg(0,"file_create %s\n", m->filename);
-       m->f=file_create(m->filename);
+       m->fi=file_create(m->filename);
        file_wordexp_destroy(wexp);
+       magic=(int *)(m->fi->begin);
+       if (*magic == 0x04034b50) {
+               cde_index_size=sizeof(struct zip_cd)+sizeof("index")-1;
+               m->eoc=(struct zip_eoc *)(m->fi->end-sizeof(struct zip_eoc));
+               m->index_cd=(struct zip_cd *)((char *)m->eoc-cde_index_size);
+               printf("length %d\n", m->eoc->zipecsz);
+               printf("entries %d\n", m->eoc->zipecenn);
+               m->cde_size=(m->eoc->zipecsz-cde_index_size)/(m->eoc->zipecenn-1);
+               printf("cde_size %d\n", m->cde_size);
+               printf("length %d\n",m->cde_size*(m->eoc->zipecenn-1)+cde_index_size);
+               printf("0x%x\n", m->eoc->zipesig);
+               printf("0x%x\n", m->index_cd->zipcensig);
+       }
        return m;
 }
 
index 8d4f30a..2480e4d 100644 (file)
@@ -260,3 +260,5 @@ ITEM(military_zone)
 ITEM(marine_poly)
 ITEM(plantation)
 ITEM(tundra)
+ITEM(tile)
+ITEM(submap)
diff --git a/navit/src/osm2navit.c b/navit/src/osm2navit.c
new file mode 100644 (file)
index 0000000..da3710a
--- /dev/null
@@ -0,0 +1,983 @@
+#include <glib.h>
+#include <malloc.h>
+#include <string.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <math.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <zlib.h>
+#include "item.h"
+#include "zipfile.h"
+
+
+static char *attrmap={
+       "amenity\n"
+       "building\n"
+       "highway        cycleway        street_nopass\n"
+       "highway        footway         street_nopass\n"
+       "highway        steps           street_nopass\n"
+       "highway        cyclepath       street_nopass\n"
+       "highway        track           street_nopass\n"
+       "highway        service         street_nopass\n"
+       "highway        pedestrian      street_nopass\n"
+       "highway        residential     street_1_city\n"
+       "highway        unclassified    street_1_city\n"
+       "highway        tertiary        street_2_city\n"
+       "highway        secondary       street_3_city\n"
+       "highway        primary         street_4_city\n"
+       "highway        trunk           street_4_city\n"
+       "highway        trunk_link      ramp\n"
+       "highway        motorway        highway_city\n"
+       "highway        motorway_link   ramp\n"
+       "landuse        allotments      wood\n"
+       "landuse        cemetery        cemetery_poly\n"
+       "landuse        forest          wood\n"
+       "leisure        park            park_poly\n"
+       "natural        wood            wood\n"
+       "natural        water           water_poly\n"
+       "place          suburb          town_poly\n"
+       "railway        rail            rail\n"
+       "railway        subway          rail\n"
+       "railway        tram            rail\n"
+       "waterway       canal           water_line\n"
+       "waterway       river           water_line\n"
+       "waterway       weir            water_line\n"
+       "waterway       stream          water_line\n"
+       "waterway       drain           water_line\n"
+};
+
+GHashTable *key_hash;
+
+static void
+build_attrmap_line(char *line)
+{
+       char *k=NULL,*v=NULL,*i=NULL,*p;
+       gpointer *data;
+       GHashTable *value_hash;
+       k=line;
+       p=index(k,'\t');
+       if (p) {
+               while (*p == '\t')
+                       *p++='\0';
+               v=p;
+               p=index(v,'\t');
+       }
+       if (p) {
+               while (*p == '\t')
+                       *p++='\0';
+               i=p;
+       }
+       if (! i)
+               i="street_unkn";
+       if (! key_hash)
+               key_hash=g_hash_table_new(g_str_hash, g_str_equal);
+       value_hash=g_hash_table_lookup(key_hash, k);
+       if (! value_hash) {
+               value_hash=g_hash_table_new(g_str_hash, g_str_equal);
+               g_hash_table_insert(key_hash, g_strdup(k), value_hash);
+       }
+       if (v) {
+               data=(gpointer)item_from_name(i);
+               g_hash_table_insert(value_hash, g_strdup(v), data);
+       }
+#if 0
+       fprintf(stderr,"'%s' '%s' '%s'\n", k, v, i);
+#endif
+}
+
+static void
+build_attrmap(char *map)
+{
+       char *p;
+       while (map) {
+               p=index(map,'\n');
+               if (p)
+                       *p++='\0';
+               if (strlen(map))
+                       build_attrmap_line(map);
+               map=p;
+       }
+}
+
+static int processed_nodes, processed_ways, processed_relations, processed_tiles;
+static int in_way, in_node, in_relation;
+
+static void
+sig_alrm(int sig)
+{
+       signal(SIGALRM, sig_alrm);
+       alarm(30);
+       fprintf(stderr,"PROGRESS: Processed %d nodes %d ways %d relations %d tiles\n", processed_nodes, 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;
+};
+
+struct attr_bin label_attr = {
+       0, attr_label
+};
+char label_attr_buffer[1024];
+
+struct attr_bin debug_attr = {
+       0, attr_debug
+};
+char debug_attr_buffer[1024];
+
+static void
+pad_text_attr(struct attr_bin *a, char *buffer)
+{
+       int l;
+       l=strlen(buffer);
+       while (l % 4) 
+               buffer[l++]='\0';
+       a->len=l/4+1;
+}
+static int parse_tag(char *p)
+{
+       char *q, *k, *v;
+       GHashTable *value_hash;
+       q=index(p, '"');
+       if (! q)
+               return 0;
+       k=q+1;
+       q=index(k, '"');
+       if (! q)
+               return 0;
+       *q++='\0';
+       q=index(q, '"');
+       if (! q)
+               return 0;
+       v=q+1;
+       q=index(v, '"');
+       if (! q)
+               return 0;
+       *q++='\0';
+       if (! strcmp(k,"name")) {
+               strcpy(label_attr_buffer, v);
+               pad_text_attr(&label_attr, label_attr_buffer);
+               return 1;
+       }
+       value_hash=g_hash_table_lookup(key_hash, k);
+       if (! value_hash)
+               return 1;
+       item.type=(enum item_type) g_hash_table_lookup(value_hash, v);
+       if (! item.type) {
+               item.type=type_street_unkn;
+               g_hash_table_insert(value_hash, v, (gpointer)item.type);
+       }
+       return 1;
+}
+
+struct buffer {
+       int malloced_step;
+       int malloced;
+       unsigned char *base;
+       int size;
+};
+
+struct tile_head {
+       int size;
+       int total_size;
+       char *name;
+       struct tile_head *next;
+       char data[0];
+};
+
+
+struct coord {
+       int x;
+       int y;
+} coord_buffer[65536];
+
+struct rect {
+       struct coord l,h;
+};
+
+int coord_count;
+
+struct node_item {
+       int id;
+       char ref_node;
+       char ref_way;
+       char ref_ref;
+       char dummy;
+       struct coord c;
+};
+
+struct buffer node_buffer = {
+       64*1024*1024,
+};
+
+struct buffer zipdir_buffer = {
+       1024*1024,
+};
+
+static void
+extend_buffer(struct buffer *b)
+{
+       b->malloced+=b->malloced_step;
+       b->base=realloc(b->base, b->malloced);
+       
+}
+
+static int parse_node(char *p)
+{
+       int c;
+       double lat, lon;
+       struct node_item *ni;
+
+       if (node_buffer.size + sizeof(struct node_item) > node_buffer.malloced) 
+               extend_buffer(&node_buffer);
+       ni=(struct node_item *)(node_buffer.base+node_buffer.size);
+       c=sscanf(p, "<node id=\"%d\" lat=\"%lf\" lon=\"%lf\"",&ni->id,&lat,&lon);
+       if (c != 3)
+               return 0;
+       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);
+       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;
+       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
+node_ref_way(int id)
+{
+       struct node_item *ni=node_item_get(id);
+       if (! ni) {
+               fprintf(stderr,"WARNING: node id %d not found\n", id);
+               return;
+       }
+       ni->ref_way++;
+}
+
+int wayid;
+
+static int
+parse_way(char *p)
+{
+       int c;
+       item.type=type_street_unkn;
+       label_attr.len=0;
+       debug_attr.len=0;
+       c=sscanf(p, "<way id=\"%d\"", &wayid);
+       if (c != 1)
+               return 0;
+       coord_count=0;
+       sprintf(debug_attr_buffer,"way_id=%d", wayid);
+       return 1;
+}
+
+static void
+write_attr(FILE *out, struct attr_bin *attr, char *buffer)
+{
+       if (attr->len) {
+               fwrite(attr, sizeof(*attr), 1, out);
+               fwrite(buffer, (attr->len-1)*4, 1, out);
+       }
+}
+
+static void
+end_way(FILE *out)
+{
+       int alen=0;
+       pad_text_attr(&debug_attr, debug_attr_buffer);
+       if (label_attr.len)
+               alen+=label_attr.len+1; 
+       if (debug_attr.len)
+               alen+=debug_attr.len+1; 
+       item.clen=coord_count*2;
+       item.len=item.clen+2+alen;
+       fwrite(&item, sizeof(item), 1, out);
+       fwrite(coord_buffer, coord_count*sizeof(struct coord), 1, out);
+       write_attr(out, &label_attr, label_attr_buffer);
+       write_attr(out, &debug_attr, debug_attr_buffer);
+}
+
+static int
+parse_nd(char *p)
+{
+       int c,ndref,len;
+       struct node_item *ni;
+       c=sscanf(p, "<nd ref=\"%d\"", &ndref);
+       if (c != 1)
+               return 0;
+#if 0
+       node_ref_way(ndref);
+#endif
+       ni=node_item_get(ndref);
+       if (ni) 
+               coord_buffer[coord_count++]=ni->c;
+       else {
+               len=strlen(p);
+               if (len > 0 && p[len-1]=='\n')
+                       p[len-1]='\0';  
+               fprintf(stderr,"WARNING: way %d: node %d not found (%s)\n",wayid,ndref,p);
+       }
+       if (coord_count > 65536) {
+               fprintf(stderr,"ERROR: Overflow\n");
+               exit(1);
+       }
+       return 1;
+}
+
+
+static int
+phase1(FILE *in, FILE *out)
+{
+       int size=4096;
+       char buffer[size];
+       char *p;
+       sig_alrm(0);
+       while (fgets(buffer, size, in)) {
+               p=index(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;
+                       processed_relations++;
+               } else if (!strncmp(p, "<member ",8)) {
+               } else if (!strncmp(p, "</node>",7)) {
+                       in_node=0;
+               } else if (!strncmp(p, "</way>",6)) {
+                       in_way=0;
+                       end_way(out);
+               } else if (!strncmp(p, "</relation>",11)) {
+                       in_relation=0;
+               } else if (!strncmp(p, "</osm>",6)) {
+               } else {
+                       fprintf(stderr,"WARNING: unknown tag in %s\n", buffer);
+               }
+       }
+       sig_alrm(0);
+       alarm(0);
+       return 1;
+}
+
+static char buffer[65536];
+
+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;
+       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(struct coord *c, int count, struct rect *r)
+{
+       if (! count)
+               return;
+       r->l=*c;
+       r->h=*c;        
+       c++;
+       while (--count) {
+               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 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},
+};
+
+static void
+tile(struct rect *r, char *ret)
+{
+       int x0,x1,x2,x3,x4;
+       int y0,y1,y2,y3,y4;
+       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 < 14 ; i++) {
+               x2=(x0+x4)/2;
+                y2=(y0+y4)/2;
+                x1=(x0+x2)/2;
+                y1=(y0+y2)/2;
+                x3=(x2+x4)/2;
+                y3=(y2+y4)/2;
+               if (     contains_bbox(x0,y0,x2,y2,r)) {
+                       strcat(ret,"d");
+                        x4=x2;
+                        y4=y2;
+                } else if (contains_bbox(x2,y0,x4,y2,r)) {
+                       strcat(ret,"c");
+                        x0=x2;
+                        y4=y2;
+                } else if (contains_bbox(x0,y2,x2,y4,r)) {
+                       strcat(ret,"b");
+                        x4=x2;
+                        y0=y2;
+                } else if (contains_bbox(x2,y2,x4,y4,r)) {
+                       strcat(ret,"a");
+                        x0=x2;
+                        y0=y2;
+               } else 
+                       return;
+       }
+}
+
+static void
+tile_bbox(char *tile, struct rect *r)
+{
+       *r=world_bbox;
+       struct coord c;
+       while (*tile) {
+               c.x=(r->l.x+r->h.x)/2;
+               c.y=(r->l.y+r->h.y)/2;
+               switch (*tile) {
+               case 'a':
+                       r->l.x=c.x;
+                       r->l.y=c.y;
+                       break;
+               case 'b':
+                       r->h.x=c.x;
+                       r->l.y=c.y;
+                       break;
+               case 'c':
+                       r->l.x=c.x;
+                       r->h.y=c.y;
+                       break;
+               case 'd':
+                       r->h.x=c.x;
+                       r->h.y=c.y;
+                       break;
+               }
+               tile++;
+       }
+}
+
+GHashTable *tile_hash;
+
+static void
+tile_data_append(char *tile, void *data, int len)
+{
+       struct tile_head *th;
+       th=g_hash_table_lookup(tile_hash, tile);
+       if (! th) {
+               th=malloc(sizeof(*th)+len);
+               th->size=0;
+               th->total_size=0;
+               th->name=g_strdup(tile);
+               th->next=NULL;
+               processed_tiles++;
+#if 0
+               fprintf(stderr,"new %s\n", tile);
+#endif
+       } else {
+               th=realloc(th, sizeof(*th)+len+th->size);
+       }
+       memcpy(th->data+th->size, data, len);
+       th->size+=len;
+       th->total_size+=len;
+       g_hash_table_insert(tile_hash, 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 void
+merge_tiles(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;
+#if 0
+       fprintf(stderr,"merging %s with %s\n", base, sub);
+#endif
+       if (! thb) {
+               thb=ths;
+               thb->name=g_strdup(base);
+               g_hash_table_insert(tile_hash, thb->name, thb);
+       } else {
+#if 0
+               thb=realloc(thb, sizeof(*thb)+ths->size+thb->size);
+               memcpy(thb->data+thb->size, ths->data, ths->size);
+               thb->size+=ths->size;
+               thb->total_size+=ths->total_size;
+               g_hash_table_insert(tile_hash, thb->name, thb);
+#if 0
+               tiles_list=g_list_remove(tiles_list,ths->name);
+#endif
+               free(ths);
+#endif
+               thb->total_size+=ths->total_size;
+               while (thb->next) 
+                       thb=thb->next;
+               thb->next=ths;
+       }
+       g_hash_table_remove(tile_hash, sub);
+}
+
+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;
+}
+
+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, "w+");
+       while (th) {
+               fwrite(th->data, th->size, 1, f);
+               th=th->next;
+       }
+       fclose(f);
+}
+
+static int
+phase2(FILE *in)
+{
+       struct item_bin *ib;
+       struct tile_head *th;
+       struct rect r;
+       char buffer[1024];
+       char basetile[1024];
+       char subtile[1024];
+       GList *tiles_list_sorted,*last;
+       int i,i_min,len,size[5],size_all,size_min,work_done;
+       
+
+       processed_nodes=processed_ways=processed_relations=processed_tiles=0;
+       sig_alrm(0);
+       tile_hash=g_hash_table_new(g_str_hash, g_str_equal);
+       while ((ib=read_item(in))) {
+               processed_ways++;
+               bbox((struct coord *)(ib+1), ib->clen/2, &r);
+               buffer[0]='\0';
+               tile(&r, buffer);
+#if 0
+               fprintf(stderr,"%s\n", buffer);
+#endif
+               tile_data_append(buffer, ib, ib->len*4+4);
+       }
+       fprintf(stderr,"read %d bytes\n", bytes_read);
+       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);
+               size_all=0;
+               while (last) {
+                       th=g_hash_table_lookup(tile_hash, last->data);
+                       size_all+=th->total_size;
+                       last=g_list_previous(last);
+               }
+               fprintf(stderr,"DEBUG: size=%d\n", size_all);
+               last=g_list_last(tiles_list_sorted);
+               work_done=0;
+               while (last) {
+                       processed_tiles++;
+                       len=strlen(last->data);
+                       if (len >= 1) {
+                               strcpy(basetile,last->data);
+                               basetile[len-1]='\0';
+                               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;
+                                               merge_tiles(basetile, subtile);
+                                       }
+                                       work_done++;
+                               } 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;
+                                               merge_tiles(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);
+       sig_alrm(0);
+       alarm(0);
+#if 0  
+       g_hash_table_foreach(tile_hash, write_tile, NULL);
+#endif
+       return 0;
+               
+}
+
+int
+dir_entries;
+
+static void
+add_zipdirentry(char *name, struct zip_cd *cd)
+{
+       int cd_size=sizeof(struct zip_cd)+strlen(name);
+       struct zip_cd *cdn;
+       if (zipdir_buffer.size + cd_size > zipdir_buffer.malloced) 
+               extend_buffer(&zipdir_buffer);
+       cdn=(struct zip_cd *)(zipdir_buffer.base+zipdir_buffer.size);
+       *cdn=*cd;
+       strcpy((char *)(cdn+1), name);
+       zipdir_buffer.size += cd_size;
+       dir_entries++;
+}
+
+int zipoffset;
+
+static void
+write_zipmember(FILE *out, char *name, int filelen, struct tile_head *th)
+{
+       struct tile_head *thc;
+       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,
+               0x0000,
+               0xbe2a,
+               0x5d37,
+               0x0,
+               0x0,
+               0x0,
+               filelen,
+               0x0000,
+               0x0000,
+               0x0000,
+               0x0000,
+               0x0,
+               zipoffset,
+       };
+       char filename[filelen+1];
+       int size=0,crc,len;
+
+       crc=crc32(0, NULL, 0);
+       thc=th;
+       while (thc) {
+               size+=thc->size;
+               crc=crc32(crc, (unsigned char *)(thc->data), thc->size);
+               thc=thc->next;
+       }
+       if (size != th->total_size) {
+               fprintf(stderr,"ERROR: size error %d vs %d\n", size, th->total_size);
+       }
+       lfh.zipcrc=crc;
+       lfh.zipsize=size;
+       lfh.zipuncmp=size;
+       cd.zipccrc=crc;
+       cd.zipcsiz=size;
+       cd.zipcunc=size;
+       strcpy(filename, name);
+       len=strlen(filename);
+       while (len < filelen) {
+               filename[len++]='_';
+       }
+       filename[filelen]='\0';
+       add_zipdirentry(filename, &cd);
+       fwrite(&lfh, sizeof(lfh), 1, out);
+       fwrite(filename, filelen, 1, out);
+       thc=th;
+       while (thc) {
+               fwrite(thc->data, thc->size, 1, out);
+               thc=thc->next;
+       }
+       zipoffset+=sizeof(lfh)+filelen+size;
+       
+}
+
+struct index_item {
+       struct item_bin item;
+       struct rect r;
+       struct attr_bin attr_order_limit;
+       short min;
+       short max;
+       struct attr_bin attr_zipfile_ref;
+       int zipfile_ref;
+};
+
+static void
+index_submap_add(char *tile)
+{
+       struct index_item ii;
+       int len=strlen(tile);
+       char index_tile[len+1];
+       strcpy(index_tile, tile);
+       if (len > 6)
+               len=6;
+       else
+               len=0;
+       index_tile[len]=0;
+       tile_bbox(tile, &ii.r);
+
+       ii.item.len=sizeof(ii)/4-1;
+       ii.item.type=type_submap;
+       ii.item.clen=4;
+
+       ii.attr_order_limit.len=2;
+       ii.attr_order_limit.type=attr_order_limit;
+       ii.min=0;
+       ii.max=0;
+
+       ii.attr_zipfile_ref.len=2;
+       ii.attr_zipfile_ref.type=attr_zipfile_ref;
+       ii.zipfile_ref=dir_entries;
+       tile_data_append(index_tile, &ii, sizeof(ii));
+#if 0
+       unsigned int *c=(unsigned int *)&ii;
+       int i;
+       for (i = 0 ; i < sizeof(ii)/4 ; i++) {
+               fprintf(stderr,"%08x ", c[i]);
+       }
+       fprintf(stderr,"\n");   
+#endif
+}
+
+static int
+phase3(FILE *out)
+{
+       struct zip_eoc eoc = {
+               0x06054b50,
+               0x0000,
+               0x0000,
+               0x0000,
+               0x0000,
+               0x0,
+               0x0,
+               0x0,
+       };
+
+       struct tile_head *th;
+       GList *tiles_list,*next;
+       int size=0,len,maxlen=0;
+
+       processed_nodes=processed_ways=processed_relations=processed_tiles=0;
+       sig_alrm(0);
+       tiles_list=get_tiles_list();
+       next=g_list_first(tiles_list);
+       while (next) {
+               if (strlen(next->data) > maxlen) 
+                       maxlen=strlen(next->data);
+               next=g_list_next(next);
+       }
+       len=maxlen;
+       while (len > 0) {
+               fprintf(stderr,"PROGRESS: collecting tiles with len=%d\n", len);
+               next=g_list_first(tiles_list);
+               while (next) {
+                       if (strlen(next->data) == len) {
+                               index_submap_add(next->data);
+                               th=g_hash_table_lookup(tile_hash, next->data);
+                               write_zipmember(out, next->data, maxlen, th);
+                               processed_tiles++;
+                               size+=th->total_size;
+                       }
+                       next=g_list_next(next);
+               }
+               len--;
+       }
+       th=g_hash_table_lookup(tile_hash, "");
+       write_zipmember(out, "index", 5, th);
+       size+=th->total_size;
+       fprintf(stderr, "DEBUG: wrote %d bytes\n", size);
+       fwrite(zipdir_buffer.base, zipdir_buffer.size, 1, out);
+       eoc.zipenum=dir_entries;
+       eoc.zipecenn=dir_entries;
+       eoc.zipecsz=zipdir_buffer.size;
+       eoc.zipeofst=zipoffset;
+       fwrite(&eoc, sizeof(eoc), 1, out);
+       sig_alrm(0);
+       alarm(0);
+       return 0;       
+}
+
+int main(int argc, char **argv)
+{
+       FILE *tmp;
+       char *map=g_strdup(attrmap);
+       build_attrmap(map);
+       tmp=fopen("tmpfile","w+");
+       fprintf(stderr,"PROGRESS: Phase 1: collecting data\n");
+       phase1(stdin,tmp);
+       fclose(tmp);
+       free(node_buffer.base);
+       node_buffer.base=NULL;
+       node_buffer.malloced=0;
+       node_buffer.size=0;
+       fprintf(stderr,"PROGRESS: Phase 2: generating tiles\n");
+       tmp=fopen("tmpfile","r");
+       phase2(tmp);
+       fclose(tmp);
+       fprintf(stderr,"PROGRESS: Phase 3: assembling map\n");
+       phase3(stdout);
+       return 0;
+}
diff --git a/navit/src/zipfile.h b/navit/src/zipfile.h
new file mode 100644 (file)
index 0000000..dd3bb49
--- /dev/null
@@ -0,0 +1,49 @@
+struct zip_lfh {
+       int ziplocsig;
+       short zipver;
+       short zipgenfld;
+       short zipmthd;
+       short ziptime;
+       short zipdate;
+       int zipcrc;
+       int zipsize;
+       int zipuncmp;
+       short zipfnln;
+       short zipxtraln;
+       char zipname[0];
+} __attribute__ ((packed));
+
+struct zip_cd {
+       int zipcensig;
+       char zipcver;
+       char zipcos;
+       char zipcvxt;
+       char zipcexos;
+       short zipcflg;
+       short zipcmthd;
+       short ziptim;
+       short zipdat;
+       int zipccrc;
+       int zipcsiz;
+       int zipcunc;
+       short zipcfnl;
+       short zipcxtl;
+       short zipccml;
+       short zipdsk;
+       short zipint;
+       int zipext;
+       int zipofst;
+       char zipcfn[0]; 
+} __attribute__ ((packed));
+
+struct zip_eoc {
+       int zipesig;
+       short zipedsk;
+       short zipecen;
+       short zipenum;
+       short zipecenn;
+       int zipecsz;
+       int zipeofst;
+       short zipecoml;
+       char zipecom[0];
+} __attribute__ ((packed));