/** * Navit, a modular navigation system. * Copyright (C) 2005-2008 Navit Team * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * version 2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include "config.h" #include "plugin.h" #include "data.h" #include "projection.h" #include "map.h" #include "maptype.h" #include "item.h" #include "attr.h" #include "coord.h" #include "transform.h" #include #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); coord_format(g.lat,g.lng,DEGREES_MINUTES_SECONDS, buffer,sizeof(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 = { projection_garmin, "iso8859-1", 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, struct attr **attrs) { struct map_priv *m; struct attr *data=attr_search(attrs, NULL, attr_data); if (! data) return NULL; *meth=map_methods_garmin_img; m=g_new(struct map_priv, 1); m->id=++map_id; m->filename=g_strdup(data->u.str); return m; } void plugin_init(void) { plugin_register_map_type("garmin_img", map_new_garmin_img); }