Fix:Mg:Applied patch from ticket #526, broken M&G street search
[navit-package] / navit / map / mg / map.c
1 /**
2  * Navit, a modular navigation system.
3  * Copyright (C) 2005-2008 Navit Team
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * version 2 as published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the
16  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  * Boston, MA  02110-1301, USA.
18  */
19
20 #include <stdio.h>
21 #include <string.h>
22 #include "config.h"
23 #include "debug.h"
24 #include "plugin.h"
25 #include "maptype.h"
26 #include "mg.h"
27
28
29 GList *maps;
30
31 static struct country_isonum {
32         int country;
33         int isonum;
34         int postal_len;
35         char *postal_prefix;
36 } country_isonums[]={
37   {  1,203},
38   {  2,703},
39   {  7,674},
40   { 11,233},
41   { 12,268},
42   { 13,428},
43   { 14,440},
44   { 15,498},
45   { 16,643},
46   { 17,804},
47   { 18,112},
48   { 20,818},
49   { 30,300},
50   { 31,528},
51   { 32, 56},
52   { 33,250},
53   { 34,724},
54   { 36,348},
55   { 39,380},
56   { 40,642},
57   { 41,756},
58   { 43, 40},
59   { 44,826},
60   { 45,208},
61   { 46,752},
62   { 47,578},
63   { 48,616},
64   { 49,276,5,"D@@"},
65   { 50,292},
66   { 51,620},
67   { 52,442},
68   { 53,372},
69   { 54,352},
70   { 55,  8},
71   { 56,470},
72   { 57,196},
73   { 58,246},
74   { 59,100},
75   { 61,422},
76   { 62, 20},
77   { 63,760},
78   { 66,682},
79   { 71,434},
80   { 72,376},
81   { 73,275},
82   { 75,438},
83   { 76,504},
84   { 77, 12},
85   { 78,788},
86   { 81,688},
87   { 83,400},
88   { 85,191},
89   { 86,705},
90   { 87, 70},
91   { 89,807},
92   { 90,792},
93   { 93,492},
94   { 94, 31},
95   { 95, 51},
96   { 98,234},
97   { 99,732},
98   {336,774},
99 };
100
101 struct map_priv * map_new_mg(struct map_methods *meth, struct attr **attrs);
102
103 static int map_id;
104
105 static char *file[]={
106         [file_border_ply]="border.ply",
107         [file_bridge_ply]="bridge.ply",
108         [file_build_ply]="build.ply",
109         [file_golf_ply]="golf.ply",
110         [file_height_ply]="height.ply",
111         [file_natpark_ply]="natpark.ply",
112         [file_nature_ply]="nature.ply",
113         [file_other_ply]="other.ply",
114         [file_rail_ply]="rail.ply",
115         [file_sea_ply]="sea.ply",
116         [file_street_bti]="street.bti",
117         [file_street_str]="street.str",
118         [file_strname_stn]="strname.stn",
119         [file_town_twn]="town.twn",
120         [file_tunnel_ply]="tunnel.ply",
121         [file_water_ply]="water.ply",
122         [file_woodland_ply]="woodland.ply",
123 };
124
125 int mg_country_from_isonum(int isonum)
126 {
127         int i;
128         for (i = 0 ; i < sizeof(country_isonums)/sizeof(struct country_isonum) ; i++)
129                 if (country_isonums[i].isonum == isonum)
130                         return country_isonums[i].country;
131         return 0;
132 }
133
134 int mg_country_to_isonum(int country)
135 {
136         int i;
137         for (i = 0 ; i < sizeof(country_isonums)/sizeof(struct country_isonum) ; i++)
138                 if (country_isonums[i].country == country)
139                         return country_isonums[i].isonum;
140         return 0;
141 }
142
143 int mg_country_postal_len(int country)
144 {
145         int i;
146         for (i = 0 ; i < sizeof(country_isonums)/sizeof(struct country_isonum) ; i++)
147                 if (country_isonums[i].country == country)
148                         return country_isonums[i].postal_len;
149         return 0;
150 }
151
152 static char *mg_country_postal_prefix(int isonum)
153 {
154         int i;
155         for (i = 0 ; i < sizeof(country_isonums)/sizeof(struct country_isonum) ; i++)
156                 if (country_isonums[i].isonum == isonum)
157                         return country_isonums[i].postal_prefix;
158         return NULL;
159 }
160
161 struct item_range town_ranges[]={
162         {type_town_label,type_port_label},
163 };
164
165 struct item_range street_ranges[]={
166         {type_street_nopass,type_street_unkn},
167 };
168
169 struct item_range poly_ranges[]={
170         {type_border_country,type_water_line},
171         {type_street_unkn,type_street_unkn},
172         {type_area,type_last},
173 };
174
175
176 static int
177 file_next(struct map_rect_priv *mr)
178 {
179         int debug=0;
180
181         for (;;) {
182                 mr->current_file++;
183                 if (mr->current_file >= file_end)
184                         return 0;
185                 mr->file=mr->m->file[mr->current_file];
186                 if (! mr->file)
187                         continue;
188                 switch (mr->current_file) {
189                 case file_strname_stn:
190                         continue;
191                 case file_town_twn:
192                         if (mr->cur_sel && !map_selection_contains_item_range(mr->cur_sel, 0, town_ranges, sizeof(town_ranges)/sizeof(struct item_range)))
193                                 continue;
194                         break;
195                 case file_street_str:
196                         if (mr->cur_sel && !map_selection_contains_item_range(mr->cur_sel, 0, street_ranges, sizeof(street_ranges)/sizeof(struct item_range)))
197                                 continue;
198                         break;
199                 default:
200                         if (mr->cur_sel && !map_selection_contains_item_range(mr->cur_sel, 0, poly_ranges, sizeof(poly_ranges)/sizeof(struct item_range)))
201                                 continue;
202                         break;
203                 }
204                 if (debug)
205                         printf("current file: '%s'\n", file[mr->current_file]);
206                 mr->cur_sel=mr->xsel;
207                 if (block_init(mr))
208                         return 1;
209         }
210 }
211
212 static void
213 map_destroy_mg(struct map_priv *m)
214 {
215         int i;
216
217         printf("mg_map_destroy\n");
218         for (i = 0 ; i < file_end ; i++) {
219                 if (m->file[i])
220                         file_destroy(m->file[i]);
221         }
222 }
223
224 extern int block_lin_count,block_idx_count,block_active_count,block_mem,block_active_mem;
225
226 struct map_rect_priv *
227 map_rect_new_mg(struct map_priv *map, struct map_selection *sel)
228 {
229         struct map_rect_priv *mr;
230         int i;
231
232         block_lin_count=0;
233         block_idx_count=0;
234         block_active_count=0;
235         block_mem=0;
236         block_active_mem=0;
237         mr=g_new0(struct map_rect_priv, 1);
238         mr->m=map;
239         mr->xsel=sel;
240         mr->current_file=-1;
241         if (sel && sel->next)
242                 for (i=0 ; i < file_end ; i++) 
243                         mr->block_hash[i]=g_hash_table_new(g_int_hash,g_int_equal);
244         file_next(mr);
245         return mr;
246 }
247
248
249 static struct item *
250 map_rect_get_item_mg(struct map_rect_priv *mr)
251 {
252         for (;;) {
253                 switch (mr->current_file) {
254                 case file_town_twn:
255                         if (town_get(mr, &mr->town, &mr->item))
256                                 return &mr->item;
257                         break;
258                 case file_border_ply:
259                 case file_bridge_ply:
260                 case file_build_ply: 
261                 case file_golf_ply: 
262                 /* case file_height_ply: */
263                 case file_natpark_ply: 
264                 case file_nature_ply: 
265                 case file_other_ply:
266                 case file_rail_ply:
267                 case file_sea_ply:
268                 /* case file_tunnel_ply: */
269                 case file_water_ply:
270                 case file_woodland_ply:
271                         if (poly_get(mr, &mr->poly, &mr->item))
272                                 return &mr->item;
273                         break;
274                 case file_street_str:
275                         if (street_get(mr, &mr->street, &mr->item))
276                                 return &mr->item;
277                         break;
278                 case file_end:
279                         return NULL;
280                 default:
281                         break;
282                 }
283                 if (block_next(mr))
284                         continue;
285                 if (mr->cur_sel->next) {
286                         mr->cur_sel=mr->cur_sel->next;
287                         if (block_init(mr))
288                                 continue;
289                 }
290                 if (file_next(mr))
291                         continue;
292                 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);
293                 return NULL;
294         }
295 }
296
297 struct item *
298 map_rect_get_item_byid_mg(struct map_rect_priv *mr, int id_hi, int id_lo)
299 {
300         mr->current_file = (id_hi >> 16) & 0xff;
301         switch (mr->current_file) {
302         case file_town_twn:
303                 if (town_get_byid(mr, &mr->town, id_hi, id_lo, &mr->item))
304                         return &mr->item;
305                 break;
306         case file_street_str:
307                 if (street_get_byid(mr, &mr->street, id_hi, id_lo, &mr->item))
308                         return &mr->item;
309                 break;
310         case file_strname_stn:
311                 if (street_name_get_byid(mr, &mr->street, id_hi, id_lo, &mr->item))
312                         return &mr->item;
313                 break;
314         default:        
315                 if (poly_get_byid(mr, &mr->poly, id_hi, id_lo, &mr->item))
316                         return &mr->item;
317                 break;
318         }
319         return NULL;
320 }
321
322
323 void
324 map_rect_destroy_mg(struct map_rect_priv *mr)
325 {
326         int i;
327         for (i=0 ; i < file_end ; i++) 
328                 if (mr->block_hash[i])
329                         g_hash_table_destroy(mr->block_hash[i]);        
330         g_free(mr);
331 }
332
333 static char *
334 map_search_mg_convert_special(char *str)
335 {
336         char *ret,*c=g_malloc(strlen(str)*2+1);
337
338         ret=c;
339         for (;;) {
340                 switch ((unsigned char)(*str)) {
341                 case 0xc4:
342                         *c++='A';
343                         break;
344                 case 0xd6:
345                         *c++='O';
346                         break;
347                 case 0xdc:
348                         *c++='U';
349                         break;
350                 case 0xdf:
351                         *c++='s';
352                         *c++='s';
353                         break;
354                 case 0xe4:
355                         *c++='a';
356                         break;
357                 case 0xf6:
358                         *c++='o';
359                         break;
360                 case 0xfc:
361                         *c++='u';
362                         break;
363                 default:
364                         dbg(1,"0x%x\n", *str);
365                         *c++=*str;
366                         break;
367                 }
368                 if (! *str)
369                         return ret;
370                 str++;
371         }
372 }
373
374 static int
375 map_search_setup(struct map_rect_priv *mr)
376 {
377         char *prefix;
378         dbg(1,"%s\n", attr_to_name(mr->search_type));
379         switch (mr->search_type) {
380         case attr_town_postal:
381                 if (mr->search_item.type != type_country_label) {
382                         dbg(0,"wrong parent type %s\n", item_to_name(mr->search_item.type));
383                         return 0;
384                 }
385                 prefix=mg_country_postal_prefix(mr->search_item.id_lo);
386                 if (! prefix)
387                         return 0;
388                 tree_search_init(mr->m->dirname, "town.b1", &mr->ts, 0);
389                 mr->current_file=file_town_twn;
390                 mr->search_str=g_strdup_printf("%s%s",prefix,mr->search_attr->u.str);
391                 dbg(0,"search_str='%s'\n",mr->search_str);
392                 mr->search_country=mg_country_from_isonum(mr->search_item.id_lo);
393                 break;
394         case attr_town_name:
395                 if (mr->search_item.type != type_country_label) {
396                         dbg(0,"wrong parent type %s\n", item_to_name(mr->search_item.type));
397                         return 0;
398                 }
399                 tree_search_init(mr->m->dirname, "town.b2", &mr->ts, 0x1000);
400                 mr->current_file=file_town_twn;
401                 mr->search_str=map_search_mg_convert_special(mr->search_attr->u.str);
402                 mr->search_country=mg_country_from_isonum(mr->search_item.id_lo);
403                 break;
404         case attr_district_name:
405                 if (mr->search_item.type != type_country_label) {
406                         dbg(0,"wrong parent type %s\n", item_to_name(mr->search_item.type));
407                         return 0;
408                 }
409                 tree_search_init(mr->m->dirname, "town.b3", &mr->ts, 0x1000);
410                 mr->current_file=file_town_twn;
411                 mr->search_str=map_search_mg_convert_special(mr->search_attr->u.str);
412                 mr->search_country=mg_country_from_isonum(mr->search_item.id_lo);
413                 break;
414         case attr_street_name:
415                 if (mr->search_item.type != type_town_streets) {
416                         GList *tmp=maps;
417                         struct item *item=NULL;
418                         struct attr attr;
419                         struct map_rect_priv *mr2;
420                         while (tmp) {   
421                                 mr2=map_rect_new_mg(tmp->data, NULL);
422                                 item=map_rect_get_item_byid_mg(mr2, mr->search_item.id_hi, mr->search_item.id_lo);
423                                 if (item)
424                                         break;
425                                 map_rect_destroy_mg(mr2);
426                                 tmp=g_list_next(tmp);
427                         }
428                         if (item) {
429                                 if (item_attr_get(item, attr_town_streets_item, &attr)) {
430                                         mr->search_item=*attr.u.item;
431                                         map_rect_destroy_mg(mr2);
432                                 } else {
433                                         map_rect_destroy_mg(mr2);
434                                         return 0;
435                                 }
436                         } else {
437                                 dbg(0,"wrong parent type %s %p 0x%x 0x%x\n", item_to_name(mr->search_item.type), item, mr->search_item.id_hi, mr->search_item.id_lo);
438                                 return 0;
439                         }
440                 }
441                 dbg(1,"street_assoc=0x%x\n", mr->search_item.id_lo);
442                 tree_search_init(mr->m->dirname, "strname.b1", &mr->ts, 0);
443                 mr->current_file=file_strname_stn;
444                 mr->search_str=g_strdup(mr->search_attr->u.str);
445                 break;
446         case attr_house_number:
447                 if (!map_priv_is(mr->search_item.map, mr->m))
448                         return 0;
449                 if (!housenumber_search_setup(mr)) {
450                         dbg(0,"failed to search for attr_house_number\n");
451                         return 0;
452                 }
453                 break;
454         default:
455                 dbg(0,"unknown search %s\n",attr_to_name(mr->search_type));
456                 return 0;
457         }
458         mr->file=mr->m->file[mr->current_file];
459         block_init(mr);
460         return 1;
461 }
462 static void map_search_cleanup(struct map_rect_priv *mr);
463
464 static struct item * map_search_get_item_mg(struct map_search_priv *ms);
465
466 static struct map_search_priv *
467 map_search_new_mg(struct map_priv *map, struct item *item, struct attr *search, int partial)
468 {
469         struct map_rect_priv *mr=g_new0(struct map_rect_priv, 1);
470         dbg(1,"searching for %s '%s'\n", attr_to_name(search->type), search->u.str);
471         dbg(1,"id_lo=0x%x\n", item->id_lo);
472         dbg(1,"search=%s\n", search->u.str);
473         mr->m=map;
474         mr->search_attr=attr_dup(search);
475         mr->search_type=search->type;
476         mr->search_item=*item;
477         mr->search_partial=partial;
478         if (search->type == attr_town_or_district_name) {
479                 mr->search_type=attr_town_name;
480                 mr->search_type_next=attr_district_name;        
481         }
482         if (!map_search_setup(mr)) {
483                 dbg(1,"map_search_new_mg failed\n");
484                 g_free(mr);
485                 return NULL;
486         }
487         mr->search_mr_tmp=map_rect_new_mg(map, NULL);
488
489         return (struct map_search_priv *)mr;
490 }
491
492 static void
493 map_search_cleanup(struct map_rect_priv *mr)
494 {
495         g_free(mr->search_str);
496         mr->search_str=NULL;
497         tree_search_free(&mr->ts);
498         mr->search_linear=0;
499         mr->search_p=NULL;
500         mr->search_blk_count=0;
501         mr->search_blk_off=NULL;
502         mr->search_block=0;
503 }
504
505 static void
506 map_search_destroy_mg(struct map_search_priv *ms)
507 {
508         struct map_rect_priv *mr=(struct map_rect_priv *)ms;
509
510         dbg(1,"mr=%p\n", mr);
511         if (! mr)
512                 return;
513         map_search_cleanup(mr);
514         if (mr->search_mr_tmp)
515                 map_rect_destroy_mg(mr->search_mr_tmp);
516         attr_free(mr->search_attr);
517         g_free(mr);
518 }
519
520 static struct item *
521 map_search_get_item_mg(struct map_search_priv *ms)
522 {
523         struct map_rect_priv *mr=(struct map_rect_priv *)ms;
524         struct item *ret=NULL;
525
526         if (! mr)
527                 return NULL;
528         switch (mr->search_type) {
529         case attr_town_postal:
530         case attr_town_name:
531         case attr_district_name:
532                 ret=town_search_get_item(mr);
533                 break;
534         case attr_street_name:
535                 ret=street_search_get_item(mr);
536                 break;
537         case attr_house_number:
538                 ret=housenumber_search_get_item(mr);
539                 break;
540         default:
541                 dbg(0,"unknown search %s\n",attr_to_name(mr->search_type));
542                 break;
543         }
544         if (!ret && mr->search_type_next != attr_none) {
545                 mr->search_type=mr->search_type_next;
546                 mr->search_type_next=attr_none;
547                 map_search_cleanup(mr);
548                 map_search_setup(mr);
549                 return map_search_get_item_mg(ms);
550         }
551         return ret;
552 }
553
554 static struct map_methods map_methods_mg = {
555         projection_mg,
556         "iso8859-1",
557         map_destroy_mg,
558         map_rect_new_mg,
559         map_rect_destroy_mg,
560         map_rect_get_item_mg,
561         map_rect_get_item_byid_mg,
562         map_search_new_mg,
563         map_search_destroy_mg,
564         map_search_get_item_mg,
565 };
566
567
568 struct map_priv *
569 map_new_mg(struct map_methods *meth, struct attr **attrs)
570 {
571         struct map_priv *m;
572         int i,maybe_missing;
573         struct attr *data=attr_search(attrs, NULL, attr_data);
574         char *filename;
575         struct file_wordexp *wexp;
576         char **wexp_data;
577
578         if (! data)
579                 return NULL;
580         
581          wexp=file_wordexp_new(data->u.str);
582          wexp_data=file_wordexp_get_array(wexp);
583
584         *meth=map_methods_mg;
585         data=attr_search(attrs, NULL, attr_data);
586
587         m=g_new(struct map_priv, 1);
588         m->id=++map_id;
589         m->dirname=g_strdup(wexp_data[0]);
590         file_wordexp_destroy(wexp);
591         for (i = 0 ; i < file_end ; i++) {
592                 if (file[i]) {
593                         filename=g_strdup_printf("%s/%s", m->dirname, file[i]);
594                         m->file[i]=file_create_caseinsensitive(filename, 0);
595                         if (! m->file[i]) {
596                                 maybe_missing=(i == file_border_ply || i == file_height_ply || i == file_sea_ply);
597                                 if (! maybe_missing)
598                                         dbg(0,"Failed to load %s\n", filename);
599                         } else
600                                 file_mmap(m->file[i]);
601                         g_free(filename);
602                 }
603         }
604         maps=g_list_append(maps, m);
605
606         return m;
607 }
608
609 void
610 plugin_init(void)
611 {
612         plugin_register_map_type("mg", map_new_mg);
613 }