diff options
Diffstat (limited to 'src/data')
-rw-r--r-- | src/data/Makefile.am | 1 | ||||
-rw-r--r-- | src/data/garmin_img/Makefile.am | 4 | ||||
-rw-r--r-- | src/data/garmin_img/garmin_img.c | 1486 | ||||
-rw-r--r-- | src/data/mg/Makefile.am | 4 | ||||
-rw-r--r-- | src/data/mg/block.c | 261 | ||||
-rw-r--r-- | src/data/mg/map.c | 296 | ||||
-rw-r--r-- | src/data/mg/mg.h | 286 | ||||
-rw-r--r-- | src/data/mg/poly.c | 196 | ||||
-rw-r--r-- | src/data/mg/street.c | 702 | ||||
-rw-r--r-- | src/data/mg/town.c | 261 | ||||
-rw-r--r-- | src/data/mg/tree.c | 232 | ||||
-rw-r--r-- | src/data/textfile/Makefile.am | 4 | ||||
-rw-r--r-- | src/data/textfile/textfile.c | 355 | ||||
-rw-r--r-- | src/data/textfile/textfile.h | 28 |
14 files changed, 4116 insertions, 0 deletions
diff --git a/src/data/Makefile.am b/src/data/Makefile.am new file mode 100644 index 00000000..35a11357 --- /dev/null +++ b/src/data/Makefile.am @@ -0,0 +1 @@ +SUBDIRS=mg textfile garmin_img diff --git a/src/data/garmin_img/Makefile.am b/src/data/garmin_img/Makefile.am new file mode 100644 index 00000000..7fb84323 --- /dev/null +++ b/src/data/garmin_img/Makefile.am @@ -0,0 +1,4 @@ +include $(top_srcdir)/Makefile.inc +AM_CPPFLAGS = @NAVIT_CFLAGS@ -I../.. +plugin_LTLIBRARIES = libdata_garmin_img.la +libdata_garmin_img_la_SOURCES = garmin_img.c diff --git a/src/data/garmin_img/garmin_img.c b/src/data/garmin_img/garmin_img.c new file mode 100644 index 00000000..86b03ca1 --- /dev/null +++ b/src/data/garmin_img/garmin_img.c @@ -0,0 +1,1486 @@ +#include <glib.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <math.h> +#include "plugin.h" +#include "data.h" +#include "map.h" +#include "maptype.h" +#include "item.h" +#include "attr.h" +#include "coord.h" +#include "transform.h" +#include "projection.h" +#include <stdio.h> +#include "attr.h" +#include "coord.h" + +struct file { + FILE *f; + int offset; +}; + + +int shift=5; +int subdiv_next=0x10; + + +static void * +file_read(struct file *f, int offset, int size) +{ + void *ptr; + int ret; + + ptr=calloc(size, 1); + if (! ptr) + return ptr; + fseek(f->f, f->offset+offset, SEEK_SET); + ret=fread(ptr, size, 1, f->f); + if (ret != 1) { + printf("fread %d vs %d offset %d+%d(0x%x)\n", ret, size, f->offset, offset,offset); + g_assert(1==0); + } + return ptr; +} + +static void +file_free(void *ptr) +{ + free(ptr); +} + +struct offset_len { + int offset; + int length; +} __attribute ((packed)); + +static void +dump_offset_len(struct offset_len *off_len) +{ + printf("offset: 0x%x(%d) length 0x%x(%d)\n", off_len->offset, off_len->offset, off_len->length, off_len->length); +} + +struct timestamp { + short creation_year; + char creation_month; + char creation_day; + char creation_hour; + char creation_minute; + char creation_second; +} __attribute__((packed)); + +struct img_header { + char xor; + char zero1[9]; + char update_month; + char update_year; + char zero2[3]; + char checksum[1]; + char signature[7]; + char unknown1[1]; + char unknown2[2]; + char unknown3[2]; + char unknown4[2]; + char unknown5[2]; + char zero3[25]; + struct timestamp ts; + char unknown6; + char map_file_identifier[7]; + char unknown12; + char map_description1[20]; + short unknown13; + short unknown14; + char e1; + char e2; + char other[413]; + char zero4[512]; + char unknown7; + char unknown8[11]; + int file_offset; + char unknown9; + char unknown10[15]; + char unknown11[480]; +} __attribute__((packed)); + +static void +dump_ts(struct timestamp *ts) +{ + printf("%d-%02d-%02d %02d:%02d:%02d\n", ts->creation_year, ts->creation_month, ts->creation_day, ts->creation_hour, ts->creation_minute, ts->creation_second); +} + +#if 0 +static void +dump_img(struct img_header *img_hdr) +{ + printf("signature: '%s'\n", img_hdr->signature); + printf("creation: "); + dump_ts(&img_hdr->ts); + printf("map_file_identifier: '%s'\n", img_hdr->map_file_identifier); + printf("file_offset: 0x%x\n", img_hdr->file_offset); + printf("e1: 0x%x(%d)\n", img_hdr->e1, img_hdr->e1); + printf("e2: 0x%x(%d)\n", img_hdr->e2, img_hdr->e2); + printf("offset 0x%x\n", (int) &img_hdr->e1 - (int) img_hdr); + printf("size %d\n", sizeof(*img_hdr)); +} +#endif + +struct fat_block { + char flag; + char filename[8]; + char type[3]; + int size; + char zero1; + char part; + char zero[14]; + unsigned short blocks[240]; +} __attribute__((packed)); + +#if 0 +static void +dump_fat_block(struct fat_block *fat_blk) +{ + int i=0; + char name[9]; + char type[4]; + printf("flag: 0x%x(%d)\n", fat_blk->flag, fat_blk->flag); + strcpy(name, fat_blk->filename); + name[8]='\0'; + strcpy(type, fat_blk->type); + type[3]='\0'; + printf("name: '%s.%s'\n", name, type); + printf("size: 0x%x(%d)\n", fat_blk->size, fat_blk->size); + printf("part: 0x%x(%d)\n", fat_blk->part, fat_blk->part); + printf("blocks: "); + while (i < 240) { + printf("0x%x(%d) ",fat_blk->blocks[i], fat_blk->blocks[i]); + if (fat_blk->blocks[i] == 0xffff) + break; + i++; + } + printf("size: %d\n", sizeof(*fat_blk)); + +} +#endif + +struct file_header { + short header_len; + char type[10]; + char unknown1; + char unknown2; + struct timestamp ts; +} __attribute__((packed)); + +static void +dump_file(struct file_header *fil_hdr) +{ + printf("header_len: %d\n", fil_hdr->header_len); + printf("type: '%s'\n", fil_hdr->type); + printf("unknown1: 0x%x(%d)\n", fil_hdr->unknown1, fil_hdr->unknown1); + printf("unknown2: 0x%x(%d)\n", fil_hdr->unknown2, fil_hdr->unknown2); + printf("creation: "); + dump_ts(&fil_hdr->ts); + printf("size %d\n", sizeof(*fil_hdr)); +} + +struct region_header { + struct file_header fil_hdr; + struct offset_len offset_len; +} __attribute__((packed)); + +#if 0 +static void +dump_region(struct region_header *rgn_hdr) +{ + dump_offset_len(&rgn_hdr->offset_len); +} +#endif + +struct map_priv { + int id; + char *filename; +}; + +struct map_rect_priv { + struct coord_rect r; + int limit; + + struct file tre; + struct tree_header *tre_hdr; + struct file rgn; + struct region_header *rgn_hdr; + struct file lbl; + struct label_header *lbl_hdr; + char *label; + + int subdiv_level_count; + int subdiv_pos; + char *subdiv; + + int rgn_offset; + int rgn_end; + struct rgn_point *pnt; + struct rgn_poly *ply; + unsigned char *ply_data; + int ply_bitpos; + int ply_bitcount; + int ply_lngbits; + int ply_latbits; + int ply_lng; + int ply_lat; + int ply_lnglimit; + int ply_latlimit; + int ply_lngsign; + int ply_latsign; + struct offset_len rgn_items[4]; + int rgn_type; + + int count; + + FILE *f; + long pos; + char line[256]; + int attr_pos; + enum attr_type attr_last; + char attrs[256]; + char attr[256]; + double lat,lng; + char lat_c,lng_c; + int eoc; + struct map_priv *m; + struct item item; +}; + +static int map_id; + +static int +contains_coord(char *line) +{ + return g_ascii_isdigit(line[0]); +} + +static int debug=1; + +static int +get_tag(char *line, char *name, int *pos, char *ret) +{ + int len,quoted; + char *p,*e,*n; + + if (debug) + printf("get_tag %s from %s\n", name, line); + if (! name) + return 0; + len=strlen(name); + if (pos) + p=line+*pos; + else + p=line; + for(;;) { + while (*p == ' ') { + p++; + } + if (! *p) + return 0; + n=p; + e=index(p,'='); + if (! e) + return 0; + p=e+1; + quoted=0; + while (*p) { + if (*p == ' ' && !quoted) + break; + if (*p == '"') + quoted=1-quoted; + p++; + } + if (e-n == len && !strncmp(n, name, len)) { + e++; + len=p-e; + if (e[0] == '"') { + e++; + len-=2; + } + strncpy(ret, e, len); + ret[len]='\0'; + if (pos) + *pos=p-line; + return 1; + } + } + return 0; +} + +static void +get_line(struct map_rect_priv *mr) +{ + mr->pos=ftell(mr->f); + fgets(mr->line, 256, mr->f); +} + +static void +map_destroy_garmin_img(struct map_priv *m) +{ + if (debug) + printf("map_destroy_garmin_img\n"); + g_free(m); +} + +static char * +map_charset_garmin_img(struct map_priv *m) +{ + return "iso8859-1"; +} + +static enum projection +map_projection_garmin_img(struct map_priv *m) +{ + return projection_garmin; +} + +struct label_data_offset { + struct offset_len offset_len; + char multiplier; + char data; +} __attribute ((packed)); + +#if 0 +static void +dump_label_data_offset(struct label_data_offset *lbl_dat) +{ + dump_offset_len(&lbl_dat->offset_len); + printf("multiplier 0x%x(%d)\n", lbl_dat->multiplier, lbl_dat->multiplier); + printf("data 0x%x(%d)\n", lbl_dat->data, lbl_dat->data); +} +#endif + +struct label_data { + struct offset_len offset_len; + short size; + int zero; +} __attribute ((packed)); + +static void +dump_label_data(struct label_data *lbl_dat) +{ + dump_offset_len(&lbl_dat->offset_len); + printf("size 0x%x(%d)\n", lbl_dat->size, lbl_dat->size); +} + +struct tree_header { + struct file_header fil_hdr; + char boundary[12]; + struct offset_len level; + struct offset_len subdivision; + struct label_data copyright; + struct offset_len tre7; + short unknown1; + char zero1; + struct label_data polyline; + struct label_data polygon; + struct label_data point; + int mapid; +}; + +static void +dump_tree_header(struct tree_header *tre_hdr) +{ + printf("tree_header:\n"); + dump_file(&tre_hdr->fil_hdr); + printf("level: "); dump_offset_len(&tre_hdr->level); + printf("subdivision: "); dump_offset_len(&tre_hdr->subdivision); + printf("copyright: "); dump_label_data(&tre_hdr->copyright); + printf("polyline: "); dump_label_data(&tre_hdr->polyline); + printf("polygon: "); dump_label_data(&tre_hdr->polygon); + printf("point: "); dump_label_data(&tre_hdr->point); + printf("len: 0x%x(%d)\n", sizeof(*tre_hdr), sizeof(*tre_hdr)); +} + +struct label_header { + struct file_header fil_hdr; + struct label_data_offset label; + struct label_data country; + struct label_data region; + struct label_data city; + struct label_data poi_index; + struct label_data_offset poi_properties; + short zero1; + char zero2; + struct label_data poi_types; + struct label_data zip; + struct label_data hway; + struct label_data exit; + struct label_data hway_data; + int unknown1; + short unknown2; + struct offset_len sort_descriptor; + struct label_data lbl13; + struct label_data lbl14; +} __attribute((packed)); + +#if 0 +static void +dump_label(struct label_header *lbl_hdr) +{ + dump_file(&lbl_hdr->fil_hdr); + printf("label:\n"); + dump_label_data_offset(&lbl_hdr->label); + printf("country:\n"); + dump_label_data(&lbl_hdr->country); + printf("region:\n"); + dump_label_data(&lbl_hdr->region); + printf("city:\n"); + dump_label_data(&lbl_hdr->city); + printf("poi_index:\n"); + dump_label_data(&lbl_hdr->poi_index); + printf("poi_properties:\n"); + dump_label_data_offset(&lbl_hdr->poi_properties); + printf("poi_types:\n"); + dump_label_data(&lbl_hdr->poi_types); + printf("zip:\n"); + dump_label_data(&lbl_hdr->zip); + printf("hway:\n"); + dump_label_data(&lbl_hdr->hway); + printf("exit:\n"); + dump_label_data(&lbl_hdr->exit); + printf("hway_data:\n"); + dump_label_data(&lbl_hdr->hway_data); + printf("lbl13:\n"); + dump_label_data(&lbl_hdr->lbl13); + printf("lbl14:\n"); + dump_label_data(&lbl_hdr->lbl14); + printf("len: 0x%x(%d)\n", sizeof(*lbl_hdr), sizeof(*lbl_hdr)); +} +#endif + +struct triple { + unsigned char data[3]; +} __attribute((packed)); + +static unsigned int +triple_u(struct triple *t) +{ + return t->data[0] | (t->data[1] << 8) | (t->data[2] << 16); +} + +static int +triple(struct triple *t) +{ + int ret=t->data[0] | (t->data[1] << 8) | (t->data[2] << 16); + if (ret > 1<<23) + ret=ret-(1<<24); + return ret; +} + +static void +dump_triple_u(struct triple *t) +{ + int val=triple_u(t); + printf("0x%x(%d)\n", val, val); +} + +struct tcoord { + struct triple lng,lat; +} __attribute((packed)); + +static void +dump_tcoord(struct tcoord *t) +{ + printf ("0x%x(%d),0x%x(%d)\n", triple_u(&t->lng), triple_u(&t->lng), triple_u(&t->lat), triple_u(&t->lat)); +} + +struct level { + unsigned char zoom; + unsigned char bits_per_coord; + unsigned short subdivisions; +} __attribute((packed)); + +static void +dump_level(struct level *lvl) +{ + printf("level:\n"); + printf("\tzoom 0x%x(%d)\n", lvl->zoom, lvl->zoom); + printf("\tbits_per_coord 0x%x(%d)\n", lvl->bits_per_coord, lvl->bits_per_coord); + printf("\tsubdivisions 0x%x(%d)\n", lvl->subdivisions, lvl->subdivisions); +} + +struct subdivision { + struct triple rgn_offset; + unsigned char types; + struct tcoord center; + unsigned short width; + unsigned short height; + unsigned short next; +} __attribute((packed)); + +static void +dump_subdivision(struct subdivision *sub) +{ + printf("subdivision:\n"); + printf("\trgn_offset: "); dump_triple_u(&sub->rgn_offset); + printf("\ttypes: 0x%x(%d)\n", sub->types, sub->types); + printf("\tcenter: "); dump_tcoord(&sub->center); + printf("\tsize: 0x%x(%d)x0x%x(%d) %s\n",sub->width & 0x7fff, sub->width & 0x7fff, sub->height, sub->height, sub->width & 0x8000 ? "Terminating" : ""); + printf("\tnext: 0x%x(%d)\n",sub->next, sub->next); + + printf("\tlen: 0x%x(%d)\n", sizeof(*sub), sizeof(*sub)); +} + +struct rgn_point { + unsigned char info; + struct triple lbl_offset; + short lng_delta; + short lat_delta; + unsigned char subtype; +} __attribute((packed)); + +static void +dump_point(struct rgn_point *pnt) +{ + printf("point:\n"); + printf("\tinfo 0x%x(%d)\n", pnt->info, pnt->info); + printf("\tlbl_offset 0x%x(%d)\n", triple_u(&pnt->lbl_offset), triple_u(&pnt->lbl_offset)); + printf("\tlng_delta 0x%x(%d)\n", pnt->lng_delta, pnt->lng_delta); + printf("\tlat_delta 0x%x(%d)\n", pnt->lat_delta, pnt->lat_delta); + printf("\tsubtype 0x%x(%d)\n", pnt->subtype, pnt->subtype); + printf("\tlen: 0x%x(%d)\n", sizeof(*pnt), sizeof(*pnt)); +} + +struct rgn_poly { + unsigned char info; + struct triple lbl_offset; + short lng_delta; + short lat_delta; + union { + struct { + unsigned char bitstream_len; + unsigned char bitstream_info; + } __attribute((packed)) p1; + struct { + unsigned short bitstream_len; + unsigned char bitstream_info; + } __attribute((packed)) p2; + } __attribute((packed)) u; +} __attribute((packed)); + +static void +dump_poly(struct rgn_poly *ply) +{ + printf("poly:\n"); + printf("\tinfo 0x%x(%d)\n", ply->info, ply->info); + printf("\tlbl_offset 0x%x(%d)\n", triple_u(&ply->lbl_offset), triple_u(&ply->lbl_offset)); + printf("\tlng_delta 0x%x(%d)\n", ply->lng_delta, ply->lng_delta); + printf("\tlat_delta 0x%x(%d)\n", ply->lat_delta, ply->lat_delta); + if (ply->info & 0x80) { + printf("\tbitstream_len 0x%x(%d)\n", ply->u.p2.bitstream_len, ply->u.p2.bitstream_len); + printf("\tbitstream_info 0x%x(%d)\n", ply->u.p2.bitstream_info, ply->u.p2.bitstream_info); + } else { + printf("\tbitstream_len 0x%x(%d)\n", ply->u.p1.bitstream_len, ply->u.p1.bitstream_len); + printf("\tbitstream_info 0x%x(%d)\n", ply->u.p1.bitstream_info, ply->u.p1.bitstream_info); + } + printf("\tlen: 0x%x(%d)\n", sizeof(*ply), sizeof(*ply)); +} + +static void +dump_hex(void *ptr, int len) +{ + unsigned char *c=ptr; + while (len--) { + printf("%02x ", *c++); + } + printf("\n"); +} + +static void +dump_hex_r(void *ptr, int len, int rec) +{ + unsigned char *c=ptr; + int l=rec; + while (len--) { + printf("%02x ", *c++); + if (! --l) { + printf("\n"); + l=rec; + } + } + printf("\n"); +} + +#if 0 +static void +dump_label_offset(struct map_rect_priv *mr, int offset) +{ + void *p; + p=file_read(&mr->lbl, mr->lbl_hdr->label.offset_len.offset+offset, 128); + printf("%s\n", (char *)p); +} +#endif + + +#if 0 +static void +dump_region_item(struct subdivision *sub, struct file *rgn, struct map_rect_priv *mr) +{ + int offset,item_offset,i,j; + unsigned short count=0; + unsigned short *offsets[4]; + unsigned short *file_offsets; + struct rgn_point *pnt; + + offset=triple_u(&sub->rgn_offset)+mr->rgn_hdr->offset_len.offset; + file_offsets=file_read(rgn, offset, 90*sizeof(unsigned short)); + printf("0x%x ", offset); dump_hex(file_offsets, 90); + for (i=0 ; i < 4 ; i++) { + printf("i=%d\n", i); + if (sub->types & (0x10 << i)) { + if (count) { + offsets[i]=&file_offsets[count-1]; + } else + offsets[i]=&count; + count++; + } else + offsets[i]=NULL; + + } + count--; + count*=2; + for (i=0 ; i < 4 ; i++) { + printf("i=%d\n", i); + if (offsets[i]) { + printf("offset[%d]=0x%x(%d)\n", i, *offsets[i], *offsets[i]); + switch (i) { + case 0: + printf("point\n"); + break; + case 1: + printf("indexed point\n"); + break; + case 2: + printf("polyline\n"); + break; + case 3: + printf("polygon\n"); + break; + } + item_offset=offset+*offsets[i]; + switch (i) { + case 0: + case 1: + for (j = 0 ; j < 10 ; j++) { + struct coord_geo g; + char buffer[1024]; + double conv=180.0/(1UL<<23); + pnt=file_read(rgn, item_offset, sizeof(*pnt)*20); + // printf("0x%x ", item_offset); dump_hex(pnt, 32); + dump_point(pnt); + g.lng=(triple(&sub->center.lng)+(pnt->lng_delta << shift))*conv; + g.lat=(triple(&sub->center.lat)+(pnt->lat_delta << shift))*conv; + printf("%f %f\n", g.lng, g.lat); + transform_geo_text(&g, buffer); + printf("%s\n", buffer); + dump_label_offset(mr, triple_u(&pnt->lbl_offset)); + if (pnt->info & 0x80) + item_offset+=sizeof(*pnt); + else + item_offset+=sizeof(*pnt)-1; + } + } + } else { + printf("offset[%d] doesn't exist\n", i); + } + } + file_free(file_offsets); +} + +#endif + +static void +dump_levels(struct map_rect_priv *mr) +{ + int i,offset; + struct level *lvl; + + offset=mr->tre_hdr->level.offset; + for (i = 0 ; i < mr->tre_hdr->level.length/sizeof(*lvl) ; i++) { + lvl=file_read(&mr->tre, offset, sizeof(*lvl)); + dump_level(lvl); + offset+=sizeof(*lvl); + } +} + +#if 0 +static void +dump_tree(struct file *f, struct file *rgn, struct map_rect_priv *mr) +{ + struct tree_header *tre_hdr; + struct subdivision *sub; + int i,offset; + + tre_hdr=file_read(f, 0, sizeof(*tre_hdr)); + dump_tree_header(tre_hdr); + offset=tre_hdr->subdivision.offset; + sub=file_read(f, offset, sizeof(*sub)); + dump_subdivision(sub); + offset+=sizeof(*sub); + for (i = 1 ; i < tre_hdr->subdivision.length/sizeof(*sub) ; i++) { + printf("i=%d\n", i); + sub=file_read(f, offset, sizeof(*sub)); + dump_subdivision(sub); + dump_region_item(sub, rgn, mr); + if (sub->width & 0x8000) + break; + offset+=sizeof(*sub); + } + file_free(tre_hdr); +} +#endif + +#if 0 +static void +dump_labels(struct file *f) +{ + struct label_header *lbl_hdr; + + lbl_hdr=file_read(f, 0, sizeof(*lbl_hdr)); + printf("**labels**\n"); + dump_label(lbl_hdr); + file_free(lbl_hdr); +#if 0 + labels=alloca(lbl_hdr.label_length); + file_read(f, lbl_hdr.label_offset, labels, lbl_hdr.label_length); + l=labels; + while (l < labels+lbl_hdr.label_length) { + printf("'%s'(%d)\n", l, strlen(l)); + l+=strlen(l)+1; + } +#endif + +} +#endif + +static void +garmin_img_coord_rewind(void *priv_data) +{ +} + +static void +parse_line(struct map_rect_priv *mr) +{ + int pos=0; + sscanf(mr->line,"%lf %c %lf %c %n",&mr->lat,&mr->lat_c,&mr->lng,&mr->lng_c,&pos); + if (pos < strlen(mr->line)) { + strcpy(mr->attrs, mr->line+pos); + } +} + +static int +get_bits(struct map_rect_priv *mr, int bits) +{ + unsigned long ret; + ret=L(*((unsigned long *)(mr->ply_data+mr->ply_bitpos/8))); + ret >>= (mr->ply_bitpos & 7); + ret &= (1 << bits)-1; + mr->ply_bitpos+=bits; + return ret; +} + +static int +garmin_img_coord_get(void *priv_data, struct coord *c, int count) +{ + struct map_rect_priv *mr=priv_data; + struct subdivision *sub=(struct subdivision *)(mr->subdiv+mr->subdiv_pos); + int ret=0; + int debug=0; + if (debug) + printf("garmin_img_coord_get %d\n",count); + if (debug) + dump_subdivision(sub); + while (count--) { + if (mr->rgn_type < 2) { + c->x=triple(&sub->center.lng)+(mr->pnt->lng_delta << shift); + c->y=triple(&sub->center.lat)+(mr->pnt->lat_delta << shift); + } else { + if (! mr->ply_bitpos) { + if (mr->ply->info & 0x80) { + mr->ply_bitcount=mr->ply->u.p2.bitstream_len*8; + mr->ply_lngbits=mr->ply->u.p2.bitstream_info & 0xf; + mr->ply_latbits=mr->ply->u.p2.bitstream_info >> 4; + } else { + mr->ply_bitcount=mr->ply->u.p1.bitstream_len*8; + mr->ply_lngbits=mr->ply->u.p1.bitstream_info & 0xf; + mr->ply_latbits=mr->ply->u.p1.bitstream_info >> 4; + } + if (mr->ply_lngbits <= 9) + mr->ply_lngbits+=2; + if (mr->ply_latbits <= 9) + mr->ply_latbits+=2; + if (! get_bits(mr,1)) { + mr->ply_lngbits+=1; + mr->ply_lngsign=0; + } else + if (get_bits(mr, 1)) + mr->ply_lngsign=-1; + else + mr->ply_lngsign=1; + if (! get_bits(mr,1)) { + mr->ply_latbits+=1; + mr->ply_latsign=0; + } else + if (get_bits(mr, 1)) + mr->ply_latsign=-1; + else + mr->ply_latsign=1; + mr->ply_lnglimit=1 << (mr->ply_lngbits-1); + mr->ply_latlimit=1 << (mr->ply_latbits-1); + mr->ply_lng=mr->ply->lng_delta; + mr->ply_lat=mr->ply->lat_delta; + if (debug) + printf("lngbits %d latbits %d bitcount %d\n", mr->ply_lngbits, mr->ply_latbits, mr->ply_bitcount); + c->x=0; + c->y=0; + } else { + if (mr->ply_bitpos + mr->ply_lngbits + mr->ply_latbits > mr->ply_bitcount) { + if (debug) + printf("out of bits %d + %d + %d >= %d\n", mr->ply_bitpos, mr->ply_lngbits, mr->ply_latbits, mr->ply_bitcount); + return ret; + } + c->x=0; + c->y=0; + int x,y; + for (;;) { + x=get_bits(mr,mr->ply_lngbits); + if (debug) + printf("x %d ", x); + if (mr->ply_lngsign || x != mr->ply_lnglimit) + break; + c->x += x-1; + } + if (mr->ply_lngsign) { + c->x=x*mr->ply_lngsign; + } else { + if (x >= mr->ply_lnglimit) + c->x = x - (mr->ply_lnglimit << 1) - c->x; + else + c->x +=x; + } + for (;;) { + y=get_bits(mr,mr->ply_latbits); + if (debug) + printf("y %d ", y); + if (mr->ply_latsign || y != mr->ply_latlimit) + break; + c->y += y-1; + } + if (mr->ply_latsign) { + c->y=y*mr->ply_latsign; + } else { + if (y >= mr->ply_latlimit) + c->y = y - (mr->ply_latlimit << 1) - c->y; + else + c->y +=y; + } + mr->ply_lng += c->x; + mr->ply_lat += c->y; + } + if (debug) + printf(": x %d y %d\n", c->x, c->y); + + c->x=triple(&sub->center.lng)+(mr->ply_lng << shift); + c->y=triple(&sub->center.lat)+(mr->ply_lat << shift); + } +#if 0 + c->x-=0x6f160; + c->y-=0x181f59; + c->x+=0x168ca1; + c->y+=0x68d815; +#endif + c++; + ret++; + if (mr->rgn_type < 2) + return ret; + } + return ret; +} + +static char * +get_label_offset(struct map_rect_priv *mr, int offset) +{ + g_assert(offset < mr->lbl_hdr->label.offset_len.length); + return file_read(&mr->lbl, mr->lbl_hdr->label.offset_len.offset+offset, 128); +} + +static void +garmin_img_attr_rewind(void *priv_data) +{ +} + +static int +garmin_img_attr_get(void *priv_data, enum attr_type attr_type, struct attr *attr) +{ + struct map_rect_priv *mr=priv_data; + int debug=0; + + if (debug) + printf("garmin_img_attr_get\n"); + if (attr_type == attr_label) { + if (debug) + printf("garmin_img_attr_get label\n"); + attr->type=attr_type; + if (mr->rgn_type < 2) { + if (mr->label) + file_free(mr->label); + mr->label=get_label_offset(mr, triple_u(&mr->pnt->lbl_offset) & 0x3fffff); + attr->u.str=mr->label; + } else { + attr->u.str=""; + } + return 1; + } + return 0; +} + +static struct item_methods methods_garmin_img = { + garmin_img_coord_rewind, + garmin_img_coord_get, + garmin_img_attr_rewind, + garmin_img_attr_get, +}; + +static int rgn_next_type(struct map_rect_priv *mr) +{ + while (mr->rgn_type < 3) { + mr->rgn_type++; + if (mr->rgn_items[mr->rgn_type].offset && mr->rgn_items[mr->rgn_type].length != 0) { + mr->rgn_offset=mr->rgn_items[mr->rgn_type].offset; + mr->rgn_end=mr->rgn_offset+mr->rgn_items[mr->rgn_type].length; + return 0; + } + } + return 1; +} + +static int +sub_next(struct map_rect_priv *mr, int next) +{ + int i,offset,first=-1,last=-1,count=-1; + int end; + unsigned short *offsets; + int debug=0; + + if (mr->subdiv_level_count <= 0) + return 1; + if (debug) + printf("%d left\n", mr->subdiv_level_count); + mr->subdiv_level_count--; + +#if 0 + if (next && mr->subdiv[mr->subdiv_current].width & 0x8000) + return 1; +#endif + if (debug) + dump_hex_r(mr->subdiv+mr->subdiv_pos, 64, 14); + mr->subdiv_pos+=next; + if (debug) + printf("subdiv_pos 0x%x\n", mr->subdiv_pos); + if (mr->subdiv_pos > mr->tre_hdr->subdivision.length) + return 1; + struct subdivision *sub=(struct subdivision *)(mr->subdiv+mr->subdiv_pos); + offset=triple_u(&sub->rgn_offset)+mr->rgn_hdr->offset_len.offset; + if (debug) { + printf("offset=0x%x\n", offset); + dump_subdivision(sub); + } + offsets=file_read(&mr->rgn, offset, 3*sizeof(unsigned short)); + + if (! next) + next=subdiv_next; + if (mr->subdiv_pos+next < mr->tre_hdr->subdivision.length) + end=triple_u(&((struct subdivision *)(mr->subdiv+mr->subdiv_pos+next))->rgn_offset)+mr->rgn_hdr->offset_len.offset; + else + end=mr->rgn_hdr->offset_len.offset+mr->rgn_hdr->offset_len.length; + if (debug) { + dump_subdivision(sub); + dump_hex(offsets, 6); + } + for (i=0 ; i < 4 ; i++) { + if (debug) + printf("i=%d ", i); + if (sub->types & (0x10 << i)) { + if (debug) + printf("+ "); + if (first == -1) { + first=i; + mr->rgn_items[i].offset=offset; + if (debug) + printf("\n"); + } else { + mr->rgn_items[i].offset=offset+offsets[count]; + if (debug) + printf("0x%x\n", offsets[count]); + mr->rgn_items[last].length=mr->rgn_items[i].offset-mr->rgn_items[last].offset; + } + last=i; + count++; + } else { + if (debug) + printf("-\n"); + mr->rgn_items[i].offset=0; + mr->rgn_items[i].length=0; + } + + } + if (first != -1) { + mr->rgn_items[first].offset+=count*2; + mr->rgn_items[first].length-=count*2; + mr->rgn_items[last].length=end-mr->rgn_items[last].offset; + } + if (debug) { + for (i=0 ; i < 4 ; i++) { + printf("%d 0x%x 0x%x\n", i, mr->rgn_items[i].offset, mr->rgn_items[i].length); + } + } + mr->rgn_type=-1; + rgn_next_type(mr); + if (debug) + printf("*** offset 0x%x\n", mr->rgn_offset); + file_free(offsets); + return 0; +} + +int item_count; + +static struct map_rect_priv * +map_rect_new_garmin_img(struct map_priv *map, struct coord_rect *r, struct layer *layers, int limit) +{ + struct map_rect_priv *mr; + struct img_header img; + + if (debug) + printf("map_rect_new_garmin_img\n"); + mr=g_new0(struct map_rect_priv, 1); + mr->m=map; + if (r) + mr->r=*r; + mr->limit=limit; + mr->item.id_hi=0; + mr->item.id_lo=0; + mr->item.meth=&methods_garmin_img; + mr->item.priv_data=mr; + mr->f=fopen(map->filename, "r"); + + fread(&img, sizeof(img), 1, mr->f); +#if 0 + dump_img(&img); + for (i = 0 ; i < (img.file_offset-sizeof(img))/sizeof(fat_blk) ; i++) { + fread(&fat_blk, sizeof(fat_blk), 1, mr->f); + if (!fat_blk.flag) + break; + dump_fat_block(&fat_blk); + } +#endif + mr->rgn.offset=0xa*2048; + mr->rgn.f=mr->f; + mr->rgn_hdr=file_read(&mr->rgn, 0, sizeof(*mr->rgn_hdr)); + + mr->tre.offset=0x62b*2048; + mr->tre.f=mr->f; + mr->tre_hdr=file_read(&mr->tre, 0, sizeof(*mr->tre_hdr)); + + mr->lbl.offset=0x64a*2048; + mr->lbl.f=mr->f; + mr->lbl_hdr=file_read(&mr->lbl, 0, sizeof(*mr->lbl_hdr)); + + mr->subdiv=file_read(&mr->tre, mr->tre_hdr->subdivision.offset, mr->tre_hdr->subdivision.length); +#if 0 + dump_hex_r(mr->subdiv, mr->tre_hdr->subdivision.length, 16); +#endif + dump_tree_header(mr->tre_hdr); + + dump_levels(mr); + + + printf("limit=%d\n", limit); + if (limit < 3) { + mr->subdiv_pos=0; + mr->subdiv_level_count=1; + shift=11; + } else if (limit < 6) { + mr->subdiv_pos=1*sizeof(struct subdivision); + mr->subdiv_level_count=5; + shift=9; + } else if (limit < 8) { + mr->subdiv_pos=6*sizeof(struct subdivision); + mr->subdiv_level_count=9; + shift=7; + } else if (limit < 10) { + mr->subdiv_pos=15*sizeof(struct subdivision); + mr->subdiv_level_count=143; + shift=5; + } else { + mr->subdiv_pos=158*sizeof(struct subdivision); + mr->subdiv_level_count=4190; + shift=2; + subdiv_next=14; + } + +#if 0 + mr->rgn_offset=triple_u(&mr->subdiv[mr->subdiv_current].rgn_offset)+mr->rgn_hdr->offset_len.offset+4; + mr->rgn_type=1; + mr->rgn_end=mr->rgn_offset+20*8; +#endif + mr->count=0; + item_count=0; + +#if 0 + printf("*** offset 0x%x\n", 0x656c-mr->rgn.offset); + printf("*** offset 0x%x\n", mr->rgn_offset); +#endif +#if 1 + sub_next(mr, 0); +#endif +#if 0 + { + struct rgn_point *pnt; + int i; + int offset=0x65cc; + for (i = 0 ; i < 26 ; i++) { + pnt=file_read(&mr->rgn, 0x656c+8*i-mr->rgn.offset, sizeof(*pnt)); + // dump_hex(pnt, sizeof(*pnt)); + dump_point(pnt); + dump_label_offset(mr, triple_u(&pnt->lbl_offset)); + } + } + exit(0); +#endif +#if 0 + dump_tree(&mr->tre,&mr->rgn,mr); +#endif + +#if 0 + f.offset=0x64a*2048; + f.f=mr->f; + dump_labels(&f); +#endif +#if 0 + fseek(mr->f, img.file_offset, SEEK_SET); + fread(&fil, sizeof(fil), 1, mr->f); + dump_file(&fil); + fread(&rgn, sizeof(rgn), 1, mr->f); + dump_region(&rgn); + fseek(mr->f, rgn.data_length, SEEK_CUR); + fread(&fil, sizeof(fil), 1, mr->f); + dump_file(&fil); +#endif + return mr; +} + + +static void +map_rect_destroy_garmin_img(struct map_rect_priv *mr) +{ + fclose(mr->f); + g_free(mr); +} + + +static struct item * +map_rect_get_item_garmin_img(struct map_rect_priv *mr) +{ + char *p,type[256]; + int ptype; + int debug=0; + + item_count++; + + if (debug) + printf("map_rect_get_item_garmin_img\n"); + for (;;) { + if (mr->rgn_offset < mr->rgn_end) { + if (debug) + printf("data available\n"); + if (mr->rgn_type >= 2) { + int len; + if (debug) + printf("polyline %d\n", mr->count); + if (mr->ply) + file_free(mr->ply); + mr->ply=file_read(&mr->rgn, mr->rgn_offset, sizeof(*mr->ply)*3); + if(triple_u(&mr->ply->lbl_offset) >= mr->lbl_hdr->label.offset_len.length) { + printf("item_count %d\n", item_count); + dump_poly(mr->ply); + dump_hex(mr->ply, 32); + printf("%d vs %d\n", triple_u(&mr->ply->lbl_offset), mr->lbl_hdr->label.offset_len.length); + } + g_assert(triple_u(&mr->ply->lbl_offset) < mr->lbl_hdr->label.offset_len.length); + if (debug) { + dump_hex(mr->ply, 16); + dump_poly(mr->ply); + } + if (mr->ply_data) + file_free(mr->ply_data); + mr->rgn_offset+=10; + if (mr->ply->info & 0x80) { + mr->rgn_offset++; + len=mr->ply->u.p2.bitstream_len; + } else + len=mr->ply->u.p1.bitstream_len; + + mr->ply_data=file_read(&mr->rgn, mr->rgn_offset, len); + mr->rgn_offset += len; + mr->ply_bitpos=0; + // dump_hex(mr->ply_data, 32); + if (mr->rgn_type == 3) { + switch(mr->ply->info & 0x7f) { + case 0x1: /* large urban area (>200k) */ + mr->item.type=type_town_poly; + break; + case 0xd: /* reservation */ + mr->item.type=type_park_poly; + break; + case 0xe: /* airport runway */ + mr->item.type=type_airport_poly; + break; + case 0x14: /* national park */ + mr->item.type=type_park_poly; + break; + case 0x32: /* sea */ + case 0x3d: /* large lake (77-250km2) */ + case 0x4c: /* intermittend water */ + mr->item.type=type_water_poly; + break; + case 0x4b: /* background */ + continue; + default: + printf("unknown polygon: 0x%x\n", mr->ply->info); + mr->item.type=type_street_3_city; + } + } else { + switch(mr->ply->info & 0x3f) { + case 0x1: /* major highway */ + mr->item.type=type_highway_land; + break; + case 0x2: /* principal highway */ + mr->item.type=type_street_3_land; + break; + case 0x6: /* residental street */ + mr->item.type=type_street_2_land; + break; + case 0x16: /* walkway/trail */ + mr->item.type=type_street_1_land; + break; + case 0x1e: /* international boundary */ + mr->item.type=type_border_country; + break; + case 0x20: /* minor land contour 1/10 */ + mr->item.type=type_height_line_1; + break; + case 0x21: /* major land contour 1/2 */ + mr->item.type=type_height_line_2; + break; + default: + printf("unknown polyline: 0x%x\n", mr->ply->info); + mr->item.type=type_street_3_city; + } + } + return &mr->item; + } + if (mr->pnt) + file_free(mr->pnt); + mr->pnt=file_read(&mr->rgn, mr->rgn_offset, sizeof(*mr->pnt)); + mr->item.type=type_none; + int subtype=mr->pnt->subtype; + if (mr->pnt->lbl_offset.data[2] & 0x80) + mr->rgn_offset+=9; + else { + mr->rgn_offset+=8; + subtype=0; + } + switch(mr->pnt->info) { + case 0x3: /* large city 2-5M */ + mr->item.type=type_town_label_2e6; + break; + case 0xa: /* small city/town 10-20k */ + mr->item.type=type_town_label_1e4; + break; + case 0xd: /* settlement 1-2K */ + mr->item.type=type_town_label_1e3; + break; + case 0x11: /* settlement less 100 */ + mr->item.type=type_town_label_5e1; + break; + case 0x1c: + switch(subtype) { + case 0x01: + mr->item.type=type_poi_wreck; + break; + } + break; + case 0x20: + mr->item.type=type_highway_exit; + break; + case 0x25: + mr->item.type=type_poi_toll_booth; + break; + case 0x2b: + switch(subtype) { + case 0x01: + mr->item.type=type_poi_hotel; + break; + case 0x03: + mr->item.type=type_poi_camp_rv; + break; + } + break; + case 0x2c: + switch(subtype) { + case 0x00: + mr->item.type=type_poi_attraction; + break; + case 0x02: + mr->item.type=type_poi_museum_history; + break; + } + break; + case 0x2e: + mr->item.type=type_poi_shopping; + break; + case 0x2f: + switch(subtype) { + case 0x01: + mr->item.type=type_poi_fuel; + break; + case 0x07: + mr->item.type=type_poi_car_dealer_parts; + break; + case 0x0b: + mr->item.type=type_poi_car_parking; + break; + case 0x15: + mr->item.type=type_poi_public_utilities; + break; + } + break; + case 0x30: + switch(subtype) { + case 0x02: + mr->item.type=type_poi_hospital; + break; + } + break; + case 0x43: + mr->item.type=type_poi_marina; + break; + case 0x46: + mr->item.type=type_poi_bar; + break; + case 0x48: + mr->item.type=type_poi_camping; + break; + case 0x49: + mr->item.type=type_poi_park; + break; + case 0x4a: + mr->item.type=type_poi_picnic; + break; + case 0x59: /* airport */ + mr->item.type=type_poi_airport; + break; + case 0x64: + switch(subtype) { + case 0x1: + mr->item.type=type_poi_bridge; + break; + case 0x2: + mr->item.type=type_poi_building; + break; + case 0x15: + mr->item.type=type_town_ghost; + break; + } + break; + case 0x65: + switch(subtype) { + case 0x0: + mr->item.type=type_poi_water_feature; + break; + case 0xc: + mr->item.type=type_poi_island; + break; + case 0xd: + mr->item.type=type_poi_lake; + break; + } + break; + case 0x66: + switch(subtype) { + case 0x0: + mr->item.type=type_poi_land_feature; + break; + case 0x6: + mr->item.type=type_poi_cape; + break; + case 0x14: + mr->item.type=type_poi_rock; + break; + } + break; + } + if (mr->item.type == type_none) { + printf("unknown point: 0x%x 0x%x\n", mr->pnt->info, mr->pnt->subtype); + dump_point(mr->pnt); + printf("label: %s\n", get_label_offset(mr, triple_u(&mr->pnt->lbl_offset) & 0x3fffff)); + mr->item.type=type_town_label; + } + return &mr->item; + } + if (debug) + printf("out of data for type\n"); + if (rgn_next_type(mr)) { + if (debug) + printf("out of data for region\n"); + if (sub_next(mr, subdiv_next)) { + if (debug) + printf("out of data for subdivision\n"); + return NULL; + } + } + } +} + +static struct item * +map_rect_get_item_byid_garmin_img(struct map_rect_priv *mr, int id_hi, int id_lo) +{ + fseek(mr->f, id_lo, SEEK_SET); + get_line(mr); + mr->item.id_hi=id_hi; + return map_rect_get_item_garmin_img(mr); +} + +static struct map_methods map_methods_garmin_img = { + map_destroy_garmin_img, + map_charset_garmin_img, + map_projection_garmin_img, + map_rect_new_garmin_img, + map_rect_destroy_garmin_img, + map_rect_get_item_garmin_img, + map_rect_get_item_byid_garmin_img, +}; + +static struct map_priv * +map_new_garmin_img(struct map_methods *meth, char *filename) +{ + struct map_priv *m; + *meth=map_methods_garmin_img; + m=g_new(struct map_priv, 1); + m->id=++map_id; + m->filename=g_strdup(filename); + return m; +} + +void +plugin_init(void) +{ + plugin_register_map_type("garmin_img", map_new_garmin_img); +} + diff --git a/src/data/mg/Makefile.am b/src/data/mg/Makefile.am new file mode 100644 index 00000000..65f0157e --- /dev/null +++ b/src/data/mg/Makefile.am @@ -0,0 +1,4 @@ +include $(top_srcdir)/Makefile.inc +AM_CPPFLAGS = @NAVIT_CFLAGS@ -I../.. -DMODULE=\"data_mg\" +plugin_LTLIBRARIES = libdata_mg.la +libdata_mg_la_SOURCES = map.c block.c town.c tree.c poly.c street.c mg.h diff --git a/src/data/mg/block.c b/src/data/mg/block.c new file mode 100644 index 00000000..93c2fb11 --- /dev/null +++ b/src/data/mg/block.c @@ -0,0 +1,261 @@ +#include <stdio.h> +#include <string.h> +#include "debug.h" +#include "mg.h" + + +int block_lin_count,block_idx_count,block_active_count,block_mem,block_active_mem; + +struct block_index_item { + unsigned long blocknum; + unsigned long blocks; +}; + +struct block_index { + unsigned long blocks; + unsigned long size; + unsigned long next; + struct block_index_item list[0]; +}; + +static struct block * +block_get(unsigned char **p) +{ + struct block *ret=(struct block *)(*p); + *p += sizeof(*ret); + return ret; +} + + +static struct block * +block_get_byid(struct file *file, int id, unsigned char **p_ret) +{ + struct block_index *blk_idx; + int blk_num,max; + + + blk_idx=(struct block_index *)(file->begin+0x1000); + max=(blk_idx->size-sizeof(struct block_index))/sizeof(struct block_index_item); + block_mem+=24; + while (id >= max) { + blk_idx=(struct block_index *)(file->begin+blk_idx->next*512); + id-=max; + } + blk_num=blk_idx->list[id].blocknum; + + *p_ret=file->begin+blk_num*512; + return block_get(p_ret); +} + +int +block_get_byindex(struct file *file, int idx, struct block_priv *blk) +{ + dbg(1,"idx=%d\n", idx); + blk->b=block_get_byid(file, idx, &blk->p); + blk->block_start=(unsigned char *)(blk->b); + blk->p_start=blk->p; + blk->end=blk->block_start+blk->b->size; + + return 1; +} + +static void +block_setup_tags(struct map_rect_priv *mr) +{ + int len; + unsigned char *p,*t; + char *str; + + mr->b.binarytree=0; + + p=mr->file->begin+0x0c; + while (*p) { + str=get_string(&p); + len=get_u32_unal(&p); + t=p; + /* printf("String '%s' len %d\n", str, len); */ + if (! strcmp(str,"FirstBatBlock")) { + /* printf("%ld\n", get_u32_unal(&t)); */ + } else if (! strcmp(str,"MaxBlockSize")) { + /* printf("%ld\n", get_u32_unal(&t)); */ + } else if (! strcmp(str,"FREE_BLOCK_LIST")) { + /* printf("%ld\n", get_u32_unal(&t)); */ + } else if (! strcmp(str,"TotalRect")) { + mr->b.b_rect.lu.x=get_u32_unal(&t); + mr->b.b_rect.lu.y=get_u32_unal(&t); + mr->b.b_rect.rl.x=get_u32_unal(&t); + mr->b.b_rect.rl.y=get_u32_unal(&t); + /* printf("0x%x,0x%x-0x%x,0x%x\n", mr->b.b_rect.lu.x, mr->b.b_rect.lu.y, mr->b.b_rect.rl.x, mr->b.b_rect.rl.y); */ + } else if (! strcmp(str,"Version")) { + /* printf("0x%lx\n", get_u32_unal(&t)); */ + } else if (! strcmp(str,"Categories")) { + /* printf("0x%x\n", get_u16(&t)); */ + } else if (! strcmp(str,"binaryTree")) { + mr->b.binarytree=get_u32_unal(&t); + /* printf("%d\n", mr->b.binarytree); */ + } else if (! strcmp(str,"CategorySets")) { + /* printf("0x%x\n", get_u16(&t)); */ + } else if (! strcmp(str,"Kommentar")) { + /* printf("%s\n", get_string(&t)); */ + } + p+=len; + } +} + +#if 0 +static void +block_rect_print(struct coord_rect *r) +{ + printf ("0x%x,0x%x-0x%x,0x%x (0x%x,0x%x)", r->lu.x, r->lu.y, r->rl.x, r->rl.y, r->lu.x/2+r->rl.x/2,r->lu.y/2+r->rl.y/2); +} +#endif + +static void +block_rect_same(struct coord_rect *r1, struct coord_rect *r2) +{ + g_assert(r1->lu.x==r2->lu.x); + g_assert(r1->lu.y==r2->lu.y); + g_assert(r1->rl.x==r2->rl.x); + g_assert(r1->rl.y==r2->rl.y); +} + +int +block_init(struct map_rect_priv *mr) +{ + mr->b.block_num=-1; + mr->b.bt.b=NULL; + mr->b.bt.next=0; + block_setup_tags(mr); + if (mr->b.binarytree) { + mr->b.bt.next=mr->b.binarytree; + mr->b.bt.p=NULL; + mr->b.bt.block_count=0; + } + if (mr->cur_sel && !coord_rect_overlap(&mr->cur_sel->rect, &mr->b.b_rect)) + return 0; + return block_next(mr); +} + + +int +block_next_lin(struct map_rect_priv *mr) +{ + for (;;) { + block_lin_count++; + block_mem+=sizeof(struct block *); + mr->b.block_num++; + if (! mr->b.block_num) + mr->b.p=mr->file->begin+0x2000; + else + mr->b.p=mr->b.block_start+mr->b.b->blocks*512; + if (mr->b.p >= mr->file->end) + return 0; + mr->b.block_start=mr->b.p; + mr->b.b=block_get(&mr->b.p); + mr->b.p_start=mr->b.p; + mr->b.end=mr->b.block_start+mr->b.b->size; + if (mr->b.b->count == -1) + return 0; + if (!mr->cur_sel || coord_rect_overlap(&mr->cur_sel->rect, &mr->b.b->r)) { + block_active_count++; + block_active_mem+=mr->b.b->blocks*512-sizeof(struct block *); + return 1; + } + } +} + +int +block_next(struct map_rect_priv *mr) +{ + int blk_num,coord,r_h,r_w; + struct block_bt_priv *bt=&mr->b.bt; + + if (!mr->b.binarytree || ! mr->cur_sel) + return block_next_lin(mr); + for (;;) { + if (! bt->p) { + dbg(1,"block 0x%x\n", bt->next); + if (bt->next == -1) + return 0; + bt->b=block_get_byid(mr->file, bt->next, &bt->p); + bt->end=(unsigned char *)mr->b.bt.b+mr->b.bt.b->size; + bt->next=bt->b->next; + bt->order=0; + dbg(1,"size 0x%x next 0x%x\n", bt->b->size, bt->b->next); + if (! mr->b.bt.block_count) { +#if 0 + if (debug) { + printf("idx rect "); + block_rect_print(&mr->b.bt.b->r); + } +#endif + bt->r=bt->b->r; + bt->r_curr=bt->r; + coord=get_u32(&mr->b.bt.p); + } else { + bt->p=(unsigned char *)bt->b+0xc; + } + bt->block_count++; + } + while (mr->b.bt.p < mr->b.bt.end) { + block_idx_count++; + blk_num=get_u32(&mr->b.bt.p); + coord=get_u32(&mr->b.bt.p); + block_mem+=8; + dbg(1,"%p vs %p coord 0x%x ", mr->b.bt.end, mr->b.bt.p, coord); + dbg(1,"block 0x%x", blk_num); + + r_w=bt->r_curr.rl.x-bt->r_curr.lu.x; + r_h=bt->r_curr.lu.y-bt->r_curr.rl.y; +#if 0 + if (debug) { + printf(" rect1 "); + block_rect_print(&bt->r_curr); + printf(" %dx%d", r_w, r_h); + } +#endif + mr->b.b=NULL; + if (blk_num != -1) { + block_mem+=8; + if (coord_rect_overlap(&mr->cur_sel->rect, &bt->r_curr)) { + mr->b.b=block_get_byid(mr->file, blk_num, &mr->b.p); + mr->b.block_num=blk_num; + g_assert(mr->b.b != NULL); + mr->b.block_start=(unsigned char *)(mr->b.b); + mr->b.p_start=mr->b.p; + mr->b.end=mr->b.block_start+mr->b.b->size; + block_rect_same(&mr->b.b->r, &bt->r_curr); + } + } + if (coord != -1) { + bt->stack[bt->stackp]=bt->r_curr; + if (r_w > r_h) { + bt->r_curr.rl.x=coord; + bt->stack[bt->stackp].lu.x=coord+1; + } else { + bt->r_curr.lu.y=coord; + bt->stack[bt->stackp].rl.y=coord+1; + } + bt->stackp++; + g_assert(bt->stackp < BT_STACK_SIZE); + } else { + if (bt->stackp) { + bt->stackp--; + bt->r_curr=bt->stack[bt->stackp]; + } else { + bt->r_curr=bt->r; + bt->order++; + if (bt->order > 100) + return 0; + } + } + if (mr->b.b) { + block_active_count++; + block_active_mem+=mr->b.b->blocks*512; + return 1; + } + } + bt->p=NULL; + } + return 0; +} diff --git a/src/data/mg/map.c b/src/data/mg/map.c new file mode 100644 index 00000000..20feb8f1 --- /dev/null +++ b/src/data/mg/map.c @@ -0,0 +1,296 @@ +#include <stdio.h> +#include <string.h> +#include "debug.h" +#include "plugin.h" +#include "maptype.h" +#include "projection.h" +#include "mg.h" + + +struct map_priv * map_new_mg(struct map_methods *meth, char *dirname, char **charset, enum projection *pro); + +static int map_id; + +static char *file[]={ + [file_border_ply]="border.ply", + [file_bridge_ply]="bridge.ply", + [file_build_ply]="build.ply", + [file_golf_ply]="golf.ply", + [file_height_ply]="height.ply", + [file_natpark_ply]="natpark.ply", + [file_nature_ply]="nature.ply", + [file_other_ply]="other.ply", + [file_rail_ply]="rail.ply", + [file_sea_ply]="sea.ply", + [file_street_bti]="street.bti", + [file_street_str]="street.str", + [file_strname_stn]="strname.stn", + [file_town_twn]="town.twn", + [file_tunnel_ply]="tunnel.ply", + [file_water_ply]="water.ply", + [file_woodland_ply]="woodland.ply", +}; + + +static int +file_next(struct map_rect_priv *mr) +{ + int debug=0; + enum layer_type layer; + + for (;;) { + mr->current_file++; + if (mr->current_file >= file_end) + return 0; + mr->file=mr->m->file[mr->current_file]; + if (! mr->file) + continue; + switch (mr->current_file) { + case file_strname_stn: + continue; + case file_town_twn: + layer=layer_town; + break; + case file_street_str: + layer=layer_street; + break; + default: + layer=layer_poly; + } + if (mr->cur_sel && !mr->cur_sel->order[layer]) + continue; + if (debug) + printf("current file: '%s'\n", file[mr->current_file]); + mr->cur_sel=mr->xsel; + if (block_init(mr)) + return 1; + } +} + +static void +map_destroy_mg(struct map_priv *m) +{ + int i; + + printf("mg_map_destroy\n"); + for (i = 0 ; i < file_end ; i++) { + if (m->file[i]) + file_destroy(m->file[i]); + } +} + +extern int block_lin_count,block_idx_count,block_active_count,block_mem,block_active_mem; + +static struct map_rect_priv * +map_rect_new_mg(struct map_priv *map, struct map_selection *sel) +{ + struct map_rect_priv *mr; + int i; + + block_lin_count=0; + block_idx_count=0; + block_active_count=0; + block_mem=0; + block_active_mem=0; + mr=g_new0(struct map_rect_priv, 1); + mr->m=map; + mr->xsel=sel; + mr->current_file=-1; + if (sel && sel->next) + for (i=0 ; i < file_end ; i++) + mr->block_hash[i]=g_hash_table_new(g_int_hash,g_int_equal); + + file_next(mr); + return mr; +} + + +static struct item * +map_rect_get_item_mg(struct map_rect_priv *mr) +{ + for (;;) { + switch (mr->current_file) { + case file_town_twn: + if (town_get(mr, &mr->town, &mr->item)) + return &mr->item; + break; + case file_border_ply: + /* case file_bridge_ply: */ + case file_build_ply: + case file_golf_ply: + /* case file_height_ply: */ + case file_natpark_ply: + case file_nature_ply: + case file_other_ply: + case file_rail_ply: + case file_sea_ply: + /* case file_tunnel_ply: */ + case file_water_ply: + case file_woodland_ply: + if (poly_get(mr, &mr->poly, &mr->item)) + return &mr->item; + break; + case file_street_str: + if (street_get(mr, &mr->street, &mr->item)) + return &mr->item; + break; + case file_end: + return NULL; + default: + break; + } + if (block_next(mr)) + continue; + if (mr->cur_sel->next) { + mr->cur_sel=mr->cur_sel->next; + if (block_init(mr)) + continue; + } + if (file_next(mr)) + continue; + dbg(1,"lin_count %d idx_count %d active_count %d %d kB (%d kB)\n", block_lin_count, block_idx_count, block_active_count, (block_mem+block_active_mem)/1024, block_active_mem/1024); + return NULL; + } +} + +static struct item * +map_rect_get_item_byid_mg(struct map_rect_priv *mr, int id_hi, int id_lo) +{ + mr->current_file = id_hi >> 16; + switch (mr->current_file) { + case file_town_twn: + if (town_get_byid(mr, &mr->town, id_hi, id_lo, &mr->item)) + return &mr->item; + break; + case file_street_str: + if (street_get_byid(mr, &mr->street, id_hi, id_lo, &mr->item)) + return &mr->item; + break; + default: + if (poly_get_byid(mr, &mr->poly, id_hi, id_lo, &mr->item)) + return &mr->item; + break; + } + return NULL; +} + + +static void +map_rect_destroy_mg(struct map_rect_priv *mr) +{ + int i; + for (i=0 ; i < file_end ; i++) + if (mr->block_hash[i]) + g_hash_table_destroy(mr->block_hash[i]); + g_free(mr); +} + +static struct map_search_priv * +map_search_new_mg(struct map_priv *map, struct item *item, struct attr *search, int partial) +{ + struct map_rect_priv *mr=g_new0(struct map_rect_priv, 1); + dbg(1,"id_lo=0x%x\n", item->id_lo); + dbg(1,"search=%s\n", search->u.str); + mr->m=map; + mr->search_type=search->type; + switch (search->type) { + case attr_town_name: + if (item->type != type_country_label) + return NULL; + tree_search_init(map->dirname, "town.b2", &mr->ts, 0x1000); + break; + case attr_street_name: + if (item->type != type_town_streets) + return NULL; + dbg(1,"street_assoc=0x%x\n", item->id_lo); + tree_search_init(map->dirname, "strname.b1", &mr->ts, 0); + break; + default: + dbg(0,"unknown search\n"); + g_free(mr); + return NULL; + } + mr->search_item=*item; + mr->search_country=item->id_lo; + mr->search_str=search->u.str; + mr->search_partial=partial; + mr->current_file=file_town_twn-1; + file_next(mr); + return (struct map_search_priv *)mr; +} + +static void +map_search_destroy_mg(struct map_search_priv *ms) +{ + struct map_rect_priv *mr=(struct map_rect_priv *)ms; + + if (! mr) + return; + tree_search_free(&mr->ts); + g_free(mr); +} + +static struct item * +map_search_get_item_mg(struct map_search_priv *ms) +{ + struct map_rect_priv *mr=(struct map_rect_priv *)ms; + + if (! mr) + return NULL; + switch (mr->search_type) { + case attr_town_name: + return town_search_get_item(mr); + case attr_street_name: + return street_search_get_item(mr); + default: + return NULL; + } +} + +static struct map_methods map_methods_mg = { + map_destroy_mg, + map_rect_new_mg, + map_rect_destroy_mg, + map_rect_get_item_mg, + map_rect_get_item_byid_mg, + map_search_new_mg, + map_search_destroy_mg, + map_search_get_item_mg, +}; + +struct map_priv * +map_new_mg(struct map_methods *meth, char *dirname, char **charset, enum projection *pro) +{ + struct map_priv *m; + int i,maybe_missing,len=strlen(dirname); + char filename[len+16]; + + *meth=map_methods_mg; + *charset="iso8859-1"; + *pro=projection_mg; + + m=g_new(struct map_priv, 1); + m->id=++map_id; + m->dirname=g_strdup(dirname); + strcpy(filename, dirname); + filename[len]='/'; + for (i = 0 ; i < file_end ; i++) { + if (file[i]) { + strcpy(filename+len+1, file[i]); + m->file[i]=file_create_caseinsensitive(filename); + if (! m->file[i]) { + maybe_missing=(i == file_border_ply || i == file_height_ply || i == file_sea_ply); + if (! maybe_missing) + g_warning("Failed to load %s", filename); + } + } + } + + return m; +} + +void +plugin_init(void) +{ + plugin_register_map_type("mg", map_new_mg); +} diff --git a/src/data/mg/mg.h b/src/data/mg/mg.h new file mode 100644 index 00000000..696fd55c --- /dev/null +++ b/src/data/mg/mg.h @@ -0,0 +1,286 @@ +#include <glib.h> +#include "attr.h" +#include "coord.h" +#include "data.h" +#include "item.h" +#include "map.h" +#include "file.h" + +struct block_data { + struct file *file; +}; + +struct block { + int blocks; + int size; + int next; + struct coord_rect r; + int count; +}; + +struct item_priv { + int cidx; + int aidx; + unsigned char *cstart,*cp,*cend; + unsigned char *astart,*ap,*aend; + enum attr_type attr_last; + enum attr_type attr_next; + struct item item; +}; + +struct town_priv { + unsigned int id; /*!< Identifier */ + struct coord c; /*!< Coordinates */ + char *name; /*!< Name */ + char *district; /*!< District */ + char *postal_code1; /*!< Postal code */ + unsigned char order; /*!< Order (Importance) */ + unsigned char type; /*!< Type */ + unsigned short country; /*!< Country */ + unsigned int unknown2; /*!< Unknown */ + unsigned char size; /*!< Size of town */ + unsigned int street_assoc; /*!< Association to streets */ + unsigned char unknown3; /*!< Unknown */ + char *postal_code2; /*!< 2nd postal code */ + unsigned int unknown4; /*!< Unknown */ + + int cidx; + int aidx; + enum attr_type attr_next; + char debug[256]; + struct item town_attr_item; +}; + +struct poly_priv { + int poly_num; + unsigned char *poly_next; + int subpoly_num; + int subpoly_num_all; + unsigned char *subpoly_next; + unsigned char *subpoly_start; + unsigned char *p; + struct coord c[2]; + char *name; + unsigned char order; + unsigned char type; + unsigned int polys; + unsigned int *count; + unsigned int count_sum; + + int aidx; + enum attr_type attr_next; +}; + +struct street_header { + unsigned char order; + int count; +} __attribute__((packed)); + +struct street_type { + unsigned char order; + unsigned short country; +} __attribute__((packed)); + +struct street_header_type { + struct street_header *header; + int type_count; + struct street_type *type; +}; + +struct street_str { + int segid; + unsigned char limit; /* 0x03,0x30=One Way,0x33=No Passing */ + unsigned char unknown2; + unsigned char unknown3; + unsigned char type; + unsigned int nameid; +}; + +struct street_name_segment { + int segid; + int country; +}; + +struct street_name { + int len; + int country; + int townassoc; + char *name1; + char *name2; + int segment_count; + struct street_name_segment *segments; + int aux_len; + unsigned char *aux_data; + int tmp_len; + unsigned char *tmp_data; +}; + +struct street_name_numbers { + int len; + int tag; + int dist; + int country; + struct coord *c; + int first; + int last; + int segment_count; + struct street_name_segment *segments; + int aux_len; + unsigned char *aux_data; + int tmp_len; + unsigned char *tmp_data; +}; + +struct street_name_number { + int len; + int tag; + struct coord *c; + int first; + int last; + struct street_name_segment *segment; +}; + + + +struct street_priv { + struct file *name_file; + struct street_header *header; + int type_count; + struct street_type *type; + struct street_str *str; + struct street_str *str_start; + unsigned char *coord_begin; + unsigned char *p; + unsigned char *p_rewind; + unsigned char *end; + unsigned char *next; + int status; + int status_rewind; + struct coord *ref; + int bytes; + struct street_name name; + enum attr_type attr_next; + char debug[256]; +}; + +enum file_index { + file_border_ply=0, + file_bridge_ply, + file_build_ply, + file_golf_ply, + file_height_ply, + file_natpark_ply, + file_nature_ply, + file_other_ply, + file_rail_ply, + file_sea_ply, + file_street_bti, + file_street_str, + file_strname_stn, + file_town_twn, + file_tunnel_ply, + file_water_ply, + file_woodland_ply, + file_end +}; + +struct map_priv { + int id; + struct file *file[file_end]; + char *dirname; +}; + +#define BT_STACK_SIZE 32 + +struct block_bt_priv { + struct block *b; + struct coord_rect r, r_curr; + int next; + int block_count; + struct coord_rect stack[BT_STACK_SIZE]; + int stackp; + int order; + unsigned char *p; + unsigned char *end; +}; + +struct block_priv { + int block_num; + struct coord_rect b_rect; + unsigned char *block_start; + struct block *b; + unsigned char *p; + unsigned char *end; + unsigned char *p_start; + int binarytree; + struct block_bt_priv bt; +}; + +struct block_offset { + unsigned short offset; + unsigned short block; +}; + + +struct tree_search_node { + struct tree_hdr *hdr; + unsigned char *p; + unsigned char *last; + unsigned char *end; + int low; + int high; + int last_low; + int last_high; + }; + +struct tree_search { + struct file *f; + int last_node; + int curr_node; + struct tree_search_node nodes[5]; +}; + + +struct map_rect_priv { + struct map_selection *xsel; + struct map_selection *cur_sel; + + struct map_priv *m; + enum file_index current_file; + struct file *file; + struct block_priv b; + struct item item; + struct town_priv town; + struct poly_priv poly; + struct street_priv street; + struct tree_search ts; + int search_country; + struct item search_item; + char *search_str; + int search_partial; + int search_linear; + unsigned char *search_p; + int search_blk_count; + enum attr_type search_type; + struct block_offset *search_blk_off; + int search_block; + GHashTable *block_hash[file_end]; + struct item_priv item3; +}; + +int block_init(struct map_rect_priv *mr); +int block_next(struct map_rect_priv *mr); +int block_get_byindex(struct file *file, int idx, struct block_priv *blk); + +int tree_search_hv(char *dirname, char *filename, unsigned int search1, unsigned int search2, int *result); +int town_get(struct map_rect_priv *mr, struct town_priv *poly, struct item *item); +int town_get_byid(struct map_rect_priv *mr, struct town_priv *twn, int id_hi, int id_lo, struct item *item); +struct item * town_search_get_item(struct map_rect_priv *mr); +int poly_get(struct map_rect_priv *mr, struct poly_priv *poly, struct item *item); +int poly_get_byid(struct map_rect_priv *mr, struct poly_priv *poly, int id_hi, int id_lo, struct item *item); +int street_get(struct map_rect_priv *mr, struct street_priv *street, struct item *item); +int street_get_byid(struct map_rect_priv *mr, struct street_priv *street, int id_hi, int id_lo, struct item *item); +void tree_search_init(char *dirname, char *filename, struct tree_search *ts, int offset); +void tree_search_free(struct tree_search *ts); +int tree_search_next(struct tree_search *ts, unsigned char **p, int dir); +int tree_search_next_lin(struct tree_search *ts, unsigned char **p); diff --git a/src/data/mg/poly.c b/src/data/mg/poly.c new file mode 100644 index 00000000..b19aeed5 --- /dev/null +++ b/src/data/mg/poly.c @@ -0,0 +1,196 @@ +#include "debug.h" +#include "mg.h" + +static void +poly_coord_rewind(void *priv_data) +{ + struct poly_priv *poly=priv_data; + + poly->p=poly->subpoly_start; + +} + +static int +poly_coord_get(void *priv_data, struct coord *c, int count) +{ + struct poly_priv *poly=priv_data; + int ret=0; + + while (count--) { + if (poly->p >= poly->subpoly_next) + break; + c->x=get_u32_unal(&poly->p); + c->y=get_u32_unal(&poly->p); + c++; + ret++; + } + return ret; +} + +static void +poly_attr_rewind(void *priv_data) +{ + struct poly_priv *poly=priv_data; + + poly->aidx=0; +} + +static int +poly_attr_get(void *priv_data, enum attr_type attr_type, struct attr *attr) +{ + struct poly_priv *poly=priv_data; + + attr->type=attr_type; + switch (attr_type) { + case attr_any: + while (poly->attr_next != attr_none) { + if (poly_attr_get(poly, poly->attr_next, attr)) + return 1; + } + return 0; + case attr_label: + attr->u.str=poly->name; + poly->attr_next=attr_none; + if (attr->u.str[0]) + return 1; + return 0; + default: + return 0; + } + return 1; +} + +static struct item_methods poly_meth = { + poly_coord_rewind, + poly_coord_get, + poly_attr_rewind, + poly_attr_get, +}; + +static void +poly_get_data(struct poly_priv *poly, unsigned char **p) +{ + poly->c[0].x=get_u32_unal(p); + poly->c[0].y=get_u32_unal(p); + poly->c[1].x=get_u32_unal(p); + poly->c[1].y=get_u32_unal(p); + *p+=sizeof(struct coord); + poly->name=(char *)(*p); + while (**p) { + (*p)++; + } + (*p)++; + poly->order=*(*p)++; + poly->type=*(*p)++; + poly->polys=get_u32_unal(p); + poly->count=(unsigned int *)(*p); (*p)+=poly->polys*sizeof(unsigned int); + poly->count_sum=get_u32_unal(p); +} + +int +poly_get(struct map_rect_priv *mr, struct poly_priv *poly, struct item *item) +{ + struct coord_rect r; + + for (;;) { + if (mr->b.p >= mr->b.end) + return 0; + if (mr->b.p == mr->b.p_start) { + poly->poly_num=0; + poly->subpoly_num=0; + poly->subpoly_num_all=0; + poly->poly_next=mr->b.p; + item->meth=&poly_meth; + } + if (poly->poly_num >= mr->b.b->count) + return 0; + if (!poly->subpoly_num) { + mr->b.p=poly->poly_next; + item->id_lo=mr->b.p-mr->file->begin; + poly_get_data(poly, &mr->b.p); + poly->poly_next=mr->b.p+poly->count_sum*sizeof(struct coord); + poly->poly_num++; + r.lu=poly->c[0]; + r.rl=poly->c[1]; + if (mr->cur_sel && (poly->order > mr->cur_sel->order[layer_poly]*3 || !coord_rect_overlap(&mr->cur_sel->rect, &r))) { + poly->subpoly_num_all+=poly->polys; + mr->b.p=poly->poly_next; + continue; + } + switch(poly->type) { + case 0x13: + item->type=type_wood; + break; + case 0x14: + item->type=type_town_poly; + break; + case 0x15: + item->type=type_cemetery_poly; + break; + case 0x1e: + item->type=type_industry_poly; + break; + case 0x24: + item->type=type_parking_lot_poly; + break; + case 0x28: + item->type=type_airport_poly; + break; + case 0x2d: + item->type=type_hospital_poly; + break; + case 0x32: + item->type=type_park_poly; + break; + case 0x34: + item->type=type_sport_poly; + break; + case 0x3c: + item->type=type_water_poly; + break; + case 0xbc: + item->type=type_water_line; + break; + case 0xc6: + item->type=type_border_country; + break; + case 0xc7: + item->type=type_border_state; + break; + case 0xd0: + item->type=type_rail; + break; + default: + dbg(0,"Unknown poly type 0x%x '%s' 0x%x,0x%x\n", poly->type,poly->name,r.lu.x,r.lu.y); + item->type=type_street_unkn; + } + } else + mr->b.p=poly->subpoly_next; + dbg(1,"%d %d %s\n", poly->subpoly_num_all, mr->b.block_num, poly->name); + item->id_lo=poly->subpoly_num_all | (mr->b.block_num << 16); + item->id_hi=(mr->current_file << 16); + dbg(1,"0x%x 0x%x\n", item->id_lo, item->id_hi); + poly->subpoly_next=mr->b.p+L(poly->count[poly->subpoly_num])*sizeof(struct coord); + poly->subpoly_num++; + poly->subpoly_num_all++; + if (poly->subpoly_num >= poly->polys) + poly->subpoly_num=0; + poly->subpoly_start=poly->p=mr->b.p; + item->priv_data=poly; + poly->attr_next=attr_label; + return 1; + } +} + +int +poly_get_byid(struct map_rect_priv *mr, struct poly_priv *poly, int id_hi, int id_lo, struct item *item) +{ + int count=id_lo & 0xffff; + int ret=0; + block_get_byindex(mr->m->file[mr->current_file], id_lo >> 16, &mr->b); + while (count-- >= 0) { + ret=poly_get(mr, poly, item); + } + return ret; +} + diff --git a/src/data/mg/street.c b/src/data/mg/street.c new file mode 100644 index 00000000..550e5006 --- /dev/null +++ b/src/data/mg/street.c @@ -0,0 +1,702 @@ +#include <stdio.h> +#include "debug.h" +#include "mg.h" + +int coord_debug; + +static void +street_name_get(struct street_name *name, unsigned char **p) +{ + unsigned char *start=*p; + name->len=get_u16_unal(p); + name->country=get_u16_unal(p); + name->townassoc=get_u32_unal(p); + name->name1=get_string(p); + name->name2=get_string(p); + name->segment_count=get_u32_unal(p); + name->segments=(struct street_name_segment *)(*p); + (*p)+=(sizeof (struct street_name_segment))*name->segment_count; + name->aux_len=name->len-(*p-start); + name->aux_data=*p; + name->tmp_len=name->aux_len; + name->tmp_data=name->aux_data; + *p=start+name->len; +} + +static void +street_name_numbers_get(struct street_name_numbers *name_numbers, unsigned char **p) +{ + unsigned char *start=*p; + name_numbers->len=get_u16(p); + name_numbers->tag=get_u8(p); + name_numbers->dist=get_u32(p); + name_numbers->country=get_u32(p); + name_numbers->c=coord_get(p); + name_numbers->first=get_u24(p); + name_numbers->last=get_u24(p); + name_numbers->segment_count=get_u32(p); + name_numbers->segments=(struct street_name_segment *)(*p); + (*p)+=sizeof(struct street_name_segment)*name_numbers->segment_count; + name_numbers->aux_len=name_numbers->len-(*p-start); + name_numbers->aux_data=*p; + name_numbers->tmp_len=name_numbers->aux_len; + name_numbers->tmp_data=name_numbers->aux_data; + *p=start+name_numbers->len; +} + +static void +street_name_number_get(struct street_name_number *name_number, unsigned char **p) +{ + unsigned char *start=*p; + name_number->len=get_u16(p); + name_number->tag=get_u8(p); + name_number->c=coord_get(p); + name_number->first=get_u24(p); + name_number->last=get_u24(p); + name_number->segment=(struct street_name_segment *)p; + *p=start+name_number->len; +} + +static void +street_name_get_by_id(struct street_name *name, struct file *file, unsigned long id) +{ + unsigned char *p; + if (id) { + p=file->begin+id+0x2000; + street_name_get(name, &p); + } +} + +static int street_get_bytes(struct coord_rect *r) +{ + int bytes,dx,dy; + bytes=2; + dx=r->rl.x-r->lu.x; + dy=r->lu.y-r->rl.y; + g_assert(dx > 0); + g_assert(dy > 0); + if (dx > 32767 || dy > 32767) + bytes=3; + if (dx > 8388608 || dy > 8388608) + bytes=4; + + return bytes; +} + +static int street_get_coord(unsigned char **pos, int bytes, struct coord *ref, struct coord *f) +{ + unsigned char *p; + int x,y,flags=0; + + p=*pos; + x=*p++; + x|=(*p++) << 8; + if (bytes == 2) { + if ( x > 0x7fff) { + x=0x10000-x; + flags=1; + } + } + else if (bytes == 3) { + x|=(*p++) << 16; + if ( x > 0x7fffff) { + x=0x1000000-x; + flags=1; + } + } else { + x|=(*p++) << 16; + x|=(*p++) << 24; + if (x < 0) { + x=-x; + flags=1; + } + } + y=*p++; + y|=(*p++) << 8; + if (bytes == 3) { + y|=(*p++) << 16; + } else if (bytes == 4) { + y|=(*p++) << 16; + y|=(*p++) << 24; + } + if (f) { + f->x=ref[0].x+x; + f->y=ref[1].y+y; + } + dbg(1,"0x%x,0x%x + 0x%x,0x%x = 0x%x,0x%x\n", x, y, ref[0].x, ref[1].y, f->x, f->y); + *pos=p; + return flags; +} + +static void +street_coord_get_begin(unsigned char **p) +{ + struct street_str *str; + + str=(struct street_str *)(*p); + while (L(str->segid)) { + str++; + } + (*p)=(unsigned char *)str; + (*p)+=4; +} + + +static void +street_coord_rewind(void *priv_data) +{ + /* struct street_priv *street=priv_data; */ + +} + +static int +street_coord_get_helper(struct street_priv *street, struct coord *c) +{ + unsigned char *n; + if (street->p+street->bytes*2 >= street->end) + return 0; + if (street->status >= 4) + return 0; + n=street->p; + if (street_get_coord(&street->p, street->bytes, street->ref, c)) { + if (street->status) + street->next=n; + street->status+=2; + if (street->status == 5) + return 0; + } + return 1; +} + +static int +street_coord_get(void *priv_data, struct coord *c, int count) +{ + struct street_priv *street=priv_data; + int ret=0,i,scount; + + if (! street->p && count) { + street->p=street->coord_begin; + scount=street->str-street->str_start; + for (i = 0 ; i < scount ; i++) { + street->status=L(street->str[i+1].segid) >= 0 ? 0:1; + while (street_coord_get_helper(street, c)); + street->p=street->next; + } + street->status_rewind=street->status=L(street->str[1].segid) >= 0 ? 0:1; + } + while (count > 0) { + if (street_coord_get_helper(street, c)) { + c++; + ret++; + count--; + } else + return ret; + } + return ret; +} + +static void +street_attr_rewind(void *priv_data) +{ + /* struct street_priv *street=priv_data; */ + +} + +static int +street_attr_get(void *priv_data, enum attr_type attr_type, struct attr *attr) +{ + struct street_priv *street=priv_data; + int nameid; + + dbg(1,"segid 0x%x\n", street->str->segid); + attr->type=attr_type; + switch (attr_type) { + case attr_any: + while (street->attr_next != attr_none) { + if (street_attr_get(street, street->attr_next, attr)) + return 1; + } + return 0; + case attr_label: + nameid=L(street->str->nameid); + if (! nameid) + return 0; + if (! street->name.len) + street_name_get_by_id(&street->name,street->name_file,nameid); + street->attr_next=attr_street_name; + attr->u.str=street->name.name2; + if (attr->u.str && attr->u.str[0]) + return 1; + attr->u.str=street->name.name1; + if (attr->u.str && attr->u.str[0]) + return 1; + return 0; + case attr_street_name: + nameid=L(street->str->nameid); + if (! nameid) + return 0; + if (! street->name.len) + street_name_get_by_id(&street->name,street->name_file,nameid); + attr->u.str=street->name.name2; + street->attr_next=attr_street_name_systematic; + return ((attr->u.str && attr->u.str[0]) ? 1:0); + case attr_street_name_systematic: + nameid=L(street->str->nameid); + if (! nameid) + return 0; + if (! street->name.len) + street_name_get_by_id(&street->name,street->name_file,nameid); + attr->u.str=street->name.name1; + street->attr_next=attr_limit; + return ((attr->u.str && attr->u.str[0]) ? 1:0); + case attr_limit: + if (street->str->type & 0x40) { + attr->u.num=(street->str->limit & 0x30) ? 2:0; + attr->u.num|=(street->str->limit & 0x03) ? 1:0; + } else { + attr->u.num=(street->str->limit & 0x30) ? 1:0; + attr->u.num|=(street->str->limit & 0x03) ? 2:0; + } + street->attr_next=attr_debug; + return 1; + case attr_debug: + street->attr_next=attr_none; + { + struct street_str *str=street->str; + sprintf(street->debug,"order:0x%x\nsegid:0x%x\nlimit:0x%x\nunknown2:0x%x\nunknown3:0x%x\ntype:0x%x\nnameid:0x%x\ntownassoc:0x%x",street->header->order,str->segid,str->limit,str->unknown2,str->unknown3,str->type,str->nameid, street->name.len ? street->name.townassoc : 0); + attr->u.str=street->debug; + } + return 1; + default: + return 0; + } + return 1; +} + +static struct item_methods street_meth = { + street_coord_rewind, + street_coord_get, + street_attr_rewind, + street_attr_get, +}; + +static void +street_get_data(struct street_priv *street, unsigned char **p) +{ + street->header=(struct street_header *)(*p); + (*p)+=sizeof(struct street_header); + street->type_count=street->header->count; + street->type=(struct street_type *)(*p); + (*p)+=street->type_count*sizeof(struct street_type); +} + + + /*0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 */ +static unsigned char limit[]={0,0,1,1,1,2,2,4,6,6,12,13,14,20,20,20,20,20,20}; + +int +street_get(struct map_rect_priv *mr, struct street_priv *street, struct item *item) +{ + if (mr->b.p == mr->b.p_start) { + street_get_data(street, &mr->b.p); + street->name_file=mr->m->file[file_strname_stn]; + if (mr->cur_sel && street->header->order > limit[mr->cur_sel->order[layer_street]]) + return 0; + street->end=mr->b.end; + street->ref=&mr->b.b->r.lu; + street->bytes=street_get_bytes(&mr->b.b->r); + street->str_start=street->str=(struct street_str *)mr->b.p; + street->coord_begin=mr->b.p; + street_coord_get_begin(&street->coord_begin); + street->p=street->coord_begin; + street->type--; + item->meth=&street_meth; + item->priv_data=street; + } else { + street->str++; + street->p=street->next; + } + if (! L(street->str->segid)) + return 0; + if (L(street->str->segid) < 0) + street->type++; +#if 0 + g_assert(street->p != NULL); +#endif + street->next=NULL; + street->status_rewind=street->status=L(street->str[1].segid) >= 0 ? 0:1; +#if 0 + if (street->type->country != 0x31) { + printf("country=0x%x\n", street->type->country); + } +#endif + item->id_hi=street->type->country | (mr->current_file << 16); + item->id_lo=L(street->str->segid) > 0 ? L(street->str->segid) : -L(street->str->segid); + switch(street->str->type & 0x1f) { + case 0xf: /* very small street */ + if (street->str->limit == 0x33) + item->type=type_street_nopass; + else + item->type=type_street_0; + break; + case 0xd: + item->type=type_ferry; + break; + case 0xc: /* small street */ + item->type=type_street_1_city; + break; + case 0xb: + item->type=type_street_2_city; + break; + case 0xa: + if ((street->str->limit == 0x03 || street->str->limit == 0x30) && street->header->order < 4) + item->type=type_street_4_city; + else + item->type=type_street_3_city; + break; + case 0x9: + if (street->header->order < 5) + item->type=type_street_4_city; + else if (street->header->order < 7) + item->type=type_street_2_city; + else + item->type=type_street_1_city; + break; + case 0x8: + item->type=type_street_2_land; + break; + case 0x7: + if ((street->str->limit == 0x03 || street->str->limit == 0x30) && street->header->order < 4) + item->type=type_street_4_city; + else + item->type=type_street_3_land; + break; + case 0x6: + item->type=type_ramp; + break; + case 0x5: + item->type=type_street_4_land; + break; + case 0x4: + item->type=type_street_4_land; + break; + case 0x3: + item->type=type_street_n_lanes; + break; + case 0x2: + item->type=type_highway_city; + break; + case 0x1: + item->type=type_highway_land; + break; + default: + item->type=type_street_unkn; + dbg(0,"unknown type 0x%x\n",street->str->type); + } +#if 0 + coord_debug=(street->str->unknown2 != 0x40 || street->str->unknown3 != 0x40); + if (coord_debug) { + item->type=type_street_unkn; + printf("%d %02x %02x %02x %02x\n", street->str->segid, street->str->type, street->str->limit, street->str->unknown2, street->str->unknown3); + } +#endif + street->p_rewind=street->p; + street->name.len=0; + street->attr_next=attr_label; + return 1; +} + +int +street_get_byid(struct map_rect_priv *mr, struct street_priv *street, int id_hi, int id_lo, struct item *item) +{ + int country=id_hi & 0xffff; + int res; + dbg(1,"enter(%p,%p,0x%x,0x%x,%p)\n", mr, street, id_hi, id_lo, item); + if (! country) + return 0; + tree_search_hv(mr->m->dirname, "street", (id_lo >> 8) | (country << 24), id_lo & 0xff, &res); + dbg(1,"res=0x%x (blk=0x%x)\n", res, res >> 12); + block_get_byindex(mr->m->file[mr->current_file], res >> 12, &mr->b); + street_get_data(street, &mr->b.p); + street->name_file=mr->m->file[file_strname_stn]; + street->end=mr->b.end; + street->ref=&mr->b.b->r.lu; + street->bytes=street_get_bytes(&mr->b.b->r); + street->str_start=street->str=(struct street_str *)mr->b.p; + street->coord_begin=mr->b.p; + street_coord_get_begin(&street->coord_begin); + street->p=street->coord_begin; + street->type--; + item->meth=&street_meth; + item->priv_data=street; + street->str+=(res & 0xfff)-1; + dbg(1,"segid 0x%x\n", street->str[1].segid); + return street_get(mr, street, item); +#if 0 + mr->b.p=mr->b.block_start+(res & 0xffff); + return town_get(mr, twn, item); +#endif + + return 0; +} + + +struct street_name_index { + int block; + unsigned short country; + long town_assoc; + char name[0]; +} __attribute__((packed)); + + +static int +street_search_compare_do(struct map_rect_priv *mr, int country, int town_assoc, char *name) +{ + int d; + + dbg(1,"enter"); + dbg(1,"country 0x%x town_assoc 0x%x name '%s'\n", country, town_assoc, name); + d=(mr->search_item.id_hi & 0xffff)-country; + dbg(1,"country %d\n", d); + if (!d) { + d=mr->search_item.id_lo-town_assoc; + dbg(1,"assoc %d 0x%x-0x%x\n",d, mr->search_item.id_lo, town_assoc); + if (! d) { + if (mr->search_partial) + d=strncasecmp(mr->search_str, name, strlen(mr->search_str)); + else + d=strcasecmp(mr->search_str, name); + dbg(1,"string %d\n", d); + } + } + dbg(1,"d=%d\n", d); + return d; +} + +static int +street_search_compare(unsigned char **p, struct map_rect_priv *mr) +{ + struct street_name_index *i; + + dbg(1,"enter\n"); + i=(struct street_name_index *)(*p); + *p+=sizeof(*i)+strlen(i->name)+1; + mr->search_block=i->block; + + dbg(1,"block 0x%x\n", i->block); + + return street_search_compare_do(mr, i->country, i->town_assoc, i->name); +} + +static void +street_name_numbers_coord_rewind(void *priv_data) +{ + /* struct street_priv *street=priv_data; */ + +} + +static void +street_name_numbers_attr_rewind(void *priv_data) +{ + /* struct street_priv *street=priv_data; */ + +} + +static int +street_name_numbers_coord_get(void *priv_data, struct coord *c, int count) +{ + return 0; +} + +static int +street_name_numbers_attr_get(void *priv_data, enum attr_type attr_type, struct attr *attr) +{ + struct map_rect_priv *mr=priv_data; + struct item *item; + + attr->type=attr_type; + switch (attr_type) { + default: + dbg(0,"unknown item\n"); + return 0; + } +} + + + + + +static struct item_methods street_name_numbers_meth = { + street_name_numbers_coord_rewind, + street_name_numbers_coord_get, + street_name_numbers_attr_rewind, + street_name_numbers_attr_get, +}; + + +static void +street_name_coord_rewind(void *priv_data) +{ + /* struct street_priv *street=priv_data; */ + +} + +static void +street_name_attr_rewind(void *priv_data) +{ + /* struct street_priv *street=priv_data; */ + +} + +static int +street_name_coord_get(void *priv_data, struct coord *c, int count) +{ + struct map_rect_priv *mr=priv_data; + struct street_name_numbers snns; + unsigned char *p=mr->street.name.aux_data; + + dbg(0,"aux_data=%p\n", p); + if (count) { + street_name_numbers_get(&snns, &p); + *c=*(snns.c); + return 1; + } + + return 0; +} + +static int +street_name_attr_get(void *priv_data, enum attr_type attr_type, struct attr *attr) +{ + struct map_rect_priv *mr=priv_data; + struct item *item; + + attr->type=attr_type; + switch (attr_type) { + case attr_street_name: + attr->u.str=mr->street.name.name2; + return ((attr->u.str && attr->u.str[0]) ? 1:0); + case attr_street_name_systematic: + attr->u.str=mr->street.name.name1; + return ((attr->u.str && attr->u.str[0]) ? 1:0); + case attr_street_name_numbers_item: + item=&mr->item3.item; + attr->u.item=item; + item->type=type_street_name_numbers; + item->id_hi=0; + item->id_lo=1; + item->meth=&street_name_numbers_meth; + item->map=NULL; + item->priv_data=mr; + { + int i; + struct street_name_numbers nns; + unsigned char *p=mr->street.name.aux_data; + unsigned char *end=p+mr->street.name.aux_len; + printf("len=0x%x\n", mr->street.name.aux_len); + for (i = 0 ; i < mr->street.name.aux_len ; i++) { + printf("%02x ",mr->street.name.aux_data[i]); + } + printf("\n"); + { + while (p < end) { + unsigned char *pn,*pn_end;; + struct street_name_number nn; + street_name_numbers_get(&nns, &p); + printf("name_numbers:\n"); + printf(" len 0x%x\n", nns.len); + printf(" tag 0x%x\n", nns.tag); + printf(" dist 0x%x\n", nns.dist); + printf(" country 0x%x\n", nns.country); + printf(" coord 0x%x,0x%x\n", nns.c->x, nns.c->y); + printf(" first %d\n", nns.first); + printf(" last %d\n", nns.last); + printf(" segment count 0x%x\n", nns.segment_count); + printf(" aux_len 0x%x\n", nns.aux_len); + pn=nns.aux_data; + pn_end=nns.aux_data+nns.aux_len; + while (pn < pn_end) { + printf(" number:\n"); + street_name_number_get(&nn, &pn); + printf(" len 0x%x\n", nn.len); + printf(" tag 0x%x\n", nn.tag); + printf(" coord 0x%x,0x%x\n", nn.c->x, nn.c->y); + printf(" first %d\n", nn.first); + printf(" last %d\n", nn.last); + } + } + } + } + return 1; + default: + dbg(0,"unknown item\n"); + return 0; + } +} + + + + + +static struct item_methods street_name_meth = { + street_name_coord_rewind, + street_name_coord_get, + street_name_attr_rewind, + street_name_attr_get, +}; + + +struct item * +street_search_get_item(struct map_rect_priv *mr) +{ + int dir=1,leaf; + unsigned char *last; + + dbg(1,"enter\n"); + if (! mr->search_blk_count) { + dbg(1,"partial 0x%x '%s' ***\n", mr->town.street_assoc, mr->search_str); + if (mr->search_linear) + return NULL; + dbg(1,"tree_search_next\n"); + mr->search_block=-1; + while ((leaf=tree_search_next(&mr->ts, &mr->search_p, dir)) != -1) { + dir=street_search_compare(&mr->search_p, mr); + } + if (mr->search_block == -1) + return NULL; + dbg(1,"mr->search_block=0x%x\n", mr->search_block); + mr->search_blk_count=1; + block_get_byindex(mr->m->file[file_strname_stn], mr->search_block, &mr->b); + mr->b.p=mr->b.block_start+12; + } + dbg(1,"name id 0x%x\n", mr->b.p-mr->m->file[file_strname_stn]->begin); + if (! mr->search_blk_count) + return NULL; + if (mr->b.p >= mr->b.end) { + if (!block_next_lin(mr)) + return NULL; + mr->b.p=mr->b.block_start+12; + } + while (mr->b.p < mr->b.end) { + last=mr->b.p; + street_name_get(&mr->street.name, &mr->b.p); + dir=street_search_compare_do(mr, mr->street.name.country, mr->street.name.townassoc, mr->street.name.name2); + dbg(1,"country 0x%x assoc 0x%x name1 '%s' name2 '%s' dir=%d\n", mr->street.name.country, mr->street.name.townassoc, mr->street.name.name1, mr->street.name.name2, dir); + if (dir < 0) { + mr->search_blk_count=0; + return NULL; + } + if (!dir) { + dbg(0,"result country 0x%x assoc 0x%x name1 '%s' name2 '%s' dir=%d aux_data=%p len=0x%x\n", mr->street.name.country, mr->street.name.townassoc, mr->street.name.name1, mr->street.name.name2, dir, mr->street.name.aux_data, mr->street.name.aux_len); + mr->item.type = type_street_name; + mr->item.id_hi=mr->street.name.country | (mr->current_file << 16) | 0x10000000; + mr->item.id_lo=last-mr->m->file[mr->current_file]->begin; + mr->item.meth=&street_name_meth; + mr->item.map=NULL; + mr->item.priv_data=mr; + return &mr->item; + } + } + return NULL; +} + diff --git a/src/data/mg/town.c b/src/data/mg/town.c new file mode 100644 index 00000000..838bc2cc --- /dev/null +++ b/src/data/mg/town.c @@ -0,0 +1,261 @@ +#include <stdio.h> +#include <string.h> +#include "debug.h" +#include "mg.h" + + + +static void +town_coord_rewind(void *priv_data) +{ + struct town_priv *twn=priv_data; + + twn->cidx=0; +} + +static int +town_coord_get(void *priv_data, struct coord *c, int count) +{ + struct town_priv *twn=priv_data; + + if (twn->cidx || count <= 0) + return 0; + twn->cidx=1; + *c=twn->c; + return 1; +} + +static void +town_attr_rewind(void *priv_data) +{ + struct town_priv *twn=priv_data; + + twn->aidx=0; + twn->attr_next=attr_label; +} + +static int +town_attr_get(void *priv_data, enum attr_type attr_type, struct attr *attr) +{ + struct town_priv *twn=priv_data; + + attr->type=attr_type; + switch (attr_type) { + case attr_any: + while (twn->attr_next != attr_none) { + if (town_attr_get(twn, twn->attr_next, attr)) + return 1; + } + return 0; + case attr_label: + attr->u.str=twn->district; + twn->attr_next=attr_town_name; + if (attr->u.str[0]) + return 1; + attr->u.str=twn->name; + return ((attr->u.str && attr->u.str[0]) ? 1:0); + case attr_town_name: + attr->u.str=twn->name; + twn->attr_next=attr_town_postal; + return ((attr->u.str && attr->u.str[0]) ? 1:0); + case attr_town_postal: + attr->u.str=twn->postal_code1; + twn->attr_next=attr_district_name; + return ((attr->u.str && attr->u.str[0]) ? 1:0); + case attr_district_name: + attr->u.str=twn->district; + twn->attr_next=attr_debug; + return ((attr->u.str && attr->u.str[0]) ? 1:0); + case attr_town_streets_item: + twn->town_attr_item.type=type_town_streets; + twn->town_attr_item.id_hi=twn->country | (file_town_twn << 16) | 0x10000000; + twn->town_attr_item.id_lo=twn->street_assoc; + attr->u.item=&twn->town_attr_item; + twn->attr_next=attr_debug; + return 1; + case attr_debug: + sprintf(twn->debug, "order %d\nsize %d\nstreet_assoc 0x%x", twn->order, twn->size, twn->street_assoc); + attr->u.str=twn->debug; + twn->attr_next=attr_none; + return 1; + default: + g_assert(1==0); + return 0; + } + return 1; +} + +static struct item_methods town_meth = { + town_coord_rewind, + town_coord_get, + town_attr_rewind, + town_attr_get, +}; + +static void +town_get_data(struct town_priv *twn, unsigned char **p) +{ + twn->id=get_u32_unal(p); + twn->c.x=get_u32_unal(p); + twn->c.y=get_u32_unal(p); + twn->name=get_string(p); + twn->district=get_string(p); + twn->postal_code1=get_string(p); + twn->order=get_u8(p); /* 1-15 (19) */ + twn->country=get_u16(p); + twn->type=get_u8(p); + twn->unknown2=get_u32_unal(p); + twn->size=get_u8(p); + twn->street_assoc=get_u32_unal(p); + twn->unknown3=get_u8(p); + twn->postal_code2=get_string(p); + twn->unknown4=get_u32_unal(p); +#if 0 + printf("%s\t%s\t%s\t%d\t%d\t%d\n",twn->name,twn->district,twn->postal_code1,twn->order, twn->country, twn->type); +#endif +} + /*0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 */ +static unsigned char limit[]={0,1,2,2,4,6,8,10,11,13,14,14,14,20,20,20,20,20,20}; + +static enum item_type town_item[]={type_town_label_5e1, type_town_label_1e2, type_town_label_2e2, type_town_label_5e2, type_town_label_1e3, type_town_label_1e3, type_town_label_2e3, type_town_label_5e3, type_town_label_1e4, type_town_label_2e4, type_town_label_5e4, type_town_label_1e5, type_town_label_1e5, type_town_label_2e5, type_town_label_5e5, type_town_label_1e6, type_town_label_2e6}; +static enum item_type district_item[]={type_district_label_5e1, type_district_label_1e2, type_district_label_2e2, type_district_label_5e2, type_district_label_1e3, type_district_label_1e3, type_district_label_2e3, type_district_label_5e3, type_district_label_1e4, type_district_label_2e4, type_district_label_5e4, type_district_label_1e5, type_district_label_1e5, type_district_label_2e5, type_district_label_5e5, type_district_label_1e6, type_district_label_2e6}; +int +town_get(struct map_rect_priv *mr, struct town_priv *twn, struct item *item) +{ + int size; + for (;;) { + if (mr->b.p >= mr->b.end) + return 0; + town_get_data(twn, &mr->b.p); + twn->cidx=0; + twn->aidx=0; + twn->attr_next=attr_label; + if (! mr->cur_sel || (twn->order <= limit[mr->cur_sel->order[layer_town]] && coord_rect_contains(&mr->cur_sel->rect,&twn->c))) { + switch(twn->type) { + case 1: + size=twn->size; + if (size >= sizeof(town_item)/sizeof(enum item_type)) + size=sizeof(town_item)/sizeof(enum item_type)-1; + item->type=town_item[size]; + break; + case 3: + size=twn->size; + if (size == 6 && twn->order < 14) + size++; + if (size == 5 && twn->order < 14) + size+=2; + if (size >= sizeof(district_item)/sizeof(enum item_type)) + size=sizeof(district_item)/sizeof(enum item_type)-1; + item->type=district_item[size]; + break; + case 4: + item->type=type_port_label; + break; + case 9: + item->type=type_highway_exit_label; + break; + default: + printf("unknown town type 0x%x '%s' '%s' 0x%x,0x%x\n", twn->type, twn->name, twn->district, twn->c.x, twn->c.y); + item->type=type_town_label; + } + item->id_hi=twn->country | (mr->current_file << 16); + item->id_lo=twn->id; + item->priv_data=twn; + item->meth=&town_meth; + return 1; + } + } +} + +int +town_get_byid(struct map_rect_priv *mr, struct town_priv *twn, int id_hi, int id_lo, struct item *item) +{ + int country=id_hi & 0xffff; + int res; + if (!tree_search_hv(mr->m->dirname, "town", (id_lo >> 8) | (country << 24), id_lo & 0xff, &res)) + return 0; + block_get_byindex(mr->m->file[mr->current_file], res >> 16, &mr->b); + mr->b.p=mr->b.block_start+(res & 0xffff); + return town_get(mr, twn, item); +} + +static int +town_search_compare(unsigned char **p, struct map_rect_priv *mr) +{ + int country, d; + char *name; + + country=get_u16(p); + dbg(1,"country 0x%x ", country); + name=get_string(p); + dbg(1,"name '%s' ",name); + mr->search_blk_count=get_u32(p); + mr->search_blk_off=(struct block_offset *)(*p); + dbg(1,"len %d ", mr->search_blk_count); + (*p)+=mr->search_blk_count*4; + d=mr->search_country-country; + if (!d) { + if (mr->search_partial) + d=strncasecmp(mr->search_str, name, strlen(mr->search_str)); + else + d=strcasecmp(mr->search_str, name); + } + dbg(1,"%d \n",d); + return d; + +} + + + +struct item * +town_search_get_item(struct map_rect_priv *mr) +{ + int dir=1,leaf; + + if (! mr->search_blk_count) { + if (mr->search_partial) { + dbg(1,"partial 0x%x '%s' ***\n", mr->search_country, mr->search_str); + if (! mr->search_linear) { + while ((leaf=tree_search_next(&mr->ts, &mr->search_p, dir)) != -1) { + dir=town_search_compare(&mr->search_p, mr); + if (! dir && leaf) { + mr->search_linear=1; + mr->search_p=NULL; + break; + } + } + if (! mr->search_linear) + return NULL; + } + if (! tree_search_next_lin(&mr->ts, &mr->search_p)) + return NULL; + if (town_search_compare(&mr->search_p, mr)) + return NULL; + dbg(1,"found %d blocks\n",mr->search_blk_count); + } else { + #if 0 + dbg(1,"full 0x%x '%s' ***\n", country, search); + while (tree_search_next(&ts, &p, dir) != -1) { + ps=p; + printf("0x%x ",p-ts.f->begin); + dir=show_town2(&p, country, search, 0); + if (! dir) { + printf("*** found full: "); + show_town2(&ps, country, search, 0); + break; + } + } + #endif + return NULL; + } + } + if (! mr->search_blk_count) + return NULL; + dbg(1,"block 0x%x offset 0x%x\n", mr->search_blk_off->block, mr->search_blk_off->offset); + block_get_byindex(mr->m->file[mr->current_file], mr->search_blk_off->block, &mr->b); + mr->b.p=mr->b.block_start+mr->search_blk_off->offset; + town_get(mr, &mr->town, &mr->item); + mr->search_blk_off++; + mr->search_blk_count--; + return &mr->item; +} diff --git a/src/data/mg/tree.c b/src/data/mg/tree.c new file mode 100644 index 00000000..aedce721 --- /dev/null +++ b/src/data/mg/tree.c @@ -0,0 +1,232 @@ +#include <stdio.h> +#include "debug.h" +#include "mg.h" + +struct tree_hdr { + unsigned int addr; + unsigned int size; + unsigned int low; +}; + +struct tree_hdr_h { + unsigned int addr; + unsigned int size; +}; + +struct tree_leaf_h { + unsigned int lower; + unsigned int higher; + unsigned int match; + unsigned int value; +}; + + +struct tree_hdr_v { + unsigned int count; + unsigned int next; + unsigned int unknown; +}; + +struct tree_leaf_v { + unsigned char key; + int value; +} __attribute__((packed)); + +static int +tree_search_h(struct file *file, unsigned int search) +{ + unsigned char *p=file->begin,*end; + int last,i=0,value,lower; + struct tree_hdr_h *thdr; + struct tree_leaf_h *tleaf; + + dbg(1,"enter\n"); + while (i++ < 1000) { + thdr=(struct tree_hdr_h *)p; + p+=sizeof(*thdr); + end=p+thdr->size; + dbg(1,"@0x%x\n", p-file->begin); + last=0; + while (p < end) { + tleaf=(struct tree_leaf_h *)p; + p+=sizeof(*tleaf); + dbg(1,"low:0x%x high:0x%x match:0x%x val:0x%x search:0x%x\n", tleaf->lower, tleaf->higher, tleaf->match, tleaf->value, search); + value=tleaf->value; + if (value == search) + return tleaf->match; + if (value > search) { + dbg(1,"lower\n"); + lower=tleaf->lower; + if (lower) + last=lower; + break; + } + last=tleaf->higher; + } + if (! last || last == -1) + return 0; + p=file->begin+last; + } + return 0; +} + +static int +tree_search_v(struct file *file, int offset, int search) +{ + unsigned char *p=file->begin+offset; + int i=0,count,next; + struct tree_hdr_v *thdr; + struct tree_leaf_v *tleaf; + while (i++ < 1000) { + thdr=(struct tree_hdr_v *)p; + p+=sizeof(*thdr); + count=L(thdr->count); + dbg(1,"offset=0x%x count=0x%x\n", p-file->begin, count); + while (count--) { + tleaf=(struct tree_leaf_v *)p; + p+=sizeof(*tleaf); + dbg(1,"0x%x 0x%x\n", tleaf->key, search); + if (tleaf->key == search) + return L(tleaf->value); + } + next=L(thdr->next); + if (! next) + break; + p=file->begin+next; + } + return 0; +} + +int +tree_search_hv(char *dirname, char *filename, unsigned int search_h, unsigned int search_v, int *result) +{ + struct file *f_idx_h, *f_idx_v; + char buffer[4096]; + int h,v; + + dbg(1,"enter(%s, %s, 0x%x, 0x%x, %p)\n",dirname, filename, search_h, search_v, result); + sprintf(buffer, "%s/%s.h1", dirname, filename); + f_idx_h=file_create_caseinsensitive(buffer); + sprintf(buffer, "%s/%s.v1", dirname, filename); + f_idx_v=file_create_caseinsensitive(buffer); + dbg(1,"%p %p\n", f_idx_h, f_idx_v); + if ((h=tree_search_h(f_idx_h, search_h))) { + dbg(1,"h=0x%x\n", h); + if ((v=tree_search_v(f_idx_v, h, search_v))) { + dbg(1,"v=0x%x\n", v); + *result=v; + file_destroy(f_idx_v); + file_destroy(f_idx_h); + dbg(1,"return 1\n"); + return 1; + } + } + file_destroy(f_idx_v); + file_destroy(f_idx_h); + dbg(1,"return 0\n"); + return 0; +} + +static struct tree_search_node * +tree_search_enter(struct tree_search *ts, int offset) +{ + struct tree_search_node *tsn=&ts->nodes[++ts->curr_node]; + unsigned char *p; + p=ts->f->begin+offset; + tsn->hdr=(struct tree_hdr *)p; + tsn->p=p+sizeof(struct tree_hdr); + tsn->last=tsn->p; + tsn->end=p+tsn->hdr->size; + tsn->low=tsn->hdr->low; + tsn->high=tsn->hdr->low; + dbg(1,"pos 0x%x addr 0x%x size 0x%x low 0x%x end 0x%x\n", p-ts->f->begin, tsn->hdr->addr, tsn->hdr->size, tsn->hdr->low, tsn->end-ts->f->begin); + return tsn; +} + +int tree_search_next(struct tree_search *ts, unsigned char **p, int dir) +{ + struct tree_search_node *tsn=&ts->nodes[ts->curr_node]; + + if (! *p) + *p=tsn->p; + dbg(1,"next *p=%p dir=%d\n", *p, dir); + dbg(1,"low1=0x%x high1=0x%x\n", tsn->low, tsn->high); + if (dir <= 0) { + dbg(1,"down 0x%x\n", tsn->low); + if (tsn->low != 0xffffffff) { + tsn=tree_search_enter(ts, tsn->low); + *p=tsn->p; + tsn->high=get_u32(p); + ts->last_node=ts->curr_node; + dbg(1,"saving last2 %d 0x%x\n", ts->curr_node, tsn->last-ts->f->begin); + dbg(1,"high2=0x%x\n", tsn->high); + return 0; + } + return -1; + } + tsn->low=tsn->high; + tsn->last=*p; + tsn->high=get_u32(p); + dbg(1,"saving last3 %d %p\n", ts->curr_node, tsn->last); + if (*p < tsn->end) + return (tsn->low == 0xffffffff ? 1 : 0); + dbg(1,"end reached\n"); + if (tsn->low != 0xffffffff) { + dbg(1,"low 0x%x\n", tsn->low); + tsn=tree_search_enter(ts, tsn->low); + *p=tsn->p; + tsn->high=get_u32(p); + ts->last_node=ts->curr_node; + dbg(1,"saving last4 %d 0x%x\n", ts->curr_node, tsn->last-ts->f->begin); + dbg(1,"high4=0x%x\n", tsn->high); + return 0; + } + return -1; +} + +int tree_search_next_lin(struct tree_search *ts, unsigned char **p) +{ + struct tree_search_node *tsn=&ts->nodes[ts->curr_node]; + int high; + + dbg(1,"pos=%d 0x%x\n", ts->curr_node, *p-ts->f->begin); + if (*p) + ts->nodes[ts->last_node].last=*p; + *p=tsn->last; + for (;;) { + high=get_u32(p); + if (*p < tsn->end) { + ts->last_node=ts->curr_node; + while (high != 0xffffffff) { + tsn=tree_search_enter(ts, high); + dbg(1,"reload %d\n",ts->curr_node); + high=tsn->low; + } + return 1; + } + dbg(1,"eon %d 0x%x 0x%x\n", ts->curr_node, *p-ts->f->begin, tsn->end-ts->f->begin); + if (! ts->curr_node) + break; + ts->curr_node--; + tsn=&ts->nodes[ts->curr_node]; + *p=tsn->last; + } + + return 0; +} + +void +tree_search_init(char *dirname, char *filename, struct tree_search *ts, int offset) +{ + char buffer[4096]; + sprintf(buffer, "%s/%s", dirname, filename); + ts->f=file_create_caseinsensitive(buffer); + ts->curr_node=-1; + tree_search_enter(ts, offset); +} + +void +tree_search_free(struct tree_search *ts) +{ + file_destroy(ts->f); +} diff --git a/src/data/textfile/Makefile.am b/src/data/textfile/Makefile.am new file mode 100644 index 00000000..92850723 --- /dev/null +++ b/src/data/textfile/Makefile.am @@ -0,0 +1,4 @@ +include $(top_srcdir)/Makefile.inc +AM_CPPFLAGS = @NAVIT_CFLAGS@ -I../.. +plugin_LTLIBRARIES = libdata_textfile.la +libdata_textfile_la_SOURCES = textfile.c textfile.h diff --git a/src/data/textfile/textfile.c b/src/data/textfile/textfile.c new file mode 100644 index 00000000..e5c3497a --- /dev/null +++ b/src/data/textfile/textfile.c @@ -0,0 +1,355 @@ +#include <glib.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <math.h> +#include "plugin.h" +#include "map.h" +#include "maptype.h" +#include "item.h" +#include "attr.h" +#include "coord.h" +#include "transform.h" +#include "projection.h" + +#include "textfile.h" + +static int map_id; + +static int +contains_coord(char *line) +{ + return g_ascii_isdigit(line[0]); +} + +static int debug=0; + +static int +get_tag(char *line, char *name, int *pos, char *ret, char *name_ret) +{ + int len=0,quoted; + char *p,*e,*n; + + if (debug) + printf("get_tag %s from %s\n", name, line); + if (name) + len=strlen(name); + if (pos) + p=line+*pos; + else + p=line; + for(;;) { + while (*p == ' ') { + p++; + } + if (! *p) + return 0; + n=p; + e=index(p,'='); + if (! e) + return 0; + p=e+1; + quoted=0; + while (*p) { + if (*p == ' ' && !quoted) + break; + if (*p == '"') + quoted=1-quoted; + p++; + } + if (name == NULL || (e-n == len && !strncmp(n, name, len))) { + if (name_ret) { + len=e-n; + strncpy(name_ret, n, len); + name_ret[len]='\0'; + } + e++; + len=p-e; + if (e[0] == '"') { + e++; + len-=2; + } + strncpy(ret, e, len); + ret[len]='\0'; + if (pos) + *pos=p-line; + return 1; + } + } + return 0; +} + +static void +get_line(struct map_rect_priv *mr) +{ + if(mr->f) { + mr->pos=ftell(mr->f); + fgets(mr->line, SIZE, mr->f); + if (strlen(mr->line) >= SIZE-1) + printf("line too long\n"); + } +} + +static void +map_destroy_textfile(struct map_priv *m) +{ + if (debug) + printf("map_destroy_textfile\n"); + g_free(m); +} + +static void +textfile_coord_rewind(void *priv_data) +{ +} + +static void +parse_line(struct map_rect_priv *mr) +{ + int pos=0; + sscanf(mr->line,"%lf %c %lf %c %n",&mr->lat,&mr->lat_c,&mr->lng,&mr->lng_c,&pos); + if (pos < strlen(mr->line)) { + strcpy(mr->attrs, mr->line+pos); + } +} + +static int +textfile_coord_get(void *priv_data, struct coord *c, int count) +{ + double lat,lng; + struct coord_geo cg; + struct map_rect_priv *mr=priv_data; + int ret=0; + if (debug) + printf("textfile_coord_get %d\n",count); + while (count--) { + if (contains_coord(mr->line) && mr->f && !feof(mr->f) && (!mr->item.id_hi || !mr->eoc)) { + parse_line(mr); + lat=mr->lat; + lng=mr->lng; + cg.lat=floor(lat/100); + lat-=cg.lat*100; + cg.lat+=lat/60; + + cg.lng=floor(lng/100); + lng-=cg.lng*100; + cg.lng+=lng/60; + + transform_from_geo(projection_mg, &cg, c); + c++; + ret++; + get_line(mr); + if (mr->item.id_hi) + mr->eoc=1; + } else { + break; + } + } + return ret; +} + +static void +textfile_attr_rewind(void *priv_data) +{ +} + +static void +textfile_encode_attr(char *attr_val, enum attr_type attr_type, struct attr *attr) +{ + if (attr_type >= attr_type_int_begin && attr_type <= attr_type_int_end) + attr->u.num=atoi(attr_val); + else + attr->u.str=attr_val; +} + +static int +textfile_attr_get(void *priv_data, enum attr_type attr_type, struct attr *attr) +{ + struct map_rect_priv *mr=priv_data; + char *str=NULL; + if (debug) + printf("textfile_attr_get mr=%p attrs='%s' ", mr, mr->attrs); + if (attr_type != mr->attr_last) { + if (debug) + printf("reset attr_pos\n"); + mr->attr_pos=0; + mr->attr_last=attr_type; + } + if (attr_type == attr_any) { + if (debug) + printf("attr_any"); + if (get_tag(mr->attrs,NULL,&mr->attr_pos,mr->attr, mr->attr_name)) { + attr_type=attr_from_name(mr->attr_name); + if (debug) + printf("found attr '%s' 0x%x\n", mr->attr_name, attr_type); + attr->type=attr_type; + textfile_encode_attr(mr->attr, attr_type, attr); + return 1; + } + } else { + str=attr_to_name(attr_type); + if (debug) + printf("attr='%s' ",str); + if (get_tag(mr->attrs,str,&mr->attr_pos,mr->attr, NULL)) { + textfile_encode_attr(mr->attr, attr_type, attr); + if (debug) + printf("found\n"); + return 1; + } + } + if (debug) + printf("not found\n"); + return 0; +} + +static struct item_methods methods_textfile = { + textfile_coord_rewind, + textfile_coord_get, + textfile_attr_rewind, + textfile_attr_get, +}; + +static struct map_rect_priv * +map_rect_new_textfile(struct map_priv *map, struct map_selection *sel) +{ + struct map_rect_priv *mr; + + if (debug) + printf("map_rect_new_textfile\n"); + mr=g_new0(struct map_rect_priv, 1); + mr->m=map; + mr->sel=sel; + mr->item.id_hi=0; + mr->item.id_lo=0; + mr->item.meth=&methods_textfile; + mr->item.priv_data=mr; + mr->f=fopen(map->filename, "r"); + if(!mr->f) { + printf("map_rect_new_textfile unable to open textfile %s\n",map->filename); + } + get_line(mr); + return mr; +} + + +static void +map_rect_destroy_textfile(struct map_rect_priv *mr) +{ + if (mr->f) { + fclose(mr->f); + } + g_free(mr); +} + +static struct item * +map_rect_get_item_textfile(struct map_rect_priv *mr) +{ + char *p,type[SIZE]; + if (debug) + printf("map_rect_get_item_textfile id_hi=%d line=%s", mr->item.id_hi, mr->line); + if (!mr->f) { + return NULL; + } + for(;;) { + if (feof(mr->f)) { + if (debug) + printf("map_rect_get_item_textfile: eof\n"); + if (mr->item.id_hi) { + return NULL; + } + mr->item.id_hi++; + fseek(mr->f, 0, SEEK_SET); + get_line(mr); + } + if (mr->item.id_hi) { + if (!contains_coord(mr->line)) { + get_line(mr); + continue; + } + if ((p=index(mr->line,'\n'))) + *p='\0'; + if (debug) + printf("map_rect_get_item_textfile: point found\n"); + mr->attrs[0]='\0'; + parse_line(mr); + mr->eoc=0; + mr->item.id_lo=mr->pos; + } else { + if (contains_coord(mr->line)) { + get_line(mr); + continue; + } + if ((p=index(mr->line,'\n'))) + *p='\0'; + if (debug) + printf("map_rect_get_item_textfile: line found\n"); + if (! mr->line[0]) { + get_line(mr); + continue; + } + mr->item.id_lo=mr->pos; + strcpy(mr->attrs, mr->line); + get_line(mr); + if (debug) + printf("mr=%p attrs=%s\n", mr, mr->attrs); + } + if (debug) + printf("get_attrs %s\n", mr->attrs); + if (get_tag(mr->attrs,"type",NULL,type,NULL)) { + if (debug) + printf("type='%s'\n", type); + mr->item.type=item_from_name(type); + if (mr->item.type == type_none) + printf("Warning: type '%s' unknown\n", type); + } else { + get_line(mr); + continue; + } + mr->attr_last=attr_none; + if (debug) + printf("return attr='%s'\n", mr->attrs); + return &mr->item; + } +} + +static struct item * +map_rect_get_item_byid_textfile(struct map_rect_priv *mr, int id_hi, int id_lo) +{ + fseek(mr->f, id_lo, SEEK_SET); + get_line(mr); + mr->item.id_hi=id_hi; + return map_rect_get_item_textfile(mr); +} + +static struct map_methods map_methods_textfile = { + map_destroy_textfile, + map_rect_new_textfile, + map_rect_destroy_textfile, + map_rect_get_item_textfile, + map_rect_get_item_byid_textfile, +}; + +static struct map_priv * +map_new_textfile(struct map_methods *meth, char *filename, char **charset, enum projection *pro) +{ + struct map_priv *m; + if (debug) + printf("map_new_textfile %s\n",filename); + *meth=map_methods_textfile; + *charset="iso8859-1"; + *pro=projection_mg; + + m=g_new(struct map_priv, 1); + m->id=++map_id; + m->filename=g_strdup(filename); + return m; +} + +void +plugin_init(void) +{ + if (debug) + printf("textfile: plugin_init\n"); + plugin_register_map_type("textfile", map_new_textfile); +} + diff --git a/src/data/textfile/textfile.h b/src/data/textfile/textfile.h new file mode 100644 index 00000000..980c95d6 --- /dev/null +++ b/src/data/textfile/textfile.h @@ -0,0 +1,28 @@ +#include <stdio.h> +#include "attr.h" +#include "coord.h" +struct map_priv { + int id; + char *filename; +}; + +#define SIZE 512 + +struct map_rect_priv { + struct map_selection *sel; + + FILE *f; + long pos; + char line[SIZE]; + int attr_pos; + enum attr_type attr_last; + char attrs[SIZE]; + char attr[SIZE]; + char attr_name[SIZE]; + double lat,lng; + char lat_c,lng_c; + int eoc; + struct map_priv *m; + struct item item; +}; + |